1 import Base 2 import ./decode_data.bend as D 3 import ./persistence_declaration.bend as Persist 4 import ./owner_product.bend as Product 5 import ./ordinary_declaration.bend as Component 6 import ./column.bend as Col 7 import ./schema_fragments.bend as Fragment 8 # One normal declaration drives schema entries and physical Store/Resources types. 9 # Names default to the one ordinary key. No user metadata or lens input. 10 # Detached schema description indexed by the component and resource owner 11 # types. It contains no world or payloads; product derives matching owner 12 # products. Raw Schema construction is trusted metadata setup. 13 type Schema<-S:Data,-Store:Type,-Resources:Type> is Data: 14 Schema{entries:List<&2,Fragment.Entry>} 15 # Schema-scoped resource key and payload type, without a resource instance. 16 # Convert with resource_schema before composition and collision validation. 17 type Resource<-S:Data,-P:Type> is Data: 18 Resource{key:String} 19 # Declare a resource key for schema S and payload P. No payload is allocated 20 # or provisioned and duplicate keys are not checked until schema validation. 21 def resource(~S:Data,~P:Type,key:String) -> Resource: 22 Resource{key} 23 # Return the authored resource key; does not read a runtime resource. 24 def resource_key(~S:Data,~P:Type,value:Resource) -> String: 25 match value: 26 case Resource{key}:key 27 # Describe a component declaration and derive its column owner type. 28 # Does not allocate storage or validate collisions. Compose with product and 29 # validate before App attachment; examples/scheduled-health/registration.bend. 30 def component(~S:Data,~P:Type,declaration:Component.Declaration) -> Schema,Unit>: 31 +key=Component.key(~S,~P,declaration) 32 Schema{[Fragment.Entry{Fragment.Component{},key,key}]} 33 # Describe a resource and derive its resource owner type without constructing 34 # its payload. This declaration supplies metadata, not a live resource value. 35 def resource_schema(~S:Data,~P:Type,declaration:Resource) -> Schema: 36 +key=resource_key(~S,~P,declaration) 37 Schema{[Fragment.Entry{Fragment.Resource{},key,key}]} 38 # Return schema entries in composition order, detached from all world owners. 39 def entries(~S:Data,~C:Type,~R:Type,value:Schema) -> List<&2,Fragment.Entry>: 40 match value: 41 case Schema{entries}:entries 42 # Compose two same-schema declarations, appending entries left then right 43 # and deriving matching component/resource Product.Owner types. Supports 44 # arbitrary affine payload types; does not copy payloads or reject collisions. 45 def product(~S:Data,~LC:Type,~LR:Type,~RC:Type,~RR:Type,left:Schema,right:Schema) -> Schema,Product.Owner>: 46 Schema{List.append(&2,Fragment.Entry,entries(~S,~LC,~LR,left),entries(~S,~RC,~RR,right))} 47 # Check composed declaration entries for schema conflicts, returning the 48 # structured Fragment.Validation result. No World exists in this operation; 49 # validation neither constructs payloads nor proves trusted storage lens laws. 50 def validate(~S:Data,~C:Type,~R:Type,value:Schema) -> Fragment.Validation: 51 Fragment.validate_loop(~S,entries(~S,~C,~R,value),[]) 52 53 # Declare a component with plain persistence classification from its bound 54 # extension. Records the classification and derives the owner type; does not 55 # execute codecs, validate input, allocate payloads or export a snapshot. 56 # Use the matching persistence declaration and identity when composing a schema. 57 def component_plain(~S:Data,~P:Type,~identity:Component.Declaration,extension:Persist.Plain) -> Schema,Unit>: 58 +key=Component.key(~S,~P,identity) 59 Schema{[Fragment.Classified{Fragment.Component{},key,key,Fragment.Plain{}}]} 60 61 # Declare a component with transient persistence classification from its bound 62 # extension. Records the classification and derives the owner type; does not 63 # execute codecs, validate input, allocate payloads or export a snapshot. 64 # Use the matching persistence declaration and identity when composing a schema. 65 def component_transient(~S:Data,~P:Type,~identity:Component.Declaration,extension:Persist.Transient) -> Schema,Unit>: 66 +key=Component.key(~S,~P,identity) 67 Schema{[Fragment.Classified{Fragment.Component{},key,key,Fragment.Transient{}}]} 68 69 # Declare a component with constructed persistence classification from its bound 70 # extension. Records the classification and derives the owner type; does not 71 # execute codecs, validate input, allocate payloads or export a snapshot. 72 # Use the matching persistence declaration and identity when composing a schema. 73 def component_constructed(~S:Data,~P:Type,~identity:Component.Declaration,~project:P -> P & D.Raw,extension:Persist.Constructed) -> Schema,Unit>: 74 +key=Component.key(~S,~P,identity) 75 Schema{[Fragment.Classified{Fragment.Component{},key,key,Fragment.Constructed{}}]} 76 77 # Declare a resource with plain persistence classification from its bound 78 # extension. Records the classification and derives the owner type; does not 79 # execute codecs, validate input, allocate payloads or export a snapshot. 80 # Use the matching persistence declaration and identity when composing a schema. 81 def resource_plain(~S:Data,~P:Type,~identity:Component.Declaration,extension:Persist.Plain) -> Schema: 82 +key=Component.key(~S,~P,identity) 83 Schema{[Fragment.Classified{Fragment.Resource{},key,key,Fragment.Plain{}}]} 84 85 # Declare a resource with transient persistence classification from its bound 86 # extension. Records the classification and derives the owner type; does not 87 # execute codecs, validate input, allocate payloads or export a snapshot. 88 # Use the matching persistence declaration and identity when composing a schema. 89 def resource_transient(~S:Data,~P:Type,~identity:Component.Declaration,extension:Persist.Transient) -> Schema: 90 +key=Component.key(~S,~P,identity) 91 Schema{[Fragment.Classified{Fragment.Resource{},key,key,Fragment.Transient{}}]} 92 93 # Declare a resource with constructed persistence classification from its bound 94 # extension. Records the classification and derives the owner type; does not 95 # execute codecs, validate input, allocate payloads or export a snapshot. 96 # Use the matching persistence declaration and identity when composing a schema. 97 def resource_constructed(~S:Data,~P:Type,~identity:Component.Declaration,~project:P -> P & D.Raw,extension:Persist.Constructed) -> Schema: 98 +key=Component.key(~S,~P,identity) 99 Schema{[Fragment.Classified{Fragment.Resource{},key,key,Fragment.Constructed{}}]}