-
-
Save clifford/2725556 to your computer and use it in GitHub Desktop.
Using database functions in Datomic transactions and annotating transaction history
This file contains hidden or 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
(use '[datomic.api :only [q db] :as d]) | |
(def uri "datomic:mem://accounts") | |
;; create database | |
(d/create-database uri) | |
;; connect to database | |
(def conn (d/connect uri)) | |
;; parse schema dtm file | |
(def schema-tx (read-string (slurp "db/schema.dtm"))) | |
;; submit schema transaction | |
@(d/transact conn schema-tx) | |
;; parse seed data dtm file | |
(def data-tx (read-string (slurp "db/accounts.dtm"))) | |
;; submit seed data transaction | |
@(d/transact conn data-tx) | |
(defn accounts [] | |
(d/q '[:find ?c ?n ?b ?count :where [?c :account/name ?n] [?c :account/balance ?b] [?c :account/transaction-count ?count]] (db conn))) | |
(defn history | |
([] (q '[:find ?tx ?f ?t ?a ?n ?when :in $ :where [?from :account/name ?f] [?to :account/name ?t] [?tx :ot/from ?from] [?tx :ot/to ?to] [?tx :ot/amount ?a] [?tx :ot/note ?n] [?tx :db/txInstant ?when]] (db conn))) | |
([acct] (q '[:find ?tx ?f ?t ?a ?n ?when :in $ ?e :where [?from :account/name ?f] [?to :account/name ?t] [?tx :ot/from ?from] [?tx :ot/to ?to] [?tx :ot/amount ?a] [?tx :ot/note ?n] [?tx :db/txInstant ?when] [?e :account/transactions ?tx]] (db conn) acct) )) | |
(defn transfer [ from to amount note] | |
(let [txid (datomic.api/tempid :db.part/tx)] | |
(d/transact conn [[:transfer from to amount] | |
[:db/add from :account/transactions txid] | |
[:db/add to :account/transactions txid] | |
[:inc from :account/transaction-count 1] | |
[:inc to :account/transaction-count 1] | |
{:db/id txid, :ot/note note :ot/from from :ot/to to :ot/amount amount}]))) | |
(defn credit [ to amount ] | |
(d/transact conn [[:credit to amount]])) | |
(def issuer (first (first (q '[:find ?e :where [?e :account/name "issuer"]] (db conn))))) | |
(def bob (first (first (q '[:find ?e :where [?e :account/name "bob"]] (db conn))))) | |
(def alice (first (first (q '[:find ?e :where [?e :account/name "alice"]] (db conn))))) | |
(prn (accounts)) | |
(transfer issuer alice 77M "Issuance to Alice") | |
(transfer issuer bob 23M "Issuance to Bob") | |
(transfer alice bob 7M "Tomatoes") | |
(println "History") | |
(prn (history)) | |
;; #<HashSet [[13194139534319 "issuer" "alice" 77M "Issuance to Alice" #inst "2012-05-08T14:35:25.252-00:00"], | |
;; [13194139534320 "issuer" "bob" 23M "Issuance to Bob" #inst "2012-05-08T14:35:25.256-00:00"], | |
;; [13194139534321 "alice" "bob" 7M "Tomatoes" #inst "2012-05-08T14:35:25.262-00:00"]]> | |
(println "Accounts") | |
(prn (accounts)) | |
;; #<HashSet [[17592186045421 "issuer" -100M 2], [17592186045423 "alice" 70M 2], [17592186045422 "bob" 30M 2]]> |
This file contains hidden or 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
[ | |
{:db/id #db/id[:db.part/user -1000001], :account/name "issuer", :account/balance 0M, :account/max-balance 0M, :account/min-balance -1000M} | |
{:db/id #db/id[:db.part/user -1000002], :account/name "bob", :account/balance 0M, :account/max-balance 100M, :account/min-balance 0M} | |
{:db/id #db/id[:db.part/user -1000003], :account/name "alice", :account/balance 0M, :account/max-balance 100M, :account/min-balance 0M} | |
] |
This file contains hidden or 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
[ | |
;; accounts | |
{ :db/id #db/id[:db.part/db] | |
:db/ident :account/name | |
:db/valueType :db.type/string | |
:db/cardinality :db.cardinality/one | |
:db/fulltext true | |
:db/unique :db.unique/value | |
:db/doc "An account's name" | |
:db.install/_attribute :db.part/db} | |
{ :db/id #db/id[:db.part/db] | |
:db/ident :account/balance | |
:db/cardinality :db.cardinality/one | |
:db/valueType :db.type/bigdec | |
:db/doc "The accounts balance" | |
:db.install/_attribute :db.part/db} | |
{ :db/id #db/id[:db.part/db] | |
:db/ident :account/transaction-count | |
:db/cardinality :db.cardinality/one | |
:db/valueType :db.type/long | |
:db/doc "The amount of transactions made with account" | |
:db.install/_attribute :db.part/db} | |
{ :db/id #db/id[:db.part/db] | |
:db/ident :account/max-balance | |
:db/cardinality :db.cardinality/one | |
:db/valueType :db.type/bigdec | |
:db/doc "The accounts maximum balance" | |
:db.install/_attribute :db.part/db} | |
{ :db/id #db/id[:db.part/db] | |
:db/ident :account/min-balance | |
:db/cardinality :db.cardinality/one | |
:db/valueType :db.type/bigdec | |
:db/doc "The accounts maximum balance" | |
:db.install/_attribute :db.part/db} | |
{ :db/id #db/id[:db.part/db] | |
:db/ident :account/transactions | |
:db/cardinality :db.cardinality/many | |
:db/valueType :db.type/ref | |
:db/doc "The accounts transactions" | |
:db.install/_attribute :db.part/db} | |
{ :db/id #db/id[:db.part/db] | |
:db/ident :ot/note | |
:db/valueType :db.type/string | |
:db/cardinality :db.cardinality/one | |
:db/doc "An note about what was transfered" | |
:db.install/_attribute :db.part/db} | |
{ :db/id #db/id[:db.part/db] | |
:db/ident :ot/amount | |
:db/valueType :db.type/bigdec | |
:db/cardinality :db.cardinality/one | |
:db/doc "Amount transacted" | |
:db.install/_attribute :db.part/db} | |
{ :db/id #db/id[:db.part/db] | |
:db/ident :ot/from | |
:db/valueType :db.type/ref | |
:db/cardinality :db.cardinality/one | |
:db/doc "Transferee" | |
:db.install/_attribute :db.part/db} | |
{ :db/id #db/id[:db.part/db] | |
:db/ident :ot/to | |
:db/valueType :db.type/ref | |
:db/cardinality :db.cardinality/one | |
:db/doc "Recipient" | |
:db.install/_attribute :db.part/db} | |
{ :db/id #db/id [:db.part/user] | |
:db/ident :inc | |
:db/fn #db/fn { :lang "clojure" | |
:params [db id attr amount] | |
:code "(let [ e (datomic.api/entity db id) | |
orig (attr e 0) ] | |
[[:db/add id attr (+ orig amount) ]])"}} | |
{ :db/id #db/id [:db.part/user] | |
:db/ident :credit | |
:db/fn #db/fn { :lang "clojure" | |
:params [db id amount] | |
:code "(let [ e (datomic.api/entity db id) | |
min-balance (:account/min-balance e 0) | |
balance (+ (:account/balance e 0) amount) ] | |
(if (>= balance min-balance) | |
[[:db/add id :account/balance balance ]] | |
(throw (Exception. \"Insufficient funds\"))))" }} | |
{ :db/id #db/id [:db.part/user] | |
:db/ident :transfer | |
:db/fn #db/fn { :lang "clojure" | |
:params [db from to amount] | |
:code "[[:credit from (- amount)] | |
[:credit to amount]]"}} | |
] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment