From 0bb5d5f5ee93dabab53f64aefcf6313be74ebe6b Mon Sep 17 00:00:00 2001 From: ChengLei Shao Date: Wed, 10 Apr 2024 08:49:19 +0800 Subject: [PATCH] chore(database): set null value when field is unique and value is empty string (#3997) * chore(database): set null value when field is unique and value is empty string * fix: build --- .../database/src/__tests__/unique.test.ts | 114 ++++++++++++++++++ packages/core/database/src/database.ts | 11 ++ 2 files changed, 125 insertions(+) create mode 100644 packages/core/database/src/__tests__/unique.test.ts diff --git a/packages/core/database/src/__tests__/unique.test.ts b/packages/core/database/src/__tests__/unique.test.ts new file mode 100644 index 0000000000..f081d5d914 --- /dev/null +++ b/packages/core/database/src/__tests__/unique.test.ts @@ -0,0 +1,114 @@ +import { Database, mockDatabase } from '@nocobase/database'; + +describe('unique field', () => { + let db: Database; + + beforeEach(async () => { + db = mockDatabase({ + logging: console.log, + }); + + await db.clean({ drop: true }); + }); + + afterEach(async () => { + await db.close(); + }); + + it('should not transform empty string to null when field is not unique', async () => { + const User = db.collection({ + name: 'users', + fields: [ + { + type: 'string', + name: 'name', + }, + ], + }); + + await db.sync(); + + await User.repository.create({ + values: [ + {}, + { + name: '', + }, + { + name: 'user3', + }, + ], + }); + + const u3 = await User.repository.findOne({ + filter: { + name: 'user3', + }, + }); + + await User.repository.update({ + filter: { + id: u3.id, + }, + values: { + name: '', + }, + }); + + await u3.reload(); + expect(u3.get('name')).toBe(''); + }); + + it('should transform empty string to null when field is unique', async () => { + const User = db.collection({ + name: 'users', + fields: [ + { + type: 'string', + name: 'name', + unique: true, + }, + ], + }); + + await db.sync(); + + await User.repository.create({ + values: [ + {}, + { + name: '', + }, + { + name: 'user3', + }, + ], + }); + + const u3 = await User.repository.findOne({ + filter: { + name: 'user3', + }, + }); + + let error; + + try { + await User.repository.update({ + filter: { + id: u3.id, + }, + values: { + name: '', + }, + }); + } catch (e) { + error = e; + } + + expect(error).toBeUndefined(); + + await u3.reload(); + expect(u3.get('name')).toBe(null); + }); +}); diff --git a/packages/core/database/src/database.ts b/packages/core/database/src/database.ts index 8096234b49..5ca61ba444 100644 --- a/packages/core/database/src/database.ts +++ b/packages/core/database/src/database.ts @@ -406,6 +406,17 @@ export class Database extends EventEmitter implements AsyncEmitter { instance?.toChangedWithAssociations?.(); }); + this.on('beforeValidate', async (instance) => { + for (const [key, attribute] of Object.entries(instance.constructor.rawAttributes)) { + // @ts-ignore + if (attribute.unique && instance.changed(key)) { + if (instance.get(key) === '') { + instance.set(key, null); + } + } + } + }); + this.on('afterUpdate', async (instance) => { instance?.toChangedWithAssociations?.(); });