@@ -21,12 +21,17 @@ The following example shows how nested patterns translate
2121into an equivalent manual query built with ` entity(...) ` and predicates.
2222
2323``` {code-cell} ipython3
24+ from krrood.entity_query_language.symbol_graph import SymbolGraph
2425from dataclasses import dataclass
2526from typing_extensions import List
2627
2728from krrood.entity_query_language.entity import (
28- let, entity, the,
29- match, entity_matching, Symbol,
29+ let, entity, Symbol,
30+ )
31+ from krrood.entity_query_language.quantify_entity import the, an
32+ from krrood.entity_query_language.match import (
33+ match,
34+ entity_matching,
3035)
3136from krrood.entity_query_language.predicate import HasType
3237
@@ -61,7 +66,19 @@ class FixedConnection(Connection):
6166@dataclass
6267class World:
6368 connections: List[Connection]
69+
70+ @dataclass
71+ class Drawer(Symbol):
72+ handle: Handle
73+ container: Container
74+
75+
76+ @dataclass
77+ class Cabinet(Symbol):
78+ container: Container
79+ drawers: List[Drawer]
6480
81+ SymbolGraph()
6582
6683# Build a small world with a few connections
6784c1 = Container("Container1")
@@ -123,3 +140,131 @@ Notes:
123140- Use ` entity_matching ` for the outer pattern when a domain is involved; inner attributes use ` match ` .
124141- Nested ` match(...) ` can be composed arbitrarily deep following your object graph.
125142- ` entity_matching ` is a syntactic sugar over the explicit ` entity ` + predicates form, so both are interchangeable.
143+
144+ ## Selecting inner objects with ` select() `
145+
146+ Use ` select(Type) ` when you want the matched inner objects to appear in the result. The evaluation then
147+ returns a mapping from the selected variables to the concrete objects (a unification dictionary).
148+
149+ ``` {code-cell} ipython3
150+ from krrood.entity_query_language.match import select
151+
152+ container, handle = select(Container), select(Handle)
153+ fixed_connection_query = the(
154+ entity_matching(FixedConnection, world.connections)(
155+ parent=container(name="Container1"),
156+ child=handle(name="Handle1"),
157+ )
158+ )
159+
160+ answers = fixed_connection_query.evaluate()
161+ print(answers[container].name, answers[handle].name)
162+ ```
163+
164+ ## Existential matches in collections with ` match_any() `
165+
166+ When matching a container-like attribute (for example, a list), use ` match_any(pattern) ` to express that
167+ at least one element of the collection should satisfy the given pattern.
168+
169+ Below we add two simple view classes and build a small scene of drawers and a cabinet.
170+
171+ ``` {code-cell} ipython3
172+ from krrood.entity_query_language.match import match_any
173+
174+ # Build a simple set of views
175+ drawer1 = Drawer(handle=h1, container=c1)
176+ drawer2 = Drawer(handle=Handle("OtherHandle"), container=other_c)
177+ cabinet1 = Cabinet(container=c1, drawers=[drawer1, drawer2])
178+ cabinet2 = Cabinet(container=other_c, drawers=[drawer2])
179+ views = [drawer1, drawer2, cabinet1, cabinet2]
180+
181+ # Query: find the cabinet that has any drawer from the set {drawer1, drawer2}
182+ cabinet_query = an(entity_matching(Cabinet, views)(drawers=match_any([drawer1, drawer2])))
183+
184+ found_cabinets = list(cabinet_query.evaluate())
185+ assert len(found_cabinets) == 2
186+ print(found_cabinets[0].container.name, found_cabinets[0].drawers[0].handle.name)
187+ print(found_cabinets[1].container.name, found_cabinets[1].drawers[0].handle.name)
188+ ```
189+
190+ ## Selecting elements from collections with ` select_any() `
191+
192+ If you want to retrieve a specific element from a collection attribute while matching, use ` select_any(Type) ` .
193+ It behaves like ` match_any(Type) ` but also selects the matched element so you can access it in the result.
194+
195+ ``` {code-cell} ipython3
196+ from krrood.entity_query_language.match import select_any
197+
198+ selected_drawers = select_any([drawer1, drawer2])
199+ # Query: find the cabinet that has any drawer from the set {drawer1, drawer2}
200+ cabinet_query = an(entity_matching(Cabinet, views)(drawers=selected_drawers))
201+
202+ ans = list(cabinet_query.evaluate())
203+ assert len(ans) == 2
204+ print(ans)
205+ ```
206+
207+ ## Selecting inner objects with ` select() `
208+
209+ Use ` select(Type) ` when you want the matched inner objects to appear in the result. The evaluation then
210+ returns a mapping from the selected variables to the concrete objects (a unification dictionary).
211+
212+ ``` {code-cell} ipython3
213+ from krrood.entity_query_language.match import select
214+
215+ container, handle = select(Container), select(Handle)
216+ fixed_connection_query = the(
217+ entity_matching(FixedConnection, world.connections)(
218+ parent=container(name="Container1"),
219+ child=handle(name="Handle1"),
220+ )
221+ )
222+
223+ answers = fixed_connection_query.evaluate()
224+ print(answers[container].name, answers[handle].name)
225+ ```
226+
227+ ## Existential matches in collections with ` match_any() `
228+
229+ When having multiple possible matches, and you care only if at least the attribute matches one possibility, use
230+ ` match_any(IterableOfPossibleValues) ` to express that
231+ at least one element of the collection should satisfy the given pattern.
232+
233+ Below we add two simple view classes and build a small scene of drawers and a cabinet.
234+
235+ ``` {code-cell} ipython3
236+ from krrood.entity_query_language.match import match_any
237+
238+ # Build a simple set of views
239+ drawer1 = Drawer(handle=h1, container=c1)
240+ drawer2 = Drawer(handle=Handle("OtherHandle"), container=other_c)
241+ cabinet1 = Cabinet(container=c1, drawers=[drawer1, drawer2])
242+ cabinet2 = Cabinet(container=other_c, drawers=[drawer2])
243+ views = [drawer1, drawer2, cabinet1, cabinet2]
244+
245+ # Query: find the cabinet that has any drawer from the set {drawer1, drawer2}
246+ cabinet_query = an(entity_matching(Cabinet, views)(drawers=match_any([drawer1, drawer2])))
247+
248+ found_cabinets = list(cabinet_query.evaluate())
249+ assert len(found_cabinets) == 2
250+ print(found_cabinets[0].container.name, found_cabinets[0].drawers[0].handle.name)
251+ print(found_cabinets[1].container.name, found_cabinets[1].drawers[0].handle.name)
252+ ```
253+
254+ ## Selecting elements from collections with ` select_any() `
255+
256+ If you want to retrieve a specific element from a collection attribute while matching, use ` select_any(Type) ` .
257+ It behaves like ` match_any(Type) ` but also selects the matched element so you can access it in the result.
258+
259+ ``` {code-cell} ipython3
260+ from krrood.entity_query_language.match import select_any, entity_selection
261+
262+ selected_drawers = select_any([drawer1, drawer2])
263+ # Query: find the cabinet that has any drawer from the set {drawer1, drawer2}
264+ cabinet = entity_selection(Cabinet, views)
265+ cabinet_query = an(cabinet(drawers=selected_drawers))
266+
267+ ans = list(cabinet_query.evaluate())
268+ assert len(ans) == 2
269+ print(ans)
270+ ```
0 commit comments