exwiw 0.2.5 → 0.2.6

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: d4b63b89a56ddce55ea6dc835bde4052b9140cff4b24da6cb9c05d5cac7d0f59
4
- data.tar.gz: a567c52917014798129638281c90d66f9f7102db624f8b601dd9e025d4351677
3
+ metadata.gz: 2ff943aae77c0ed0f79dc80c2e68527badcae7c6b330e89aec6a019adf0dd1e5
4
+ data.tar.gz: 8a146a76aea7ab0bd3aeabb27ccf789f575f86e1d965b64b2432c250addb003b
5
5
  SHA512:
6
- metadata.gz: 0d782a227fb06e75ac28d35a636f28ccb224dd1c1eb1aad7015863bd8365082be6f51c948f3e7beafbca12d10ac1162af9170e1e064f07a7ca7b64e1433a71d4
7
- data.tar.gz: 994f8795368c96bc9f773526da33cf8f3d024eac6fcb0665e028f3fc8bd2f67fc5424d4e2e3ada7e91d7a3eb4e2906bd2464d18c4da01d134ba051426e49b9e0
6
+ metadata.gz: 6dbd0212c4ca02aba3839f17bfe7fc45283f17cb7264d903527fbafda04a4cc9b5c756762a1422fae549b143a60ec825669581311ada63972c2288bdb744e47c
7
+ data.tar.gz: 6364942e8ee51055eb2ed2bffc16995b1a19c64b977790fa8ff4222742f034ae6d4b0b7410f779f70655bb2d6d3ea33af7321853727a2c9300adcdcbd45fc763
data/CHANGELOG.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.2.6] - 2026-05-29
6
+
7
+ ### Added
8
+
9
+ - `schema:generate` now supports Rails multiple-database setups (`connects_to`). Models are bucketed by their database (`connection_db_config.name`, e.g. `primary` / `analytics`) and each database's config files are written into its own subdirectory under `OUTPUT_DIR_PATH` (`exwiw/primary/`, `exwiw/analytics/`, ...). Rails-managed tables (`schema_migrations` / `ar_internal_metadata`) are emitted under whichever database actually owns them. Single-database apps are unaffected and still write flat into the output directory. This replaces the previous behavior of raising `MultipleDatabasesNotSupportedError`.
10
+
5
11
  ## [0.2.5] - 2026-05-29
6
12
 
7
13
  ### Added
data/README.md CHANGED
@@ -128,6 +128,22 @@ By default, the schema files will be saved in the `exwiw` directory. You can spe
128
128
  OUTPUT_DIR_PATH=custom_directory bundle exec rake exwiw:schema:generate
129
129
  ```
130
130
 
131
+ #### Multiple databases
132
+
133
+ If the application uses Rails' multiple-database support (`connects_to`), `schema:generate` buckets models by the database they connect to and writes each database's config files into its own subdirectory of the output directory, named after the database config name (`primary`, `analytics`, ...):
134
+
135
+ ```
136
+ exwiw/
137
+ primary/
138
+ shops.json
139
+ users.json
140
+ schema_migrations.json
141
+ analytics/
142
+ analytics_events.json
143
+ ```
144
+
145
+ Rails-managed tables (`schema_migrations` / `ar_internal_metadata`) are emitted under whichever database actually contains them. Single-database applications are unaffected and continue to write files flat into the output directory.
146
+
131
147
  ### Configuration
132
148
 
133
149
  This is an example of the one table schema:
@@ -250,7 +266,7 @@ Constraints:
250
266
 
251
267
  - Defining `primary_key`, `columns`, or `belongs_tos` on a rails-managed entry is rejected with `ArgumentError` on load.
252
268
  - A rails-managed table cannot be used as `--target-table`.
253
- - Multi-database setups are not yet supported the table name is read from the global `ActiveRecord::Base` accessor.
269
+ - In multi-database setups, the rails-managed entry is emitted under whichever database's connection actually contains the table (see [Multiple databases](#multiple-databases)). The table name itself is still derived from the global `ActiveRecord::Base.schema_migrations_table_name` / `internal_metadata_table_name` (prefix/suffix) accessors.
254
270
 
255
271
  ### Bulk insert chunk size
256
272
 
@@ -5,8 +5,6 @@ require "json"
5
5
 
6
6
  module Exwiw
7
7
  class SchemaGenerator
8
- class MultipleDatabasesNotSupportedError < StandardError; end
9
-
10
8
  def self.from_rails_application(output_dir:)
11
9
  Rails.application.eager_load!
12
10
  new(models: ActiveRecord::Base.descendants, output_dir: output_dir)
@@ -18,33 +16,53 @@ module Exwiw
18
16
  end
19
17
 
20
18
  def generate!
21
- tables = build_tables
22
- write_files(tables)
23
- tables
19
+ groups = build_table_groups
20
+ write_groups(groups)
21
+ groups
24
22
  end
25
23
 
26
- def build_tables
24
+ # Returns a Hash keyed by the database name.
25
+ #
26
+ # - Single-database setup: the only key is `nil`, signalling that the table
27
+ # configs should be written flat into `output_dir` (backwards compatible).
28
+ # - Multi-database setup (Rails `connects_to`): one key per database
29
+ # (`connection_db_config.name`, e.g. "primary" / "analytics"), each
30
+ # mapping to that database's table configs. They are written into
31
+ # `output_dir/<db_name>/`.
32
+ def build_table_groups
27
33
  models = concrete_models
28
- validate_single_database!(models)
34
+ grouped = models.group_by { |model| database_name_for(model) }
29
35
 
30
- tables_from_models = models.group_by(&:table_name).map do |table_name, model_group|
31
- representative = model_group.first
32
- TableConfig.from_symbol_keys(
33
- name: table_name,
34
- primary_key: representative.primary_key,
35
- belongs_tos: aggregate_belongs_tos(model_group),
36
- columns: representative.column_names.map { |name| { name: name } },
37
- )
36
+ if grouped.size <= 1
37
+ conn = models.empty? ? ActiveRecord::Base.connection : models.first.connection
38
+ return { nil => build_tables_for(models, conn) }
38
39
  end
39
40
 
40
- tables_from_models + build_rails_managed_tables
41
+ grouped.each_with_object({}) do |(db_name, group_models), result|
42
+ conn = group_models.first.connection
43
+ result[db_name] = build_tables_for(group_models, conn)
44
+ end
41
45
  end
42
46
 
43
- def write_files(tables)
44
- FileUtils.mkdir_p(@output_dir)
47
+ # Backwards-compatible flat list of all table configs. Only meaningful for
48
+ # a single-database setup; for multi-database setups prefer
49
+ # `#build_table_groups` so the database association is preserved.
50
+ def build_tables
51
+ build_table_groups.values.flatten
52
+ end
53
+
54
+ def write_groups(groups)
55
+ groups.each do |db_name, tables|
56
+ dir = db_name.nil? ? @output_dir : File.join(@output_dir, db_name)
57
+ write_files(dir, tables)
58
+ end
59
+ end
60
+
61
+ def write_files(dir, tables)
62
+ FileUtils.mkdir_p(dir)
45
63
 
46
64
  tables.each do |table|
47
- path = File.join(@output_dir, "#{table.name}.json")
65
+ path = File.join(dir, "#{table.name}.json")
48
66
  config_to_write =
49
67
  if File.exist?(path)
50
68
  TableConfig.from(JSON.parse(File.read(path))).merge(table)
@@ -55,20 +73,31 @@ module Exwiw
55
73
  end
56
74
  end
57
75
 
76
+ private def build_tables_for(models, conn)
77
+ tables_from_models = models.group_by(&:table_name).map do |table_name, model_group|
78
+ representative = model_group.first
79
+ TableConfig.from_symbol_keys(
80
+ name: table_name,
81
+ primary_key: representative.primary_key,
82
+ belongs_tos: aggregate_belongs_tos(model_group),
83
+ columns: representative.column_names.map { |name| { name: name } },
84
+ )
85
+ end
86
+
87
+ tables_from_models + build_rails_managed_tables(conn)
88
+ end
89
+
58
90
  private def concrete_models
59
91
  @models.reject(&:abstract_class?).select(&:table_exists?)
60
92
  end
61
93
 
62
- # NOTE: multi-database setup には未対応。`ActiveRecord::Base.schema_migrations_table_name`
63
- # `internal_metadata_table_name` はクラスレベルのグローバル設定を返すため、
64
- # connection 毎にテーブル名が違うケース (`connects_to` で別 DB を扱う場合や
65
- # `ActiveRecord::Base` 以外で `connection.schema_migration.table_name` を上書きしている場合)
66
- # を拾えない。現状は `validate_single_database!` で multi-DB を弾いているので
67
- # ここに到達するのは単一 DB 構成のみという前提で動いている。
68
- # multi-DB 対応する際は、対象の connection に紐づく schema_migration から
69
- # テーブル名を取り、connection 毎にエントリを生成する必要がある。
70
- private def build_rails_managed_tables
71
- conn = ActiveRecord::Base.connection
94
+ # rails-managed テーブル (`schema_migrations` / `ar_internal_metadata`) は
95
+ # モデルクラスを持たないため `ActiveRecord::Base.descendants` からは拾えない。
96
+ # multi-DB 構成では各 connection が独立した migration 履歴テーブルを持つので、
97
+ # 対象 connection を受け取り、その connection 上に該当テーブルが存在する場合のみ
98
+ # エントリを生成する。テーブル名そのものは prefix/suffix を含むグローバル設定
99
+ # (`ActiveRecord::Base.schema_migrations_table_name` 等) から得る。
100
+ private def build_rails_managed_tables(conn)
72
101
  result = []
73
102
 
74
103
  schema_migrations_name = ActiveRecord::Base.schema_migrations_table_name
@@ -108,22 +137,13 @@ module Exwiw
108
137
  end
109
138
  end
110
139
 
111
- # `connection_specification_name` is a quasi-private API but has been stable
112
- # across Rails 6.1 - 8.x. With Rails multi-DB (`connects_to`), every
113
- # descendant of the same abstract base shares one spec name regardless of
114
- # role/shard, so distinct values across concrete models indicate genuinely
115
- # separate databases.
116
- private def validate_single_database!(models)
117
- return if models.empty?
118
-
119
- specs = models.map(&:connection_specification_name).uniq
120
- return if specs.size <= 1
121
-
122
- raise MultipleDatabasesNotSupportedError, <<~MSG
123
- exwiw does not yet support Rails multiple-database setup.
124
- Detected connection specifications: #{specs.inspect}
125
- Track progress at https://github.com/riseshia/exwiw/issues
126
- MSG
140
+ # Identifies which database a model belongs to. With Rails multi-DB
141
+ # (`connects_to` backed by `database.yml`), `connection_db_config.name`
142
+ # returns the configuration name ("primary", "analytics", ...) which is
143
+ # stable across roles/shards and makes a natural per-database directory
144
+ # name. Single-database apps all share one name, collapsing into one group.
145
+ private def database_name_for(model)
146
+ model.connection_db_config.name
127
147
  end
128
148
  end
129
149
  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.5"
4
+ VERSION = "0.2.6"
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.5
4
+ version: 0.2.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shia