Skip to content

feat(ogar-adapter-surrealql): emit array<record> for to-many associations (#2 Stage A)#136

Merged
AdaWorldAPI merged 1 commit into
mainfrom
claude/odoo-rs-transcode-lf8ya5
Jun 29, 2026
Merged

feat(ogar-adapter-surrealql): emit array<record> for to-many associations (#2 Stage A)#136
AdaWorldAPI merged 1 commit into
mainfrom
claude/odoo-rs-transcode-lf8ya5

Conversation

@claude

@claude claude Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

#2 Stage A (from the odoo-rs #19 thinning roadmap): close W3.3's
"One2many/Many2many array<record>" emitter gap so the shared SurrealQL emitter
covers to-many relations — the prerequisite for deleting od-ontology's native
emit fork.

Before, emit_field_assoc rendered only the owning side and dropped to-many
associations to a comment. Now that the lift carries the association (OGAR #132
relation_kind → HasMany/HasAndBelongsToMany + comodel), it renders:

kind Odoo emit
BelongsTo Many2one record<X> / option<record<X>> (unchanged)
HasMany One2many array<record<X>>
HasAndBelongsToMany Many2many array<record<X>>
HasOne (Rails-only) comment marker (unchanged)

Target handling mirrors the owning-side record<X> exactly (dotted Odoo
comodels quoted) — no new normalization.

Scoped deferrals (documented, not silent):

  • The One2many computed VALUE <-comodel.<inverse> READONLY reverse-link is
    the separate W3.3 "computed VALUE" gap — deferred; this lands the structural
    array TYPE.
  • Parse-back of array<record<…>> is the companion surrealdb-parser
    follow-up; today's walk recovers the owning-side record<X> only (the same
    emit-richer-than-parse asymmetry the prior comment-marker had). The gated
    round-trip tests cover BelongsTo + primitives and are unaffected.

Test Plan

Probe-verified (default features, no surrealdb — the emit side is pure
string-gen): 22 tests pass, 3 new (emit_class_with_has_many_renders_array_of_record,
..._has_and_belongs_to_many_..., ..._has_one_keeps_non_owning_comment),
clippy -D warnings clean. The OGAR workspace's surrealdb-parser leg builds
on CI.

🤖 Generated with Claude Code


Generated by Claude Code

…ions (#2 Stage A)

W3.3's "One2many/Many2many array<record>" emitter gap: the shared SurrealQL
emitter rendered only the owning side (BelongsTo → record<X>) and dropped
to-many associations to a comment marker. Now that the lift carries the
association (OGAR #132 `relation_kind` → HasMany/HasAndBelongsToMany + comodel),
`emit_field_assoc` renders both as `array<record<comodel>>`:

- BelongsTo (Many2one)            -> record<X> / option<record<X>>   (unchanged)
- HasMany (One2many)              -> array<record<X>>                 (NEW)
- HasAndBelongsToMany (Many2many) -> array<record<X>>                 (NEW)
- HasOne (Rails-only, non-owning) -> comment marker                  (unchanged)

Target handling mirrors the owning-side record<X> exactly (dotted Odoo comodels
are quoted), so no new normalization. The One2many *computed* `VALUE
<-comodel.<inverse> READONLY` reverse-link is the separate W3.3 "computed VALUE"
gap and is deferred; this lands the structural array TYPE. Parse-back of
`array<record<…>>` is the companion `surrealdb-parser` follow-up — today's
`walk` recovers the owning-side record<X> only (same emit-richer-than-parse
asymmetry the prior comment-marker had; the gated round-trip tests cover
BelongsTo + primitives, unaffected).

This is #2 Stage A from odoo-rs #19 — it unblocks deleting od-ontology's native
emit fork (W3.3) once the shared emitter covers the schema.

Verified via probe (default features, no surrealdb): 22 tests pass (3 new:
has_many/has_and_belongs_to_many → array<record>, has_one → comment),
clippy -D warnings clean. The emit side is pure string-gen (no surrealdb);
the OGAR workspace's surrealdb-parser leg builds on CI.

Co-Authored-By: Claude <noreply@anthropic.com>
@AdaWorldAPI AdaWorldAPI merged commit f93aae4 into main Jun 29, 2026
1 check passed
AdaWorldAPI pushed a commit that referenced this pull request Jun 29, 2026
…§1.5)

Operator correction (2026-06-29): the facet "versions" are useless because one
compiled ClassView recombines all the carvings while sinking into OGAR and
getting COMPILED into the binary — NOT parsed from SurrealQL (slow even with
JIT). Captures the load-bearing architecture so future sessions invest in the
spine, not the membrane:

- New §1.5 — the compiled ClassView spine:
  a. recombines the facet layout (6×(1:2) / 4×(1:2:3) / 3×(1:2:3:4)) — no
     hardcoded V1/V2/V3 facet "versions"; one compiled reader subsumes them.
  b. sub-range hierarchy mapping (e.g. 1..3 of 12) + NESTED ClassViews stacked
     into compiled CONSTRUCTORS (composition of compiled readers, not a runtime
     interpreter).
  c. lazy + lazy-lock-reused materialization of the 32×GUID SoA (build once on
     first touch; the key prerenders nodes with zero value-decode).
  + why compiled beats parsed, and where SurrealQL sits (storage membrane,
    never the hot path — ADR-022/023).
- §1 pull-back reframed: modes are NOT co-equal — (a) compiled ClassView =
  spine/hot-path; (b) SurrealQL emit = storage-membrane adapter.
- §6 re-prioritised: the compiled ClassView spine is THE priority; #136 Stage A
  (array<record>) and the od-ontology fork-deletion are membrane work,
  secondary. Tier-byte arithmetic of each carving to be pinned against
  FacetCascade before coding — not guessed.

Co-Authored-By: Claude <noreply@anthropic.com>
AdaWorldAPI pushed a commit that referenced this pull request Jun 30, 2026
…sembler

Adds the keystone gap named in E-KEEP-AR-REMOVE-ORM / the OP convergence
assessment: a Rails-correct sibling of compile_graph_python. Identical
shape (mint_graph::<P> + per-class facet resolution) but routes through
the existing lift_model_graph (Language::Ruby) instead of
lift_model_graph_python — pure operator-reuse, no new lift, and
project_odoo_fields is correctly never invoked for Rails (it would
double-count; lift_model_graph_python's own doc-comment says so).

Proves the convergence claim in code: compile_graph_ruby::<OpenProjectPort>
on a WorkPackage graph and compile_graph_ruby::<RedminePort> on an Issue
graph mint to the SAME low-u16 concept (0x0102 project_work_item) and
DIFFERENT high-u16 render prefixes (0x0001 vs 0x0007) — one canonical
concept, two render skins, machine-checked rather than asserted.

Drive-by fix: 3 pre-existing Function{...} literal constructions
(emit.rs, mint.rs's account_move fixture, lib.rs) broke against the
already-merged ruff#38 (writes/calls fields) because this crate's
ruff_spo_triplet dep floats on branch=main. Added ..Default::default()
to each — no behavior change, restores compilation.

Verification: standalone probe workspace (path-dep ogar-vocab +
ogar-from-ruff, git-dep ruff branch=main) — the OGAR workspace itself
can't resolve in-sandbox (ogar-adapter-surrealql's surrealdb-ast git dep
403s), the same pattern prior PRs (#131/#132/#136/#138/#141) used.
44/44 tests pass (3 new + 41 pre-existing unbroken); clippy --no-deps
-D warnings clean at the pinned 1.95.0 toolchain (ogar-vocab itself has
pre-existing unrelated clippy debt from never being --workspace-gated,
out of scope here); doc-links resolve.
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