chore(order): dml (#10292)
* ../../core/types/src/dml/index.ts * ../../core/types/src/dml/index.ts * fix: relationships mapping * handle nullable foreign keys types * handle nullable foreign keys types * handle nullable foreign keys types * continue to update product category repository * fix all product category repositories issues * fix product category service types * fix product module service types * fix product module service types * fix repository template type * refactor: use a singleton DMLToMikroORM factory instance Since the MikroORM MetadataStorage is global, we will also have to turn DML to MikroORM entities conversion use a global bucket as well * refactor: update product module to use DML in tests * wip: tests * WIP product linkable fixes * continue type fixing and start test fixing * test: fix more tests * fix repository * fix pivot table computaion + fix mikro orm repository * fix many to many management and configuration * fix many to many management and configuration * fix many to many management and configuration * update product tag relation configuration * Introduce experimental dml hooks to fix some issues with categories * more fixes * fix product tests * add missing id prefixes * fix product category handle management * test: fix more failing tests * test: make it all green * test: fix breaking tests * fix: build issues * fix: build issues * fix: more breaking tests * refactor: fix issues after merge * refactor: fix issues after merge * refactor: surpress types error * test: fix DML failing tests * improve many to many inference + tests * Wip fix columns from product entity * remove product model before create hook and manage handle validation and transformation at the service level * test: fix breaking unit tests * fix: product module service to not update handle on product update * fix define link and joiner config * test: fix joiner config test * test: fix joiner config test * fix joiner config primary keys * Fix joiner config builder * Fix joiner config builder * test: remove only modifier from test * refactor: remove hooks usage from product collection * refactor: remove hooks usage from product-option * refactor: remove hooks usage for computing category handle * refactor: remove hooks usage from productCategory model * refactor: remove hooks from DML * refactor: remove cruft * order dml * cleanup * re add foerign key indexes * wip * chore: remove unused types * wip * changes * rm raw * autoincrement * wip * rel * refactor: cleanup * migration and models configuration adjustments * cleanup * number searchable * fix random ordering * fix * test: fix product-category tests * test: update breaking DML tests * test: array assertion to not care about ordering * fix: temporarily apply id ordering for products * types * wip * WIP type improvements * update order models * partially fix types temporarely * rel * fix: recursive type issue * improve type inference breaks * improve type inference breaks * update models * rm nullable * default value * repository * update default value handling * fix unit tests * WIP * toMikroORM * fix relations * cascades * fix * experimental dml hooks * rm migration * serial * nullable autoincrement * fix model * model changes * fix one to one DML * order test * fix addresses * fix unit tests * Re align dml entity name inference * update model table name config * update model table name config * revert * update return relation * WIP * hasOne * models * fix * model * initial commit * cart service * order module * utils unit test * index engine * changeset * merge * fix hasOne with fk * update * free text filter per entity * tests * prod category * property string many to many * fix big number * link modules migration set names * merge * shipping option rules * serializer * unit test * fix test mikro orm init * fix test mikro orm init * Maintain merge object properties * fix test mikro orm init * prevent unit test from connecting to db * wip * fix test * fix test * link test * schema * models * auto increment * hook * model hooks * order * wip * orm version * request return field * fix return configuration on order model * workflows * core flows * unit test * test * base repo * test * base repo * test fix * inventory move * locking inventory * test * free text fix * rm timeout mock * migrate fulfillment values * v6.4.3 * cleanup * link-modules update sql * revert test * remove fake timers --------- Co-authored-by: adrien2p <adrien.deperetti@gmail.com> Co-authored-by: Harminder Virk <virk.officials@gmail.com> Co-authored-by: Oli Juhl <59018053+olivermrbl@users.noreply.github.com>
This commit is contained in:
178 files changed
+5731
-7120
No files matched your search
@@ -63,7 +63,7 @@ class ProductOptionValue {
|
||||
fieldName: "option_id",
|
||||
mapToPk: true,
|
||||
nullable: true,
|
||||
onDelete: "cascade",
|
||||
deleteRule: "cascade",
|
||||
})
|
||||
option_id: string | null
|
||||
|
||||
@@ -88,7 +88,7 @@ class ProductVariant {
|
||||
@ManyToOne(() => Product, {
|
||||
columnType: "text",
|
||||
nullable: true,
|
||||
onDelete: "cascade",
|
||||
deleteRule: "cascade",
|
||||
fieldName: "product_id",
|
||||
mapToPk: true,
|
||||
})
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Entity, MikroORM, OnInit, Property } from "@mikro-orm/core"
|
||||
import { defineConfig } from "@mikro-orm/postgresql"
|
||||
import { BaseEntity } from "../base-entity"
|
||||
|
||||
describe("BaseEntity", () => {
|
||||
@@ -10,11 +11,15 @@ describe("BaseEntity", () => {
|
||||
}
|
||||
}
|
||||
|
||||
const orm = await MikroORM.init({
|
||||
entities: [Entity1],
|
||||
dbName: "test",
|
||||
type: "postgresql",
|
||||
})
|
||||
const orm = await MikroORM.init(
|
||||
defineConfig({
|
||||
entities: [Entity1],
|
||||
dbName: "test",
|
||||
user: "postgres",
|
||||
password: "",
|
||||
connect: false,
|
||||
})
|
||||
)
|
||||
|
||||
const manager = orm.em.fork()
|
||||
const entity1 = manager.create(Entity1, {})
|
||||
@@ -28,11 +33,15 @@ describe("BaseEntity", () => {
|
||||
@Entity()
|
||||
class Entity1 extends BaseEntity {}
|
||||
|
||||
const orm = await MikroORM.init({
|
||||
entities: [Entity1],
|
||||
dbName: "test",
|
||||
type: "postgresql",
|
||||
})
|
||||
const orm = await MikroORM.init(
|
||||
defineConfig({
|
||||
entities: [Entity1],
|
||||
dbName: "test",
|
||||
user: "postgres",
|
||||
password: "",
|
||||
connect: false,
|
||||
})
|
||||
)
|
||||
|
||||
const manager = orm.em.fork()
|
||||
const entity1 = manager.create(Entity1, {})
|
||||
@@ -52,11 +61,15 @@ describe("BaseEntity", () => {
|
||||
@Entity()
|
||||
class ProductOptionValue extends BaseEntity {}
|
||||
|
||||
const orm = await MikroORM.init({
|
||||
entities: [ProductModel, ProductCategoryEntity, ProductOptionValue],
|
||||
dbName: "test",
|
||||
type: "postgresql",
|
||||
})
|
||||
const orm = await MikroORM.init(
|
||||
defineConfig({
|
||||
entities: [ProductModel, ProductCategoryEntity, ProductOptionValue],
|
||||
dbName: "test",
|
||||
user: "postgres",
|
||||
password: "",
|
||||
connect: false,
|
||||
})
|
||||
)
|
||||
|
||||
const manager = orm.em.fork()
|
||||
|
||||
@@ -105,11 +118,15 @@ describe("BaseEntity", () => {
|
||||
}
|
||||
}
|
||||
|
||||
const orm = await MikroORM.init({
|
||||
entities: [ProductModel, ProductCategoryEntity, ProductOptionValue],
|
||||
dbName: "test",
|
||||
type: "postgresql",
|
||||
})
|
||||
const orm = await MikroORM.init(
|
||||
defineConfig({
|
||||
entities: [ProductModel, ProductCategoryEntity, ProductOptionValue],
|
||||
dbName: "test",
|
||||
user: "postgres",
|
||||
password: "",
|
||||
connect: false,
|
||||
})
|
||||
)
|
||||
|
||||
const manager = orm.em.fork()
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { BigNumberRawValue } from "@medusajs/types"
|
||||
import { Entity, MikroORM, PrimaryKey } from "@mikro-orm/core"
|
||||
import { defineConfig } from "@mikro-orm/postgresql"
|
||||
import { BigNumber } from "../../../totals/big-number"
|
||||
import { MikroOrmBigNumberProperty } from "../big-number-field"
|
||||
|
||||
@@ -23,11 +24,15 @@ describe("@MikroOrmBigNumberProperty", () => {
|
||||
let orm!: MikroORM
|
||||
|
||||
beforeEach(async () => {
|
||||
orm = await MikroORM.init({
|
||||
entities: [TestAmount],
|
||||
dbName: "test",
|
||||
type: "postgresql",
|
||||
})
|
||||
orm = await MikroORM.init(
|
||||
defineConfig({
|
||||
entities: [TestAmount],
|
||||
dbName: "test",
|
||||
user: "postgres",
|
||||
password: "",
|
||||
connect: false,
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
@@ -51,9 +56,7 @@ describe("@MikroOrmBigNumberProperty", () => {
|
||||
try {
|
||||
;(testAmount as any).amount = null
|
||||
} catch (e) {
|
||||
expect(e.message).toEqual(
|
||||
"Invalid BigNumber value: null. Should be one of: string, number, BigNumber (bignumber.js), BigNumberRawValue"
|
||||
)
|
||||
expect(e.message).toEqual("Cannot set value null for amount.")
|
||||
}
|
||||
|
||||
testAmount.nullable_amount = null
|
||||
|
||||
+14
-9
@@ -1,4 +1,5 @@
|
||||
import { MikroORM } from "@mikro-orm/core"
|
||||
import { defineConfig } from "@mikro-orm/postgresql"
|
||||
import { SearchableEntity1, SearchableEntity2 } from "../__fixtures__/utils"
|
||||
import { mikroOrmFreeTextSearchFilterOptionsFactory } from "../mikro-orm-free-text-search-filter"
|
||||
|
||||
@@ -6,21 +7,23 @@ describe("mikroOrmFreeTextSearchFilterOptionsFactory", () => {
|
||||
let orm
|
||||
|
||||
beforeEach(async () => {
|
||||
orm = await MikroORM.init({
|
||||
entities: [SearchableEntity1, SearchableEntity2],
|
||||
dbName: "test",
|
||||
type: "postgresql",
|
||||
})
|
||||
orm = await MikroORM.init(
|
||||
defineConfig({
|
||||
entities: [SearchableEntity1, SearchableEntity2],
|
||||
user: "postgres",
|
||||
password: "",
|
||||
dbName: "test",
|
||||
connect: false,
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it("should return a filter function that filters entities based on the free text search value", async () => {
|
||||
const entityManager = orm.em.fork()
|
||||
const freeTextSearchValue = "search"
|
||||
|
||||
const models = [SearchableEntity1, SearchableEntity2]
|
||||
|
||||
let filterConstraints = mikroOrmFreeTextSearchFilterOptionsFactory(
|
||||
models
|
||||
SearchableEntity1.name
|
||||
).cond(
|
||||
{
|
||||
value: freeTextSearchValue,
|
||||
@@ -51,7 +54,9 @@ describe("mikroOrmFreeTextSearchFilterOptionsFactory", () => {
|
||||
],
|
||||
})
|
||||
|
||||
filterConstraints = mikroOrmFreeTextSearchFilterOptionsFactory(models).cond(
|
||||
filterConstraints = mikroOrmFreeTextSearchFilterOptionsFactory(
|
||||
SearchableEntity2.name
|
||||
).cond(
|
||||
{
|
||||
value: freeTextSearchValue,
|
||||
fromEntity: SearchableEntity2.name,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { MikroORM } from "@mikro-orm/core"
|
||||
import { defineConfig } from "@mikro-orm/postgresql"
|
||||
import {
|
||||
Entity1WithUnDecoratedProp,
|
||||
Entity2WithUnDecoratedProp,
|
||||
@@ -11,18 +12,22 @@ import { mikroOrmSerializer } from "../mikro-orm-serializer"
|
||||
|
||||
describe("mikroOrmSerializer", () => {
|
||||
beforeEach(async () => {
|
||||
await MikroORM.init({
|
||||
entities: [
|
||||
Entity1WithUnDecoratedProp,
|
||||
Entity2WithUnDecoratedProp,
|
||||
Product,
|
||||
ProductOption,
|
||||
ProductOptionValue,
|
||||
ProductVariant,
|
||||
],
|
||||
dbName: "test",
|
||||
type: "postgresql",
|
||||
})
|
||||
await MikroORM.init(
|
||||
defineConfig({
|
||||
entities: [
|
||||
Entity1WithUnDecoratedProp,
|
||||
Entity2WithUnDecoratedProp,
|
||||
Product,
|
||||
ProductOption,
|
||||
ProductOptionValue,
|
||||
ProductVariant,
|
||||
],
|
||||
user: "postgres",
|
||||
password: "",
|
||||
dbName: "test",
|
||||
connect: false,
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it("should serialize an entity", async () => {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { CustomTsMigrationGenerator } from "../mikro-orm-create-connection"
|
||||
|
||||
function unwrapSql(sql: string) {
|
||||
return sql.match(/this.addSql\('(.*?)'\)/)?.[1]
|
||||
return sql.toString().match(/this.addSql\(`(.*?)`\)/)?.[1]
|
||||
}
|
||||
|
||||
describe("CustomTsMigrationGenerator", () => {
|
||||
|
||||
@@ -26,20 +26,24 @@ export function MikroOrmBigNumberProperty(
|
||||
set(value: BigNumberInput) {
|
||||
if (options?.nullable && !isPresent(value)) {
|
||||
this.__helper.__data[columnName] = null
|
||||
this.__helper.__data[rawColumnName]
|
||||
this.__helper.__data[rawColumnName] = null
|
||||
this[rawColumnName] = null
|
||||
} else {
|
||||
let bigNumber: BigNumber
|
||||
|
||||
if (value instanceof BigNumber) {
|
||||
bigNumber = value
|
||||
} else if (this[rawColumnName]) {
|
||||
const precision = this[rawColumnName].precision
|
||||
bigNumber = new BigNumber(value, {
|
||||
precision,
|
||||
})
|
||||
} else {
|
||||
bigNumber = new BigNumber(value)
|
||||
try {
|
||||
if (value instanceof BigNumber) {
|
||||
bigNumber = value
|
||||
} else if (this[rawColumnName]) {
|
||||
const precision = this[rawColumnName].precision
|
||||
bigNumber = new BigNumber(value, {
|
||||
precision,
|
||||
})
|
||||
} else {
|
||||
bigNumber = new BigNumber(value)
|
||||
}
|
||||
} catch (e) {
|
||||
throw new Error(`Cannot set value ${value} for ${columnName}.`)
|
||||
}
|
||||
|
||||
const raw = bigNumber.raw!
|
||||
@@ -80,6 +84,7 @@ export function MikroOrmBigNumberProperty(
|
||||
type: "any",
|
||||
columnType: "numeric",
|
||||
trackChanges: false,
|
||||
runtimeType: "any",
|
||||
...options,
|
||||
})(target, columnName)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const DB_HOST = process.env.DB_HOST ?? "localhost"
|
||||
const DB_USERNAME = process.env.DB_USERNAME ?? ""
|
||||
const DB_USERNAME = process.env.DB_USERNAME ?? "postgres"
|
||||
const DB_PASSWORD = process.env.DB_PASSWORD
|
||||
|
||||
export const pgGodCredentials = {
|
||||
|
||||
+11
-9
@@ -1,3 +1,4 @@
|
||||
import { BigNumberRawValue } from "@medusajs/types"
|
||||
import {
|
||||
BeforeCreate,
|
||||
Collection,
|
||||
@@ -13,11 +14,11 @@ import {
|
||||
Unique,
|
||||
wrap,
|
||||
} from "@mikro-orm/core"
|
||||
import { mikroOrmBaseRepositoryFactory } from "../../mikro-orm-repository"
|
||||
import { defineConfig } from "@mikro-orm/postgresql"
|
||||
import BigNumber from "bignumber.js"
|
||||
import { dropDatabase } from "pg-god"
|
||||
import { MikroOrmBigNumberProperty } from "../../big-number-field"
|
||||
import BigNumber from "bignumber.js"
|
||||
import { BigNumberRawValue } from "@medusajs/types"
|
||||
import { mikroOrmBaseRepositoryFactory } from "../../mikro-orm-repository"
|
||||
import { getDatabaseURL, pgGodCredentials } from "../__fixtures__/database"
|
||||
|
||||
const dbName = "mikroorm-integration-1"
|
||||
@@ -78,7 +79,7 @@ class Entity2 {
|
||||
nullable: true,
|
||||
mapToPk: true,
|
||||
fieldName: "entity1_id",
|
||||
onDelete: "set null",
|
||||
deleteRule: "set null",
|
||||
})
|
||||
entity1_id: string
|
||||
|
||||
@@ -143,11 +144,12 @@ describe("mikroOrmRepository", () => {
|
||||
pgGodCredentials
|
||||
)
|
||||
|
||||
orm = await MikroORM.init({
|
||||
entities: [Entity1, Entity2],
|
||||
clientUrl: getDatabaseURL(dbName),
|
||||
type: "postgresql",
|
||||
})
|
||||
orm = await MikroORM.init(
|
||||
defineConfig({
|
||||
entities: [Entity1, Entity2],
|
||||
clientUrl: getDatabaseURL(dbName),
|
||||
})
|
||||
)
|
||||
|
||||
const generator = orm.getSchemaGenerator()
|
||||
await generator.ensureDatabase()
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { mikroOrmUpdateDeletedAtRecursively } from "../../utils"
|
||||
import { MikroORM } from "@mikro-orm/core"
|
||||
import { SqlEntityManager } from "@mikro-orm/postgresql"
|
||||
import { defineConfig, SqlEntityManager } from "@mikro-orm/postgresql"
|
||||
import { dropDatabase } from "pg-god"
|
||||
import { mikroOrmUpdateDeletedAtRecursively } from "../../utils"
|
||||
import { getDatabaseURL, pgGodCredentials } from "../__fixtures__/database"
|
||||
import {
|
||||
DeepRecursiveEntity1,
|
||||
DeepRecursiveEntity2,
|
||||
@@ -12,8 +14,6 @@ import {
|
||||
RecursiveEntity1,
|
||||
RecursiveEntity2,
|
||||
} from "../__fixtures__/utils"
|
||||
import { dropDatabase } from "pg-god"
|
||||
import { getDatabaseURL, pgGodCredentials } from "../__fixtures__/database"
|
||||
|
||||
const dbName = "mikroorm-utils-integration-1"
|
||||
|
||||
@@ -38,21 +38,22 @@ describe("mikroOrmUpdateDeletedAtRecursively", () => {
|
||||
pgGodCredentials
|
||||
)
|
||||
|
||||
orm = await MikroORM.init({
|
||||
entities: [
|
||||
Entity1,
|
||||
Entity2,
|
||||
RecursiveEntity1,
|
||||
RecursiveEntity2,
|
||||
DeepRecursiveEntity1,
|
||||
DeepRecursiveEntity2,
|
||||
DeepRecursiveEntity3,
|
||||
DeepRecursiveEntity4,
|
||||
InternalCircularDependencyEntity1,
|
||||
],
|
||||
clientUrl: getDatabaseURL(dbName),
|
||||
type: "postgresql",
|
||||
})
|
||||
orm = await MikroORM.init(
|
||||
defineConfig({
|
||||
entities: [
|
||||
Entity1,
|
||||
Entity2,
|
||||
RecursiveEntity1,
|
||||
RecursiveEntity2,
|
||||
DeepRecursiveEntity1,
|
||||
DeepRecursiveEntity2,
|
||||
DeepRecursiveEntity3,
|
||||
DeepRecursiveEntity4,
|
||||
InternalCircularDependencyEntity1,
|
||||
],
|
||||
clientUrl: getDatabaseURL(dbName),
|
||||
})
|
||||
)
|
||||
|
||||
const generator = orm.getSchemaGenerator()
|
||||
await generator.ensureDatabase()
|
||||
|
||||
@@ -45,34 +45,38 @@ export async function mikroOrmCreateConnection(
|
||||
schema = database.connection.context?.client?.config?.searchPath
|
||||
}
|
||||
|
||||
const { MikroORM } = await import("@mikro-orm/postgresql")
|
||||
return await MikroORM.init({
|
||||
discovery: { disableDynamicFileAccess: true, warnWhenNoEntities: false },
|
||||
entities,
|
||||
debug: database.debug ?? process.env.NODE_ENV?.startsWith("dev") ?? false,
|
||||
baseDir: process.cwd(),
|
||||
clientUrl,
|
||||
schema,
|
||||
driverOptions,
|
||||
tsNode: process.env.APP_ENV === "development",
|
||||
type: "postgresql",
|
||||
filters: database.filters ?? {},
|
||||
migrations: {
|
||||
disableForeignKeys: false,
|
||||
path: pathToMigrations,
|
||||
generator: CustomTsMigrationGenerator,
|
||||
silent: !(
|
||||
database.debug ??
|
||||
process.env.NODE_ENV?.startsWith("dev") ??
|
||||
false
|
||||
),
|
||||
},
|
||||
schemaGenerator: {
|
||||
disableForeignKeys: false,
|
||||
},
|
||||
pool: {
|
||||
min: 2,
|
||||
...database.pool,
|
||||
},
|
||||
})
|
||||
const { MikroORM, defineConfig } = await import("@mikro-orm/postgresql")
|
||||
return await MikroORM.init(
|
||||
defineConfig({
|
||||
discovery: { disableDynamicFileAccess: true, warnWhenNoEntities: false },
|
||||
entities,
|
||||
debug: database.debug ?? process.env.NODE_ENV?.startsWith("dev") ?? false,
|
||||
baseDir: process.cwd(),
|
||||
clientUrl,
|
||||
schema,
|
||||
driverOptions,
|
||||
tsNode: process.env.APP_ENV === "development",
|
||||
filters: database.filters ?? {},
|
||||
assign: {
|
||||
convertCustomTypes: true,
|
||||
},
|
||||
migrations: {
|
||||
disableForeignKeys: false,
|
||||
path: pathToMigrations,
|
||||
generator: CustomTsMigrationGenerator,
|
||||
silent: !(
|
||||
database.debug ??
|
||||
process.env.NODE_ENV?.startsWith("dev") ??
|
||||
false
|
||||
),
|
||||
},
|
||||
schemaGenerator: {
|
||||
disableForeignKeys: false,
|
||||
},
|
||||
pool: {
|
||||
min: 2,
|
||||
...database.pool,
|
||||
},
|
||||
})
|
||||
)
|
||||
}
|
||||
@@ -4,23 +4,20 @@ import type {
|
||||
FindOneOptions,
|
||||
FindOptions,
|
||||
} from "@mikro-orm/core"
|
||||
import { EntityMetadata, EntitySchema, ReferenceType } from "@mikro-orm/core"
|
||||
import { EntityMetadata, ReferenceKind } from "@mikro-orm/core"
|
||||
import { SqlEntityManager } from "@mikro-orm/postgresql"
|
||||
|
||||
export const FreeTextSearchFilterKey = "freeTextSearch"
|
||||
export const FreeTextSearchFilterKeyPrefix = "freeTextSearch_"
|
||||
|
||||
interface FilterArgument {
|
||||
value: string
|
||||
fromEntity: string
|
||||
}
|
||||
|
||||
function getEntityProperties(entity: EntityClass<any> | EntitySchema): {
|
||||
function getEntityProperties(metadata: EntityMetadata<any>): {
|
||||
[key: string]: EntityProperty<any>
|
||||
} {
|
||||
return (
|
||||
(entity as EntityClass<any>)?.prototype.__meta?.properties ??
|
||||
(entity as EntitySchema).meta?.properties
|
||||
)
|
||||
return metadata.properties
|
||||
}
|
||||
|
||||
function retrieveRelationsConstraints(
|
||||
@@ -31,7 +28,7 @@ function retrieveRelationsConstraints(
|
||||
type: string
|
||||
name: string
|
||||
},
|
||||
models: (EntityClass<any> | EntitySchema)[],
|
||||
metadata: EntityMetadata<any>,
|
||||
searchValue: string,
|
||||
visited: Set<string> = new Set(),
|
||||
shouldStop: boolean = false
|
||||
@@ -46,13 +43,12 @@ function retrieveRelationsConstraints(
|
||||
|
||||
const relationFreeTextSearchWhere: any = []
|
||||
|
||||
const relationClass = models.find((m) => m.name === relation.type)!
|
||||
const relationProperties = getEntityProperties(relationClass)
|
||||
const relationProperties = getEntityProperties(metadata)
|
||||
|
||||
for (const propertyConfiguration of Object.values(relationProperties)) {
|
||||
if (
|
||||
!(propertyConfiguration as any).searchable ||
|
||||
propertyConfiguration.reference !== ReferenceType.SCALAR
|
||||
propertyConfiguration.kind !== ReferenceKind.SCALAR
|
||||
) {
|
||||
continue
|
||||
}
|
||||
@@ -69,9 +65,7 @@ function retrieveRelationsConstraints(
|
||||
})
|
||||
}
|
||||
|
||||
const innerRelations: EntityProperty[] =
|
||||
(relationClass as EntityClass<any>)?.prototype.__meta?.relations ??
|
||||
(relationClass as EntitySchema).meta?.relations
|
||||
const innerRelations: EntityProperty[] = metadata.relations
|
||||
|
||||
for (const innerRelation of innerRelations) {
|
||||
const branchVisited = new Set(Array.from(visited))
|
||||
@@ -108,7 +102,7 @@ function retrieveRelationsConstraints(
|
||||
mapToPk: innerRelation.mapToPk,
|
||||
type: innerRelation.type,
|
||||
},
|
||||
models,
|
||||
innerRelation.targetMeta!,
|
||||
searchValue,
|
||||
branchVisited,
|
||||
isSelfCircularDependency
|
||||
@@ -128,10 +122,9 @@ function retrieveRelationsConstraints(
|
||||
return relationFreeTextSearchWhere
|
||||
}
|
||||
|
||||
export const mikroOrmFreeTextSearchFilterOptionsFactory = (
|
||||
models: (EntityClass<any> | EntitySchema)[]
|
||||
) => {
|
||||
export const mikroOrmFreeTextSearchFilterOptionsFactory = (model: string) => {
|
||||
return {
|
||||
name: FreeTextSearchFilterKeyPrefix + model,
|
||||
cond: (
|
||||
freeTextSearchArgs: FilterArgument,
|
||||
operation: string,
|
||||
@@ -144,7 +137,7 @@ export const mikroOrmFreeTextSearchFilterOptionsFactory = (
|
||||
return {}
|
||||
}
|
||||
|
||||
const { value, fromEntity } = freeTextSearchArgs
|
||||
const { value } = freeTextSearchArgs
|
||||
|
||||
if (options?.visited?.size) {
|
||||
/**
|
||||
@@ -158,17 +151,17 @@ export const mikroOrmFreeTextSearchFilterOptionsFactory = (
|
||||
}
|
||||
}
|
||||
|
||||
const entityMetadata = manager.getDriver().getMetadata().get(fromEntity)
|
||||
const entityMetadata = manager.getDriver().getMetadata().get(model)
|
||||
|
||||
const freeTextSearchWhere = retrieveRelationsConstraints(
|
||||
{
|
||||
targetMeta: entityMetadata,
|
||||
mapToPk: false,
|
||||
searchable: true,
|
||||
type: fromEntity,
|
||||
type: model,
|
||||
name: entityMetadata.name!,
|
||||
},
|
||||
models,
|
||||
entityMetadata,
|
||||
value
|
||||
)
|
||||
|
||||
@@ -180,8 +173,5 @@ export const mikroOrmFreeTextSearchFilterOptionsFactory = (
|
||||
$or: freeTextSearchWhere,
|
||||
}
|
||||
},
|
||||
default: true,
|
||||
args: false,
|
||||
entity: models.map((m) => m.name) as string[],
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
LoadStrategy,
|
||||
FilterQuery as MikroFilterQuery,
|
||||
FindOptions as MikroOptions,
|
||||
ReferenceType,
|
||||
ReferenceKind,
|
||||
} from "@mikro-orm/core"
|
||||
import { SqlEntityManager } from "@mikro-orm/postgresql"
|
||||
import {
|
||||
@@ -245,24 +245,6 @@ export class MikroOrmBaseRepository<const T extends object = object>
|
||||
|
||||
return [entities, softDeletedEntitiesMap]
|
||||
}
|
||||
|
||||
applyFreeTextSearchFilters<T>(
|
||||
findOptions: DAL.FindOptions<T & { q?: string }>,
|
||||
retrieveConstraintsToApply: (q: string) => any[]
|
||||
): void {
|
||||
if (!("q" in findOptions.where) || !findOptions.where.q) {
|
||||
delete findOptions.where.q
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
const q = findOptions.where.q as string
|
||||
delete findOptions.where.q
|
||||
|
||||
findOptions.where = {
|
||||
$and: [findOptions.where, { $or: retrieveConstraintsToApply(q) }],
|
||||
} as unknown as DAL.FindOptions<T & { q?: string }>["where"]
|
||||
}
|
||||
}
|
||||
|
||||
export class MikroOrmBaseTreeRepository<
|
||||
@@ -391,7 +373,7 @@ export function mikroOrmBaseRepositoryFactory<const T extends object>(
|
||||
const relation = relations.find((relation) => relation.name === key)
|
||||
const shouldInit =
|
||||
relation &&
|
||||
relation.reference === ReferenceType.MANY_TO_MANY &&
|
||||
relation.kind === ReferenceKind.MANY_TO_MANY &&
|
||||
Array.isArray(update[key]) &&
|
||||
!update[key].length
|
||||
|
||||
@@ -434,7 +416,9 @@ export function mikroOrmBaseRepositoryFactory<const T extends object>(
|
||||
await this.initManyToManyToDetachAllItemsIfNeeded(data, context)
|
||||
|
||||
data.map((_, index) => {
|
||||
manager.assign(data[index].entity, data[index].update)
|
||||
manager.assign(data[index].entity, data[index].update, {
|
||||
mergeObjectProperties: true,
|
||||
})
|
||||
manager.persist(data[index].entity)
|
||||
})
|
||||
|
||||
@@ -578,7 +562,7 @@ export function mikroOrmBaseRepositoryFactory<const T extends object>(
|
||||
const existingEntity = existingEntitiesMap.get(key)
|
||||
if (existingEntity) {
|
||||
const updatedType = manager.assign(existingEntity, data_)
|
||||
updatedEntities.push(updatedType)
|
||||
updatedEntities.push(updatedType as any)
|
||||
} else {
|
||||
const newEntity = manager.create(this.entity, data_)
|
||||
createdEntities.push(newEntity as InferRepositoryReturnType<T>)
|
||||
@@ -698,8 +682,8 @@ export function mikroOrmBaseRepositoryFactory<const T extends object>(
|
||||
// TODO: Handle ONE_TO_ONE
|
||||
// One to one and Many to one are handled outside of the assignment as they need to happen before the main entity is created
|
||||
if (
|
||||
relation.reference === ReferenceType.ONE_TO_ONE ||
|
||||
relation.reference === ReferenceType.MANY_TO_ONE
|
||||
relation.kind === ReferenceKind.ONE_TO_ONE ||
|
||||
relation.kind === ReferenceKind.MANY_TO_ONE
|
||||
) {
|
||||
return
|
||||
}
|
||||
@@ -765,7 +749,7 @@ export function mikroOrmBaseRepositoryFactory<const T extends object>(
|
||||
return this.getEntityWithId(manager, relation.type, normalizedItem)
|
||||
})
|
||||
|
||||
if (relation.reference === ReferenceType.MANY_TO_MANY) {
|
||||
if (relation.kind === ReferenceKind.MANY_TO_MANY) {
|
||||
const currentPivotColumn = relation.inverseJoinColumns[0]
|
||||
const parentPivotColumn = relation.joinColumns[0]
|
||||
|
||||
@@ -805,7 +789,7 @@ export function mikroOrmBaseRepositoryFactory<const T extends object>(
|
||||
return { entities: normalizedData, performedActions }
|
||||
}
|
||||
|
||||
if (relation.reference === ReferenceType.ONE_TO_MANY) {
|
||||
if (relation.kind === ReferenceKind.ONE_TO_MANY) {
|
||||
const joinColumns =
|
||||
relation.targetMeta?.properties[relation.mappedBy]?.joinColumns
|
||||
|
||||
@@ -815,7 +799,7 @@ export function mikroOrmBaseRepositoryFactory<const T extends object>(
|
||||
joinColumnsConstraints[joinColumn] = data[referencedColumnName]
|
||||
})
|
||||
|
||||
const toDeleteEntities = await manager.find<any>(
|
||||
const toDeleteEntities = await manager.find<any, any, "id">(
|
||||
relation.type,
|
||||
{
|
||||
...joinColumnsConstraints,
|
||||
@@ -869,7 +853,7 @@ export function mikroOrmBaseRepositoryFactory<const T extends object>(
|
||||
}
|
||||
|
||||
// If it is a many-to-one we ensure the ID is set for when we want to set/unset an association
|
||||
if (relation.reference === ReferenceType.MANY_TO_ONE) {
|
||||
if (relation.kind === ReferenceKind.MANY_TO_ONE) {
|
||||
if (originalData === null) {
|
||||
entryCopy[relation.joinColumns[0]] = null
|
||||
return null
|
||||
@@ -927,7 +911,7 @@ export function mikroOrmBaseRepositoryFactory<const T extends object>(
|
||||
.filter(
|
||||
([_, propDef]: any) =>
|
||||
propDef.persist === false &&
|
||||
propDef.reference === ReferenceType.MANY_TO_ONE
|
||||
propDef.kind === ReferenceKind.MANY_TO_ONE
|
||||
)
|
||||
.forEach(([key]) => {
|
||||
delete resp[key]
|
||||
|
||||
@@ -7,36 +7,45 @@ import {
|
||||
Loaded,
|
||||
Platform,
|
||||
Reference,
|
||||
ReferenceType,
|
||||
ReferenceKind,
|
||||
SerializationContext,
|
||||
SerializeOptions,
|
||||
Utils,
|
||||
} from "@mikro-orm/core"
|
||||
|
||||
type CustomSerializeOptions<T, P = any> = SerializeOptions<T, P & string> & {
|
||||
preventCircularRef?: boolean
|
||||
populate?: [keyof T][] | boolean
|
||||
}
|
||||
|
||||
function isVisible<T extends object>(
|
||||
meta: EntityMetadata<T>,
|
||||
propName: string,
|
||||
options: SerializeOptions<T, any> & { preventCircularRef?: boolean } = {}
|
||||
options: CustomSerializeOptions<T> = {}
|
||||
): boolean {
|
||||
if (options.populate === true) {
|
||||
return options.populate
|
||||
return true
|
||||
}
|
||||
|
||||
if (
|
||||
Array.isArray(options.populate) &&
|
||||
options.populate?.find(
|
||||
options.exclude?.find((item) => item === propName)
|
||||
) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (
|
||||
Array.isArray(options.populate) &&
|
||||
(options.populate?.find(
|
||||
(item) => item === propName || item.startsWith(propName + ".")
|
||||
)
|
||||
) ||
|
||||
options.populate.includes("*"))
|
||||
) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (options.exclude?.find((item) => item === propName)) {
|
||||
return false
|
||||
}
|
||||
|
||||
const prop = meta.properties[propName]
|
||||
const visible = prop && !prop.hidden
|
||||
const visible = (prop && !prop.hidden) || prop === undefined // allow unknown properties
|
||||
const prefixed = prop && !prop.primary && propName.startsWith("_") // ignore prefixed properties, if it's not a PK
|
||||
|
||||
return visible && !prefixed
|
||||
@@ -45,13 +54,14 @@ function isVisible<T extends object>(
|
||||
function isPopulated<T extends object>(
|
||||
entity: T,
|
||||
propName: string,
|
||||
options: SerializeOptions<T, any>
|
||||
options: CustomSerializeOptions<T>
|
||||
): boolean {
|
||||
if (
|
||||
typeof options.populate !== "boolean" &&
|
||||
options.populate?.find(
|
||||
Array.isArray(options.populate) &&
|
||||
(options.populate?.find(
|
||||
(item) => item === propName || item.startsWith(propName + ".")
|
||||
)
|
||||
) ||
|
||||
options.populate.includes("*"))
|
||||
) {
|
||||
return true
|
||||
}
|
||||
@@ -78,9 +88,7 @@ function filterEntityPropToSerialize({
|
||||
}: {
|
||||
propName: string
|
||||
meta: EntityMetadata
|
||||
options: SerializeOptions<object, any> & {
|
||||
preventCircularRef?: boolean
|
||||
}
|
||||
options: CustomSerializeOptions<any>
|
||||
parents?: string[]
|
||||
}): boolean {
|
||||
parents ??= []
|
||||
@@ -92,7 +100,7 @@ function filterEntityPropToSerialize({
|
||||
prop &&
|
||||
options.preventCircularRef &&
|
||||
isVisibleRes &&
|
||||
prop.reference !== ReferenceType.SCALAR
|
||||
prop.kind !== ReferenceKind.SCALAR
|
||||
) {
|
||||
// mapToPk would represent a foreign key and we want to keep them
|
||||
if (!!prop.mapToPk) {
|
||||
@@ -108,7 +116,7 @@ function filterEntityPropToSerialize({
|
||||
export class EntitySerializer {
|
||||
static serialize<T extends object, P extends string = never>(
|
||||
entity: T,
|
||||
options: SerializeOptions<T, P> & { preventCircularRef?: boolean } = {},
|
||||
options: CustomSerializeOptions<T, P> = {},
|
||||
parents: string[] = []
|
||||
): EntityDTO<Loaded<T, P>> {
|
||||
const parents_ = Array.from(new Set(parents))
|
||||
@@ -118,12 +126,11 @@ export class EntitySerializer {
|
||||
let contextCreated = false
|
||||
|
||||
if (!wrapped.__serializationContext.root) {
|
||||
const root = new SerializationContext<T>()
|
||||
const root = new SerializationContext<T>({} as any)
|
||||
SerializationContext.propagate(
|
||||
root,
|
||||
entity,
|
||||
(meta, prop) =>
|
||||
meta.properties[prop]?.reference !== ReferenceType.SCALAR
|
||||
(meta, prop) => meta.properties[prop]?.kind !== ReferenceKind.SCALAR
|
||||
)
|
||||
contextCreated = true
|
||||
}
|
||||
@@ -238,25 +245,25 @@ export class EntitySerializer {
|
||||
|
||||
private static propertyName<T>(
|
||||
meta: EntityMetadata<T>,
|
||||
prop: keyof T & string,
|
||||
prop: string,
|
||||
platform?: Platform
|
||||
): string {
|
||||
/* istanbul ignore next */
|
||||
if (meta.properties[prop]?.serializedName) {
|
||||
return meta.properties[prop].serializedName as keyof T & string
|
||||
return meta.properties[prop].serializedName as string
|
||||
}
|
||||
|
||||
if (meta.properties[prop]?.primary && platform) {
|
||||
return platform.getSerializedPrimaryKeyField(prop) as keyof T & string
|
||||
return platform.getSerializedPrimaryKeyField(prop) as string
|
||||
}
|
||||
|
||||
return prop
|
||||
}
|
||||
|
||||
private static processProperty<T extends object>(
|
||||
prop: keyof T & string,
|
||||
prop: string,
|
||||
entity: T,
|
||||
options: SerializeOptions<T, any>,
|
||||
options: CustomSerializeOptions<T>,
|
||||
parents: string[] = []
|
||||
): T[keyof T] | undefined {
|
||||
const parents_ = [...parents, entity.constructor.name]
|
||||
@@ -284,12 +291,17 @@ export class EntitySerializer {
|
||||
}
|
||||
|
||||
if (Utils.isCollection(entity[prop])) {
|
||||
return this.processCollection(prop, entity, options, parents_)
|
||||
return this.processCollection(
|
||||
prop as keyof T & string,
|
||||
entity,
|
||||
options,
|
||||
parents_
|
||||
)
|
||||
}
|
||||
|
||||
if (Utils.isEntity(entity[prop], true)) {
|
||||
return this.processEntity(
|
||||
prop,
|
||||
prop as keyof T & string,
|
||||
entity,
|
||||
wrapped.__platform,
|
||||
options,
|
||||
@@ -298,7 +310,7 @@ export class EntitySerializer {
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
if (property?.reference === ReferenceType.EMBEDDED) {
|
||||
if (property?.reference === ReferenceKind.EMBEDDED) {
|
||||
if (Array.isArray(entity[prop])) {
|
||||
return (entity[prop] as object[]).map((item) =>
|
||||
helper(item).toJSON()
|
||||
@@ -322,9 +334,9 @@ export class EntitySerializer {
|
||||
}
|
||||
|
||||
private static extractChildOptions<T extends object, U extends object>(
|
||||
options: SerializeOptions<T, any>,
|
||||
options: CustomSerializeOptions<T>,
|
||||
prop: keyof T & string
|
||||
): SerializeOptions<U, any> {
|
||||
): CustomSerializeOptions<U> {
|
||||
const extractChildElements = (items: string[]) => {
|
||||
return items
|
||||
.filter((field) => field.startsWith(`${prop}.`))
|
||||
@@ -333,20 +345,22 @@ export class EntitySerializer {
|
||||
|
||||
return {
|
||||
...options,
|
||||
populate: Array.isArray(options.populate)
|
||||
? extractChildElements(options.populate)
|
||||
: options.populate,
|
||||
exclude: Array.isArray(options.exclude)
|
||||
? extractChildElements(options.exclude)
|
||||
: options.exclude,
|
||||
} as SerializeOptions<U, any>
|
||||
populate:
|
||||
Array.isArray(options.populate) && !options.populate.includes("*")
|
||||
? extractChildElements(options.populate as unknown as string[])
|
||||
: options.populate,
|
||||
exclude:
|
||||
Array.isArray(options.exclude) && !options.exclude.includes("*")
|
||||
? extractChildElements(options.exclude)
|
||||
: options.exclude,
|
||||
} as CustomSerializeOptions<U>
|
||||
}
|
||||
|
||||
private static processEntity<T extends object>(
|
||||
prop: keyof T & string,
|
||||
entity: T,
|
||||
platform: Platform,
|
||||
options: SerializeOptions<T, any>,
|
||||
options: CustomSerializeOptions<T>,
|
||||
parents: string[] = []
|
||||
): T[keyof T] | undefined {
|
||||
const parents_ = [...parents, entity.constructor.name]
|
||||
@@ -373,7 +387,7 @@ export class EntitySerializer {
|
||||
private static processCollection<T extends object>(
|
||||
prop: keyof T & string,
|
||||
entity: T,
|
||||
options: SerializeOptions<T, any>,
|
||||
options: CustomSerializeOptions<T>,
|
||||
parents: string[] = []
|
||||
): T[keyof T] | undefined {
|
||||
const parents_ = [...parents, entity.constructor.name]
|
||||
@@ -401,6 +415,7 @@ export const mikroOrmSerializer = <TOutput extends object>(
|
||||
data: any,
|
||||
options?: Parameters<typeof EntitySerializer.serialize>[1] & {
|
||||
preventCircularRef?: boolean
|
||||
populate?: string[] | boolean
|
||||
}
|
||||
): Promise<TOutput> => {
|
||||
return new Promise<TOutput>((resolve) => {
|
||||
@@ -422,10 +437,11 @@ export const mikroOrmSerializer = <TOutput extends object>(
|
||||
let result: any = forSerialization.map((entity) =>
|
||||
EntitySerializer.serialize(entity, {
|
||||
forceObject: true,
|
||||
populate: true,
|
||||
populate: ["*"],
|
||||
|
||||
preventCircularRef: true,
|
||||
...options,
|
||||
} as SerializeOptions<any, any>)
|
||||
} as CustomSerializeOptions<any>)
|
||||
) as TOutput[]
|
||||
|
||||
if (notForSerialization.length) {
|
||||
|
||||
Reference in new issue
Block a user