recognized_query_declaration.bend
bendvy-ecs-core@0.1.0.0 · 78 lines · 0 definitions
1import Base
2import bendvy-ecs-core@0.1.0.0/compose.bend as Q
3import bendvy-ecs-core@0.1.0.0/ordinary_query_declaration.bend as N
4import bendvy-ecs-core@0.1.0.0/internal/compact_operational_frame.bend as F
5import bendvy-ecs-core@0.1.0.0/ordinary_component_binding.bend as B
6import bendvy-ecs-core@0.1.0.0/column.bend as Col
7import bendvy-ecs-core@0.1.0.0/component.bend as C
8import bendvy-ecs-core@0.1.0.0/capabilities.bend as Cap
9import bendvy-ecs-core@0.1.0.0/ordinary_schema.bend as Schema
10import bendvy-ecs-core@0.1.0.0/ordinary_owned_event_family_resource.bend as Resource
11import bendvy-ecs-core@0.1.0.0/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/.
23type Declaration<-S:Data,-Store:Type,-R:Type,-E:Data,-Ops:Type -> Type> is Type:
24 Declaration{legacy:Unit -> N.Declaration<S,Q.Frame<S,Store,R,E>,Ops(Q.Frame<S,Store,R,E>)>,caps:Unit -> Ops(F.Frame<S,Store,R,E>),select:F.Frame<S,Store,R,E> -> F.Frame<S,Store,R,E> & 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.
28def ordinary(~S:Data,~Store:Type,~R:Type,~E:Data,~Ops:Type -> Type,declaration:Declaration<S,Store,R,E,Ops>) -> N.Declaration<S,Q.Frame<S,Store,R,E>,Ops(Q.Frame<S,Store,R,E>)>:
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.
34def caps(~S:Data,~Store:Type,~R:Type,~E:Data,~Ops:Type -> Type,declaration:Declaration<S,Store,R,E,Ops>) -> Ops(F.Frame<S,Store,R,E>):
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.
40def selector(~S:Data,~Store:Type,~R:Type,~E:Data,~Ops:Type -> Type,declaration:Declaration<S,Store,R,E,Ops>) -> F.Frame<S,Store,R,E> -> F.Frame<S,Store,R,E> & 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.
47def write_caps(~S:Data,~Store:Type,~R:Type,~E:Data,~Rest:Type,~P:Type,~V:Data,~Token:Data,~take:Store -> Rest & Col.Column<S,P>,~put:Rest -> Col.Column<S,P> -> Store,~view:P -> P & V,~binding:B.Binding<S,Store,Rest,P,V,Token,take,put,view>) -> Cap.Write<F.Frame<S,Store,R,E>,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.
54def write(~S:Data,~Store:Type,~R:Type,~E:Data,~Rest:Type,~P:Type,~V:Data,~Token:Data,~take:Store -> Rest & Col.Column<S,P>,~put:Rest -> Col.Column<S,P> -> Store,~view:P -> P & V,~binding:B.Binding<S,Store,Rest,P,V,Token,take,put,view>) -> Declaration<S,Store,R,E,H => Cap.Write<H,P,V>>:
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.
59def resource_caps(~S:Data,~Store:Type,~R:Type,~Logs:Type,~E:Data,~V:Data,~view:R -> R & V) -> Cap.ValueWrite<F.Frame<S,Store,Product.Owner<R,Logs>,E>,R,V>:
60 Cap.ValueWrite{F.bridge_get(~S,~Store,~Product.Owner<R,Logs>,~E,~V,~Resource.read(~S,~Store,~R,~Logs,~E,~V,~view)),F.bridge_set(~S,~Store,~Product.Owner<R,Logs>,~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.
66def resource_write(~S:Data,~Store:Type,~R:Type,~Logs:Type,~E:Data,~V:Data,~identity:Schema.Resource<S,R>,~view:R -> R & V) -> Declaration<S,Store,Product.Owner<R,Logs>,E,H => Cap.ValueWrite<H,R,V>>:
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<R,Logs>,~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.
70def pair_caps(~S:Data,~Store:Type,~R:Type,~E:Data,~L:Type -> Type,~Right:Type -> Type,~left:Declaration<S,Store,R,E,L>,~right:Declaration<S,Store,R,E,Right>) -> L(F.Frame<S,Store,R,E>) & Right(F.Frame<S,Store,R,E>):
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.
77def pair(~S:Data,~Store:Type,~R:Type,~E:Data,~L:Type -> Type,~Right:Type -> Type,~left:Declaration<S,Store,R,E,L>,~right:Declaration<S,Store,R,E,Right>) -> Declaration<S,Store,R,E,H => L(H) & Right(H)>:
78 Declaration{_=>N.pair(~S,~Q.Frame<S,Store,R,E>,~L(Q.Frame<S,Store,R,E>),~Right(Q.Frame<S,Store,R,E>),~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))}