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