Skip to content

Bidirectional ManyToOne: generate inverse collection + join allowlist - #127

Merged
cultron merged 4 commits into
mainfrom
feat/bidirectional-manytoone-joins
Aug 13, 2026
Merged

Bidirectional ManyToOne: generate inverse collection + join allowlist#127
cultron merged 4 commits into
mainfrom
feat/bidirectional-manytoone-joins

Conversation

@cultron

@cultron cultron commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

What

A declared ManyToOne relationship now generates both sides, mirroring how OneToMany already works: the target entity gets the inverse collection property and the controller join allowlist.

Why

The AI schema builder declares relationships as Book →ManyToOne→ Author. The parser only generated the FK side, so Author had no books property and no join allowlist entry — Authors?join=books||title (nestjsx) and Authors?select=books(title) (PostgREST) were both silently dropped. Found during the staging dual-dialect validation of service 4717.

Behavior

  • Default: bidirectional (matches OneToMany declarations).
  • bi_directional: false keeps the old FK-only unidirectional shape.
  • Self-referencing relationships stay unidirectional (both sides would collide on the same RelationshipMap key).
  • Redundant OneToMany + ManyToOne pairs dedupe in getRelationshipForTemplate (same name+referenceName key).

Note: parse.ts has both the live inline switch in parseRelationship and the older exported parseManytoOne (only referenced by tests) — both updated to keep them consistent.

Verification

  • 324 tests pass (fixtures updated to the new shape; opt-out case added).
  • Regenerated a Post →ManyToOne→ Author service: compiles clean; booted it and the collection-side embed returns rows in both dialects, matching the declared side.

Rollout note

Merging publishes a new CLI version via the main workflow. Deployed pairing then needs the usual follow-through: client APSO_CLI_VERSION bump. Template tag/TEMPLATE_REFS are unaffected.

🤖 Generated with Claude Code

cultron and others added 4 commits August 12, 2026 10:31
The CLI cloned template main at HEAD, so the @apso/crud version a
scaffold got was a date cutoff, not an explicit pairing. Pin the
TypeScript template to v2.0.0 — the first revision on published
@apso/crud ^1.0.1 (nestjsx + PostgREST dual dialect). Python and Go
templates stay on main; their repos are untagged and do not carry the
dialect work.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The v2 template ships only @apso/crud* dependencies, but the code
generators still emitted @nestjsx/crud imports, so a fresh scaffold +
generate produced code that could not resolve its CRUD imports (the
source of the v1/v2 base-image mismatch, task #84). Swap the import
module paths in the Eta templates — @apso/crud exports every symbol
under the same names (import-swap parity).

Verified end-to-end: clone template v2.0.0, generate a 2-entity schema
with relationships, npm install, nest build — compiles clean against
published @apso/crud 1.0.2.

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

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

A declared ManyToOne produced only the FK side, so the target entity had
no collection property and no controller join allowlist: the AI schema
builder declares Book->ManyToOne->Author, and Authors?join=books (or the
PostgREST select=books(title)) was silently dropped in both dialects.

Mirror the OneToMany case with the roles swapped: the target now gets
the inverse OneToMany property and join. bi_directional: false keeps
the old FK-only shape, and self-references stay unidirectional.

Verified: 324 tests pass; regenerated a Book->ManyToOne->Author service,
compiles clean, and the collection-side embed returns rows in both the
nestjsx and PostgREST dialects at runtime.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@cultron
cultron merged commit d0c2273 into main Aug 13, 2026
4 checks passed
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.

1 participant