Created
May 9, 2012 15:22
-
-
Save stuarthalloway/2645453 to your computer and use it in GitHub Desktop.
Datomic queries against Clojure collections
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; Datomic example code | |
(use '[datomic.api :only (db q) :as d]) | |
;; ?answer binds a scalar | |
(q '[:find ?answer :in ?answer] | |
42) | |
;; of course you can bind more than one of anything | |
(q '[:find ?last ?first :in ?last ?first] | |
"Doe" "John") | |
;; [?last ?first] binds a tuple | |
(q '[:find ?last ?first :in [?last ?first]] | |
["Doe" "John"]) | |
;; [?first ...] binds a collection | |
(q '[:find ?first | |
:in [?first ...]] | |
["John" "Jane" "Phineas"]) | |
;; [[?first ?last]] binds a relation | |
(q '[:find ?first | |
:in [[?first ?last]]] | |
[["John" "Doe"] | |
["Jane" "Doe"]]) | |
;; a database binding name starts with $ instead of ? | |
;; any relation with 4-tuples E/A/V/T can act as a database | |
;; so in Datomic, you can mock a database with a list of lists | |
(q '[:find ?first | |
:in $db | |
:where [$db _ :firstName ?first]] | |
[[1 :firstName "John"]]) | |
;; same as previous, but omit $db for single-database query | |
;; any relation with 4-tuples eavt can act as a database | |
(q '[:find ?first | |
:where [_ :firstName ?first]] | |
[[1 :firstName "John" 42] | |
[1 :lastName "Doe" 42]]) | |
;; simple in-memory join, two tuple bindings | |
(q '[:find ?first ?height | |
:in [?last ?first ?email] [?email ?height]] | |
["Doe" "John" "[email protected]"] | |
["[email protected]" 71]) | |
;; simple in-memory join, two relation bindings | |
;; see next example for a faster approach | |
(q '[:find ?first ?height | |
:in [[?last ?first ?email]] [[?email ?height]]] | |
[["Doe" "John" "[email protected]"] | |
["Doe" "Jane" "[email protected]"]] | |
[["[email protected]" 73] | |
["[email protected]" 71]]) | |
;; same as previous example, but with database expressions | |
;; runs faster than relation bindings (as of July 2012) | |
(q '[:find ?first ?height | |
:in $a $b | |
:where [$a ?last ?first ?email] | |
[$b ?email ?height]] | |
[["Doe" "John" "[email protected]"] | |
["Doe" "Jane" "[email protected]"]] | |
[["[email protected]" 73] | |
["[email protected]" 71]]) | |
;; simple in-memory join, two database bindings | |
(q '[:find ?first ?height | |
:in $db1 $db2 | |
:where [$db1 ?e1 :firstName ?first] | |
[$db1 ?e1 :email ?email] | |
[$db2 ?e2 :email ?email] | |
[$db2 ?e2 :height ?height]] | |
[[1 :firstName "John"] | |
[1 :email "[email protected]"] | |
[2 :firstName "Jane"] | |
[2 :email "[email protected]"]] | |
[[100 :email "[email protected]"] | |
[100 :height 73] | |
[101 :email "[email protected]"] | |
[101 :height 71]]) | |
;; compare to http://stackoverflow.com/questions/3717939/iterating-and-processing-an-arraylist | |
(q '[:find ?car ?speed | |
:in [[?car ?speed]] | |
:where [(> ?speed 100)]] | |
[["Stock" 225] | |
["Spud" 80] | |
["Rocket" 400] | |
["Stock" 225] | |
["Clunker" 40]]) | |
;; compare to http://stackoverflow.com/questions/109383/how-to-sort-a-mapkey-value-on-the-values-in-java | |
(->> (q '[:find ?k ?v | |
:in [[?k ?v] ...]] | |
{:D 67.3 :A 99.5 :B 67.4 :C 67.5}) | |
(sort-by second)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
if we use map-args with
d/q
, then the query would look like thisas we can see, the
dummy-db
and the:in $
goes hand in hand, so we could write a function, which just adds those to queries.if the query would be in map format, then such function would be easier to implement:
then we can write a function, which injects the
dummy-db
and doctors the:in
clause: