### Datalog Queries in Pyramid (Clojure) Source: https://github.com/lilactown/pyramid/blob/main/docs/GUIDE.md Provides an example of using the experimental datalog query engine in `pyramid.query` to find specific data patterns. This is useful for developer inspection and troubleshooting within a Pyramid database. ```clojure (require '[pyramid.query :refer [q]]) ;; find the names of people with best friends, and their best friends' name (q [:find ?name ?best-friend :where [?e :friend/best ?bf] [?e :person/name ?name] [?bf :person/name ?best-friend]] animorphs-3) ;; => (["Marco" "Jake"] ["Jake" "Marco"]) ``` -------------------------------- ### Query Top-Level Keys in Pyramid Source: https://github.com/lilactown/pyramid/blob/main/docs/GUIDE.md Demonstrates how to perform a pull query that joins on top-level keys within the Pyramid database, such as querying species information. ```clojure (p/pull animorphs-3 [{:species [{:andalites [:person/name]}]}]) ;; => {:species {:andalites [{:person/name "Ax"}]}} ``` -------------------------------- ### Access Entity Data in Pyramid DB Source: https://github.com/lilactown/pyramid/blob/main/docs/GUIDE.md Demonstrates how to retrieve specific entity data from a Pyramid database using `get-in`. This leverages the map structure of the DB for efficient data access. ```clojure (get-in animorphs [:person/id 1]) ;; => {:person/id 1 :person/name "Marco"} ``` -------------------------------- ### Normalize Clojure Data into a Pyramid DB Source: https://github.com/lilactown/pyramid/blob/main/docs/GUIDE.md This snippet shows how to instantiate a Pyramid database by passing a vector of maps to `p/db`. The function normalizes the input data, assuming entities are identified by a keyword like `:id`. ```clojure (require '[pyramid.core :as p]) (def data {:person/id 0 :person/name "Rachel" :friend/list [{:person/id 1 :person/name "Marco"} {:person/id 2 :person/name "Cassie"} {:person/id 3 :person/name "Jake"} {:person/id 4 :person/name "Tobias"} {:person/id 5 :person/name "Ax"}]}) ;; you can pass in multiple entities to instantiate a db, so `p/db` gets a vector (def animorphs (p/db [data])) ;; => {:person/id {0 {:person/id 0 ;; :person/name "Rachel" ;; :friend/list [[:person/id 1] ;; [:person/id 2] ;; [:person/id 3] ;; [:person/id 4] ;; [:person/id 5]]} ;; 1 {:person/id 1 :person/name "Marco"} ;; 2 {:person/id 2 :person/name "Cassie"} ;; 3 {:person/id 3 :person/name "Jake"} ;; 4 {:person/id 4 :person/name "Tobias"} ;; 5 {:person/id 5 :person/name "Ax"}}} ``` -------------------------------- ### Perform Basic Pull Query in Pyramid Source: https://github.com/lilactown/pyramid/blob/main/docs/GUIDE.md This snippet demonstrates a basic pull query using `p/pull` on a Pyramid database. It retrieves data associated with a specific entity identifier. ```clojure (p/pull animorphs-3 [[:person/id 1]]) ;; => {[:person/id 1] {:person/id 1 ;; :person/name "Marco" ;; :friend/best {:person/id 3}}} ``` -------------------------------- ### Pull Entity Data with EQL in Pyramid (Clojure) Source: https://github.com/lilactown/pyramid/blob/main/docs/GUIDE.md Shows how to retrieve specific information about an entity using EQL (Entity Query Language) in Pyramid. It illustrates basic entity pulling and how to resolve nested references by extending the EQL query. ```clojure (p/pull animorphs-3 [[:person/id 1]]) ;; => {[:person/id 1] ;; {:person/id 1, :person/name "Marco", :friend/best #:person{:id 3}}} ``` ```clojure (p/pull animorphs-3 [{[:person/id 1] [:person/name {:friend/best [:person/name]}]}]) ;; => {[:person/id 1] {:person/name "Marco", :friend/best #:person{:name "Jake"}}} ``` -------------------------------- ### Recursive Pull Query in Pyramid Source: https://github.com/lilactown/pyramid/blob/main/docs/GUIDE.md Shows an example of a recursive pull query in Pyramid, utilizing `...` to traverse nested data structures. This allows for querying deeply nested or cyclic relationships within the database. ```clojure (def query '[{[:person/id 0] [:person/id :person/name {:friend/list ...}]}]) (= (-> (p/pull animorphs-3 query) (get [:person/id 0])) data) ;; => true ``` -------------------------------- ### Add Nested Data to Pyramid DB Source: https://github.com/lilactown/pyramid/blob/main/docs/GUIDE.md Illustrates using the `p/add` function to normalize and incorporate potentially nested data into an existing Pyramid database. `p/add` returns a new immutable database with the updated information. ```clojure ;; Marco and Jake are each others best friend (def animorphs-2 (p/add animorphs {:person/id 1 :friend/best {:person/id 3 :friend/best {:person/id 1}}})) ;; => {:person/id {0 {:person/id 0 ;; :person/name "Rachel" ;; :friend/list [[:person/id 1] ;; [:person/id 2] ;; [:person/id 3] ;; [:person/id 4] ;; [:person/id 5]]} ;; 1 {:person/id 1 ;; :person/name "Marco" ;; :friend/best [:person/id 3]} ;; 2 {:person/id 2 :person/name "Cassie"} ;; 3 {:person/id 3 ;; :person/name "Jake" ;; :friend/best [:person/id 1]} ;; 4 {:person/id 4 :person/name "Tobias"} ;; 5 {:person/id 5 :person/name "Ax"}}} ``` -------------------------------- ### Perform Recursive Queries in Clojure Source: https://context7.com/lilactown/pyramid/llms.txt Supports both bounded and infinite recursion for traversing tree/graph structures. This example shows how to perform a bounded recursion to a specific depth and an infinite recursion to traverse an entire file tree. ```clojure (require '[pyramid.core :as p]) (def file-tree {:entries {:entry/id "root" :entry/folders [{:entry/id "docs" :entry/folders [{:entry/id "api"} {:entry/id "guides"}]} {:entry/id "src" :entry/folders [{:entry/id "core"}]}]}}) (def db (p/db [file-tree])) ;; Bounded recursion (depth 2) (p/pull db '[{:entries [:entry/id {:entry/folders 2}]}]) ;; => {:entries {:entry/id "root" ;; :entry/folders [{:entry/id "docs" ;; :entry/folders [{:entry/id "api"} ;; {:entry/id "guides"}]} ;; {:entry/id "src" ;; :entry/folders [{:entry/id "core"}]}]}} ;; Infinite recursion (traverse entire tree) (p/pull db '[{:entries [:entry/id {:entry/folders ...}]}]) ;; Returns the complete nested structure ``` -------------------------------- ### Add Non-Entity Maps to Pyramid DB Source: https://github.com/lilactown/pyramid/blob/main/docs/GUIDE.md Shows how to use `p/add` to merge arbitrary maps into the database, which normalizes and references nested entities. This is useful for creating additional indexes, such as species information. ```clojure (def animorphs-3 (p/add animorphs-2 {:species {:andalites [{:person/id 5 :person/species "andalite"}]}})) ;; => {:person/id {,,, ;; 5 {:person/id 5 ;; :person/name "Ax" ;; :person/species "andalite"} ;; :species {:andalites [[:person/id 5]]}} ``` -------------------------------- ### Lookup Reference Example in Clojure Source: https://github.com/lilactown/pyramid/blob/main/README.md A lookup reference is a 2-element Clojure vector used as a pointer to a domain entity. It consists of a keyword and a value, enabling joins in query results. The `pyramid.core/pull` function utilizes these references. ```clojure ```clojure [:person/id 1234] ``` ``` -------------------------------- ### Implement Visitor Pattern in Clojure Source: https://context7.com/lilactown/pyramid/llms.txt Attach transformation functions to queries using metadata. Visitors receive the database and selection, enabling data transformation during query execution. This example demonstrates a simple visitor for creating a full name and a nested visitor for formatting key-value pairs. ```clojure (require '[pyramid.core :as p]) (def data {:people [{:given-name "Bob" :surname "Smith" :age 29} {:given-name "Alice" :surname "Meyer" :age 43}]}) ;; Visitor function transforms each person map to a full name string (defn fullname [_db {:keys [given-name surname]}] (str given-name " " surname)) ;; Attach visitor via metadata (def query [{:people ^{:visitor fullname} [:given-name :surname]}]) (p/pull data query) ;; => {:people ["Bob Smith" "Alice Meyer"]} ;; Nested visitors for complex transformations (defn format-entry [_db {:keys [name value]}] (str name ": " value)) (def nested-query [{:items ^{:visitor format-entry} [:name :value]}]) (p/pull {:items [{:name "Width" :value 100} {:name "Height" :value 200}]} nested-query) ;; => {:items ["Width: 100" "Height: 200"]} ``` -------------------------------- ### Delete Entities with `delete` in Clojure Source: https://context7.com/lilactown/pyramid/llms.txt Removes an entity and all references to it throughout the database. This example shows how to delete a person entity by their ID and demonstrates that references to the deleted entity are also removed. ```clojure (require '[pyramid.core :as p]) (def db (p/db [{:people/all [{:person/id 0 :person/name "Alice" :best-friend {:person/id 1}} {:person/id 1 :person/name "Bob"}]}])) ;; Delete person with id 1 (def db2 (p/delete db [:person/id 1])) ;; => {:people/all [[:person/id 0]] ;; :person/id {0 {:person/id 0 ;; :person/name "Alice" ;; :person/favorites {:favorite/ice-cream "vanilla"}}}} ;; Note: Reference to [:person/id 1] is removed from best-friend ``` -------------------------------- ### Replace Entity in Pyramid (Clojure) Source: https://github.com/lilactown/pyramid/blob/main/docs/GUIDE.md Demonstrates how to replace an existing entity in the Pyramid database. This involves dissociating the old entity data and then adding the new data for the same entity ID. It ensures that all previous data associated with the entity is overwritten. ```clojure (-> (p/db [{:person/id 0 :foo "bar"}]) (update :person/id dissoc 0) (p/add {:person/id 0 :bar "baz"})) ;; => {:person/id {0 {:person/id 0 :bar "baz"}}} ``` -------------------------------- ### Perform Union Queries in Clojure Source: https://context7.com/lilactown/pyramid/llms.txt Union queries select different properties based on entity type, useful for heterogeneous collections like chat entries with messages, photos, and audio. This example demonstrates how to query different fields for message, audio, and photo entries within a chat. ```clojure (require '[pyramid.core :as p]) (def chat-data {:chat/entries [{:message/id 0 :message/text "Hello" :chat.entry/timestamp "1234"} {:audio/id 0 :audio/url "audio://file.mp3" :audio/duration 120 :chat.entry/timestamp "1235"} {:photo/id 0 :photo/url "photo://img.jpg" :photo/width 800 :photo/height 600 :chat.entry/timestamp "1236"}]}) (def db (p/db [chat-data])) ;; Union query selects appropriate fields per entity type (def query [{:chat/entries {:message/id [:message/id :message/text :chat.entry/timestamp] :audio/id [:audio/id :audio/url :audio/duration :chat.entry/timestamp] :photo/id [:photo/id :photo/url :photo/width :photo/height :chat.entry/timestamp]}}]) (p/pull db query) ;; => {:chat/entries [{:message/id 0 :message/text "Hello" :chat.entry/timestamp "1234"} ;; {:audio/id 0 :audio/url "audio://file.mp3" :audio/duration 120 ;; :chat.entry/timestamp "1235"} ;; {:photo/id 0 :photo/url "photo://img.jpg" :photo/width 800 ;; :photo/height 600 :chat.entry/timestamp "1236"}]} ``` -------------------------------- ### Perform Nested Pull Query in Pyramid Source: https://github.com/lilactown/pyramid/blob/main/docs/GUIDE.md Illustrates performing a nested pull query in Pyramid, joining on idents and keys within entities. The query resolves references to retrieve nested data like the names of friends. ```clojure (p/pull animorphs-3 [{[:person/id 1] [:person/name {:friend/best [:person/name]}]}]) ;; => {[:person/id 1] {:person/name "Marco" ;; :friend/best {:person/name "Jake"}}} ``` -------------------------------- ### Entity Map Example in Clojure Source: https://github.com/lilactown/pyramid/blob/main/README.md An entity map is a Clojure map containing information that uniquely identifies a domain entity. It typically includes an ID and other attributes. This structure is fundamental for data normalization within the Pyramid project. ```clojure ```clojure {:person/id 1234 :person/name "Bill" :person/age 67} ``` ``` -------------------------------- ### Experimental Datalog Queries with q in Clojure Source: https://context7.com/lilactown/pyramid/llms.txt The `pyramid.query` namespace offers experimental Datomic/DataScript-style datalog queries for developer inspection and troubleshooting. The `q` function allows executing datalog queries against a Pyramid database, facilitating complex data retrieval and analysis. ```clojure (require '[pyramid.core :as p] '[pyramid.query :refer [q]]) (def db (p/db [{:person/id 1 :person/name "Marco" :friend/best {:person/id 3}} {:person/id 3 :person/name "Jake" :friend/best {:person/id 1}} {:person/id 2 :person/name "Cassie"}])) ;; Find names of people with best friends and their best friends' names (q '[:find ?name ?best-friend :where [?e :friend/best ?bf] [?e :person/name ?name] [?bf :person/name ?best-friend]] db) ;; => (["Marco" "Jake"] ["Jake" "Marco"]) ;; Find all person IDs (q '[:find ?id :where [?e :person/id ?id]] db) ;; => ([1] [3] [2]) ``` -------------------------------- ### Transform Selected Data with Pyramid Visitors (Clojure) Source: https://github.com/lilactown/pyramid/blob/main/README.md Illustrates how to combine Pyramid's querying capabilities with the Visitor pattern for data transformation. By annotating queries with metadata, custom functions can be applied during a depth-first, post-order traversal to modify selected data. ```clojure (def data {:people [{:given-name "Bob" :surname "Smith" :age 29} {:given-name "Alice" :surname "Meyer" :age 43}] :items {}}) (defn fullname [_db {:keys [given-name surname] :as person}] (str given-name " " surname)) (def query [{:people ^{:visitor fullname} [:given-name :surname]}]) (pyramid.core/pull data query) ;; => {:people ["Bob Smith" "Alice Meyer"]} ``` -------------------------------- ### Query Graph Data with `pull` and EQL in Clojure Source: https://context7.com/lilactown/pyramid/llms.txt Executes EQL (EDN Query Language) queries against a Pyramid database to select and traverse data. It supports property selection, joins, ident lookups, union queries, recursion, and visitor transformations for flexible data retrieval. ```clojure (require '[pyramid.core :as p]) (def data {:people/all [{:person/id 0 :person/name "Alice" :person/age 25 :best-friend {:person/id 1} :person/favorites {:favorite/color "blue"}} {:person/id 1 :person/name "Bob" :person/age 23}]}) (def db (p/db [data])) ;; Simple property selection (p/pull db [:people/all]) ;; => {:people/all [{:person/id 0} {:person/id 1}]} ;; Join with property selection (p/pull db [{:people/all [:person/name :person/id]}]) ;; => {:people/all [{:person/name "Alice" :person/id 0} ;; {:person/name "Bob" :person/id 1}]} ;; Nested joins with reference resolution (p/pull db [{:people/all [:person/name {:best-friend [:person/name]}]}]) ;; => {:people/all [{:person/name "Alice" :best-friend {:person/name "Bob"}} ;; {:person/name "Bob"}]} ;; Ident lookup (direct entity access) (p/pull db [[:person/id 1]]) ;; => {[:person/id 1] {:person/id 1 :person/name "Bob" :person/age 23}} ;; Join on ident (p/pull db [{[:person/id 0] [:person/name :person/favorites]}]) ;; => {[:person/id 0] {:person/name "Alice" ;; :person/favorites {:favorite/color "blue"}}} ``` -------------------------------- ### Create Normalized Database with `db` in Clojure Source: https://context7.com/lilactown/pyramid/llms.txt Creates a normalized database from a collection of entities identified by keys ending in `/id`. Nested data is automatically flattened into a tabular structure with lookup references. This function is essential for initializing the Pyramid database. ```clojure (require '[pyramid.core :as p]) ;; Create a database from nested entity data (def data {:person/id 0 :person/name "Rachel" :friend/list [{:person/id 1 :person/name "Marco"} {:person/id 2 :person/name "Cassie"} {:person/id 3 :person/name "Jake"}]}) (def animorphs (p/db [data])) ;; => {:person/id {0 {:person/id 0 ;; :person/name "Rachel" ;; :friend/list [[:person/id 1] ;; [:person/id 2] ;; [:person/id 3]]} ;; 1 {:person/id 1 :person/name "Marco"} ;; 2 {:person/id 2 :person/name "Cassie"} ;; 3 {:person/id 3 :person/name "Jake"}}} ;; Direct access using get-in (get-in animorphs [:person/id 1]) ;; => {:person/id 1 :person/name "Marco"} ``` -------------------------------- ### Extending with IPullable Protocol in Clojure Source: https://context7.com/lilactown/pyramid/llms.txt The `IPullable` protocol allows extending Pyramid to work with custom data stores for entity resolution. By implementing the `resolve-ref` function, developers can integrate Pyramid with various backends like Datomic, DataScript, or SQLite, enabling Pyramid to manage data beyond in-memory storage. ```clojure (require '[pyramid.pull :as pull]) ;; IPullable protocol defines resolve-ref for looking up entities ;; Default implementation uses get-in on maps: (pull/resolve-ref {:person/id {1 {:person/id 1 :name "Alice"}}} [:person/id 1]) ;; => {:person/id 1 :name "Alice"} ;; Extend to custom stores (e.g., Datomic, DataScript, SQLite) ;; by implementing (resolve-ref [store lookup-ref]) ``` -------------------------------- ### Select Data from Nested Structures with Pyramid (Clojure) Source: https://github.com/lilactown/pyramid/blob/main/README.md Demonstrates how to use Pyramid's `pull` function to select specific data fields from nested Clojure data structures based on a defined query. This is analogous to a supercharged `select-keys` operation. ```clojure (def data {:people [{:given-name "Bob" :surname "Smith" :age 29} {:given-name "Alice" :surname "Meyer" :age 43}] :items {}}) (def query [{:people [:given-name]}]) (pyramid.core/pull data query) ;; => {:people [{:given-name "Bob"} {:given-name "Alice"}]} ``` -------------------------------- ### Convert Data to Query with data->query in Clojure Source: https://context7.com/lilactown/pyramid/llms.txt The `data->query` function generates an EQL query that mirrors the structure of existing data. This is useful for understanding query syntax and for dynamically constructing queries based on data shapes. It handles various data structures, including nested maps and vectors of maps. ```clojure (require '[pyramid.core :as p]) (p/data->query {:a 42}) ;; => [:a] (p/data->query {:a {:b 42}}) ;; => [{:a [:b]}] (p/data->query {:a [{:b 42} {:c :d}]}) ;; => [{:a [:b :c]}] (p/data->query {[:person/id 42] {:name "Alice"}}) ;; => [{[:person/id 42] [:name]}] ``` -------------------------------- ### Add and Normalize Data with `add` in Clojure Source: https://context7.com/lilactown/pyramid/llms.txt Adds new data into an existing Pyramid database, normalizing entities and merging data for existing entities. Nested entities are extracted and referenced. It can also create custom indexes for non-entity data. ```clojure (require '[pyramid.core :as p]) ;; Start with an empty db and add entities (def db1 (p/add {} {:person/id 0 :person/name "Alice"})) ;; => {:person/id {0 {:person/id 0 :person/name "Alice"}}} ;; Add more entities including nested references (def db2 (p/add db1 {:person/id 1 :person/name "Bob" :best-friend {:person/id 0}})) ;; => {:person/id {0 {:person/id 0 :person/name "Alice"} ;; 1 {:person/id 1 ;; :person/name "Bob" ;; :best-friend [:person/id 0]}}} ;; Merge data about existing entities (def db3 (p/add db2 {:person/id 0 :person/age 25})) ;; => {:person/id {0 {:person/id 0 :person/name "Alice" :person/age 25} ;; 1 {:person/id 1 :person/name "Bob" :best-friend [:person/id 0]}}} ;; Add non-entity data (creates custom indexes) (def db4 (p/add db3 {:species {:humans [[:person/id 0] [:person/id 1]]}})) ;; => {:person/id {...} ;; :species {:humans [[:person/id 0] [:person/id 1]]}} ``` -------------------------------- ### Report Functions: add-report and pull-report in Clojure Source: https://context7.com/lilactown/pyramid/llms.txt These functions retrieve metadata about entities affected by add/pull operations. `add-report` returns the database, added entities, and created indices. `pull-report` returns the queried data and visited entities. They are essential for understanding data changes and dependencies within the Pyramid data structure. ```clojure (require '[pyramid.core :as p]) ;; add-report returns db, entities added, and indices created (p/add-report {} {:me {:person/id 0 :person/name "Alice" :best-friend {:person/id 1 :person/name "Bob"}}}) ;; => {:db {:person/id {0 {:person/id 0 :person/name "Alice" ;; :best-friend [:person/id 1]} ;; 1 {:person/id 1 :person/name "Bob"}}} ;; :me [:person/id 0]} ;; :entities #{[:person/id 0] [:person/id 1]} ;; :indices #{:me}} ;; pull-report returns data and entities visited (def db (p/db [{:people/all [{:person/id 0 :person/name "Alice"} {:person/id 1 :person/name "Bob"}]}])) (p/pull-report db [{:people/all [:person/name]}]) ;; => {:data {:people/all [{:person/name "Alice"} {:person/name "Bob"}]} ;; :entities #{[:person/id 0] [:person/id 1]} ;; :indices #{:people/all}} ``` -------------------------------- ### Custom Ident Functions for Entity Identification in Clojure Source: https://context7.com/lilactown/pyramid/llms.txt Pyramid allows defining custom entity identification strategies using `pyramid.ident` functions. This enables identification based on keys other than the default ID, local schema definitions via metadata, or complex custom logic involving entity attributes like type and ID. ```clojure (require '[pyramid.core :as p] '[pyramid.ident :as ident]) ;; Use a non-id key for identification (p/db [{:color "red" :hex "#ff0000"}] (ident/by-keys :color)) ;; => {:color {"red" {:color "red" :hex "#ff0000"}}} ;; Local schema via metadata (p/db [^{:db/ident :color} {:color "red" :hex "#ff0000"}]) ;; => {:color {"red" {:color "red" :hex "#ff0000"}}} ;; Complex custom identification function (def identify-by-type-id (fn [entity] (let [{:keys [type id]} entity] (when (and type id) [(keyword type "id") id])))) (p/db [{:type "person" :id "123" :name "Alice"} {:type "item" :id "456" :name "Widget"}] identify-by-type-id) ;; => {:person/id {"123" {:type "person" :id "123" :name "Alice"}} ;; :item/id {"456" {:type "item" :id "456" :name "Widget"}}} ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.