proto.io 0.0.216 → 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 (46) 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 +1 -1
  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 +5 -3
  8. package/dist/adapters/storage/progres.js +474 -111
  9. package/dist/adapters/storage/progres.js.map +1 -1
  10. package/dist/adapters/storage/progres.mjs +474 -111
  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 +2 -2
  16. package/dist/client.mjs.map +1 -1
  17. package/dist/index.d.ts +3 -3
  18. package/dist/index.js +3 -9
  19. package/dist/index.js.map +1 -1
  20. package/dist/index.mjs +4 -4
  21. package/dist/index.mjs.map +1 -1
  22. package/dist/internals/{base-BO3ZP6EF.d.ts → base-CWnOBKD5.d.ts} +2 -2
  23. package/dist/internals/base-CWnOBKD5.d.ts.map +1 -0
  24. package/dist/internals/{chunk-DDkLpKXp.d.ts → chunk-CNNSQpRF.d.ts} +3 -3
  25. package/dist/internals/chunk-CNNSQpRF.d.ts.map +1 -0
  26. package/dist/internals/{index-CYhA8SU8.d.ts → index-BRIlS3mY.d.ts} +3 -9
  27. package/dist/internals/index-BRIlS3mY.d.ts.map +1 -0
  28. package/dist/internals/{index-HdMgLYtD.d.ts → index-Bs8n7Q8f.d.ts} +55 -18
  29. package/dist/internals/index-Bs8n7Q8f.d.ts.map +1 -0
  30. package/dist/internals/{index-DF2AfSGK.mjs → index-DfqABzjr.mjs} +134 -141
  31. package/dist/internals/index-DfqABzjr.mjs.map +1 -0
  32. package/dist/internals/{index-DfnPpl1I.js → index-DylUjD_1.js} +133 -146
  33. package/dist/internals/index-DylUjD_1.js.map +1 -0
  34. package/dist/internals/{validator-LNgZGT_l.mjs → validator-CEcBF4Cn.mjs} +728 -27
  35. package/dist/internals/validator-CEcBF4Cn.mjs.map +1 -0
  36. package/dist/internals/{validator-BBjOdLiT.js → validator-mcBCJP4P.js} +734 -27
  37. package/dist/internals/validator-mcBCJP4P.js.map +1 -0
  38. package/package.json +1 -1
  39. package/dist/internals/base-BO3ZP6EF.d.ts.map +0 -1
  40. package/dist/internals/chunk-DDkLpKXp.d.ts.map +0 -1
  41. package/dist/internals/index-CYhA8SU8.d.ts.map +0 -1
  42. package/dist/internals/index-DF2AfSGK.mjs.map +0 -1
  43. package/dist/internals/index-DfnPpl1I.js.map +0 -1
  44. package/dist/internals/index-HdMgLYtD.d.ts.map +0 -1
  45. package/dist/internals/validator-BBjOdLiT.js.map +0 -1
  46. package/dist/internals/validator-LNgZGT_l.mjs.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-BBjOdLiT.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' }}`;
@@ -708,7 +708,7 @@ const decodeType = (type, value) => {
708
708
  };
709
709
 
710
710
  //
711
- // expressions.ts
711
+ // types.ts
712
712
  //
713
713
  // The MIT License
714
714
  // Copyright (c) 2021 - 2025 O2ter Limited. All rights reserved.
@@ -731,7 +731,8 @@ const decodeType = (type, value) => {
731
731
  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
732
732
  // THE SOFTWARE.
733
733
  //
734
- const isArrayExpression = (expr) => {
734
+ const _PrimitiveValue = ['boolean', 'number', 'decimal', 'string', 'date'];
735
+ const isArrayExpr = (expr) => {
735
736
  if (expr instanceof validator.QueryArrayExpression)
736
737
  return true;
737
738
  if (expr instanceof validator.QueryValueExpression)
@@ -745,62 +746,428 @@ const arrayLength = (expr) => {
745
746
  return _.isArray(expr.value) ? expr.value.length : 0;
746
747
  return 0;
747
748
  };
748
- const mapExpression = (expr, callback) => {
749
+ const mapExpr = (expr, callback) => {
749
750
  if (expr instanceof validator.QueryArrayExpression)
750
751
  return _.map(expr.exprs, x => callback(x));
751
752
  if (expr instanceof validator.QueryValueExpression)
752
753
  return _.isArray(expr.value) ? _.map(expr.value, x => callback(new validator.QueryValueExpression(x))) : [];
753
754
  return [];
754
755
  };
755
- const _PrimitiveValue = ['boolean', 'number', 'decimal', 'string', 'date'];
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
+ //
756
875
  const encodeTypedQueryExpression = (compiler, parent, expr) => {
757
876
  if (expr instanceof validator.QueryKeyExpression) {
758
877
  const { element, dataType } = fetchElement(compiler, parent, expr.key);
759
878
  const _dataType = dataType ? index._typeof(dataType) : null;
760
- if (_dataType === 'number') {
761
- return [
762
- { type: 'number', sql: element },
763
- { type: 'decimal', sql: sql `CAST((${element}) AS DECIMAL)` },
764
- ];
765
- }
766
- else if (_dataType === 'decimal') {
767
- return [
768
- { type: 'decimal', sql: element },
769
- { type: 'number', sql: element },
770
- ];
771
- }
772
- else if (_dataType && _PrimitiveValue.includes(_dataType)) {
773
- return [{ type: _dataType, sql: element }];
774
- }
879
+ if (!_dataType || !_PrimitiveValue.includes(_dataType))
880
+ return;
881
+ return { type: _dataType, sql: element };
775
882
  }
776
883
  if (expr instanceof validator.QueryValueExpression) {
777
884
  if (_.isBoolean(expr.value))
778
- return [{ type: 'boolean', sql: sql `${{ value: expr.value }}` }];
885
+ return { type: 'boolean', sql: sql `${{ value: expr.value }}` };
779
886
  if (_.isNumber(expr.value))
780
- return [
781
- { type: 'number', sql: sql `${{ value: expr.value }}` },
782
- { type: 'decimal', sql: sql `CAST(${{ quote: (new Decimal(expr.value)).toString() }} AS DECIMAL)` },
783
- ];
887
+ return { type: 'number', sql: sql `${{ value: expr.value }}` };
784
888
  if (expr.value instanceof Decimal)
785
- return [
786
- { type: 'decimal', sql: sql `CAST(${{ quote: expr.value.toString() }} AS DECIMAL)` },
787
- { type: 'number', sql: sql `${{ value: expr.value.toNumber() }}` },
788
- ];
889
+ return { type: 'decimal', sql: sql `CAST(${{ quote: expr.value.toString() }} AS DECIMAL)` };
789
890
  if (_.isString(expr.value))
790
- return [{ type: 'string', sql: sql `${{ value: expr.value }}` }];
891
+ return { type: 'string', sql: sql `${{ value: expr.value }}` };
791
892
  if (_.isDate(expr.value))
792
- return [{ type: 'date', sql: sql `${{ value: expr.value }}` }];
893
+ return { type: 'date', sql: sql `${{ value: expr.value }}` };
793
894
  }
794
895
  if (expr instanceof validator.QueryCoditionalExpression ||
795
896
  expr instanceof validator.QueryComparisonExpression ||
796
897
  expr instanceof validator.QueryNotExpression) {
797
898
  const value = encodeBooleanExpression(compiler, parent, expr);
798
899
  if (value)
799
- return [{ type: 'boolean', sql: value }];
900
+ return { type: 'boolean', sql: value };
800
901
  }
801
902
  if (expr instanceof validator.QueryDistanceExpression) {
802
903
  const value = encodeDistanceQueryExpression(compiler, parent, expr);
803
- return [{ type: 'number', sql: value }];
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
+ };
804
1171
  }
805
1172
  };
806
1173
  const encodeJsonQueryExpression = (compiler, parent, expr) => {
@@ -826,57 +1193,19 @@ const encodeJsonQueryExpression = (compiler, parent, expr) => {
826
1193
  if (expr instanceof validator.QueryArrayExpression) {
827
1194
  return sql `jsonb_build_array(${_.map(expr.exprs, x => encodeJsonQueryExpression(compiler, parent, x))})`;
828
1195
  }
829
- const value = encodeQueryExpression(compiler, parent, expr);
830
- if (!value)
1196
+ const typed = encodeTypedQueryExpression(compiler, parent, expr);
1197
+ if (!typed)
831
1198
  throw Error('Invalid expression');
832
- return sql `to_jsonb(${value})`;
833
- };
834
- const encodeVectorExpression = (compiler, parent, exprs) => {
835
- if (exprs.length === 1) {
836
- const [expr] = exprs;
837
- if (expr instanceof validator.QueryKeyExpression) {
838
- const { element, dataType } = fetchElement(compiler, parent, expr.key);
839
- if (!dataType || !index.isVector(dataType))
840
- throw Error('Invalid expression');
841
- return { sql: element, dimension: dataType.dimension };
842
- }
843
- if (expr instanceof validator.QueryValueExpression) {
844
- if (!_.isArray(expr.value) || !_.every(expr.value, x => _.isFinite(x)))
845
- throw Error('Invalid expression');
846
- return { sql: sql `${{ value: expr.value }}::DOUBLE PRECISION[]`, dimension: expr.value.length };
847
- }
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');
848
1208
  }
849
- const result = _.map(exprs, x => _.find(encodeTypedQueryExpression(compiler, parent, x), e => e.type === 'number')?.sql);
850
- if (_.some(result, x => _.isNil(x)))
851
- throw Error('Invalid expression');
852
- return { sql: sql `ARRAY[${_.map(result, x => sql `COALESCE(${x}, 0)`)}]`, dimension: result.length };
853
- };
854
- const encodeDistanceQueryExpression = (compiler, parent, expr) => {
855
- const { sql: left, dimension: d1 } = encodeVectorExpression(compiler, parent, expr.left);
856
- const { sql: right, dimension: d2 } = encodeVectorExpression(compiler, parent, expr.right);
857
- if (d1 !== d2)
858
- throw Error('Invalid expression');
859
- const operatorMap = {
860
- '$distance': sql `<->`,
861
- '$innerProduct': sql `<#>`,
862
- '$negInnerProduct': sql `<#>`,
863
- '$cosineDistance': sql `<=>`,
864
- '$rectilinearDistance': sql `<+>`,
865
- };
866
- const _expr = sql `
867
- CAST(
868
- ${left} AS VECTOR(${{ literal: `${d1}` }})
869
- )
870
- ${operatorMap[expr.type]}
871
- CAST(
872
- ${right} AS VECTOR(${{ literal: `${d2}` }})
873
- )
874
- `;
875
- return expr.type === '$innerProduct' ? sql `-1 * (${_expr})` : _expr;
876
- };
877
- const matchType = (first, second) => {
878
- const found = _.find(first, l => _.some(second, r => l.type === r.type));
879
- return found ? [found, _.find(second, r => r.type === found.type)] : undefined;
880
1209
  };
881
1210
  const encodeBooleanExpression = (compiler, parent, expr) => {
882
1211
  if (expr instanceof validator.QueryCoditionalExpression) {
@@ -898,23 +1227,29 @@ const encodeBooleanExpression = (compiler, parent, expr) => {
898
1227
  '$lt': sql `<`,
899
1228
  '$lte': sql `<=`,
900
1229
  };
901
- if (isArrayExpression(expr.left) &&
902
- isArrayExpression(expr.right) &&
1230
+ if (isArrayExpr(expr.left) &&
1231
+ isArrayExpr(expr.right) &&
903
1232
  arrayLength(expr.left) === arrayLength(expr.right)) {
904
- const _left = mapExpression(expr.left, x => encodeTypedQueryExpression(compiler, parent, x));
905
- const _right = mapExpression(expr.right, x => encodeTypedQueryExpression(compiler, parent, x));
906
- const mapped = _.compact(_.map(_.zip(_left, _right), ([l, r]) => matchType(l, r)));
907
- if (mapped.length === _left.length) {
908
- const [l, r] = _.unzip(mapped);
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);
909
1238
  return sql `(${_.map(l, x => x.sql)}) ${operatorMap[expr.type]} (${_.map(r, x => x.sql)})`;
910
1239
  }
911
1240
  }
912
1241
  const _left = encodeTypedQueryExpression(compiler, parent, expr.left);
913
1242
  const _right = encodeTypedQueryExpression(compiler, parent, expr.right);
914
1243
  if (_left && _right) {
915
- const matched = matchType(_left, _right);
916
- if (matched)
917
- return sql `${matched[0].sql} ${operatorMap[expr.type]} ${matched[1].sql}`;
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
+ }
918
1253
  }
919
1254
  const _left2 = encodeJsonQueryExpression(compiler, parent, expr.left);
920
1255
  const _right2 = encodeJsonQueryExpression(compiler, parent, expr.right);
@@ -926,12 +1261,6 @@ const encodeBooleanExpression = (compiler, parent, expr) => {
926
1261
  }
927
1262
  throw Error('Invalid expression');
928
1263
  };
929
- const encodeQueryExpression = (compiler, parent, expr) => {
930
- if (expr instanceof validator.QueryDistanceExpression) {
931
- return encodeDistanceQueryExpression(compiler, parent, expr);
932
- }
933
- return encodeBooleanExpression(compiler, parent, expr);
934
- };
935
1264
 
936
1265
  //
937
1266
  // storage.ts
@@ -1098,13 +1427,18 @@ class SqlStorage {
1098
1427
  const self = this;
1099
1428
  const compiler = self._makeCompiler(false, query.extraFilter);
1100
1429
  const _matchesType = self._matchesType(compiler, query);
1101
- const _query = compiler._selectQuery({ ...query, sort: {} }, ({ fetchName }) => ({
1102
- sort: sql `ORDER BY ${self.dialect.random(opts?.weight ? _.first(encodeTypedQueryExpression(compiler, {
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, {
1103
1434
  name: fetchName,
1104
1435
  className: query.className,
1105
1436
  groupMatches: query.groupMatches,
1106
- }, opts.weight))?.sql : undefined)}`,
1107
- }));
1437
+ }, opts.weight);
1438
+ if (!weight)
1439
+ throw Error('Invalid expression');
1440
+ return { sort: sql `ORDER BY ${self.dialect.random(weight.sql)}` };
1441
+ });
1108
1442
  return (async function* () {
1109
1443
  const objects = self.query(_query);
1110
1444
  for await (const object of objects) {
@@ -1983,7 +2317,7 @@ const selectPopulate = (compiler, parent, populate, field) => {
1983
2317
  ];
1984
2318
  if (!_.isEmpty(groupMatches?.[field])) {
1985
2319
  for (const [key, expr] of _.entries(groupMatches[field])) {
1986
- if (expr instanceof validator.QueryNoParamAccumulator) {
2320
+ if (expr instanceof validator.QueryZeroParamAccumulator) {
1987
2321
  switch (expr.type) {
1988
2322
  case '$count':
1989
2323
  columns.push(sql `
@@ -1996,11 +2330,10 @@ const selectPopulate = (compiler, parent, populate, field) => {
1996
2330
  break;
1997
2331
  }
1998
2332
  }
1999
- else if (expr instanceof validator.QueryExprAccumulator) {
2333
+ else if (expr instanceof validator.QueryUnaryAccumulator) {
2000
2334
  if (!expr.expr)
2001
2335
  throw Error('Invalid expression');
2002
- const exprs = encodeTypedQueryExpression(compiler, populate, expr.expr);
2003
- const value = _.first(exprs)?.sql;
2336
+ const { sql: value } = encodeTypedQueryExpression(compiler, populate, expr.expr) ?? {};
2004
2337
  if (!value)
2005
2338
  throw Error('Invalid expression');
2006
2339
  switch (expr.type) {
@@ -2043,8 +2376,7 @@ const selectPopulate = (compiler, parent, populate, field) => {
2043
2376
  }[expr.mode];
2044
2377
  if (!expr.input)
2045
2378
  throw Error('Invalid expression');
2046
- const exprs = encodeTypedQueryExpression(compiler, populate, expr.input);
2047
- const value = _.first(exprs)?.sql;
2379
+ const { sql: value } = encodeTypedQueryExpression(compiler, populate, expr.input) ?? {};
2048
2380
  if (!value)
2049
2381
  throw Error('Invalid expression');
2050
2382
  columns.push(sql `
@@ -2632,6 +2964,36 @@ const encodeFieldExpression = (compiler, parent, field, expr) => {
2632
2964
  throw Error('Invalid expression');
2633
2965
  };
2634
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
+
2635
2997
  //
2636
2998
  // relation.ts
2637
2999
  //
@@ -2703,7 +3065,8 @@ const PostgresDialect = {
2703
3065
  updateOperation,
2704
3066
  selectPopulate,
2705
3067
  encodeFieldExpression,
2706
- encodeQueryExpression,
3068
+ encodeBooleanExpression,
3069
+ encodeSortExpression,
2707
3070
  encodePopulate,
2708
3071
  encodeRelation,
2709
3072
  encodeSortKey,