exwiw 0.2.9 → 0.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7e5d922e740407599ecb3fa3992e0de402434bacfb38ca817a189a53acf16ab3
4
- data.tar.gz: 2a8919778bb9395434587ebb69f49f4d8445cb1890e0999cb065b5577d802532
3
+ metadata.gz: e62483afc43054ae026c232502f40f6c1a92381a9c2c833ef1f7d603f6b845ae
4
+ data.tar.gz: 660a006272b9156bbc98af2a0c288f7943bdd40523adffc45de713b36a5d0426
5
5
  SHA512:
6
- metadata.gz: e38a240087564c3e3909106268fba7ad3a8dce881924f8b210b1733d65f0bc12d3bb514af80be21e6f0ad39707f99e96edbaed3cc7c54e2d26677c3a0c7d203f
7
- data.tar.gz: cca54067266034f8df074fce301623fd6c0c860e9fd1a13eac43d930b89f46a7b63d3e6230d155abcce3f6ab021c2299d518f8131d26ee5bcbe7c0a535093ee9
6
+ metadata.gz: 988813923c5e8a2aa1fd499c3af3a2d5467fc9a77b60664b1cd8d245ed1837a1cf43dc88a872bbbcfb7951902624e6b61fb50d290af6716a06c1fe8bb376ae6a
7
+ data.tar.gz: d8f751b794c20658c643ab2aeca769b01f7b50e9acc46c9605a4d7121d0d5fa8041bfbdad8021ede6bbfefc8cb36a937509120f25b7bdd059aaf6989f4c94e00
data/CHANGELOG.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.3.0] - 2026-05-31
6
+
5
7
  ## [0.2.9] - 2026-05-31
6
8
 
7
9
  ### Added
data/README.md CHANGED
@@ -67,6 +67,8 @@ exwiw \
67
67
  --log-level=info
68
68
  ```
69
69
 
70
+ By default `--ids` are matched against the target table's primary key. `--ids-column=COLUMN` matches them against a different column instead (e.g. `--target-table=users --ids=alice@example.com --ids-column=email`). Related tables are still extracted correctly: their foreign keys are resolved through the target via a subquery (`WHERE fk IN (SELECT pk FROM target WHERE COLUMN IN (...))`), so only the target table's filter column changes. This is the SQL-adapter counterpart of the mongodb `--ids-field`; the two are mutually exclusive and each is rejected by the other adapter family. Note: if `COLUMN` is itself masked, re-running `delete-*` against an already-imported (masked) dump won't match, so prefer a stable natural key.
71
+
70
72
  When `--target-table` and `--ids` are omitted, exwiw dumps all tables defined in `--config-dir`:
71
73
 
72
74
  ```bash
@@ -412,7 +414,7 @@ The MongoDB adapter is experimental. To use it:
412
414
  - The MongoDB adapter consumes a separate config type, `MongodbCollectionConfig`, with MongoDB-native naming. Use `fields` (instead of the SQL adapters' `columns`), and set `"primary_key": "_id"`. Foreign keys (`shop_id`, `user_id`, ...) stay as ordinary fields.
413
415
  - `--ids` values are coerced to the type actually stored in `_id` before filtering: integer-looking ids become `Integer`, 24-char hex ids become `BSON::ObjectId` (Mongoid's default `_id` type — a plain String would never match an ObjectId), and any other string is left as-is.
414
416
  - `--target-collection=COLLECTION` is a mongodb-only alias of `--target-table` (use whichever reads better for MongoDB). Specifying both, or using `--target-collection` with a non-mongodb adapter, is an error.
415
- - `--ids-field=FIELD` matches `--ids` against `FIELD` on the target collection instead of its primary key (e.g. `--target-collection=users --ids=a@example.com --ids-field=email`). Downstream foreign-key propagation still keys off the primary key, so only the target collection's filter changes. Unlike the primary-key path, the supplied ids are **not** type-coerced (the stored type of a custom field is unknown), so pass values matching the field's actual type. This flag is currently **mongodb-only** (the SQL adapters reject it; supporting them is a TODO).
417
+ - `--ids-field=FIELD` matches `--ids` against `FIELD` on the target collection instead of its primary key (e.g. `--target-collection=users --ids=a@example.com --ids-field=email`). Downstream foreign-key propagation still keys off the primary key, so only the target collection's filter changes. Unlike the primary-key path, the supplied ids are **not** type-coerced (the stored type of a custom field is unknown), so pass values matching the field's actual type. This flag is **mongodb-only**; the SQL adapters use `--ids-column` instead (see below).
416
418
  - Output is JSON Lines (`insert-{idx}-{collection}.jsonl`) using MongoDB Extended JSON (relaxed mode). Import with `mongoimport`:
417
419
  ```bash
418
420
  mongoimport --db app_dev --collection users --file dump/insert-002-users.jsonl
@@ -0,0 +1,93 @@
1
+ # `--ids-column` を SQL アダプタに実装
2
+
3
+ ## Context
4
+
5
+ MongoDB アダプタには `--ids-field` フラグがあり、`--ids` を対象テーブルの主キー以外の
6
+ フィールドにマッチさせられる(`lib/exwiw/adapter/mongodb_adapter.rb:48-65`)。一方で
7
+ SQL アダプタ(mysql2 / postgresql / sqlite3)では未実装で、CLI が明示的に拒否している
8
+ (`lib/exwiw/cli.rb:183-189` の TODO、`lib/exwiw/query_ast_builder.rb:109-118` の TODO)。
9
+
10
+ このプランでは同等の機能を SQL アダプタにも提供する。命名・ゲーティングは既存の
11
+ `--target-table` / `--target-collection` の分け方を踏襲し、**アダプタ別に厳密分離**する:
12
+
13
+ - `--ids-field` … mongodb 専用(既存)
14
+ - `--ids-column` … SQL アダプタ専用(新規)
15
+ - 両方同時指定は拒否、不適合アダプタとの組み合わせも拒否
16
+
17
+ 内部的には双方とも `DumpTarget#ids_field` に集約される(`--target-collection` が
18
+ `@target_table_name` に畳まれるのと同じパターン)。
19
+
20
+ ## 変更内容
21
+
22
+ ### 1. `lib/exwiw/cli.rb` — フラグ定義・畳み込み・バリデーション
23
+
24
+ - **インスタンス変数追加**(`initialize`, 42行目付近): `@ids_column = nil` を追加。
25
+ - **フラグ定義**(`parser`, 309行目付近): `--ids-field` の直後に追加。
26
+ ```ruby
27
+ opts.on("--ids-column=[COLUMN]", "Column on the target table that --ids is matched against. Defaults to the primary key. (sql adapters only)") { |v| @ids_column = v }
28
+ ```
29
+ - **エイリアス畳み込み**: `resolve_target_collection_alias!`(210行目)に倣い
30
+ `resolve_ids_column_alias!` を新設し `validate_options!` の冒頭で呼ぶ。挙動:
31
+ - `--ids-field` と `--ids-column` の同時指定を拒否
32
+ ("Specify only one of --ids-field and --ids-column")。
33
+ - `--ids-column` を mongodb で使った場合は拒否
34
+ ("--ids-column is only supported by the sql adapters (use --ids-field)")。
35
+ - 問題なければ `@ids_field = @ids_column` に畳み込む。
36
+ - **`--ids-field` の検証更新**(175-190行目):
37
+ - `--target-table` 必須チェックは「`@ids_field` が立っていれば」で共通化されるため、
38
+ 畳み込み後はそのまま両方をカバーする(メッセージは ids_field/ids_column を
39
+ 使った側に合わせて出し分けるか、汎用文言にする — 実装時に調整)。
40
+ - mongodb 限定チェック(186-189行目)は `--ids-field` 用に維持
41
+ ("--ids-field is currently only supported by the mongodb adapter" のまま)。
42
+
43
+ 実装方針: 畳み込み前にどちらのフラグが使われたかが分かる状態で
44
+ 「target-table 必須」「アダプタ整合」を検証してから `@ids_field` に集約する。
45
+
46
+ ### 2. `lib/exwiw/query_ast_builder.rb` — WHERE 句に反映
47
+
48
+ **当初の想定(1行変更)は関連テーブルで不正確になることが判明**したため、設計を変更した。
49
+ SQL アダプタは単一クエリで `dump_target.ids` を外部キーに直接伝播する
50
+ (`orders.user_id IN ids`)。これは `--ids` が主キーである前提のため、`--ids-column`
51
+ で別カラムを指定すると関連テーブルが壊れる(mongodb は @state に主キーを溜めて伝播する
52
+ ので正しい)。
53
+
54
+ 採用したアプローチ: **ターゲットを介すサブクエリ**。`ids_field` 指定時、外部キー制約を
55
+ `fk IN (SELECT pk FROM target WHERE ids_field IN (ids))` に置き換える。direct /
56
+ indirect / polymorphic を一律に正しく扱える。
57
+
58
+ - `lib/exwiw/query_ast.rb`: `Subquery` 構造体を追加。`WhereClause` に
59
+ operator `:in_subquery`(value が `Subquery`)を導入し `to_h` を対応。
60
+ - `lib/exwiw/query_ast_builder.rb`: `dump_target_fk_clause(foreign_key)` ヘルパーを新設。
61
+ `ids_field` 無しなら従来通り `eq`、有りなら `:in_subquery` を返す。
62
+ - `build_where_clauses`(direct belongs_to)と `build_join_clauses`
63
+ (indirect の `relation_to_dump_target` hop)の両方で利用。
64
+ - ターゲットテーブル自身のフィルタは `ids_field || primary_key` の `eq`(従来どおり)。
65
+ - 各 SQL アダプタ(postgresql / mysql2 / sqlite3)の `compile_where_condition` に
66
+ `:in_subquery` 分岐と `compile_subquery` を追加。`is_a?(WhereClause)` のままなので
67
+ bulk_delete のサブクエリ生成・JoinClause.to_h もそのまま動く。
68
+
69
+ 補足: `--ids-column` がマスク対象カラムの場合、`delete-*` の冪等性が崩れる
70
+ (README に注記済み)。
71
+
72
+ ## 検証
73
+
74
+ - `bundle exec rspec spec/cli_spec.rb` — 既存の `--ids-field` validation を維持しつつ、
75
+ 新規ケースを追加:
76
+ - `--ids-column` が `@ids_field`(畳み込み後)にパースされる
77
+ - `--ids-column` を mongodb で指定すると拒否される
78
+ - `--ids-field` と `--ids-column` の同時指定が拒否される
79
+ - `--ids-column` を target-table 無しで指定すると拒否される
80
+ - `bundle exec rspec spec/query_ast_builder_spec.rb`(存在すれば)に
81
+ `ids_field` 指定時に対象テーブルの WHERE が主キーではなく当該カラムになることを確認する
82
+ ケースを追加。
83
+ - `explain` サブコマンド(SQL のみ対応)で end-to-end 確認:
84
+ 既存 scenario(例 `scenario/sqlite3-schema`)に対し
85
+ `--target-table=... --ids=... --ids-column=<col>` を渡し、出力 SQL の WHERE が
86
+ `<table>.<col> IN (...)` になることを目視確認。
87
+ - `bundle exec rspec`(全体)でリグレッションが無いこと。
88
+
89
+ ## ドキュメント
90
+
91
+ `README.md:415` の `--ids-field` 説明を更新し、SQL では `--ids-column` を使う旨と例
92
+ (例: `--target-table=users --ids=a@example.com --ids-column=email`)を追記。
93
+ 「SQL adapters reject it / TODO」の記述を解消する。
@@ -201,11 +201,20 @@ module Exwiw
201
201
  else
202
202
  "#{key} IN (#{values.join(', ')})"
203
203
  end
204
+ elsif where_clause.operator == :in_subquery
205
+ "#{key} IN (#{compile_subquery(where_clause.value)})"
204
206
  else
205
207
  raise "Unsupported operator: #{where_clause.operator}"
206
208
  end
207
209
  end
208
210
 
211
+ private def compile_subquery(subquery)
212
+ inner_values = subquery.where_values.map { |v| escape_value(v) }
213
+ "SELECT #{subquery.table_name}.#{subquery.select_column} " \
214
+ "FROM #{subquery.table_name} " \
215
+ "WHERE #{subquery.table_name}.#{subquery.where_column} IN (#{inner_values.join(', ')})"
216
+ end
217
+
209
218
  private def escape_value(value)
210
219
  case value
211
220
  when nil
@@ -243,11 +243,20 @@ module Exwiw
243
243
  else
244
244
  "#{key} IN (#{values.join(', ')})"
245
245
  end
246
+ elsif where_clause.operator == :in_subquery
247
+ "#{key} IN (#{compile_subquery(where_clause.value)})"
246
248
  else
247
249
  raise "Unsupported operator: #{where_clause.operator}"
248
250
  end
249
251
  end
250
252
 
253
+ private def compile_subquery(subquery)
254
+ inner_values = subquery.where_values.map { |v| escape_value(v) }
255
+ "SELECT #{subquery.table_name}.#{subquery.select_column} " \
256
+ "FROM #{subquery.table_name} " \
257
+ "WHERE #{subquery.table_name}.#{subquery.where_column} IN (#{inner_values.join(', ')})"
258
+ end
259
+
251
260
  private def escape_value(value)
252
261
  case value
253
262
  when nil
@@ -188,11 +188,20 @@ module Exwiw
188
188
  else
189
189
  "#{key} IN (#{values.join(', ')})"
190
190
  end
191
+ elsif where_clause.operator == :in_subquery
192
+ "#{key} IN (#{compile_subquery(where_clause.value)})"
191
193
  else
192
194
  raise "Unsupported operator: #{where_clause.operator}"
193
195
  end
194
196
  end
195
197
 
198
+ private def compile_subquery(subquery)
199
+ inner_values = subquery.where_values.map { |v| escape_value(v) }
200
+ "SELECT #{subquery.table_name}.#{subquery.select_column} " \
201
+ "FROM #{subquery.table_name} " \
202
+ "WHERE #{subquery.table_name}.#{subquery.where_column} IN (#{inner_values.join(', ')})"
203
+ end
204
+
196
205
  private def escape_value(value)
197
206
  case value
198
207
  when nil
data/lib/exwiw/cli.rb CHANGED
@@ -40,6 +40,7 @@ module Exwiw
40
40
  @target_collection_name = nil
41
41
  @ids = []
42
42
  @ids_field = nil
43
+ @ids_column = nil
43
44
  @output_format = nil
44
45
  @insert_only = nil
45
46
  @after_insert_hook_path = nil
@@ -99,6 +100,7 @@ module Exwiw
99
100
 
100
101
  private def validate_options!
101
102
  resolve_target_collection_alias!
103
+ resolve_ids_column_alias!
102
104
 
103
105
  if @subcommand == "explain"
104
106
  validate_explain_only!
@@ -172,23 +174,6 @@ module Exwiw
172
174
  exit 1
173
175
  end
174
176
 
175
- if @ids_field
176
- # --ids-field overrides the field --ids filters against on the target
177
- # table; it is meaningless without a target table to constrain.
178
- if !@target_table_name
179
- $stderr.puts "--target-table is required when --ids-field is specified"
180
- exit 1
181
- end
182
-
183
- # TODO: support --ids-field for the sql adapters (mysql2/postgresql/
184
- # sqlite3) by threading dump_target.ids_field through QueryAstBuilder's
185
- # WHERE clause on the target table. For now it is mongodb-only.
186
- if @database_adapter != "mongodb"
187
- $stderr.puts "--ids-field is currently only supported by the mongodb adapter"
188
- exit 1
189
- end
190
- end
191
-
192
177
  if @after_insert_hook_path
193
178
  unless File.file?(@after_insert_hook_path)
194
179
  $stderr.puts "--after-insert-hook file not found: #{@after_insert_hook_path}"
@@ -223,6 +208,43 @@ module Exwiw
223
208
  @target_table_name = @target_collection_name
224
209
  end
225
210
 
211
+ # `--ids-column` is the sql-adapter spelling of `--ids-field` (the mongodb
212
+ # spelling). Both override which column/field `--ids` is matched against on
213
+ # the target table; internally they fold into the single @ids_field carried
214
+ # by DumpTarget. Mirror the --target-table/--target-collection split: each
215
+ # flag is restricted to its adapter family and the two are mutually
216
+ # exclusive. Runs after resolve_target_collection_alias! so
217
+ # @target_table_name already reflects the collection alias.
218
+ private def resolve_ids_column_alias!
219
+ if @ids_field && @ids_column
220
+ $stderr.puts "Specify only one of --ids-field and --ids-column"
221
+ exit 1
222
+ end
223
+
224
+ if @ids_field && @database_adapter != "mongodb"
225
+ $stderr.puts "--ids-field is only supported by the mongodb adapter (use --ids-column)"
226
+ exit 1
227
+ end
228
+
229
+ if @ids_column
230
+ sql_adapters = ["mysql2", "postgresql", "sqlite3"]
231
+ unless sql_adapters.include?(@database_adapter)
232
+ $stderr.puts "--ids-column is only supported by the sql adapters (use --ids-field)"
233
+ exit 1
234
+ end
235
+
236
+ @ids_field = @ids_column
237
+ end
238
+
239
+ # --ids-field/--ids-column override the column --ids filters against on
240
+ # the target table; meaningless without a target table to constrain.
241
+ if @ids_field && !@target_table_name
242
+ flag = @ids_column ? "--ids-column" : "--ids-field"
243
+ $stderr.puts "--target-table is required when #{flag} is specified"
244
+ exit 1
245
+ end
246
+ end
247
+
226
248
  private def validate_explain_only!
227
249
  if @database_adapter == "mongodb"
228
250
  $stderr.puts "mongodb adapter is not yet supported by 'explain' subcommand"
@@ -306,7 +328,8 @@ module Exwiw
306
328
  opts.on("--target-table=[TABLE]", "Target table for extraction. If omitted, dump all tables.") { |v| @target_table_name = v }
307
329
  opts.on("--target-collection=[COLLECTION]", "Alias of --target-table for the mongodb adapter.") { |v| @target_collection_name = v }
308
330
  opts.on("--ids=[IDS]", "Comma-separated list of identifiers. Required when --target-table is given.") { |v| @ids = v.split(',') }
309
- opts.on("--ids-field=[FIELD]", "Field on the target table that --ids is matched against. Defaults to the primary key. (mongodb adapter only)") { |v| @ids_field = v }
331
+ opts.on("--ids-field=[FIELD]", "Field on the target collection that --ids is matched against. Defaults to the primary key. (mongodb adapter only)") { |v| @ids_field = v }
332
+ opts.on("--ids-column=[COLUMN]", "Column on the target table that --ids is matched against. Defaults to the primary key. (sql adapters only)") { |v| @ids_column = v }
310
333
  opts.on("--output-format=[FORMAT]", "Output format: insert (default) or copy (PostgreSQL only, dump subcommand only)") { |v| @output_format = v }
311
334
  opts.on("--insert-only", "Do not generate DELETE SQL files (dump subcommand only)") { @insert_only = true }
312
335
  opts.on("--after-insert-hook=PATH", "Path to a .rb or .sh post-processing hook executed after all insert/delete files are written (dump subcommand only)") do |v|
@@ -41,7 +41,26 @@ module Exwiw
41
41
  {
42
42
  column_name: column_name,
43
43
  operator: operator,
44
- value: value,
44
+ value: value.is_a?(Subquery) ? value.to_h : value,
45
+ }
46
+ end
47
+ end
48
+
49
+ # Resolves a set of values on `where_column` to the rows' `select_column`
50
+ # via a nested SELECT. Used as the `value` of a WhereClause whose operator
51
+ # is `:in_subquery`, so `--ids-column`/`--ids-field` can filter related
52
+ # tables through the target table's primary key:
53
+ #
54
+ # <table>.<fk> IN (SELECT <table_name>.<select_column>
55
+ # FROM <table_name>
56
+ # WHERE <table_name>.<where_column> IN (<where_values>))
57
+ Subquery = Struct.new(:table_name, :select_column, :where_column, :where_values, keyword_init: true) do
58
+ def to_h
59
+ {
60
+ table_name: table_name,
61
+ select_column: select_column,
62
+ where_column: where_column,
63
+ where_values: where_values,
45
64
  }
46
65
  end
47
66
  end
@@ -73,11 +73,7 @@ module Exwiw
73
73
  end
74
74
  relation_to_dump_target = to_table.belongs_to(dump_target.table_name)
75
75
  if relation_to_dump_target
76
- join_clause.where_clauses.push QueryAst::WhereClause.new(
77
- column_name: relation_to_dump_target.foreign_key,
78
- operator: :eq,
79
- value: dump_target.ids
80
- )
76
+ join_clause.where_clauses.push dump_target_fk_clause(relation_to_dump_target.foreign_key)
81
77
 
82
78
  # 中間テーブルが dump target へ polymorphic belongs_to している場合は、
83
79
  # 型カラム (foreign_type) も join 条件に追加する。型カラムは to_table
@@ -107,12 +103,12 @@ module Exwiw
107
103
  clauses = []
108
104
 
109
105
  if table.name == dump_target.table_name
110
- # TODO: honor dump_target.ids_field here so `--ids` can match a non
111
- # primary-key column on the target table (currently mongodb-only; the
112
- # CLI rejects --ids-field for the sql adapters). When implemented, use
113
- # `dump_target.ids_field || table.primary_key` as the column_name.
106
+ # `--ids-column` (folded into dump_target.ids_field by the CLI) lets
107
+ # `--ids` match a non primary-key column on the target table; otherwise
108
+ # fall back to the primary key. Only the target table's filter changes —
109
+ # downstream foreign-key propagation still keys off the primary key.
114
110
  clauses.push Exwiw::QueryAst::WhereClause.new(
115
- column_name: table.primary_key,
111
+ column_name: dump_target.ids_field || table.primary_key,
116
112
  operator: :eq,
117
113
  value: dump_target.ids
118
114
  )
@@ -123,11 +119,7 @@ module Exwiw
123
119
  belongs_to = table.belongs_to(dump_target.table_name)
124
120
  return clauses if belongs_to.nil?
125
121
 
126
- clauses.push Exwiw::QueryAst::WhereClause.new(
127
- column_name: belongs_to.foreign_key,
128
- operator: :eq,
129
- value: dump_target.ids
130
- )
122
+ clauses.push dump_target_fk_clause(belongs_to.foreign_key)
131
123
 
132
124
  # polymorphic belongs_to の場合は外部キーだけでは型を区別できないため
133
125
  # (例: reviewable_id=1 が Product なのか別モデルなのか判別できない)、
@@ -147,6 +139,36 @@ module Exwiw
147
139
  clauses
148
140
  end
149
141
 
142
+ # Builds the WHERE clause that constrains a `foreign_key` pointing at the
143
+ # dump target. Normally `--ids` are the target's primary keys, so a plain
144
+ # `foreign_key IN (ids)` suffices. When `--ids-column`/`--ids-field` is set
145
+ # (dump_target.ids_field), `--ids` match a non primary-key column instead,
146
+ # so the foreign key must be resolved through the target table:
147
+ # `foreign_key IN (SELECT pk FROM target WHERE ids_field IN (ids))`.
148
+ # This keeps related-table extraction correct regardless of whether the
149
+ # relation is direct, indirect, or polymorphic.
150
+ private def dump_target_fk_clause(foreign_key)
151
+ unless dump_target.ids_field
152
+ return Exwiw::QueryAst::WhereClause.new(
153
+ column_name: foreign_key,
154
+ operator: :eq,
155
+ value: dump_target.ids
156
+ )
157
+ end
158
+
159
+ target = table_by_name.fetch(dump_target.table_name)
160
+ Exwiw::QueryAst::WhereClause.new(
161
+ column_name: foreign_key,
162
+ operator: :in_subquery,
163
+ value: Exwiw::QueryAst::Subquery.new(
164
+ table_name: target.name,
165
+ select_column: target.primary_key,
166
+ where_column: dump_target.ids_field,
167
+ where_values: dump_target.ids
168
+ )
169
+ )
170
+ end
171
+
150
172
  private def find_path_to_dump_target(table, table_by_name, dump_target)
151
173
  return [] if table.name == dump_target.table_name
152
174
 
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.9"
4
+ VERSION = "0.3.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.2.9
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shia
@@ -40,6 +40,7 @@ files:
40
40
  - docs/plans/2026-05-22-after-insert-hook.md
41
41
  - docs/plans/2026-05-22-postgres-copy-mode-scenario-test.md
42
42
  - docs/plans/2026-05-29-rails-managed-tables.md
43
+ - docs/plans/2026-05-31-ids-column-for-sql-adapters.md
43
44
  - exe/exwiw
44
45
  - lib/exwiw.rb
45
46
  - lib/exwiw/adapter.rb