mimi-db 0.2.3 → 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f6c134a70d22d57cb28bc7eef7dd2dea944f743c
4
- data.tar.gz: 9f7088a8658380872586ef77d273d4b9db8a4f22
3
+ metadata.gz: 7d8e5f05648963455f22f4495aeed73bbab8edd4
4
+ data.tar.gz: b519848493d926249f1be91a586e80aaceff153e
5
5
  SHA512:
6
- metadata.gz: 64fb09362a80c2b1d60f671d4672862a4a70753024509c5a08091dfc5c8c846ba5df476190918f15d5e0968dae0abc4e3282a4dc18d2303cc7acaf0f8f2caa98
7
- data.tar.gz: 6f6a42c8af65974cc9ddf7fcd4785e10cf0c1c2b16efc9320bda145ad3048b459304e41a82c3acad5ad38aec9ca76542363239de7f138740ff0e0de67c54dc25
6
+ metadata.gz: 0f61958bb7e08cbf6d2ed28e8ed566a983f38365894257eb84b5ed579da21b248cfbd6898a964d267b22e1d22a6b806c6c0add014afa245a143c997a0a784fbf
7
+ data.tar.gz: 5256b301a6bd6891cf3cf47698ae34608b9b68858b7d39c1854da2bfc041779b2dfacd101c6b7306b569d91e95c28298beae2aadbec97c3f3ba872a273783ff0
@@ -83,24 +83,28 @@ module Mimi
83
83
 
84
84
  def run_change_table!
85
85
  diff = Mimi::DB::Dictate::SchemaDiff.diff(from_schema, to_schema)
86
- if diff.empty?
86
+ if diff[:columns].empty? && diff[:indexes].empty?
87
87
  logger.info "- no changes: #{table_name}"
88
88
  return
89
89
  end
90
90
  logger.info "- ALTER TABLE: #{table_name}"
91
- run_change_table_columns!(diff[:columns]) if diff[:columns]
92
- run_change_table_indexes!(diff[:indexes]) if diff[:indexes]
91
+ run_change_table_columns!(diff[:columns]) unless diff[:columns].empty?
92
+ run_change_table_indexes!(diff[:indexes]) unless diff[:indexes].empty?
93
93
  end
94
94
 
95
95
  def run_change_table_columns!(diff_columns)
96
- diff_columns[:remove]&.each { |c| drop_column!(table_name, c) }
97
- diff_columns[:change]&.each { |c| change_column!(table_name, c) }
98
- diff_columns[:add]&.each { |c| add_column!(table_name, c) }
96
+ diff_columns.each do |c, diff|
97
+ drop_column!(table_name, c) if diff[:from] && diff[:to].nil?
98
+ change_column!(table_name, diff[:to]) if diff[:from] && diff[:to]
99
+ add_column!(table_name, diff[:to]) if diff[:from].nil? && diff[:to]
100
+ end
99
101
  end
100
102
 
101
103
  def run_change_table_indexes!(diff_indexes)
102
- diff_indexes[:remove]&.each { |i| drop_index!(table_name, i) }
103
- diff_indexes[:add]&.each { |i| add_index!(table_name, i) }
104
+ diff_indexes.each do |i, diff|
105
+ drop_index!(table_name, diff[:from]) if diff[:from] && diff[:to].nil?
106
+ add_index!(table_name, diff[:to]) if diff[:from].nil? && diff[:to]
107
+ end
104
108
  end
105
109
 
106
110
  def run_create_table!
@@ -15,58 +15,35 @@ module Mimi
15
15
  #
16
16
  # Compares two schema definitions
17
17
  #
18
- # @return [Hash] :columns, :indexes => :add, :remove, :change
18
+ # @return [Hash] :columns, :indexes => :from, :to
19
19
  #
20
20
  def self.diff(from, to, opts = {})
21
21
  options = DEFAULT_OPTIONS.merge(opts)
22
- from_column_names = from.columns.values.map(&:name)
23
- to_column_names = to.columns.values.map(&:name)
24
- columns_names_remove = from_column_names - to_column_names
25
- columns_names_add = to_column_names - from_column_names
26
- columns_add = to.columns.values.select do |c|
27
- columns_names_add.include?(c.name)
22
+ result = { table_name: from.table_name, columns: {}, indexes: {} }
23
+ all_column_names = (from.columns.values.map(&:name) + to.columns.values.map(&:name)).uniq
24
+ all_column_names.each do |c|
25
+ if from.columns[c] && to.columns[c].nil?
26
+ result[:columns][c] = { from: from.columns[c], to: nil }
27
+ elsif from.columns[c] && to.columns[c] && !(from.columns[c] == to.columns[c])
28
+ result[:columns][c] = { from: from.columns[c], to: to.columns[c] }
29
+ elsif from.columns[c].nil? && to.columns[c]
30
+ result[:columns][c] = { from: nil, to: to.columns[c] }
31
+ end
32
+ end
33
+ from_indexes = from.indexes.map { |i| [i.columns, i] }.to_h
34
+ to_indexes = to.indexes.map { |i| [i.columns, i] }.to_h
35
+ all_index_cols = (from_indexes.keys + to_indexes.keys).uniq
36
+ all_index_cols.each do |cc|
37
+ if from_indexes[cc] && to_indexes[cc].nil?
38
+ result[:indexes][cc] = { from: from_indexes[cc], to: nil }
39
+ elsif from_indexes[cc] && to_indexes[cc]
40
+ # index diff is not supported
41
+ elsif from_indexes[cc].nil? && to_indexes[cc]
42
+ result[:indexes][cc] = { from: nil, to: to_indexes[cc]}
43
+ end
28
44
  end
29
- columns_change = to.columns.values.reject do |c|
30
- res = from.columns[c.name].nil? || from.columns[c.name] == c
31
- res ||= c.type == :primary_key unless options[:force_primary_key]
32
- end
33
- from_indexes_c = from.indexes.map(&:columns).uniq
34
- to_indexes_c = to.indexes.map(&:columns).uniq
35
- # ignore primary key indexes
36
- from_indexes_c -= [[from.primary_key&.name]]
37
- to_indexes_c -= [[to.primary_key&.name]]
38
45
 
39
- indexes_c_remove = from_indexes_c - to_indexes_c
40
- indexes_c_add = to_indexes_c - from_indexes_c
41
- indexes_remove = from.indexes.select do |idx|
42
- indexes_c_remove.include?(idx.columns)
43
- end
44
- indexes_add = to.indexes.select do |idx|
45
- indexes_c_add.include?(idx.columns)
46
- end
47
-
48
- diff = {}
49
- unless columns_names_remove.empty?
50
- diff[:columns] ||= {}
51
- diff[:columns][:remove] = columns_names_remove
52
- end
53
- unless columns_change.empty?
54
- diff[:columns] ||= {}
55
- diff[:columns][:change] = columns_change
56
- end
57
- unless columns_add.empty?
58
- diff[:columns] ||= {}
59
- diff[:columns][:add] = columns_add
60
- end
61
- unless indexes_remove.empty?
62
- diff[:indexes] ||= {}
63
- diff[:indexes][:remove] = indexes_remove
64
- end
65
- unless indexes_add.empty?
66
- diff[:indexes] ||= {}
67
- diff[:indexes][:add] = indexes_add
68
- end
69
- diff
46
+ result
70
47
  end
71
48
  end # module SchemaDiff
72
49
  end # module Dictate
@@ -85,6 +85,31 @@ module Mimi
85
85
  logger.error "DB::Dictate failed to update DB schema: #{e}"
86
86
  raise
87
87
  end
88
+
89
+ # Diff existing DB schema and the target schema
90
+ #
91
+ # @param opts [Hash]
92
+ # @return [Hash]
93
+ #
94
+ def self.diff_schema!(opts = {})
95
+ logger = opts[:logger] || ActiveRecord::Base.logger
96
+ diff = { add_tables: [], change_tables: [], drop_tables: []}
97
+ Mimi::DB.all_table_names.each do |t|
98
+ m = Mimi::DB::Dictate::Migrator.new(t, opts)
99
+ if m.from_schema && m.to_schema.nil?
100
+ diff[:drop_tables] << t
101
+ elsif m.from_schema && m.to_schema
102
+ t_diff = Mimi::DB::Dictate::SchemaDiff.diff(m.from_schema, m.to_schema)
103
+ diff[:change_tables] << t_diff unless t_diff[:columns].empty? && t_diff[:indexes].empty?
104
+ elsif m.from_schema.nil? && m.to_schema
105
+ diff[:add_tables] << m.to_schema
106
+ end
107
+ end
108
+ diff
109
+ rescue StandardError => e
110
+ logger.error "DB::Dictate failed to update DB schema: #{e}"
111
+ raise
112
+ end
88
113
  end # module Dictate
89
114
  end # module DB
90
115
  end # module Mimi
@@ -60,6 +60,34 @@ module Mimi
60
60
  Mimi::DB::Dictate.update_schema!(opts)
61
61
  end
62
62
 
63
+ # Discovers differences between existing DB schema and target schema
64
+ # defined in models.
65
+ #
66
+ # @example
67
+ # Mimi::DB.diff_schema
68
+ #
69
+ # # =>
70
+ # # {
71
+ # # add_tables: [<table_schema1>, <table_schema2> ...],
72
+ # # change_tables: [
73
+ # # { table_name: ...,
74
+ # # columns: {
75
+ # # "<column_name1>" => {
76
+ # # from: { <column_definition or nil> },
77
+ # # to: { <column_definition or nil> }
78
+ # # }
79
+ # # }
80
+ # # }, ...
81
+ # # ],
82
+ # # drop_tables: [<table_name1>, ...]
83
+ # # }
84
+ # @return [Hash]
85
+ #
86
+ def diff_schema!(opts = {})
87
+ opts[:logger] ||= Mimi::DB.logger
88
+ Mimi::DB::Dictate.diff_schema(opts)
89
+ end
90
+
63
91
  # Creates the database specified in the current configuration.
64
92
  #
65
93
  def create!
@@ -1,5 +1,5 @@
1
1
  module Mimi
2
2
  module DB
3
- VERSION = '0.2.3'.freeze
3
+ VERSION = '0.2.4'.freeze
4
4
  end
5
5
  end
data/lib/tasks/db.rake CHANGED
@@ -59,6 +59,14 @@ namespace :db do
59
59
  logger.info "* Updating database schema (DRY RUN): #{Mimi::DB.module_options[:db_database]}"
60
60
  Mimi::DB.update_schema!(destructive: true, dry_run: true)
61
61
  end
62
+
63
+ desc 'Display differences between existing DB schema and target schema'
64
+ task diff: :"db:start" do
65
+ logger.info "* Diff database schema: #{Mimi::DB.module_options[:db_database]}"
66
+ diff = Mimi::DB.diff_schema(destructive: true, dry_run: true)
67
+ require 'pp'
68
+ pp diff
69
+ end
62
70
  end
63
71
  end
64
72
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mimi-db
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Kukushkin