Skip to content

Emit one MongoDB embedded config per (parent, path) occurrence#164

Open
nyancat3 wants to merge 2 commits into
mainfrom
feat/mongodb-multi-path-embedded-config
Open

Emit one MongoDB embedded config per (parent, path) occurrence#164
nyancat3 wants to merge 2 commits into
mainfrom
feat/mongodb-multi-path-embedded-config

Conversation

@nyancat3

@nyancat3 nyancat3 commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

背景

Mongoid スキーマ生成タスク(rake exwiw:schema:generate_mongoid)は、モデルをコレクション名でグルーピングし、埋め込みドキュメントのクラスごとに 1 つだけ 設定ファイルを出力していた。しかし同じ埋め込みクラスが複数の (親コレクション, パス) に埋め込まれている場合(親をまたいで再利用される値オブジェクト、あるいは 1 つの親の複数キーに埋め込まれるケース)、生成される embedded_in は 1 箇所ぶんだけになる。

その結果、そのクラスに対して宣言したフィールド単位のマスキング(replace_with / ignore)は 1 箇所にしか効かず、他の埋め込み箇所は素のままダンプされてしまう。

一方でランタイム(MongodbAdapter)は、埋め込み設定を (embedded_in.collection_name, path) ごとに独立して適用できる作りになっている。ギャップは生成側にのみ存在していた。

対応

  • 全モデルの embeds_one / embeds_many を走査して、埋め込みクラスの (親コレクション, パス) の出現箇所をすべて発見し、出現箇所ごとに 1 つの設定を出力するようにした。
  • クラスが宣言している embedded_in に一致する出現箇所は、従来どおりコレクション名そのままの名前を維持する。これにより:
    • 単一箇所のみの埋め込み(既存の大多数)は出力が完全に不変(ファイル名・スナップショットとも同一)。
    • 後から 2 箇所目が増えても、既存ファイルはリネームされず、追加ぶんのファイルだけが増える。
  • 追加の出現箇所は、親コレクションとパスで一意化した名前(例: addresses__shipments__address)を付与。ランタイムはこの名前ではなく embedded_in でサブドキュメントを解決するため、名前は識別子・ファイル名としてのみ機能する。
  • 再生成時は各出現箇所を自分のファイルに対してマージするため、出現箇所ごとのハンドエディット(マスキング)が保持される。

補足(耐久性の確認)

  • MongoDB/Mongoid 系には schema:tidy は存在せず(tidy は ActiveRecord 版 SchemaGenerator のみ)、write_files は生成対象外のファイルを削除しない。したがって出現箇所ごとの設定ファイルが再生成で削除されることはない。

テスト

  • 共有埋め込みクラスを 2 箇所に埋め込んだフィクスチャを追加(MODELS/SEED には含めず、既存のスナップショット/件数コントラクトに影響なし)。
  • 追加した spec:
    • 出現箇所ごとに別名・別 embedded_in の設定が生成される
    • 単一箇所では従来どおりコレクション名そのままで、一意化サフィックスは付かない
    • 出現箇所ごとに JSON ファイルが書き出される
    • 再生成で両ファイルが残り、各出現箇所のマスキングが独立して保持される
    • 生成設定が MongodbAdapter のマスキングを両箇所で駆動する(エンドツーエンド)
  • bundle exec rspec: 699 examples, 0 failures。

nyancat3 and others added 2 commits July 9, 2026 12:42
The Mongoid schema generator grouped models by collection name and emitted
a single embedded config bound to one embedded_in, so an embedded class
embedded at more than one (parent, path) place got a config for only one
occurrence; per-field masking declared for that class applied at that single
location while every other occurrence dumped raw.

Discover every occurrence by scanning all models' embeds_one/embeds_many
relations and emit one config per occurrence. The occurrence matching the
class's declared embedded_in keeps the plain collection name (existing
single-occurrence output is byte-for-byte unchanged and never renamed when a
second occurrence later appears); each additional occurrence gets a name
disambiguated by its parent collection and path. Each occurrence merges
against its own file on regeneration, preserving hand-edited masks per
occurrence.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the Mongoid schema generator so that when the same embedded class appears in multiple distinct (parent collection, path) locations, exwiw emits one embedded config per occurrence rather than a single config per embedded class/collection—ensuring masking rules apply everywhere the value object is embedded.

Changes:

  • Extend Exwiw::MongoidSchemaGenerator to discover embedded occurrences by scanning all models’ embeds_one / embeds_many relations and emit one config per (parent, path) occurrence.
  • Add dummy Mongoid models + specs covering multi-occurrence emission, per-occurrence file output, regeneration durability, and end-to-end masking via MongodbAdapter.
  • Update README and CHANGELOG to document the new behavior.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
spec/mongoid_schema_generator_spec.rb Adds specs validating per-occurrence config emission, file persistence across regen, and adapter-driven masking correctness.
script/mongoid_models.rb Adds isolated dummy models representing a shared embedded value object used in two distinct (parent, path) locations.
README.md Documents per-occurrence embedded config behavior and provides an illustrative example.
lib/exwiw/mongoid_schema_generator.rb Implements embedding occurrence indexing and multi-occurrence config emission.
CHANGELOG.md Notes the new generator behavior under Unreleased.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +88 to 96
private def build_configs_for(collection_name, models, existing_by_name, embedding_index)
occurrences = embedding_index[collection_name]

if models.any?(&:embedded?) && occurrences.size >= 2
build_multi_occurrence_configs(collection_name, models, occurrences, existing_by_name)
else
[build_collection_for(collection_name, models, existing_by_name[collection_name])]
end
end
Comment on lines +229 to +234
declared =
begin
embedded_in_for(models.find(&:embedded?))
rescue StandardError
nil
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants