Files
CHORUS/vendor/github.com/ipld/go-ipld-prime/schema/dmt/compile.go
anthonyrawlins 9bdcbe0447 Integrate BACKBEAT SDK and resolve KACHING license validation
Major integrations and fixes:
- Added BACKBEAT SDK integration for P2P operation timing
- Implemented beat-aware status tracking for distributed operations
- Added Docker secrets support for secure license management
- Resolved KACHING license validation via HTTPS/TLS
- Updated docker-compose configuration for clean stack deployment
- Disabled rollback policies to prevent deployment failures
- Added license credential storage (CHORUS-DEV-MULTI-001)

Technical improvements:
- BACKBEAT P2P operation tracking with phase management
- Enhanced configuration system with file-based secrets
- Improved error handling for license validation
- Clean separation of KACHING and CHORUS deployment stacks

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-06 07:56:26 +10:00

428 lines
13 KiB
Go

package schemadmt
import (
"fmt"
"github.com/ipld/go-ipld-prime/datamodel"
"github.com/ipld/go-ipld-prime/schema"
)
// Compile transforms a description of a schema in raw data model ("dmt") form
// into a compiled schema.TypeSystem, which is the ready-to-use form.
//
// The first parameter is mutated by this process,
// and the second parameter is the data source.
//
// The compilation process includes first inserting the "prelude" types into the
// schema.TypeSystem -- that is, the "type Bool bool" and "type String string", etc,
// which are generally presumed to be present in any type system.
//
// The compilation process attempts to check the validity of the schema at a logical level as it goes.
// For example, references to type names not present elsewhere in the same schema are now an error
// (even though that has been easily representable in the dmt.Schema form up until this point).
//
// Note that this API is EXPERIMENTAL and will likely change.
// It supports many features of IPLD Schemas,
// but it may yet not support all of them.
// 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"))
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))
}
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,
// but trying to use them in any way may result in panics.
// Consider making that less prone to misuse, such as making it illegal to
// call TypeByName until ValidateGraph is happy.
if errs := ts.ValidateGraph(); errs != nil {
// Return the first error.
for _, err := range errs {
return err
}
}
return nil
}
// Note that the parser and compiler support defaults. We're lacking support in bindnode.
func todoFromImplicitlyFalseBool(b *bool) bool {
if b == nil {
return false
}
return *b
}
func anonTypeName(nameOrDefn TypeNameOrInlineDefn) string {
if nameOrDefn.TypeName != nil {
return *nameOrDefn.TypeName
}
defn := *nameOrDefn.InlineDefn
switch {
case defn.TypeDefnMap != nil:
defn := defn.TypeDefnMap
return fmt.Sprintf("Map__%s__%s", defn.KeyType, anonTypeName(defn.ValueType))
case defn.TypeDefnList != nil:
defn := defn.TypeDefnList
return fmt.Sprintf("List__%s", anonTypeName(defn.ValueType))
case defn.TypeDefnLink != nil:
return anonLinkName(*defn.TypeDefnLink)
default:
panic(fmt.Errorf("%#v", defn))
}
}
func anonLinkName(defn TypeDefnLink) string {
if defn.ExpectedType != nil {
return fmt.Sprintf("Link__%s", *defn.ExpectedType)
}
return "Link__Link"
}
func parseKind(s string) datamodel.Kind {
switch s {
case "map":
return datamodel.Kind_Map
case "list":
return datamodel.Kind_List
case "null":
return datamodel.Kind_Null
case "bool":
return datamodel.Kind_Bool
case "int":
return datamodel.Kind_Int
case "float":
return datamodel.Kind_Float
case "string":
return datamodel.Kind_String
case "bytes":
return datamodel.Kind_Bytes
case "link":
return datamodel.Kind_Link
default:
return datamodel.Kind_Invalid
}
}
func spawnType(ts *schema.TypeSystem, name schema.TypeName, defn TypeDefn) (schema.Type, error) {
switch {
// Scalar types without parameters.
case defn.TypeDefnBool != nil:
return schema.SpawnBool(name), nil
case defn.TypeDefnString != nil:
return schema.SpawnString(name), nil
case defn.TypeDefnBytes != nil:
return schema.SpawnBytes(name), nil
case defn.TypeDefnInt != nil:
return schema.SpawnInt(name), nil
case defn.TypeDefnFloat != nil:
return schema.SpawnFloat(name), nil
case defn.TypeDefnList != nil:
typ := defn.TypeDefnList
tname := ""
if typ.ValueType.TypeName != nil {
tname = *typ.ValueType.TypeName
} else if tname = anonTypeName(typ.ValueType); ts.TypeByName(tname) == nil {
anonDefn := TypeDefn{
TypeDefnMap: typ.ValueType.InlineDefn.TypeDefnMap,
TypeDefnList: typ.ValueType.InlineDefn.TypeDefnList,
TypeDefnLink: typ.ValueType.InlineDefn.TypeDefnLink,
}
anonType, err := spawnType(ts, tname, anonDefn)
if err != nil {
return nil, err
}
ts.Accumulate(anonType)
}
switch {
case typ.Representation == nil ||
typ.Representation.ListRepresentation_List != nil:
// default behavior
default:
return nil, fmt.Errorf("TODO: support other list repr in schema package")
}
return schema.SpawnList(name,
tname,
todoFromImplicitlyFalseBool(typ.ValueNullable),
), nil
case defn.TypeDefnMap != nil:
typ := defn.TypeDefnMap
tname := ""
if typ.ValueType.TypeName != nil {
tname = *typ.ValueType.TypeName
} else if tname = anonTypeName(typ.ValueType); ts.TypeByName(tname) == nil {
anonDefn := TypeDefn{
TypeDefnMap: typ.ValueType.InlineDefn.TypeDefnMap,
TypeDefnList: typ.ValueType.InlineDefn.TypeDefnList,
TypeDefnLink: typ.ValueType.InlineDefn.TypeDefnLink,
}
anonType, err := spawnType(ts, tname, anonDefn)
if err != nil {
return nil, err
}
ts.Accumulate(anonType)
}
switch {
case typ.Representation == nil ||
typ.Representation.MapRepresentation_Map != nil:
// default behavior
case typ.Representation.MapRepresentation_Stringpairs != nil:
return nil, fmt.Errorf("TODO: support stringpairs map repr in schema package")
default:
return nil, fmt.Errorf("TODO: support other map repr in schema package")
}
return schema.SpawnMap(name,
typ.KeyType,
tname,
todoFromImplicitlyFalseBool(typ.ValueNullable),
), nil
case defn.TypeDefnStruct != nil:
typ := defn.TypeDefnStruct
var fields []schema.StructField
for _, fname := range typ.Fields.Keys {
field := typ.Fields.Values[fname]
tname := ""
if field.Type.TypeName != nil {
tname = *field.Type.TypeName
} else if tname = anonTypeName(field.Type); ts.TypeByName(tname) == nil {
// Note that TypeDefn and InlineDefn aren't the same enum.
anonDefn := TypeDefn{
TypeDefnMap: field.Type.InlineDefn.TypeDefnMap,
TypeDefnList: field.Type.InlineDefn.TypeDefnList,
TypeDefnLink: field.Type.InlineDefn.TypeDefnLink,
}
anonType, err := spawnType(ts, tname, anonDefn)
if err != nil {
return nil, err
}
ts.Accumulate(anonType)
}
fields = append(fields, schema.SpawnStructField(fname,
tname,
todoFromImplicitlyFalseBool(field.Optional),
todoFromImplicitlyFalseBool(field.Nullable),
))
}
var repr schema.StructRepresentation
switch {
case typ.Representation.StructRepresentation_Map != nil:
rp := typ.Representation.StructRepresentation_Map
if rp.Fields == nil {
repr = schema.SpawnStructRepresentationMap2(nil, nil)
break
}
renames := make(map[string]string, len(rp.Fields.Keys))
implicits := make(map[string]schema.ImplicitValue, len(rp.Fields.Keys))
for _, name := range rp.Fields.Keys {
details := rp.Fields.Values[name]
if details.Rename != nil {
renames[name] = *details.Rename
}
if imp := details.Implicit; imp != nil {
var sumVal schema.ImplicitValue
switch {
case imp.Bool != nil:
sumVal = schema.ImplicitValue_Bool(*imp.Bool)
case imp.String != nil:
sumVal = schema.ImplicitValue_String(*imp.String)
case imp.Int != nil:
sumVal = schema.ImplicitValue_Int(*imp.Int)
default:
panic("TODO: implicit value kind")
}
implicits[name] = sumVal
}
}
repr = schema.SpawnStructRepresentationMap2(renames, implicits)
case typ.Representation.StructRepresentation_Tuple != nil:
rp := typ.Representation.StructRepresentation_Tuple
if rp.FieldOrder == nil {
repr = schema.SpawnStructRepresentationTuple()
break
}
return nil, fmt.Errorf("TODO: support for tuples with field orders in the schema package")
case typ.Representation.StructRepresentation_Stringjoin != nil:
join := typ.Representation.StructRepresentation_Stringjoin.Join
if join == "" {
return nil, fmt.Errorf("stringjoin has empty join value")
}
repr = schema.SpawnStructRepresentationStringjoin(join)
default:
return nil, fmt.Errorf("TODO: support other struct repr in schema package")
}
return schema.SpawnStruct(name,
fields,
repr,
), nil
case defn.TypeDefnUnion != nil:
typ := defn.TypeDefnUnion
var members []schema.TypeName
for _, member := range typ.Members {
if member.TypeName != nil {
members = append(members, *member.TypeName)
} else {
tname := anonLinkName(*member.UnionMemberInlineDefn.TypeDefnLink)
members = append(members, tname)
if ts.TypeByName(tname) == nil {
anonDefn := TypeDefn{
TypeDefnLink: member.UnionMemberInlineDefn.TypeDefnLink,
}
anonType, err := spawnType(ts, tname, anonDefn)
if err != nil {
return nil, err
}
ts.Accumulate(anonType)
}
}
}
remainingMembers := make(map[string]bool)
for _, memberName := range members {
remainingMembers[memberName] = true
}
validMember := func(memberName string) error {
switch remaining, known := remainingMembers[memberName]; {
case remaining:
remainingMembers[memberName] = false
return nil
case !known:
return fmt.Errorf("%q is not a valid member of union %q", memberName, name)
default:
return fmt.Errorf("%q is duplicate in the union repr of %q", memberName, name)
}
}
var repr schema.UnionRepresentation
switch {
case typ.Representation.UnionRepresentation_Kinded != nil:
rp := typ.Representation.UnionRepresentation_Kinded
table := make(map[datamodel.Kind]schema.TypeName, len(rp.Keys))
for _, kindStr := range rp.Keys {
kind := parseKind(kindStr)
member := rp.Values[kindStr]
switch {
case member.TypeName != nil:
memberName := *member.TypeName
validMember(memberName)
table[kind] = memberName
case member.UnionMemberInlineDefn != nil:
tname := anonLinkName(*member.UnionMemberInlineDefn.TypeDefnLink)
validMember(tname)
table[kind] = tname
}
}
repr = schema.SpawnUnionRepresentationKinded(table)
case typ.Representation.UnionRepresentation_Keyed != nil:
rp := typ.Representation.UnionRepresentation_Keyed
table := make(map[string]schema.TypeName, len(rp.Keys))
for _, key := range rp.Keys {
member := rp.Values[key]
switch {
case member.TypeName != nil:
memberName := *member.TypeName
validMember(memberName)
table[key] = memberName
case member.UnionMemberInlineDefn != nil:
tname := anonLinkName(*member.UnionMemberInlineDefn.TypeDefnLink)
validMember(tname)
table[key] = tname
}
}
repr = schema.SpawnUnionRepresentationKeyed(table)
case typ.Representation.UnionRepresentation_StringPrefix != nil:
prefixes := typ.Representation.UnionRepresentation_StringPrefix.Prefixes
for _, key := range prefixes.Keys {
validMember(prefixes.Values[key])
}
repr = schema.SpawnUnionRepresentationStringprefix("", prefixes.Values)
default:
return nil, fmt.Errorf("TODO: support other union repr in schema package")
}
for memberName, remaining := range remainingMembers {
if remaining {
return nil, fmt.Errorf("%q is not present in the union repr of %q", memberName, name)
}
}
return schema.SpawnUnion(name,
members,
repr,
), nil
case defn.TypeDefnEnum != nil:
typ := defn.TypeDefnEnum
var repr schema.EnumRepresentation
// TODO: we should probably also reject duplicates.
validMember := func(name string) bool {
for _, memberName := range typ.Members {
if memberName == name {
return true
}
}
return false
}
switch {
case typ.Representation.EnumRepresentation_String != nil:
rp := typ.Representation.EnumRepresentation_String
for memberName := range rp.Values {
if !validMember(memberName) {
return nil, fmt.Errorf("%q is not a valid member of enum %q", memberName, name)
}
}
repr = schema.EnumRepresentation_String(rp.Values)
case typ.Representation.EnumRepresentation_Int != nil:
rp := typ.Representation.EnumRepresentation_Int
for memberName := range rp.Values {
if !validMember(memberName) {
return nil, fmt.Errorf("%q is not a valid member of enum %q", memberName, name)
}
}
repr = schema.EnumRepresentation_Int(rp.Values)
default:
return nil, fmt.Errorf("TODO: support other enum repr in schema package")
}
return schema.SpawnEnum(name,
typ.Members,
repr,
), nil
case defn.TypeDefnLink != nil:
typ := defn.TypeDefnLink
if typ.ExpectedType == nil {
return schema.SpawnLink(name), nil
}
return schema.SpawnLinkReference(name, *typ.ExpectedType), nil
case defn.TypeDefnAny != nil:
return schema.SpawnAny(name), nil
default:
panic(fmt.Errorf("%#v", defn))
}
}