Code cleanup and add support for default values and nullable relationships (#7687)
This commit is contained in:
@@ -21,6 +21,35 @@ describe("Base relationship", () => {
|
||||
expect(relationship.parse("user")).toEqual({
|
||||
name: "user",
|
||||
type: "hasOne",
|
||||
nullable: false,
|
||||
entity: entityRef,
|
||||
options: {
|
||||
foreignKey: "user_id",
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test("mark relationship as nullable", () => {
|
||||
class HasOne<T> extends BaseRelationship<T> {
|
||||
protected relationshipType: "hasOne" | "hasMany" | "manyToMany" = "hasOne"
|
||||
}
|
||||
|
||||
const user = {
|
||||
username: new TextSchema(),
|
||||
}
|
||||
|
||||
const entityRef = () => user
|
||||
const relationship = new HasOne(entityRef, {
|
||||
foreignKey: "user_id",
|
||||
}).nullable()
|
||||
|
||||
expectTypeOf(relationship["$dataType"]).toEqualTypeOf<
|
||||
(() => typeof user) | null
|
||||
>()
|
||||
expect(relationship.parse("user")).toEqual({
|
||||
name: "user",
|
||||
type: "hasOne",
|
||||
nullable: true,
|
||||
entity: entityRef,
|
||||
options: {
|
||||
foreignKey: "user_id",
|
||||
|
||||
@@ -6,7 +6,7 @@ describe("Base schema", () => {
|
||||
test("create a schema type from base schema", () => {
|
||||
class StringSchema extends BaseSchema<string> {
|
||||
protected dataType: SchemaMetadata["dataType"] = {
|
||||
name: "string",
|
||||
name: "text",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,10 +16,9 @@ describe("Base schema", () => {
|
||||
expect(schema.parse("username")).toEqual({
|
||||
fieldName: "username",
|
||||
dataType: {
|
||||
name: "string",
|
||||
name: "text",
|
||||
},
|
||||
nullable: false,
|
||||
optional: false,
|
||||
indexes: [],
|
||||
relationships: [],
|
||||
})
|
||||
@@ -28,7 +27,7 @@ describe("Base schema", () => {
|
||||
test("apply nullable modifier", () => {
|
||||
class StringSchema extends BaseSchema<string> {
|
||||
protected dataType: SchemaMetadata["dataType"] = {
|
||||
name: "string",
|
||||
name: "text",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,54 +37,31 @@ describe("Base schema", () => {
|
||||
expect(schema.parse("username")).toEqual({
|
||||
fieldName: "username",
|
||||
dataType: {
|
||||
name: "string",
|
||||
name: "text",
|
||||
},
|
||||
nullable: true,
|
||||
optional: false,
|
||||
indexes: [],
|
||||
relationships: [],
|
||||
})
|
||||
})
|
||||
|
||||
test("apply optional modifier", () => {
|
||||
test("define default value", () => {
|
||||
class StringSchema extends BaseSchema<string> {
|
||||
protected dataType: SchemaMetadata["dataType"] = {
|
||||
name: "string",
|
||||
name: "text",
|
||||
}
|
||||
}
|
||||
|
||||
const schema = new StringSchema().optional()
|
||||
const schema = new StringSchema().default("foo")
|
||||
|
||||
expectTypeOf(schema["$dataType"]).toEqualTypeOf<string | undefined>()
|
||||
expectTypeOf(schema["$dataType"]).toEqualTypeOf<string>()
|
||||
expect(schema.parse("username")).toEqual({
|
||||
fieldName: "username",
|
||||
dataType: {
|
||||
name: "string",
|
||||
name: "text",
|
||||
},
|
||||
defaultValue: "foo",
|
||||
nullable: false,
|
||||
optional: true,
|
||||
indexes: [],
|
||||
relationships: [],
|
||||
})
|
||||
})
|
||||
|
||||
test("apply optional + nullable modifier", () => {
|
||||
class StringSchema extends BaseSchema<string> {
|
||||
protected dataType: SchemaMetadata["dataType"] = {
|
||||
name: "string",
|
||||
}
|
||||
}
|
||||
|
||||
const schema = new StringSchema().optional().nullable()
|
||||
|
||||
expectTypeOf(schema["$dataType"]).toEqualTypeOf<string | undefined | null>()
|
||||
expect(schema.parse("username")).toEqual({
|
||||
fieldName: "username",
|
||||
dataType: {
|
||||
name: "string",
|
||||
},
|
||||
nullable: true,
|
||||
optional: true,
|
||||
indexes: [],
|
||||
relationships: [],
|
||||
})
|
||||
|
||||
@@ -12,7 +12,6 @@ describe("Boolean schema", () => {
|
||||
name: "boolean",
|
||||
},
|
||||
nullable: false,
|
||||
optional: false,
|
||||
indexes: [],
|
||||
relationships: [],
|
||||
})
|
||||
|
||||
@@ -12,7 +12,6 @@ describe("DateTime schema", () => {
|
||||
name: "dateTime",
|
||||
},
|
||||
nullable: false,
|
||||
optional: false,
|
||||
indexes: [],
|
||||
relationships: [],
|
||||
})
|
||||
|
||||
@@ -122,6 +122,56 @@ describe("Entity builder", () => {
|
||||
])
|
||||
})
|
||||
|
||||
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", {
|
||||
|
||||
@@ -17,19 +17,16 @@ describe("Enum schema", () => {
|
||||
},
|
||||
},
|
||||
nullable: false,
|
||||
optional: false,
|
||||
indexes: [],
|
||||
relationships: [],
|
||||
})
|
||||
})
|
||||
|
||||
test("apply nullable and optional modifiers", () => {
|
||||
const schema = new EnumSchema(["admin", "moderator", "editor"])
|
||||
.nullable()
|
||||
.optional()
|
||||
test("apply nullable modifier", () => {
|
||||
const schema = new EnumSchema(["admin", "moderator", "editor"]).nullable()
|
||||
|
||||
expectTypeOf(schema["$dataType"]).toEqualTypeOf<
|
||||
"admin" | "moderator" | "editor" | null | undefined
|
||||
"admin" | "moderator" | "editor" | null
|
||||
>()
|
||||
|
||||
expect(schema.parse("role")).toEqual({
|
||||
@@ -41,7 +38,6 @@ describe("Enum schema", () => {
|
||||
},
|
||||
},
|
||||
nullable: true,
|
||||
optional: true,
|
||||
indexes: [],
|
||||
relationships: [],
|
||||
})
|
||||
|
||||
@@ -15,6 +15,7 @@ describe("HasMany relationship", () => {
|
||||
expect(relationship.parse("user")).toEqual({
|
||||
name: "user",
|
||||
type: "hasMany",
|
||||
nullable: false,
|
||||
entity: entityRef,
|
||||
options: {},
|
||||
})
|
||||
|
||||
@@ -15,6 +15,7 @@ describe("HasOne relationship", () => {
|
||||
expect(relationship.parse("user")).toEqual({
|
||||
name: "user",
|
||||
type: "hasOne",
|
||||
nullable: false,
|
||||
entity: entityRef,
|
||||
options: {},
|
||||
})
|
||||
|
||||
@@ -12,7 +12,6 @@ describe("JSON schema", () => {
|
||||
name: "json",
|
||||
},
|
||||
nullable: false,
|
||||
optional: false,
|
||||
indexes: [],
|
||||
relationships: [],
|
||||
})
|
||||
|
||||
@@ -15,6 +15,7 @@ describe("ManyToMany relationship", () => {
|
||||
expect(relationship.parse("user")).toEqual({
|
||||
name: "user",
|
||||
type: "manyToMany",
|
||||
nullable: false,
|
||||
entity: entityRef,
|
||||
options: {},
|
||||
})
|
||||
|
||||
@@ -12,7 +12,6 @@ describe("Number schema", () => {
|
||||
name: "number",
|
||||
},
|
||||
nullable: false,
|
||||
optional: false,
|
||||
indexes: [],
|
||||
relationships: [],
|
||||
})
|
||||
|
||||
@@ -9,10 +9,9 @@ describe("String schema", () => {
|
||||
expect(schema.parse("username")).toEqual({
|
||||
fieldName: "username",
|
||||
dataType: {
|
||||
name: "string",
|
||||
name: "text",
|
||||
},
|
||||
nullable: false,
|
||||
optional: false,
|
||||
indexes: [],
|
||||
relationships: [],
|
||||
})
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import { RelationshipType, SchemaType } from "./types"
|
||||
|
||||
/**
|
||||
* Dml entity is a representation of a DML model with a unique
|
||||
* name, its schema and relationships.
|
||||
*/
|
||||
export class DmlEntity<
|
||||
Schema extends Record<string, SchemaType<any> | RelationshipType<any>>
|
||||
> {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { DmlEntity } from "./entity"
|
||||
import { TextSchema } from "./schema/text"
|
||||
import { EnumSchema } from "./schema/enum"
|
||||
import { JSONSchema } from "./schema/json"
|
||||
import { HasOne } from "./relations/has_one"
|
||||
import { HasMany } from "./relations/has_many"
|
||||
@@ -8,52 +9,114 @@ import { BooleanSchema } from "./schema/boolean"
|
||||
import { DateTimeSchema } from "./schema/date_time"
|
||||
import { ManyToMany } from "./relations/many_to_many"
|
||||
import { RelationshipType, SchemaType } from "./types"
|
||||
import { EnumSchema } from "./schema/enum"
|
||||
import { HasOneThroughMany } from "./relations/has_one_through_many"
|
||||
|
||||
/**
|
||||
* Entity builder exposes the API to create an entity and define its
|
||||
* schema using the shorthand methods.
|
||||
*/
|
||||
export class EntityBuilder {
|
||||
/**
|
||||
* Define an entity or a model. The name should be unique across
|
||||
* all the entities.
|
||||
*/
|
||||
define<
|
||||
Schema extends Record<string, SchemaType<any> | RelationshipType<any>>
|
||||
>(name: string, schema: Schema) {
|
||||
return new DmlEntity(name, schema)
|
||||
}
|
||||
|
||||
/**
|
||||
* Define a text/string based column
|
||||
*/
|
||||
text() {
|
||||
return new TextSchema()
|
||||
}
|
||||
|
||||
/**
|
||||
* Define a boolean column
|
||||
*/
|
||||
boolean() {
|
||||
return new BooleanSchema()
|
||||
}
|
||||
|
||||
/**
|
||||
* Define a numeric/integer column
|
||||
*/
|
||||
number() {
|
||||
return new NumberSchema()
|
||||
}
|
||||
|
||||
/**
|
||||
* Define a timestampz column
|
||||
*/
|
||||
dateTime() {
|
||||
return new DateTimeSchema()
|
||||
}
|
||||
|
||||
/**
|
||||
* Define a JSON column to store data as a
|
||||
* JSON string
|
||||
*/
|
||||
json() {
|
||||
return new JSONSchema()
|
||||
}
|
||||
|
||||
/**
|
||||
* Define an enum column where only a pre-defined set
|
||||
* of values are allowed.
|
||||
*/
|
||||
enum<const Values extends unknown>(values: Values[]) {
|
||||
return new EnumSchema<Values>(values)
|
||||
}
|
||||
|
||||
/**
|
||||
* Has one relationship defines a relationship between two entities
|
||||
* where the owner of the relationship has exactly one instance
|
||||
* of the related entity.
|
||||
*
|
||||
* For example: A user "hasOne" profile
|
||||
*
|
||||
* You may use the "belongsTo" relationship to define the inverse
|
||||
* of the "hasOne" relationship
|
||||
*/
|
||||
hasOne<T>(entityBuilder: T, options?: Record<string, any>) {
|
||||
return new HasOne<T>(entityBuilder, options || {})
|
||||
}
|
||||
|
||||
/**
|
||||
* Has many relationship defines a relationship between two entities
|
||||
* where the owner of the relationship has many instance of the
|
||||
* related entity.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* - A user "hasMany" books
|
||||
* - A user "hasMany" addresses
|
||||
*/
|
||||
hasMany<T>(entityBuilder: T, options?: Record<string, any>) {
|
||||
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
|
||||
* where the owner of the relationship has many instance of the
|
||||
* related entity via a pivot table.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* - A user has many teams. But a team has many users as well. So this
|
||||
* relationship requires a pivot table to establish a many to many
|
||||
* relationship between two entities
|
||||
*/
|
||||
manyToMany<T>(entityBuilder: T, options?: Record<string, any>) {
|
||||
return new ManyToMany<T>(entityBuilder, options || {})
|
||||
}
|
||||
|
||||
@@ -23,32 +23,36 @@ import type {
|
||||
|
||||
/**
|
||||
* DML entity data types to PostgreSQL data types via
|
||||
* Mikro ORM
|
||||
* Mikro ORM.
|
||||
*
|
||||
* We remove "enum" type from here, because we use a dedicated
|
||||
* mikro orm decorator for that
|
||||
*/
|
||||
const COLUMN_TYPES: {
|
||||
[K in KnownDataTypes]: string
|
||||
[K in Exclude<KnownDataTypes, "enum">]: string
|
||||
} = {
|
||||
boolean: "boolean",
|
||||
dateTime: "timestamptz",
|
||||
number: "integer",
|
||||
string: "text",
|
||||
text: "text",
|
||||
json: "jsonb",
|
||||
enum: "enum", // ignore for now
|
||||
}
|
||||
|
||||
/**
|
||||
* DML entity data types to Mikro ORM property
|
||||
* types
|
||||
* types.
|
||||
*
|
||||
* We remove "enum" type from here, because we use a dedicated
|
||||
* mikro orm decorator for that
|
||||
*/
|
||||
const PROPERTY_TYPES: {
|
||||
[K in KnownDataTypes]: string
|
||||
[K in Exclude<KnownDataTypes, "enum">]: string
|
||||
} = {
|
||||
boolean: "boolean",
|
||||
dateTime: "date",
|
||||
number: "number",
|
||||
string: "string",
|
||||
text: "string",
|
||||
json: "any",
|
||||
enum: "enum", // ignore for now
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,20 +69,23 @@ function defineProperty(
|
||||
Enum({
|
||||
items: () => field.dataType.options!.choices,
|
||||
nullable: field.nullable,
|
||||
default: field.defaultValue,
|
||||
})(MikroORMEntity.prototype, field.fieldName)
|
||||
return
|
||||
}
|
||||
|
||||
/**
|
||||
* Define rest of properties
|
||||
*/
|
||||
const columnType = COLUMN_TYPES[field.dataType.name]
|
||||
const propertyType = PROPERTY_TYPES[field.dataType.name]
|
||||
|
||||
/**
|
||||
* @todo: Add support for default value
|
||||
*/
|
||||
Property({ columnType, type: propertyType, nullable: field.nullable })(
|
||||
MikroORMEntity.prototype,
|
||||
field.fieldName
|
||||
)
|
||||
Property({
|
||||
columnType,
|
||||
type: propertyType,
|
||||
nullable: field.nullable,
|
||||
default: field.defaultValue,
|
||||
})(MikroORMEntity.prototype, field.fieldName)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,7 +96,8 @@ function defineRelationship(
|
||||
relationship: RelationshipMetadata
|
||||
) {
|
||||
/**
|
||||
* Defining relationships
|
||||
* We expect the relationship.entity to be a function that
|
||||
* lazily returns the related entity
|
||||
*/
|
||||
const relatedEntity =
|
||||
typeof relationship.entity === "function"
|
||||
@@ -115,6 +123,10 @@ function defineRelationship(
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Converting the related entity name (which should be in camelCase)
|
||||
* to "PascalCase"
|
||||
*/
|
||||
const relatedModelName = upperCaseFirst(relatedEntity.name)
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { SchemaType } from "../types"
|
||||
import { OptionalModifier } from "./optional"
|
||||
import { MaybeFieldMetadata } from "../types"
|
||||
|
||||
/**
|
||||
* Nullable modifier marks a schema node as nullable
|
||||
*/
|
||||
export class NullableModifier<T> {
|
||||
/**
|
||||
* A type-only property to infer the JavScript data-type
|
||||
@@ -12,17 +14,12 @@ export class NullableModifier<T> {
|
||||
* The parent schema on which the nullable modifier is
|
||||
* applied
|
||||
*/
|
||||
#schema: SchemaType<T>
|
||||
|
||||
constructor(schema: SchemaType<T>) {
|
||||
this.#schema = schema
|
||||
#schema: {
|
||||
parse(fieldName: string): MaybeFieldMetadata
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply optional modifier on the schema
|
||||
*/
|
||||
optional() {
|
||||
return new OptionalModifier<T | null>(this)
|
||||
constructor(schema: { parse(fieldName: string): MaybeFieldMetadata }) {
|
||||
this.#schema = schema
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
import { SchemaType } from "../types"
|
||||
import { NullableModifier } from "./nullable"
|
||||
|
||||
export class OptionalModifier<T> {
|
||||
/**
|
||||
* A type-only property to infer the JavScript data-type
|
||||
* of the schema property
|
||||
*/
|
||||
declare $dataType: T | undefined
|
||||
|
||||
/**
|
||||
* The parent schema on which the nullable modifier is
|
||||
* applied
|
||||
*/
|
||||
#schema: SchemaType<T>
|
||||
|
||||
constructor(schema: SchemaType<T>) {
|
||||
this.#schema = schema
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply nullable modifier on the schema
|
||||
*/
|
||||
nullable() {
|
||||
return new NullableModifier<T | undefined>(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the serialized metadata
|
||||
*/
|
||||
parse(fieldName: string) {
|
||||
const schema = this.#schema.parse(fieldName)
|
||||
schema.optional = true
|
||||
return schema
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import { NullableModifier } from "../modifiers/nullable"
|
||||
import { RelationshipMetadata, RelationshipType } from "../types"
|
||||
|
||||
/**
|
||||
@@ -24,12 +25,20 @@ export abstract class BaseRelationship<T> implements RelationshipType<T> {
|
||||
this.#options = options
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply nullable modifier on the schema
|
||||
*/
|
||||
nullable() {
|
||||
return new NullableModifier<T>(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parsed copy of the relationship
|
||||
*/
|
||||
parse(relationshipName: string): RelationshipMetadata {
|
||||
return {
|
||||
name: relationshipName,
|
||||
nullable: false,
|
||||
entity: this.#referencedEntity,
|
||||
options: this.#options,
|
||||
type: this.relationshipType,
|
||||
|
||||
@@ -1,6 +1,16 @@
|
||||
import { BaseRelationship } from "./base"
|
||||
import { RelationshipMetadata } from "../types"
|
||||
|
||||
/**
|
||||
* HasMany relationship defines a relationship between two entities
|
||||
* where the owner of the relationship has many instance of the
|
||||
* related entity.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* - A user HasMany books
|
||||
* - A user HasMany addresses
|
||||
*/
|
||||
export class HasMany<T> extends BaseRelationship<T> {
|
||||
protected relationshipType: RelationshipMetadata["type"] = "hasMany"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,16 @@
|
||||
import { BaseRelationship } from "./base"
|
||||
import { RelationshipMetadata } from "../types"
|
||||
|
||||
/**
|
||||
* HasOne relationship defines a relationship between two entities
|
||||
* where the owner of the relationship has exactly one instance
|
||||
* of the related entity.
|
||||
*
|
||||
* For example: A user HasOne profile
|
||||
*
|
||||
* You may use the "BelongsTo" relationship to define the inverse
|
||||
* of the "HasOne" relationship
|
||||
*/
|
||||
export class HasOne<T> extends BaseRelationship<T> {
|
||||
protected relationshipType: RelationshipMetadata["type"] = "hasOne"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,17 @@
|
||||
import { BaseRelationship } from "./base"
|
||||
import { RelationshipMetadata } from "../types"
|
||||
|
||||
/**
|
||||
* ManyToMany relationship defines a relationship between two entities
|
||||
* where the owner of the relationship has many instance of the
|
||||
* related entity via a pivot table.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* - A user has many teams. But a team has many users as well. So this
|
||||
* relationship requires a pivot table to establish a many to many
|
||||
* relationship between two entities
|
||||
*/
|
||||
export class ManyToMany<T> extends BaseRelationship<T> {
|
||||
protected relationshipType: RelationshipMetadata["type"] = "manyToMany"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { SchemaMetadata, SchemaType } from "../types"
|
||||
import { NullableModifier } from "../modifiers/nullable"
|
||||
import { OptionalModifier } from "../modifiers/optional"
|
||||
|
||||
/**
|
||||
* The base schema class offers shared affordances to define
|
||||
@@ -9,6 +8,7 @@ import { OptionalModifier } from "../modifiers/optional"
|
||||
export abstract class BaseSchema<T> implements SchemaType<T> {
|
||||
#indexes: SchemaMetadata["indexes"] = []
|
||||
#relationships: SchemaMetadata["relationships"] = []
|
||||
#defaultValue?: T
|
||||
|
||||
/**
|
||||
* The runtime dataType for the schema. It is not the same as
|
||||
@@ -30,10 +30,11 @@ export abstract class BaseSchema<T> implements SchemaType<T> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply optional modifier on the schema
|
||||
* Define default value for the property
|
||||
*/
|
||||
optional() {
|
||||
return new OptionalModifier<T>(this)
|
||||
default(value: T) {
|
||||
this.#defaultValue = value
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -44,7 +45,7 @@ export abstract class BaseSchema<T> implements SchemaType<T> {
|
||||
fieldName,
|
||||
dataType: this.dataType,
|
||||
nullable: false,
|
||||
optional: false,
|
||||
defaultValue: this.#defaultValue,
|
||||
indexes: this.#indexes,
|
||||
relationships: this.#relationships,
|
||||
}
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { SchemaMetadata } from "../types"
|
||||
import { BaseSchema } from "./base"
|
||||
|
||||
/**
|
||||
* The BooleanSchema class is used to define a boolean
|
||||
* property
|
||||
*/
|
||||
export class BooleanSchema extends BaseSchema<boolean> {
|
||||
protected dataType: SchemaMetadata["dataType"] = {
|
||||
name: "boolean",
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { SchemaMetadata } from "../types"
|
||||
import { BaseSchema } from "./base"
|
||||
|
||||
/**
|
||||
* The DateTimeSchema class is used to define a timestampz
|
||||
* property
|
||||
*/
|
||||
export class DateTimeSchema extends BaseSchema<Date> {
|
||||
protected dataType: SchemaMetadata["dataType"] = {
|
||||
name: "dateTime",
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { SchemaMetadata } from "../types"
|
||||
import { BaseSchema } from "./base"
|
||||
|
||||
/**
|
||||
* The EnumSchema is used to define a property with pre-defined
|
||||
* list of choices.
|
||||
*/
|
||||
export class EnumSchema<
|
||||
const Values extends unknown
|
||||
> extends BaseSchema<Values> {
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { SchemaMetadata } from "../types"
|
||||
import { BaseSchema } from "./base"
|
||||
|
||||
/**
|
||||
* The JSONSchema is used to define a property that stores
|
||||
* data as a JSON string
|
||||
*/
|
||||
export class JSONSchema extends BaseSchema<string> {
|
||||
protected dataType: SchemaMetadata["dataType"] = {
|
||||
name: "json",
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { SchemaMetadata } from "../types"
|
||||
import { BaseSchema } from "./base"
|
||||
|
||||
/**
|
||||
* The NumberSchema is used to define a numeric/integer
|
||||
* property
|
||||
*/
|
||||
export class NumberSchema extends BaseSchema<number> {
|
||||
protected dataType: SchemaMetadata["dataType"] = {
|
||||
name: "number",
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
import { SchemaMetadata } from "../types"
|
||||
import { BaseSchema } from "./base"
|
||||
|
||||
/**
|
||||
* The NumberSchema is used to define a textual property
|
||||
*/
|
||||
export class TextSchema extends BaseSchema<string> {
|
||||
protected dataType: SchemaMetadata["dataType"] = {
|
||||
name: "string",
|
||||
name: "text",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
export const MIKRO_ORM_ENTITY_GENERATOR = Symbol.for(
|
||||
"generate_mikro_orm_entity"
|
||||
)
|
||||
@@ -4,7 +4,7 @@ import { DmlEntity } from "./entity"
|
||||
* The supported data types
|
||||
*/
|
||||
export type KnownDataTypes =
|
||||
| "string"
|
||||
| "text"
|
||||
| "boolean"
|
||||
| "enum"
|
||||
| "number"
|
||||
@@ -12,23 +12,22 @@ export type KnownDataTypes =
|
||||
| "json"
|
||||
|
||||
/**
|
||||
* The meta-data returned by the relationship parse
|
||||
* method
|
||||
* Any field that contains "nullable" and "optional" properties
|
||||
* in their metadata are qualified as maybe fields.
|
||||
*
|
||||
* This allows us to wrap them inside "NullableModifier" and
|
||||
* "OptionalModifier" classes.
|
||||
*/
|
||||
export type RelationshipMetadata = {
|
||||
name: string
|
||||
type: "hasOne" | "hasMany" | "hasOneThroughMany" | "manyToMany"
|
||||
entity: unknown
|
||||
options: Record<string, any>
|
||||
export type MaybeFieldMetadata = {
|
||||
nullable: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* The meta-data returned by the schema parse method
|
||||
*/
|
||||
export type SchemaMetadata = {
|
||||
nullable: boolean
|
||||
optional: boolean
|
||||
export type SchemaMetadata = MaybeFieldMetadata & {
|
||||
fieldName: string
|
||||
defaultValue?: any
|
||||
dataType: {
|
||||
name: KnownDataTypes
|
||||
options?: Record<string, any>
|
||||
@@ -50,6 +49,17 @@ export type SchemaType<T> = {
|
||||
parse(fieldName: string): SchemaMetadata
|
||||
}
|
||||
|
||||
/**
|
||||
* The meta-data returned by the relationship parse
|
||||
* method
|
||||
*/
|
||||
export type RelationshipMetadata = MaybeFieldMetadata & {
|
||||
name: string
|
||||
type: "hasOne" | "hasMany" | "hasOneThroughMany" | "manyToMany"
|
||||
entity: unknown
|
||||
options: Record<string, any>
|
||||
}
|
||||
|
||||
/**
|
||||
* Definition of a relationship type. It should have a parse
|
||||
* method to get the metadata and a type-only property
|
||||
|
||||
Reference in New Issue
Block a user