Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for Property Definitions #308

Merged
28 commits merged into from
Dec 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changes/unreleased/Feature-20231115-143536.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
kind: Feature
body: Add support for Property Definitions
time: 2023-12-07T15:22:26.29648-05:00
89 changes: 89 additions & 0 deletions property.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package opslevel

import "fmt"

type PropertyDefinitionInput struct {
Name string `json:"name"`
Schema JSONString `json:"schema"`
}

type PropertyDefinition struct {
Aliases []string `graphql:"aliases" json:"aliases"`
Id ID `graphql:"id" json:"id"`
Name string `graphql:"name" json:"name"`
Schema JSON `json:"schema" scalar:"true"` // Do not add graphql struct tag here
Copy link
Collaborator

@rocktavious rocktavious Dec 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well you can add graphql struct tags if you neeed - you actually just need scalar:"true" because JSON is a custom scalar type we wrote.

}

type PropertyDefinitionConnection struct {
Nodes []PropertyDefinition
PageInfo PageInfo
TotalCount int `graphql:"-"`
}

func (client *Client) CreatePropertyDefinition(input PropertyDefinitionInput) (*PropertyDefinition, error) {
var m struct {
Payload struct {
Definition PropertyDefinition `graphql:"definition"`
Errors []OpsLevelErrors `graphql:"errors"`
} `graphql:"propertyDefinitionCreate(input: $input)"`
}
v := PayloadVariables{
"input": input,
}
err := client.Mutate(&m, v, WithName("PropertyDefinitionCreate"))
return &m.Payload.Definition, HandleErrors(err, m.Payload.Errors)
}

func (client *Client) GetPropertyDefinition(input string) (*PropertyDefinition, error) {
var q struct {
Account struct {
Definition PropertyDefinition `graphql:"propertyDefinition(input: $input)"`
}
}
v := PayloadVariables{
"input": *NewIdentifier(input),
}
err := client.Query(&q, v, WithName("PropertyDefinitionGet"))
if q.Account.Definition.Id == "" {
err = fmt.Errorf("PropertyDefinition with ID or Alias matching '%s' not found", input)

Check warning on line 48 in property.go

View check run for this annotation

Codecov / codecov/patch

property.go#L48

Added line #L48 was not covered by tests
This conversation was marked as resolved.
Show resolved Hide resolved
}
return &q.Account.Definition, HandleErrors(err, nil)
}

func (client *Client) ListPropertyDefinitions(variables *PayloadVariables) (PropertyDefinitionConnection, error) {
var q struct {
Account struct {
Definitions PropertyDefinitionConnection `graphql:"propertyDefinitions(after: $after, first: $first)"`
}
}
if variables == nil {
variables = client.InitialPageVariablesPointer()
}
if err := client.Query(&q, *variables, WithName("PropertyDefinitionList")); err != nil {
return PropertyDefinitionConnection{}, err

Check warning on line 63 in property.go

View check run for this annotation

Codecov / codecov/patch

property.go#L63

Added line #L63 was not covered by tests
}
for q.Account.Definitions.PageInfo.HasNextPage {
(*variables)["after"] = q.Account.Definitions.PageInfo.End
resp, err := client.ListPropertyDefinitions(variables)
if err != nil {
return PropertyDefinitionConnection{}, err

Check warning on line 69 in property.go

View check run for this annotation

Codecov / codecov/patch

property.go#L69

Added line #L69 was not covered by tests
}
q.Account.Definitions.Nodes = append(q.Account.Definitions.Nodes, resp.Nodes...)
q.Account.Definitions.PageInfo = resp.PageInfo
q.Account.Definitions.TotalCount += len(q.Account.Definitions.Nodes)
}
return q.Account.Definitions, nil
}

func (client *Client) DeletePropertyDefinition(input string) error {
var m struct {
Payload struct {
Errors []OpsLevelErrors `graphql:"errors"`
} `graphql:"propertyDefinitionDelete(resource: $input)"`
}
v := PayloadVariables{
"input": *NewIdentifier(input),
}
err := client.Mutate(&m, v, WithName("PropertyDefinitionDelete"))
return HandleErrors(err, m.Payload.Errors)
}
135 changes: 135 additions & 0 deletions property_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package opslevel_test

import (
"fmt"
"testing"

ol "github.com/opslevel/opslevel-go/v2023"
"github.com/rocktavious/autopilot/v2023"
)

const schemaString = `{"$ref":"#/$defs/MyProp","$defs":{"MyProp":{"properties":{"name":{"type":"string","title":"the name","description":"The name of a friend","default":"alex","examples":["joe","lucy"]}},"additionalProperties":false,"type":"object","required":["name"]}}}`

func TestCreatePropertyDefinition(t *testing.T) {
// Arrange
This conversation was marked as resolved.
Show resolved Hide resolved
schema := ol.NewJSON(schemaString)
expectedPropertyDefinition := autopilot.Register[ol.PropertyDefinition]("expected_property_definition", ol.PropertyDefinition{
Aliases: []string{"my_prop"},
Id: "XXX",
Name: "my-prop",
Schema: schema,
})
propertyDefinitionInput := autopilot.Register[ol.PropertyDefinitionInput]("property_definition_input", ol.PropertyDefinitionInput{
Name: "my-prop",
Schema: ol.JSONString(schemaString),
})
testRequest := NewTestRequest(
`"mutation PropertyDefinitionCreate($input:PropertyDefinitionInput!){propertyDefinitionCreate(input: $input){definition{aliases,id,name,schema},errors{message,path}}}"`,
`{"input": {{ template "property_definition_input" }} }`,
fmt.Sprintf(`{"data":{"propertyDefinitionCreate":{"definition": {"aliases":["my_prop"],"id":"XXX","name":"my-prop","schema": %s}, "errors":[] }}}`, schema.ToJSON()),
)
client := BestTestClient(t, "properties/definition_create", testRequest)

// Act
actualPropertyDefinition, err := client.CreatePropertyDefinition(propertyDefinitionInput)

// Assert
autopilot.Ok(t, err)
autopilot.Equals(t, expectedPropertyDefinition, *actualPropertyDefinition)
autopilot.Equals(t, ol.JSON(propertyDefinitionInput.Schema.Map()), actualPropertyDefinition.Schema)
}

func TestDeletePropertyDefinition(t *testing.T) {
// Arrange
testRequest := NewTestRequest(
`"mutation PropertyDefinitionDelete($input:IdentifierInput!){propertyDefinitionDelete(resource: $input){errors{message,path}}}"`,
`{"input":{"alias":"my_prop"}}`,
`{"data":{"propertyDefinitionDelete":{"errors":[]}}}`,
)
client := BestTestClient(t, "properties/definition_delete", testRequest)

// Act
err := client.DeletePropertyDefinition("my_prop")

// Assert
autopilot.Ok(t, err)
}

func TestGetPropertyDefinition(t *testing.T) {
// Arrange
schema := ol.NewJSON(schemaString)
expectedPropertyDefinition := autopilot.Register[ol.PropertyDefinition]("expected_property_definition",
ol.PropertyDefinition{
Aliases: []string{"my_prop"},
Id: "XXX",
Name: "my-prop",
Schema: schema,
})
testRequest := NewTestRequest(
`"query PropertyDefinitionGet($input:IdentifierInput!){account{propertyDefinition(input: $input){aliases,id,name,schema}}}"`,
`{"input":{"alias":"my_prop"}}`,
fmt.Sprintf(`{"data":{"account":{"propertyDefinition": {"aliases":["my_prop"],"id":"XXX","name":"my-prop","schema": %s }}}}`, schema.ToJSON()),
)
client := BestTestClient(t, "properties/definition_get", testRequest)

// Act
property, err := client.GetPropertyDefinition("my_prop")

// Assert
autopilot.Ok(t, err)
autopilot.Equals(t, "XXX", string(property.Id))
autopilot.Equals(t, expectedPropertyDefinition, *property)
autopilot.Equals(t, "my-prop", property.Name)
autopilot.Equals(t, schema, property.Schema)
}

func TestListPropertyDefinitions(t *testing.T) {
// Arrange
schema := ol.NewJSON(schemaString)
expectedPropDefsPageOne := autopilot.Register[[]ol.PropertyDefinition]("property_definitions", []ol.PropertyDefinition{
{
Aliases: []string{"prop1"},
Id: "XXX",
Name: "prop1",
Schema: ol.NewJSON(schemaString),
},
{
Aliases: []string{"prop2"},
Id: "XXX",
Name: "prop2",
Schema: ol.NewJSON(schemaString),
},
})
expectedPropDefPageTwo := autopilot.Register[ol.PropertyDefinition]("property_definition_3", ol.PropertyDefinition{
Aliases: []string{"prop3"},
Id: "XXX",
Name: "prop3",
Schema: ol.NewJSON(schemaString),
})
testRequestOne := NewTestRequest(
`"query PropertyDefinitionList($after:String!$first:Int!){account{propertyDefinitions(after: $after, first: $first){nodes{aliases,id,name,schema},{{ template "pagination_request" }}}}}"`,
`{{ template "pagination_initial_query_variables" }}`,
fmt.Sprintf(`{"data":{"account":{"propertyDefinitions":{"nodes":[{"aliases":["prop1"],"id":"XXX","name":"prop1","schema": %s},{"aliases":["prop2"],"id":"XXX","name":"prop2","schema": %s}],{{ template "pagination_initial_pageInfo_response" }}}}}}`, schema.ToJSON(), schema.ToJSON()),
)
testRequestTwo := NewTestRequest(
`"query PropertyDefinitionList($after:String!$first:Int!){account{propertyDefinitions(after: $after, first: $first){nodes{aliases,id,name,schema},{{ template "pagination_request" }}}}}"`,
`{{ template "pagination_second_query_variables" }}`,
fmt.Sprintf(`{"data":{"account":{"propertyDefinitions":{"nodes":[{"aliases":["prop3"],"id":"XXX","name":"prop3","schema": %s}],{{ template "pagination_second_pageInfo_response" }}}}}}`, schema.ToJSON()),
)
requests := []TestRequest{testRequestOne, testRequestTwo}
client := BestTestClient(t, "properties/definition_list", requests...)

// Act
properties, err := client.ListPropertyDefinitions(nil)
result := properties.Nodes

// Assert
autopilot.Ok(t, err)
autopilot.Equals(t, 3, len(result))
autopilot.Equals(t, expectedPropDefsPageOne[0], result[0])
autopilot.Equals(t, expectedPropDefsPageOne[1], result[1])
autopilot.Equals(t, expectedPropDefPageTwo, result[2])
autopilot.Equals(t, expectedPropDefsPageOne[0].Schema, result[0].Schema)
autopilot.Equals(t, expectedPropDefsPageOne[1].Schema, result[1].Schema)
autopilot.Equals(t, expectedPropDefPageTwo.Schema, result[2].Schema)
}
Loading