ordinary_query_observable.bend
bendvy-ecs-core@0.1.0.0 · 107 lines · 0 definitions
1import Base
2import bendvy-ecs-core@0.1.0.0/ordinary_query_declaration.bend as N
3import bendvy-ecs-core@0.1.0.0/ordinary_component_binding.bend as B
4import bendvy-ecs-core@0.1.0.0/ordinary_declaration.bend as Identity
5import bendvy-ecs-core@0.1.0.0/ordinary_query_selections.bend as F
6import bendvy-ecs-core@0.1.0.0/inspector_query_projection.bend as P
7import bendvy-ecs-core@0.1.0.0/inspector_query_families.bend as Families
8import bendvy-ecs-core@0.1.0.0/inspector_query_world.bend as IW
9import bendvy-ecs-core@0.1.0.0/inspector_query.bend as IQ
10import bendvy-ecs-core@0.1.0.0/inspector.bend as I
11import bendvy-ecs-core@0.1.0.0/compose.bend as Q
12import bendvy-ecs-core@0.1.0.0/column.bend as Col
13import bendvy-ecs-core@0.1.0.0/component.bend as C
14import bendvy-ecs-core@0.1.0.0/capabilities.bend as Cap
15
16# One ordinary declaration delays both lowerings from the same component binding.
17# Operational transaction authority never enters the detached read-only query.
18# One query declaration supplies operational grants and detached inspection
19# from the same bindings. Declaration uses the ordinary evaluator; the
20# PreparedDeclaration variant also supplies an enumeration callback. Raw
21# constructors are trusted adapters. Payload owners never enter detached V.
22type Declaration<-S:Data,-H:Type,-G:Type,-IH:Type,-V:Data> is Type:
23 Declaration{operational:Unit -> N.Declaration<S,H,G>,inspection:Unit -> P.DeclaredSelection<IH,S,V>}
24 PreparedDeclaration{operational:Unit -> N.Declaration<S,H,G>,inspection:Unit -> P.DeclaredSelection<IH,S,V>,enumerate:IH -> IH & List<&2,IQ.ProjectedRow<S,V>>}
25# Consume the observable declaration and obtain its typed operational query.
26# Does not enumerate rows or run a body; H remains the operational owner type.
27def operational(~S:Data,~H:Type,~G:Type,~IH:Type,~V:Data,declaration:Declaration<S,H,G,IH,V>) -> N.Declaration<S,H,G>:
28 match declaration:
29 case Declaration{operational,_}:operational(Unit{})
30 case PreparedDeclaration{operational,_,_}:operational(Unit{})
31# Consume the declaration and obtain its detached read-only selection recipe.
32# IH is separate from operational H; no write grant is transferred to inspection.
33def inspection(~S:Data,~H:Type,~G:Type,~IH:Type,~V:Data,declaration:Declaration<S,H,G,IH,V>) -> P.DeclaredSelection<IH,S,V>:
34 match declaration:
35 case Declaration{_,inspection}:inspection(Unit{})
36 case PreparedDeclaration{_,inspection,_}:inspection(Unit{})
37# Return declaration-derived query clauses for access/debug descriptions.
38# Consumes this declaration value, without inspecting or modifying a world.
39def clauses(~S:Data,~H:Type,~G:Type,~IH:Type,~V:Data,declaration:Declaration<S,H,G,IH,V>) -> List<&2,N.Clause<S>>:
40 N.clauses(~S,~H,~G,operational(~S,~H,~G,~IH,~V,declaration))
41
42# Declare required component read access and the matching detached inspection.
43# The trusted binding fixes schema and storage lenses. view consumes/returns
44# Payload and exposes Data V; operational results are Found/ComponentAbsent/
45# MissingEntity, including stale/foreign rejection. No row is read at setup.
46def read(~S:Data,~Store:Type,~Rest:Type,~Payload:Type,~V:Data,~Token:Data,~take:Store -> Rest & Col.Column<S,Payload>,~put:Rest -> Col.Column<S,Payload> -> Store,~view:Payload -> Payload & V,~R:Type,~E:Data,~binding:B.Binding<S,Store,Rest,Payload,V,Token,take,put,view>) -> Declaration<S,Q.Frame<S,Store,R,E>,Cap.Read<Q.Frame<S,Store,R,E>,V>,I.Frame<S,Store,R,E>,C.Access<V>>:
47 Declaration{_=>(N.read(~S,~Payload,~Store,~R,~E,~Rest,~V,~Token,~B.identity(~S,~Store,~Rest,~Payload,~V,~Token,~take,~put,~view,binding),~view,~take,~put)),_=>(F.inspect_slot(~S,~Store,~R,~E,~Rest,~Payload,~V,~Token,~take,~put,~view,~binding,~Families.Required{}))}
48
49# Declare required component read/write access with read-only inspection.
50# Writes consume replacement Payload; failed sets record an error for enclosing
51# Compose execution/rollback and do not return rejected input through the grant.
52# Detached inspection exposes only V and never authorizes a write.
53def write(~S:Data,~Store:Type,~Rest:Type,~Payload:Type,~V:Data,~Token:Data,~take:Store -> Rest & Col.Column<S,Payload>,~put:Rest -> Col.Column<S,Payload> -> Store,~view:Payload -> Payload & V,~R:Type,~E:Data,~binding:B.Binding<S,Store,Rest,Payload,V,Token,take,put,view>) -> Declaration<S,Q.Frame<S,Store,R,E>,Cap.Write<Q.Frame<S,Store,R,E>,Payload,V>,I.Frame<S,Store,R,E>,C.Access<V>>:
54 Declaration{_=>(N.write(~S,~Payload,~Store,~R,~E,~Rest,~V,~Token,~B.identity(~S,~Store,~Rest,~Payload,~V,~Token,~take,~put,~view,binding),~view,~take,~put)),_=>(F.inspect_slot(~S,~Store,~R,~E,~Rest,~Payload,~V,~Token,~take,~put,~view,~binding,~Families.Required{}))}
55
56# Declare read access without requiring component presence on a live row.
57# Operational and detached selections preserve absence explicitly; stale/foreign
58# handles remain MissingEntity rather than matching as optional live rows.
59def optional(~S:Data,~Store:Type,~Rest:Type,~Payload:Type,~V:Data,~Token:Data,~take:Store -> Rest & Col.Column<S,Payload>,~put:Rest -> Col.Column<S,Payload> -> Store,~view:Payload -> Payload & V,~R:Type,~E:Data,~binding:B.Binding<S,Store,Rest,Payload,V,Token,take,put,view>) -> Declaration<S,Q.Frame<S,Store,R,E>,Cap.Read<Q.Frame<S,Store,R,E>,V>,I.Frame<S,Store,R,E>,C.Access<V>>:
60 Declaration{_=>(N.optional(~S,~Payload,~Store,~R,~E,~Rest,~V,~Token,~B.identity(~S,~Store,~Rest,~Payload,~V,~Token,~take,~put,~view,binding),~view,~take,~put)),_=>(F.inspect_slot(~S,~Store,~R,~E,~Rest,~Payload,~V,~Token,~take,~put,~view,~binding,~Families.Optional{}))}
61
62# Require presence without granting payload operations; detached projection
63# contributes Unit. Combine with pair for additional independently granted data.
64def with_component(~S:Data,~Store:Type,~Rest:Type,~Payload:Type,~V:Data,~Token:Data,~take:Store -> Rest & Col.Column<S,Payload>,~put:Rest -> Col.Column<S,Payload> -> Store,~view:Payload -> Payload & V,~R:Type,~E:Data,~binding:B.Binding<S,Store,Rest,Payload,V,Token,take,put,view>) -> Declaration<S,Q.Frame<S,Store,R,E>,Unit,I.Frame<S,Store,R,E>,Unit>:
65 Declaration{_=>(N.with_component(~S,~Payload,~Store,~R,~E,~Rest,~V,~Token,~B.identity(~S,~Store,~Rest,~Payload,~V,~Token,~take,~put,~view,binding),~view,~take,~put)),_=>(P.constrain(~I.Frame<S,Store,R,E>,~S,~Unit,~P.empty(~I.Frame<S,Store,R,E>,~S),~F.inspect_with(~S,~Store,~R,~E,~Rest,~Payload,~V,~Token,~take,~put,~view,~binding)))}
66
67# Require absence without granting payload operations; detached projection
68# contributes Unit. Structural membership changes at explicit barriers.
69def without_component(~S:Data,~Store:Type,~Rest:Type,~Payload:Type,~V:Data,~Token:Data,~take:Store -> Rest & Col.Column<S,Payload>,~put:Rest -> Col.Column<S,Payload> -> Store,~view:Payload -> Payload & V,~R:Type,~E:Data,~binding:B.Binding<S,Store,Rest,Payload,V,Token,take,put,view>) -> Declaration<S,Q.Frame<S,Store,R,E>,Unit,I.Frame<S,Store,R,E>,Unit>:
70 Declaration{_=>(N.without_component(~S,~Payload,~Store,~R,~E,~Rest,~V,~Token,~B.identity(~S,~Store,~Rest,~Payload,~V,~Token,~take,~put,~view,binding),~view,~take,~put)),_=>(P.constrain(~I.Frame<S,Store,R,E>,~S,~Unit,~P.empty(~I.Frame<S,Store,R,E>,~S),~F.inspect_without(~S,~Store,~R,~E,~Rest,~Payload,~V,~Token,~take,~put,~view,~binding)))}
71
72# Add a lifecycle filter without payload access; inspection uses its supplied
73# cursor and operational execution uses the registered system cursor. Merely
74# constructing or inspecting this declaration advances neither system cursor.
75def added(~S:Data,~Store:Type,~Rest:Type,~Payload:Type,~V:Data,~Token:Data,~take:Store -> Rest & Col.Column<S,Payload>,~put:Rest -> Col.Column<S,Payload> -> Store,~view:Payload -> Payload & V,~R:Type,~E:Data,~binding:B.Binding<S,Store,Rest,Payload,V,Token,take,put,view>) -> Declaration<S,Q.Frame<S,Store,R,E>,Unit,I.Frame<S,Store,R,E>,Unit>:
76 Declaration{_=>(N.added(~S,~Payload,~Store,~R,~E,~Rest,~V,~Token,~B.identity(~S,~Store,~Rest,~Payload,~V,~Token,~take,~put,~view,binding),~view,~take,~put)),_=>(P.constrain(~I.Frame<S,Store,R,E>,~S,~Unit,~P.empty(~I.Frame<S,Store,R,E>,~S),~F.inspect_filter(~S,~Store,~R,~E,~Rest,~Payload,~V,~Token,~take,~put,~view,~binding,~Q.Added{})))}
77
78# Add a changed-since-cursor filter without payload access. The operational
79# and Inspector owners retain separate cursor authority; declaration construction
80# and detached inspection do not consume registered system visibility.
81def changed(~S:Data,~Store:Type,~Rest:Type,~Payload:Type,~V:Data,~Token:Data,~take:Store -> Rest & Col.Column<S,Payload>,~put:Rest -> Col.Column<S,Payload> -> Store,~view:Payload -> Payload & V,~R:Type,~E:Data,~binding:B.Binding<S,Store,Rest,Payload,V,Token,take,put,view>) -> Declaration<S,Q.Frame<S,Store,R,E>,Unit,I.Frame<S,Store,R,E>,Unit>:
82 Declaration{_=>(N.changed(~S,~Payload,~Store,~R,~E,~Rest,~V,~Token,~B.identity(~S,~Store,~Rest,~Payload,~V,~Token,~take,~put,~view,binding),~view,~take,~put)),_=>(P.constrain(~I.Frame<S,Store,R,E>,~S,~Unit,~P.empty(~I.Frame<S,Store,R,E>,~S),~F.inspect_filter(~S,~Store,~R,~E,~Rest,~Payload,~V,~Token,~take,~put,~view,~binding,~Q.Changed{})))}
83
84# Compose conjunctive selections from the same schema and owner types.
85# Operational grants retain (L & R), detached values Product<LV,RV>, and clause
86# order is left then right. Nest pairs for arbitrary heterogeneous shapes.
87# Example: examples/scheduled-health/registration.bend, query().
88def pair(~S:Data,~H:Type,~L:Type,~R:Type,~IH:Type,~LV:Data,~RV:Data,~left:Declaration<S,H,L,IH,LV>,~right:Declaration<S,H,R,IH,RV>) -> Declaration<S,H,L & R,IH,P.Product<LV,RV>>:
89 Declaration{_=>(N.pair(~S,~H,~L,~R,~operational(~S,~H,~L,~IH,~LV,left),~operational(~S,~H,~R,~IH,~RV,right))),_=>(P.pair(~IH,~S,~LV,~RV,~inspection(~S,~H,~L,~IH,~LV,left),~inspection(~S,~H,~R,~IH,~RV,right)))}
90def prepared_query(~S:Data,~Store:Type,~R:Type,~E:Data,~V:Data,~selection:P.DeclaredSelection<I.Frame<S,Store,R,E>,S,V>,enumerate:I.Frame<S,Store,R,E> -> I.Frame<S,Store,R,E> & List<&2,IQ.ProjectedRow<S,V>>) -> IQ.ComposedReadQuery<I.Frame<S,Store,R,E>,S,V>:
91 IQ.ComposedReadQuery{enumerate,owner=>target=>IQ.get_composed(~I.Frame<S,Store,R,E>,~S,~V,~IQ.grant_composed(~I.Frame<S,Store,R,E>,~S,~V,~selection,~IW.inspect_world(~S,~Store,~R,~E)),owner,target)}
92def inspect_query_value(~S:Data,~Store:Type,~R:Type,~E:Data,~H:Type,~G:Type,~V:Data,~declaration:Declaration<S,H,G,I.Frame<S,Store,R,E>,V>,kind:Declaration<S,H,G,I.Frame<S,Store,R,E>,V>) -> IQ.ComposedReadQuery<I.Frame<S,Store,R,E>,S,V>:
93 match kind:
94 case Declaration{_,_}:IQ.grant_composed(~I.Frame<S,Store,R,E>,~S,~V,~inspection(~S,~H,~G,~I.Frame<S,Store,R,E>,~V,declaration),~IW.inspect_world(~S,~Store,~R,~E))
95 case PreparedDeclaration{_,_,enumerate}:prepared_query(~S,~Store,~R,~E,~V,~inspection(~S,~H,~G,~I.Frame<S,Store,R,E>,~V,declaration),enumerate)
96# Lower this observable declaration into an Inspector composed read query.
97# Preserves prepared enumeration when present; supplies no write operations.
98# Run it with the public Inspector owner, not a registered system owner, so
99# detached observations do not consume system cursors or event retention.
100def inspect_query(~S:Data,~Store:Type,~R:Type,~E:Data,~H:Type,~G:Type,~V:Data,~declaration:Declaration<S,H,G,I.Frame<S,Store,R,E>,V>) -> IQ.ComposedReadQuery<I.Frame<S,Store,R,E>,S,V>:
101 inspect_query_value(~S,~Store,~R,~E,~H,~G,~V,~declaration,declaration)
102
103# Declare write access plus a formatter for detached Data V in enabled debug.
104# Formatter receives no Payload owner; transaction/refusal semantics match write.
105# Inspection remains read-only even though the operational grant permits writes.
106def write_displayed(~S:Data,~Store:Type,~Rest:Type,~Payload:Type,~V:Data,~Token:Data,~take:Store -> Rest & Col.Column<S,Payload>,~put:Rest -> Col.Column<S,Payload> -> Store,~view:Payload -> Payload & V,~R:Type,~E:Data,~display:V -> String,~binding:B.Binding<S,Store,Rest,Payload,V,Token,take,put,view>) -> Declaration<S,Q.Frame<S,Store,R,E>,Cap.Write<Q.Frame<S,Store,R,E>,Payload,V>,I.Frame<S,Store,R,E>,C.Access<V>>:
107 Declaration{_=>(N.write_displayed(~S,~Payload,~Store,~R,~E,~Rest,~V,~Token,~B.identity(~S,~Store,~Rest,~Payload,~V,~Token,~take,~put,~view,binding),~view,~display,~take,~put)),_=>(F.inspect_slot(~S,~Store,~R,~E,~Rest,~Payload,~V,~Token,~take,~put,~view,~binding,~Families.Required{}))}