From 3bb2a2d46e647309d7167fdfbf1e5e9dbc25cc9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Ad=C3=A1mek?= Date: Tue, 7 Jul 2020 18:08:22 +0200 Subject: [PATCH] fix(core): support nullable bigints Closes #631 --- docs/docs/using-bigint-pks.md | 4 +++ packages/core/src/types/BigIntType.ts | 14 +++++++-- tests/issues/GH482.test.ts | 43 ++++++++++++++++++++++++++- 3 files changed, 57 insertions(+), 4 deletions(-) diff --git a/docs/docs/using-bigint-pks.md b/docs/docs/using-bigint-pks.md index f201ba32a282..89e0adb69faa 100644 --- a/docs/docs/using-bigint-pks.md +++ b/docs/docs/using-bigint-pks.md @@ -22,6 +22,10 @@ If you want to use native `bigint` type, you will need to create new type based export class NativeBigIntType extends BigIntType { convertToJSValue(value: any): any { + if (!value) { + return value; + } + return BigInt(value); } diff --git a/packages/core/src/types/BigIntType.ts b/packages/core/src/types/BigIntType.ts index 2132ba4278ca..3b02bc00cb29 100644 --- a/packages/core/src/types/BigIntType.ts +++ b/packages/core/src/types/BigIntType.ts @@ -5,13 +5,21 @@ import { EntityProperty } from '../typings'; /** * This type will automatically convert string values returned from the database to native JS bigints. */ -export class BigIntType extends Type { +export class BigIntType extends Type { + + convertToDatabaseValue(value: string | bigint | null | undefined): string | null | undefined { + if (!value) { + return value as null | undefined; + } - convertToDatabaseValue(value: string | bigint): string { return '' + value; } - convertToJSValue(value: string | bigint): string { + convertToJSValue(value: string | bigint | null | undefined): string | null | undefined { + if (!value) { + return value as null | undefined; + } + return '' + value; } diff --git a/tests/issues/GH482.test.ts b/tests/issues/GH482.test.ts index d2bca2e9a3b4..eca57dd25dc0 100644 --- a/tests/issues/GH482.test.ts +++ b/tests/issues/GH482.test.ts @@ -1,4 +1,4 @@ -import { Entity, PrimaryKey, MikroORM, BigIntType, OneToMany, Collection, Enum, ManyToOne, Logger } from '@mikro-orm/core'; +import { Entity, PrimaryKey, MikroORM, BigIntType, OneToMany, Collection, Enum, ManyToOne, Logger, Property } from '@mikro-orm/core'; import { SqliteDriver } from '@mikro-orm/sqlite'; export enum LevelType { @@ -12,6 +12,9 @@ class Job { @PrimaryKey({ type: BigIntType }) id!: string; + @Property({ type: BigIntType, nullable: true }) + optional?: string | null; // GH issue 631 + @OneToMany('Level', 'job', { orphanRemoval: true }) levels = new Collection(this); @@ -51,6 +54,7 @@ describe('GH issue 482', () => { test(`orphan removal with composite keys`, async () => { const job = new Job(); + job.id = '1'; job.levels.add(new Level(LevelType.A)); job.levels.add(new Level(LevelType.B)); await orm.em.persistAndFlush(job); @@ -66,6 +70,43 @@ describe('GH issue 482', () => { expect(mock.mock.calls[1][0]).toMatch(`delete from "level" where "type" = 'A' and "job_id" = '1'`); expect(mock.mock.calls[2][0]).toMatch(`delete from "level" where "type" = 'B' and "job_id" = '1'`); expect(mock.mock.calls[3][0]).toMatch('commit'); + mock.mock.calls.length = 0; + }); + + test(`GH issue 631 - nullable bigint type`, async () => { + const mock = jest.fn(); + const logger = new Logger(mock, true); + Object.assign(orm.config, { logger }); + orm.config.set('highlight', false); + orm.config.set('debug', ['query', 'query-params']); + + const job = new Job(); + job.id = '2'; + orm.em.persist(job); + job.optional = '1'; + await orm.em.flush(); + job.optional = null; + await orm.em.flush(); + job.optional = '1'; + await orm.em.flush(); + job.optional = undefined; + await orm.em.flush(); + orm.em.clear(); + const j = await orm.em.findOneOrFail(Job, job.id); + expect(j.optional).toBeNull(); + + expect(mock.mock.calls[0][0]).toMatch('begin'); + expect(mock.mock.calls[1][0]).toMatch(`insert into "job" ("id", "optional") values ('2', '1') returning "id"`); + expect(mock.mock.calls[2][0]).toMatch('commit'); + expect(mock.mock.calls[3][0]).toMatch('begin'); + expect(mock.mock.calls[4][0]).toMatch(`update "job" set "optional" = NULL where "id" = '2'`); + expect(mock.mock.calls[5][0]).toMatch('commit'); + expect(mock.mock.calls[6][0]).toMatch('begin'); + expect(mock.mock.calls[7][0]).toMatch(`update "job" set "optional" = '1' where "id" = '2'`); + expect(mock.mock.calls[8][0]).toMatch('commit'); + expect(mock.mock.calls[9][0]).toMatch('begin'); + expect(mock.mock.calls[10][0]).toMatch(`update "job" set "optional" = NULL where "id" = '2'`); + expect(mock.mock.calls[11][0]).toMatch('commit'); }); });