feat: set field (#1237)
* feat: set field * feat: array field repository * feat: ArrayFieldRepository * fix: add set parse * test: array field repository * chore: update submodule * chore: field bind & unbind Co-authored-by: chenos <chenlinxh@gmail.com>
This commit is contained in:
parent
0c80992f7d
commit
393ada2bc5
@ -25,6 +25,7 @@ describe('add action', () => {
|
|||||||
{ type: 'hasOne', name: 'profile' },
|
{ type: 'hasOne', name: 'profile' },
|
||||||
{ type: 'belongsToMany', name: 'tags', through: 'posts_tags' },
|
{ type: 'belongsToMany', name: 'tags', through: 'posts_tags' },
|
||||||
{ type: 'string', name: 'status', defaultValue: 'draft' },
|
{ type: 'string', name: 'status', defaultValue: 'draft' },
|
||||||
|
{ type: 'set', name: 'set_field' },
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -51,6 +52,51 @@ describe('add action', () => {
|
|||||||
await app.destroy();
|
await app.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('add values to set field', async () => {
|
||||||
|
const p1 = await Post.repository.create({});
|
||||||
|
const response = await app
|
||||||
|
.agent()
|
||||||
|
.resource('posts.set_field', p1.get('id'))
|
||||||
|
.add({
|
||||||
|
values: ['a', 'b'],
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(response.statusCode).toEqual(200);
|
||||||
|
|
||||||
|
const listResponse = await app.agent().resource('posts.set_field', p1.get('id')).list({
|
||||||
|
paginate: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(listResponse.status).toEqual(200);
|
||||||
|
expect(listResponse.body).toEqual(['a', 'b']);
|
||||||
|
|
||||||
|
await app
|
||||||
|
.agent()
|
||||||
|
.resource('posts.set_field', p1.get('id'))
|
||||||
|
.remove({
|
||||||
|
values: ['b'],
|
||||||
|
});
|
||||||
|
|
||||||
|
const listResponse1 = await app.agent().resource('posts.set_field', p1.get('id')).list({
|
||||||
|
paginate: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(listResponse1.body).toEqual(['a']);
|
||||||
|
|
||||||
|
await app
|
||||||
|
.agent()
|
||||||
|
.resource('posts.set_field', p1.get('id'))
|
||||||
|
.set({
|
||||||
|
values: ['b', 'c', 'd'],
|
||||||
|
});
|
||||||
|
|
||||||
|
const listResponse2 = await app.agent().resource('posts.set_field', p1.get('id')).list({
|
||||||
|
paginate: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(listResponse2.body).toEqual(['b', 'c', 'd']);
|
||||||
|
});
|
||||||
|
|
||||||
test('add belongs to many', async () => {
|
test('add belongs to many', async () => {
|
||||||
const p1 = await Post.repository.create({
|
const p1 = await Post.repository.create({
|
||||||
values: {
|
values: {
|
||||||
|
@ -1,11 +1,22 @@
|
|||||||
import { Context } from '..';
|
import { Context } from '..';
|
||||||
import { getRepositoryFromParams } from '../utils';
|
import { getRepositoryFromParams } from '../utils';
|
||||||
import { BelongsToManyRepository, MultipleRelationRepository, HasManyRepository } from '@nocobase/database';
|
import {
|
||||||
|
BelongsToManyRepository,
|
||||||
|
MultipleRelationRepository,
|
||||||
|
HasManyRepository,
|
||||||
|
ArrayFieldRepository,
|
||||||
|
} from '@nocobase/database';
|
||||||
|
|
||||||
export async function add(ctx: Context, next) {
|
export async function add(ctx: Context, next) {
|
||||||
const repository = getRepositoryFromParams(ctx);
|
const repository = getRepositoryFromParams(ctx);
|
||||||
|
|
||||||
if (!(repository instanceof MultipleRelationRepository || repository instanceof HasManyRepository)) {
|
if (
|
||||||
|
!(
|
||||||
|
repository instanceof MultipleRelationRepository ||
|
||||||
|
repository instanceof HasManyRepository ||
|
||||||
|
repository instanceof ArrayFieldRepository
|
||||||
|
)
|
||||||
|
) {
|
||||||
return await next();
|
return await next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { Database, Model } from '..';
|
import { Database, Model } from '..';
|
||||||
|
import { ArrayFieldRepository } from '../field-repository/array-field-repository';
|
||||||
import { mockDatabase } from './index';
|
import { mockDatabase } from './index';
|
||||||
|
|
||||||
describe('database', () => {
|
describe('database', () => {
|
||||||
@ -47,6 +48,15 @@ describe('database', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should get array field repository', async () => {
|
||||||
|
db.collection({
|
||||||
|
name: 'tests',
|
||||||
|
fields: [{ type: 'set', name: 'set-field' }],
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(db.getRepository('tests.set-field', '1')).toBeInstanceOf(ArrayFieldRepository);
|
||||||
|
});
|
||||||
|
|
||||||
test('import', async () => {
|
test('import', async () => {
|
||||||
await db.import({
|
await db.import({
|
||||||
directory: path.resolve(__dirname, './fixtures/collections'),
|
directory: path.resolve(__dirname, './fixtures/collections'),
|
||||||
|
@ -0,0 +1,94 @@
|
|||||||
|
import { mockDatabase } from '../index';
|
||||||
|
import Database from '../../database';
|
||||||
|
import { ArrayFieldRepository } from '../../field-repository/array-field-repository';
|
||||||
|
|
||||||
|
describe('Array field repository', () => {
|
||||||
|
let db: Database;
|
||||||
|
|
||||||
|
let TestCollection;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
db = mockDatabase();
|
||||||
|
TestCollection = db.collection({
|
||||||
|
name: 'test',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
type: 'set',
|
||||||
|
name: 'set-field',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
await db.sync();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
await db.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add item into fields', async () => {
|
||||||
|
const a1 = await TestCollection.repository.create({});
|
||||||
|
|
||||||
|
const fieldRepository = new ArrayFieldRepository(TestCollection, 'set-field', a1.get('id'));
|
||||||
|
await fieldRepository.add({
|
||||||
|
values: 'a',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(await fieldRepository.get()).toEqual(['a']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should remove item', async () => {
|
||||||
|
const a1 = await TestCollection.repository.create({});
|
||||||
|
|
||||||
|
const fieldRepository = new ArrayFieldRepository(TestCollection, 'set-field', a1.get('id'));
|
||||||
|
await fieldRepository.add({
|
||||||
|
values: ['a', 'b', 'c'],
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(await fieldRepository.get()).toEqual(['a', 'b', 'c']);
|
||||||
|
await fieldRepository.remove({
|
||||||
|
values: ['c'],
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(await fieldRepository.get()).toEqual(['a', 'b']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set items', async () => {
|
||||||
|
const a1 = await TestCollection.repository.create({});
|
||||||
|
|
||||||
|
const fieldRepository = new ArrayFieldRepository(TestCollection, 'set-field', a1.get('id'));
|
||||||
|
await fieldRepository.add({
|
||||||
|
values: ['a', 'b', 'c'],
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(await fieldRepository.get()).toEqual(['a', 'b', 'c']);
|
||||||
|
await fieldRepository.set({
|
||||||
|
values: ['d', 'e'],
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(await fieldRepository.get()).toEqual(['d', 'e']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should toggle item', async () => {
|
||||||
|
const a1 = await TestCollection.repository.create({});
|
||||||
|
|
||||||
|
const fieldRepository = new ArrayFieldRepository(TestCollection, 'set-field', a1.get('id'));
|
||||||
|
await fieldRepository.add({
|
||||||
|
values: ['a', 'b', 'c'],
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(await fieldRepository.get()).toEqual(['a', 'b', 'c']);
|
||||||
|
|
||||||
|
await fieldRepository.toggle({
|
||||||
|
value: 'c',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(await fieldRepository.get()).toEqual(['a', 'b']);
|
||||||
|
|
||||||
|
await fieldRepository.toggle({
|
||||||
|
value: 'c',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(await fieldRepository.get()).toEqual(['a', 'b', 'c']);
|
||||||
|
});
|
||||||
|
});
|
37
packages/core/database/src/__tests__/fields/set.test.ts
Normal file
37
packages/core/database/src/__tests__/fields/set.test.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import { mockDatabase } from '../';
|
||||||
|
import { Database } from '../../database';
|
||||||
|
|
||||||
|
describe('set field', () => {
|
||||||
|
let db: Database;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
db = mockDatabase();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
await db.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set Set field', async () => {
|
||||||
|
const A = db.collection({
|
||||||
|
name: 'a',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
type: 'set',
|
||||||
|
name: 'set',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
await db.sync();
|
||||||
|
|
||||||
|
const a = await A.repository.create({});
|
||||||
|
|
||||||
|
a.set('set', ['a', 'b', 'c', 'a']);
|
||||||
|
|
||||||
|
await a.save();
|
||||||
|
|
||||||
|
const setValue = a.get('set');
|
||||||
|
expect(setValue).toEqual(['a', 'b', 'c']);
|
||||||
|
});
|
||||||
|
});
|
@ -15,13 +15,14 @@ import {
|
|||||||
Sequelize,
|
Sequelize,
|
||||||
SyncOptions,
|
SyncOptions,
|
||||||
Transactionable,
|
Transactionable,
|
||||||
Utils
|
Utils,
|
||||||
} from 'sequelize';
|
} from 'sequelize';
|
||||||
import { SequelizeStorage, Umzug } from 'umzug';
|
import { SequelizeStorage, Umzug } from 'umzug';
|
||||||
import { Collection, CollectionOptions, RepositoryType } from './collection';
|
import { Collection, CollectionOptions, RepositoryType } from './collection';
|
||||||
import { ImporterReader, ImportFileExtension } from './collection-importer';
|
import { ImporterReader, ImportFileExtension } from './collection-importer';
|
||||||
import ReferencesMap from './features/ReferencesMap';
|
import ReferencesMap from './features/ReferencesMap';
|
||||||
import { referentialIntegrityCheck } from './features/referential-integrity-check';
|
import { referentialIntegrityCheck } from './features/referential-integrity-check';
|
||||||
|
import { ArrayFieldRepository } from './field-repository/array-field-repository';
|
||||||
import * as FieldTypes from './fields';
|
import * as FieldTypes from './fields';
|
||||||
import { Field, FieldContext, RelationField } from './fields';
|
import { Field, FieldContext, RelationField } from './fields';
|
||||||
import { InheritedCollection } from './inherited-collection';
|
import { InheritedCollection } from './inherited-collection';
|
||||||
@ -57,7 +58,7 @@ import {
|
|||||||
SyncListener,
|
SyncListener,
|
||||||
UpdateListener,
|
UpdateListener,
|
||||||
UpdateWithAssociationsListener,
|
UpdateWithAssociationsListener,
|
||||||
ValidateListener
|
ValidateListener,
|
||||||
} from './types';
|
} from './types';
|
||||||
|
|
||||||
export interface MergeOptions extends merge.Options {}
|
export interface MergeOptions extends merge.Options {}
|
||||||
@ -375,6 +376,7 @@ export class Database extends EventEmitter implements AsyncEmitter {
|
|||||||
|
|
||||||
getRepository<R extends Repository>(name: string): R;
|
getRepository<R extends Repository>(name: string): R;
|
||||||
getRepository<R extends RelationRepository>(name: string, relationId: string | number): R;
|
getRepository<R extends RelationRepository>(name: string, relationId: string | number): R;
|
||||||
|
getRepository<R extends ArrayFieldRepository>(name: string, relationId: string | number): R;
|
||||||
|
|
||||||
getRepository<R extends RelationRepository>(name: string, relationId?: string | number): Repository | R {
|
getRepository<R extends RelationRepository>(name: string, relationId?: string | number): Repository | R {
|
||||||
if (relationId) {
|
if (relationId) {
|
||||||
|
@ -0,0 +1,127 @@
|
|||||||
|
import { Transactionable } from 'sequelize/types';
|
||||||
|
import { Collection } from '../collection';
|
||||||
|
import lodash from 'lodash';
|
||||||
|
import { transactionWrapperBuilder } from '../decorators/transaction-decorator';
|
||||||
|
import { ArrayField } from '../fields';
|
||||||
|
|
||||||
|
const transaction = transactionWrapperBuilder(function () {
|
||||||
|
return this.collection.model.sequelize.transaction();
|
||||||
|
});
|
||||||
|
|
||||||
|
export class ArrayFieldRepository {
|
||||||
|
constructor(protected collection: Collection, protected fieldName: string, protected targetValue: string | number) {
|
||||||
|
const field = collection.getField(fieldName);
|
||||||
|
if (!(field instanceof ArrayField)) {
|
||||||
|
throw new Error('Field must be of type Array');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@transaction()
|
||||||
|
async get(options?: Transactionable) {
|
||||||
|
const instance = await this.getInstance(options);
|
||||||
|
return instance.get(this.fieldName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@transaction()
|
||||||
|
async find(options?: Transactionable) {
|
||||||
|
return await this.get(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
@transaction((args, transaction) => {
|
||||||
|
return {
|
||||||
|
values: args[0],
|
||||||
|
transaction,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
async set(
|
||||||
|
options: Transactionable & {
|
||||||
|
values: Array<string | number> | string | number;
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
const { transaction } = options;
|
||||||
|
|
||||||
|
const instance = await this.getInstance({
|
||||||
|
transaction,
|
||||||
|
});
|
||||||
|
|
||||||
|
instance.set(this.fieldName, lodash.castArray(options.values));
|
||||||
|
await instance.save({ transaction });
|
||||||
|
}
|
||||||
|
|
||||||
|
@transaction((args, transaction) => {
|
||||||
|
return {
|
||||||
|
value: args[0],
|
||||||
|
transaction,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
async toggle(
|
||||||
|
options: Transactionable & {
|
||||||
|
value: string | number;
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
const { transaction } = options;
|
||||||
|
|
||||||
|
const instance = await this.getInstance({
|
||||||
|
transaction,
|
||||||
|
});
|
||||||
|
|
||||||
|
const oldValue = instance.get(this.fieldName) || [];
|
||||||
|
const newValue = oldValue.includes(options.value)
|
||||||
|
? lodash.without(oldValue, options.value)
|
||||||
|
: [...oldValue, options.value];
|
||||||
|
instance.set(this.fieldName, newValue);
|
||||||
|
await instance.save({ transaction });
|
||||||
|
}
|
||||||
|
|
||||||
|
@transaction((args, transaction) => {
|
||||||
|
return {
|
||||||
|
values: args[0],
|
||||||
|
transaction,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
async add(
|
||||||
|
options: Transactionable & {
|
||||||
|
values: Array<string | number> | string | number;
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
const { transaction } = options;
|
||||||
|
|
||||||
|
const instance = await this.getInstance({
|
||||||
|
transaction,
|
||||||
|
});
|
||||||
|
|
||||||
|
const oldValue = instance.get(this.fieldName) || [];
|
||||||
|
|
||||||
|
const newValue = [...oldValue, ...lodash.castArray(options.values)];
|
||||||
|
instance.set(this.fieldName, newValue);
|
||||||
|
await instance.save({ transaction });
|
||||||
|
}
|
||||||
|
|
||||||
|
@transaction((args, transaction) => {
|
||||||
|
return {
|
||||||
|
values: args[0],
|
||||||
|
transaction,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
async remove(
|
||||||
|
options: Transactionable & {
|
||||||
|
values: Array<string | number> | string | number;
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
const { transaction } = options;
|
||||||
|
|
||||||
|
const instance = await this.getInstance({
|
||||||
|
transaction,
|
||||||
|
});
|
||||||
|
|
||||||
|
const oldValue = instance.get(this.fieldName) || [];
|
||||||
|
instance.set(this.fieldName, lodash.without(oldValue, ...lodash.castArray(options.values)));
|
||||||
|
await instance.save({ transaction });
|
||||||
|
}
|
||||||
|
|
||||||
|
protected getInstance(options: Transactionable) {
|
||||||
|
return this.collection.repository.findOne({
|
||||||
|
filterByTk: this.targetValue,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -10,23 +10,23 @@ export class ArrayField extends Field {
|
|||||||
return DataTypes.JSON;
|
return DataTypes.JSON;
|
||||||
}
|
}
|
||||||
|
|
||||||
sortValue(model) {
|
sortValue = (model) => {
|
||||||
const oldValue = model.get(this.options.name);
|
const oldValue = model.get(this.options.name);
|
||||||
|
|
||||||
if (oldValue) {
|
if (oldValue) {
|
||||||
const newValue = oldValue.sort();
|
const newValue = oldValue.sort();
|
||||||
model.set(this.options.name, newValue);
|
model.set(this.options.name, newValue);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
bind() {
|
bind() {
|
||||||
super.bind();
|
super.bind();
|
||||||
this.on('beforeSave', this.sortValue.bind(this));
|
this.on('beforeSave', this.sortValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
unbind() {
|
unbind() {
|
||||||
super.unbind();
|
super.unbind();
|
||||||
this.off('beforeSave', this.sortValue.bind(this));
|
this.off('beforeSave', this.sortValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ import {
|
|||||||
DoubleFieldOptions,
|
DoubleFieldOptions,
|
||||||
FloatFieldOptions,
|
FloatFieldOptions,
|
||||||
IntegerFieldOptions,
|
IntegerFieldOptions,
|
||||||
RealFieldOptions
|
RealFieldOptions,
|
||||||
} from './number-field';
|
} from './number-field';
|
||||||
import { PasswordFieldOptions } from './password-field';
|
import { PasswordFieldOptions } from './password-field';
|
||||||
import { RadioFieldOptions } from './radio-field';
|
import { RadioFieldOptions } from './radio-field';
|
||||||
@ -26,8 +26,10 @@ import { UUIDFieldOptions } from './uuid-field';
|
|||||||
import { VirtualFieldOptions } from './virtual-field';
|
import { VirtualFieldOptions } from './virtual-field';
|
||||||
import { FormulaFieldOptions } from './formula-field';
|
import { FormulaFieldOptions } from './formula-field';
|
||||||
import { SequenceFieldOptions } from './sequence-field';
|
import { SequenceFieldOptions } from './sequence-field';
|
||||||
|
import { SetFieldOptions } from './set-field';
|
||||||
|
|
||||||
export * from './array-field';
|
export * from './array-field';
|
||||||
|
export * from './set-field';
|
||||||
export * from './belongs-to-field';
|
export * from './belongs-to-field';
|
||||||
export * from './belongs-to-many-field';
|
export * from './belongs-to-many-field';
|
||||||
export * from './boolean-field';
|
export * from './boolean-field';
|
||||||
@ -68,6 +70,7 @@ export type FieldOptions =
|
|||||||
| VirtualFieldOptions
|
| VirtualFieldOptions
|
||||||
| FormulaFieldOptions
|
| FormulaFieldOptions
|
||||||
| ArrayFieldOptions
|
| ArrayFieldOptions
|
||||||
|
| SetFieldOptions
|
||||||
| TimeFieldOptions
|
| TimeFieldOptions
|
||||||
| DateFieldOptions
|
| DateFieldOptions
|
||||||
| UidFieldOptions
|
| UidFieldOptions
|
||||||
|
25
packages/core/database/src/fields/set-field.ts
Normal file
25
packages/core/database/src/fields/set-field.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { ArrayField } from './array-field';
|
||||||
|
import { BaseColumnFieldOptions } from './field';
|
||||||
|
|
||||||
|
export interface SetFieldOptions extends BaseColumnFieldOptions {
|
||||||
|
type: 'set';
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SetField extends ArrayField {
|
||||||
|
beforeSave = (model) => {
|
||||||
|
const oldValue = model.get(this.options.name);
|
||||||
|
if (oldValue) {
|
||||||
|
model.set(this.options.name, [...new Set(oldValue)]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
bind() {
|
||||||
|
super.bind();
|
||||||
|
this.on('beforeSave', this.beforeSave);
|
||||||
|
}
|
||||||
|
|
||||||
|
unbind() {
|
||||||
|
super.unbind();
|
||||||
|
this.off('beforeSave', this.beforeSave);
|
||||||
|
}
|
||||||
|
}
|
@ -15,3 +15,4 @@ export * from './relation-repository/multiple-relation-repository';
|
|||||||
export * from './relation-repository/single-relation-repository';
|
export * from './relation-repository/single-relation-repository';
|
||||||
export * from './repository';
|
export * from './repository';
|
||||||
export * from './update-associations';
|
export * from './update-associations';
|
||||||
|
export * from './field-repository/array-field-repository';
|
||||||
|
@ -10,14 +10,15 @@ import {
|
|||||||
ModelCtor,
|
ModelCtor,
|
||||||
Op,
|
Op,
|
||||||
Transactionable,
|
Transactionable,
|
||||||
UpdateOptions as SequelizeUpdateOptions
|
UpdateOptions as SequelizeUpdateOptions,
|
||||||
} from 'sequelize';
|
} from 'sequelize';
|
||||||
import { WhereOperators } from 'sequelize/types/lib/model';
|
import { WhereOperators } from 'sequelize/types/lib/model';
|
||||||
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 mustHaveFilter from './decorators/must-have-filter-decorator';
|
||||||
import { transactionWrapperBuilder } from './decorators/transaction-decorator';
|
import { transactionWrapperBuilder } from './decorators/transaction-decorator';
|
||||||
import { RelationField } from './fields';
|
import { ArrayFieldRepository } from './field-repository/array-field-repository';
|
||||||
|
import { ArrayField, RelationField } from './fields';
|
||||||
import FilterParser from './filter-parser';
|
import FilterParser from './filter-parser';
|
||||||
import { Model } from './model';
|
import { Model } from './model';
|
||||||
import operators from './operators';
|
import operators from './operators';
|
||||||
@ -161,19 +162,29 @@ const transaction = transactionWrapperBuilder(function () {
|
|||||||
class RelationRepositoryBuilder<R extends RelationRepository> {
|
class RelationRepositoryBuilder<R extends RelationRepository> {
|
||||||
collection: Collection;
|
collection: Collection;
|
||||||
associationName: string;
|
associationName: string;
|
||||||
association: Association;
|
association: Association | { associationType: string };
|
||||||
|
|
||||||
builderMap = {
|
builderMap = {
|
||||||
HasOne: HasOneRepository,
|
HasOne: HasOneRepository,
|
||||||
BelongsTo: BelongsToRepository,
|
BelongsTo: BelongsToRepository,
|
||||||
BelongsToMany: BelongsToManyRepository,
|
BelongsToMany: BelongsToManyRepository,
|
||||||
HasMany: HasManyRepository,
|
HasMany: HasManyRepository,
|
||||||
|
ArrayField: ArrayFieldRepository,
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(collection: Collection, associationName: string) {
|
constructor(collection: Collection, associationName: string) {
|
||||||
this.collection = collection;
|
this.collection = collection;
|
||||||
this.associationName = associationName;
|
this.associationName = associationName;
|
||||||
this.association = this.collection.model.associations[this.associationName];
|
this.association = this.collection.model.associations[this.associationName];
|
||||||
|
|
||||||
|
if (!this.association) {
|
||||||
|
const field = collection.getField(associationName);
|
||||||
|
if (field && field instanceof ArrayField) {
|
||||||
|
this.association = {
|
||||||
|
associationType: 'ArrayField',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected builder() {
|
protected builder() {
|
||||||
|
@ -286,6 +286,7 @@ export class Resourcer {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const resource = this.getResource(getNameByParams(params));
|
const resource = this.getResource(getNameByParams(params));
|
||||||
|
|
||||||
// 为关系资源时,暂时需要再执行一遍 parseRequest
|
// 为关系资源时,暂时需要再执行一遍 parseRequest
|
||||||
if (resource.options.type && resource.options.type !== 'single') {
|
if (resource.options.type && resource.options.type !== 'single') {
|
||||||
params = parseRequest(
|
params = parseRequest(
|
||||||
@ -299,6 +300,7 @@ export class Resourcer {
|
|||||||
accessors: this.options.accessors || accessors,
|
accessors: this.options.accessors || accessors,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!params) {
|
if (!params) {
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
@ -140,6 +140,13 @@ export function parseRequest(request: ParseRequest, options: ParseOptions = {}):
|
|||||||
delete: accessors.remove,
|
delete: accessors.remove,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
set: {
|
||||||
|
'/:associatedName/:associatedIndex/:resourceName': {
|
||||||
|
get: accessors.list,
|
||||||
|
post: accessors.add,
|
||||||
|
delete: accessors.remove,
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const params: ParsedParams = {};
|
const params: ParsedParams = {};
|
||||||
|
Loading…
Reference in New Issue
Block a user