fix(m2m-array): check naming collision (#5059)

This commit is contained in:
YANG QIA 2024-08-15 11:55:36 +08:00 committed by GitHub
parent b15a635ee8
commit 161407c803
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 41 additions and 24 deletions

View File

@ -78,8 +78,8 @@ describe('belongs to array field', () => {
describe('association keys check', async () => { describe('association keys check', async () => {
it('targetKey is required', async () => { it('targetKey is required', async () => {
try { await expect(
await db.sequelize.transaction(async (transaction) => { db.sequelize.transaction(async (transaction) => {
const field = await fieldRepo.create({ const field = await fieldRepo.create({
values: { values: {
interface: 'mbm', interface: 'mbm',
@ -92,15 +92,13 @@ describe('belongs to array field', () => {
transaction, transaction,
}); });
await field.load({ transaction }); await field.load({ transaction });
}); }),
} catch (error) { ).rejects.toThrow(/Target key is required/);
expect(error.message).toContain('Target key is required');
}
}); });
it('foreign field must be an array or set field', async () => { it('foreign field must be an array or set field', async () => {
try { await expect(
await db.sequelize.transaction(async (transaction) => { db.sequelize.transaction(async (transaction) => {
const field = await fieldRepo.create({ const field = await fieldRepo.create({
values: { values: {
interface: 'mbm', interface: 'mbm',
@ -114,20 +112,16 @@ describe('belongs to array field', () => {
transaction, transaction,
}); });
await field.load({ transaction }); await field.load({ transaction });
}); }),
} catch (error) { ).rejects.toThrow(/The type of foreign key "username" in collection "users" must be ARRAY, JSON or JSONB/);
expect(error.message).toContain(
'The type of foreign key "username" in collection "users" must be ARRAY, JSON or JSONB',
);
}
}); });
it('element type of foreign field must be match the type of target field', async () => { it('element type of foreign field must be match the type of target field', async () => {
if (db.sequelize.getDialect() !== 'postgres') { if (db.sequelize.getDialect() !== 'postgres') {
return; return;
} }
try { await expect(
await db.sequelize.transaction(async (transaction) => { db.sequelize.transaction(async (transaction) => {
const field = await fieldRepo.create({ const field = await fieldRepo.create({
values: { values: {
interface: 'mbm', interface: 'mbm',
@ -141,14 +135,12 @@ describe('belongs to array field', () => {
transaction, transaction,
}); });
await field.load({ transaction }); await field.load({ transaction });
}); }),
} catch (error) { ).rejects.toThrow(
expect(error.message).toContain( /The element type "STRING" of foreign key "tag_ids" does not match the type "BIGINT" of target key "id" in collection "tags"/,
'The element type "STRING" of foreign key "tag_ids" does not match the type "BIGINT" of target key "id" in collection "tags"', );
);
}
expect( await expect(
db.sequelize.transaction(async (transaction) => { db.sequelize.transaction(async (transaction) => {
const field = await fieldRepo.create({ const field = await fieldRepo.create({
values: { values: {
@ -166,5 +158,25 @@ describe('belongs to array field', () => {
}), }),
).resolves.not.toThrow(); ).resolves.not.toThrow();
}); });
it('the name of foreign key must not be the same as the name of the field', async () => {
await expect(
db.sequelize.transaction(async (transaction) => {
const field = await fieldRepo.create({
values: {
interface: 'mbm',
collectionName: 'users',
name: 'tag_ids_same',
type: 'belongsToArray',
foreignKey: 'tag_ids_same',
target: 'tags',
targetKey: 'stringCode',
},
transaction,
});
await field.load({ transaction });
}),
).rejects.toThrow(/Naming collision/);
});
}); });
}); });

View File

@ -12,10 +12,15 @@ import { elementTypeMap } from '../belongs-to-array-field';
export const createForeignKey = (db: Database) => { export const createForeignKey = (db: Database) => {
return async (model: Model, { transaction }) => { return async (model: Model, { transaction }) => {
const { type, collectionName, target, targetKey, foreignKey } = model.get(); const { type, collectionName, target, targetKey, foreignKey, name } = model.get();
if (type !== 'belongsToArray') { if (type !== 'belongsToArray') {
return; return;
} }
if (name === foreignKey) {
throw new Error(
`Naming collision between attribute '${foreignKey}' and association '${name}' on model ${collectionName}. To remedy this, change either foreignKey or as in your association definition`,
);
}
const r = db.getRepository('fields'); const r = db.getRepository('fields');
const instance = await r.findOne({ const instance = await r.findOne({
filter: { filter: {