{-# OPTIONS_GHC -Wno-unused-imports #-}

-- |
-- [Previous Chapter: Entities and Components Basics]("Mischief.ECS.Tutorial.Guides.Basics")
--
-- [Next Chapter: Quasi-Query Conversion]("Mischief.ECS.Tutorial.Guides.QuasiConversion")
--
-- [Main Page]("Mischief.ECS")
module Mischief.ECS.Tutorial.Guides.QueryBasics
  ( -- * Learn You an ECS for Great Mischief! - 2.3. Query Basics
    -- $intro

    -- * Query Data
    -- $qd

    -- * Query Filters
    -- $qf

    -- * What about @q@?
    -- $q

    -- * What was that about a Query?
    -- $query

    -- * [Next Chapter: Quasi-Query Conversion]("Mischief.ECS.Tutorial.Guides.QuasiConversion")
  )
where

import Mischief.ECS

-- $intro
-- In an ECS, queries are a mechanism used to read data based on a certain user-defined format. In Mischief, they're a bit more complex than that;
-- queries are pure functions chained together which can trigger effects in the World, as well as retrieve data.
--
-- This chapter is an introduction to the @q@ quasi-quoter, and a short how-to guide on reading data from entities. The next chapters
-- delve into more complex queries.

-- $qd
-- Query Data is a tuple of types that are queryable. Query Data can be written using the @qd@ macro. Here are the things you can query for:
--
-- * Components: get a component's value.
--
-- @
-- ['qd'|Name, Health|]
-- @
--
-- * Relationships: get relationships with a specific component. Either all relationships, or just with a specific entity. This will return either a
-- single @Rel@ or a list of them.
--
-- @
-- ['qd'|Likes -> *|]
-- @
--
-- @
-- ['qd'|Likes -> bob|]
-- @
--
-- * Transitive Components: similar to the previous but you give it an entire query to grab from each of the targets. Will return a @From@ or a list of them.
--
-- @
-- ['qd'|Likes -> (Name, Health)|]
-- @
--
-- * Resource: Grabs a resource from the world.
--
-- @
-- ['qd'|Res SomeRes]
-- @
--
-- When you query for each of these types, the query will filter out any entities that don't have them.
-- For instance, if you're querying for @Health@, you're leaving out entities that don't have @Health@, and if
-- you're querying for @Likes -> *@ you're leaving out entities that like no one.
--
-- In order to include optional components, resources, relationships, you can use the @Maybe@ keyword:
--
-- @
-- ['qd'|Name, Maybe Health, Maybe Likes -> (Name)]
-- @

-- $qf
-- Query Filters can be used to filter the entities that a query is looking at. They can be written with the @qf@ quasi-quoter.
--
-- There are three such filters:
--
-- * With: filters out entities that do not have this component.
--
-- @
-- ['qf'|With Player|]
-- @
--
-- * Without: filters out entities that have this component.
--
-- @
-- ['qf'|Without Enemy|]
-- @
--
-- * Changed: filters out /most/ entities that haven't had this component be re-inserted since the current system last ran:
--
-- @
-- ['qf'|Changed Name|]
-- @
--
-- Filters can be combined with @&&@ and @||@. Separating them by @,@ will result in an implicit @&&@:
--
-- @
-- ['qf'|With Health, Changed Name|]
-- @
--
-- Is the same as:
--
-- @
-- ['qf'|With Health && Changed Name|]
-- @

-- $q
-- @q@ combines the previous two quasi-quoters, and produces a @Query@.
--
-- For instance, the following will result in a @Query (Name, Player)@:
--
-- @
-- ['q'|Name, Player / Without Enemy|]
-- @
--
-- The first part (left of the @/@) is the same as @qd@, while the other is the same as @qf@. The @/@ along with the filter can be omitted. Note that
-- the filter in @q@ must be an Archetype Filter!
--
-- Additionally, @q@ accepts an Entity at the start, filling the Query with just the components from that Entity:
--
-- @
-- ['q'|bob. Name, Health|]
-- @
--
-- Grabbing the @Name@ and @Health@ of /just/ bob is an @O(1)@ operation.

-- $query
-- @Query (Name, Player)@ is a Query through which the @Name@ and @Player@ components flow. You can think of it
-- as a wrapper around @[(Name, Player)]@, although it's a bit more complicated than that.
--
-- The list of components can be extracted from a Query using @query@ or @single@:
--
-- @
-- names \<- 'query' ['q'|Name|]
-- @
--
-- @
-- 'Just' bobName \<- 'single' ['q'|bob. Name|]
-- @
--
-- @single@ is the same as @query@ but instead of returning a list, it returns a @Maybe@ depending on if that list had exactly one element or not. It is useful
-- if you're retrieving the components of a specific entity or if you know there's only one entity that could fit your query (for instance, there is only one Player spawned).