Fork me on GitHub
#xtdb
<
2022-04-03
>
Ivan Fedorov10:04:04

Heyy, any ready recipes for unique constraint transaction functions? Or how to use match for that? E.g. I have a user where I want both email and username to be unique

dvingo00:04:27

for the match version - I use this helper that I lifted from emccue:

(defn match-update-entity
  "Takes xtdb node, an xt/id and a map. Uses match to merge the new entity with the existing xtdb document atomically.
  Recurs until successful with no limit.

  shout out emccue:
  
  "
  [xtdb-node entity-id new-entity]
  (let [[[old-entity]] (seq (xt/q (xt/db xtdb-node)
                              '{:find  [(pull ?eid [*])]
                                :where [[?eid :xt/id id]]
                                :in    [id]}
                              entity-id))
        new-entity     (merge old-entity new-entity)
        tx             (xt/submit-tx xtdb-node [[::xt/match entity-id old-entity] [::xt/put new-entity]])
        most-recent-tx (xt/await-tx xtdb-node tx)]
    (if (xt/tx-committed? xtdb-node tx)
      most-recent-tx
      (recur xtdb-node entity-id new-entity))))

👍 2
emccue01:04:04

honored

🙂 2
Niki15:04:56

(require '[xtdb.api :as xt])
  
(def check-unique
  '(fn [ctx attr value]
     (let [db  (xtdb.api/db ctx)
           res (xtdb.api/q db
                 [:find (quote ?e)
                  :in (quote ?value)
                  :where [(quote ?e) attr (quote ?value)]]
                 value)]
       (if (empty? res)
         []
         false))))

(defn install-fns! [node]
  (xt/submit-tx node [[::xt/put {:xt/id :check-unique
                                 :xt/fn check-unique}]]))

(with-open [node (xt/start-node {})]
  (install-fns! node)
  [(xt/tx-committed? node
     (xt/await-tx node
       (xt/submit-tx node
         [[::xt/fn :check-unique :user/name "Niki"]
          [::xt/put {:xt/id "1" :user/name "Niki"}]])))
   (xt/tx-committed? node
     (xt/await-tx node
       (xt/submit-tx node
         [[::xt/fn :check-unique :user/name "Niki"]
          [::xt/put {:xt/id "1" :user/name "Niki"}]])))])

🙏 2
emccue16:04:34

Maybe there is a link-out type of elaboration to do on that 3 point list on the docs

👍 1
1