cosmos-sdk/schema/module_schema.go

175 lines
4.2 KiB
Go

package schema
import (
"encoding/json"
"fmt"
"sort"
)
// ModuleSchema represents the logical schema of a module for purposes of indexing and querying.
type ModuleSchema struct {
types map[string]Type
}
// 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 {
if _, ok := typeMap[typ.TypeName()]; ok {
return ModuleSchema{}, fmt.Errorf("duplicate type %q", typ.TypeName())
}
typeMap[typ.TypeName()] = typ
}
res := ModuleSchema{types: typeMap}
err := res.Validate()
if err != nil {
return ModuleSchema{}, err
}
return res, nil
}
// 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 MustCompileModuleSchema(types ...Type) ModuleSchema {
sch, err := CompileModuleSchema(types...)
if err != nil {
panic(err)
}
return sch
}
// Validate validates the module schema.
func (s ModuleSchema) Validate() error {
for _, typ := range s.types {
err := typ.Validate(s)
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, s)
}
// 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) AllTypes(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.AllTypes(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.AllTypes(func(t Type) bool {
enumType, ok := t.(EnumType)
if ok {
return f(enumType)
}
return true
})
}
type moduleSchemaJson struct {
ObjectTypes []ObjectType `json:"object_types"`
EnumTypes []EnumType `json:"enum_types"`
}
// MarshalJSON implements the json.Marshaler interface for ModuleSchema.
// It marshals the module schema into a JSON object with the object types and enum types
// under the keys "object_types" and "enum_types" respectively.
func (s ModuleSchema) MarshalJSON() ([]byte, error) {
asJson := moduleSchemaJson{}
s.ObjectTypes(func(objType ObjectType) bool {
asJson.ObjectTypes = append(asJson.ObjectTypes, objType)
return true
})
s.EnumTypes(func(enumType EnumType) bool {
asJson.EnumTypes = append(asJson.EnumTypes, enumType)
return true
})
return json.Marshal(asJson)
}
// UnmarshalJSON implements the json.Unmarshaler interface for ModuleSchema.
// See MarshalJSON for the JSON format.
func (s *ModuleSchema) UnmarshalJSON(data []byte) error {
asJson := moduleSchemaJson{}
err := json.Unmarshal(data, &asJson)
if err != nil {
return err
}
types := map[string]Type{}
for _, objType := range asJson.ObjectTypes {
types[objType.Name] = objType
}
for _, enumType := range asJson.EnumTypes {
types[enumType.Name] = enumType
}
s.types = types
// validate adds all enum types to the type map
err = s.Validate()
if err != nil {
return err
}
return nil
}
func (ModuleSchema) isTypeSet() {}
var _ TypeSet = ModuleSchema{}