Skip to content

Commit

Permalink
feat: add support for float properties (#10551)
Browse files Browse the repository at this point in the history
  • Loading branch information
thetutlage authored Dec 12, 2024
1 parent cccce65 commit 885c82d
Show file tree
Hide file tree
Showing 9 changed files with 209 additions and 0 deletions.
6 changes: 6 additions & 0 deletions .changeset/popular-baboons-allow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@medusajs/types": patch
"@medusajs/utils": patch
---

feat: add support for float properties
1 change: 1 addition & 0 deletions packages/core/types/src/dml/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export type KnownDataTypes =
| "enum"
| "number"
| "bigNumber"
| "float"
| "serial"
| "dateTime"
| "array"
Expand Down
88 changes: 88 additions & 0 deletions packages/core/utils/src/dml/__tests__/entity-builder.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1450,6 +1450,94 @@ describe("Entity builder", () => {
},
})
})

test("define a float property", () => {
const tax = model.define("tax", {
id: model.number(),
rate: model.float(),
})

expect(tax.name).toEqual("Tax")
expect(tax.parse().tableName).toEqual("tax")

const Tax = toMikroORMEntity(tax)
expectTypeOf(new Tax()).toMatchTypeOf<{
id: number
rate: number
}>()

const metaData = MetadataStorage.getMetadataFromDecorator(Tax)
expect(metaData.className).toEqual("Tax")
expect(metaData.path).toEqual("Tax")

expect(metaData.filters).toEqual({
softDeletable: {
name: "softDeletable",
cond: expect.any(Function),
default: true,
args: false,
},
})

expect(metaData.properties).toEqual({
id: {
reference: "scalar",
type: "number",
columnType: "integer",
name: "id",
fieldName: "id",
nullable: false,
getter: false,
setter: false,
},
rate: {
reference: "scalar",
type: "number",
columnType: "real",
name: "rate",
fieldName: "rate",
serializer: Number,
nullable: false,
getter: false,
setter: false,
},
created_at: {
reference: "scalar",
type: "date",
columnType: "timestamptz",
name: "created_at",
fieldName: "created_at",
defaultRaw: "now()",
onCreate: expect.any(Function),
nullable: false,
getter: false,
setter: false,
},
updated_at: {
reference: "scalar",
type: "date",
columnType: "timestamptz",
name: "updated_at",
fieldName: "updated_at",
defaultRaw: "now()",
onCreate: expect.any(Function),
onUpdate: expect.any(Function),
nullable: false,
getter: false,
setter: false,
},
deleted_at: {
reference: "scalar",
type: "date",
columnType: "timestamptz",
name: "deleted_at",
fieldName: "deleted_at",
nullable: true,
getter: false,
setter: false,
},
})
})
})

describe("Entity builder | relationships", () => {
Expand Down
19 changes: 19 additions & 0 deletions packages/core/utils/src/dml/__tests__/float-property.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { expectTypeOf } from "expect-type"
import { FloatProperty } from "../properties"

describe("Float property", () => {
test("create float property type", () => {
const property = new FloatProperty()

expectTypeOf(property["$dataType"]).toEqualTypeOf<number>()
expect(property.parse("rate")).toEqual({
fieldName: "rate",
dataType: {
name: "float",
},
nullable: false,
indexes: [],
relationships: [],
})
})
})
21 changes: 21 additions & 0 deletions packages/core/utils/src/dml/entity-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { HasMany } from "./relations/has-many"
import { HasOne } from "./relations/has-one"
import { HasOneWithForeignKey } from "./relations/has-one-fk"
import { ManyToMany } from "./relations/many-to-many"
import { FloatProperty } from "./properties"

/**
* The implicit properties added by EntityBuilder in every schema
Expand Down Expand Up @@ -249,6 +250,26 @@ export class EntityBuilder {
return new BigNumberProperty()
}

/**
* This method defines a float property that allows for
* values with decimal places
*
* @example
* import { model } from "@medusajs/framework/utils"
*
* const MyCustom = model.define("tax", {
* tax_rate: model.float(),
* // ...
* })
*
* export default MyCustom
*
* @customNamespace Property Types
*/
float() {
return new FloatProperty()
}

/**
* This method defines an autoincrement property.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const COLUMN_TYPES: {
dateTime: "timestamptz",
number: "integer",
bigNumber: "numeric",
float: "real",
serial: "number",
text: "text",
json: "jsonb",
Expand All @@ -53,6 +54,7 @@ const PROPERTY_TYPES: {
dateTime: "date",
number: "number",
bigNumber: "number",
float: "number",
serial: "number",
text: "string",
json: "any",
Expand Down Expand Up @@ -277,6 +279,31 @@ export function defineProperty(
return
}

/**
* Handling serial property separately to set the column type
*/
if (field.dataType.name === "float") {
Property({
columnType: "real",
type: "number",
nullable: field.nullable,
fieldName: field.fieldName,
/**
* Applying number serializer to convert value back to a
* JavaScript number
*/
serializer: Number,
/**
* MikroORM does not ignore undefined values for default when generating
* the database schema SQL. Conditionally add it here to prevent undefined
* from being set as default value in SQL.
*/
...(isDefined(field.defaultValue) && { default: field.defaultValue }),
})(MikroORMEntity.prototype, field.fieldName)

return
}

/**
* Define rest of properties
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ describe("EntityBuilder", () => {
id: model.id().primaryKey(),
username: model.text(),
points: model.number().default(0).nullable(),
tax_rate: model.float().default(0).nullable(),
})

;[User] = toMikroOrmEntities([user])
Expand Down Expand Up @@ -86,6 +87,7 @@ describe("EntityBuilder", () => {
id: user1.id,
username: "User 1",
points: 0,
tax_rate: 0,
created_at: expect.any(Date),
updated_at: expect.any(Date),
deleted_at: null,
Expand All @@ -112,6 +114,7 @@ describe("EntityBuilder", () => {
id: user1.id,
username: "User 1",
points: null,
tax_rate: 0,
created_at: expect.any(Date),
updated_at: expect.any(Date),
deleted_at: null,
Expand Down Expand Up @@ -139,6 +142,34 @@ describe("EntityBuilder", () => {
id: user1.id,
username: "User 1",
points: null,
tax_rate: 0,
created_at: expect.any(Date),
updated_at: expect.any(Date),
deleted_at: null,
})
})

it("set the tax rate as a float value", async () => {
let manager = orm.em.fork()

const user1 = manager.create(User, {
username: "User 1",
tax_rate: 1.2122,
})
expect(user1.tax_rate).toEqual(1.2122)

await manager.persistAndFlush([user1])
manager = orm.em.fork()

const user = await manager.findOne(User, {
id: user1.id,
})

expect(await mikroOrmSerializer(user)).toEqual({
id: user1.id,
username: "User 1",
points: 0,
tax_rate: 1.2122,
created_at: expect.any(Date),
updated_at: expect.any(Date),
deleted_at: null,
Expand Down
15 changes: 15 additions & 0 deletions packages/core/utils/src/dml/properties/float.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { BaseProperty } from "./base"

/**
* The FloatProperty is used to define values with decimal
* places.
*/
export class FloatProperty extends BaseProperty<number> {
protected dataType = {
name: "float",
} as const

static isFloatProperty(obj: any): obj is FloatProperty {
return obj?.dataType?.name === "float"
}
}
1 change: 1 addition & 0 deletions packages/core/utils/src/dml/properties/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ export * from "./id"
export * from "./json"
export * from "./nullable"
export * from "./number"
export * from "./float"
export * from "./primary-key"
export * from "./text"

0 comments on commit 885c82d

Please sign in to comment.