-
Notifications
You must be signed in to change notification settings - Fork 2
Tutorial 01 Basic Transact Query
Alice has been browsing Corestore and decides to buy a PhoneX 12. She adds a USB-C cable to her order while checking out, then thinks better of it and removes it before confirming. This tutorial walks through asserting and retracting facts, and querying the results.
Every piece of data in Minigraf is an EAV triple: an entity, an attribute, and a value. The entity is a keyword that names the thing, the attribute is a namespaced keyword describing the property, and the value is a string, number, boolean, or a reference to another entity.
; A fact is a triple: [entity attribute value]
[:laptop-pro :product/name "LaptopPro 15"]
[:laptop-pro :product/price 1299]
[:laptop-pro :product/category :cat-laptops] ; value is a reference to another entity
There are no schemas or table definitions — facts can be added freely, and entities can carry any combination of attributes.
With the base data loaded, query all products and their prices:
; List all products with their prices
(query [:find ?name ?price
:where [?p :product/name ?name]
[?p :product/price ?price]])
Expected output (8 rows, order may vary):
?name ?price
----------------------------------------
"BudgetBook 14" 699
"LaptopPro 15" 1299
"PhoneX 12" 799
"USB-C Cable 2m" 19
"PhoneX 11" 599
"NoiseCancel Pro" 249
"ClearView 27" Monitor" 449
"Compact Keyboard" 89
Variables start with ? and act as placeholders. The engine finds every fact matching each clause and unifies the variables across clauses. Here, ?p appears in both clauses, so only entities that have both a :product/name and a :product/price will be included. ?name and ?price are projected into the result.
; tx 4: Alice's first order
(transact [
[:alice-order-1 :order/customer :alice]
[:alice-order-1 :order/status :placed]
[:alice-order-1-item-1 :order-item/order :alice-order-1]
[:alice-order-1-item-1 :order-item/product :phone-x]
[:alice-order-1-item-1 :order-item/qty 1]
[:alice-order-1-item-1 :order-item/price 799]
[:alice-order-1-item-2 :order-item/order :alice-order-1]
[:alice-order-1-item-2 :order-item/product :usb-cable]
[:alice-order-1-item-2 :order-item/qty 1]
[:alice-order-1-item-2 :order-item/price 19]
])
All ten facts are asserted in a single atomic transaction. The order is represented as an entity (:alice-order-1) with two line-item entities (:alice-order-1-item-1, :alice-order-1-item-2). Each item references the order entity and the product entity it relates to.
(query [:find ?product-name ?qty ?price
:where [?item :order-item/order :alice-order-1]
[?item :order-item/product ?p]
[?p :product/name ?product-name]
[?item :order-item/qty ?qty]
[?item :order-item/price ?price]])
Expected:
"PhoneX 12" 1 799
"USB-C Cable 2m" 1 19
The variable ?item appears in multiple clauses. The engine constrains all those clauses to the same entity — only rows where the same ?item satisfies every clause are included. This is how multi-clause joins work: shared variables act as join keys without any explicit JOIN syntax.
; tx 5: Alice cancels the USB cable
(retract [
[:alice-order-1-item-2 :order-item/order :alice-order-1]
[:alice-order-1-item-2 :order-item/product :usb-cable]
[:alice-order-1-item-2 :order-item/qty 1]
[:alice-order-1-item-2 :order-item/price 19]
])
retract marks each listed fact as asserted = false. The original facts are not deleted — they remain in history and are visible via time-travel queries (covered in Section 2: :as-of and Section 3). The current view of the database shows only net-asserted facts, so the cable line item disappears from queries.
Re-run the same query from the previous section:
(query [:find ?product-name ?qty ?price
:where [?item :order-item/order :alice-order-1]
[?item :order-item/product ?p]
[?p :product/name ?product-name]
[?item :order-item/qty ?qty]
[?item :order-item/price ?price]])
Expected:
"PhoneX 12" 1 799
The USB cable no longer appears because its facts are retracted and excluded from the current view.
(query [:find ?customer-name ?status
:where [?order :order/customer ?customer]
[?customer :customer/name ?customer-name]
[?order :order/status ?status]])
Expected:
"Alice" :placed
This query joins across three entity types: an order, the customer it references, and the customer's name attribute.
- A fact is an EAV triple
[entity attribute value] -
transactasserts facts atomically;retractmarks them as not-asserted -
Variables (
?name) unify across clauses — the same variable name means the same value - Multi-clause joins constrain results to matching combinations — no explicit join syntax needed
← Setup | → Section 2: :as-of