proto.io 0.0.216 → 0.0.218
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.
- package/dist/adapters/file/aliyun-oss.d.ts +3 -3
- package/dist/adapters/file/database.d.ts +2 -2
- package/dist/adapters/file/database.js +2 -2
- package/dist/adapters/file/database.mjs +2 -2
- package/dist/adapters/file/filesystem.d.ts +3 -3
- package/dist/adapters/file/google-cloud-storage.d.ts +3 -3
- package/dist/adapters/storage/progres.d.ts +5 -3
- package/dist/adapters/storage/progres.js +511 -148
- package/dist/adapters/storage/progres.js.map +1 -1
- package/dist/adapters/storage/progres.mjs +511 -148
- package/dist/adapters/storage/progres.mjs.map +1 -1
- package/dist/client.d.ts +3 -3
- package/dist/client.js +2 -8
- package/dist/client.js.map +1 -1
- package/dist/client.mjs +3 -3
- package/dist/client.mjs.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +28 -34
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +29 -29
- package/dist/index.mjs.map +1 -1
- package/dist/internals/{base-BO3ZP6EF.d.ts → base-CqeIQTE9.d.ts} +2 -2
- package/dist/internals/base-CqeIQTE9.d.ts.map +1 -0
- package/dist/internals/{chunk-DDkLpKXp.d.ts → chunk-CLKTwfRe.d.ts} +3 -3
- package/dist/internals/chunk-CLKTwfRe.d.ts.map +1 -0
- package/dist/internals/{index-B8TESzd9.js → index-CLKTEIj0.js} +2 -2
- package/dist/internals/index-CLKTEIj0.js.map +1 -0
- package/dist/internals/{index-DF2AfSGK.mjs → index-CZ5fKgiJ.mjs} +159 -166
- package/dist/internals/index-CZ5fKgiJ.mjs.map +1 -0
- package/dist/internals/{index-CYhA8SU8.d.ts → index-Ci8d33k-.d.ts} +3 -9
- package/dist/internals/index-Ci8d33k-.d.ts.map +1 -0
- package/dist/internals/{index-HdMgLYtD.d.ts → index-DQHWdslW.d.ts} +59 -22
- package/dist/internals/index-DQHWdslW.d.ts.map +1 -0
- package/dist/internals/{index-BzDsTt4R.mjs → index-gWcE22mf.mjs} +2 -2
- package/dist/internals/index-gWcE22mf.mjs.map +1 -0
- package/dist/internals/{index-DfnPpl1I.js → index-xHeu-AjT.js} +158 -171
- package/dist/internals/index-xHeu-AjT.js.map +1 -0
- package/dist/internals/{validator-BBjOdLiT.js → validator-B5yHpyvb.js} +743 -36
- package/dist/internals/validator-B5yHpyvb.js.map +1 -0
- package/dist/internals/{validator-LNgZGT_l.mjs → validator-DX2nXeQo.mjs} +736 -35
- package/dist/internals/validator-DX2nXeQo.mjs.map +1 -0
- package/package.json +2 -2
- package/dist/internals/base-BO3ZP6EF.d.ts.map +0 -1
- package/dist/internals/chunk-DDkLpKXp.d.ts.map +0 -1
- package/dist/internals/index-B8TESzd9.js.map +0 -1
- package/dist/internals/index-BzDsTt4R.mjs.map +0 -1
- package/dist/internals/index-CYhA8SU8.d.ts.map +0 -1
- package/dist/internals/index-DF2AfSGK.mjs.map +0 -1
- package/dist/internals/index-DfnPpl1I.js.map +0 -1
- package/dist/internals/index-HdMgLYtD.d.ts.map +0 -1
- package/dist/internals/validator-BBjOdLiT.js.map +0 -1
- package/dist/internals/validator-LNgZGT_l.mjs.map +0 -1
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
5
|
var _ = require('lodash');
|
|
6
|
-
var index = require('../../internals/index-
|
|
6
|
+
var index = require('../../internals/index-CLKTEIj0.js');
|
|
7
7
|
var pg = require('pg');
|
|
8
8
|
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-
|
|
12
|
+
var validator = require('../../internals/validator-B5yHpyvb.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');
|
|
@@ -189,12 +189,12 @@ const _encodeSorting = (includes, populates, sort) => {
|
|
|
189
189
|
return sorting;
|
|
190
190
|
};
|
|
191
191
|
const _defaultInsertOpts = (options) => {
|
|
192
|
-
const
|
|
192
|
+
const id = random$1.generateId(options.objectIdSize);
|
|
193
193
|
return {
|
|
194
|
-
_id: sql `${{ value:
|
|
194
|
+
_id: sql `${{ value: id }}`,
|
|
195
195
|
...options.className === 'User' ? {
|
|
196
|
-
_rperm: sql `${{ value: [
|
|
197
|
-
_wperm: sql `${{ value: [
|
|
196
|
+
_rperm: sql `${{ value: [id] }}`,
|
|
197
|
+
_wperm: sql `${{ value: [id] }}`,
|
|
198
198
|
} : {},
|
|
199
199
|
};
|
|
200
200
|
};
|
|
@@ -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.
|
|
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.
|
|
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' }}`;
|
|
@@ -632,12 +632,12 @@ const encodeType = (colname, dataType, value) => {
|
|
|
632
632
|
break;
|
|
633
633
|
return sql `ARRAY[${_.map(value, x => _encodeJsonValue(index._encodeValue(x)))}]::JSONB[]`;
|
|
634
634
|
case 'pointer':
|
|
635
|
-
if (value instanceof index.TObject && value.
|
|
636
|
-
return sql `${{ value: `${value.className}$${value.
|
|
635
|
+
if (value instanceof index.TObject && value.id)
|
|
636
|
+
return sql `${{ value: `${value.className}$${value.id}` }}`;
|
|
637
637
|
break;
|
|
638
638
|
case 'relation':
|
|
639
|
-
if (_.isArray(value) && _.every(value, x => x instanceof index.TObject && x.
|
|
640
|
-
return sql `${{ value: _.uniq(_.map(value, (x) => `${x.className}$${x.
|
|
639
|
+
if (_.isArray(value) && _.every(value, x => x instanceof index.TObject && x.id)) {
|
|
640
|
+
return sql `${{ value: _.uniq(_.map(value, (x) => `${x.className}$${x.id}`)) }}`;
|
|
641
641
|
}
|
|
642
642
|
break;
|
|
643
643
|
}
|
|
@@ -708,7 +708,7 @@ const decodeType = (type, value) => {
|
|
|
708
708
|
};
|
|
709
709
|
|
|
710
710
|
//
|
|
711
|
-
//
|
|
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
|
|
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
|
|
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
|
|
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
|
|
761
|
-
return
|
|
762
|
-
|
|
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
|
|
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
|
|
891
|
+
return { type: 'string', sql: sql `${{ value: expr.value }}` };
|
|
791
892
|
if (_.isDate(expr.value))
|
|
792
|
-
return
|
|
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
|
|
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
|
|
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
|
|
830
|
-
if (!
|
|
1196
|
+
const typed = encodeTypedQueryExpression(compiler, parent, expr);
|
|
1197
|
+
if (!typed)
|
|
831
1198
|
throw Error('Invalid expression');
|
|
832
|
-
|
|
833
|
-
}
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
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 (
|
|
902
|
-
|
|
1230
|
+
if (isArrayExpr(expr.left) &&
|
|
1231
|
+
isArrayExpr(expr.right) &&
|
|
903
1232
|
arrayLength(expr.left) === arrayLength(expr.right)) {
|
|
904
|
-
const _left =
|
|
905
|
-
const _right =
|
|
906
|
-
const
|
|
907
|
-
if (
|
|
908
|
-
const [l, r] = _.unzip(
|
|
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
|
-
|
|
916
|
-
|
|
917
|
-
|
|
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
|
|
@@ -988,7 +1317,7 @@ class SqlStorage {
|
|
|
988
1317
|
const _value = _.get(value, path);
|
|
989
1318
|
if (_.isPlainObject(_value)) {
|
|
990
1319
|
const decoded = this._decodeObject(type.target, _value, matchType);
|
|
991
|
-
if (decoded.
|
|
1320
|
+
if (decoded.id)
|
|
992
1321
|
_.set(result, path, decoded);
|
|
993
1322
|
}
|
|
994
1323
|
}
|
|
@@ -1028,7 +1357,7 @@ class SqlStorage {
|
|
|
1028
1357
|
else if (index.isPointer(dataType)) {
|
|
1029
1358
|
if (_.isPlainObject(value)) {
|
|
1030
1359
|
const decoded = this._decodeObject(dataType.target, value, matchType);
|
|
1031
|
-
if (decoded.
|
|
1360
|
+
if (decoded.id)
|
|
1032
1361
|
obj[_private.PVK].attributes[key] = decoded;
|
|
1033
1362
|
}
|
|
1034
1363
|
}
|
|
@@ -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
|
-
|
|
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)
|
|
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) {
|
|
@@ -1116,7 +1450,7 @@ class SqlStorage {
|
|
|
1116
1450
|
const self = this;
|
|
1117
1451
|
const query = sql `
|
|
1118
1452
|
SELECT *
|
|
1119
|
-
FROM (${this._refs(_.pick(this.schema, classNames), object.className, index.TObject.defaultKeys, sql `${{ value: `${object.className}$${object.
|
|
1453
|
+
FROM (${this._refs(_.pick(this.schema, classNames), object.className, index.TObject.defaultKeys, sql `${{ value: `${object.className}$${object.id}` }}`)}) AS "$"
|
|
1120
1454
|
${_.isNil(roles) ? sql `` : sql `WHERE ${{ identifier: '$' }}.${{ identifier: '_rperm' }} && ${{ value: roles }}`}
|
|
1121
1455
|
`;
|
|
1122
1456
|
return (async function* () {
|
|
@@ -1707,25 +2041,25 @@ const updateOperation = (paths, dataType, operation) => {
|
|
|
1707
2041
|
case '$addToSet':
|
|
1708
2042
|
case '$push':
|
|
1709
2043
|
{
|
|
1710
|
-
if (!_.isArray(value) || !_.every(value, x => x instanceof index.TObject && x.
|
|
2044
|
+
if (!_.isArray(value) || !_.every(value, x => x instanceof index.TObject && x.id))
|
|
1711
2045
|
break;
|
|
1712
|
-
const
|
|
2046
|
+
const ids = _.uniq(_.map(value, (x) => `${x.className}$${x.id}`));
|
|
1713
2047
|
return sql `ARRAY(
|
|
1714
2048
|
SELECT DISTINCT "$"
|
|
1715
|
-
FROM UNNEST(${{ identifier: column }} || ARRAY[${_.map(
|
|
2049
|
+
FROM UNNEST(${{ identifier: column }} || ARRAY[${_.map(ids, (x) => sql `${{ value: x }}`)}]) "$"
|
|
1716
2050
|
RIGHT JOIN ${{ identifier: dataType.target }} ON "$" = (${{ quote: dataType.target + '$' }} || ${{ identifier: dataType.target }}._id)
|
|
1717
2051
|
)`;
|
|
1718
2052
|
}
|
|
1719
2053
|
case '$removeAll':
|
|
1720
2054
|
{
|
|
1721
|
-
if (!_.isArray(value) || !_.every(value, x => x instanceof index.TObject && x.
|
|
2055
|
+
if (!_.isArray(value) || !_.every(value, x => x instanceof index.TObject && x.id))
|
|
1722
2056
|
break;
|
|
1723
|
-
const
|
|
2057
|
+
const ids = _.uniq(_.map(value, (x) => `${x.className}$${x.id}`));
|
|
1724
2058
|
return sql `ARRAY(
|
|
1725
2059
|
SELECT "$"
|
|
1726
2060
|
FROM UNNEST(${{ identifier: column }}) "$"
|
|
1727
2061
|
RIGHT JOIN ${{ identifier: dataType.target }} ON "$" = (${{ quote: dataType.target + '$' }} || ${{ identifier: dataType.target }}._id)
|
|
1728
|
-
WHERE "$" NOT IN (${_.map(
|
|
2062
|
+
WHERE "$" NOT IN (${_.map(ids, (x) => sql `${{ value: x }}`)})
|
|
1729
2063
|
)`;
|
|
1730
2064
|
}
|
|
1731
2065
|
}
|
|
@@ -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.
|
|
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.
|
|
2333
|
+
else if (expr instanceof validator.QueryUnaryAccumulator) {
|
|
2000
2334
|
if (!expr.expr)
|
|
2001
2335
|
throw Error('Invalid expression');
|
|
2002
|
-
const
|
|
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
|
|
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 `
|
|
@@ -2227,9 +2559,9 @@ const encodeFieldExpression = (compiler, parent, field, expr) => {
|
|
|
2227
2559
|
if (_.isNil(expr.value))
|
|
2228
2560
|
return sql `${element} IS NULL`;
|
|
2229
2561
|
if (!_.isString(dataType) && dataType?.type === 'pointer') {
|
|
2230
|
-
if (!(expr.value instanceof index.TObject) || dataType.target !== expr.value.className || !expr.value.
|
|
2562
|
+
if (!(expr.value instanceof index.TObject) || dataType.target !== expr.value.className || !expr.value.id)
|
|
2231
2563
|
break;
|
|
2232
|
-
return sql `${element} ${nullSafeEqual()} ${{ value: expr.value.
|
|
2564
|
+
return sql `${element} ${nullSafeEqual()} ${{ value: expr.value.id }}`;
|
|
2233
2565
|
}
|
|
2234
2566
|
return sql `${element} ${nullSafeEqual()} ${encodeValue(expr.value)}`;
|
|
2235
2567
|
}
|
|
@@ -2240,9 +2572,9 @@ const encodeFieldExpression = (compiler, parent, field, expr) => {
|
|
|
2240
2572
|
if (_.isNil(expr.value))
|
|
2241
2573
|
return sql `${element} IS NOT NULL`;
|
|
2242
2574
|
if (!_.isString(dataType) && dataType?.type === 'pointer') {
|
|
2243
|
-
if (!(expr.value instanceof index.TObject) || dataType.target !== expr.value.className || !expr.value.
|
|
2575
|
+
if (!(expr.value instanceof index.TObject) || dataType.target !== expr.value.className || !expr.value.id)
|
|
2244
2576
|
break;
|
|
2245
|
-
return sql `${element} ${nullSafeNotEqual()} ${{ value: expr.value.
|
|
2577
|
+
return sql `${element} ${nullSafeNotEqual()} ${{ value: expr.value.id }}`;
|
|
2246
2578
|
}
|
|
2247
2579
|
return sql `${element} ${nullSafeNotEqual()} ${encodeValue(expr.value)}`;
|
|
2248
2580
|
}
|
|
@@ -2284,8 +2616,8 @@ const encodeFieldExpression = (compiler, parent, field, expr) => {
|
|
|
2284
2616
|
return sql `${element} ${{ literal: op }} ${encodeValue(expr.value)}`;
|
|
2285
2617
|
}
|
|
2286
2618
|
}
|
|
2287
|
-
else if (!_.isString(dataType) && dataType?.type === 'pointer' && expr.value instanceof index.TObject && expr.value.
|
|
2288
|
-
return sql `${element} ${{ literal: op }} ${{ value: expr.value.
|
|
2619
|
+
else if (!_.isString(dataType) && dataType?.type === 'pointer' && expr.value instanceof index.TObject && expr.value.id) {
|
|
2620
|
+
return sql `${element} ${{ literal: op }} ${{ value: expr.value.id }}`;
|
|
2289
2621
|
}
|
|
2290
2622
|
else if (!dataType) {
|
|
2291
2623
|
if (expr.value instanceof Decimal || _.isNumber(expr.value)) {
|
|
@@ -2321,9 +2653,9 @@ const encodeFieldExpression = (compiler, parent, field, expr) => {
|
|
|
2321
2653
|
if (!_.isString(dataType) && dataType?.type === 'pointer') {
|
|
2322
2654
|
if (_.isNil(value))
|
|
2323
2655
|
return sql `${element} IS NULL`;
|
|
2324
|
-
if (!(value instanceof index.TObject) || dataType.target !== value.className || !value.
|
|
2656
|
+
if (!(value instanceof index.TObject) || dataType.target !== value.className || !value.id)
|
|
2325
2657
|
break;
|
|
2326
|
-
return sql `${element} ${nullSafeEqual()} ${{ value: value.
|
|
2658
|
+
return sql `${element} ${nullSafeEqual()} ${{ value: value.id }}`;
|
|
2327
2659
|
}
|
|
2328
2660
|
return sql `${element} ${nullSafeEqual()} ${encodeValue(value)}`;
|
|
2329
2661
|
}
|
|
@@ -2331,12 +2663,12 @@ const encodeFieldExpression = (compiler, parent, field, expr) => {
|
|
|
2331
2663
|
const containsNil = _.some(expr.value, x => _.isNil(x));
|
|
2332
2664
|
const values = _.filter(expr.value, x => !_.isNil(x));
|
|
2333
2665
|
if (!_.isString(dataType) && dataType?.type === 'pointer') {
|
|
2334
|
-
if (!_.every(values, x => x instanceof index.TObject && dataType.target === x.className && x.
|
|
2666
|
+
if (!_.every(values, x => x instanceof index.TObject && dataType.target === x.className && x.id))
|
|
2335
2667
|
break;
|
|
2336
2668
|
if (containsNil) {
|
|
2337
|
-
return sql `${element} IS NULL OR ${element} IN (${_.map(values, (x) => sql `${{ value: x.
|
|
2669
|
+
return sql `${element} IS NULL OR ${element} IN (${_.map(values, (x) => sql `${{ value: x.id }}`)})`;
|
|
2338
2670
|
}
|
|
2339
|
-
return sql `${element} IN (${_.map(values, (x) => sql `${{ value: x.
|
|
2671
|
+
return sql `${element} IN (${_.map(values, (x) => sql `${{ value: x.id }}`)})`;
|
|
2340
2672
|
}
|
|
2341
2673
|
if (containsNil) {
|
|
2342
2674
|
return sql `${element} IS NULL OR ${element} IN (${_.map(values, x => encodeValue(x))})`;
|
|
@@ -2357,9 +2689,9 @@ const encodeFieldExpression = (compiler, parent, field, expr) => {
|
|
|
2357
2689
|
if (!_.isString(dataType) && dataType?.type === 'pointer') {
|
|
2358
2690
|
if (_.isNil(value))
|
|
2359
2691
|
return sql `${element} IS NOT NULL`;
|
|
2360
|
-
if (!(value instanceof index.TObject) || dataType.target !== value.className || !value.
|
|
2692
|
+
if (!(value instanceof index.TObject) || dataType.target !== value.className || !value.id)
|
|
2361
2693
|
break;
|
|
2362
|
-
return sql `${element} ${nullSafeNotEqual()} ${{ value: value.
|
|
2694
|
+
return sql `${element} ${nullSafeNotEqual()} ${{ value: value.id }}`;
|
|
2363
2695
|
}
|
|
2364
2696
|
return sql `${element} ${nullSafeNotEqual()} ${encodeValue(value)}`;
|
|
2365
2697
|
}
|
|
@@ -2367,12 +2699,12 @@ const encodeFieldExpression = (compiler, parent, field, expr) => {
|
|
|
2367
2699
|
const containsNil = _.some(expr.value, x => _.isNil(x));
|
|
2368
2700
|
const values = _.filter(expr.value, x => !_.isNil(x));
|
|
2369
2701
|
if (!_.isString(dataType) && dataType?.type === 'pointer') {
|
|
2370
|
-
if (!_.every(values, x => x instanceof index.TObject && dataType.target === x.className && x.
|
|
2702
|
+
if (!_.every(values, x => x instanceof index.TObject && dataType.target === x.className && x.id))
|
|
2371
2703
|
break;
|
|
2372
2704
|
if (containsNil) {
|
|
2373
|
-
return sql `${element} IS NOT NULL AND ${element} NOT IN (${_.map(values, (x) => sql `${{ value: x.
|
|
2705
|
+
return sql `${element} IS NOT NULL AND ${element} NOT IN (${_.map(values, (x) => sql `${{ value: x.id }}`)})`;
|
|
2374
2706
|
}
|
|
2375
|
-
return sql `${element} NOT IN (${_.map(values, (x) => sql `${{ value: x.
|
|
2707
|
+
return sql `${element} NOT IN (${_.map(values, (x) => sql `${{ value: x.id }}`)})`;
|
|
2376
2708
|
}
|
|
2377
2709
|
if (containsNil) {
|
|
2378
2710
|
return sql `${element} IS NOT NULL AND ${element} NOT IN (${_.map(values, x => encodeValue(x))})`;
|
|
@@ -2402,14 +2734,14 @@ const encodeFieldExpression = (compiler, parent, field, expr) => {
|
|
|
2402
2734
|
return sql `${element} ${{ literal: op }} ${{ value: index._encodeValue(expr.value) }}`;
|
|
2403
2735
|
}
|
|
2404
2736
|
if (relation && parent.className) {
|
|
2405
|
-
if (!_.every(expr.value, x => x instanceof index.TObject && relation.target === x.className && x.
|
|
2737
|
+
if (!_.every(expr.value, x => x instanceof index.TObject && relation.target === x.className && x.id))
|
|
2406
2738
|
break;
|
|
2407
2739
|
const tempName = `_populate_expr_$${compiler.nextIdx()}`;
|
|
2408
2740
|
const populate = _selectRelationPopulate(compiler, { className: parent.className, name: parent.name }, relation.populate, `$${field}`, false);
|
|
2409
2741
|
return sql `ARRAY(
|
|
2410
2742
|
SELECT ${{ identifier: '_id' }}
|
|
2411
2743
|
FROM (${populate}) AS ${{ identifier: tempName }}
|
|
2412
|
-
) ${{ literal: op }} ARRAY[${_.map(expr.value, (x) => sql `${{ value: x.
|
|
2744
|
+
) ${{ literal: op }} ARRAY[${_.map(expr.value, (x) => sql `${{ value: x.id }}`)}]::TEXT[]`;
|
|
2413
2745
|
}
|
|
2414
2746
|
if (!dataType) {
|
|
2415
2747
|
return sql `jsonb_typeof(${element}) ${nullSafeEqual()} 'array' AND ${element} ${{ literal: op }} ${_encodeJsonValue(index._encodeValue(expr.value))}`;
|
|
@@ -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
|
//
|
|
@@ -2665,7 +3027,7 @@ const encodeRelation = (compiler, parent, relatedBy) => {
|
|
|
2665
3027
|
SELECT 1
|
|
2666
3028
|
FROM ${{ identifier: relatedBy.className }} AS ${{ identifier: name }}
|
|
2667
3029
|
${!_.isEmpty(joins) ? { literal: joins, separator: '\n' } : sql ``}
|
|
2668
|
-
WHERE ${_foreign('_id')} = ${{ value: relatedBy.
|
|
3030
|
+
WHERE ${_foreign('_id')} = ${{ value: relatedBy.id }} AND ${sql `(${{ quote: parent.className + '$' }} || ${_local('_id')})`} = ANY(${field})
|
|
2669
3031
|
)`;
|
|
2670
3032
|
};
|
|
2671
3033
|
|
|
@@ -2703,7 +3065,8 @@ const PostgresDialect = {
|
|
|
2703
3065
|
updateOperation,
|
|
2704
3066
|
selectPopulate,
|
|
2705
3067
|
encodeFieldExpression,
|
|
2706
|
-
|
|
3068
|
+
encodeBooleanExpression,
|
|
3069
|
+
encodeSortExpression,
|
|
2707
3070
|
encodePopulate,
|
|
2708
3071
|
encodeRelation,
|
|
2709
3072
|
encodeSortKey,
|