feat: update option must have filter or filterByTk (#847)
* feat: update option must have filter or filterByTk * fix: typo * fix: typo (cherry picked from commit 83e6f93e1e3a188781530ec7492de1ed917a4dc1) # Conflicts: # packages/plugins/acl/src/server.ts # packages/plugins/collection-manager/src/__tests__/field-options/indexes.test.ts
This commit is contained in:
parent
ceed13d77e
commit
3082a7d6f8
@ -3,9 +3,9 @@ import { getRepositoryFromParams } from '../utils';
|
|||||||
|
|
||||||
export async function update(ctx: Context, next) {
|
export async function update(ctx: Context, next) {
|
||||||
const repository = getRepositoryFromParams(ctx);
|
const repository = getRepositoryFromParams(ctx);
|
||||||
const { filterByTk, values, whitelist, blacklist, filter, updateAssociationValues } = ctx.action.params;
|
const { forceUpdate, filterByTk, values, whitelist, blacklist, filter, updateAssociationValues } = ctx.action.params;
|
||||||
|
|
||||||
const instance = await repository.update({
|
ctx.body = await repository.update({
|
||||||
filterByTk,
|
filterByTk,
|
||||||
values,
|
values,
|
||||||
whitelist,
|
whitelist,
|
||||||
@ -13,8 +13,8 @@ export async function update(ctx: Context, next) {
|
|||||||
filter,
|
filter,
|
||||||
updateAssociationValues,
|
updateAssociationValues,
|
||||||
context: ctx,
|
context: ctx,
|
||||||
|
forceUpdate,
|
||||||
});
|
});
|
||||||
|
|
||||||
ctx.body = instance;
|
|
||||||
await next();
|
await next();
|
||||||
}
|
}
|
||||||
|
@ -87,6 +87,7 @@ describe('has one repository', () => {
|
|||||||
avatar: 'new_updated_avatar',
|
avatar: 'new_updated_avatar',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect((await UserProfileRepository.find())['avatar']).toEqual('new_updated_avatar');
|
expect((await UserProfileRepository.find())['avatar']).toEqual('new_updated_avatar');
|
||||||
await UserProfileRepository.destroy();
|
await UserProfileRepository.destroy();
|
||||||
expect(await UserProfileRepository.find()).toBeNull();
|
expect(await UserProfileRepository.find()).toBeNull();
|
||||||
|
@ -57,4 +57,39 @@ describe('update', () => {
|
|||||||
|
|
||||||
expect(p1.toJSON()['tags']).toEqual([]);
|
expect(p1.toJSON()['tags']).toEqual([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not update items without filter or filterByPk', async () => {
|
||||||
|
await db.getRepository('posts').create({
|
||||||
|
values: {
|
||||||
|
title: 'p1',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
let error;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await db.getRepository('posts').update({
|
||||||
|
values: {
|
||||||
|
title: 'p3',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
error = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(error).not.toBeUndefined();
|
||||||
|
|
||||||
|
const p1 = await db.getRepository('posts').findOne();
|
||||||
|
expect(p1.toJSON()['title']).toEqual('p1');
|
||||||
|
|
||||||
|
await db.getRepository('posts').update({
|
||||||
|
values: {
|
||||||
|
title: 'p3',
|
||||||
|
},
|
||||||
|
filterByTk: p1.get('id') as number,
|
||||||
|
});
|
||||||
|
|
||||||
|
await p1.reload();
|
||||||
|
expect(p1.toJSON()['title']).toEqual('p3');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
const mustHaveFilter = () => (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
|
||||||
|
const oldValue = descriptor.value;
|
||||||
|
|
||||||
|
descriptor.value = function () {
|
||||||
|
const options = arguments[0];
|
||||||
|
|
||||||
|
if (!options?.filter && !options?.filterByTk && !options?.forceUpdate) {
|
||||||
|
throw new Error(`must provide filter or filterByTk for ${propertyKey} call, or set forceUpdate to true`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return oldValue.apply(this, arguments);
|
||||||
|
};
|
||||||
|
|
||||||
|
return descriptor;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default mustHaveFilter;
|
@ -9,7 +9,7 @@ import {
|
|||||||
FindOptions,
|
FindOptions,
|
||||||
TargetKey,
|
TargetKey,
|
||||||
TK,
|
TK,
|
||||||
UpdateOptions
|
UpdateOptions,
|
||||||
} from '../repository';
|
} from '../repository';
|
||||||
import { updateModelByValues } from '../update-associations';
|
import { updateModelByValues } from '../update-associations';
|
||||||
import { UpdateGuard } from '../update-guard';
|
import { UpdateGuard } from '../update-guard';
|
||||||
|
@ -7,7 +7,7 @@ import FilterParser from '../filter-parser';
|
|||||||
import { Model } from '../model';
|
import { Model } from '../model';
|
||||||
import { OptionsParser } from '../options-parser';
|
import { OptionsParser } from '../options-parser';
|
||||||
import { CreateOptions, Filter, FindOptions } from '../repository';
|
import { CreateOptions, Filter, FindOptions } from '../repository';
|
||||||
import { transactionWrapperBuilder } from '../transaction-decorator';
|
import { transactionWrapperBuilder } from '../decorators/transaction-decorator';
|
||||||
import { updateAssociations } from '../update-associations';
|
import { updateAssociations } from '../update-associations';
|
||||||
import { UpdateGuard } from '../update-guard';
|
import { UpdateGuard } from '../update-guard';
|
||||||
|
|
||||||
|
@ -13,6 +13,8 @@ import {
|
|||||||
} from 'sequelize';
|
} from 'sequelize';
|
||||||
import { Collection } from './collection';
|
import { Collection } from './collection';
|
||||||
import { Database } from './database';
|
import { Database } from './database';
|
||||||
|
import mustHaveFilter from './decorators/must-have-filter-decorator';
|
||||||
|
import { transactionWrapperBuilder } from './decorators/transaction-decorator';
|
||||||
import { RelationField } from './fields';
|
import { RelationField } from './fields';
|
||||||
import FilterParser from './filter-parser';
|
import FilterParser from './filter-parser';
|
||||||
import { Model } from './model';
|
import { Model } from './model';
|
||||||
@ -22,7 +24,6 @@ import { BelongsToRepository } from './relation-repository/belongs-to-repository
|
|||||||
import { HasManyRepository } from './relation-repository/hasmany-repository';
|
import { HasManyRepository } from './relation-repository/hasmany-repository';
|
||||||
import { HasOneRepository } from './relation-repository/hasone-repository';
|
import { HasOneRepository } from './relation-repository/hasone-repository';
|
||||||
import { RelationRepository } from './relation-repository/relation-repository';
|
import { RelationRepository } from './relation-repository/relation-repository';
|
||||||
import { transactionWrapperBuilder } from './transaction-decorator';
|
|
||||||
import { updateAssociations, updateModelByValues } from './update-associations';
|
import { updateAssociations, updateModelByValues } from './update-associations';
|
||||||
import { UpdateGuard } from './update-guard';
|
import { UpdateGuard } from './update-guard';
|
||||||
|
|
||||||
@ -345,7 +346,8 @@ export class Repository<TModelAttributes extends {} = any, TCreationAttributes e
|
|||||||
* @param options
|
* @param options
|
||||||
*/
|
*/
|
||||||
@transaction()
|
@transaction()
|
||||||
async update(options: UpdateOptions) {
|
@mustHaveFilter()
|
||||||
|
async update(options: UpdateOptions & { forceUpdate?: boolean }) {
|
||||||
const transaction = await this.getTransaction(options);
|
const transaction = await this.getTransaction(options);
|
||||||
const guard = UpdateGuard.fromOptions(this.model, options);
|
const guard = UpdateGuard.fromOptions(this.model, options);
|
||||||
|
|
||||||
|
@ -26,14 +26,18 @@ describe('acl', () => {
|
|||||||
const UserRepo = db.getCollection('users').repository;
|
const UserRepo = db.getCollection('users').repository;
|
||||||
admin = await UserRepo.create({
|
admin = await UserRepo.create({
|
||||||
values: {
|
values: {
|
||||||
roles: ['admin']
|
roles: ['admin'],
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const userPlugin = app.getPlugin('@nocobase/plugin-users') as UsersPlugin;
|
const userPlugin = app.getPlugin('@nocobase/plugin-users') as UsersPlugin;
|
||||||
adminAgent = app.agent().auth(userPlugin.jwtService.sign({
|
|
||||||
|
adminAgent = app.agent().auth(
|
||||||
|
userPlugin.jwtService.sign({
|
||||||
userId: admin.get('id'),
|
userId: admin.get('id'),
|
||||||
}), { type: 'bearer' });
|
}),
|
||||||
|
{ type: 'bearer' },
|
||||||
|
);
|
||||||
|
|
||||||
uiSchemaRepository = db.getRepository('uiSchemas');
|
uiSchemaRepository = db.getRepository('uiSchemas');
|
||||||
});
|
});
|
||||||
@ -41,7 +45,7 @@ describe('acl', () => {
|
|||||||
it('should works with universal actions', async () => {
|
it('should works with universal actions', async () => {
|
||||||
await db.getRepository('roles').create({
|
await db.getRepository('roles').create({
|
||||||
values: {
|
values: {
|
||||||
name: 'new'
|
name: 'new',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -54,15 +58,14 @@ describe('acl', () => {
|
|||||||
).toBeNull();
|
).toBeNull();
|
||||||
|
|
||||||
// grant universal action
|
// grant universal action
|
||||||
await adminAgent
|
await adminAgent.resource('roles').update({
|
||||||
.resource('roles')
|
|
||||||
.update({
|
|
||||||
resourceIndex: 'new',
|
resourceIndex: 'new',
|
||||||
values: {
|
values: {
|
||||||
strategy: {
|
strategy: {
|
||||||
actions: ['create'],
|
actions: ['create'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
forceUpdate: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
@ -104,9 +107,7 @@ describe('acl', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
await adminAgent
|
await adminAgent.resource('roles.resources', 'new').create({
|
||||||
.resource('roles.resources', 'new')
|
|
||||||
.create({
|
|
||||||
values: {
|
values: {
|
||||||
name: 'c1',
|
name: 'c1',
|
||||||
usingActionsConfig: true,
|
usingActionsConfig: true,
|
||||||
@ -150,9 +151,9 @@ describe('acl', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// create c1 published scope
|
// create c1 published scope
|
||||||
const { body: { data: publishedScope } } = await adminAgent
|
const {
|
||||||
.resource('rolesResourcesScopes')
|
body: { data: publishedScope },
|
||||||
.create({
|
} = await adminAgent.resource('rolesResourcesScopes').create({
|
||||||
values: {
|
values: {
|
||||||
resourceName: 'c1',
|
resourceName: 'c1',
|
||||||
name: 'published',
|
name: 'published',
|
||||||
@ -165,9 +166,7 @@ describe('acl', () => {
|
|||||||
// await db.getRepository('rolesResourcesScopes').findOne();
|
// await db.getRepository('rolesResourcesScopes').findOne();
|
||||||
|
|
||||||
// set admin resources
|
// set admin resources
|
||||||
await adminAgent
|
await adminAgent.resource('roles.resources', 'new').create({
|
||||||
.resource('roles.resources', 'new')
|
|
||||||
.create({
|
|
||||||
values: {
|
values: {
|
||||||
name: 'c1',
|
name: 'c1',
|
||||||
usingActionsConfig: true,
|
usingActionsConfig: true,
|
||||||
@ -215,9 +214,7 @@ describe('acl', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// revoke action
|
// revoke action
|
||||||
const response = await adminAgent
|
const response = await adminAgent.resource('roles.resources', role.get('name')).list({
|
||||||
.resource('roles.resources', role.get('name'))
|
|
||||||
.list({
|
|
||||||
appends: ['actions'],
|
appends: ['actions'],
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -226,9 +223,7 @@ describe('acl', () => {
|
|||||||
const actions = response.body.data[0].actions;
|
const actions = response.body.data[0].actions;
|
||||||
const collectionName = response.body.data[0].name;
|
const collectionName = response.body.data[0].name;
|
||||||
|
|
||||||
await adminAgent
|
await adminAgent.resource('roles.resources', role.get('name')).update({
|
||||||
.resource('roles.resources', role.get('name'))
|
|
||||||
.update({
|
|
||||||
filterByTk: collectionName,
|
filterByTk: collectionName,
|
||||||
values: {
|
values: {
|
||||||
name: 'c1',
|
name: 'c1',
|
||||||
@ -254,7 +249,7 @@ describe('acl', () => {
|
|||||||
it('should revoke resource when collection destroy', async () => {
|
it('should revoke resource when collection destroy', async () => {
|
||||||
await db.getRepository('roles').create({
|
await db.getRepository('roles').create({
|
||||||
values: {
|
values: {
|
||||||
name: 'new'
|
name: 'new',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -272,9 +267,7 @@ describe('acl', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
await adminAgent
|
await adminAgent.resource('roles.resources').create({
|
||||||
.resource('roles.resources')
|
|
||||||
.create({
|
|
||||||
associatedIndex: 'new',
|
associatedIndex: 'new',
|
||||||
values: {
|
values: {
|
||||||
name: 'posts',
|
name: 'posts',
|
||||||
@ -314,7 +307,7 @@ describe('acl', () => {
|
|||||||
it('should revoke actions when not using actions config', async () => {
|
it('should revoke actions when not using actions config', async () => {
|
||||||
await db.getRepository('roles').create({
|
await db.getRepository('roles').create({
|
||||||
values: {
|
values: {
|
||||||
name: 'new'
|
name: 'new',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -325,9 +318,7 @@ describe('acl', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
await adminAgent
|
await adminAgent.resource('roles.resources').create({
|
||||||
.resource('roles.resources')
|
|
||||||
.create({
|
|
||||||
associatedIndex: 'new',
|
associatedIndex: 'new',
|
||||||
values: {
|
values: {
|
||||||
name: 'posts',
|
name: 'posts',
|
||||||
@ -352,9 +343,7 @@ describe('acl', () => {
|
|||||||
action: 'create',
|
action: 'create',
|
||||||
});
|
});
|
||||||
|
|
||||||
await adminAgent
|
await adminAgent.resource('roles.resources', 'new').update({
|
||||||
.resource('roles.resources', 'new')
|
|
||||||
.update({
|
|
||||||
filterByTk: (
|
filterByTk: (
|
||||||
await db.getRepository('rolesResources').findOne({
|
await db.getRepository('rolesResources').findOne({
|
||||||
filter: {
|
filter: {
|
||||||
@ -376,9 +365,7 @@ describe('acl', () => {
|
|||||||
}),
|
}),
|
||||||
).toBeNull();
|
).toBeNull();
|
||||||
|
|
||||||
await adminAgent
|
await adminAgent.resource('roles.resources', 'new').update({
|
||||||
.resource('roles.resources', 'new')
|
|
||||||
.update({
|
|
||||||
filterByTk: (
|
filterByTk: (
|
||||||
await db.getRepository('rolesResources').findOne({
|
await db.getRepository('rolesResources').findOne({
|
||||||
filter: {
|
filter: {
|
||||||
@ -408,7 +395,7 @@ describe('acl', () => {
|
|||||||
it('should add fields when field created', async () => {
|
it('should add fields when field created', async () => {
|
||||||
await db.getRepository('roles').create({
|
await db.getRepository('roles').create({
|
||||||
values: {
|
values: {
|
||||||
name: 'new'
|
name: 'new',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -426,9 +413,7 @@ describe('acl', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
await adminAgent
|
await adminAgent.resource('roles.resources').create({
|
||||||
.resource('roles.resources')
|
|
||||||
.create({
|
|
||||||
associatedIndex: 'new',
|
associatedIndex: 'new',
|
||||||
values: {
|
values: {
|
||||||
name: 'posts',
|
name: 'posts',
|
||||||
@ -494,14 +479,17 @@ describe('acl', () => {
|
|||||||
const UserRepo = db.getCollection('users').repository;
|
const UserRepo = db.getCollection('users').repository;
|
||||||
const user = await UserRepo.create({
|
const user = await UserRepo.create({
|
||||||
values: {
|
values: {
|
||||||
roles: ['new']
|
roles: ['new'],
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const userPlugin = app.getPlugin('@nocobase/plugin-users') as UsersPlugin;
|
const userPlugin = app.getPlugin('@nocobase/plugin-users') as UsersPlugin;
|
||||||
const userAgent = app.agent().auth(userPlugin.jwtService.sign({
|
const userAgent = app.agent().auth(
|
||||||
|
userPlugin.jwtService.sign({
|
||||||
userId: user.get('id'),
|
userId: user.get('id'),
|
||||||
}), { type: 'bearer' });
|
}),
|
||||||
|
{ type: 'bearer' },
|
||||||
|
);
|
||||||
|
|
||||||
const schema = {
|
const schema = {
|
||||||
'x-uid': 'test',
|
'x-uid': 'test',
|
||||||
|
@ -17,7 +17,6 @@ export async function prepareApp() {
|
|||||||
app.plugin(PluginUiSchema);
|
app.plugin(PluginUiSchema);
|
||||||
app.plugin(PluginErrorHandler);
|
app.plugin(PluginErrorHandler);
|
||||||
app.plugin(PluginCollectionManager);
|
app.plugin(PluginCollectionManager);
|
||||||
|
|
||||||
app.plugin(PluginACL);
|
app.plugin(PluginACL);
|
||||||
await app.loadAndInstall();
|
await app.loadAndInstall();
|
||||||
|
|
||||||
|
@ -32,14 +32,17 @@ describe('role api', () => {
|
|||||||
const UserRepo = db.getCollection('users').repository;
|
const UserRepo = db.getCollection('users').repository;
|
||||||
admin = await UserRepo.create({
|
admin = await UserRepo.create({
|
||||||
values: {
|
values: {
|
||||||
roles: ['admin']
|
roles: ['admin'],
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const userPlugin = app.getPlugin('@nocobase/plugin-users') as UsersPlugin;
|
const userPlugin = app.getPlugin('@nocobase/plugin-users') as UsersPlugin;
|
||||||
adminAgent = app.agent().auth(userPlugin.jwtService.sign({
|
adminAgent = app.agent().auth(
|
||||||
|
userPlugin.jwtService.sign({
|
||||||
userId: admin.get('id'),
|
userId: admin.get('id'),
|
||||||
}), { type: 'bearer' });
|
}),
|
||||||
|
{ type: 'bearer' },
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should list actions', async () => {
|
it('should list actions', async () => {
|
||||||
@ -49,9 +52,8 @@ describe('role api', () => {
|
|||||||
|
|
||||||
it('should grant universal role actions', async () => {
|
it('should grant universal role actions', async () => {
|
||||||
// grant role actions
|
// grant role actions
|
||||||
const response = await adminAgent
|
const response = await adminAgent.resource('roles').update({
|
||||||
.resource('roles')
|
forceUpdate: true,
|
||||||
.update({
|
|
||||||
values: {
|
values: {
|
||||||
strategy: {
|
strategy: {
|
||||||
actions: ['create:all', 'view:own'],
|
actions: ['create:all', 'view:own'],
|
||||||
|
@ -416,10 +416,12 @@ export class PluginACL extends Plugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const User = this.db.getCollection('users');
|
const User = this.db.getCollection('users');
|
||||||
|
|
||||||
await User.repository.update({
|
await User.repository.update({
|
||||||
values: {
|
values: {
|
||||||
roles: ['root', 'admin', 'member'],
|
roles: ['root', 'admin', 'member'],
|
||||||
},
|
},
|
||||||
|
forceUpdate: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const RolesUsers = this.db.getCollection('rolesUsers');
|
const RolesUsers = this.db.getCollection('rolesUsers');
|
||||||
|
@ -8,9 +8,7 @@ describe('field indexes', () => {
|
|||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
app = await createApp();
|
app = await createApp();
|
||||||
agent = app.agent();
|
agent = app.agent();
|
||||||
await agent
|
await agent.resource('collections').create({
|
||||||
.resource('collections')
|
|
||||||
.create({
|
|
||||||
values: {
|
values: {
|
||||||
name: 'test1',
|
name: 'test1',
|
||||||
},
|
},
|
||||||
@ -21,60 +19,59 @@ describe('field indexes', () => {
|
|||||||
await app.destroy();
|
await app.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it.only('create unique constraint after added dulplicated records', async () => {
|
it('create unique constraint after added duplicated records', async () => {
|
||||||
const tableName = 'test1';
|
const tableName = 'test1';
|
||||||
// create an field with unique constraint
|
// create an field with unique constraint
|
||||||
const field = await agent
|
const field = await agent.resource('collections.fields', tableName).create({
|
||||||
.resource('collections.fields', tableName)
|
|
||||||
.create({
|
|
||||||
values: {
|
values: {
|
||||||
name: 'title',
|
name: 'title',
|
||||||
type: 'string'
|
type: 'string',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// create a record
|
// create a record
|
||||||
const response1 = await agent.resource(tableName).create({
|
const response1 = await agent.resource(tableName).create({
|
||||||
values: { title: 't1' }
|
values: { title: 't1' },
|
||||||
});
|
});
|
||||||
|
|
||||||
// create another same record
|
// create another same record
|
||||||
const response2 = await agent.resource(tableName).create({
|
const response2 = await agent.resource(tableName).create({
|
||||||
values: { title: 't1' }
|
values: { title: 't1' },
|
||||||
});
|
});
|
||||||
|
|
||||||
const response3 = await agent.resource('fields').update({
|
const response3 = await agent.resource('fields').update({
|
||||||
filterByTk: field.id,
|
filterByTk: field.body.data.key,
|
||||||
values: {
|
values: {
|
||||||
unique: true
|
unique: true,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(response3.status).toBe(400);
|
expect(response3.status).toBe(400);
|
||||||
|
|
||||||
const response4 = await agent.resource(tableName).create({
|
const response4 = await agent.resource(tableName).create({
|
||||||
values: { title: 't1' }
|
values: { title: 't1' },
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(response4.status).toBe(200);
|
expect(response4.status).toBe(200);
|
||||||
expect(response4.body.data.title).toBe('t1');
|
expect(response4.body.data.title).toBe('t1');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('field value cannot be duplicated with unique index', async () => {
|
it('field value cannot be duplicated with unique index', async () => {
|
||||||
const tableName = 'test1';
|
const tableName = 'test1';
|
||||||
// create an field with unique constraint
|
// create a field with unique constraint
|
||||||
const field = await agent
|
const field = await agent.resource('collections.fields', tableName).create({
|
||||||
.resource('collections.fields', tableName)
|
|
||||||
.create({
|
|
||||||
values: {
|
values: {
|
||||||
name: 'title',
|
name: 'title',
|
||||||
type: 'string',
|
type: 'string',
|
||||||
unique: true
|
unique: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// create a record
|
// create a record
|
||||||
const response1 = await agent.resource(tableName).create({
|
const response1 = await agent.resource(tableName).create({
|
||||||
values: {
|
values: {
|
||||||
title: 't1'
|
title: 't1',
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
expect(response1.status).toBe(200);
|
expect(response1.status).toBe(200);
|
||||||
expect(response1.body.data.title).toBe('t1');
|
expect(response1.body.data.title).toBe('t1');
|
||||||
@ -82,48 +79,49 @@ describe('field indexes', () => {
|
|||||||
// create another record with the same value on unique field should fail
|
// create another record with the same value on unique field should fail
|
||||||
const response2 = await agent.resource(tableName).create({
|
const response2 = await agent.resource(tableName).create({
|
||||||
values: {
|
values: {
|
||||||
title: 't1'
|
title: 't1',
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
expect(response2.status).toBe(400);
|
expect(response2.status).toBe(400);
|
||||||
|
|
||||||
// update field to remove unique constraint
|
// update field to remove unique constraint
|
||||||
await agent.resource('fields').update({
|
await agent.resource('fields').update({
|
||||||
filterByTk: field.id,
|
filterByTk: field.body.data.key,
|
||||||
values: {
|
values: {
|
||||||
unique: false
|
unique: false,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// create another record with the same value on unique field should be ok
|
// create another record with the same value on unique field should be ok
|
||||||
const response3 = await agent.resource(tableName).create({
|
const response3 = await agent.resource(tableName).create({
|
||||||
values: {
|
values: {
|
||||||
title: 't1'
|
title: 't1',
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
expect(response3.status).toBe(200);
|
expect(response3.status).toBe(200);
|
||||||
expect(response3.body.data.title).toBe('t1');
|
expect(response3.body.data.title).toBe('t1');
|
||||||
|
|
||||||
// update field to add unique constraint should fail because of duplicated records
|
// update field to add unique constraint should fail because of duplicated records
|
||||||
const response4 = await agent.resource('fields').update({
|
const response4 = await agent.resource('fields').update({
|
||||||
filterByTk: field.id,
|
filterByTk: field.body.data.key,
|
||||||
values: {
|
values: {
|
||||||
unique: true
|
unique: true,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(response4.status).toBe(400);
|
expect(response4.status).toBe(400);
|
||||||
|
|
||||||
// remove a duplicated record
|
// remove a duplicated record
|
||||||
await agent.resource(tableName).destroy({
|
await agent.resource(tableName).destroy({
|
||||||
filterByTk: response3.body.data.id
|
filterByTk: response3.body.data.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
// update field to add unique constraint should be ok
|
// update field to add unique constraint should be ok
|
||||||
const response6 = await agent.resource('fields').update({
|
const response6 = await agent.resource('fields').update({
|
||||||
filterByTk: field.id,
|
filterByTk: field.body.data.key,
|
||||||
values: {
|
values: {
|
||||||
unique: true
|
unique: true,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
expect(response6.status).toBe(200);
|
expect(response6.status).toBe(200);
|
||||||
});
|
});
|
||||||
|
@ -11,7 +11,7 @@ import {
|
|||||||
afterCreateForReverseField,
|
afterCreateForReverseField,
|
||||||
beforeCreateForChildrenCollection,
|
beforeCreateForChildrenCollection,
|
||||||
beforeCreateForReverseField,
|
beforeCreateForReverseField,
|
||||||
beforeInitOptions
|
beforeInitOptions,
|
||||||
} from './hooks';
|
} from './hooks';
|
||||||
import { CollectionModel, FieldModel } from './models';
|
import { CollectionModel, FieldModel } from './models';
|
||||||
|
|
||||||
@ -67,7 +67,7 @@ export class CollectionManagerPlugin extends Plugin {
|
|||||||
if (context) {
|
if (context) {
|
||||||
await model.migrate({
|
await model.migrate({
|
||||||
isNew: true,
|
isNew: true,
|
||||||
transaction
|
transaction,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -76,7 +76,7 @@ export class CollectionManagerPlugin extends Plugin {
|
|||||||
if (context) {
|
if (context) {
|
||||||
await model.migrate({
|
await model.migrate({
|
||||||
isNew: true,
|
isNew: true,
|
||||||
transaction
|
transaction,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user