diff --git a/dev/src/dev.clj b/dev/src/dev.clj index d9a0209ffdb939d92cc612a639deadfe10168a2c..a472a6792225bca57278e8c61e43bf6e0449f125 100644 --- a/dev/src/dev.clj +++ b/dev/src/dev.clj @@ -106,7 +106,8 @@ explain-query] [dev.migrate migrate! - rollback!] + rollback! + migration-sql-by-id] [model-tracking track! untrack! diff --git a/dev/src/dev/migrate.clj b/dev/src/dev/migrate.clj index 1c3d4e6f3df51a885f6bec30d88f88ec2ec3647b..65f57291bb298ac8d9ad82dc02add7c908f0070e 100644 --- a/dev/src/dev/migrate.clj +++ b/dev/src/dev/migrate.clj @@ -1,12 +1,17 @@ (ns dev.migrate (:gen-class) (:require + [clojure.string :as str] [metabase.db :as mdb] [metabase.db.liquibase :as liquibase] [metabase.util.malli :as mu] [toucan2.core :as t2]) (:import - (liquibase Liquibase))) + (liquibase Contexts Liquibase RuntimeEnvironment) + (liquibase.changelog ChangeLogIterator) + (liquibase.changelog.filter ChangeSetFilter) + (liquibase.sqlgenerator SqlGeneratorFactory) + (liquibase.changelog.visitor ListVisitor))) (set! *warn-on-reflection* true) @@ -101,3 +106,37 @@ (throw (ex-info "Invalid command" {:command cmd :args args}))))) + +(defn- stmts-to-sql + [stmts sql-generator-factory database] + (str/join "\n" (for [stmt stmts + sql (.generateSql ^SqlGeneratorFactory sql-generator-factory stmt database)] + (.toString sql)))) + +(defn- change->sql + [change sql-generator-factory database] + {:forward (stmts-to-sql (.generateStatements change database) sql-generator-factory database) + :rollback (stmts-to-sql (.generateRollbackStatements change database) sql-generator-factory database)}) + +(defn migration-sql-by-id + "Get the sql statements for a specific migration ID. + (migration-sql-by-id \"v51.2024-06-12T18:53:02\") + ;; => + {:forward \"DROP INDEX public.idx_user_id_device_id;\", + :rollback \"CREATE INDEX idx_user_id_device_id ON public.login_history(session_id, device_id);\"}" + [id] + (t2/with-connection [conn] + (liquibase/with-liquibase [^Liquibase liquibase conn] + (let [database (.getDatabase liquibase) + change-log-iterator (ChangeLogIterator. (.getDatabaseChangeLog liquibase) (into-array ChangeSetFilter [])) + list-visistor (ListVisitor.) + runtime-env (RuntimeEnvironment. database (Contexts.) nil) + _ (.run change-log-iterator list-visistor runtime-env) + change-set (first (filter #(= id (.getId %))(.getSeenChangeSets list-visistor))) + sql-generator-factory (SqlGeneratorFactory/getInstance)] + (reduce (fn [acc data] + ;; merge all changes in one change set into one single :forward and :rollback + (merge-with (fn [x y] + (str x "\n" y)) acc data)) + {} + (map #(change->sql % sql-generator-factory database) (.getChanges change-set))))))) diff --git a/dev/test/dev/migrate_test.clj b/dev/test/dev/migrate_test.clj new file mode 100644 index 0000000000000000000000000000000000000000..171c97bbc0a840b7af9930eccd75f406eb82dc85 --- /dev/null +++ b/dev/test/dev/migrate_test.clj @@ -0,0 +1,11 @@ +(ns dev.migrate-test + (:require + [clojure.test :refer :all] + [metabase.dev.migrate :as dev.migrate])) + +(deftest migration-sql-by-id-test + (is (= {:forward + "ALTER TABLE public.query_field RENAME COLUMN direct_reference TO explicit_reference;", + :rollback + "ALTER TABLE public.query_field RENAME COLUMN explicit_reference TO direct_reference;"} + (dev.migrate/migration-sql-by-id "v51.2024-06-07T12:37:36"))))