refactor(schema)!: rename Schema -> TypeSet and other small renamings (#21446)

This commit is contained in:
Aaron Craelius 2024-08-30 13:01:48 -04:00 committed by GitHub
parent b33ed0716b
commit ce8f9d40f2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 106 additions and 89 deletions

View File

@ -36,7 +36,7 @@ func init() {
AllKindsObject.ValueFields = append(AllKindsObject.ValueFields, field)
}
ExampleSchema = schema.MustNewModuleSchema(
ExampleSchema = schema.MustCompileModuleSchema(
AllKindsObject,
SingletonObject,
VoteObject,

View File

@ -371,7 +371,7 @@ func (e exampleBankModule) subBalance(acct, denom string, amount uint64) error {
func init() {
var err error
exampleBankSchema, err = schema.NewModuleSchema(schema.ObjectType{
exampleBankSchema, err = schema.CompileModuleSchema(schema.ObjectType{
Name: "balances",
KeyFields: []schema.Field{
{
@ -435,7 +435,7 @@ type oneValueModule struct {
func init() {
var err error
oneValueModSchema, err = schema.NewModuleSchema(schema.ObjectType{
oneValueModSchema, err = schema.CompileModuleSchema(schema.ObjectType{
Name: "item",
ValueFields: []schema.Field{
{Name: "value", Kind: schema.StringKind},

View File

@ -10,7 +10,7 @@ import (
type modA struct{}
func (m modA) ModuleCodec() (schema.ModuleCodec, error) {
modSchema, err := schema.NewModuleSchema(schema.ObjectType{Name: "A", KeyFields: []schema.Field{{Name: "field1", Kind: schema.StringKind}}})
modSchema, err := schema.CompileModuleSchema(schema.ObjectType{Name: "A", KeyFields: []schema.Field{{Name: "field1", Kind: schema.StringKind}}})
if err != nil {
return schema.ModuleCodec{}, err
}
@ -22,7 +22,7 @@ func (m modA) ModuleCodec() (schema.ModuleCodec, error) {
type modB struct{}
func (m modB) ModuleCodec() (schema.ModuleCodec, error) {
modSchema, err := schema.NewModuleSchema(schema.ObjectType{Name: "B", KeyFields: []schema.Field{{Name: "field2", Kind: schema.StringKind}}})
modSchema, err := schema.CompileModuleSchema(schema.ObjectType{Name: "B", KeyFields: []schema.Field{{Name: "field2", Kind: schema.StringKind}}})
if err != nil {
return schema.ModuleCodec{}, err
}
@ -44,7 +44,7 @@ var testResolver = ModuleSetDecoderResolver(moduleSet)
func TestModuleSetDecoderResolver_IterateAll(t *testing.T) {
objectTypes := map[string]bool{}
err := testResolver.IterateAll(func(moduleName string, cdc schema.ModuleCodec) error {
cdc.Schema.Types(func(t schema.Type) bool {
cdc.Schema.AllTypes(func(t schema.Type) bool {
objTyp, ok := t.(schema.ObjectType)
if ok {
objectTypes[objTyp.Name] = true

View File

@ -332,7 +332,7 @@ func TestCompareModuleSchemas(t *testing.T) {
}
func requireModuleSchema(t *testing.T, types ...schema.Type) schema.ModuleSchema {
s, err := schema.NewModuleSchema(types...)
s, err := schema.CompileModuleSchema(types...)
if err != nil {
t.Fatal(err)
}

View File

@ -44,7 +44,7 @@ func (e EnumType) TypeName() string {
func (EnumType) isType() {}
// Validate validates the enum definition.
func (e EnumType) Validate(Schema) error {
func (e EnumType) Validate(TypeSet) error {
if !ValidateName(e.Name) {
return fmt.Errorf("invalid enum definition name %q", e.Name)
}

View File

@ -108,7 +108,7 @@ func TestEnumDefinition_Validate(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := tt.enum.Validate(EmptySchema{})
err := tt.enum.Validate(EmptyTypeSet())
if tt.errContains == "" {
if err != nil {
t.Errorf("expected valid enum definition to pass validation, got: %v", err)

View File

@ -20,7 +20,7 @@ type Field struct {
}
// Validate validates the field.
func (c Field) Validate(schema Schema) error {
func (c Field) Validate(typeSet TypeSet) error {
// valid name
if !ValidateName(c.Name) {
return fmt.Errorf("invalid field name %q", c.Name)
@ -38,7 +38,7 @@ func (c Field) Validate(schema Schema) error {
return fmt.Errorf("enum field %q must have a referenced type", c.Name)
}
ty, ok := schema.LookupType(c.ReferencedType)
ty, ok := typeSet.LookupType(c.ReferencedType)
if !ok {
return fmt.Errorf("enum field %q references unknown type %q", c.Name, c.ReferencedType)
}
@ -58,7 +58,7 @@ func (c Field) Validate(schema Schema) error {
// ValidateValue validates that the value conforms to the field's kind and nullability.
// Unlike Kind.ValidateValue, it also checks that the value conforms to the EnumType
// if the field is an EnumKind.
func (c Field) ValidateValue(value interface{}, schema Schema) error {
func (c Field) ValidateValue(value interface{}, typeSet TypeSet) error {
if value == nil {
if !c.Nullable {
return fmt.Errorf("field %q cannot be null", c.Name)
@ -72,7 +72,7 @@ func (c Field) ValidateValue(value interface{}, schema Schema) error {
switch c.Kind {
case EnumKind:
ty, ok := schema.LookupType(c.ReferencedType)
ty, ok := typeSet.LookupType(c.ReferencedType)
if !ok {
return fmt.Errorf("enum field %q references unknown type %q", c.Name, c.ReferencedType)
}

View File

@ -225,7 +225,7 @@ func TestFieldJSON(t *testing.T) {
}
}
var testEnumSchema = MustNewModuleSchema(EnumType{
var testEnumSchema = MustCompileModuleSchema(EnumType{
Name: "enum",
Values: []EnumValueDefinition{{Name: "a", Value: 1}, {Name: "b", Value: 2}},
})

View File

@ -4,16 +4,16 @@ import "fmt"
// ValidateObjectKey validates that the value conforms to the set of fields as a Key in an ObjectUpdate.
// See ObjectUpdate.Key for documentation on the requirements of such keys.
func ValidateObjectKey(keyFields []Field, value interface{}, schema Schema) error {
return validateFieldsValue(keyFields, value, schema)
func ValidateObjectKey(keyFields []Field, value interface{}, typeSet TypeSet) error {
return validateFieldsValue(keyFields, value, typeSet)
}
// ValidateObjectValue validates that the value conforms to the set of fields as a Value in an ObjectUpdate.
// See ObjectUpdate.Value for documentation on the requirements of such values.
func ValidateObjectValue(valueFields []Field, value interface{}, schema Schema) error {
func ValidateObjectValue(valueFields []Field, value interface{}, typeSet TypeSet) error {
valueUpdates, ok := value.(ValueUpdates)
if !ok {
return validateFieldsValue(valueFields, value, schema)
return validateFieldsValue(valueFields, value, typeSet)
}
values := map[string]interface{}{}
@ -31,7 +31,7 @@ func ValidateObjectValue(valueFields []Field, value interface{}, schema Schema)
continue
}
if err := field.ValidateValue(v, schema); err != nil {
if err := field.ValidateValue(v, typeSet); err != nil {
return err
}
@ -45,13 +45,13 @@ func ValidateObjectValue(valueFields []Field, value interface{}, schema Schema)
return nil
}
func validateFieldsValue(fields []Field, value interface{}, schema Schema) error {
func validateFieldsValue(fields []Field, value interface{}, typeSet TypeSet) error {
if len(fields) == 0 {
return nil
}
if len(fields) == 1 {
return fields[0].ValidateValue(value, schema)
return fields[0].ValidateValue(value, typeSet)
}
values, ok := value.([]interface{})
@ -63,7 +63,7 @@ func validateFieldsValue(fields []Field, value interface{}, schema Schema) error
return fmt.Errorf("expected %d key fields, got %d values", len(fields), len(value.([]interface{})))
}
for i, field := range fields {
if err := field.ValidateValue(values[i], schema); err != nil {
if err := field.ValidateValue(values[i], typeSet); err != nil {
return err
}
}

View File

@ -56,7 +56,7 @@ func TestValidateForKeyFields(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := ValidateObjectKey(tt.keyFields, tt.key, EmptySchema{})
err := ValidateObjectKey(tt.keyFields, tt.key, EmptyTypeSet())
if tt.errContains == "" {
if err != nil {
t.Fatalf("unexpected error: %v", err)
@ -128,7 +128,7 @@ func TestValidateForValueFields(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := ValidateObjectValue(tt.valueFields, tt.value, EmptySchema{})
err := ValidateObjectValue(tt.valueFields, tt.value, EmptyTypeSet())
if tt.errContains == "" {
if err != nil {
t.Fatalf("unexpected error: %v", err)

View File

@ -11,9 +11,9 @@ type ModuleSchema struct {
types map[string]Type
}
// NewModuleSchema constructs a new ModuleSchema and validates it. Any module schema returned without an error
// is guaranteed to be valid.
func NewModuleSchema(types ...Type) (ModuleSchema, error) {
// CompileModuleSchema compiles the types into a ModuleSchema and validates it.
// Any module schema returned without an error is guaranteed to be valid.
func CompileModuleSchema(types ...Type) (ModuleSchema, error) {
typeMap := map[string]Type{}
for _, typ := range types {
@ -34,10 +34,10 @@ func NewModuleSchema(types ...Type) (ModuleSchema, error) {
return res, nil
}
// MustNewModuleSchema constructs a new ModuleSchema and panics if it is invalid.
// MustCompileModuleSchema constructs a new ModuleSchema and panics if it is invalid.
// This should only be used in test code or static initialization where it is safe to panic!
func MustNewModuleSchema(types ...Type) ModuleSchema {
sch, err := NewModuleSchema(types...)
func MustCompileModuleSchema(types ...Type) ModuleSchema {
sch, err := CompileModuleSchema(types...)
if err != nil {
panic(err)
}
@ -79,7 +79,7 @@ func (s ModuleSchema) LookupType(name string) (Type, bool) {
// Types calls the provided function for each type in the module schema and stops if the function returns false.
// The types are iterated over in sorted order by name. This function is compatible with go 1.23 iterators.
func (s ModuleSchema) Types(f func(Type) bool) {
func (s ModuleSchema) AllTypes(f func(Type) bool) {
keys := make([]string, 0, len(s.types))
for k := range s.types {
keys = append(keys, k)
@ -94,7 +94,7 @@ func (s ModuleSchema) Types(f func(Type) bool) {
// ObjectTypes iterators over all the object types in the schema in alphabetical order.
func (s ModuleSchema) ObjectTypes(f func(ObjectType) bool) {
s.Types(func(t Type) bool {
s.AllTypes(func(t Type) bool {
objTyp, ok := t.(ObjectType)
if ok {
return f(objTyp)
@ -105,7 +105,7 @@ func (s ModuleSchema) ObjectTypes(f func(ObjectType) bool) {
// EnumTypes iterators over all the enum types in the schema in alphabetical order.
func (s ModuleSchema) EnumTypes(f func(EnumType) bool) {
s.Types(func(t Type) bool {
s.AllTypes(func(t Type) bool {
enumType, ok := t.(EnumType)
if ok {
return f(enumType)
@ -169,4 +169,6 @@ func (s *ModuleSchema) UnmarshalJSON(data []byte) error {
return nil
}
var _ Schema = ModuleSchema{}
func (ModuleSchema) isTypeSet() {}
var _ TypeSet = ModuleSchema{}

View File

@ -66,8 +66,8 @@ func TestModuleSchema_Validate(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// because validate is called when calling NewModuleSchema, we just call NewModuleSchema
_, err := NewModuleSchema(tt.types...)
// because validate is called when calling CompileModuleSchema, we just call CompileModuleSchema
_, err := CompileModuleSchema(tt.types...)
if tt.errContains == "" {
if err != nil {
t.Fatalf("unexpected error: %v", err)
@ -169,7 +169,7 @@ func TestModuleSchema_ValidateObjectUpdate(t *testing.T) {
func requireModuleSchema(t *testing.T, types ...Type) ModuleSchema {
t.Helper()
moduleSchema, err := NewModuleSchema(types...)
moduleSchema, err := CompileModuleSchema(types...)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
@ -240,7 +240,7 @@ func TestModuleSchema_Types(t *testing.T) {
moduleSchema := exampleSchema(t)
var typeNames []string
moduleSchema.Types(func(typ Type) bool {
moduleSchema.AllTypes(func(typ Type) bool {
typeNames = append(typeNames, typ.TypeName())
return true
})
@ -252,7 +252,7 @@ func TestModuleSchema_Types(t *testing.T) {
typeNames = nil
// scan just the first type and return false
moduleSchema.Types(func(typ Type) bool {
moduleSchema.AllTypes(func(typ Type) bool {
typeNames = append(typeNames, typ.TypeName())
return false
})

View File

@ -37,7 +37,7 @@ func (o ObjectType) TypeName() string {
func (ObjectType) isType() {}
// Validate validates the object type.
func (o ObjectType) Validate(schema Schema) error {
func (o ObjectType) Validate(typeSet TypeSet) error {
if !ValidateName(o.Name) {
return fmt.Errorf("invalid object type name %q", o.Name)
}
@ -45,7 +45,7 @@ func (o ObjectType) Validate(schema Schema) error {
fieldNames := map[string]bool{}
for _, field := range o.KeyFields {
if err := field.Validate(schema); err != nil {
if err := field.Validate(typeSet); err != nil {
return fmt.Errorf("invalid key field %q: %v", field.Name, err) //nolint:errorlint // false positive due to using go1.12
}
@ -64,7 +64,7 @@ func (o ObjectType) Validate(schema Schema) error {
}
for _, field := range o.ValueFields {
if err := field.Validate(schema); err != nil {
if err := field.Validate(typeSet); err != nil {
return fmt.Errorf("invalid value field %q: %v", field.Name, err) //nolint:errorlint // false positive due to using go1.12
}
@ -82,12 +82,12 @@ func (o ObjectType) Validate(schema Schema) error {
}
// ValidateObjectUpdate validates that the update conforms to the object type.
func (o ObjectType) ValidateObjectUpdate(update ObjectUpdate, schema Schema) error {
func (o ObjectType) ValidateObjectUpdate(update ObjectUpdate, typeSet TypeSet) error {
if o.Name != update.TypeName {
return fmt.Errorf("object type name %q does not match update type name %q", o.Name, update.TypeName)
}
if err := ValidateObjectKey(o.KeyFields, update.Key, schema); err != nil {
if err := ValidateObjectKey(o.KeyFields, update.Key, typeSet); err != nil {
return fmt.Errorf("invalid key for object type %q: %v", update.TypeName, err) //nolint:errorlint // false positive due to using go1.12
}
@ -95,5 +95,5 @@ func (o ObjectType) ValidateObjectUpdate(update ObjectUpdate, schema Schema) err
return nil
}
return ValidateObjectValue(o.ValueFields, update.Value, schema)
return ValidateObjectValue(o.ValueFields, update.Value, typeSet)
}

View File

@ -205,7 +205,7 @@ func TestObjectType_Validate(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := tt.objectType.Validate(EmptySchema{})
err := tt.objectType.Validate(EmptyTypeSet())
if tt.errContains == "" {
if err != nil {
t.Fatalf("unexpected error: %v", err)
@ -267,7 +267,7 @@ func TestObjectType_ValidateObjectUpdate(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := tt.objectType.ValidateObjectUpdate(tt.object, EmptySchema{})
err := tt.objectType.ValidateObjectUpdate(tt.object, EmptyTypeSet())
if tt.errContains == "" {
if err != nil {
t.Fatalf("unexpected error: %v", err)

View File

@ -12,6 +12,6 @@ import (
func TestEnumType(t *testing.T) {
rapid.Check(t, func(t *rapid.T) {
enumType := EnumType().Draw(t, "enum")
require.NoError(t, enumType.Validate(schema.EmptySchema{}))
require.NoError(t, enumType.Validate(schema.EmptyTypeSet()))
})
}

View File

@ -10,7 +10,7 @@ import (
// that can be used in reproducible unit testing and property based testing.
var ExampleAppSchema = map[string]schema.ModuleSchema{
"all_kinds": mkAllKindsModule(),
"test_cases": schema.MustNewModuleSchema(
"test_cases": schema.MustCompileModuleSchema(
schema.ObjectType{
Name: "Singleton",
KeyFields: []schema.Field{},
@ -138,7 +138,7 @@ func mkAllKindsModule() schema.ModuleSchema {
types = append(types, typ)
}
return schema.MustNewModuleSchema(types...)
return schema.MustCompileModuleSchema(types...)
}
func mkTestObjectType(kind schema.Kind) schema.ObjectType {

View File

@ -19,8 +19,8 @@ var (
)
// FieldGen generates random Field's based on the validity criteria of fields.
func FieldGen(sch schema.Schema) *rapid.Generator[schema.Field] {
enumTypes := slices.DeleteFunc(slices.Collect(sch.Types), func(t schema.Type) bool {
func FieldGen(typeSet schema.TypeSet) *rapid.Generator[schema.Field] {
enumTypes := slices.DeleteFunc(slices.Collect(typeSet.AllTypes), func(t schema.Type) bool {
_, ok := t.(schema.EnumType)
return !ok
})
@ -50,16 +50,16 @@ func FieldGen(sch schema.Schema) *rapid.Generator[schema.Field] {
}
// KeyFieldGen generates random key fields based on the validity criteria of key fields.
func KeyFieldGen(sch schema.Schema) *rapid.Generator[schema.Field] {
return FieldGen(sch).Filter(func(f schema.Field) bool {
func KeyFieldGen(typeSet schema.TypeSet) *rapid.Generator[schema.Field] {
return FieldGen(typeSet).Filter(func(f schema.Field) bool {
return !f.Nullable && f.Kind.ValidKeyKind()
})
}
// FieldValueGen generates random valid values for the field, aiming to exercise the full range of possible
// values for the field.
func FieldValueGen(field schema.Field, sch schema.Schema) *rapid.Generator[any] {
gen := baseFieldValue(field, sch)
func FieldValueGen(field schema.Field, typeSet schema.TypeSet) *rapid.Generator[any] {
gen := baseFieldValue(field, typeSet)
if field.Nullable {
return rapid.OneOf(gen, rapid.Just[any](nil)).AsAny()
@ -68,7 +68,7 @@ func FieldValueGen(field schema.Field, sch schema.Schema) *rapid.Generator[any]
return gen
}
func baseFieldValue(field schema.Field, sch schema.Schema) *rapid.Generator[any] {
func baseFieldValue(field schema.Field, typeSet schema.TypeSet) *rapid.Generator[any] {
switch field.Kind {
case schema.StringKind:
return rapid.StringOf(rapid.Rune().Filter(func(r rune) bool {
@ -113,7 +113,7 @@ func baseFieldValue(field schema.Field, sch schema.Schema) *rapid.Generator[any]
case schema.AddressKind:
return rapid.SliceOfN(rapid.Byte(), 20, 64).AsAny()
case schema.EnumKind:
typ, found := sch.LookupType(field.ReferencedType)
typ, found := typeSet.LookupType(field.ReferencedType)
enumTyp, ok := typ.(schema.EnumType)
if !found || !ok {
panic(fmt.Errorf("enum type %q not found", field.ReferencedType))
@ -128,18 +128,18 @@ func baseFieldValue(field schema.Field, sch schema.Schema) *rapid.Generator[any]
}
// ObjectKeyGen generates a value that is valid for the provided object key fields.
func ObjectKeyGen(keyFields []schema.Field, sch schema.Schema) *rapid.Generator[any] {
func ObjectKeyGen(keyFields []schema.Field, typeSet schema.TypeSet) *rapid.Generator[any] {
if len(keyFields) == 0 {
return rapid.Just[any](nil)
}
if len(keyFields) == 1 {
return FieldValueGen(keyFields[0], sch)
return FieldValueGen(keyFields[0], typeSet)
}
gens := make([]*rapid.Generator[any], len(keyFields))
for i, field := range keyFields {
gens[i] = FieldValueGen(field, sch)
gens[i] = FieldValueGen(field, typeSet)
}
return rapid.Custom(func(t *rapid.T) any {
@ -156,7 +156,7 @@ func ObjectKeyGen(keyFields []schema.Field, sch schema.Schema) *rapid.Generator[
// are valid for insertion (in the case forUpdate is false) or for update (in the case forUpdate is true).
// Values that are for update may skip some fields in a ValueUpdates instance whereas values for insertion
// will always contain all values.
func ObjectValueGen(valueFields []schema.Field, forUpdate bool, sch schema.Schema) *rapid.Generator[any] {
func ObjectValueGen(valueFields []schema.Field, forUpdate bool, typeSet schema.TypeSet) *rapid.Generator[any] {
if len(valueFields) == 0 {
// if we have no value fields, always return nil
return rapid.Just[any](nil)
@ -164,7 +164,7 @@ func ObjectValueGen(valueFields []schema.Field, forUpdate bool, sch schema.Schem
gens := make([]*rapid.Generator[any], len(valueFields))
for i, field := range valueFields {
gens[i] = FieldValueGen(field, sch)
gens[i] = FieldValueGen(field, typeSet)
}
return rapid.Custom(func(t *rapid.T) any {
// return ValueUpdates 50% of the time

View File

@ -27,7 +27,7 @@ var checkFieldValue = func(t *rapid.T) {
require.NoError(t, field.ValidateValue(fieldValue, testEnumSchema))
}
var testEnumSchema = schema.MustNewModuleSchema(schema.EnumType{
var testEnumSchema = schema.MustCompileModuleSchema(schema.EnumType{
Name: "test_enum",
Values: []schema.EnumValueDefinition{{Name: "a", Value: 1}, {Name: "b", Value: 2}},
})

View File

@ -11,7 +11,7 @@ func ModuleSchemaGen() *rapid.Generator[schema.ModuleSchema] {
enumTypesGen := distinctTypes(EnumType())
return rapid.Custom(func(t *rapid.T) schema.ModuleSchema {
enumTypes := enumTypesGen.Draw(t, "enumTypes")
tempSchema, err := schema.NewModuleSchema(enumTypes...)
tempSchema, err := schema.CompileModuleSchema(enumTypes...)
if err != nil {
t.Fatal(err)
}
@ -19,7 +19,7 @@ func ModuleSchemaGen() *rapid.Generator[schema.ModuleSchema] {
objectTypes := distinctTypes(ObjectTypeGen(tempSchema)).Draw(t, "objectTypes")
allTypes := append(enumTypes, objectTypes...)
modSchema, err := schema.NewModuleSchema(allTypes...)
modSchema, err := schema.CompileModuleSchema(allTypes...)
if err != nil {
t.Fatal(err)
}

View File

@ -8,12 +8,12 @@ import (
)
// ObjectTypeGen generates random ObjectType's based on the validity criteria of object types.
func ObjectTypeGen(sch schema.Schema) *rapid.Generator[schema.ObjectType] {
keyFieldsGen := rapid.SliceOfNDistinct(KeyFieldGen(sch), 1, 6, func(f schema.Field) string {
func ObjectTypeGen(typeSet schema.TypeSet) *rapid.Generator[schema.ObjectType] {
keyFieldsGen := rapid.SliceOfNDistinct(KeyFieldGen(typeSet), 1, 6, func(f schema.Field) string {
return f.Name
})
valueFieldsGen := rapid.SliceOfNDistinct(FieldGen(sch), 1, 12, func(f schema.Field) string {
valueFieldsGen := rapid.SliceOfNDistinct(FieldGen(typeSet), 1, 12, func(f schema.Field) string {
return f.Name
})
@ -21,7 +21,7 @@ func ObjectTypeGen(sch schema.Schema) *rapid.Generator[schema.ObjectType] {
typ := schema.ObjectType{
Name: NameGen.Filter(func(s string) bool {
// filter out names that already exist in the schema
_, found := sch.LookupType(s)
_, found := typeSet.LookupType(s)
return !found
}).Draw(t, "name"),
}
@ -56,13 +56,13 @@ func hasDuplicateFieldNames(typeNames map[string]bool, fields []schema.Field) bo
}
// ObjectInsertGen generates object updates that are valid for insertion.
func ObjectInsertGen(objectType schema.ObjectType, sch schema.Schema) *rapid.Generator[schema.ObjectUpdate] {
return ObjectUpdateGen(objectType, nil, sch)
func ObjectInsertGen(objectType schema.ObjectType, typeSet schema.TypeSet) *rapid.Generator[schema.ObjectUpdate] {
return ObjectUpdateGen(objectType, nil, typeSet)
}
// ObjectUpdateGen generates object updates that are valid for updates using the provided state map as a source
// of valid existing keys.
func ObjectUpdateGen(objectType schema.ObjectType, state *btree.Map[string, schema.ObjectUpdate], sch schema.Schema) *rapid.Generator[schema.ObjectUpdate] {
func ObjectUpdateGen(objectType schema.ObjectType, state *btree.Map[string, schema.ObjectUpdate], sch schema.TypeSet) *rapid.Generator[schema.ObjectUpdate] {
keyGen := ObjectKeyGen(objectType.KeyFields, sch).Filter(func(key interface{}) bool {
// filter out keys that exist in the state
if state != nil {

View File

@ -14,16 +14,16 @@ import (
type ObjectCollection struct {
options Options
objectType schema.ObjectType
sch schema.Schema
typeSet schema.TypeSet
objects *btree.Map[string, schema.ObjectUpdate]
updateGen *rapid.Generator[schema.ObjectUpdate]
valueFieldIndices map[string]int
}
// NewObjectCollection creates a new ObjectCollection for the given object type.
func NewObjectCollection(objectType schema.ObjectType, options Options, sch schema.Schema) *ObjectCollection {
func NewObjectCollection(objectType schema.ObjectType, options Options, typeSet schema.TypeSet) *ObjectCollection {
objects := &btree.Map[string, schema.ObjectUpdate]{}
updateGen := schematesting.ObjectUpdateGen(objectType, objects, sch)
updateGen := schematesting.ObjectUpdateGen(objectType, objects, typeSet)
valueFieldIndices := make(map[string]int, len(objectType.ValueFields))
for i, field := range objectType.ValueFields {
valueFieldIndices[field.Name] = i
@ -32,7 +32,7 @@ func NewObjectCollection(objectType schema.ObjectType, options Options, sch sche
return &ObjectCollection{
options: options,
objectType: objectType,
sch: sch,
typeSet: typeSet,
objects: objects,
updateGen: updateGen,
valueFieldIndices: valueFieldIndices,
@ -45,7 +45,7 @@ func (o *ObjectCollection) ApplyUpdate(update schema.ObjectUpdate) error {
return fmt.Errorf("update type name %q does not match object type name %q", update.TypeName, o.objectType.Name)
}
err := o.objectType.ValidateObjectUpdate(update, o.sch)
err := o.objectType.ValidateObjectUpdate(update, o.typeSet)
if err != nil {
return err
}

View File

@ -7,30 +7,45 @@ type Type interface {
TypeName() string
// Validate validates the type.
Validate(Schema) error
Validate(TypeSet) error
// isType is a private method that ensures that only types in this package can be marked as types.
isType()
}
// Schema represents something that has types and allows them to be looked up by name.
// TypeSet represents something that has types and allows them to be looked up by name.
// Currently, the only implementation is ModuleSchema.
type Schema interface {
type TypeSet interface {
// LookupType looks up a type by name.
LookupType(name string) (Type, bool)
// Types calls the given function for each type in the schema.
Types(f func(Type) bool)
// AllTypes calls the given function for each type in the type set.
// This function is compatible with go 1.23 iterators and can be used like this:
// for t := range types.AllTypes {
// // do something with t
// }
AllTypes(f func(Type) bool)
// isTypeSet is a private method that ensures that only types in this package can be marked as type sets.
isTypeSet()
}
// EmptySchema is a schema that contains no types.
// EmptyTypeSet is a schema that contains no types.
// It can be used in Validate methods when there is no schema needed or available.
type EmptySchema struct{}
func EmptyTypeSet() TypeSet {
return emptyTypeSetInst
}
// LookupType always returns false because there are no types in an EmptySchema.
func (EmptySchema) LookupType(name string) (Type, bool) {
var emptyTypeSetInst = emptyTypeSet{}
type emptyTypeSet struct{}
// LookupType always returns false because there are no types in an EmptyTypeSet.
func (emptyTypeSet) LookupType(string) (Type, bool) {
return nil, false
}
// Types does nothing because there are no types in an EmptySchema.
func (EmptySchema) Types(f func(Type) bool) {}
// Types does nothing because there are no types in an EmptyTypeSet.
func (emptyTypeSet) AllTypes(func(Type) bool) {}
func (emptyTypeSet) isTypeSet() {}