Example with Joining Multiple Sources.

Contents

Example with Joining Multiple Sources.#

In this example, we show the how EQL can perform complex queries that require joining of multiple sources (equivalent to tables in a structured database) without ever mentioning join or how to join, instead it is implicit in the conditions of the query.

This allows for a minimal query description that only contains the high level logic.

Example Usage#

from dataclasses import dataclass, field

from typing_extensions import List

from entity_query_language import an, set_of, From, symbol, HasType, symbolic_mode


@symbol
@dataclass
class Body:
    name: str


@dataclass
class Container(Body):
    ...


@dataclass
class Handle(Body):
    ...


@symbol
@dataclass
class Connection:
    parent: Body
    child: Body


@dataclass
class PrismaticConnection(Connection):
    ...


@dataclass
class FixedConnection(Connection):
    ...


@symbol
@dataclass
class World:
    id_: int
    bodies: List[Body]
    connections: List[Connection] = field(default_factory=list)


# Create the world with its bodies and connections
world = World(1, [Container("Container1"), Container("Container2"), Handle("Handle1"), Handle("Handle2")])
c1_c2 = PrismaticConnection(world.bodies[0], world.bodies[1])
c2_h2 = FixedConnection(world.bodies[1], world.bodies[3])
world.connections = [c1_c2, c2_h2]

# Query for the kinematic tree of the drawer which has more than one component.
with symbolic_mode():
    # Declare the variables
    prismatic_connection = PrismaticConnection(From(world.connections))
    fixed_connection = FixedConnection(From(world.connections))
    parent_container = prismatic_connection.parent
    drawer_body = fixed_connection.parent
    handle = fixed_connection.child

    # Declare the selected variables that will be outputted by the query
    drawer_kinematic_tree = (parent_container, prismatic_connection, drawer_body,
                             fixed_connection, handle)

    # Write the query body
    query = an(set_of(drawer_kinematic_tree,
                      HasType(prismatic_connection.parent, Container),
                      HasType(fixed_connection.child, Handle),
                      prismatic_connection.child == fixed_connection.parent)
               )
results = list(query.evaluate())
assert len(results) == 1
assert results[0][parent_container].name == "Container1"
assert results[0][drawer_body].name == "Container2"
assert results[0][handle].name == "Handle2"

In the above example we want to find all drawers and their components by describing their kinematic tree using a conjunction (AND operation) of conditions that show how the components are connected to each other to form the kinematic tree.