anchor.diff:  
   == Exploration with Pathom Viz #TODO
   
  -= Getting Started
  -
  -In this chapter we'll give you some basics for using the library to parse arbitrary
  -queries. In order to understand this book you should understand the
  -syntax of these queries. This chapter will touch on some basics. More details can be found in
  -the Om Next documentation and in the
  -http://book.fulcrologic.com/#_the_query_and_mutation_language[Fulcro Developer's Guide]
  -
  -For now, you can get by with just a short introduction:
  += Getting Started on Pathom core engine
   
   == Query Notation Introduction
   
  
positive.code: `:com.wsscode.pathom.core/reader` can be used to supply reader(s) for the parser to use.  The `reader` can be a map from
  attributes to functions, a plain function, or even a vector of functions. It is asked to read the value for the elements
  of the query using the current environment. We'll expand on that as we go, or you can read more in the <<Readers,Readers section>>.
  
  == A Trivial Parser
  
  Our first example will be for a very simple parser that can resolve a single scalar property using
  a function that you define:
  
  [source,clojure]
  ----
  (ns pathom-docs.hello-pathom
    (:require [com.wsscode.pathom.core :as p]))
  
  ; Our first reader, defined with a map whose keys are the dispatch key from the query,
  ; and whose value is a function to resolve the data to return.
  (def computed
    ; here we define that for the dispatch-key :hello we are going to return "World"
    {:hello (fn [env] "World")})
  
  ; Create a parser
  (def parser (p/parser {}))
  
  ; Run the parser, using the reader, against a simple query (arguments are env and query):
  (parser {::p/reader computed} [:hello])
  ; => {:hello "World"}
  ----
  
  == Types of Reads
  
  When parsing a graph API there are 3 major types of reading that you want to do at any level:
  
  . *Entity attributes*: Attributes that are *already* present on the current entity (the current context). For example, if we have already loaded (and are at) a `customer` node, it might have attributes like `:customer/id` and `:customer/name`. When the query asks for those we can fetch them from the entity itself.
  . *Computed attributes*: If the desired key is *not* literally present as data on the entity of the current context then we can try to compute it from one (or many) other readers, those readers are usually maps (if your query is known to have a closed sets of attributes) or multimethods (if you want an extensible open sets of attributes), and they can be configured to handle the keys by doing some process/computation. There are 2 categories of these:
  .. *Globals*: if the computed attribute *doesn't* depend on any data from the entity in the current context then it is a global computation and can be used independent of the current context.
  .. *Derived attributes*: Computing the attribute depends on some existing property of the current entity. Derivations are often relationship mappings, like navigating a join on `:customer/address` or `:customer/friends`. They may also be a transformation of real data from the contextual entity.
  . *Entity lookups*: This is the Om.next default way to look for a specific entity on the graph using the notation `[:customer/id 123]` (where the first element names a unique identity key, and the second gives the unique id). Using such a literal entity lookup is a way of explicitly setting the context. It is essentially a "goto entity" for graph notation.
  
  We will cover examples of all of these in this chapter.  Pathom also includes <<Connect,Connect>>: an API
  defining the mechanism of *Computed attributes*.  Many people will find that API to be the most direct path to a flexible parser
  for their system.
  
  IMPORTANT: Use qualified (ideally namespaced) keywords. You should take great care to use unique names for your graph query attributes. The contextual behavior can lead to confusion very quickly, and it is made worse if you're not sure which part of your query is even running. Also, software evolution will almost certainly lead you to use your queries with new APIs, and you will want to avoid naming collisions.
  
  == Some Basics
  
  In this section we'll develop a small parser that uses the primary elements of the core API. First, let's talk about some
  of the basics a little more.
  
  === Reader Chains
  
  It is very common for your parser to need more than one reader in order to process your queries. In these cases
  the `:p/reader` option to the parser can be a vector of readers.  If a vector is given then they are tried in order until one of them resolves the read (or they all give up).  Since `nil` is a valid possible value the a reader *must* return special values in order to indicate how the chain should behave.
  
  * It can return `::p/not-found` to indicate the attribute was not found, and *no further action* should be taken.
  * It can return `::p/continue` to indicate the attribute was not found, but the next reader (if available) should be tried.
  
  === The Map Reader
  
  Not all things need to be computed.  Very often the current context will already have attributes that were read during
  some prior step (for example, a computed attribute might have read an entire entity from the database and made it the
  current context). The map reader plugin is a plugin that has the following behavior:
  
  * If the attribute requested exists in the current parsing context (with any value, even nil), it returns it.
  * If the attribute is missing, it returns `::p/continue`, which is an indication to move to the next reader in the chain.
  * If the attribute is present, it properly returns the value.
  
  The map reader is also capable of resolving relations (if present in the context). For example, if there is a join in the query
  and a vector of data at that join key in the context, then it will attempt to fulfill the subquery of the join.
  
  The map reader is almost always inserted into a reader chain because it is so common to read clumps of things from a database
  into the context and resolve them one by one as the query parsing proceeds.
  
  === Plugins
  
  Pathom allows a parser to have a collection of plugins that modify its behavior. Plugins is a top-level option when creating the parser, and the value is a vector of plugins:
  
  ```
  (def parser (p/parser {::p/plugins [...]}))
  ```
  
  In this section we'll be using a few plugins to make our lives easier.
  
  === The Environment Plugin
  
  Typically the parsing environment will need to include things you create and inject every time you parse a query (e.g. a
  database connection) and some parser-related things (e.g. the reader) that might be the same all the time.
  
  In the earlier example we created the parser and then *explicitly* supplied a reader to the environment every time we
  called it. In cases where there are specific things that you'd always like included in the environment we can instead
  use the plugin system to pre-set them for every parse.
  
  So, in our prior example we had:
  
  ```
  (def parser (p/parser {}))
  ```
  
  and every call to the parser needed an explicit reader: `(parser {::p/reader computed} [:hello])`
  
  The `p/env-plugin` is a parser plugin that automatically merges a map of configuration into the parsing environment every time the parser is called. Thus, our earlier example can be converted to:
  
  ```
  (def parser (p/parser {::p/plugins [(p/env-plugin {::p/reader computed})]}))
  ```
  
  and now each call to the parser needs nothing in the env on each invocation: `(parser {} [:hello])`.
  
  Providing an environment is such a common operation that there is a shortcut to set it up:
  
  ```
  (def parser (p/parser {::p/env {::p/reader computed}}))
  ```
  
  The `::p/env` option to the parser tells it to install the `env-plugin` with the given configuration.
  
  === The Example
  
  The example below sets up a more complex scenario where we'll want to pass a database in the environment on every call
  (it might change over time), but we'll place the reader logic in the environment plugin so we can only mention that part
  of the setup once.
  
  Here's a quick summary of the things we'll be using for quick reference:
  
  [Horizontal]
  `p/join`:: Satisfy a to-one join, and continue parsing.
  `p/join-seq`:: Satisfy a to-many join, and continue parsing
  `p/entity-attr!`:: Look up a (required) attribute from the current entity (context). Throws if missing.
  `p/map-reader`:: The map reader, as discussed previously.
  
  Our example first starts with the expected preamble:
  
  [source,clojure]
  ----
  (ns pathom-docs.hello-entities
    (:require [com.wsscode.pathom.core :as p]))
  ----
  
  Next we define some pretend database tables where the key is our pretend row ID, and the value is a pretend entity. Since
  we're using keywords as IDs, you'll also note that our "relations" are either simple keywords (to-one) or vectors of
  keywords (to-many):
  
  [source,clojure]
  ----
  ; define some data of tv shows, as a simple map-based table
  (def tv-shows
    {:rm  #:tv-show{:title         "Rick and Morty"
                    :character-ids [:rick :summer :morty]}
     :bcs #:tv-show{:title         "Better Call Saul"
                    :character-ids [:bcs]}
     :got #:tv-show{:title         "Game of Thrones"
                    :character-ids [:arya :ygritte]}})
  
  ; TV show characters, "joined" to tv-shows by "tv-show-id"
  (def characters
    {:rick    #:character{:name "Rick Sanshes" :tv-show-id :rm}
     :summer  #:character{:name "Summer Smith" :tv-show-id :rm}
     :saul    #:character{:name "Saul Goodman" :tv-show-id :bcs}
     :arya    #:character{:name "Arya Stark" :tv-show-id :got}
     :morty   #:character{:name "Morty Smith" :tv-show-id :rm}
     :ygritte #:character{:name "Ygritte" :tv-show-id :got}})
  ----
  
  thus, the `:character/tv-show-id :got` entry in the characters table is a pointer to the Game of Thrones (got) TV show in the
  TV shows table.
  
  
  Next we'll define a helper function that will help us look up things in these tables.
  
  NOTE: we'll combine the tables above together into our parsing environment as `:db` in a later step, like this `{:db (atom {:characters characters :tv-shows tv-shows})}`. Our helpers assume this.
  
  [source,clojure]
  ----
  (defn characters-by-ids
    "This helper is given the parsing environment (where we'll pass in our database) and a list of character IDs.
     It returns the sequence of rows in the table that match those IDs."
    [{::keys [db] :as env} ids]
    (map (get @db :characters) ids))
  ----
  
  and next a map-based reader for "resolving" a few things that are derived from either
  the context, or a more complex "query" of the database.  Note that we're parsing a graph
  query, so whenever we expect an attribute to be used as a join we must use the join helpers
  to tell the parser to continue processing the subquery of the join:
  
  [source,clojure]
  ----
  ;; an example of a reader that doesn't need any context: This returns a random character from our database.
  (def computed
    {:characters/random
     (fn [{::keys [db] :as env}]
       (let [character (rand-nth (-> @db :characters vals vec))]
         ; Use `join` to recursively parse the sub-query with the new to-one entity context
         (p/join character env)))
  
     ; another "globally accessible" bit of data that can be queried (independent of context)
     ; and returns a to-many result of some pre-chosen "leaing role" characters.
     :characters/main
     (fn [env]
       ; Process to-many joins with join-seq using a sequence as the new context:
       (p/join-seq env (characters-by-ids env [:rick :morty :saul :arya])))
  
     ; an example of a more complex computed relashionship:
     ; extract the tv-show according to the :character/tv-show-id
     ; on a character entity (current context)
     :character/tv-show
     (fn [{::keys [db] :as env}]
       ; the p/entity-attr! will try to get the :character/tv-show from current entity
       ; if it's not there it will make a query for it using the same parser. If
       ; it can't be got it will trigger an exception with the issue details, making
       ; easier to identify the problem
       (let [tv-show-id (p/entity-attr! env :character/tv-show-id)]
         (p/join (some-> @db :tv-shows (get tv-show-id)) env)))
  
     ; example of making a computed property, get the number of characters
     ; (the current context must be a tv-show)
     :tv-show/characters-count
     (fn [env]
       ; just give a count on members, and again, will raise exception if
       ; :tv-show/character-ids fails to be reached
       (count (p/entity-attr! env :tv-show/character-ids)))})
  ----
  
  Finally we can define the parser itself.  Note that we add in a `p/map-reader` to do the work of looking up any
  queried attributes that we've already placed in the environment (via `join` and `join-seq`):
  
  [source,clojure]
  ----
  (def parser
    ; This time we are using the env-plugin to initialize the environment, this is good
    ; to set the defaults for your parser to be called. Also, we are attaching the built-in
    ; reader map-reader on the game, so it will read the keys from the entity map. Check
    ; Entity page on wiki for more information.
    (p/parser {::p/plugins [(p/env-plugin {::p/reader [p/map-reader computed]})]}))
  ----
  
  Now we can call the parser any number of times with various queries. Note that this is where we're injecting our
  simple map-based database into the environment:
  
  [source,clojure]
  ----
  ; call the parser, create and send our atom database
  (parser {::db (atom {:characters characters
                       :tv-shows   tv-shows})}
          [{:characters/main [:character/name {:character/tv-show [:tv-show/title
                                                                   :tv-show/characters-count]}]}
           ; feeling lucky today?
           {:characters/random [:character/name]}])
  ; =>
  ; #:characters{:main   [#:character{:name "Rick Sanshes", :tv-show #:tv-show{:name "Rick and Morty", :characters-count 3}}
  ;                       #:character{:name "Morty Smith", :tv-show #:tv-show{:name "Rick and Morty", :characters-count 3}}
  ;                       #:character{:name "Saul Goodman", :tv-show #:tv-show{:name "Better Call Saul", :characters-count 1}}
  ;                       #:character{:name "Arya Stark", :tv-show #:tv-show{:name "Game of Thrones", :characters-count 2}}],
  ;              :random #:character{:name "Saul Goodman"}}
  ----
  
  == Entity Lookups
  
  Entity lookups are done by *ident* (as defined by Om Next and Fulcro). An *ident* is simply a vector whose first element is a keyword and second element is any value. The first element is thought of as the "table" or "kind" of thing, and the second as the ID of a specific one. For example `[:character/id :rick]` is an ident that "conceptually points to" the entity of type/table "character/id" with ID ":rick".
  
  You typically add support for entity lookups using a multimethod that dispatches on the first element of an ident. The predefined value `::p/continue` can be used by an entity lookup reader to indicate that it should ask the next reader to try to resolve the lookup.
  
  We'll be using one additional new function:
  
  [Horizontal]
  `p/ident-value`:: Given the env, it will return the ID portion of the ident that is being resolved (current context).
  
  The code below can be added to the prior example:
  
  [source,clojure]
  ----
  ; databases and other prior code
  ...
  
  ;;;;;; Handle Entity Lookups ;;;;;;;
  
  (defmulti entity p/entity-dispatch)
  
  ; default case returns ::p/continue to sign to pathom that
  ; this reader can't handle the given entry
  (defmethod entity :default [_] ::p/continue)
  
  (defmethod entity :character/id [{::keys [db] :as env}]
    ; from the key [:character/id :rick], p/ident-value will return :rick
    (let [id (p/ident-value env)]
      ; same thing as would find a record by id on your database
      ; we return ::p/continue to signal this reader wans't able to
      ; fetch it entity, so the parser can try the next one, more about this
      ; on Readers with page
      (p/join (get-in @db [:characters id] ::p/continue) env)))
  
  ; same thing for tv shows
  (defmethod entity :tv-show/id [{::keys [db] :as env}]
    (let [id (p/ident-value env)]
      (p/join (get-in @db [:tv-shows id] ::p/continue) env)))
  
  (def parser
    ; add our entity reader to our reader list
    (p/parser {::p/plugins [(p/env-plugin {::p/reader [p/map-reader
                                                       computed
                                                       entity]})]}))
  
  ; testing our new queries
  (parser {::db (atom {:characters characters
                       :tv-shows   tv-shows})}
          [[:character/id :arya] ; query for the entire entity
           {[:tv-show/id :rm] ; use the given tv show as the "context" for the join
            [:tv-show/title
             {:tv-show/characters [:character/name]}]}])
  ; =>
  ; {[:character/id :arya] #:character{:name "Arya Stark", :tv-show-id :got}
  ;  [:tv-show/id :rm]     #:tv-show{:title      "Rick and Morty"
  ;                                  :characters [#:character{:name "Rick Sanshes"}
  ;                                               #:character{:name "Summer Smith"}
  ;                                               #:character{:name "Morty Smith"}]}}
  ----
  
  These building blocks enable quite a bit of query processing. As your graph grows larger it will make sense to use some additional tools to help split your parser into different pieces. In particular `computed` can be written with a dispatch mechanism instead of being represented as a map. See the section about
  <<dispatch-helpers,dispatch helpers>> for more information.
  
  Here is the complete code for the example:
  
  [source,clojure]
  ----
  (ns pathom-docs.hello-entities
    (:require [com.wsscode.pathom.core :as p]))
  
  (def tv-shows
    {:rm  #:tv-show{:title         "Rick and Morty"
                    :character-ids [:rick :summer :morty]}
     :bcs #:tv-show{:title         "Better Call Saul"
                    :character-ids [:bcs]}
     :got #:tv-show{:title         "Game of Thrones"
                    :character-ids [:arya :ygritte]}})
  
  (def characters
    {:rick    #:character{:name "Rick Sanshes" :tv-show-id :rm}
     :summer  #:character{:name "Summer Smith" :tv-show-id :rm}
     :saul    #:character{:name "Saul Goodman" :tv-show-id :bcs}
     :arya    #:character{:name "Arya Stark" :tv-show-id :got}
     :morty   #:character{:name "Morty Smith" :tv-show-id :rm}
     :ygritte #:character{:name "Ygritte" :tv-show-id :got}})
  
  (defn characters-by-ids [{::keys [db]} ids]
    (map (get @db :characters) ids))
  
  (def computed
    {:characters/random
     (fn [{::keys [db] :as env}]
       ; take a hand of the entity we want to be the current node
       (let [character (rand-nth (-> @db :characters vals vec))]
         ; to parse the sub-query with the entity we use the join function
         (p/join character env)))
  
     :characters/main
     (fn [env]
       ; since we decided to get the env in the characters-by-ids the argument
       ; passing is a brease
       (p/join-seq env (characters-by-ids env [:rick :morty :saul :arya])))
  
     :character/tv-show
     (fn [{::keys [db] :as env}]
       (let [tv-show-id (p/entity-attr! env :character/tv-show-id)]
         (p/join (some-> @db :tv-shows (get tv-show-id)) env)))
  
     :tv-show/characters
     (fn [env]
       (let [ids (p/entity-attr! env :tv-show/character-ids)]
         (p/join-seq env (characters-by-ids env ids))))
  
     :tv-show/characters-count
     (fn [env]
       (count (p/entity-attr! env :tv-show/character-ids)))})
  
  (defmulti entity p/entity-dispatch)
  
  (defmethod entity :default [_] ::p/continue)
  
  (defmethod entity :character/id [{::keys [db] :as env}]
    (let [id (p/ident-value env)]
      (p/join (get-in @db [:characters id] ::p/continue) env)))
  
  (defmethod entity :tv-show/id [{::keys [db] :as env}]
    (let [id (p/ident-value env)]
      (p/join (get-in @db [:tv-shows id] ::p/continue) env)))
  
  (def parser
    (p/parser {::p/plugins [(p/env-plugin {::p/reader [p/map-reader
                                                       computed
                                                       entity]})]}))
  
  (parser {::db (atom {:characters characters
                       :tv-shows   tv-shows})}
          [[:character/id :arya]
           {[:tv-show/id :rm]
            [:tv-show/title
             {:tv-show/characters [:character/name]}]}])
  ; =>
  ; {[:character/id :arya] #:character{:name "Arya Stark", :tv-show-id :got}
  ;  [:tv-show/id :rm]     #:tv-show{:title      "Rick and Morty"
  ;                                  :characters [#:character{:name "Rick Sanshes"}
  ;                                               #:character{:name "Summer Smith"}
  ;                                               #:character{:name "Morty Smith"}]}}
  ----
  
  = Pathom Core Engine [[Core]]
  
  
negative.code: 
  == Async parsing [[AsyncParsing]]
  
  NOTE: Nowadays the parallel parser is the recommended one to use because of the query
  strategy, but all the concepts presented here for async parser also applies to the
  parallel parser, which is async.
  
  If you want to write parsers to run in Javascript environments, then async operations are the norm. The async
  parser is a version of the parser were you can return core async channels from the readers instead of raw
  values. This allows for the creation of parsers that do network requests or any other async operation.
  