-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdatascript.clj
119 lines (98 loc) · 3.88 KB
/
datascript.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
; # Setup Datascript
; move some to deps.edn?
(require '[clojure.tools.deps.alpha.repl :refer [add-libs]])
^{::clerk/visibility {:result :hide}}
(add-libs '{datascript/datascript {:mvn/version "1.4.2"}})
^{::clerk/visibility {:result :hide}}
(require '[datascript.core :as d])
; # Create the empty database
; ## Schema
; need more info on [schema usage](https://github.com/kristianmandrup/datascript-tutorial/blob/master/create_schema.md)
;;
;; Unlike XTDB, in Datascript, we quire some sechema setup. This identifies attributes like `:issuer` as references to other entities.
;; In RDF terms that means another subject, in OO terms it means another object.
^{::clerk/visibility {:result :hide}}
(def schema {:issuer {:db/valueType :db.type/ref :db/cardinality :db.cardinality/one}
:asset {:db/valueType :db.type/ref :db/cardinality :db.cardinality/one}
:holdings {:db/valueType :db.type/ref :db/cardinality :db.cardinality/many}
;; TODO: find differences between :db.unique/identity and db.unique/value
:ticker {:db/unique :db.unique/identity}})
^{::clerk/visibility {:result :hide}}
(def conn (d/create-conn schema))
;; from xtdb nextjournal notebook
(d/transact! conn
[ ;; add 3 companies
{:db/id ":company/t1", :name "IBM"}
{:db/id ":company/t2", :name "JP Morgan"}
{:db/id -100, :name "Ford"}
;; add 3 assets based on those companies
{:db/id ":security/t1",
:issuer ":company/t1" :ticker "IBM",
:type :Equity}
{:db/id ":security/t2",
:issuer ":company/t2" :ticker "JPM",
:type :Equity}
{:db/id ":security/t3",
:issuer -100 :ticker "F",
:type :Equity}
;; add 2 positions (portfolio unspecified)
{:db/id ":pm/p1", :asset ":security/t1", :quantity 100}
{:db/id ":pm/p2", :asset ":security/t2", :quantity 200}
;; add portfolio (with those 2 positions)
{:db/id ":p/p1",
:holdings [":pm/p1" ":pm/p2"],
:name "My Trading Portfolio"}])
;; use pull syntax to get security info and issuer name
(d/q '[:find (pull ?security ["*" {:issuer [:name]}])
:where [?security :ticker "F"]]
@conn)
(d/q '[:find (pull ?h [:quantity {:asset [:ticker {:issuer [:name]}]}])
:where [?port :name "My Trading Portfolio"]
[?port :holdings ?h]]
@conn)
;; same info flattened
(d/q '[:find ?t ?q ?n
:where [?port :name "My Trading Portfolio"]
[?port :holdings ?h]
[?h :quantity ?q]
[?h :asset ?a]
[?a :ticker ?t]
[?a :issuer ?c]
[?c :name ?n]]
@conn)
;; now transpose so we can use it for a dataset
(->> (d/q '[:find ?t ?q ?n
:where [?port :name "My Trading Portfolio"]
[?port :holdings ?h]
[?h :quantity ?q]
[?h :asset ?a]
[?a :ticker ?t]
[?a :issuer ?c]
[?c :name ?n]]
@conn)
(apply map vector)
(map vector [:ticker :quantity :name])
(into {}))
;; ## Entities
(def security (d/entity @conn [:ticker "JPM"]))
(-> security :issuer :name)
security
; # Add Pricing
(d/db-with @conn
[{:db/id [:ticker "JPM"] :price 121.5}])
(-> (d/entity @conn [:ticker "JPM"]) :price)
(def db-1
(d/db-with @conn
[{:db/id [:ticker "JPM"] :price 121.5}
{:db/id [:ticker "IBM"] :price 132.5}
{:db/id [:ticker "F"] :price 21.5}]))
(def db-2
(d/db-with @conn
[{:db/id [:ticker "JPM"] :price 125.8}]))
(->> [:ticker "JPM"] (d/entity db-1) :price)
(->> [:ticker "JPM"] (d/entity db-2) :price)
(def db-3
(:db-after
(d/with @conn
[{:db/id [:ticker "JPM"] :price 135.1}])))
(->> (d/entity db-3 [:ticker "IBM"]) :price)