13. Molecule
Schema of attributes
eid :person/likes String value … …
E A V T Op
string
boolean
long
bigint
float
double
big dec
ref
instant (date)
uuid
uri
bytes
keyword (enum)
Types
{":db/ident" ":person/likes"
":db/valueType" ":db.type/string"}
14. Molecule
Schema of attributes
eid :person/likes String value … …
E A V T Op
one
many
Cardinality{":db/ident" ":person/likes"
":db/valueType" ":db.type/string"
":db/cardinality" ":db.cardinality/one"}
15. Molecule
Schema of attributes
eid :person/likes String value … …
E A V T Op
{":db/ident" ":person/likes"
":db/valueType" ":db.type/string"
":db/cardinality" ":db.cardinality/one"
":db/doc" "What a Person likes"} doc
unique/value
unique/identity
index
fulltext
isComponent
noHistory
Options
21. Molecule
fred :person/likes pizza tx4 (10:31) assert
Mutable
E A V T Op
Immutable facts
Id likes
fred pizza
… …
Person table
{ id: fred
likes: “pizza” }
Person document
22. Molecule
Id likes created
fred pizza 10:31
… … …
Person table E A V T Op
fred :person/likes pizza tx4 (10:31) assert
Create Assert
{ id: fred
likes: “pizza”
created: “10:31” }
Person document
23. Molecule
fred :person/likes pizza tx5 (12:45) retract
fred :person/likes pasta tx5 (12:45) assert
Id likes created updated
fred pasta 10:31 12:45
… … …
fred :person/likes pizza tx4 (10:31) assert
Update
Person table
Retract-Assert
Person document
{ id: fred
likes: pasta
created: “10:31”
updated: “12:45” }
E A V T Op
24. Molecule
fred :person/likes pasta tx6 (17:10) retract
fred :person/likes pizza tx5 (12:45) retract
fred :person/likes pasta tx5 (12:45) assert
Id likes created updated
fred NULL 10:31 17:10
… … …
Delete
Person table
Retract
E A V T Op
Person document
{ id: fred
likes: null
created: “10:31”
updated: “17:10” }
fred :person/likes pizza tx4 (10:31) assert
25. Molecule
101 :person/likes pizza tx4 (10:31) assert
101 :person/likes pizza tx5 (12:45) retract
101 :person/likes pasta tx5 (12:45) assert
101 :person/likes pasta tx6 (17:10) retract
Read
E A V T Op [:find ?v
:where
[101 :person/likes ?v]]
=> Nil (no current likes)
26. Molecule
101 :person/likes pizza tx4 (10:31) assert
101 :person/likes pizza tx5 (12:45) retract
101 :person/likes pasta tx5 (12:45) assert
101 :person/likes pasta tx6 (17:10) retract
asOf
E A V T Op [:find ?v
:in db.asOf(tx5)
:where
[101 :person/likes ?v]]
=> [pasta]
27. Molecule
101 :person/likes pizza tx4 (10:31) assert
101 :person/likes pizza tx5 (12:45) retract
101 :person/likes pasta tx5 (12:45) assert
101 :person/likes pasta tx6 (17:10) retract
History
E A V T Op [:find ?v ?t ?op
:in db.history
:where
[101 :person/likes ?v ?t ?op]]
=> [pizza tx4 assert ]
[pasta tx5 retract]
[pasta tx5 assert ]
[pasta tx6 retract]
28. Molecule
101 :person/likes pizza tx1 assert
102 :person/likes pasta tx2 assert
103 :person/likes sushi tx3 assert
104 :person/likes burger tx4 assert
Since
E A V T Op [:find ?v
:in db.since(tx2)
:where
[?e :person/likes ?v]]
=> [sushi burger]
(updated slide)
29. Molecule
101 :person/likes pizza tx4 (10:31) assert
101 :person/likes pizza tx5 (12:45) retract
101 :person/likes pasta tx5 (12:45) assert
101 :person/likes pasta tx6 (17:10) retract
With (the future!)
E A V T Op [:find ?v
:in db.with(testDataTx)
:where
[101 :person/likes ?v]]
=> [penne]
101 :person/likes penne tx7 assert
testDataTx = { id: 101
likes: “penne” }
As though we had created this fact
53. Molecule
Molecule DSL
Molecules
Your domain terms
Namespace "Person"
Attribute :person/name
Person1[String]
No need to implement
here - macro
implements!
Only the return type is
needed!
77. Molecule
Attributes
eid 104
:person/name Ben
:person/likes pizza
:person/age 5
eid 101
:person/name Fred
:person/likes pizza
:person/age 38
:site/cat customer
eid 103
:person/name Lisa
:person/age 7
• Mandatory ("attr")
• Fact exists
• Value is returned
• Tacet
• Optional"Person names, ages and likes"
78. Molecule
Attributes
eid 104
:person/name Ben
:person/likes pizza
:person/age 5
eid 101
:person/name Fred
:person/likes pizza
:person/age 38
:site/cat customer
eid 103
:person/name Lisa
:person/age 7
• Mandatory ("attr")
• Fact exists
• Value returned
• Tacet ("attr_")
• Fact exists
• Value not returned
• Optional
"Names and ages of Persons that like something"
79. Molecule
Attributes
eid 104
:person/name Ben
:person/likes pizza
:person/age 5
eid 101
:person/name Fred
:person/likes pizza
:person/age 38
:site/cat customer
eid 103
:person/name Lisa
:person/age 7
• Mandatory ("attr")
• Fact exists
• Value returned
• Tacet ("attr_")
• Fact exists
• Value not returned
• Optional ("attr$")
• Fact may exists
• Option[Value] returned
"Names, ages and possibly likes of Persons"
80. Molecule
Expressions
eid 104
:person/name Ben
:person/likes pizza
:person/age 5
eid 101
:person/name Fred
:person/likes pizza
:person/age 38
:site/cat customer
eid 103
:person/name Lisa
:person/age 7
• Equality
• Fulltext search
• Negation
• Null / Nil
• Comparison
• Aggregates
• Logical OR
"Names and likes of Persons that likes pizza"
81. Molecule
Expressions
• Equality + tacet
• Fulltext search
• Negation
• Null / Nil
• Comparison
• Aggregates
• Logical OR
eid 104
:person/name Ben
:person/likes pizza
:person/age 5
eid 101
:person/name Fred
:person/likes pizza
:person/age 38
:site/cat customer
eid 103
:person/name Lisa
:person/age 7
"Names of persons that like pizza"
82. Molecule
Expressions
eid 104
:person/name Ben
:person/likes pizza
:person/age 5
eid 101
:person/name Fred Ben
:person/likes pizza
:person/age 38
:site/cat customer
eid 103
:person/name Lisa
:person/age 7
• Equality
• Fulltext search
• Negation
• Null / Nil
• Comparison
• Aggregates
• Logical OR
84. Molecule
Expressions
eid 104
:person/name Ben
:person/likes pizza
:person/age 5
eid 101
:person/name Fred
:person/likes pizza
:person/age 38
:site/cat customer
eid 103
:person/name Lisa
:person/age 7
• Equality
• Fulltext search
• Negation
• Null / Nil
• Comparison
• Aggregates
• Logical OR
"Names of Persons that haven't stated what
they like"
:person/likes fact not asserted for Lisa
- or it has been retracted!
86. Molecule
Expressions
eid 104
:person/name Ben
:person/likes pizza
:person/age 5
eid 101
:person/name Fred
:person/likes pizza
:person/age 38
:site/cat customer
eid 103
:person/name Lisa
:person/age 7
• Equality
• Fulltext search
• Negation
• Null / Nil
• Comparison
• Aggregates
• Logical OR
"Minimum age of all persons"
"Count of all persons with an age asserted"
"Average age of persons (with age asserted)"
87. Molecule
Expressions
eid 104
:person/name Ben
:person/likes pizza
:person/age 5
eid 101
:person/name Fred
:person/likes pizza
:person/age 38
:site/cat customer
eid 103
:person/name Lisa
:person/age 7
• Equality
• Fulltext search
• Negation
• Null / Nil
• Comparison
• Aggregates
• Logical OR
"Names and ages of Persons that are 5, 6 or 7
years old"
110. Molecule
[:find ?v1 ?v2 ?v3 ?v4
:where
[?e :xlwk/liawj ?v1]
[?e :iauw/sokqx ?v2]
[?e :kzmm/wwpai ?v3]
[?e :ajdg/tybnq ?v4]
]
Attributes can have any name
Namespaces are not tables
Entity ids tie facts together
119. Molecule
• Create
• Save
• Insert
• 2-step insert
• Read
• Update
• Card-one
• Delete
CRUD
fred :person/likes pizza tx4 assert
fred :person/likes pizza tx5 retract
fred :person/likes pasta tx5 assert
E A V T Op
120. Molecule
• Create
• Save
• Insert
• 2-step insert
• Read
• Update
• Card-one
• Delete
CRUD
fred :person/likes pizza tx4 assert
fred :person/likes pizza tx5 retract
fred :person/likes pasta tx5 assert
fred :person/likes pasta tx6 retract
E A V T Op
141. Molecule
Magic
tx4
Tx data
e5 :person/name Fred tx4 assert
e5 :person/likes pizza tx4 assert
tx4 :db/txInstant 10:31 ...? assert
E A V T Op
Transaction is an entity!
(here with entity id tx4...)
142. Molecule
Tx data
e5 :person/name Fred tx4 assert
e5 :person/likes pizza tx4 assert
tx4 :db/txInstant date1 tx4 assert
E A V T Op
144. Molecule
Tx data
e5 :person/name Fred tx4 assert
e5 :person/likes pizza tx4 assert
tx4 :db/txInstant date1 tx4 assert
E A V T Op
145. Molecule
Tx data
e5 :person/name Fred tx4 assert
e5 :person/likes pizza tx4 assert
tx4 :db/txInstant date1 tx4 assert
E A V T Op
List(
(17592186045445L, :person/name, "Fred", 13194139534340L, true),
(17592186045445L, :person/likes, "pizza", 13194139534340L, true),
(13194139534340L, :db/txInstant, "Tue Apr 26 18:35:41 CEST 2017", 13194139534340L, true)
)
146. Molecule
Tx data
e5 :person/name Fred tx4 assert
e5 :person/likes pizza tx4 assert
tx4 :db/txInstant date1 tx4 assert
E A V T Op
List(
(17592186045445L, :person/name, "Fred", 13194139534340L, true),
(17592186045445L, :person/likes, "pizza", 13194139534340L, true),
(13194139534340L, :db/txInstant, "Tue Apr 26 18:35:41 CEST 2017", 13194139534340L, true)
)
Long clojure.keyword Object (various types) Long Boolean
147. Molecule
Tx data
e5 :person/name Fred tx4 assert
e5 :person/likes pizza tx4 assert
tx4 :db/txInstant date1 tx4 assert
E A V T Op
List(
(17592186045445L, 147L, "Fred", 13194139534340L, true),
(17592186045445L, 148L, "pizza", 13194139534340L, true),
(13194139534340L, 18L, "Tue Apr 26 18:35:41 CEST 2017", 13194139534340L, true)
)
Long Long Object (various types) Long Boolean
148. Molecule
Tx data
e5 :person/name Fred tx4 assert
e5 :person/likes pizza tx4 assert
tx4 :db/txInstant date1 tx4 assert
E A V T Op
In what transaction was
Freds name asserted?
149. Molecule
Tx data
e5 :person/name Fred tx4 assert
e5 :person/likes pizza tx4 assert
tx4 :db/txInstant date1 tx4 assert
E A V T Op
When was Freds name asserted?
150. Molecule
Tx meta data
e5 :person/name Fred tx4 assert
e5 :person/likes pizza tx4 assert
tx4 :db/txInstant date1 tx4 assert
tx4 ... ... tx4 assert
tx4 ... ... tx4 assert
E A V T Op
151. Molecule
Tx meta data
e5 :person/name Fred tx4 assert
e5 :person/likes pizza tx4 assert
tx4 :db/txInstant date1 tx4 assert
tx4 :audit/user Lisa tx4 assert
tx4 ... ... tx4 assert
E A V T Op
Who did it?
152. Molecule
Tx meta data
e5 :person/name Fred tx4 assert
e5 :person/likes pizza tx4 assert
tx4 :db/txInstant date1 tx4 assert
tx4 :audit/user Lisa tx4 assert
tx4 :audit/uc survey tx4 assert
E A V T Op
Who did it?
Why?
153. Molecule
Tx meta data
e5 :person/name Fred tx4 assert
e5 :person/likes pizza tx4 assert
tx4 :db/txInstant date1 tx4 assert
tx4 :audit/user Lisa tx4 assert
tx4 :audit/uc survey tx4 assert
E A V T Op
Who did it?
Why?
154. Molecule
Tx meta data
e5 :person/name Fred tx4 assert
e5 :person/likes pizza tx4 assert
tx4 :db/txInstant date1 tx4 assert
tx4 :audit/user Lisa tx4 assert
tx4 :audit/uc survey tx4 assert
E A V T Op
Who did it?
Why?
"Lisa added Fred as part of a survey"
155. Molecule
Tx meta data
e5 :person/name Fred tx4 assert
e5 :person/likes pizza tx4 assert
tx4 :db/txInstant date1 tx4 assert
tx4 :audit/user Lisa tx4 assert
tx4 :audit/uc survey tx4 assert
E A V T Op
When did they do it?
Who did it?
Why?
"Lisa added Fred as part of a survey
onTuesday the 26th of April"
156. Molecule
Tx meta data
e5 :person/name Fred tx4 assert
e5 :person/likes pizza tx4 assert
tx4 :db/txInstant date1 tx4 assert
tx4 :audit/user Lisa tx4 assert
tx4 :audit/uc survey tx4 assert
E A V T Op
When did they do it?
Who did it?
Why?
"Fred was surveyed"
157. Molecule
Tx meta data
e5 :person/name Fred tx4 assert
e5 :person/likes pizza tx4 assert
tx4 :db/txInstant date1 tx4 assert
tx4 :audit/user Lisa tx4 assert
tx4 :audit/uc survey tx4 assert
E A V T Op
When did they do it?
Who did it?
Why?
"Lisas surveyee liked pizza"
159. Molecule
asOf
fred :person/name Fred t1 assert
fred :person/likes pizza t1 assert
fred :person/likes pizza t2 retract
fred :person/likes pasta t2 assert
E A V T Op
160. Molecule
asOf
fred :person/name Fred t1 assert
fred :person/likes pizza t1 assert
fred :person/likes pizza t2 retract
fred :person/likes pasta t2 assert
E A V T Op
"What did Fred like before?"
161. Molecule
history
fred :person/name Fred t1 TRUE
fred :person/likes pizza t1 TRUE
fred :person/likes pizza t2 FALSE
fred :person/likes pasta t2 TRUE
E A V T Added
API changed from `.history.get` to `.getHistory`
All time filters now have the verb form `get<filter>`
This should avoid confusion with attribute names
162. Molecule
history
fred :person/name Fred t1 TRUE
fred :person/likes pizza t1 TRUE
fred :person/likes pizza t2 FALSE
fred :person/likes pasta t2 TRUE
E A V T Added
163. Molecule
history
E A/V T Op
Getting all generic data about the `like` attribute history:
Generic attributes tie to a single domain attribute
164. Molecule
history
E A V T Op
... or go fully generic and ask for any attribute history of an entity:
167. Molecule
history
"Who have disliked what and when?"
Multiple mandatory attributes not allowed in history queries.
It would be like unifying multiple timelines into one timeline
which is not useful.
171. Molecule
history + tx meta data
"Who changed what taste
during interviews with Peter?"
172. Molecule
history + tx meta data
"Who changed what taste
during interviews with Peter and when?"
"Who disliked pizza
during an interview and when?"
173. Molecule
history + tx meta data
Who changed what taste
during interviews with Peter and when?
Who disliked pizza
during an interview and when?
Who liked what and when?
Who got the info in what use case?
174. Molecule
since
101 :person/likes pizza tx1 TRUE
102 :person/likes pasta tx2 TRUE
103 :person/likes sushi tx3 TRUE
104 :person/likes burger tx4 TRUE
E A V T Added
(updated slide)
186. Molecule
Person
• id
• name
• born
‣ doThis()
‣ doThat()
Ctx 1
customer.doThis()
customer.buy()
Ctx 2
user.login()
Slow changing
Not so fast changing
Ctx 3
manager.add(p1)
Customer
‣ buy()
‣ complain()
User
‣ login()
‣ comment()
Manager
‣ add(person)
‣ getReport()
Faster changing
Runtime
187. Molecule
Person
• id
• name
• born
‣ doThis()
‣ doThat()
Ctx 1
customer.doThis()
customer.buy()
Ctx 2
user.login()
Slow changing
Not so fast changing
Ctx 3
manager.login()
manager.add(p1)
Customer
‣ buy()
‣ complain()
User
‣ login()
‣ comment()
Manager
‣ add(person)
‣ getReport()
Faster changing
Relatively faster changing
Runtime
188. Molecule
Person
• id
• name
• born
PersonService(p)
‣ p.doThis()
‣ p.doThat()
‣ p.ctx1a()
‣ p.ctx1b()
‣ p.ctx2a()
‣ etc...
Ctx 1
personService(p1).doThis()
personService(p2).ctx1a()
personService(p1).ctx1b()
Ctx 2
person2.ctx2a()
Fast changing RuntimeSlow changing
189. Molecule
Person
• id
• name
• born
PersonCmdCtx1(p)
‣ p.ctx1a()
‣ p.ctx1b()
Ctx 1
PersonCmdCtx1(p2).ctx1a()
PersonCmdCtx1(p1).ctx1b()
Ctx 2
PersonCmdCtx2.ctx2a()
PersonCmdCtx2(p)
‣ p.ctx2a()
Slow changing Fast changing Runtime
190. Molecule
Entity
• id
• attr1
• attr2
• etc...
Slow changing Fast changing
EntityConsumer(e)
‣ action1()
‣ action2()
‣ etc()
• Services
• Event source commands
• Ad hoc classes
• Etc..
191. Molecule
EntityConsumer(e)
‣ action1()
‣ action2()
‣ etc()
Person
• id
• name
• born
Customer
• status
User
• email
• passw
Manager
• clearance
• employees
Seldom changing
Often changing
Occassionally changing
And more subtypes...
Fast changing
192. Molecule
EntityConsumer(e)
‣ action1()
‣ action2()
‣ etc()
Person
• id
• born
• name
Customer
• status
User
• email
• passw
Manager
• clearance
• employees
Very seldom changing
Often changing
Occassionally changing
Never changing
And more subtypes...
Fast changing
198. Molecule
Molecules• Get data from the app process
• No need to cast raw data from
a db server to populate rigid
domain classes, only to pull the
data out again
• Get/set exactly the data you
need
• Always typed data
• Easy type-safe migrations
• Use your domain terms directly
• Absolute minium of ceremony
• Maximum runtime performance
• Time
• Fun!
PasswChange(eid, newPassw)
Get current User data:
Check stuff...
Save:
199. Molecule
• Get data from the app process
• No need to cast raw data from
a db server to populate rigid
domain classes, only to pull it out
again
• Get/set exactly the data you
need
• Always typed data
• Easy type-safe migrations
• Use your domain terms directly
• Absolute minium of ceremony
• Maximum runtime performance
• Time
• Fun!
Thank you!
Questions?