jsonbadger 0.5.0 → 0.6.0
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/README.md +36 -18
- package/docs/api/connection.md +144 -0
- package/docs/api/delta-tracker.md +106 -0
- package/docs/api/document.md +77 -0
- package/docs/api/field-types.md +329 -0
- package/docs/api/index.md +35 -0
- package/docs/api/model.md +392 -0
- package/docs/api/query-builder.md +81 -0
- package/docs/api/schema.md +204 -0
- package/docs/architecture-flow.md +397 -0
- package/docs/examples.md +495 -218
- package/docs/jsonb-ops.md +171 -0
- package/docs/lifecycle/model-compilation.md +111 -0
- package/docs/lifecycle.md +146 -0
- package/docs/query-translation.md +11 -10
- package/package.json +10 -3
- package/src/connection/connect.js +12 -17
- package/src/connection/connection.js +128 -0
- package/src/connection/server-capabilities.js +60 -59
- package/src/constants/defaults.js +32 -19
- package/src/constants/{id-strategies.js → id-strategy.js} +28 -29
- package/src/constants/intake-mode.js +8 -0
- package/src/debug/debug-logger.js +17 -15
- package/src/errors/model-overwrite-error.js +25 -0
- package/src/errors/query-error.js +25 -23
- package/src/errors/validation-error.js +25 -23
- package/src/field-types/base-field-type.js +137 -140
- package/src/field-types/builtins/advanced.js +365 -365
- package/src/field-types/builtins/index.js +579 -585
- package/src/field-types/field-type-namespace.js +9 -0
- package/src/field-types/registry.js +149 -122
- package/src/index.js +26 -36
- package/src/migration/ensure-index.js +157 -154
- package/src/migration/ensure-schema.js +27 -15
- package/src/migration/ensure-table.js +44 -31
- package/src/migration/schema-indexes-resolver.js +8 -6
- package/src/model/document-instance.js +29 -540
- package/src/model/document.js +60 -0
- package/src/model/factory/constants.js +36 -0
- package/src/model/factory/index.js +58 -0
- package/src/model/model.js +875 -0
- package/src/model/operations/delete-one.js +39 -0
- package/src/model/operations/insert-one.js +35 -0
- package/src/model/operations/query-builder.js +132 -0
- package/src/model/operations/update-one.js +333 -0
- package/src/model/state.js +34 -0
- package/src/schema/field-definition-parser.js +213 -218
- package/src/schema/path-introspection.js +87 -82
- package/src/schema/schema-compiler.js +126 -212
- package/src/schema/schema.js +621 -138
- package/src/sql/index.js +17 -0
- package/src/sql/jsonb/ops.js +153 -0
- package/src/{query → sql/jsonb}/path-parser.js +54 -43
- package/src/sql/jsonb/read/elem-match.js +133 -0
- package/src/{query → sql/jsonb/read}/operators/contains.js +13 -7
- package/src/sql/jsonb/read/operators/elem-match.js +9 -0
- package/src/{query → sql/jsonb/read}/operators/has-all-keys.js +17 -11
- package/src/{query → sql/jsonb/read}/operators/has-any-keys.js +18 -11
- package/src/sql/jsonb/read/operators/has-key.js +12 -0
- package/src/{query → sql/jsonb/read}/operators/jsonpath-exists.js +22 -15
- package/src/{query → sql/jsonb/read}/operators/jsonpath-match.js +22 -15
- package/src/{query → sql/jsonb/read}/operators/size.js +23 -16
- package/src/sql/parameter-binder.js +18 -13
- package/src/sql/read/build-count-query.js +12 -0
- package/src/sql/read/build-find-query.js +25 -0
- package/src/sql/read/limit-skip.js +21 -0
- package/src/sql/read/sort.js +85 -0
- package/src/sql/read/where/base-fields.js +310 -0
- package/src/sql/read/where/casting.js +90 -0
- package/src/sql/read/where/context.js +79 -0
- package/src/sql/read/where/field-clause.js +58 -0
- package/src/sql/read/where/index.js +38 -0
- package/src/sql/read/where/operator-entries.js +29 -0
- package/src/{query → sql/read/where}/operators/all.js +16 -10
- package/src/sql/read/where/operators/eq.js +12 -0
- package/src/{query → sql/read/where}/operators/gt.js +23 -16
- package/src/{query → sql/read/where}/operators/gte.js +23 -16
- package/src/{query → sql/read/where}/operators/in.js +18 -12
- package/src/sql/read/where/operators/index.js +40 -0
- package/src/{query → sql/read/where}/operators/lt.js +23 -16
- package/src/{query → sql/read/where}/operators/lte.js +23 -16
- package/src/sql/read/where/operators/ne.js +12 -0
- package/src/{query → sql/read/where}/operators/nin.js +18 -12
- package/src/{query → sql/read/where}/operators/regex.js +14 -8
- package/src/sql/read/where/operators.js +126 -0
- package/src/sql/read/where/text-operators.js +83 -0
- package/src/sql/run.js +46 -0
- package/src/sql/write/build-delete-query.js +33 -0
- package/src/sql/write/build-insert-query.js +42 -0
- package/src/sql/write/build-update-query.js +65 -0
- package/src/utils/assert.js +34 -27
- package/src/utils/delta-tracker/.archive/1 tracker-redesign-codex-v2.md +250 -0
- package/src/utils/delta-tracker/.archive/1 tracker-redesign-gemini.md +101 -0
- package/src/utils/delta-tracker/.archive/2 evaluation by gemini.txt +65 -0
- package/src/utils/delta-tracker/.archive/2 evaluation by grok.txt +39 -0
- package/src/utils/delta-tracker/.archive/3 gemini evaluate grok.txt +37 -0
- package/src/utils/delta-tracker/.archive/3 grok evaluate gemini.txt +63 -0
- package/src/utils/delta-tracker/.archive/4 gemini veredict.txt +16 -0
- package/src/utils/delta-tracker/.archive/index.1.js +587 -0
- package/src/utils/delta-tracker/.archive/index.2.js +612 -0
- package/src/utils/delta-tracker/index.js +592 -0
- package/src/utils/dirty-tracker/inline.js +335 -0
- package/src/utils/dirty-tracker/instance.js +414 -0
- package/src/utils/dirty-tracker/static.js +343 -0
- package/src/utils/json-safe.js +13 -9
- package/src/utils/object-path.js +227 -33
- package/src/utils/object.js +408 -168
- package/src/utils/string.js +55 -0
- package/src/utils/value.js +169 -30
- package/docs/api.md +0 -152
- package/src/connection/disconnect.js +0 -16
- package/src/connection/pool-store.js +0 -46
- package/src/model/model-factory.js +0 -555
- package/src/query/limit-skip-compiler.js +0 -31
- package/src/query/operators/elem-match.js +0 -3
- package/src/query/operators/eq.js +0 -6
- package/src/query/operators/has-key.js +0 -6
- package/src/query/operators/index.js +0 -60
- package/src/query/operators/ne.js +0 -6
- package/src/query/query-builder.js +0 -93
- package/src/query/sort-compiler.js +0 -30
- package/src/query/where-compiler.js +0 -477
- package/src/sql/sql-runner.js +0 -31
|
@@ -1,365 +1,365 @@
|
|
|
1
|
-
import BaseFieldType from '#src/field-types/base-field-type.js';
|
|
2
|
-
|
|
3
|
-
const INT32_MIN = -2147483648;
|
|
4
|
-
const INT32_MAX = 2147483647;
|
|
5
|
-
const decimal_string_pattern = /^[+-]?(?:\d+\.?\d*|\.\d+)(?:e[+-]?\d+)?$/i;
|
|
6
|
-
|
|
7
|
-
function decimal128_type_reference() {
|
|
8
|
-
return;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
function double_type_reference() {
|
|
12
|
-
return;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function int32_type_reference() {
|
|
16
|
-
return;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function union_type_reference() {
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function Decimal128FieldType(path_value, options) {
|
|
24
|
-
BaseFieldType.call(this, path_value, options);
|
|
25
|
-
this.instance = 'Decimal128';
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
Decimal128FieldType.prototype = Object.create(BaseFieldType.prototype);
|
|
29
|
-
Decimal128FieldType.prototype.constructor = Decimal128FieldType;
|
|
30
|
-
|
|
31
|
-
Decimal128FieldType.prototype.cast = function (value) {
|
|
32
|
-
if(value === undefined || value === null) {
|
|
33
|
-
return value;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if(typeof value === 'bigint') {
|
|
37
|
-
return value.toString();
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
if(typeof value === 'number') {
|
|
41
|
-
if(!Number.isFinite(value)) {
|
|
42
|
-
throw this.create_field_error('cast_error', 'Cast to Decimal128 failed for path "' + this.path + '"', value);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return String(value);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if(typeof value === 'string') {
|
|
49
|
-
const normalized_value = value.trim();
|
|
50
|
-
|
|
51
|
-
if(!decimal_string_pattern.test(normalized_value)) {
|
|
52
|
-
throw this.create_field_error('cast_error', 'Cast to Decimal128 failed for path "' + this.path + '"', value);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
return normalized_value;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
if(value && typeof value.valueOf === 'function') {
|
|
59
|
-
const value_of_result = value.valueOf();
|
|
60
|
-
|
|
61
|
-
if(value_of_result !== value) {
|
|
62
|
-
return this.cast(value_of_result);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
throw this.create_field_error('cast_error', 'Cast to Decimal128 failed for path "' + this.path + '"', value);
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
function BigIntFieldType(path_value, options) {
|
|
70
|
-
BaseFieldType.call(this, path_value, options);
|
|
71
|
-
this.instance = 'BigInt';
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
BigIntFieldType.prototype = Object.create(BaseFieldType.prototype);
|
|
75
|
-
BigIntFieldType.prototype.constructor = BigIntFieldType;
|
|
76
|
-
|
|
77
|
-
BigIntFieldType.prototype.cast = function (value) {
|
|
78
|
-
if(value === undefined || value === null) {
|
|
79
|
-
return value;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
if(typeof value === 'bigint') {
|
|
83
|
-
return value;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if(value === true) {
|
|
87
|
-
return 1n;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
if(value === false) {
|
|
91
|
-
return 0n;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
if(typeof value === 'number') {
|
|
95
|
-
if(!Number.isFinite(value) || !Number.isInteger(value)) {
|
|
96
|
-
throw this.create_field_error('cast_error', 'Cast to BigInt failed for path "' + this.path + '"', value);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
return BigInt(value);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
if(typeof value === 'string') {
|
|
103
|
-
const normalized_value = value.trim();
|
|
104
|
-
|
|
105
|
-
if(!/^[+-]?\d+$/.test(normalized_value)) {
|
|
106
|
-
throw this.create_field_error('cast_error', 'Cast to BigInt failed for path "' + this.path + '"', value);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
try {
|
|
110
|
-
return BigInt(normalized_value);
|
|
111
|
-
} catch(error) {
|
|
112
|
-
throw this.create_field_error('cast_error', 'Cast to BigInt failed for path "' + this.path + '"', value);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
if(value && typeof value.valueOf === 'function') {
|
|
117
|
-
const value_of_result = value.valueOf();
|
|
118
|
-
|
|
119
|
-
if(value_of_result !== value) {
|
|
120
|
-
return this.cast(value_of_result);
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
throw this.create_field_error('cast_error', 'Cast to BigInt failed for path "' + this.path + '"', value);
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
function DoubleFieldType(path_value, options) {
|
|
128
|
-
BaseFieldType.call(this, path_value, options);
|
|
129
|
-
this.instance = 'Double';
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
DoubleFieldType.prototype = Object.create(BaseFieldType.prototype);
|
|
133
|
-
DoubleFieldType.prototype.constructor = DoubleFieldType;
|
|
134
|
-
|
|
135
|
-
DoubleFieldType.prototype.cast = function (value) {
|
|
136
|
-
if(value === undefined || value === null) {
|
|
137
|
-
return value;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
if(value === true) {
|
|
141
|
-
return 1;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
if(value === false) {
|
|
145
|
-
return 0;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
if(typeof value === 'number') {
|
|
149
|
-
if(!Number.isFinite(value)) {
|
|
150
|
-
throw this.create_field_error('cast_error', 'Cast to Double failed for path "' + this.path + '"', value);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
return value;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
if(typeof value === 'string') {
|
|
157
|
-
if(value.trim() === '') {
|
|
158
|
-
return null;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
const string_number = Number(value);
|
|
162
|
-
|
|
163
|
-
if(!Number.isFinite(string_number)) {
|
|
164
|
-
throw this.create_field_error('cast_error', 'Cast to Double failed for path "' + this.path + '"', value);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
return string_number;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
if(value && typeof value.valueOf === 'function') {
|
|
171
|
-
const value_of_result = value.valueOf();
|
|
172
|
-
|
|
173
|
-
if(value_of_result !== value) {
|
|
174
|
-
return this.cast(value_of_result);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
throw this.create_field_error('cast_error', 'Cast to Double failed for path "' + this.path + '"', value);
|
|
179
|
-
};
|
|
180
|
-
|
|
181
|
-
function Int32FieldType(path_value, options) {
|
|
182
|
-
BaseFieldType.call(this, path_value, options);
|
|
183
|
-
this.instance = 'Int32';
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
Int32FieldType.prototype = Object.create(BaseFieldType.prototype);
|
|
187
|
-
Int32FieldType.prototype.constructor = Int32FieldType;
|
|
188
|
-
|
|
189
|
-
Int32FieldType.prototype.cast = function (value) {
|
|
190
|
-
if(value === undefined || value === null) {
|
|
191
|
-
return value;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
if(value === true) {
|
|
195
|
-
return 1;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
if(value === false) {
|
|
199
|
-
return 0;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
if(typeof value === 'string') {
|
|
203
|
-
if(value.trim() === '') {
|
|
204
|
-
return null;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
const string_number = Number(value);
|
|
208
|
-
return cast_int32(this, string_number, value);
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
if(typeof value === 'number') {
|
|
212
|
-
return cast_int32(this, value, value);
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
if(value && typeof value.valueOf === 'function') {
|
|
216
|
-
const value_of_result = value.valueOf();
|
|
217
|
-
|
|
218
|
-
if(value_of_result !== value) {
|
|
219
|
-
return this.cast(value_of_result);
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
throw this.create_field_error('cast_error', 'Cast to Int32 failed for path "' + this.path + '"', value);
|
|
224
|
-
};
|
|
225
|
-
|
|
226
|
-
function UnionFieldType(path_value, options) {
|
|
227
|
-
BaseFieldType.call(this, path_value, options);
|
|
228
|
-
this.instance = 'Union';
|
|
229
|
-
this.of_field_types = Array.isArray(options && options.of_field_types) ? options.of_field_types.slice() : [];
|
|
230
|
-
this.validators.push({
|
|
231
|
-
kind: 'union'
|
|
232
|
-
});
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
UnionFieldType.prototype = Object.create(BaseFieldType.prototype);
|
|
236
|
-
UnionFieldType.prototype.constructor = UnionFieldType;
|
|
237
|
-
|
|
238
|
-
UnionFieldType.prototype.cast = function (value, context_value) {
|
|
239
|
-
if(value === undefined || value === null) {
|
|
240
|
-
return value;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
if(this.of_field_types.length === 0) {
|
|
244
|
-
throw this.create_field_error('cast_error', 'Union type at path "' + this.path + '" requires at least one candidate type', value);
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
const union_context = context_value || {};
|
|
248
|
-
let candidate_index = 0;
|
|
249
|
-
|
|
250
|
-
while(candidate_index < this.of_field_types.length) {
|
|
251
|
-
const candidate_field_type = this.of_field_types[candidate_index];
|
|
252
|
-
|
|
253
|
-
if(is_exact_union_match(candidate_field_type, value)) {
|
|
254
|
-
candidate_field_type.validate(value, union_context);
|
|
255
|
-
return value;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
candidate_index += 1;
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
let last_error = null;
|
|
262
|
-
candidate_index = 0;
|
|
263
|
-
|
|
264
|
-
while(candidate_index < this.of_field_types.length) {
|
|
265
|
-
const candidate_field_type = this.of_field_types[candidate_index];
|
|
266
|
-
|
|
267
|
-
try {
|
|
268
|
-
return normalize_union_candidate(candidate_field_type, value, union_context);
|
|
269
|
-
} catch(error) {
|
|
270
|
-
last_error = error;
|
|
271
|
-
candidate_index += 1;
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
throw last_error || this.create_field_error('cast_error', 'Cast to Union failed for path "' + this.path + '"', value);
|
|
276
|
-
};
|
|
277
|
-
|
|
278
|
-
function cast_int32(field_type, numeric_value, original_value) {
|
|
279
|
-
if(!Number.isFinite(numeric_value) || !Number.isInteger(numeric_value)) {
|
|
280
|
-
throw field_type.create_field_error('cast_error', 'Cast to Int32 failed for path "' + field_type.path + '"', original_value);
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
if(numeric_value < INT32_MIN || numeric_value > INT32_MAX) {
|
|
284
|
-
throw field_type.create_field_error('cast_error', 'Cast to Int32 failed for path "' + field_type.path + '"', original_value);
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
return numeric_value;
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
function normalize_union_candidate(candidate_field_type, value, context_value) {
|
|
291
|
-
let next_value = value;
|
|
292
|
-
|
|
293
|
-
if(typeof candidate_field_type.apply_set === 'function') {
|
|
294
|
-
next_value = candidate_field_type.apply_set(next_value, context_value);
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
next_value = candidate_field_type.cast(next_value, context_value);
|
|
298
|
-
candidate_field_type.validate(next_value, context_value);
|
|
299
|
-
return next_value;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
function is_exact_union_match(candidate_field_type, value) {
|
|
303
|
-
const instance_name = candidate_field_type.instance;
|
|
304
|
-
|
|
305
|
-
if(instance_name === 'String') {
|
|
306
|
-
return typeof value === 'string';
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
if(instance_name === 'Number' || instance_name === 'Double') {
|
|
310
|
-
return typeof value === 'number' && Number.isFinite(value);
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
if(instance_name === 'Int32') {
|
|
314
|
-
return typeof value === 'number' && Number.isInteger(value) && value >= INT32_MIN && value <= INT32_MAX;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
if(instance_name === 'BigInt') {
|
|
318
|
-
return typeof value === 'bigint';
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
if(instance_name === 'Boolean') {
|
|
322
|
-
return typeof value === 'boolean';
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
if(instance_name === 'Date') {
|
|
326
|
-
return value instanceof Date && !Number.isNaN(value.getTime());
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
if(instance_name === 'Buffer') {
|
|
330
|
-
return Buffer.isBuffer(value);
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
if(instance_name === 'Array') {
|
|
334
|
-
return Array.isArray(value);
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
if(instance_name === 'Map') {
|
|
338
|
-
return value instanceof Map || (value !== null && typeof value === 'object' && !Array.isArray(value) && !Buffer.isBuffer(value) && !(value instanceof Date));
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
if(instance_name === 'Mixed') {
|
|
342
|
-
return true;
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
return false;
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
export {
|
|
349
|
-
// Type
|
|
350
|
-
decimal128_type_reference,
|
|
351
|
-
double_type_reference,
|
|
352
|
-
int32_type_reference,
|
|
353
|
-
union_type_reference,
|
|
354
|
-
|
|
355
|
-
// FieldType constructors
|
|
356
|
-
BigIntFieldType,
|
|
357
|
-
Decimal128FieldType,
|
|
358
|
-
DoubleFieldType,
|
|
359
|
-
Int32FieldType,
|
|
360
|
-
UnionFieldType,
|
|
361
|
-
|
|
362
|
-
// Constants
|
|
363
|
-
INT32_MIN,
|
|
364
|
-
INT32_MAX
|
|
365
|
-
};
|
|
1
|
+
import BaseFieldType from '#src/field-types/base-field-type.js';
|
|
2
|
+
|
|
3
|
+
const INT32_MIN = -2147483648;
|
|
4
|
+
const INT32_MAX = 2147483647;
|
|
5
|
+
const decimal_string_pattern = /^[+-]?(?:\d+\.?\d*|\.\d+)(?:e[+-]?\d+)?$/i;
|
|
6
|
+
|
|
7
|
+
function decimal128_type_reference() {
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function double_type_reference() {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function int32_type_reference() {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function union_type_reference() {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function Decimal128FieldType(path_value, options) {
|
|
24
|
+
BaseFieldType.call(this, path_value, options);
|
|
25
|
+
this.instance = 'Decimal128';
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
Decimal128FieldType.prototype = Object.create(BaseFieldType.prototype);
|
|
29
|
+
Decimal128FieldType.prototype.constructor = Decimal128FieldType;
|
|
30
|
+
|
|
31
|
+
Decimal128FieldType.prototype.cast = function (value) {
|
|
32
|
+
if(value === undefined || value === null) {
|
|
33
|
+
return value;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if(typeof value === 'bigint') {
|
|
37
|
+
return value.toString();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if(typeof value === 'number') {
|
|
41
|
+
if(!Number.isFinite(value)) {
|
|
42
|
+
throw this.create_field_error('cast_error', 'Cast to Decimal128 failed for path "' + this.path + '"', value);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return String(value);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if(typeof value === 'string') {
|
|
49
|
+
const normalized_value = value.trim();
|
|
50
|
+
|
|
51
|
+
if(!decimal_string_pattern.test(normalized_value)) {
|
|
52
|
+
throw this.create_field_error('cast_error', 'Cast to Decimal128 failed for path "' + this.path + '"', value);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return normalized_value;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if(value && typeof value.valueOf === 'function') {
|
|
59
|
+
const value_of_result = value.valueOf();
|
|
60
|
+
|
|
61
|
+
if(value_of_result !== value) {
|
|
62
|
+
return this.cast(value_of_result);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
throw this.create_field_error('cast_error', 'Cast to Decimal128 failed for path "' + this.path + '"', value);
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
function BigIntFieldType(path_value, options) {
|
|
70
|
+
BaseFieldType.call(this, path_value, options);
|
|
71
|
+
this.instance = 'BigInt';
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
BigIntFieldType.prototype = Object.create(BaseFieldType.prototype);
|
|
75
|
+
BigIntFieldType.prototype.constructor = BigIntFieldType;
|
|
76
|
+
|
|
77
|
+
BigIntFieldType.prototype.cast = function (value) {
|
|
78
|
+
if(value === undefined || value === null) {
|
|
79
|
+
return value;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if(typeof value === 'bigint') {
|
|
83
|
+
return value;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if(value === true) {
|
|
87
|
+
return 1n;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if(value === false) {
|
|
91
|
+
return 0n;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if(typeof value === 'number') {
|
|
95
|
+
if(!Number.isFinite(value) || !Number.isInteger(value)) {
|
|
96
|
+
throw this.create_field_error('cast_error', 'Cast to BigInt failed for path "' + this.path + '"', value);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return BigInt(value);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if(typeof value === 'string') {
|
|
103
|
+
const normalized_value = value.trim();
|
|
104
|
+
|
|
105
|
+
if(!/^[+-]?\d+$/.test(normalized_value)) {
|
|
106
|
+
throw this.create_field_error('cast_error', 'Cast to BigInt failed for path "' + this.path + '"', value);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
try {
|
|
110
|
+
return BigInt(normalized_value);
|
|
111
|
+
} catch(error) {
|
|
112
|
+
throw this.create_field_error('cast_error', 'Cast to BigInt failed for path "' + this.path + '"', value);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if(value && typeof value.valueOf === 'function') {
|
|
117
|
+
const value_of_result = value.valueOf();
|
|
118
|
+
|
|
119
|
+
if(value_of_result !== value) {
|
|
120
|
+
return this.cast(value_of_result);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
throw this.create_field_error('cast_error', 'Cast to BigInt failed for path "' + this.path + '"', value);
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
function DoubleFieldType(path_value, options) {
|
|
128
|
+
BaseFieldType.call(this, path_value, options);
|
|
129
|
+
this.instance = 'Double';
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
DoubleFieldType.prototype = Object.create(BaseFieldType.prototype);
|
|
133
|
+
DoubleFieldType.prototype.constructor = DoubleFieldType;
|
|
134
|
+
|
|
135
|
+
DoubleFieldType.prototype.cast = function (value) {
|
|
136
|
+
if(value === undefined || value === null) {
|
|
137
|
+
return value;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if(value === true) {
|
|
141
|
+
return 1;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if(value === false) {
|
|
145
|
+
return 0;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if(typeof value === 'number') {
|
|
149
|
+
if(!Number.isFinite(value)) {
|
|
150
|
+
throw this.create_field_error('cast_error', 'Cast to Double failed for path "' + this.path + '"', value);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return value;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if(typeof value === 'string') {
|
|
157
|
+
if(value.trim() === '') {
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const string_number = Number(value);
|
|
162
|
+
|
|
163
|
+
if(!Number.isFinite(string_number)) {
|
|
164
|
+
throw this.create_field_error('cast_error', 'Cast to Double failed for path "' + this.path + '"', value);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return string_number;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if(value && typeof value.valueOf === 'function') {
|
|
171
|
+
const value_of_result = value.valueOf();
|
|
172
|
+
|
|
173
|
+
if(value_of_result !== value) {
|
|
174
|
+
return this.cast(value_of_result);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
throw this.create_field_error('cast_error', 'Cast to Double failed for path "' + this.path + '"', value);
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
function Int32FieldType(path_value, options) {
|
|
182
|
+
BaseFieldType.call(this, path_value, options);
|
|
183
|
+
this.instance = 'Int32';
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
Int32FieldType.prototype = Object.create(BaseFieldType.prototype);
|
|
187
|
+
Int32FieldType.prototype.constructor = Int32FieldType;
|
|
188
|
+
|
|
189
|
+
Int32FieldType.prototype.cast = function (value) {
|
|
190
|
+
if(value === undefined || value === null) {
|
|
191
|
+
return value;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if(value === true) {
|
|
195
|
+
return 1;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if(value === false) {
|
|
199
|
+
return 0;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if(typeof value === 'string') {
|
|
203
|
+
if(value.trim() === '') {
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const string_number = Number(value);
|
|
208
|
+
return cast_int32(this, string_number, value);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if(typeof value === 'number') {
|
|
212
|
+
return cast_int32(this, value, value);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if(value && typeof value.valueOf === 'function') {
|
|
216
|
+
const value_of_result = value.valueOf();
|
|
217
|
+
|
|
218
|
+
if(value_of_result !== value) {
|
|
219
|
+
return this.cast(value_of_result);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
throw this.create_field_error('cast_error', 'Cast to Int32 failed for path "' + this.path + '"', value);
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
function UnionFieldType(path_value, options) {
|
|
227
|
+
BaseFieldType.call(this, path_value, options);
|
|
228
|
+
this.instance = 'Union';
|
|
229
|
+
this.of_field_types = Array.isArray(options && options.of_field_types) ? options.of_field_types.slice() : [];
|
|
230
|
+
this.validators.push({
|
|
231
|
+
kind: 'union'
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
UnionFieldType.prototype = Object.create(BaseFieldType.prototype);
|
|
236
|
+
UnionFieldType.prototype.constructor = UnionFieldType;
|
|
237
|
+
|
|
238
|
+
UnionFieldType.prototype.cast = function (value, context_value) {
|
|
239
|
+
if(value === undefined || value === null) {
|
|
240
|
+
return value;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if(this.of_field_types.length === 0) {
|
|
244
|
+
throw this.create_field_error('cast_error', 'Union type at path "' + this.path + '" requires at least one candidate type', value);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const union_context = context_value || {};
|
|
248
|
+
let candidate_index = 0;
|
|
249
|
+
|
|
250
|
+
while(candidate_index < this.of_field_types.length) {
|
|
251
|
+
const candidate_field_type = this.of_field_types[candidate_index];
|
|
252
|
+
|
|
253
|
+
if(is_exact_union_match(candidate_field_type, value)) {
|
|
254
|
+
candidate_field_type.validate(value, union_context);
|
|
255
|
+
return value;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
candidate_index += 1;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
let last_error = null;
|
|
262
|
+
candidate_index = 0;
|
|
263
|
+
|
|
264
|
+
while(candidate_index < this.of_field_types.length) {
|
|
265
|
+
const candidate_field_type = this.of_field_types[candidate_index];
|
|
266
|
+
|
|
267
|
+
try {
|
|
268
|
+
return normalize_union_candidate(candidate_field_type, value, union_context);
|
|
269
|
+
} catch(error) {
|
|
270
|
+
last_error = error;
|
|
271
|
+
candidate_index += 1;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
throw last_error || this.create_field_error('cast_error', 'Cast to Union failed for path "' + this.path + '"', value);
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
function cast_int32(field_type, numeric_value, original_value) {
|
|
279
|
+
if(!Number.isFinite(numeric_value) || !Number.isInteger(numeric_value)) {
|
|
280
|
+
throw field_type.create_field_error('cast_error', 'Cast to Int32 failed for path "' + field_type.path + '"', original_value);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if(numeric_value < INT32_MIN || numeric_value > INT32_MAX) {
|
|
284
|
+
throw field_type.create_field_error('cast_error', 'Cast to Int32 failed for path "' + field_type.path + '"', original_value);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
return numeric_value;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function normalize_union_candidate(candidate_field_type, value, context_value) {
|
|
291
|
+
let next_value = value;
|
|
292
|
+
|
|
293
|
+
if(typeof candidate_field_type.apply_set === 'function') {
|
|
294
|
+
next_value = candidate_field_type.apply_set(next_value, context_value);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
next_value = candidate_field_type.cast(next_value, context_value);
|
|
298
|
+
candidate_field_type.validate(next_value, context_value);
|
|
299
|
+
return next_value;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function is_exact_union_match(candidate_field_type, value) {
|
|
303
|
+
const instance_name = candidate_field_type.instance;
|
|
304
|
+
|
|
305
|
+
if(instance_name === 'String') {
|
|
306
|
+
return typeof value === 'string';
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
if(instance_name === 'Number' || instance_name === 'Double') {
|
|
310
|
+
return typeof value === 'number' && Number.isFinite(value);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
if(instance_name === 'Int32') {
|
|
314
|
+
return typeof value === 'number' && Number.isInteger(value) && value >= INT32_MIN && value <= INT32_MAX;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
if(instance_name === 'BigInt') {
|
|
318
|
+
return typeof value === 'bigint';
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
if(instance_name === 'Boolean') {
|
|
322
|
+
return typeof value === 'boolean';
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
if(instance_name === 'Date') {
|
|
326
|
+
return value instanceof Date && !Number.isNaN(value.getTime());
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
if(instance_name === 'Buffer') {
|
|
330
|
+
return Buffer.isBuffer(value);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
if(instance_name === 'Array') {
|
|
334
|
+
return Array.isArray(value);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
if(instance_name === 'Map') {
|
|
338
|
+
return value instanceof Map || (value !== null && typeof value === 'object' && !Array.isArray(value) && !Buffer.isBuffer(value) && !(value instanceof Date));
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
if(instance_name === 'Mixed') {
|
|
342
|
+
return true;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
return false;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
export {
|
|
349
|
+
// Type alias helpers
|
|
350
|
+
decimal128_type_reference,
|
|
351
|
+
double_type_reference,
|
|
352
|
+
int32_type_reference,
|
|
353
|
+
union_type_reference,
|
|
354
|
+
|
|
355
|
+
// FieldType constructors
|
|
356
|
+
BigIntFieldType,
|
|
357
|
+
Decimal128FieldType,
|
|
358
|
+
DoubleFieldType,
|
|
359
|
+
Int32FieldType,
|
|
360
|
+
UnionFieldType,
|
|
361
|
+
|
|
362
|
+
// Constants
|
|
363
|
+
INT32_MIN,
|
|
364
|
+
INT32_MAX
|
|
365
|
+
};
|