proto.io 0.0.215 → 0.0.217

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 (48) hide show
  1. package/dist/adapters/file/aliyun-oss.d.ts +3 -3
  2. package/dist/adapters/file/database.d.ts +2 -2
  3. package/dist/adapters/file/database.js +1 -1
  4. package/dist/adapters/file/database.mjs +2 -2
  5. package/dist/adapters/file/filesystem.d.ts +3 -3
  6. package/dist/adapters/file/google-cloud-storage.d.ts +3 -3
  7. package/dist/adapters/storage/progres.d.ts +8 -10
  8. package/dist/adapters/storage/progres.js +833 -451
  9. package/dist/adapters/storage/progres.js.map +1 -1
  10. package/dist/adapters/storage/progres.mjs +834 -452
  11. package/dist/adapters/storage/progres.mjs.map +1 -1
  12. package/dist/client.d.ts +3 -3
  13. package/dist/client.js +1 -7
  14. package/dist/client.js.map +1 -1
  15. package/dist/client.mjs +3 -3
  16. package/dist/client.mjs.map +1 -1
  17. package/dist/index.d.ts +3 -3
  18. package/dist/index.js +9 -16
  19. package/dist/index.js.map +1 -1
  20. package/dist/index.mjs +11 -12
  21. package/dist/index.mjs.map +1 -1
  22. package/dist/internals/{base-Cp5le5dC.d.ts → base-CWnOBKD5.d.ts} +2 -2
  23. package/dist/internals/base-CWnOBKD5.d.ts.map +1 -0
  24. package/dist/internals/{chunk--Vo2-p-z.d.ts → chunk-CNNSQpRF.d.ts} +3 -3
  25. package/dist/internals/chunk-CNNSQpRF.d.ts.map +1 -0
  26. package/dist/internals/{index-CZUGnb-y.d.ts → index-BRIlS3mY.d.ts} +3 -9
  27. package/dist/internals/index-BRIlS3mY.d.ts.map +1 -0
  28. package/dist/internals/{index-YLrO0f2D.d.ts → index-Bs8n7Q8f.d.ts} +60 -20
  29. package/dist/internals/index-Bs8n7Q8f.d.ts.map +1 -0
  30. package/dist/internals/{index-al1N-qi7.mjs → index-BzDsTt4R.mjs} +2 -2
  31. package/dist/internals/{index-al1N-qi7.mjs.map → index-BzDsTt4R.mjs.map} +1 -1
  32. package/dist/internals/{index-ZPbBr9Db.mjs → index-DfqABzjr.mjs} +135 -142
  33. package/dist/internals/index-DfqABzjr.mjs.map +1 -0
  34. package/dist/internals/{index-DfnPpl1I.js → index-DylUjD_1.js} +133 -146
  35. package/dist/internals/index-DylUjD_1.js.map +1 -0
  36. package/dist/internals/{validator-ChrCrz_C.mjs → validator-CEcBF4Cn.mjs} +730 -27
  37. package/dist/internals/validator-CEcBF4Cn.mjs.map +1 -0
  38. package/dist/internals/{validator-m6wY35c6.js → validator-mcBCJP4P.js} +737 -27
  39. package/dist/internals/validator-mcBCJP4P.js.map +1 -0
  40. package/package.json +1 -1
  41. package/dist/internals/base-Cp5le5dC.d.ts.map +0 -1
  42. package/dist/internals/chunk--Vo2-p-z.d.ts.map +0 -1
  43. package/dist/internals/index-CZUGnb-y.d.ts.map +0 -1
  44. package/dist/internals/index-DfnPpl1I.js.map +0 -1
  45. package/dist/internals/index-YLrO0f2D.d.ts.map +0 -1
  46. package/dist/internals/index-ZPbBr9Db.mjs.map +0 -1
  47. package/dist/internals/validator-ChrCrz_C.mjs.map +0 -1
  48. package/dist/internals/validator-m6wY35c6.js.map +0 -1
@@ -1,11 +1,11 @@
1
1
  import _ from 'lodash';
2
- import { a as isRelation, i as isPointer, b as isShape, e as decodeUpdateOp, s as shapePaths, c as isPrimitive, T as TObject, _ as _isTypeof, f as isVector, g as _encodeValue, h as _decodeValue, j as dimensionOf, k as _typeof } from '../../internals/index-al1N-qi7.mjs';
2
+ import { a as isRelation, i as isPointer, b as isShape, e as decodeUpdateOp, s as shapePaths, c as isPrimitive, T as TObject, _ as _encodeValue, f as dimensionOf, g as _decodeValue, h as _typeof, j as isVector, k as _isTypeof } from '../../internals/index-BzDsTt4R.mjs';
3
3
  import { Pool, types } from 'pg';
4
4
  import QueryStream from 'pg-query-stream';
5
5
  import { asyncStream, IteratorPool } from '@o2ter/utils-js';
6
6
  import Decimal from 'decimal.js';
7
7
  import { escapeLiteral, escapeIdentifier } from 'pg/lib/utils';
8
- import { r as resolveColumn, a as resolveDataType$1, c as QueryCoditionalSelector, d as QueryFieldSelector, e as QueryExpressionSelector, Q as QueryValidator, f as QueryDistanceExpression, g as QueryKeyExpression, h as QueryValueExpression, i as QueryCoditionalExpression, j as QueryComparisonExpression, k as QueryNotExpression, l as QueryArrayExpression, m as QueryNoParamAccumulator, n as QueryExprAccumulator, o as QueryPercentileAccumulator, b as QuerySelector, F as FieldSelectorExpression } from '../../internals/validator-ChrCrz_C.mjs';
8
+ import { r as resolveColumn, b as resolveDataType$1, d as QueryCoditionalSelector, e as QueryFieldSelector, f as QueryExpressionSelector, g as QueryArrayExpression, h as QueryValueExpression, i as QueryKeyExpression, j as QueryCoditionalExpression, k as QueryComparisonExpression, l as QueryNotExpression, m as QueryDistanceExpression, n as QueryZeroParamExpression, o as QueryUnaryExpression, p as QueryBinaryExpression, q as QueryListExpression, s as QueryTernaryExpression, t as QueryCondExpression, Q as QueryValidator, u as QueryZeroParamAccumulator, v as QueryUnaryAccumulator, w as QueryPercentileAccumulator, c as QuerySelector, F as FieldSelectorExpression } from '../../internals/validator-CEcBF4Cn.mjs';
9
9
  import '@o2ter/crypto-js';
10
10
  import { c as PROTO_EVENT } from '../../internals/const-Dkp7Nsv5.mjs';
11
11
  import { g as generateId } from '../../internals/random-CYjWDvex.mjs';
@@ -409,7 +409,7 @@ class QueryCompiler {
409
409
  return this.dialect.encodeFieldExpression(this, parent, filter.field, filter.expr);
410
410
  }
411
411
  if (filter instanceof QueryExpressionSelector) {
412
- return this.dialect.encodeQueryExpression(this, parent, filter.expr);
412
+ return this.dialect.encodeBooleanExpression(this, parent, filter.expr);
413
413
  }
414
414
  }
415
415
  _selectIncludes(className, includes) {
@@ -424,7 +424,7 @@ class QueryCompiler {
424
424
  _encodeSort(sort, parent) {
425
425
  if (_.isArray(sort)) {
426
426
  return sql `${_.map(sort, ({ expr, order }) => {
427
- const _expr = this.dialect.encodeQueryExpression(this, parent, expr);
427
+ const _expr = this.dialect.encodeSortExpression(this, parent, expr);
428
428
  if (!_expr)
429
429
  throw Error('Invalid expression');
430
430
  return sql `${_expr} ${{ literal: order === 1 ? 'ASC' : 'DESC' }}`;
@@ -536,6 +536,728 @@ class QueryCompiler {
536
536
  }
537
537
  }
538
538
 
539
+ //
540
+ // encode.ts
541
+ //
542
+ // The MIT License
543
+ // Copyright (c) 2021 - 2025 O2ter Limited. All rights reserved.
544
+ //
545
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
546
+ // of this software and associated documentation files (the "Software"), to deal
547
+ // in the Software without restriction, including without limitation the rights
548
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
549
+ // copies of the Software, and to permit persons to whom the Software is
550
+ // furnished to do so, subject to the following conditions:
551
+ //
552
+ // The above copyright notice and this permission notice shall be included in
553
+ // all copies or substantial portions of the Software.
554
+ //
555
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
556
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
557
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
558
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
559
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
560
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
561
+ // THE SOFTWARE.
562
+ //
563
+ const _encodeJsonValue = (value) => {
564
+ if (_.isArray(value))
565
+ return sql `jsonb_build_array(${_.map(value, x => _encodeJsonValue(x))})`;
566
+ if (_.isPlainObject(value))
567
+ return sql `jsonb_build_object(${_.map(value, (v, k) => sql `${{ value: k }}, ${_encodeJsonValue(v)}`)})`;
568
+ return sql `to_jsonb(${{ value }})`;
569
+ };
570
+ const _jsonPopulateInclude = (className, colname, dataType) => {
571
+ switch (_typeof(dataType)) {
572
+ case 'decimal':
573
+ return sql `jsonb_build_object(
574
+ '$decimal', CAST(${{ identifier: className }}.${{ identifier: colname }} AS TEXT)
575
+ ) AS ${{ identifier: colname }}`;
576
+ case 'date':
577
+ return sql `jsonb_build_object(
578
+ '$date', to_char(${{ identifier: className }}.${{ identifier: colname }} AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"')
579
+ ) AS ${{ identifier: colname }}`;
580
+ default:
581
+ return sql `${{ identifier: className }}.${{ identifier: colname }}`;
582
+ }
583
+ };
584
+ const encodeType = (colname, dataType, value) => {
585
+ if (_.isNil(value))
586
+ return sql `NULL`;
587
+ switch (_.isString(dataType) ? dataType : dataType.type) {
588
+ case 'boolean':
589
+ if (_.isBoolean(value))
590
+ return sql `${{ value }}`;
591
+ break;
592
+ case 'number':
593
+ if (_.isNumber(value) && _.isFinite(value))
594
+ return sql `${{ value }}`;
595
+ if (value instanceof Decimal)
596
+ return sql `${{ value: value.toNumber() }}`;
597
+ break;
598
+ case 'decimal':
599
+ if (_.isNumber(value) && _.isFinite(value))
600
+ return sql `CAST(${{ quote: (new Decimal(value)).toString() }} AS DECIMAL)`;
601
+ if (value instanceof Decimal)
602
+ return sql `CAST(${{ quote: value.toString() }} AS DECIMAL)`;
603
+ break;
604
+ case 'string':
605
+ if (_.isString(value))
606
+ return sql `${{ value }}`;
607
+ break;
608
+ case 'string[]':
609
+ if (_.isArray(value) && _.every(value, x => _.isString(x)))
610
+ return sql `ARRAY[${_.map(value, x => sql `${{ value: x }}`)}]::TEXT[]`;
611
+ break;
612
+ case 'date':
613
+ if (_.isDate(value))
614
+ return sql `${{ value }}`;
615
+ break;
616
+ case 'object':
617
+ if (_.isPlainObject(value))
618
+ return sql `${{ value: _encodeValue(value) }}`;
619
+ break;
620
+ case 'vector':
621
+ if (!_.isArray(value) || value.length !== dimensionOf(dataType))
622
+ break;
623
+ if (!_.every(value, x => _.isFinite(x)))
624
+ break;
625
+ return sql `${{ value }}::DOUBLE PRECISION[]`;
626
+ case 'array':
627
+ if (!_.isArray(value))
628
+ break;
629
+ return sql `ARRAY[${_.map(value, x => _encodeJsonValue(_encodeValue(x)))}]::JSONB[]`;
630
+ case 'pointer':
631
+ if (value instanceof TObject && value.objectId)
632
+ return sql `${{ value: `${value.className}$${value.objectId}` }}`;
633
+ break;
634
+ case 'relation':
635
+ if (_.isArray(value) && _.every(value, x => x instanceof TObject && x.objectId)) {
636
+ return sql `${{ value: _.uniq(_.map(value, (x) => `${x.className}$${x.objectId}`)) }}`;
637
+ }
638
+ break;
639
+ }
640
+ throw Error('Invalid data type');
641
+ };
642
+ const decodeType = (type, value) => {
643
+ switch (type) {
644
+ case 'boolean':
645
+ if (_.isBoolean(value))
646
+ return value;
647
+ if (value === 'true')
648
+ return true;
649
+ if (value === 'false')
650
+ return false;
651
+ break;
652
+ case 'number':
653
+ if (_.isNumber(value))
654
+ return value;
655
+ if (_.isString(value)) {
656
+ const float = parseFloat(value);
657
+ return _.isNaN(float) ? null : float;
658
+ }
659
+ break;
660
+ case 'decimal':
661
+ if (_.isString(value) || _.isNumber(value))
662
+ return new Decimal(value);
663
+ if (value instanceof Decimal)
664
+ return value;
665
+ if (_.isPlainObject(value) && _.isString(value.$decimal))
666
+ return new Decimal(value.$decimal);
667
+ break;
668
+ case 'string':
669
+ if (_.isString(value))
670
+ return value;
671
+ break;
672
+ case 'string[]':
673
+ if (_.isArray(value) && _.every(value, x => _.isString(x)))
674
+ return value;
675
+ break;
676
+ case 'date':
677
+ if (_.isDate(value))
678
+ return value;
679
+ if (_.isString(value)) {
680
+ const date = new Date(value);
681
+ if (isFinite(date.valueOf()))
682
+ return date;
683
+ }
684
+ if (_.isPlainObject(value) && _.isString(value.$date))
685
+ return new Date(value.$date);
686
+ break;
687
+ case 'object':
688
+ if (_.isPlainObject(value))
689
+ return _decodeValue(value);
690
+ break;
691
+ case 'array':
692
+ if (_.isArray(value))
693
+ return _decodeValue(value);
694
+ break;
695
+ case 'vector':
696
+ if (!_.isArray(value))
697
+ break;
698
+ if (_.every(value, x => _.isNumber(x))) {
699
+ return value;
700
+ }
701
+ break;
702
+ }
703
+ return null;
704
+ };
705
+
706
+ //
707
+ // types.ts
708
+ //
709
+ // The MIT License
710
+ // Copyright (c) 2021 - 2025 O2ter Limited. All rights reserved.
711
+ //
712
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
713
+ // of this software and associated documentation files (the "Software"), to deal
714
+ // in the Software without restriction, including without limitation the rights
715
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
716
+ // copies of the Software, and to permit persons to whom the Software is
717
+ // furnished to do so, subject to the following conditions:
718
+ //
719
+ // The above copyright notice and this permission notice shall be included in
720
+ // all copies or substantial portions of the Software.
721
+ //
722
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
723
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
724
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
725
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
726
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
727
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
728
+ // THE SOFTWARE.
729
+ //
730
+ const _PrimitiveValue = ['boolean', 'number', 'decimal', 'string', 'date'];
731
+ const isArrayExpr = (expr) => {
732
+ if (expr instanceof QueryArrayExpression)
733
+ return true;
734
+ if (expr instanceof QueryValueExpression)
735
+ return _.isArray(expr.value);
736
+ return false;
737
+ };
738
+ const arrayLength = (expr) => {
739
+ if (expr instanceof QueryArrayExpression)
740
+ return expr.exprs.length;
741
+ if (expr instanceof QueryValueExpression)
742
+ return _.isArray(expr.value) ? expr.value.length : 0;
743
+ return 0;
744
+ };
745
+ const mapExpr = (expr, callback) => {
746
+ if (expr instanceof QueryArrayExpression)
747
+ return _.map(expr.exprs, x => callback(x));
748
+ if (expr instanceof QueryValueExpression)
749
+ return _.isArray(expr.value) ? _.map(expr.value, x => callback(new QueryValueExpression(x))) : [];
750
+ return [];
751
+ };
752
+ const zipExpr = (lhs, rhs) => {
753
+ const result = [];
754
+ for (const [l, r] of _.zip(lhs, rhs)) {
755
+ if (!l || !r)
756
+ return;
757
+ if (l.type === r.type)
758
+ result.push([l, r]);
759
+ else if (l.type === 'number' && r.type === 'decimal')
760
+ result.push([l, { type: 'decimal', sql: sql `CAST((${r.sql}) AS DECIMAL)` }]);
761
+ else if (l.type === 'decimal' && r.type === 'number')
762
+ result.push([{ type: 'decimal', sql: sql `CAST((${l.sql}) AS DECIMAL)` }, r]);
763
+ else
764
+ return;
765
+ }
766
+ return result;
767
+ };
768
+ const typeCastExpr = (expr, type) => {
769
+ if (!expr)
770
+ return;
771
+ if (expr.type === type)
772
+ return expr;
773
+ if (expr.type === 'number' && type === 'decimal')
774
+ return { type, sql: sql `CAST((${expr.sql}) AS DECIMAL)` };
775
+ if (expr.type === 'decimal' && type === 'number')
776
+ return { type, sql: sql `CAST((${expr.sql}) AS DOUBLE PRECISION)` };
777
+ };
778
+
779
+ //
780
+ // vector.ts
781
+ //
782
+ // The MIT License
783
+ // Copyright (c) 2021 - 2025 O2ter Limited. All rights reserved.
784
+ //
785
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
786
+ // of this software and associated documentation files (the "Software"), to deal
787
+ // in the Software without restriction, including without limitation the rights
788
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
789
+ // copies of the Software, and to permit persons to whom the Software is
790
+ // furnished to do so, subject to the following conditions:
791
+ //
792
+ // The above copyright notice and this permission notice shall be included in
793
+ // all copies or substantial portions of the Software.
794
+ //
795
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
796
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
797
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
798
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
799
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
800
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
801
+ // THE SOFTWARE.
802
+ //
803
+ const encodeVectorExpression = (compiler, parent, exprs) => {
804
+ if (exprs.length === 1) {
805
+ const [expr] = exprs;
806
+ if (expr instanceof QueryKeyExpression) {
807
+ const { element, dataType } = fetchElement(compiler, parent, expr.key);
808
+ if (!dataType || !isVector(dataType))
809
+ throw Error('Invalid expression');
810
+ return { sql: element, dimension: dataType.dimension };
811
+ }
812
+ if (expr instanceof QueryValueExpression) {
813
+ if (!_.isArray(expr.value) || !_.every(expr.value, x => _.isFinite(x)))
814
+ throw Error('Invalid expression');
815
+ return { sql: sql `${{ value: expr.value }}::DOUBLE PRECISION[]`, dimension: expr.value.length };
816
+ }
817
+ }
818
+ const result = _.compact(_.map(exprs, x => typeCastExpr(encodeTypedQueryExpression(compiler, parent, x), 'number')?.sql));
819
+ if (result.length !== exprs.length)
820
+ throw Error('Invalid expression');
821
+ return { sql: sql `ARRAY[${_.map(result, x => sql `COALESCE(${x}, 0)`)}]`, dimension: result.length };
822
+ };
823
+ const encodeDistanceQueryExpression = (compiler, parent, expr) => {
824
+ const { sql: left, dimension: d1 } = encodeVectorExpression(compiler, parent, expr.left);
825
+ const { sql: right, dimension: d2 } = encodeVectorExpression(compiler, parent, expr.right);
826
+ if (d1 !== d2)
827
+ throw Error('Invalid expression');
828
+ const operatorMap = {
829
+ '$distance': sql `<->`,
830
+ '$innerProduct': sql `<#>`,
831
+ '$negInnerProduct': sql `<#>`,
832
+ '$cosineDistance': sql `<=>`,
833
+ '$rectilinearDistance': sql `<+>`,
834
+ };
835
+ const _expr = sql `
836
+ CAST(
837
+ ${left} AS VECTOR(${{ literal: `${d1}` }})
838
+ )
839
+ ${operatorMap[expr.type]}
840
+ CAST(
841
+ ${right} AS VECTOR(${{ literal: `${d2}` }})
842
+ )
843
+ `;
844
+ return expr.type === '$innerProduct' ? sql `-1 * (${_expr})` : _expr;
845
+ };
846
+
847
+ //
848
+ // index.ts
849
+ //
850
+ // The MIT License
851
+ // Copyright (c) 2021 - 2025 O2ter Limited. All rights reserved.
852
+ //
853
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
854
+ // of this software and associated documentation files (the "Software"), to deal
855
+ // in the Software without restriction, including without limitation the rights
856
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
857
+ // copies of the Software, and to permit persons to whom the Software is
858
+ // furnished to do so, subject to the following conditions:
859
+ //
860
+ // The above copyright notice and this permission notice shall be included in
861
+ // all copies or substantial portions of the Software.
862
+ //
863
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
864
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
865
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
866
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
867
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
868
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
869
+ // THE SOFTWARE.
870
+ //
871
+ const encodeTypedQueryExpression = (compiler, parent, expr) => {
872
+ if (expr instanceof QueryKeyExpression) {
873
+ const { element, dataType } = fetchElement(compiler, parent, expr.key);
874
+ const _dataType = dataType ? _typeof(dataType) : null;
875
+ if (!_dataType || !_PrimitiveValue.includes(_dataType))
876
+ return;
877
+ return { type: _dataType, sql: element };
878
+ }
879
+ if (expr instanceof QueryValueExpression) {
880
+ if (_.isBoolean(expr.value))
881
+ return { type: 'boolean', sql: sql `${{ value: expr.value }}` };
882
+ if (_.isNumber(expr.value))
883
+ return { type: 'number', sql: sql `${{ value: expr.value }}` };
884
+ if (expr.value instanceof Decimal)
885
+ return { type: 'decimal', sql: sql `CAST(${{ quote: expr.value.toString() }} AS DECIMAL)` };
886
+ if (_.isString(expr.value))
887
+ return { type: 'string', sql: sql `${{ value: expr.value }}` };
888
+ if (_.isDate(expr.value))
889
+ return { type: 'date', sql: sql `${{ value: expr.value }}` };
890
+ }
891
+ if (expr instanceof QueryCoditionalExpression ||
892
+ expr instanceof QueryComparisonExpression ||
893
+ expr instanceof QueryNotExpression) {
894
+ const value = encodeBooleanExpression(compiler, parent, expr);
895
+ if (value)
896
+ return { type: 'boolean', sql: value };
897
+ }
898
+ if (expr instanceof QueryDistanceExpression) {
899
+ const value = encodeDistanceQueryExpression(compiler, parent, expr);
900
+ return { type: 'number', sql: value };
901
+ }
902
+ if (expr instanceof QueryZeroParamExpression) {
903
+ switch (expr.type) {
904
+ case '$rand': return { type: 'number', sql: sql `RANDOM()` };
905
+ case '$now': return { type: 'date', sql: sql `CAST(NOW() AS TIMESTAMP(3) WITH TIME ZONE)` };
906
+ }
907
+ }
908
+ if (expr instanceof QueryUnaryExpression) {
909
+ const value = encodeTypedQueryExpression(compiler, parent, expr.expr);
910
+ if (!value)
911
+ return;
912
+ switch (expr.type) {
913
+ case '$abs':
914
+ case '$neg':
915
+ case '$sqrt':
916
+ case '$cbrt':
917
+ case '$ceil':
918
+ case '$floor':
919
+ case '$round':
920
+ case '$exp':
921
+ case '$ln':
922
+ case '$log10':
923
+ case '$sin':
924
+ case '$cos':
925
+ case '$tan':
926
+ case '$asin':
927
+ case '$acos':
928
+ case '$atan':
929
+ case '$asinh':
930
+ case '$acosh':
931
+ case '$atanh':
932
+ case '$sinh':
933
+ case '$cosh':
934
+ case '$tanh':
935
+ case '$degrees':
936
+ case '$radians':
937
+ case '$sign':
938
+ {
939
+ const op = {
940
+ '$abs': 'ABS',
941
+ '$neg': '-',
942
+ '$sqrt': 'SQRT',
943
+ '$cbrt': 'CBRT',
944
+ '$ceil': 'CEIL',
945
+ '$floor': 'FLOOR',
946
+ '$round': 'ROUND',
947
+ '$exp': 'EXP',
948
+ '$ln': 'LN',
949
+ '$log10': 'LOG10',
950
+ '$sin': 'SIN',
951
+ '$cos': 'COS',
952
+ '$tan': 'TAN',
953
+ '$asin': 'ASIN',
954
+ '$acos': 'ACOS',
955
+ '$atan': 'ATAN',
956
+ '$asinh': 'ASINH',
957
+ '$acosh': 'ACOSH',
958
+ '$atanh': 'ATANH',
959
+ '$sinh': 'SINH',
960
+ '$cosh': 'COSH',
961
+ '$tanh': 'TANH',
962
+ '$degrees': 'DEGREES',
963
+ '$radians': 'RADIANS',
964
+ '$sign': 'SIGN',
965
+ }[expr.type];
966
+ if (!_.includes(['number', 'decimal'], value.type))
967
+ return;
968
+ return { type: 'number', sql: sql `${{ literal: op }}(${value.sql})` };
969
+ }
970
+ case '$log2':
971
+ if (!_.includes(['number', 'decimal'], value.type))
972
+ return;
973
+ return { type: value.type, sql: sql `(LOG(${value.sql}) / LOG(2))` };
974
+ case '$size':
975
+ if (!_.includes(['string', 'string[]', 'array'], value.type))
976
+ return;
977
+ return { type: 'number', sql: sql `LENGTH(${value.sql})` };
978
+ case '$lower':
979
+ case '$upper':
980
+ {
981
+ const op = {
982
+ '$lower': 'LOWER',
983
+ '$upper': 'UPPER',
984
+ }[expr.type];
985
+ if (value.type !== 'string')
986
+ return;
987
+ return { type: 'string', sql: sql `${{ literal: op }}(${value.sql})` };
988
+ }
989
+ }
990
+ }
991
+ if (expr instanceof QueryBinaryExpression) {
992
+ const left = encodeTypedQueryExpression(compiler, parent, expr.left);
993
+ const right = encodeTypedQueryExpression(compiler, parent, expr.right);
994
+ if (!left || !right)
995
+ return;
996
+ switch (expr.type) {
997
+ case '$divide':
998
+ case '$subtract':
999
+ {
1000
+ const op = {
1001
+ '$divide': '/',
1002
+ '$subtract': '-',
1003
+ }[expr.type];
1004
+ if (left.type === right.type) {
1005
+ return { type: left.type, sql: sql `(${left.sql}) ${{ literal: op }} (${right.sql})` };
1006
+ }
1007
+ if (left.type === 'decimal' && right.type === 'number') {
1008
+ return { type: 'decimal', sql: sql `CAST((${left.sql}) AS DECIMAL) ${{ literal: op }} (${right.sql})` };
1009
+ }
1010
+ if (left.type === 'number' && right.type === 'decimal') {
1011
+ return { type: 'decimal', sql: sql `(${left.sql}) ${{ literal: op }} CAST((${right.sql}) AS DECIMAL)` };
1012
+ }
1013
+ }
1014
+ break;
1015
+ case '$log':
1016
+ {
1017
+ if (left.type === right.type) {
1018
+ return { type: left.type, sql: sql `(LOG(${left.sql}) / LOG(${right.sql}))` };
1019
+ }
1020
+ if (left.type === 'decimal' && right.type === 'number') {
1021
+ return { type: 'decimal', sql: sql `(LOG(${left.sql}) / LOG(CAST((${right.sql}) AS DECIMAL)))` };
1022
+ }
1023
+ if (left.type === 'number' && right.type === 'decimal') {
1024
+ return { type: 'decimal', sql: sql `(LOG(CAST((${left.sql}) AS DECIMAL) / LOG(${right.sql}))` };
1025
+ }
1026
+ }
1027
+ break;
1028
+ case '$pow':
1029
+ case '$atan2':
1030
+ {
1031
+ const op = {
1032
+ '$pow': 'POWER',
1033
+ '$atan2': 'ATAN2',
1034
+ }[expr.type];
1035
+ if (left.type === right.type) {
1036
+ return { type: left.type, sql: sql `${{ literal: op }}((${left.sql}), (${right.sql}))` };
1037
+ }
1038
+ if (left.type === 'decimal' && right.type === 'number') {
1039
+ return { type: 'decimal', sql: sql `${{ literal: op }}((${left.sql}), CAST((${right.sql}) AS DECIMAL))` };
1040
+ }
1041
+ if (left.type === 'number' && right.type === 'decimal') {
1042
+ return { type: 'decimal', sql: sql `${{ literal: op }}(CAST((${left.sql}) AS DECIMAL), (${right.sql}))` };
1043
+ }
1044
+ }
1045
+ break;
1046
+ case '$trim':
1047
+ case '$ltrim':
1048
+ case '$rtrim':
1049
+ {
1050
+ const op = {
1051
+ '$trim': 'TRIM',
1052
+ '$ltrim': 'LTRIM',
1053
+ '$rtrim': 'RTRIM',
1054
+ }[expr.type];
1055
+ if (left?.type !== 'string' || right?.type !== 'string')
1056
+ return;
1057
+ return { type: 'string', sql: sql `${{ literal: op }}(${left.sql}, ${right.sql})` };
1058
+ }
1059
+ case '$first':
1060
+ case '$last':
1061
+ {
1062
+ if (!_.includes(['number', 'decimal'], right.type))
1063
+ return;
1064
+ if (left?.type === 'string') {
1065
+ const op = {
1066
+ '$first': 'LEFT',
1067
+ '$last': 'RIGHT',
1068
+ }[expr.type];
1069
+ return { type: 'string', sql: sql `${{ literal: op }}(${left.sql}, ${right.sql})` };
1070
+ }
1071
+ }
1072
+ break;
1073
+ case '$ldrop':
1074
+ case '$rdrop':
1075
+ {
1076
+ if (!_.includes(['number', 'decimal'], right.type))
1077
+ return;
1078
+ if (left?.type === 'string') {
1079
+ const op = {
1080
+ '$ldrop': 'RIGHT',
1081
+ '$rdrop': 'LEFT',
1082
+ }[expr.type];
1083
+ return { type: 'string', sql: sql `${{ literal: op }}(${left.sql}, -(${right.sql}))` };
1084
+ }
1085
+ }
1086
+ break;
1087
+ }
1088
+ }
1089
+ if (expr instanceof QueryListExpression) {
1090
+ const values = _.compact(_.map(expr.exprs, x => encodeTypedQueryExpression(compiler, parent, x)));
1091
+ if (values.length !== expr.exprs.length)
1092
+ return;
1093
+ switch (expr.type) {
1094
+ case '$add':
1095
+ case '$multiply':
1096
+ {
1097
+ const op = {
1098
+ '$add': '+',
1099
+ '$multiply': '*',
1100
+ }[expr.type];
1101
+ if (_.every(values, x => x.type === 'number')) {
1102
+ return { type: 'number', sql: sql `${{ literal: _.map(values, x => x.sql), separator: ` ${op} ` }}` };
1103
+ }
1104
+ if (_.every(values, x => x.type === 'number' || x.type === 'decimal')) {
1105
+ return { type: 'decimal', sql: sql `${{ literal: _.map(values, x => x.type === 'decimal' ? x.sql : sql `CAST((${x.sql}) AS DECIMAL)`), separator: ` ${op} ` }}` };
1106
+ }
1107
+ }
1108
+ break;
1109
+ case '$ifNull':
1110
+ {
1111
+ const type = values[0].type;
1112
+ if (_.every(values, x => x.type === type)) {
1113
+ return { type, sql: sql `COALESCE(${{ literal: _.map(values, x => x.sql) }})` };
1114
+ }
1115
+ }
1116
+ break;
1117
+ case '$concat':
1118
+ {
1119
+ if (_.every(values, x => x.type === 'string')) {
1120
+ return { type: 'string', sql: sql `CONCAT(${{ literal: _.map(values, x => x.sql) }})` };
1121
+ }
1122
+ }
1123
+ break;
1124
+ }
1125
+ }
1126
+ if (expr instanceof QueryTernaryExpression) {
1127
+ const first = encodeTypedQueryExpression(compiler, parent, expr.first);
1128
+ const second = encodeTypedQueryExpression(compiler, parent, expr.second);
1129
+ const last = encodeTypedQueryExpression(compiler, parent, expr.last);
1130
+ if (!first || !second || !last)
1131
+ return;
1132
+ switch (expr.type) {
1133
+ case '$lpad':
1134
+ case '$rpad':
1135
+ {
1136
+ const op = {
1137
+ '$lpad': 'LPAD',
1138
+ '$rpad': 'RPAD',
1139
+ }[expr.type];
1140
+ if (first?.type !== 'string' || last?.type !== 'string')
1141
+ return;
1142
+ if (!_.includes(['number', 'decimal'], second.type))
1143
+ return;
1144
+ return { type: 'string', sql: sql `${{ literal: op }}(${first.sql}, ${second.sql}, ${last.sql})` };
1145
+ }
1146
+ }
1147
+ }
1148
+ if (expr instanceof QueryCondExpression) {
1149
+ const branches = _.flatMap(_.map(expr.branch, x => ({
1150
+ case: encodeTypedQueryExpression(compiler, parent, x.case),
1151
+ then: encodeTypedQueryExpression(compiler, parent, x.then),
1152
+ })), x => x.case && x.then ? ({ case: x.case, then: x.then }) : []);
1153
+ if (branches.length !== expr.branch.length)
1154
+ return;
1155
+ const defaultCase = encodeTypedQueryExpression(compiler, parent, expr.default);
1156
+ if (!defaultCase)
1157
+ return;
1158
+ if (!_.every(branches, x => x.case.type === 'boolean' && x.then.type === defaultCase.type))
1159
+ return;
1160
+ return {
1161
+ type: defaultCase.type,
1162
+ sql: sql `CASE ${{
1163
+ literal: _.map(branches, x => sql `WHEN (${x.case.sql}) THEN (${x.then.sql})`),
1164
+ separator: ' '
1165
+ }} ELSE (${defaultCase.sql}) END`,
1166
+ };
1167
+ }
1168
+ };
1169
+ const encodeJsonQueryExpression = (compiler, parent, expr) => {
1170
+ if (expr instanceof QueryKeyExpression) {
1171
+ const { element, dataType } = fetchElement(compiler, parent, expr.key);
1172
+ if (dataType && isPrimitive(dataType)) {
1173
+ switch (_typeof(dataType)) {
1174
+ case 'boolean': return sql `to_jsonb(${element})`;
1175
+ case 'number': return sql `to_jsonb(${element})`;
1176
+ case 'decimal': return sql `jsonb_build_object('$decimal', CAST(${element} AS TEXT))`;
1177
+ case 'string': return sql `to_jsonb(${element})`;
1178
+ case 'string[]': return sql `to_jsonb(${element})`;
1179
+ case 'date': return sql `jsonb_build_object(
1180
+ '$date', to_char(${element} AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"')
1181
+ )`;
1182
+ }
1183
+ }
1184
+ return sql `${element}`;
1185
+ }
1186
+ if (expr instanceof QueryValueExpression) {
1187
+ return _encodeJsonValue(_encodeValue(expr.value));
1188
+ }
1189
+ if (expr instanceof QueryArrayExpression) {
1190
+ return sql `jsonb_build_array(${_.map(expr.exprs, x => encodeJsonQueryExpression(compiler, parent, x))})`;
1191
+ }
1192
+ const typed = encodeTypedQueryExpression(compiler, parent, expr);
1193
+ if (!typed)
1194
+ throw Error('Invalid expression');
1195
+ switch (typed.type) {
1196
+ case 'boolean': return sql `to_jsonb(${typed.sql})`;
1197
+ case 'number': return sql `to_jsonb(${typed.sql})`;
1198
+ case 'decimal': return sql `jsonb_build_object('$decimal', CAST(${typed.sql} AS TEXT))`;
1199
+ case 'string': return sql `to_jsonb(${typed.sql})`;
1200
+ case 'date': return sql `jsonb_build_object(
1201
+ '$date', to_char(${typed.sql} AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"')
1202
+ )`;
1203
+ default: throw Error('Invalid expression');
1204
+ }
1205
+ };
1206
+ const encodeBooleanExpression = (compiler, parent, expr) => {
1207
+ if (expr instanceof QueryCoditionalExpression) {
1208
+ const queries = _.compact(_.map(expr.exprs, x => encodeBooleanExpression(compiler, parent, x)));
1209
+ if (_.isEmpty(queries))
1210
+ return;
1211
+ switch (expr.type) {
1212
+ case '$and': return sql `(${{ literal: _.map(queries, x => sql `(${x})`), separator: ' AND ' }})`;
1213
+ case '$nor': return sql `(${{ literal: _.map(queries, x => sql `NOT (${x})`), separator: ' AND ' }})`;
1214
+ case '$or': return sql `(${{ literal: _.map(queries, x => sql `(${x})`), separator: ' OR ' }})`;
1215
+ }
1216
+ }
1217
+ if (expr instanceof QueryComparisonExpression) {
1218
+ const operatorMap = {
1219
+ '$eq': nullSafeEqual(),
1220
+ '$ne': nullSafeNotEqual(),
1221
+ '$gt': sql `>`,
1222
+ '$gte': sql `>=`,
1223
+ '$lt': sql `<`,
1224
+ '$lte': sql `<=`,
1225
+ };
1226
+ if (isArrayExpr(expr.left) &&
1227
+ isArrayExpr(expr.right) &&
1228
+ arrayLength(expr.left) === arrayLength(expr.right)) {
1229
+ const _left = mapExpr(expr.left, x => encodeTypedQueryExpression(compiler, parent, x));
1230
+ const _right = mapExpr(expr.right, x => encodeTypedQueryExpression(compiler, parent, x));
1231
+ const zipped = zipExpr(_left, _right) ?? [];
1232
+ if (_left.length === zipped.length) {
1233
+ const [l, r] = _.unzip(zipped);
1234
+ return sql `(${_.map(l, x => x.sql)}) ${operatorMap[expr.type]} (${_.map(r, x => x.sql)})`;
1235
+ }
1236
+ }
1237
+ const _left = encodeTypedQueryExpression(compiler, parent, expr.left);
1238
+ const _right = encodeTypedQueryExpression(compiler, parent, expr.right);
1239
+ if (_left && _right) {
1240
+ if (_left.type === _right.type) {
1241
+ return sql `(${_left.sql}) ${operatorMap[expr.type]} (${_right.sql})`;
1242
+ }
1243
+ if (_left.type === 'decimal' && _right.type === 'number') {
1244
+ return sql `CAST((${_left.sql}) AS DOUBLE PRECISION) ${operatorMap[expr.type]} (${_right.sql})`;
1245
+ }
1246
+ if (_left.type === 'number' && _right.type === 'decimal') {
1247
+ return sql `(${_left.sql}) ${operatorMap[expr.type]} CAST((${_right.sql}) AS DOUBLE PRECISION)`;
1248
+ }
1249
+ }
1250
+ const _left2 = encodeJsonQueryExpression(compiler, parent, expr.left);
1251
+ const _right2 = encodeJsonQueryExpression(compiler, parent, expr.right);
1252
+ return sql `${_left2} ${operatorMap[expr.type]} ${_right2}`;
1253
+ }
1254
+ if (expr instanceof QueryNotExpression) {
1255
+ const _expr = encodeBooleanExpression(compiler, parent, expr.expr);
1256
+ return _expr ? sql `NOT (${_expr})` : undefined;
1257
+ }
1258
+ throw Error('Invalid expression');
1259
+ };
1260
+
539
1261
  //
540
1262
  // storage.ts
541
1263
  //
@@ -701,8 +1423,17 @@ class SqlStorage {
701
1423
  const self = this;
702
1424
  const compiler = self._makeCompiler(false, query.extraFilter);
703
1425
  const _matchesType = self._matchesType(compiler, query);
704
- const _query = compiler._selectQuery({ ...query, sort: {} }, {
705
- sort: sql `ORDER BY ${self.dialect.random(opts ?? {})}`,
1426
+ const _query = compiler._selectQuery({ ...query, sort: {} }, ({ fetchName }) => {
1427
+ if (!opts?.weight)
1428
+ return { sort: sql `ORDER BY ${self.dialect.random()}` };
1429
+ const weight = encodeTypedQueryExpression(compiler, {
1430
+ name: fetchName,
1431
+ className: query.className,
1432
+ groupMatches: query.groupMatches,
1433
+ }, opts.weight);
1434
+ if (!weight)
1435
+ throw Error('Invalid expression');
1436
+ return { sort: sql `ORDER BY ${self.dialect.random(weight.sql)}` };
706
1437
  });
707
1438
  return (async function* () {
708
1439
  const objects = self.query(_query);
@@ -947,8 +1678,8 @@ const encodeSortKey = (compiler, parent, key) => {
947
1678
  const { element } = fetchElement(compiler, parent, key);
948
1679
  return element;
949
1680
  };
950
- const random = (opts) => {
951
- return opts.weight ? sql `-ln(random()) / ${{ identifier: opts.weight }}` : sql `random()`;
1681
+ const random = (weight) => {
1682
+ return weight ? sql `-ln(random()) / ${weight}` : sql `random()`;
952
1683
  };
953
1684
 
954
1685
  //
@@ -1165,201 +1896,34 @@ class PostgresDriver extends PostgresClientDriver {
1165
1896
  this.database = database;
1166
1897
  }
1167
1898
  async shutdown() {
1168
- await this._release_pubsub();
1169
- await this.database.end();
1170
- }
1171
- _init_pubsub() {
1172
- if (this.pubsub || this.database.ending || this.database.ended)
1173
- return;
1174
- this.pubsub = new PostgresPubSub(this.database.connect());
1175
- }
1176
- async _release_pubsub() {
1177
- const pubsub = this.pubsub;
1178
- this.pubsub = undefined;
1179
- await pubsub?.shutdown();
1180
- }
1181
- subscribe(channel, callback) {
1182
- this._init_pubsub();
1183
- if (!this.pubsub)
1184
- return () => void 0;
1185
- const release = this.pubsub.subscribe(({ channel: _channel, payload }) => {
1186
- if (_channel === channel)
1187
- callback(payload);
1188
- });
1189
- return () => {
1190
- release();
1191
- if (this.pubsub?.isEmpty())
1192
- this._release_pubsub();
1193
- };
1194
- }
1195
- }
1196
-
1197
- //
1198
- // encode.ts
1199
- //
1200
- // The MIT License
1201
- // Copyright (c) 2021 - 2025 O2ter Limited. All rights reserved.
1202
- //
1203
- // Permission is hereby granted, free of charge, to any person obtaining a copy
1204
- // of this software and associated documentation files (the "Software"), to deal
1205
- // in the Software without restriction, including without limitation the rights
1206
- // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1207
- // copies of the Software, and to permit persons to whom the Software is
1208
- // furnished to do so, subject to the following conditions:
1209
- //
1210
- // The above copyright notice and this permission notice shall be included in
1211
- // all copies or substantial portions of the Software.
1212
- //
1213
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1214
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1215
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1216
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1217
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1218
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1219
- // THE SOFTWARE.
1220
- //
1221
- const _encodeJsonValue = (value) => {
1222
- if (_.isArray(value))
1223
- return sql `jsonb_build_array(${_.map(value, x => _encodeJsonValue(x))})`;
1224
- if (_.isPlainObject(value))
1225
- return sql `jsonb_build_object(${_.map(value, (v, k) => sql `${{ value: k }}, ${_encodeJsonValue(v)}`)})`;
1226
- return sql `to_jsonb(${{ value }})`;
1227
- };
1228
- const _jsonPopulateInclude = (className, colname, dataType) => {
1229
- switch (_typeof(dataType)) {
1230
- case 'decimal':
1231
- return sql `jsonb_build_object(
1232
- '$decimal', CAST(${{ identifier: className }}.${{ identifier: colname }} AS TEXT)
1233
- ) AS ${{ identifier: colname }}`;
1234
- case 'date':
1235
- return sql `jsonb_build_object(
1236
- '$date', to_char(${{ identifier: className }}.${{ identifier: colname }} AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"')
1237
- ) AS ${{ identifier: colname }}`;
1238
- default:
1239
- return sql `${{ identifier: className }}.${{ identifier: colname }}`;
1240
- }
1241
- };
1242
- const encodeType = (colname, dataType, value) => {
1243
- if (_.isNil(value))
1244
- return sql `NULL`;
1245
- switch (_.isString(dataType) ? dataType : dataType.type) {
1246
- case 'boolean':
1247
- if (_.isBoolean(value))
1248
- return sql `${{ value }}`;
1249
- break;
1250
- case 'number':
1251
- if (_.isNumber(value) && _.isFinite(value))
1252
- return sql `${{ value }}`;
1253
- if (value instanceof Decimal)
1254
- return sql `${{ value: value.toNumber() }}`;
1255
- break;
1256
- case 'decimal':
1257
- if (_.isNumber(value) && _.isFinite(value))
1258
- return sql `CAST(${{ quote: (new Decimal(value)).toString() }} AS DECIMAL)`;
1259
- if (value instanceof Decimal)
1260
- return sql `CAST(${{ quote: value.toString() }} AS DECIMAL)`;
1261
- break;
1262
- case 'string':
1263
- if (_.isString(value))
1264
- return sql `${{ value }}`;
1265
- break;
1266
- case 'string[]':
1267
- if (_.isArray(value) && _.every(value, x => _.isString(x)))
1268
- return sql `ARRAY[${_.map(value, x => sql `${{ value: x }}`)}]::TEXT[]`;
1269
- break;
1270
- case 'date':
1271
- if (_.isDate(value))
1272
- return sql `${{ value }}`;
1273
- break;
1274
- case 'object':
1275
- if (_.isPlainObject(value))
1276
- return sql `${{ value: _encodeValue(value) }}`;
1277
- break;
1278
- case 'vector':
1279
- if (!_.isArray(value) || value.length !== dimensionOf(dataType))
1280
- break;
1281
- if (!_.every(value, x => _.isFinite(x)))
1282
- break;
1283
- return sql `${{ value }}::DOUBLE PRECISION[]`;
1284
- case 'array':
1285
- if (!_.isArray(value))
1286
- break;
1287
- return sql `ARRAY[${_.map(value, x => _encodeJsonValue(_encodeValue(x)))}]::JSONB[]`;
1288
- case 'pointer':
1289
- if (value instanceof TObject && value.objectId)
1290
- return sql `${{ value: `${value.className}$${value.objectId}` }}`;
1291
- break;
1292
- case 'relation':
1293
- if (_.isArray(value) && _.every(value, x => x instanceof TObject && x.objectId)) {
1294
- return sql `${{ value: _.uniq(_.map(value, (x) => `${x.className}$${x.objectId}`)) }}`;
1295
- }
1296
- break;
1297
- }
1298
- throw Error('Invalid data type');
1299
- };
1300
- const decodeType = (type, value) => {
1301
- switch (type) {
1302
- case 'boolean':
1303
- if (_.isBoolean(value))
1304
- return value;
1305
- if (value === 'true')
1306
- return true;
1307
- if (value === 'false')
1308
- return false;
1309
- break;
1310
- case 'number':
1311
- if (_.isNumber(value))
1312
- return value;
1313
- if (_.isString(value)) {
1314
- const float = parseFloat(value);
1315
- return _.isNaN(float) ? null : float;
1316
- }
1317
- break;
1318
- case 'decimal':
1319
- if (_.isString(value) || _.isNumber(value))
1320
- return new Decimal(value);
1321
- if (value instanceof Decimal)
1322
- return value;
1323
- if (_.isPlainObject(value) && _.isString(value.$decimal))
1324
- return new Decimal(value.$decimal);
1325
- break;
1326
- case 'string':
1327
- if (_.isString(value))
1328
- return value;
1329
- break;
1330
- case 'string[]':
1331
- if (_.isArray(value) && _.every(value, x => _.isString(x)))
1332
- return value;
1333
- break;
1334
- case 'date':
1335
- if (_.isDate(value))
1336
- return value;
1337
- if (_.isString(value)) {
1338
- const date = new Date(value);
1339
- if (isFinite(date.valueOf()))
1340
- return date;
1341
- }
1342
- if (_.isPlainObject(value) && _.isString(value.$date))
1343
- return new Date(value.$date);
1344
- break;
1345
- case 'object':
1346
- if (_.isPlainObject(value))
1347
- return _decodeValue(value);
1348
- break;
1349
- case 'array':
1350
- if (_.isArray(value))
1351
- return _decodeValue(value);
1352
- break;
1353
- case 'vector':
1354
- if (!_.isArray(value))
1355
- break;
1356
- if (_.every(value, x => _.isNumber(x))) {
1357
- return value;
1358
- }
1359
- break;
1899
+ await this._release_pubsub();
1900
+ await this.database.end();
1360
1901
  }
1361
- return null;
1362
- };
1902
+ _init_pubsub() {
1903
+ if (this.pubsub || this.database.ending || this.database.ended)
1904
+ return;
1905
+ this.pubsub = new PostgresPubSub(this.database.connect());
1906
+ }
1907
+ async _release_pubsub() {
1908
+ const pubsub = this.pubsub;
1909
+ this.pubsub = undefined;
1910
+ await pubsub?.shutdown();
1911
+ }
1912
+ subscribe(channel, callback) {
1913
+ this._init_pubsub();
1914
+ if (!this.pubsub)
1915
+ return () => void 0;
1916
+ const release = this.pubsub.subscribe(({ channel: _channel, payload }) => {
1917
+ if (_channel === channel)
1918
+ callback(payload);
1919
+ });
1920
+ return () => {
1921
+ release();
1922
+ if (this.pubsub?.isEmpty())
1923
+ this._release_pubsub();
1924
+ };
1925
+ }
1926
+ }
1363
1927
 
1364
1928
  //
1365
1929
  // update.ts
@@ -1647,232 +2211,6 @@ const updateOperation = (paths, dataType, operation) => {
1647
2211
  throw Error('Invalid update operation');
1648
2212
  };
1649
2213
 
1650
- //
1651
- // expressions.ts
1652
- //
1653
- // The MIT License
1654
- // Copyright (c) 2021 - 2025 O2ter Limited. All rights reserved.
1655
- //
1656
- // Permission is hereby granted, free of charge, to any person obtaining a copy
1657
- // of this software and associated documentation files (the "Software"), to deal
1658
- // in the Software without restriction, including without limitation the rights
1659
- // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1660
- // copies of the Software, and to permit persons to whom the Software is
1661
- // furnished to do so, subject to the following conditions:
1662
- //
1663
- // The above copyright notice and this permission notice shall be included in
1664
- // all copies or substantial portions of the Software.
1665
- //
1666
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1667
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1668
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1669
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1670
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1671
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1672
- // THE SOFTWARE.
1673
- //
1674
- const isArrayExpression = (expr) => {
1675
- if (expr instanceof QueryArrayExpression)
1676
- return true;
1677
- if (expr instanceof QueryValueExpression)
1678
- return _.isArray(expr.value);
1679
- return false;
1680
- };
1681
- const arrayLength = (expr) => {
1682
- if (expr instanceof QueryArrayExpression)
1683
- return expr.exprs.length;
1684
- if (expr instanceof QueryValueExpression)
1685
- return _.isArray(expr.value) ? expr.value.length : 0;
1686
- return 0;
1687
- };
1688
- const mapExpression = (expr, callback) => {
1689
- if (expr instanceof QueryArrayExpression)
1690
- return _.map(expr.exprs, x => callback(x));
1691
- if (expr instanceof QueryValueExpression)
1692
- return _.isArray(expr.value) ? _.map(expr.value, x => callback(new QueryValueExpression(x))) : [];
1693
- return [];
1694
- };
1695
- const _PrimitiveValue = ['boolean', 'number', 'decimal', 'string', 'date'];
1696
- const encodeTypedQueryExpression = (compiler, parent, expr) => {
1697
- if (expr instanceof QueryKeyExpression) {
1698
- const { element, dataType } = fetchElement(compiler, parent, expr.key);
1699
- const _dataType = dataType ? _typeof(dataType) : null;
1700
- if (_dataType === 'number') {
1701
- return [
1702
- { type: 'number', sql: element },
1703
- { type: 'decimal', sql: sql `CAST((${element}) AS DECIMAL)` },
1704
- ];
1705
- }
1706
- else if (_dataType === 'decimal') {
1707
- return [
1708
- { type: 'decimal', sql: element },
1709
- { type: 'number', sql: element },
1710
- ];
1711
- }
1712
- else if (_dataType && _PrimitiveValue.includes(_dataType)) {
1713
- return [{ type: _dataType, sql: element }];
1714
- }
1715
- }
1716
- if (expr instanceof QueryValueExpression) {
1717
- if (_.isBoolean(expr.value))
1718
- return [{ type: 'boolean', sql: sql `${{ value: expr.value }}` }];
1719
- if (_.isNumber(expr.value))
1720
- return [
1721
- { type: 'number', sql: sql `${{ value: expr.value }}` },
1722
- { type: 'decimal', sql: sql `CAST(${{ quote: (new Decimal(expr.value)).toString() }} AS DECIMAL)` },
1723
- ];
1724
- if (expr.value instanceof Decimal)
1725
- return [
1726
- { type: 'decimal', sql: sql `CAST(${{ quote: expr.value.toString() }} AS DECIMAL)` },
1727
- { type: 'number', sql: sql `${{ value: expr.value.toNumber() }}` },
1728
- ];
1729
- if (_.isString(expr.value))
1730
- return [{ type: 'string', sql: sql `${{ value: expr.value }}` }];
1731
- if (_.isDate(expr.value))
1732
- return [{ type: 'date', sql: sql `${{ value: expr.value }}` }];
1733
- }
1734
- if (expr instanceof QueryCoditionalExpression ||
1735
- expr instanceof QueryComparisonExpression ||
1736
- expr instanceof QueryNotExpression) {
1737
- const value = encodeBooleanExpression(compiler, parent, expr);
1738
- if (value)
1739
- return [{ type: 'boolean', sql: value }];
1740
- }
1741
- if (expr instanceof QueryDistanceExpression) {
1742
- const value = encodeDistanceQueryExpression(compiler, parent, expr);
1743
- return [{ type: 'number', sql: value }];
1744
- }
1745
- };
1746
- const encodeJsonQueryExpression = (compiler, parent, expr) => {
1747
- if (expr instanceof QueryKeyExpression) {
1748
- const { element, dataType } = fetchElement(compiler, parent, expr.key);
1749
- if (dataType && isPrimitive(dataType)) {
1750
- switch (_typeof(dataType)) {
1751
- case 'boolean': return sql `to_jsonb(${element})`;
1752
- case 'number': return sql `to_jsonb(${element})`;
1753
- case 'decimal': return sql `jsonb_build_object('$decimal', CAST(${element} AS TEXT))`;
1754
- case 'string': return sql `to_jsonb(${element})`;
1755
- case 'string[]': return sql `to_jsonb(${element})`;
1756
- case 'date': return sql `jsonb_build_object(
1757
- '$date', to_char(${element} AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"')
1758
- )`;
1759
- }
1760
- }
1761
- return sql `${element}`;
1762
- }
1763
- if (expr instanceof QueryValueExpression) {
1764
- return _encodeJsonValue(_encodeValue(expr.value));
1765
- }
1766
- if (expr instanceof QueryArrayExpression) {
1767
- return sql `jsonb_build_array(${_.map(expr.exprs, x => encodeJsonQueryExpression(compiler, parent, x))})`;
1768
- }
1769
- const value = encodeQueryExpression(compiler, parent, expr);
1770
- if (!value)
1771
- throw Error('Invalid expression');
1772
- return sql `to_jsonb(${value})`;
1773
- };
1774
- const encodeVectorExpression = (compiler, parent, exprs) => {
1775
- if (exprs.length === 1) {
1776
- const [expr] = exprs;
1777
- if (expr instanceof QueryKeyExpression) {
1778
- const { element, dataType } = fetchElement(compiler, parent, expr.key);
1779
- if (!dataType || !isVector(dataType))
1780
- throw Error('Invalid expression');
1781
- return { sql: element, dimension: dataType.dimension };
1782
- }
1783
- if (expr instanceof QueryValueExpression) {
1784
- if (!_.isArray(expr.value) || !_.every(expr.value, x => _.isFinite(x)))
1785
- throw Error('Invalid expression');
1786
- return { sql: sql `${{ value: expr.value }}::DOUBLE PRECISION[]`, dimension: expr.value.length };
1787
- }
1788
- }
1789
- const result = _.map(exprs, x => _.find(encodeTypedQueryExpression(compiler, parent, x), e => e.type === 'number')?.sql);
1790
- if (_.some(result, x => _.isNil(x)))
1791
- throw Error('Invalid expression');
1792
- return { sql: sql `ARRAY[${_.map(result, x => sql `COALESCE(${x}, 0)`)}]`, dimension: result.length };
1793
- };
1794
- const encodeDistanceQueryExpression = (compiler, parent, expr) => {
1795
- const { sql: left, dimension: d1 } = encodeVectorExpression(compiler, parent, expr.left);
1796
- const { sql: right, dimension: d2 } = encodeVectorExpression(compiler, parent, expr.right);
1797
- if (d1 !== d2)
1798
- throw Error('Invalid expression');
1799
- const operatorMap = {
1800
- '$distance': sql `<->`,
1801
- '$innerProduct': sql `<#>`,
1802
- '$negInnerProduct': sql `<#>`,
1803
- '$cosineDistance': sql `<=>`,
1804
- '$rectilinearDistance': sql `<+>`,
1805
- };
1806
- const _expr = sql `
1807
- CAST(
1808
- ${left} AS VECTOR(${{ literal: `${d1}` }})
1809
- )
1810
- ${operatorMap[expr.type]}
1811
- CAST(
1812
- ${right} AS VECTOR(${{ literal: `${d2}` }})
1813
- )
1814
- `;
1815
- return expr.type === '$innerProduct' ? sql `-1 * (${_expr})` : _expr;
1816
- };
1817
- const matchType = (first, second) => {
1818
- const found = _.find(first, l => _.some(second, r => l.type === r.type));
1819
- return found ? [found, _.find(second, r => r.type === found.type)] : undefined;
1820
- };
1821
- const encodeBooleanExpression = (compiler, parent, expr) => {
1822
- if (expr instanceof QueryCoditionalExpression) {
1823
- const queries = _.compact(_.map(expr.exprs, x => encodeBooleanExpression(compiler, parent, x)));
1824
- if (_.isEmpty(queries))
1825
- return;
1826
- switch (expr.type) {
1827
- case '$and': return sql `(${{ literal: _.map(queries, x => sql `(${x})`), separator: ' AND ' }})`;
1828
- case '$nor': return sql `(${{ literal: _.map(queries, x => sql `NOT (${x})`), separator: ' AND ' }})`;
1829
- case '$or': return sql `(${{ literal: _.map(queries, x => sql `(${x})`), separator: ' OR ' }})`;
1830
- }
1831
- }
1832
- if (expr instanceof QueryComparisonExpression) {
1833
- const operatorMap = {
1834
- '$eq': nullSafeEqual(),
1835
- '$ne': nullSafeNotEqual(),
1836
- '$gt': sql `>`,
1837
- '$gte': sql `>=`,
1838
- '$lt': sql `<`,
1839
- '$lte': sql `<=`,
1840
- };
1841
- if (isArrayExpression(expr.left) &&
1842
- isArrayExpression(expr.right) &&
1843
- arrayLength(expr.left) === arrayLength(expr.right)) {
1844
- const _left = mapExpression(expr.left, x => encodeTypedQueryExpression(compiler, parent, x));
1845
- const _right = mapExpression(expr.right, x => encodeTypedQueryExpression(compiler, parent, x));
1846
- const mapped = _.compact(_.map(_.zip(_left, _right), ([l, r]) => matchType(l, r)));
1847
- if (mapped.length === _left.length) {
1848
- const [l, r] = _.unzip(mapped);
1849
- return sql `(${_.map(l, x => x.sql)}) ${operatorMap[expr.type]} (${_.map(r, x => x.sql)})`;
1850
- }
1851
- }
1852
- const _left = encodeTypedQueryExpression(compiler, parent, expr.left);
1853
- const _right = encodeTypedQueryExpression(compiler, parent, expr.right);
1854
- if (_left && _right) {
1855
- const matched = matchType(_left, _right);
1856
- if (matched)
1857
- return sql `${matched[0].sql} ${operatorMap[expr.type]} ${matched[1].sql}`;
1858
- }
1859
- const _left2 = encodeJsonQueryExpression(compiler, parent, expr.left);
1860
- const _right2 = encodeJsonQueryExpression(compiler, parent, expr.right);
1861
- return sql `${_left2} ${operatorMap[expr.type]} ${_right2}`;
1862
- }
1863
- if (expr instanceof QueryNotExpression) {
1864
- const _expr = encodeBooleanExpression(compiler, parent, expr.expr);
1865
- return _expr ? sql `NOT (${_expr})` : undefined;
1866
- }
1867
- throw Error('Invalid expression');
1868
- };
1869
- const encodeQueryExpression = (compiler, parent, expr) => {
1870
- if (expr instanceof QueryDistanceExpression) {
1871
- return encodeDistanceQueryExpression(compiler, parent, expr);
1872
- }
1873
- return encodeBooleanExpression(compiler, parent, expr);
1874
- };
1875
-
1876
2214
  //
1877
2215
  // populate.ts
1878
2216
  //
@@ -1975,7 +2313,7 @@ const selectPopulate = (compiler, parent, populate, field) => {
1975
2313
  ];
1976
2314
  if (!_.isEmpty(groupMatches?.[field])) {
1977
2315
  for (const [key, expr] of _.entries(groupMatches[field])) {
1978
- if (expr instanceof QueryNoParamAccumulator) {
2316
+ if (expr instanceof QueryZeroParamAccumulator) {
1979
2317
  switch (expr.type) {
1980
2318
  case '$count':
1981
2319
  columns.push(sql `
@@ -1988,30 +2326,44 @@ const selectPopulate = (compiler, parent, populate, field) => {
1988
2326
  break;
1989
2327
  }
1990
2328
  }
1991
- else if (expr instanceof QueryExprAccumulator) {
1992
- const op = {
1993
- '$max': 'MAX',
1994
- '$min': 'MIN',
1995
- '$avg': 'AVG',
1996
- '$sum': 'SUM',
1997
- '$stdDevPop': 'STDDEV_POP',
1998
- '$stdDevSamp': 'STDDEV_SAMP',
1999
- '$varPop': 'VAR_POP',
2000
- '$varSamp': 'VAR_SAMP',
2001
- }[expr.type];
2329
+ else if (expr instanceof QueryUnaryAccumulator) {
2002
2330
  if (!expr.expr)
2003
2331
  throw Error('Invalid expression');
2004
- const exprs = encodeTypedQueryExpression(compiler, populate, expr.expr);
2005
- const value = _.first(exprs)?.sql;
2332
+ const { sql: value } = encodeTypedQueryExpression(compiler, populate, expr.expr) ?? {};
2006
2333
  if (!value)
2007
2334
  throw Error('Invalid expression');
2008
- columns.push(sql `
2009
- (
2010
- SELECT ${{ literal: op }}(${value}) FROM (
2011
- ${_selectRelationPopulate(compiler, parent, populate, field, false)}
2012
- ) ${{ identifier: populate.name }}
2013
- ) AS ${{ identifier: `${field}.${key}` }}
2014
- `);
2335
+ switch (expr.type) {
2336
+ case '$most':
2337
+ columns.push(sql `
2338
+ (
2339
+ SELECT MODE() WITHIN GROUP (ORDER BY (${value})) FROM (
2340
+ ${_selectRelationPopulate(compiler, parent, populate, field, false)}
2341
+ ) ${{ identifier: populate.name }}
2342
+ ) AS ${{ identifier: `${field}.${key}` }}
2343
+ `);
2344
+ break;
2345
+ default:
2346
+ {
2347
+ const op = {
2348
+ '$max': 'MAX',
2349
+ '$min': 'MIN',
2350
+ '$avg': 'AVG',
2351
+ '$sum': 'SUM',
2352
+ '$stdDevPop': 'STDDEV_POP',
2353
+ '$stdDevSamp': 'STDDEV_SAMP',
2354
+ '$varPop': 'VAR_POP',
2355
+ '$varSamp': 'VAR_SAMP',
2356
+ }[expr.type];
2357
+ columns.push(sql `
2358
+ (
2359
+ SELECT ${{ literal: op }}(${value}) FROM (
2360
+ ${_selectRelationPopulate(compiler, parent, populate, field, false)}
2361
+ ) ${{ identifier: populate.name }}
2362
+ ) AS ${{ identifier: `${field}.${key}` }}
2363
+ `);
2364
+ }
2365
+ break;
2366
+ }
2015
2367
  }
2016
2368
  else if (expr instanceof QueryPercentileAccumulator) {
2017
2369
  const op = {
@@ -2020,8 +2372,7 @@ const selectPopulate = (compiler, parent, populate, field) => {
2020
2372
  }[expr.mode];
2021
2373
  if (!expr.input)
2022
2374
  throw Error('Invalid expression');
2023
- const exprs = encodeTypedQueryExpression(compiler, populate, expr.input);
2024
- const value = _.first(exprs)?.sql;
2375
+ const { sql: value } = encodeTypedQueryExpression(compiler, populate, expr.input) ?? {};
2025
2376
  if (!value)
2026
2377
  throw Error('Invalid expression');
2027
2378
  columns.push(sql `
@@ -2609,6 +2960,36 @@ const encodeFieldExpression = (compiler, parent, field, expr) => {
2609
2960
  throw Error('Invalid expression');
2610
2961
  };
2611
2962
 
2963
+ //
2964
+ // index.ts
2965
+ //
2966
+ // The MIT License
2967
+ // Copyright (c) 2021 - 2025 O2ter Limited. All rights reserved.
2968
+ //
2969
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
2970
+ // of this software and associated documentation files (the "Software"), to deal
2971
+ // in the Software without restriction, including without limitation the rights
2972
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
2973
+ // copies of the Software, and to permit persons to whom the Software is
2974
+ // furnished to do so, subject to the following conditions:
2975
+ //
2976
+ // The above copyright notice and this permission notice shall be included in
2977
+ // all copies or substantial portions of the Software.
2978
+ //
2979
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2980
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2981
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2982
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2983
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2984
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2985
+ // THE SOFTWARE.
2986
+ //
2987
+ const encodeSortExpression = (compiler, parent, expr) => {
2988
+ if (expr instanceof QueryDistanceExpression) {
2989
+ return encodeDistanceQueryExpression(compiler, parent, expr);
2990
+ }
2991
+ };
2992
+
2612
2993
  //
2613
2994
  // relation.ts
2614
2995
  //
@@ -2680,7 +3061,8 @@ const PostgresDialect = {
2680
3061
  updateOperation,
2681
3062
  selectPopulate,
2682
3063
  encodeFieldExpression,
2683
- encodeQueryExpression,
3064
+ encodeBooleanExpression,
3065
+ encodeSortExpression,
2684
3066
  encodePopulate,
2685
3067
  encodeRelation,
2686
3068
  encodeSortKey,