@nocobase/database 1.6.0-alpha.2 → 1.6.0-alpha.21
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/{relation-repository → belongs-to-array}/belongs-to-array-repository.d.ts +3 -1
- package/lib/{relation-repository → belongs-to-array}/belongs-to-array-repository.js +26 -3
- package/lib/collection.d.ts +4 -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/index.d.ts +1 -1
- package/lib/index.js +2 -2
- package/lib/interfaces/datetime-interface.d.ts +23 -0
- package/lib/interfaces/datetime-interface.js +28 -4
- package/lib/interfaces/datetime-no-tz-interface.d.ts +8 -0
- package/lib/interfaces/datetime-no-tz-interface.js +10 -3
- package/lib/interfaces/to-many-interface.js +12 -2
- package/lib/operators/boolean.js +19 -6
- package/lib/operators/string.js +64 -36
- 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 +2 -1
- package/lib/relation-repository/types.d.ts +77 -6
- package/lib/repository.d.ts +6 -6
- package/lib/repository.js +18 -48
- package/lib/update-associations.d.ts +5 -3
- package/lib/update-associations.js +15 -23
- package/lib/utils/filter-utils.d.ts +13 -0
- package/lib/utils/filter-utils.js +86 -0
- package/lib/utils.d.ts +3 -0
- package/lib/utils.js +18 -0
- package/package.json +4 -4
|
@@ -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
|
/**
|
|
@@ -48,10 +48,10 @@ __export(single_relation_repository_exports, {
|
|
|
48
48
|
SingleRelationRepository: () => SingleRelationRepository
|
|
49
49
|
});
|
|
50
50
|
module.exports = __toCommonJS(single_relation_repository_exports);
|
|
51
|
-
var import_lodash = __toESM(require("lodash"));
|
|
52
51
|
var import_target_collection_decorator = __toESM(require("../decorators/target-collection-decorator"));
|
|
53
52
|
var import_update_associations = require("../update-associations");
|
|
54
53
|
var import_relation_repository = require("./relation-repository");
|
|
54
|
+
var import_lodash = __toESM(require("lodash"));
|
|
55
55
|
const _SingleRelationRepository = class _SingleRelationRepository extends import_relation_repository.RelationRepository {
|
|
56
56
|
async remove(options) {
|
|
57
57
|
const transaction2 = await this.getTransaction(options);
|
|
@@ -97,6 +97,7 @@ const _SingleRelationRepository = class _SingleRelationRepository extends import
|
|
|
97
97
|
const transaction2 = await this.getTransaction(options);
|
|
98
98
|
const target = await this.find({
|
|
99
99
|
transaction: transaction2,
|
|
100
|
+
// @ts-ignore
|
|
100
101
|
targetCollection: options.targetCollection
|
|
101
102
|
});
|
|
102
103
|
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 './belongs-to-array/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("./belongs-to-array/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
|
*/
|
|
@@ -290,6 +255,9 @@ const _Repository = class _Repository {
|
|
|
290
255
|
await eagerLoadingTree.load(transaction2);
|
|
291
256
|
rows = eagerLoadingTree.root.instances;
|
|
292
257
|
} else {
|
|
258
|
+
if (opts.where && model.primaryKeyAttributes.length === 0) {
|
|
259
|
+
opts.where = import_sequelize.Utils.mapWhereFieldNames(opts.where, model);
|
|
260
|
+
}
|
|
293
261
|
rows = await model.findAll({
|
|
294
262
|
...opts,
|
|
295
263
|
transaction: transaction2
|
|
@@ -339,27 +307,28 @@ const _Repository = class _Repository {
|
|
|
339
307
|
* Get the first record matching the attributes or create it.
|
|
340
308
|
*/
|
|
341
309
|
async firstOrCreate(options) {
|
|
342
|
-
const { filterKeys, values, transaction: transaction2, hooks } = options;
|
|
310
|
+
const { filterKeys, values, transaction: transaction2, hooks, context } = options;
|
|
343
311
|
const filter = _Repository.valuesToFilter(values, filterKeys);
|
|
344
|
-
const instance = await this.findOne({ filter, transaction: transaction2 });
|
|
312
|
+
const instance = await this.findOne({ filter, transaction: transaction2, context });
|
|
345
313
|
if (instance) {
|
|
346
314
|
return instance;
|
|
347
315
|
}
|
|
348
|
-
return this.create({ values, transaction: transaction2, hooks });
|
|
316
|
+
return this.create({ values, transaction: transaction2, hooks, context });
|
|
349
317
|
}
|
|
350
318
|
async updateOrCreate(options) {
|
|
351
|
-
const { filterKeys, values, transaction: transaction2, hooks } = options;
|
|
319
|
+
const { filterKeys, values, transaction: transaction2, hooks, context } = options;
|
|
352
320
|
const filter = _Repository.valuesToFilter(values, filterKeys);
|
|
353
|
-
const instance = await this.findOne({ filter, transaction: transaction2 });
|
|
321
|
+
const instance = await this.findOne({ filter, transaction: transaction2, context });
|
|
354
322
|
if (instance) {
|
|
355
323
|
return await this.update({
|
|
356
324
|
filterByTk: instance.get(this.collection.filterTargetKey || this.collection.model.primaryKeyAttribute),
|
|
357
325
|
values,
|
|
358
326
|
transaction: transaction2,
|
|
359
|
-
hooks
|
|
327
|
+
hooks,
|
|
328
|
+
context
|
|
360
329
|
});
|
|
361
330
|
}
|
|
362
|
-
return this.create({ values, transaction: transaction2, hooks });
|
|
331
|
+
return this.create({ values, transaction: transaction2, hooks, context });
|
|
363
332
|
}
|
|
364
333
|
async create(options) {
|
|
365
334
|
if (Array.isArray(options.values)) {
|
|
@@ -500,7 +469,7 @@ const _Repository = class _Repository {
|
|
|
500
469
|
throw new Error(`filterByTk is not supported for collection that has no primary key`);
|
|
501
470
|
}
|
|
502
471
|
}
|
|
503
|
-
if (filterByTk && !options.filter) {
|
|
472
|
+
if (filterByTk && !(0, import_utils.isValidFilter)(options.filter)) {
|
|
504
473
|
const where = [];
|
|
505
474
|
for (const tk of filterByTk) {
|
|
506
475
|
const optionParser = new import_options_parser.OptionsParser(
|
|
@@ -595,6 +564,7 @@ const _Repository = class _Repository {
|
|
|
595
564
|
}
|
|
596
565
|
};
|
|
597
566
|
__name(_Repository, "Repository");
|
|
567
|
+
__publicField(_Repository, "valuesToFilter", import_filter_utils.valuesToFilter);
|
|
598
568
|
__decorateClass([
|
|
599
569
|
transaction()
|
|
600
570
|
], _Repository.prototype, "create", 1);
|
|
@@ -13,7 +13,9 @@ export declare function modelAssociations(instance: Model): {
|
|
|
13
13
|
[key: string]: Association<import("sequelize").Model<any, any>, import("sequelize").Model<any, any>>;
|
|
14
14
|
};
|
|
15
15
|
export declare function belongsToManyAssociations(instance: Model): Array<BelongsToMany>;
|
|
16
|
-
export declare function modelAssociationByKey(instance: Model, key: string): Association
|
|
16
|
+
export declare function modelAssociationByKey(instance: Model, key: string): Association & {
|
|
17
|
+
update?: (instance: Model, value: any, options: UpdateAssociationOptions) => Promise<any>;
|
|
18
|
+
};
|
|
17
19
|
type UpdateValue = {
|
|
18
20
|
[key: string]: any;
|
|
19
21
|
};
|
|
@@ -26,7 +28,7 @@ interface UpdateOptions extends Transactionable {
|
|
|
26
28
|
sanitized?: boolean;
|
|
27
29
|
sourceModel?: Model;
|
|
28
30
|
}
|
|
29
|
-
interface UpdateAssociationOptions extends Transactionable, Hookable {
|
|
31
|
+
export interface UpdateAssociationOptions extends Transactionable, Hookable {
|
|
30
32
|
updateAssociationValues?: string[];
|
|
31
33
|
sourceModel?: Model;
|
|
32
34
|
context?: any;
|
|
@@ -49,7 +51,7 @@ export declare function updateAssociations(instance: Model, values: any, options
|
|
|
49
51
|
* @param value
|
|
50
52
|
* @param options
|
|
51
53
|
*/
|
|
52
|
-
export declare function updateAssociation(instance: Model, key: string, value: any, options?: UpdateAssociationOptions): Promise<
|
|
54
|
+
export declare function updateAssociation(instance: Model, key: string, value: any, options?: UpdateAssociationOptions): Promise<any>;
|
|
53
55
|
/**
|
|
54
56
|
* update belongsTo and HasOne
|
|
55
57
|
* @param model
|
|
@@ -51,18 +51,7 @@ module.exports = __toCommonJS(update_associations_exports);
|
|
|
51
51
|
var import_lodash = __toESM(require("lodash"));
|
|
52
52
|
var import_model = require("./model");
|
|
53
53
|
var import_update_guard = require("./update-guard");
|
|
54
|
-
|
|
55
|
-
return typeof value === "undefined" || value === null;
|
|
56
|
-
}
|
|
57
|
-
__name(isUndefinedOrNull, "isUndefinedOrNull");
|
|
58
|
-
function isStringOrNumber(value) {
|
|
59
|
-
return typeof value === "string" || typeof value === "number";
|
|
60
|
-
}
|
|
61
|
-
__name(isStringOrNumber, "isStringOrNumber");
|
|
62
|
-
function getKeysByPrefix(keys, prefix) {
|
|
63
|
-
return keys.filter((key) => key.startsWith(`${prefix}.`)).map((key) => key.substring(prefix.length + 1));
|
|
64
|
-
}
|
|
65
|
-
__name(getKeysByPrefix, "getKeysByPrefix");
|
|
54
|
+
var import_utils = require("./utils");
|
|
66
55
|
function modelAssociations(instance) {
|
|
67
56
|
return instance.constructor.associations;
|
|
68
57
|
}
|
|
@@ -183,6 +172,9 @@ async function updateAssociation(instance, key, value, options = {}) {
|
|
|
183
172
|
if (options.associationContext && isReverseAssociationPair(association, options.associationContext)) {
|
|
184
173
|
return false;
|
|
185
174
|
}
|
|
175
|
+
if (association.update) {
|
|
176
|
+
return association.update(instance, value, options);
|
|
177
|
+
}
|
|
186
178
|
switch (association.associationType) {
|
|
187
179
|
case "HasOne":
|
|
188
180
|
case "BelongsTo":
|
|
@@ -205,14 +197,14 @@ async function updateSingleAssociation(model, key, value, options = {}) {
|
|
|
205
197
|
throw new Error(`The value of '${key}' cannot be in array format`);
|
|
206
198
|
}
|
|
207
199
|
const { recursive, context, updateAssociationValues = [], transaction } = options;
|
|
208
|
-
const keys = getKeysByPrefix(updateAssociationValues, key);
|
|
200
|
+
const keys = (0, import_utils.getKeysByPrefix)(updateAssociationValues, key);
|
|
209
201
|
const setAccessor = association.accessors.set;
|
|
210
202
|
const removeAssociation = /* @__PURE__ */ __name(async () => {
|
|
211
203
|
await model[setAccessor](null, { transaction });
|
|
212
204
|
model.setDataValue(key, null);
|
|
213
205
|
return true;
|
|
214
206
|
}, "removeAssociation");
|
|
215
|
-
if (isUndefinedOrNull(value)) {
|
|
207
|
+
if ((0, import_utils.isUndefinedOrNull)(value)) {
|
|
216
208
|
return await removeAssociation();
|
|
217
209
|
}
|
|
218
210
|
if (association.associationType === "HasOne" && !model.get(association.sourceKeyAttribute)) {
|
|
@@ -226,7 +218,7 @@ async function updateSingleAssociation(model, key, value, options = {}) {
|
|
|
226
218
|
);
|
|
227
219
|
}
|
|
228
220
|
}, "checkBelongsToForeignKeyValue");
|
|
229
|
-
if (isStringOrNumber(value)) {
|
|
221
|
+
if ((0, import_utils.isStringOrNumber)(value)) {
|
|
230
222
|
await model[setAccessor](value, { context, transaction });
|
|
231
223
|
return true;
|
|
232
224
|
}
|
|
@@ -245,7 +237,7 @@ async function updateSingleAssociation(model, key, value, options = {}) {
|
|
|
245
237
|
M = association.target;
|
|
246
238
|
dataKey = M.primaryKeyAttribute;
|
|
247
239
|
}
|
|
248
|
-
if (isStringOrNumber(value[dataKey])) {
|
|
240
|
+
if ((0, import_utils.isStringOrNumber)(value[dataKey])) {
|
|
249
241
|
const instance2 = await M.findOne({
|
|
250
242
|
where: {
|
|
251
243
|
[dataKey]: value[dataKey]
|
|
@@ -298,10 +290,10 @@ async function updateMultipleAssociation(model, key, value, options = {}) {
|
|
|
298
290
|
return false;
|
|
299
291
|
}
|
|
300
292
|
const { recursive, context, updateAssociationValues = [], transaction } = options;
|
|
301
|
-
const keys = getKeysByPrefix(updateAssociationValues, key);
|
|
293
|
+
const keys = (0, import_utils.getKeysByPrefix)(updateAssociationValues, key);
|
|
302
294
|
const setAccessor = association.accessors.set;
|
|
303
295
|
const createAccessor = association.accessors.create;
|
|
304
|
-
if (isUndefinedOrNull(value)) {
|
|
296
|
+
if ((0, import_utils.isUndefinedOrNull)(value)) {
|
|
305
297
|
await model[setAccessor](null, { transaction, context, individualHooks: true, validate: false });
|
|
306
298
|
model.setDataValue(key, null);
|
|
307
299
|
return;
|
|
@@ -309,7 +301,7 @@ async function updateMultipleAssociation(model, key, value, options = {}) {
|
|
|
309
301
|
if (association.associationType === "HasMany" && !model.get(association.sourceKeyAttribute)) {
|
|
310
302
|
throw new Error(`The source key ${association.sourceKeyAttribute} is not set in ${model.constructor.name}`);
|
|
311
303
|
}
|
|
312
|
-
if (isStringOrNumber(value)) {
|
|
304
|
+
if ((0, import_utils.isStringOrNumber)(value)) {
|
|
313
305
|
await model[setAccessor](value, { transaction, context, individualHooks: true, validate: false });
|
|
314
306
|
return;
|
|
315
307
|
}
|
|
@@ -317,10 +309,10 @@ async function updateMultipleAssociation(model, key, value, options = {}) {
|
|
|
317
309
|
const setItems = [];
|
|
318
310
|
const objectItems = [];
|
|
319
311
|
for (const item of value) {
|
|
320
|
-
if (isUndefinedOrNull(item)) {
|
|
312
|
+
if ((0, import_utils.isUndefinedOrNull)(item)) {
|
|
321
313
|
continue;
|
|
322
314
|
}
|
|
323
|
-
if (isStringOrNumber(item)) {
|
|
315
|
+
if ((0, import_utils.isStringOrNumber)(item)) {
|
|
324
316
|
setItems.push(item);
|
|
325
317
|
} else if (item instanceof import_model.Model) {
|
|
326
318
|
setItems.push(item);
|
|
@@ -360,10 +352,10 @@ async function updateMultipleAssociation(model, key, value, options = {}) {
|
|
|
360
352
|
if (throughValue) {
|
|
361
353
|
accessorOptions["through"] = throughValue;
|
|
362
354
|
}
|
|
363
|
-
if (pk !== targetKey && !isUndefinedOrNull(item[pk]) && isUndefinedOrNull(item[targetKey])) {
|
|
355
|
+
if (pk !== targetKey && !(0, import_utils.isUndefinedOrNull)(item[pk]) && (0, import_utils.isUndefinedOrNull)(item[targetKey])) {
|
|
364
356
|
throw new Error(`${targetKey} field value is empty`);
|
|
365
357
|
}
|
|
366
|
-
if (isUndefinedOrNull(item[targetKey])) {
|
|
358
|
+
if ((0, import_utils.isUndefinedOrNull)(item[targetKey])) {
|
|
367
359
|
const instance = await model[createAccessor](item, accessorOptions);
|
|
368
360
|
await updateAssociations(instance, item, {
|
|
369
361
|
...options,
|
|
@@ -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/lib/utils.d.ts
CHANGED
|
@@ -13,3 +13,6 @@ export declare function getTableName(collectionName: string, options: any): any;
|
|
|
13
13
|
export declare function snakeCase(name: string): any;
|
|
14
14
|
export declare function patchSequelizeQueryInterface(db: Database): void;
|
|
15
15
|
export declare function percent2float(value: string): number;
|
|
16
|
+
export declare function isUndefinedOrNull(value: any): boolean;
|
|
17
|
+
export declare function isStringOrNumber(value: any): boolean;
|
|
18
|
+
export declare function getKeysByPrefix(keys: string[], prefix: string): string[];
|