jsonbadger 0.5.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. package/README.md +36 -18
  2. package/docs/api/connection.md +144 -0
  3. package/docs/api/delta-tracker.md +106 -0
  4. package/docs/api/document.md +77 -0
  5. package/docs/api/field-types.md +329 -0
  6. package/docs/api/index.md +35 -0
  7. package/docs/api/model.md +392 -0
  8. package/docs/api/query-builder.md +81 -0
  9. package/docs/api/schema.md +204 -0
  10. package/docs/architecture-flow.md +397 -0
  11. package/docs/examples.md +495 -218
  12. package/docs/jsonb-ops.md +171 -0
  13. package/docs/lifecycle/model-compilation.md +111 -0
  14. package/docs/lifecycle.md +146 -0
  15. package/docs/query-translation.md +11 -10
  16. package/package.json +10 -3
  17. package/src/connection/connect.js +12 -17
  18. package/src/connection/connection.js +128 -0
  19. package/src/connection/server-capabilities.js +60 -59
  20. package/src/constants/defaults.js +32 -19
  21. package/src/constants/{id-strategies.js → id-strategy.js} +28 -29
  22. package/src/constants/intake-mode.js +8 -0
  23. package/src/debug/debug-logger.js +17 -15
  24. package/src/errors/model-overwrite-error.js +25 -0
  25. package/src/errors/query-error.js +25 -23
  26. package/src/errors/validation-error.js +25 -23
  27. package/src/field-types/base-field-type.js +137 -140
  28. package/src/field-types/builtins/advanced.js +365 -365
  29. package/src/field-types/builtins/index.js +579 -585
  30. package/src/field-types/field-type-namespace.js +9 -0
  31. package/src/field-types/registry.js +149 -122
  32. package/src/index.js +26 -36
  33. package/src/migration/ensure-index.js +157 -154
  34. package/src/migration/ensure-schema.js +27 -15
  35. package/src/migration/ensure-table.js +44 -31
  36. package/src/migration/schema-indexes-resolver.js +8 -6
  37. package/src/model/document-instance.js +29 -540
  38. package/src/model/document.js +60 -0
  39. package/src/model/factory/constants.js +36 -0
  40. package/src/model/factory/index.js +58 -0
  41. package/src/model/model.js +875 -0
  42. package/src/model/operations/delete-one.js +39 -0
  43. package/src/model/operations/insert-one.js +35 -0
  44. package/src/model/operations/query-builder.js +132 -0
  45. package/src/model/operations/update-one.js +333 -0
  46. package/src/model/state.js +34 -0
  47. package/src/schema/field-definition-parser.js +213 -218
  48. package/src/schema/path-introspection.js +87 -82
  49. package/src/schema/schema-compiler.js +126 -212
  50. package/src/schema/schema.js +621 -138
  51. package/src/sql/index.js +17 -0
  52. package/src/sql/jsonb/ops.js +153 -0
  53. package/src/{query → sql/jsonb}/path-parser.js +54 -43
  54. package/src/sql/jsonb/read/elem-match.js +133 -0
  55. package/src/{query → sql/jsonb/read}/operators/contains.js +13 -7
  56. package/src/sql/jsonb/read/operators/elem-match.js +9 -0
  57. package/src/{query → sql/jsonb/read}/operators/has-all-keys.js +17 -11
  58. package/src/{query → sql/jsonb/read}/operators/has-any-keys.js +18 -11
  59. package/src/sql/jsonb/read/operators/has-key.js +12 -0
  60. package/src/{query → sql/jsonb/read}/operators/jsonpath-exists.js +22 -15
  61. package/src/{query → sql/jsonb/read}/operators/jsonpath-match.js +22 -15
  62. package/src/{query → sql/jsonb/read}/operators/size.js +23 -16
  63. package/src/sql/parameter-binder.js +18 -13
  64. package/src/sql/read/build-count-query.js +12 -0
  65. package/src/sql/read/build-find-query.js +25 -0
  66. package/src/sql/read/limit-skip.js +21 -0
  67. package/src/sql/read/sort.js +85 -0
  68. package/src/sql/read/where/base-fields.js +310 -0
  69. package/src/sql/read/where/casting.js +90 -0
  70. package/src/sql/read/where/context.js +79 -0
  71. package/src/sql/read/where/field-clause.js +58 -0
  72. package/src/sql/read/where/index.js +38 -0
  73. package/src/sql/read/where/operator-entries.js +29 -0
  74. package/src/{query → sql/read/where}/operators/all.js +16 -10
  75. package/src/sql/read/where/operators/eq.js +12 -0
  76. package/src/{query → sql/read/where}/operators/gt.js +23 -16
  77. package/src/{query → sql/read/where}/operators/gte.js +23 -16
  78. package/src/{query → sql/read/where}/operators/in.js +18 -12
  79. package/src/sql/read/where/operators/index.js +40 -0
  80. package/src/{query → sql/read/where}/operators/lt.js +23 -16
  81. package/src/{query → sql/read/where}/operators/lte.js +23 -16
  82. package/src/sql/read/where/operators/ne.js +12 -0
  83. package/src/{query → sql/read/where}/operators/nin.js +18 -12
  84. package/src/{query → sql/read/where}/operators/regex.js +14 -8
  85. package/src/sql/read/where/operators.js +126 -0
  86. package/src/sql/read/where/text-operators.js +83 -0
  87. package/src/sql/run.js +46 -0
  88. package/src/sql/write/build-delete-query.js +33 -0
  89. package/src/sql/write/build-insert-query.js +42 -0
  90. package/src/sql/write/build-update-query.js +65 -0
  91. package/src/utils/assert.js +34 -27
  92. package/src/utils/delta-tracker/.archive/1 tracker-redesign-codex-v2.md +250 -0
  93. package/src/utils/delta-tracker/.archive/1 tracker-redesign-gemini.md +101 -0
  94. package/src/utils/delta-tracker/.archive/2 evaluation by gemini.txt +65 -0
  95. package/src/utils/delta-tracker/.archive/2 evaluation by grok.txt +39 -0
  96. package/src/utils/delta-tracker/.archive/3 gemini evaluate grok.txt +37 -0
  97. package/src/utils/delta-tracker/.archive/3 grok evaluate gemini.txt +63 -0
  98. package/src/utils/delta-tracker/.archive/4 gemini veredict.txt +16 -0
  99. package/src/utils/delta-tracker/.archive/index.1.js +587 -0
  100. package/src/utils/delta-tracker/.archive/index.2.js +612 -0
  101. package/src/utils/delta-tracker/index.js +592 -0
  102. package/src/utils/dirty-tracker/inline.js +335 -0
  103. package/src/utils/dirty-tracker/instance.js +414 -0
  104. package/src/utils/dirty-tracker/static.js +343 -0
  105. package/src/utils/json-safe.js +13 -9
  106. package/src/utils/object-path.js +227 -33
  107. package/src/utils/object.js +408 -168
  108. package/src/utils/string.js +55 -0
  109. package/src/utils/value.js +169 -30
  110. package/docs/api.md +0 -152
  111. package/src/connection/disconnect.js +0 -16
  112. package/src/connection/pool-store.js +0 -46
  113. package/src/model/model-factory.js +0 -555
  114. package/src/query/limit-skip-compiler.js +0 -31
  115. package/src/query/operators/elem-match.js +0 -3
  116. package/src/query/operators/eq.js +0 -6
  117. package/src/query/operators/has-key.js +0 -6
  118. package/src/query/operators/index.js +0 -60
  119. package/src/query/operators/ne.js +0 -6
  120. package/src/query/query-builder.js +0 -93
  121. package/src/query/sort-compiler.js +0 -30
  122. package/src/query/where-compiler.js +0 -477
  123. 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 references
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
+ };