@nocobase/database 1.5.0-beta.9 → 1.5.1

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.
@@ -9,9 +9,10 @@
9
9
  import { Transactionable } from 'sequelize/types';
10
10
  import { Collection } from '../collection';
11
11
  import { FindOptions } from '../repository';
12
- import { MultipleRelationRepository } from './multiple-relation-repository';
12
+ import { MultipleRelationRepository } from '../relation-repository/multiple-relation-repository';
13
13
  import Database from '../database';
14
14
  import { Model } from '../model';
15
+ import { UpdateAssociationOptions } from '../update-associations';
15
16
  export declare class BelongsToArrayAssociation {
16
17
  db: Database;
17
18
  associationType: string;
@@ -33,6 +34,7 @@ export declare class BelongsToArrayAssociation {
33
34
  generateInclude(): {
34
35
  on: import("sequelize/types/utils").Literal;
35
36
  };
37
+ update(instance: Model, value: any, options?: UpdateAssociationOptions): Promise<void>;
36
38
  }
37
39
  export declare class BelongsToArrayRepository extends MultipleRelationRepository {
38
40
  private belongsToArrayAssociation;
@@ -7,9 +7,11 @@
7
7
  * For more information, please refer to: https://www.nocobase.com/agreement.
8
8
  */
9
9
 
10
+ var __create = Object.create;
10
11
  var __defProp = Object.defineProperty;
11
12
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
12
13
  var __getOwnPropNames = Object.getOwnPropertyNames;
14
+ var __getProtoOf = Object.getPrototypeOf;
13
15
  var __hasOwnProp = Object.prototype.hasOwnProperty;
14
16
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
15
17
  var __export = (target, all) => {
@@ -24,6 +26,14 @@ var __copyProps = (to, from, except, desc) => {
24
26
  }
25
27
  return to;
26
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
+ ));
27
37
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
38
  var __decorateClass = (decorators, target, key, kind) => {
29
39
  var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
@@ -39,9 +49,9 @@ __export(belongs_to_array_repository_exports, {
39
49
  BelongsToArrayRepository: () => BelongsToArrayRepository
40
50
  });
41
51
  module.exports = __toCommonJS(belongs_to_array_repository_exports);
42
- var import_lodash = require("lodash");
52
+ var import_lodash = __toESM(require("lodash"));
43
53
  var import_transaction_decorator = require("../decorators/transaction-decorator");
44
- var import_multiple_relation_repository = require("./multiple-relation-repository");
54
+ var import_multiple_relation_repository = require("../relation-repository/multiple-relation-repository");
45
55
  const transaction = (0, import_transaction_decorator.transactionWrapperBuilder)(function() {
46
56
  return this.collection.model.sequelize.transaction();
47
57
  });
@@ -83,6 +93,19 @@ const _BelongsToArrayAssociation = class _BelongsToArrayAssociation {
83
93
  on: this.db.sequelize.literal(`${left}=any(${right})`)
84
94
  };
85
95
  }
96
+ async update(instance, value, options = {}) {
97
+ await instance.update(
98
+ {
99
+ [this.as]: value
100
+ },
101
+ {
102
+ values: {
103
+ [this.as]: value
104
+ },
105
+ transaction: options == null ? void 0 : options.transaction
106
+ }
107
+ );
108
+ }
86
109
  };
87
110
  __name(_BelongsToArrayAssociation, "BelongsToArrayAssociation");
88
111
  let BelongsToArrayAssociation = _BelongsToArrayAssociation;
@@ -109,7 +132,7 @@ const _BelongsToArrayRepository = class _BelongsToArrayRepository extends import
109
132
  addFilter[targetKey] = options.filterByTk;
110
133
  }
111
134
  const findOptions = {
112
- ...(0, import_lodash.omit)(options, ["filterByTk", "where", "values", "attributes"]),
135
+ ...import_lodash.default.omit(options, ["filterByTk", "where", "values", "attributes"]),
113
136
  filter: {
114
137
  $and: [options.filter || {}, addFilter]
115
138
  }
@@ -40,6 +40,7 @@ export interface CollectionOptions extends Omit<ModelOptions, 'name' | 'hooks'>
40
40
  writableView?: boolean;
41
41
  filterTargetKey?: string | string[];
42
42
  fields?: FieldOptions[];
43
+ fieldSort?: string[];
43
44
  model?: string | ModelStatic<Model>;
44
45
  repository?: string | RepositoryType;
45
46
  sortable?: CollectionSortable;
@@ -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 === null || value === void 0) {
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 === null || value === void 0) {
80
+ if (value == null) {
81
81
  this.setDataValue(name, value);
82
82
  } else {
83
- this.setDataValue(name, Math.floor(new Date(value).getTime() / rationalNumber));
83
+ this.setDataValue(
84
+ name,
85
+ Math.floor(typeof value === "number" ? value : new Date(value).getTime() / rationalNumber)
86
+ );
84
87
  }
85
88
  }
86
89
  };
@@ -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) {
package/lib/index.d.ts CHANGED
@@ -26,7 +26,7 @@ export * from './relation-repository/belongs-to-repository';
26
26
  export * from './relation-repository/hasmany-repository';
27
27
  export * from './relation-repository/multiple-relation-repository';
28
28
  export * from './relation-repository/single-relation-repository';
29
- export * from './relation-repository/belongs-to-array-repository';
29
+ export * from './belongs-to-array/belongs-to-array-repository';
30
30
  export * from './repository';
31
31
  export * from './update-associations';
32
32
  export { snakeCase } from './utils';
package/lib/index.js CHANGED
@@ -81,7 +81,7 @@ __reExport(src_exports, require("./relation-repository/belongs-to-repository"),
81
81
  __reExport(src_exports, require("./relation-repository/hasmany-repository"), module.exports);
82
82
  __reExport(src_exports, require("./relation-repository/multiple-relation-repository"), module.exports);
83
83
  __reExport(src_exports, require("./relation-repository/single-relation-repository"), module.exports);
84
- __reExport(src_exports, require("./relation-repository/belongs-to-array-repository"), module.exports);
84
+ __reExport(src_exports, require("./belongs-to-array/belongs-to-array-repository"), module.exports);
85
85
  __reExport(src_exports, require("./repository"), module.exports);
86
86
  __reExport(src_exports, require("./update-associations"), module.exports);
87
87
  var import_utils = require("./utils");
@@ -133,7 +133,7 @@ __reExport(src_exports, require("./dialects"), module.exports);
133
133
  ...require("./relation-repository/hasmany-repository"),
134
134
  ...require("./relation-repository/multiple-relation-repository"),
135
135
  ...require("./relation-repository/single-relation-repository"),
136
- ...require("./relation-repository/belongs-to-array-repository"),
136
+ ...require("./belongs-to-array/belongs-to-array-repository"),
137
137
  ...require("./repository"),
138
138
  ...require("./update-associations"),
139
139
  ...require("./value-parsers"),
@@ -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) {
@@ -38,7 +38,7 @@ const _ToManyInterface = class _ToManyInterface extends import_base_interface.Ba
38
38
  }
39
39
  str = `${str}`.trim();
40
40
  const items = str.split(",");
41
- const { filterKey, targetCollection, transaction } = ctx;
41
+ const { filterKey, targetCollection, transaction, field } = ctx;
42
42
  const targetInstances = await targetCollection.repository.find({
43
43
  filter: {
44
44
  [filterKey]: items
@@ -51,7 +51,17 @@ const _ToManyInterface = class _ToManyInterface extends import_base_interface.Ba
51
51
  }
52
52
  });
53
53
  const primaryKeyAttribute = targetCollection.model.primaryKeyAttribute;
54
- return targetInstances.map((targetInstance) => targetInstance[primaryKeyAttribute]);
54
+ const targetKey = field.options.targetKey;
55
+ const values = targetInstances.map((targetInstance) => {
56
+ const result = {
57
+ [targetKey]: targetInstance[targetKey]
58
+ };
59
+ if (targetKey !== primaryKeyAttribute) {
60
+ result[primaryKeyAttribute] = targetInstance[primaryKeyAttribute];
61
+ }
62
+ return result;
63
+ });
64
+ return values;
55
65
  }
56
66
  };
57
67
  __name(_ToManyInterface, "ToManyInterface");
@@ -31,17 +31,30 @@ __export(boolean_exports, {
31
31
  module.exports = __toCommonJS(boolean_exports);
32
32
  var import_sequelize = require("sequelize");
33
33
  var boolean_default = {
34
- $isFalsy() {
34
+ $isFalsy(value) {
35
+ if (value === true || value === "true") {
36
+ return {
37
+ [import_sequelize.Op.or]: {
38
+ [import_sequelize.Op.is]: null,
39
+ [import_sequelize.Op.eq]: false
40
+ }
41
+ };
42
+ }
43
+ return {
44
+ [import_sequelize.Op.eq]: true
45
+ };
46
+ },
47
+ $isTruly(value) {
48
+ if (value === true || value === "true") {
49
+ return {
50
+ [import_sequelize.Op.eq]: true
51
+ };
52
+ }
35
53
  return {
36
54
  [import_sequelize.Op.or]: {
37
55
  [import_sequelize.Op.is]: null,
38
56
  [import_sequelize.Op.eq]: false
39
57
  }
40
58
  };
41
- },
42
- $isTruly() {
43
- return {
44
- [import_sequelize.Op.eq]: true
45
- };
46
59
  }
47
60
  };
@@ -36,6 +36,46 @@ function escapeLike(value) {
36
36
  return value.replace(/[_%]/g, "\\$&");
37
37
  }
38
38
  __name(escapeLike, "escapeLike");
39
+ const getFieldName = /* @__PURE__ */ __name((ctx) => {
40
+ const fullNameSplit = ctx.fullName.split(".");
41
+ const fieldName = ctx.fieldName;
42
+ let columnName = fieldName;
43
+ const associationPath = [];
44
+ if (fullNameSplit.length > 1) {
45
+ for (let i = 0; i < fullNameSplit.length - 1; i++) {
46
+ associationPath.push(fullNameSplit[i]);
47
+ }
48
+ }
49
+ const getModelFromAssociationPath = /* @__PURE__ */ __name(() => {
50
+ let model2 = ctx.model;
51
+ for (const association of associationPath) {
52
+ model2 = model2.associations[association].target;
53
+ }
54
+ return model2;
55
+ }, "getModelFromAssociationPath");
56
+ const model = getModelFromAssociationPath();
57
+ let columnPrefix = model.name;
58
+ if (model.rawAttributes[fieldName]) {
59
+ columnName = model.rawAttributes[fieldName].field || fieldName;
60
+ }
61
+ if (associationPath.length > 0) {
62
+ const association = associationPath.join("->");
63
+ columnPrefix = association;
64
+ }
65
+ columnName = `${columnPrefix}.${columnName}`;
66
+ return columnName;
67
+ }, "getFieldName");
68
+ function getFieldExpression(value, ctx, operator) {
69
+ if ((0, import_utils.isPg)(ctx)) {
70
+ const fieldName = getFieldName(ctx);
71
+ const queryInterface = ctx.db.sequelize.getQueryInterface();
72
+ const quotedField = queryInterface.quoteIdentifiers(fieldName);
73
+ return import_sequelize.Sequelize.literal(`CAST(${quotedField} AS TEXT) ${operator} ${ctx.db.sequelize.escape(value)}`);
74
+ }
75
+ const op = operator === "LIKE" ? import_sequelize.Op.like : operator === "NOT LIKE" ? import_sequelize.Op.notLike : operator === "ILIKE" ? import_sequelize.Op.like : operator === "NOT ILIKE" ? import_sequelize.Op.notLike : import_sequelize.Op.like;
76
+ return { [op]: value };
77
+ }
78
+ __name(getFieldExpression, "getFieldExpression");
39
79
  var string_default = {
40
80
  $includes(value, ctx) {
41
81
  if (value === null) {
@@ -44,16 +84,14 @@ var string_default = {
44
84
  };
45
85
  }
46
86
  if (Array.isArray(value)) {
47
- const conditions = value.map((item) => ({
48
- [(0, import_utils.isPg)(ctx) ? import_sequelize.Op.iLike : import_sequelize.Op.like]: `%${escapeLike(item)}%`
49
- }));
87
+ const conditions = value.map(
88
+ (item) => getFieldExpression(`%${escapeLike(item)}%`, ctx, (0, import_utils.isPg)(ctx) ? "ILIKE" : "LIKE")
89
+ );
50
90
  return {
51
91
  [import_sequelize.Op.or]: conditions
52
92
  };
53
93
  }
54
- return {
55
- [(0, import_utils.isPg)(ctx) ? import_sequelize.Op.iLike : import_sequelize.Op.like]: `%${escapeLike(value)}%`
56
- };
94
+ return getFieldExpression(`%${escapeLike(value)}%`, ctx, (0, import_utils.isPg)(ctx) ? "ILIKE" : "LIKE");
57
95
  },
58
96
  $notIncludes(value, ctx) {
59
97
  if (value === null) {
@@ -62,67 +100,57 @@ var string_default = {
62
100
  };
63
101
  }
64
102
  if (Array.isArray(value)) {
65
- const conditions = value.map((item) => ({
66
- [(0, import_utils.isPg)(ctx) ? import_sequelize.Op.notILike : import_sequelize.Op.notLike]: `%${escapeLike(item)}%`
67
- }));
103
+ const conditions = value.map(
104
+ (item) => getFieldExpression(`%${escapeLike(item)}%`, ctx, (0, import_utils.isPg)(ctx) ? "NOT ILIKE" : "NOT LIKE")
105
+ );
68
106
  return {
69
107
  [import_sequelize.Op.and]: conditions
70
108
  };
71
109
  }
72
- return {
73
- [(0, import_utils.isPg)(ctx) ? import_sequelize.Op.notILike : import_sequelize.Op.notLike]: `%${escapeLike(value)}%`
74
- };
110
+ return getFieldExpression(`%${escapeLike(value)}%`, ctx, (0, import_utils.isPg)(ctx) ? "NOT ILIKE" : "NOT LIKE");
75
111
  },
76
112
  $startsWith(value, ctx) {
77
113
  if (Array.isArray(value)) {
78
- const conditions = value.map((item) => ({
79
- [(0, import_utils.isPg)(ctx) ? import_sequelize.Op.iLike : import_sequelize.Op.like]: `${escapeLike(item)}%`
80
- }));
114
+ const conditions = value.map(
115
+ (item) => getFieldExpression(`${escapeLike(item)}%`, ctx, (0, import_utils.isPg)(ctx) ? "ILIKE" : "LIKE")
116
+ );
81
117
  return {
82
118
  [import_sequelize.Op.or]: conditions
83
119
  };
84
120
  }
85
- return {
86
- [(0, import_utils.isPg)(ctx) ? import_sequelize.Op.iLike : import_sequelize.Op.like]: `${escapeLike(value)}%`
87
- };
121
+ return getFieldExpression(`${escapeLike(value)}%`, ctx, (0, import_utils.isPg)(ctx) ? "ILIKE" : "LIKE");
88
122
  },
89
123
  $notStartsWith(value, ctx) {
90
124
  if (Array.isArray(value)) {
91
- const conditions = value.map((item) => ({
92
- [(0, import_utils.isPg)(ctx) ? import_sequelize.Op.notILike : import_sequelize.Op.notLike]: `${escapeLike(item)}%`
93
- }));
125
+ const conditions = value.map(
126
+ (item) => getFieldExpression(`${escapeLike(item)}%`, ctx, (0, import_utils.isPg)(ctx) ? "NOT ILIKE" : "NOT LIKE")
127
+ );
94
128
  return {
95
129
  [import_sequelize.Op.and]: conditions
96
130
  };
97
131
  }
98
- return {
99
- [(0, import_utils.isPg)(ctx) ? import_sequelize.Op.notILike : import_sequelize.Op.notLike]: `${escapeLike(value)}%`
100
- };
132
+ return getFieldExpression(`${escapeLike(value)}%`, ctx, (0, import_utils.isPg)(ctx) ? "NOT ILIKE" : "NOT LIKE");
101
133
  },
102
134
  $endWith(value, ctx) {
103
135
  if (Array.isArray(value)) {
104
- const conditions = value.map((item) => ({
105
- [(0, import_utils.isPg)(ctx) ? import_sequelize.Op.iLike : import_sequelize.Op.like]: `%${escapeLike(item)}`
106
- }));
136
+ const conditions = value.map(
137
+ (item) => getFieldExpression(`%${escapeLike(item)}`, ctx, (0, import_utils.isPg)(ctx) ? "ILIKE" : "LIKE")
138
+ );
107
139
  return {
108
140
  [import_sequelize.Op.or]: conditions
109
141
  };
110
142
  }
111
- return {
112
- [(0, import_utils.isPg)(ctx) ? import_sequelize.Op.iLike : import_sequelize.Op.like]: `%${escapeLike(value)}`
113
- };
143
+ return getFieldExpression(`%${escapeLike(value)}`, ctx, (0, import_utils.isPg)(ctx) ? "ILIKE" : "LIKE");
114
144
  },
115
145
  $notEndWith(value, ctx) {
116
146
  if (Array.isArray(value)) {
117
- const conditions = value.map((item) => ({
118
- [(0, import_utils.isPg)(ctx) ? import_sequelize.Op.notILike : import_sequelize.Op.notLike]: `%${escapeLike(item)}`
119
- }));
147
+ const conditions = value.map(
148
+ (item) => getFieldExpression(`%${escapeLike(item)}`, ctx, (0, import_utils.isPg)(ctx) ? "NOT ILIKE" : "NOT LIKE")
149
+ );
120
150
  return {
121
151
  [import_sequelize.Op.and]: conditions
122
152
  };
123
153
  }
124
- return {
125
- [(0, import_utils.isPg)(ctx) ? import_sequelize.Op.notILike : import_sequelize.Op.notLike]: `%${escapeLike(value)}`
126
- };
154
+ return getFieldExpression(`%${escapeLike(value)}`, ctx, (0, import_utils.isPg)(ctx) ? "NOT ILIKE" : "NOT LIKE");
127
155
  }
128
156
  };
@@ -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 { AssociatedOptions, MultipleRelationRepository } from './multiple-relation-repository';
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, Transactionable } from 'sequelize';
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
- type FindAndCountOptions = CommonFindOptions;
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?: FindAndCountOptions): Promise<[any[], number]>;
15
+ findAndCount(options?: FindOptions): Promise<[any[], number]>;
20
16
  count(options?: CountOptions): Promise<number>;
21
- findOne(options?: FindOneOptions): Promise<any>;
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?: TK | DestroyOptions): Promise<boolean>;
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 '../repository';
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 { Appends, Except, Fields, Filter, TargetKey, UpdateOptions } from '../repository';
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?: SingleRelationFindOption): Promise<any>;
28
- findOne(options?: SingleRelationFindOption): Promise<Model<any>>;
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
  /**
@@ -51,6 +51,7 @@ module.exports = __toCommonJS(single_relation_repository_exports);
51
51
  var import_target_collection_decorator = __toESM(require("../decorators/target-collection-decorator"));
52
52
  var import_update_associations = require("../update-associations");
53
53
  var import_relation_repository = require("./relation-repository");
54
+ var import_lodash = __toESM(require("lodash"));
54
55
  const _SingleRelationRepository = class _SingleRelationRepository extends import_relation_repository.RelationRepository {
55
56
  async remove(options) {
56
57
  const transaction2 = await this.getTransaction(options);
@@ -96,13 +97,14 @@ const _SingleRelationRepository = class _SingleRelationRepository extends import
96
97
  const transaction2 = await this.getTransaction(options);
97
98
  const target = await this.find({
98
99
  transaction: transaction2,
100
+ // @ts-ignore
99
101
  targetCollection: options.targetCollection
100
102
  });
101
103
  if (!target) {
102
104
  throw new Error("The record does not exist");
103
105
  }
104
106
  await (0, import_update_associations.updateModelByValues)(target, options == null ? void 0 : options.values, {
105
- ...options,
107
+ ...import_lodash.default.omit(options, "values"),
106
108
  transaction: transaction2
107
109
  });
108
110
  if (options.hooks !== false) {
@@ -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 { TargetKey, Values } from '../repository';
10
- import { Transactionable } from 'sequelize';
11
- export type PrimaryKeyWithThroughValues = [TargetKey, Values];
12
- export interface AssociatedOptions extends Transactionable {
13
- tk?: TargetKey | TargetKey[] | PrimaryKeyWithThroughValues | PrimaryKeyWithThroughValues[];
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;
@@ -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, FindAndCountOptions as SequelizeAndCountOptions, FindOptions as SequelizeFindOptions, ModelStatic, Transactionable, UpdateOptions as SequelizeUpdateOptions, WhereOperators } from 'sequelize';
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 { BelongsToArrayRepository } from './relation-repository/belongs-to-array-repository';
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(values: Values, filterKeys: Array<string>): {
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 import_flat = require("flat");
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 import_belongs_to_array_repository = require("./relation-repository/belongs-to-array-repository");
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<boolean>;
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
- function isUndefinedOrNull(value) {
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[];
package/lib/utils.js CHANGED
@@ -38,7 +38,10 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
38
38
  var utils_exports = {};
39
39
  __export(utils_exports, {
40
40
  checkIdentifier: () => checkIdentifier,
41
+ getKeysByPrefix: () => getKeysByPrefix,
41
42
  getTableName: () => getTableName,
43
+ isStringOrNumber: () => isStringOrNumber,
44
+ isUndefinedOrNull: () => isUndefinedOrNull,
42
45
  md5: () => md5,
43
46
  patchSequelizeQueryInterface: () => patchSequelizeQueryInterface,
44
47
  percent2float: () => percent2float,
@@ -125,10 +128,25 @@ function percent2float(value) {
125
128
  return parseFloat(value) * v / (100 * v);
126
129
  }
127
130
  __name(percent2float, "percent2float");
131
+ function isUndefinedOrNull(value) {
132
+ return typeof value === "undefined" || value === null;
133
+ }
134
+ __name(isUndefinedOrNull, "isUndefinedOrNull");
135
+ function isStringOrNumber(value) {
136
+ return typeof value === "string" || typeof value === "number";
137
+ }
138
+ __name(isStringOrNumber, "isStringOrNumber");
139
+ function getKeysByPrefix(keys, prefix) {
140
+ return keys.filter((key) => key.startsWith(`${prefix}.`)).map((key) => key.substring(prefix.length + 1));
141
+ }
142
+ __name(getKeysByPrefix, "getKeysByPrefix");
128
143
  // Annotate the CommonJS export names for ESM import in node:
129
144
  0 && (module.exports = {
130
145
  checkIdentifier,
146
+ getKeysByPrefix,
131
147
  getTableName,
148
+ isStringOrNumber,
149
+ isUndefinedOrNull,
132
150
  md5,
133
151
  patchSequelizeQueryInterface,
134
152
  percent2float,
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@nocobase/database",
3
- "version": "1.5.0-beta.9",
3
+ "version": "1.5.1",
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.5.0-beta.9",
10
- "@nocobase/utils": "1.5.0-beta.9",
9
+ "@nocobase/logger": "1.5.1",
10
+ "@nocobase/utils": "1.5.1",
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": "fef0bcb5f95705cd83607f03a6c911550016281b"
41
+ "gitHead": "b16a0ff226482d0de847656ea26fd621b1d685cf"
42
42
  }