cosmos-sdk/schema/module_schema.go

144 lines
3.4 KiB
Go

package schema
import (
"fmt"
"sort"
)
// ModuleSchema represents the logical schema of a module for purposes of indexing and querying.
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(objectTypes []ObjectType) (ModuleSchema, error) {
types := map[string]Type{}
for _, objectType := range objectTypes {
types[objectType.Name] = objectType
}
res := ModuleSchema{types: types}
// validate adds all enum types to the type map
err := res.Validate()
if err != nil {
return ModuleSchema{}, err
}
return res, nil
}
func addEnumType(types map[string]Type, field Field) error {
enumDef := field.EnumType
if enumDef.Name == "" {
return nil
}
existing, ok := types[enumDef.Name]
if !ok {
types[enumDef.Name] = enumDef
return nil
}
existingEnum, ok := existing.(EnumType)
if !ok {
return fmt.Errorf("enum %q already exists as a different non-enum type", enumDef.Name)
}
if len(existingEnum.Values) != len(enumDef.Values) {
return fmt.Errorf("enum %q has different number of values in different fields", enumDef.Name)
}
existingValues := map[string]bool{}
for _, value := range existingEnum.Values {
existingValues[value] = true
}
for _, value := range enumDef.Values {
_, ok := existingValues[value]
if !ok {
return fmt.Errorf("enum %q has different values in different fields", enumDef.Name)
}
}
return nil
}
// Validate validates the module schema.
func (s ModuleSchema) Validate() error {
for _, typ := range s.types {
objTyp, ok := typ.(ObjectType)
if !ok {
continue
}
// all enum types get added to the type map when we call ObjectType.validate
err := objTyp.validate(s.types)
if err != nil {
return err
}
}
return nil
}
// ValidateObjectUpdate validates that the update conforms to the module schema.
func (s ModuleSchema) ValidateObjectUpdate(update ObjectUpdate) error {
typ, ok := s.types[update.TypeName]
if !ok {
return fmt.Errorf("object type %q not found in module schema", update.TypeName)
}
objTyp, ok := typ.(ObjectType)
if !ok {
return fmt.Errorf("type %q is not an object type", update.TypeName)
}
return objTyp.ValidateObjectUpdate(update)
}
// LookupType looks up a type by name in the module schema.
func (s ModuleSchema) LookupType(name string) (Type, bool) {
typ, ok := s.types[name]
return typ, ok
}
// 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) {
keys := make([]string, 0, len(s.types))
for k := range s.types {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
if !f(s.types[k]) {
break
}
}
}
// 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 {
objTyp, ok := t.(ObjectType)
if ok {
return f(objTyp)
}
return true
})
}
// 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 {
enumType, ok := t.(EnumType)
if ok {
return f(enumType)
}
return true
})
}