feat: rename resourceKey & associatedKey to resourceIndex & associatedIndex (#126)

* resourceIndex & associatedIndex

* resourceIndex & associatedIndex
This commit is contained in:
chenos 2021-12-04 16:28:52 +08:00 committed by GitHub
parent 62796f136c
commit c1b560e928
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
50 changed files with 273 additions and 269 deletions

View File

@ -1,4 +1,6 @@
const path = require('path'); const path = require('path');
const { pathsToModuleNameMapper } = require('ts-jest/utils');
const { compilerOptions } = require('./tsconfig.jest.json');
module.exports = { module.exports = {
preset: 'ts-jest', preset: 'ts-jest',
@ -10,6 +12,9 @@ module.exports = {
// '**/__tests__/**/*.[jt]s?(x)', // '**/__tests__/**/*.[jt]s?(x)',
'**/?(*.)+(spec|test).[jt]s?(x)' '**/?(*.)+(spec|test).[jt]s?(x)'
], ],
moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths, {
prefix: '<rootDir>/',
}),
modulePathIgnorePatterns: [ modulePathIgnorePatterns: [
"<rootDir>/.dumi/", "<rootDir>/.dumi/",
"<rootDir>/packages/father-build/", "<rootDir>/packages/father-build/",

View File

@ -23,7 +23,7 @@ describe('create', () => {
], ],
}); });
await api.db.sync(); await api.db.sync();
const response = await api.resource('tests').create({ const response = await api.agent().resource('tests').create({
values: { name: 'n1' }, values: { name: 'n1' },
}); });
expect(response.body.name).toBe('n1'); expect(response.body.name).toBe('n1');
@ -45,7 +45,7 @@ describe('create', () => {
}); });
await api.db.sync(); await api.db.sync();
const [Post, Comment] = api.db.getModels(['posts', 'comments']); const [Post, Comment] = api.db.getModels(['posts', 'comments']);
const response = await api.resource('posts').create({ const response = await api.agent().resource('posts').create({
values: { values: {
title: 't1', title: 't1',
comments: [ comments: [
@ -56,8 +56,8 @@ describe('create', () => {
}); });
expect(await Post.count()).toBe(1); expect(await Post.count()).toBe(1);
expect(await Comment.count()).toBe(2); expect(await Comment.count()).toBe(2);
await api.resource('posts.comments').create({ await api.agent().resource('posts.comments').create({
associatedKey: response.body.id, associatedIndex: response.body.id,
values: { content: 'c1' }, values: { content: 'c1' },
}); });
expect(await Comment.count()).toBe(3); expect(await Comment.count()).toBe(3);

View File

@ -9,14 +9,14 @@ describe('destroy', () => {
dataWrapping: false, dataWrapping: false,
}); });
registerActions(api); registerActions(api);
api.db.table({ api.collection({
name: 'posts', name: 'posts',
fields: [ fields: [
{ type: 'string', name: 'title' }, { type: 'string', name: 'title' },
{ type: 'hasMany', name: 'comments' }, { type: 'hasMany', name: 'comments' },
], ],
}); });
api.db.table({ api.collection({
name: 'comments', name: 'comments',
fields: [{ type: 'string', name: 'content' }], fields: [{ type: 'string', name: 'content' }],
}); });
@ -35,8 +35,8 @@ describe('destroy', () => {
where: { id: post.id }, where: { id: post.id },
}), }),
).toBe(1); ).toBe(1);
await api.resource('posts').destroy({ await api.agent().resource('posts').destroy({
resourceKey: post.id, resourceIndex: post.id,
}); });
expect( expect(
await Post.count({ await Post.count({
@ -52,9 +52,9 @@ describe('destroy', () => {
await post.updateAssociations({ await post.updateAssociations({
comments: [comment], comments: [comment],
}); });
await api.resource('posts.comments').destroy({ await api.agent().resource('posts.comments').destroy({
resourceKey: comment.id, resourceIndex: comment.id,
associatedKey: post.id, associatedIndex: post.id,
}); });
const comment2 = await Comment.findByPk(comment.id); const comment2 = await Comment.findByPk(comment.id);
expect(comment2).toBeNull(); expect(comment2).toBeNull();

View File

@ -32,8 +32,8 @@ describe('get', () => {
it('get', async () => { it('get', async () => {
const Post = api.db.getModel('posts'); const Post = api.db.getModel('posts');
const post = await Post.create({ title: 't1' }); const post = await Post.create({ title: 't1' });
const response = await api.resource('posts').get({ const response = await api.agent().resource('posts').get({
resourceKey: post.id, resourceIndex: post.id,
fields: ['id', 'title'] fields: ['id', 'title']
}); });
expect(post.toJSON()).toMatchObject(response.body); expect(post.toJSON()).toMatchObject(response.body);
@ -46,9 +46,9 @@ describe('get', () => {
await post.updateAssociations({ await post.updateAssociations({
comments: [comment] comments: [comment]
}); });
const response = await api.resource('posts.comments').get({ const response = await api.agent().resource('posts.comments').get({
resourceKey: comment.id, resourceIndex: comment.id,
associatedKey: post.id, associatedIndex: post.id,
fields: ['id', 'post_id', 'content'] fields: ['id', 'post_id', 'content']
}); });
const comment2 = await Comment.findByPk(comment.id); const comment2 = await Comment.findByPk(comment.id);

View File

@ -40,7 +40,7 @@ describe('list', () => {
describe('fields', () => { describe('fields', () => {
it('fields', async () => { it('fields', async () => {
const response = await api.resource('posts').list({ const response = await api.agent().resource('posts').list({
fields: ['title'], fields: ['title'],
filter: { filter: {
title: 't1', title: 't1',
@ -55,7 +55,7 @@ describe('list', () => {
}); });
it('fields#appends', async () => { it('fields#appends', async () => {
const response = await api.resource('posts').list({ const response = await api.agent().resource('posts').list({
fields: { fields: {
appends: ['comments'], appends: ['comments'],
}, },
@ -89,7 +89,7 @@ describe('list', () => {
describe('filter', () => { describe('filter', () => {
it('and', async () => { it('and', async () => {
const response = await api.resource('posts').list({ const response = await api.agent().resource('posts').list({
filter: { filter: {
and: [ and: [
{ title: 't1' }, { title: 't1' },
@ -109,7 +109,7 @@ describe('list', () => {
}); });
}); });
it('or', async () => { it('or', async () => {
const response = await api.resource('posts').list({ const response = await api.agent().resource('posts').list({
filter: { filter: {
or: [ or: [
{ title: 't1' }, { title: 't1' },

View File

@ -31,11 +31,11 @@ describe('sort', () => {
}); });
it('targetId', async () => { it('targetId', async () => {
await api.resource('tests').sort({ await api.agent().resource('tests').sort({
sourceId: 1, sourceId: 1,
targetId: 3, targetId: 3,
}); });
const response = await api.resource('tests').list({ const response = await api.agent().resource('tests').list({
sort: ['sort'], sort: ['sort'],
}); });
expect(response.body).toMatchObject({ expect(response.body).toMatchObject({
@ -61,11 +61,11 @@ describe('sort', () => {
}); });
it('targetId', async () => { it('targetId', async () => {
await api.resource('tests').sort({ await api.agent().resource('tests').sort({
sourceId: 3, sourceId: 3,
targetId: 1, targetId: 1,
}); });
const response = await api.resource('tests').list({ const response = await api.agent().resource('tests').list({
sort: ['sort'], sort: ['sort'],
}); });
expect(response.body).toMatchObject({ expect(response.body).toMatchObject({
@ -91,12 +91,12 @@ describe('sort', () => {
}); });
it('sortField', async () => { it('sortField', async () => {
await api.resource('tests').sort({ await api.agent().resource('tests').sort({
sortField: 'sort2', sortField: 'sort2',
sourceId: 1, sourceId: 1,
targetId: 3, targetId: 3,
}); });
const response = await api.resource('tests').list({ const response = await api.agent().resource('tests').list({
sort: ['sort2'], sort: ['sort2'],
}); });
expect(response.body).toMatchObject({ expect(response.body).toMatchObject({
@ -122,11 +122,11 @@ describe('sort', () => {
}); });
it('sticky', async () => { it('sticky', async () => {
await api.resource('tests').sort({ await api.agent().resource('tests').sort({
sourceId: 3, sourceId: 3,
sticky: true, sticky: true,
}); });
const response = await api.resource('tests').list({ const response = await api.agent().resource('tests').list({
sort: ['sort'], sort: ['sort'],
}); });
expect(response.body).toMatchObject({ expect(response.body).toMatchObject({
@ -183,11 +183,11 @@ describe('sort', () => {
}); });
it('targetId/1->6', async () => { it('targetId/1->6', async () => {
await api.resource('tests').sort({ await api.agent().resource('tests').sort({
sourceId: 1, sourceId: 1,
targetId: 6, targetId: 6,
}); });
let response = await api.resource('tests').list({ let response = await api.agent().resource('tests').list({
sort: ['sort'], sort: ['sort'],
filter: { state: 1 }, filter: { state: 1 },
}); });
@ -207,7 +207,7 @@ describe('sort', () => {
}, },
], ],
}); });
response = await api.resource('tests').list({ response = await api.agent().resource('tests').list({
sort: ['sort'], sort: ['sort'],
filter: { state: 2 }, filter: { state: 2 },
}); });
@ -238,12 +238,12 @@ describe('sort', () => {
}); });
it('targetId/1->6 - method=insertAfter', async () => { it('targetId/1->6 - method=insertAfter', async () => {
await api.resource('tests').sort({ await api.agent().resource('tests').sort({
sourceId: 1, sourceId: 1,
targetId: 6, targetId: 6,
method: 'insertAfter', method: 'insertAfter',
}); });
let response = await api.resource('tests').list({ let response = await api.agent().resource('tests').list({
sort: ['sort'], sort: ['sort'],
filter: { state: 1 }, filter: { state: 1 },
}); });
@ -263,7 +263,7 @@ describe('sort', () => {
}, },
], ],
}); });
response = await api.resource('tests').list({ response = await api.agent().resource('tests').list({
sort: ['sort'], sort: ['sort'],
filter: { state: 2 }, filter: { state: 2 },
}); });
@ -294,11 +294,11 @@ describe('sort', () => {
}); });
it('targetId/6->2', async () => { it('targetId/6->2', async () => {
await api.resource('tests').sort({ await api.agent().resource('tests').sort({
sourceId: 6, sourceId: 6,
targetId: 2, targetId: 2,
}); });
let response = await api.resource('tests').list({ let response = await api.agent().resource('tests').list({
sort: ['sort'], sort: ['sort'],
filter: { state: 1 }, filter: { state: 1 },
}); });
@ -326,7 +326,7 @@ describe('sort', () => {
}, },
], ],
}); });
response = await api.resource('tests').list({ response = await api.agent().resource('tests').list({
sort: ['sort'], sort: ['sort'],
filter: { state: 2 }, filter: { state: 2 },
}); });
@ -349,12 +349,12 @@ describe('sort', () => {
}); });
it('targetId/6->2 - method=insertAfter', async () => { it('targetId/6->2 - method=insertAfter', async () => {
await api.resource('tests').sort({ await api.agent().resource('tests').sort({
sourceId: 6, sourceId: 6,
targetId: 2, targetId: 2,
method: 'insertAfter', method: 'insertAfter',
}); });
let response = await api.resource('tests').list({ let response = await api.agent().resource('tests').list({
sort: ['sort'], sort: ['sort'],
filter: { state: 1 }, filter: { state: 1 },
}); });
@ -382,7 +382,7 @@ describe('sort', () => {
}, },
], ],
}); });
response = await api.resource('tests').list({ response = await api.agent().resource('tests').list({
sort: ['sort'], sort: ['sort'],
filter: { state: 2 }, filter: { state: 2 },
}); });
@ -405,13 +405,13 @@ describe('sort', () => {
}); });
it('targetScope', async () => { it('targetScope', async () => {
await api.resource('tests').sort({ await api.agent().resource('tests').sort({
sourceId: 1, sourceId: 1,
targetScope: { targetScope: {
state: 2, state: 2,
}, },
}); });
let response = await api.resource('tests').list({ let response = await api.agent().resource('tests').list({
sort: ['sort'], sort: ['sort'],
filter: { state: 1 }, filter: { state: 1 },
}); });
@ -431,7 +431,7 @@ describe('sort', () => {
}, },
], ],
}); });
response = await api.resource('tests').list({ response = await api.agent().resource('tests').list({
sort: ['sort'], sort: ['sort'],
filter: { state: 2 }, filter: { state: 2 },
}); });
@ -462,14 +462,14 @@ describe('sort', () => {
}); });
it('targetScope - method=prepend', async () => { it('targetScope - method=prepend', async () => {
await api.resource('tests').sort({ await api.agent().resource('tests').sort({
sourceId: 1, sourceId: 1,
targetScope: { targetScope: {
state: 2, state: 2,
}, },
method: 'prepend', method: 'prepend',
}); });
let response = await api.resource('tests').list({ let response = await api.agent().resource('tests').list({
sort: ['sort'], sort: ['sort'],
filter: { state: 1 }, filter: { state: 1 },
}); });
@ -486,7 +486,7 @@ describe('sort', () => {
}, },
], ],
}); });
response = await api.resource('tests').list({ response = await api.agent().resource('tests').list({
sort: ['sort'], sort: ['sort'],
filter: { state: 2 }, filter: { state: 2 },
}); });

View File

@ -32,8 +32,8 @@ describe('update', () => {
it('update', async () => { it('update', async () => {
const Post = api.db.getModel('posts'); const Post = api.db.getModel('posts');
const post = await Post.create(); const post = await Post.create();
await api.resource('posts').update({ await api.agent().resource('posts').update({
resourceKey: post.id, resourceIndex: post.id,
values: { values: {
title: 't1', title: 't1',
}, },
@ -51,9 +51,9 @@ describe('update', () => {
await post.updateAssociations({ await post.updateAssociations({
comments: [comment] comments: [comment]
}); });
await api.resource('posts.comments').update({ await api.agent().resource('posts.comments').update({
resourceKey: comment.id, resourceIndex: comment.id,
associatedKey: post.id, associatedIndex: post.id,
values: { values: {
content: 'c2', content: 'c2',
}, },

View File

@ -28,7 +28,7 @@ export async function add(ctx: Context, next: Next) {
throw new Error(`${associatedName} associated model invalid`); throw new Error(`${associatedName} associated model invalid`);
} }
const { add: addAccessor } = resourceField.getAccessors(); const { add: addAccessor } = resourceField.getAccessors();
const { resourceKey, resourceKeyAttribute, fields = [] } = ctx.action.params; const { resourceIndex, resourceIndexAttribute, fields = [] } = ctx.action.params;
const TargetModel = ctx.db.getModel(resourceField.getTarget()); const TargetModel = ctx.db.getModel(resourceField.getTarget());
// const options = TargetModel.parseApiJson({ // const options = TargetModel.parseApiJson({
// fields, // fields,
@ -36,7 +36,7 @@ export async function add(ctx: Context, next: Next) {
const model = await TargetModel.findOne({ const model = await TargetModel.findOne({
// ...options, // ...options,
where: { where: {
[resourceKeyAttribute || resourceField.options.targetKey || TargetModel.primaryKeyAttribute]: resourceKey, [resourceIndexAttribute || resourceField.options.targetKey || TargetModel.primaryKeyAttribute]: resourceIndex,
}, },
// @ts-ignore // @ts-ignore
context: ctx, context: ctx,

View File

@ -27,8 +27,8 @@ export async function destroy(ctx: Context, next: Next) {
resourceField, resourceField,
associatedName, associatedName,
resourceName, resourceName,
resourceKey, resourceIndex,
resourceKeyAttribute, resourceIndexAttribute,
filter, filter,
} = ctx.action.params; } = ctx.action.params;
const transaction = await ctx.db.sequelize.transaction(); const transaction = await ctx.db.sequelize.transaction();
@ -58,11 +58,11 @@ export async function destroy(ctx: Context, next: Next) {
resourceField instanceof BELONGSTOMANY resourceField instanceof BELONGSTOMANY
) { ) {
const primaryKey = const primaryKey =
resourceKeyAttribute || resourceIndexAttribute ||
resourceField.options.targetKey || resourceField.options.targetKey ||
TargetModel.primaryKeyAttribute; TargetModel.primaryKeyAttribute;
const models: Model[] = await associated[getAccessor]({ const models: Model[] = await associated[getAccessor]({
where: resourceKey ? { [primaryKey]: resourceKey } : where, where: resourceIndex ? { [primaryKey]: resourceIndex } : where,
...commonOptions, ...commonOptions,
}); });
// TODO不能程序上解除关系直接通过 onDelete 触发,或者通过 afterDestroy 处理 // TODO不能程序上解除关系直接通过 onDelete 触发,或者通过 afterDestroy 处理
@ -79,9 +79,9 @@ export async function destroy(ctx: Context, next: Next) {
} else { } else {
const Model = ctx.db.getModel(resourceName); const Model = ctx.db.getModel(resourceName);
const { where } = Model.parseApiJson({ filter, context: ctx }); const { where } = Model.parseApiJson({ filter, context: ctx });
const primaryKey = resourceKeyAttribute || Model.primaryKeyAttribute; const primaryKey = resourceIndexAttribute || Model.primaryKeyAttribute;
count = await Model.destroy({ count = await Model.destroy({
where: resourceKey ? { [primaryKey]: resourceKey } : where, where: resourceIndex ? { [primaryKey]: resourceIndex } : where,
// @ts-ignore hooks 里添加 context // @ts-ignore hooks 里添加 context
...commonOptions, ...commonOptions,
individualHooks: true, individualHooks: true,

View File

@ -20,8 +20,8 @@ export async function get(ctx: Context, next: Next) {
resourceField, resourceField,
associatedName, associatedName,
resourceName, resourceName,
resourceKey, resourceIndex,
resourceKeyAttribute, resourceIndexAttribute,
fields = [] fields = []
} = ctx.action.params; } = ctx.action.params;
if (associated && resourceField) { if (associated && resourceField) {
@ -50,7 +50,7 @@ export async function get(ctx: Context, next: Next) {
const [model]: Model[] = await associated[getAccessor]({ const [model]: Model[] = await associated[getAccessor]({
...options, ...options,
where: { where: {
[resourceKeyAttribute || resourceField.options.targetKey || TargetModel.primaryKeyAttribute]: resourceKey, [resourceIndexAttribute || resourceField.options.targetKey || TargetModel.primaryKeyAttribute]: resourceIndex,
}, },
context: ctx, context: ctx,
}); });
@ -64,7 +64,7 @@ export async function get(ctx: Context, next: Next) {
const data = await Model.findOne({ const data = await Model.findOne({
...options, ...options,
where: { where: {
[resourceKeyAttribute || Model.primaryKeyAttribute]: resourceKey, [resourceIndexAttribute || Model.primaryKeyAttribute]: resourceIndex,
}, },
// @ts-ignore hooks 里添加 context // @ts-ignore hooks 里添加 context
context: ctx, context: ctx,

View File

@ -33,7 +33,7 @@ export async function remove(ctx: Context, next: Next) {
throw new Error(`${associatedName} associated model invalid`); throw new Error(`${associatedName} associated model invalid`);
} }
const { get: getAccessor, remove: removeAccessor, set: setAccessor } = resourceField.getAccessors(); const { get: getAccessor, remove: removeAccessor, set: setAccessor } = resourceField.getAccessors();
const { resourceKey, resourceKeyAttribute, fields = [] } = ctx.action.params; const { resourceIndex, resourceIndexAttribute, fields = [] } = ctx.action.params;
const TargetModel = ctx.db.getModel(resourceField.getTarget()); const TargetModel = ctx.db.getModel(resourceField.getTarget());
const options = TargetModel.parseApiJson({ const options = TargetModel.parseApiJson({
fields, fields,
@ -44,7 +44,7 @@ export async function remove(ctx: Context, next: Next) {
const [model]: Model[] = await associated[getAccessor]({ const [model]: Model[] = await associated[getAccessor]({
...options, ...options,
where: { where: {
[resourceKeyAttribute || resourceField.options.targetKey || TargetModel.primaryKeyAttribute]: resourceKey, [resourceIndexAttribute || resourceField.options.targetKey || TargetModel.primaryKeyAttribute]: resourceIndex,
}, },
context: ctx, context: ctx,
}); });

View File

@ -33,14 +33,14 @@ export async function set(ctx: Context, next: Next) {
throw new Error(`${associatedName} associated model invalid`); throw new Error(`${associatedName} associated model invalid`);
} }
const { set: setAccessor } = resourceField.getAccessors(); const { set: setAccessor } = resourceField.getAccessors();
const { resourceKey, resourceKeyAttribute, fields = [] } = ctx.action.params; const { resourceIndex, resourceIndexAttribute, fields = [] } = ctx.action.params;
const TargetModel = ctx.db.getModel(resourceField.getTarget()); const TargetModel = ctx.db.getModel(resourceField.getTarget());
// const options = TargetModel.parseApiJson({ // const options = TargetModel.parseApiJson({
// fields, // fields,
// }); // });
const model = await TargetModel.findOne({ const model = await TargetModel.findOne({
where: { where: {
[resourceKeyAttribute || resourceField.options.targetKey || TargetModel.primaryKeyAttribute]: resourceKey, [resourceIndexAttribute || resourceField.options.targetKey || TargetModel.primaryKeyAttribute]: resourceIndex,
}, },
// @ts-ignore // @ts-ignore
context: ctx, context: ctx,

View File

@ -18,10 +18,10 @@ import {
export async function sort(ctx: Context, next: Next) { export async function sort(ctx: Context, next: Next) {
const { const {
resourceName, resourceName,
resourceKey, resourceIndex,
resourceField, resourceField,
associatedName, associatedName,
associatedKey, associatedIndex,
associated, associated,
values = {}, values = {},
...others ...others
@ -41,7 +41,7 @@ export async function sort(ctx: Context, next: Next) {
const table = ctx.db.getTable(resourceName); const table = ctx.db.getTable(resourceName);
const { primaryKeyAttribute } = Model; const { primaryKeyAttribute } = Model;
const sourceId = others.sourceId || resourceKey; const sourceId = others.sourceId || resourceIndex;
const field = others.sortField || values?.sortField || values?.field || 'sort'; const field = others.sortField || values?.sortField || values?.field || 'sort';
const targetId = others.targetId || values?.targetId || values?.target?.[primaryKeyAttribute]; const targetId = others.targetId || values?.targetId || values?.target?.[primaryKeyAttribute];
const method = others.method || values?.method; const method = others.method || values?.method;
@ -70,7 +70,7 @@ export async function sort(ctx: Context, next: Next) {
const where = {}; const where = {};
if (associated && resourceField instanceof HASMANY) { if (associated && resourceField instanceof HASMANY) {
where[resourceField.options.foreignKey] = associatedKey; where[resourceField.options.foreignKey] = associatedIndex;
} }
// 找到操作对象 // 找到操作对象

View File

@ -24,20 +24,20 @@ export async function toggle(ctx: Context, next: Next) {
throw new Error(`${associatedName} associated model invalid`); throw new Error(`${associatedName} associated model invalid`);
} }
const { get: getAccessor, remove: removeAccessor, set: setAccessor, add: addAccessor } = resourceField.getAccessors(); const { get: getAccessor, remove: removeAccessor, set: setAccessor, add: addAccessor } = resourceField.getAccessors();
const { resourceKey, resourceKeyAttribute, fields = [] } = ctx.action.params; const { resourceIndex, resourceIndexAttribute, fields = [] } = ctx.action.params;
const TargetModel = ctx.db.getModel(resourceField.getTarget()); const TargetModel = ctx.db.getModel(resourceField.getTarget());
const options = TargetModel.parseApiJson({ const options = TargetModel.parseApiJson({
fields, fields,
}); });
if (resourceField instanceof HASONE || resourceField instanceof BELONGSTO) { if (resourceField instanceof HASONE || resourceField instanceof BELONGSTO) {
const m1 = await associated[getAccessor](); const m1 = await associated[getAccessor]();
if (m1 && m1[resourceKeyAttribute || resourceField.options.targetKey || TargetModel.primaryKeyAttribute] == resourceKey) { if (m1 && m1[resourceIndexAttribute || resourceField.options.targetKey || TargetModel.primaryKeyAttribute] == resourceIndex) {
ctx.body = await associated[setAccessor](null); ctx.body = await associated[setAccessor](null);
} else { } else {
const m2 = await TargetModel.findOne({ const m2 = await TargetModel.findOne({
// ...options, // ...options,
where: { where: {
[resourceKeyAttribute || resourceField.options.targetKey || TargetModel.primaryKeyAttribute]: resourceKey, [resourceIndexAttribute || resourceField.options.targetKey || TargetModel.primaryKeyAttribute]: resourceIndex,
}, },
// @ts-ignore // @ts-ignore
context: ctx, context: ctx,
@ -48,7 +48,7 @@ export async function toggle(ctx: Context, next: Next) {
const [model]: Model[] = await associated[getAccessor]({ const [model]: Model[] = await associated[getAccessor]({
...options, ...options,
where: { where: {
[resourceKeyAttribute || resourceField.options.targetKey || TargetModel.primaryKeyAttribute]: resourceKey, [resourceIndexAttribute || resourceField.options.targetKey || TargetModel.primaryKeyAttribute]: resourceIndex,
}, },
context: ctx, context: ctx,
}); });
@ -58,7 +58,7 @@ export async function toggle(ctx: Context, next: Next) {
const m2 = await TargetModel.findOne({ const m2 = await TargetModel.findOne({
// ...options, // ...options,
where: { where: {
[resourceKeyAttribute || resourceField.options.targetKey || TargetModel.primaryKeyAttribute]: resourceKey, [resourceIndexAttribute || resourceField.options.targetKey || TargetModel.primaryKeyAttribute]: resourceIndex,
}, },
// @ts-ignore // @ts-ignore
context: ctx, context: ctx,

View File

@ -24,9 +24,9 @@ export async function update(ctx: Context, next: Next) {
associatedName, associatedName,
resourceField, resourceField,
resourceName, resourceName,
resourceKey, resourceIndex,
// TODO(question): 这个属性从哪设置的? // TODO(question): 这个属性从哪设置的?
resourceKeyAttribute, resourceIndexAttribute,
fields, fields,
values: data values: data
} = ctx.action.params; } = ctx.action.params;
@ -53,7 +53,7 @@ export async function update(ctx: Context, next: Next) {
const [model]: Model[] = await associated[getAccessor]({ const [model]: Model[] = await associated[getAccessor]({
...options, ...options,
where: { where: {
[resourceKeyAttribute || resourceField.options.targetKey || TargetModel.primaryKeyAttribute]: resourceKey, [resourceIndexAttribute || resourceField.options.targetKey || TargetModel.primaryKeyAttribute]: resourceIndex,
} }
}); });
@ -66,7 +66,7 @@ export async function update(ctx: Context, next: Next) {
const through = await ThroughModel.findOne({ const through = await ThroughModel.findOne({
where: { where: {
[foreignKey]: associated[sourceKey], [foreignKey]: associated[sourceKey],
[otherKey]: resourceKey, [otherKey]: resourceIndex,
}, },
transaction transaction
}); });
@ -88,7 +88,7 @@ export async function update(ctx: Context, next: Next) {
const model = await Model.findOne({ const model = await Model.findOne({
...options, ...options,
where: { where: {
[resourceKeyAttribute || Model.primaryKeyAttribute]: resourceKey, [resourceIndexAttribute || Model.primaryKeyAttribute]: resourceIndex,
} }
}); });
// @ts-ignore // @ts-ignore

View File

@ -7,9 +7,9 @@ export async function associated(ctx: Context, next: Next) {
return next(); return next();
} }
const { associated, associatedName, associatedKey, resourceName } = ctx.action.params; const { associated, associatedName, associatedIndex, resourceName } = ctx.action.params;
if (!associatedName || !associatedKey) { if (!associatedName || !associatedIndex) {
return next(); return next();
} }
@ -37,7 +37,7 @@ export async function associated(ctx: Context, next: Next) {
if (key) { if (key) {
const model = await Model.findOne({ const model = await Model.findOne({
where: { where: {
[key]: associatedKey, [key]: associatedIndex,
} }
}); });
if (model) { if (model) {

View File

@ -66,7 +66,7 @@ const useActionPermissionSubmit = () => {
const role = useContext(RoleContext); const role = useContext(RoleContext);
const resource = useResourceRequest({ const resource = useResourceRequest({
resourceName: 'roles', resourceName: 'roles',
resourceKey: role.name, resourceIndex: role.name,
}); });
return { return {
async run() { async run() {
@ -134,7 +134,7 @@ const useDetailsResource = ({ onSuccess }) => {
const ctx = useContext(TableRowContext); const ctx = useContext(TableRowContext);
const resource = useResourceRequest({ const resource = useResourceRequest({
resourceName: 'collections', resourceName: 'collections',
resourceKey: ctx.record[props.rowKey], resourceIndex: ctx.record[props.rowKey],
}); });
const service = useRequest( const service = useRequest(
(params?: any) => { (params?: any) => {
@ -762,7 +762,7 @@ function EditFieldButton() {
const fieldInterface = interfaces.get(form.values?.interface); const fieldInterface = interfaces.get(form.values?.interface);
fieldInterface?.initialize && fieldInterface?.initialize(form.values); fieldInterface?.initialize && fieldInterface?.initialize(form.values);
await resource.save(form.values, { await resource.save(form.values, {
resourceKey: ctx.record.key, resourceIndex: ctx.record.key,
}); });
setVisible(false); setVisible(false);
await service.refresh(); await service.refresh();

View File

@ -66,7 +66,7 @@ const useFieldPermissions = () => {
}; };
const resource = useResourceRequest({ const resource = useResourceRequest({
associatedName: 'collections', associatedName: 'collections',
associatedKey: ctx.record.name, associatedIndex: ctx.record.name,
resourceName: 'fields', resourceName: 'fields',
}); });
const service = useRequest( const service = useRequest(

View File

@ -33,7 +33,7 @@ export const MenuPermissionTable = observer((props) => {
console.log('allUiSchemaKyes', allUiSchemaKyes); console.log('allUiSchemaKyes', allUiSchemaKyes);
const resource = useResourceRequest({ const resource = useResourceRequest({
associatedName: 'roles', associatedName: 'roles',
associatedKey: role.name, associatedIndex: role.name,
resourceName: 'ui_schemas', resourceName: 'ui_schemas',
}); });
useRequest(() => resource.list(), { useRequest(() => resource.list(), {
@ -44,7 +44,7 @@ export const MenuPermissionTable = observer((props) => {
}); });
const resource2 = useResourceRequest({ const resource2 = useResourceRequest({
resourceName: 'roles', resourceName: 'roles',
resourceKey: role.name, resourceIndex: role.name,
}); });
if (loading) { if (loading) {
return <Spin size={'large'} className={'nb-spin-center'} />; return <Spin size={'large'} className={'nb-spin-center'} />;
@ -106,7 +106,7 @@ export const MenuPermissionTable = observer((props) => {
return [...prevUiSchemaKeys]; return [...prevUiSchemaKeys];
}); });
await resource.toggle({ await resource.toggle({
resourceKey: value, resourceIndex: value,
}); });
}} }}
/> />

View File

@ -59,7 +59,7 @@ const useActionPermissionSubmit = () => {
const role = useContext(RoleContext); const role = useContext(RoleContext);
const resource = useResourceRequest({ const resource = useResourceRequest({
resourceName: 'roles', resourceName: 'roles',
resourceKey: role.name, resourceIndex: role.name,
}); });
return { return {
async run() { async run() {
@ -127,7 +127,7 @@ const useDetailsResource = ({ onSuccess }) => {
const ctx = useContext(TableRowContext); const ctx = useContext(TableRowContext);
const resource = useResourceRequest({ const resource = useResourceRequest({
resourceName: 'roles', resourceName: 'roles',
resourceKey: ctx.record[props.rowKey], resourceIndex: ctx.record[props.rowKey],
}); });
const service = useRequest( const service = useRequest(
(params?: any) => { (params?: any) => {

View File

@ -10,12 +10,12 @@ export const SystemSettingsContext = createContext(null);
export function SystemSettingsProvider(props) { export function SystemSettingsProvider(props) {
const resource = useResourceRequest({ const resource = useResourceRequest({
resourceName: 'system_settings', resourceName: 'system_settings',
resourceKey: 1, resourceIndex: 1,
}); });
const service = useRequest( const service = useRequest(
() => () =>
resource.get({ resource.get({
resourceKey: 1, resourceIndex: 1,
appends: ['logo'], appends: ['logo'],
}), }),
{ {

View File

@ -152,13 +152,13 @@ const useAssociationResource = (options) => {
const collectionField = useContext(CollectionFieldContext); const collectionField = useContext(CollectionFieldContext);
const { collection } = useCollectionContext(); const { collection } = useCollectionContext();
const ctx = useContext(TableRowContext); const ctx = useContext(TableRowContext);
const associatedKey = ctx?.record?.id; const associatedIndex = ctx?.record?.id;
console.log('useAssociationResource', collection, collectionField, schema['x-component-props']); console.log('useAssociationResource', collection, collectionField, schema['x-component-props']);
const { associatedName, resourceName } = schema['x-component-props'] || {}; const { associatedName, resourceName } = schema['x-component-props'] || {};
const resource = useResourceRequest({ const resource = useResourceRequest({
associatedName, associatedName,
resourceName, resourceName,
associatedKey, associatedIndex,
}); });
const service = useRequest((params) => resource.list(params), { const service = useRequest((params) => resource.list(params), {
manual: schema['x-component'] === 'Form', manual: schema['x-component'] === 'Form',

View File

@ -3,19 +3,19 @@ import { request as req } from './schemas';
export interface ResourceOptions { export interface ResourceOptions {
resourceName: string; resourceName: string;
associatedKey?: any; associatedIndex?: any;
associatedName?: string; associatedName?: string;
resourceKey?: any; resourceIndex?: any;
} }
export interface GetOptions { export interface GetOptions {
resourceKey?: any; resourceIndex?: any;
defaultAppends?: any[]; defaultAppends?: any[];
appends?: string[]; appends?: string[];
} }
export interface SaveOptions { export interface SaveOptions {
resourceKey?: any; resourceIndex?: any;
} }
export interface ListOptions { export interface ListOptions {
@ -42,8 +42,8 @@ export class Resource {
sort(options) { sort(options) {
const { resourceName } = this.options; const { resourceName } = this.options;
const { resourceKey, target, field = 'sort' } = options; const { resourceIndex, target, field = 'sort' } = options;
return this.request(`${resourceName}:sort/${resourceKey}`, { return this.request(`${resourceName}:sort/${resourceIndex}`, {
method: 'post', method: 'post',
data: { data: {
target, target,
@ -61,10 +61,10 @@ export class Resource {
pageSize, pageSize,
...others ...others
} = options; } = options;
const { associatedKey, associatedName, resourceName } = this.options; const { associatedIndex, associatedName, resourceName } = this.options;
let url = `${resourceName}:list`; let url = `${resourceName}:list`;
if (associatedName && associatedKey) { if (associatedName && associatedIndex) {
url = `${associatedName}/${associatedKey}/${resourceName}:list`; url = `${associatedName}/${associatedIndex}/${resourceName}:list`;
} }
return this.request(url, { return this.request(url, {
method: 'get', method: 'get',
@ -80,13 +80,13 @@ export class Resource {
} }
get(options: GetOptions = {}) { get(options: GetOptions = {}) {
const resourceKey = options.resourceKey || this.options.resourceKey; const resourceIndex = options.resourceIndex || this.options.resourceIndex;
const { resourceName } = this.options; const { resourceName } = this.options;
if (!resourceKey) { if (!resourceIndex) {
return Promise.resolve({ data: {} }); return Promise.resolve({ data: {} });
} }
const { defaultAppends = [], appends = [], ...others } = options; const { defaultAppends = [], appends = [], ...others } = options;
return this.request(`${resourceName}:get/${resourceKey}`, { return this.request(`${resourceName}:get/${resourceIndex}`, {
params: { params: {
...others, ...others,
'fields[appends]': defaultAppends.concat(appends).join(','), 'fields[appends]': defaultAppends.concat(appends).join(','),
@ -95,10 +95,10 @@ export class Resource {
} }
create(values: any) { create(values: any) {
const { associatedKey, associatedName, resourceName } = this.options; const { associatedIndex, associatedName, resourceName } = this.options;
let url = `${resourceName}:create`; let url = `${resourceName}:create`;
if (associatedKey && associatedName) { if (associatedIndex && associatedName) {
url = `${associatedName}/${associatedKey}/${url}`; url = `${associatedName}/${associatedIndex}/${url}`;
} }
return this.request(url, { return this.request(url, {
method: 'post', method: 'post',
@ -107,13 +107,13 @@ export class Resource {
} }
save(values: any, options: SaveOptions = {}) { save(values: any, options: SaveOptions = {}) {
const resourceKey = options.resourceKey || this.options.resourceKey; const resourceIndex = options.resourceIndex || this.options.resourceIndex;
const { associatedKey, associatedName, resourceName } = this.options; const { associatedIndex, associatedName, resourceName } = this.options;
let url = `${resourceName}:${ let url = `${resourceName}:${
resourceKey ? `update/${resourceKey}` : 'create' resourceIndex ? `update/${resourceIndex}` : 'create'
}`; }`;
if (associatedKey && associatedName) { if (associatedIndex && associatedName) {
url = `${associatedName}/${associatedKey}/${url}`; url = `${associatedName}/${associatedIndex}/${url}`;
} }
return this.request(url, { return this.request(url, {
method: 'post', method: 'post',
@ -171,9 +171,9 @@ export class Resource {
} }
toggle(options?: any) { toggle(options?: any) {
const { associatedKey, associatedName, resourceName } = this.options; const { associatedIndex, associatedName, resourceName } = this.options;
const { resourceKey } = options; const { resourceIndex } = options;
let url = `${associatedName}/${associatedKey}/${resourceName}:toggle/${resourceKey}`; let url = `${associatedName}/${associatedIndex}/${resourceName}:toggle/${resourceIndex}`;
return this.request(url, { return this.request(url, {
method: 'post', method: 'post',
}); });

View File

@ -279,7 +279,7 @@ Calendar.useResource = ({ onSuccess }) => {
const record = useContext(RecordContext); const record = useContext(RecordContext);
const resource = useResourceRequest({ const resource = useResourceRequest({
resourceName: collection?.name || props.collectionName, resourceName: collection?.name || props.collectionName,
resourceKey: record['id'], resourceIndex: record['id'],
}); });
console.log( console.log(
'collection?.name || props.collectionName', 'collection?.name || props.collectionName',

View File

@ -294,11 +294,11 @@ const InternalKanban = observer((props: any) => {
[groupField.name]: overColumnId, [groupField.name]: overColumnId,
}, },
{ {
resourceKey: activeId, resourceIndex: activeId,
}, },
); );
await resource.sort({ await resource.sort({
resourceKey: activeId, resourceIndex: activeId,
field: 'sort', field: 'sort',
target: lastId target: lastId
? { ? {
@ -331,11 +331,11 @@ const InternalKanban = observer((props: any) => {
[groupField.name]: overColumnId, [groupField.name]: overColumnId,
}, },
{ {
resourceKey: activeId, resourceIndex: activeId,
}, },
); );
await resource.sort({ await resource.sort({
resourceKey: activeId, resourceIndex: activeId,
field: 'sort', field: 'sort',
target: { target: {
id: overId, id: overId,
@ -347,11 +347,11 @@ const InternalKanban = observer((props: any) => {
[groupField.name]: overId, [groupField.name]: overId,
}, },
{ {
resourceKey: activeId, resourceIndex: activeId,
}, },
); );
await resource.sort({ await resource.sort({
resourceKey: activeId, resourceIndex: activeId,
field: 'sort', field: 'sort',
target: lastId target: lastId
? { ? {
@ -468,7 +468,7 @@ Kanban.useUpdateAction = () => {
return { return {
async run() { async run() {
await resource.save(omit(form.values, ['sort']), { await resource.save(omit(form.values, ['sort']), {
resourceKey: ctx.record.id, resourceIndex: ctx.record.id,
}); });
setVisible(false); setVisible(false);
await service.refresh(); await service.refresh();
@ -482,7 +482,7 @@ Kanban.useRowResource = ({ onSuccess }) => {
const ctx = useContext(KanbanCardContext); const ctx = useContext(KanbanCardContext);
const resource = useResourceRequest({ const resource = useResourceRequest({
resourceName: collection?.name || props.collectionName, resourceName: collection?.name || props.collectionName,
resourceKey: ctx?.record?.id, resourceIndex: ctx?.record?.id,
}); });
const service = useRequest( const service = useRequest(
(params?: any) => { (params?: any) => {
@ -524,7 +524,7 @@ Kanban.useSingleResource = ({ onSuccess }) => {
const resource = useResourceRequest({ const resource = useResourceRequest({
resourceName: collection?.name || props.collectionName, resourceName: collection?.name || props.collectionName,
resourceKey: ctx?.record?.id, resourceIndex: ctx?.record?.id,
}); });
const service = useRequest( const service = useRequest(
(params?: any) => { (params?: any) => {

View File

@ -1006,7 +1006,7 @@ Menu.DesignableBar = (props) => {
}; };
const resource = Resource.make({ const resource = Resource.make({
associatedName: 'ui_schemas', associatedName: 'ui_schemas',
associatedKey: schema['key'], associatedIndex: schema['key'],
resourceName: 'roles', resourceName: 'roles',
}); });
const uiSchemasRoles = await resource.list(); const uiSchemasRoles = await resource.list();
@ -1043,7 +1043,7 @@ Menu.DesignableBar = (props) => {
}); });
await Resource.make({ await Resource.make({
resourceName: 'ui_schemas', resourceName: 'ui_schemas',
resourceKey: schema['key'], resourceIndex: schema['key'],
}).save(values); }).save(values);
}} }}
> >

View File

@ -489,7 +489,7 @@ Select.Drawer.useResource = ({ onSuccess }) => {
const ctx = useContext(OptionTagContext); const ctx = useContext(OptionTagContext);
const resource = useResourceRequest({ const resource = useResourceRequest({
resourceName: collection?.name, resourceName: collection?.name,
resourceKey: ctx.data.id, resourceIndex: ctx.data.id,
}); });
console.log('OptionTagContext', ctx.data.id); console.log('OptionTagContext', ctx.data.id);
const { schema } = useDesignable(); const { schema } = useDesignable();

View File

@ -43,7 +43,7 @@ export const TableMain = () => {
field.move(fromIndex, toIndex); field.move(fromIndex, toIndex);
refresh(); refresh();
await resource.sort({ await resource.sort({
resourceKey: fromId, resourceIndex: fromId,
target: { target: {
[rowKey]: toId, [rowKey]: toId,
}, },

View File

@ -11,7 +11,7 @@ export const useActionLogDetailsResource = ({ onSuccess }) => {
const ctx = useContext(TableRowContext); const ctx = useContext(TableRowContext);
const resource = useResourceRequest({ const resource = useResourceRequest({
resourceName: 'action_logs', resourceName: 'action_logs',
resourceKey: ctx.record[props.rowKey], resourceIndex: ctx.record[props.rowKey],
}); });
const service = useRequest( const service = useRequest(
(params?: any) => { (params?: any) => {

View File

@ -12,7 +12,7 @@ export const useResource = ({ onSuccess, manual = true }) => {
const ctx = useContext(TableRowContext); const ctx = useContext(TableRowContext);
const resource = useResourceRequest({ const resource = useResourceRequest({
resourceName: collection?.name || props.collectionName, resourceName: collection?.name || props.collectionName,
resourceKey: ctx.record[props.rowKey], resourceIndex: ctx.record[props.rowKey],
}); });
const { schema } = useDesignable(); const { schema } = useDesignable();
const fieldFields = (schema: Schema) => { const fieldFields = (schema: Schema) => {

View File

@ -20,7 +20,7 @@ export const useTableUpdateAction = () => {
async run() { async run() {
if (refreshRequestOnChange) { if (refreshRequestOnChange) {
await resource.save(form.values, { await resource.save(form.values, {
resourceKey: ctx.record[rowKey], resourceIndex: ctx.record[rowKey],
}); });
if (formService) { if (formService) {
await formService.refresh(); await formService.refresh();

View File

@ -1,5 +1,4 @@
import Database from '@nocobase/database'; import Database from '@nocobase/database';
import { registerActions } from '@nocobase/actions';
import { mockServer, MockServer } from '@nocobase/test'; import { mockServer, MockServer } from '@nocobase/test';
import logPlugin from '../server'; import logPlugin from '../server';
@ -9,13 +8,9 @@ describe('hook', () => {
beforeEach(async () => { beforeEach(async () => {
api = mockServer(); api = mockServer();
api.registerPlugin({ api.plugin(require('@nocobase/plugin-users').default);
collections: require('@nocobase/plugin-collections/src/server').default, api.plugin(logPlugin);
users: require('@nocobase/plugin-users/src/server').default, await api.load();
logs: logPlugin,
});
registerActions(api);
await api.loadPlugins();
db = api.db; db = api.db;
db.table({ db.table({
name: 'posts', name: 'posts',
@ -34,8 +29,7 @@ describe('hook', () => {
}); });
await db.sync(); await db.sync();
const User = db.getModel('users'); const User = db.getModel('users');
const user = await User.create({ nickname: 'a', token: 'token1' }); await User.create({ nickname: 'a', token: 'token1' });
api.agent().set('Authorization', `Bearer ${user.token}`);
}); });
afterEach(async () => { afterEach(async () => {
@ -53,15 +47,17 @@ describe('hook', () => {
}); });
it('resource', async () => { it('resource', async () => {
const response = await api.resource('posts').create({ const agent = api.agent()
agent.set('Authorization', `Bearer token1`);
const response = await agent.resource('posts').create({
values: { title: 't1' }, values: { title: 't1' },
}); });
await api.resource('posts').update({ await agent.resource('posts').update({
resourceKey: response.body.data.id, resourceIndex: response.body.data.id,
values: { title: 't2' }, values: { title: 't2' },
}); });
await api.resource('posts').destroy({ await agent.resource('posts').destroy({
resourceKey: response.body.data.id, resourceIndex: response.body.data.id,
}); });
const ActionLog = db.getModel('action_logs'); const ActionLog = db.getModel('action_logs');
const count = await ActionLog.count(); const count = await ActionLog.count();

View File

@ -0,0 +1 @@
export { default } from './server';

View File

@ -85,10 +85,10 @@ export async function getApp() {
} }
interface ActionParams { interface ActionParams {
resourceKey?: string | number; resourceIndex?: string | number;
// resourceName?: string; // resourceName?: string;
// associatedName?: string; // associatedName?: string;
associatedKey?: string | number; associatedIndex?: string | number;
fields?: any; fields?: any;
filter?: any; filter?: any;
values?: any; values?: any;
@ -118,14 +118,14 @@ export function getAPI(agent) {
return new Proxy({}, { return new Proxy({}, {
get(target, method: string, receiver) { get(target, method: string, receiver) {
return (params: ActionParams = {}) => { return (params: ActionParams = {}) => {
const { associatedKey, resourceKey, values = {}, filePath, ...restParams } = params; const { associatedIndex, resourceIndex, values = {}, filePath, ...restParams } = params;
let url = `/api/${name}`; let url = `/api/${name}`;
if (associatedKey) { if (associatedIndex) {
url = `/api/${name.split('.').join(`/${associatedKey}/`)}`; url = `/api/${name.split('.').join(`/${associatedIndex}/`)}`;
} }
url += `:${method as string}`; url += `:${method as string}`;
if (resourceKey) { if (resourceIndex) {
url += `/${resourceKey}`; url += `/${resourceIndex}`;
} }
switch (method) { switch (method) {

View File

@ -243,7 +243,7 @@ export default {
// condition: "{{ $self.value }}", // condition: "{{ $self.value }}",
schema: { schema: {
"x-component-props": { "x-component-props": {
"associatedKey": "{{ typeof $self.value === 'string' ? $self.value : $form.values.collection_name }}" "associatedIndex": "{{ typeof $self.value === 'string' ? $self.value : $form.values.collection_name }}"
}, },
}, },
}, },
@ -253,7 +253,7 @@ export default {
// condition: "{{ $self.value }}", // condition: "{{ $self.value }}",
schema: { schema: {
"x-component-props": { "x-component-props": {
"associatedKey": "{{ typeof $self.value === 'string' ? $self.value : $form.values.collection_name }}" "associatedIndex": "{{ typeof $self.value === 'string' ? $self.value : $form.values.collection_name }}"
}, },
}, },
}, },
@ -263,7 +263,7 @@ export default {
// condition: "{{ $self.value }}", // condition: "{{ $self.value }}",
schema: { schema: {
"x-component-props": { "x-component-props": {
"associatedKey": "{{ typeof $self.value === 'string' ? $self.value : $form.values.collection_name }}" "associatedIndex": "{{ typeof $self.value === 'string' ? $self.value : $form.values.collection_name }}"
}, },
}, },
}, },
@ -273,7 +273,7 @@ export default {
// condition: "{{ $self.value }}", // condition: "{{ $self.value }}",
schema: { schema: {
"x-component-props": { "x-component-props": {
"associatedKey": "{{ typeof $self.value === 'string' ? $self.value : $form.values.collection_name }}" "associatedIndex": "{{ typeof $self.value === 'string' ? $self.value : $form.values.collection_name }}"
}, },
}, },
}, },
@ -406,7 +406,7 @@ export default {
condition: "{{ ($form.values.collection_name || $form.values.collection) && $self.value === 'customField' }}", condition: "{{ ($form.values.collection_name || $form.values.collection) && $self.value === 'customField' }}",
schema: { schema: {
"x-component-props": { "x-component-props": {
"associatedKey": "{{ $form.values.collection_name || $form.values.collection }}" "associatedIndex": "{{ $form.values.collection_name || $form.values.collection }}"
}, },
}, },
}, },

View File

@ -84,7 +84,7 @@ export default {
// condition: "{{ $self.value }}", // condition: "{{ $self.value }}",
schema: { schema: {
"x-component-props": { "x-component-props": {
"associatedKey": "{{ typeof $self.value === 'string' ? $self.value : $form.values.collection_name }}", "associatedIndex": "{{ typeof $self.value === 'string' ? $self.value : $form.values.collection_name }}",
"sourceName": "{{ $form.values.automation ? $form.values.automation.collection_name : null }}" "sourceName": "{{ $form.values.automation ? $form.values.automation.collection_name : null }}"
}, },
}, },
@ -95,7 +95,7 @@ export default {
// condition: "{{ $self.value }}", // condition: "{{ $self.value }}",
schema: { schema: {
"x-component-props": { "x-component-props": {
"associatedKey": "{{ typeof $self.value === 'string' ? $self.value : $form.values.collection_name }}", "associatedIndex": "{{ typeof $self.value === 'string' ? $self.value : $form.values.collection_name }}",
"sourceName": "{{ $form.values.automation ? $form.values.automation.collection_name : null }}" "sourceName": "{{ $form.values.automation ? $form.values.automation.collection_name : null }}"
}, },
}, },

View File

@ -80,10 +80,10 @@ export async function getApp() {
} }
interface ActionParams { interface ActionParams {
resourceKey?: string | number; resourceIndex?: string | number;
// resourceName?: string; // resourceName?: string;
// associatedName?: string; // associatedName?: string;
associatedKey?: string | number; associatedIndex?: string | number;
fields?: any; fields?: any;
filter?: any; filter?: any;
values?: any; values?: any;
@ -110,14 +110,14 @@ export function getAgent(app: Application): Agent {
return new Proxy({}, { return new Proxy({}, {
get(target, method, receiver) { get(target, method, receiver) {
return (params: ActionParams = {}) => { return (params: ActionParams = {}) => {
const { associatedKey, resourceKey, values = {}, ...restParams } = params; const { associatedIndex, resourceIndex, values = {}, ...restParams } = params;
let url = `/api/${name}`; let url = `/api/${name}`;
if (associatedKey) { if (associatedIndex) {
url = `/api/${name.split('.').join(`/${associatedKey}/`)}`; url = `/api/${name.split('.').join(`/${associatedIndex}/`)}`;
} }
url += `:${method as string}`; url += `:${method as string}`;
if (resourceKey) { if (resourceIndex) {
url += `/${resourceKey}`; url += `/${resourceIndex}`;
} }
console.log(url); console.log(url);
if (['list', 'get'].indexOf(method as string) !== -1) { if (['list', 'get'].indexOf(method as string) !== -1) {

View File

@ -94,21 +94,21 @@ describe('action', () => {
}); });
describe('belongsTo attachment', () => { describe('belongsTo attachment', () => {
it('upload with associatedKey, fail as 400 because file mimetype does not match', async () => { it('upload with associatedIndex, fail as 400 because file mimetype does not match', async () => {
const User = db.getModel('users'); const User = db.getModel('users');
const user = await User.create(); const user = await User.create();
const response = await agent.resource('users.avatar').upload({ const response = await agent.resource('users.avatar').upload({
associatedKey: user.id, associatedIndex: user.id,
file: path.resolve(__dirname, './files/text.txt') file: path.resolve(__dirname, './files/text.txt')
}); });
expect(response.status).toBe(400); expect(response.status).toBe(400);
}); });
it('upload with associatedKey', async () => { it('upload with associatedIndex', async () => {
const User = db.getModel('users'); const User = db.getModel('users');
const user = await User.create(); const user = await User.create();
const { body } = await agent.resource('users.avatar').upload({ const { body } = await agent.resource('users.avatar').upload({
associatedKey: user.id, associatedIndex: user.id,
file: path.resolve(__dirname, './files/image.png'), file: path.resolve(__dirname, './files/image.png'),
values: { width: 100, height: 100 } values: { width: 100, height: 100 }
}); });
@ -155,7 +155,7 @@ describe('action', () => {
const User = db.getModel('users'); const User = db.getModel('users');
const user = await User.create(); const user = await User.create();
const { body } = await agent.resource('users.pubkeys').upload({ const { body } = await agent.resource('users.pubkeys').upload({
associatedKey: user.id, associatedIndex: user.id,
file: path.resolve(__dirname, './files/text.txt'), file: path.resolve(__dirname, './files/text.txt'),
values: {} values: {}
}); });
@ -167,8 +167,8 @@ describe('action', () => {
expect(content.text).toBe('Hello world!\n'); expect(content.text).toBe('Hello world!\n');
}); });
// TODO(bug): 没有 associatedKey 时路径解析资源名称不对,无法进入 action // TODO(bug): 没有 associatedIndex 时路径解析资源名称不对,无法进入 action
it.skip('upload without associatedKey', async () => { it.skip('upload without associatedIndex', async () => {
const { body } = await agent.resource('users.avatar').upload({ const { body } = await agent.resource('users.avatar').upload({
file: path.resolve(__dirname, './files/image.png'), file: path.resolve(__dirname, './files/image.png'),
values: { width: 100, height: 100 } values: { width: 100, height: 100 }

View File

@ -2,7 +2,7 @@ import path from 'path';
import supertest from 'supertest'; import supertest from 'supertest';
import { MockServer, mockServer } from '@nocobase/test'; import { MockServer, mockServer } from '@nocobase/test';
import plugin from '../server'; import plugin from '../';
export async function getApp(options = {}): Promise<MockServer> { export async function getApp(options = {}): Promise<MockServer> {
const app = mockServer({ const app = mockServer({

View File

@ -113,11 +113,11 @@ export async function action(ctx: Context, next: Next) {
// TODO(optimize): 应使用关联 accessors 获取 // TODO(optimize): 应使用关联 accessors 获取
const result = await storage.createAttachment(data, { transaction }); const result = await storage.createAttachment(data, { transaction });
const { associatedName, associatedKey, resourceField } = ctx.action.params; const { associatedName, associatedIndex, resourceField } = ctx.action.params;
if (associatedKey && resourceField) { if (associatedIndex && resourceField) {
const Attachment = ctx.db.getModel('attachments'); const Attachment = ctx.db.getModel('attachments');
const SourceModel = ctx.db.getModel(associatedName); const SourceModel = ctx.db.getModel(associatedName);
const source = await SourceModel.findByPk(associatedKey, { transaction }); const source = await SourceModel.findByPk(associatedIndex, { transaction });
await source[resourceField.getAccessors().set](result[Attachment.primaryKeyAttribute], { transaction }); await source[resourceField.getAccessors().set](result[Attachment.primaryKeyAttribute], { transaction });
} }

View File

@ -1 +1,2 @@
export * from './constants'; export * from './constants';
export { default } from './server';

View File

@ -14,14 +14,14 @@ export default {
const SystemSetting = database.getModel('system_settings'); const SystemSetting = database.getModel('system_settings');
resourcer.use(async (ctx, next) => { resourcer.use(async (ctx, next) => {
const { actionName, resourceName, resourceKey } = ctx.action.params; const { actionName, resourceName, resourceIndex } = ctx.action.params;
if (resourceName === 'system_settings' && actionName === 'get') { if (resourceName === 'system_settings' && actionName === 'get') {
let model = await SystemSetting.findOne(); let model = await SystemSetting.findOne();
if (!model) { if (!model) {
model = await SystemSetting.create(); model = await SystemSetting.create();
} }
ctx.action.mergeParams({ ctx.action.mergeParams({
resourceKey: model.id, resourceIndex: model.id,
}); });
} }
await next(); await next();

View File

@ -80,10 +80,10 @@ export async function getApp() {
} }
interface ActionParams { interface ActionParams {
resourceKey?: string | number; resourceIndex?: string | number;
// resourceName?: string; // resourceName?: string;
// associatedName?: string; // associatedName?: string;
associatedKey?: string | number; associatedIndex?: string | number;
fields?: any; fields?: any;
filter?: any; filter?: any;
values?: any; values?: any;
@ -110,14 +110,14 @@ export function getAgent(app: Application): Agent {
return new Proxy({}, { return new Proxy({}, {
get(target, method, receiver) { get(target, method, receiver) {
return (params: ActionParams = {}) => { return (params: ActionParams = {}) => {
const { associatedKey, resourceKey, values = {}, ...restParams } = params; const { associatedIndex, resourceIndex, values = {}, ...restParams } = params;
let url = `/api/${name}`; let url = `/api/${name}`;
if (associatedKey) { if (associatedIndex) {
url = `/api/${name.split('.').join(`/${associatedKey}/`)}`; url = `/api/${name.split('.').join(`/${associatedIndex}/`)}`;
} }
url += `:${method as string}`; url += `:${method as string}`;
if (resourceKey) { if (resourceIndex) {
url += `/${resourceKey}`; url += `/${resourceIndex}`;
} }
console.log(url); console.log(url);
if (['list', 'get'].indexOf(method as string) !== -1) { if (['list', 'get'].indexOf(method as string) !== -1) {

View File

@ -25,8 +25,8 @@ export const create = async (ctx: Context, next: Next) => {
const body = ctx.body; const body = ctx.body;
ctx.action.mergeParams( ctx.action.mergeParams(
{ {
associatedKey: values.parentKey, associatedIndex: values.parentKey,
resourceKey: body.key, resourceIndex: body.key,
...(sticky ...(sticky
? { ? {
sticky: true, sticky: true,
@ -70,8 +70,8 @@ export const update = async (ctx: Context, next: Next) => {
const body = ctx.body; const body = ctx.body;
ctx.action.mergeParams( ctx.action.mergeParams(
{ {
associatedKey: values.parentKey, associatedIndex: values.parentKey,
resourceKey: body.key, resourceIndex: body.key,
...(sticky ...(sticky
? { ? {
sticky: true, sticky: true,
@ -95,10 +95,10 @@ export const update = async (ctx: Context, next: Next) => {
}; };
export const getTree = async (ctx: Context, next: Next) => { export const getTree = async (ctx: Context, next: Next) => {
const { resourceKey, filter } = ctx.action.params; const { resourceIndex, filter } = ctx.action.params;
const UISchema = ctx.db.getModel('ui_schemas'); const UISchema = ctx.db.getModel('ui_schemas');
if (resourceKey) { if (resourceIndex) {
const schema = await UISchema.findByPk(resourceKey); const schema = await UISchema.findByPk(resourceIndex);
const property = schema.toProperty(); const property = schema.toProperty();
const properties = await schema.getProperties(); const properties = await schema.getProperties();
if (Object.keys(properties).length) { if (Object.keys(properties).length) {

View File

@ -0,0 +1 @@
export { default } from './server';

View File

@ -271,11 +271,11 @@ describe('koa middleware', () => {
const response = await agent const response = await agent
.post('/resourcer/tests:update') .post('/resourcer/tests:update')
.send({ .send({
resourceKey: 1, resourceIndex: 1,
values: { 'aa': 'aa' } values: { 'aa': 'aa' }
}); });
expect(response.body).toEqual({ expect(response.body).toEqual({
resourceKey: 1, resourceIndex: 1,
actionName: 'update', actionName: 'update',
resourceName: 'tests', resourceName: 'tests',
values: { col1: 'val1', aa: 'aa' } values: { col1: 'val1', aa: 'aa' }
@ -293,7 +293,7 @@ describe('koa middleware', () => {
.get('/users/1/settings'); .get('/users/1/settings');
expect(response.body).toEqual({ expect(response.body).toEqual({
associatedName: 'users', associatedName: 'users',
associatedKey: '1', associatedIndex: '1',
resourceName: 'settings', resourceName: 'settings',
actionName: 'get' actionName: 'get'
}); });
@ -303,7 +303,7 @@ describe('koa middleware', () => {
.post('/users/1/settings'); .post('/users/1/settings');
expect(response.body).toEqual({ expect(response.body).toEqual({
associatedName: 'users', associatedName: 'users',
associatedKey: '1', associatedIndex: '1',
resourceName: 'settings', resourceName: 'settings',
actionName: 'update' actionName: 'update'
}); });
@ -313,7 +313,7 @@ describe('koa middleware', () => {
.delete('/users/1/settings'); .delete('/users/1/settings');
expect(response.body).toEqual({ expect(response.body).toEqual({
associatedName: 'users', associatedName: 'users',
associatedKey: '1', associatedIndex: '1',
resourceName: 'settings', resourceName: 'settings',
actionName: 'destroy' actionName: 'destroy'
}); });
@ -331,7 +331,7 @@ describe('koa middleware', () => {
.get('/users/1/posts'); .get('/users/1/posts');
expect(response.body).toEqual({ expect(response.body).toEqual({
associatedName: 'users', associatedName: 'users',
associatedKey: '1', associatedIndex: '1',
resourceName: 'posts', resourceName: 'posts',
actionName: 'list' actionName: 'list'
}); });
@ -341,9 +341,9 @@ describe('koa middleware', () => {
.get('/users/1/posts/1'); .get('/users/1/posts/1');
expect(response.body).toEqual({ expect(response.body).toEqual({
associatedName: 'users', associatedName: 'users',
associatedKey: '1', associatedIndex: '1',
resourceName: 'posts', resourceName: 'posts',
resourceKey: '1', resourceIndex: '1',
actionName: 'get' actionName: 'get'
}); });
}); });
@ -352,7 +352,7 @@ describe('koa middleware', () => {
.post('/users/1/posts'); .post('/users/1/posts');
expect(response.body).toEqual({ expect(response.body).toEqual({
associatedName: 'users', associatedName: 'users',
associatedKey: '1', associatedIndex: '1',
resourceName: 'posts', resourceName: 'posts',
actionName: 'create' actionName: 'create'
}); });
@ -362,9 +362,9 @@ describe('koa middleware', () => {
.put('/users/1/posts/1'); .put('/users/1/posts/1');
expect(response.body).toEqual({ expect(response.body).toEqual({
associatedName: 'users', associatedName: 'users',
associatedKey: '1', associatedIndex: '1',
resourceName: 'posts', resourceName: 'posts',
resourceKey: '1', resourceIndex: '1',
actionName: 'update' actionName: 'update'
}); });
}); });
@ -373,9 +373,9 @@ describe('koa middleware', () => {
.delete('/users/1/posts/1'); .delete('/users/1/posts/1');
expect(response.body).toEqual({ expect(response.body).toEqual({
associatedName: 'users', associatedName: 'users',
associatedKey: '1', associatedIndex: '1',
resourceName: 'posts', resourceName: 'posts',
resourceKey: '1', resourceIndex: '1',
actionName: 'destroy' actionName: 'destroy'
}); });
}); });
@ -392,7 +392,7 @@ describe('koa middleware', () => {
.get('/posts/1/user'); .get('/posts/1/user');
expect(response.body).toEqual({ expect(response.body).toEqual({
associatedName: 'posts', associatedName: 'posts',
associatedKey: '1', associatedIndex: '1',
resourceName: 'user', resourceName: 'user',
actionName: 'get' actionName: 'get'
}); });
@ -402,9 +402,9 @@ describe('koa middleware', () => {
.post('/posts/1/user/1'); .post('/posts/1/user/1');
expect(response.body).toEqual({ expect(response.body).toEqual({
associatedName: 'posts', associatedName: 'posts',
associatedKey: '1', associatedIndex: '1',
resourceName: 'user', resourceName: 'user',
resourceKey: '1', resourceIndex: '1',
actionName: 'set' actionName: 'set'
}); });
}); });
@ -413,7 +413,7 @@ describe('koa middleware', () => {
.delete('/posts/1/user'); .delete('/posts/1/user');
expect(response.body).toEqual({ expect(response.body).toEqual({
associatedName: 'posts', associatedName: 'posts',
associatedKey: '1', associatedIndex: '1',
resourceName: 'user', resourceName: 'user',
actionName: 'remove' actionName: 'remove'
}); });
@ -431,7 +431,7 @@ describe('koa middleware', () => {
.get('/posts/1/tags'); .get('/posts/1/tags');
expect(response.body).toEqual({ expect(response.body).toEqual({
associatedName: 'posts', associatedName: 'posts',
associatedKey: '1', associatedIndex: '1',
resourceName: 'tags', resourceName: 'tags',
actionName: 'list' actionName: 'list'
}); });
@ -441,9 +441,9 @@ describe('koa middleware', () => {
.get('/posts/1/tags/1'); .get('/posts/1/tags/1');
expect(response.body).toEqual({ expect(response.body).toEqual({
associatedName: 'posts', associatedName: 'posts',
associatedKey: '1', associatedIndex: '1',
resourceName: 'tags', resourceName: 'tags',
resourceKey: '1', resourceIndex: '1',
actionName: 'get' actionName: 'get'
}); });
}); });
@ -452,7 +452,7 @@ describe('koa middleware', () => {
.post('/posts/1/tags'); .post('/posts/1/tags');
expect(response.body).toEqual({ expect(response.body).toEqual({
associatedName: 'posts', associatedName: 'posts',
associatedKey: '1', associatedIndex: '1',
resourceName: 'tags', resourceName: 'tags',
actionName: 'set' actionName: 'set'
}); });
@ -462,9 +462,9 @@ describe('koa middleware', () => {
.post('/posts/1/tags/1'); .post('/posts/1/tags/1');
expect(response.body).toEqual({ expect(response.body).toEqual({
associatedName: 'posts', associatedName: 'posts',
associatedKey: '1', associatedIndex: '1',
resourceName: 'tags', resourceName: 'tags',
resourceKey: '1', resourceIndex: '1',
actionName: 'add' actionName: 'add'
}); });
}); });
@ -473,9 +473,9 @@ describe('koa middleware', () => {
.put('/posts/1/tags/1'); .put('/posts/1/tags/1');
expect(response.body).toEqual({ expect(response.body).toEqual({
associatedName: 'posts', associatedName: 'posts',
associatedKey: '1', associatedIndex: '1',
resourceName: 'tags', resourceName: 'tags',
resourceKey: '1', resourceIndex: '1',
actionName: 'update' actionName: 'update'
}); });
}); });
@ -484,9 +484,9 @@ describe('koa middleware', () => {
.delete('/posts/1/tags/1'); .delete('/posts/1/tags/1');
expect(response.body).toEqual({ expect(response.body).toEqual({
associatedName: 'posts', associatedName: 'posts',
associatedKey: '1', associatedIndex: '1',
resourceName: 'tags', resourceName: 'tags',
resourceKey: '1', resourceIndex: '1',
actionName: 'remove' actionName: 'remove'
}); });
}); });
@ -628,7 +628,7 @@ describe('koa middleware', () => {
}); });
expect(response.body).toEqual({ expect(response.body).toEqual({
associatedName: 'users', associatedName: 'users',
associatedKey: 'name', associatedIndex: 'name',
resourceName: 'posts', resourceName: 'posts',
actionName: 'list', actionName: 'list',
fields: { appends: ['rel1', 'rel2'] } fields: { appends: ['rel1', 'rel2'] }
@ -640,7 +640,7 @@ describe('koa middleware', () => {
actions: { actions: {
list: { list: {
async middleware(ctx, next) { async middleware(ctx, next) {
ctx.action.mergeParams({ filter: { user_name: ctx.action.params.associatedKey } }); ctx.action.mergeParams({ filter: { user_name: ctx.action.params.associatedIndex } });
await next(); await next();
}, },
}, },
@ -650,7 +650,7 @@ describe('koa middleware', () => {
.get('/users/name/posts'); .get('/users/name/posts');
expect(response.body).toEqual({ expect(response.body).toEqual({
associatedName: 'users', associatedName: 'users',
associatedKey: 'name', associatedIndex: 'name',
resourceName: 'posts', resourceName: 'posts',
actionName: 'list', actionName: 'list',
filter: { user_name: 'name' }, filter: { user_name: 'name' },
@ -662,7 +662,7 @@ describe('koa middleware', () => {
actions: { actions: {
list: { list: {
async middleware(ctx, next) { async middleware(ctx, next) {
ctx.action.mergeParams({ fields: { only: [ctx.action.params.associatedKey] } }, { fields: 'append' }); ctx.action.mergeParams({ fields: { only: [ctx.action.params.associatedIndex] } }, { fields: 'append' });
await next(); await next();
}, },
}, },
@ -672,7 +672,7 @@ describe('koa middleware', () => {
.get('/users/name/posts'); .get('/users/name/posts');
expect(response.body).toEqual({ expect(response.body).toEqual({
associatedName: 'users', associatedName: 'users',
associatedKey: 'name', associatedIndex: 'name',
resourceName: 'posts', resourceName: 'posts',
actionName: 'list', actionName: 'list',
fields: { fields: {

View File

@ -111,7 +111,7 @@ describe('utils', () => {
path: '/posts/1', path: '/posts/1',
method: 'GET', method: 'GET',
}); });
expect(params).toEqual({ resourceName: 'posts', resourceKey: '1', actionName: 'get' }); expect(params).toEqual({ resourceName: 'posts', resourceIndex: '1', actionName: 'get' });
}); });
it('update action', () => { it('update action', () => {
@ -119,7 +119,7 @@ describe('utils', () => {
path: '/posts/1', path: '/posts/1',
method: 'PUT', method: 'PUT',
}); });
expect(params).toEqual({ resourceName: 'posts', resourceKey: '1', actionName: 'update' }); expect(params).toEqual({ resourceName: 'posts', resourceIndex: '1', actionName: 'update' });
}); });
it('update action', () => { it('update action', () => {
@ -127,7 +127,7 @@ describe('utils', () => {
path: '/posts/1', path: '/posts/1',
method: 'PATCH', method: 'PATCH',
}); });
expect(params).toEqual({ resourceName: 'posts', resourceKey: '1', actionName: 'update' }); expect(params).toEqual({ resourceName: 'posts', resourceIndex: '1', actionName: 'update' });
}); });
it('delete action', () => { it('delete action', () => {
@ -135,7 +135,7 @@ describe('utils', () => {
path: '/posts/1', path: '/posts/1',
method: 'delete', method: 'delete',
}); });
expect(params).toEqual({ resourceName: 'posts', resourceKey: '1', actionName: 'destroy' }); expect(params).toEqual({ resourceName: 'posts', resourceIndex: '1', actionName: 'destroy' });
}); });
it('delete action', () => { it('delete action', () => {
@ -143,7 +143,7 @@ describe('utils', () => {
path: '/posts/1,2,3,4,5,6', path: '/posts/1,2,3,4,5,6',
method: 'delete', method: 'delete',
}); });
expect(params).toEqual({ resourceName: 'posts', resourceKey: '1,2,3,4,5,6', actionName: 'destroy' }); expect(params).toEqual({ resourceName: 'posts', resourceIndex: '1,2,3,4,5,6', actionName: 'destroy' });
}); });
it('index action', () => { it('index action', () => {
@ -151,7 +151,7 @@ describe('utils', () => {
path: '/posts/1/comments', path: '/posts/1/comments',
method: 'GET', method: 'GET',
}); });
expect(params).toEqual({ resourceName: 'comments', associatedName: 'posts', associatedKey: '1', actionName: 'list' }); expect(params).toEqual({ resourceName: 'comments', associatedName: 'posts', associatedIndex: '1', actionName: 'list' });
}); });
it('store action', () => { it('store action', () => {
@ -159,7 +159,7 @@ describe('utils', () => {
path: '/posts/1/comments', path: '/posts/1/comments',
method: 'POST', method: 'POST',
}); });
expect(params).toEqual({ resourceName: 'comments', associatedName: 'posts', associatedKey: '1', actionName: 'create' }); expect(params).toEqual({ resourceName: 'comments', associatedName: 'posts', associatedIndex: '1', actionName: 'create' });
}); });
it('get action', () => { it('get action', () => {
@ -167,7 +167,7 @@ describe('utils', () => {
path: '/posts/1/comments/1', path: '/posts/1/comments/1',
method: 'GET', method: 'GET',
}); });
expect(params).toEqual({ resourceName: 'comments', resourceKey: '1', associatedName: 'posts', associatedKey: '1', actionName: 'get' }); expect(params).toEqual({ resourceName: 'comments', resourceIndex: '1', associatedName: 'posts', associatedIndex: '1', actionName: 'get' });
}); });
it('update action', () => { it('update action', () => {
@ -175,7 +175,7 @@ describe('utils', () => {
path: '/posts/1/comments/1', path: '/posts/1/comments/1',
method: 'PUT', method: 'PUT',
}); });
expect(params).toEqual({ resourceName: 'comments', resourceKey: '1', associatedName: 'posts', associatedKey: '1', actionName: 'update' }); expect(params).toEqual({ resourceName: 'comments', resourceIndex: '1', associatedName: 'posts', associatedIndex: '1', actionName: 'update' });
}); });
it('update action', () => { it('update action', () => {
@ -183,7 +183,7 @@ describe('utils', () => {
path: '/posts/1/comments/1', path: '/posts/1/comments/1',
method: 'PATCH', method: 'PATCH',
}); });
expect(params).toEqual({ resourceName: 'comments', resourceKey: '1', associatedName: 'posts', associatedKey: '1', actionName: 'update' }); expect(params).toEqual({ resourceName: 'comments', resourceIndex: '1', associatedName: 'posts', associatedIndex: '1', actionName: 'update' });
}); });
it('get action', () => { it('get action', () => {
@ -191,7 +191,7 @@ describe('utils', () => {
path: '/posts/1/comments/1', path: '/posts/1/comments/1',
method: 'delete', method: 'delete',
}); });
expect(params).toEqual({ resourceName: 'comments', resourceKey: '1', associatedName: 'posts', associatedKey: '1', actionName: 'destroy' }); expect(params).toEqual({ resourceName: 'comments', resourceIndex: '1', associatedName: 'posts', associatedIndex: '1', actionName: 'destroy' });
}); });
it('export action', () => { it('export action', () => {
@ -215,7 +215,7 @@ describe('utils', () => {
path: '/posts:export/1', path: '/posts:export/1',
method: 'POST', method: 'POST',
}); });
expect(params).toEqual({ resourceName: 'posts', resourceKey: '1', actionName: 'export' }); expect(params).toEqual({ resourceName: 'posts', resourceIndex: '1', actionName: 'export' });
}); });
it('attach action', () => { it('attach action', () => {
@ -225,8 +225,8 @@ describe('utils', () => {
}); });
expect(params).toEqual({ expect(params).toEqual({
resourceName: 'tags', resourceName: 'tags',
resourceKey: '2', resourceIndex: '2',
associatedKey: '1', associatedIndex: '1',
associatedName: 'posts', associatedName: 'posts',
actionName: 'attach', actionName: 'attach',
}); });

View File

@ -149,7 +149,7 @@ export interface ActionParams {
/** /**
* *
*/ */
resourceKey?: string; resourceIndex?: string;
/** /**
* *
*/ */
@ -157,7 +157,7 @@ export interface ActionParams {
/** /**
* *
*/ */
associatedKey?: string; associatedIndex?: string;
/** /**
* *
*/ */

View File

@ -26,9 +26,9 @@ export interface ParseOptions {
export interface ParsedParams { export interface ParsedParams {
actionName?: string; actionName?: string;
resourceName?: string; resourceName?: string;
resourceKey?: string; resourceIndex?: string;
associatedName?: string; associatedName?: string;
associatedKey?: string; associatedIndex?: string;
// table: string; // table: string;
// tableKey?: string | number; // tableKey?: string | number;
// relatedTable?: string; // relatedTable?: string;
@ -76,18 +76,18 @@ export function parseRequest(request: ParseRequest, options: ParseOptions = {}):
post: accessors.create, post: accessors.create,
delete: accessors.delete delete: accessors.delete
}, },
'/:resourceName/:resourceKey': { '/:resourceName/:resourceIndex': {
get: accessors.get, get: accessors.get,
put: accessors.update, put: accessors.update,
patch: accessors.update, patch: accessors.update,
delete: accessors.delete, delete: accessors.delete,
}, },
'/:associatedName/:associatedKey/:resourceName': { '/:associatedName/:associatedIndex/:resourceName': {
get: accessors.list, get: accessors.list,
post: accessors.create, post: accessors.create,
delete: accessors.delete, delete: accessors.delete,
}, },
'/:associatedName/:associatedKey/:resourceName/:resourceKey': { '/:associatedName/:associatedIndex/:resourceName/:resourceIndex': {
get: accessors.get, get: accessors.get,
post: accessors.create, post: accessors.create,
put: accessors.update, put: accessors.update,
@ -96,7 +96,7 @@ export function parseRequest(request: ParseRequest, options: ParseOptions = {}):
}, },
}, },
hasOne: { hasOne: {
'/:associatedName/:associatedKey/:resourceName': { '/:associatedName/:associatedIndex/:resourceName': {
get: accessors.get, get: accessors.get,
post: accessors.update, post: accessors.update,
put: accessors.update, put: accessors.update,
@ -105,12 +105,12 @@ export function parseRequest(request: ParseRequest, options: ParseOptions = {}):
}, },
}, },
hasMany: { hasMany: {
'/:associatedName/:associatedKey/:resourceName': { '/:associatedName/:associatedIndex/:resourceName': {
get: accessors.list, get: accessors.list,
post: accessors.create, post: accessors.create,
delete: accessors.delete, delete: accessors.delete,
}, },
'/:associatedName/:associatedKey/:resourceName/:resourceKey': { '/:associatedName/:associatedIndex/:resourceName/:resourceIndex': {
get: accessors.get, get: accessors.get,
post: accessors.create, post: accessors.create,
put: accessors.update, put: accessors.update,
@ -119,20 +119,20 @@ export function parseRequest(request: ParseRequest, options: ParseOptions = {}):
}, },
}, },
belongsTo: { belongsTo: {
'/:associatedName/:associatedKey/:resourceName': { '/:associatedName/:associatedIndex/:resourceName': {
get: accessors.get, get: accessors.get,
delete: accessors.remove, delete: accessors.remove,
}, },
'/:associatedName/:associatedKey/:resourceName/:resourceKey': { '/:associatedName/:associatedIndex/:resourceName/:resourceIndex': {
post: accessors.set, post: accessors.set,
}, },
}, },
belongsToMany: { belongsToMany: {
'/:associatedName/:associatedKey/:resourceName': { '/:associatedName/:associatedIndex/:resourceName': {
get: accessors.list, get: accessors.list,
post: accessors.set, post: accessors.set,
}, },
'/:associatedName/:associatedKey/:resourceName/:resourceKey': { '/:associatedName/:associatedIndex/:resourceName/:resourceIndex': {
get: accessors.get, get: accessors.get,
post: accessors.add, post: accessors.add,
put: accessors.update, // Many to Many 的 update 是针对 through put: accessors.update, // Many to Many 的 update 是针对 through

View File

@ -15,17 +15,17 @@ interface ActionParams {
perPage?: number; perPage?: number;
values?: any; values?: any;
resourceName?: string; resourceName?: string;
resourceKey?: string; resourceIndex?: string;
associatedName?: string; associatedName?: string;
associatedKey?: string; associatedIndex?: string;
[key: string]: any; [key: string]: any;
} }
interface SortActionParams { interface SortActionParams {
resourceName?: string; resourceName?: string;
resourceKey?: any; resourceIndex?: any;
associatedName?: string; associatedName?: string;
associatedKey?: any; associatedIndex?: any;
sourceId?: any; sourceId?: any;
targetId?: any; targetId?: any;
sortField?: string; sortField?: string;
@ -58,21 +58,21 @@ export class MockServer extends Application {
get(target, method: string, receiver) { get(target, method: string, receiver) {
return (params: ActionParams = {}) => { return (params: ActionParams = {}) => {
const { const {
associatedKey, associatedIndex,
resourceKey, resourceIndex,
values = {}, values = {},
file, file,
...restParams ...restParams
} = params; } = params;
let url = prefix; let url = prefix;
if (keys.length > 1) { if (keys.length > 1) {
url = `/${keys[0]}/${associatedKey}/${keys[1]}` url = `/${keys[0]}/${associatedIndex}/${keys[1]}`
} else { } else {
url = `/${name}`; url = `/${name}`;
} }
url += `:${method as string}`; url += `:${method as string}`;
if (resourceKey) { if (resourceIndex) {
url += `/${resourceKey}`; url += `/${resourceIndex}`;
} }
switch (method) { switch (method) {