feat(orm): --resolve-relation CLI flag + ORM-minimizing docs#203
Conversation
The resolve_relations engine hook (pre-resolve relations in Polars so Odoo skips name_search) was only reachable programmatically / via a transform script. Add a repeatable --resolve-relation flag (source_column:model:key_field:relation_field [:xmlid|dbid]) that parses into the resolve_relations spec list. Also document the ORM-minimizing optimizations (pre-resolve relations, --skip-unchanged anti-join, side-effect suppression, --auto-clean) in the performance-tuning guide — they were implemented but undocumented. Parser + CLI tests included.
There was a problem hiding this comment.
Code Review
This pull request introduces a new --resolve-relation CLI option to pre-resolve relational columns in Polars before loading data into Odoo, minimizing Odoo's ORM work. It includes documentation updates, a parser helper, and unit tests. The review feedback suggests improving the parser validation to reject specs with empty fields (e.g., country::code:country_id) and adding corresponding test coverage for this validation.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| if len(parts) not in (4, 5): | ||
| raise click.BadParameter( | ||
| f"--resolve-relation {raw!r}: expected " | ||
| "'source_column:model:key_field:relation_field[:xmlid|dbid]'." | ||
| ) |
There was a problem hiding this comment.
The parser currently only checks the number of colon-separated parts, but does not verify if any of the required fields (the first four parts) are empty (e.g., country::code:country_id). If an empty string is parsed for the model or key field, it will lead to failures or unexpected behavior later during the Polars join or Odoo query. We should validate that all required parts are non-empty.
if len(parts) not in (4, 5) or not all(parts[:4]):
raise click.BadParameter(
f"--resolve-relation {raw!r}: expected "
"'source_column:model:key_field:relation_field[:xmlid|dbid]' "
"with non-empty fields."
)| def test_parse_rejects_wrong_part_count() -> None: | ||
| """A spec with too few parts is rejected.""" | ||
| with pytest.raises(click.BadParameter): | ||
| _parse_resolve_relation_specs(("country:res.country:code",)) |
There was a problem hiding this comment.
To ensure that the new validation for empty fields in the --resolve-relation spec is thoroughly tested, we should add a test case that verifies that specs with empty fields are rejected.
| def test_parse_rejects_wrong_part_count() -> None: | |
| """A spec with too few parts is rejected.""" | |
| with pytest.raises(click.BadParameter): | |
| _parse_resolve_relation_specs(("country:res.country:code",)) | |
| def test_parse_rejects_wrong_part_count() -> None: | |
| """A spec with too few parts is rejected.""" | |
| with pytest.raises(click.BadParameter): | |
| _parse_resolve_relation_specs(("country:res.country:code",)) | |
| def test_parse_rejects_empty_fields() -> None: | |
| """A spec with empty fields is rejected.""" | |
| with pytest.raises(click.BadParameter): | |
| _parse_resolve_relation_specs(("country::code:country_id",)) |
Validate the 4 required parts are non-empty (e.g. 'country::code:country_id' was accepted before), with a test.
|
Both applied: the parser now rejects specs with any empty required field ( |
|
This is already in — |
…ons-cli # Conflicts: # src/fluvo/__main__.py
Fills the two gaps found while auditing the (already-implemented) ORM-minimizing load path.
Context
The ORM-minimizing feature is essentially built:
export_id_map,Processor.resolve_relation, theresolve_relationsengine hook, the vectorized Polars anti-join inidempotent.py,--auto-clean, and thetest_orm_minimizing.pyacceptance e2e all exist. The e2e passes on real Odoo 18 (optimized-vs-naive parity, idempotency, timing — 21 e2e tests green). Two gaps remained:1.
--resolve-relationCLI flagThe
resolve_relationsengine hook (pre-resolve a relation in Polars so Odoo runs noname_search) was only reachable programmatically or from a transform script. This adds a repeatable CLI flag:fluvo import --connection-file conf/connection.conf --file partners.csv \ --model res.partner \ --resolve-relation country:res.country:code:country_idFormat:
source_column:model:key_field:relation_field[:xmlid|dbid]. Parsed into theresolve_relationsspec list (_parse_resolve_relation_specs), with validation. Parser + CLI tests included.2. Docs
The ORM-minimizing optimizations were implemented but undocumented (a docs audit found
resolve-relation,auto-clean,skip-unchanged, thename_search-avoidance rationale all at 0 doc files). Added a "Minimizing Odoo's ORM Work" section to the performance-tuning guide covering pre-resolving relations,--skip-unchanged, side-effect suppression, and--auto-clean.No behavior change to existing imports — the flag is additive and opt-in.