Skip to content

Commit

Permalink
major: Rename term :migration[s] to :operation[s]
Browse files Browse the repository at this point in the history
While this tool is primarily intended to be used for running migrations,
it can in fact be used for running any kind of once off operation. For
example this can be used for seeding data in dev.

In order to encourage its broader use any instances of the term
'migration' has been renamed in this commit to 'operation'.

This change had already started to be implemented in previous commits,
but this commit changes the public API to follow suite.

This will make it seem less weird to use a migration tool for other
use-cases.
  • Loading branch information
julienvincent committed Feb 5, 2024
1 parent 1d93338 commit aa3b5d5
Show file tree
Hide file tree
Showing 7 changed files with 50 additions and 50 deletions.
20 changes: 10 additions & 10 deletions packages/mallard/src/k16/mallard/api.clj
Original file line number Diff line number Diff line change
Expand Up @@ -6,44 +6,44 @@
(set! *warn-on-reflection* true)

(defn run-up!
"Execute all unapplied migrations"
"Execute all unapplied operations"
[props]
(executor/execute! (assoc props :direction :up)))

(defn run-down!
"Rollback all applied migrations"
"Rollback all applied operations"
[props]
(executor/execute! (assoc props :direction :down)))

(defn run-next!
"Run the next unapplied migration"
"Run the next unapplied operation"
[props]
(executor/execute! (merge props {:direction :up
:limit 1})))

(defn undo!
"Rollback the last applied migration"
"Rollback the last applied operation"
[props]
(executor/execute! (merge props {:direction :down
:limit 1})))

(defn redo!
"Reapply the last applied migration. This will roll it back first"
"Reapply the last applied operation. This will roll it back first"
[props]
(undo! props)
(run-next! props))

(defn run
"A run function to be used in a Deps.edn project to execute migrations using the file loader.
"A run function to be used in a Deps.edn project to execute operations using the file loader.
:init-store! - Should be given a symbol that resolves to a datastore init function.
:migrations-dir - should be a resource path to a directory containing migration files that will
be loaded using the file loader.
:load-dir - should be a resource path to a directory containing operation files that will
be loaded using the file loader.
:action - should be given an action to perform. One of #{:up :down :next :undo :redo}"
[{create-ctx-fn :create-ctx!
create-store-fn :create-store!
shutdown-fn :shutdown!
migrations-dir :migrations-dir
load-dir :load-dir
action :action}]

(let [create-store! (requiring-resolve create-store-fn)
Expand All @@ -52,7 +52,7 @@
(create-ctx))
store (create-store! context)
props {:context context
:migrations (loaders.fs/load-migrations! migrations-dir)
:operations (loaders.fs/load! load-dir)
:store store}]

(case action
Expand Down
12 changes: 6 additions & 6 deletions packages/mallard/src/k16/mallard/dev.clj
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,17 @@

[:or
[:map
[:migrations executor/?Operations]]
[:operations executor/?Operations]]

[:map
[:migrations-dir :string]]]])
[:load-dir :string]]]])

(def run-migrations-component!
(def run!
{:gx/start
{:gx/processor (fn [{:keys [props]}]
(let [{:keys [store context migrations migrations-dir]} props]
(let [{:keys [store context operations load-dir]} props]
(api/run-up! {:store store
:context context
:migrations (or migrations
(loaders.fs/load-migrations! migrations-dir))})))
:operations (or operations
(loaders.fs/load! load-dir))})))
:gx/props-schema ?Props}})
26 changes: 13 additions & 13 deletions packages/mallard/src/k16/mallard/executor.clj
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,18 @@
[:map
[:context {:optional true} [:maybe :any]]
[:store datastore.api/?DataStore]
[:migrations ?Operations]
[:operations ?Operations]
[:limit {:optional true} [:int {:min 1}]]
[:direction [:enum :up :down]]])

(defn- index-by [key-fn col]
(->> col
(map (fn [migration]
[(key-fn migration) migration]))
(map (fn [item]
[(key-fn item) item]))
(into {})))

(defn- project-op-log
"Reduces over the op-log to project the concrete sequence of currently applied migrations ids.
"Reduces over the op-log to project the concrete sequence of currently applied operation ids.
The op-log contains a sequence of `:up` and `:down` operations which can be reduced down to a
sequence of only `:up` operation ids
Expand All @@ -59,7 +59,7 @@
:down (if (= (:id op) (last operations))
(pop operations)
(throw (ex-info (str "Error reprocessing op-log. A :down operation did not "
"follow an :up migration of the same id")
"follow an :up operation of the same id")
{:last-op (last operations)
:current-op (:id op)})))))
[]
Expand Down Expand Up @@ -104,20 +104,20 @@
(defn- find-unapplied
"Return an ordered set of operations based on the current op-log state and desired `:direction`.
- If the direction is `:up` this will return the remaining set of *unapplied* migrations.
- If the direction is `:down` this will return the *applied* migrations in reverse order."
- If the direction is `:up` this will return the remaining set of *unapplied* operations.
- If the direction is `:down` this will return the *applied* operations in reverse order."
[op-log operations direction]
(let [{:keys [applied unapplied]} (derive-active-state op-log operations)]
(case direction
:up unapplied
:down (reverse applied))))

(defn- execute-one!
"Execute a single migration and return an ?OpLogEntry to be appended to the op-log."
"Execute a single operation and return an ?OpLogEntry to be appended to the op-log."
[context operation direction]
(let [{:keys [id run-up! run-down!]} operation
ts (t/now)]
(log/info (str "Executing migration " id " [" direction "]"))
(log/info (str "Executing operation " id " [" direction "]"))

(case direction
:up (run-up! context)
Expand All @@ -131,16 +131,16 @@
:finished_at (t/now)}))

(defn execute!
"Execute the given migrations and return the new log of operations. This will handle locking
and will mutate the datastore with the changing op-log as migrations are applied."
[{:keys [context store migrations direction limit] :as props}]
"Execute the given operations and append to the op-log which is then returned. This will handle locking
and will mutate the datastore with the changing op-log as operations are applied."
[{:keys [context store operations direction limit] :as props}]
(when-not (m/validate ?ExecuteProps props)
(throw (ex-info "Invalid arguments provided"
{:errors (me/humanize (m/explain ?ExecuteProps props))})))

(let [state (datastore.api/load-state store)
op-log (atom (or (:log state) []))
unapplied (cond-> (find-unapplied (:log state) migrations direction)
unapplied (cond-> (find-unapplied (:log state) operations direction)
limit ((partial take limit)))
lock (datastore.api/acquire-lock! store)]

Expand Down
14 changes: 7 additions & 7 deletions packages/mallard/src/k16/mallard/loaders/fs.clj
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
(re-find #"^\(ns\s+([^\s);]+)")
second))

(defn resolve-migration-files [dir]
(defn resolve-operation-files [dir]
(->> (or (io/resource dir)
(io/file dir))
io/file
Expand All @@ -24,17 +24,17 @@
sort
vec))

(defmacro load-migrations!
"Given a file or resource directory path attempt to load all files found within as migrations.
(defmacro load!
"Given a file or resource directory path attempt to load all files found within as operations.
This is implemented as a macro to allow preloading migrations during native-image compilation. This
also allows loading of migrations when they are bundled as resources within a jar as the full resource
This is implemented as a macro to allow preloading operations during native-image compilation. This
also allows loading of operations when they are bundled as resources within a jar as the full resource
paths are known up front."
[dir]
(let [namespaces (try (resolve-migration-files dir)
(let [namespaces (try (resolve-operation-files dir)
(catch Exception _))]
`(let [namespaces# (or ~namespaces
(resolve-migration-files ~dir))]
(resolve-operation-files ~dir))]
(doseq [namespace# namespaces#]
(require (symbol namespace#)))

Expand Down
4 changes: 2 additions & 2 deletions packages/mallard/src/k16/mallard/loaders/ns.clj
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

(set! *warn-on-reflection* true)

(defn load-migrations!
"Dynamically require all given namespaces as migration files."
(defn load!
"Dynamically require all given namespaces as operation files."
[namespaces]
(->> namespaces
(map (fn [ns']
Expand Down
22 changes: 11 additions & 11 deletions packages/mallard/test/k16/mallard/executor_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@
(is (= ExceptionInfo (type ex)))
(is (= "Invalid arguments provided" (ex-message ex)))
(is (= {:errors {:direction ["missing required key"],
:migrations ["missing required key"],
:operations ["missing required key"],
:store ["missing required key"]}}
(ex-data ex))))

(let [ex (try (executor/execute! {:migrations :wrong
(let [ex (try (executor/execute! {:operations :wrong
:direction :left
:store "incorrect store"
:limit 0})
Expand All @@ -46,7 +46,7 @@
(is (= ExceptionInfo (type ex)))
(is (= "Invalid arguments provided" (ex-message ex)))
(is (= {:errors {:direction ["should be either :up or :down"],
:migrations ["should be a sequence of operations"],
:operations ["should be a sequence of operations"],
:store ["should Implement DataStore protocol"],
:limit ["should be at least 1"]}}
(ex-data ex))))))
Expand All @@ -68,16 +68,16 @@
(executor/execute! {:store store
:context context
:direction :up
:migrations migs})
:operations migs})
(executor/execute! {:store store
:context context
:direction :down
:migrations migs}))))
:operations migs}))))

(deftest single-execution-test
(let [store (stores.memory/create-memory-datastore)
op-log (executor/execute! {:store store
:migrations migrations
:operations migrations
:direction :up
:limit 1})]

Expand All @@ -93,7 +93,7 @@
(deftest multi-execution-test
(let [store (stores.memory/create-memory-datastore)
op-log (executor/execute! {:store store
:migrations migrations
:operations migrations
:direction :up})]

(is (= 3 (count op-log)))
Expand All @@ -109,7 +109,7 @@

(testing "Undoing the last migration"
(let [op-log (executor/execute! {:store store
:migrations migrations
:operations migrations
:direction :down
:limit 1})]

Expand All @@ -132,7 +132,7 @@

(testing "Rerunning the last migration"
(let [op-log (executor/execute! {:store store
:migrations migrations
:operations migrations
:direction :up
:limit 1})]

Expand All @@ -155,7 +155,7 @@
:finished_at (t/now)}]})

(let [op-log (executor/execute! {:store store
:migrations migrations
:operations migrations
:direction :up
:limit 1})]

Expand All @@ -174,7 +174,7 @@
:finished_at (t/now)}]})

(let [ex (try (executor/execute! {:store store
:migrations []
:operations []
:direction :down
:limit 1})
(catch Exception e e))]
Expand Down
2 changes: 1 addition & 1 deletion packages/mallard/test/k16/mallard/loaders/fs_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

(deftest fs-loader-test
(testing "It should load migrations from disk in the correct order"
(let [migrations (loaders.fs/load-migrations! "fixtures/migrations")]
(let [migrations (loaders.fs/load! "fixtures/migrations")]
(is (match? [{:id "1-migration"
:run-up! (requiring-resolve 'fixtures.migrations.1-migration/run-up!)
:run-down! (requiring-resolve 'fixtures.migrations.1-migration/run-down!)}
Expand Down

0 comments on commit aa3b5d5

Please sign in to comment.