@nocobase/database 0.9.2-alpha.2 → 0.9.2-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/collection.d.ts +8 -0
- package/lib/collection.js +3 -3
- package/lib/database.d.ts +2 -3
- package/lib/database.js +2 -2
- package/lib/fields/relation-field.d.ts +1 -2
- package/lib/filter-parser.js +2 -2
- package/lib/model-hook.d.ts +1 -1
- package/lib/operators/empty.js +1 -1
- package/lib/options-parser.js +2 -2
- package/lib/relation-repository/belongs-to-many-repository.d.ts +2 -2
- package/lib/relation-repository/belongs-to-repository.d.ts +2 -3
- package/lib/relation-repository/hasmany-repository.d.ts +2 -2
- package/lib/relation-repository/hasone-repository.d.ts +1 -1
- package/lib/relation-repository/multiple-relation-repository.d.ts +2 -2
- package/lib/relation-repository/single-relation-repository.d.ts +1 -1
- package/lib/relation-repository/single-relation-repository.js +1 -1
- package/lib/update-associations.js +1 -1
- package/lib/utils.js +1 -1
- package/package.json +4 -4
- package/src/__tests__/field-options/hidden.test.ts +12 -8
- package/src/__tests__/fields/belongs-to-field.test.ts +2 -5
- package/src/__tests__/fields/date.test.ts +1 -3
- package/src/__tests__/fields/has-many-field.test.ts +1 -1
- package/src/__tests__/filter.test.ts +41 -0
- package/src/__tests__/hooks/afterCreateWithAssociations.test.ts +1 -2
- package/src/__tests__/migrator.test.ts +1 -2
- package/src/__tests__/model-hook.test.ts +2 -2
- package/src/__tests__/operator/eq.test.ts +3 -15
- package/src/__tests__/operator/ne.test.ts +1 -5
- package/src/__tests__/option-parser.test.ts +2 -2
- package/src/__tests__/relation-repository/belongs-to-many-repository.test.ts +12 -12
- package/src/__tests__/sequelize-hooks.test.ts +1 -6
- package/src/__tests__/sort.test.ts +2 -2
- package/src/collection.ts +13 -3
- package/src/database.ts +3 -3
- package/src/fields/has-many-field.ts +1 -1
- package/src/fields/has-one-field.ts +1 -1
- package/src/fields/index.ts +1 -1
- package/src/fields/number-field.ts +1 -3
- package/src/fields/relation-field.ts +1 -1
- package/src/filter-parser.ts +2 -2
- package/src/model-hook.ts +1 -1
- package/src/operators/empty.ts +1 -1
- package/src/operators/notIn.ts +0 -1
- package/src/options-parser.ts +3 -3
- package/src/relation-repository/belongs-to-many-repository.ts +2 -2
- package/src/relation-repository/belongs-to-repository.ts +2 -2
- package/src/relation-repository/hasmany-repository.ts +2 -2
- package/src/relation-repository/hasone-repository.ts +1 -1
- package/src/relation-repository/multiple-relation-repository.ts +1 -1
- package/src/relation-repository/single-relation-repository.ts +2 -2
- package/src/types.ts +16 -6
- package/src/update-associations.ts +1 -1
- package/src/utils.ts +1 -1
package/lib/collection.d.ts
CHANGED
|
@@ -14,6 +14,14 @@ declare type dumpable = 'required' | 'optional' | 'skip';
|
|
|
14
14
|
export interface CollectionOptions extends Omit<ModelOptions, 'name' | 'hooks'> {
|
|
15
15
|
name: string;
|
|
16
16
|
namespace?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Used for @nocobase/plugin-duplicator
|
|
19
|
+
* @see packages/core/database/src/collection-group-manager.tss
|
|
20
|
+
*
|
|
21
|
+
* @prop {'required' | 'optional' | 'skip'} dumpable - Determine whether the collection is dumped
|
|
22
|
+
* @prop {string[] | string} [with] - Collections dumped with this collection
|
|
23
|
+
* @prop {any} [delayRestore] - A function to execute after all collections are restored
|
|
24
|
+
*/
|
|
17
25
|
duplicator?: dumpable | {
|
|
18
26
|
dumpable: dumpable;
|
|
19
27
|
with?: string[] | string;
|
package/lib/collection.js
CHANGED
|
@@ -56,7 +56,7 @@ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o =
|
|
|
56
56
|
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
|
|
57
57
|
class Collection extends _events().EventEmitter {
|
|
58
58
|
get filterTargetKey() {
|
|
59
|
-
|
|
59
|
+
const targetKey = _lodash().default.get(this.options, 'filterTargetKey', this.model.primaryKeyAttribute);
|
|
60
60
|
if (!targetKey && this.model.rawAttributes['id']) {
|
|
61
61
|
return 'id';
|
|
62
62
|
}
|
|
@@ -273,7 +273,7 @@ class Collection extends _events().EventEmitter {
|
|
|
273
273
|
sourceFieldName = _options$source$split2[1];
|
|
274
274
|
const sourceCollection = this.db.collections.get(sourceCollectionName);
|
|
275
275
|
if (!sourceCollection) {
|
|
276
|
-
throw new Error(`source collection "${sourceCollectionName}" not found`);
|
|
276
|
+
throw new Error(`source collection "${sourceCollectionName}" not found for field "${name}" at collection "${this.name}"`);
|
|
277
277
|
}
|
|
278
278
|
const sourceField = sourceCollection.fields.get(sourceFieldName);
|
|
279
279
|
options = _objectSpread(_objectSpread({}, sourceField.options), options);
|
|
@@ -469,7 +469,7 @@ class Collection extends _events().EventEmitter {
|
|
|
469
469
|
return;
|
|
470
470
|
}
|
|
471
471
|
// collection defined indexes
|
|
472
|
-
|
|
472
|
+
const indexes = this.model.options.indexes || [];
|
|
473
473
|
let indexName = [];
|
|
474
474
|
let indexItem;
|
|
475
475
|
if (typeof index === 'string') {
|
package/lib/database.d.ts
CHANGED
|
@@ -22,8 +22,7 @@ import { BaseValueParser } from './value-parsers';
|
|
|
22
22
|
import QueryInterface from './query-interface/query-interface';
|
|
23
23
|
import { Logger } from '@nocobase/logger';
|
|
24
24
|
import { CollectionGroupManager } from './collection-group-manager';
|
|
25
|
-
export
|
|
26
|
-
}
|
|
25
|
+
export declare type MergeOptions = merge.Options;
|
|
27
26
|
export interface PendingOptions {
|
|
28
27
|
field: RelationField;
|
|
29
28
|
model: ModelStatic<Model>;
|
|
@@ -170,7 +169,7 @@ export declare class Database extends EventEmitter implements AsyncEmitter {
|
|
|
170
169
|
}
|
|
171
170
|
export declare function extendCollection(collectionOptions: CollectionOptions, mergeOptions?: MergeOptions): {
|
|
172
171
|
collectionOptions: CollectionOptions;
|
|
173
|
-
mergeOptions:
|
|
172
|
+
mergeOptions: merge.Options;
|
|
174
173
|
extend: boolean;
|
|
175
174
|
};
|
|
176
175
|
export declare const extend: typeof extendCollection;
|
package/lib/database.js
CHANGED
|
@@ -482,7 +482,7 @@ class Database extends _events().EventEmitter {
|
|
|
482
482
|
collectionName = _path$split2[0],
|
|
483
483
|
associationName = _path$split2[1],
|
|
484
484
|
args = _path$split2.slice(2);
|
|
485
|
-
|
|
485
|
+
const collection = this.getCollection(collectionName);
|
|
486
486
|
if (!collection) {
|
|
487
487
|
return;
|
|
488
488
|
}
|
|
@@ -507,7 +507,7 @@ class Database extends _events().EventEmitter {
|
|
|
507
507
|
_name$split2 = _slicedToArray(_name$split, 2),
|
|
508
508
|
collectionName = _name$split2[0],
|
|
509
509
|
associationName = _name$split2[1];
|
|
510
|
-
|
|
510
|
+
const collection = this.collections.get(collectionName);
|
|
511
511
|
if (associationName) {
|
|
512
512
|
var _collection$getField;
|
|
513
513
|
const target = (_collection$getField = collection.getField(associationName)) === null || _collection$getField === void 0 ? void 0 : _collection$getField.target;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { BaseFieldOptions, Field } from './field';
|
|
2
|
-
export
|
|
3
|
-
}
|
|
2
|
+
export declare type BaseRelationFieldOptions = BaseFieldOptions;
|
|
4
3
|
export interface MultipleRelationFieldOptions extends BaseRelationFieldOptions {
|
|
5
4
|
sortBy?: string | string[];
|
|
6
5
|
}
|
package/lib/filter-parser.js
CHANGED
|
@@ -101,7 +101,7 @@ class FilterParser {
|
|
|
101
101
|
continue;
|
|
102
102
|
}
|
|
103
103
|
debug('handle filter key "%s: "%s"', key, value);
|
|
104
|
-
|
|
104
|
+
const keys = key.split('.');
|
|
105
105
|
// paths ?
|
|
106
106
|
const paths = [];
|
|
107
107
|
// origins ?
|
|
@@ -223,7 +223,7 @@ class FilterParser {
|
|
|
223
223
|
getFieldNameFromQueryPath(queryPath) {
|
|
224
224
|
const paths = queryPath.split('.');
|
|
225
225
|
let fieldName;
|
|
226
|
-
|
|
226
|
+
const fullPaths = [];
|
|
227
227
|
var _iterator = _createForOfIteratorHelper(paths),
|
|
228
228
|
_step;
|
|
229
229
|
try {
|
package/lib/model-hook.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export declare class ModelHook {
|
|
|
4
4
|
database: Database;
|
|
5
5
|
boundEvents: Set<string>;
|
|
6
6
|
constructor(database: Database);
|
|
7
|
-
match(event: string |
|
|
7
|
+
match(event: string | symbol): keyof SequelizeHooks | null;
|
|
8
8
|
findModelName(hookArgs: any): any;
|
|
9
9
|
bindEvent(type: any): void;
|
|
10
10
|
hasBoundEvent(type: any): boolean;
|
package/lib/operators/empty.js
CHANGED
|
@@ -28,7 +28,7 @@ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o =
|
|
|
28
28
|
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
|
|
29
29
|
const findFilterFieldType = ctx => {
|
|
30
30
|
const db = ctx.db;
|
|
31
|
-
|
|
31
|
+
const path = ctx.path.split('.');
|
|
32
32
|
// remove operators
|
|
33
33
|
path.pop();
|
|
34
34
|
const fieldName = path.pop();
|
package/lib/options-parser.js
CHANGED
|
@@ -79,7 +79,7 @@ class OptionsParser {
|
|
|
79
79
|
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
80
80
|
const sortKey = _step.value;
|
|
81
81
|
let direction = sortKey.startsWith('-') ? 'DESC' : 'ASC';
|
|
82
|
-
|
|
82
|
+
const sortField = sortKey.replace('-', '').split('.');
|
|
83
83
|
if (this.database.inDialect('postgres', 'sqlite')) {
|
|
84
84
|
direction = `${direction} NULLS LAST`;
|
|
85
85
|
}
|
|
@@ -197,7 +197,7 @@ class OptionsParser {
|
|
|
197
197
|
const exceptPath = except.split('.');
|
|
198
198
|
const association = exceptPath[0];
|
|
199
199
|
const lastLevel = exceptPath.length <= 2;
|
|
200
|
-
|
|
200
|
+
const existIncludeIndex = queryParams['include'].findIndex(include => include['association'] == association);
|
|
201
201
|
if (existIncludeIndex == -1) {
|
|
202
202
|
// if include not exists, ignore this except
|
|
203
203
|
return;
|
|
@@ -10,7 +10,7 @@ interface IBelongsToManyRepository<M extends Model> {
|
|
|
10
10
|
findOne(options?: FindOneOptions): Promise<M>;
|
|
11
11
|
create(options?: CreateOptions): Promise<M>;
|
|
12
12
|
update(options?: UpdateOptions): Promise<M>;
|
|
13
|
-
destroy(options?: number | string | number[] | string[] | DestroyOptions): Promise<
|
|
13
|
+
destroy(options?: number | string | number[] | string[] | DestroyOptions): Promise<boolean>;
|
|
14
14
|
set(options: TargetKey | TargetKey[] | AssociatedOptions): Promise<void>;
|
|
15
15
|
add(options: TargetKey | TargetKey[] | AssociatedOptions): Promise<void>;
|
|
16
16
|
remove(options: TargetKey | TargetKey[] | AssociatedOptions): Promise<void>;
|
|
@@ -21,7 +21,7 @@ interface IBelongsToManyRepository<M extends Model> {
|
|
|
21
21
|
}
|
|
22
22
|
export declare class BelongsToManyRepository extends MultipleRelationRepository implements IBelongsToManyRepository<any> {
|
|
23
23
|
create(options?: CreateBelongsToManyOptions): Promise<any>;
|
|
24
|
-
destroy(options?: TargetKey | TargetKey[] | DestroyOptions): Promise<
|
|
24
|
+
destroy(options?: TargetKey | TargetKey[] | DestroyOptions): Promise<boolean>;
|
|
25
25
|
protected setTargets(call: 'add' | 'set', options: TargetKey | TargetKey[] | PrimaryKeyWithThroughValues | PrimaryKeyWithThroughValues[] | AssociatedOptions): Promise<void>;
|
|
26
26
|
add(options: TargetKey | TargetKey[] | PrimaryKeyWithThroughValues | PrimaryKeyWithThroughValues[] | AssociatedOptions): Promise<void>;
|
|
27
27
|
set(options: TargetKey | TargetKey[] | PrimaryKeyWithThroughValues | PrimaryKeyWithThroughValues[] | AssociatedOptions): Promise<void>;
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import { Model } from '../model';
|
|
2
2
|
import { CreateOptions, UpdateOptions } from '../repository';
|
|
3
3
|
import { SingleRelationFindOption, SingleRelationRepository } from './single-relation-repository';
|
|
4
|
-
|
|
5
|
-
}
|
|
4
|
+
declare type BelongsToFindOptions = SingleRelationFindOption;
|
|
6
5
|
interface IBelongsToRepository<M extends Model> {
|
|
7
6
|
find(options?: BelongsToFindOptions): Promise<M>;
|
|
8
7
|
findOne(options?: BelongsToFindOptions): Promise<M>;
|
|
9
8
|
create(options?: CreateOptions): Promise<M>;
|
|
10
9
|
update(options?: UpdateOptions): Promise<M>;
|
|
11
|
-
destroy(): Promise<
|
|
10
|
+
destroy(): Promise<boolean>;
|
|
12
11
|
set(primaryKey: any): Promise<void>;
|
|
13
12
|
remove(): Promise<void>;
|
|
14
13
|
}
|
|
@@ -7,14 +7,14 @@ interface IHasManyRepository<M extends Model> {
|
|
|
7
7
|
findOne(options?: FindOneOptions): Promise<M>;
|
|
8
8
|
create(options?: CreateOptions): Promise<M>;
|
|
9
9
|
update(options?: UpdateOptions): Promise<M>;
|
|
10
|
-
destroy(options?: TK | DestroyOptions): Promise<
|
|
10
|
+
destroy(options?: TK | DestroyOptions): Promise<boolean>;
|
|
11
11
|
set(options: TargetKey | TargetKey[] | AssociatedOptions): Promise<void>;
|
|
12
12
|
add(options: TargetKey | TargetKey[] | AssociatedOptions): Promise<void>;
|
|
13
13
|
remove(options: TargetKey | TargetKey[] | AssociatedOptions): Promise<void>;
|
|
14
14
|
}
|
|
15
15
|
export declare class HasManyRepository extends MultipleRelationRepository implements IHasManyRepository<any> {
|
|
16
16
|
find(options?: FindOptions): Promise<any>;
|
|
17
|
-
destroy(options?: TK | DestroyOptions): Promise<
|
|
17
|
+
destroy(options?: TK | DestroyOptions): Promise<boolean>;
|
|
18
18
|
handleKeyOfAdd(options: any): any;
|
|
19
19
|
set(options: TargetKey | TargetKey[] | AssociatedOptions): Promise<void>;
|
|
20
20
|
add(options: TargetKey | TargetKey[] | AssociatedOptions): Promise<void>;
|
|
@@ -6,7 +6,7 @@ interface IHasOneRepository<M extends Model> {
|
|
|
6
6
|
findOne(options?: SingleRelationFindOption): Promise<M>;
|
|
7
7
|
create(options?: CreateOptions): Promise<M>;
|
|
8
8
|
update(options?: any): Promise<M>;
|
|
9
|
-
destroy(): Promise<
|
|
9
|
+
destroy(): Promise<boolean>;
|
|
10
10
|
set(primaryKey: any): Promise<void>;
|
|
11
11
|
remove(): Promise<void>;
|
|
12
12
|
}
|
|
@@ -13,8 +13,8 @@ export declare abstract class MultipleRelationRepository extends RelationReposit
|
|
|
13
13
|
findOne(options?: FindOneOptions): Promise<any>;
|
|
14
14
|
remove(options: TargetKey | TargetKey[] | AssociatedOptions): Promise<void>;
|
|
15
15
|
update(options?: UpdateOptions): Promise<any>;
|
|
16
|
-
destroy(options?: TK | DestroyOptions): Promise<
|
|
17
|
-
protected destroyByFilter(filter: Filter, transaction?: Transaction): Promise<
|
|
16
|
+
destroy(options?: TK | DestroyOptions): Promise<boolean>;
|
|
17
|
+
protected destroyByFilter(filter: Filter, transaction?: Transaction): Promise<boolean>;
|
|
18
18
|
protected filterHasInclude(filter: Filter, options?: any): boolean;
|
|
19
19
|
protected accessors(): MultiAssociationAccessors;
|
|
20
20
|
}
|
|
@@ -16,7 +16,7 @@ export declare abstract class SingleRelationRepository extends RelationRepositor
|
|
|
16
16
|
set(options: TargetKey | SetOption): Promise<void>;
|
|
17
17
|
find(options?: SingleRelationFindOption): Promise<Model<any> | null>;
|
|
18
18
|
findOne(options?: SingleRelationFindOption): Promise<Model<any>>;
|
|
19
|
-
destroy(options?: Transactionable): Promise<
|
|
19
|
+
destroy(options?: Transactionable): Promise<boolean>;
|
|
20
20
|
update(options: UpdateOptions): Promise<any>;
|
|
21
21
|
accessors(): SingleAssociationAccessors;
|
|
22
22
|
}
|
|
@@ -44,7 +44,7 @@ class SingleRelationRepository extends _relationRepository.RelationRepository {
|
|
|
44
44
|
var _this2 = this;
|
|
45
45
|
return _asyncToGenerator(function* () {
|
|
46
46
|
const transaction = yield _this2.getTransaction(options);
|
|
47
|
-
|
|
47
|
+
const handleKey = _lodash().default.isPlainObject(options) ? options.tk : options;
|
|
48
48
|
const sourceModel = yield _this2.getSourceModel(transaction);
|
|
49
49
|
return yield sourceModel[_this2.accessors().set](handleKey, {
|
|
50
50
|
transaction
|
package/lib/utils.js
CHANGED
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nocobase/database",
|
|
3
|
-
"version": "0.9.2-alpha.
|
|
3
|
+
"version": "0.9.2-alpha.4",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"types": "./lib/index.d.ts",
|
|
7
7
|
"license": "Apache-2.0",
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"@nocobase/logger": "0.9.2-alpha.
|
|
10
|
-
"@nocobase/utils": "0.9.2-alpha.
|
|
9
|
+
"@nocobase/logger": "0.9.2-alpha.4",
|
|
10
|
+
"@nocobase/utils": "0.9.2-alpha.4",
|
|
11
11
|
"async-mutex": "^0.3.2",
|
|
12
12
|
"cron-parser": "4.4.0",
|
|
13
13
|
"deepmerge": "^4.2.2",
|
|
@@ -28,5 +28,5 @@
|
|
|
28
28
|
"url": "git+https://github.com/nocobase/nocobase.git",
|
|
29
29
|
"directory": "packages/database"
|
|
30
30
|
},
|
|
31
|
-
"gitHead": "
|
|
31
|
+
"gitHead": "96cb023f353a4fb099dea074c575be65ebab813f"
|
|
32
32
|
}
|
|
@@ -234,10 +234,12 @@ describe('hidden field options', () => {
|
|
|
234
234
|
await repo.create({
|
|
235
235
|
values: {
|
|
236
236
|
title: 'post1',
|
|
237
|
-
users: [
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
237
|
+
users: [
|
|
238
|
+
{
|
|
239
|
+
name: 'abc',
|
|
240
|
+
password: '123',
|
|
241
|
+
},
|
|
242
|
+
],
|
|
241
243
|
},
|
|
242
244
|
});
|
|
243
245
|
const instance = await repo.findOne({
|
|
@@ -284,10 +286,12 @@ describe('hidden field options', () => {
|
|
|
284
286
|
await repo.create({
|
|
285
287
|
values: {
|
|
286
288
|
title: 'post1',
|
|
287
|
-
users: [
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
289
|
+
users: [
|
|
290
|
+
{
|
|
291
|
+
name: 'abc',
|
|
292
|
+
password: '123',
|
|
293
|
+
},
|
|
294
|
+
],
|
|
291
295
|
},
|
|
292
296
|
});
|
|
293
297
|
const instance = await repo.findOne({
|
|
@@ -65,10 +65,8 @@ describe('belongs to field', () => {
|
|
|
65
65
|
|
|
66
66
|
it('custom targetKey and foreignKey', async () => {
|
|
67
67
|
db.collection({
|
|
68
|
-
name:
|
|
69
|
-
fields: [
|
|
70
|
-
{ type: "string", name: "key" },
|
|
71
|
-
]
|
|
68
|
+
name: 'posts',
|
|
69
|
+
fields: [{ type: 'string', name: 'key' }],
|
|
72
70
|
});
|
|
73
71
|
|
|
74
72
|
const Comment = db.collection({
|
|
@@ -118,7 +116,6 @@ describe('belongs to field', () => {
|
|
|
118
116
|
error = e;
|
|
119
117
|
}
|
|
120
118
|
|
|
121
|
-
|
|
122
119
|
expect(error).toBeInstanceOf(IdentifierError);
|
|
123
120
|
});
|
|
124
121
|
|
|
@@ -10,9 +10,7 @@ describe('date-field', () => {
|
|
|
10
10
|
db = mockDatabase();
|
|
11
11
|
db.collection({
|
|
12
12
|
name: 'tests',
|
|
13
|
-
fields: [
|
|
14
|
-
{ name: 'date1', type: 'date' },
|
|
15
|
-
],
|
|
13
|
+
fields: [{ name: 'date1', type: 'date' }],
|
|
16
14
|
});
|
|
17
15
|
await db.sync();
|
|
18
16
|
repository = db.getRepository('tests');
|
|
@@ -186,7 +186,7 @@ describe('has many field', () => {
|
|
|
186
186
|
name: 'comments',
|
|
187
187
|
fields: [
|
|
188
188
|
{ type: 'string', name: 'content' },
|
|
189
|
-
{ type: 'belongsTo', name: 'post', onDelete:
|
|
189
|
+
{ type: 'belongsTo', name: 'post', onDelete: 'CASCADE' },
|
|
190
190
|
],
|
|
191
191
|
});
|
|
192
192
|
|
|
@@ -14,6 +14,47 @@ describe('filter', () => {
|
|
|
14
14
|
await db.close();
|
|
15
15
|
});
|
|
16
16
|
|
|
17
|
+
it('should filter by hasMany association field', async () => {
|
|
18
|
+
const DeptCollection = db.collection({
|
|
19
|
+
name: 'depts',
|
|
20
|
+
fields: [
|
|
21
|
+
{ type: 'string', name: 'name' },
|
|
22
|
+
{ type: 'belongsTo', name: 'org', target: 'orgs' },
|
|
23
|
+
],
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const OrgCollection = db.collection({
|
|
27
|
+
name: 'orgs',
|
|
28
|
+
fields: [
|
|
29
|
+
{ type: 'string', name: 'name' },
|
|
30
|
+
{ type: 'hasMany', name: 'depts', target: 'depts' },
|
|
31
|
+
],
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
await db.sync();
|
|
35
|
+
|
|
36
|
+
await OrgCollection.repository.create({
|
|
37
|
+
values: [
|
|
38
|
+
{
|
|
39
|
+
name: 'org1',
|
|
40
|
+
depts: [{ name: 'dept1' }, { name: 'dept2' }],
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
name: 'org2',
|
|
44
|
+
depts: [{ name: 'dept3' }, { name: 'dept4' }],
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const dept1 = await DeptCollection.repository.findOne({});
|
|
50
|
+
|
|
51
|
+
const orgs = await OrgCollection.repository.find({
|
|
52
|
+
filter: { $and: [{ depts: { id: { $eq: dept1.get('id') } } }] },
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
expect(orgs.length).toBe(1);
|
|
56
|
+
});
|
|
57
|
+
|
|
17
58
|
it('should filter by association field', async () => {
|
|
18
59
|
const UserCollection = db.collection({
|
|
19
60
|
name: 'users',
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { Database, Migration, mockDatabase } from '@nocobase/database';
|
|
2
2
|
import { resolve } from 'path';
|
|
3
3
|
|
|
4
|
-
const names = (migrations: Array<{ name: string }>) => migrations.map(m => m.name);
|
|
4
|
+
const names = (migrations: Array<{ name: string }>) => migrations.map((m) => m.name);
|
|
5
5
|
|
|
6
6
|
describe('migrator', () => {
|
|
7
7
|
let db: Database;
|
|
8
8
|
|
|
9
9
|
beforeEach(async () => {
|
|
10
|
-
|
|
11
10
|
db = mockDatabase({
|
|
12
11
|
tablePrefix: 'test_',
|
|
13
12
|
});
|
|
@@ -31,7 +31,7 @@ describe('model hook', () => {
|
|
|
31
31
|
test('sequelize model hooks with existing collection', async () => {
|
|
32
32
|
db.collection({
|
|
33
33
|
name: 'posts',
|
|
34
|
-
fields: []
|
|
34
|
+
fields: [],
|
|
35
35
|
});
|
|
36
36
|
const matcher = db.modelHook.match('posts.beforeCreate');
|
|
37
37
|
expect(matcher).toEqual('beforeCreate');
|
|
@@ -45,7 +45,7 @@ describe('model hook', () => {
|
|
|
45
45
|
test('customized model hooks', async () => {
|
|
46
46
|
db.collection({
|
|
47
47
|
name: 'posts',
|
|
48
|
-
fields: []
|
|
48
|
+
fields: [],
|
|
49
49
|
});
|
|
50
50
|
const matcher = db.modelHook.match('posts.beforeCreateWithAssociations');
|
|
51
51
|
expect(matcher).toBeNull();
|
|
@@ -22,11 +22,7 @@ describe('eq operator', () => {
|
|
|
22
22
|
|
|
23
23
|
it('should eq with array', async () => {
|
|
24
24
|
await db.getRepository('tests').create({
|
|
25
|
-
values: [
|
|
26
|
-
{ name: '123' },
|
|
27
|
-
{ name: '234' },
|
|
28
|
-
{ name: '345' },
|
|
29
|
-
]
|
|
25
|
+
values: [{ name: '123' }, { name: '234' }, { name: '345' }],
|
|
30
26
|
});
|
|
31
27
|
|
|
32
28
|
const results = await db.getRepository('tests').count({
|
|
@@ -40,11 +36,7 @@ describe('eq operator', () => {
|
|
|
40
36
|
|
|
41
37
|
it('should eq with array', async () => {
|
|
42
38
|
await db.getRepository('tests').create({
|
|
43
|
-
values: [
|
|
44
|
-
{ name: '123' },
|
|
45
|
-
{ name: '234' },
|
|
46
|
-
{ name: '345' },
|
|
47
|
-
]
|
|
39
|
+
values: [{ name: '123' }, { name: '234' }, { name: '345' }],
|
|
48
40
|
});
|
|
49
41
|
|
|
50
42
|
const results = await db.getRepository('tests').count({
|
|
@@ -58,11 +50,7 @@ describe('eq operator', () => {
|
|
|
58
50
|
|
|
59
51
|
it('should eq with array', async () => {
|
|
60
52
|
await db.getRepository('tests').create({
|
|
61
|
-
values: [
|
|
62
|
-
{ name: '123' },
|
|
63
|
-
{ name: '234' },
|
|
64
|
-
{ name: '345' },
|
|
65
|
-
]
|
|
53
|
+
values: [{ name: '123' }, { name: '234' }, { name: '345' }],
|
|
66
54
|
});
|
|
67
55
|
|
|
68
56
|
const results = await db.getRepository('tests').count({
|
|
@@ -45,11 +45,7 @@ describe('ne operator', () => {
|
|
|
45
45
|
|
|
46
46
|
it('should ne with array', async () => {
|
|
47
47
|
await db.getRepository('tests').create({
|
|
48
|
-
values: [
|
|
49
|
-
{ name: '123' },
|
|
50
|
-
{ name: '234' },
|
|
51
|
-
{ name: '345' },
|
|
52
|
-
]
|
|
48
|
+
values: [{ name: '123' }, { name: '234' }, { name: '345' }],
|
|
53
49
|
});
|
|
54
50
|
|
|
55
51
|
const results = await db.getRepository('tests').count({
|
|
@@ -61,7 +61,7 @@ describe('option parser', () => {
|
|
|
61
61
|
});
|
|
62
62
|
|
|
63
63
|
test('fields with association', () => {
|
|
64
|
-
|
|
64
|
+
const options: any = {
|
|
65
65
|
fields: ['id', 'name', 'tags.id', 'tags.name'],
|
|
66
66
|
};
|
|
67
67
|
|
|
@@ -83,7 +83,7 @@ describe('option parser', () => {
|
|
|
83
83
|
});
|
|
84
84
|
|
|
85
85
|
test('with sort option', () => {
|
|
86
|
-
if (db.inDialect('mysql'))
|
|
86
|
+
if (db.inDialect('mysql')) {
|
|
87
87
|
expect(1).toBe(1);
|
|
88
88
|
return;
|
|
89
89
|
}
|
|
@@ -157,7 +157,7 @@ describe('belongs to many with target key', function () {
|
|
|
157
157
|
});
|
|
158
158
|
|
|
159
159
|
test('destroy with target key and filter', async () => {
|
|
160
|
-
|
|
160
|
+
const t1 = await Tag.repository.create({
|
|
161
161
|
values: {
|
|
162
162
|
name: 't1',
|
|
163
163
|
status: 'published',
|
|
@@ -486,7 +486,7 @@ describe('belongs to many', () => {
|
|
|
486
486
|
|
|
487
487
|
const PostTagRepository = new BelongsToManyRepository(Post, 'tags', p1.id);
|
|
488
488
|
|
|
489
|
-
|
|
489
|
+
const t1 = await PostTagRepository.findOne({
|
|
490
490
|
filter: {
|
|
491
491
|
name: 't1',
|
|
492
492
|
},
|
|
@@ -571,7 +571,7 @@ describe('belongs to many', () => {
|
|
|
571
571
|
});
|
|
572
572
|
|
|
573
573
|
test('add', async () => {
|
|
574
|
-
|
|
574
|
+
const t1 = await Tag.repository.create({
|
|
575
575
|
values: { name: 't1' },
|
|
576
576
|
});
|
|
577
577
|
|
|
@@ -582,7 +582,7 @@ describe('belongs to many', () => {
|
|
|
582
582
|
const PostTagRepository = new BelongsToManyRepository(Post, 'tags', p1.id);
|
|
583
583
|
await PostTagRepository.add([[t1.id, { tagged_at: '123' }]]);
|
|
584
584
|
|
|
585
|
-
|
|
585
|
+
const p1Tag = await PostTagRepository.findOne();
|
|
586
586
|
expect(p1Tag.posts_tags.tagged_at).toEqual('123');
|
|
587
587
|
});
|
|
588
588
|
|
|
@@ -603,7 +603,7 @@ describe('belongs to many', () => {
|
|
|
603
603
|
|
|
604
604
|
await PostTagRepository.set([t1.id]);
|
|
605
605
|
|
|
606
|
-
|
|
606
|
+
const p1Tags = await PostTagRepository.find();
|
|
607
607
|
expect(p1Tags.length).toEqual(1);
|
|
608
608
|
|
|
609
609
|
await PostTagRepository.set([[t1.id, { tagged_at: '999' }]]);
|
|
@@ -618,7 +618,7 @@ describe('belongs to many', () => {
|
|
|
618
618
|
});
|
|
619
619
|
|
|
620
620
|
test('find by pk', async () => {
|
|
621
|
-
|
|
621
|
+
const t1 = await Tag.repository.create({
|
|
622
622
|
values: {
|
|
623
623
|
name: 't1',
|
|
624
624
|
},
|
|
@@ -646,7 +646,7 @@ describe('belongs to many', () => {
|
|
|
646
646
|
});
|
|
647
647
|
|
|
648
648
|
test('toggle', async () => {
|
|
649
|
-
|
|
649
|
+
const t1 = await Tag.repository.create({
|
|
650
650
|
values: { name: 't1' },
|
|
651
651
|
});
|
|
652
652
|
|
|
@@ -664,7 +664,7 @@ describe('belongs to many', () => {
|
|
|
664
664
|
});
|
|
665
665
|
|
|
666
666
|
test('remove', async () => {
|
|
667
|
-
|
|
667
|
+
const t1 = await Tag.repository.create({
|
|
668
668
|
values: { name: 't1' },
|
|
669
669
|
});
|
|
670
670
|
|
|
@@ -682,7 +682,7 @@ describe('belongs to many', () => {
|
|
|
682
682
|
});
|
|
683
683
|
|
|
684
684
|
test('destroy all', async () => {
|
|
685
|
-
|
|
685
|
+
const t1 = await Tag.repository.create({
|
|
686
686
|
values: {
|
|
687
687
|
name: 't1',
|
|
688
688
|
},
|
|
@@ -709,7 +709,7 @@ describe('belongs to many', () => {
|
|
|
709
709
|
});
|
|
710
710
|
|
|
711
711
|
test('destroy by id and filter', async () => {
|
|
712
|
-
|
|
712
|
+
const t1 = await Tag.repository.create({
|
|
713
713
|
values: {
|
|
714
714
|
name: 't1',
|
|
715
715
|
status: 'published',
|
|
@@ -746,7 +746,7 @@ describe('belongs to many', () => {
|
|
|
746
746
|
});
|
|
747
747
|
|
|
748
748
|
test('destroy with id', async () => {
|
|
749
|
-
|
|
749
|
+
const t1 = await Tag.repository.create({
|
|
750
750
|
values: {
|
|
751
751
|
name: 't1',
|
|
752
752
|
},
|
|
@@ -774,7 +774,7 @@ describe('belongs to many', () => {
|
|
|
774
774
|
});
|
|
775
775
|
|
|
776
776
|
test('transaction', async () => {
|
|
777
|
-
|
|
777
|
+
const t1 = await Tag.repository.create({
|
|
778
778
|
values: {
|
|
779
779
|
name: 't1',
|
|
780
780
|
},
|
|
@@ -33,12 +33,7 @@ describe('sequelize-hooks', () => {
|
|
|
33
33
|
});
|
|
34
34
|
await collection.sync();
|
|
35
35
|
await collection.model.create();
|
|
36
|
-
expect(orders).toEqual([
|
|
37
|
-
'model.beforeCreate',
|
|
38
|
-
'beforeCreate',
|
|
39
|
-
'model.afterCreate',
|
|
40
|
-
'afterCreate'
|
|
41
|
-
]);
|
|
36
|
+
expect(orders).toEqual(['model.beforeCreate', 'beforeCreate', 'model.afterCreate', 'afterCreate']);
|
|
42
37
|
});
|
|
43
38
|
|
|
44
39
|
describe('afterSync', () => {
|
|
@@ -41,11 +41,11 @@ describe('sort', function () {
|
|
|
41
41
|
sort: '-num',
|
|
42
42
|
});
|
|
43
43
|
const nums = items.map((item) => item.get('num'));
|
|
44
|
-
expect(nums).toEqual([3,2,1,null]);
|
|
44
|
+
expect(nums).toEqual([3, 2, 1, null]);
|
|
45
45
|
const items2 = await Test.repository.find({
|
|
46
46
|
sort: 'num',
|
|
47
47
|
});
|
|
48
48
|
const nums2 = items2.map((item) => item.get('num'));
|
|
49
|
-
expect(nums2).toEqual([1,2,3,null]);
|
|
49
|
+
expect(nums2).toEqual([1, 2, 3, null]);
|
|
50
50
|
});
|
|
51
51
|
});
|
package/src/collection.ts
CHANGED
|
@@ -24,6 +24,14 @@ type dumpable = 'required' | 'optional' | 'skip';
|
|
|
24
24
|
export interface CollectionOptions extends Omit<ModelOptions, 'name' | 'hooks'> {
|
|
25
25
|
name: string;
|
|
26
26
|
namespace?: string;
|
|
27
|
+
/**
|
|
28
|
+
* Used for @nocobase/plugin-duplicator
|
|
29
|
+
* @see packages/core/database/src/collection-group-manager.tss
|
|
30
|
+
*
|
|
31
|
+
* @prop {'required' | 'optional' | 'skip'} dumpable - Determine whether the collection is dumped
|
|
32
|
+
* @prop {string[] | string} [with] - Collections dumped with this collection
|
|
33
|
+
* @prop {any} [delayRestore] - A function to execute after all collections are restored
|
|
34
|
+
*/
|
|
27
35
|
duplicator?:
|
|
28
36
|
| dumpable
|
|
29
37
|
| {
|
|
@@ -71,7 +79,7 @@ export class Collection<
|
|
|
71
79
|
repository: Repository<TModelAttributes, TCreationAttributes>;
|
|
72
80
|
|
|
73
81
|
get filterTargetKey() {
|
|
74
|
-
|
|
82
|
+
const targetKey = lodash.get(this.options, 'filterTargetKey', this.model.primaryKeyAttribute);
|
|
75
83
|
if (!targetKey && this.model.rawAttributes['id']) {
|
|
76
84
|
return 'id';
|
|
77
85
|
}
|
|
@@ -285,7 +293,9 @@ export class Collection<
|
|
|
285
293
|
const [sourceCollectionName, sourceFieldName] = options.source.split('.');
|
|
286
294
|
const sourceCollection = this.db.collections.get(sourceCollectionName);
|
|
287
295
|
if (!sourceCollection) {
|
|
288
|
-
throw new Error(
|
|
296
|
+
throw new Error(
|
|
297
|
+
`source collection "${sourceCollectionName}" not found for field "${name}" at collection "${this.name}"`,
|
|
298
|
+
);
|
|
289
299
|
}
|
|
290
300
|
const sourceField = sourceCollection.fields.get(sourceFieldName);
|
|
291
301
|
options = { ...sourceField.options, ...options };
|
|
@@ -472,7 +482,7 @@ export class Collection<
|
|
|
472
482
|
}
|
|
473
483
|
|
|
474
484
|
// collection defined indexes
|
|
475
|
-
|
|
485
|
+
const indexes: any = this.model.options.indexes || [];
|
|
476
486
|
|
|
477
487
|
let indexName = [];
|
|
478
488
|
let indexItem;
|
package/src/database.ts
CHANGED
|
@@ -71,7 +71,7 @@ import { Logger } from '@nocobase/logger';
|
|
|
71
71
|
import { CollectionGroupManager } from './collection-group-manager';
|
|
72
72
|
import { ViewCollection } from './view-collection';
|
|
73
73
|
|
|
74
|
-
export
|
|
74
|
+
export type MergeOptions = merge.Options;
|
|
75
75
|
|
|
76
76
|
export interface PendingOptions {
|
|
77
77
|
field: RelationField;
|
|
@@ -500,7 +500,7 @@ export class Database extends EventEmitter implements AsyncEmitter {
|
|
|
500
500
|
}
|
|
501
501
|
|
|
502
502
|
const [collectionName, associationName, ...args] = path.split('.');
|
|
503
|
-
|
|
503
|
+
const collection = this.getCollection(collectionName);
|
|
504
504
|
|
|
505
505
|
if (!collection) {
|
|
506
506
|
return;
|
|
@@ -529,7 +529,7 @@ export class Database extends EventEmitter implements AsyncEmitter {
|
|
|
529
529
|
}
|
|
530
530
|
|
|
531
531
|
const [collectionName, associationName] = name.split('.');
|
|
532
|
-
|
|
532
|
+
const collection = this.collections.get(collectionName);
|
|
533
533
|
|
|
534
534
|
if (associationName) {
|
|
535
535
|
const target = collection.getField(associationName)?.target;
|
package/src/fields/index.ts
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
DoubleFieldOptions,
|
|
14
14
|
FloatFieldOptions,
|
|
15
15
|
IntegerFieldOptions,
|
|
16
|
-
RealFieldOptions
|
|
16
|
+
RealFieldOptions,
|
|
17
17
|
} from './number-field';
|
|
18
18
|
import { PasswordFieldOptions } from './password-field';
|
|
19
19
|
import { RadioFieldOptions } from './radio-field';
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { DataTypes } from 'sequelize';
|
|
2
2
|
import { BaseColumnFieldOptions, Field } from './field';
|
|
3
3
|
|
|
4
|
-
abstract class NumberField extends Field {
|
|
5
|
-
|
|
6
|
-
}
|
|
4
|
+
abstract class NumberField extends Field {}
|
|
7
5
|
|
|
8
6
|
export class IntegerField extends NumberField {
|
|
9
7
|
get dataType() {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { BaseFieldOptions, Field } from './field';
|
|
2
2
|
|
|
3
|
-
export
|
|
3
|
+
export type BaseRelationFieldOptions = BaseFieldOptions;
|
|
4
4
|
|
|
5
5
|
export interface MultipleRelationFieldOptions extends BaseRelationFieldOptions {
|
|
6
6
|
sortBy?: string | string[];
|
package/src/filter-parser.ts
CHANGED
|
@@ -96,7 +96,7 @@ export default class FilterParser {
|
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
debug('handle filter key "%s: "%s"', key, value);
|
|
99
|
-
|
|
99
|
+
const keys = key.split('.');
|
|
100
100
|
|
|
101
101
|
// paths ?
|
|
102
102
|
const paths = [];
|
|
@@ -236,7 +236,7 @@ export default class FilterParser {
|
|
|
236
236
|
private getFieldNameFromQueryPath(queryPath: string) {
|
|
237
237
|
const paths = queryPath.split('.');
|
|
238
238
|
let fieldName;
|
|
239
|
-
|
|
239
|
+
const fullPaths = [];
|
|
240
240
|
for (const path of paths) {
|
|
241
241
|
if (path.startsWith('$') || !lodash.isNaN(parseInt(path))) {
|
|
242
242
|
continue;
|
package/src/model-hook.ts
CHANGED
|
@@ -15,7 +15,7 @@ export class ModelHook {
|
|
|
15
15
|
this.database = database;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
match(event: string |
|
|
18
|
+
match(event: string | symbol): keyof SequelizeHooks | null {
|
|
19
19
|
// NOTE: skip Symbol event
|
|
20
20
|
if (!lodash.isString(event)) {
|
|
21
21
|
return null;
|
package/src/operators/empty.ts
CHANGED
package/src/operators/notIn.ts
CHANGED
package/src/options-parser.ts
CHANGED
|
@@ -74,7 +74,7 @@ export class OptionsParser {
|
|
|
74
74
|
const orderParams = [];
|
|
75
75
|
for (const sortKey of sort) {
|
|
76
76
|
let direction = sortKey.startsWith('-') ? 'DESC' : 'ASC';
|
|
77
|
-
|
|
77
|
+
const sortField: Array<any> = sortKey.replace('-', '').split('.');
|
|
78
78
|
|
|
79
79
|
if (this.database.inDialect('postgres', 'sqlite')) {
|
|
80
80
|
direction = `${direction} NULLS LAST`;
|
|
@@ -192,7 +192,7 @@ export class OptionsParser {
|
|
|
192
192
|
const association = exceptPath[0];
|
|
193
193
|
const lastLevel = exceptPath.length <= 2;
|
|
194
194
|
|
|
195
|
-
|
|
195
|
+
const existIncludeIndex = queryParams['include'].findIndex((include) => include['association'] == association);
|
|
196
196
|
|
|
197
197
|
if (existIncludeIndex == -1) {
|
|
198
198
|
// if include not exists, ignore this except
|
|
@@ -242,7 +242,7 @@ export class OptionsParser {
|
|
|
242
242
|
// appends: ['posts']
|
|
243
243
|
// appends: ['posts.title']
|
|
244
244
|
// All of these can be seen as last level
|
|
245
|
-
let lastLevel
|
|
245
|
+
let lastLevel = false;
|
|
246
246
|
|
|
247
247
|
if (appendFields.length == 1) {
|
|
248
248
|
lastLevel = true;
|
|
@@ -23,7 +23,7 @@ interface IBelongsToManyRepository<M extends Model> {
|
|
|
23
23
|
update(options?: UpdateOptions): Promise<M>;
|
|
24
24
|
|
|
25
25
|
// 删除
|
|
26
|
-
destroy(options?: number | string | number[] | string[] | DestroyOptions): Promise<
|
|
26
|
+
destroy(options?: number | string | number[] | string[] | DestroyOptions): Promise<boolean>;
|
|
27
27
|
|
|
28
28
|
// 建立关联
|
|
29
29
|
set(options: TargetKey | TargetKey[] | AssociatedOptions): Promise<void>;
|
|
@@ -67,7 +67,7 @@ export class BelongsToManyRepository extends MultipleRelationRepository implemen
|
|
|
67
67
|
transaction,
|
|
68
68
|
};
|
|
69
69
|
})
|
|
70
|
-
async destroy(options?: TargetKey | TargetKey[] | DestroyOptions): Promise<
|
|
70
|
+
async destroy(options?: TargetKey | TargetKey[] | DestroyOptions): Promise<boolean> {
|
|
71
71
|
const transaction = await this.getTransaction(options);
|
|
72
72
|
const association = <BelongsToMany>this.association;
|
|
73
73
|
|
|
@@ -2,7 +2,7 @@ import { Model } from '../model';
|
|
|
2
2
|
import { CreateOptions, UpdateOptions } from '../repository';
|
|
3
3
|
import { SingleRelationFindOption, SingleRelationRepository } from './single-relation-repository';
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
type BelongsToFindOptions = SingleRelationFindOption;
|
|
6
6
|
|
|
7
7
|
interface IBelongsToRepository<M extends Model> {
|
|
8
8
|
// 不需要 findOne,find 就是 findOne
|
|
@@ -13,7 +13,7 @@ interface IBelongsToRepository<M extends Model> {
|
|
|
13
13
|
// 更新
|
|
14
14
|
update(options?: UpdateOptions): Promise<M>;
|
|
15
15
|
// 删除
|
|
16
|
-
destroy(): Promise<
|
|
16
|
+
destroy(): Promise<boolean>;
|
|
17
17
|
// 建立关联
|
|
18
18
|
set(primaryKey: any): Promise<void>;
|
|
19
19
|
// 移除关联
|
|
@@ -22,7 +22,7 @@ interface IHasManyRepository<M extends Model> {
|
|
|
22
22
|
// 更新
|
|
23
23
|
update(options?: UpdateOptions): Promise<M>;
|
|
24
24
|
// 删除
|
|
25
|
-
destroy(options?: TK | DestroyOptions): Promise<
|
|
25
|
+
destroy(options?: TK | DestroyOptions): Promise<boolean>;
|
|
26
26
|
// 建立关联
|
|
27
27
|
set(options: TargetKey | TargetKey[] | AssociatedOptions): Promise<void>;
|
|
28
28
|
// 附加关联
|
|
@@ -59,7 +59,7 @@ export class HasManyRepository extends MultipleRelationRepository implements IHa
|
|
|
59
59
|
transaction,
|
|
60
60
|
};
|
|
61
61
|
})
|
|
62
|
-
async destroy(options?: TK | DestroyOptions): Promise<
|
|
62
|
+
async destroy(options?: TK | DestroyOptions): Promise<boolean> {
|
|
63
63
|
const transaction = await this.getTransaction(options);
|
|
64
64
|
|
|
65
65
|
const sourceModel = await this.getSourceModel(transaction);
|
|
@@ -205,7 +205,7 @@ export abstract class MultipleRelationRepository extends RelationRepository {
|
|
|
205
205
|
return instances;
|
|
206
206
|
}
|
|
207
207
|
|
|
208
|
-
async destroy(options?: TK | DestroyOptions): Promise<
|
|
208
|
+
async destroy(options?: TK | DestroyOptions): Promise<boolean> {
|
|
209
209
|
return false;
|
|
210
210
|
}
|
|
211
211
|
|
|
@@ -35,7 +35,7 @@ export abstract class SingleRelationRepository extends RelationRepository {
|
|
|
35
35
|
})
|
|
36
36
|
async set(options: TargetKey | SetOption): Promise<void> {
|
|
37
37
|
const transaction = await this.getTransaction(options);
|
|
38
|
-
|
|
38
|
+
const handleKey = lodash.isPlainObject(options) ? (<SetOption>options).tk : options;
|
|
39
39
|
|
|
40
40
|
const sourceModel = await this.getSourceModel(transaction);
|
|
41
41
|
|
|
@@ -91,7 +91,7 @@ export abstract class SingleRelationRepository extends RelationRepository {
|
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
@transaction()
|
|
94
|
-
async destroy(options?: Transactionable): Promise<
|
|
94
|
+
async destroy(options?: Transactionable): Promise<boolean> {
|
|
95
95
|
const transaction = await this.getTransaction(options);
|
|
96
96
|
|
|
97
97
|
const target = await this.find({
|
package/src/types.ts
CHANGED
|
@@ -25,15 +25,24 @@ export type ModelCreateEventTypes = ModelCreateEventType | `${CollectionNameType
|
|
|
25
25
|
export type ModelUpdateEventTypes = ModelUpdateEventType | `${CollectionNameType}.${ModelUpdateEventType}`;
|
|
26
26
|
export type ModelSaveEventTypes = ModelSaveEventType | `${CollectionNameType}.${ModelSaveEventType}`;
|
|
27
27
|
export type ModelDestroyEventTypes = ModelDestroyEventType | `${CollectionNameType}.${ModelDestroyEventType}`;
|
|
28
|
-
export type ModelCreateWithAssociationsEventTypes =
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
export type ModelCreateWithAssociationsEventTypes =
|
|
29
|
+
| ModelCreateWithAssociationsEventType
|
|
30
|
+
| `${CollectionNameType}.${ModelCreateWithAssociationsEventType}`;
|
|
31
|
+
export type ModelUpdateWithAssociationsEventTypes =
|
|
32
|
+
| ModelUpdateWithAssociationsEventType
|
|
33
|
+
| `${CollectionNameType}.${ModelUpdateWithAssociationsEventType}`;
|
|
34
|
+
export type ModelSaveWithAssociationsEventTypes =
|
|
35
|
+
| ModelSaveWithAssociationsEventType
|
|
36
|
+
| `${CollectionNameType}.${ModelSaveWithAssociationsEventType}`;
|
|
31
37
|
|
|
32
38
|
export type ModelBulkCreateEvnetTypes = ModelBulkCreateEvnetType | `${CollectionNameType}.${ModelBulkCreateEvnetType}`;
|
|
33
39
|
export type ModelBulkUpdateEvnetTypes = ModelBulkUpdateEvnetType | `${CollectionNameType}.${ModelBulkUpdateEvnetType}`;
|
|
34
|
-
export type ModelBulkDestroyEvnetTypes =
|
|
40
|
+
export type ModelBulkDestroyEvnetTypes =
|
|
41
|
+
| ModelBulkDestroyEvnetType
|
|
42
|
+
| `${CollectionNameType}.${ModelBulkDestroyEvnetType}`;
|
|
35
43
|
|
|
36
|
-
export type ModelEventTypes =
|
|
44
|
+
export type ModelEventTypes =
|
|
45
|
+
| ModelSyncEventType
|
|
37
46
|
| ModelValidateEventTypes
|
|
38
47
|
| ModelCreateEventTypes
|
|
39
48
|
| ModelUpdateEventTypes
|
|
@@ -51,7 +60,8 @@ export type DatabaseAfterDefineCollectionEventType = 'afterDefineCollection';
|
|
|
51
60
|
export type DatabaseBeforeRemoveCollectionEventType = 'beforeRemoveCollection';
|
|
52
61
|
export type DatabaseAfterRemoveCollectionEventType = 'afterRemoveCollection';
|
|
53
62
|
|
|
54
|
-
export type DatabaseEventTypes =
|
|
63
|
+
export type DatabaseEventTypes =
|
|
64
|
+
| DatabaseBeforeDefineCollectionEventType
|
|
55
65
|
| DatabaseAfterDefineCollectionEventType
|
|
56
66
|
| DatabaseBeforeRemoveCollectionEventType
|
|
57
67
|
| DatabaseAfterRemoveCollectionEventType;
|
package/src/utils.ts
CHANGED