1 import Base 2 import ./compose.bend as Q 3 import ./ordinary_query_declaration.bend as N 4 import ./internal/compact_operational_frame.bend as F 5 import ./ordinary_component_binding.bend as B 6 import ./column.bend as Col 7 import ./component.bend as C 8 import ./capabilities.bend as Cap 9 import ./ordinary_schema.bend as Schema 10 import ./ordinary_owned_event_family_resource.bend as Resource 11 import ./owner_product.bend as Product 12 13 # The owner functor is retained before ordinary grant erasure. Raw declarations 14 # continue through the existing registration path. 15 # A closed query declaration for the recognized App entry, tied to schema S and 16 # its component/resource owners. Ops gives the same declared capabilities for 17 # both ordinary and compact execution; callbacks must return their opaque owner. 18 # Use write, resource_write and pair below. This additive surface does not supply 19 # all ordinary query combinators or an adapter for arbitrary custom selectors. 20 # Complete setup: the Sparse consumer's motion.bend:recognized and 21 # motion-driver.bend:define under test-fixtures/connected-performance/ 22 # sparse-motion64/consumer/s-perf/canonical-api-v1/sparse-runtime-v1/. 23 type Declaration<-S:Data,-Store:Type,-R:Type,-E:Data,-Ops:Type -> Type> is Type: 24 Declaration{legacy:Unit -> N.Declaration,Ops(Q.Frame)>,caps:Unit -> Ops(F.Frame),select:F.Frame -> F.Frame & Bool} 25 # Convert the recognized declaration into its ordinary operational declaration. 26 # Consumes the carrier; call a closed declaration template again when both forms 27 # are needed. Selection, access clauses and grants come from this same carrier. 28 def ordinary(~S:Data,~Store:Type,~R:Type,~E:Data,~Ops:Type -> Type,declaration:Declaration) -> N.Declaration,Ops(Q.Frame)>: 29 match declaration: 30 case Declaration{legacy,_,_}:legacy(Unit{}) 31 # Advanced runner projection: consume the declaration and obtain operations for 32 # the compact opaque frame. Application callbacks receive these through their 33 # Ops parameter; they should not construct or unwrap a compact frame themselves. 34 def caps(~S:Data,~Store:Type,~R:Type,~E:Data,~Ops:Type -> Type,declaration:Declaration) -> Ops(F.Frame): 35 match declaration: 36 case Declaration{_,caps,_}:caps(Unit{}) 37 # Advanced runner projection: consume the declaration and obtain its row filter. 38 # The filter returns the updated frame even when the row does not match. This 39 # operation does not enumerate entities or grant access beyond the declaration. 40 def selector(~S:Data,~Store:Type,~R:Type,~E:Data,~Ops:Type -> Type,declaration:Declaration) -> F.Frame -> F.Frame & Bool: 41 match declaration: 42 case Declaration{_,_,select}:select 43 44 # Internal capability assembly for write; the binding fixes the component path. 45 # The getter threads its payload back with a Data view; the setter uses the 46 # ordinary transactional write path. Prefer write in setup. 47 def write_caps(~S:Data,~Store:Type,~R:Type,~E:Data,~Rest:Type,~P:Type,~V:Data,~Token:Data,~take:Store -> Rest & Col.Column,~put:Rest -> Col.Column -> Store,~view:P -> P & V,~binding:B.Binding) -> Cap.Write,P,V>: 48 Cap.Write{F.read(~S,~Store,~R,~E,~Rest,~P,~V,~take,~put,~view),F.bridge_set(~S,~Store,~R,~E,~P,~Q.set(~S,~Store,~R,~E,~Rest,~P,~V,~Token,~take,~put,~view,~B.family(~S,~Store,~Rest,~P,~V,~Token,~take,~put,~view,binding)))} 49 # Declare required read/write access to one schema-bound component family. 50 # Only matching rows invoke the body. P may be an affine Type; view threads P 51 # back together with a Data observation V. take/put describe the same store 52 # path as binding. The returned declaration supplies Cap.Write; 53 # access failures still flow through the query's normal error/rollback result. 54 def write(~S:Data,~Store:Type,~R:Type,~E:Data,~Rest:Type,~P:Type,~V:Data,~Token:Data,~take:Store -> Rest & Col.Column,~put:Rest -> Col.Column -> Store,~view:P -> P & V,~binding:B.Binding) -> Declaration Cap.Write>: 55 Declaration{_=>N.write(~S,~P,~Store,~R,~E,~Rest,~V,~Token,~B.identity(~S,~Store,~Rest,~P,~V,~Token,~take,~put,~view,binding),~view,~take,~put),_=>write_caps(~S,~Store,~R,~E,~Rest,~P,~V,~Token,~take,~put,~view,~binding),F.family_match(~S,~Store,~R,~E,~Rest,~P,~V,~take,~put,~view,~Q.Required{})} 56 # Internal capability assembly for resource_write. Keeps the resource and Logs 57 # owners together and uses the ordinary resource transaction bridge; this is not 58 # a direct application resource handle or permission to bypass rollback. 59 def resource_caps(~S:Data,~Store:Type,~R:Type,~Logs:Type,~E:Data,~V:Data,~view:R -> R & V) -> Cap.ValueWrite,E>,R,V>: 60 Cap.ValueWrite{F.bridge_get(~S,~Store,~Product.Owner,~E,~V,~Resource.read(~S,~Store,~R,~Logs,~E,~V,~view)),F.bridge_set(~S,~Store,~Product.Owner,~E,~R,~Resource.set(~S,~Store,~R,~Logs,~E))} 61 # Declare read/write access to a schema resource whose owner is paired with Logs. 62 # The owner-preserving view returns a Data value; resource selection alone does 63 # not exclude an entity row. The supplied identity determines declared access. 64 # Writes retain the ordinary resource undo/rollback behavior. Pair this with a 65 # component declaration when the body also needs a current entity component. 66 def resource_write(~S:Data,~Store:Type,~R:Type,~Logs:Type,~E:Data,~V:Data,~identity:Schema.Resource,~view:R -> R & V) -> Declaration,E,H => Cap.ValueWrite>: 67 Declaration{_=>Resource.write(~S,~Store,~R,~Logs,~E,~V,~identity,~view),_=>resource_caps(~S,~Store,~R,~Logs,~E,~V,~view),F.all(~S,~Store,~Product.Owner,~E)} 68 # Internal grant assembly for pair: produce left and right operation bundles 69 # for the same compact owner. Prefer pair rather than assembling these manually. 70 def pair_caps(~S:Data,~Store:Type,~R:Type,~E:Data,~L:Type -> Type,~Right:Type -> Type,~left:Declaration,~right:Declaration) -> L(F.Frame) & Right(F.Frame): 71 (caps(~S,~Store,~R,~E,~L,left),caps(~S,~Store,~R,~E,~Right,right)) 72 # Combine two declarations for the same schema/store/resource owners. 73 # The body receives (leftCaps, rightCaps) in that order. Selection runs left first; 74 # if it returns False, right is not called, and the returned owner is preserved. 75 # The ordinary form keeps the same clause order, including duplicate clauses; 76 # this does not promise that two grants refer to disjoint component columns. 77 def pair(~S:Data,~Store:Type,~R:Type,~E:Data,~L:Type -> Type,~Right:Type -> Type,~left:Declaration,~right:Declaration) -> Declaration L(H) & Right(H)>: 78 Declaration{_=>N.pair(~S,~Q.Frame,~L(Q.Frame),~Right(Q.Frame),~ordinary(~S,~Store,~R,~E,~L,left),~ordinary(~S,~Store,~R,~E,~Right,right)),_=>pair_caps(~S,~Store,~R,~E,~L,~Right,~left,~right),F.both(~S,~Store,~R,~E,~selector(~S,~Store,~R,~E,~L,left),~selector(~S,~Store,~R,~E,~Right,right))}