Skip to content

Commit

Permalink
support custom types (#4)
Browse files Browse the repository at this point in the history
* support custom types

* fix test
  • Loading branch information
yyna authored Nov 4, 2024
1 parent d0979ee commit 1286af9
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 18 deletions.
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,7 @@ Common args for all commands:
| `:migrations-dir` | Path to store migrations dir, relative to the `resources` dir. | `false` | string path (example: `"path/to/migrations"`) | `"db/migrations"` |
| `:resources-dir` | Path to resources dir to create migrations dir when it doesn't exist yet. | `false` | string path (example: `"path/to/resources"`) | `"resources"` |
| `:migrations-table` | Model name for storing applied migrations. | `false` | string (example: `"migrations"`) | `"automigrate_migrations"` |
| `:custom-types` | Set of custom field types to be used in models. | `false` | `nil` |

### `make`

Expand Down Expand Up @@ -800,3 +801,29 @@ make release :patch # bump git tag version by semver rules and push to remote r
Copyright © 2021 Andrey Bogoyavlenskiy

Distributed under the MIT License.

### Custom field types

You can use custom field types in your models by providing a set of custom types to the commands:

```clojure
;; Using with make command
(make {:custom-types #{:dml-type}})

;; Using with migrate command
(migrate {:custom-types #{:dml-type}})

;; Using with explain command
(explain {:number 7
:custom-types #{:dml-type}})

;; Using in models.edn
{:users-change-history
{:fields [[:changed-dml :dml-type {:null false}]]}}
```

Note: The custom type must be already defined in your database before using it in migrations. For example:

```sql
CREATE TYPE dml_type AS ENUM ('INSERT', 'UPDATE', 'DELETE');
```
41 changes: 26 additions & 15 deletions src/automigrate/core.clj
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
[automigrate.util.spec :as spec-util]
[automigrate.util.file :as file-util]
[automigrate.errors :as errors]
[automigrate.help :as automigrate-help])
[automigrate.help :as automigrate-help]
[automigrate.fields :as fields])
(:refer-clojure :exclude [list]))


Expand All @@ -21,6 +22,7 @@
(s/def ::jdbc-url (s/and some? (s/conformer str)))
(s/def ::jdbc-url-env-var string?)
(s/def ::number int?)
(s/def ::custom-types (s/coll-of keyword? :kind set?))


(s/def ::cmd
Expand Down Expand Up @@ -64,7 +66,8 @@
::name
::models-file
::migrations-dir
::resources-dir]))
::resources-dir
::custom-types]))


(s/def ::migrate-args
Expand Down Expand Up @@ -123,9 +126,11 @@ Available options:
Set `:empty-sql` - for creating an empty raw SQL migration. (optional)
:models-file - Path to the file with model definitions relative to the `resources` dir. Default: `db/models.edn`. (optional)
:migrations-dir - Path to directory containing migration files relative to the `resources` dir. Default: `db/migrations`. (optional)
:resources-dir - Path to resources dir to create migrations dir, if it doesn't exist. Default: `resources` (optional)"
[args]
(run-fn migrations/make-migration args ::make-args))
:resources-dir - Path to resources dir to create migrations dir, if it doesn't exist. Default: `resources` (optional)
:custom-types - Set of custom field types to be used in models. Example: #{:dml-type}. (optional)"
[{:keys [custom-types] :as args}]
(binding [fields/*custom-types* custom-types]
(run-fn migrations/make-migration args ::make-args)))


(defn migrate
Expand All @@ -136,14 +141,16 @@ Available options:
:jdbc-url - JDBC url for the database connection. Default: get from `DATABASE_URL` env var. (optional)
:jdbc-url-env-var - Name of environment variable for jdbc-url. Default: `DATABASE_URL`. (optional)
:migrations-dir - Path to directory containing migration files relative to the `resources` dir. Default: `db/migrations`. (optional)
:migrations-table - Custom name for the migrations table in the database. (optional)"
:migrations-table - Custom name for the migrations table in the database. (optional)
:custom-types - Set of custom field types to be used in models. Example: #{:dml-type}. (optional)"
([]
; 0-arity function can be used inside application code if there are no any options.
(migrate {}))
([{:keys [jdbc-url-env-var] :as args}]
(let [jdbc-url-env-var* (or jdbc-url-env-var JDBC-URL-ENV-VAR)
args* (update args :jdbc-url #(or % (System/getenv jdbc-url-env-var*)))]
(run-fn migrations/migrate args* ::migrate-args))))
([{:keys [jdbc-url-env-var custom-types] :as args}]
(binding [fields/*custom-types* custom-types]
(let [jdbc-url-env-var* (or jdbc-url-env-var JDBC-URL-ENV-VAR)
args* (update args :jdbc-url #(or % (System/getenv jdbc-url-env-var*)))]
(run-fn migrations/migrate args* ::migrate-args)))))


(defn explain
Expand All @@ -153,9 +160,11 @@ Available options:
:number - Integer number of the migration to explain. (required)
:direction - Direction of the migration to explain, can be `forward` (default) or `backward`. (optional)
:format - Format of explanation, can be `sql` (default) or `human`. (optional)
:migrations-dir - Path to directory containing migration files relative to the `resources` dir. Default: `db/migrations`. (optional)"
[args]
(run-fn migrations/explain args ::explain-args))
:migrations-dir - Path to directory containing migration files relative to the `resources` dir. Default: `db/migrations`. (optional)
:custom-types - Set of custom field types to be used in models. Example: #{:dml-type}. (optional)"
[{:keys [custom-types] :as args}]
(binding [fields/*custom-types* custom-types]
(run-fn migrations/explain args ::explain-args)))


(defn list
Expand Down Expand Up @@ -204,8 +213,10 @@ Available options:
(def cli-options-make
(concat
cli-options-common
[[nil "--name NAME"]]
[[nil "--type TYPE"]]))
[[nil "--name NAME"]
[nil "--type TYPE"]
[nil "--custom-types TYPES"
:parse-fn #(set (map keyword (str/split % #",")))]]))


(def cli-options-migrate
Expand Down
13 changes: 11 additions & 2 deletions src/automigrate/fields.clj
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@
:datemultirange}))


(def ^:dynamic *custom-types* nil)


(defn- field-type-dispatch
[value]
(cond
Expand All @@ -128,9 +131,15 @@
(defmulti field-type field-type-dispatch)


(s/def ::custom-type keyword?)


(defmethod field-type :keyword
[_]
::keyword-type)
[value]
(if (and (some? *custom-types*)
(contains? *custom-types* value))
::custom-type
::keyword-type))


(defmethod field-type :char
Expand Down
4 changes: 4 additions & 0 deletions src/automigrate/sql.clj
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,10 @@
[{array-value :array
type-value :type}]
(let [type-sql (cond
(and (some? fields/*custom-types*)
(contains? fields/*custom-types* type-value))
[:raw (name (model-util/kw->snake-case type-value))]

; :add-column clause in honeysql converts type name in kebab case into
; two separated words. So, for custom enum types we have to convert
; custom type name to snake case to use it in SQL as a single word.
Expand Down
3 changes: 2 additions & 1 deletion test/automigrate/help_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
" Set `:empty-sql` - for creating an empty raw SQL migration. (optional)\n"
" :models-file - Path to the file with model definitions relative to the `resources` dir. Default: `db/models.edn`. (optional)\n"
" :migrations-dir - Path to directory containing migration files relative to the `resources` dir. Default: `db/migrations`. (optional)\n"
" :resources-dir - Path to resources dir to create migrations dir, if it doesn't exist. Default: `resources` (optional)\n\n")
" :resources-dir - Path to resources dir to create migrations dir, if it doesn't exist. Default: `resources` (optional)\n"
" :custom-types - Set of custom field types to be used in models. Example: #{:dml-type}. (optional)\n\n")
(with-out-str
(help/show-help! {:cmd 'make})))))

0 comments on commit 1286af9

Please sign in to comment.