Skip to content

refactor(find-options)!: remove deprecated join option from find methods#12188

Merged
pkuczynski merged 6 commits intomasterfrom
refactor/remove-deprecated-find-options
Mar 18, 2026
Merged

refactor(find-options)!: remove deprecated join option from find methods#12188
pkuczynski merged 6 commits intomasterfrom
refactor/remove-deprecated-find-options

Conversation

@pkuczynski
Copy link
Copy Markdown
Member

@pkuczynski pkuczynski commented Mar 11, 2026

Remove the deprecated join property from FindOneOptions and FindManyOptions, along with the JoinOptions interface and all related handling code.

  • Delete src/find-options/JoinOptions.ts interface
  • Remove join property from FindOneOptions
  • Remove join handling from SelectQueryBuilder.setFindOptions()
  • Remove extractFindManyOptionsAlias() and join type guard from FindOptionsUtils
  • Remove unused FindOptionsUtils import from EntityManager
  • Convert all test and sample join: usages to equivalent relations: syntax
  • Add migration guide entry for the removal

@pkuczynski pkuczynski added this to the 1.0 milestone Mar 11, 2026
@pkuczynski pkuczynski self-assigned this Mar 11, 2026
@qodo-free-for-open-source-projects
Copy link
Copy Markdown

Review Summary by Qodo

Remove deprecated find options APIs (join, string-based select/relations)

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Remove deprecated join property from find options interfaces
• Remove deprecated string-array syntax for select and relations
• Remove JoinOptions interface and related handling code
• Migrate all samples and tests to object-based relations syntax
• Remove FindOptionsUtils.extractFindManyOptionsAlias() helper method
Diagram
flowchart LR
  A["Deprecated APIs<br/>join, string arrays"] -->|removed| B["FindOneOptions<br/>FindManyOptions"]
  C["JoinOptions<br/>interface"] -->|deleted| B
  D["FindOptionsSelectByString<br/>FindOptionsRelationByString"] -->|removed| B
  E["Sample code<br/>Test code"] -->|migrated to| F["Object-based<br/>relations syntax"]
  G["EntityManager<br/>SelectQueryBuilder"] -->|simplified| H["Removed join<br/>handling logic"]
Loading

Grey Divider

File Changes

1. src/find-options/FindOneOptions.ts ✨ Enhancement +4/-17

Remove deprecated join and string-based options

src/find-options/FindOneOptions.ts


2. src/find-options/FindOptionsRelations.ts ✨ Enhancement +0/-7

Remove FindOptionsRelationByString deprecated type

src/find-options/FindOptionsRelations.ts


3. src/find-options/FindOptionsSelect.ts ✨ Enhancement +0/-7

Remove FindOptionsSelectByString deprecated type

src/find-options/FindOptionsSelect.ts


View more (32)
4. src/find-options/JoinOptions.ts ✨ Enhancement +0/-71

Delete entire deprecated JoinOptions interface

src/find-options/JoinOptions.ts


5. src/find-options/FindOptionsUtils.ts ✨ Enhancement +1/-16

Remove extractFindManyOptionsAlias helper method

src/find-options/FindOptionsUtils.ts


6. src/entity-manager/EntityManager.ts ✨ Enhancement +5/-22

Remove join handling and alias extraction logic

src/entity-manager/EntityManager.ts


7. src/entity-manager/MongoEntityManager.ts ✨ Enhancement +4/-14

Remove string-based select conversion handling

src/entity-manager/MongoEntityManager.ts


8. src/query-builder/SelectQueryBuilder.ts ✨ Enhancement +9/-79

Remove join option processing and array conversion

src/query-builder/SelectQueryBuilder.ts


9. src/index.ts ✨ Enhancement +0/-1

Remove JoinOptions export from public API

src/index.ts


10. sample/sample18-lazy-relations/app.ts ✨ Enhancement +2/-8

Migrate from join to relations object syntax

sample/sample18-lazy-relations/app.ts


11. sample/sample19-one-side-relations/app.ts ✨ Enhancement +4/-7

Migrate from join to relations object syntax

sample/sample19-one-side-relations/app.ts


12. sample/sample21-custom-join-table-column/app.ts ✨ Enhancement +3/-6

Migrate from join to relations object syntax

sample/sample21-custom-join-table-column/app.ts


13. test/functional/cascades/cascade-insert-from-both-sides/cascade-insert-from-both-sides.test.ts 🧪 Tests +2/-12

Migrate tests from join to relations syntax

test/functional/cascades/cascade-insert-from-both-sides/cascade-insert-from-both-sides.test.ts


14. test/functional/data-source/data-source.test.ts 🧪 Tests +2/-2

Migrate tests to object-based relations

test/functional/data-source/data-source.test.ts


15. test/functional/find-options/select/find-options-select.test.ts 🧪 Tests +4/-4

Migrate tests to object-based relations

test/functional/find-options/select/find-options-select.test.ts


16. test/functional/persistence/custom-column-name-pk/custom-column-name-pk.test.ts 🧪 Tests +1/-6

Migrate tests from join to relations syntax

test/functional/persistence/custom-column-name-pk/custom-column-name-pk.test.ts


17. test/functional/persistence/custom-column-names/persistence-custom-column-names.test.ts 🧪 Tests +9/-22

Migrate tests from join to relations syntax

test/functional/persistence/custom-column-names/persistence-custom-column-names.test.ts


18. test/functional/persistence/many-to-many/persistence-many-to-many.test.ts 🧪 Tests +21/-35

Migrate tests from join to relations syntax

test/functional/persistence/many-to-many/persistence-many-to-many.test.ts


19. test/functional/persistence/multi-primary-key-on-both-sides/multi-primary-key.test.ts 🧪 Tests +1/-6

Migrate tests from join to relations syntax

test/functional/persistence/multi-primary-key-on-both-sides/multi-primary-key.test.ts


20. test/functional/persistence/multi-primary-key/multi-primary-key.test.ts 🧪 Tests +1/-6

Migrate tests from join to relations syntax

test/functional/persistence/multi-primary-key/multi-primary-key.test.ts


21. test/functional/persistence/one-to-many/persistence-one-to-many.test.ts 🧪 Tests +3/-18

Migrate tests from join to relations syntax

test/functional/persistence/one-to-many/persistence-one-to-many.test.ts


22. test/functional/persistence/partial-persist/partial-persist.test.ts 🧪 Tests +4/-24

Migrate tests from join to relations syntax

test/functional/persistence/partial-persist/partial-persist.test.ts


23. test/functional/relations/relation-mapped-to-different-name-column/relation-mapped-to-different-name-column.test.ts 🧪 Tests +1/-6

Migrate tests from join to relations syntax

test/functional/relations/relation-mapped-to-different-name-column/relation-mapped-to-different-name-column.test.ts


24. test/functional/relations/relation-with-primary-key/relation-with-primary-key.test.ts 🧪 Tests +1/-6

Migrate tests from join to relations syntax

test/functional/relations/relation-with-primary-key/relation-with-primary-key.test.ts


25. test/functional/repository/find-options-locking/find-options-locking.test.ts 🧪 Tests +3/-5

Migrate tests from join to relations syntax

test/functional/repository/find-options-locking/find-options-locking.test.ts


26. test/functional/repository/set-add-remove-relations/repository-set-add-remove-relations.test.ts 🧪 Tests +8/-36

Migrate tests from join to relations syntax

test/functional/repository/set-add-remove-relations/repository-set-add-remove-relations.test.ts


27. test/github-issues/151/issue-151.test.ts 🧪 Tests +0/-57

Delete test file using deprecated join syntax

test/github-issues/151/issue-151.test.ts


28. test/github-issues/161/issue-161.test.ts 🧪 Tests +0/-136

Delete test file using deprecated join syntax

test/github-issues/161/issue-161.test.ts


29. test/github-issues/7558/issue-7758.test.ts 🧪 Tests +3/-1

Migrate test to object-based relations

test/github-issues/7558/issue-7758.test.ts


30. docs/docs/guides/8-migration-v1.md 📝 Documentation +46/-0

Add migration guide for find options changes

docs/docs/guides/8-migration-v1.md


31. test/github-issues/151/entity/Category.ts Additional files +0/-12

...

test/github-issues/151/entity/Category.ts


32. test/github-issues/151/entity/Post.ts Additional files +0/-26

...

test/github-issues/151/entity/Post.ts


33. test/github-issues/151/entity/PostMetadata.ts Additional files +0/-17

...

test/github-issues/151/entity/PostMetadata.ts


34. test/github-issues/161/entity/Request.ts Additional files +0/-23

...

test/github-issues/161/entity/Request.ts


35. test/github-issues/161/entity/Ticket.ts Additional files +0/-21

...

test/github-issues/161/entity/Ticket.ts


Grey Divider

Qodo Logo

@pkuczynski pkuczynski enabled auto-merge (squash) March 11, 2026 22:39
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Mar 11, 2026

commit: 4a1a970

@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages bot commented Mar 11, 2026

Deploying typeorm with  Cloudflare Pages  Cloudflare Pages

Latest commit: 93807bd
Status: ✅  Deploy successful!
Preview URL: https://4b5e15a9.typeorm.pages.dev
Branch Preview URL: https://refactor-remove-deprecated-f.typeorm.pages.dev

View logs

@pkuczynski pkuczynski disabled auto-merge March 11, 2026 22:44
@qodo-free-for-open-source-projects
Copy link
Copy Markdown

qodo-free-for-open-source-projects bot commented Mar 11, 2026

Code Review by Qodo

🐞 Bugs (5) 📘 Rule violations (2) 📎 Requirement gaps (0) 📐 Spec deviations (0)

Grey Divider


Action required

1. Mongo rejects join filter 🐞 Bug ✓ Correctness
Description
MongoEntityManager now calls FindOptionsUtils.rejectJoinOption on optionsOrConditions even when
it is a plain filter object (Partial/FilterOperators), so a query like `manager.find(User, {
join: "x" })` will throw instead of filtering. This is a MongoDB-only behavioral regression because
SQL find APIs don’t accept conditions at the top level the same way.
Code

src/entity-manager/MongoEntityManager.ts[1114]

+        FindOptionsUtils.rejectJoinOption(optionsOrConditions)
Evidence
MongoEntityManager.find explicitly accepts optionsOrConditions as a union that includes plain
condition objects (Partial), not just typed FindManyOptions. The conversion helpers call
rejectJoinOption before determining whether the value is actually a find-options object, and
rejectJoinOption throws whenever a top-level join key is present with any non-nullish value—so a
legitimate condition object with a join property will now be rejected.

src/entity-manager/MongoEntityManager.ts[101-107]
src/entity-manager/MongoEntityManager.ts[1104-1124]
src/entity-manager/MongoEntityManager.ts[1130-1148]
src/find-options/FindOptionsUtils.ts[20-32]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`FindOptionsUtils.rejectJoinOption` throws for any object that has a non-nullish `join` property. In `MongoEntityManager`, this guard is applied to `optionsOrConditions` **even when it is a plain Mongo filter/conditions object** (`Partial&amp;lt;Entity&amp;gt;` / `FilterOperators&amp;lt;Entity&amp;gt;`), causing legitimate filters like `{ join: &amp;quot;...&amp;quot; }` to throw.
### Issue Context
MongoEntityManager overloads allow passing either typed find-options or a plain conditions object. The runtime guard should only reject the **deprecated find-options JoinOptions shape**, not any arbitrary `join` key.
### Fix Focus Areas
- src/find-options/FindOptionsUtils.ts[20-32]
- src/entity-manager/MongoEntityManager.ts[1104-1124]
- src/entity-manager/MongoEntityManager.ts[1130-1148]
### Suggested fix approach
1. Update `rejectJoinOption` to only throw when `options.join` looks like the removed JoinOptions structure (e.g., is an object and contains one of: `alias`, `leftJoin`, `innerJoin`, `leftJoinAndSelect`, `innerJoinAndSelect`).
 - Example logic:
   - If `options?.join == null`: return
   - If `typeof options.join !== &amp;quot;object&amp;quot;`: return (so scalar `join` filters keep working)
   - If none of the known JoinOptions keys exist on `options.join`: return
   - Else throw `TypeORMError`
2. Keep the MongoEntityManager calls as-is (they are useful for catching JS/untyped callers), but with the narrowed detection to avoid false positives on condition objects.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Mongo join becomes filter 🐞 Bug ✓ Correctness
Description
After removing join from FindOptionsUtils.isFindOneOptions/isFindManyOptions, an object like `{
join: {...} } is no longer classified as FindOptions in MongoEntityManager` and is instead used as
the MongoDB filter object. This can cause queries to return wrong/empty results for untyped/JS
callers still passing the (now removed) join option.
Code

src/find-options/FindOptionsUtils.ts[R32-37]

              typeof possibleOptions.select === "object" ||
              typeof possibleOptions.relations === "object" ||
              typeof possibleOptions.where === "object" ||
-                // typeof possibleOptions.where === "string" ||
-                typeof possibleOptions.join === "object" ||
              typeof possibleOptions.order === "object" ||
              typeof possibleOptions.cache === "object" ||
              typeof possibleOptions.cache === "boolean" ||
Evidence
isFindOneOptions no longer considers a join property, so MongoEntityManager will not treat `{
join: ... }` as options; it returns the object as-is and passes it as the Mongo filter.

src/find-options/FindOptionsUtils.ts[24-47]
src/entity-manager/MongoEntityManager.ts[1104-1122]
src/entity-manager/MongoEntityManager.ts[101-118]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`MongoEntityManager` can receive untyped inputs where callers still pass the removed `join` option. After this PR, `{ join: ... }` is no longer recognized as FindOptions and is treated as the MongoDB filter, producing wrong/empty results.
## Issue Context
This is a breaking change, but failing fast with a clear error is safer than silently changing query semantics.
## Fix Focus Areas
- src/entity-manager/MongoEntityManager.ts[1104-1144]
- src/find-options/FindOptionsUtils.ts[24-47]
## Suggested fix
- In `convertFindManyOptionsOrConditionsToMongodbQuery` and `convertFindOneOptionsOrConditionsToMongodbQuery`, detect `(optionsOrConditions as any)?.join != null` and throw a `TypeORMError` with a message like: `FindOptions.join was removed. Use relations: {...} for left joins or QueryBuilder for other join types.`
- (Optional) Add a small unit/functional test ensuring `{ join: {...} }` throws rather than being treated as filter criteria.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Mongo select ignored 🐞 Bug ✓ Correctness
Description
MongoEntityManager still applies cursor.project(...) when options.select is provided, but
convertFindOptionsSelectToProjectCriteria now always returns {}, so MongoDB projections are
never applied. This breaks FindOneOptions.select behavior for MongoDB and can cause over-fetching.
Code

src/entity-manager/MongoEntityManager.ts[R1089-1094]

protected convertFindOptionsSelectToProjectCriteria(
-        selects: FindOptionsSelect<any> | FindOptionsSelectByString<any>,
+        selects: FindOptionsSelect<any>,
) {
-        if (Array.isArray(selects)) {
-            return selects.reduce((projectCriteria, key) => {
-                projectCriteria[key] = 1
-                return projectCriteria
-            }, {} as any)
-        } else {
-            // todo: implement
-            return {}
-        }
+        // todo: implement
+        return {}
}
Evidence
MongoDB queries call cursor.project() whenever select is present, but the converter always
returns an empty projection object, so the selection is effectively ignored despite select being
part of the public options API (via FindOneOptions).

src/entity-manager/MongoEntityManager.ts[117-124]
src/entity-manager/MongoEntityManager.ts[1089-1094]
src/find-options/mongodb/MongoFindOneOptions.ts[7-15]
src/find-options/FindOneOptions.ts[17-31]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
MongoDB `select` find-option is currently ignored because `convertFindOptionsSelectToProjectCriteria()` always returns `{}`, yet `MongoEntityManager` still calls `cursor.project(...)` whenever `select` is present.
### Issue Context
`MongoFindOneOptions` inherits `select` from `FindOneOptions`, so `select` is part of the Mongo API surface and should work (or fail explicitly).
### Fix Focus Areas
- src/entity-manager/MongoEntityManager.ts[100-139]
- src/entity-manager/MongoEntityManager.ts[1089-1094]
### Implementation notes
- Convert `FindOptionsSelect` object syntax into a Mongo projection object, e.g. `{ id: true, profile: { name: true } }` -&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;gt; `{ id: 1, &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;profile.name&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;: 1 }`.
- Treat `true` as include field, ignore `false`/`undefined`.
- Consider handling `selectionKey: true` for nested objects by projecting the parent field (`parent: 1`) or flattening appropriately.
- If conversion yields no keys, avoid calling `cursor.project({})` (or throw) to prevent silent no-op behavior.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

4. post! bypasses nullability 📘 Rule violation ⚙ Maintainability ⭐ New
Description
The sample introduces non-null assertions (post!) after findOne(), bypassing the type system
instead of handling the possible null result. This can hide real runtime null cases and is
inconsistent with the “no type-bypass noise” requirement.
Code

sample/sample18-lazy-relations/app.ts[R99-113]

+                return postRepository.findOne({
+                    where: { id: savedPost.id },
+                    relations: {
+                        categories: true,
                    },
                })
            })
-            .then((posts) => {
-                console.log("Post with categories are loaded: ", posts)
+            .then((post) => {
+                console.log("Post with categories is loaded: ", post)
                console.log("Lets remove one of the categories: ")
-                return posts[0].categories.then((categories) => {
+                return post!.categories.then((categories) => {
                    // temporary
                    categories!.splice(0, 1)
-                    return postRepository.save(posts[0])
+                    return postRepository.save(post!)
                })
Evidence
Compliance PR ID 4 prohibits adding type-bypass noise; the updated sample code adds non-null
assertions (post!) to silence TypeScript’s Post | null typing from findOne() rather than
handling the null case.

Rule 4: Remove AI-generated noise
sample/sample18-lazy-relations/app.ts[99-113]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The sample uses non-null assertions (`post!`) after `findOne()`, which bypasses TypeScript null-safety and can hide runtime `null` cases.

## Issue Context
`postRepository.findOne(...)` returns `Post | null`. The current code uses `post!` to proceed instead of explicitly handling the `null` branch.

## Fix Focus Areas
- sample/sample18-lazy-relations/app.ts[99-113]

## Suggested change
Replace `post!` usages with an explicit null check (e.g., `if (!post) throw new Error(&quot;Post not found&quot;)`) before accessing `post.categories` and before calling `save(post)`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. rejectJoinOption uses any 📘 Rule violation ⚙ Maintainability
Description
FindOptionsUtils.rejectJoinOption introduces a new any-typed parameter, which weakens type
safety and can hide incorrect usage patterns. This conflicts with the guideline to avoid
type-bypassing constructs and stylistic noise in new changes.
Code

src/find-options/FindOptionsUtils.ts[R25-32]

+    static rejectJoinOption(options: any): void {
+        if (options && typeof options === "object" && options.join != null) {
+            throw new TypeORMError(
+                `"join" option has been removed. Use "relations" for left joins ` +
+                    `or QueryBuilder for other join types. See the v1 migration guide for details.`,
+            )
+        }
+    }
Evidence
PR Compliance ID 4 requires avoiding AI-like slop such as any usage to bypass type issues. The
newly added method rejectJoinOption(options: any) explicitly uses any for the input options.

Rule 4: Remove AI-generated noise
src/find-options/FindOptionsUtils.ts[20-32]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A new helper `FindOptionsUtils.rejectJoinOption` was added with a parameter typed as `any`, which reduces type safety and can mask mistakes.
## Issue Context
The method is meant to validate untyped/JS callers, but it can still be implemented without `any` by using `unknown` and narrowing.
## Fix Focus Areas
- src/find-options/FindOptionsUtils.ts[20-32]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. Sample category filter lost 🐞 Bug ✓ Correctness
Description
In sample18-lazy-relations, replacing innerJoinAndSelect with relations changes the query from
an INNER JOIN filter to LEFT JOIN loading, so find() returns posts without categories and the
sample’s posts[0].categories step can operate on the wrong post (or an empty relation) and no
longer demonstrates category removal correctly.
Code

sample/sample18-lazy-relations/app.ts[R99-103]

            return postRepository.find({
-                    join: {
-                        alias: "post",
-                        innerJoinAndSelect: { categories: "post.categories" },
+                    relations: {
+                        categories: true,
                },
            })
Evidence
The sample creates multiple posts before the categories post, then calls `find({ relations: {
categories: true }}) and assumes posts[0] is the post that has categories. However, relations`
loading uses LEFT joins (non-filtering), so posts without categories are included in the result set
and the first element is not guaranteed to be the categories post.

sample/sample18-lazy-relations/app.ts[27-50]
sample/sample18-lazy-relations/app.ts[89-113]
src/query-builder/SelectQueryBuilder.ts[3950-4008]
docs/docs/guides/8-migration-v1.md[351-351]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`sample18-lazy-relations` previously used an `innerJoinAndSelect` via deprecated `find` join options to load only posts that have categories. After migrating to `relations`, TypeORM loads relations using LEFT JOINs, so `find()` returns posts without categories too. The sample then assumes `posts[0]` has categories and attempts to remove one, which can become a no-op or operate on the wrong post.
### Issue Context
- The sample creates at least two posts *without* categories before creating the &amp;amp;amp;amp;quot;Post &amp;amp;amp;amp;amp; Categories&amp;amp;amp;amp;quot; record.
- `relations` uses LEFT joins (non-filtering).
### Fix Focus Areas
- sample/sample18-lazy-relations/app.ts[89-113]
### Suggested change (one of)
1) Capture the result of `postRepository.save(post)` for the categories post and then load by its `id` using `findOne` + `relations`.
2) Use QueryBuilder for an INNER JOIN filter (as the migration guide recommends for inner joins) and then operate on the returned post.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (2)
7. Join option not rejected 🐞 Bug ⛯ Reliability
Description
The deprecated findOptions.join is no longer applied by SelectQueryBuilder, but there is no
runtime error when it is still provided; for JS/any callers it can be silently ignored, producing
queries without the expected joins.
Code

src/query-builder/SelectQueryBuilder.ts[L3318-3358]

-            if (this.findOptions.join) {
-                if (this.findOptions.join.leftJoin)
-                    Object.keys(this.findOptions.join.leftJoin).forEach(
-                        (key) => {
-                            this.leftJoin(
-                                this.findOptions.join!.leftJoin![key],
-                                key,
-                            )
-                        },
-                    )
-
-                if (this.findOptions.join.innerJoin)
-                    Object.keys(this.findOptions.join.innerJoin).forEach(
-                        (key) => {
-                            this.innerJoin(
-                                this.findOptions.join!.innerJoin![key],
-                                key,
-                            )
-                        },
-                    )
-
-                if (this.findOptions.join.leftJoinAndSelect)
-                    Object.keys(
-                        this.findOptions.join.leftJoinAndSelect,
-                    ).forEach((key) => {
-                        this.leftJoinAndSelect(
-                            this.findOptions.join!.leftJoinAndSelect![key],
-                            key,
-                        )
-                    })
-
-                if (this.findOptions.join.innerJoinAndSelect)
-                    Object.keys(
-                        this.findOptions.join.innerJoinAndSelect,
-                    ).forEach((key) => {
-                        this.innerJoinAndSelect(
-                            this.findOptions.join!.innerJoinAndSelect![key],
-                            key,
-                        )
-                    })
-            }
Evidence
The PR adds explicit runtime errors for removed string-array select/relations, but join is
neither part of the FindOneOptions API anymore nor validated at runtime in applyFindOptions. As
a result, providing join (especially alongside valid options like where) can be accepted and
then ignored during query building, yielding incomplete result shapes without a clear error message.

src/query-builder/SelectQueryBuilder.ts[3162-3187]
src/query-builder/SelectQueryBuilder.ts[3281-3351]
src/find-options/FindOneOptions.ts[17-40]
src/find-options/FindOptionsUtils.ts[24-45]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`findOptions.join` has been removed, but it is not explicitly rejected at runtime. JS/`any` callers can still pass `join`, and it may be silently ignored during query building.
## Issue Context
`SelectQueryBuilder.applyFindOptions` now throws for removed string-array `select`/`relations`, but there is no analogous check for `join`.
## Fix Focus Areas
- src/query-builder/SelectQueryBuilder.ts[3148-3204]
## Suggested fix approach
- In `applyFindOptions` (early in the method, near the other validation checks), detect `(this.findOptions as any).join` and throw `TypeORMError` with a migration message (e.g., &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;FindOptions.join was removed; use relations object syntax or QueryBuilder joins&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;).
- Optionally also guard in `FindOptionsUtils.isFindOneOptions`/`isFindManyOptions` or `setFindOptions` to provide earlier/friendlier failure modes, but the `applyFindOptions` guard is sufficient for correctness.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


8. Array select migration error🐞 Bug ⛯ Reliability
Description
Array-based select/relations inputs can still be passed by untyped callers, but the query
builder now treats arrays as objects and iterates numeric keys, throwing
EntityPropertyNotFoundError for property paths like "0". This yields a confusing runtime failure
instead of a clear migration error for removed syntax.
Code

src/query-builder/SelectQueryBuilder.ts[R3162-3167]

if (this.findOptions.select) {
-                const select = Array.isArray(this.findOptions.select)
-                    ? OrmUtils.propertyPathsToTruthyObject(
-                          this.findOptions.select as string[],
-                      )
-                    : this.findOptions.select
-
    this.buildSelect(
-                    select,
+                    this.findOptions.select,
        this.expressionMap.mainAlias!.metadata,
        this.expressionMap.mainAlias!.name,
    )
Evidence
SelectQueryBuilder now forwards findOptions.select/relations directly into builders that
iterate for (const key in ...) and validate those keys as entity property paths. If an array is
provided at runtime, the keys are indices (e.g. "0"), which triggers EntityPropertyNotFoundError
with an unclear message.

src/query-builder/SelectQueryBuilder.ts[3162-3182]
src/query-builder/SelectQueryBuilder.ts[3877-3894]
src/error/EntityPropertyNotFoundError.ts[7-12]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
After removing support for string-array `select`/`relations`, runtime callers (e.g. JavaScript or `any`-typed TypeScript) can still pass arrays. The current code then throws `EntityPropertyNotFoundError` for numeric keys like &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;0&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;, which is a confusing migration experience.
### Issue Context
Even though types were updated, runtime validation is still valuable for users not protected by TypeScript.
### Fix Focus Areas
- src/query-builder/SelectQueryBuilder.ts[3162-3193]
- src/query-builder/SelectQueryBuilder.ts[3877-3921]
### Suggested fix
- Before calling `buildSelect` / `buildRelations`, check `Array.isArray(this.findOptions.select)` / `Array.isArray(this.findOptions.relations)`.
- If true, throw an error like: `String-array select/relations are removed in v1. Use object syntax: select: { col: true }, relations: { rel: true }`.
- This preserves the intentional breaking change but improves debuggability and reduces support burden.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Grey Divider

Previous review results

Review updated until commit 4a1a970

Results up to commit fcdb6d0


🐞 Bugs (5) 📘 Rule violations (1) 📎 Requirement gaps (0) 📐 Spec deviations (0)

Grey Divider
Action required
1. Mongo rejects join filter 🐞 Bug ✓ Correctness ⭐ New
Description
MongoEntityManager now calls FindOptionsUtils.rejectJoinOption on optionsOrConditions even when
it is a plain filter object (Partial<Entity>/FilterOperators), so a query like
manager.find(User, { join: "x" }) will throw instead of filtering. This is a MongoDB-only
behavioral regression because SQL find APIs don’t accept conditions at the top level the same way.
Code

src/entity-manager/MongoEntityManager.ts[1114]

+        FindOptionsUtils.rejectJoinOption(optionsOrConditions)
Evidence
MongoEntityManager.find explicitly accepts optionsOrConditions as a union that includes plain
condition objects (Partial<Entity>), not just typed FindManyOptions. The conversion helpers call
rejectJoinOption before determining whether the value is actually a find-options object, and
rejectJoinOption throws whenever a top-level join key is present with any non-nullish value—so a
legitimate condition object with a join property will now be rejected.

src/entity-manager/MongoEntityManager.ts[101-107]
src/entity-manager/MongoEntityManager.ts[1104-1124]
src/entity-manager/MongoEntityManager.ts[1130-1148]
src/find-options/FindOptionsUtils.ts[20-32]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`FindOptionsUtils.rejectJoinOption` throws for any object that has a non-nullish `join` property. In `MongoEntityManager`, this guard is applied to `optionsOrConditions` **even when it is a plain Mongo filter/conditions object** (`Partial&lt;Entity&gt;` / `FilterOperators&lt;Entity&gt;`), causing legitimate filters like `{ join: &quot;...&quot; }` to throw.

### Issue Context
MongoEntityManager overloads allow passing either typed find-options or a plain conditions object. The runtime guard should only reject the **deprecated find-options JoinOptions shape**, not any arbitrary `join` key.

### Fix Focus Areas
- src/find-options/FindOptionsUtils.ts[20-32]
- src/entity-manager/MongoEntityManager.ts[1104-1124]
- src/entity-manager/MongoEntityManager.ts[1130-1148]

### Suggested fix approach
1. Update `rejectJoinOption` to only throw when `options.join` looks like the removed JoinOptions structure (e.g., is an object and contains one of: `alias`, `leftJoin`, `innerJoin`, `leftJoinAndSelect`, `innerJoinAndSelect`).
  - Example logic:
    - If `options?.join == null`: return
    - If `typeof options.join !== &quot;object&quot;`: return (so scalar `join` filters keep working)
    - If none of the known JoinOptions keys exist on `options.join`: return
    - Else throw `TypeORMError`
2. Keep the MongoEntityManager calls as-is (they are useful for catching JS/untyped callers), but with the narrowed detection to avoid false positives on condition objects.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Mongo join becomes filter 🐞 Bug ✓ Correctness
Description
After removing join from FindOptionsUtils.isFindOneOptions/isFindManyOptions, an object like `{
join: {...} } is no longer classified as FindOptions in MongoEntityManager` and is instead used as
the MongoDB filter object. This can cause queries to return wrong/empty results for untyped/JS
callers still passing the (now removed) join option.
Code

src/find-options/FindOptionsUtils.ts[R32-37]

               typeof possibleOptions.select === "object" ||
               typeof possibleOptions.relations === "object" ||
               typeof possibleOptions.where === "object" ||
-                // typeof possibleOptions.where === "string" ||
-                typeof possibleOptions.join === "object" ||
               typeof possibleOptions.order === "object" ||
               typeof possibleOptions.cache === "object" ||
               typeof possibleOptions.cache === "boolean" ||
Evidence
isFindOneOptions no longer considers a join property, so MongoEntityManager will not treat `{
join: ... }` as options; it returns the object as-is and passes it as the Mongo filter.

src/find-options/FindOptionsUtils.ts[24-47]
src/entity-manager/MongoEntityManager.ts[1104-1122]
src/entity-manager/MongoEntityManager.ts[101-118]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`MongoEntityManager` can receive untyped inputs where callers still pass the removed `join` option. After this PR, `{ join: ... }` is no longer recognized as FindOptions and is treated as the MongoDB filter, producing wrong/empty results.
## Issue Context
This is a breaking change, but failing fast with a clear error is safer than silently changing query semantics.
## Fix Focus Areas
- src/entity-manager/MongoEntityManager.ts[1104-1144]
- src/find-options/FindOptionsUtils.ts[24-47]
## Suggested fix
- In `convertFindManyOptionsOrConditionsToMongodbQuery` and `convertFindOneOptionsOrConditionsToMongodbQuery`, detect `(optionsOrConditions as any)?.join != null` and throw a `TypeORMError` with a message like: `FindOptions.join was removed. Use relations: {...} for left joins or QueryBuilder for other join types.`
- (Optional) Add a small unit/functional test ensuring `{ join: {...} }` throws rather than being treated as filter criteria.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Mongo select ignored 🐞 Bug ✓ Correctness
Description
MongoEntityManager still applies cursor.project(...) when options.select is provided, but
convertFindOptionsSelectToProjectCriteria now always returns {}, so MongoDB projections are
never applied. This breaks FindOneOptions.select behavior for MongoDB and can cause over-fetching.
Code

src/entity-manager/MongoEntityManager.ts[R1089-1094]

protected convertFindOptionsSelectToProjectCriteria(
-        selects: FindOptionsSelect<any> | FindOptionsSelectByString<any>,
+        selects: FindOptionsSelect<any>,
) {
-        if (Array.isArray(selects)) {
-            return selects.reduce((projectCriteria, key) => {
-                projectCriteria[key] = 1
-                return projectCriteria
-            }, {} as any)
-        } else {
-            // todo: implement
-            return {}
-        }
+        // todo: implement
+        return {}
}
Evidence
MongoDB queries call cursor.project() whenever select is present, but the converter always
returns an empty projection object, so the selection is effectively ignored despite select being
part of the public options API (via FindOneOptions).

src/entity-manager/MongoEntityManager.ts[117-124]
src/entity-manager/MongoEntityManager.ts[1089-1094]
src/find-options/mongodb/MongoFindOneOptions.ts[7-15]
src/find-options/FindOneOptions.ts[17-31]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
MongoDB `select` find-option is currently ignored because `convertFindOptionsSelectToProjectCriteria()` always returns `{}`, yet `MongoEntityManager` still calls `cursor.project(...)` whenever `select` is present.
### Issue Context
`MongoFindOneOptions` inherits `select` from `FindOneOptions`, so `select` is part of the Mongo API surface and should work (or fail explicitly).
### Fix Focus Areas
- src/entity-manager/MongoEntityManager.ts[100-139]
- src/entity-manager/MongoEntityManager.ts[1089-1094]
### Implementation notes
- Convert `FindOptionsSelect` object syntax into a Mongo projection object, e.g. `{ id: true, profile: { name: true } }` -&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;gt; `{ id: 1, &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;profile.name&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;: 1 }`.
- Treat `true` as include field, ignore `false`/`undefined`.
- Consider handling `selectionKey: true` for nested objects by projecting the parent field (`parent: 1`) or flattening appropriately.
- If conversion yields no keys, avoid calling `cursor.project({})` (or throw) to prevent silent no-op behavior.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended
4. rejectJoinOption uses any 📘 Rule violation ⚙ Maintainability ⭐ New
Description
FindOptionsUtils.rejectJoinOption introduces a new any-typed parameter, which weakens type
safety and can hide incorrect usage patterns. This conflicts with the guideline to avoid
type-bypassing constructs and stylistic noise in new changes.
Code

src/find-options/FindOptionsUtils.ts[R25-32]

+    static rejectJoinOption(options: any): void {
+        if (options && typeof options === "object" && options.join != null) {
+            throw new TypeORMError(
+                `"join" option has been removed. Use "relations" for left joins ` +
+                    `or QueryBuilder for other join types. See the v1 migration guide for details.`,
+            )
+        }
+    }
Evidence
PR Compliance ID 4 requires avoiding AI-like slop such as any usage to bypass type issues. The
newly added method rejectJoinOption(options: any) explicitly uses any for the input options.

Rule 4: Remove AI-generated noise
src/find-options/FindOptionsUtils.ts[20-32]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A new helper `FindOptionsUtils.rejectJoinOption` was added with a parameter typed as `any`, which reduces type safety and can mask mistakes.

## Issue Context
The method is meant to validate untyped/JS callers, but it can still be implemented without `any` by using `unknown` and narrowing.

## Fix Focus Areas
- src/find-options/FindOptionsUtils.ts[20-32]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. Sample category filter lost 🐞 Bug ✓ Correctness
Description
In sample18-lazy-relations, replacing innerJoinAndSelect with relations changes the query from
an INNER JOIN filter to LEFT JOIN loading, so find() returns posts without categories and the
sample’s posts[0].categories step can operate on the wrong post (or an empty relation) and no
longer demonstrates category removal correctly.
Code

sample/sample18-lazy-relations/app.ts[R99-103]

             return postRepository.find({
-                    join: {
-                        alias: "post",
-                        innerJoinAndSelect: { categories: "post.categories" },
+                    relations: {
+                        categories: true,
                 },
             })
Evidence
The sample creates multiple posts before the categories post, then calls `find({ relations: {
categories: true }}) and assumes posts[0] is the post that has categories. However, relations`
loading uses LEFT joins (non-filtering), so posts without categories are included in the result set
and the first element is not guaranteed to be the categories post.

sample/sample18-lazy-relations/app.ts[27-50]
sample/sample18-lazy-relations/app.ts[89-113]
src/query-builder/SelectQueryBuilder.ts[3950-4008]
docs/docs/guides/8-migration-v1.md[351-351]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`sample18-lazy-relations` previously used an `innerJoinAndSelect` via deprecated `find` join options to load only posts that have categories. After migrating to `relations`, TypeORM loads relations using LEFT JOINs, so `find()` returns posts without categories too. The sample then assumes `posts[0]` has categories and attempts to remove one, which can become a no-op or operate on the wrong post.
### Issue Context
- The sample creates at least two posts *without* categories before creating the &amp;amp;amp;quot;Post &amp;amp;amp;amp; Categories&amp;amp;amp;quot; record.
- `relations` uses LEFT joins (non-filtering).
### Fix Focus Areas
- sample/sample18-lazy-relations/app.ts[89-113]
### Suggested change (one of)
1) Capture the result of `postRepository.save(post)` for the categories post and then load by its `id` using `findOne` + `relations`.
2) Use QueryBuilder for an INNER JOIN filter (as the migration guide recommends for inner joins) and then operate on the returned post.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. Join option not rejected 🐞 Bug ⛯ Reliability
Description
The deprecated findOptions.join is no longer applied by SelectQueryBuilder, but there is no
runtime error when it is still provided; for JS/any callers it can be silently ignored, producing
queries without the expected joins.
Code

src/query-builder/SelectQueryBuilder.ts[L3318-3358]

-            if (this.findOptions.join) {
-                if (this.findOptions.join.leftJoin)
-                    Object.keys(this.findOptions.join.leftJoin).forEach(
-                        (key) => {
-                            this.leftJoin(
-                                this.findOptions.join!.leftJoin![key],
-                                key,
-                            )
-                        },
-                    )
-
-                if (this.findOptions.join.innerJoin)
-                    Object.keys(this.findOptions.join.innerJoin).forEach(
-                        (key) => {
-                            this.innerJoin(
-                                this.findOptions.join!.innerJoin![key],
-                                key,
-                            )
-                        },
-                    )
-
-                if (this.findOptions.join.leftJoinAndSelect)
-                    Object.keys(
-                        this.findOptions.join.leftJoinAndSelect,
-                    ).forEach((key) => {
-                        this.leftJoinAndSelect(
-                            this.findOptions.join!.leftJoinAndSelect![key],
-                            key,
-                        )
-                    })
-
-                if (this.findOptions.join.innerJoinAndSelect)
-                    Object.keys(
-                        this.findOptions.join.innerJoinAndSelect,
-                    ).forEach((key) => {
-                        this.innerJoinAndSelect(
-                            this.findOptions.join!.innerJoinAndSelect![key],
-                            key,
-                        )
-                    })
-            }
Evidence
The PR adds explicit runtime errors for removed string-array select/relations, but join is
neither part of the FindOneOptions API anymore nor validated at runtime in applyFindOptions. As
a result, providing join (especially alongside valid options like where) can be accepted and
then ignored during query building, yielding incomplete result shapes without a clear error message.

src/query-builder/SelectQueryBuilder.ts[3162-3187]
src/query-builder/SelectQueryBuilder.ts[3281-3351]
src/find-options/FindOneOptions.ts[17-40]
src/find-options/FindOptionsUtils.ts[24-45]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`findOptions.join` has been removed, but it is not explicitly rejected at runtime. JS/`any` callers can still pass `join`, and it may be silently ignored during query building.
## Issue Context
`SelectQueryBuilder.applyFindOptions` now throws for removed string-array `select`/`relations`, but there is no analogous check for `join`.
## Fix Focus Areas
- src/query-builder/SelectQueryBuilder.ts[3148-3204]
## Suggested fix approach
- In `applyFindOptions` (early in the method, near the other validation checks), detect `(this.findOptions as any).join` and throw `TypeORMError` with a migration message (e.g., &amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;FindOptions.join was removed; use relations object syntax or QueryBuilder joins&amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;).
- Optionally also guard in `FindOptionsUtils.isFindOneOptions`/`isFindManyOptions` or `setFindOptions` to provide earlier/friendlier failure modes, but the `applyFindOptions` guard is sufficient for correctness.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (1)
7. Array select migration error🐞 Bug ⛯ Reliability
Description
Array-based select/relations inputs can still be passed by untyped callers, but the query
builder now treats arrays as objects and iterates numeric keys, throwing
EntityPropertyNotFoundError for property paths like "0". This yields a confusing runtime failure
instead of a clear migration error for removed syntax.
Code

src/query-builder/SelectQueryBuilder.ts[R3162-3167]

 if (this.findOptions.select) {
-                const select = Array.isArray(this.findOptions.select)
-                    ? OrmUtils.propertyPathsToTruthyObject(
-                          this.findOptions.select as string[],
-                      )
-                    : this.findOptions.select
-
     this.buildSelect(
-                    select,
+                    this.findOptions.select,
         this.expressionMap.mainAlias!.metadata,
         this.expressionMap.mainAlias!.name,
     )
Evidence
SelectQueryBuilder now forwards findOptions.select/relations directly into builders that
iterate for (const key in ...) and validate those keys as entity property paths. If an array is
provided at runtime, the keys are indices (e.g. "0"), which triggers EntityPropertyNotFoundError
with an unclear message.

src/query-builder/SelectQueryBuilder.ts[3162-3182]
src/query-builder/SelectQueryBuilder.ts[3877-3894]
src/error/EntityPropertyNotFoundError.ts[7-12]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
After removing support for string-array `select`/`relations`, runtime callers (e.g. JavaScript or `any`-typed TypeScript) can still pass arrays. The current code then throws `EntityPropertyNotFoundError` for numeric keys like &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;0&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;, which is a confusing migration experience.
### Issue Context
Even though types were updated, runtime validation is still valuable for users not protected by TypeScript.
### Fix Focus Areas
- src/query-builder/SelectQueryBuilder.ts[3162-3193]
- src/query-builder/SelectQueryBuilder.ts[3877-3921]
### Suggested fix
- Before calling `buildSelect` / `buildRelations`, check `Array.isArray(this.findOptions.select)` / `Array.isArray(this.findOptions.relations)`.
- If true, throw an error like: `String-array select/relations are removed in v1. Use object syntax: select: { col: true }, relations: { rel: true }`.
- This preserves the intentional breaking change but improves debuggability and reduces support burden.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider Grey Divider
Results up to commit 93807bd


🐞 Bugs (4) 📘 Rule violations (0) 📎 Requirement gaps (0) 📐 Spec deviations (0)

Grey Divider
Action required
1. Mongo join becomes filter 🐞 Bug ✓ Correctness ⭐ New
Description
After removing join from FindOptionsUtils.isFindOneOptions/isFindManyOptions, an object like `{
join: {...} } is no longer classified as FindOptions in MongoEntityManager` and is instead used as
the MongoDB filter object. This can cause queries to return wrong/empty results for untyped/JS
callers still passing the (now removed) join option.
Code

src/find-options/FindOptionsUtils.ts[R32-37]

                typeof possibleOptions.select === "object" ||
                typeof possibleOptions.relations === "object" ||
                typeof possibleOptions.where === "object" ||
-                // typeof possibleOptions.where === "string" ||
-                typeof possibleOptions.join === "object" ||
                typeof possibleOptions.order === "object" ||
                typeof possibleOptions.cache === "object" ||
                typeof possibleOptions.cache === "boolean" ||
Evidence
isFindOneOptions no longer considers a join property, so MongoEntityManager will not treat `{
join: ... }` as options; it returns the object as-is and passes it as the Mongo filter.

src/find-options/FindOptionsUtils.ts[24-47]
src/entity-manager/MongoEntityManager.ts[1104-1122]
src/entity-manager/MongoEntityManager.ts[101-118]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`MongoEntityManager` can receive untyped inputs where callers still pass the removed `join` option. After this PR, `{ join: ... }` is no longer recognized as FindOptions and is treated as the MongoDB filter, producing wrong/empty results.

## Issue Context
This is a breaking change, but failing fast with a clear error is safer than silently changing query semantics.

## Fix Focus Areas
- src/entity-manager/MongoEntityManager.ts[1104-1144]
- src/find-options/FindOptionsUtils.ts[24-47]

## Suggested fix
- In `convertFindManyOptionsOrConditionsToMongodbQuery` and `convertFindOneOptionsOrConditionsToMongodbQuery`, detect `(optionsOrConditions as any)?.join != null` and throw a `TypeORMError` with a message like: `FindOptions.join was removed. Use relations: {...} for left joins or QueryBuilder for other join types.`
- (Optional) Add a small unit/functional test ensuring `{ join: {...} }` throws rather than being treated as filter criteria.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Mongo select ignored 🐞 Bug ✓ Correctness
Description
MongoEntityManager still applies cursor.project(...) when options.select is provided, but
convertFindOptionsSelectToProjectCriteria now always returns {}, so MongoDB projections are
never applied. This breaks FindOneOptions.select behavior for MongoDB and can cause over-fetching.
Code

src/entity-manager/MongoEntityManager.ts[R1089-1094]

protected convertFindOptionsSelectToProjectCriteria(
-        selects: FindOptionsSelect<any> | FindOptionsSelectByString...

@qodo-free-for-open-source-projects
Copy link
Copy Markdown

Persistent review updated to latest commit aa3ed31

@qodo-free-for-open-source-projects
Copy link
Copy Markdown

Persistent review updated to latest commit 6291560

@qodo-free-for-open-source-projects
Copy link
Copy Markdown

Persistent review updated to latest commit ff6041f

@coveralls
Copy link
Copy Markdown

coveralls commented Mar 11, 2026

Coverage Status

coverage: 73.248% (+0.03%) from 73.221%
when pulling 4a1a970 on refactor/remove-deprecated-find-options
into 981d601 on master.

@qodo-free-for-open-source-projects
Copy link
Copy Markdown

Persistent review updated to latest commit 824b829

@qodo-free-for-open-source-projects
Copy link
Copy Markdown

Persistent review updated to latest commit 8f87a4d

@qodo-free-for-open-source-projects
Copy link
Copy Markdown

Persistent review updated to latest commit daf7c80

@pkuczynski pkuczynski enabled auto-merge (squash) March 12, 2026 16:17
@qodo-free-for-open-source-projects
Copy link
Copy Markdown

Persistent review updated to latest commit bc5a599

@alumni alumni disabled auto-merge March 12, 2026 20:08
@alumni
Copy link
Copy Markdown
Collaborator

alumni commented Mar 12, 2026

Following #12188 (comment), I'd only remove join for now, keep everything else unchanged.

@qodo-free-for-open-source-projects
Copy link
Copy Markdown

Persistent review updated to latest commit abda80c

Remove the deprecated `join` property from `FindOneOptions` and
`FindManyOptions`, along with the `JoinOptions` interface and all
related handling code.

- Delete `src/find-options/JoinOptions.ts` interface
- Remove `join` property from `FindOneOptions`
- Remove `join` handling from `SelectQueryBuilder.setFindOptions()`
- Remove `extractFindManyOptionsAlias()` and `join` type guard from `FindOptionsUtils`
- Remove unused `FindOptionsUtils` import from `EntityManager`
- Convert all test and sample `join:` usages to equivalent `relations:` syntax
- Add migration guide entry for the removal
@pkuczynski pkuczynski force-pushed the refactor/remove-deprecated-find-options branch from abda80c to 0f9eb91 Compare March 14, 2026 21:41
@qodo-free-for-open-source-projects
Copy link
Copy Markdown

qodo-free-for-open-source-projects bot commented Mar 14, 2026

Persistent review updated to latest commit 0f9eb91

@pkuczynski pkuczynski changed the title refactor(find-options): remove deprecated join, string-based select and relations refactor(find-options)!: remove deprecated join option from find methods Mar 14, 2026
… suite

The "should allow locking a relation of a relation" test relied on the
removed join option with innerJoinAndSelect. Since relations only
produces LEFT JOINs, PostgreSQL rejects FOR UPDATE on the nullable
side. Move the test to the query-builder locking suite using
innerJoinAndSelect and expand the migration guide to document when
QueryBuilder is needed instead of relations.
@qodo-free-for-open-source-projects
Copy link
Copy Markdown

qodo-free-for-open-source-projects bot commented Mar 14, 2026

Persistent review updated to latest commit 9e91b53

@qodo-free-for-open-source-projects
Copy link
Copy Markdown

Persistent review updated to latest commit 93807bd

@qodo-free-for-open-source-projects
Copy link
Copy Markdown

Persistent review updated to latest commit fcdb6d0

@pkuczynski pkuczynski closed this Mar 18, 2026
@pkuczynski pkuczynski reopened this Mar 18, 2026
@qodo-free-for-open-source-projects
Copy link
Copy Markdown

Review Summary by Qodo

Remove deprecated join option and add runtime validation with migration guide

🐞 Bug fix ✨ Enhancement

Grey Divider

Walkthroughs

Description
• Remove deprecated join option from find methods and interfaces
  - Delete JoinOptions interface and all related handling code
  - Remove join property from FindOneOptions
  - Remove join processing from SelectQueryBuilder.setFindOptions()
• Add runtime validation to reject removed join option
  - Implement rejectJoinOption() in FindOptionsUtils for untyped callers
  - Apply validation in SelectQueryBuilder and MongoEntityManager
• Convert all test and sample code to use relations syntax
  - Update 20+ test files and 3 sample files
  - Move nested-relation locking test to QueryBuilder suite
• Expand migration guide with detailed conversion examples
  - Document leftJoinAndSelectrelations mapping
  - Show QueryBuilder alternatives for other join types
  - Include PostgreSQL locking considerations
Diagram
flowchart LR
  A["Deprecated join option"] -->|Remove from types| B["FindOneOptions/FindManyOptions"]
  A -->|Delete interface| C["JoinOptions.ts"]
  A -->|Remove handling| D["SelectQueryBuilder"]
  E["Runtime validation"] -->|Add rejectJoinOption| F["FindOptionsUtils"]
  F -->|Apply in| D
  F -->|Apply in| G["MongoEntityManager"]
  H["Test/Sample updates"] -->|Convert to relations| I["20+ test files"]
  H -->|Convert to relations| J["3 sample files"]
  K["Migration guide"] -->|Document conversions| L["v1 migration guide"]
Loading

Grey Divider

File Changes

1. src/find-options/JoinOptions.ts 🐞 Bug fix +0/-71

Delete deprecated JoinOptions interface file

src/find-options/JoinOptions.ts


2. src/find-options/FindOneOptions.ts 🐞 Bug fix +0/-7

Remove join property from FindOneOptions

src/find-options/FindOneOptions.ts


3. src/find-options/FindOptionsUtils.ts ✨ Enhancement +15/-14

Add runtime validation and remove join extraction

src/find-options/FindOptionsUtils.ts


View more (23)
4. src/query-builder/SelectQueryBuilder.ts 🐞 Bug fix +1/-42

Remove join option handling and add validation

src/query-builder/SelectQueryBuilder.ts


5. src/entity-manager/EntityManager.ts 🐞 Bug fix +5/-22

Remove FindOptionsUtils import and join alias extraction

src/entity-manager/EntityManager.ts


6. src/entity-manager/MongoEntityManager.ts ✨ Enhancement +4/-0

Add runtime join option rejection in conversion methods

src/entity-manager/MongoEntityManager.ts


7. src/index.ts 🐞 Bug fix +0/-1

Remove JoinOptions export from public API

src/index.ts


8. sample/sample18-lazy-relations/app.ts 📝 Documentation +11/-12

Convert join syntax to relations in sample code

sample/sample18-lazy-relations/app.ts


9. sample/sample19-one-side-relations/app.ts 📝 Documentation +4/-7

Convert join syntax to relations in sample code

sample/sample19-one-side-relations/app.ts


10. sample/sample21-custom-join-table-column/app.ts 📝 Documentation +3/-6

Convert join syntax to relations in sample code

sample/sample21-custom-join-table-column/app.ts


11. test/functional/cascades/cascade-insert-from-both-sides/cascade-insert-from-both-sides.test.ts 🧪 Tests +4/-10

Convert join to relations in cascade tests

test/functional/cascades/cascade-insert-from-both-sides/cascade-insert-from-both-sides.test.ts


12. test/functional/persistence/custom-column-name-pk/custom-column-name-pk.test.ts 🧪 Tests +2/-5

Convert join to relations in persistence tests

test/functional/persistence/custom-column-name-pk/custom-column-name-pk.test.ts


13. test/functional/persistence/custom-column-names/persistence-custom-column-names.test.ts 🧪 Tests +12/-19

Convert join to relations in custom column tests

test/functional/persistence/custom-column-names/persistence-custom-column-names.test.ts


14. test/functional/persistence/many-to-many/persistence-many-to-many.test.ts 🧪 Tests +21/-35

Convert join to relations in many-to-many tests

test/functional/persistence/many-to-many/persistence-many-to-many.test.ts


15. test/functional/persistence/multi-primary-key-on-both-sides/multi-primary-key.test.ts 🧪 Tests +2/-5

Convert join to relations in multi-key tests

test/functional/persistence/multi-primary-key-on-both-sides/multi-primary-key.test.ts


16. test/functional/persistence/multi-primary-key/multi-primary-key.test.ts 🧪 Tests +2/-5

Convert join to relations in multi-key tests

test/functional/persistence/multi-primary-key/multi-primary-key.test.ts


17. test/functional/persistence/one-to-many/persistence-one-to-many.test.ts 🧪 Tests +6/-15

Convert join to relations in one-to-many tests

test/functional/persistence/one-to-many/persistence-one-to-many.test.ts


18. test/functional/persistence/partial-persist/partial-persist.test.ts 🧪 Tests +8/-20

Convert join to relations in partial persist tests

test/functional/persistence/partial-persist/partial-persist.test.ts


19. test/functional/query-builder/locking/query-builder-locking.test.ts 🧪 Tests +19/-0

Add nested relation locking test with innerJoinAndSelect

test/functional/query-builder/locking/query-builder-locking.test.ts


20. test/functional/repository/find-options-locking/find-options-locking.test.ts 🧪 Tests +0/-26

Remove locking test that relied on join option

test/functional/repository/find-options-locking/find-options-locking.test.ts


21. test/functional/repository/set-add-remove-relations/repository-set-add-remove-relations.test.ts 🧪 Tests +16/-28

Convert join to relations in relation manipulation tests

test/functional/repository/set-add-remove-relations/repository-set-add-remove-relations.test.ts


22. test/functional/relations/relation-mapped-to-different-name-column/relation-mapped-to-different-name-column.test.ts 🧪 Tests +2/-5

Convert join to relations in relation mapping tests

test/functional/relations/relation-mapped-to-different-name-column/relation-mapped-to-different-name-column.test.ts


23. test/functional/relations/relation-with-primary-key/relation-with-primary-key.test.ts 🧪 Tests +2/-5

Convert join to relations in primary key relation tests

test/functional/relations/relation-with-primary-key/relation-with-primary-key.test.ts


24. test/github-issues/151/issue-151.test.ts 🧪 Tests +2/-5

Convert join to relations in GitHub issue test

test/github-issues/151/issue-151.test.ts


25. test/github-issues/161/issue-161.test.ts 🧪 Tests +6/-13

Convert join to relations in GitHub issue test

test/github-issues/161/issue-161.test.ts


26. docs/docs/guides/8-migration-v1.md 📝 Documentation +90/-0

Add comprehensive migration guide for join removal

docs/docs/guides/8-migration-v1.md


Grey Divider

Qodo Logo

@pkuczynski pkuczynski enabled auto-merge (squash) March 18, 2026 22:59
@sonarqubecloud
Copy link
Copy Markdown

@qodo-free-for-open-source-projects
Copy link
Copy Markdown

Persistent review updated to latest commit fcdb6d0

@qodo-free-for-open-source-projects
Copy link
Copy Markdown

Persistent review updated to latest commit 4a1a970

@pkuczynski pkuczynski merged commit e863026 into master Mar 18, 2026
43 checks passed
@pkuczynski pkuczynski deleted the refactor/remove-deprecated-find-options branch March 18, 2026 23:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

6 participants