Overall revamp of relationships (#7690)
This commit is contained in:
1 parent
129fb447d0
commit
fbd8eef18b
25 files changed
+1388
-625
No files matched your search
+11
-5
@@ -1,23 +1,29 @@
|
|||||||
import { expectTypeOf } from "expect-type"
|
import { expectTypeOf } from "expect-type"
|
||||||
import { HasOne } from "../relations/has_one"
|
|
||||||
import { TextSchema } from "../schema/text"
|
import { TextSchema } from "../schema/text"
|
||||||
|
import { BaseRelationship } from "../relations/base"
|
||||||
|
|
||||||
|
describe("Base relationship", () => {
|
||||||
|
test("define a custom relationship", () => {
|
||||||
|
class HasOne<T> extends BaseRelationship<T> {
|
||||||
|
protected relationshipType: "hasOne" | "hasMany" | "manyToMany" = "hasOne"
|
||||||
|
}
|
||||||
|
|
||||||
describe("HasOne relationship", () => {
|
|
||||||
test("define hasOne relationship", () => {
|
|
||||||
const user = {
|
const user = {
|
||||||
username: new TextSchema(),
|
username: new TextSchema(),
|
||||||
}
|
}
|
||||||
|
|
||||||
const entityRef = () => user
|
const entityRef = () => user
|
||||||
const relationship = new HasOne(entityRef, {})
|
const relationship = new HasOne(entityRef, {
|
||||||
|
mappedBy: "user_id",
|
||||||
|
})
|
||||||
|
|
||||||
expectTypeOf(relationship["$dataType"]).toEqualTypeOf<() => typeof user>()
|
expectTypeOf(relationship["$dataType"]).toEqualTypeOf<() => typeof user>()
|
||||||
expect(relationship.parse("user")).toEqual({
|
expect(relationship.parse("user")).toEqual({
|
||||||
name: "user",
|
name: "user",
|
||||||
type: "hasOne",
|
type: "hasOne",
|
||||||
nullable: false,
|
nullable: false,
|
||||||
|
mappedBy: "user_id",
|
||||||
entity: entityRef,
|
entity: entityRef,
|
||||||
options: {},
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
File renamed without changes.
File renamed without changes.
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
import { expectTypeOf } from "expect-type"
|
import { expectTypeOf } from "expect-type"
|
||||||
import { DateTimeSchema } from "../schema/date_time"
|
import { DateTimeSchema } from "../schema/date-time"
|
||||||
|
|
||||||
describe("DateTime schema", () => {
|
describe("DateTime schema", () => {
|
||||||
test("create datetime schema type", () => {
|
test("create datetime schema type", () => {
|
||||||
File diff suppressed because it is too large.
Load diff
@@ -1,509 +0,0 @@
|
|||||||
import { expectTypeOf } from "expect-type"
|
|
||||||
import { MetadataStorage } from "@mikro-orm/core"
|
|
||||||
import { EntityBuilder } from "../entity_builder"
|
|
||||||
import { createMikrORMEntity } from "../helpers/create_mikro_orm_entity"
|
|
||||||
import { EntityConstructor } from "../types"
|
|
||||||
|
|
||||||
describe("Entity builder", () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
MetadataStorage.clear()
|
|
||||||
})
|
|
||||||
|
|
||||||
test("define an entity", () => {
|
|
||||||
const model = new EntityBuilder()
|
|
||||||
const user = model.define("user", {
|
|
||||||
id: model.number(),
|
|
||||||
username: model.text(),
|
|
||||||
email: model.text(),
|
|
||||||
})
|
|
||||||
|
|
||||||
const User = createMikrORMEntity(user)
|
|
||||||
expectTypeOf(new User()).toMatchTypeOf<{
|
|
||||||
id: number
|
|
||||||
username: string
|
|
||||||
email: string
|
|
||||||
}>()
|
|
||||||
|
|
||||||
const metaData = MetadataStorage.getMetadataFromDecorator(User)
|
|
||||||
expect(metaData.className).toEqual("User")
|
|
||||||
expect(metaData.path).toEqual("User")
|
|
||||||
expect(metaData.properties).toEqual({
|
|
||||||
id: {
|
|
||||||
reference: "scalar",
|
|
||||||
type: "number",
|
|
||||||
columnType: "integer",
|
|
||||||
name: "id",
|
|
||||||
nullable: false,
|
|
||||||
getter: false,
|
|
||||||
setter: false,
|
|
||||||
},
|
|
||||||
username: {
|
|
||||||
reference: "scalar",
|
|
||||||
type: "string",
|
|
||||||
columnType: "text",
|
|
||||||
name: "username",
|
|
||||||
nullable: false,
|
|
||||||
getter: false,
|
|
||||||
setter: false,
|
|
||||||
},
|
|
||||||
email: {
|
|
||||||
reference: "scalar",
|
|
||||||
type: "string",
|
|
||||||
columnType: "text",
|
|
||||||
name: "email",
|
|
||||||
nullable: false,
|
|
||||||
getter: false,
|
|
||||||
setter: false,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
test("define an entity with enum property", () => {
|
|
||||||
const model = new EntityBuilder()
|
|
||||||
const user = model.define("user", {
|
|
||||||
id: model.number(),
|
|
||||||
username: model.text(),
|
|
||||||
email: model.text(),
|
|
||||||
role: model.enum(["moderator", "admin", "guest"]),
|
|
||||||
})
|
|
||||||
|
|
||||||
const User = createMikrORMEntity(user)
|
|
||||||
expectTypeOf(new User()).toMatchTypeOf<{
|
|
||||||
id: number
|
|
||||||
username: string
|
|
||||||
email: string
|
|
||||||
role: "moderator" | "admin" | "guest"
|
|
||||||
}>()
|
|
||||||
|
|
||||||
const metaData = MetadataStorage.getMetadataFromDecorator(User)
|
|
||||||
|
|
||||||
expect(metaData.className).toEqual("User")
|
|
||||||
expect(metaData.path).toEqual("User")
|
|
||||||
expect(metaData.properties).toEqual({
|
|
||||||
id: {
|
|
||||||
reference: "scalar",
|
|
||||||
type: "number",
|
|
||||||
columnType: "integer",
|
|
||||||
name: "id",
|
|
||||||
nullable: false,
|
|
||||||
getter: false,
|
|
||||||
setter: false,
|
|
||||||
},
|
|
||||||
username: {
|
|
||||||
reference: "scalar",
|
|
||||||
type: "string",
|
|
||||||
columnType: "text",
|
|
||||||
name: "username",
|
|
||||||
nullable: false,
|
|
||||||
getter: false,
|
|
||||||
setter: false,
|
|
||||||
},
|
|
||||||
email: {
|
|
||||||
reference: "scalar",
|
|
||||||
type: "string",
|
|
||||||
columnType: "text",
|
|
||||||
name: "email",
|
|
||||||
nullable: false,
|
|
||||||
getter: false,
|
|
||||||
setter: false,
|
|
||||||
},
|
|
||||||
role: {
|
|
||||||
reference: "scalar",
|
|
||||||
enum: true,
|
|
||||||
items: expect.any(Function),
|
|
||||||
nullable: false,
|
|
||||||
name: "role",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
expect(metaData.properties["role"].items()).toEqual([
|
|
||||||
"moderator",
|
|
||||||
"admin",
|
|
||||||
"guest",
|
|
||||||
])
|
|
||||||
})
|
|
||||||
|
|
||||||
test("define an entity with default value", () => {
|
|
||||||
const model = new EntityBuilder()
|
|
||||||
const user = model.define("user", {
|
|
||||||
id: model.number(),
|
|
||||||
username: model.text().default("foo"),
|
|
||||||
email: model.text(),
|
|
||||||
})
|
|
||||||
|
|
||||||
const User = createMikrORMEntity(user)
|
|
||||||
expectTypeOf(new User()).toMatchTypeOf<{
|
|
||||||
id: number
|
|
||||||
username: string
|
|
||||||
email: string
|
|
||||||
}>()
|
|
||||||
|
|
||||||
const metaData = MetadataStorage.getMetadataFromDecorator(User)
|
|
||||||
expect(metaData.className).toEqual("User")
|
|
||||||
expect(metaData.path).toEqual("User")
|
|
||||||
expect(metaData.properties).toEqual({
|
|
||||||
id: {
|
|
||||||
reference: "scalar",
|
|
||||||
type: "number",
|
|
||||||
columnType: "integer",
|
|
||||||
name: "id",
|
|
||||||
nullable: false,
|
|
||||||
getter: false,
|
|
||||||
setter: false,
|
|
||||||
},
|
|
||||||
username: {
|
|
||||||
reference: "scalar",
|
|
||||||
type: "string",
|
|
||||||
default: "foo",
|
|
||||||
columnType: "text",
|
|
||||||
name: "username",
|
|
||||||
nullable: false,
|
|
||||||
getter: false,
|
|
||||||
setter: false,
|
|
||||||
},
|
|
||||||
email: {
|
|
||||||
reference: "scalar",
|
|
||||||
type: "string",
|
|
||||||
columnType: "text",
|
|
||||||
name: "email",
|
|
||||||
nullable: false,
|
|
||||||
getter: false,
|
|
||||||
setter: false,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
test("define hasMany relationship", () => {
|
|
||||||
const model = new EntityBuilder()
|
|
||||||
const email = model.define("email", {
|
|
||||||
email: model.text(),
|
|
||||||
isVerified: model.boolean(),
|
|
||||||
})
|
|
||||||
|
|
||||||
const user = model.define("user", {
|
|
||||||
id: model.number(),
|
|
||||||
username: model.text(),
|
|
||||||
emails: model.hasMany(() => email),
|
|
||||||
})
|
|
||||||
|
|
||||||
const User = createMikrORMEntity(user)
|
|
||||||
expectTypeOf(new User()).toMatchTypeOf<{
|
|
||||||
id: number
|
|
||||||
username: string
|
|
||||||
emails: EntityConstructor<{ email: string; isVerified: boolean }>
|
|
||||||
}>()
|
|
||||||
|
|
||||||
const metaData = MetadataStorage.getMetadataFromDecorator(User)
|
|
||||||
expect(metaData.className).toEqual("User")
|
|
||||||
expect(metaData.path).toEqual("User")
|
|
||||||
expect(metaData.properties).toEqual({
|
|
||||||
id: {
|
|
||||||
reference: "scalar",
|
|
||||||
type: "number",
|
|
||||||
columnType: "integer",
|
|
||||||
name: "id",
|
|
||||||
nullable: false,
|
|
||||||
getter: false,
|
|
||||||
setter: false,
|
|
||||||
},
|
|
||||||
username: {
|
|
||||||
reference: "scalar",
|
|
||||||
type: "string",
|
|
||||||
columnType: "text",
|
|
||||||
name: "username",
|
|
||||||
nullable: false,
|
|
||||||
getter: false,
|
|
||||||
setter: false,
|
|
||||||
},
|
|
||||||
emails: {
|
|
||||||
reference: "1:m",
|
|
||||||
name: "emails",
|
|
||||||
entity: "Email",
|
|
||||||
cascade: ["persist"],
|
|
||||||
mappedBy: expect.any(Function),
|
|
||||||
orphanRemoval: true,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
test("define hasMany and hasOneThroughMany relationships", () => {
|
|
||||||
const model = new EntityBuilder()
|
|
||||||
const order = model.define("order", {
|
|
||||||
amount: model.number(),
|
|
||||||
user: model.hasOneThroughMany(() => user),
|
|
||||||
})
|
|
||||||
|
|
||||||
const user = model.define("user", {
|
|
||||||
id: model.number(),
|
|
||||||
username: model.text(),
|
|
||||||
orders: model.hasMany(() => order),
|
|
||||||
})
|
|
||||||
|
|
||||||
const User = createMikrORMEntity(user)
|
|
||||||
const Order = createMikrORMEntity(order)
|
|
||||||
expectTypeOf(new User()).toMatchTypeOf<{
|
|
||||||
id: number
|
|
||||||
username: string
|
|
||||||
orders: EntityConstructor<{
|
|
||||||
amount: number
|
|
||||||
user: EntityConstructor<{
|
|
||||||
id: number
|
|
||||||
username: string
|
|
||||||
}>
|
|
||||||
}>
|
|
||||||
}>()
|
|
||||||
|
|
||||||
const metaData = MetadataStorage.getMetadataFromDecorator(User)
|
|
||||||
|
|
||||||
expect(metaData.className).toEqual("User")
|
|
||||||
expect(metaData.path).toEqual("User")
|
|
||||||
expect(metaData.properties).toEqual({
|
|
||||||
id: {
|
|
||||||
reference: "scalar",
|
|
||||||
type: "number",
|
|
||||||
columnType: "integer",
|
|
||||||
name: "id",
|
|
||||||
nullable: false,
|
|
||||||
getter: false,
|
|
||||||
setter: false,
|
|
||||||
},
|
|
||||||
username: {
|
|
||||||
reference: "scalar",
|
|
||||||
type: "string",
|
|
||||||
columnType: "text",
|
|
||||||
name: "username",
|
|
||||||
nullable: false,
|
|
||||||
getter: false,
|
|
||||||
setter: false,
|
|
||||||
},
|
|
||||||
orders: {
|
|
||||||
reference: "1:m",
|
|
||||||
name: "orders",
|
|
||||||
cascade: ["persist"],
|
|
||||||
mappedBy: expect.any(Function),
|
|
||||||
orphanRemoval: true,
|
|
||||||
entity: "Order",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const orderMetaDdata = MetadataStorage.getMetadataFromDecorator(Order)
|
|
||||||
expect(orderMetaDdata.className).toEqual("Order")
|
|
||||||
expect(orderMetaDdata.path).toEqual("Order")
|
|
||||||
expect(orderMetaDdata.properties).toEqual({
|
|
||||||
amount: {
|
|
||||||
reference: "scalar",
|
|
||||||
type: "number",
|
|
||||||
columnType: "integer",
|
|
||||||
name: "amount",
|
|
||||||
nullable: false,
|
|
||||||
getter: false,
|
|
||||||
setter: false,
|
|
||||||
},
|
|
||||||
user: {
|
|
||||||
reference: "m:1",
|
|
||||||
name: "user",
|
|
||||||
entity: "User",
|
|
||||||
persist: false,
|
|
||||||
},
|
|
||||||
user_id: {
|
|
||||||
columnType: "text",
|
|
||||||
entity: "User",
|
|
||||||
fieldName: "user_id",
|
|
||||||
mapToPk: true,
|
|
||||||
name: "user_id",
|
|
||||||
nullable: false,
|
|
||||||
onDelete: "cascade",
|
|
||||||
reference: "m:1",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
test("define hasOne relationship on both sides", () => {
|
|
||||||
const model = new EntityBuilder()
|
|
||||||
const user = model.define("user", {
|
|
||||||
id: model.number(),
|
|
||||||
email: model.text(),
|
|
||||||
profile: model.hasOne(() => profile),
|
|
||||||
})
|
|
||||||
|
|
||||||
const profile = model.define("profile", {
|
|
||||||
id: model.number(),
|
|
||||||
user_id: model.number(),
|
|
||||||
user: model.hasOne(() => user),
|
|
||||||
})
|
|
||||||
|
|
||||||
const User = createMikrORMEntity(user)
|
|
||||||
const Profile = createMikrORMEntity(profile)
|
|
||||||
|
|
||||||
expectTypeOf(new User()).toMatchTypeOf<{
|
|
||||||
id: number
|
|
||||||
email: string
|
|
||||||
profile: EntityConstructor<{
|
|
||||||
id: number
|
|
||||||
user_id: number
|
|
||||||
user: EntityConstructor<{
|
|
||||||
id: number
|
|
||||||
email: string
|
|
||||||
}>
|
|
||||||
}>
|
|
||||||
}>()
|
|
||||||
|
|
||||||
const metaData = MetadataStorage.getMetadataFromDecorator(User)
|
|
||||||
|
|
||||||
expect(metaData.className).toEqual("User")
|
|
||||||
expect(metaData.path).toEqual("User")
|
|
||||||
expect(metaData.properties).toEqual({
|
|
||||||
id: {
|
|
||||||
reference: "scalar",
|
|
||||||
type: "number",
|
|
||||||
columnType: "integer",
|
|
||||||
name: "id",
|
|
||||||
nullable: false,
|
|
||||||
getter: false,
|
|
||||||
setter: false,
|
|
||||||
},
|
|
||||||
email: {
|
|
||||||
reference: "scalar",
|
|
||||||
type: "string",
|
|
||||||
columnType: "text",
|
|
||||||
name: "email",
|
|
||||||
nullable: false,
|
|
||||||
getter: false,
|
|
||||||
setter: false,
|
|
||||||
},
|
|
||||||
profile: {
|
|
||||||
name: "profile",
|
|
||||||
cascade: ["persist"],
|
|
||||||
entity: "Profile",
|
|
||||||
nullable: false,
|
|
||||||
onDelete: "cascade",
|
|
||||||
owner: true,
|
|
||||||
reference: "1:1",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const profileMetadata = MetadataStorage.getMetadataFromDecorator(Profile)
|
|
||||||
expect(profileMetadata.className).toEqual("Profile")
|
|
||||||
expect(profileMetadata.path).toEqual("Profile")
|
|
||||||
expect(profileMetadata.properties).toEqual({
|
|
||||||
id: {
|
|
||||||
reference: "scalar",
|
|
||||||
type: "number",
|
|
||||||
columnType: "integer",
|
|
||||||
name: "id",
|
|
||||||
nullable: false,
|
|
||||||
getter: false,
|
|
||||||
setter: false,
|
|
||||||
},
|
|
||||||
user: {
|
|
||||||
cascade: ["persist"],
|
|
||||||
entity: "User",
|
|
||||||
name: "user",
|
|
||||||
nullable: false,
|
|
||||||
onDelete: "cascade",
|
|
||||||
owner: true,
|
|
||||||
reference: "1:1",
|
|
||||||
},
|
|
||||||
user_id: {
|
|
||||||
columnType: "integer",
|
|
||||||
getter: false,
|
|
||||||
name: "user_id",
|
|
||||||
nullable: false,
|
|
||||||
reference: "scalar",
|
|
||||||
setter: false,
|
|
||||||
type: "number",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
test("define manyToMany relationships", () => {
|
|
||||||
const model = new EntityBuilder()
|
|
||||||
const user = model.define("user", {
|
|
||||||
id: model.number(),
|
|
||||||
email: model.text(),
|
|
||||||
books: model.manyToMany(() => book),
|
|
||||||
})
|
|
||||||
|
|
||||||
const book = model.define("book", {
|
|
||||||
id: model.number(),
|
|
||||||
title: model.text(),
|
|
||||||
authors: model.manyToMany(() => user),
|
|
||||||
})
|
|
||||||
|
|
||||||
const User = createMikrORMEntity(user)
|
|
||||||
const Book = createMikrORMEntity(book)
|
|
||||||
|
|
||||||
expectTypeOf(new User()).toMatchTypeOf<{
|
|
||||||
id: number
|
|
||||||
email: string
|
|
||||||
books: EntityConstructor<{
|
|
||||||
id: number
|
|
||||||
title: string
|
|
||||||
authors: EntityConstructor<{
|
|
||||||
id: number
|
|
||||||
email: string
|
|
||||||
}>
|
|
||||||
}>
|
|
||||||
}>()
|
|
||||||
|
|
||||||
const metaData = MetadataStorage.getMetadataFromDecorator(User)
|
|
||||||
|
|
||||||
expect(metaData.className).toEqual("User")
|
|
||||||
expect(metaData.path).toEqual("User")
|
|
||||||
expect(metaData.properties).toEqual({
|
|
||||||
id: {
|
|
||||||
reference: "scalar",
|
|
||||||
type: "number",
|
|
||||||
columnType: "integer",
|
|
||||||
name: "id",
|
|
||||||
nullable: false,
|
|
||||||
getter: false,
|
|
||||||
setter: false,
|
|
||||||
},
|
|
||||||
email: {
|
|
||||||
reference: "scalar",
|
|
||||||
type: "string",
|
|
||||||
columnType: "text",
|
|
||||||
name: "email",
|
|
||||||
nullable: false,
|
|
||||||
getter: false,
|
|
||||||
setter: false,
|
|
||||||
},
|
|
||||||
books: {
|
|
||||||
name: "books",
|
|
||||||
entity: "Book",
|
|
||||||
mappedBy: expect.any(Function),
|
|
||||||
reference: "m:n",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const bookMetaData = MetadataStorage.getMetadataFromDecorator(Book)
|
|
||||||
expect(bookMetaData.className).toEqual("Book")
|
|
||||||
expect(bookMetaData.path).toEqual("Book")
|
|
||||||
expect(bookMetaData.properties).toEqual({
|
|
||||||
id: {
|
|
||||||
reference: "scalar",
|
|
||||||
type: "number",
|
|
||||||
columnType: "integer",
|
|
||||||
name: "id",
|
|
||||||
nullable: false,
|
|
||||||
getter: false,
|
|
||||||
setter: false,
|
|
||||||
},
|
|
||||||
authors: {
|
|
||||||
entity: "User",
|
|
||||||
name: "authors",
|
|
||||||
reference: "m:n",
|
|
||||||
mappedBy: expect.any(Function),
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
columnType: "text",
|
|
||||||
getter: false,
|
|
||||||
name: "title",
|
|
||||||
nullable: false,
|
|
||||||
reference: "scalar",
|
|
||||||
setter: false,
|
|
||||||
type: "string",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
File renamed without changes.
+1
-2
@@ -1,6 +1,6 @@
|
|||||||
import { expectTypeOf } from "expect-type"
|
import { expectTypeOf } from "expect-type"
|
||||||
import { HasMany } from "../relations/has_many"
|
|
||||||
import { TextSchema } from "../schema/text"
|
import { TextSchema } from "../schema/text"
|
||||||
|
import { HasMany } from "../relations/has-many"
|
||||||
|
|
||||||
describe("HasMany relationship", () => {
|
describe("HasMany relationship", () => {
|
||||||
test("define hasMany relationship", () => {
|
test("define hasMany relationship", () => {
|
||||||
@@ -17,7 +17,6 @@ describe("HasMany relationship", () => {
|
|||||||
type: "hasMany",
|
type: "hasMany",
|
||||||
nullable: false,
|
nullable: false,
|
||||||
entity: entityRef,
|
entity: entityRef,
|
||||||
options: {},
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
+5
-23
@@ -1,21 +1,15 @@
|
|||||||
import { expectTypeOf } from "expect-type"
|
import { expectTypeOf } from "expect-type"
|
||||||
import { TextSchema } from "../schema/text"
|
import { TextSchema } from "../schema/text"
|
||||||
import { BaseRelationship } from "../relations/base"
|
import { HasOne } from "../relations/has-one"
|
||||||
|
|
||||||
describe("Base relationship", () => {
|
|
||||||
test("define a custom relationship", () => {
|
|
||||||
class HasOne<T> extends BaseRelationship<T> {
|
|
||||||
protected relationshipType: "hasOne" | "hasMany" | "manyToMany" = "hasOne"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
describe("HasOne relationship", () => {
|
||||||
|
test("define hasOne relationship", () => {
|
||||||
const user = {
|
const user = {
|
||||||
username: new TextSchema(),
|
username: new TextSchema(),
|
||||||
}
|
}
|
||||||
|
|
||||||
const entityRef = () => user
|
const entityRef = () => user
|
||||||
const relationship = new HasOne(entityRef, {
|
const relationship = new HasOne(entityRef, {})
|
||||||
foreignKey: "user_id",
|
|
||||||
})
|
|
||||||
|
|
||||||
expectTypeOf(relationship["$dataType"]).toEqualTypeOf<() => typeof user>()
|
expectTypeOf(relationship["$dataType"]).toEqualTypeOf<() => typeof user>()
|
||||||
expect(relationship.parse("user")).toEqual({
|
expect(relationship.parse("user")).toEqual({
|
||||||
@@ -23,25 +17,16 @@ describe("Base relationship", () => {
|
|||||||
type: "hasOne",
|
type: "hasOne",
|
||||||
nullable: false,
|
nullable: false,
|
||||||
entity: entityRef,
|
entity: entityRef,
|
||||||
options: {
|
|
||||||
foreignKey: "user_id",
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
test("mark relationship as nullable", () => {
|
test("mark relationship as nullable", () => {
|
||||||
class HasOne<T> extends BaseRelationship<T> {
|
|
||||||
protected relationshipType: "hasOne" | "hasMany" | "manyToMany" = "hasOne"
|
|
||||||
}
|
|
||||||
|
|
||||||
const user = {
|
const user = {
|
||||||
username: new TextSchema(),
|
username: new TextSchema(),
|
||||||
}
|
}
|
||||||
|
|
||||||
const entityRef = () => user
|
const entityRef = () => user
|
||||||
const relationship = new HasOne(entityRef, {
|
const relationship = new HasOne(entityRef, {}).nullable()
|
||||||
foreignKey: "user_id",
|
|
||||||
}).nullable()
|
|
||||||
|
|
||||||
expectTypeOf(relationship["$dataType"]).toEqualTypeOf<
|
expectTypeOf(relationship["$dataType"]).toEqualTypeOf<
|
||||||
(() => typeof user) | null
|
(() => typeof user) | null
|
||||||
@@ -51,9 +36,6 @@ describe("Base relationship", () => {
|
|||||||
type: "hasOne",
|
type: "hasOne",
|
||||||
nullable: true,
|
nullable: true,
|
||||||
entity: entityRef,
|
entity: entityRef,
|
||||||
options: {
|
|
||||||
foreignKey: "user_id",
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
File renamed without changes.
+1
-2
@@ -1,6 +1,6 @@
|
|||||||
import { expectTypeOf } from "expect-type"
|
import { expectTypeOf } from "expect-type"
|
||||||
import { TextSchema } from "../schema/text"
|
import { TextSchema } from "../schema/text"
|
||||||
import { ManyToMany } from "../relations/many_to_many"
|
import { ManyToMany } from "../relations/many-to-many"
|
||||||
|
|
||||||
describe("ManyToMany relationship", () => {
|
describe("ManyToMany relationship", () => {
|
||||||
test("define manyToMany relationship", () => {
|
test("define manyToMany relationship", () => {
|
||||||
@@ -17,7 +17,6 @@ describe("ManyToMany relationship", () => {
|
|||||||
type: "manyToMany",
|
type: "manyToMany",
|
||||||
nullable: false,
|
nullable: false,
|
||||||
entity: entityRef,
|
entity: entityRef,
|
||||||
options: {},
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
File renamed without changes.
File renamed without changes.
+16
-17
@@ -2,14 +2,14 @@ import { DmlEntity } from "./entity"
|
|||||||
import { TextSchema } from "./schema/text"
|
import { TextSchema } from "./schema/text"
|
||||||
import { EnumSchema } from "./schema/enum"
|
import { EnumSchema } from "./schema/enum"
|
||||||
import { JSONSchema } from "./schema/json"
|
import { JSONSchema } from "./schema/json"
|
||||||
import { HasOne } from "./relations/has_one"
|
import { HasOne } from "./relations/has-one"
|
||||||
import { HasMany } from "./relations/has_many"
|
import { HasMany } from "./relations/has-many"
|
||||||
import { NumberSchema } from "./schema/number"
|
import { NumberSchema } from "./schema/number"
|
||||||
import { BooleanSchema } from "./schema/boolean"
|
import { BooleanSchema } from "./schema/boolean"
|
||||||
import { DateTimeSchema } from "./schema/date_time"
|
import { BelongsTo } from "./relations/belongs-to"
|
||||||
import { ManyToMany } from "./relations/many_to_many"
|
import { DateTimeSchema } from "./schema/date-time"
|
||||||
import { RelationshipType, SchemaType } from "./types"
|
import { ManyToMany } from "./relations/many-to-many"
|
||||||
import { HasOneThroughMany } from "./relations/has_one_through_many"
|
import type { RelationshipOptions, RelationshipType, SchemaType } from "./types"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Entity builder exposes the API to create an entity and define its
|
* Entity builder exposes the API to create an entity and define its
|
||||||
@@ -80,10 +80,17 @@ export class EntityBuilder {
|
|||||||
* You may use the "belongsTo" relationship to define the inverse
|
* You may use the "belongsTo" relationship to define the inverse
|
||||||
* of the "hasOne" relationship
|
* of the "hasOne" relationship
|
||||||
*/
|
*/
|
||||||
hasOne<T>(entityBuilder: T, options?: Record<string, any>) {
|
hasOne<T>(entityBuilder: T, options?: RelationshipOptions) {
|
||||||
return new HasOne<T>(entityBuilder, options || {})
|
return new HasOne<T>(entityBuilder, options || {})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define inverse of "hasOne" and "hasMany" relationship.
|
||||||
|
*/
|
||||||
|
belongsTo<T>(entityBuilder: T, options?: RelationshipOptions) {
|
||||||
|
return new BelongsTo<T>(entityBuilder, options || {})
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Has many relationship defines a relationship between two entities
|
* Has many relationship defines a relationship between two entities
|
||||||
* where the owner of the relationship has many instance of the
|
* where the owner of the relationship has many instance of the
|
||||||
@@ -94,18 +101,10 @@ export class EntityBuilder {
|
|||||||
* - A user "hasMany" books
|
* - A user "hasMany" books
|
||||||
* - A user "hasMany" addresses
|
* - A user "hasMany" addresses
|
||||||
*/
|
*/
|
||||||
hasMany<T>(entityBuilder: T, options?: Record<string, any>) {
|
hasMany<T>(entityBuilder: T, options?: RelationshipOptions) {
|
||||||
return new HasMany<T>(entityBuilder, options || {})
|
return new HasMany<T>(entityBuilder, options || {})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Define a hasOneThroughMany relationship between two entities.
|
|
||||||
* @todo Remove in favor of "belongTo"
|
|
||||||
*/
|
|
||||||
hasOneThroughMany<T>(entityBuilder: T, options?: Record<string, any>) {
|
|
||||||
return new HasOneThroughMany<T>(entityBuilder, options || {})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ManyToMany relationship defines a relationship between two entities
|
* ManyToMany relationship defines a relationship between two entities
|
||||||
* where the owner of the relationship has many instance of the
|
* where the owner of the relationship has many instance of the
|
||||||
@@ -117,7 +116,7 @@ export class EntityBuilder {
|
|||||||
* relationship requires a pivot table to establish a many to many
|
* relationship requires a pivot table to establish a many to many
|
||||||
* relationship between two entities
|
* relationship between two entities
|
||||||
*/
|
*/
|
||||||
manyToMany<T>(entityBuilder: T, options?: Record<string, any>) {
|
manyToMany<T>(entityBuilder: T, options?: RelationshipOptions) {
|
||||||
return new ManyToMany<T>(entityBuilder, options || {})
|
return new ManyToMany<T>(entityBuilder, options || {})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+133
-36
@@ -1,11 +1,10 @@
|
|||||||
import {
|
import {
|
||||||
|
Enum,
|
||||||
Entity,
|
Entity,
|
||||||
OneToMany,
|
OneToMany,
|
||||||
Property,
|
Property,
|
||||||
OneToOne,
|
OneToOne,
|
||||||
ManyToMany,
|
ManyToMany,
|
||||||
Enum,
|
|
||||||
Cascade,
|
|
||||||
ManyToOne,
|
ManyToOne,
|
||||||
} from "@mikro-orm/core"
|
} from "@mikro-orm/core"
|
||||||
import { DmlEntity } from "../entity"
|
import { DmlEntity } from "../entity"
|
||||||
@@ -15,11 +14,13 @@ import type {
|
|||||||
Infer,
|
Infer,
|
||||||
SchemaType,
|
SchemaType,
|
||||||
KnownDataTypes,
|
KnownDataTypes,
|
||||||
RelationshipType,
|
|
||||||
SchemaMetadata,
|
SchemaMetadata,
|
||||||
|
RelationshipType,
|
||||||
EntityConstructor,
|
EntityConstructor,
|
||||||
RelationshipMetadata,
|
RelationshipMetadata,
|
||||||
} from "../types"
|
} from "../types"
|
||||||
|
import { HasOne } from "../relations/has-one"
|
||||||
|
import { HasMany } from "../relations/has-many"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DML entity data types to PostgreSQL data types via
|
* DML entity data types to PostgreSQL data types via
|
||||||
@@ -88,6 +89,130 @@ function defineProperty(
|
|||||||
})(MikroORMEntity.prototype, field.fieldName)
|
})(MikroORMEntity.prototype, field.fieldName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines has one relationship on the Mikro ORM entity.
|
||||||
|
*/
|
||||||
|
function defineHasOneRelationship(
|
||||||
|
MikroORMEntity: EntityConstructor<any>,
|
||||||
|
relationship: RelationshipMetadata,
|
||||||
|
relatedEntity: DmlEntity<
|
||||||
|
Record<string, SchemaType<any> | RelationshipType<any>>
|
||||||
|
>
|
||||||
|
) {
|
||||||
|
const relatedModelName = upperCaseFirst(relatedEntity.name)
|
||||||
|
OneToOne({
|
||||||
|
entity: relatedModelName,
|
||||||
|
nullable: relationship.nullable,
|
||||||
|
mappedBy: relationship.mappedBy as any,
|
||||||
|
})(MikroORMEntity.prototype, relationship.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines has many relationship on the Mikro ORM entity
|
||||||
|
*/
|
||||||
|
function defineHasManyRelationship(
|
||||||
|
MikroORMEntity: EntityConstructor<any>,
|
||||||
|
relationship: RelationshipMetadata,
|
||||||
|
relatedEntity: DmlEntity<
|
||||||
|
Record<string, SchemaType<any> | RelationshipType<any>>
|
||||||
|
>
|
||||||
|
) {
|
||||||
|
const relatedModelName = upperCaseFirst(relatedEntity.name)
|
||||||
|
OneToMany({
|
||||||
|
entity: relatedModelName,
|
||||||
|
orphanRemoval: true,
|
||||||
|
mappedBy: relationship.mappedBy || camelToSnakeCase(MikroORMEntity.name),
|
||||||
|
})(MikroORMEntity.prototype, relationship.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines belongs to relationship on the Mikro ORM entity. The belongsTo
|
||||||
|
* relationship inspects the related entity for the other side of
|
||||||
|
* the relationship and then uses one of the following Mikro ORM
|
||||||
|
* relationship.
|
||||||
|
*
|
||||||
|
* - OneToOne: When the other side uses "hasOne" with "owner: true"
|
||||||
|
* - ManyToOne: When the other side uses "hasMany"
|
||||||
|
*/
|
||||||
|
function defineBelongsToRelationship(
|
||||||
|
MikroORMEntity: EntityConstructor<any>,
|
||||||
|
relationship: RelationshipMetadata,
|
||||||
|
relatedEntity: DmlEntity<
|
||||||
|
Record<string, SchemaType<any> | RelationshipType<any>>
|
||||||
|
>
|
||||||
|
) {
|
||||||
|
const mappedBy =
|
||||||
|
relationship.mappedBy || camelToSnakeCase(MikroORMEntity.name)
|
||||||
|
const otherSideRelation = relatedEntity.schema[mappedBy]
|
||||||
|
const relatedModelName = upperCaseFirst(relatedEntity.name)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensure the mapped by is defined as relationship on the other side
|
||||||
|
*/
|
||||||
|
if (!otherSideRelation) {
|
||||||
|
throw new Error(
|
||||||
|
`Missing property "${mappedBy}" on "${relatedEntity.name}" entity. Make sure to define it as a relationship`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Otherside is a has many. Hence we should defined a ManyToOne
|
||||||
|
*/
|
||||||
|
if (otherSideRelation instanceof HasMany) {
|
||||||
|
ManyToOne({
|
||||||
|
entity: relatedModelName,
|
||||||
|
columnType: "text",
|
||||||
|
mapToPk: true,
|
||||||
|
fieldName: camelToSnakeCase(`${relationship.name}Id`),
|
||||||
|
nullable: relationship.nullable,
|
||||||
|
})(MikroORMEntity.prototype, camelToSnakeCase(`${relationship.name}Id`))
|
||||||
|
|
||||||
|
ManyToOne({
|
||||||
|
entity: relatedModelName,
|
||||||
|
persist: false,
|
||||||
|
})(MikroORMEntity.prototype, relationship.name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Otherside is a has one. Hence we should defined a OneToOne
|
||||||
|
*/
|
||||||
|
if (otherSideRelation instanceof HasOne) {
|
||||||
|
const relatedModelName = upperCaseFirst(relatedEntity.name)
|
||||||
|
OneToOne({
|
||||||
|
entity: relatedModelName,
|
||||||
|
nullable: relationship.nullable,
|
||||||
|
mappedBy: mappedBy,
|
||||||
|
owner: true,
|
||||||
|
})(MikroORMEntity.prototype, relationship.name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Other side is some unsupported data-type
|
||||||
|
*/
|
||||||
|
throw new Error(
|
||||||
|
`Invalid relationship reference for "${mappedBy}" on "${relatedEntity.name}" entity. Make sure to define a hasOne or hasMany relationship`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a many to many relationship on the Mikro ORM entity
|
||||||
|
*/
|
||||||
|
function defineManyToManyRelationship(
|
||||||
|
MikroORMEntity: EntityConstructor<any>,
|
||||||
|
relationship: RelationshipMetadata,
|
||||||
|
relatedEntity: DmlEntity<
|
||||||
|
Record<string, SchemaType<any> | RelationshipType<any>>
|
||||||
|
>
|
||||||
|
) {
|
||||||
|
const relatedModelName = upperCaseFirst(relatedEntity.name)
|
||||||
|
ManyToMany({
|
||||||
|
entity: relatedModelName,
|
||||||
|
mappedBy: relationship.mappedBy as any,
|
||||||
|
})(MikroORMEntity.prototype, relationship.name)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines a DML entity schema field as a Mikro ORM relationship
|
* Defines a DML entity schema field as a Mikro ORM relationship
|
||||||
*/
|
*/
|
||||||
@@ -134,44 +259,16 @@ function defineRelationship(
|
|||||||
*/
|
*/
|
||||||
switch (relationship.type) {
|
switch (relationship.type) {
|
||||||
case "hasOne":
|
case "hasOne":
|
||||||
OneToOne({
|
defineHasOneRelationship(MikroORMEntity, relationship, relatedEntity)
|
||||||
entity: relatedModelName,
|
|
||||||
cascade: [Cascade.PERSIST], // accept via options
|
|
||||||
owner: true, // accept via options
|
|
||||||
onDelete: "cascade", // accept via options
|
|
||||||
nullable: false, // accept via options
|
|
||||||
})(MikroORMEntity.prototype, relationship.name)
|
|
||||||
break
|
break
|
||||||
case "hasMany":
|
case "hasMany":
|
||||||
OneToMany({
|
defineHasManyRelationship(MikroORMEntity, relationship, relatedEntity)
|
||||||
entity: relatedModelName,
|
|
||||||
cascade: [Cascade.PERSIST], // accept via options
|
|
||||||
orphanRemoval: true,
|
|
||||||
mappedBy: (related: any) =>
|
|
||||||
related[camelToSnakeCase(MikroORMEntity.name)], // optionally via options,
|
|
||||||
})(MikroORMEntity.prototype, relationship.name)
|
|
||||||
break
|
break
|
||||||
case "hasOneThroughMany":
|
case "belongsTo":
|
||||||
ManyToOne({
|
defineBelongsToRelationship(MikroORMEntity, relationship, relatedEntity)
|
||||||
entity: relatedModelName,
|
|
||||||
columnType: "text", // infer from primary key data-type
|
|
||||||
mapToPk: true,
|
|
||||||
nullable: false, // accept via options
|
|
||||||
fieldName: camelToSnakeCase(`${relationship.name}Id`),
|
|
||||||
onDelete: "cascade", // accept via options
|
|
||||||
})(MikroORMEntity.prototype, camelToSnakeCase(`${relationship.name}Id`))
|
|
||||||
|
|
||||||
ManyToOne({
|
|
||||||
entity: relatedModelName,
|
|
||||||
persist: false,
|
|
||||||
})(MikroORMEntity.prototype, relationship.name)
|
|
||||||
break
|
break
|
||||||
case "manyToMany":
|
case "manyToMany":
|
||||||
ManyToMany({
|
defineManyToManyRelationship(MikroORMEntity, relationship, relatedEntity)
|
||||||
entity: relatedModelName,
|
|
||||||
mappedBy: (related: any) =>
|
|
||||||
related[camelToSnakeCase(MikroORMEntity.name)], // optionally via options,
|
|
||||||
})(MikroORMEntity.prototype, relationship.name)
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,12 @@
|
|||||||
import { MaybeFieldMetadata } from "../types"
|
import { RelationshipType, SchemaType } from "../types"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Nullable modifier marks a schema node as nullable
|
* Nullable modifier marks a schema node as nullable
|
||||||
*/
|
*/
|
||||||
export class NullableModifier<T> {
|
export class NullableModifier<
|
||||||
|
T,
|
||||||
|
Schema extends SchemaType<T> | RelationshipType<T>
|
||||||
|
> {
|
||||||
/**
|
/**
|
||||||
* A type-only property to infer the JavScript data-type
|
* A type-only property to infer the JavScript data-type
|
||||||
* of the schema property
|
* of the schema property
|
||||||
@@ -14,20 +17,18 @@ export class NullableModifier<T> {
|
|||||||
* The parent schema on which the nullable modifier is
|
* The parent schema on which the nullable modifier is
|
||||||
* applied
|
* applied
|
||||||
*/
|
*/
|
||||||
#schema: {
|
#schema: Schema
|
||||||
parse(fieldName: string): MaybeFieldMetadata
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(schema: { parse(fieldName: string): MaybeFieldMetadata }) {
|
constructor(schema: Schema) {
|
||||||
this.#schema = schema
|
this.#schema = schema
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the serialized metadata
|
* Returns the serialized metadata
|
||||||
*/
|
*/
|
||||||
parse(fieldName: string) {
|
parse(fieldName: string): ReturnType<Schema["parse"]> {
|
||||||
const schema = this.#schema.parse(fieldName)
|
const schema = this.#schema.parse(fieldName)
|
||||||
schema.nullable = true
|
schema.nullable = true
|
||||||
return schema
|
return schema as ReturnType<Schema["parse"]>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
import { NullableModifier } from "../modifiers/nullable"
|
import {
|
||||||
import { RelationshipMetadata, RelationshipType } from "../types"
|
RelationshipMetadata,
|
||||||
|
RelationshipOptions,
|
||||||
|
RelationshipType,
|
||||||
|
} from "../types"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The BaseRelationship encapsulates the repetitive parts of defining
|
* The BaseRelationship encapsulates the repetitive parts of defining
|
||||||
@@ -7,7 +10,8 @@ import { RelationshipMetadata, RelationshipType } from "../types"
|
|||||||
*/
|
*/
|
||||||
export abstract class BaseRelationship<T> implements RelationshipType<T> {
|
export abstract class BaseRelationship<T> implements RelationshipType<T> {
|
||||||
#referencedEntity: T
|
#referencedEntity: T
|
||||||
#options: Record<string, any>
|
|
||||||
|
protected options: RelationshipOptions
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The relationship type.
|
* The relationship type.
|
||||||
@@ -20,16 +24,9 @@ export abstract class BaseRelationship<T> implements RelationshipType<T> {
|
|||||||
*/
|
*/
|
||||||
declare $dataType: T
|
declare $dataType: T
|
||||||
|
|
||||||
constructor(referencedEntity: T, options: Record<string, any>) {
|
constructor(referencedEntity: T, options: RelationshipOptions) {
|
||||||
this.#referencedEntity = referencedEntity
|
this.#referencedEntity = referencedEntity
|
||||||
this.#options = options
|
this.options = options
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply nullable modifier on the schema
|
|
||||||
*/
|
|
||||||
nullable() {
|
|
||||||
return new NullableModifier<T>(this)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -39,8 +36,8 @@ export abstract class BaseRelationship<T> implements RelationshipType<T> {
|
|||||||
return {
|
return {
|
||||||
name: relationshipName,
|
name: relationshipName,
|
||||||
nullable: false,
|
nullable: false,
|
||||||
|
mappedBy: this.options.mappedBy,
|
||||||
entity: this.#referencedEntity,
|
entity: this.#referencedEntity,
|
||||||
options: this.#options,
|
|
||||||
type: this.relationshipType,
|
type: this.relationshipType,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { BaseRelationship } from "./base"
|
||||||
|
import { RelationshipMetadata } from "../types"
|
||||||
|
import { NullableModifier } from "../modifiers/nullable"
|
||||||
|
|
||||||
|
export class BelongsTo<T> extends BaseRelationship<T> {
|
||||||
|
protected relationshipType: RelationshipMetadata["type"] = "belongsTo"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply nullable modifier on the schema
|
||||||
|
*/
|
||||||
|
nullable() {
|
||||||
|
return new NullableModifier<T, BelongsTo<T>>(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
File renamed without changes.
+8
@@ -1,4 +1,5 @@
|
|||||||
import { BaseRelationship } from "./base"
|
import { BaseRelationship } from "./base"
|
||||||
|
import { NullableModifier } from "../modifiers/nullable"
|
||||||
import { RelationshipMetadata } from "../types"
|
import { RelationshipMetadata } from "../types"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -13,4 +14,11 @@ import { RelationshipMetadata } from "../types"
|
|||||||
*/
|
*/
|
||||||
export class HasOne<T> extends BaseRelationship<T> {
|
export class HasOne<T> extends BaseRelationship<T> {
|
||||||
protected relationshipType: RelationshipMetadata["type"] = "hasOne"
|
protected relationshipType: RelationshipMetadata["type"] = "hasOne"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply nullable modifier on the schema
|
||||||
|
*/
|
||||||
|
nullable() {
|
||||||
|
return new NullableModifier<T, HasOne<T>>(this)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
import { BaseRelationship } from "./base"
|
|
||||||
import { RelationshipMetadata } from "../types"
|
|
||||||
|
|
||||||
export class HasOneThroughMany<T> extends BaseRelationship<T> {
|
|
||||||
protected relationshipType: RelationshipMetadata["type"] = "hasOneThroughMany"
|
|
||||||
}
|
|
||||||
File renamed without changes.
@@ -26,7 +26,7 @@ export abstract class BaseSchema<T> implements SchemaType<T> {
|
|||||||
* Apply nullable modifier on the schema
|
* Apply nullable modifier on the schema
|
||||||
*/
|
*/
|
||||||
nullable() {
|
nullable() {
|
||||||
return new NullableModifier<T>(this)
|
return new NullableModifier<T, this>(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
File renamed without changes.
@@ -11,6 +11,16 @@ export type KnownDataTypes =
|
|||||||
| "dateTime"
|
| "dateTime"
|
||||||
| "json"
|
| "json"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The available on Delete actions
|
||||||
|
*/
|
||||||
|
export type OnDeleteActions =
|
||||||
|
| "cascade"
|
||||||
|
| "no action"
|
||||||
|
| "set null"
|
||||||
|
| "set default"
|
||||||
|
| (string & {})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Any field that contains "nullable" and "optional" properties
|
* Any field that contains "nullable" and "optional" properties
|
||||||
* in their metadata are qualified as maybe fields.
|
* in their metadata are qualified as maybe fields.
|
||||||
@@ -49,15 +59,22 @@ export type SchemaType<T> = {
|
|||||||
parse(fieldName: string): SchemaMetadata
|
parse(fieldName: string): SchemaMetadata
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Options accepted by all the relationships
|
||||||
|
*/
|
||||||
|
export type RelationshipOptions = {
|
||||||
|
mappedBy?: string
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The meta-data returned by the relationship parse
|
* The meta-data returned by the relationship parse
|
||||||
* method
|
* method
|
||||||
*/
|
*/
|
||||||
export type RelationshipMetadata = MaybeFieldMetadata & {
|
export type RelationshipMetadata = MaybeFieldMetadata & {
|
||||||
name: string
|
name: string
|
||||||
type: "hasOne" | "hasMany" | "hasOneThroughMany" | "manyToMany"
|
type: "hasOne" | "hasMany" | "belongsTo" | "manyToMany"
|
||||||
entity: unknown
|
entity: unknown
|
||||||
options: Record<string, any>
|
mappedBy?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -86,6 +103,8 @@ export type Infer<T> = T extends DmlEntity<infer Schema>
|
|||||||
? EntityConstructor<{
|
? EntityConstructor<{
|
||||||
[K in keyof Schema]: Schema[K]["$dataType"] extends () => infer R
|
[K in keyof Schema]: Schema[K]["$dataType"] extends () => infer R
|
||||||
? Infer<R>
|
? Infer<R>
|
||||||
|
: Schema[K]["$dataType"] extends (() => infer R) | null
|
||||||
|
? Infer<R> | null
|
||||||
: Schema[K]["$dataType"]
|
: Schema[K]["$dataType"]
|
||||||
}>
|
}>
|
||||||
: never
|
: never
|
||||||
Reference in new issue
Block a user