Skip to content
Merged

Apps #9401

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Cascade, EntityName, ManyToManyOptions } from '@mikro-orm/core';
import { RelationOptions as TypeOrmRelationOptions } from 'typeorm';
import { omit } from 'underscore';
import { deepClone, isObject } from '@gauzy/utils';
import { MultiORMEnum } from '../../../../core/utils';
import { MultiORMEnum, getORMType } from '../../../../core/utils';
import { TypeOrmManyToMany } from './type-orm';
import { MikroOrmManyToMany } from './mikro-orm';
import { MikroORMInverseSide, TypeORMInverseSide, TypeORMRelationOptions, TypeORMTarget } from './shared-types';
Expand Down Expand Up @@ -56,21 +56,28 @@ export function MultiORMManyToMany<T>(
// If options are not provided, initialize an empty object
if (!options) options = {} as RelationOptions<T>;

// Use TypeORM decorator for Many-to-Many
TypeOrmManyToMany(
typeFunctionOrTarget as TypeORMTarget<T>,
inverseSideProperty as TypeORMInverseSide<T>,
options as TypeORMRelationOptions
)(target, propertyKey);

// Use MikroORM decorator for Many-to-Many
MikroOrmManyToMany(
mapManyToManyArgsForMikroORM({
typeFunctionOrTarget,
inverseSide: inverseSideProperty as InverseSide<T>,
options
})
)(target, propertyKey);
// Determine which ORM is in use
const ormType = getORMType();
Copy link

Choose a reason for hiding this comment

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

getORMType() is evaluated when decorators run (class definition time), so if DB_ORM isn’t set before entity modules are imported it will default to TypeORM and skip registering MikroORM relation metadata. That can lead to missing relations in MikroORM runtime (or vice‑versa) depending on import order/config initialization.

Other Locations
  • packages/core/src/lib/core/decorators/entity/relations/many-to-one.decorator.ts:71
  • packages/core/src/lib/core/decorators/entity/relations/one-to-many.decorator.ts:60
  • packages/core/src/lib/core/decorators/entity/relations/one-to-one.decorator.ts:71

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.


// Apply TypeORM decorator when using TypeORM
if (ormType === MultiORMEnum.TypeORM) {
TypeOrmManyToMany(
typeFunctionOrTarget as TypeORMTarget<T>,
inverseSideProperty as TypeORMInverseSide<T>,
options as TypeORMRelationOptions
)(target, propertyKey);
}

// Apply MikroORM decorator when using MikroORM
if (ormType === MultiORMEnum.MikroORM) {
MikroOrmManyToMany(
mapManyToManyArgsForMikroORM({
typeFunctionOrTarget,
inverseSide: inverseSideProperty as InverseSide<T>,
options
})
)(target, propertyKey);
}
};
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Cascade, EntityName, ManyToOneOptions } from '@mikro-orm/core';
import { omit } from 'underscore';
import { deepClone, isObject } from '@gauzy/utils';
import { MultiORMEnum, getORMType } from '../../../../core/utils';
import { TypeOrmManyToOne } from './type-orm';
import { MikroOrmManyToOne } from './mikro-orm';
import {
Expand Down Expand Up @@ -66,23 +67,30 @@ export function MultiORMManyToOne<T, O>(
// If options are not provided, initialize an empty object
if (!options) options = {} as RelationOptions<T, O>;

// Use TypeORM decorator for Many-to-One
TypeOrmManyToOne(
typeFunctionOrTarget as TypeORMTarget<T>,
inverseSideOrOptions as TypeORMInverseSide<T>,
options as TypeORMRelationOptions
)(target, propertyKey);

// Use MikroORM decorator for Many-to-One
MikroOrmManyToOne(
mapManyToOneArgsForMikroORM({
typeFunctionOrTarget,
inverseSideOrOptions: inverseSideProperty as InverseSide<T>,
options,
propertyKey,
target
})
)(target, propertyKey);
// Determine which ORM is in use
const ormType = getORMType();

// Apply TypeORM decorator when using TypeORM
if (ormType === MultiORMEnum.TypeORM) {
TypeOrmManyToOne(
typeFunctionOrTarget as TypeORMTarget<T>,
inverseSideOrOptions as TypeORMInverseSide<T>,
options as TypeORMRelationOptions
)(target, propertyKey);
Comment on lines +73 to +79
Copy link
Contributor

Choose a reason for hiding this comment

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

[P0] TypeORM ManyToOne decorator can receive the options object as the inverse-side argument.

In MultiORMManyToOne, when inverseSideOrOptions is an object it is treated as options and inverseSideProperty remains unset, but the TypeORM branch still calls TypeOrmManyToOne(..., inverseSideOrOptions as TypeORMInverseSide<T>, ...). Under TypeORM, calls like MultiORMManyToOne(User, { nullable: true }) will pass that options object as the inverse side and likely break relation metadata registration.

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/core/src/lib/core/decorators/entity/relations/many-to-one.decorator.ts
Line: 73:79

Comment:
[P0] TypeORM ManyToOne decorator can receive the *options object* as the inverse-side argument.

In `MultiORMManyToOne`, when `inverseSideOrOptions` is an object it is treated as `options` and `inverseSideProperty` remains unset, but the TypeORM branch still calls `TypeOrmManyToOne(..., inverseSideOrOptions as TypeORMInverseSide<T>, ...)`. Under TypeORM, calls like `MultiORMManyToOne(User, { nullable: true })` will pass that options object as the inverse side and likely break relation metadata registration.

How can I resolve this? If you propose a fix, please make it concise.

}

// Apply MikroORM decorator when using MikroORM
if (ormType === MultiORMEnum.MikroORM) {
MikroOrmManyToOne(
mapManyToOneArgsForMikroORM({
typeFunctionOrTarget,
inverseSideOrOptions: inverseSideProperty as InverseSide<T>,
options,
propertyKey,
target
})
)(target, propertyKey);
}
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Cascade, EntityName, OneToManyOptions } from '@mikro-orm/core';
import { RelationOptions as TypeOrmRelationOptions } from 'typeorm';
import { omit } from 'underscore';
import { deepClone, isObject } from '@gauzy/utils';
import { MultiORMEnum, getORMType } from '../../../../core/utils';
import { TypeOrmOneToMany } from './type-orm';
import { MikroOrmOneToMany } from './mikro-orm';
import { MikroORMInverseSide, TypeORMInverseSide, TypeORMRelationOptions, TypeORMTarget } from './shared-types';
Expand Down Expand Up @@ -55,21 +56,28 @@ export function MultiORMOneToMany<T>(
// If options are not provided, initialize an empty object
if (!options) options = {} as RelationOptions<T>;

// Apply TypeORM One-to-Many decorator
TypeOrmOneToMany(
typeFunctionOrTarget as TypeORMTarget<T>,
inverseSideProperty as TypeORMInverseSide<T>,
options as TypeORMRelationOptions
)(target, propertyKey);
// Determine which ORM is in use
const ormType = getORMType();

// Apply MikroORM One-to-Many decorator
MikroOrmOneToMany(
mapOneToManyArgsForMikroORM({
typeFunctionOrTarget,
inverseSide: inverseSideProperty as InverseSide<T>,
options
})
)(target, propertyKey);
// Apply TypeORM One-to-Many decorator when using TypeORM
if (ormType === MultiORMEnum.TypeORM) {
TypeOrmOneToMany(
typeFunctionOrTarget as TypeORMTarget<T>,
inverseSideProperty as TypeORMInverseSide<T>,
options as TypeORMRelationOptions
)(target, propertyKey);
}

// Apply MikroORM One-to-Many decorator when using MikroORM
if (ormType === MultiORMEnum.MikroORM) {
MikroOrmOneToMany(
mapOneToManyArgsForMikroORM({
typeFunctionOrTarget,
inverseSide: inverseSideProperty as InverseSide<T>,
options
})
)(target, propertyKey);
}
};
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Cascade, EntityName, OneToOneOptions } from '@mikro-orm/core';
import { omit } from 'underscore';
import { deepClone, isObject } from '@gauzy/utils';
import { MultiORMEnum } from '../../../../core/utils';
import { MultiORMEnum, getORMType } from '../../../../core/utils';
import {
MikroORMInverseSide,
TypeORMInverseSide,
Expand Down Expand Up @@ -67,22 +67,29 @@ export function MultiORMOneToOne<T, O>(
// If options are not provided, initialize an empty object
if (!options) options = {} as RelationOptions<T, O>;

// Use TypeORM decorator for One-to-One
TypeOrmOneToOne(
typeFunctionOrTarget as TypeORMTarget<T>,
inverseSideOrOptions as TypeORMInverseSide<T>,
options as TypeORMRelationOptions
)(target, propertyKey);

// Use MikroORM decorator for One-to-One
MikroOrmOneToOne(
mapOneToOneArgsForMikroORM({
typeFunctionOrTarget,
inverseSideOrOptions: inverseSideProperty as InverseSide<T>,
options,
propertyKey
})
)(target, propertyKey);
// Determine which ORM is in use
const ormType = getORMType();

// Apply TypeORM decorator when using TypeORM
if (ormType === MultiORMEnum.TypeORM) {
TypeOrmOneToOne(
typeFunctionOrTarget as TypeORMTarget<T>,
inverseSideOrOptions as TypeORMInverseSide<T>,
options as TypeORMRelationOptions
)(target, propertyKey);
Comment on lines +73 to +79
Copy link
Contributor

Choose a reason for hiding this comment

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

[P0] TypeORM OneToOne decorator can receive the options object as the inverse-side argument.

MultiORMOneToOne normalizes params such that if inverseSideOrOptions is an object it becomes options and inverseSideProperty remains unset, but the TypeORM branch still passes inverseSideOrOptions as the inverse-side arg. Under TypeORM, calls like MultiORMOneToOne(Profile, { cascade: true }) will end up passing the options object as the inverse side, which can break relation metadata.

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/core/src/lib/core/decorators/entity/relations/one-to-one.decorator.ts
Line: 73:79

Comment:
[P0] TypeORM OneToOne decorator can receive the *options object* as the inverse-side argument.

`MultiORMOneToOne` normalizes params such that if `inverseSideOrOptions` is an object it becomes `options` and `inverseSideProperty` remains unset, but the TypeORM branch still passes `inverseSideOrOptions` as the inverse-side arg. Under TypeORM, calls like `MultiORMOneToOne(Profile, { cascade: true })` will end up passing the options object as the inverse side, which can break relation metadata.

How can I resolve this? If you propose a fix, please make it concise.

}

// Apply MikroORM decorator when using MikroORM
if (ormType === MultiORMEnum.MikroORM) {
MikroOrmOneToOne(
mapOneToOneArgsForMikroORM({
typeFunctionOrTarget,
inverseSideOrOptions: inverseSideProperty as InverseSide<T>,
options,
propertyKey
})
)(target, propertyKey);
}
};
}

Expand Down
3 changes: 2 additions & 1 deletion packages/ui-config/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"dependsOn": [
{
"target": "setup-env",
"projects": "self"
"projects": "self",
"params": "forward"
}
],
"options": {
Expand Down
25 changes: 7 additions & 18 deletions packages/ui-core/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,17 @@
"prefix": "lib",
"projectType": "library",
"tags": [],
"implicitDependencies": [
"constants",
"contracts",
"ui-config"
],
"implicitDependencies": ["constants", "contracts", "ui-config"],
"targets": {
"build": {
"executor": "@nx/angular:package",
"outputs": [
"{workspaceRoot}/dist/{projectRoot}"
],
"outputs": ["{workspaceRoot}/dist/{projectRoot}"],
"dependsOn": [
"^build",
{
"target": "config",
"projects": "self"
"projects": "self",
"params": "forward"
}
],
"options": {
Expand All @@ -41,23 +36,17 @@
"executor": "nx:run-commands",
"configurations": {
"production": {
"commands": [
"nx build ui-config --configuration=production"
]
"commands": ["nx build ui-config --configuration=production"]
},
"development": {
"commands": [
"nx build ui-config --configuration=development"
]
"commands": ["nx build ui-config --configuration=development"]
}
},
"defaultConfiguration": "development"
},
"test": {
"executor": "@nx/jest:jest",
"outputs": [
"{workspaceRoot}/coverage/{projectRoot}"
],
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
"options": {
"jestConfig": "packages/ui-core/jest.config.ts",
"tsConfig": "packages/ui-core/tsconfig.spec.json"
Expand Down
Loading