fix: Handle multiple id prop generation (#8097)
* fix: Handle multiple id prop generation * throw on duplicate id + cleanup * fix mistakenly removed files * fix * fix * passzord string * passzord string
This commit is contained in:
1 parent
82b620c488
commit
136da3f3ce
10 files changed
+111
-69
No files matched your search
@@ -48,6 +48,6 @@
|
|||||||
"build": "rimraf dist && tsc --build",
|
"build": "rimraf dist && tsc --build",
|
||||||
"watch": "tsc --build --watch",
|
"watch": "tsc --build --watch",
|
||||||
"test": "jest --silent --bail --maxWorkers=50% --forceExit --testPathIgnorePatterns='/integration-tests/' -- src/**/__tests__/**/*.ts",
|
"test": "jest --silent --bail --maxWorkers=50% --forceExit --testPathIgnorePatterns='/integration-tests/' -- src/**/__tests__/**/*.ts",
|
||||||
"test:integration": "jest --silent --bail --maxWorkers=50% --forceExit -- src/**/integration-tests/__tests__/**/*.ts"
|
"test:integration": "jest --silent --bail --runInBand --forceExit -- src/**/integration-tests/__tests__/**/*.ts"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,6 +7,8 @@ import {
|
|||||||
toMikroOrmEntities,
|
toMikroOrmEntities,
|
||||||
toMikroORMEntity,
|
toMikroORMEntity,
|
||||||
} from "../helpers/create-mikro-orm-entity"
|
} from "../helpers/create-mikro-orm-entity"
|
||||||
|
import { User } from "@medusajs/icons"
|
||||||
|
import { DuplicateIdPropertyError } from "../errors"
|
||||||
|
|
||||||
describe("Entity builder", () => {
|
describe("Entity builder", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
@@ -548,6 +550,26 @@ describe("Entity builder", () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test("should throw on duplicate id definition", () => {
|
||||||
|
const user = model.define("user", {
|
||||||
|
id: model.id().primaryKey(),
|
||||||
|
uuid: model.id(),
|
||||||
|
name: model.text(),
|
||||||
|
})
|
||||||
|
|
||||||
|
let err
|
||||||
|
try {
|
||||||
|
toMikroORMEntity(user)
|
||||||
|
} catch (e) {
|
||||||
|
err = e
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(err).toBeInstanceOf(DuplicateIdPropertyError)
|
||||||
|
expect(err.message).toBe(
|
||||||
|
"The model User can only have one usage of the id() property"
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
test("should mark a property as searchable", () => {
|
test("should mark a property as searchable", () => {
|
||||||
const user = model.define("user", {
|
const user = model.define("user", {
|
||||||
id: model.number(),
|
id: model.number(),
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
export class DuplicateIdPropertyError extends Error {
|
||||||
|
constructor(modelName: string) {
|
||||||
|
super(`The model ${modelName} can only have one usage of the id() property`)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,6 +13,8 @@ import { defineProperty } from "./entity-builder/define-property"
|
|||||||
import { defineRelationship } from "./entity-builder/define-relationship"
|
import { defineRelationship } from "./entity-builder/define-relationship"
|
||||||
import { parseEntityName } from "./entity-builder/parse-entity-name"
|
import { parseEntityName } from "./entity-builder/parse-entity-name"
|
||||||
import { applyEntityIndexes, applyIndexes } from "./mikro-orm/apply-indexes"
|
import { applyEntityIndexes, applyIndexes } from "./mikro-orm/apply-indexes"
|
||||||
|
import { IdProperty } from "../properties/id"
|
||||||
|
import { DuplicateIdPropertyError } from "../errors"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Factory function to create the mikro orm entity builder. The return
|
* Factory function to create the mikro orm entity builder. The return
|
||||||
@@ -62,6 +64,8 @@ export function createMikrORMEntity() {
|
|||||||
MANY_TO_MANY_TRACKED_REALTIONS,
|
MANY_TO_MANY_TRACKED_REALTIONS,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let hasIdAlreadyDefined = false
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Processing schema fields
|
* Processing schema fields
|
||||||
*/
|
*/
|
||||||
@@ -69,6 +73,13 @@ export function createMikrORMEntity() {
|
|||||||
const field = property.parse(name)
|
const field = property.parse(name)
|
||||||
|
|
||||||
if ("fieldName" in field) {
|
if ("fieldName" in field) {
|
||||||
|
if (IdProperty.isIdProperty(field)) {
|
||||||
|
if (hasIdAlreadyDefined) {
|
||||||
|
throw new DuplicateIdPropertyError(modelName)
|
||||||
|
}
|
||||||
|
hasIdAlreadyDefined = true
|
||||||
|
}
|
||||||
|
|
||||||
defineProperty(MikroORMEntity, name, property as PropertyType<any>)
|
defineProperty(MikroORMEntity, name, property as PropertyType<any>)
|
||||||
applyIndexes(MikroORMEntity, tableName, field)
|
applyIndexes(MikroORMEntity, tableName, field)
|
||||||
applySearchable(MikroORMEntity, field)
|
applySearchable(MikroORMEntity, field)
|
||||||
|
|||||||
@@ -190,7 +190,8 @@ export function defineProperty(
|
|||||||
/**
|
/**
|
||||||
* Hook to generate entity within the code
|
* Hook to generate entity within the code
|
||||||
*/
|
*/
|
||||||
MikroORMEntity.prototype.generateId = function () {
|
const generateIdMethodName = `generateId`
|
||||||
|
MikroORMEntity.prototype[generateIdMethodName] = function () {
|
||||||
this[field.fieldName] = generateEntityId(
|
this[field.fieldName] = generateEntityId(
|
||||||
this[field.fieldName],
|
this[field.fieldName],
|
||||||
field.dataType.options?.prefix
|
field.dataType.options?.prefix
|
||||||
@@ -200,8 +201,8 @@ export function defineProperty(
|
|||||||
/**
|
/**
|
||||||
* Execute hook via lifecycle decorators
|
* Execute hook via lifecycle decorators
|
||||||
*/
|
*/
|
||||||
BeforeCreate()(MikroORMEntity.prototype, "generateId")
|
BeforeCreate()(MikroORMEntity.prototype, generateIdMethodName)
|
||||||
OnInit()(MikroORMEntity.prototype, "generateId")
|
OnInit()(MikroORMEntity.prototype, generateIdMethodName)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-21
@@ -3,41 +3,34 @@ import {
|
|||||||
MetadataStorage,
|
MetadataStorage,
|
||||||
MikroORM,
|
MikroORM,
|
||||||
} from "@mikro-orm/core"
|
} from "@mikro-orm/core"
|
||||||
import { model } from "../entity-builder"
|
import { model } from "../../entity-builder"
|
||||||
import { toMikroOrmEntities } from "../helpers/create-mikro-orm-entity"
|
import { toMikroOrmEntities } from "../../helpers/create-mikro-orm-entity"
|
||||||
import { createDatabase, dropDatabase } from "pg-god"
|
import { createDatabase, dropDatabase } from "pg-god"
|
||||||
import { mikroOrmSerializer } from "../../dal"
|
import { CustomTsMigrationGenerator, mikroOrmSerializer } from "../../../dal"
|
||||||
import { FileSystem } from "../../common"
|
|
||||||
import { join } from "path"
|
|
||||||
import { EntityConstructor } from "@medusajs/types"
|
import { EntityConstructor } from "@medusajs/types"
|
||||||
|
import { pgGodCredentials } from "../utils"
|
||||||
|
import { FileSystem } from "../../../common"
|
||||||
|
import { join } from "path"
|
||||||
|
|
||||||
const DB_HOST = process.env.DB_HOST
|
export const fileSystem = new FileSystem(
|
||||||
const DB_USERNAME = process.env.DB_USERNAME
|
join(__dirname, "../../integration-tests-migrations-enum")
|
||||||
const DB_PASSWORD = process.env.DB_PASSWORD
|
)
|
||||||
|
|
||||||
const pgGodCredentials = {
|
|
||||||
user: DB_USERNAME,
|
|
||||||
password: DB_PASSWORD,
|
|
||||||
host: DB_HOST,
|
|
||||||
}
|
|
||||||
|
|
||||||
const fileSystem = new FileSystem(join(__dirname, "../../migrations"))
|
|
||||||
|
|
||||||
describe("EntityBuilder | enum", () => {
|
describe("EntityBuilder | enum", () => {
|
||||||
const dbName = "EntityBuilder-enum"
|
const dbName = "EntityBuilder-enum"
|
||||||
|
|
||||||
let orm!: MikroORM
|
let orm!: MikroORM
|
||||||
let Team: EntityConstructor<any>, User: EntityConstructor<any>
|
let User: EntityConstructor<any>
|
||||||
|
|
||||||
afterAll(() => {
|
afterAll(async () => {
|
||||||
fileSystem.cleanup()
|
await fileSystem.cleanup()
|
||||||
})
|
})
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
MetadataStorage.clear()
|
MetadataStorage.clear()
|
||||||
|
|
||||||
const user = model.define("user", {
|
const user = model.define("user", {
|
||||||
id: model.id(),
|
id: model.id().primaryKey(),
|
||||||
username: model.text(),
|
username: model.text(),
|
||||||
role: model.enum(["admin", "moderator", "editor"]),
|
role: model.enum(["admin", "moderator", "editor"]),
|
||||||
})
|
})
|
||||||
@@ -50,8 +43,14 @@ describe("EntityBuilder | enum", () => {
|
|||||||
entities: [User],
|
entities: [User],
|
||||||
tsNode: true,
|
tsNode: true,
|
||||||
dbName,
|
dbName,
|
||||||
debug: true,
|
password: pgGodCredentials.password,
|
||||||
|
host: pgGodCredentials.host,
|
||||||
|
user: pgGodCredentials.user,
|
||||||
type: "postgresql",
|
type: "postgresql",
|
||||||
|
migrations: {
|
||||||
|
generator: CustomTsMigrationGenerator,
|
||||||
|
path: fileSystem.basePath,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const migrator = orm.getMigrator()
|
const migrator = orm.getMigrator()
|
||||||
+18
-22
@@ -1,23 +1,16 @@
|
|||||||
import { MetadataStorage, MikroORM } from "@mikro-orm/core"
|
import { MetadataStorage, MikroORM } from "@mikro-orm/core"
|
||||||
import { model } from "../entity-builder"
|
import { model } from "../../entity-builder"
|
||||||
import { toMikroOrmEntities } from "../helpers/create-mikro-orm-entity"
|
import { toMikroOrmEntities } from "../../helpers/create-mikro-orm-entity"
|
||||||
import { createDatabase, dropDatabase } from "pg-god"
|
import { createDatabase, dropDatabase } from "pg-god"
|
||||||
import { CustomTsMigrationGenerator, mikroOrmSerializer } from "../../dal"
|
import { CustomTsMigrationGenerator, mikroOrmSerializer } from "../../../dal"
|
||||||
import { FileSystem } from "../../common"
|
|
||||||
import { join } from "path"
|
|
||||||
import { EntityConstructor } from "@medusajs/types"
|
import { EntityConstructor } from "@medusajs/types"
|
||||||
|
import { pgGodCredentials } from "../utils"
|
||||||
|
import { FileSystem } from "../../../common"
|
||||||
|
import { join } from "path"
|
||||||
|
|
||||||
const DB_HOST = process.env.DB_HOST
|
export const fileSystem = new FileSystem(
|
||||||
const DB_USERNAME = process.env.DB_USERNAME
|
join(__dirname, "../../integration-tests-migrations-many-to-many")
|
||||||
const DB_PASSWORD = process.env.DB_PASSWORD
|
)
|
||||||
|
|
||||||
const pgGodCredentials = {
|
|
||||||
user: DB_USERNAME,
|
|
||||||
password: DB_PASSWORD,
|
|
||||||
host: DB_HOST,
|
|
||||||
}
|
|
||||||
|
|
||||||
const fileSystem = new FileSystem(join(__dirname, "../../migrations"))
|
|
||||||
|
|
||||||
describe("manyToMany - manyToMany", () => {
|
describe("manyToMany - manyToMany", () => {
|
||||||
const dbName = "EntityBuilder-ManyToMany"
|
const dbName = "EntityBuilder-ManyToMany"
|
||||||
@@ -28,15 +21,15 @@ describe("manyToMany - manyToMany", () => {
|
|||||||
User: EntityConstructor<any>,
|
User: EntityConstructor<any>,
|
||||||
Squad: EntityConstructor<any>
|
Squad: EntityConstructor<any>
|
||||||
|
|
||||||
afterAll(() => {
|
afterAll(async () => {
|
||||||
fileSystem.cleanup()
|
await fileSystem.cleanup()
|
||||||
})
|
})
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
MetadataStorage.clear()
|
MetadataStorage.clear()
|
||||||
|
|
||||||
const team = model.define("team", {
|
const team = model.define("team", {
|
||||||
id: model.id(),
|
id: model.id().primaryKey(),
|
||||||
name: model.text(),
|
name: model.text(),
|
||||||
users: model.manyToMany(() => user, {
|
users: model.manyToMany(() => user, {
|
||||||
pivotEntity: () => squad,
|
pivotEntity: () => squad,
|
||||||
@@ -45,13 +38,13 @@ describe("manyToMany - manyToMany", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const squad = model.define("teamUsers", {
|
const squad = model.define("teamUsers", {
|
||||||
id: model.id(),
|
id: model.id().primaryKey(),
|
||||||
user: model.belongsTo(() => user, { mappedBy: "squads" }),
|
user: model.belongsTo(() => user, { mappedBy: "squads" }),
|
||||||
squad: model.belongsTo(() => team, { mappedBy: "users" }),
|
squad: model.belongsTo(() => team, { mappedBy: "users" }),
|
||||||
})
|
})
|
||||||
|
|
||||||
const user = model.define("user", {
|
const user = model.define("user", {
|
||||||
id: model.id(),
|
id: model.id().primaryKey(),
|
||||||
username: model.text(),
|
username: model.text(),
|
||||||
squads: model.manyToMany(() => team, {
|
squads: model.manyToMany(() => team, {
|
||||||
pivotEntity: () => squad,
|
pivotEntity: () => squad,
|
||||||
@@ -67,10 +60,13 @@ describe("manyToMany - manyToMany", () => {
|
|||||||
entities: [Team, User, Squad],
|
entities: [Team, User, Squad],
|
||||||
tsNode: true,
|
tsNode: true,
|
||||||
dbName,
|
dbName,
|
||||||
debug: true,
|
password: pgGodCredentials.password,
|
||||||
|
host: pgGodCredentials.host,
|
||||||
|
user: pgGodCredentials.user,
|
||||||
type: "postgresql",
|
type: "postgresql",
|
||||||
migrations: {
|
migrations: {
|
||||||
generator: CustomTsMigrationGenerator,
|
generator: CustomTsMigrationGenerator,
|
||||||
|
path: fileSystem.basePath,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
+20
-21
@@ -1,23 +1,16 @@
|
|||||||
import { MetadataStorage, MikroORM } from "@mikro-orm/core"
|
import { MetadataStorage, MikroORM } from "@mikro-orm/core"
|
||||||
import { model } from "../entity-builder"
|
import { model } from "../../entity-builder"
|
||||||
import { toMikroOrmEntities } from "../helpers/create-mikro-orm-entity"
|
import { toMikroOrmEntities } from "../../helpers/create-mikro-orm-entity"
|
||||||
import { createDatabase, dropDatabase } from "pg-god"
|
import { createDatabase, dropDatabase } from "pg-god"
|
||||||
import { mikroOrmSerializer } from "../../dal"
|
import { CustomTsMigrationGenerator, mikroOrmSerializer } from "../../../dal"
|
||||||
import { FileSystem } from "../../common"
|
|
||||||
import { join } from "path"
|
|
||||||
import { EntityConstructor } from "@medusajs/types"
|
import { EntityConstructor } from "@medusajs/types"
|
||||||
|
import { pgGodCredentials } from "../utils"
|
||||||
|
import { FileSystem } from "../../../common"
|
||||||
|
import { join } from "path"
|
||||||
|
|
||||||
const DB_HOST = process.env.DB_HOST
|
export const fileSystem = new FileSystem(
|
||||||
const DB_USERNAME = process.env.DB_USERNAME
|
join(__dirname, "../../integration-tests-migrations-many-to-one")
|
||||||
const DB_PASSWORD = process.env.DB_PASSWORD
|
)
|
||||||
|
|
||||||
const pgGodCredentials = {
|
|
||||||
user: DB_USERNAME,
|
|
||||||
password: DB_PASSWORD,
|
|
||||||
host: DB_HOST,
|
|
||||||
}
|
|
||||||
|
|
||||||
const fileSystem = new FileSystem(join(__dirname, "../../migrations"))
|
|
||||||
|
|
||||||
describe("manyToOne - belongTo", () => {
|
describe("manyToOne - belongTo", () => {
|
||||||
const dbName = "EntityBuilder-ManyToOne"
|
const dbName = "EntityBuilder-ManyToOne"
|
||||||
@@ -25,21 +18,21 @@ describe("manyToOne - belongTo", () => {
|
|||||||
let orm!: MikroORM
|
let orm!: MikroORM
|
||||||
let Team: EntityConstructor<any>, User: EntityConstructor<any>
|
let Team: EntityConstructor<any>, User: EntityConstructor<any>
|
||||||
|
|
||||||
afterAll(() => {
|
afterAll(async () => {
|
||||||
fileSystem.cleanup()
|
await fileSystem.cleanup()
|
||||||
})
|
})
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
MetadataStorage.clear()
|
MetadataStorage.clear()
|
||||||
|
|
||||||
const team = model.define("team", {
|
const team = model.define("team", {
|
||||||
id: model.id(),
|
id: model.id().primaryKey(),
|
||||||
name: model.text(),
|
name: model.text(),
|
||||||
user: model.belongsTo(() => user, { mappedBy: "teams" }),
|
user: model.belongsTo(() => user, { mappedBy: "teams" }),
|
||||||
})
|
})
|
||||||
|
|
||||||
const user = model.define("user", {
|
const user = model.define("user", {
|
||||||
id: model.id(),
|
id: model.id().primaryKey(),
|
||||||
username: model.text(),
|
username: model.text(),
|
||||||
teams: model.hasMany(() => team, { mappedBy: "user" }),
|
teams: model.hasMany(() => team, { mappedBy: "user" }),
|
||||||
})
|
})
|
||||||
@@ -52,8 +45,14 @@ describe("manyToOne - belongTo", () => {
|
|||||||
entities: [Team, User],
|
entities: [Team, User],
|
||||||
tsNode: true,
|
tsNode: true,
|
||||||
dbName,
|
dbName,
|
||||||
debug: true,
|
password: pgGodCredentials.password,
|
||||||
|
host: pgGodCredentials.host,
|
||||||
|
user: pgGodCredentials.user,
|
||||||
type: "postgresql",
|
type: "postgresql",
|
||||||
|
migrations: {
|
||||||
|
generator: CustomTsMigrationGenerator,
|
||||||
|
path: fileSystem.basePath,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const migrator = orm.getMigrator()
|
const migrator = orm.getMigrator()
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
const DB_HOST = process.env.DB_HOST ?? "localhost"
|
||||||
|
const DB_USERNAME = process.env.DB_USERNAME ?? ""
|
||||||
|
const DB_PASSWORD = process.env.DB_PASSWORD ?? ""
|
||||||
|
|
||||||
|
export const pgGodCredentials = {
|
||||||
|
user: DB_USERNAME,
|
||||||
|
password: DB_PASSWORD,
|
||||||
|
host: DB_HOST,
|
||||||
|
}
|
||||||
@@ -11,7 +11,7 @@ export class IdProperty extends BaseProperty<string> {
|
|||||||
[IsIdProperty] = true
|
[IsIdProperty] = true
|
||||||
|
|
||||||
static isIdProperty(value: any): value is IdProperty {
|
static isIdProperty(value: any): value is IdProperty {
|
||||||
return !!value?.[IsIdProperty]
|
return !!value?.[IsIdProperty] || value?.dataType?.name === "id"
|
||||||
}
|
}
|
||||||
|
|
||||||
protected dataType: {
|
protected dataType: {
|
||||||
|
|||||||
Reference in new issue
Block a user