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
@@ -5,7 +5,7 @@ import QueryStream from 'pg-query-stream';
5
5
  import { asyncStream, IteratorPool } from '@o2ter/utils-js';
6
6
  import Decimal from 'decimal.js';
7
7
  import { escapeLiteral, escapeIdentifier } from 'pg/lib/utils';
8
- import { r as resolveColumn, b as resolveDataType$1, d as QueryCoditionalSelector, e as QueryFieldSelector, f as QueryExpressionSelector, g as QueryKeyExpression, h as QueryValueExpression, i as QueryCoditionalExpression, j as QueryComparisonExpression, k as QueryNotExpression, l as QueryDistanceExpression, m as QueryArrayExpression, Q as QueryValidator, n as QueryNoParamAccumulator, o as QueryExprAccumulator, p as QueryPercentileAccumulator, c as QuerySelector, F as FieldSelectorExpression } from '../../internals/validator-LNgZGT_l.mjs';
8
+ import { r as resolveColumn, b as resolveDataType$1, d as QueryCoditionalSelector, e as QueryFieldSelector, f as QueryExpressionSelector, g as QueryArrayExpression, h as QueryValueExpression, i as QueryKeyExpression, j as QueryCoditionalExpression, k as QueryComparisonExpression, l as QueryNotExpression, m as QueryDistanceExpression, n as QueryZeroParamExpression, o as QueryUnaryExpression, p as QueryBinaryExpression, q as QueryListExpression, s as QueryTernaryExpression, t as QueryCondExpression, Q as QueryValidator, u as QueryZeroParamAccumulator, v as QueryUnaryAccumulator, w as QueryPercentileAccumulator, c as QuerySelector, F as FieldSelectorExpression } from '../../internals/validator-CEcBF4Cn.mjs';
9
9
  import '@o2ter/crypto-js';
10
10
  import { c as PROTO_EVENT } from '../../internals/const-Dkp7Nsv5.mjs';
11
11
  import { g as generateId } from '../../internals/random-CYjWDvex.mjs';
@@ -409,7 +409,7 @@ class QueryCompiler {
409
409
  return this.dialect.encodeFieldExpression(this, parent, filter.field, filter.expr);
410
410
  }
411
411
  if (filter instanceof QueryExpressionSelector) {
412
- return this.dialect.encodeQueryExpression(this, parent, filter.expr);
412
+ return this.dialect.encodeBooleanExpression(this, parent, filter.expr);
413
413
  }
414
414
  }
415
415
  _selectIncludes(className, includes) {
@@ -424,7 +424,7 @@ class QueryCompiler {
424
424
  _encodeSort(sort, parent) {
425
425
  if (_.isArray(sort)) {
426
426
  return sql `${_.map(sort, ({ expr, order }) => {
427
- const _expr = this.dialect.encodeQueryExpression(this, parent, expr);
427
+ const _expr = this.dialect.encodeSortExpression(this, parent, expr);
428
428
  if (!_expr)
429
429
  throw Error('Invalid expression');
430
430
  return sql `${_expr} ${{ literal: order === 1 ? 'ASC' : 'DESC' }}`;
@@ -704,7 +704,7 @@ const decodeType = (type, value) => {
704
704
  };
705
705
 
706
706
  //
707
- // expressions.ts
707
+ // types.ts
708
708
  //
709
709
  // The MIT License
710
710
  // Copyright (c) 2021 - 2025 O2ter Limited. All rights reserved.
@@ -727,7 +727,8 @@ const decodeType = (type, value) => {
727
727
  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
728
728
  // THE SOFTWARE.
729
729
  //
730
- const isArrayExpression = (expr) => {
730
+ const _PrimitiveValue = ['boolean', 'number', 'decimal', 'string', 'date'];
731
+ const isArrayExpr = (expr) => {
731
732
  if (expr instanceof QueryArrayExpression)
732
733
  return true;
733
734
  if (expr instanceof QueryValueExpression)
@@ -741,62 +742,428 @@ const arrayLength = (expr) => {
741
742
  return _.isArray(expr.value) ? expr.value.length : 0;
742
743
  return 0;
743
744
  };
744
- const mapExpression = (expr, callback) => {
745
+ const mapExpr = (expr, callback) => {
745
746
  if (expr instanceof QueryArrayExpression)
746
747
  return _.map(expr.exprs, x => callback(x));
747
748
  if (expr instanceof QueryValueExpression)
748
749
  return _.isArray(expr.value) ? _.map(expr.value, x => callback(new QueryValueExpression(x))) : [];
749
750
  return [];
750
751
  };
751
- const _PrimitiveValue = ['boolean', 'number', 'decimal', 'string', 'date'];
752
+ const zipExpr = (lhs, rhs) => {
753
+ const result = [];
754
+ for (const [l, r] of _.zip(lhs, rhs)) {
755
+ if (!l || !r)
756
+ return;
757
+ if (l.type === r.type)
758
+ result.push([l, r]);
759
+ else if (l.type === 'number' && r.type === 'decimal')
760
+ result.push([l, { type: 'decimal', sql: sql `CAST((${r.sql}) AS DECIMAL)` }]);
761
+ else if (l.type === 'decimal' && r.type === 'number')
762
+ result.push([{ type: 'decimal', sql: sql `CAST((${l.sql}) AS DECIMAL)` }, r]);
763
+ else
764
+ return;
765
+ }
766
+ return result;
767
+ };
768
+ const typeCastExpr = (expr, type) => {
769
+ if (!expr)
770
+ return;
771
+ if (expr.type === type)
772
+ return expr;
773
+ if (expr.type === 'number' && type === 'decimal')
774
+ return { type, sql: sql `CAST((${expr.sql}) AS DECIMAL)` };
775
+ if (expr.type === 'decimal' && type === 'number')
776
+ return { type, sql: sql `CAST((${expr.sql}) AS DOUBLE PRECISION)` };
777
+ };
778
+
779
+ //
780
+ // vector.ts
781
+ //
782
+ // The MIT License
783
+ // Copyright (c) 2021 - 2025 O2ter Limited. All rights reserved.
784
+ //
785
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
786
+ // of this software and associated documentation files (the "Software"), to deal
787
+ // in the Software without restriction, including without limitation the rights
788
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
789
+ // copies of the Software, and to permit persons to whom the Software is
790
+ // furnished to do so, subject to the following conditions:
791
+ //
792
+ // The above copyright notice and this permission notice shall be included in
793
+ // all copies or substantial portions of the Software.
794
+ //
795
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
796
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
797
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
798
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
799
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
800
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
801
+ // THE SOFTWARE.
802
+ //
803
+ const encodeVectorExpression = (compiler, parent, exprs) => {
804
+ if (exprs.length === 1) {
805
+ const [expr] = exprs;
806
+ if (expr instanceof QueryKeyExpression) {
807
+ const { element, dataType } = fetchElement(compiler, parent, expr.key);
808
+ if (!dataType || !isVector(dataType))
809
+ throw Error('Invalid expression');
810
+ return { sql: element, dimension: dataType.dimension };
811
+ }
812
+ if (expr instanceof QueryValueExpression) {
813
+ if (!_.isArray(expr.value) || !_.every(expr.value, x => _.isFinite(x)))
814
+ throw Error('Invalid expression');
815
+ return { sql: sql `${{ value: expr.value }}::DOUBLE PRECISION[]`, dimension: expr.value.length };
816
+ }
817
+ }
818
+ const result = _.compact(_.map(exprs, x => typeCastExpr(encodeTypedQueryExpression(compiler, parent, x), 'number')?.sql));
819
+ if (result.length !== exprs.length)
820
+ throw Error('Invalid expression');
821
+ return { sql: sql `ARRAY[${_.map(result, x => sql `COALESCE(${x}, 0)`)}]`, dimension: result.length };
822
+ };
823
+ const encodeDistanceQueryExpression = (compiler, parent, expr) => {
824
+ const { sql: left, dimension: d1 } = encodeVectorExpression(compiler, parent, expr.left);
825
+ const { sql: right, dimension: d2 } = encodeVectorExpression(compiler, parent, expr.right);
826
+ if (d1 !== d2)
827
+ throw Error('Invalid expression');
828
+ const operatorMap = {
829
+ '$distance': sql `<->`,
830
+ '$innerProduct': sql `<#>`,
831
+ '$negInnerProduct': sql `<#>`,
832
+ '$cosineDistance': sql `<=>`,
833
+ '$rectilinearDistance': sql `<+>`,
834
+ };
835
+ const _expr = sql `
836
+ CAST(
837
+ ${left} AS VECTOR(${{ literal: `${d1}` }})
838
+ )
839
+ ${operatorMap[expr.type]}
840
+ CAST(
841
+ ${right} AS VECTOR(${{ literal: `${d2}` }})
842
+ )
843
+ `;
844
+ return expr.type === '$innerProduct' ? sql `-1 * (${_expr})` : _expr;
845
+ };
846
+
847
+ //
848
+ // index.ts
849
+ //
850
+ // The MIT License
851
+ // Copyright (c) 2021 - 2025 O2ter Limited. All rights reserved.
852
+ //
853
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
854
+ // of this software and associated documentation files (the "Software"), to deal
855
+ // in the Software without restriction, including without limitation the rights
856
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
857
+ // copies of the Software, and to permit persons to whom the Software is
858
+ // furnished to do so, subject to the following conditions:
859
+ //
860
+ // The above copyright notice and this permission notice shall be included in
861
+ // all copies or substantial portions of the Software.
862
+ //
863
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
864
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
865
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
866
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
867
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
868
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
869
+ // THE SOFTWARE.
870
+ //
752
871
  const encodeTypedQueryExpression = (compiler, parent, expr) => {
753
872
  if (expr instanceof QueryKeyExpression) {
754
873
  const { element, dataType } = fetchElement(compiler, parent, expr.key);
755
874
  const _dataType = dataType ? _typeof(dataType) : null;
756
- if (_dataType === 'number') {
757
- return [
758
- { type: 'number', sql: element },
759
- { type: 'decimal', sql: sql `CAST((${element}) AS DECIMAL)` },
760
- ];
761
- }
762
- else if (_dataType === 'decimal') {
763
- return [
764
- { type: 'decimal', sql: element },
765
- { type: 'number', sql: element },
766
- ];
767
- }
768
- else if (_dataType && _PrimitiveValue.includes(_dataType)) {
769
- return [{ type: _dataType, sql: element }];
770
- }
875
+ if (!_dataType || !_PrimitiveValue.includes(_dataType))
876
+ return;
877
+ return { type: _dataType, sql: element };
771
878
  }
772
879
  if (expr instanceof QueryValueExpression) {
773
880
  if (_.isBoolean(expr.value))
774
- return [{ type: 'boolean', sql: sql `${{ value: expr.value }}` }];
881
+ return { type: 'boolean', sql: sql `${{ value: expr.value }}` };
775
882
  if (_.isNumber(expr.value))
776
- return [
777
- { type: 'number', sql: sql `${{ value: expr.value }}` },
778
- { type: 'decimal', sql: sql `CAST(${{ quote: (new Decimal(expr.value)).toString() }} AS DECIMAL)` },
779
- ];
883
+ return { type: 'number', sql: sql `${{ value: expr.value }}` };
780
884
  if (expr.value instanceof Decimal)
781
- return [
782
- { type: 'decimal', sql: sql `CAST(${{ quote: expr.value.toString() }} AS DECIMAL)` },
783
- { type: 'number', sql: sql `${{ value: expr.value.toNumber() }}` },
784
- ];
885
+ return { type: 'decimal', sql: sql `CAST(${{ quote: expr.value.toString() }} AS DECIMAL)` };
785
886
  if (_.isString(expr.value))
786
- return [{ type: 'string', sql: sql `${{ value: expr.value }}` }];
887
+ return { type: 'string', sql: sql `${{ value: expr.value }}` };
787
888
  if (_.isDate(expr.value))
788
- return [{ type: 'date', sql: sql `${{ value: expr.value }}` }];
889
+ return { type: 'date', sql: sql `${{ value: expr.value }}` };
789
890
  }
790
891
  if (expr instanceof QueryCoditionalExpression ||
791
892
  expr instanceof QueryComparisonExpression ||
792
893
  expr instanceof QueryNotExpression) {
793
894
  const value = encodeBooleanExpression(compiler, parent, expr);
794
895
  if (value)
795
- return [{ type: 'boolean', sql: value }];
896
+ return { type: 'boolean', sql: value };
796
897
  }
797
898
  if (expr instanceof QueryDistanceExpression) {
798
899
  const value = encodeDistanceQueryExpression(compiler, parent, expr);
799
- return [{ type: 'number', sql: value }];
900
+ return { type: 'number', sql: value };
901
+ }
902
+ if (expr instanceof QueryZeroParamExpression) {
903
+ switch (expr.type) {
904
+ case '$rand': return { type: 'number', sql: sql `RANDOM()` };
905
+ case '$now': return { type: 'date', sql: sql `CAST(NOW() AS TIMESTAMP(3) WITH TIME ZONE)` };
906
+ }
907
+ }
908
+ if (expr instanceof QueryUnaryExpression) {
909
+ const value = encodeTypedQueryExpression(compiler, parent, expr.expr);
910
+ if (!value)
911
+ return;
912
+ switch (expr.type) {
913
+ case '$abs':
914
+ case '$neg':
915
+ case '$sqrt':
916
+ case '$cbrt':
917
+ case '$ceil':
918
+ case '$floor':
919
+ case '$round':
920
+ case '$exp':
921
+ case '$ln':
922
+ case '$log10':
923
+ case '$sin':
924
+ case '$cos':
925
+ case '$tan':
926
+ case '$asin':
927
+ case '$acos':
928
+ case '$atan':
929
+ case '$asinh':
930
+ case '$acosh':
931
+ case '$atanh':
932
+ case '$sinh':
933
+ case '$cosh':
934
+ case '$tanh':
935
+ case '$degrees':
936
+ case '$radians':
937
+ case '$sign':
938
+ {
939
+ const op = {
940
+ '$abs': 'ABS',
941
+ '$neg': '-',
942
+ '$sqrt': 'SQRT',
943
+ '$cbrt': 'CBRT',
944
+ '$ceil': 'CEIL',
945
+ '$floor': 'FLOOR',
946
+ '$round': 'ROUND',
947
+ '$exp': 'EXP',
948
+ '$ln': 'LN',
949
+ '$log10': 'LOG10',
950
+ '$sin': 'SIN',
951
+ '$cos': 'COS',
952
+ '$tan': 'TAN',
953
+ '$asin': 'ASIN',
954
+ '$acos': 'ACOS',
955
+ '$atan': 'ATAN',
956
+ '$asinh': 'ASINH',
957
+ '$acosh': 'ACOSH',
958
+ '$atanh': 'ATANH',
959
+ '$sinh': 'SINH',
960
+ '$cosh': 'COSH',
961
+ '$tanh': 'TANH',
962
+ '$degrees': 'DEGREES',
963
+ '$radians': 'RADIANS',
964
+ '$sign': 'SIGN',
965
+ }[expr.type];
966
+ if (!_.includes(['number', 'decimal'], value.type))
967
+ return;
968
+ return { type: 'number', sql: sql `${{ literal: op }}(${value.sql})` };
969
+ }
970
+ case '$log2':
971
+ if (!_.includes(['number', 'decimal'], value.type))
972
+ return;
973
+ return { type: value.type, sql: sql `(LOG(${value.sql}) / LOG(2))` };
974
+ case '$size':
975
+ if (!_.includes(['string', 'string[]', 'array'], value.type))
976
+ return;
977
+ return { type: 'number', sql: sql `LENGTH(${value.sql})` };
978
+ case '$lower':
979
+ case '$upper':
980
+ {
981
+ const op = {
982
+ '$lower': 'LOWER',
983
+ '$upper': 'UPPER',
984
+ }[expr.type];
985
+ if (value.type !== 'string')
986
+ return;
987
+ return { type: 'string', sql: sql `${{ literal: op }}(${value.sql})` };
988
+ }
989
+ }
990
+ }
991
+ if (expr instanceof QueryBinaryExpression) {
992
+ const left = encodeTypedQueryExpression(compiler, parent, expr.left);
993
+ const right = encodeTypedQueryExpression(compiler, parent, expr.right);
994
+ if (!left || !right)
995
+ return;
996
+ switch (expr.type) {
997
+ case '$divide':
998
+ case '$subtract':
999
+ {
1000
+ const op = {
1001
+ '$divide': '/',
1002
+ '$subtract': '-',
1003
+ }[expr.type];
1004
+ if (left.type === right.type) {
1005
+ return { type: left.type, sql: sql `(${left.sql}) ${{ literal: op }} (${right.sql})` };
1006
+ }
1007
+ if (left.type === 'decimal' && right.type === 'number') {
1008
+ return { type: 'decimal', sql: sql `CAST((${left.sql}) AS DECIMAL) ${{ literal: op }} (${right.sql})` };
1009
+ }
1010
+ if (left.type === 'number' && right.type === 'decimal') {
1011
+ return { type: 'decimal', sql: sql `(${left.sql}) ${{ literal: op }} CAST((${right.sql}) AS DECIMAL)` };
1012
+ }
1013
+ }
1014
+ break;
1015
+ case '$log':
1016
+ {
1017
+ if (left.type === right.type) {
1018
+ return { type: left.type, sql: sql `(LOG(${left.sql}) / LOG(${right.sql}))` };
1019
+ }
1020
+ if (left.type === 'decimal' && right.type === 'number') {
1021
+ return { type: 'decimal', sql: sql `(LOG(${left.sql}) / LOG(CAST((${right.sql}) AS DECIMAL)))` };
1022
+ }
1023
+ if (left.type === 'number' && right.type === 'decimal') {
1024
+ return { type: 'decimal', sql: sql `(LOG(CAST((${left.sql}) AS DECIMAL) / LOG(${right.sql}))` };
1025
+ }
1026
+ }
1027
+ break;
1028
+ case '$pow':
1029
+ case '$atan2':
1030
+ {
1031
+ const op = {
1032
+ '$pow': 'POWER',
1033
+ '$atan2': 'ATAN2',
1034
+ }[expr.type];
1035
+ if (left.type === right.type) {
1036
+ return { type: left.type, sql: sql `${{ literal: op }}((${left.sql}), (${right.sql}))` };
1037
+ }
1038
+ if (left.type === 'decimal' && right.type === 'number') {
1039
+ return { type: 'decimal', sql: sql `${{ literal: op }}((${left.sql}), CAST((${right.sql}) AS DECIMAL))` };
1040
+ }
1041
+ if (left.type === 'number' && right.type === 'decimal') {
1042
+ return { type: 'decimal', sql: sql `${{ literal: op }}(CAST((${left.sql}) AS DECIMAL), (${right.sql}))` };
1043
+ }
1044
+ }
1045
+ break;
1046
+ case '$trim':
1047
+ case '$ltrim':
1048
+ case '$rtrim':
1049
+ {
1050
+ const op = {
1051
+ '$trim': 'TRIM',
1052
+ '$ltrim': 'LTRIM',
1053
+ '$rtrim': 'RTRIM',
1054
+ }[expr.type];
1055
+ if (left?.type !== 'string' || right?.type !== 'string')
1056
+ return;
1057
+ return { type: 'string', sql: sql `${{ literal: op }}(${left.sql}, ${right.sql})` };
1058
+ }
1059
+ case '$first':
1060
+ case '$last':
1061
+ {
1062
+ if (!_.includes(['number', 'decimal'], right.type))
1063
+ return;
1064
+ if (left?.type === 'string') {
1065
+ const op = {
1066
+ '$first': 'LEFT',
1067
+ '$last': 'RIGHT',
1068
+ }[expr.type];
1069
+ return { type: 'string', sql: sql `${{ literal: op }}(${left.sql}, ${right.sql})` };
1070
+ }
1071
+ }
1072
+ break;
1073
+ case '$ldrop':
1074
+ case '$rdrop':
1075
+ {
1076
+ if (!_.includes(['number', 'decimal'], right.type))
1077
+ return;
1078
+ if (left?.type === 'string') {
1079
+ const op = {
1080
+ '$ldrop': 'RIGHT',
1081
+ '$rdrop': 'LEFT',
1082
+ }[expr.type];
1083
+ return { type: 'string', sql: sql `${{ literal: op }}(${left.sql}, -(${right.sql}))` };
1084
+ }
1085
+ }
1086
+ break;
1087
+ }
1088
+ }
1089
+ if (expr instanceof QueryListExpression) {
1090
+ const values = _.compact(_.map(expr.exprs, x => encodeTypedQueryExpression(compiler, parent, x)));
1091
+ if (values.length !== expr.exprs.length)
1092
+ return;
1093
+ switch (expr.type) {
1094
+ case '$add':
1095
+ case '$multiply':
1096
+ {
1097
+ const op = {
1098
+ '$add': '+',
1099
+ '$multiply': '*',
1100
+ }[expr.type];
1101
+ if (_.every(values, x => x.type === 'number')) {
1102
+ return { type: 'number', sql: sql `${{ literal: _.map(values, x => x.sql), separator: ` ${op} ` }}` };
1103
+ }
1104
+ if (_.every(values, x => x.type === 'number' || x.type === 'decimal')) {
1105
+ return { type: 'decimal', sql: sql `${{ literal: _.map(values, x => x.type === 'decimal' ? x.sql : sql `CAST((${x.sql}) AS DECIMAL)`), separator: ` ${op} ` }}` };
1106
+ }
1107
+ }
1108
+ break;
1109
+ case '$ifNull':
1110
+ {
1111
+ const type = values[0].type;
1112
+ if (_.every(values, x => x.type === type)) {
1113
+ return { type, sql: sql `COALESCE(${{ literal: _.map(values, x => x.sql) }})` };
1114
+ }
1115
+ }
1116
+ break;
1117
+ case '$concat':
1118
+ {
1119
+ if (_.every(values, x => x.type === 'string')) {
1120
+ return { type: 'string', sql: sql `CONCAT(${{ literal: _.map(values, x => x.sql) }})` };
1121
+ }
1122
+ }
1123
+ break;
1124
+ }
1125
+ }
1126
+ if (expr instanceof QueryTernaryExpression) {
1127
+ const first = encodeTypedQueryExpression(compiler, parent, expr.first);
1128
+ const second = encodeTypedQueryExpression(compiler, parent, expr.second);
1129
+ const last = encodeTypedQueryExpression(compiler, parent, expr.last);
1130
+ if (!first || !second || !last)
1131
+ return;
1132
+ switch (expr.type) {
1133
+ case '$lpad':
1134
+ case '$rpad':
1135
+ {
1136
+ const op = {
1137
+ '$lpad': 'LPAD',
1138
+ '$rpad': 'RPAD',
1139
+ }[expr.type];
1140
+ if (first?.type !== 'string' || last?.type !== 'string')
1141
+ return;
1142
+ if (!_.includes(['number', 'decimal'], second.type))
1143
+ return;
1144
+ return { type: 'string', sql: sql `${{ literal: op }}(${first.sql}, ${second.sql}, ${last.sql})` };
1145
+ }
1146
+ }
1147
+ }
1148
+ if (expr instanceof QueryCondExpression) {
1149
+ const branches = _.flatMap(_.map(expr.branch, x => ({
1150
+ case: encodeTypedQueryExpression(compiler, parent, x.case),
1151
+ then: encodeTypedQueryExpression(compiler, parent, x.then),
1152
+ })), x => x.case && x.then ? ({ case: x.case, then: x.then }) : []);
1153
+ if (branches.length !== expr.branch.length)
1154
+ return;
1155
+ const defaultCase = encodeTypedQueryExpression(compiler, parent, expr.default);
1156
+ if (!defaultCase)
1157
+ return;
1158
+ if (!_.every(branches, x => x.case.type === 'boolean' && x.then.type === defaultCase.type))
1159
+ return;
1160
+ return {
1161
+ type: defaultCase.type,
1162
+ sql: sql `CASE ${{
1163
+ literal: _.map(branches, x => sql `WHEN (${x.case.sql}) THEN (${x.then.sql})`),
1164
+ separator: ' '
1165
+ }} ELSE (${defaultCase.sql}) END`,
1166
+ };
800
1167
  }
801
1168
  };
802
1169
  const encodeJsonQueryExpression = (compiler, parent, expr) => {
@@ -822,57 +1189,19 @@ const encodeJsonQueryExpression = (compiler, parent, expr) => {
822
1189
  if (expr instanceof QueryArrayExpression) {
823
1190
  return sql `jsonb_build_array(${_.map(expr.exprs, x => encodeJsonQueryExpression(compiler, parent, x))})`;
824
1191
  }
825
- const value = encodeQueryExpression(compiler, parent, expr);
826
- if (!value)
1192
+ const typed = encodeTypedQueryExpression(compiler, parent, expr);
1193
+ if (!typed)
827
1194
  throw Error('Invalid expression');
828
- return sql `to_jsonb(${value})`;
829
- };
830
- const encodeVectorExpression = (compiler, parent, exprs) => {
831
- if (exprs.length === 1) {
832
- const [expr] = exprs;
833
- if (expr instanceof QueryKeyExpression) {
834
- const { element, dataType } = fetchElement(compiler, parent, expr.key);
835
- if (!dataType || !isVector(dataType))
836
- throw Error('Invalid expression');
837
- return { sql: element, dimension: dataType.dimension };
838
- }
839
- if (expr instanceof QueryValueExpression) {
840
- if (!_.isArray(expr.value) || !_.every(expr.value, x => _.isFinite(x)))
841
- throw Error('Invalid expression');
842
- return { sql: sql `${{ value: expr.value }}::DOUBLE PRECISION[]`, dimension: expr.value.length };
843
- }
1195
+ switch (typed.type) {
1196
+ case 'boolean': return sql `to_jsonb(${typed.sql})`;
1197
+ case 'number': return sql `to_jsonb(${typed.sql})`;
1198
+ case 'decimal': return sql `jsonb_build_object('$decimal', CAST(${typed.sql} AS TEXT))`;
1199
+ case 'string': return sql `to_jsonb(${typed.sql})`;
1200
+ case 'date': return sql `jsonb_build_object(
1201
+ '$date', to_char(${typed.sql} AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"')
1202
+ )`;
1203
+ default: throw Error('Invalid expression');
844
1204
  }
845
- const result = _.map(exprs, x => _.find(encodeTypedQueryExpression(compiler, parent, x), e => e.type === 'number')?.sql);
846
- if (_.some(result, x => _.isNil(x)))
847
- throw Error('Invalid expression');
848
- return { sql: sql `ARRAY[${_.map(result, x => sql `COALESCE(${x}, 0)`)}]`, dimension: result.length };
849
- };
850
- const encodeDistanceQueryExpression = (compiler, parent, expr) => {
851
- const { sql: left, dimension: d1 } = encodeVectorExpression(compiler, parent, expr.left);
852
- const { sql: right, dimension: d2 } = encodeVectorExpression(compiler, parent, expr.right);
853
- if (d1 !== d2)
854
- throw Error('Invalid expression');
855
- const operatorMap = {
856
- '$distance': sql `<->`,
857
- '$innerProduct': sql `<#>`,
858
- '$negInnerProduct': sql `<#>`,
859
- '$cosineDistance': sql `<=>`,
860
- '$rectilinearDistance': sql `<+>`,
861
- };
862
- const _expr = sql `
863
- CAST(
864
- ${left} AS VECTOR(${{ literal: `${d1}` }})
865
- )
866
- ${operatorMap[expr.type]}
867
- CAST(
868
- ${right} AS VECTOR(${{ literal: `${d2}` }})
869
- )
870
- `;
871
- return expr.type === '$innerProduct' ? sql `-1 * (${_expr})` : _expr;
872
- };
873
- const matchType = (first, second) => {
874
- const found = _.find(first, l => _.some(second, r => l.type === r.type));
875
- return found ? [found, _.find(second, r => r.type === found.type)] : undefined;
876
1205
  };
877
1206
  const encodeBooleanExpression = (compiler, parent, expr) => {
878
1207
  if (expr instanceof QueryCoditionalExpression) {
@@ -894,23 +1223,29 @@ const encodeBooleanExpression = (compiler, parent, expr) => {
894
1223
  '$lt': sql `<`,
895
1224
  '$lte': sql `<=`,
896
1225
  };
897
- if (isArrayExpression(expr.left) &&
898
- isArrayExpression(expr.right) &&
1226
+ if (isArrayExpr(expr.left) &&
1227
+ isArrayExpr(expr.right) &&
899
1228
  arrayLength(expr.left) === arrayLength(expr.right)) {
900
- const _left = mapExpression(expr.left, x => encodeTypedQueryExpression(compiler, parent, x));
901
- const _right = mapExpression(expr.right, x => encodeTypedQueryExpression(compiler, parent, x));
902
- const mapped = _.compact(_.map(_.zip(_left, _right), ([l, r]) => matchType(l, r)));
903
- if (mapped.length === _left.length) {
904
- const [l, r] = _.unzip(mapped);
1229
+ const _left = mapExpr(expr.left, x => encodeTypedQueryExpression(compiler, parent, x));
1230
+ const _right = mapExpr(expr.right, x => encodeTypedQueryExpression(compiler, parent, x));
1231
+ const zipped = zipExpr(_left, _right) ?? [];
1232
+ if (_left.length === zipped.length) {
1233
+ const [l, r] = _.unzip(zipped);
905
1234
  return sql `(${_.map(l, x => x.sql)}) ${operatorMap[expr.type]} (${_.map(r, x => x.sql)})`;
906
1235
  }
907
1236
  }
908
1237
  const _left = encodeTypedQueryExpression(compiler, parent, expr.left);
909
1238
  const _right = encodeTypedQueryExpression(compiler, parent, expr.right);
910
1239
  if (_left && _right) {
911
- const matched = matchType(_left, _right);
912
- if (matched)
913
- return sql `${matched[0].sql} ${operatorMap[expr.type]} ${matched[1].sql}`;
1240
+ if (_left.type === _right.type) {
1241
+ return sql `(${_left.sql}) ${operatorMap[expr.type]} (${_right.sql})`;
1242
+ }
1243
+ if (_left.type === 'decimal' && _right.type === 'number') {
1244
+ return sql `CAST((${_left.sql}) AS DOUBLE PRECISION) ${operatorMap[expr.type]} (${_right.sql})`;
1245
+ }
1246
+ if (_left.type === 'number' && _right.type === 'decimal') {
1247
+ return sql `(${_left.sql}) ${operatorMap[expr.type]} CAST((${_right.sql}) AS DOUBLE PRECISION)`;
1248
+ }
914
1249
  }
915
1250
  const _left2 = encodeJsonQueryExpression(compiler, parent, expr.left);
916
1251
  const _right2 = encodeJsonQueryExpression(compiler, parent, expr.right);
@@ -922,12 +1257,6 @@ const encodeBooleanExpression = (compiler, parent, expr) => {
922
1257
  }
923
1258
  throw Error('Invalid expression');
924
1259
  };
925
- const encodeQueryExpression = (compiler, parent, expr) => {
926
- if (expr instanceof QueryDistanceExpression) {
927
- return encodeDistanceQueryExpression(compiler, parent, expr);
928
- }
929
- return encodeBooleanExpression(compiler, parent, expr);
930
- };
931
1260
 
932
1261
  //
933
1262
  // storage.ts
@@ -1094,13 +1423,18 @@ class SqlStorage {
1094
1423
  const self = this;
1095
1424
  const compiler = self._makeCompiler(false, query.extraFilter);
1096
1425
  const _matchesType = self._matchesType(compiler, query);
1097
- const _query = compiler._selectQuery({ ...query, sort: {} }, ({ fetchName }) => ({
1098
- sort: sql `ORDER BY ${self.dialect.random(opts?.weight ? _.first(encodeTypedQueryExpression(compiler, {
1426
+ const _query = compiler._selectQuery({ ...query, sort: {} }, ({ fetchName }) => {
1427
+ if (!opts?.weight)
1428
+ return { sort: sql `ORDER BY ${self.dialect.random()}` };
1429
+ const weight = encodeTypedQueryExpression(compiler, {
1099
1430
  name: fetchName,
1100
1431
  className: query.className,
1101
1432
  groupMatches: query.groupMatches,
1102
- }, opts.weight))?.sql : undefined)}`,
1103
- }));
1433
+ }, opts.weight);
1434
+ if (!weight)
1435
+ throw Error('Invalid expression');
1436
+ return { sort: sql `ORDER BY ${self.dialect.random(weight.sql)}` };
1437
+ });
1104
1438
  return (async function* () {
1105
1439
  const objects = self.query(_query);
1106
1440
  for await (const object of objects) {
@@ -1979,7 +2313,7 @@ const selectPopulate = (compiler, parent, populate, field) => {
1979
2313
  ];
1980
2314
  if (!_.isEmpty(groupMatches?.[field])) {
1981
2315
  for (const [key, expr] of _.entries(groupMatches[field])) {
1982
- if (expr instanceof QueryNoParamAccumulator) {
2316
+ if (expr instanceof QueryZeroParamAccumulator) {
1983
2317
  switch (expr.type) {
1984
2318
  case '$count':
1985
2319
  columns.push(sql `
@@ -1992,11 +2326,10 @@ const selectPopulate = (compiler, parent, populate, field) => {
1992
2326
  break;
1993
2327
  }
1994
2328
  }
1995
- else if (expr instanceof QueryExprAccumulator) {
2329
+ else if (expr instanceof QueryUnaryAccumulator) {
1996
2330
  if (!expr.expr)
1997
2331
  throw Error('Invalid expression');
1998
- const exprs = encodeTypedQueryExpression(compiler, populate, expr.expr);
1999
- const value = _.first(exprs)?.sql;
2332
+ const { sql: value } = encodeTypedQueryExpression(compiler, populate, expr.expr) ?? {};
2000
2333
  if (!value)
2001
2334
  throw Error('Invalid expression');
2002
2335
  switch (expr.type) {
@@ -2039,8 +2372,7 @@ const selectPopulate = (compiler, parent, populate, field) => {
2039
2372
  }[expr.mode];
2040
2373
  if (!expr.input)
2041
2374
  throw Error('Invalid expression');
2042
- const exprs = encodeTypedQueryExpression(compiler, populate, expr.input);
2043
- const value = _.first(exprs)?.sql;
2375
+ const { sql: value } = encodeTypedQueryExpression(compiler, populate, expr.input) ?? {};
2044
2376
  if (!value)
2045
2377
  throw Error('Invalid expression');
2046
2378
  columns.push(sql `
@@ -2628,6 +2960,36 @@ const encodeFieldExpression = (compiler, parent, field, expr) => {
2628
2960
  throw Error('Invalid expression');
2629
2961
  };
2630
2962
 
2963
+ //
2964
+ // index.ts
2965
+ //
2966
+ // The MIT License
2967
+ // Copyright (c) 2021 - 2025 O2ter Limited. All rights reserved.
2968
+ //
2969
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
2970
+ // of this software and associated documentation files (the "Software"), to deal
2971
+ // in the Software without restriction, including without limitation the rights
2972
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
2973
+ // copies of the Software, and to permit persons to whom the Software is
2974
+ // furnished to do so, subject to the following conditions:
2975
+ //
2976
+ // The above copyright notice and this permission notice shall be included in
2977
+ // all copies or substantial portions of the Software.
2978
+ //
2979
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2980
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2981
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2982
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2983
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2984
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2985
+ // THE SOFTWARE.
2986
+ //
2987
+ const encodeSortExpression = (compiler, parent, expr) => {
2988
+ if (expr instanceof QueryDistanceExpression) {
2989
+ return encodeDistanceQueryExpression(compiler, parent, expr);
2990
+ }
2991
+ };
2992
+
2631
2993
  //
2632
2994
  // relation.ts
2633
2995
  //
@@ -2699,7 +3061,8 @@ const PostgresDialect = {
2699
3061
  updateOperation,
2700
3062
  selectPopulate,
2701
3063
  encodeFieldExpression,
2702
- encodeQueryExpression,
3064
+ encodeBooleanExpression,
3065
+ encodeSortExpression,
2703
3066
  encodePopulate,
2704
3067
  encodeRelation,
2705
3068
  encodeSortKey,