@nocobase/database 1.4.0-alpha.20240906133133 → 1.4.0-alpha.20240910145333

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.
Files changed (36) hide show
  1. package/lib/collection.d.ts +2 -2
  2. package/lib/collection.js +3 -0
  3. package/lib/database.d.ts +3 -3
  4. package/lib/database.js +2 -2
  5. package/lib/fields/date-field.d.ts +7 -2
  6. package/lib/fields/date-field.js +89 -0
  7. package/lib/fields/date-only-field.d.ts +15 -0
  8. package/lib/fields/date-only-field.js +45 -0
  9. package/lib/fields/datetime-field.d.ts +15 -0
  10. package/lib/fields/datetime-field.js +41 -0
  11. package/lib/fields/datetime-no-tz-field.d.ts +24 -0
  12. package/lib/fields/datetime-no-tz-field.js +128 -0
  13. package/lib/fields/datetime-tz-field.d.ts +15 -0
  14. package/lib/fields/datetime-tz-field.js +41 -0
  15. package/lib/fields/field.d.ts +1 -1
  16. package/lib/fields/field.js +3 -2
  17. package/lib/fields/index.d.ts +10 -1
  18. package/lib/fields/index.js +11 -1
  19. package/lib/fields/unix-timestamp-field.d.ts +22 -0
  20. package/lib/fields/unix-timestamp-field.js +94 -0
  21. package/lib/model.d.ts +1 -0
  22. package/lib/model.js +12 -0
  23. package/lib/operators/date.js +65 -24
  24. package/lib/options-parser.d.ts +1 -0
  25. package/lib/options-parser.js +24 -7
  26. package/lib/relation-repository/hasmany-repository.js +8 -11
  27. package/lib/relation-repository/multiple-relation-repository.d.ts +1 -0
  28. package/lib/relation-repository/multiple-relation-repository.js +11 -3
  29. package/lib/relation-repository/relation-repository.d.ts +6 -3
  30. package/lib/relation-repository/relation-repository.js +22 -2
  31. package/lib/repository.d.ts +5 -2
  32. package/lib/repository.js +26 -15
  33. package/lib/update-associations.d.ts +2 -1
  34. package/lib/view/field-type-map.d.ts +2 -2
  35. package/lib/view/field-type-map.js +17 -17
  36. package/package.json +4 -4
@@ -0,0 +1,22 @@
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
+ import { DataTypes } from 'sequelize';
10
+ import { DateField } from './date-field';
11
+ import { BaseColumnFieldOptions } from './field';
12
+ export declare class UnixTimestampField extends DateField {
13
+ get dataType(): DataTypes.BigIntDataTypeConstructor;
14
+ dateToValue(val: any): any;
15
+ additionalSequelizeOptions(): {
16
+ get(): any;
17
+ set(value: any): void;
18
+ };
19
+ }
20
+ export interface UnixTimestampFieldOptions extends BaseColumnFieldOptions {
21
+ type: 'unixTimestamp';
22
+ }
@@ -0,0 +1,94 @@
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 __defProp = Object.defineProperty;
11
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
12
+ var __getOwnPropNames = Object.getOwnPropertyNames;
13
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
14
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
15
+ var __export = (target, all) => {
16
+ for (var name in all)
17
+ __defProp(target, name, { get: all[name], enumerable: true });
18
+ };
19
+ var __copyProps = (to, from, except, desc) => {
20
+ if (from && typeof from === "object" || typeof from === "function") {
21
+ for (let key of __getOwnPropNames(from))
22
+ if (!__hasOwnProp.call(to, key) && key !== except)
23
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
24
+ }
25
+ return to;
26
+ };
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
+ var unix_timestamp_field_exports = {};
29
+ __export(unix_timestamp_field_exports, {
30
+ UnixTimestampField: () => UnixTimestampField
31
+ });
32
+ module.exports = __toCommonJS(unix_timestamp_field_exports);
33
+ var import_sequelize = require("sequelize");
34
+ var import_date_field = require("./date-field");
35
+ const _UnixTimestampField = class _UnixTimestampField extends import_date_field.DateField {
36
+ get dataType() {
37
+ return import_sequelize.DataTypes.BIGINT;
38
+ }
39
+ dateToValue(val) {
40
+ var _a, _b, _c, _d, _e;
41
+ if (val === null || val === void 0) {
42
+ return val;
43
+ }
44
+ let { accuracy } = this.options;
45
+ if ((_c = (_b = (_a = this.options) == null ? void 0 : _a.uiSchema) == null ? void 0 : _b["x-component-props"]) == null ? void 0 : _c.accuracy) {
46
+ accuracy = (_e = (_d = this.options) == null ? void 0 : _d.uiSchema["x-component-props"]) == null ? void 0 : _e.accuracy;
47
+ }
48
+ if (!accuracy) {
49
+ accuracy = "second";
50
+ }
51
+ let rationalNumber = 1e3;
52
+ if (accuracy === "millisecond") {
53
+ rationalNumber = 1;
54
+ }
55
+ return Math.floor(new Date(val).getTime() / rationalNumber);
56
+ }
57
+ additionalSequelizeOptions() {
58
+ var _a, _b, _c, _d, _e;
59
+ const { name } = this.options;
60
+ let { accuracy } = this.options;
61
+ if ((_c = (_b = (_a = this.options) == null ? void 0 : _a.uiSchema) == null ? void 0 : _b["x-component-props"]) == null ? void 0 : _c.accuracy) {
62
+ accuracy = (_e = (_d = this.options) == null ? void 0 : _d.uiSchema["x-component-props"]) == null ? void 0 : _e.accuracy;
63
+ }
64
+ if (!accuracy) {
65
+ accuracy = "second";
66
+ }
67
+ let rationalNumber = 1e3;
68
+ if (accuracy === "millisecond") {
69
+ rationalNumber = 1;
70
+ }
71
+ return {
72
+ get() {
73
+ const value = this.getDataValue(name);
74
+ if (value === null || value === void 0) {
75
+ return value;
76
+ }
77
+ return new Date(value * rationalNumber);
78
+ },
79
+ set(value) {
80
+ if (value === null || value === void 0) {
81
+ this.setDataValue(name, value);
82
+ } else {
83
+ this.setDataValue(name, Math.floor(new Date(value).getTime() / rationalNumber));
84
+ }
85
+ }
86
+ };
87
+ }
88
+ };
89
+ __name(_UnixTimestampField, "UnixTimestampField");
90
+ let UnixTimestampField = _UnixTimestampField;
91
+ // Annotate the CommonJS export names for ESM import in node:
92
+ 0 && (module.exports = {
93
+ UnixTimestampField
94
+ });
package/lib/model.d.ts CHANGED
@@ -20,6 +20,7 @@ export declare class Model<TModelAttributes extends {} = any, TCreationAttribute
20
20
  protected _previousDataValuesWithAssociations: {};
21
21
  get db(): Database;
22
22
  static sync(options: any): Promise<any>;
23
+ static callSetters(values: any, options: any): {};
23
24
  toChangedWithAssociations(): void;
24
25
  changedWithAssociations(key?: string, value?: any): boolean | unknown[] | this;
25
26
  clearChangedWithAssociations(): void;
package/lib/model.js CHANGED
@@ -56,6 +56,18 @@ const _Model = class _Model extends import_sequelize.Model {
56
56
  const runner = new import_sync_runner.SyncRunner(this);
57
57
  return await runner.runSync(options);
58
58
  }
59
+ static callSetters(values, options) {
60
+ const result = {};
61
+ for (const key of Object.keys(values)) {
62
+ const field = this.collection.getField(key);
63
+ if (field && field.setter) {
64
+ result[key] = field.setter.call(field, values[key], options, values, key);
65
+ } else {
66
+ result[key] = values[key];
67
+ }
68
+ }
69
+ return result;
70
+ }
59
71
  // TODO
60
72
  toChangedWithAssociations() {
61
73
  this._changedWithAssociations = /* @__PURE__ */ new Set([...this._changedWithAssociations, ...this._changed]);
@@ -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 date_exports = {};
29
39
  __export(date_exports, {
@@ -32,116 +42,147 @@ __export(date_exports, {
32
42
  module.exports = __toCommonJS(date_exports);
33
43
  var import_utils = require("@nocobase/utils");
34
44
  var import_sequelize = require("sequelize");
45
+ var import_moment = __toESM(require("moment"));
35
46
  function isDate(input) {
36
47
  return input instanceof Date || Object.prototype.toString.call(input) === "[object Date]";
37
48
  }
38
49
  __name(isDate, "isDate");
39
- const toDate = /* @__PURE__ */ __name((date) => {
40
- if (isDate(date)) {
41
- return date;
50
+ const toDate = /* @__PURE__ */ __name((date, options = {}) => {
51
+ const { ctx } = options;
52
+ const val = isDate(date) ? date : new Date(date);
53
+ const field = ctx.db.getFieldByPath(ctx.fieldPath);
54
+ if (!field) {
55
+ return val;
42
56
  }
43
- return new Date(date);
57
+ if (field.constructor.name === "UnixTimestampField") {
58
+ return field.dateToValue(val);
59
+ }
60
+ if (field.constructor.name === "DatetimeNoTzField") {
61
+ return (0, import_moment.default)(val).utcOffset("+00:00").format("YYYY-MM-DD HH:mm:ss");
62
+ }
63
+ if (field.constructor.name === "DateOnlyField") {
64
+ return (0, import_moment.default)(val).format("YYYY-MM-DD HH:mm:ss");
65
+ }
66
+ return val;
44
67
  }, "toDate");
68
+ function parseDateTimezone(ctx) {
69
+ const field = ctx.db.getFieldByPath(ctx.fieldPath);
70
+ if (!field) {
71
+ return ctx.db.options.timezone;
72
+ }
73
+ if (field.constructor.name === "DatetimeNoTzField") {
74
+ return "+00:00";
75
+ }
76
+ if (field.constructor.name === "DateOnlyField") {
77
+ return "+00:00";
78
+ }
79
+ return ctx.db.options.timezone;
80
+ }
81
+ __name(parseDateTimezone, "parseDateTimezone");
82
+ function isDatetimeString(str) {
83
+ return /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/.test(str);
84
+ }
85
+ __name(isDatetimeString, "isDatetimeString");
45
86
  var date_default = {
46
87
  $dateOn(value, ctx) {
47
88
  const r = (0, import_utils.parseDate)(value, {
48
- timezone: ctx.db.options.timezone
89
+ timezone: parseDateTimezone(ctx)
49
90
  });
50
91
  if (typeof r === "string") {
51
92
  return {
52
- [import_sequelize.Op.eq]: toDate(r)
93
+ [import_sequelize.Op.eq]: toDate(r, { ctx })
53
94
  };
54
95
  }
55
96
  if (Array.isArray(r)) {
56
97
  return {
57
- [import_sequelize.Op.and]: [{ [import_sequelize.Op.gte]: toDate(r[0]) }, { [import_sequelize.Op.lt]: toDate(r[1]) }]
98
+ [import_sequelize.Op.and]: [{ [import_sequelize.Op.gte]: toDate(r[0], { ctx }) }, { [import_sequelize.Op.lt]: toDate(r[1], { ctx }) }]
58
99
  };
59
100
  }
60
101
  throw new Error(`Invalid Date ${JSON.stringify(value)}`);
61
102
  },
62
103
  $dateNotOn(value, ctx) {
63
104
  const r = (0, import_utils.parseDate)(value, {
64
- timezone: ctx.db.options.timezone
105
+ timezone: parseDateTimezone(ctx)
65
106
  });
66
107
  if (typeof r === "string") {
67
108
  return {
68
- [import_sequelize.Op.ne]: toDate(r)
109
+ [import_sequelize.Op.ne]: toDate(r, { ctx })
69
110
  };
70
111
  }
71
112
  if (Array.isArray(r)) {
72
113
  return {
73
- [import_sequelize.Op.or]: [{ [import_sequelize.Op.lt]: toDate(r[0]) }, { [import_sequelize.Op.gte]: toDate(r[1]) }]
114
+ [import_sequelize.Op.or]: [{ [import_sequelize.Op.lt]: toDate(r[0], { ctx }) }, { [import_sequelize.Op.gte]: toDate(r[1], { ctx }) }]
74
115
  };
75
116
  }
76
117
  throw new Error(`Invalid Date ${JSON.stringify(value)}`);
77
118
  },
78
119
  $dateBefore(value, ctx) {
79
120
  const r = (0, import_utils.parseDate)(value, {
80
- timezone: ctx.db.options.timezone
121
+ timezone: parseDateTimezone(ctx)
81
122
  });
82
123
  if (typeof r === "string") {
83
124
  return {
84
- [import_sequelize.Op.lt]: toDate(r)
125
+ [import_sequelize.Op.lt]: toDate(r, { ctx })
85
126
  };
86
127
  } else if (Array.isArray(r)) {
87
128
  return {
88
- [import_sequelize.Op.lt]: toDate(r[0])
129
+ [import_sequelize.Op.lt]: toDate(r[0], { ctx })
89
130
  };
90
131
  }
91
132
  throw new Error(`Invalid Date ${JSON.stringify(value)}`);
92
133
  },
93
134
  $dateNotBefore(value, ctx) {
94
135
  const r = (0, import_utils.parseDate)(value, {
95
- timezone: ctx.db.options.timezone
136
+ timezone: parseDateTimezone(ctx)
96
137
  });
97
138
  if (typeof r === "string") {
98
139
  return {
99
- [import_sequelize.Op.gte]: toDate(r)
140
+ [import_sequelize.Op.gte]: toDate(r, { ctx })
100
141
  };
101
142
  } else if (Array.isArray(r)) {
102
143
  return {
103
- [import_sequelize.Op.gte]: toDate(r[0])
144
+ [import_sequelize.Op.gte]: toDate(r[0], { ctx })
104
145
  };
105
146
  }
106
147
  throw new Error(`Invalid Date ${JSON.stringify(value)}`);
107
148
  },
108
149
  $dateAfter(value, ctx) {
109
150
  const r = (0, import_utils.parseDate)(value, {
110
- timezone: ctx.db.options.timezone
151
+ timezone: parseDateTimezone(ctx)
111
152
  });
112
153
  if (typeof r === "string") {
113
154
  return {
114
- [import_sequelize.Op.gt]: toDate(r)
155
+ [import_sequelize.Op.gt]: toDate(r, { ctx })
115
156
  };
116
157
  } else if (Array.isArray(r)) {
117
158
  return {
118
- [import_sequelize.Op.gte]: toDate(r[1])
159
+ [import_sequelize.Op.gte]: toDate(r[1], { ctx })
119
160
  };
120
161
  }
121
162
  throw new Error(`Invalid Date ${JSON.stringify(value)}`);
122
163
  },
123
164
  $dateNotAfter(value, ctx) {
124
165
  const r = (0, import_utils.parseDate)(value, {
125
- timezone: ctx.db.options.timezone
166
+ timezone: parseDateTimezone(ctx)
126
167
  });
127
168
  if (typeof r === "string") {
128
169
  return {
129
- [import_sequelize.Op.lte]: toDate(r)
170
+ [import_sequelize.Op.lte]: toDate(r, { ctx })
130
171
  };
131
172
  } else if (Array.isArray(r)) {
132
173
  return {
133
- [import_sequelize.Op.lt]: toDate(r[1])
174
+ [import_sequelize.Op.lt]: toDate(r[1], { ctx })
134
175
  };
135
176
  }
136
177
  throw new Error(`Invalid Date ${JSON.stringify(value)}`);
137
178
  },
138
179
  $dateBetween(value, ctx) {
139
180
  const r = (0, import_utils.parseDate)(value, {
140
- timezone: ctx.db.options.timezone
181
+ timezone: parseDateTimezone(ctx)
141
182
  });
142
183
  if (r) {
143
184
  return {
144
- [import_sequelize.Op.and]: [{ [import_sequelize.Op.gte]: toDate(r[0]) }, { [import_sequelize.Op.lt]: toDate(r[1]) }]
185
+ [import_sequelize.Op.and]: [{ [import_sequelize.Op.gte]: toDate(r[0], { ctx }) }, { [import_sequelize.Op.lt]: toDate(r[1], { ctx }) }]
145
186
  };
146
187
  }
147
188
  throw new Error(`Invalid Date ${JSON.stringify(value)}`);
@@ -26,6 +26,7 @@ export declare class OptionsParser {
26
26
  static appendInheritInspectAttribute(include: any, collection: any): any;
27
27
  isAssociation(key: string): boolean;
28
28
  isAssociationPath(path: string): boolean;
29
+ filterByTkToWhereOption(): {};
29
30
  toSequelizeParams(): any;
30
31
  /**
31
32
  * parser sort options
@@ -90,17 +90,34 @@ const _OptionsParser = class _OptionsParser {
90
90
  isAssociationPath(path) {
91
91
  return this.isAssociation(path.split(".")[0]);
92
92
  }
93
+ filterByTkToWhereOption() {
94
+ var _a;
95
+ const filterByTkOption = (_a = this.options) == null ? void 0 : _a.filterByTk;
96
+ if (!filterByTkOption) {
97
+ return {};
98
+ }
99
+ if (import_lodash.default.isPlainObject(this.options.filterByTk)) {
100
+ const where = {};
101
+ for (const [key, value] of Object.entries(filterByTkOption)) {
102
+ where[key] = value;
103
+ }
104
+ return where;
105
+ }
106
+ const filterTargetKey = this.context.targetKey || this.collection.filterTargetKey;
107
+ if (Array.isArray(filterTargetKey)) {
108
+ throw new Error("multi filter target key value must be object");
109
+ }
110
+ return {
111
+ [filterTargetKey]: filterByTkOption
112
+ };
113
+ }
93
114
  toSequelizeParams() {
94
115
  var _a, _b;
95
116
  const queryParams = this.filterParser.toSequelizeParams();
96
117
  if ((_a = this.options) == null ? void 0 : _a.filterByTk) {
118
+ const filterByTkWhere = this.filterByTkToWhereOption();
97
119
  queryParams.where = {
98
- [import_sequelize.Op.and]: [
99
- queryParams.where,
100
- {
101
- [this.context.targetKey || this.collection.filterTargetKey]: this.options.filterByTk
102
- }
103
- ]
120
+ [import_sequelize.Op.and]: [queryParams.where, filterByTkWhere]
104
121
  };
105
122
  }
106
123
  if ((_b = this.options) == null ? void 0 : _b.include) {
@@ -123,7 +140,7 @@ const _OptionsParser = class _OptionsParser {
123
140
  sort = sort.split(",");
124
141
  }
125
142
  let defaultSortField = this.model.primaryKeyAttribute;
126
- if (!defaultSortField && this.collection.filterTargetKey) {
143
+ if (!defaultSortField && this.collection.filterTargetKey && !Array.isArray(this.collection.filterTargetKey)) {
127
144
  defaultSortField = this.collection.filterTargetKey;
128
145
  }
129
146
  if (defaultSortField && !((_b = this.options) == null ? void 0 : _b.group)) {
@@ -45,29 +45,26 @@ var import_relation_repository = require("./relation-repository");
45
45
  const _HasManyRepository = class _HasManyRepository extends import_multiple_relation_repository.MultipleRelationRepository {
46
46
  async find(options) {
47
47
  const targetRepository = this.targetCollection.repository;
48
- const addFilter = {
49
- [this.association.foreignKey]: this.sourceKeyValue
50
- };
51
- if (options == null ? void 0 : options.filterByTk) {
52
- addFilter[this.associationField.targetKey] = options.filterByTk;
48
+ const targetFilterOptions = await this.targetRepositoryFilterOptionsBySourceValue();
49
+ const findOptionsOmit = ["where", "values", "attributes"];
50
+ if ((options == null ? void 0 : options.filterByTk) && !this.isMultiTargetKey(options.filterByTk)) {
51
+ targetFilterOptions[this.associationField.targetKey] = options.filterByTk;
52
+ findOptionsOmit.push("filterByTk");
53
53
  }
54
54
  const findOptions = {
55
- ...(0, import_lodash.omit)(options, ["filterByTk", "where", "values", "attributes"]),
55
+ ...(0, import_lodash.omit)(options, findOptionsOmit),
56
56
  filter: {
57
- $and: [options.filter || {}, addFilter]
57
+ $and: [(options == null ? void 0 : options.filter) || {}, targetFilterOptions]
58
58
  }
59
59
  };
60
60
  return await targetRepository.find(findOptions);
61
61
  }
62
62
  async aggregate(options) {
63
63
  const targetRepository = this.targetCollection.repository;
64
- const addFilter = {
65
- [this.association.foreignKey]: this.sourceKeyValue
66
- };
67
64
  const aggOptions = {
68
65
  ...options,
69
66
  filter: {
70
- $and: [options.filter || {}, addFilter]
67
+ $and: [options.filter || {}, await this.targetRepositoryFilterOptionsBySourceValue()]
71
68
  }
72
69
  };
73
70
  return await targetRepository.aggregate(aggOptions);
@@ -14,6 +14,7 @@ export interface AssociatedOptions extends Transactionable {
14
14
  tk?: TK;
15
15
  }
16
16
  export declare abstract class MultipleRelationRepository extends RelationRepository {
17
+ targetRepositoryFilterOptionsBySourceValue(): Promise<any>;
17
18
  find(options?: FindOptions): Promise<any>;
18
19
  findAndCount(options?: FindAndCountOptions): Promise<[any[], number]>;
19
20
  count(options?: CountOptions): Promise<number>;
@@ -55,6 +55,16 @@ var import_update_associations = require("../update-associations");
55
55
  var import_update_guard = require("../update-guard");
56
56
  var import_relation_repository = require("./relation-repository");
57
57
  const _MultipleRelationRepository = class _MultipleRelationRepository extends import_relation_repository.RelationRepository {
58
+ async targetRepositoryFilterOptionsBySourceValue() {
59
+ let filterForeignKeyValue = this.sourceKeyValue;
60
+ if (this.isMultiTargetKey()) {
61
+ const sourceModel = await this.getSourceModel();
62
+ filterForeignKeyValue = sourceModel.get(this.association.sourceKey);
63
+ }
64
+ return {
65
+ [this.association.foreignKey]: filterForeignKeyValue
66
+ };
67
+ }
58
68
  async find(options) {
59
69
  const targetRepository = this.targetCollection.repository;
60
70
  const association = this.association;
@@ -68,9 +78,7 @@ const _MultipleRelationRepository = class _MultipleRelationRepository extends im
68
78
  const appendFilter = {
69
79
  isPivotFilter: true,
70
80
  association: pivotAssoc,
71
- where: {
72
- [association.foreignKey]: this.sourceKeyValue
73
- }
81
+ where: await this.targetRepositoryFilterOptionsBySourceValue()
74
82
  };
75
83
  return targetRepository.find({
76
84
  include: [appendFilter],
@@ -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 } from '../repository';
14
+ import { CreateOptions, Filter, FindOptions, TargetKey } from '../repository';
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;
@@ -20,11 +20,14 @@ export declare abstract class RelationRepository {
20
20
  targetCollection: Collection;
21
21
  associationName: string;
22
22
  associationField: RelationField;
23
- sourceKeyValue: string | number;
23
+ sourceKeyValue: TargetKey;
24
24
  sourceInstance: Model;
25
25
  db: Database;
26
26
  database: Database;
27
- constructor(sourceCollection: Collection, association: string, sourceKeyValue: string | number);
27
+ constructor(sourceCollection: Collection, association: string, sourceKeyValue: TargetKey);
28
+ decodeMultiTargetKey(str: string): any;
29
+ setSourceKeyValue(sourceKeyValue: TargetKey): void;
30
+ isMultiTargetKey(value?: any): boolean;
28
31
  get collection(): Collection<any, any>;
29
32
  abstract find(options?: FindOptions): Promise<any>;
30
33
  chunk(options: FindOptions & {
@@ -73,13 +73,27 @@ const _RelationRepository = class _RelationRepository {
73
73
  this.db = sourceCollection.context.database;
74
74
  this.database = this.db;
75
75
  this.sourceCollection = sourceCollection;
76
- this.sourceKeyValue = sourceKeyValue;
76
+ this.setSourceKeyValue(sourceKeyValue);
77
77
  this.associationName = association;
78
78
  this.association = this.sourceCollection.model.associations[association];
79
79
  this.associationField = this.sourceCollection.getField(association);
80
80
  this.targetModel = this.association.target;
81
81
  this.targetCollection = this.sourceCollection.context.database.modelCollection.get(this.targetModel);
82
82
  }
83
+ decodeMultiTargetKey(str) {
84
+ try {
85
+ const decoded = decodeURIComponent(str);
86
+ return JSON.parse(decoded);
87
+ } catch (e) {
88
+ return false;
89
+ }
90
+ }
91
+ setSourceKeyValue(sourceKeyValue) {
92
+ this.sourceKeyValue = typeof sourceKeyValue === "string" ? this.decodeMultiTargetKey(sourceKeyValue) || sourceKeyValue : sourceKeyValue;
93
+ }
94
+ isMultiTargetKey(value) {
95
+ return import_lodash.default.isPlainObject(value || this.sourceKeyValue);
96
+ }
83
97
  get collection() {
84
98
  return this.db.getCollection(this.targetModel.name);
85
99
  }
@@ -147,7 +161,13 @@ const _RelationRepository = class _RelationRepository {
147
161
  }
148
162
  async getSourceModel(transaction2) {
149
163
  if (!this.sourceInstance) {
150
- this.sourceInstance = await this.sourceCollection.model.findOne({
164
+ this.sourceInstance = this.isMultiTargetKey() ? await this.sourceCollection.repository.findOne({
165
+ filter: {
166
+ // @ts-ignore
167
+ ...this.sourceKeyValue
168
+ },
169
+ transaction: transaction2
170
+ }) : await this.sourceCollection.model.findOne({
151
171
  where: {
152
172
  [this.associationField.sourceKey]: this.sourceKeyValue
153
173
  },
@@ -26,7 +26,9 @@ export { Transactionable } from 'sequelize';
26
26
  export interface FilterAble {
27
27
  filter: Filter;
28
28
  }
29
- export type TargetKey = string | number;
29
+ export type BaseTargetKey = string | number;
30
+ export type MultiTargetKey = Record<string, BaseTargetKey>;
31
+ export type TargetKey = BaseTargetKey | MultiTargetKey;
30
32
  export type TK = TargetKey | TargetKey[];
31
33
  type FieldValue = string | number | bigint | boolean | Date | Buffer | null | FieldValue[] | FilterWithOperator;
32
34
  type Operators = keyof typeof operators & keyof WhereOperators;
@@ -116,7 +118,7 @@ declare class RelationRepositoryBuilder<R extends RelationRepository> {
116
118
  BelongsToArray: typeof BelongsToArrayRepository;
117
119
  };
118
120
  constructor(collection: Collection, associationName: string);
119
- of(id: string | number): R;
121
+ of(id: TargetKey): R;
120
122
  protected builder(): {
121
123
  HasOne: typeof HasOneRepository;
122
124
  BelongsTo: typeof BelongsToRepository;
@@ -171,6 +173,7 @@ export declare class Repository<TModelAttributes extends {} = any, TCreationAttr
171
173
  *
172
174
  */
173
175
  findById(id: string | number): Promise<Model<any, any>>;
176
+ findByTargetKey(targetKey: TargetKey): Promise<any>;
174
177
  /**
175
178
  * Find one record from database
176
179
  *
package/lib/repository.js CHANGED
@@ -175,13 +175,11 @@ const _Repository = class _Repository {
175
175
  };
176
176
  }
177
177
  if (countOptions == null ? void 0 : countOptions.filterByTk) {
178
+ const optionParser = new import_options_parser.OptionsParser(options, {
179
+ collection: this.collection
180
+ });
178
181
  options["where"] = {
179
- [import_sequelize.Op.and]: [
180
- options["where"] || {},
181
- {
182
- [this.collection.filterTargetKey]: options.filterByTk
183
- }
184
- ]
182
+ [import_sequelize.Op.and]: [options["where"] || {}, optionParser.filterByTkToWhereOption()]
185
183
  };
186
184
  }
187
185
  const queryOptions = {
@@ -191,11 +189,10 @@ const _Repository = class _Repository {
191
189
  if (((_a = queryOptions.include) == null ? void 0 : _a.length) === 0) {
192
190
  delete queryOptions.include;
193
191
  }
194
- const count = await this.collection.model.count({
192
+ return await this.collection.model.count({
195
193
  ...queryOptions,
196
194
  transaction: transaction2
197
195
  });
198
- return count;
199
196
  }
200
197
  async aggregate(options) {
201
198
  var _a;
@@ -325,6 +322,9 @@ const _Repository = class _Repository {
325
322
  findById(id) {
326
323
  return this.collection.model.findByPk(id);
327
324
  }
325
+ findByTargetKey(targetKey) {
326
+ return this.findOne({ filterByTk: targetKey });
327
+ }
328
328
  /**
329
329
  * Find one record from database
330
330
  *
@@ -374,7 +374,7 @@ const _Repository = class _Repository {
374
374
  action: "create",
375
375
  underscored: this.collection.options.underscored
376
376
  });
377
- const values = guard.sanitize(options.values || {});
377
+ const values = this.model.callSetters(guard.sanitize(options.values || {}), options);
378
378
  const instance = await this.model.create(values, {
379
379
  ...options,
380
380
  transaction: transaction2
@@ -418,7 +418,7 @@ const _Repository = class _Repository {
418
418
  }
419
419
  const transaction2 = await this.getTransaction(options);
420
420
  const guard = import_update_guard.UpdateGuard.fromOptions(this.model, { ...options, underscored: this.collection.options.underscored });
421
- const values = guard.sanitize(options.values);
421
+ const values = this.model.callSetters(guard.sanitize(options.values || {}), options);
422
422
  if (options.individualHooks === false) {
423
423
  const { model: Model2 } = this.collection;
424
424
  const primaryKeyField = Model2.primaryKeyField || Model2.primaryKeyAttribute;
@@ -501,15 +501,26 @@ const _Repository = class _Repository {
501
501
  }
502
502
  }
503
503
  if (filterByTk && !options.filter) {
504
- return await this.model.destroy({
504
+ const where = [];
505
+ for (const tk of filterByTk) {
506
+ const optionParser = new import_options_parser.OptionsParser(
507
+ {
508
+ filterByTk: tk
509
+ },
510
+ {
511
+ collection: this.collection
512
+ }
513
+ );
514
+ where.push(optionParser.filterByTkToWhereOption());
515
+ }
516
+ const destroyOptions = {
505
517
  ...options,
506
518
  where: {
507
- [modelFilterKey]: {
508
- [import_sequelize.Op.in]: filterByTk
509
- }
519
+ [import_sequelize.Op.or]: where
510
520
  },
511
521
  transaction: transaction2
512
- });
522
+ };
523
+ return await this.model.destroy(destroyOptions);
513
524
  }
514
525
  if (options.filter && (0, import_utils.isValidFilter)(options.filter)) {
515
526
  if (this.collection.model.primaryKeyAttributes.length !== 1 && !import_lodash.default.get(this.collection.options, "filterTargetKey")) {