@nocobase/database 1.9.0-beta.1 → 1.9.0-beta.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/collection.d.ts +7 -0
- package/lib/collection.js +67 -0
- package/lib/cursor-builder.js +4 -3
- package/lib/database.d.ts +2 -1
- package/lib/database.js +31 -3
- package/lib/dialects/mysql-dialect.d.ts +2 -1
- package/lib/dialects/mysql-dialect.js +5 -2
- package/lib/eager-loading/eager-loading-tree.js +2 -20
- package/lib/fields/field.d.ts +25 -2
- package/lib/fields/index.d.ts +3 -1
- package/lib/fields/index.js +3 -1
- package/lib/fields/number-field.d.ts +1 -1
- package/lib/fields/snowflake-id-field.d.ts +29 -0
- package/lib/fields/snowflake-id-field.js +79 -0
- package/lib/fields/string-field.d.ts +1 -1
- package/lib/index.d.ts +2 -0
- package/lib/index.js +8 -0
- package/lib/inherited-sync-runner.js +5 -0
- package/lib/interfaces/number-interface.d.ts +1 -0
- package/lib/interfaces/number-interface.js +28 -0
- package/lib/magic-attribute-model.js +3 -0
- package/lib/operators/empty.d.ts +1 -4
- package/lib/operators/index.d.ts +1 -2
- package/lib/options-parser.js +1 -1
- package/lib/query-interface/postgres-query-interface.d.ts +3 -1
- package/lib/query-interface/postgres-query-interface.js +9 -2
- package/lib/query-interface/query-interface.d.ts +3 -1
- package/lib/relation-repository/belongs-to-many-repository.js +5 -0
- package/lib/relation-repository/relation-repository.js +1 -0
- package/lib/repository.d.ts +3 -0
- package/lib/repository.js +87 -2
- package/lib/update-associations.js +25 -0
- package/lib/utils/field-validation.d.ts +59 -0
- package/lib/utils/field-validation.js +143 -0
- package/lib/utils/filter-include.d.ts +55 -0
- package/lib/utils/filter-include.js +118 -0
- package/lib/utils.d.ts +1 -0
- package/lib/utils.js +22 -0
- package/lib/view/view-inference.js +1 -0
- package/package.json +5 -4
package/lib/collection.d.ts
CHANGED
|
@@ -88,6 +88,13 @@ export declare class Collection<TModelAttributes extends {} = any, TCreationAttr
|
|
|
88
88
|
get db(): Database;
|
|
89
89
|
get treeParentField(): BelongsToField | null;
|
|
90
90
|
get treeChildrenField(): HasManyField | null;
|
|
91
|
+
validate(options: {
|
|
92
|
+
values: Record<string, any> | Record<string, any>[];
|
|
93
|
+
operation: 'create' | 'update';
|
|
94
|
+
context: {
|
|
95
|
+
t: Function;
|
|
96
|
+
};
|
|
97
|
+
}): void;
|
|
91
98
|
isMultiFilterTargetKey(): boolean;
|
|
92
99
|
tableName(): any;
|
|
93
100
|
/**
|
package/lib/collection.js
CHANGED
|
@@ -53,9 +53,11 @@ var import_events = require("events");
|
|
|
53
53
|
var import_lodash = __toESM(require("lodash"));
|
|
54
54
|
var import_safe_json_stringify = __toESM(require("safe-json-stringify"));
|
|
55
55
|
var import_sequelize = require("sequelize");
|
|
56
|
+
var import_fields = require("./fields");
|
|
56
57
|
var import_model = require("./model");
|
|
57
58
|
var import_repository = require("./repository");
|
|
58
59
|
var import_utils = require("./utils");
|
|
60
|
+
var import_field_validation = require("./utils/field-validation");
|
|
59
61
|
function EnsureAtomicity(target, propertyKey, descriptor) {
|
|
60
62
|
const originalMethod = descriptor.value;
|
|
61
63
|
descriptor.value = function(...args) {
|
|
@@ -152,6 +154,71 @@ const _Collection = class _Collection extends import_events.EventEmitter {
|
|
|
152
154
|
}
|
|
153
155
|
}
|
|
154
156
|
}
|
|
157
|
+
validate(options) {
|
|
158
|
+
const { values: updateValues, context, operation } = options;
|
|
159
|
+
if (!updateValues) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
const values = Array.isArray(updateValues) ? updateValues : [updateValues];
|
|
163
|
+
const { t } = context || { t: /* @__PURE__ */ __name((key, options2) => key, "t") };
|
|
164
|
+
const unwrapTplLabel = /* @__PURE__ */ __name((label) => {
|
|
165
|
+
if (typeof label !== "string") return label;
|
|
166
|
+
const m = label.match(/^[\s\t]*\{\{\s*t\(\s*(['"])(.*?)\1(?:\s*,[\s\S]*)?\)\s*\}\}[\s\t]*$/);
|
|
167
|
+
return m ? m[2] : label;
|
|
168
|
+
}, "unwrapTplLabel");
|
|
169
|
+
const helper = /* @__PURE__ */ __name((field, value) => {
|
|
170
|
+
var _a, _b, _c;
|
|
171
|
+
const val = value[field.name];
|
|
172
|
+
if (!field.options.validation) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
const fieldLabel = unwrapTplLabel(((_a = field.options.uiSchema) == null ? void 0 : _a.title) || field.name);
|
|
176
|
+
if (field instanceof import_fields.RelationField) {
|
|
177
|
+
if ((_b = field.options) == null ? void 0 : _b.validation.rules) {
|
|
178
|
+
const isRequired = (_c = field.options) == null ? void 0 : _c.validation.rules.some((rule) => rule.name === "required");
|
|
179
|
+
if (isRequired && !val) {
|
|
180
|
+
throw new Error(
|
|
181
|
+
t("{{#label}} is required", {
|
|
182
|
+
ns: "client",
|
|
183
|
+
"#label": `${t("Collection", { ns: "client" })}: ${this.name}, ${t("Field", { ns: "client" })}: ${t(
|
|
184
|
+
fieldLabel,
|
|
185
|
+
{ ns: "client" }
|
|
186
|
+
)}`
|
|
187
|
+
})
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
const joiSchema = (0, import_field_validation.buildJoiSchema)(field.options.validation, {
|
|
194
|
+
label: `${t("Collection", { ns: "client" })}: ${this.name}, ${t("Field", { ns: "client" })}: ${t(fieldLabel, {
|
|
195
|
+
ns: "client"
|
|
196
|
+
})}`,
|
|
197
|
+
value: val
|
|
198
|
+
});
|
|
199
|
+
const { error } = joiSchema.validate(val, {
|
|
200
|
+
messages: (0, import_field_validation.getJoiErrorMessage)(t)
|
|
201
|
+
});
|
|
202
|
+
if (error) {
|
|
203
|
+
throw error;
|
|
204
|
+
}
|
|
205
|
+
}, "helper");
|
|
206
|
+
for (const value of values) {
|
|
207
|
+
if (operation === "create") {
|
|
208
|
+
for (const [, field] of this.fields) {
|
|
209
|
+
helper(field, value);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
if (operation === "update") {
|
|
213
|
+
for (const key of Object.keys(value)) {
|
|
214
|
+
const field = this.getField(key);
|
|
215
|
+
if (field) {
|
|
216
|
+
helper(field, value);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
155
222
|
isMultiFilterTargetKey() {
|
|
156
223
|
return Array.isArray(this.filterTargetKey) && this.filterTargetKey.length > 1;
|
|
157
224
|
}
|
package/lib/cursor-builder.js
CHANGED
|
@@ -87,7 +87,7 @@ const _SmartCursorBuilder = class _SmartCursorBuilder {
|
|
|
87
87
|
AND a.attnum = ANY(ix.indkey)
|
|
88
88
|
AND t.relkind = 'r'
|
|
89
89
|
AND n.nspname = current_schema()
|
|
90
|
-
AND t.relname =
|
|
90
|
+
AND t.relname = ?
|
|
91
91
|
ORDER BY
|
|
92
92
|
i.relname,
|
|
93
93
|
array_position(ix.indkey, a.attnum)
|
|
@@ -145,8 +145,9 @@ const _SmartCursorBuilder = class _SmartCursorBuilder {
|
|
|
145
145
|
isUnique: indexType < 3
|
|
146
146
|
});
|
|
147
147
|
}
|
|
148
|
-
const
|
|
149
|
-
index
|
|
148
|
+
const seqInIndex = dialect === "postgres" ? row.seq_in_index : row.SEQ_IN_INDEX;
|
|
149
|
+
const index = indexes.get(indexName);
|
|
150
|
+
index.columns[seqInIndex - 1] = columnName;
|
|
150
151
|
}
|
|
151
152
|
for (const index of indexes.values()) {
|
|
152
153
|
if (index.isPrimary) {
|
package/lib/database.d.ts
CHANGED
|
@@ -118,7 +118,7 @@ export declare class Database extends EventEmitter implements AsyncEmitter {
|
|
|
118
118
|
/**
|
|
119
119
|
* @internal
|
|
120
120
|
*/
|
|
121
|
-
sequelizeOptions(options:
|
|
121
|
+
sequelizeOptions(options: DatabaseOptions): IDatabaseOptions;
|
|
122
122
|
/**
|
|
123
123
|
* @internal
|
|
124
124
|
*/
|
|
@@ -128,6 +128,7 @@ export declare class Database extends EventEmitter implements AsyncEmitter {
|
|
|
128
128
|
inDialect(...dialect: string[]): boolean;
|
|
129
129
|
isMySQLCompatibleDialect(): boolean;
|
|
130
130
|
isPostgresCompatibleDialect(): boolean;
|
|
131
|
+
wrapSequelizeRunForMySQL(): void;
|
|
131
132
|
/**
|
|
132
133
|
* Add collection to database
|
|
133
134
|
* @param options
|
package/lib/database.js
CHANGED
|
@@ -176,6 +176,9 @@ const _Database = class _Database extends import_events.EventEmitter {
|
|
|
176
176
|
);
|
|
177
177
|
const sequelizeOptions = this.sequelizeOptions(this.options);
|
|
178
178
|
this.sequelize = new import_sequelize.Sequelize(sequelizeOptions);
|
|
179
|
+
if (options.dialect === "mysql") {
|
|
180
|
+
this.wrapSequelizeRunForMySQL();
|
|
181
|
+
}
|
|
179
182
|
this.queryInterface = (0, import_query_interface_builder.default)(this);
|
|
180
183
|
this.collections = /* @__PURE__ */ new Map();
|
|
181
184
|
this.modelHook = new import_model_hook.ModelHook(this);
|
|
@@ -397,6 +400,30 @@ const _Database = class _Database extends import_events.EventEmitter {
|
|
|
397
400
|
isPostgresCompatibleDialect() {
|
|
398
401
|
return this.inDialect("postgres");
|
|
399
402
|
}
|
|
403
|
+
/*
|
|
404
|
+
* https://github.com/sidorares/node-mysql2/issues/1239#issuecomment-766867699
|
|
405
|
+
* https://github.com/sidorares/node-mysql2/pull/1407#issuecomment-1325789581
|
|
406
|
+
* > I'm starting to think simple "always send (parameter.toString()) as VAR_STRING" unless the type is explicitly specified by user" might be actually the best behaviour
|
|
407
|
+
*/
|
|
408
|
+
wrapSequelizeRunForMySQL() {
|
|
409
|
+
const that = this;
|
|
410
|
+
const run = this.sequelize.dialect.Query.prototype.run;
|
|
411
|
+
this.sequelize.dialect.Query.prototype.run = function(sql, parameters) {
|
|
412
|
+
if (!/^update\s+/i.test(sql.trim()) || !(parameters == null ? void 0 : parameters.length)) {
|
|
413
|
+
return run.apply(this, [sql, parameters]);
|
|
414
|
+
}
|
|
415
|
+
try {
|
|
416
|
+
parameters.forEach((p, index) => {
|
|
417
|
+
if (typeof p === "number") {
|
|
418
|
+
parameters[index] = p.toString();
|
|
419
|
+
}
|
|
420
|
+
});
|
|
421
|
+
} catch (err) {
|
|
422
|
+
that.logger.error(err);
|
|
423
|
+
}
|
|
424
|
+
return run.apply(this, [sql, parameters]);
|
|
425
|
+
};
|
|
426
|
+
}
|
|
400
427
|
/**
|
|
401
428
|
* Add collection to database
|
|
402
429
|
* @param options
|
|
@@ -611,8 +638,8 @@ const _Database = class _Database extends import_events.EventEmitter {
|
|
|
611
638
|
}
|
|
612
639
|
/* istanbul ignore next -- @preserve */
|
|
613
640
|
async auth(options = {}) {
|
|
614
|
-
const { retry =
|
|
615
|
-
const startingDelay =
|
|
641
|
+
const { retry = 10, ...others } = options;
|
|
642
|
+
const startingDelay = 1e3;
|
|
616
643
|
const timeMultiple = 2;
|
|
617
644
|
let attemptNumber = 1;
|
|
618
645
|
const authenticate = /* @__PURE__ */ __name(async () => {
|
|
@@ -635,7 +662,8 @@ const _Database = class _Database extends import_events.EventEmitter {
|
|
|
635
662
|
await (0, import_exponential_backoff.backOff)(authenticate, {
|
|
636
663
|
numOfAttempts: retry,
|
|
637
664
|
startingDelay,
|
|
638
|
-
timeMultiple
|
|
665
|
+
timeMultiple,
|
|
666
|
+
maxDelay: 30 * 1e3
|
|
639
667
|
});
|
|
640
668
|
} catch (error) {
|
|
641
669
|
throw new Error(`Unable to connect to the database`, { cause: error });
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
9
|
import { BaseDialect } from './base-dialect';
|
|
10
|
+
import { DatabaseOptions } from '../database';
|
|
10
11
|
export declare class MysqlDialect extends BaseDialect {
|
|
11
12
|
static dialectName: string;
|
|
12
13
|
getVersionGuard(): {
|
|
@@ -14,5 +15,5 @@ export declare class MysqlDialect extends BaseDialect {
|
|
|
14
15
|
get: (v: string) => string;
|
|
15
16
|
version: string;
|
|
16
17
|
};
|
|
17
|
-
getSequelizeOptions(options:
|
|
18
|
+
getSequelizeOptions(options: DatabaseOptions): import("../database").IDatabaseOptions;
|
|
18
19
|
}
|
|
@@ -32,7 +32,6 @@ __export(mysql_dialect_exports, {
|
|
|
32
32
|
MysqlDialect: () => MysqlDialect
|
|
33
33
|
});
|
|
34
34
|
module.exports = __toCommonJS(mysql_dialect_exports);
|
|
35
|
-
var import_utils = require("@nocobase/utils");
|
|
36
35
|
var import_base_dialect = require("./base-dialect");
|
|
37
36
|
const _MysqlDialect = class _MysqlDialect extends import_base_dialect.BaseDialect {
|
|
38
37
|
getVersionGuard() {
|
|
@@ -46,7 +45,11 @@ const _MysqlDialect = class _MysqlDialect extends import_base_dialect.BaseDialec
|
|
|
46
45
|
};
|
|
47
46
|
}
|
|
48
47
|
getSequelizeOptions(options) {
|
|
49
|
-
|
|
48
|
+
const dialectOptions = {
|
|
49
|
+
...options.dialectOptions || {},
|
|
50
|
+
multipleStatements: true
|
|
51
|
+
};
|
|
52
|
+
options.dialectOptions = dialectOptions;
|
|
50
53
|
return options;
|
|
51
54
|
}
|
|
52
55
|
};
|
|
@@ -44,6 +44,7 @@ var import_lodash = __toESM(require("lodash"));
|
|
|
44
44
|
var import_sequelize = require("sequelize");
|
|
45
45
|
var import_append_child_collection_name_after_repository_find = require("../listeners/append-child-collection-name-after-repository-find");
|
|
46
46
|
var import_options_parser = require("../options-parser");
|
|
47
|
+
var import_utils = require("../utils");
|
|
47
48
|
const pushAttribute = /* @__PURE__ */ __name((node, attribute) => {
|
|
48
49
|
if (import_lodash.default.isArray(node.attributes) && !node.attributes.includes(attribute)) {
|
|
49
50
|
node.attributes.push(attribute);
|
|
@@ -85,25 +86,6 @@ const queryParentSQL = /* @__PURE__ */ __name((options) => {
|
|
|
85
86
|
)
|
|
86
87
|
SELECT ${q(targetKeyField)} AS ${q(targetKey)}, ${q(foreignKeyField)} AS ${q(foreignKey)} FROM cte`;
|
|
87
88
|
}, "queryParentSQL");
|
|
88
|
-
const processIncludes = /* @__PURE__ */ __name((includes, model, parentAs = "") => {
|
|
89
|
-
includes.forEach((include, index) => {
|
|
90
|
-
const association = model.associations[include.association];
|
|
91
|
-
if (association == null ? void 0 : association.generateInclude) {
|
|
92
|
-
includes[index] = {
|
|
93
|
-
...include,
|
|
94
|
-
...association.generateInclude(parentAs)
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
if (include.include && Array.isArray(include.include) && include.include.length > 0) {
|
|
98
|
-
const nextModel = association == null ? void 0 : association.target;
|
|
99
|
-
if (!nextModel) {
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
processIncludes(include.include, nextModel, parentAs ? `${parentAs}->${association.as}` : association.as);
|
|
103
|
-
}
|
|
104
|
-
});
|
|
105
|
-
return includes;
|
|
106
|
-
}, "processIncludes");
|
|
107
89
|
const _EagerLoadingTree = class _EagerLoadingTree {
|
|
108
90
|
root;
|
|
109
91
|
db;
|
|
@@ -233,7 +215,7 @@ const _EagerLoadingTree = class _EagerLoadingTree {
|
|
|
233
215
|
attributes: [primaryKeyField],
|
|
234
216
|
group: `${node.model.name}.${primaryKeyField}`,
|
|
235
217
|
transaction,
|
|
236
|
-
include: processIncludes(includeForFilter, node.model)
|
|
218
|
+
include: (0, import_utils.processIncludes)(includeForFilter, node.model)
|
|
237
219
|
})).map((row) => {
|
|
238
220
|
return { row, pk: row[primaryKeyField] };
|
|
239
221
|
});
|
package/lib/fields/field.d.ts
CHANGED
|
@@ -10,17 +10,39 @@ import { DataType, ModelAttributeColumnOptions, ModelIndexesOptions, SyncOptions
|
|
|
10
10
|
import { Collection } from '../collection';
|
|
11
11
|
import { Database } from '../database';
|
|
12
12
|
import { ModelEventTypes } from '../types';
|
|
13
|
+
import { BasicType, BooleanSchema, NumberSchema, ObjectSchema, StringSchema } from 'joi';
|
|
13
14
|
export interface FieldContext {
|
|
14
15
|
database: Database;
|
|
15
16
|
collection: Collection;
|
|
16
17
|
}
|
|
17
|
-
|
|
18
|
+
type RuleSchemaMap = {
|
|
19
|
+
string: StringSchema;
|
|
20
|
+
boolean: BooleanSchema;
|
|
21
|
+
number: NumberSchema;
|
|
22
|
+
object: ObjectSchema;
|
|
23
|
+
};
|
|
24
|
+
export type FieldValidationRuleName<T extends BasicType> = T extends keyof RuleSchemaMap ? keyof RuleSchemaMap[T] : never;
|
|
25
|
+
export interface FieldValidationRule<T extends BasicType> {
|
|
26
|
+
key: string;
|
|
27
|
+
name: FieldValidationRuleName<T>;
|
|
28
|
+
args?: {
|
|
29
|
+
[key: string]: any;
|
|
30
|
+
};
|
|
31
|
+
paramsType?: 'object';
|
|
32
|
+
}
|
|
33
|
+
export interface ValidationOptions<T extends BasicType = BasicType> {
|
|
34
|
+
type: T;
|
|
35
|
+
rules: FieldValidationRule<T>[];
|
|
36
|
+
[key: string]: any;
|
|
37
|
+
}
|
|
38
|
+
export interface BaseFieldOptions<T extends BasicType = BasicType> {
|
|
18
39
|
name?: string;
|
|
19
40
|
hidden?: boolean;
|
|
20
41
|
translation?: boolean;
|
|
42
|
+
validation?: ValidationOptions<T>;
|
|
21
43
|
[key: string]: any;
|
|
22
44
|
}
|
|
23
|
-
export interface BaseColumnFieldOptions extends BaseFieldOptions
|
|
45
|
+
export interface BaseColumnFieldOptions<T extends BasicType = BasicType> extends BaseFieldOptions<T>, Omit<ModelAttributeColumnOptions, 'type'> {
|
|
24
46
|
dataType?: DataType;
|
|
25
47
|
index?: boolean | ModelIndexesOptions;
|
|
26
48
|
}
|
|
@@ -50,3 +72,4 @@ export declare abstract class Field {
|
|
|
50
72
|
additionalSequelizeOptions(): {};
|
|
51
73
|
typeToString(): any;
|
|
52
74
|
}
|
|
75
|
+
export {};
|
package/lib/fields/index.d.ts
CHANGED
|
@@ -32,6 +32,7 @@ import { UnixTimestampFieldOptions } from './unix-timestamp-field';
|
|
|
32
32
|
import { DateOnlyFieldOptions } from './date-only-field';
|
|
33
33
|
import { DatetimeNoTzFieldOptions } from './datetime-no-tz-field';
|
|
34
34
|
import { DatetimeTzFieldOptions } from './datetime-tz-field';
|
|
35
|
+
import { SnowflakeIdFieldOptions } from './snowflake-id-field';
|
|
35
36
|
export * from './array-field';
|
|
36
37
|
export * from './belongs-to-field';
|
|
37
38
|
export * from './belongs-to-many-field';
|
|
@@ -60,4 +61,5 @@ export * from './virtual-field';
|
|
|
60
61
|
export * from './nanoid-field';
|
|
61
62
|
export * from './encryption-field';
|
|
62
63
|
export * from './unix-timestamp-field';
|
|
63
|
-
export
|
|
64
|
+
export * from './snowflake-id-field';
|
|
65
|
+
export type FieldOptions = BaseFieldOptions | StringFieldOptions | IntegerFieldOptions | FloatFieldOptions | DecimalFieldOptions | DoubleFieldOptions | RealFieldOptions | JsonFieldOptions | JsonbFieldOptions | BooleanFieldOptions | RadioFieldOptions | TextFieldOptions | VirtualFieldOptions | ArrayFieldOptions | SetFieldOptions | TimeFieldOptions | DateFieldOptions | DatetimeTzFieldOptions | DatetimeNoTzFieldOptions | DateOnlyFieldOptions | UnixTimestampFieldOptions | UidFieldOptions | UUIDFieldOptions | NanoidFieldOptions | PasswordFieldOptions | ContextFieldOptions | BelongsToFieldOptions | HasOneFieldOptions | HasManyFieldOptions | BelongsToManyFieldOptions | EncryptionField | SnowflakeIdFieldOptions;
|
package/lib/fields/index.js
CHANGED
|
@@ -51,6 +51,7 @@ __reExport(fields_exports, require("./virtual-field"), module.exports);
|
|
|
51
51
|
__reExport(fields_exports, require("./nanoid-field"), module.exports);
|
|
52
52
|
__reExport(fields_exports, require("./encryption-field"), module.exports);
|
|
53
53
|
__reExport(fields_exports, require("./unix-timestamp-field"), module.exports);
|
|
54
|
+
__reExport(fields_exports, require("./snowflake-id-field"), module.exports);
|
|
54
55
|
// Annotate the CommonJS export names for ESM import in node:
|
|
55
56
|
0 && (module.exports = {
|
|
56
57
|
...require("./array-field"),
|
|
@@ -80,5 +81,6 @@ __reExport(fields_exports, require("./unix-timestamp-field"), module.exports);
|
|
|
80
81
|
...require("./virtual-field"),
|
|
81
82
|
...require("./nanoid-field"),
|
|
82
83
|
...require("./encryption-field"),
|
|
83
|
-
...require("./unix-timestamp-field")
|
|
84
|
+
...require("./unix-timestamp-field"),
|
|
85
|
+
...require("./snowflake-id-field")
|
|
84
86
|
});
|
|
@@ -13,7 +13,7 @@ export declare abstract class NumberField extends Field {
|
|
|
13
13
|
export declare class IntegerField extends NumberField {
|
|
14
14
|
get dataType(): DataTypes.IntegerDataTypeConstructor;
|
|
15
15
|
}
|
|
16
|
-
export interface IntegerFieldOptions extends BaseColumnFieldOptions {
|
|
16
|
+
export interface IntegerFieldOptions extends BaseColumnFieldOptions<'number'> {
|
|
17
17
|
type: 'integer';
|
|
18
18
|
}
|
|
19
19
|
export declare class BigIntField extends NumberField {
|
|
@@ -0,0 +1,29 @@
|
|
|
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 { BaseColumnFieldOptions, Field } from './field';
|
|
11
|
+
interface Application {
|
|
12
|
+
snowflakeIdGenerator: {
|
|
13
|
+
generate(): number | BigInt;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export declare class SnowflakeIdField extends Field {
|
|
17
|
+
private static app;
|
|
18
|
+
static setApp(app: Application): void;
|
|
19
|
+
get dataType(): DataTypes.BigIntDataTypeConstructor;
|
|
20
|
+
private setId;
|
|
21
|
+
init(): void;
|
|
22
|
+
bind(): void;
|
|
23
|
+
unbind(): void;
|
|
24
|
+
}
|
|
25
|
+
export interface SnowflakeIdFieldOptions extends BaseColumnFieldOptions {
|
|
26
|
+
type: 'snowflakeId';
|
|
27
|
+
epoch?: number;
|
|
28
|
+
}
|
|
29
|
+
export {};
|
|
@@ -0,0 +1,79 @@
|
|
|
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 __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
15
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
16
|
+
var __export = (target, all) => {
|
|
17
|
+
for (var name in all)
|
|
18
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
19
|
+
};
|
|
20
|
+
var __copyProps = (to, from, except, desc) => {
|
|
21
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
22
|
+
for (let key of __getOwnPropNames(from))
|
|
23
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
24
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
25
|
+
}
|
|
26
|
+
return to;
|
|
27
|
+
};
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
30
|
+
var snowflake_id_field_exports = {};
|
|
31
|
+
__export(snowflake_id_field_exports, {
|
|
32
|
+
SnowflakeIdField: () => SnowflakeIdField
|
|
33
|
+
});
|
|
34
|
+
module.exports = __toCommonJS(snowflake_id_field_exports);
|
|
35
|
+
var import_sequelize = require("sequelize");
|
|
36
|
+
var import_field = require("./field");
|
|
37
|
+
const _SnowflakeIdField = class _SnowflakeIdField extends import_field.Field {
|
|
38
|
+
static setApp(app) {
|
|
39
|
+
this.app = app;
|
|
40
|
+
}
|
|
41
|
+
get dataType() {
|
|
42
|
+
return import_sequelize.DataTypes.BIGINT;
|
|
43
|
+
}
|
|
44
|
+
setId(name, instance) {
|
|
45
|
+
const value = instance.get(name);
|
|
46
|
+
if (!value) {
|
|
47
|
+
const generator = this.constructor.app.snowflakeIdGenerator;
|
|
48
|
+
instance.set(name, generator.generate());
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
init() {
|
|
52
|
+
const { name } = this.options;
|
|
53
|
+
this.listener = (instance) => this.setId(name, instance);
|
|
54
|
+
this.bulkListener = async (instances) => {
|
|
55
|
+
for (const instance of instances) {
|
|
56
|
+
this.setId(name, instance);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
bind() {
|
|
61
|
+
super.bind();
|
|
62
|
+
this.on("beforeValidate", this.listener);
|
|
63
|
+
this.on("beforeSave", this.listener);
|
|
64
|
+
this.on("beforeBulkCreate", this.bulkListener);
|
|
65
|
+
}
|
|
66
|
+
unbind() {
|
|
67
|
+
super.unbind();
|
|
68
|
+
this.off("beforeValidate", this.listener);
|
|
69
|
+
this.off("beforeSave", this.listener);
|
|
70
|
+
this.off("beforeBulkCreate", this.bulkListener);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
__name(_SnowflakeIdField, "SnowflakeIdField");
|
|
74
|
+
__publicField(_SnowflakeIdField, "app");
|
|
75
|
+
let SnowflakeIdField = _SnowflakeIdField;
|
|
76
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
77
|
+
0 && (module.exports = {
|
|
78
|
+
SnowflakeIdField
|
|
79
|
+
});
|
|
@@ -14,7 +14,7 @@ export declare class StringField extends Field {
|
|
|
14
14
|
set(value: any): void;
|
|
15
15
|
};
|
|
16
16
|
}
|
|
17
|
-
export interface StringFieldOptions extends BaseColumnFieldOptions {
|
|
17
|
+
export interface StringFieldOptions extends BaseColumnFieldOptions<'string'> {
|
|
18
18
|
type: 'string';
|
|
19
19
|
length?: number;
|
|
20
20
|
trim?: boolean;
|
package/lib/index.d.ts
CHANGED
|
@@ -41,3 +41,5 @@ export * from './view-collection';
|
|
|
41
41
|
export { default as fieldTypeMap } from './view/field-type-map';
|
|
42
42
|
export * from './view/view-inference';
|
|
43
43
|
export * from './update-guard';
|
|
44
|
+
export { default as operators } from './operators';
|
|
45
|
+
export { filterIncludes, mergeIncludes } from './utils/filter-include';
|
package/lib/index.js
CHANGED
|
@@ -54,8 +54,11 @@ __export(src_exports, {
|
|
|
54
54
|
ValidationErrorItem: () => import_sequelize.ValidationErrorItem,
|
|
55
55
|
default: () => import_database.Database,
|
|
56
56
|
fieldTypeMap: () => import_field_type_map.default,
|
|
57
|
+
filterIncludes: () => import_filter_include.filterIncludes,
|
|
57
58
|
fn: () => import_sequelize.fn,
|
|
58
59
|
literal: () => import_sequelize.literal,
|
|
60
|
+
mergeIncludes: () => import_filter_include.mergeIncludes,
|
|
61
|
+
operators: () => import_operators.default,
|
|
59
62
|
snakeCase: () => import_utils.snakeCase,
|
|
60
63
|
sqlParser: () => import_sql_parser.default,
|
|
61
64
|
where: () => import_sequelize.where
|
|
@@ -96,6 +99,8 @@ __reExport(src_exports, require("./view-collection"), module.exports);
|
|
|
96
99
|
var import_field_type_map = __toESM(require("./view/field-type-map"));
|
|
97
100
|
__reExport(src_exports, require("./view/view-inference"), module.exports);
|
|
98
101
|
__reExport(src_exports, require("./update-guard"), module.exports);
|
|
102
|
+
var import_operators = __toESM(require("./operators"));
|
|
103
|
+
var import_filter_include = require("./utils/filter-include");
|
|
99
104
|
// Annotate the CommonJS export names for ESM import in node:
|
|
100
105
|
0 && (module.exports = {
|
|
101
106
|
BaseError,
|
|
@@ -114,8 +119,11 @@ __reExport(src_exports, require("./update-guard"), module.exports);
|
|
|
114
119
|
ValidationError,
|
|
115
120
|
ValidationErrorItem,
|
|
116
121
|
fieldTypeMap,
|
|
122
|
+
filterIncludes,
|
|
117
123
|
fn,
|
|
118
124
|
literal,
|
|
125
|
+
mergeIncludes,
|
|
126
|
+
operators,
|
|
119
127
|
snakeCase,
|
|
120
128
|
sqlParser,
|
|
121
129
|
where,
|
|
@@ -77,6 +77,11 @@ const _InheritedSyncRunner = class _InheritedSyncRunner {
|
|
|
77
77
|
let maxSequenceName;
|
|
78
78
|
if (childAttributes.id && childAttributes.id.autoIncrement) {
|
|
79
79
|
for (const parent of parents) {
|
|
80
|
+
const attributes2 = parent.model.getAttributes();
|
|
81
|
+
const parentIdField = attributes2["id"];
|
|
82
|
+
if (!(parentIdField == null ? void 0 : parentIdField.autoIncrement)) {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
80
85
|
const sequenceNameResult = await queryInterface.sequelize.query(
|
|
81
86
|
`SELECT column_default
|
|
82
87
|
FROM information_schema.columns
|
|
@@ -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,12 +26,21 @@ 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 number_interface_exports = {};
|
|
29
39
|
__export(number_interface_exports, {
|
|
30
40
|
NumberInterface: () => NumberInterface
|
|
31
41
|
});
|
|
32
42
|
module.exports = __toCommonJS(number_interface_exports);
|
|
43
|
+
var import_lodash = __toESM(require("lodash"));
|
|
33
44
|
var import_base_interface = require("./base-interface");
|
|
34
45
|
const _NumberInterface = class _NumberInterface extends import_base_interface.BaseInterface {
|
|
35
46
|
sanitizeValue(value) {
|
|
@@ -63,6 +74,23 @@ const _NumberInterface = class _NumberInterface extends import_base_interface.Ba
|
|
|
63
74
|
validate(value) {
|
|
64
75
|
return !isNaN(value);
|
|
65
76
|
}
|
|
77
|
+
toString(value, ctx) {
|
|
78
|
+
var _a, _b, _c, _d;
|
|
79
|
+
value = super.toString(value, ctx);
|
|
80
|
+
const step = (_c = (_b = (_a = this.options) == null ? void 0 : _a.uiSchema) == null ? void 0 : _b["x-component-props"]) == null ? void 0 : _c.step;
|
|
81
|
+
if (value != null && !import_lodash.default.isUndefined(step)) {
|
|
82
|
+
const s = step.toString();
|
|
83
|
+
const precision = ((_d = s.split(".")[1]) == null ? void 0 : _d.length) || 0;
|
|
84
|
+
const num = Number(value);
|
|
85
|
+
if (precision > 0) {
|
|
86
|
+
const factor = Math.pow(10, precision);
|
|
87
|
+
const rounded = Math.round(num * factor) / factor;
|
|
88
|
+
return rounded.toFixed(precision);
|
|
89
|
+
}
|
|
90
|
+
return num.toFixed(0);
|
|
91
|
+
}
|
|
92
|
+
return value;
|
|
93
|
+
}
|
|
66
94
|
};
|
|
67
95
|
__name(_NumberInterface, "NumberInterface");
|
|
68
96
|
let NumberInterface = _NumberInterface;
|
|
@@ -126,6 +126,9 @@ const _MagicAttributeModel = class _MagicAttributeModel extends import_model.Mod
|
|
|
126
126
|
return this;
|
|
127
127
|
}
|
|
128
128
|
if (!options) options = {};
|
|
129
|
+
if (this.dataValues[this.magicAttribute] === null) {
|
|
130
|
+
this.dataValues[this.magicAttribute] = {};
|
|
131
|
+
}
|
|
129
132
|
if (!options.raw) {
|
|
130
133
|
originalValue = this.dataValues[key];
|
|
131
134
|
}
|
package/lib/operators/empty.d.ts
CHANGED
|
@@ -6,8 +6,5 @@
|
|
|
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
|
-
declare const _default:
|
|
10
|
-
$empty(_: any, ctx: any): any;
|
|
11
|
-
$notEmpty(_: any, ctx: any): any;
|
|
12
|
-
};
|
|
9
|
+
declare const _default: Record<string, any>;
|
|
13
10
|
export default _default;
|
package/lib/operators/index.d.ts
CHANGED
package/lib/options-parser.js
CHANGED
|
@@ -150,7 +150,7 @@ const _OptionsParser = class _OptionsParser {
|
|
|
150
150
|
if (defaultSortField && !((_b = this.options) == null ? void 0 : _b.group)) {
|
|
151
151
|
defaultSortField = import_lodash.default.castArray(defaultSortField);
|
|
152
152
|
for (const key of defaultSortField) {
|
|
153
|
-
if (!sort.includes(key)) {
|
|
153
|
+
if (!sort.includes(key) && !sort.includes(`-${key}`)) {
|
|
154
154
|
sort.push(key);
|
|
155
155
|
}
|
|
156
156
|
}
|
|
@@ -27,7 +27,9 @@ export default class PostgresQueryInterface extends QueryInterface {
|
|
|
27
27
|
currentVal: number;
|
|
28
28
|
}>;
|
|
29
29
|
collectionTableExists(collection: Collection, options?: any): Promise<any>;
|
|
30
|
-
listViews(
|
|
30
|
+
listViews(options?: {
|
|
31
|
+
schema?: string;
|
|
32
|
+
}): Promise<[unknown[], unknown]>;
|
|
31
33
|
viewDef(viewName: string): Promise<string>;
|
|
32
34
|
parseSQL(sql: string): any;
|
|
33
35
|
viewColumnUsage(options: any): Promise<{
|