Skip to content

Conversation

@wszgrcy
Copy link
Contributor

@wszgrcy wszgrcy commented Aug 19, 2025

Description of change

support entity schema trees, equal to @Tree

Pull-Request Checklist

  • Code is up-to-date with the master branch
  • This pull request links relevant issues as Fixes #00000
  • There are new or updated unit tests validating the change
  • Documentation has been updated to reflect this change

Summary by CodeRabbit

  • New Features

    • Entity schemas can now declare tree structures (e.g., nested-set), enabling parent/child relations and full TreeRepository support (findRoots, findAncestors, findDescendants).
  • Tests

    • Added functional tests validating nested-set tree behavior: attaching nodes and querying roots, ancestors, and descendants.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 19, 2025

Walkthrough

Adds tree metadata support to EntitySchema: a new optional trees property in EntitySchemaOptions, transformer logic to register tree metadata into metadataArgsStorage, and functional tests introducing a nested-set Category schema with corresponding TreeRepository operations.

Changes

Cohort / File(s) Summary
EntitySchema options update
src/entity-schema/EntitySchemaOptions.ts
Adds optional property trees?: Omit<TreeMetadataArgs, "target">[] and imports TreeMetadataArgs.
Transformer tree handling
src/entity-schema/EntitySchemaTransformer.ts
Extends transformation to iterate options.trees and push { target, type, options } entries into metadataArgsStorage.trees during recursive transform.
Tests: nested-set tree
test/functional/entity-schema/trees/nested-set/entity/Category.ts, test/functional/entity-schema/trees/nested-set/nested-set.ts
Adds Category EntitySchema configured as a nested-set tree with self-relations and a functional test that validates roots, ancestors, and descendants via TreeRepository.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor App
  participant EntitySchema as EntitySchema (with options.trees)
  participant Transformer as EntitySchemaTransformer
  participant Storage as metadataArgsStorage

  App->>Transformer: transform(EntitySchema)
  Transformer->>Transformer: transformColumnsRecursive(...)
  alt options.trees present
    loop each tree option
      Transformer->>Storage: trees.push({ target, type, options })
    end
  else no trees
    note over Transformer: no tree metadata collected
  end
  Transformer-->>App: Metadata arguments updated
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • alumni
  • gioboa

Poem

A twig, a trunk, a schema grows tall—
I thump my paws and nest in the fall.
Nodes link up, roots find their set,
Ancestors whisper, “Don’t forget.”
Descendants hop down every bough—
Our forest compiles nicely now. 🌲🐇

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title clearly and succinctly conveys the main enhancement—adding tree support to entity schemas—uses a conventional “feat:” prefix, and avoids extraneous details, making it easy for a reviewer to grasp the primary change.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@pkg-pr-new
Copy link

pkg-pr-new bot commented Aug 19, 2025

typeorm-sql-js-example

npm i https://pkg.pr.new/typeorm/typeorm@11606

commit: d5892c7

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (5)
src/entity-schema/EntitySchemaOptions.ts (1)

140-141: Clarify API semantics: document that only a single tree strategy is supported per entity

Decorator-based entities only support one @Tree(...) per entity. The plural shape (trees: []) is OK for consistency with other arrays, but without guidance it invites multiple entries, which would be undefined behavior. At minimum, add JSDoc that this array must contain at most one element and is equivalent to @Tree(...).

Apply this diff to document intent:

-    trees?: Omit<TreeMetadataArgs, "target">[]
+    /**
+     * Tree configuration for this entity (equivalent to using `@Tree(...)`).
+     * Note: only a single tree strategy is supported per entity; provide at most one entry.
+     */
+    trees?: Omit<TreeMetadataArgs, "target">[]
src/entity-schema/EntitySchemaTransformer.ts (1)

400-408: Enforce single tree per entity; optional: emit tree metadata at top-level (not during embedded recursion)

Registering tree metadata is correct. Two improvements:

  • Prevent multiple tree strategies on a single entity (only one is supported).
  • Optional: consider moving this block to the top-level transform (alongside table/ inheritance) to avoid accidental emission from embeddeds if someone mistakenly places trees on an embedded schema.

Apply this guard to avoid multiple entries:

-        if (options.trees) {
-            options.trees.forEach((tree) => {
+        if (options.trees) {
+            if (options.trees.length > 1) {
+                throw new Error(
+                    `Only one tree strategy is supported per entity schema (${String(
+                        options.target || options.name,
+                    )}).`,
+                )
+            }
+            options.trees.forEach((tree) => {
                 metadataArgsStorage.trees.push({
                     target: options.target || options.name,
                     type: tree.type,
                     options: tree.options,
                 })
             })
         }

If you prefer, I can follow up with a small refactor to move this emission to transform(), right after pushing the table metadata.

test/functional/entity-schema/trees/nested-set/entity/Category.ts (2)

21-31: Add inverseSide to make relations explicit and self-documenting

Tree-specific flags work, but adding inverseSide reduces ambiguity and matches patterns used elsewhere in the codebase.

Apply this diff:

         parentCategory: {
             type: "many-to-one",
             treeParent: true,
             target: "Category",
+            inverseSide: "childCategories",
         },
         childCategories: {
             type: "one-to-many",
             treeChildren: true,
             target: "Category",
             cascade: true,
+            inverseSide: "parentCategory",
         },

3-8: Improve typings to avoid any (optional)

Using any/any[] here works for tests but loses type-safety. Consider introducing a small model type to keep generics aligned without colliding with the exported constant name.

For example:

type CategoryModel = {
  id: number
  name: string
  parentCategory: CategoryModel | null
  childCategories: CategoryModel[]
}

export const Category = new EntitySchema<CategoryModel>({ /* ... */ })
test/functional/entity-schema/trees/nested-set/nested-set.ts (1)

23-68: Solid happy-path coverage; consider adding a negative test for multiple roots

The flow validates roots/ancestors/descendants and exercises the new schema-based tree metadata. To match decorator-based coverage, consider adding a test asserting that saving a second root is rejected for nested-set trees.

You can append a separate spec:

it("should reject multiple roots for nested-set", () =>
  Promise.all(
    connections.map(async (connection) => {
      const repo = connection.getTreeRepository(Category)

      const a1 = await repo.save({ name: "a1" })
      // Attempt a second root
      await repo
        .save({ name: "b1" })
        .then(() => {
          throw new Error("expected rejection for multiple roots")
        })
        .catch((err) => {
          err.message.should.match(/Nested sets do not support multiple root entities/i)
        })
    }),
  ))
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled
  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 22b26d1 and a3ea81f.

📒 Files selected for processing (4)
  • src/entity-schema/EntitySchemaOptions.ts (2 hunks)
  • src/entity-schema/EntitySchemaTransformer.ts (1 hunks)
  • test/functional/entity-schema/trees/nested-set/entity/Category.ts (1 hunks)
  • test/functional/entity-schema/trees/nested-set/nested-set.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
test/functional/entity-schema/trees/nested-set/entity/Category.ts (3)
test/github-issues/7068/entity/Category.ts (1)
  • Category (14-29)
test/github-issues/8443/nested-set/entity/Category.ts (1)
  • Category (11-29)
test/github-issues/9534/entity/Category.ts (1)
  • Category (11-41)
🔇 Additional comments (2)
src/entity-schema/EntitySchemaOptions.ts (1)

17-17: LGTM: Tree metadata import is appropriate

Importing TreeMetadataArgs here is correct and keeps the new option strongly typed.

test/functional/entity-schema/trees/nested-set/entity/Category.ts (1)

33-34: LGTM: Tree configuration via EntitySchema is correctly wired

trees: [{ type: "nested-set" }] is the expected declaration for the nested-set strategy.

@coveralls
Copy link

coveralls commented Aug 19, 2025

Coverage Status

coverage: 76.431% (+0.004%) from 76.427%
when pulling d5892c7 on piying-org:entity-schema-tree
into 4f05718 on typeorm:master.

@wszgrcy
Copy link
Contributor Author

wszgrcy commented Sep 1, 2025

@alumni @gioboa
Could you please help check if this PR can be merged, and if there are any improvements needed

@gioboa gioboa requested review from alumni and sgarner September 19, 2025 12:59
Copy link
Collaborator

@gioboa gioboa left a comment

Choose a reason for hiding this comment

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

Thanks for your help @wszgrcy

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
src/entity-schema/EntitySchemaOptions.ts (1)

139-141: Prefer a singular tree option (one tree per entity).

Decorator parity: entities support exactly one tree type. An array invites invalid configs (multiple entries). Recommend a singular property and adjust the transformer accordingly.

Apply:

-  trees?: Omit<TreeMetadataArgs, "target">[]
+  /**
+   * Tree configuration for this entity (e.g. "closure-table", "nested-set", "materialized-path").
+   */
+  tree?: Omit<TreeMetadataArgs, "target">

If keeping trees for backward symmetry with array-based options, at least validate length ≤ 1 in the transformer and use the first entry.

Would you confirm whether multiple trees per entity are intended? If not, I can provide a follow-up patch to enforce a single entry.

src/entity-schema/EntitySchemaTransformer.ts (1)

400-408: Enforce a single tree and simplify handling.

Current code allows multiple trees and processes within the recursive path. Recommend:

  • Use a singular option and push once, avoiding embedded schemas.

If adopting tree (singular), change this block to:

-        if (options.trees) {
-            options.trees.forEach((tree) => {
-                metadataArgsStorage.trees.push({
-                    target: options.target || options.name,
-                    type: tree.type,
-                    options: tree.options,
-                })
-            })
-        }
+        if (options.tree) {
+            metadataArgsStorage.trees.push({
+                target: options.target || options.name,
+                type: options.tree.type,
+                options: options.tree.options,
+            })
+        }

If keeping an array, minimally guard against multiple entries and ignore/throw on extras; also consider moving this logic to the top-level transform (non-recursive) to prevent accidental registration from embeddeds.

Please confirm whether we should (a) reject multiple entries or (b) accept only the first. I can supply a precise patch for either path.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a3ea81f and d5892c7.

📒 Files selected for processing (4)
  • src/entity-schema/EntitySchemaOptions.ts (2 hunks)
  • src/entity-schema/EntitySchemaTransformer.ts (1 hunks)
  • test/functional/entity-schema/trees/nested-set/entity/Category.ts (1 hunks)
  • test/functional/entity-schema/trees/nested-set/nested-set.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • test/functional/entity-schema/trees/nested-set/entity/Category.ts
  • test/functional/entity-schema/trees/nested-set/nested-set.ts
🧰 Additional context used
🧬 Code graph analysis (1)
src/entity-schema/EntitySchemaOptions.ts (1)
src/metadata-args/TreeMetadataArgs.ts (1)
  • TreeMetadataArgs (7-22)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (20)
  • GitHub Check: tests-linux (18) / better-sqlite3
  • GitHub Check: tests-linux (20) / sap
  • GitHub Check: tests-linux (18) / mysql_mariadb
  • GitHub Check: tests-linux (18) / mongodb
  • GitHub Check: tests-linux (20) / mssql
  • GitHub Check: tests-linux (18) / mssql
  • GitHub Check: tests-linux (20) / cockroachdb
  • GitHub Check: tests-linux (20) / mysql_mariadb
  • GitHub Check: tests-linux (20) / sqljs
  • GitHub Check: tests-linux (20) / mongodb
  • GitHub Check: tests-linux (20) / mysql_mariadb_latest
  • GitHub Check: tests-linux (20) / oracle
  • GitHub Check: tests-linux (20) / better-sqlite3
  • GitHub Check: tests-windows / sqljs
  • GitHub Check: tests-linux (20) / sqlite
  • GitHub Check: tests-linux (20) / postgres (14)
  • GitHub Check: tests-linux (20) / postgres (17)
  • GitHub Check: tests-windows / sqlite
  • GitHub Check: tests-windows / better-sqlite3
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (1)
src/entity-schema/EntitySchemaOptions.ts (1)

17-17: Import looks correct.

Path and type usage align with existing metadata-args structure.

Copy link
Collaborator

@gioboa gioboa left a comment

Choose a reason for hiding this comment

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

👍 tests are ✅ let's merge it
Thanks

@gioboa gioboa merged commit 925dee0 into typeorm:master Sep 29, 2025
62 checks passed
ThbltLmr pushed a commit to ThbltLmr/typeorm that referenced this pull request Dec 2, 2025
mgohin pushed a commit to mgohin/typeorm that referenced this pull request Jan 15, 2026
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.

4 participants