@nocobase/database 1.5.0-beta.9 → 1.6.0-alpha.10
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 +3 -0
- package/lib/database.js +1 -0
- package/lib/dialects/mysql-dialect.d.ts +1 -0
- package/lib/dialects/mysql-dialect.js +5 -0
- package/lib/fields/belongs-to-many-field.js +4 -1
- package/lib/fields/unix-timestamp-field.js +7 -4
- package/lib/filter-match.js +3 -1
- package/lib/interfaces/datetime-interface.js +7 -0
- package/lib/relation-repository/hasmany-repository.d.ts +2 -1
- package/lib/relation-repository/multiple-relation-repository.d.ts +6 -10
- package/lib/relation-repository/multiple-relation-repository.js +7 -0
- package/lib/relation-repository/relation-repository.d.ts +5 -1
- package/lib/relation-repository/relation-repository.js +33 -0
- package/lib/relation-repository/single-relation-repository.d.ts +3 -10
- package/lib/relation-repository/single-relation-repository.js +1 -0
- package/lib/relation-repository/types.d.ts +77 -6
- package/lib/repository.d.ts +6 -6
- package/lib/repository.js +15 -48
- package/lib/utils/filter-utils.d.ts +13 -0
- package/lib/utils/filter-utils.js +86 -0
- package/package.json +4 -4
package/lib/collection.d.ts
CHANGED
|
@@ -29,15 +29,18 @@ export type DumpRules = BuiltInGroup | ({
|
|
|
29
29
|
} & BaseDumpRules) | ({
|
|
30
30
|
group: BuiltInGroup | string;
|
|
31
31
|
} & BaseDumpRules);
|
|
32
|
+
export type MigrationRule = 'overwrite' | 'skip' | 'upsert' | 'schema-only' | 'insert-ignore';
|
|
32
33
|
export interface CollectionOptions extends Omit<ModelOptions, 'name' | 'hooks'> {
|
|
33
34
|
name: string;
|
|
34
35
|
title?: string;
|
|
35
36
|
namespace?: string;
|
|
37
|
+
migrationRules?: MigrationRule[];
|
|
36
38
|
dumpRules?: DumpRules;
|
|
37
39
|
tableName?: string;
|
|
38
40
|
inherits?: string[] | string;
|
|
39
41
|
viewName?: string;
|
|
40
42
|
writableView?: boolean;
|
|
43
|
+
isThrough?: boolean;
|
|
41
44
|
filterTargetKey?: string | string[];
|
|
42
45
|
fields?: FieldOptions[];
|
|
43
46
|
model?: string | ModelStatic<Model>;
|
package/lib/database.js
CHANGED
|
@@ -220,6 +220,7 @@ const _Database = class _Database extends import_events.EventEmitter {
|
|
|
220
220
|
autoGenId: false,
|
|
221
221
|
timestamps: false,
|
|
222
222
|
dumpRules: "required",
|
|
223
|
+
migrationRules: ["schema-only", "overwrite", "skip"],
|
|
223
224
|
origin: "@nocobase/database",
|
|
224
225
|
fields: [{ type: "string", name: "name", primaryKey: true }]
|
|
225
226
|
});
|
|
@@ -32,6 +32,7 @@ __export(mysql_dialect_exports, {
|
|
|
32
32
|
MysqlDialect: () => MysqlDialect
|
|
33
33
|
});
|
|
34
34
|
module.exports = __toCommonJS(mysql_dialect_exports);
|
|
35
|
+
var import_utils = require("@nocobase/utils");
|
|
35
36
|
var import_base_dialect = require("./base-dialect");
|
|
36
37
|
const _MysqlDialect = class _MysqlDialect extends import_base_dialect.BaseDialect {
|
|
37
38
|
getVersionGuard() {
|
|
@@ -44,6 +45,10 @@ const _MysqlDialect = class _MysqlDialect extends import_base_dialect.BaseDialec
|
|
|
44
45
|
version: ">=8.0.17"
|
|
45
46
|
};
|
|
46
47
|
}
|
|
48
|
+
getSequelizeOptions(options) {
|
|
49
|
+
import_utils.lodash.set(options, "dialectOptions.multipleStatements", true);
|
|
50
|
+
return options;
|
|
51
|
+
}
|
|
47
52
|
};
|
|
48
53
|
__name(_MysqlDialect, "MysqlDialect");
|
|
49
54
|
__publicField(_MysqlDialect, "dialectName", "mysql");
|
|
@@ -125,7 +125,10 @@ const _BelongsToManyField = class _BelongsToManyField extends import_relation_fi
|
|
|
125
125
|
Through = database.getCollection(through);
|
|
126
126
|
} else {
|
|
127
127
|
const throughCollectionOptions = {
|
|
128
|
-
name: through
|
|
128
|
+
name: through,
|
|
129
|
+
isThrough: true,
|
|
130
|
+
sourceCollectionName: this.collection.name,
|
|
131
|
+
targetCollectionName: this.target
|
|
129
132
|
};
|
|
130
133
|
if (this.collection.options.dumpRules) {
|
|
131
134
|
throughCollectionOptions["dumpRules"] = this.collection.options.dumpRules;
|
|
@@ -52,7 +52,7 @@ const _UnixTimestampField = class _UnixTimestampField extends import_date_field.
|
|
|
52
52
|
if (accuracy === "millisecond") {
|
|
53
53
|
rationalNumber = 1;
|
|
54
54
|
}
|
|
55
|
-
return Math.floor(new Date(val).getTime() / rationalNumber);
|
|
55
|
+
return Math.floor(typeof val === "number" ? val : new Date(val).getTime() / rationalNumber);
|
|
56
56
|
}
|
|
57
57
|
additionalSequelizeOptions() {
|
|
58
58
|
var _a, _b, _c, _d, _e;
|
|
@@ -71,16 +71,19 @@ const _UnixTimestampField = class _UnixTimestampField extends import_date_field.
|
|
|
71
71
|
return {
|
|
72
72
|
get() {
|
|
73
73
|
const value = this.getDataValue(name);
|
|
74
|
-
if (value
|
|
74
|
+
if (value == null) {
|
|
75
75
|
return value;
|
|
76
76
|
}
|
|
77
77
|
return new Date(value * rationalNumber);
|
|
78
78
|
},
|
|
79
79
|
set(value) {
|
|
80
|
-
if (value
|
|
80
|
+
if (value == null) {
|
|
81
81
|
this.setDataValue(name, value);
|
|
82
82
|
} else {
|
|
83
|
-
this.setDataValue(
|
|
83
|
+
this.setDataValue(
|
|
84
|
+
name,
|
|
85
|
+
Math.floor(typeof value === "number" ? value : new Date(value).getTime() / rationalNumber)
|
|
86
|
+
);
|
|
84
87
|
}
|
|
85
88
|
}
|
|
86
89
|
};
|
package/lib/filter-match.js
CHANGED
|
@@ -69,7 +69,9 @@ function filterMatch(model, where) {
|
|
|
69
69
|
$ne: /* @__PURE__ */ __name((value, condition) => value !== condition, "$ne"),
|
|
70
70
|
$in: /* @__PURE__ */ __name((value, condition) => condition.includes(value), "$in"),
|
|
71
71
|
$or: /* @__PURE__ */ __name((model2, conditions) => Object.values(conditions).some((condition) => filterMatch(model2, condition)), "$or"),
|
|
72
|
-
$and: /* @__PURE__ */ __name((model2, conditions) => Object.values(conditions).every((condition) => filterMatch(model2, condition)), "$and")
|
|
72
|
+
$and: /* @__PURE__ */ __name((model2, conditions) => Object.values(conditions).every((condition) => filterMatch(model2, condition)), "$and"),
|
|
73
|
+
// boolean
|
|
74
|
+
$isFalsy: /* @__PURE__ */ __name((value) => !value, "$isFalsy")
|
|
73
75
|
};
|
|
74
76
|
for (const [key, value] of Object.entries(where)) {
|
|
75
77
|
if (operatorFunctions[key] !== void 0) {
|
|
@@ -84,6 +84,13 @@ const _DatetimeInterface = class _DatetimeInterface extends import_base_interfac
|
|
|
84
84
|
if (!value) {
|
|
85
85
|
return null;
|
|
86
86
|
}
|
|
87
|
+
if (typeof value === "number") {
|
|
88
|
+
const valueStr = value.toString();
|
|
89
|
+
const dateOnlyMatch = /^(\d{4})[-/]?(\d{2})[-/]?(\d{2})$/.exec(valueStr);
|
|
90
|
+
if (dateOnlyMatch) {
|
|
91
|
+
value = valueStr;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
87
94
|
if (typeof value === "string") {
|
|
88
95
|
const dateInfo = this.parseDateString(value);
|
|
89
96
|
if (dateInfo) {
|
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
9
|
import { AggregateOptions, DestroyOptions, FindOptions, TargetKey, TK } from '../repository';
|
|
10
|
-
import {
|
|
10
|
+
import { MultipleRelationRepository } from './multiple-relation-repository';
|
|
11
|
+
import { AssociatedOptions } from './types';
|
|
11
12
|
export declare class HasManyRepository extends MultipleRelationRepository {
|
|
12
13
|
find(options?: FindOptions): Promise<any>;
|
|
13
14
|
aggregate(options: AggregateOptions): Promise<any>;
|
|
@@ -6,24 +6,20 @@
|
|
|
6
6
|
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
|
-
import { MultiAssociationAccessors, Transaction
|
|
10
|
-
import { CommonFindOptions, CountOptions, DestroyOptions, Filter, FindOneOptions, FindOptions, TargetKey, TK, UpdateOptions } from '../repository';
|
|
9
|
+
import { MultiAssociationAccessors, Transaction } from 'sequelize';
|
|
11
10
|
import { RelationRepository } from './relation-repository';
|
|
12
|
-
|
|
13
|
-
export interface AssociatedOptions extends Transactionable {
|
|
14
|
-
tk?: TK;
|
|
15
|
-
}
|
|
11
|
+
import { AssociatedOptions, CountOptions, DestroyOptions, Filter, FindOptions, TargetKey, UpdateOptions, FirstOrCreateOptions } from './types';
|
|
16
12
|
export declare abstract class MultipleRelationRepository extends RelationRepository {
|
|
17
13
|
targetRepositoryFilterOptionsBySourceValue(): Promise<any>;
|
|
18
14
|
find(options?: FindOptions): Promise<any>;
|
|
19
|
-
findAndCount(options?:
|
|
15
|
+
findAndCount(options?: FindOptions): Promise<[any[], number]>;
|
|
20
16
|
count(options?: CountOptions): Promise<number>;
|
|
21
|
-
findOne(options?:
|
|
17
|
+
findOne(options?: FindOptions): Promise<any>;
|
|
22
18
|
remove(options: TargetKey | TargetKey[] | AssociatedOptions): Promise<void>;
|
|
23
19
|
update(options?: UpdateOptions): Promise<any>;
|
|
24
|
-
destroy(options?:
|
|
20
|
+
destroy(options?: TargetKey | DestroyOptions): Promise<boolean>;
|
|
25
21
|
protected destroyByFilter(filter: Filter, transaction?: Transaction): Promise<boolean>;
|
|
26
22
|
protected filterHasInclude(filter: Filter, options?: any): boolean;
|
|
27
23
|
protected accessors(): MultiAssociationAccessors;
|
|
24
|
+
updateOrCreate(options: FirstOrCreateOptions): Promise<any>;
|
|
28
25
|
}
|
|
29
|
-
export {};
|
|
@@ -191,6 +191,10 @@ const _MultipleRelationRepository = class _MultipleRelationRepository extends im
|
|
|
191
191
|
accessors() {
|
|
192
192
|
return super.accessors();
|
|
193
193
|
}
|
|
194
|
+
async updateOrCreate(options) {
|
|
195
|
+
const result = await super.updateOrCreate(options);
|
|
196
|
+
return Array.isArray(result) ? result[0] : result;
|
|
197
|
+
}
|
|
194
198
|
};
|
|
195
199
|
__name(_MultipleRelationRepository, "MultipleRelationRepository");
|
|
196
200
|
__decorateClass([
|
|
@@ -205,6 +209,9 @@ __decorateClass([
|
|
|
205
209
|
(0, import_relation_repository.transaction)(),
|
|
206
210
|
import_target_collection_decorator.default
|
|
207
211
|
], _MultipleRelationRepository.prototype, "update", 1);
|
|
212
|
+
__decorateClass([
|
|
213
|
+
(0, import_relation_repository.transaction)()
|
|
214
|
+
], _MultipleRelationRepository.prototype, "updateOrCreate", 1);
|
|
208
215
|
let MultipleRelationRepository = _MultipleRelationRepository;
|
|
209
216
|
// Annotate the CommonJS export names for ESM import in node:
|
|
210
217
|
0 && (module.exports = {
|
|
@@ -11,7 +11,7 @@ import { Collection } from '../collection';
|
|
|
11
11
|
import Database from '../database';
|
|
12
12
|
import { RelationField } from '../fields/relation-field';
|
|
13
13
|
import { Model } from '../model';
|
|
14
|
-
import { CreateOptions, Filter, FindOptions, TargetKey } from '
|
|
14
|
+
import { CreateOptions, Filter, FindOptions, FirstOrCreateOptions, TargetKey, UpdateOptions } from './types';
|
|
15
15
|
export declare const transaction: (transactionInjector?: any) => (target: any, name: any, descriptor: any) => any;
|
|
16
16
|
export declare abstract class RelationRepository {
|
|
17
17
|
sourceCollection: Collection;
|
|
@@ -30,6 +30,8 @@ export declare abstract class RelationRepository {
|
|
|
30
30
|
isMultiTargetKey(value?: any): boolean;
|
|
31
31
|
get collection(): Collection<any, any>;
|
|
32
32
|
abstract find(options?: FindOptions): Promise<any>;
|
|
33
|
+
abstract findOne(options?: FindOptions): Promise<any>;
|
|
34
|
+
abstract update(options: UpdateOptions): Promise<any>;
|
|
33
35
|
chunk(options: FindOptions & {
|
|
34
36
|
chunkSize: number;
|
|
35
37
|
callback: (rows: Model[], options: FindOptions) => Promise<void>;
|
|
@@ -37,6 +39,8 @@ export declare abstract class RelationRepository {
|
|
|
37
39
|
convertTk(options: any): any;
|
|
38
40
|
convertTks(options: any): any[];
|
|
39
41
|
targetKey(): any;
|
|
42
|
+
firstOrCreate(options: FirstOrCreateOptions): Promise<any>;
|
|
43
|
+
updateOrCreate(options: FirstOrCreateOptions): Promise<any>;
|
|
40
44
|
create(options?: CreateOptions): Promise<any>;
|
|
41
45
|
getSourceModel(transaction?: Transaction): Promise<Model<any, any>>;
|
|
42
46
|
protected accessors(): import("sequelize").SingleAssociationAccessors | import("sequelize").MultiAssociationAccessors;
|
|
@@ -55,6 +55,7 @@ var import_filter_parser = __toESM(require("../filter-parser"));
|
|
|
55
55
|
var import_options_parser = require("../options-parser");
|
|
56
56
|
var import_update_associations = require("../update-associations");
|
|
57
57
|
var import_update_guard = require("../update-guard");
|
|
58
|
+
var import_filter_utils = require("../utils/filter-utils");
|
|
58
59
|
const transaction = (0, import_transaction_decorator.transactionWrapperBuilder)(function() {
|
|
59
60
|
return this.sourceCollection.model.sequelize.transaction();
|
|
60
61
|
});
|
|
@@ -141,6 +142,32 @@ const _RelationRepository = class _RelationRepository {
|
|
|
141
142
|
targetKey() {
|
|
142
143
|
return this.associationField.targetKey;
|
|
143
144
|
}
|
|
145
|
+
async firstOrCreate(options) {
|
|
146
|
+
const { filterKeys, values, transaction: transaction2, hooks, context } = options;
|
|
147
|
+
const filter = (0, import_filter_utils.valuesToFilter)(values, filterKeys);
|
|
148
|
+
const instance = await this.findOne({ filter, transaction: transaction2, context });
|
|
149
|
+
if (instance) {
|
|
150
|
+
return instance;
|
|
151
|
+
}
|
|
152
|
+
return this.create({ values, transaction: transaction2, hooks, context });
|
|
153
|
+
}
|
|
154
|
+
async updateOrCreate(options) {
|
|
155
|
+
const { filterKeys, values, transaction: transaction2, hooks, context } = options;
|
|
156
|
+
const filter = (0, import_filter_utils.valuesToFilter)(values, filterKeys);
|
|
157
|
+
const instance = await this.findOne({ filter, transaction: transaction2, context });
|
|
158
|
+
if (instance) {
|
|
159
|
+
return await this.update({
|
|
160
|
+
filterByTk: instance.get(
|
|
161
|
+
this.targetCollection.filterTargetKey || this.targetCollection.model.primaryKeyAttribute
|
|
162
|
+
),
|
|
163
|
+
values,
|
|
164
|
+
transaction: transaction2,
|
|
165
|
+
hooks,
|
|
166
|
+
context
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
return this.create({ values, transaction: transaction2, hooks, context });
|
|
170
|
+
}
|
|
144
171
|
async create(options) {
|
|
145
172
|
if (Array.isArray(options.values)) {
|
|
146
173
|
return Promise.all(options.values.map((record) => this.create({ ...options, values: record })));
|
|
@@ -210,6 +237,12 @@ const _RelationRepository = class _RelationRepository {
|
|
|
210
237
|
}
|
|
211
238
|
};
|
|
212
239
|
__name(_RelationRepository, "RelationRepository");
|
|
240
|
+
__decorateClass([
|
|
241
|
+
transaction()
|
|
242
|
+
], _RelationRepository.prototype, "firstOrCreate", 1);
|
|
243
|
+
__decorateClass([
|
|
244
|
+
transaction()
|
|
245
|
+
], _RelationRepository.prototype, "updateOrCreate", 1);
|
|
213
246
|
__decorateClass([
|
|
214
247
|
transaction()
|
|
215
248
|
], _RelationRepository.prototype, "create", 1);
|
|
@@ -8,15 +8,8 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { SingleAssociationAccessors, Transactionable } from 'sequelize';
|
|
10
10
|
import { Model } from '../model';
|
|
11
|
-
import {
|
|
11
|
+
import { FindOptions, TargetKey, UpdateOptions } from './types';
|
|
12
12
|
import { RelationRepository } from './relation-repository';
|
|
13
|
-
export interface SingleRelationFindOption extends Transactionable {
|
|
14
|
-
fields?: Fields;
|
|
15
|
-
except?: Except;
|
|
16
|
-
appends?: Appends;
|
|
17
|
-
filter?: Filter;
|
|
18
|
-
targetCollection?: string;
|
|
19
|
-
}
|
|
20
13
|
interface SetOption extends Transactionable {
|
|
21
14
|
tk?: TargetKey;
|
|
22
15
|
}
|
|
@@ -24,8 +17,8 @@ export declare abstract class SingleRelationRepository extends RelationRepositor
|
|
|
24
17
|
abstract filterOptions(sourceModel: any): any;
|
|
25
18
|
remove(options?: Transactionable): Promise<void>;
|
|
26
19
|
set(options: TargetKey | SetOption): Promise<void>;
|
|
27
|
-
find(options?:
|
|
28
|
-
findOne(options?:
|
|
20
|
+
find(options?: FindOptions): Promise<any>;
|
|
21
|
+
findOne(options?: FindOptions): Promise<Model<any>>;
|
|
29
22
|
destroy(options?: Transactionable): Promise<boolean>;
|
|
30
23
|
update(options: UpdateOptions): Promise<any>;
|
|
31
24
|
/**
|
|
@@ -96,6 +96,7 @@ const _SingleRelationRepository = class _SingleRelationRepository extends import
|
|
|
96
96
|
const transaction2 = await this.getTransaction(options);
|
|
97
97
|
const target = await this.find({
|
|
98
98
|
transaction: transaction2,
|
|
99
|
+
// @ts-ignore
|
|
99
100
|
targetCollection: options.targetCollection
|
|
100
101
|
});
|
|
101
102
|
if (!target) {
|
|
@@ -6,10 +6,81 @@
|
|
|
6
6
|
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
export
|
|
13
|
-
|
|
9
|
+
import { AssociationKeysToBeUpdate, BlackList, Values, WhiteList } from '@nocobase/database';
|
|
10
|
+
import { Transaction } from 'sequelize';
|
|
11
|
+
import { CreateOptions as SequelizeCreateOptions, UpdateOptions as SequelizeUpdateOptions } from 'sequelize/types/model';
|
|
12
|
+
export type TargetKey = string | number | {
|
|
13
|
+
[key: string]: any;
|
|
14
|
+
};
|
|
15
|
+
export interface Filter {
|
|
16
|
+
[key: string]: any;
|
|
17
|
+
}
|
|
18
|
+
export interface Appends {
|
|
19
|
+
[key: string]: true | Appends;
|
|
20
|
+
}
|
|
21
|
+
export interface Except {
|
|
22
|
+
[key: string]: true | Except;
|
|
23
|
+
}
|
|
24
|
+
export interface CommonOptions {
|
|
25
|
+
transaction?: Transaction;
|
|
26
|
+
context?: any;
|
|
27
|
+
}
|
|
28
|
+
export interface FindOptions extends CommonOptions {
|
|
29
|
+
filter?: Filter;
|
|
30
|
+
filterByTk?: TargetKey;
|
|
31
|
+
fields?: string[];
|
|
32
|
+
appends?: string[];
|
|
33
|
+
except?: string[];
|
|
34
|
+
sort?: string[];
|
|
35
|
+
limit?: number;
|
|
36
|
+
offset?: number;
|
|
37
|
+
raw?: boolean;
|
|
38
|
+
targetCollection?: string;
|
|
39
|
+
}
|
|
40
|
+
export interface CountOptions extends CommonOptions {
|
|
41
|
+
filter?: Filter;
|
|
42
|
+
}
|
|
43
|
+
export interface CreateOptions extends SequelizeCreateOptions {
|
|
44
|
+
values?: Values | Values[];
|
|
45
|
+
whitelist?: WhiteList;
|
|
46
|
+
blacklist?: BlackList;
|
|
47
|
+
updateAssociationValues?: AssociationKeysToBeUpdate;
|
|
48
|
+
context?: any;
|
|
49
|
+
}
|
|
50
|
+
export interface UpdateOptions extends Omit<SequelizeUpdateOptions, 'where'> {
|
|
51
|
+
values: Values;
|
|
52
|
+
filter?: Filter;
|
|
53
|
+
filterByTk?: TargetKey;
|
|
54
|
+
whitelist?: WhiteList;
|
|
55
|
+
blacklist?: BlackList;
|
|
56
|
+
updateAssociationValues?: AssociationKeysToBeUpdate;
|
|
57
|
+
targetCollection?: string;
|
|
58
|
+
context?: any;
|
|
59
|
+
}
|
|
60
|
+
export interface DestroyOptions extends CommonOptions {
|
|
61
|
+
filter?: Filter;
|
|
62
|
+
filterByTk?: TargetKey;
|
|
63
|
+
truncate?: boolean;
|
|
64
|
+
context?: any;
|
|
65
|
+
}
|
|
66
|
+
export interface FirstOrCreateOptions extends CommonOptions {
|
|
67
|
+
filterKeys: string[];
|
|
68
|
+
values: any;
|
|
69
|
+
hooks?: boolean;
|
|
70
|
+
context?: any;
|
|
71
|
+
}
|
|
72
|
+
export interface ThroughValues {
|
|
73
|
+
[key: string]: any;
|
|
74
|
+
}
|
|
75
|
+
export interface AssociatedOptions extends CommonOptions {
|
|
76
|
+
tk?: TargetKey | TargetKey[];
|
|
77
|
+
transaction?: Transaction;
|
|
78
|
+
}
|
|
79
|
+
export interface PrimaryKeyWithThroughValues {
|
|
80
|
+
pk: any;
|
|
81
|
+
throughValues?: ThroughValues;
|
|
82
|
+
}
|
|
83
|
+
export interface ToggleOptions extends CommonOptions {
|
|
84
|
+
tk?: TargetKey;
|
|
85
|
+
transaction?: Transaction;
|
|
14
86
|
}
|
|
15
|
-
export type setAssociationOptions = TargetKey | TargetKey[] | PrimaryKeyWithThroughValues | PrimaryKeyWithThroughValues[] | AssociatedOptions;
|
package/lib/repository.d.ts
CHANGED
|
@@ -7,18 +7,19 @@
|
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
9
|
/// <reference types="node" />
|
|
10
|
-
import { Association, BulkCreateOptions, CountOptions as SequelizeCountOptions, CreateOptions as SequelizeCreateOptions, DestroyOptions as SequelizeDestroyOptions,
|
|
10
|
+
import { Association, BulkCreateOptions, ModelStatic, FindAndCountOptions as SequelizeAndCountOptions, CountOptions as SequelizeCountOptions, CreateOptions as SequelizeCreateOptions, DestroyOptions as SequelizeDestroyOptions, FindOptions as SequelizeFindOptions, UpdateOptions as SequelizeUpdateOptions, Transactionable, WhereOperators } from 'sequelize';
|
|
11
11
|
import { Collection } from './collection';
|
|
12
12
|
import { Database } from './database';
|
|
13
13
|
import { ArrayFieldRepository } from './field-repository/array-field-repository';
|
|
14
14
|
import { Model } from './model';
|
|
15
15
|
import operators from './operators';
|
|
16
|
+
import { BelongsToArrayRepository } from './relation-repository/belongs-to-array-repository';
|
|
16
17
|
import { BelongsToManyRepository } from './relation-repository/belongs-to-many-repository';
|
|
17
18
|
import { BelongsToRepository } from './relation-repository/belongs-to-repository';
|
|
18
19
|
import { HasManyRepository } from './relation-repository/hasmany-repository';
|
|
19
20
|
import { HasOneRepository } from './relation-repository/hasone-repository';
|
|
20
21
|
import { RelationRepository } from './relation-repository/relation-repository';
|
|
21
|
-
import {
|
|
22
|
+
import { valuesToFilter } from './utils/filter-utils';
|
|
22
23
|
interface CreateManyOptions extends BulkCreateOptions {
|
|
23
24
|
records: Values[];
|
|
24
25
|
}
|
|
@@ -134,19 +135,18 @@ export interface AggregateOptions {
|
|
|
134
135
|
filter?: Filter;
|
|
135
136
|
distinct?: boolean;
|
|
136
137
|
}
|
|
137
|
-
interface FirstOrCreateOptions extends Transactionable {
|
|
138
|
+
export interface FirstOrCreateOptions extends Transactionable {
|
|
138
139
|
filterKeys: string[];
|
|
139
140
|
values?: Values;
|
|
140
141
|
hooks?: boolean;
|
|
142
|
+
context?: any;
|
|
141
143
|
}
|
|
142
144
|
export declare class Repository<TModelAttributes extends {} = any, TCreationAttributes extends {} = TModelAttributes> {
|
|
143
145
|
database: Database;
|
|
144
146
|
collection: Collection;
|
|
145
147
|
model: ModelStatic<Model>;
|
|
146
148
|
constructor(collection: Collection);
|
|
147
|
-
static valuesToFilter
|
|
148
|
-
$and: any[];
|
|
149
|
-
};
|
|
149
|
+
static valuesToFilter: typeof valuesToFilter;
|
|
150
150
|
/**
|
|
151
151
|
* return count by filter
|
|
152
152
|
*/
|
package/lib/repository.js
CHANGED
|
@@ -13,6 +13,7 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
13
13
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
14
14
|
var __getProtoOf = Object.getPrototypeOf;
|
|
15
15
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
16
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
16
17
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
17
18
|
var __export = (target, all) => {
|
|
18
19
|
for (var name in all)
|
|
@@ -43,16 +44,16 @@ var __decorateClass = (decorators, target, key, kind) => {
|
|
|
43
44
|
if (kind && result) __defProp(target, key, result);
|
|
44
45
|
return result;
|
|
45
46
|
};
|
|
47
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
46
48
|
var repository_exports = {};
|
|
47
49
|
__export(repository_exports, {
|
|
48
50
|
Repository: () => Repository,
|
|
49
51
|
Transactionable: () => import_sequelize2.Transactionable
|
|
50
52
|
});
|
|
51
53
|
module.exports = __toCommonJS(repository_exports);
|
|
52
|
-
var
|
|
54
|
+
var import_utils = require("@nocobase/utils");
|
|
53
55
|
var import_lodash = __toESM(require("lodash"));
|
|
54
56
|
var import_sequelize = require("sequelize");
|
|
55
|
-
var import_utils = require("@nocobase/utils");
|
|
56
57
|
var import_must_have_filter_decorator = __toESM(require("./decorators/must-have-filter-decorator"));
|
|
57
58
|
var import_target_collection_decorator = __toESM(require("./decorators/target-collection-decorator"));
|
|
58
59
|
var import_transaction_decorator = require("./decorators/transaction-decorator");
|
|
@@ -61,13 +62,14 @@ var import_array_field_repository = require("./field-repository/array-field-repo
|
|
|
61
62
|
var import_fields = require("./fields");
|
|
62
63
|
var import_filter_parser = __toESM(require("./filter-parser"));
|
|
63
64
|
var import_options_parser = require("./options-parser");
|
|
65
|
+
var import_belongs_to_array_repository = require("./relation-repository/belongs-to-array-repository");
|
|
64
66
|
var import_belongs_to_many_repository = require("./relation-repository/belongs-to-many-repository");
|
|
65
67
|
var import_belongs_to_repository = require("./relation-repository/belongs-to-repository");
|
|
66
68
|
var import_hasmany_repository = require("./relation-repository/hasmany-repository");
|
|
67
69
|
var import_hasone_repository = require("./relation-repository/hasone-repository");
|
|
68
70
|
var import_update_associations = require("./update-associations");
|
|
69
71
|
var import_update_guard = require("./update-guard");
|
|
70
|
-
var
|
|
72
|
+
var import_filter_utils = require("./utils/filter-utils");
|
|
71
73
|
var import_sequelize2 = require("sequelize");
|
|
72
74
|
const debug = require("debug")("noco-database");
|
|
73
75
|
const transaction = (0, import_transaction_decorator.transactionWrapperBuilder)(function() {
|
|
@@ -124,43 +126,6 @@ const _Repository = class _Repository {
|
|
|
124
126
|
this.collection = collection;
|
|
125
127
|
this.model = collection.model;
|
|
126
128
|
}
|
|
127
|
-
static valuesToFilter(values = {}, filterKeys) {
|
|
128
|
-
const removeArrayIndexInKey = /* @__PURE__ */ __name((key) => {
|
|
129
|
-
const chunks = key.split(".");
|
|
130
|
-
return chunks.filter((chunk) => {
|
|
131
|
-
return !chunk.match(/\d+/);
|
|
132
|
-
}).join(".");
|
|
133
|
-
}, "removeArrayIndexInKey");
|
|
134
|
-
const filterAnd = [];
|
|
135
|
-
const flattedValues = (0, import_flat.flatten)(values);
|
|
136
|
-
const flattedValuesObject = {};
|
|
137
|
-
for (const key in flattedValues) {
|
|
138
|
-
const keyWithoutArrayIndex = removeArrayIndexInKey(key);
|
|
139
|
-
if (flattedValuesObject[keyWithoutArrayIndex]) {
|
|
140
|
-
if (!Array.isArray(flattedValuesObject[keyWithoutArrayIndex])) {
|
|
141
|
-
flattedValuesObject[keyWithoutArrayIndex] = [flattedValuesObject[keyWithoutArrayIndex]];
|
|
142
|
-
}
|
|
143
|
-
flattedValuesObject[keyWithoutArrayIndex].push(flattedValues[key]);
|
|
144
|
-
} else {
|
|
145
|
-
flattedValuesObject[keyWithoutArrayIndex] = [flattedValues[key]];
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
for (const filterKey of filterKeys) {
|
|
149
|
-
const filterValue = flattedValuesObject[filterKey] ? flattedValuesObject[filterKey] : import_lodash.default.get(values, filterKey);
|
|
150
|
-
if (filterValue) {
|
|
151
|
-
filterAnd.push({
|
|
152
|
-
[filterKey]: filterValue
|
|
153
|
-
});
|
|
154
|
-
} else {
|
|
155
|
-
filterAnd.push({
|
|
156
|
-
[filterKey]: null
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
return {
|
|
161
|
-
$and: filterAnd
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
129
|
/**
|
|
165
130
|
* return count by filter
|
|
166
131
|
*/
|
|
@@ -339,27 +304,28 @@ const _Repository = class _Repository {
|
|
|
339
304
|
* Get the first record matching the attributes or create it.
|
|
340
305
|
*/
|
|
341
306
|
async firstOrCreate(options) {
|
|
342
|
-
const { filterKeys, values, transaction: transaction2, hooks } = options;
|
|
307
|
+
const { filterKeys, values, transaction: transaction2, hooks, context } = options;
|
|
343
308
|
const filter = _Repository.valuesToFilter(values, filterKeys);
|
|
344
|
-
const instance = await this.findOne({ filter, transaction: transaction2 });
|
|
309
|
+
const instance = await this.findOne({ filter, transaction: transaction2, context });
|
|
345
310
|
if (instance) {
|
|
346
311
|
return instance;
|
|
347
312
|
}
|
|
348
|
-
return this.create({ values, transaction: transaction2, hooks });
|
|
313
|
+
return this.create({ values, transaction: transaction2, hooks, context });
|
|
349
314
|
}
|
|
350
315
|
async updateOrCreate(options) {
|
|
351
|
-
const { filterKeys, values, transaction: transaction2, hooks } = options;
|
|
316
|
+
const { filterKeys, values, transaction: transaction2, hooks, context } = options;
|
|
352
317
|
const filter = _Repository.valuesToFilter(values, filterKeys);
|
|
353
|
-
const instance = await this.findOne({ filter, transaction: transaction2 });
|
|
318
|
+
const instance = await this.findOne({ filter, transaction: transaction2, context });
|
|
354
319
|
if (instance) {
|
|
355
320
|
return await this.update({
|
|
356
321
|
filterByTk: instance.get(this.collection.filterTargetKey || this.collection.model.primaryKeyAttribute),
|
|
357
322
|
values,
|
|
358
323
|
transaction: transaction2,
|
|
359
|
-
hooks
|
|
324
|
+
hooks,
|
|
325
|
+
context
|
|
360
326
|
});
|
|
361
327
|
}
|
|
362
|
-
return this.create({ values, transaction: transaction2, hooks });
|
|
328
|
+
return this.create({ values, transaction: transaction2, hooks, context });
|
|
363
329
|
}
|
|
364
330
|
async create(options) {
|
|
365
331
|
if (Array.isArray(options.values)) {
|
|
@@ -500,7 +466,7 @@ const _Repository = class _Repository {
|
|
|
500
466
|
throw new Error(`filterByTk is not supported for collection that has no primary key`);
|
|
501
467
|
}
|
|
502
468
|
}
|
|
503
|
-
if (filterByTk && !options.filter) {
|
|
469
|
+
if (filterByTk && !(0, import_utils.isValidFilter)(options.filter)) {
|
|
504
470
|
const where = [];
|
|
505
471
|
for (const tk of filterByTk) {
|
|
506
472
|
const optionParser = new import_options_parser.OptionsParser(
|
|
@@ -595,6 +561,7 @@ const _Repository = class _Repository {
|
|
|
595
561
|
}
|
|
596
562
|
};
|
|
597
563
|
__name(_Repository, "Repository");
|
|
564
|
+
__publicField(_Repository, "valuesToFilter", import_filter_utils.valuesToFilter);
|
|
598
565
|
__decorateClass([
|
|
599
566
|
transaction()
|
|
600
567
|
], _Repository.prototype, "create", 1);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
type Values = Record<string, any>;
|
|
10
|
+
export declare function valuesToFilter(values: Values, filterKeys: Array<string>): {
|
|
11
|
+
$and: any[];
|
|
12
|
+
};
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
var __create = Object.create;
|
|
11
|
+
var __defProp = Object.defineProperty;
|
|
12
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
13
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
14
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
15
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
16
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
17
|
+
var __export = (target, all) => {
|
|
18
|
+
for (var name in all)
|
|
19
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
20
|
+
};
|
|
21
|
+
var __copyProps = (to, from, except, desc) => {
|
|
22
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
23
|
+
for (let key of __getOwnPropNames(from))
|
|
24
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
25
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
26
|
+
}
|
|
27
|
+
return to;
|
|
28
|
+
};
|
|
29
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
30
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
31
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
32
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
33
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
34
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
35
|
+
mod
|
|
36
|
+
));
|
|
37
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
38
|
+
var filter_utils_exports = {};
|
|
39
|
+
__export(filter_utils_exports, {
|
|
40
|
+
valuesToFilter: () => valuesToFilter
|
|
41
|
+
});
|
|
42
|
+
module.exports = __toCommonJS(filter_utils_exports);
|
|
43
|
+
var import_lodash = __toESM(require("lodash"));
|
|
44
|
+
var import_flat = require("flat");
|
|
45
|
+
function valuesToFilter(values = {}, filterKeys) {
|
|
46
|
+
const removeArrayIndexInKey = /* @__PURE__ */ __name((key) => {
|
|
47
|
+
const chunks = key.split(".");
|
|
48
|
+
return chunks.filter((chunk) => {
|
|
49
|
+
return !chunk.match(/\d+/);
|
|
50
|
+
}).join(".");
|
|
51
|
+
}, "removeArrayIndexInKey");
|
|
52
|
+
const filterAnd = [];
|
|
53
|
+
const flattedValues = (0, import_flat.flatten)(values);
|
|
54
|
+
const flattedValuesObject = {};
|
|
55
|
+
for (const key in flattedValues) {
|
|
56
|
+
const keyWithoutArrayIndex = removeArrayIndexInKey(key);
|
|
57
|
+
if (flattedValuesObject[keyWithoutArrayIndex]) {
|
|
58
|
+
if (!Array.isArray(flattedValuesObject[keyWithoutArrayIndex])) {
|
|
59
|
+
flattedValuesObject[keyWithoutArrayIndex] = [flattedValuesObject[keyWithoutArrayIndex]];
|
|
60
|
+
}
|
|
61
|
+
flattedValuesObject[keyWithoutArrayIndex].push(flattedValues[key]);
|
|
62
|
+
} else {
|
|
63
|
+
flattedValuesObject[keyWithoutArrayIndex] = [flattedValues[key]];
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
for (const filterKey of filterKeys) {
|
|
67
|
+
const filterValue = flattedValuesObject[filterKey] ? flattedValuesObject[filterKey] : import_lodash.default.get(values, filterKey);
|
|
68
|
+
if (filterValue) {
|
|
69
|
+
filterAnd.push({
|
|
70
|
+
[filterKey]: filterValue
|
|
71
|
+
});
|
|
72
|
+
} else {
|
|
73
|
+
filterAnd.push({
|
|
74
|
+
[filterKey]: null
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
$and: filterAnd
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
__name(valuesToFilter, "valuesToFilter");
|
|
83
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
84
|
+
0 && (module.exports = {
|
|
85
|
+
valuesToFilter
|
|
86
|
+
});
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nocobase/database",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0-alpha.10",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"types": "./lib/index.d.ts",
|
|
7
7
|
"license": "AGPL-3.0",
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"@nocobase/logger": "1.
|
|
10
|
-
"@nocobase/utils": "1.
|
|
9
|
+
"@nocobase/logger": "1.6.0-alpha.10",
|
|
10
|
+
"@nocobase/utils": "1.6.0-alpha.10",
|
|
11
11
|
"async-mutex": "^0.3.2",
|
|
12
12
|
"chalk": "^4.1.1",
|
|
13
13
|
"cron-parser": "4.4.0",
|
|
@@ -38,5 +38,5 @@
|
|
|
38
38
|
"url": "git+https://github.com/nocobase/nocobase.git",
|
|
39
39
|
"directory": "packages/database"
|
|
40
40
|
},
|
|
41
|
-
"gitHead": "
|
|
41
|
+
"gitHead": "8ba8204282be7bf6674ef427fdbe31caa65977d5"
|
|
42
42
|
}
|