This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-06-24
Channels
- # babashka (11)
- # beginners (62)
- # calva (9)
- # cider (7)
- # clj-kondo (18)
- # cljfx (2)
- # cljsrn (4)
- # clojure (55)
- # clojure-australia (3)
- # clojure-dev (2)
- # clojure-europe (39)
- # clojure-italy (3)
- # clojure-nl (3)
- # clojure-spec (5)
- # clojure-uk (5)
- # clojured (7)
- # clojurescript (16)
- # clojureverse-ops (2)
- # conjure (22)
- # cursive (12)
- # data-science (13)
- # datomic (8)
- # duct (7)
- # emacs (11)
- # events (1)
- # fulcro (12)
- # helix (10)
- # integrant (21)
- # introduce-yourself (5)
- # jobs (2)
- # jobs-discuss (16)
- # lsp (1)
- # malli (5)
- # meander (7)
- # membrane (9)
- # pathom (9)
- # reitit (5)
- # releases (3)
- # ring (2)
- # sci (18)
- # shadow-cljs (35)
- # sql (15)
clojure hive-mind, i want you opinion on something. Assume I have a schema.clj
which contains my datomic schema (the usual). Every time I start the application (in development and in production) this schema is transacted so whatever has been added gets correctly transacted too. Now, some time ago I added a new attribute {:db/ident :foo/bar ...}
, now after a few weeks turns out that I want to rename this attribute like :alice/bob
. Following the documentation of datomic i'm supposed to {:db/id :foo/bar :db/ident :alice/bob}
, but that clearly doesn't work in development as :foo/bar
isn't yet defined when i start my system (it's in the same transaction) but would work on a running system with the attribute already installed. How do you handle these cases?
so migrations is just a list of txs to run in order... or a fully qualified symbol denoting a function to call (connection given as argument)
separate txs help with that and I like that we can see the schema evolution from the schema file as well
We do the same. This:
[{:db/ident :tx/id
:db/cardinality :db.cardinality/one
:db/valueType :db.type/keyword
:db/unique :db.unique/value}
{:db/ident :tx/status
:db/valueType :db.type/ref
:db/cardinality :db.cardinality/one}
{:db/ident :tx.status/applied}]
is always transacted on startup. Everything else looks like:
{:tx-id :migration-0001
:tx-data
[{:db/ident :editor-session/pid
:db/cardinality :db.cardinality/one
:db/valueType :db.type/string
:db/unique :db.unique/value}]}
Or:
{:tx-id :migration-0002
:tx-kind :fn
:tx-data
server.db.migrations/somefn}
These are kept as resources which are transacted by:
(defn tx-resource!
[conn resource]
(tx! conn (resources/read-resource resource)))
(defn- tx-status
[conn tx-id]
(-> (conn->db conn)
(q-by-ident [:tx/id tx-id] [{:tx/status [:db/ident]}])
:tx/status
:db/ident))
(defn- tx-apply!
[conn {:keys [tx-id tx-data]}]
(tx! conn (conj tx-data {:tx/id tx-id :tx/status
:tx.status/applied})))
(defn- tx-applied?
[conn tx-id]
(case (tx-status conn tx-id)
:tx.status/applied true
nil))
(defn tx-idempotent!
[conn resource]
(let [{:keys [tx-id tx-data tx-kind] :as props} (resources/read-resource resource)]
(when-not (tx-applied? conn tx-id)
(case tx-kind
:fn (do
(require (symbol (namespace tx-data)))
(tx-apply! conn (assoc props :tx-data ((resolve tx-data) conn))))
(tx-apply! conn props)))))
I wrote most of this before I discovered https://github.com/magnetcoop/stork which is pretty similar. I borrowed its approach to supporting migration functions