exwiw 0.9.24 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -21,6 +21,15 @@ module Exwiw
21
21
  added_tables added_columns removed_tables removed_columns changed_tables needs_mask_decision
22
22
  ].freeze
23
23
 
24
+ # The subset of the removals that would break an `export` run: a non-ignored
25
+ # config still referencing a table or column the schema no longer has, i.e.
26
+ # the extraction SELECT would name something that does not exist. Removals of
27
+ # `ignore: true` entries stay out (nothing selects them), as do additions.
28
+ # `--fail-on=stale` keys the exit code to these. Deliberate over-approximation:
29
+ # a hand-written config naming a database VIEW lands here too (tidy's stance),
30
+ # though a SELECT against it would succeed.
31
+ STALE_CATEGORIES = %w[stale_tables stale_columns].freeze
32
+
24
33
  def self.from_rails_application(schema_dir:)
25
34
  Rails.application.eager_load!
26
35
  new(models: ActiveRecord::Base.descendants, schema_dir: schema_dir)
@@ -81,6 +90,12 @@ module Exwiw
81
90
  CATEGORIES.all? { |category| report.fetch(category, []).empty? }
82
91
  end
83
92
 
93
+ # Whether the report contains drift that would break an extraction run
94
+ # (see STALE_CATEGORIES). Always a subset of what makes clean? false.
95
+ def self.stale?(report)
96
+ STALE_CATEGORIES.any? { |category| !report.fetch(category, []).empty? }
97
+ end
98
+
84
99
  private def regenerate_into(tmp_dir)
85
100
  FileUtils.cp_r(File.join(@schema_dir, "."), tmp_dir) if Dir.exist?(@schema_dir)
86
101
  @regenerator.call(tmp_dir)
@@ -111,7 +126,7 @@ module Exwiw
111
126
  end
112
127
 
113
128
  private def diff(committed, regenerated)
114
- report = CATEGORIES.to_h { |category| [category, []] }
129
+ report = (CATEGORIES + STALE_CATEGORIES).to_h { |category| [category, []] }
115
130
 
116
131
  (committed.keys | regenerated.keys).sort.each do |key|
117
132
  before = committed[key]
@@ -122,7 +137,11 @@ module Exwiw
122
137
  next
123
138
  end
124
139
  if after.nil?
125
- report["removed_tables"] << table_label(key, before)
140
+ label = table_label(key, before)
141
+ report["removed_tables"] << label
142
+ # A rails-managed table is dumped whole, so its disappearance breaks
143
+ # the export too; only `ignore: true` keeps a removed table out.
144
+ report["stale_tables"] << label unless before["ignore"]
126
145
  next
127
146
  end
128
147
  next if before == after
@@ -132,6 +151,10 @@ module Exwiw
132
151
  added, removed = column_diff(before, after)
133
152
  report["added_columns"] += added.sort.map { |column| "#{label}.#{column}" }
134
153
  report["removed_columns"] += removed.sort.map { |column| "#{label}.#{column}" }
154
+ if extracted?(before)
155
+ stale = removed & extracted_column_names(before)
156
+ report["stale_columns"] += stale.sort.map { |column| "#{label}.#{column}" }
157
+ end
135
158
  end
136
159
 
137
160
  report
@@ -148,6 +171,22 @@ module Exwiw
148
171
  (config["columns"] || config["fields"] || []).map { |column| column["name"] }
149
172
  end
150
173
 
174
+ # Whether the extraction SELECT names this table's columns: an `ignore: true`
175
+ # config only contributes DDL, and a rails-managed one is dumped as
176
+ # `SELECT *` — so a removed column cannot break either. (A removed
177
+ # rails-managed table still can; #diff handles that separately.)
178
+ private def extracted?(config)
179
+ !config["ignore"] && !TableConfig::RAILS_MANAGED_TYPES.include?(config["type"])
180
+ end
181
+
182
+ # The columns the extraction SELECT actually names: `ignore: true` columns
183
+ # are dropped when the config loads, so their staleness breaks nothing.
184
+ private def extracted_column_names(config)
185
+ (config["columns"] || config["fields"] || [])
186
+ .reject { |column| column["ignore"] }
187
+ .map { |column| column["name"] }
188
+ end
189
+
151
190
  # How a table is named in the report. The database is part of the label, or
152
191
  # the same table name in two of them collides (each has `schema_migrations`).
153
192
  private def table_label(key, config)
data/lib/exwiw/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Exwiw
4
- VERSION = "0.9.24"
4
+ VERSION = "1.1.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: exwiw
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.24
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shia