chore(twenty-server): upgrade typeorm to 0.3.29 (#21957)

## Summary

Upgrades **typeorm `0.3.26` → `0.3.29`** and adapts the twenty-orm
`update`/`upsert` overrides to typeorm's newly-added
`options.returning`. Upgrading to resolve
[this](https://github.com/twentyhq/twenty/security/dependabot/1573)
alert.

## Why

`0.3.29` is the latest release compatible with
`@ptc-org/nestjs-query-typeorm` (peers `typeorm@^0.3.15`; the `1.x` line
has no compatible release, so it's blocked until that dependency moves).

## Changes

**`chore` — bump**
- `typeorm` patch descriptor `0.3.26 → 0.3.29` + `yarn.lock`.
- Local patch carried over **unchanged** (pure rename) — both hunks
(`PickKeysByType` nullable-awareness, `DeleteResult.generatedMaps`) are
still absent upstream in `0.3.29`, so it remains load-bearing.

**`refactor` — adapt overrides**
- `0.3.29` adds `options?: UpdateOptions` (carrying `returning`) to
`EntityManager`/`Repository` `update()`. The override must accept it at
the base-mandated position, so it's added as its **own dedicated
parameter** (not hidden inside `permissionOptions`), honoring
`options.returning` with a fallback to Twenty's permission-aware
`selectedColumns` (`'*'` default).
- The same merge is applied to `upsert()`, which already received
`UpsertOptions` but was dropping its `returning` field — so both write
methods now treat the option identically.
- Internal call sites + specs updated for the new parameter slot.

## Verification

- `nx typecheck twenty-server` — **0 errors**
- twenty-orm unit tests — **191 / 191 pass**
- `oxlint` / `oxfmt` — clean
This commit is contained in:
Abdullah.
2026-06-22 19:08:09 +05:00
committed by GitHub
parent 6eb60f8a49
commit c171c62099
10 changed files with 83 additions and 43 deletions
+1 -1
View File
@@ -166,7 +166,7 @@
"tsdav": "^2.2.0",
"tslib": "2.8.1",
"type-fest": "4.10.1",
"typeorm": "patch:typeorm@0.3.26#./patches/typeorm+0.3.26.patch",
"typeorm": "patch:typeorm@0.3.29#./patches/typeorm+0.3.29.patch",
"unzipper": "^0.12.3",
"uuid": "^11.1.1",
"zod": "^4.1.11"
@@ -474,7 +474,13 @@ describe('WorkspaceEntityManager', () => {
describe('Update Methods', () => {
it('should call createQueryBuilder with permissionOptions for update', async () => {
await withWorkspaceContext(mockWorkspaceContext, () =>
entityManager.update('test-entity', {}, {}, mockPermissionOptions),
entityManager.update(
'test-entity',
{},
{},
undefined,
mockPermissionOptions,
),
);
expect(entityManager['createQueryBuilder']).toHaveBeenCalledWith(
'test-entity',
@@ -30,6 +30,7 @@ import { FindOptionsUtils } from 'typeorm/find-options/FindOptionsUtils';
import { EntityPersistExecutor } from 'typeorm/persistence/EntityPersistExecutor';
import { type QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity';
import { PlainObjectToDatabaseEntityTransformer } from 'typeorm/query-builder/transformer/PlainObjectToDatabaseEntityTransformer';
import { type UpdateOptions } from 'typeorm/repository/UpdateOptions';
import { type UpsertOptions } from 'typeorm/repository/UpsertOptions';
import { InstanceChecker } from 'typeorm/util/InstanceChecker';
@@ -320,7 +321,7 @@ export class WorkspaceEntityManager extends EntityManager {
.into(target)
.values(entities)
.orUpdate(overwrites, conflictTargets, upsertOptions)
.returning(selectedColumns);
.returning(options.returning ?? selectedColumns);
return queryBuilder.execute();
}
@@ -338,6 +339,7 @@ export class WorkspaceEntityManager extends EntityManager {
| ObjectId[]
| unknown,
partialEntity: QueryDeepPartialEntity<Entity>,
options?: UpdateOptions,
permissionOptions?: PermissionOptions,
selectedColumns: string[] | '*' = '*',
): Promise<UpdateResult> {
@@ -370,7 +372,7 @@ export class WorkspaceEntityManager extends EntityManager {
.update()
.set(partialEntity)
.whereInIds(criteria)
.returning(selectedColumns)
.returning(options?.returning ?? selectedColumns)
.execute();
} else {
return this.createQueryBuilder(
@@ -382,7 +384,7 @@ export class WorkspaceEntityManager extends EntityManager {
.update()
.set(partialEntity)
.where(criteria)
.returning(selectedColumns)
.returning(options?.returning ?? selectedColumns)
.execute();
}
}
@@ -438,6 +440,7 @@ export class WorkspaceEntityManager extends EntityManager {
target,
criteria,
values,
undefined,
permissionOptions,
selectedColumns,
);
@@ -1050,6 +1053,7 @@ export class WorkspaceEntityManager extends EntityManager {
target,
criteria,
values,
undefined,
permissionOptions,
selectedColumns,
);
@@ -405,6 +405,7 @@ describe('WorkspaceRepository', () => {
'test-entity',
{ id: 'test-id' },
{ name: 'test' },
undefined,
{
shouldBypassPermissionChecks: false,
objectRecordsPermissions: mockObjectRecordsPermissions,
@@ -17,6 +17,7 @@ import {
} from 'typeorm';
import { type PickKeysByType } from 'typeorm/common/PickKeysByType';
import { type QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity';
import { type UpdateOptions } from 'typeorm/repository/UpdateOptions';
import { type UpsertOptions } from 'typeorm/repository/UpsertOptions';
import { type FeatureFlagMap } from 'src/engine/core-modules/feature-flag/interfaces/feature-flag-map.interface';
@@ -592,6 +593,7 @@ export class WorkspaceRepository<
| ObjectId[]
| FindOptionsWhere<T>,
partialEntity: QueryDeepPartialEntity<T>,
options?: UpdateOptions,
entityManager?: WorkspaceEntityManager,
selectedColumns?: string[],
): Promise<UpdateResult> {
@@ -610,6 +612,7 @@ export class WorkspaceRepository<
this.target,
criteria,
partialEntity,
options,
permissionOptions,
selectedColumns,
);
@@ -408,6 +408,7 @@ export class WorkflowCommonWorkspaceService {
await workflowRepository.update(
workflowId,
{ statuses: newStatuses },
undefined,
queryRunner.manager,
);
}
@@ -417,6 +418,7 @@ export class WorkflowCommonWorkspaceService {
await workflowVersionRepository.update(
workflowVersion.id,
{ status: WorkflowVersionStatus.DEACTIVATED },
undefined,
queryRunner.manager,
);
}
@@ -438,6 +438,7 @@ export class WorkflowRunWorkspaceService {
workflowRunToUpdate.id,
partialUpdate,
undefined,
undefined,
['id'],
);
}, authContext);
@@ -283,6 +283,7 @@ export class WorkflowTriggerWorkspaceService {
await workflowVersionRepository.update(
{ id: workflow.lastPublishedVersionId },
{ status: WorkflowVersionStatus.ARCHIVED },
undefined,
queryRunner.manager,
);
}
@@ -290,6 +291,7 @@ export class WorkflowTriggerWorkspaceService {
await workflowRepository.update(
{ id: workflow.id },
{ lastPublishedVersionId: workflowVersion.id },
undefined,
queryRunner.manager,
);
}
@@ -317,6 +319,7 @@ export class WorkflowTriggerWorkspaceService {
await workflowVersionRepository.update(
{ id: workflowVersion.id },
{ status: WorkflowVersionStatus.ACTIVE },
undefined,
queryRunner.manager,
);
@@ -374,6 +377,7 @@ export class WorkflowTriggerWorkspaceService {
await workflowVersionRepository.update(
{ id: workflowVersion.id },
{ status: WorkflowVersionStatus.DEACTIVATED },
undefined,
queryRunner.manager,
);
+57 -38
View File
@@ -26923,6 +26923,13 @@ __metadata:
languageName: node
linkType: hard
"ansis@npm:^4.2.0":
version: 4.3.1
resolution: "ansis@npm:4.3.1"
checksum: 10c0/d1a48090f9c33b18f254a3496e5336a20391a51140b552a1c0bc38710ae7c8bc36a62658f28759797d7bce15e89b893e9ef1962ea1ea42a291d112263f6e593c
languageName: node
linkType: hard
"any-promise@npm:^1.0.0":
version: 1.3.0
resolution: "any-promise@npm:1.3.0"
@@ -31051,7 +31058,7 @@ __metadata:
languageName: node
linkType: hard
"dayjs@npm:^1.10.0, dayjs@npm:^1.11.13":
"dayjs@npm:^1.10.0, dayjs@npm:^1.11.20":
version: 1.11.21
resolution: "dayjs@npm:1.11.21"
checksum: 10c0/bd97dfdc4bfea3c66268635690313828b386faa040fbc1f829ff42a2bd748b72c9d9b3c8f9616ce9e61fcb78923f1461a462c969c54b1084458ae1b715898fb0
@@ -31228,6 +31235,18 @@ __metadata:
languageName: node
linkType: hard
"dedent@npm:^1.7.2":
version: 1.7.2
resolution: "dedent@npm:1.7.2"
peerDependencies:
babel-plugin-macros: ^3.1.0
peerDependenciesMeta:
babel-plugin-macros:
optional: true
checksum: 10c0/acaff07cac355b93f17b1b17ebbb84d3cc55af6ab4b7814c3f505e061903e168bc6bf9ddce331552d64dee1525f0b4c549c9ade46aebfac6f69caaed74e90751
languageName: node
linkType: hard
"deeks@npm:3.1.0":
version: 3.1.0
resolution: "deeks@npm:3.1.0"
@@ -31914,7 +31933,7 @@ __metadata:
languageName: node
linkType: hard
"dotenv@npm:^16.3.0, dotenv@npm:^16.4.5, dotenv@npm:^16.4.7, dotenv@npm:^16.5.0":
"dotenv@npm:^16.3.0, dotenv@npm:^16.4.5, dotenv@npm:^16.5.0, dotenv@npm:^16.6.1":
version: 16.6.1
resolution: "dotenv@npm:16.6.1"
checksum: 10c0/15ce56608326ea0d1d9414a5c8ee6dcf0fffc79d2c16422b4ac2268e7e2d76ff5a572d37ffe747c377de12005f14b3cc22361e79fc7f1061cce81f77d2c973dc
@@ -35337,7 +35356,7 @@ __metadata:
languageName: node
linkType: hard
"glob@npm:^10.0.0, glob@npm:^10.3.10, glob@npm:^10.3.7, glob@npm:^10.4.5":
"glob@npm:^10.0.0, glob@npm:^10.3.10, glob@npm:^10.3.7, glob@npm:^10.5.0":
version: 10.5.0
resolution: "glob@npm:10.5.0"
dependencies:
@@ -50682,7 +50701,7 @@ __metadata:
languageName: node
linkType: hard
"sha.js@npm:^2.4.0, sha.js@npm:^2.4.11":
"sha.js@npm:^2.4.0, sha.js@npm:^2.4.12":
version: 2.4.12
resolution: "sha.js@npm:2.4.12"
dependencies:
@@ -51596,7 +51615,7 @@ __metadata:
languageName: node
linkType: hard
"sql-highlight@npm:^6.0.0":
"sql-highlight@npm:^6.1.0":
version: 6.1.0
resolution: "sql-highlight@npm:6.1.0"
checksum: 10c0/9614f4608bfde8ea7bf9b2fe9233dcc99a619c91cbc3f5cd85a6fb5ad4b2177f4ac8ca4a0191f4243ff8aea3b6f2a1229efc88635298269e0049b2ac08bde263
@@ -54304,7 +54323,7 @@ __metadata:
twenty-emails: "workspace:*"
twenty-shared: "workspace:*"
type-fest: "npm:4.10.1"
typeorm: "patch:typeorm@0.3.26#./patches/typeorm+0.3.26.patch"
typeorm: "patch:typeorm@0.3.29#./patches/typeorm+0.3.29.patch"
unzipper: "npm:^0.12.3"
uuid: "npm:^11.1.1"
zod: "npm:^4.1.11"
@@ -54705,38 +54724,38 @@ __metadata:
languageName: node
linkType: hard
"typeorm@npm:0.3.26":
version: 0.3.26
resolution: "typeorm@npm:0.3.26"
"typeorm@npm:0.3.29":
version: 0.3.29
resolution: "typeorm@npm:0.3.29"
dependencies:
"@sqltools/formatter": "npm:^1.2.5"
ansis: "npm:^3.17.0"
ansis: "npm:^4.2.0"
app-root-path: "npm:^3.1.0"
buffer: "npm:^6.0.3"
dayjs: "npm:^1.11.13"
debug: "npm:^4.4.0"
dedent: "npm:^1.6.0"
dotenv: "npm:^16.4.7"
glob: "npm:^10.4.5"
sha.js: "npm:^2.4.11"
sql-highlight: "npm:^6.0.0"
dayjs: "npm:^1.11.20"
debug: "npm:^4.4.3"
dedent: "npm:^1.7.2"
dotenv: "npm:^16.6.1"
glob: "npm:^10.5.0"
reflect-metadata: "npm:^0.2.2"
sha.js: "npm:^2.4.12"
sql-highlight: "npm:^6.1.0"
tslib: "npm:^2.8.1"
uuid: "npm:^11.1.0"
uuid: "npm:^11.1.1"
yargs: "npm:^17.7.2"
peerDependencies:
"@google-cloud/spanner": ^5.18.0 || ^6.0.0 || ^7.0.0
"@google-cloud/spanner": ^5.18.0 || ^6.0.0 || ^7.0.0 || ^8.0.0
"@sap/hana-client": ^2.14.22
better-sqlite3: ^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0 || ^12.0.0
ioredis: ^5.0.4
mongodb: ^5.8.0 || ^6.0.0
mssql: ^9.1.1 || ^10.0.1 || ^11.0.1
mssql: ^9.1.1 || ^10.0.0 || ^11.0.0 || ^12.0.0
mysql2: ^2.2.5 || ^3.0.1
oracledb: ^6.3.0
pg: ^8.5.1
pg-native: ^3.0.0
pg-query-stream: ^4.0.0
redis: ^3.1.1 || ^4.0.0 || ^5.0.14
reflect-metadata: ^0.1.14 || ^0.2.0
sql.js: ^1.4.0
sqlite3: ^5.0.3
ts-node: ^10.7.0
@@ -54778,42 +54797,42 @@ __metadata:
typeorm: cli.js
typeorm-ts-node-commonjs: cli-ts-node-commonjs.js
typeorm-ts-node-esm: cli-ts-node-esm.js
checksum: 10c0/a09ed0609a5799718bc837450b84593f6a64e6698e0662162eee2f7f12591ad9cb6f9173b42ae1d16f784d1ea09712c6e886481f4a3bdc7f851402cfde54e65a
checksum: 10c0/9fe642e87657ff81005edfcf983f183a3172adba0eaca90fdc36fba1dd1348b41444f2b168d98adc57f3dc16b20b86bdde65c489cad9ba35bb7627c103dcc413
languageName: node
linkType: hard
"typeorm@patch:typeorm@0.3.26#./patches/typeorm+0.3.26.patch::locator=twenty-server%40workspace%3Apackages%2Ftwenty-server":
version: 0.3.26
resolution: "typeorm@patch:typeorm@npm%3A0.3.26#./patches/typeorm+0.3.26.patch::version=0.3.26&hash=e61204&locator=twenty-server%40workspace%3Apackages%2Ftwenty-server"
"typeorm@patch:typeorm@0.3.29#./patches/typeorm+0.3.29.patch::locator=twenty-server%40workspace%3Apackages%2Ftwenty-server":
version: 0.3.29
resolution: "typeorm@patch:typeorm@npm%3A0.3.29#./patches/typeorm+0.3.29.patch::version=0.3.29&hash=e61204&locator=twenty-server%40workspace%3Apackages%2Ftwenty-server"
dependencies:
"@sqltools/formatter": "npm:^1.2.5"
ansis: "npm:^3.17.0"
ansis: "npm:^4.2.0"
app-root-path: "npm:^3.1.0"
buffer: "npm:^6.0.3"
dayjs: "npm:^1.11.13"
debug: "npm:^4.4.0"
dedent: "npm:^1.6.0"
dotenv: "npm:^16.4.7"
glob: "npm:^10.4.5"
sha.js: "npm:^2.4.11"
sql-highlight: "npm:^6.0.0"
dayjs: "npm:^1.11.20"
debug: "npm:^4.4.3"
dedent: "npm:^1.7.2"
dotenv: "npm:^16.6.1"
glob: "npm:^10.5.0"
reflect-metadata: "npm:^0.2.2"
sha.js: "npm:^2.4.12"
sql-highlight: "npm:^6.1.0"
tslib: "npm:^2.8.1"
uuid: "npm:^11.1.0"
uuid: "npm:^11.1.1"
yargs: "npm:^17.7.2"
peerDependencies:
"@google-cloud/spanner": ^5.18.0 || ^6.0.0 || ^7.0.0
"@google-cloud/spanner": ^5.18.0 || ^6.0.0 || ^7.0.0 || ^8.0.0
"@sap/hana-client": ^2.14.22
better-sqlite3: ^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0 || ^12.0.0
ioredis: ^5.0.4
mongodb: ^5.8.0 || ^6.0.0
mssql: ^9.1.1 || ^10.0.1 || ^11.0.1
mssql: ^9.1.1 || ^10.0.0 || ^11.0.0 || ^12.0.0
mysql2: ^2.2.5 || ^3.0.1
oracledb: ^6.3.0
pg: ^8.5.1
pg-native: ^3.0.0
pg-query-stream: ^4.0.0
redis: ^3.1.1 || ^4.0.0 || ^5.0.14
reflect-metadata: ^0.1.14 || ^0.2.0
sql.js: ^1.4.0
sqlite3: ^5.0.3
ts-node: ^10.7.0
@@ -54855,7 +54874,7 @@ __metadata:
typeorm: cli.js
typeorm-ts-node-commonjs: cli-ts-node-commonjs.js
typeorm-ts-node-esm: cli-ts-node-esm.js
checksum: 10c0/66268d90c1019c0b1c39971985d0f3f673f0236ce9a21835c7de16d5db54e3dcee39cbfad1985b0e0feb603b4f440fb25c6c6222c55a17452ac1b746d3a9e0f5
checksum: 10c0/8966a5471cb4b54922a2b1b408f9d1cef0cdd0c247807741cef6f510ce1b2954e77d788fa4f772d38c2edd0625640c3357be57aee57dd59add9b326c59f301b6
languageName: node
linkType: hard