Code cleanup and add support for default values and nullable relationships (#7687)

This commit is contained in:
Harminder Virk
2024-06-12 14:39:03 +05:30
committed by GitHub
parent ee6bdd0ab0
commit 6d43daa930
30 changed files with 291 additions and 131 deletions
@@ -21,6 +21,35 @@ describe("Base relationship", () => {
expect(relationship.parse("user")).toEqual({ expect(relationship.parse("user")).toEqual({
name: "user", name: "user",
type: "hasOne", 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, entity: entityRef,
options: { options: {
foreignKey: "user_id", foreignKey: "user_id",
@@ -6,7 +6,7 @@ describe("Base schema", () => {
test("create a schema type from base schema", () => { test("create a schema type from base schema", () => {
class StringSchema extends BaseSchema<string> { class StringSchema extends BaseSchema<string> {
protected dataType: SchemaMetadata["dataType"] = { protected dataType: SchemaMetadata["dataType"] = {
name: "string", name: "text",
} }
} }
@@ -16,10 +16,9 @@ describe("Base schema", () => {
expect(schema.parse("username")).toEqual({ expect(schema.parse("username")).toEqual({
fieldName: "username", fieldName: "username",
dataType: { dataType: {
name: "string", name: "text",
}, },
nullable: false, nullable: false,
optional: false,
indexes: [], indexes: [],
relationships: [], relationships: [],
}) })
@@ -28,7 +27,7 @@ describe("Base schema", () => {
test("apply nullable modifier", () => { test("apply nullable modifier", () => {
class StringSchema extends BaseSchema<string> { class StringSchema extends BaseSchema<string> {
protected dataType: SchemaMetadata["dataType"] = { protected dataType: SchemaMetadata["dataType"] = {
name: "string", name: "text",
} }
} }
@@ -38,54 +37,31 @@ describe("Base schema", () => {
expect(schema.parse("username")).toEqual({ expect(schema.parse("username")).toEqual({
fieldName: "username", fieldName: "username",
dataType: { dataType: {
name: "string", name: "text",
}, },
nullable: true, nullable: true,
optional: false,
indexes: [], indexes: [],
relationships: [], relationships: [],
}) })
}) })
test("apply optional modifier", () => { test("define default value", () => {
class StringSchema extends BaseSchema<string> { class StringSchema extends BaseSchema<string> {
protected dataType: SchemaMetadata["dataType"] = { 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({ expect(schema.parse("username")).toEqual({
fieldName: "username", fieldName: "username",
dataType: { dataType: {
name: "string", name: "text",
}, },
defaultValue: "foo",
nullable: false, 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: [], indexes: [],
relationships: [], relationships: [],
}) })
@@ -12,7 +12,6 @@ describe("Boolean schema", () => {
name: "boolean", name: "boolean",
}, },
nullable: false, nullable: false,
optional: false,
indexes: [], indexes: [],
relationships: [], relationships: [],
}) })
@@ -12,7 +12,6 @@ describe("DateTime schema", () => {
name: "dateTime", name: "dateTime",
}, },
nullable: false, nullable: false,
optional: false,
indexes: [], indexes: [],
relationships: [], 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", () => { test("define hasMany relationship", () => {
const model = new EntityBuilder() const model = new EntityBuilder()
const email = model.define("email", { const email = model.define("email", {
@@ -17,19 +17,16 @@ describe("Enum schema", () => {
}, },
}, },
nullable: false, nullable: false,
optional: false,
indexes: [], indexes: [],
relationships: [], relationships: [],
}) })
}) })
test("apply nullable and optional modifiers", () => { test("apply nullable modifier", () => {
const schema = new EnumSchema(["admin", "moderator", "editor"]) const schema = new EnumSchema(["admin", "moderator", "editor"]).nullable()
.nullable()
.optional()
expectTypeOf(schema["$dataType"]).toEqualTypeOf< expectTypeOf(schema["$dataType"]).toEqualTypeOf<
"admin" | "moderator" | "editor" | null | undefined "admin" | "moderator" | "editor" | null
>() >()
expect(schema.parse("role")).toEqual({ expect(schema.parse("role")).toEqual({
@@ -41,7 +38,6 @@ describe("Enum schema", () => {
}, },
}, },
nullable: true, nullable: true,
optional: true,
indexes: [], indexes: [],
relationships: [], relationships: [],
}) })
@@ -15,6 +15,7 @@ describe("HasMany relationship", () => {
expect(relationship.parse("user")).toEqual({ expect(relationship.parse("user")).toEqual({
name: "user", name: "user",
type: "hasMany", type: "hasMany",
nullable: false,
entity: entityRef, entity: entityRef,
options: {}, options: {},
}) })
@@ -15,6 +15,7 @@ describe("HasOne relationship", () => {
expect(relationship.parse("user")).toEqual({ expect(relationship.parse("user")).toEqual({
name: "user", name: "user",
type: "hasOne", type: "hasOne",
nullable: false,
entity: entityRef, entity: entityRef,
options: {}, options: {},
}) })
@@ -12,7 +12,6 @@ describe("JSON schema", () => {
name: "json", name: "json",
}, },
nullable: false, nullable: false,
optional: false,
indexes: [], indexes: [],
relationships: [], relationships: [],
}) })
@@ -15,6 +15,7 @@ describe("ManyToMany relationship", () => {
expect(relationship.parse("user")).toEqual({ expect(relationship.parse("user")).toEqual({
name: "user", name: "user",
type: "manyToMany", type: "manyToMany",
nullable: false,
entity: entityRef, entity: entityRef,
options: {}, options: {},
}) })
@@ -12,7 +12,6 @@ describe("Number schema", () => {
name: "number", name: "number",
}, },
nullable: false, nullable: false,
optional: false,
indexes: [], indexes: [],
relationships: [], relationships: [],
}) })
@@ -9,10 +9,9 @@ describe("String schema", () => {
expect(schema.parse("username")).toEqual({ expect(schema.parse("username")).toEqual({
fieldName: "username", fieldName: "username",
dataType: { dataType: {
name: "string", name: "text",
}, },
nullable: false, nullable: false,
optional: false,
indexes: [], indexes: [],
relationships: [], relationships: [],
}) })
+4
View File
@@ -1,5 +1,9 @@
import { RelationshipType, SchemaType } from "./types" 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< export class DmlEntity<
Schema extends Record<string, SchemaType<any> | RelationshipType<any>> Schema extends Record<string, SchemaType<any> | RelationshipType<any>>
> { > {
+64 -1
View File
@@ -1,5 +1,6 @@
import { DmlEntity } from "./entity" import { DmlEntity } from "./entity"
import { TextSchema } from "./schema/text" import { TextSchema } from "./schema/text"
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"
@@ -8,52 +9,114 @@ import { BooleanSchema } from "./schema/boolean"
import { DateTimeSchema } from "./schema/date_time" import { DateTimeSchema } from "./schema/date_time"
import { ManyToMany } from "./relations/many_to_many" import { ManyToMany } from "./relations/many_to_many"
import { RelationshipType, SchemaType } from "./types" import { RelationshipType, SchemaType } from "./types"
import { EnumSchema } from "./schema/enum"
import { HasOneThroughMany } from "./relations/has_one_through_many" 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 { export class EntityBuilder {
/**
* Define an entity or a model. The name should be unique across
* all the entities.
*/
define< define<
Schema extends Record<string, SchemaType<any> | RelationshipType<any>> Schema extends Record<string, SchemaType<any> | RelationshipType<any>>
>(name: string, schema: Schema) { >(name: string, schema: Schema) {
return new DmlEntity(name, schema) return new DmlEntity(name, schema)
} }
/**
* Define a text/string based column
*/
text() { text() {
return new TextSchema() return new TextSchema()
} }
/**
* Define a boolean column
*/
boolean() { boolean() {
return new BooleanSchema() return new BooleanSchema()
} }
/**
* Define a numeric/integer column
*/
number() { number() {
return new NumberSchema() return new NumberSchema()
} }
/**
* Define a timestampz column
*/
dateTime() { dateTime() {
return new DateTimeSchema() return new DateTimeSchema()
} }
/**
* Define a JSON column to store data as a
* JSON string
*/
json() { json() {
return new JSONSchema() return new JSONSchema()
} }
/**
* Define an enum column where only a pre-defined set
* of values are allowed.
*/
enum<const Values extends unknown>(values: Values[]) { enum<const Values extends unknown>(values: Values[]) {
return new EnumSchema<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>) { hasOne<T>(entityBuilder: T, options?: Record<string, any>) {
return new HasOne<T>(entityBuilder, options || {}) 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>) { hasMany<T>(entityBuilder: T, options?: Record<string, any>) {
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>) { hasOneThroughMany<T>(entityBuilder: T, options?: Record<string, any>) {
return new HasOneThroughMany<T>(entityBuilder, options || {}) 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>) { manyToMany<T>(entityBuilder: T, options?: Record<string, any>) {
return new ManyToMany<T>(entityBuilder, options || {}) return new ManyToMany<T>(entityBuilder, options || {})
} }
@@ -23,32 +23,36 @@ import type {
/** /**
* DML entity data types to PostgreSQL data types via * 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: { const COLUMN_TYPES: {
[K in KnownDataTypes]: string [K in Exclude<KnownDataTypes, "enum">]: string
} = { } = {
boolean: "boolean", boolean: "boolean",
dateTime: "timestamptz", dateTime: "timestamptz",
number: "integer", number: "integer",
string: "text", text: "text",
json: "jsonb", json: "jsonb",
enum: "enum", // ignore for now
} }
/** /**
* DML entity data types to Mikro ORM property * 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: { const PROPERTY_TYPES: {
[K in KnownDataTypes]: string [K in Exclude<KnownDataTypes, "enum">]: string
} = { } = {
boolean: "boolean", boolean: "boolean",
dateTime: "date", dateTime: "date",
number: "number", number: "number",
string: "string", text: "string",
json: "any", json: "any",
enum: "enum", // ignore for now
} }
/** /**
@@ -65,20 +69,23 @@ function defineProperty(
Enum({ Enum({
items: () => field.dataType.options!.choices, items: () => field.dataType.options!.choices,
nullable: field.nullable, nullable: field.nullable,
default: field.defaultValue,
})(MikroORMEntity.prototype, field.fieldName) })(MikroORMEntity.prototype, field.fieldName)
return return
} }
/**
* Define rest of properties
*/
const columnType = COLUMN_TYPES[field.dataType.name] const columnType = COLUMN_TYPES[field.dataType.name]
const propertyType = PROPERTY_TYPES[field.dataType.name] const propertyType = PROPERTY_TYPES[field.dataType.name]
/** Property({
* @todo: Add support for default value columnType,
*/ type: propertyType,
Property({ columnType, type: propertyType, nullable: field.nullable })( nullable: field.nullable,
MikroORMEntity.prototype, default: field.defaultValue,
field.fieldName })(MikroORMEntity.prototype, field.fieldName)
)
} }
/** /**
@@ -89,7 +96,8 @@ function defineRelationship(
relationship: RelationshipMetadata relationship: RelationshipMetadata
) { ) {
/** /**
* Defining relationships * We expect the relationship.entity to be a function that
* lazily returns the related entity
*/ */
const relatedEntity = const relatedEntity =
typeof relationship.entity === "function" 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) const relatedModelName = upperCaseFirst(relatedEntity.name)
/** /**
@@ -1,6 +1,8 @@
import { SchemaType } from "../types" import { MaybeFieldMetadata } from "../types"
import { OptionalModifier } from "./optional"
/**
* Nullable modifier marks a schema node as nullable
*/
export class NullableModifier<T> { export class NullableModifier<T> {
/** /**
* A type-only property to infer the JavScript data-type * 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 * The parent schema on which the nullable modifier is
* applied * applied
*/ */
#schema: SchemaType<T> #schema: {
parse(fieldName: string): MaybeFieldMetadata
constructor(schema: SchemaType<T>) {
this.#schema = schema
} }
/** constructor(schema: { parse(fieldName: string): MaybeFieldMetadata }) {
* Apply optional modifier on the schema this.#schema = schema
*/
optional() {
return new OptionalModifier<T | null>(this)
} }
/** /**
@@ -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" import { RelationshipMetadata, RelationshipType } from "../types"
/** /**
@@ -24,12 +25,20 @@ export abstract class BaseRelationship<T> implements RelationshipType<T> {
this.#options = options this.#options = options
} }
/**
* Apply nullable modifier on the schema
*/
nullable() {
return new NullableModifier<T>(this)
}
/** /**
* Returns the parsed copy of the relationship * Returns the parsed copy of the relationship
*/ */
parse(relationshipName: string): RelationshipMetadata { parse(relationshipName: string): RelationshipMetadata {
return { return {
name: relationshipName, name: relationshipName,
nullable: false,
entity: this.#referencedEntity, entity: this.#referencedEntity,
options: this.#options, options: this.#options,
type: this.relationshipType, type: this.relationshipType,
@@ -1,6 +1,16 @@
import { BaseRelationship } from "./base" import { BaseRelationship } from "./base"
import { RelationshipMetadata } from "../types" 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> { export class HasMany<T> extends BaseRelationship<T> {
protected relationshipType: RelationshipMetadata["type"] = "hasMany" protected relationshipType: RelationshipMetadata["type"] = "hasMany"
} }
@@ -1,6 +1,16 @@
import { BaseRelationship } from "./base" import { BaseRelationship } from "./base"
import { RelationshipMetadata } from "../types" 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> { export class HasOne<T> extends BaseRelationship<T> {
protected relationshipType: RelationshipMetadata["type"] = "hasOne" protected relationshipType: RelationshipMetadata["type"] = "hasOne"
} }
@@ -1,6 +1,17 @@
import { BaseRelationship } from "./base" import { BaseRelationship } from "./base"
import { RelationshipMetadata } from "../types" 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> { export class ManyToMany<T> extends BaseRelationship<T> {
protected relationshipType: RelationshipMetadata["type"] = "manyToMany" protected relationshipType: RelationshipMetadata["type"] = "manyToMany"
} }
+6 -5
View File
@@ -1,6 +1,5 @@
import { SchemaMetadata, SchemaType } from "../types" import { SchemaMetadata, SchemaType } from "../types"
import { NullableModifier } from "../modifiers/nullable" import { NullableModifier } from "../modifiers/nullable"
import { OptionalModifier } from "../modifiers/optional"
/** /**
* The base schema class offers shared affordances to define * 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> { export abstract class BaseSchema<T> implements SchemaType<T> {
#indexes: SchemaMetadata["indexes"] = [] #indexes: SchemaMetadata["indexes"] = []
#relationships: SchemaMetadata["relationships"] = [] #relationships: SchemaMetadata["relationships"] = []
#defaultValue?: T
/** /**
* The runtime dataType for the schema. It is not the same as * 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() { default(value: T) {
return new OptionalModifier<T>(this) this.#defaultValue = value
return this
} }
/** /**
@@ -44,7 +45,7 @@ export abstract class BaseSchema<T> implements SchemaType<T> {
fieldName, fieldName,
dataType: this.dataType, dataType: this.dataType,
nullable: false, nullable: false,
optional: false, defaultValue: this.#defaultValue,
indexes: this.#indexes, indexes: this.#indexes,
relationships: this.#relationships, relationships: this.#relationships,
} }
@@ -1,6 +1,10 @@
import { SchemaMetadata } from "../types" import { SchemaMetadata } from "../types"
import { BaseSchema } from "./base" import { BaseSchema } from "./base"
/**
* The BooleanSchema class is used to define a boolean
* property
*/
export class BooleanSchema extends BaseSchema<boolean> { export class BooleanSchema extends BaseSchema<boolean> {
protected dataType: SchemaMetadata["dataType"] = { protected dataType: SchemaMetadata["dataType"] = {
name: "boolean", name: "boolean",
@@ -1,6 +1,10 @@
import { SchemaMetadata } from "../types" import { SchemaMetadata } from "../types"
import { BaseSchema } from "./base" import { BaseSchema } from "./base"
/**
* The DateTimeSchema class is used to define a timestampz
* property
*/
export class DateTimeSchema extends BaseSchema<Date> { export class DateTimeSchema extends BaseSchema<Date> {
protected dataType: SchemaMetadata["dataType"] = { protected dataType: SchemaMetadata["dataType"] = {
name: "dateTime", name: "dateTime",
@@ -1,6 +1,10 @@
import { SchemaMetadata } from "../types" import { SchemaMetadata } from "../types"
import { BaseSchema } from "./base" import { BaseSchema } from "./base"
/**
* The EnumSchema is used to define a property with pre-defined
* list of choices.
*/
export class EnumSchema< export class EnumSchema<
const Values extends unknown const Values extends unknown
> extends BaseSchema<Values> { > extends BaseSchema<Values> {
@@ -1,6 +1,10 @@
import { SchemaMetadata } from "../types" import { SchemaMetadata } from "../types"
import { BaseSchema } from "./base" 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> { export class JSONSchema extends BaseSchema<string> {
protected dataType: SchemaMetadata["dataType"] = { protected dataType: SchemaMetadata["dataType"] = {
name: "json", name: "json",
@@ -1,6 +1,10 @@
import { SchemaMetadata } from "../types" import { SchemaMetadata } from "../types"
import { BaseSchema } from "./base" import { BaseSchema } from "./base"
/**
* The NumberSchema is used to define a numeric/integer
* property
*/
export class NumberSchema extends BaseSchema<number> { export class NumberSchema extends BaseSchema<number> {
protected dataType: SchemaMetadata["dataType"] = { protected dataType: SchemaMetadata["dataType"] = {
name: "number", name: "number",
+4 -1
View File
@@ -1,8 +1,11 @@
import { SchemaMetadata } from "../types" import { SchemaMetadata } from "../types"
import { BaseSchema } from "./base" import { BaseSchema } from "./base"
/**
* The NumberSchema is used to define a textual property
*/
export class TextSchema extends BaseSchema<string> { export class TextSchema extends BaseSchema<string> {
protected dataType: SchemaMetadata["dataType"] = { protected dataType: SchemaMetadata["dataType"] = {
name: "string", name: "text",
} }
} }
-3
View File
@@ -1,3 +0,0 @@
export const MIKRO_ORM_ENTITY_GENERATOR = Symbol.for(
"generate_mikro_orm_entity"
)
+21 -11
View File
@@ -4,7 +4,7 @@ import { DmlEntity } from "./entity"
* The supported data types * The supported data types
*/ */
export type KnownDataTypes = export type KnownDataTypes =
| "string" | "text"
| "boolean" | "boolean"
| "enum" | "enum"
| "number" | "number"
@@ -12,23 +12,22 @@ export type KnownDataTypes =
| "json" | "json"
/** /**
* The meta-data returned by the relationship parse * Any field that contains "nullable" and "optional" properties
* method * in their metadata are qualified as maybe fields.
*
* This allows us to wrap them inside "NullableModifier" and
* "OptionalModifier" classes.
*/ */
export type RelationshipMetadata = { export type MaybeFieldMetadata = {
name: string nullable: boolean
type: "hasOne" | "hasMany" | "hasOneThroughMany" | "manyToMany"
entity: unknown
options: Record<string, any>
} }
/** /**
* The meta-data returned by the schema parse method * The meta-data returned by the schema parse method
*/ */
export type SchemaMetadata = { export type SchemaMetadata = MaybeFieldMetadata & {
nullable: boolean
optional: boolean
fieldName: string fieldName: string
defaultValue?: any
dataType: { dataType: {
name: KnownDataTypes name: KnownDataTypes
options?: Record<string, any> options?: Record<string, any>
@@ -50,6 +49,17 @@ export type SchemaType<T> = {
parse(fieldName: string): SchemaMetadata 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 * Definition of a relationship type. It should have a parse
* method to get the metadata and a type-only property * method to get the metadata and a type-only property