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

feat(schema): expose useful functions for building schemas #569

Merged
merged 1 commit into from
Aug 5, 2024
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
53 changes: 24 additions & 29 deletions schema/dmt/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,37 +27,14 @@ import (
// It supports several validations for logical coherency of schemas,
// but may not yet successfully reject all invalid schemas.
func Compile(ts *schema.TypeSystem, node *Schema) error {
// Prelude; probably belongs elsewhere.
{
ts.Accumulate(schema.SpawnBool("Bool"))
ts.Accumulate(schema.SpawnInt("Int"))
ts.Accumulate(schema.SpawnFloat("Float"))
ts.Accumulate(schema.SpawnString("String"))
ts.Accumulate(schema.SpawnBytes("Bytes"))
// Add basic types
schema.SpawnDefaultBasicTypes(ts)

ts.Accumulate(schema.SpawnAny("Any"))

ts.Accumulate(schema.SpawnMap("Map", "String", "Any", false))
ts.Accumulate(schema.SpawnList("List", "Any", false))

// Should be &Any, really.
ts.Accumulate(schema.SpawnLink("Link"))

// TODO: schema package lacks support?
// ts.Accumulate(schema.SpawnUnit("Null", NullRepr))
// Add the schema types
err := SpawnSchemaTypes(ts, node)
if err != nil {
return err
}

for _, name := range node.Types.Keys {
defn := node.Types.Values[name]

// TODO: once ./schema supports anonymous/inline types, remove the ts argument.
typ, err := spawnType(ts, name, defn)
if err != nil {
return err
}
ts.Accumulate(typ)
}

// TODO: if this fails and the user forgot to check Compile's returned error,
// we can leave the TypeSystem in an unfortunate broken state:
// they can obtain types out of the TypeSystem and they are non-nil,
Expand All @@ -73,6 +50,24 @@ func Compile(ts *schema.TypeSystem, node *Schema) error {
return nil
}

// SpawnSchemaTypes is a lighter verion of compile that doesn't add basic types and doesn't validate the graph --
// for use when you want to build a type system from multiple sources and validate later
func SpawnSchemaTypes(ts *schema.TypeSystem, node *Schema) error {

for _, name := range node.Types.Keys {
defn := node.Types.Values[name]

// TODO: once ./schema supports anonymous/inline types, remove the ts argument.
typ, err := spawnType(ts, name, defn)
if err != nil {
return err
}
ts.Accumulate(typ)
}

return nil
}

// Note that the parser and compiler support defaults. We're lacking support in bindnode.
func todoFromImplicitlyFalseBool(b *bool) bool {
if b == nil {
Expand Down
87 changes: 87 additions & 0 deletions schema/tmpBuilders.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,93 @@
return &TypeEnum{typeBase{name, nil}, members, repr}
}

// Utility function adding default basic types to schema type system
func SpawnDefaultBasicTypes(ts *TypeSystem) {
ts.Accumulate(SpawnBool("Bool"))
ts.Accumulate(SpawnInt("Int"))
ts.Accumulate(SpawnFloat("Float"))
ts.Accumulate(SpawnString("String"))
ts.Accumulate(SpawnBytes("Bytes"))

ts.Accumulate(SpawnAny("Any"))

ts.Accumulate(SpawnMap("Map", "String", "Any", false))
ts.Accumulate(SpawnList("List", "Any", false))

// Should be &Any, really.
ts.Accumulate(SpawnLink("Link"))

// TODO: schema package lacks support?
// ts.Accumulate(schema.SpawnUnit("Null", NullRepr))
}

// Clone creates a copy of a type that is not in the original's universe (so it can be used elsewhere safely)
func Clone(typ Type) Type {
switch kindedType := typ.(type) {
case *TypeBool:
return SpawnBool(kindedType.Name())
case *TypeString:
return SpawnString(kindedType.Name())
case *TypeBytes:
return SpawnBytes(kindedType.Name())
case *TypeInt:
return SpawnInt(kindedType.Name())
case *TypeFloat:
return SpawnFloat(kindedType.Name())
case *TypeAny:
return SpawnAny(kindedType.Name())
case *TypeMap:
return SpawnMap(kindedType.Name(),
kindedType.KeyType().Name(),
kindedType.ValueType().Name(),
kindedType.ValueIsNullable())
case *TypeList:
return SpawnList(kindedType.Name(), kindedType.ValueType().Name(), kindedType.ValueIsNullable())
Comment on lines +191 to +193
Copy link
Member

Choose a reason for hiding this comment

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

hah, we don't store representation strategy for these even though we have space for it in the dmt, TODO at some point I guess

case *TypeLink:
if kindedType.HasReferencedType() {
return SpawnLinkReference(kindedType.Name(), kindedType.ReferencedType().Name())
} else {
return SpawnLink(kindedType.Name())
}
case *TypeUnion:
members := kindedType.Members()
memberNames := make([]TypeName, 0, len(members))
for _, member := range members {
memberNames = append(memberNames, member.Name())
}
return SpawnUnion(kindedType.Name(), memberNames, kindedType.RepresentationStrategy())
case *TypeStruct:
oldFields := kindedType.Fields()
newFields := make([]StructField, 0, len(oldFields))
for _, oldField := range oldFields {
newFields = append(newFields, SpawnStructField(oldField.Name(), oldField.Type().Name(), oldField.IsOptional(), oldField.IsNullable()))
}
return SpawnStruct(kindedType.Name(), newFields, kindedType.RepresentationStrategy())
case *TypeEnum:
return SpawnEnum(kindedType.Name(), kindedType.Members(), kindedType.RepresentationStrategy())
default:
panic("unexpected type, don't know how to clone")

Check warning on line 217 in schema/tmpBuilders.go

View check run for this annotation

Codecov / codecov/patch

schema/tmpBuilders.go#L173-L217

Added lines #L173 - L217 were not covered by tests
}
}

func MergeTypeSystem(target *TypeSystem, source *TypeSystem, ignoreDups bool) {
for _, name := range source.Names() {
typ := Clone(source.TypeByName(name))
if ignoreDups {
accumulateWithRecovery(target, typ)
} else {
target.Accumulate(typ)
}

Check warning on line 228 in schema/tmpBuilders.go

View check run for this annotation

Codecov / codecov/patch

schema/tmpBuilders.go#L221-L228

Added lines #L221 - L228 were not covered by tests
}
}

func accumulateWithRecovery(ts *TypeSystem, typ Type) {
defer func() {
_ = recover()
}()
ts.Accumulate(typ)

Check warning on line 236 in schema/tmpBuilders.go

View check run for this annotation

Codecov / codecov/patch

schema/tmpBuilders.go#L232-L236

Added lines #L232 - L236 were not covered by tests
}

// The methods relating to TypeSystem are also mutation-heavy and placeholdery.

func (ts *TypeSystem) Init() {
Expand Down
Loading