Mark keys as primary with explicit method call (#7900)
This commit is contained in:
@@ -1,10 +1,21 @@
|
|||||||
|
/**
|
||||||
|
* Symbol to identify a DML entity from an object
|
||||||
|
*/
|
||||||
export const IsDmlEntity = Symbol.for("isDmlEntity")
|
export const IsDmlEntity = Symbol.for("isDmlEntity")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Representation of DML schema. It must be a key-value pair
|
||||||
|
* with string based keys and properties/relationships
|
||||||
|
* as the value.
|
||||||
|
*/
|
||||||
export type DMLSchema = Record<
|
export type DMLSchema = Record<
|
||||||
string,
|
string,
|
||||||
PropertyType<any> | RelationshipType<any>
|
PropertyType<any> | RelationshipType<any>
|
||||||
>
|
>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Representation of a DML entity
|
||||||
|
*/
|
||||||
export interface IDmlEntity<Schema extends DMLSchema> {
|
export interface IDmlEntity<Schema extends DMLSchema> {
|
||||||
[IsDmlEntity]: true
|
[IsDmlEntity]: true
|
||||||
schema: Schema
|
schema: Schema
|
||||||
@@ -66,9 +77,9 @@ export type PropertyType<T> = {
|
|||||||
*/
|
*/
|
||||||
export type RelationshipOptions = {
|
export type RelationshipOptions = {
|
||||||
/**
|
/**
|
||||||
* The name of the relationship as defined
|
* The name of the relationship as defined in the other
|
||||||
* in the other data model. This is only required
|
* data model. This is only required by the `belongsTo`
|
||||||
* by the `belongsTo` relationship method.
|
* relationship method.
|
||||||
*/
|
*/
|
||||||
mappedBy?: string
|
mappedBy?: string
|
||||||
} & Record<string, any>
|
} & Record<string, any>
|
||||||
@@ -107,7 +118,8 @@ export interface EntityConstructor<Props> extends Function {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* From a IDmlEntity, infer the foreign keys name and type for belongsTo relation meaning hasOne and ManyToOne
|
* From a IDmlEntity, infer the foreign keys name and type for
|
||||||
|
* "belongsTo" relation meaning "hasOne" and "ManyToOne"
|
||||||
*/
|
*/
|
||||||
export type InferForeignKeys<T> = T extends IDmlEntity<infer Schema>
|
export type InferForeignKeys<T> = T extends IDmlEntity<infer Schema>
|
||||||
? {
|
? {
|
||||||
|
|||||||
@@ -1291,7 +1291,8 @@ describe("Entity builder", () => {
|
|||||||
columnType: "text",
|
columnType: "text",
|
||||||
name: "id",
|
name: "id",
|
||||||
nullable: false,
|
nullable: false,
|
||||||
primary: true,
|
getter: false,
|
||||||
|
setter: false,
|
||||||
},
|
},
|
||||||
username: {
|
username: {
|
||||||
reference: "scalar",
|
reference: "scalar",
|
||||||
@@ -1346,9 +1347,9 @@ describe("Entity builder", () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
test("mark id as non-primary", () => {
|
test("mark id as primary", () => {
|
||||||
const user = model.define("user", {
|
const user = model.define("user", {
|
||||||
id: model.id({ primaryKey: false }),
|
id: model.id().primaryKey(),
|
||||||
username: model.text(),
|
username: model.text(),
|
||||||
email: model.text(),
|
email: model.text(),
|
||||||
})
|
})
|
||||||
@@ -1391,8 +1392,7 @@ describe("Entity builder", () => {
|
|||||||
columnType: "text",
|
columnType: "text",
|
||||||
name: "id",
|
name: "id",
|
||||||
nullable: false,
|
nullable: false,
|
||||||
getter: false,
|
primary: true,
|
||||||
setter: false,
|
|
||||||
},
|
},
|
||||||
username: {
|
username: {
|
||||||
reference: "scalar",
|
reference: "scalar",
|
||||||
@@ -1451,7 +1451,7 @@ describe("Entity builder", () => {
|
|||||||
|
|
||||||
test("define prefix for the id", () => {
|
test("define prefix for the id", () => {
|
||||||
const user = model.define("user", {
|
const user = model.define("user", {
|
||||||
id: model.id({ primaryKey: false, prefix: "us" }),
|
id: model.id({ prefix: "us" }).primaryKey(),
|
||||||
username: model.text(),
|
username: model.text(),
|
||||||
email: model.text(),
|
email: model.text(),
|
||||||
})
|
})
|
||||||
@@ -1494,8 +1494,7 @@ describe("Entity builder", () => {
|
|||||||
columnType: "text",
|
columnType: "text",
|
||||||
name: "id",
|
name: "id",
|
||||||
nullable: false,
|
nullable: false,
|
||||||
getter: false,
|
primary: true,
|
||||||
setter: false,
|
|
||||||
},
|
},
|
||||||
username: {
|
username: {
|
||||||
reference: "scalar",
|
reference: "scalar",
|
||||||
@@ -1554,124 +1553,25 @@ describe("Entity builder", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe("Entity builder | primaryKey", () => {
|
describe("Entity builder | primaryKey", () => {
|
||||||
test("should create both id fields and primaryKey fields", () => {
|
test("should infer primaryKeys from a model", () => {
|
||||||
const user = model.define("user", {
|
const user = model.define("user", {
|
||||||
id: model.id(),
|
id: model.id().primaryKey(),
|
||||||
email: model.text().primaryKey(),
|
email: model.text().primaryKey(),
|
||||||
account_id: model.number().primaryKey(),
|
account_id: model.number(),
|
||||||
})
|
})
|
||||||
|
|
||||||
const entityBuilder = createMikrORMEntity()
|
const entityBuilder = createMikrORMEntity()
|
||||||
const User = entityBuilder(user)
|
const User = entityBuilder(user)
|
||||||
|
|
||||||
expectTypeOf(new User()).toMatchTypeOf<{
|
|
||||||
id: string
|
|
||||||
email: string
|
|
||||||
account_id: number
|
|
||||||
}>()
|
|
||||||
|
|
||||||
const metaData = MetadataStorage.getMetadataFromDecorator(User)
|
const metaData = MetadataStorage.getMetadataFromDecorator(User)
|
||||||
|
|
||||||
expect(metaData.properties).toEqual({
|
|
||||||
id: {
|
|
||||||
reference: "scalar",
|
|
||||||
type: "string",
|
|
||||||
columnType: "text",
|
|
||||||
name: "id",
|
|
||||||
nullable: false,
|
|
||||||
getter: false,
|
|
||||||
setter: false,
|
|
||||||
},
|
|
||||||
email: {
|
|
||||||
columnType: "text",
|
|
||||||
name: "email",
|
|
||||||
nullable: false,
|
|
||||||
primary: true,
|
|
||||||
reference: "scalar",
|
|
||||||
type: "string",
|
|
||||||
},
|
|
||||||
account_id: {
|
|
||||||
columnType: "integer",
|
|
||||||
name: "account_id",
|
|
||||||
nullable: false,
|
|
||||||
primary: true,
|
|
||||||
reference: "scalar",
|
|
||||||
type: "number",
|
|
||||||
},
|
|
||||||
created_at: {
|
|
||||||
reference: "scalar",
|
|
||||||
type: "date",
|
|
||||||
columnType: "timestamptz",
|
|
||||||
name: "created_at",
|
|
||||||
defaultRaw: "now()",
|
|
||||||
onCreate: expect.any(Function),
|
|
||||||
nullable: false,
|
|
||||||
getter: false,
|
|
||||||
setter: false,
|
|
||||||
},
|
|
||||||
updated_at: {
|
|
||||||
reference: "scalar",
|
|
||||||
type: "date",
|
|
||||||
columnType: "timestamptz",
|
|
||||||
name: "updated_at",
|
|
||||||
defaultRaw: "now()",
|
|
||||||
onCreate: expect.any(Function),
|
|
||||||
onUpdate: expect.any(Function),
|
|
||||||
nullable: false,
|
|
||||||
getter: false,
|
|
||||||
setter: false,
|
|
||||||
},
|
|
||||||
deleted_at: {
|
|
||||||
reference: "scalar",
|
|
||||||
type: "date",
|
|
||||||
columnType: "timestamptz",
|
|
||||||
name: "deleted_at",
|
|
||||||
nullable: true,
|
|
||||||
getter: false,
|
|
||||||
setter: false,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
test("should infer primaryKeys from a model", () => {
|
|
||||||
let user = model.define("user", {
|
|
||||||
id: model.id(),
|
|
||||||
email: model.text(),
|
|
||||||
account_id: model.number(),
|
|
||||||
})
|
|
||||||
|
|
||||||
const entityBuilder = createMikrORMEntity()
|
|
||||||
let User = entityBuilder(user)
|
|
||||||
let metaData = MetadataStorage.getMetadataFromDecorator(User)
|
|
||||||
|
|
||||||
expect(metaData.properties.id).toEqual({
|
|
||||||
columnType: "text",
|
|
||||||
name: "id",
|
|
||||||
nullable: false,
|
|
||||||
primary: true,
|
|
||||||
reference: "scalar",
|
|
||||||
type: "string",
|
|
||||||
})
|
|
||||||
|
|
||||||
user = model.define("user", {
|
|
||||||
id: model.id(),
|
|
||||||
email: model.text().primaryKey(),
|
|
||||||
account_id: model.number(),
|
|
||||||
})
|
|
||||||
|
|
||||||
User = entityBuilder(user)
|
|
||||||
metaData = MetadataStorage.getMetadataFromDecorator(User)
|
|
||||||
|
|
||||||
expect(metaData.properties.id).toEqual({
|
expect(metaData.properties.id).toEqual({
|
||||||
columnType: "text",
|
columnType: "text",
|
||||||
name: "id",
|
name: "id",
|
||||||
nullable: false,
|
nullable: false,
|
||||||
reference: "scalar",
|
reference: "scalar",
|
||||||
type: "string",
|
type: "string",
|
||||||
getter: false,
|
primary: true,
|
||||||
setter: false,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(metaData.properties.email).toEqual({
|
expect(metaData.properties.email).toEqual({
|
||||||
columnType: "text",
|
columnType: "text",
|
||||||
name: "email",
|
name: "email",
|
||||||
@@ -1680,53 +1580,6 @@ describe("Entity builder", () => {
|
|||||||
type: "string",
|
type: "string",
|
||||||
primary: true,
|
primary: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(metaData.properties.account_id).toEqual({
|
|
||||||
columnType: "integer",
|
|
||||||
name: "account_id",
|
|
||||||
nullable: false,
|
|
||||||
reference: "scalar",
|
|
||||||
type: "number",
|
|
||||||
getter: false,
|
|
||||||
setter: false,
|
|
||||||
})
|
|
||||||
|
|
||||||
user = model.define("user", {
|
|
||||||
id: model.id(),
|
|
||||||
email: model.text().primaryKey(),
|
|
||||||
account_id: model.number().primaryKey(),
|
|
||||||
})
|
|
||||||
|
|
||||||
User = entityBuilder(user)
|
|
||||||
metaData = MetadataStorage.getMetadataFromDecorator(User)
|
|
||||||
|
|
||||||
expect(metaData.properties.id).toEqual({
|
|
||||||
columnType: "text",
|
|
||||||
name: "id",
|
|
||||||
nullable: false,
|
|
||||||
reference: "scalar",
|
|
||||||
type: "string",
|
|
||||||
getter: false,
|
|
||||||
setter: false,
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(metaData.properties.email).toEqual({
|
|
||||||
columnType: "text",
|
|
||||||
name: "email",
|
|
||||||
nullable: false,
|
|
||||||
reference: "scalar",
|
|
||||||
type: "string",
|
|
||||||
primary: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(metaData.properties.account_id).toEqual({
|
|
||||||
columnType: "integer",
|
|
||||||
name: "account_id",
|
|
||||||
nullable: false,
|
|
||||||
reference: "scalar",
|
|
||||||
type: "number",
|
|
||||||
primary: true,
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -5,24 +5,6 @@ describe("Id property", () => {
|
|||||||
test("create id property type", () => {
|
test("create id property type", () => {
|
||||||
const property = new IdProperty()
|
const property = new IdProperty()
|
||||||
|
|
||||||
expectTypeOf(property["$dataType"]).toEqualTypeOf<string>()
|
|
||||||
expect(property.parse("id")).toEqual({
|
|
||||||
fieldName: "id",
|
|
||||||
dataType: {
|
|
||||||
name: "id",
|
|
||||||
options: {
|
|
||||||
primaryKey: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
nullable: false,
|
|
||||||
indexes: [],
|
|
||||||
relationships: [],
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
test("create id property type with marking it as a primary key", () => {
|
|
||||||
const property = new IdProperty({ primaryKey: false })
|
|
||||||
|
|
||||||
expectTypeOf(property["$dataType"]).toEqualTypeOf<string>()
|
expectTypeOf(property["$dataType"]).toEqualTypeOf<string>()
|
||||||
expect(property.parse("id")).toEqual({
|
expect(property.parse("id")).toEqual({
|
||||||
fieldName: "id",
|
fieldName: "id",
|
||||||
@@ -37,4 +19,22 @@ describe("Id property", () => {
|
|||||||
relationships: [],
|
relationships: [],
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test("create id property type with marking it as a primary key", () => {
|
||||||
|
const property = new IdProperty().primaryKey()
|
||||||
|
|
||||||
|
expectTypeOf(property["$dataType"]).toEqualTypeOf<string>()
|
||||||
|
expect(property.parse("id")).toEqual({
|
||||||
|
fieldName: "id",
|
||||||
|
dataType: {
|
||||||
|
name: "id",
|
||||||
|
options: {
|
||||||
|
primaryKey: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
nullable: false,
|
||||||
|
indexes: [],
|
||||||
|
relationships: [],
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -17,4 +17,20 @@ describe("Text property", () => {
|
|||||||
relationships: [],
|
relationships: [],
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test("mark text property as primary key", () => {
|
||||||
|
const property = new TextProperty().primaryKey()
|
||||||
|
|
||||||
|
expectTypeOf(property["$dataType"]).toEqualTypeOf<string>()
|
||||||
|
expect(property.parse("username")).toEqual({
|
||||||
|
fieldName: "username",
|
||||||
|
dataType: {
|
||||||
|
name: "text",
|
||||||
|
options: { primaryKey: true, searchable: false },
|
||||||
|
},
|
||||||
|
nullable: false,
|
||||||
|
indexes: [],
|
||||||
|
relationships: [],
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import type { DMLSchema, RelationshipOptions } from "@medusajs/types"
|
|||||||
import { DmlEntity } from "./entity"
|
import { DmlEntity } from "./entity"
|
||||||
import { createBigNumberProperties } from "./helpers/entity-builder/create-big-number-properties"
|
import { createBigNumberProperties } from "./helpers/entity-builder/create-big-number-properties"
|
||||||
import { createDefaultProperties } from "./helpers/entity-builder/create-default-properties"
|
import { createDefaultProperties } from "./helpers/entity-builder/create-default-properties"
|
||||||
import { inferPrimaryKeyProperties } from "./helpers/entity-builder/infer-primary-key-properties"
|
|
||||||
import { ArrayProperty } from "./properties/array"
|
import { ArrayProperty } from "./properties/array"
|
||||||
import { BigNumberProperty } from "./properties/big-number"
|
import { BigNumberProperty } from "./properties/big-number"
|
||||||
import { BooleanProperty } from "./properties/boolean"
|
import { BooleanProperty } from "./properties/boolean"
|
||||||
@@ -22,7 +21,9 @@ import { ManyToMany } from "./relations/many-to-many"
|
|||||||
*/
|
*/
|
||||||
const IMPLICIT_PROPERTIES = ["created_at", "updated_at", "deleted_at"]
|
const IMPLICIT_PROPERTIES = ["created_at", "updated_at", "deleted_at"]
|
||||||
|
|
||||||
export type DefineOptions = string | {
|
export type DefineOptions =
|
||||||
|
| string
|
||||||
|
| {
|
||||||
/**
|
/**
|
||||||
* The data model's name.
|
* The data model's name.
|
||||||
*/
|
*/
|
||||||
@@ -31,10 +32,10 @@ export type DefineOptions = string | {
|
|||||||
* The name of the data model's table in the database.
|
* The name of the data model's table in the database.
|
||||||
*/
|
*/
|
||||||
tableName: string
|
tableName: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ManyToManyOptions = RelationshipOptions &
|
export type ManyToManyOptions = RelationshipOptions &
|
||||||
(
|
(
|
||||||
| {
|
| {
|
||||||
/**
|
/**
|
||||||
* The name of the pivot table
|
* The name of the pivot table
|
||||||
@@ -58,7 +59,7 @@ export type ManyToManyOptions = RelationshipOptions &
|
|||||||
*/
|
*/
|
||||||
pivotEntity?: () => DmlEntity<any>
|
pivotEntity?: () => DmlEntity<any>
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Entity builder exposes the API to create an entity and define its
|
* Entity builder exposes the API to create an entity and define its
|
||||||
@@ -103,7 +104,6 @@ export class EntityBuilder {
|
|||||||
schema: Schema
|
schema: Schema
|
||||||
) {
|
) {
|
||||||
this.#disallowImplicitProperties(schema)
|
this.#disallowImplicitProperties(schema)
|
||||||
schema = inferPrimaryKeyProperties(schema)
|
|
||||||
|
|
||||||
return new DmlEntity(nameOrConfig, {
|
return new DmlEntity(nameOrConfig, {
|
||||||
...schema,
|
...schema,
|
||||||
@@ -115,23 +115,22 @@ export class EntityBuilder {
|
|||||||
/**
|
/**
|
||||||
* This method defines an automatically generated string ID property.
|
* This method defines an automatically generated string ID property.
|
||||||
*
|
*
|
||||||
* By default, this property is considered to be the data model’s primary key.
|
* You must use the "primaryKey" modifier to mark the property as the
|
||||||
*
|
* primary key.
|
||||||
* @param {ConstructorParameters<typeof IdProperty>[0]} options - The ID's options.
|
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* import { model } from "@medusajs/utils"
|
* import { model } from "@medusajs/utils"
|
||||||
*
|
*
|
||||||
* const MyCustom = model.define("my_custom", {
|
* const User = model.define("User", {
|
||||||
* id: model.id(),
|
* id: model.id().primaryKey(),
|
||||||
* // ...
|
* // ...
|
||||||
* })
|
* })
|
||||||
*
|
*
|
||||||
* export default MyCustom
|
* export default User
|
||||||
*
|
*
|
||||||
* @customNamespace Property Types
|
* @customNamespace Property Types
|
||||||
*/
|
*/
|
||||||
id(options?: ConstructorParameters<typeof IdProperty>[0]) {
|
id(options?: { prefix?: string }) {
|
||||||
return new IdProperty(options)
|
return new IdProperty(options)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -406,10 +405,7 @@ export class EntityBuilder {
|
|||||||
*
|
*
|
||||||
* @customNamespace Relationship Methods
|
* @customNamespace Relationship Methods
|
||||||
*/
|
*/
|
||||||
manyToMany<T>(
|
manyToMany<T>(entityBuilder: T, options?: ManyToManyOptions) {
|
||||||
entityBuilder: T,
|
|
||||||
options?: ManyToManyOptions
|
|
||||||
) {
|
|
||||||
return new ManyToMany<T>(entityBuilder, options || {})
|
return new ManyToMany<T>(entityBuilder, options || {})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,14 +87,14 @@ export function createMikrORMEntity() {
|
|||||||
*/
|
*/
|
||||||
export const toMikroORMEntity = <T>(
|
export const toMikroORMEntity = <T>(
|
||||||
entity: T
|
entity: T
|
||||||
): T extends DmlEntity<infer Schema> ? Infer<T> : T => {
|
): T extends DmlEntity<any> ? Infer<T> : T => {
|
||||||
let mikroOrmEntity: T | EntityConstructor<any> = entity
|
let mikroOrmEntity: T | EntityConstructor<any> = entity
|
||||||
|
|
||||||
if (DmlEntity.isDmlEntity(entity)) {
|
if (DmlEntity.isDmlEntity(entity)) {
|
||||||
mikroOrmEntity = createMikrORMEntity()(entity)
|
mikroOrmEntity = createMikrORMEntity()(entity)
|
||||||
}
|
}
|
||||||
|
|
||||||
return mikroOrmEntity as T extends DmlEntity<infer Schema> ? Infer<T> : T
|
return mikroOrmEntity as T extends DmlEntity<any> ? Infer<T> : T
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,74 +0,0 @@
|
|||||||
import { DMLSchema } from "@medusajs/types"
|
|
||||||
import { IdProperty } from "../../properties/id"
|
|
||||||
|
|
||||||
/*
|
|
||||||
The id() property is an core opinionated property that will act as a primaryKey
|
|
||||||
by default and come with built-in logic when converted to a mikroorm entity. If no other
|
|
||||||
primaryKey() properties are found within the schema, we continue treating the id() property
|
|
||||||
as a primaryKey. When other fields are set as explicit primaryKey fields, we convert the
|
|
||||||
id() property to no longer be a primaryKey.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
Model 1:
|
|
||||||
id: model.id() -> primary key
|
|
||||||
code: model.text()
|
|
||||||
|
|
||||||
Model 2:
|
|
||||||
id: model.id()
|
|
||||||
code: model.text().primaryKey() -> primary key
|
|
||||||
|
|
||||||
Model 3:
|
|
||||||
id: model.id()
|
|
||||||
code: model.text().primaryKey() -> composite primary key
|
|
||||||
name: model.text().primaryKey() -> composite primary key
|
|
||||||
*/
|
|
||||||
export function inferPrimaryKeyProperties<TSchema extends DMLSchema>(
|
|
||||||
schema: TSchema
|
|
||||||
) {
|
|
||||||
// If explicit primaryKey fields are not found, no inferrence is required. Return early.
|
|
||||||
if (!getExplicitPrimaryKeyFields(schema).length) {
|
|
||||||
return schema
|
|
||||||
}
|
|
||||||
|
|
||||||
// If explicit primaryKey fields are found, set any id() properties to no longer be
|
|
||||||
// set to primaryKey.
|
|
||||||
for (const [field, property] of Object.entries(schema)) {
|
|
||||||
const parsed = property.parse(field)
|
|
||||||
const isRelationshipType = "type" in parsed
|
|
||||||
|
|
||||||
if (isRelationshipType) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parsed.dataType.name === "id") {
|
|
||||||
;(property as IdProperty).primaryKey(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return schema
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Gets all explicit primary key fields from a schema, except id properties.
|
|
||||||
|
|
||||||
eg: model.define('test', {
|
|
||||||
id: model.id(), -> implicit primaryKey field,
|
|
||||||
text: model.text(),
|
|
||||||
textPrimary: model.text().primaryKey(), -> explicit primaryKey field
|
|
||||||
numberPrimary: model.number().primaryKey(), -> explicit primaryKey field
|
|
||||||
belongsTo: model.belongsTo(() => belongsToAnother),
|
|
||||||
})
|
|
||||||
*/
|
|
||||||
function getExplicitPrimaryKeyFields(schema: DMLSchema) {
|
|
||||||
return Object.entries(schema).filter(([field, property]) => {
|
|
||||||
const parsed = property.parse(field)
|
|
||||||
const isRelationshipType = "type" in parsed
|
|
||||||
|
|
||||||
// Return early if its a relationship property or an id property
|
|
||||||
if (isRelationshipType || parsed.dataType.name === "id") {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return !!parsed.dataType.options?.primaryKey
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -11,33 +11,33 @@ export class IdProperty extends BaseProperty<string> {
|
|||||||
primaryKey: boolean
|
primaryKey: boolean
|
||||||
prefix?: string
|
prefix?: string
|
||||||
}
|
}
|
||||||
}
|
} = {
|
||||||
|
|
||||||
constructor(options?: {
|
|
||||||
/**
|
|
||||||
* Whether the ID is the data model's primary key.
|
|
||||||
*
|
|
||||||
* @defaultValue true
|
|
||||||
*/
|
|
||||||
primaryKey?: boolean
|
|
||||||
/**
|
|
||||||
* By default, Medusa shortens the data model's name and uses it as the
|
|
||||||
* prefix of all IDs. For example, `cm_123`.
|
|
||||||
*
|
|
||||||
* Use this option to specify the prefix to use instead.
|
|
||||||
*/
|
|
||||||
prefix?: string
|
|
||||||
}) {
|
|
||||||
super()
|
|
||||||
this.dataType = {
|
|
||||||
name: "id",
|
name: "id",
|
||||||
options: { primaryKey: true, ...options },
|
options: { primaryKey: false },
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
primaryKey(decision: boolean) {
|
constructor(options?: { prefix?: string }) {
|
||||||
this.dataType.options.primaryKey = decision
|
super()
|
||||||
|
this.dataType.options.prefix = options?.prefix
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method indicates that the property is the data model's primary key.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* import { model } from "@medusajs/utils"
|
||||||
|
*
|
||||||
|
* const Product = model.define("Product", {
|
||||||
|
* id: model.id().primaryKey(),
|
||||||
|
* // ...
|
||||||
|
* })
|
||||||
|
*
|
||||||
|
* export default Product
|
||||||
|
*
|
||||||
|
* @customNamespace Property Configuration Methods
|
||||||
|
*/
|
||||||
|
primaryKey() {
|
||||||
|
this.dataType.options.primaryKey = true
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,8 +8,15 @@ export class TextProperty extends BaseProperty<string> {
|
|||||||
name: "text"
|
name: "text"
|
||||||
options: {
|
options: {
|
||||||
primaryKey: boolean
|
primaryKey: boolean
|
||||||
|
prefix?: string
|
||||||
searchable: boolean
|
searchable: boolean
|
||||||
}
|
}
|
||||||
|
} = {
|
||||||
|
name: "text",
|
||||||
|
options: {
|
||||||
|
primaryKey: false,
|
||||||
|
searchable: false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -18,12 +25,12 @@ export class TextProperty extends BaseProperty<string> {
|
|||||||
* @example
|
* @example
|
||||||
* import { model } from "@medusajs/utils"
|
* import { model } from "@medusajs/utils"
|
||||||
*
|
*
|
||||||
* const MyCustom = model.define("my_custom", {
|
* const Product = model.define("Product", {
|
||||||
* code: model.text().primaryKey(),
|
* code: model.text().primaryKey(),
|
||||||
* // ...
|
* // ...
|
||||||
* })
|
* })
|
||||||
*
|
*
|
||||||
* export default MyCustom
|
* export default Product
|
||||||
*
|
*
|
||||||
* @customNamespace Property Configuration Methods
|
* @customNamespace Property Configuration Methods
|
||||||
*/
|
*/
|
||||||
@@ -53,13 +60,4 @@ export class TextProperty extends BaseProperty<string> {
|
|||||||
|
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(options?: { primaryKey?: boolean; searchable?: boolean }) {
|
|
||||||
super()
|
|
||||||
|
|
||||||
this.dataType = {
|
|
||||||
name: "text",
|
|
||||||
options: { primaryKey: false, searchable: false, ...options },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { model } from "@medusajs/utils"
|
|||||||
import { Notification } from "./notification"
|
import { Notification } from "./notification"
|
||||||
|
|
||||||
export const NotificationProvider = model.define("notificationProvider", {
|
export const NotificationProvider = model.define("notificationProvider", {
|
||||||
id: model.id({ prefix: "notpro" }),
|
id: model.id({ prefix: "notpro" }).primaryKey(),
|
||||||
handle: model.text(),
|
handle: model.text(),
|
||||||
name: model.text(),
|
name: model.text(),
|
||||||
is_enabled: model.boolean().default(true),
|
is_enabled: model.boolean().default(true),
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { NotificationProvider } from "./notification-provider"
|
|||||||
|
|
||||||
// We probably want to have a TTL for each entry, so we don't bloat the DB (and also for GDPR reasons if TTL < 30 days).
|
// We probably want to have a TTL for each entry, so we don't bloat the DB (and also for GDPR reasons if TTL < 30 days).
|
||||||
export const Notification = model.define("notification", {
|
export const Notification = model.define("notification", {
|
||||||
id: model.id({ prefix: "noti" }),
|
id: model.id({ prefix: "noti" }).primaryKey(),
|
||||||
// This can be an email, phone number, or username, depending on the channel.
|
// This can be an email, phone number, or username, depending on the channel.
|
||||||
to: model.text(),
|
to: model.text(),
|
||||||
channel: model.text(),
|
channel: model.text(),
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { model } from "@medusajs/utils"
|
|||||||
import RegionCountry from "./country"
|
import RegionCountry from "./country"
|
||||||
|
|
||||||
const Region = model.define("region", {
|
const Region = model.define("region", {
|
||||||
id: model.id({ prefix: "reg" }),
|
id: model.id({ prefix: "reg" }).primaryKey(),
|
||||||
name: model.text().searchable(),
|
name: model.text().searchable(),
|
||||||
currency_code: model.text().searchable(),
|
currency_code: model.text().searchable(),
|
||||||
automatic_taxes: model.boolean().default(true),
|
automatic_taxes: model.boolean().default(true),
|
||||||
|
|||||||
Reference in New Issue
Block a user