Skip to content

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

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open

Add migrator.ragtime component #4

wants to merge 2 commits into from

Conversation

ayato-p
Copy link
Collaborator

@ayato-p ayato-p commented Jun 15, 2017

No description provided.

@ayato-p ayato-p requested a review from rfkm June 15, 2017 09:17
Copy link
Owner

@rfkm rfkm left a 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.

java.time.format.DateTimeFormatter
java.time.LocalDateTime))

(defprotocol IMigrator
Copy link
Owner

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?

(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"))]
Copy link
Owner

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"))]
  ...)

(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"))]
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

(defn generate* [migrator description]
(let [{:keys [migrations-path style]} migrator
path (some-> (io/resource migrations-path)
io/file
Copy link
Owner

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.


(remigrate [this]
(let [{:keys [datastore index migrations]} this
last-applied (last (ragtime/applied-migrations datastore index))
Copy link
Owner

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)?

Copy link
Collaborator Author

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)))
Copy link
Owner

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)))

: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"]]
Copy link
Owner

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.

(log/warnf "Migrations directory `%s` does not exist" migrations-path))
(case style
:edn (gen-edn-files path description)
:sql (gen-sql-files path description)
Copy link
Owner

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.

:plugins [[lein-modules "0.3.11"]]
:profiles
{:provided {:dependencies [[ragtime "0.7.1"]]}
:dev {:resource-paths ["dev-resources"]}})
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this necessary?


task/Task
(task-name [this] :migration)
(spec [this] {:desc "Migration tasks"})
Copy link
Owner

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".

(remigrate [this])
(rollback [this opts])
(generate [this description]))
(defn validate-component-state [component]
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

defn-?

@@ -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"]]
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

integer -> positive integer

(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]})))
Copy link
Owner

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)))
Copy link
Owner

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"))
Copy link
Owner

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))
Copy link
Owner

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))
Copy link
Owner

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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants