relation_query.bend
bendvy-ecs-core@0.1.0.0 · 121 lines · 0 definitions
1import Base
2import bendvy-ecs-core@0.1.0.0/deferred_command.bend as Deferred
3import bendvy-ecs-core@0.1.0.0/trace_facts.bend as TraceFacts
4import entity_key.bend as Key
5import relation_types.bend as G
6import relation_graph.bend as Graph
7import relation_commands.bend as A
8import world.bend as W
9import transaction.bend as X
10import query.bend as Q
11import component.bend as Cmp
12import capabilities.bend as Cap
13
14# Relation requirements have arbitrary declaration length. The application C
15# remains Type; only immutable relation handles/snapshots are Data.
16type End is Data:
17 Outgoing{}
18 Incoming{}
19type Requirement<S:Data> is Data:
20 Requirement{key:String,descriptor:G.Descriptor<S>,end:End,mode:Q.Selection,project:Bool}
21type Spec<S:Data> is Data:
22 Spec{requirements:List<&2,Requirement<S>>}
23type Value<S:Data> is Data:
24 Missing{}
25 Target{handle:W.Handle<S>}
26 Sources{handles:List<&2,W.Handle<S>>}
27type Cell<S:Data> is Data:
28 Cell{key:String,end:End,value:Value<S>}
29type Row<S:Data,V:Data> is Data:
30 Row{entity:W.Handle<S>,cells:List<&2,Cell<S>>,component:V}
31def read_relation(~S:Data,key:String,descriptor:G.Descriptor<S>) -> Requirement<S>:
32 Requirement{key,descriptor,Outgoing{},Q.Required{},True{}}
33def optional_relation(~S:Data,key:String,descriptor:G.Descriptor<S>) -> Requirement<S>:
34 Requirement{key,descriptor,Outgoing{},Q.Optional{},True{}}
35def read_related(~S:Data,key:String,descriptor:G.Descriptor<S>) -> Requirement<S>:
36 Requirement{key,descriptor,Incoming{},Q.Required{},True{}}
37def optional_related(~S:Data,key:String,descriptor:G.Descriptor<S>) -> Requirement<S>:
38 Requirement{key,descriptor,Incoming{},Q.Optional{},True{}}
39def with_relation(~S:Data,descriptor:G.Descriptor<S>) -> Requirement<S>:
40 Requirement{"",descriptor,Outgoing{},Q.Present{},False{}}
41def without_relation(~S:Data,descriptor:G.Descriptor<S>) -> Requirement<S>:
42 Requirement{"",descriptor,Outgoing{},Q.Absent{},False{}}
43def with_related(~S:Data,descriptor:G.Descriptor<S>) -> Requirement<S>:
44 Requirement{"",descriptor,Incoming{},Q.Present{},False{}}
45def without_related(~S:Data,descriptor:G.Descriptor<S>) -> Requirement<S>:
46 Requirement{"",descriptor,Incoming{},Q.Absent{},False{}}
47def handles_acc(~S:Data,ids:List<&2,Key.Key>,+namespace:U32,acc:List<&2,W.Handle<S>>) -> List<&2,W.Handle<S>>:
48 match ids:
49 case []: List.reverse(&2,W.Handle<S>,acc)
50 case id <> rest: handles_acc(~S,rest,namespace,W.Handle{namespace,id} <> acc)
51def outgoing_value(~S:Data,value:Maybe<&2,Key.Key>,namespace:U32) -> Value<S>:
52 match value:
53 case None{}: Missing{}
54 case Some{id}: Target{W.Handle{namespace,id}}
55def incoming_value(~S:Data,ids:List<&2,Key.Key>,namespace:U32) -> Value<S>:
56 match ids:
57 case []: Missing{}
58 case first <> rest: Sources{handles_acc(~S,first <> rest,namespace,[])}
59def value(~S:Data,graph:G.Graph<S>,descriptor:G.Descriptor<S>,end:End,+namespace:U32,id:Key.Key) -> Value<S>:
60 match end:
61 case Outgoing{}: outgoing_value(~S,Graph.target(~S,graph,descriptor,id),namespace)
62 case Incoming{}: incoming_value(~S,Graph.inverse(~S,graph,descriptor,id),namespace)
63def presence(~S:Data,value:Value<S>) -> Cmp.Access<Bool>:
64 match value:
65 case Missing{}: Cmp.ComponentAbsent{}
66 case _: Cmp.Found{True{}}
67def add_cell(~S:Data,project:Bool,key:String,end:End,value:Value<S>,cells:List<&2,Cell<S>>) -> List<&2,Cell<S>>:
68 match project:
69 case False{}: cells
70 case True{}: Cell{key,end,value} <> cells
71def requirements(~S:Data,remaining:List<&2,Requirement<S>>,+graph:G.Graph<S>,+namespace:U32,+id:Key.Key,selected:Bool,acc:List<&2,Cell<S>>) -> Bool & List<&2,Cell<S>>:
72 match remaining:
73 case []: (selected,List.reverse(&2,Cell<S>,acc))
74 case Requirement{key,descriptor,+end,mode,project} <> rest:
75 +observed = value(~S,graph,descriptor,end,namespace,id)
76 requirements(~S,rest,graph,namespace,id,selected && Q.selection_aux(~Bool,mode,presence(~S,observed)),add_cell(~S,project,key,end,observed,acc))
77def spec_rows_result(~S:Data,~V:Data,observed:Bool & List<&2,Cell<S>>,handle:W.Handle<S>,component:V) -> Bool & Row<S,V>:
78 (selected,cells) = observed
79 (selected,Row{handle,cells,component})
80def spec_rows(~S:Data,~V:Data,spec:Spec<S>,graph:G.Graph<S>,handle:W.Handle<S>,component:V) -> Bool & Row<S,V>:
81 match spec handle:
82 case Spec{items} W.Handle{+namespace,+id}: spec_rows_result(~S,~V,requirements(~S,items,graph,namespace,id,True{},[]),W.Handle{namespace,id},component)
83def graph_read(~S:Data,~C:Type,store:A.Store<S,C>) -> A.Store<S,C> & G.Graph<S>:
84 match store:
85 case A.Store{components,+graph}: (A.Store{components,graph},graph)
86def inspect_done(~S:Data,~V:Data,~C:Type,~R:Type,~E:Data,~spec:Spec<S>,observed:W.World<S,A.Store<S,C>,R,A.Notice<S,E>> & G.Graph<S>,handle:W.Handle<S>,component:V,undo:List<(W.World<S,A.Store<S,C>,R,A.Notice<S,E>> -> W.World<S,A.Store<S,C>,R,A.Notice<S,E>>)>,commands:List<Deferred.Command<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>>>,events:List<&2,A.Notice<S,E>>,trace:TraceFacts.State) -> X.Tx<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>,A.Notice<S,E>> & (Bool & Row<S,V>):
87 (world,graph) = observed
88 (X.Tx{world,undo,commands,events,trace},spec_rows(~S,~V,spec,graph,handle,component))
89def inspect(~S:Data,~V:Data,~C:Type,~R:Type,~E:Data,~spec:Spec<S>,tx:X.Tx<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>,A.Notice<S,E>>,handle:W.Handle<S>,component:V) -> X.Tx<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>,A.Notice<S,E>> & (Bool & Row<S,V>):
90 match tx:
91 case X.Tx{world,undo,commands,events,trace}: inspect_done(~S,~V,~C,~R,~E,~spec,W.with_store(~S,~A.Store<S,C>,~R,~A.Notice<S,E>,~G.Graph<S>,graph_read(~S,~C),world),handle,component,undo,commands,events,trace)
92def row_get(~S:Data,~V:Data,~H:Type,+row:Row<S,V>,owner:H) -> H & Row<S,V>:
93 (owner,row)
94def invoke(~S:Data,~V:Data,~C:Type,~R:Type,~E:Data,~Out:Data,~body:@-H:Type -> Cap.ValueRead<H,Row<S,V>> -> H -> H & Out,row:Row<S,V>,tx:X.Tx<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>,A.Notice<S,E>>) -> X.Tx<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>,A.Notice<S,E>> & Out:
95 body(X.Tx<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>,A.Notice<S,E>>,Cap.ValueRead{row_get(~S,~V,~X.Tx<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>,A.Notice<S,E>>,row)},tx)
96def output_prepend(~S:Data,~C:Type,~R:Type,~E:Data,~Out:Data,value:Out,observed:X.Tx<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>,A.Notice<S,E>> & List<&2,Out>) -> X.Tx<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>,A.Notice<S,E>> & List<&2,Out>:
97 (tx,rest) = observed
98 (tx,value <> rest)
99def output_join(~S:Data,~V:Data,~C:Type,~R:Type,~E:Data,~Out:Data,observed:X.Tx<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>,A.Notice<S,E>> & Out,next:X.Tx<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>,A.Notice<S,E>> -> X.Tx<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>,A.Notice<S,E>> & List<&2,Out>) -> X.Tx<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>,A.Notice<S,E>> & List<&2,Out>:
100 (tx,value) = observed
101 output_prepend(~S,~C,~R,~E,~Out,value,next(tx))
102def selected_row(~S:Data,~V:Data,~C:Type,~R:Type,~E:Data,~Out:Data,~body:@-H:Type -> Cap.ValueRead<H,Row<S,V>> -> H -> H & Out,observed:X.Tx<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>,A.Notice<S,E>> & (Bool & Row<S,V>),next:X.Tx<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>,A.Notice<S,E>> -> X.Tx<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>,A.Notice<S,E>> & List<&2,Out>) -> X.Tx<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>,A.Notice<S,E>> & List<&2,Out>:
103 match observed:
104 case (tx,(False{},_)): next(tx)
105 case (tx,(True{},row)): output_join(~S,~V,~C,~R,~E,~Out,invoke(~S,~V,~C,~R,~E,~Out,~body,row,tx),next)
106def component_join(~S:Data,~V:Data,~C:Type,~R:Type,~E:Data,~Out:Data,~spec:Spec<S>,~body:@-H:Type -> Cap.ValueRead<H,Row<S,V>> -> H -> H & Out,handle:W.Handle<S>,observed:X.Tx<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>,A.Notice<S,E>> & (Bool & V),next:X.Tx<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>,A.Notice<S,E>> -> X.Tx<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>,A.Notice<S,E>> & List<&2,Out>) -> X.Tx<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>,A.Notice<S,E>> & List<&2,Out>:
107 match observed:
108 case (tx,(False{},_)): next(tx)
109 case (tx,(True{},component)): selected_row(~S,~V,~C,~R,~E,~Out,~body,inspect(~S,~V,~C,~R,~E,~spec,tx,handle,component),next)
110def scan(~S:Data,~V:Data,~C:Type,~R:Type,~E:Data,~Out:Data,~spec:Spec<S>,~component_selected:X.Tx<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>,A.Notice<S,E>> -> W.Handle<S> -> X.Tx<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>,A.Notice<S,E>> & (Bool & V),~body:@-H:Type -> Cap.ValueRead<H,Row<S,V>> -> H -> H & Out,handles:List<&2,W.Handle<S>>,tx:X.Tx<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>,A.Notice<S,E>>) -> X.Tx<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>,A.Notice<S,E>> & List<&2,Out>:
111 match handles:
112 case []: (tx,[])
113 case +handle <> rest: component_join(~S,~V,~C,~R,~E,~Out,~spec,~body,handle,component_selected(tx,handle),tx => scan(~S,~V,~C,~R,~E,~Out,~spec,~component_selected,~body,rest,tx))
114def finish(~S:Data,~C:Type,~R:Type,~E:Data,~Out:Data,observed:X.Tx<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>,A.Notice<S,E>> & List<&2,Out>) -> W.World<S,A.Store<S,C>,R,A.Notice<S,E>> & List<&2,Out>:
115 match observed:
116 case (X.Tx{world,_,_,_,_},values): (world,values)
117def reserved(~S:Data,~V:Data,~C:Type,~R:Type,~E:Data,~Out:Data,~spec:Spec<S>,~component_selected:X.Tx<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>,A.Notice<S,E>> -> W.Handle<S> -> X.Tx<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>,A.Notice<S,E>> & (Bool & V),~body:@-H:Type -> Cap.ValueRead<H,Row<S,V>> -> H -> H & Out,observed:W.World<S,A.Store<S,C>,R,A.Notice<S,E>> & List<&2,W.Handle<S>>) -> W.World<S,A.Store<S,C>,R,A.Notice<S,E>> & List<&2,Out>:
118 (world,handles) = observed
119 finish(~S,~C,~R,~E,~Out,scan(~S,~V,~C,~R,~E,~Out,~spec,~component_selected,~body,handles,X.begin(~W.World<S,A.Store<S,C>,R,A.Notice<S,E>>,~A.Notice<S,E>,world)))
120def each(~S:Data,~V:Data,~C:Type,~R:Type,~E:Data,~Out:Data,~spec:Spec<S>,~component_selected:X.Tx<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>,A.Notice<S,E>> -> W.Handle<S> -> X.Tx<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>,A.Notice<S,E>> & (Bool & V),~body:@-H:Type -> Cap.ValueRead<H,Row<S,V>> -> H -> H & Out,world:W.World<S,A.Store<S,C>,R,A.Notice<S,E>>) -> W.World<S,A.Store<S,C>,R,A.Notice<S,E>> & List<&2,Out>:
121 reserved(~S,~V,~C,~R,~E,~Out,~spec,~component_selected,~body,W.handles(~S,~A.Store<S,C>,~R,~A.Notice<S,E>,world))