mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-05-05 13:39:24 +08:00
chore(data-source-main): field name exists error message (#4689)
* chore: test * chore: throw field name exists error * chore: error message * chore: error locale * fix: i18n message
This commit is contained in:
parent
f61b56fe4f
commit
bb82faf583
@ -109,6 +109,7 @@ export class Locale {
|
|||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.keys(resources).forEach((name) => {
|
Object.keys(resources).forEach((name) => {
|
||||||
this.app.i18n.addResources(lang, name, resources[name]);
|
this.app.i18n.addResources(lang, name, resources[name]);
|
||||||
});
|
});
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"field-name-exists": "Field name \"{{name}}\" already exists in collection \"{{collectionName}}\""
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"field-name-exists": "字段标识 \"{{name}}\" 已存在"
|
||||||
|
}
|
@ -66,6 +66,7 @@ describe('collections repository', () => {
|
|||||||
},
|
},
|
||||||
context: {},
|
context: {},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(field1.toJSON()).toMatchObject({
|
expect(field1.toJSON()).toMatchObject({
|
||||||
type: 'belongsToMany',
|
type: 'belongsToMany',
|
||||||
collectionName: 'foos',
|
collectionName: 'foos',
|
||||||
@ -81,6 +82,7 @@ describe('collections repository', () => {
|
|||||||
},
|
},
|
||||||
context: {},
|
context: {},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(field2.toJSON()).toMatchObject({
|
expect(field2.toJSON()).toMatchObject({
|
||||||
type: 'belongsTo',
|
type: 'belongsTo',
|
||||||
collectionName: 'foos',
|
collectionName: 'foos',
|
||||||
|
@ -132,6 +132,35 @@ describe('collections repository', () => {
|
|||||||
await app.destroy();
|
await app.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should throw error when field name already exists', async () => {
|
||||||
|
await Field.repository.create({
|
||||||
|
values: {
|
||||||
|
name: 'name',
|
||||||
|
type: 'string',
|
||||||
|
collectionName: 'tests',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
let error;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await Field.repository.create({
|
||||||
|
values: {
|
||||||
|
name: 'name',
|
||||||
|
type: 'string',
|
||||||
|
collectionName: 'tests',
|
||||||
|
},
|
||||||
|
context: {},
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
error = err;
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(error).toBeDefined();
|
||||||
|
expect(error.name).toBe('FieldNameExistsError');
|
||||||
|
expect(error.value).toBe('name');
|
||||||
|
expect(error.collectionName).toBe('tests');
|
||||||
|
});
|
||||||
|
|
||||||
it('should generate the name and key randomly', async () => {
|
it('should generate the name and key randomly', async () => {
|
||||||
const field = await Field.repository.create({
|
const field = await Field.repository.create({
|
||||||
values: {
|
values: {
|
||||||
|
@ -84,6 +84,41 @@ describe('collections repository', () => {
|
|||||||
await app.destroy();
|
await app.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should throw error when create field with same name', async () => {
|
||||||
|
const response = await agent.resource('collections').create({
|
||||||
|
values: {
|
||||||
|
name: 'test',
|
||||||
|
autoGenId: false,
|
||||||
|
sortable: false,
|
||||||
|
timestamps: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(response.statusCode).toBe(200);
|
||||||
|
|
||||||
|
const response2 = await agent.resource('fields').create({
|
||||||
|
values: {
|
||||||
|
name: 'field',
|
||||||
|
type: 'string',
|
||||||
|
collectionName: 'test',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(response2.statusCode).toBe(200);
|
||||||
|
|
||||||
|
const response3 = await agent.resource('fields').create({
|
||||||
|
values: {
|
||||||
|
name: 'field',
|
||||||
|
type: 'string',
|
||||||
|
collectionName: 'test',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(response3.statusCode).toBe(400);
|
||||||
|
const responseBody = response3.body;
|
||||||
|
console.log(responseBody);
|
||||||
|
});
|
||||||
|
|
||||||
it('should skip sync when create empty collection', async () => {
|
it('should skip sync when create empty collection', async () => {
|
||||||
const response = await agent.resource('collections').create({
|
const response = await agent.resource('collections').create({
|
||||||
values: {
|
values: {
|
||||||
|
@ -0,0 +1,21 @@
|
|||||||
|
/**
|
||||||
|
* This file is part of the NocoBase (R) project.
|
||||||
|
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
||||||
|
* Authors: NocoBase Team.
|
||||||
|
*
|
||||||
|
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
||||||
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class FieldNameExistsError extends Error {
|
||||||
|
value: string;
|
||||||
|
collectionName: string;
|
||||||
|
|
||||||
|
constructor(value: string, collectionName: string) {
|
||||||
|
super(`Field name "${value}" already exists in collection "${collectionName}"`);
|
||||||
|
this.value = value;
|
||||||
|
this.collectionName = collectionName;
|
||||||
|
|
||||||
|
this.name = 'FieldNameExistsError';
|
||||||
|
}
|
||||||
|
}
|
@ -27,6 +27,7 @@ import { beforeCreateForViewCollection } from './hooks/beforeCreateForViewCollec
|
|||||||
import { CollectionModel, FieldModel } from './models';
|
import { CollectionModel, FieldModel } from './models';
|
||||||
import collectionActions from './resourcers/collections';
|
import collectionActions from './resourcers/collections';
|
||||||
import viewResourcer from './resourcers/views';
|
import viewResourcer from './resourcers/views';
|
||||||
|
import { FieldNameExistsError } from './errors/field-name-exists-error';
|
||||||
|
|
||||||
export class PluginDataSourceMainServer extends Plugin {
|
export class PluginDataSourceMainServer extends Plugin {
|
||||||
public schema: string;
|
public schema: string;
|
||||||
@ -128,6 +129,30 @@ export class PluginDataSourceMainServer extends Plugin {
|
|||||||
this.app.db.on('fields.beforeCreate', beforeCreateForValidateField(this.app.db));
|
this.app.db.on('fields.beforeCreate', beforeCreateForValidateField(this.app.db));
|
||||||
|
|
||||||
this.app.db.on('fields.afterCreate', afterCreateForReverseField(this.app.db));
|
this.app.db.on('fields.afterCreate', afterCreateForReverseField(this.app.db));
|
||||||
|
|
||||||
|
this.app.db.on('fields.beforeCreate', async (model: FieldModel, options) => {
|
||||||
|
const { transaction } = options;
|
||||||
|
// validate field name
|
||||||
|
const collectionName = model.get('collectionName');
|
||||||
|
const name = model.get('name');
|
||||||
|
|
||||||
|
if (!collectionName || !name) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const exists = await this.app.db.getRepository('fields').findOne({
|
||||||
|
filter: {
|
||||||
|
collectionName,
|
||||||
|
name,
|
||||||
|
},
|
||||||
|
transaction,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (exists) {
|
||||||
|
throw new FieldNameExistsError(name, collectionName);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
this.app.db.on('fields.beforeUpdate', beforeUpdateForValidateField(this.app.db));
|
this.app.db.on('fields.beforeUpdate', beforeUpdateForValidateField(this.app.db));
|
||||||
|
|
||||||
this.app.db.on('fields.beforeUpdate', async (model, options) => {
|
this.app.db.on('fields.beforeUpdate', async (model, options) => {
|
||||||
@ -308,6 +333,25 @@ export class PluginDataSourceMainServer extends Plugin {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
errorHandlerPlugin.errorHandler.register(
|
||||||
|
(err) => err instanceof FieldNameExistsError,
|
||||||
|
(err, ctx) => {
|
||||||
|
ctx.status = 400;
|
||||||
|
|
||||||
|
ctx.body = {
|
||||||
|
errors: [
|
||||||
|
{
|
||||||
|
message: ctx.i18n.t('field-name-exists', {
|
||||||
|
name: err.value,
|
||||||
|
collectionName: err.collectionName,
|
||||||
|
ns: 'data-source-main',
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
this.app.resourcer.use(async (ctx, next) => {
|
this.app.resourcer.use(async (ctx, next) => {
|
||||||
if (ctx.action.resourceName === 'collections.fields' && ['create', 'update'].includes(ctx.action.actionName)) {
|
if (ctx.action.resourceName === 'collections.fields' && ['create', 'update'].includes(ctx.action.actionName)) {
|
||||||
ctx.action.mergeParams({
|
ctx.action.mergeParams({
|
||||||
|
Loading…
x
Reference in New Issue
Block a user