exwiw 0.2.1 → 0.2.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4855b3fc49afc6cc69606579eb15c0cf430c4123024ec8e9b26a5215989292d3
4
- data.tar.gz: 1ee99545e00cb43292c59b918dc24d3b4f764427f8708fca773c0b507f6c1e2d
3
+ metadata.gz: db5d466378dd55180ac229c2276c4e5e228a067a69b648ed7979d142f5b12ce7
4
+ data.tar.gz: 2be8b1ffe33cdaa1d9443ec7a3f36f7108f506addfbadb3fa06ac8ba312a89a8
5
5
  SHA512:
6
- metadata.gz: fcbe518ae634e294bd48e61088dd4bd0f1012b317b08d921bcbd7ee95e4e595c69c9df59ad18593dbcee35b017c1fa6a198102f27757183b804218920ff64cbb
7
- data.tar.gz: 48475293bc58a6f32ec9edc68c3bdc0bdd1427233ec4cd2366fb656e5fdd1e050a260056fc69e73c5735eeb8cb6b457ef7244a13589946430f138359cc050911
6
+ metadata.gz: 17ae95279fe11b231c50a2c0d2e2ead9adcf2db6eb3fb79f7ee54f1af816c26dae23ace12d6fa901655817b26101777af04d70fd76751c6e45bc576d99ef7503
7
+ data.tar.gz: 99415623bdf900053d466d58c8a45fb1be380167a9d66cf9d265c8122c9fd6e3c96c8e48cb5e9e971e2783db595b63b1d525a850a3871e294a751263747b12b1
data/CHANGELOG.md CHANGED
@@ -2,6 +2,18 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.2.3] - 2026-05-27
6
+
7
+ ### Fixed
8
+
9
+ - PostgreSQL: schema dump now includes `CREATE TYPE ... AS ENUM` for custom enum types referenced by dumped tables. Previously `pg_dump --table` excluded schema-level type definitions, causing `type "..." does not exist` errors on import. ([#22](https://github.com/heyinc/exwiw/pull/22))
10
+
11
+ ## [0.2.2] - 2026-05-26
12
+
13
+ ### Changed
14
+
15
+ - `skip: true` table config now still emits the table's DDL into `insert-000-schema.{sql,js}` so downstream schemas stay consistent; only data extraction (`insert-*` / `delete-*`) is skipped. Previously the table was excluded from the schema file as well.
16
+
5
17
  ## [0.2.1] - 2026-05-23
6
18
 
7
19
  ### Added
data/README.md CHANGED
@@ -203,7 +203,7 @@ Note: Ruby hooks are evaluated via `instance_eval` inside the exwiw process —
203
203
 
204
204
  ### Skip a table
205
205
 
206
- Set `"skip": true` on a table's config JSON to explicitly exclude it from the dump. The table is omitted from `insert-000-schema.{sql,js}`, and no `insert-*` / `delete-*` files are generated for it. Skipped tables are also not queried at all.
206
+ Set `"skip": true` on a table's config JSON to exclude it from data extraction. The table's DDL is still emitted into `insert-000-schema.{sql,js}` so the schema stays consistent, but no `insert-*` / `delete-*` files are generated for it and the table is never queried.
207
207
 
208
208
  ```json
209
209
  {
@@ -347,7 +347,12 @@ At runtime:
347
347
 
348
348
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
349
349
 
350
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
350
+ To install this gem onto your local machine, run `bundle exec rake install`.
351
+
352
+ To release a new version:
353
+
354
+ 1. Run the **Release PR** workflow from the Actions tab with the new version number (e.g. `0.2.3`). This creates a PR that bumps `version.rb` and `CHANGELOG.md`.
355
+ 2. Merge the PR. The **Release** workflow runs automatically, creating a git tag and publishing the gem to [rubygems.org](https://rubygems.org).
351
356
 
352
357
  ## Contributing
353
358
 
@@ -52,6 +52,13 @@ module Exwiw
52
52
  raise "pg_dump failed (exit #{status.exitstatus}): #{stderr}"
53
53
  end
54
54
 
55
+ enum_types = query_enum_types(table_names)
56
+ unless enum_types.empty?
57
+ enum_ddl = DdlPostprocessor.create_type_enum_statements(enum_types)
58
+ @logger.debug(" Found #{enum_types.size} enum type(s) to prepend.")
59
+ stdout = enum_ddl + stdout
60
+ end
61
+
55
62
  idempotent = stdout
56
63
  idempotent = DdlPostprocessor.add_if_not_exists_to_create_schema(idempotent)
57
64
  idempotent = DdlPostprocessor.add_if_not_exists_to_create_sequence(idempotent)
@@ -264,6 +271,40 @@ module Exwiw
264
271
  end
265
272
  end
266
273
 
274
+ private def query_enum_types(table_names)
275
+ return [] if table_names.empty?
276
+
277
+ placeholders = table_names.each_with_index.map { |_, i| "$#{i + 1}" }.join(', ')
278
+ sql = <<~SQL
279
+ SELECT DISTINCT
280
+ n.nspname AS type_schema,
281
+ t.typname AS type_name,
282
+ array_agg(e.enumlabel ORDER BY e.enumsortorder) AS enum_labels
283
+ FROM pg_attribute a
284
+ JOIN pg_class c ON c.oid = a.attrelid
285
+ JOIN pg_namespace cn ON cn.oid = c.relnamespace
286
+ JOIN pg_type t ON t.oid = a.atttypid
287
+ JOIN pg_namespace n ON n.oid = t.typnamespace
288
+ JOIN pg_enum e ON e.enumtypid = t.oid
289
+ WHERE c.relname IN (#{placeholders})
290
+ AND a.attnum > 0
291
+ AND NOT a.attisdropped
292
+ AND t.typtype = 'e'
293
+ GROUP BY n.nspname, t.typname
294
+ ORDER BY n.nspname, t.typname
295
+ SQL
296
+
297
+ result = connection.exec_params(sql, table_names)
298
+ decoder = PG::TextDecoder::Array.new
299
+ result.map do |row|
300
+ {
301
+ schema: row['type_schema'],
302
+ name: row['type_name'],
303
+ labels: decoder.decode(row['enum_labels']),
304
+ }
305
+ end
306
+ end
307
+
267
308
  private def connection
268
309
  @connection ||=
269
310
  begin
@@ -57,5 +57,24 @@ module Exwiw
57
57
  SQL
58
58
  end
59
59
  end
60
+
61
+ # Generate idempotent CREATE TYPE ... AS ENUM statements.
62
+ # +enum_types+ is an Array of Hashes with keys :schema, :name, :labels.
63
+ def create_type_enum_statements(enum_types)
64
+ return "" if enum_types.empty?
65
+
66
+ stmts = enum_types.map do |t|
67
+ qualified_name = "\"#{t[:schema]}\".\"#{t[:name]}\""
68
+ labels_sql = t[:labels].map { |l| "'#{l.gsub("'", "''")}'" }.join(', ')
69
+ <<~SQL.chomp
70
+ DO $exwiw$ BEGIN
71
+ CREATE TYPE #{qualified_name} AS ENUM (#{labels_sql});
72
+ EXCEPTION WHEN duplicate_object THEN NULL;
73
+ END $exwiw$;
74
+ SQL
75
+ end
76
+
77
+ stmts.join("\n\n") + "\n\n"
78
+ end
60
79
  end
61
80
  end
@@ -19,7 +19,7 @@ module Exwiw
19
19
  def run
20
20
  adapter = Adapter.build(@connection_config, @logger)
21
21
  configs = load_table_config(adapter.class.table_config_class)
22
- configs = reject_and_validate_skipped(configs)
22
+ validate_skipped(configs)
23
23
 
24
24
  table_by_name = configs.each_with_object({}) { |config, hash| hash[config.name] = config }
25
25
 
@@ -31,8 +31,13 @@ module Exwiw
31
31
 
32
32
  total_size = ordered_table_names.size
33
33
  ordered_table_names.each_with_index do |table_name, idx|
34
- @logger.debug("Explaining '#{table_name}'... (#{idx + 1}/#{total_size})")
35
34
  table = table_by_name.fetch(table_name)
35
+ if table.skip
36
+ @logger.debug("Skipping explain for '#{table_name}' (skip:true)")
37
+ next
38
+ end
39
+
40
+ @logger.debug("Explaining '#{table_name}'... (#{idx + 1}/#{total_size})")
36
41
 
37
42
  query_ast = adapter.build_query(table, @dump_target, table_by_name)
38
43
  sql = adapter.compile_ast(query_ast)
@@ -54,9 +59,9 @@ module Exwiw
54
59
  end
55
60
  end
56
61
 
57
- private def reject_and_validate_skipped(configs)
62
+ private def validate_skipped(configs)
58
63
  skipped_names = configs.select { |c| c.skip }.map(&:name).to_set
59
- return configs if skipped_names.empty?
64
+ return if skipped_names.empty?
60
65
 
61
66
  configs.each do |config|
62
67
  next if config.skip
@@ -75,9 +80,6 @@ module Exwiw
75
80
  raise ArgumentError,
76
81
  "--target-table '#{@dump_target.table_name}' is marked skip:true and cannot be used as a dump target."
77
82
  end
78
-
79
- skipped_names.each { |n| @logger.info("Skipping table '#{n}' (skip:true)") }
80
- configs.reject { |c| c.skip }
81
83
  end
82
84
  end
83
85
  end
data/lib/exwiw/runner.rb CHANGED
@@ -30,7 +30,7 @@ module Exwiw
30
30
  adapter = Adapter.build(@connection_config, @logger)
31
31
  configs = load_table_config(adapter.class.table_config_class)
32
32
 
33
- configs = reject_and_validate_skipped(configs)
33
+ validate_skipped(configs)
34
34
 
35
35
  table_by_name = configs.each_with_object({}) { |config, hash| hash[config.name] = config }
36
36
 
@@ -51,9 +51,15 @@ module Exwiw
51
51
 
52
52
  total_size = ordered_table_names.size
53
53
  ordered_table_names.each_with_index do |table_name, idx|
54
- @logger.info("Processing table '#{table_name}'... (#{idx + 1}/#{total_size})")
55
54
  table = table_by_name.fetch(table_name)
56
55
 
56
+ if table.skip
57
+ @logger.info("Skipping data extraction for '#{table_name}' (skip:true)")
58
+ next
59
+ end
60
+
61
+ @logger.info("Processing table '#{table_name}'... (#{idx + 1}/#{total_size})")
62
+
57
63
  query_ast = adapter.build_query(table, @dump_target, table_by_name)
58
64
  results = adapter.execute(query_ast)
59
65
  record_num = results.size
@@ -123,9 +129,9 @@ module Exwiw
123
129
  end
124
130
  end
125
131
 
126
- private def reject_and_validate_skipped(configs)
132
+ private def validate_skipped(configs)
127
133
  skipped_names = configs.select { |c| c.skip }.map(&:name).to_set
128
- return configs if skipped_names.empty?
134
+ return if skipped_names.empty?
129
135
 
130
136
  configs.each do |config|
131
137
  next if config.skip
@@ -145,8 +151,7 @@ module Exwiw
145
151
  "--target-table '#{@dump_target.table_name}' is marked skip:true and cannot be used as a dump target."
146
152
  end
147
153
 
148
- skipped_names.each { |n| @logger.info("Skipping table '#{n}' (skip:true)") }
149
- configs.reject { |c| c.skip }
154
+ skipped_names.each { |n| @logger.info("Table '#{n}' is marked skip:true (schema will be included, data extraction skipped)") }
150
155
  end
151
156
  end
152
157
  end
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.2.1"
4
+ VERSION = "0.2.3"
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.2.1
4
+ version: 0.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shia