From 6275bb770c55f99169ab8e9593711ce27849d89e Mon Sep 17 00:00:00 2001 From: Jared O'Connell Date: Tue, 7 May 2024 12:46:19 -0400 Subject: [PATCH 1/5] Refactored namespaces to use maps of objects Also refactored the namespace fields to have defaults provided in the ScalarType struct --- schema/any.go | 8 +------- schema/bool.go | 3 ++- schema/enum.go | 2 +- schema/float.go | 13 ++++--------- schema/int.go | 15 +++++---------- schema/list.go | 4 ++-- schema/map.go | 6 +++--- schema/object.go | 4 ++-- schema/object_test.go | 2 +- schema/oneof.go | 4 ++-- schema/oneof_test.go | 2 +- schema/pattern.go | 2 +- schema/property.go | 4 ++-- schema/ref.go | 11 +++++------ schema/schema.go | 4 ++-- schema/schema_schema.go | 2 +- schema/scope.go | 14 +++++++------- schema/scope_test.go | 4 ++-- schema/step_output.go | 4 ++-- schema/string.go | 15 +++++---------- schema/types.go | 17 ++++++++++++++--- 21 files changed, 65 insertions(+), 75 deletions(-) diff --git a/schema/any.go b/schema/any.go index c62f1af..5e7bcaf 100644 --- a/schema/any.go +++ b/schema/any.go @@ -12,6 +12,7 @@ func NewAnySchema() *AnySchema { // AnySchema is a wildcard allowing maps, lists, integers, strings, bools. and floats. type AnySchema struct { + ScalarType } func (a *AnySchema) ReflectedType() reflect.Type { @@ -87,13 +88,6 @@ func (a *AnySchema) Serialize(data any) (any, error) { return a.checkAndConvert(data) } -func (a *AnySchema) ApplyScope(_ Scope, _ string) {} - -func (a *AnySchema) ValidateReferences() error { - // No references in this type. No work to do. - return nil -} - func (a *AnySchema) TypeID() TypeID { return TypeIDAny } diff --git a/schema/bool.go b/schema/bool.go index b8934ee..968180d 100644 --- a/schema/bool.go +++ b/schema/bool.go @@ -18,6 +18,7 @@ func NewBoolSchema() *BoolSchema { // BoolSchema holds the schema information for boolean types. type BoolSchema struct { + ScalarType } func (b BoolSchema) Unserialize(data any) (any, error) { @@ -121,7 +122,7 @@ func (b BoolSchema) SerializeType(data bool) (any, error) { return b.Serialize(data) } -func (b BoolSchema) ApplyScope(_ Scope, _ string) {} +func (b BoolSchema) ApplyNamespace(objects map[string]*ObjectSchema, namespace string) {} func (b BoolSchema) ValidateReferences() error { // No references in this type. No work to do. diff --git a/schema/enum.go b/schema/enum.go index f7fc3cb..a627352 100644 --- a/schema/enum.go +++ b/schema/enum.go @@ -26,7 +26,7 @@ func (e EnumSchema[T]) ValidValues() map[T]*DisplayValue { return e.ValidValuesMap } -func (e EnumSchema[T]) ApplyScope(_ Scope, _ string) {} +func (e EnumSchema[T]) ApplyNamespace(objects map[string]*ObjectSchema, namespace string) {} func (e EnumSchema[T]) ValidateReferences() error { // No references in this type. No work to do. diff --git a/schema/float.go b/schema/float.go index 0a3469a..fab3b00 100644 --- a/schema/float.go +++ b/schema/float.go @@ -20,13 +20,14 @@ type Float interface { // NewFloatSchema creates a new float schema from the specified values. func NewFloatSchema(min *float64, max *float64, units *UnitsDefinition) *FloatSchema { return &FloatSchema{ - min, - max, - units, + MinValue: min, + MaxValue: max, + UnitsValue: units, } } type FloatSchema struct { + ScalarType MinValue *float64 `json:"min"` MaxValue *float64 `json:"max"` UnitsValue *UnitsDefinition `json:"units"` @@ -51,12 +52,6 @@ func (f FloatSchema) Max() *float64 { func (f FloatSchema) Units() *UnitsDefinition { return f.UnitsValue } -func (f FloatSchema) ApplyScope(_ Scope, _ string) {} - -func (f FloatSchema) ValidateReferences() error { - // No references in this type. No work to do. - return nil -} func (f FloatSchema) Unserialize(data any) (any, error) { unserialized, err := floatInputMapper(data, f.UnitsValue) diff --git a/schema/int.go b/schema/int.go index daad9ad..23974ab 100644 --- a/schema/int.go +++ b/schema/int.go @@ -11,6 +11,7 @@ import ( // configuration but cannot serialize, unserialize or validate. For that functionality please use IntType. type Int interface { TypedType[int64] + ScalarType Min() *int64 Max() *int64 Units() *UnitsDefinition @@ -19,13 +20,14 @@ type Int interface { // NewIntSchema creates a new integer schema with the specified values. func NewIntSchema(min *int64, max *int64, units *UnitsDefinition) *IntSchema { return &IntSchema{ - min, - max, - units, + MinValue: min, + MaxValue: max, + UnitsValue: units, } } type IntSchema struct { + ScalarType MinValue *int64 `json:"min"` MaxValue *int64 `json:"max"` UnitsValue *UnitsDefinition `json:"units"` @@ -35,13 +37,6 @@ func (i IntSchema) ReflectedType() reflect.Type { return reflect.TypeOf(int64(0)) } -func (i IntSchema) ApplyScope(_ Scope, _ string) {} - -func (i IntSchema) ValidateReferences() error { - // No references in this type. No work to do. - return nil -} - func (i IntSchema) TypeID() TypeID { return TypeIDInt } diff --git a/schema/list.go b/schema/list.go index 405bd29..a62f14a 100644 --- a/schema/list.go +++ b/schema/list.go @@ -81,8 +81,8 @@ func (l AbstractListSchema[ItemType]) Max() *int64 { return l.MaxValue } -func (l AbstractListSchema[ItemType]) ApplyScope(scope Scope, namespace string) { - l.ItemsValue.ApplyScope(scope, namespace) +func (l AbstractListSchema[ItemType]) ApplyNamespace(objects map[string]*ObjectSchema, namespace string) { + l.ItemsValue.ApplyNamespace(objects, namespace) } func (l AbstractListSchema[ItemType]) ValidateReferences() error { diff --git a/schema/map.go b/schema/map.go index e49dd25..56e2693 100644 --- a/schema/map.go +++ b/schema/map.go @@ -80,9 +80,9 @@ func (m MapSchema[K, V]) Max() *int64 { return m.MaxValue } -func (m MapSchema[K, V]) ApplyScope(scope Scope, namespace string) { - m.KeysValue.ApplyScope(scope, namespace) - m.ValuesValue.ApplyScope(scope, namespace) +func (m MapSchema[K, V]) ApplyNamespace(objects map[string]*ObjectSchema, namespace string) { + m.KeysValue.ApplyNamespace(objects, namespace) + m.ValuesValue.ApplyNamespace(objects, namespace) } func (m MapSchema[K, V]) ValidateReferences() error { diff --git a/schema/object.go b/schema/object.go index de4910b..d55b74b 100644 --- a/schema/object.go +++ b/schema/object.go @@ -57,9 +57,9 @@ func (o *ObjectSchema) GetDefaults() map[string]any { return o.defaultValues } -func (o *ObjectSchema) ApplyScope(scope Scope, namespace string) { +func (o *ObjectSchema) ApplyNamespace(objects map[string]*ObjectSchema, namespace string) { for _, property := range o.PropertiesValue { - property.ApplyScope(scope, namespace) + property.ApplyNamespace(objects, namespace) } } diff --git a/schema/object_test.go b/schema/object_test.go index 8c3081e..1c1b613 100644 --- a/schema/object_test.go +++ b/schema/object_test.go @@ -552,7 +552,7 @@ func TestObjectSchema_ValidateCompatibility(t *testing.T) { assert.Error(t, testStructSchema.ValidateCompatibility(testOptionalFieldSchema)) // Not the same // Schema validation with ref objectTestRef := schema.NewRefSchema("testStruct", nil) - objectTestRef.ApplyScope(testStructScope, schema.DEFAULT_NAMESPACE) + objectTestRef.ApplyNamespace(testStructScope.Objects(), schema.SelfNamespace) assert.NoError(t, objectTestRef.ValidateCompatibility(testStructSchema)) assert.NoError(t, testStructSchema.ValidateCompatibility(objectTestRef)) // Schema validation with scope diff --git a/schema/oneof.go b/schema/oneof.go index af941e8..be3b0a7 100644 --- a/schema/oneof.go +++ b/schema/oneof.go @@ -43,9 +43,9 @@ func (o OneOfSchema[KeyType]) DiscriminatorFieldName() string { return o.DiscriminatorFieldNameValue } -func (o OneOfSchema[KeyType]) ApplyScope(scope Scope, namespace string) { +func (o OneOfSchema[KeyType]) ApplyNamespace(objects map[string]*ObjectSchema, namespace string) { for _, t := range o.TypesValue { - t.ApplyScope(scope, namespace) + t.ApplyNamespace(objects, namespace) } // scope must be applied before we can access the subtypes' properties err := o.validateSubtypeDiscriminatorInlineFields() diff --git a/schema/oneof_test.go b/schema/oneof_test.go index 410a213..2bdde7e 100644 --- a/schema/oneof_test.go +++ b/schema/oneof_test.go @@ -199,7 +199,7 @@ func Test_OneOf_ConstructorBypass(t *testing.T) { //nolint:funlen scopeAny := assert.NoErrorR[any](t)(schema.DescribeScope().Unserialize(input_schema)) scopeSchemaTyped := scopeAny.(*schema.ScopeSchema) - scopeSchemaTyped.ApplyScope(scopeSchemaTyped, schema.DEFAULT_NAMESPACE) + scopeSchemaTyped.ApplyNamespace(scopeSchemaTyped.Objects(), schema.SelfNamespace) assert.NoError(t, scopeSchemaTyped.Validate(input_data_fullname)) unserialized := assert.NoErrorR[any](t)(scopeSchemaTyped.Unserialize(input_data_fullname)) serialized := assert.NoErrorR[any](t)(scopeSchemaTyped.Serialize(unserialized)) diff --git a/schema/pattern.go b/schema/pattern.go index 8ba148e..a26b4cc 100644 --- a/schema/pattern.go +++ b/schema/pattern.go @@ -25,7 +25,7 @@ func (p PatternSchema) TypeID() TypeID { return TypeIDPattern } -func (p PatternSchema) ApplyScope(_ Scope, _ string) {} +func (p PatternSchema) ApplyNamespace(objects map[string]*ObjectSchema, namespace string) {} func (p PatternSchema) ValidateReferences() error { // No references in this type. No work to do. diff --git a/schema/property.go b/schema/property.go index f1a1500..b27386a 100644 --- a/schema/property.go +++ b/schema/property.go @@ -122,8 +122,8 @@ func (p *PropertySchema) Examples() []string { return p.ExamplesValue } -func (p *PropertySchema) ApplyScope(scope Scope, namespace string) { - p.TypeValue.ApplyScope(scope, namespace) +func (p *PropertySchema) ApplyNamespace(objects map[string]*ObjectSchema, namespace string) { + p.TypeValue.ApplyNamespace(objects, namespace) } func (p *PropertySchema) ValidateReferences() error { diff --git a/schema/ref.go b/schema/ref.go index 24fd616..9dbaa88 100644 --- a/schema/ref.go +++ b/schema/ref.go @@ -7,7 +7,7 @@ import ( // Ref holds the definition of a reference to a scope-wide object. The ref must always be inside a scope, // either directly or indirectly. If several scopes are embedded within each other, the Ref references the object -// in the scope specified. DEFAULT_NAMESPACE for current scope. +// in the scope specified. SelfNamespace for current scope. type Ref interface { Object @@ -20,7 +20,7 @@ type Ref interface { // NewRefSchema creates a new reference to an object in a wrapping Scope by ID. func NewRefSchema(id string, display Display) *RefSchema { - return NewNamespacedRefSchema(id, DEFAULT_NAMESPACE, display) + return NewNamespacedRefSchema(id, SelfNamespace, display) } // NewNamespacedRefSchema creates a new reference to an object in a wrapping Scope by ID and namespace. @@ -105,13 +105,12 @@ func (r *RefSchema) Display() Display { return r.DisplayValue } -// ApplyScope links the reference to the object if the given namespace +// ApplyNamespace links the reference to the object if the given namespace // matches the ref's namespace. Other namespaces are skipped. -func (r *RefSchema) ApplyScope(scope Scope, namespace string) { +func (r *RefSchema) ApplyNamespace(objects map[string]*ObjectSchema, namespace string) { if namespace != r.ObjectNamespace { - return // The scope does not apply to this reference. + return // The objects do not apply to this reference. } - objects := scope.Objects() referencedObject, ok := objects[r.IDValue] if !ok { availableObjects := "" diff --git a/schema/schema.go b/schema/schema.go index 7795f77..7effebd 100644 --- a/schema/schema.go +++ b/schema/schema.go @@ -48,9 +48,9 @@ func (s SchemaSchema) Steps() map[string]Step { func (s SchemaSchema) applyScope() { for _, step := range s.StepsValue { // We can apply an empty scope because the scope does not need another scope. - step.InputValue.ApplyScope(nil, DEFAULT_NAMESPACE) + step.InputValue.ApplyNamespace(nil, SelfNamespace) for _, output := range step.OutputsValue { - output.ApplyScope(nil, DEFAULT_NAMESPACE) + output.ApplyNamespace(nil, SelfNamespace) } } } diff --git a/schema/schema_schema.go b/schema/schema_schema.go index 66dabc9..0db659e 100644 --- a/schema/schema_schema.go +++ b/schema/schema_schema.go @@ -843,7 +843,7 @@ var basicObjects = []*ObjectSchema{ nil, nil, nil, - PointerTo(DEFAULT_NAMESPACE), + PointerTo(SelfNamespace), nil, ), "display": displayProperty, diff --git a/schema/scope.go b/schema/scope.go index 729d3f3..b7a8a2c 100644 --- a/schema/scope.go +++ b/schema/scope.go @@ -33,7 +33,7 @@ func NewScopeSchema(rootObject *ObjectSchema, objects ...*ObjectSchema) *ScopeSc } for _, v := range objectMap { - v.ApplyScope(schema, DEFAULT_NAMESPACE) + v.ApplyNamespace(schema.Objects(), SelfNamespace) } return schema @@ -93,16 +93,16 @@ func (s *ScopeSchema) Serialize(data any) (any, error) { return s.RootObject().Serialize(data) } -func (s *ScopeSchema) ApplyScope(externalScope Scope, namespace string) { +func (s *ScopeSchema) ApplyNamespace(externalObjects map[string]*ObjectSchema, namespace string) { // When the namespace is the default namespace, each scope should pass itself down. - var scopeToApply Scope - if namespace == DEFAULT_NAMESPACE { - scopeToApply = s + var objectsToApply map[string]*ObjectSchema + if namespace == SelfNamespace { + objectsToApply = s.Objects() } else { - scopeToApply = externalScope + objectsToApply = externalObjects } for _, v := range s.ObjectsValue { - v.ApplyScope(scopeToApply, namespace) + v.ApplyNamespace(objectsToApply, namespace) } } diff --git a/schema/scope_test.go b/schema/scope_test.go index 2c4bcc6..97ef805 100644 --- a/schema/scope_test.go +++ b/schema/scope_test.go @@ -464,7 +464,7 @@ func TestApplyingExternalNamespace(t *testing.T) { assert.Error(t, err) assert.Contains(t, err.Error(), "missing its link") assert.Equals(t, testData.ref.ObjectReady(), false) - testData.scope.ApplyScope(externalScope, "test-namespace") + testData.scope.ApplyNamespace(externalScope.Objects(), "test-namespace") assert.Equals(t, testData.ref.ObjectReady(), true) // Now it's applied, so the error should be resolved. // Outermost @@ -492,7 +492,7 @@ func TestApplyingExternalNamespaceToNonRefTypes(t *testing.T) { // Not applied yet // Should be no error because none of the given types can contain references. assert.NoError(t, testType.ValidateReferences()) - testType.ApplyScope(scopeTestObjectEmptySchema, "test-namespace") + testType.ApplyNamespace(scopeTestObjectEmptySchema.Objects(), "test-namespace") // Should still be no error. assert.NoError(t, testType.ValidateReferences()) }) diff --git a/schema/step_output.go b/schema/step_output.go index 31ff10d..74ff67d 100644 --- a/schema/step_output.go +++ b/schema/step_output.go @@ -55,8 +55,8 @@ func (s StepOutputSchema) Serialize(data any) (any, error) { return s.SchemaValue.Serialize(data) } -func (s StepOutputSchema) ApplyScope(scope Scope, namespace string) { - s.SchemaValue.ApplyScope(scope, namespace) +func (s StepOutputSchema) ApplyNamespace(objects map[string]*ObjectSchema, namespace string) { + s.SchemaValue.ApplyNamespace(objects, namespace) } func (s StepOutputSchema) ValidateReferences() error { diff --git a/schema/string.go b/schema/string.go index 299e6fa..e5dd404 100644 --- a/schema/string.go +++ b/schema/string.go @@ -19,13 +19,15 @@ type String interface { // NewStringSchema creates a new string schema. func NewStringSchema(minLen *int64, maxLen *int64, pattern *regexp.Regexp) *StringSchema { return &StringSchema{ - minLen, - maxLen, - pattern, + MinValue: minLen, + MaxValue: maxLen, + PatternValue: pattern, } } type StringSchema struct { + ScalarType + MinValue *int64 `json:"min"` MaxValue *int64 `json:"max"` PatternValue *regexp.Regexp `json:"pattern"` @@ -53,13 +55,6 @@ func (s StringSchema) Pattern() *regexp.Regexp { return s.PatternValue } -func (s StringSchema) ApplyScope(_ Scope, _ string) {} - -func (s StringSchema) ValidateReferences() error { - // No references in this type. No work to do. - return nil -} - func (s StringSchema) Unserialize(data any) (any, error) { return s.UnserializeType(data) } diff --git a/schema/types.go b/schema/types.go index ac22674..b148164 100644 --- a/schema/types.go +++ b/schema/types.go @@ -50,7 +50,7 @@ const ( TypeIDAny TypeID = "any" ) -const DEFAULT_NAMESPACE string = "" +const SelfNamespace string = "" // Serializable describes the minimum feature set a part of the schema hierarchy must implement. type Serializable interface { @@ -64,8 +64,8 @@ type Serializable interface { ValidateCompatibility(typeOrData any) error // Serialize serializes the provided data. Serialize(data any) (any, error) - // ApplyScope notifies the current schema being added to a scope. - ApplyScope(scope Scope, namespace string) + // ApplyNamespace makes namespace object available to resolve references. + ApplyNamespace(objects map[string]*ObjectSchema, namespace string) // ValidateReferences validates that all references had their referenced objects found. // Useful to ensure the error is caught early rather than later when it's used. ValidateReferences() error @@ -88,6 +88,17 @@ type TypedType[T any] interface { SerializeType(data T) (any, error) } +type ScalarType struct { +} + +func (s *ScalarType) ApplyNamespace(_ map[string]*ObjectSchema, _ string) { + // Scalar types have no references, so the namespace can be ignored. +} + +func (s *ScalarType) ValidateReferences() error { + return nil // Scalar types have no references, so no work to do. +} + // MapKeyType are types that can be used as map keys. type MapKeyType interface { int64 | string From 23ce5e87efe058ab30ebad454d7eeb272a103d8d Mon Sep 17 00:00:00 2001 From: Jared O'Connell Date: Tue, 7 May 2024 12:58:59 -0400 Subject: [PATCH 2/5] Fix linter, and remove now-unneeded functions --- schema/bool.go | 7 ------- schema/bool_test.go | 12 ++++-------- schema/enum.go | 8 +------- schema/enum_int.go | 2 +- schema/enum_string.go | 2 +- 5 files changed, 7 insertions(+), 24 deletions(-) diff --git a/schema/bool.go b/schema/bool.go index 968180d..cb5ede6 100644 --- a/schema/bool.go +++ b/schema/bool.go @@ -122,13 +122,6 @@ func (b BoolSchema) SerializeType(data bool) (any, error) { return b.Serialize(data) } -func (b BoolSchema) ApplyNamespace(objects map[string]*ObjectSchema, namespace string) {} - -func (b BoolSchema) ValidateReferences() error { - // No references in this type. No work to do. - return nil -} - func (b BoolSchema) TypeID() TypeID { return TypeIDBool } diff --git a/schema/bool_test.go b/schema/bool_test.go index 8256e77..73be02d 100644 --- a/schema/bool_test.go +++ b/schema/bool_test.go @@ -186,17 +186,13 @@ func TestBoolSerializationCycle(t *testing.T) { } func TestBoolJSONMarshal(t *testing.T) { - j, err := json.Marshal(schema.NewBoolSchema()) - if err != nil { - t.Fatal(err) - } + boolType := schema.NewBoolSchema() + j, err := json.Marshal(&boolType) + assert.NoError(t, err) if string(j) != "{}" { t.Fatalf("Unexpected JSON output: %s", j) } - boolType := schema.NewBoolSchema() - if err := json.Unmarshal(j, &boolType); err != nil { - t.Fatal(err) - } + assert.NoError(t, json.Unmarshal(j, &boolType)) } func TestBoolSchema(t *testing.T) { diff --git a/schema/enum.go b/schema/enum.go index a627352..8119c67 100644 --- a/schema/enum.go +++ b/schema/enum.go @@ -19,6 +19,7 @@ type Enum[T enumValue] interface { } type EnumSchema[T enumValue] struct { + ScalarType ValidValuesMap map[T]*DisplayValue `json:"values"` } @@ -26,13 +27,6 @@ func (e EnumSchema[T]) ValidValues() map[T]*DisplayValue { return e.ValidValuesMap } -func (e EnumSchema[T]) ApplyNamespace(objects map[string]*ObjectSchema, namespace string) {} - -func (e EnumSchema[T]) ValidateReferences() error { - // No references in this type. No work to do. - return nil -} - func (e EnumSchema[T]) ReflectedType() reflect.Type { var defaultValue T return reflect.TypeOf(defaultValue) diff --git a/schema/enum_int.go b/schema/enum_int.go index 16ca216..d228294 100644 --- a/schema/enum_int.go +++ b/schema/enum_int.go @@ -6,7 +6,7 @@ import "fmt" func NewIntEnumSchema(validValues map[int64]*DisplayValue, units *UnitsDefinition) *IntEnumSchema { return &IntEnumSchema{ EnumSchema[int64]{ - validValues, + ValidValuesMap: validValues, }, units, } diff --git a/schema/enum_string.go b/schema/enum_string.go index a068147..2738349 100644 --- a/schema/enum_string.go +++ b/schema/enum_string.go @@ -6,7 +6,7 @@ import "fmt" func NewStringEnumSchema(validValues map[string]*DisplayValue) *StringEnumSchema { return &StringEnumSchema{ EnumSchema[string]{ - validValues, + ValidValuesMap: validValues, }, } } From 3e2237bcccef91b257c2d37c47e432399447d794 Mon Sep 17 00:00:00 2001 From: Jared O'Connell Date: Tue, 7 May 2024 18:23:04 -0400 Subject: [PATCH 3/5] Address review feedback and other improvements --- schema/bool_test.go | 6 ++++-- schema/pattern.go | 8 +------- schema/ref.go | 4 ++-- schema/schema.go | 2 +- schema/schema_schema.go | 2 +- schema/types.go | 3 +++ 6 files changed, 12 insertions(+), 13 deletions(-) diff --git a/schema/bool_test.go b/schema/bool_test.go index 73be02d..4a3a9cc 100644 --- a/schema/bool_test.go +++ b/schema/bool_test.go @@ -187,12 +187,14 @@ func TestBoolSerializationCycle(t *testing.T) { func TestBoolJSONMarshal(t *testing.T) { boolType := schema.NewBoolSchema() - j, err := json.Marshal(&boolType) + //nolint:staticcheck + j, err := json.Marshal(boolType) assert.NoError(t, err) if string(j) != "{}" { t.Fatalf("Unexpected JSON output: %s", j) } - assert.NoError(t, json.Unmarshal(j, &boolType)) + //nolint:staticcheck + assert.NoError(t, json.Unmarshal(j, boolType)) } func TestBoolSchema(t *testing.T) { diff --git a/schema/pattern.go b/schema/pattern.go index a26b4cc..1429697 100644 --- a/schema/pattern.go +++ b/schema/pattern.go @@ -19,19 +19,13 @@ func NewPatternSchema() *PatternSchema { } type PatternSchema struct { + ScalarType } func (p PatternSchema) TypeID() TypeID { return TypeIDPattern } -func (p PatternSchema) ApplyNamespace(objects map[string]*ObjectSchema, namespace string) {} - -func (p PatternSchema) ValidateReferences() error { - // No references in this type. No work to do. - return nil -} - func (p PatternSchema) ReflectedType() reflect.Type { return reflect.TypeOf(®exp.Regexp{}) } diff --git a/schema/ref.go b/schema/ref.go index 9dbaa88..195c6a6 100644 --- a/schema/ref.go +++ b/schema/ref.go @@ -128,8 +128,8 @@ func (r *RefSchema) ValidateReferences() error { if r.referencedObjectCache != nil { return nil // Success } - // The only way, unless there is a bug, for it to get here is if ApplyScope was not called with the - // correct namespace, or if the code disregards the error returned by ApplyScope. ApplyScope should + // The only way, unless there is a bug, for it to get here is if ApplyNamespace was not called with the + // correct namespace, or if the code disregards the error returned by ApplyNamespace. ApplyNamespace should // always set referencedObjectCache or return an error if the correct namespace is applied. return BadArgumentError{ Message: fmt.Sprintf( diff --git a/schema/schema.go b/schema/schema.go index 7effebd..6730dda 100644 --- a/schema/schema.go +++ b/schema/schema.go @@ -45,7 +45,7 @@ func (s SchemaSchema) Steps() map[string]Step { return result } -func (s SchemaSchema) applyScope() { +func (s SchemaSchema) applyNamespace() { for _, step := range s.StepsValue { // We can apply an empty scope because the scope does not need another scope. step.InputValue.ApplyNamespace(nil, SelfNamespace) diff --git a/schema/schema_schema.go b/schema/schema_schema.go index 0db659e..0d86c70 100644 --- a/schema/schema_schema.go +++ b/schema/schema_schema.go @@ -1313,6 +1313,6 @@ func UnserializeSchema(data any) (*SchemaSchema, error) { return nil, err } result := s.(*SchemaSchema) - result.applyScope() + result.applyNamespace() return result, nil } diff --git a/schema/types.go b/schema/types.go index b148164..6650fd4 100644 --- a/schema/types.go +++ b/schema/types.go @@ -88,6 +88,9 @@ type TypedType[T any] interface { SerializeType(data T) (any, error) } +// ScalarType is a struct that provides default implementations for ApplyScope and +// ValidateReferences for types that cannot contain references. Those two +// functions do not do anything when there are no references. type ScalarType struct { } From 24a22605dabe30a879ccda3393d64c24c6de3b0b Mon Sep 17 00:00:00 2001 From: Jared O'Connell Date: Tue, 7 May 2024 18:25:59 -0400 Subject: [PATCH 4/5] Address review comments --- schema/ref.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/schema/ref.go b/schema/ref.go index 195c6a6..9f88f7b 100644 --- a/schema/ref.go +++ b/schema/ref.go @@ -7,7 +7,7 @@ import ( // Ref holds the definition of a reference to a scope-wide object. The ref must always be inside a scope, // either directly or indirectly. If several scopes are embedded within each other, the Ref references the object -// in the scope specified. SelfNamespace for current scope. +// in the scope specified. SelfNamespace refers to the current scope. type Ref interface { Object @@ -109,7 +109,7 @@ func (r *RefSchema) Display() Display { // matches the ref's namespace. Other namespaces are skipped. func (r *RefSchema) ApplyNamespace(objects map[string]*ObjectSchema, namespace string) { if namespace != r.ObjectNamespace { - return // The objects do not apply to this reference. + return // This reference does not refer to an object in the supplied namespace. } referencedObject, ok := objects[r.IDValue] if !ok { From 6ee7f8bc57b5511f8b2682c96537f862a56daf7f Mon Sep 17 00:00:00 2001 From: Jared O'Connell Date: Wed, 8 May 2024 18:33:48 -0400 Subject: [PATCH 5/5] Addressed review feedback --- schema/oneof_test.go | 2 +- schema/schema.go | 4 ++-- schema/scope.go | 10 +++++++--- schema/types.go | 6 +++--- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/schema/oneof_test.go b/schema/oneof_test.go index 2bdde7e..c7613c9 100644 --- a/schema/oneof_test.go +++ b/schema/oneof_test.go @@ -199,7 +199,7 @@ func Test_OneOf_ConstructorBypass(t *testing.T) { //nolint:funlen scopeAny := assert.NoErrorR[any](t)(schema.DescribeScope().Unserialize(input_schema)) scopeSchemaTyped := scopeAny.(*schema.ScopeSchema) - scopeSchemaTyped.ApplyNamespace(scopeSchemaTyped.Objects(), schema.SelfNamespace) + scopeSchemaTyped.ApplySelf() assert.NoError(t, scopeSchemaTyped.Validate(input_data_fullname)) unserialized := assert.NoErrorR[any](t)(scopeSchemaTyped.Unserialize(input_data_fullname)) serialized := assert.NoErrorR[any](t)(scopeSchemaTyped.Serialize(unserialized)) diff --git a/schema/schema.go b/schema/schema.go index 6730dda..b592c9d 100644 --- a/schema/schema.go +++ b/schema/schema.go @@ -48,9 +48,9 @@ func (s SchemaSchema) Steps() map[string]Step { func (s SchemaSchema) applyNamespace() { for _, step := range s.StepsValue { // We can apply an empty scope because the scope does not need another scope. - step.InputValue.ApplyNamespace(nil, SelfNamespace) + step.InputValue.ApplySelf() for _, output := range step.OutputsValue { - output.ApplyNamespace(nil, SelfNamespace) + output.Schema().ApplySelf() } } } diff --git a/schema/scope.go b/schema/scope.go index b7a8a2c..aededdd 100644 --- a/schema/scope.go +++ b/schema/scope.go @@ -15,6 +15,7 @@ type Scope interface { Root() string RootObject() *ObjectSchema + ApplySelf() SelfSerialize() (any, error) } @@ -32,9 +33,7 @@ func NewScopeSchema(rootObject *ObjectSchema, objects ...*ObjectSchema) *ScopeSc root, } - for _, v := range objectMap { - v.ApplyNamespace(schema.Objects(), SelfNamespace) - } + schema.ApplySelf() return schema } @@ -93,6 +92,11 @@ func (s *ScopeSchema) Serialize(data any) (any, error) { return s.RootObject().Serialize(data) } +func (s *ScopeSchema) ApplySelf() { + // Currently ApplyNamespace ignores externalObjects when namespace is SelfNamespace. + s.ApplyNamespace(nil, SelfNamespace) +} + func (s *ScopeSchema) ApplyNamespace(externalObjects map[string]*ObjectSchema, namespace string) { // When the namespace is the default namespace, each scope should pass itself down. var objectsToApply map[string]*ObjectSchema diff --git a/schema/types.go b/schema/types.go index 6650fd4..0a953c9 100644 --- a/schema/types.go +++ b/schema/types.go @@ -88,9 +88,9 @@ type TypedType[T any] interface { SerializeType(data T) (any, error) } -// ScalarType is a struct that provides default implementations for ApplyScope and -// ValidateReferences for types that cannot contain references. Those two -// functions do not do anything when there are no references. +// ScalarType is a struct that provides default implementations for +// ApplyNamespace and ValidateReferences for types that cannot contain +// references. type ScalarType struct { }