View Source Ecspanse.Query (ECSpanse v0.9.0)

The Ecspanse.Query module provides a set of functions for querying entities, components and resources.

The queries are read-only operations they do not modify the state of the components or resources.

Queries can be run both from within the Ecspanse systems and from outside of the framework.

Summary

Generic

Returns a single tuple wiht components for a t/0 query. Returns nil if no result was found. Raises if more than one entry.

select/2 is the most versatile function for querying entities and components. On its own, it will return an Ecspanse.Query struct that holds the query details. The struct needs to be passed to Ecspanse.Query.stream/1 or Ecspanse.Query.one/1 to get the results.

Returns a stream of components tuples for a t/0 query.

Entities

Checks if an entity exists by its ID, or by the entity struct.

Returns a component's entity.

Relationships

Returns true if the entity has at least a child with the given component module.

Returns true if the entity has at least a child with all the given component modules.

Returns true if the entity has at least a parent with the given component module.

Returns true if the entity has at least a parent with all the given component modules.

Reurns true if a given entity is a child of another entity.

Reurns true if a given entity is a parent of another entity.

Returns the list of ancestor entities for the given entity. That means the parents of the entity and their parents and so on.

Returns the list of child entities for the given entity.

Returns the list of descendant entities for the given entity. That means the children of the entity and their children and so on.

Returns the list of parent entities for the given entity.

Components

Fetches the component by its module for a given entity.

Fetches a tuple of components by their modules for a given entity. The entity must have all the components for the query to succeed.

Returns true if the entity has a component with the given module.

Returns true if the entity has all the components with the given modules.

Lists all the components for a given entity.

Resources

Fetches a resource by its module.

Tags

Fetches an entity's component by a list of tags. Raises if more than one entry is found.

Returns a list of components tagged with a list of tags for all entities.

Returns a list of components tagged with a list of tags for the ancestors of a given entity.

Returns a list of components tagged with a list of tags for the children of a given entity.

Returns a list of components tagged with a list of tags for the descendants of a given entity.

Returns a list of components tagged with a list of tags for a given list of entities. The components are not grouped by entity, but returned as a flat list.

Returns a list of components tagged with a list of tags for a given entity.

Returns a list of components tagged with a list of tags for the parents of a given entity.

Lists a component's tags.

Types

t()

The query preparation struct.

Generic

@spec one(t()) :: components_state :: tuple() | nil

Returns a single tuple wiht components for a t/0 query. Returns nil if no result was found. Raises if more than one entry.

See the select/2 function for more info.

Link to this function

select(component_modules_tuple, filters \\ [])

View Source
@spec select(
  component_modules :: tuple(),
  keyword()
) :: t()

select/2 is the most versatile function for querying entities and components. On its own, it will return an Ecspanse.Query struct that holds the query details. The struct needs to be passed to Ecspanse.Query.stream/1 or Ecspanse.Query.one/1 to get the results.

Arguments

1. component_modules

The first argument is a tuple of components to be selected. The query will return the components only for the entities that have all the components in the tuple.

The entity can be queried as well by adding Ecspanse.Entity as the first element in the tuple. Also, optional components can be queries, by adding the :opt key. The optional components should be placed at the end of the tuple.

The restults will be returned in the same order as the components in the tuple. This makes it easy to use pattern matching on the result.

2. filters

The filters are optional. They can be used to further narrow down the results.

  • :with - a list of components that the entity must have in addition to the ones specified in the component_modules tuple. But those components will not be returned in the result. :with filter has one option: :without - a list of components that the entity must not have.
  • :or_with - similar to :with. It allows to specify multiple filters for the same query. Multiple or_with filters can be used in the same query. The results will be returned if the entity components match any of the filters.
  • :for - a list of Ecspanse.Entity.t/0 that the query should be run for. The components will be returned only for those entities.
  • :not_for - a list of Ecspanse.Entity.t/0 that the query should not be run for. The components will be returned for all entities except those.
  • :for_children_of - a list of Ecspanse.Entity.t/0. The components will be returned only for the children of those entities.
  • :for_descendants_of - a list of Ecspanse.Entity.t/0. The components will be returned only for all descendants of those entities.
  • :for_parents_of - a list of Ecspanse.Entity.t/0. The components will be returned only for the parents of those entities.
  • :for_ancestors_of - a list of Ecspanse.Entity.t/0. The components will be returned only for all ancestors of those entities.

Info

Combining the following filters is not supported: :for, :not_for, :for_children_of, :for_descendants_of, :for_parents_of, :for_ancestors_of. Only one of them can be used in a query. Otherwise it will rise an error.

Examples

  Ecspanse.Query.select({Ecspanse.Entity, Demo.Components.Health, opt: Demo.Components.Mana},
    with: [Demo.Components.Orc],
    or_with: [[Demo.Components.Wizard], without: [Demo.Components.WhiteMagic]],
    for_descendants_of: [enemy_clan_entity]
  )
  |> Ecspanse.Query.stream()
  |> Enum.to_list()

a potential result may be:

  [
    {orc_entity, %Demo.Components.Health{value: 100}, nil},
    {wizard_entity, %Demo.Components.Health{value: 60}, %Demo.Components.Mana{value: 200}}
  ]
@spec stream(t()) :: Enumerable.t()

Returns a stream of components tuples for a t/0 query.

See the select/2 function for more info.

Entities

Link to this function

entity_exists?(entity_id)

View Source
@spec entity_exists?(Ecspanse.Entity.id() | Ecspanse.Entity.t()) :: boolean()

Checks if an entity exists by its ID, or by the entity struct.

@spec fetch_entity(Ecspanse.Entity.id()) ::
  {:ok, Ecspanse.Entity.t()} | {:error, :not_found}

Fetches an Ecspanse.Entity.t/0 by its ID.

An entity exists only if it has at least one component.

Examples

  {:ok, %Ecspanse.Entity{}} = Ecspanse.Query.fetch_entity(hero_entity_id)
Link to this function

get_component_entity(component)

View Source
@spec get_component_entity(component_state :: struct()) :: Ecspanse.Entity.t()

Returns a component's entity.

Examples

  {:ok, %Ecspanse.Entity{}} = Ecspanse.Query.get_component_entity(hero_component)

Relationships

Link to this function

has_children_with_component?(entity, component_module)

View Source
@spec has_children_with_component?(Ecspanse.Entity.t(), module()) :: boolean()

Returns true if the entity has at least a child with the given component module.

Examples

  true = Ecspanse.Query.has_children_with_component?(hero_entity, Demo.Components.Boots)
Link to this function

has_children_with_components?(entity, component_module_list)

View Source
@spec has_children_with_components?(Ecspanse.Entity.t(), [module()]) :: boolean()

Returns true if the entity has at least a child with all the given component modules.

Examples

  true = Ecspanse.Query.has_children_with_components?(hero_entity, [Demo.Components.Boots, Demo.Components.Sword])
Link to this function

has_parents_with_component?(entity, component_module)

View Source
@spec has_parents_with_component?(Ecspanse.Entity.t(), module()) :: boolean()

Returns true if the entity has at least a parent with the given component module.

Examples

  true = Ecspanse.Query.has_parents_with_component?(boots_entity, Demo.Components.Hero)
Link to this function

has_parents_with_components?(entity, component_module_list)

View Source
@spec has_parents_with_components?(Ecspanse.Entity.t(), [module()]) :: boolean()

Returns true if the entity has at least a parent with all the given component modules.

Examples

  true = Ecspanse.Query.has_parents_with_components?(boots_entity, [Demo.Components.Hero, Demo.Components.Gold])
@spec is_child_of?(parent: Ecspanse.Entity.t(), child: Ecspanse.Entity.t()) ::
  boolean()

Reurns true if a given entity is a child of another entity.

Examples

  true = Ecspanse.Query.is_child_of?(parent: hero_entity, child: boots_entity)
@spec is_parent_of?(parent: Ecspanse.Entity.t(), child: Ecspanse.Entity.t()) ::
  boolean()

Reurns true if a given entity is a parent of another entity.

Examples

  true = Ecspanse.Query.is_parent_of?(parent: hero_entity, child: boots_entity)
@spec list_ancestors(Ecspanse.Entity.t()) :: [Ecspanse.Entity.t()]

Returns the list of ancestor entities for the given entity. That means the parents of the entity and their parents and so on.

Examples

  [hero_entity, level_entity] = Ecspanse.Query.list_ancestors(compass_entity)
@spec list_children(Ecspanse.Entity.t()) :: [Ecspanse.Entity.t()]

Returns the list of child entities for the given entity.

Examples

  [sword_item_entity, magic_potion_entity] = Ecspanse.Query.list_children(hero_entity)
Link to this function

list_descendants(entity)

View Source
@spec list_descendants(Ecspanse.Entity.t()) :: [Ecspanse.Entity.t()]

Returns the list of descendant entities for the given entity. That means the children of the entity and their children and so on.

Examples

  [inventory_entity, map_entity] = Ecspanse.Query.list_descendants(hero_entity)
@spec list_parents(Ecspanse.Entity.t()) :: [Ecspanse.Entity.t()]

Returns the list of parent entities for the given entity.

Examples

  [hero_entity] = Ecspanse.Query.list_parents(inventory_entity)

Components

Link to this function

fetch_component(entity, component_module)

View Source
@spec fetch_component(Ecspanse.Entity.t(), module()) ::
  {:ok, component_state :: struct()} | {:error, :not_found}

Fetches the component by its module for a given entity.

Examples

  {:ok, gold_component} = Ecspanse.Query.fetch_component(hero_entity, Demo.Components.Gold)
Link to this function

fetch_components(entity, component_modules_tuple)

View Source
@spec fetch_components(Ecspanse.Entity.t(), component_modules :: tuple()) ::
  {:ok, components_state :: tuple()} | {:error, :not_found}

Fetches a tuple of components by their modules for a given entity. The entity must have all the components for the query to succeed.

Examples

  {:ok, {gold_component, gems_component}} = Ecspanse.Query.fetch_components(hero_entity, {Demo.Components.Gold, Demo.Components.Gems})
Link to this function

has_component?(entity, component_module)

View Source
@spec has_component?(Ecspanse.Entity.t(), module()) :: boolean()

Returns true if the entity has a component with the given module.

Examples

  true = Ecspanse.Query.has_component?(hero_entity, Demo.Components.Gold)
Link to this function

has_components?(entity, component_module_list)

View Source
@spec has_components?(Ecspanse.Entity.t(), [module()]) :: boolean()

Returns true if the entity has all the components with the given modules.

Examples

  true = Ecspanse.Query.has_components?(hero_entity, [Demo.Components.Gold, Demo.Components.Gems])
@spec list_components(Ecspanse.Entity.t()) :: [components_state :: struct()]

Lists all the components for a given entity.

The output is an unordered list of all the entity's components.

Note

The Ecspanse.Component.Children and Ecspanse.Component.Parents components are excluded from the output.

Use the provided list_children/1 and list_parents/1 functions to query the entity's relations.

Examples

  [gold_component, gems_component, position_component, energy_component] =
    Ecspanse.Query.list_components(hero_entity)

Resources

Link to this function

fetch_resource(resource_module)

View Source
@spec fetch_resource(resource_module :: module()) ::
  {:ok, resource_state :: struct()} | {:error, :not_found}

Fetches a resource by its module.

Examples

  {:ok, lobby_resource} = Ecspanse.Query.fetch_resource(Demo.Resources.Lobby)

Tags

Link to this function

fetch_tagged_component(entity, tags)

View Source
@spec fetch_tagged_component(Ecspanse.Entity.t(), [tag :: atom()]) ::
  {:ok, components_state :: struct()} | {:error, :not_found}

Fetches an entity's component by a list of tags. Raises if more than one entry is found.

Note

The project logic must ensure that only one component per entity is tagged with the given tags.

Examples

  {:ok, %Demo.Components.Paladin{} = hero_class_component} =
    Ecspanse.Query.fetch_tagged_component(hero_entity, [:class])
Link to this function

list_tagged_components(tags)

View Source
@spec list_tagged_components([tag :: atom()]) :: [components_state :: struct()]

Returns a list of components tagged with a list of tags for all entities.

The components need to be tagged with all the given tags to return.

Examples

  [gold_component, gems_component] = Ecspanse.Query.list_tagged_components([:resource, :available])
Link to this function

list_tagged_components_for_ancestors(entity, tags)

View Source
@spec list_tagged_components_for_ancestors(Ecspanse.Entity.t(), [tag :: atom()]) :: [
  components_state :: struct()
]

Returns a list of components tagged with a list of tags for the ancestors of a given entity.

The components need to be tagged with all the given tags to return.

Examples

  [dungeon_component] = Ecspanse.Query.list_tagged_components_for_ancestors(hero_entity, [:dungeon])
Link to this function

list_tagged_components_for_children(entity, tags)

View Source
@spec list_tagged_components_for_children(Ecspanse.Entity.t(), [tag :: atom()]) :: [
  components_state :: struct()
]

Returns a list of components tagged with a list of tags for the children of a given entity.

The components need to be tagged with all the given tags to return.

Examples

  [boots_component, compass_component] = Ecspanse.Query.list_tagged_components_for_children(hero_entity, [:inventory])
Link to this function

list_tagged_components_for_descendants(entity, tags)

View Source
@spec list_tagged_components_for_descendants(Ecspanse.Entity.t(), [tag :: atom()]) ::
  [
    components_state :: struct()
  ]

Returns a list of components tagged with a list of tags for the descendants of a given entity.

The components need to be tagged with all the given tags to return.

Examples

  [orc_component, orc_component, wizard_component] = Ecspanse.Query.list_tagged_components_for_descendants(dungeon_entity, [:enemy])
Link to this function

list_tagged_components_for_entities(entities, tags)

View Source
@spec list_tagged_components_for_entities([Ecspanse.Entity.t()], [tag :: atom()]) :: [
  components_state :: struct()
]

Returns a list of components tagged with a list of tags for a given list of entities. The components are not grouped by entity, but returned as a flat list.

The components need to be tagged with all the given tags to return.

Examples

  [gold_component, gems_component, gems_component] = Ecspanse.Query.list_tagged_components_for_entities([hero_entity, enemy_entity], [:resource, :available])
Link to this function

list_tagged_components_for_entity(entity, tags)

View Source
@spec list_tagged_components_for_entity(Ecspanse.Entity.t(), [tag :: atom()]) :: [
  components_state :: struct()
]

Returns a list of components tagged with a list of tags for a given entity.

The components need to be tagged with all the given tags to return.

Examples

  [gold_component, gems_component] = Ecspanse.Query.list_tagged_components_for_entity(hero_entity, [:resource, :available])
Link to this function

list_tagged_components_for_parents(entity, tags)

View Source
@spec list_tagged_components_for_parents(Ecspanse.Entity.t(), [tag :: atom()]) :: [
  components_state :: struct()
]

Returns a list of components tagged with a list of tags for the parents of a given entity.

The components need to be tagged with all the given tags to return.

Examples

  [hero_component] = Ecspanse.Query.list_tagged_components_for_parents(boots_entity, [:hero])
@spec list_tags(components_state :: struct()) :: [tag :: atom()]

Lists a component's tags.

Examples

  [:resource, :available] = Ecspanse.Query.list_tags(gold_component)

Types

@type t() :: %Ecspanse.Query{
  for_ancestors_of: [Ecspanse.Entity.t()],
  for_children_of: [Ecspanse.Entity.t()],
  for_descendants_of: [Ecspanse.Entity.t()],
  for_entities: [Ecspanse.Entity.t()],
  for_parents_of: [Ecspanse.Entity.t()],
  not_for_entities: [Ecspanse.Entity.t()],
  or: [
    [
      with_components: [component_module :: module()],
      without_components: [component_module :: module()]
    ]
  ],
  return_entity: boolean(),
  select: [component_module :: module()],
  select_optional: [component_module :: module()]
}

The query preparation struct.