@powersync/service-sync-rules 0.17.10

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 (72) hide show
  1. package/LICENSE +67 -0
  2. package/README.md +3 -0
  3. package/dist/DartSchemaGenerator.d.ts +12 -0
  4. package/dist/DartSchemaGenerator.js +39 -0
  5. package/dist/DartSchemaGenerator.js.map +1 -0
  6. package/dist/ExpressionType.d.ts +33 -0
  7. package/dist/ExpressionType.js +61 -0
  8. package/dist/ExpressionType.js.map +1 -0
  9. package/dist/IdSequence.d.ts +4 -0
  10. package/dist/IdSequence.js +9 -0
  11. package/dist/IdSequence.js.map +1 -0
  12. package/dist/JsSchemaGenerator.d.ts +12 -0
  13. package/dist/JsSchemaGenerator.js +42 -0
  14. package/dist/JsSchemaGenerator.js.map +1 -0
  15. package/dist/SchemaGenerator.d.ts +14 -0
  16. package/dist/SchemaGenerator.js +26 -0
  17. package/dist/SchemaGenerator.js.map +1 -0
  18. package/dist/SourceTableInterface.d.ts +5 -0
  19. package/dist/SourceTableInterface.js +2 -0
  20. package/dist/SourceTableInterface.js.map +1 -0
  21. package/dist/SqlBucketDescriptor.d.ts +37 -0
  22. package/dist/SqlBucketDescriptor.js +111 -0
  23. package/dist/SqlBucketDescriptor.js.map +1 -0
  24. package/dist/SqlDataQuery.d.ts +39 -0
  25. package/dist/SqlDataQuery.js +237 -0
  26. package/dist/SqlDataQuery.js.map +1 -0
  27. package/dist/SqlParameterQuery.d.ts +43 -0
  28. package/dist/SqlParameterQuery.js +238 -0
  29. package/dist/SqlParameterQuery.js.map +1 -0
  30. package/dist/SqlSyncRules.d.ts +52 -0
  31. package/dist/SqlSyncRules.js +247 -0
  32. package/dist/SqlSyncRules.js.map +1 -0
  33. package/dist/StaticSchema.d.ts +26 -0
  34. package/dist/StaticSchema.js +61 -0
  35. package/dist/StaticSchema.js.map +1 -0
  36. package/dist/StaticSqlParameterQuery.d.ts +24 -0
  37. package/dist/StaticSqlParameterQuery.js +66 -0
  38. package/dist/StaticSqlParameterQuery.js.map +1 -0
  39. package/dist/TablePattern.d.ts +17 -0
  40. package/dist/TablePattern.js +56 -0
  41. package/dist/TablePattern.js.map +1 -0
  42. package/dist/TableQuerySchema.d.ts +9 -0
  43. package/dist/TableQuerySchema.js +34 -0
  44. package/dist/TableQuerySchema.js.map +1 -0
  45. package/dist/errors.d.ts +22 -0
  46. package/dist/errors.js +58 -0
  47. package/dist/errors.js.map +1 -0
  48. package/dist/generators.d.ts +6 -0
  49. package/dist/generators.js +7 -0
  50. package/dist/generators.js.map +1 -0
  51. package/dist/index.d.ts +18 -0
  52. package/dist/index.js +19 -0
  53. package/dist/index.js.map +1 -0
  54. package/dist/json_schema.d.ts +3 -0
  55. package/dist/json_schema.js +48 -0
  56. package/dist/json_schema.js.map +1 -0
  57. package/dist/sql_filters.d.ts +91 -0
  58. package/dist/sql_filters.js +506 -0
  59. package/dist/sql_filters.js.map +1 -0
  60. package/dist/sql_functions.d.ts +54 -0
  61. package/dist/sql_functions.js +773 -0
  62. package/dist/sql_functions.js.map +1 -0
  63. package/dist/sql_support.d.ts +22 -0
  64. package/dist/sql_support.js +213 -0
  65. package/dist/sql_support.js.map +1 -0
  66. package/dist/types.d.ts +174 -0
  67. package/dist/types.js +10 -0
  68. package/dist/types.js.map +1 -0
  69. package/dist/utils.d.ts +45 -0
  70. package/dist/utils.js +173 -0
  71. package/dist/utils.js.map +1 -0
  72. package/package.json +29 -0
@@ -0,0 +1,773 @@
1
+ import { JSONBig } from '@powersync/service-jsonbig';
2
+ import { SQLITE_FALSE, SQLITE_TRUE, sqliteBool } from './sql_support.js';
3
+ import { jsonValueToSqlite } from './utils.js';
4
+ // Declares @syncpoint/wkx module
5
+ // This allows for consumers of this lib to resolve types correctly
6
+ /// <reference types="./wkx.d.ts" />
7
+ import wkx from '@syncpoint/wkx';
8
+ import { ExpressionType, TYPE_INTEGER } from './ExpressionType.js';
9
+ export const BASIC_OPERATORS = new Set([
10
+ '=',
11
+ '!=',
12
+ '<',
13
+ '>',
14
+ '<=',
15
+ '>=',
16
+ '+',
17
+ '-',
18
+ '*',
19
+ '/',
20
+ '||',
21
+ 'AND',
22
+ 'OR',
23
+ 'IS',
24
+ 'IS NOT'
25
+ ]);
26
+ const upper = {
27
+ call(value) {
28
+ const text = castAsText(value);
29
+ return text?.toUpperCase() ?? null;
30
+ },
31
+ parameters: [{ name: 'value', type: ExpressionType.ANY, optional: false }],
32
+ getReturnType(args) {
33
+ return ExpressionType.TEXT;
34
+ }
35
+ };
36
+ const lower = {
37
+ call(value) {
38
+ const text = castAsText(value);
39
+ return text?.toLowerCase() ?? null;
40
+ },
41
+ parameters: [{ name: 'value', type: ExpressionType.ANY, optional: false }],
42
+ getReturnType(args) {
43
+ return ExpressionType.TEXT;
44
+ }
45
+ };
46
+ const hex = {
47
+ call(value) {
48
+ const binary = castAsBlob(value);
49
+ if (binary == null) {
50
+ return '';
51
+ }
52
+ return Buffer.from(binary).toString('hex').toUpperCase();
53
+ },
54
+ parameters: [{ name: 'value', type: ExpressionType.ANY, optional: false }],
55
+ getReturnType(args) {
56
+ return ExpressionType.TEXT;
57
+ }
58
+ };
59
+ const length = {
60
+ call(value) {
61
+ if (value == null) {
62
+ return null;
63
+ }
64
+ else if (value instanceof Uint8Array) {
65
+ return BigInt(value.byteLength);
66
+ }
67
+ else {
68
+ value = castAsText(value);
69
+ return BigInt(value.length);
70
+ }
71
+ },
72
+ parameters: [{ name: 'value', type: ExpressionType.ANY, optional: false }],
73
+ getReturnType(args) {
74
+ return ExpressionType.INTEGER;
75
+ }
76
+ };
77
+ const base64 = {
78
+ call(value) {
79
+ const binary = castAsBlob(value);
80
+ if (binary == null) {
81
+ return '';
82
+ }
83
+ return Buffer.from(binary).toString('base64');
84
+ },
85
+ parameters: [{ name: 'value', type: ExpressionType.ANY, optional: false }],
86
+ getReturnType(args) {
87
+ return ExpressionType.TEXT;
88
+ }
89
+ };
90
+ const fn_typeof = {
91
+ call(value) {
92
+ return sqliteTypeOf(value);
93
+ },
94
+ parameters: [{ name: 'value', type: ExpressionType.ANY, optional: false }],
95
+ getReturnType(args) {
96
+ return ExpressionType.TEXT;
97
+ }
98
+ };
99
+ const ifnull = {
100
+ call(x, y) {
101
+ if (x == null) {
102
+ return y;
103
+ }
104
+ else {
105
+ return x;
106
+ }
107
+ },
108
+ parameters: [
109
+ { name: 'x', type: ExpressionType.ANY, optional: false },
110
+ { name: 'y', type: ExpressionType.ANY, optional: false }
111
+ ],
112
+ getReturnType(args) {
113
+ if (args.length == 0) {
114
+ return ExpressionType.NONE;
115
+ }
116
+ else if (args.length == 1) {
117
+ return args[0];
118
+ }
119
+ else {
120
+ return args[0].or(args[1]);
121
+ }
122
+ }
123
+ };
124
+ const json_extract = {
125
+ call(json, path) {
126
+ return jsonExtract(json, path, 'json_extract');
127
+ },
128
+ parameters: [
129
+ { name: 'json', type: ExpressionType.ANY, optional: false },
130
+ { name: 'path', type: ExpressionType.ANY, optional: false }
131
+ ],
132
+ getReturnType(args) {
133
+ return ExpressionType.ANY_JSON;
134
+ }
135
+ };
136
+ const json_array_length = {
137
+ call(json, path) {
138
+ if (path != null) {
139
+ json = json_extract.call(json, path);
140
+ }
141
+ const jsonString = castAsText(json);
142
+ if (jsonString == null) {
143
+ return null;
144
+ }
145
+ const jsonParsed = JSONBig.parse(jsonString);
146
+ if (!Array.isArray(jsonParsed)) {
147
+ return 0n;
148
+ }
149
+ return BigInt(jsonParsed.length);
150
+ },
151
+ parameters: [
152
+ { name: 'json', type: ExpressionType.ANY, optional: false },
153
+ { name: 'path', type: ExpressionType.ANY, optional: true }
154
+ ],
155
+ getReturnType(args) {
156
+ return ExpressionType.INTEGER;
157
+ }
158
+ };
159
+ const json_valid = {
160
+ call(json) {
161
+ const jsonString = castAsText(json);
162
+ if (jsonString == null) {
163
+ return SQLITE_FALSE;
164
+ }
165
+ try {
166
+ JSONBig.parse(jsonString);
167
+ return SQLITE_TRUE;
168
+ }
169
+ catch (e) {
170
+ return SQLITE_FALSE;
171
+ }
172
+ },
173
+ parameters: [{ name: 'json', type: ExpressionType.ANY, optional: false }],
174
+ getReturnType(args) {
175
+ return ExpressionType.INTEGER;
176
+ }
177
+ };
178
+ const unixepoch = {
179
+ call(value, specifier, specifier2) {
180
+ if (value == null) {
181
+ return null;
182
+ }
183
+ let flags = {
184
+ unixepoch: false,
185
+ subsecond: false
186
+ };
187
+ if (specifier == null) {
188
+ }
189
+ else if (specifier == 'unixepoch') {
190
+ flags.unixepoch = true;
191
+ if (specifier2 == null) {
192
+ }
193
+ else if (specifier2 == 'subsec' || specifier2 == 'subsecond') {
194
+ flags.subsecond = true;
195
+ }
196
+ else {
197
+ return null;
198
+ }
199
+ }
200
+ else if (specifier == 'subsec' || specifier == 'subsecond') {
201
+ flags.subsecond = true;
202
+ }
203
+ else {
204
+ return null;
205
+ }
206
+ const epoch = convertToDate(value, flags)?.getTime();
207
+ if (epoch == null || !Number.isFinite(epoch)) {
208
+ return null;
209
+ }
210
+ if (flags.subsecond) {
211
+ return epoch / 1000.0;
212
+ }
213
+ else {
214
+ return BigInt(Math.floor(epoch / 1000.0));
215
+ }
216
+ },
217
+ parameters: [
218
+ { name: 'value', type: ExpressionType.ANY, optional: false },
219
+ { name: 'specifier', type: ExpressionType.ANY, optional: true },
220
+ { name: 'specifier2', type: ExpressionType.ANY, optional: true }
221
+ ],
222
+ getReturnType(args) {
223
+ return ExpressionType.INTEGER.or(ExpressionType.REAL);
224
+ }
225
+ };
226
+ const datetime = {
227
+ call(value, specifier, specifier2) {
228
+ if (value == null) {
229
+ return null;
230
+ }
231
+ let flags = {
232
+ unixepoch: false,
233
+ subsecond: false
234
+ };
235
+ if (specifier == null) {
236
+ }
237
+ else if (specifier == 'unixepoch') {
238
+ flags.unixepoch = true;
239
+ if (specifier2 == null) {
240
+ }
241
+ else if (specifier2 == 'subsec' || specifier2 == 'subsecond') {
242
+ flags.subsecond = true;
243
+ }
244
+ else {
245
+ return null;
246
+ }
247
+ }
248
+ else if (specifier == 'subsec' || specifier == 'subsecond') {
249
+ flags.subsecond = true;
250
+ }
251
+ else {
252
+ return null;
253
+ }
254
+ const epoch = convertToDate(value, flags);
255
+ if (epoch == null || !Number.isFinite(epoch.getTime())) {
256
+ return null;
257
+ }
258
+ const baseString = epoch.toISOString().replace(/T/, ' ').replace(/^\-0+/, '-');
259
+ if (flags.subsecond) {
260
+ return baseString.replace(/Z$/, '');
261
+ }
262
+ else {
263
+ return baseString.replace(/(\.\d+)?Z$/, '');
264
+ }
265
+ },
266
+ parameters: [
267
+ { name: 'value', type: ExpressionType.ANY, optional: false },
268
+ { name: 'specifier', type: ExpressionType.ANY, optional: true },
269
+ { name: 'specifier2', type: ExpressionType.ANY, optional: true }
270
+ ],
271
+ getReturnType(args) {
272
+ return ExpressionType.TEXT;
273
+ }
274
+ };
275
+ const st_asgeojson = {
276
+ call(geometry) {
277
+ const geo = parseGeometry(geometry);
278
+ if (geo == null) {
279
+ return null;
280
+ }
281
+ return JSONBig.stringify(geo.toGeoJSON());
282
+ },
283
+ parameters: [{ name: 'geometry', type: ExpressionType.ANY, optional: false }],
284
+ getReturnType(args) {
285
+ return ExpressionType.TEXT;
286
+ }
287
+ };
288
+ const st_astext = {
289
+ call(geometry) {
290
+ const geo = parseGeometry(geometry);
291
+ if (geo == null) {
292
+ return null;
293
+ }
294
+ return geo.toWkt();
295
+ },
296
+ parameters: [{ name: 'geometry', type: ExpressionType.ANY, optional: false }],
297
+ getReturnType(args) {
298
+ return ExpressionType.TEXT;
299
+ }
300
+ };
301
+ const st_x = {
302
+ call(geometry) {
303
+ const geo = parseGeometry(geometry);
304
+ if (geo == null) {
305
+ return null;
306
+ }
307
+ if (geo instanceof wkx.Point) {
308
+ return geo.x;
309
+ }
310
+ return null;
311
+ },
312
+ parameters: [{ name: 'geometry', type: ExpressionType.ANY, optional: false }],
313
+ getReturnType(args) {
314
+ return ExpressionType.REAL;
315
+ }
316
+ };
317
+ const st_y = {
318
+ call(geometry) {
319
+ const geo = parseGeometry(geometry);
320
+ if (geo == null) {
321
+ return null;
322
+ }
323
+ if (geo instanceof wkx.Point) {
324
+ return geo.y;
325
+ }
326
+ return null;
327
+ },
328
+ parameters: [{ name: 'geometry', type: ExpressionType.ANY, optional: false }],
329
+ getReturnType(args) {
330
+ return ExpressionType.REAL;
331
+ }
332
+ };
333
+ export const SQL_FUNCTIONS_NAMED = {
334
+ upper,
335
+ lower,
336
+ hex,
337
+ length,
338
+ base64,
339
+ typeof: fn_typeof,
340
+ ifnull,
341
+ json_extract,
342
+ json_array_length,
343
+ json_valid,
344
+ unixepoch,
345
+ datetime,
346
+ st_asgeojson,
347
+ st_astext,
348
+ st_x,
349
+ st_y
350
+ };
351
+ export const SQL_FUNCTIONS_CALL = Object.fromEntries(Object.entries(SQL_FUNCTIONS_NAMED).map(([name, fn]) => [name, fn.call]));
352
+ export const SQL_FUNCTIONS = SQL_FUNCTIONS_NAMED;
353
+ export const CAST_TYPES = new Set(['text', 'numeric', 'integer', 'real', 'blob']);
354
+ const textEncoder = new TextEncoder();
355
+ const textDecoder = new TextDecoder();
356
+ export function castAsText(value) {
357
+ if (value == null) {
358
+ return null;
359
+ }
360
+ else if (value instanceof Uint8Array) {
361
+ return textDecoder.decode(value);
362
+ }
363
+ else {
364
+ return value.toString();
365
+ }
366
+ }
367
+ export function castAsBlob(value) {
368
+ if (value == null) {
369
+ return null;
370
+ }
371
+ else if (value instanceof Uint8Array) {
372
+ return value;
373
+ }
374
+ if (typeof value != 'string') {
375
+ value = value.toString();
376
+ }
377
+ return textEncoder.encode(value);
378
+ }
379
+ export function cast(value, to) {
380
+ if (value == null) {
381
+ return null;
382
+ }
383
+ if (to == 'text') {
384
+ return castAsText(value);
385
+ }
386
+ else if (to == 'numeric') {
387
+ if (value instanceof Uint8Array) {
388
+ value = textDecoder.decode(value);
389
+ }
390
+ if (typeof value == 'string') {
391
+ return parseNumeric(value);
392
+ }
393
+ else if (typeof value == 'number' || typeof value == 'bigint') {
394
+ return value;
395
+ }
396
+ else {
397
+ return 0n;
398
+ }
399
+ }
400
+ else if (to == 'real') {
401
+ if (value instanceof Uint8Array) {
402
+ value = textDecoder.decode(value);
403
+ }
404
+ if (typeof value == 'string') {
405
+ const nr = parseFloat(value);
406
+ if (isNaN(nr)) {
407
+ return 0.0;
408
+ }
409
+ else {
410
+ return nr;
411
+ }
412
+ }
413
+ else if (typeof value == 'number') {
414
+ return value;
415
+ }
416
+ else if (typeof value == 'bigint') {
417
+ return Number(value);
418
+ }
419
+ else {
420
+ return 0.0;
421
+ }
422
+ }
423
+ else if (to == 'integer') {
424
+ if (value instanceof Uint8Array) {
425
+ value = textDecoder.decode(value);
426
+ }
427
+ if (typeof value == 'string') {
428
+ return parseBigInt(value);
429
+ }
430
+ else if (typeof value == 'number') {
431
+ return Number.isInteger(value) ? BigInt(value) : BigInt(Math.floor(value));
432
+ }
433
+ else if (typeof value == 'bigint') {
434
+ return value;
435
+ }
436
+ else {
437
+ return 0n;
438
+ }
439
+ }
440
+ else if (to == 'blob') {
441
+ return castAsBlob(value);
442
+ }
443
+ else {
444
+ throw new Error(`Type not supported for cast: '${to}'`);
445
+ }
446
+ }
447
+ export function sqliteTypeOf(arg) {
448
+ if (arg == null) {
449
+ return 'null';
450
+ }
451
+ else if (typeof arg == 'string') {
452
+ return 'text';
453
+ }
454
+ else if (typeof arg == 'bigint') {
455
+ return 'integer';
456
+ }
457
+ else if (typeof arg == 'number') {
458
+ return 'real';
459
+ }
460
+ else if (arg instanceof Uint8Array) {
461
+ return 'blob';
462
+ }
463
+ else {
464
+ // Should not happen
465
+ throw new Error(`Unknown type: ${arg}`);
466
+ }
467
+ }
468
+ export function parseGeometry(value) {
469
+ let blob;
470
+ if (value == null) {
471
+ return null;
472
+ }
473
+ else if (value instanceof Uint8Array) {
474
+ blob = Buffer.from(value);
475
+ }
476
+ else if (typeof value == 'string') {
477
+ blob = Buffer.from(value, 'hex');
478
+ }
479
+ else {
480
+ return null;
481
+ }
482
+ const geo = wkx.Geometry.parse(blob);
483
+ return geo;
484
+ }
485
+ function parseNumeric(text) {
486
+ const match = /^\s*(\d+)(\.\d*)?(e[+\-]?\d+)?/i.exec(text);
487
+ if (!match) {
488
+ return 0n;
489
+ }
490
+ if (match[2] != null || match[3] != null) {
491
+ const v = parseFloat(match[0]);
492
+ return isNaN(v) ? 0n : v;
493
+ }
494
+ else {
495
+ return BigInt(match[1]);
496
+ }
497
+ }
498
+ function parseBigInt(text) {
499
+ const match = /^\s*(\d+)/.exec(text);
500
+ if (!match) {
501
+ return 0n;
502
+ }
503
+ return BigInt(match[1]);
504
+ }
505
+ function isNumeric(a) {
506
+ return typeof a == 'number' || typeof a == 'bigint';
507
+ }
508
+ export function evaluateOperator(op, a, b) {
509
+ switch (op) {
510
+ case '=':
511
+ case '!=':
512
+ case '>':
513
+ case '<':
514
+ case '>=':
515
+ case '<=': {
516
+ if (a == null || b == null) {
517
+ return null;
518
+ }
519
+ const diff = compare(a, b);
520
+ if (op == '=') {
521
+ return sqliteBool(diff === 0);
522
+ }
523
+ else if (op == '!=') {
524
+ return sqliteBool(diff !== 0);
525
+ }
526
+ else if (op == '>') {
527
+ return sqliteBool(diff > 0);
528
+ }
529
+ else if (op == '<') {
530
+ return sqliteBool(diff < 0);
531
+ }
532
+ else if (op == '>=') {
533
+ return sqliteBool(diff >= 0);
534
+ }
535
+ else if (op == '<=') {
536
+ return sqliteBool(diff <= 0);
537
+ }
538
+ else {
539
+ throw new Error('unreachable');
540
+ }
541
+ }
542
+ // Not currently supported by the parser, but used with IS NULL
543
+ case 'IS': {
544
+ const diff = compare(a, b);
545
+ return sqliteBool(diff === 0);
546
+ }
547
+ // Not currently supported by the parser, but used with IS NOT NULL
548
+ case 'IS NOT': {
549
+ const diff = compare(a, b);
550
+ return sqliteBool(diff !== 0);
551
+ }
552
+ case '+':
553
+ case '-':
554
+ case '*':
555
+ case '/':
556
+ return doMath(op, a, b);
557
+ case '||':
558
+ return concat(a, b);
559
+ case 'AND':
560
+ return sqliteBool(sqliteBool(a) && sqliteBool(b));
561
+ case 'OR':
562
+ return sqliteBool(sqliteBool(a) || sqliteBool(b));
563
+ case 'IN':
564
+ if (a == null || b == null) {
565
+ return null;
566
+ }
567
+ if (typeof b != 'string') {
568
+ throw new Error('IN is only supported on JSON arrays');
569
+ }
570
+ const bParsed = JSON.parse(b);
571
+ if (!Array.isArray(bParsed)) {
572
+ throw new Error('IN is only supported on JSON arrays');
573
+ }
574
+ return sqliteBool(bParsed.includes(a));
575
+ default:
576
+ throw new Error(`Operator not supported: ${op}`);
577
+ }
578
+ }
579
+ export function getOperatorReturnType(op, left, right) {
580
+ switch (op) {
581
+ case '=':
582
+ case '!=':
583
+ case '>':
584
+ case '<':
585
+ case '>=':
586
+ case '<=': {
587
+ return ExpressionType.INTEGER;
588
+ }
589
+ // Not currently supported by the parser, but used with IS NULL
590
+ case 'IS': {
591
+ return ExpressionType.INTEGER;
592
+ }
593
+ // Not currently supported by the parser, but used with IS NOT NULL
594
+ case 'IS NOT': {
595
+ return ExpressionType.INTEGER;
596
+ }
597
+ case '+':
598
+ case '-':
599
+ case '*':
600
+ case '/':
601
+ if (left.typeFlags == TYPE_INTEGER && right.typeFlags == TYPE_INTEGER) {
602
+ // INT, INT stays INT
603
+ return ExpressionType.INTEGER;
604
+ }
605
+ else if (left.isNumericOnly() && right.isNumericOnly()) {
606
+ // INT, REAL or REAL, INT or REAL, REAL => always REAL
607
+ return ExpressionType.REAL;
608
+ }
609
+ else {
610
+ // Unknown - could be REAL or INT
611
+ return ExpressionType.NUMERIC;
612
+ }
613
+ case '||':
614
+ return ExpressionType.TEXT;
615
+ case 'AND':
616
+ return ExpressionType.INTEGER;
617
+ case 'OR':
618
+ return ExpressionType.INTEGER;
619
+ case 'IN':
620
+ return ExpressionType.INTEGER;
621
+ default:
622
+ return ExpressionType.NONE;
623
+ }
624
+ }
625
+ function doMath(op, a, b) {
626
+ if (a == null || b == null) {
627
+ return null;
628
+ }
629
+ let na = cast(a, 'numeric');
630
+ let nb = cast(b, 'numeric');
631
+ if (typeof na == 'bigint' && typeof nb != 'bigint') {
632
+ // bigint, real
633
+ na = Number(na);
634
+ }
635
+ else if (typeof na != 'bigint' && typeof nb == 'bigint') {
636
+ // real, bigint
637
+ nb = Number(nb);
638
+ }
639
+ switch (op) {
640
+ case '+':
641
+ return na + nb;
642
+ case '-':
643
+ return na - nb;
644
+ case '*':
645
+ return na * nb;
646
+ case '/':
647
+ return na / nb;
648
+ default:
649
+ throw new Error(`Operator not supported: ${op}`);
650
+ }
651
+ }
652
+ function concat(a, b) {
653
+ const aText = castAsText(a);
654
+ const bText = castAsText(b);
655
+ if (aText == null || bText == null) {
656
+ return null;
657
+ }
658
+ return aText + bText;
659
+ }
660
+ export function jsonExtract(sourceValue, path, operator) {
661
+ const valueText = castAsText(sourceValue);
662
+ const pathText = castAsText(path);
663
+ if (valueText == null || pathText == null) {
664
+ return null;
665
+ }
666
+ const components = pathText.split('.');
667
+ if (components[0] == '$') {
668
+ components.shift();
669
+ }
670
+ else if (operator == 'json_extract') {
671
+ throw new Error(`JSON path must start with $.`);
672
+ }
673
+ let value = JSONBig.parse(valueText);
674
+ for (let c of components) {
675
+ if (value == null) {
676
+ break;
677
+ }
678
+ value = value[c];
679
+ }
680
+ if (operator == '->') {
681
+ // -> must always stringify
682
+ return JSONBig.stringify(value);
683
+ }
684
+ else if (typeof value == 'object' || Array.isArray(value)) {
685
+ // Objects and arrays must be stringified
686
+ return JSONBig.stringify(value);
687
+ }
688
+ else {
689
+ // Plain scalar value - simple conversion.
690
+ return jsonValueToSqlite(value);
691
+ }
692
+ }
693
+ export function convertToDate(dateTime, flags) {
694
+ if (typeof dateTime == 'string') {
695
+ return parseUTCDate(dateTime);
696
+ }
697
+ else if (typeof dateTime == 'bigint') {
698
+ if (flags.unixepoch) {
699
+ return new Date(Number(dateTime) * 1000.0);
700
+ }
701
+ else {
702
+ return julianToJSDate(Number(dateTime));
703
+ }
704
+ }
705
+ else if (typeof dateTime == 'number') {
706
+ if (flags.unixepoch) {
707
+ return new Date(dateTime * 1000.0);
708
+ }
709
+ else {
710
+ return julianToJSDate(dateTime);
711
+ }
712
+ }
713
+ else {
714
+ return null;
715
+ }
716
+ }
717
+ function parseUTCDate(isoDateString) {
718
+ const hasTimezone = /[Zz]|[+\-]\d{2}:\d{2}$/;
719
+ const isJulienDay = /^\d+(\.\d*)?$/;
720
+ if (hasTimezone.test(isoDateString)) {
721
+ // If the string already has a timezone, parse it directly
722
+ return new Date(isoDateString);
723
+ }
724
+ else if (isJulienDay.test(isoDateString)) {
725
+ return julianToJSDate(parseFloat(isoDateString));
726
+ }
727
+ else {
728
+ // If the string has no timezone, append "Z" to the end to interpret it as UTC
729
+ return new Date(isoDateString + 'Z');
730
+ }
731
+ }
732
+ function julianToJSDate(julianDay) {
733
+ // The Julian date for the Unix Epoch is 2440587.5
734
+ const julianAtEpoch = 2440587.5;
735
+ // Calculate the difference between the Julian date and the Unix Epoch in days
736
+ const daysSinceEpoch = julianDay - julianAtEpoch;
737
+ // Convert this to milliseconds
738
+ const msSinceEpoch = daysSinceEpoch * 24 * 60 * 60 * 1000;
739
+ // Create a new Date object with this number of milliseconds since the Unix Epoch
740
+ return new Date(msSinceEpoch);
741
+ }
742
+ const TYPE_ORDERING = {
743
+ null: 0,
744
+ integer: 1,
745
+ real: 1,
746
+ text: 2,
747
+ blob: 3
748
+ };
749
+ function compare(a, b) {
750
+ // https://www.sqlite.org/datatype3.html#comparisons
751
+ if (a == null && b == null) {
752
+ // Only for IS / IS NOT
753
+ return 0;
754
+ }
755
+ if ((isNumeric(a) && isNumeric(b)) || (typeof a == 'string' && typeof b == 'string')) {
756
+ if (a == b) {
757
+ return 0;
758
+ }
759
+ else if (a > b) {
760
+ return 1;
761
+ }
762
+ else {
763
+ return -1;
764
+ }
765
+ }
766
+ else if (a instanceof Uint8Array && b instanceof Uint8Array) {
767
+ throw new Error('Comparing blobs is not supported currently');
768
+ }
769
+ const typeA = sqliteTypeOf(a);
770
+ const typeB = sqliteTypeOf(b);
771
+ return TYPE_ORDERING[typeA] - TYPE_ORDERING[typeB];
772
+ }
773
+ //# sourceMappingURL=sql_functions.js.map