-
Notifications
You must be signed in to change notification settings - Fork 1
Add migrator.ragtime component #4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm really sorry for the delay. I left some comments.
extra/src/zou/migrator/ragtime.clj
Outdated
java.time.format.DateTimeFormatter | ||
java.time.LocalDateTime)) | ||
|
||
(defprotocol IMigrator |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm recently having second thoughts about making protocols which will be never reused practically (I understand this is based on my code, though..).
How about simply defining functions?
extra/src/zou/migrator/ragtime.clj
Outdated
(let [separator (.getSeparator (FileSystems/getDefault)) | ||
prefix (str path separator (gen-file-name description)) | ||
up-sql (io/file (str prefix ".up.sql")) | ||
down-sql (io/file (str prefix ".down.sql"))] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO, it would be better to pass path
to parent
paramter of io/file
:
(let [prefix (gen-file-name description)
up-sql (io/file path (str prefix ".up.sql"))
down-sql (io/file path (str prefix ".down.sql"))]
...)
extra/src/zou/migrator/ragtime.clj
Outdated
(defn- gen-edn-files [path description] | ||
(let [separator (.getSeparator (FileSystems/getDefault)) | ||
prefix (str path separator (gen-file-name description)) | ||
edn (io/file (str prefix ".edn"))] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
extra/src/zou/migrator/ragtime.clj
Outdated
(defn generate* [migrator description] | ||
(let [{:keys [migrations-path style]} migrator | ||
path (some-> (io/resource migrations-path) | ||
io/file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this will throw an exception when migration-path
is an immutable classpath such as URL(= jar).
generate
exists only for convenience during development, so the failure itself is ok, but please consider raising a more user-friendly error.
extra/src/zou/migrator/ragtime.clj
Outdated
|
||
(remigrate [this] | ||
(let [{:keys [datastore index migrations]} this | ||
last-applied (last (ragtime/applied-migrations datastore index)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have a question.
What happens when there is a difference between the applied migration and the current one that actually exists on the file system?
Does Ragtime remember the actual content of the applied migrations (not only id)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ragtime manage only id.
In that case, Ragtime will fail or just works (it's depends on what the difference between those).
I think rollback
also has same issue.
(doseq [f' (.listFiles f)] | ||
(func func f'))) | ||
(io/delete-file f))] | ||
(delete-recur delete-recur (io/file h2db-dir))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't remember why such a hacky way is needed (maybe for mutual anonymous recursion?), but I guess the following code should work in this case:
(letfn [(delete-recur [f]
(when (.isDirectory f)
(doseq [f' (.listFiles f)]
(delete-recur f')))
(io/delete-file f))]
(delete-recur (io/file h2db-dir)))
extra/src/zou/migrator/ragtime.clj
Outdated
:desc "Rolls back the database" | ||
:option-specs [["-n" "--n N" "How many changes to rollback" | ||
:parse-fn #(Long/parseLong %) | ||
:validate [#(re-matches #"^\d+$" %) "Must be integer"]] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIRC, the validation functions will be applied to parsed values. So, this validation should always fail.
pos?
might be a good alternative as a validation function.
extra/src/zou/migrator/ragtime.clj
Outdated
(log/warnf "Migrations directory `%s` does not exist" migrations-path)) | ||
(case style | ||
:edn (gen-edn-files path description) | ||
:sql (gen-sql-files path description) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Optional) I think that's a good use case of mutimethods.
extra/project.clj
Outdated
:plugins [[lein-modules "0.3.11"]] | ||
:profiles | ||
{:provided {:dependencies [[ragtime "0.7.1"]]} | ||
:dev {:resource-paths ["dev-resources"]}}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this necessary?
extra/src/zou/migrator/ragtime.clj
Outdated
|
||
task/Task | ||
(task-name [this] :migration) | ||
(spec [this] {:desc "Migration tasks"}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is better to use the more concrete name and description like :ragtime
and "Ragtime tasks"
.
extra/src/zou/migrator/ragtime.clj
Outdated
(remigrate [this]) | ||
(rollback [this opts]) | ||
(generate [this description])) | ||
(defn validate-component-state [component] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
defn-
?
extra/src/zou/migrator/ragtime.clj
Outdated
@@ -119,7 +125,7 @@ | |||
:desc "Rolls back the database" | |||
:option-specs [["-n" "--n N" "How many changes to rollback" | |||
:parse-fn #(Long/parseLong %) | |||
:validate [#(re-matches #"^\d+$" %) "Must be integer"]] | |||
:validate [pos? "Must be integer"]] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
integer
-> positive integer
extra/src/zou/migrator/ragtime.clj
Outdated
(defn validate-component-state [component] | ||
(let [{:keys [datastore index migrations]} component] | ||
(when-not (and datastore index migrations) | ||
(throw (ex-info "Ragtime component has not been initialized" {:keys [:datastore :index :migrations]}))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this map seems not so useful. It might be better to simply throw IllegalStateException
or pass actual data corresponding to the keys to ex-data (if they are an implementation detail, the former (w/ debug log) might be better).
n (if (nil? n) 1 n) | ||
opts (select-keys ragtime-component [:reporter])] | ||
(if (and (seq applied) | ||
(or (seq id) (integer? n))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, IMO, it'd be better to validate arguments separately and raise an error if it fails, rather than just saying "No migrations to roll back".
(generate-files style (-> resource io/file .getPath) description) | ||
(throw (ex-info (format "Migrations directory `%s` %s" | ||
migrations-path | ||
(if resource "not a directory" "does not exist")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not a directory
It seems like you don't actually check whether it's a directory or not :p
(def h2db-file (str h2db-dir "/h2db.sql")) | ||
(def empty-file-attrs (into-array java.nio.file.attribute.FileAttribute [])) | ||
|
||
(def h2db-file (Files/createTempFile "h2db-" ".sql" empty-file-attrs)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use java.io.File/createTempFile
without empty-file-attrs
|
||
(def empty-file-attrs (into-array java.nio.file.attribute.FileAttribute [])) | ||
|
||
(def h2db-file (Files/createTempFile "h2db-" ".sql" empty-file-attrs)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Btw, why don't you use in-memory mode?
No description provided.