proto.io 0.0.213 → 0.0.214
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.js.map +1 -1
- package/dist/adapters/file/database.mjs +1 -1
- 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 +1 -1
- package/dist/adapters/storage/progres.js +111 -82
- package/dist/adapters/storage/progres.js.map +1 -1
- package/dist/adapters/storage/progres.mjs +73 -44
- package/dist/adapters/storage/progres.mjs.map +1 -1
- package/dist/client.d.ts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +42 -42
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/internals/{base-CZGalGrd.d.ts → base-E1b8J-Fs.d.ts} +2 -2
- package/dist/internals/base-E1b8J-Fs.d.ts.map +1 -0
- package/dist/internals/{chunk-BsT9SYny.d.ts → chunk-D1bD7otk.d.ts} +3 -3
- package/dist/internals/chunk-D1bD7otk.d.ts.map +1 -0
- package/dist/internals/{index-Boxwkqe0.d.ts → index-CbjY-gJ7.d.ts} +6 -8
- package/dist/internals/index-CbjY-gJ7.d.ts.map +1 -0
- package/dist/internals/{index-NF-U_3zG.d.ts → index-SSEdPyhp.d.ts} +2 -2
- package/dist/internals/index-SSEdPyhp.d.ts.map +1 -0
- package/dist/internals/random-CYjWDvex.mjs +37 -0
- package/dist/internals/random-CYjWDvex.mjs.map +1 -0
- package/dist/internals/random-nkOQ9U6S.js +39 -0
- package/dist/internals/random-nkOQ9U6S.js.map +1 -0
- package/dist/internals/{index-D8O7SinR.js → validator-DoRPoIs2.js} +586 -2
- package/dist/internals/validator-DoRPoIs2.js.map +1 -0
- package/dist/internals/{index-DG9HHO_U.mjs → validator-Dxmbwa3P.mjs} +583 -3
- package/dist/internals/validator-Dxmbwa3P.mjs.map +1 -0
- package/package.json +1 -1
- package/dist/internals/base-CZGalGrd.d.ts.map +0 -1
- package/dist/internals/chunk-BsT9SYny.d.ts.map +0 -1
- package/dist/internals/index-Boxwkqe0.d.ts.map +0 -1
- package/dist/internals/index-D8O7SinR.js.map +0 -1
- package/dist/internals/index-DG9HHO_U.mjs.map +0 -1
- package/dist/internals/index-NF-U_3zG.d.ts.map +0 -1
- package/dist/internals/random-CufRbivU.mjs +0 -526
- package/dist/internals/random-CufRbivU.mjs.map +0 -1
- package/dist/internals/random-DzvxbWAc.js +0 -532
- package/dist/internals/random-DzvxbWAc.js.map +0 -1
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
var _ = require('lodash');
|
|
4
4
|
var index = require('./index-B8TESzd9.js');
|
|
5
5
|
var Decimal = require('decimal.js');
|
|
6
|
+
var _private = require('./private-Ciddhure.js');
|
|
6
7
|
|
|
7
8
|
//
|
|
8
9
|
// keys.ts
|
|
@@ -309,6 +310,9 @@ class QueryExpression {
|
|
|
309
310
|
eval(value) {
|
|
310
311
|
return true;
|
|
311
312
|
}
|
|
313
|
+
evalType(schema, className) {
|
|
314
|
+
return [];
|
|
315
|
+
}
|
|
312
316
|
}
|
|
313
317
|
class QueryCoditionalExpression extends QueryExpression {
|
|
314
318
|
type;
|
|
@@ -344,6 +348,9 @@ class QueryCoditionalExpression extends QueryExpression {
|
|
|
344
348
|
case '$or': return _.some(this.exprs, expr => expr.eval(value));
|
|
345
349
|
}
|
|
346
350
|
}
|
|
351
|
+
evalType(schema, className) {
|
|
352
|
+
return ['boolean'];
|
|
353
|
+
}
|
|
347
354
|
}
|
|
348
355
|
class QueryComparisonExpression extends QueryExpression {
|
|
349
356
|
type;
|
|
@@ -377,6 +384,9 @@ class QueryComparisonExpression extends QueryExpression {
|
|
|
377
384
|
case '$ne': return !equal(this.left.eval(value), this.right.eval(value));
|
|
378
385
|
}
|
|
379
386
|
}
|
|
387
|
+
evalType(schema, className) {
|
|
388
|
+
return ['boolean'];
|
|
389
|
+
}
|
|
380
390
|
}
|
|
381
391
|
class QueryNotExpression extends QueryExpression {
|
|
382
392
|
expr;
|
|
@@ -396,6 +406,9 @@ class QueryNotExpression extends QueryExpression {
|
|
|
396
406
|
eval(value) {
|
|
397
407
|
return !this.expr.eval(value);
|
|
398
408
|
}
|
|
409
|
+
evalType(schema, className) {
|
|
410
|
+
return ['boolean'];
|
|
411
|
+
}
|
|
399
412
|
}
|
|
400
413
|
class QueryArrayExpression extends QueryExpression {
|
|
401
414
|
exprs;
|
|
@@ -415,6 +428,9 @@ class QueryArrayExpression extends QueryExpression {
|
|
|
415
428
|
eval(value) {
|
|
416
429
|
return _.map(this.exprs, x => x.eval(value));
|
|
417
430
|
}
|
|
431
|
+
evalType(schema, className) {
|
|
432
|
+
return ['array'];
|
|
433
|
+
}
|
|
418
434
|
}
|
|
419
435
|
class QueryDistanceExpression extends QueryExpression {
|
|
420
436
|
type;
|
|
@@ -453,6 +469,9 @@ class QueryDistanceExpression extends QueryExpression {
|
|
|
453
469
|
case '$rectilinearDistance': return rectilinearDistance(left, right);
|
|
454
470
|
}
|
|
455
471
|
}
|
|
472
|
+
evalType(schema, className) {
|
|
473
|
+
return ['number'];
|
|
474
|
+
}
|
|
456
475
|
}
|
|
457
476
|
class QueryKeyExpression extends QueryExpression {
|
|
458
477
|
key;
|
|
@@ -469,6 +488,10 @@ class QueryKeyExpression extends QueryExpression {
|
|
|
469
488
|
eval(value) {
|
|
470
489
|
return getValue(value, this.key);
|
|
471
490
|
}
|
|
491
|
+
evalType(schema, className) {
|
|
492
|
+
const { paths: [, ...subpath], dataType } = resolveColumn(schema, className, this.key);
|
|
493
|
+
return _.isEmpty(subpath) ? [dataType] : [];
|
|
494
|
+
}
|
|
472
495
|
}
|
|
473
496
|
class QueryValueExpression extends QueryExpression {
|
|
474
497
|
value;
|
|
@@ -479,6 +502,21 @@ class QueryValueExpression extends QueryExpression {
|
|
|
479
502
|
eval(value) {
|
|
480
503
|
return value;
|
|
481
504
|
}
|
|
505
|
+
evalType(schema, className) {
|
|
506
|
+
if (_.isDate(this.value))
|
|
507
|
+
return ['date'];
|
|
508
|
+
if (_.isBoolean(this.value))
|
|
509
|
+
return ['boolean'];
|
|
510
|
+
if (_.isArray(this.value))
|
|
511
|
+
return ['array'];
|
|
512
|
+
if (_.isString(this.value))
|
|
513
|
+
return ['string'];
|
|
514
|
+
if (_.isNumber(this.value))
|
|
515
|
+
return ['number', 'decimal'];
|
|
516
|
+
if (this.value instanceof Decimal)
|
|
517
|
+
return ['decimal', 'number'];
|
|
518
|
+
return [];
|
|
519
|
+
}
|
|
482
520
|
}
|
|
483
521
|
|
|
484
522
|
//
|
|
@@ -774,17 +812,563 @@ class QueryExpressionSelector extends QuerySelector {
|
|
|
774
812
|
}
|
|
775
813
|
}
|
|
776
814
|
|
|
815
|
+
//
|
|
816
|
+
// accumulators.ts
|
|
817
|
+
//
|
|
818
|
+
// The MIT License
|
|
819
|
+
// Copyright (c) 2021 - 2025 O2ter Limited. All rights reserved.
|
|
820
|
+
//
|
|
821
|
+
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
822
|
+
// of this software and associated documentation files (the "Software"), to deal
|
|
823
|
+
// in the Software without restriction, including without limitation the rights
|
|
824
|
+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
825
|
+
// copies of the Software, and to permit persons to whom the Software is
|
|
826
|
+
// furnished to do so, subject to the following conditions:
|
|
827
|
+
//
|
|
828
|
+
// The above copyright notice and this permission notice shall be included in
|
|
829
|
+
// all copies or substantial portions of the Software.
|
|
830
|
+
//
|
|
831
|
+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
832
|
+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
833
|
+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
834
|
+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
835
|
+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
836
|
+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
837
|
+
// THE SOFTWARE.
|
|
838
|
+
//
|
|
839
|
+
const accumulatorExprKeys = [
|
|
840
|
+
'$max',
|
|
841
|
+
'$min',
|
|
842
|
+
'$sum',
|
|
843
|
+
'$avg',
|
|
844
|
+
'$stdDevPop',
|
|
845
|
+
'$stdDevSamp',
|
|
846
|
+
'$varPop',
|
|
847
|
+
'$varSamp'
|
|
848
|
+
];
|
|
849
|
+
const accumulatorNoParamKeys = [
|
|
850
|
+
'$count'
|
|
851
|
+
];
|
|
852
|
+
|
|
853
|
+
//
|
|
854
|
+
// accumulators.ts
|
|
855
|
+
//
|
|
856
|
+
// The MIT License
|
|
857
|
+
// Copyright (c) 2021 - 2025 O2ter Limited. All rights reserved.
|
|
858
|
+
//
|
|
859
|
+
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
860
|
+
// of this software and associated documentation files (the "Software"), to deal
|
|
861
|
+
// in the Software without restriction, including without limitation the rights
|
|
862
|
+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
863
|
+
// copies of the Software, and to permit persons to whom the Software is
|
|
864
|
+
// furnished to do so, subject to the following conditions:
|
|
865
|
+
//
|
|
866
|
+
// The above copyright notice and this permission notice shall be included in
|
|
867
|
+
// all copies or substantial portions of the Software.
|
|
868
|
+
//
|
|
869
|
+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
870
|
+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
871
|
+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
872
|
+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
873
|
+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
874
|
+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
875
|
+
// THE SOFTWARE.
|
|
876
|
+
//
|
|
877
|
+
class QueryAccumulator {
|
|
878
|
+
static decode(query) {
|
|
879
|
+
for (const [key, expr] of _.toPairs(query)) {
|
|
880
|
+
if (_.includes(accumulatorExprKeys, key)) {
|
|
881
|
+
return new QueryExprAccumulator(key, QueryExpression.decode(expr ?? [], false));
|
|
882
|
+
}
|
|
883
|
+
else if (_.includes(accumulatorNoParamKeys, key)) {
|
|
884
|
+
return new QueryNoParamAccumulator(key);
|
|
885
|
+
}
|
|
886
|
+
else {
|
|
887
|
+
throw Error('Invalid expression');
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
throw Error('Invalid expression');
|
|
891
|
+
}
|
|
892
|
+
simplify() {
|
|
893
|
+
return this;
|
|
894
|
+
}
|
|
895
|
+
keyPaths() {
|
|
896
|
+
return [];
|
|
897
|
+
}
|
|
898
|
+
mapKey(callback) {
|
|
899
|
+
return this;
|
|
900
|
+
}
|
|
901
|
+
evalType(schema, className) {
|
|
902
|
+
return;
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
class QueryNoParamAccumulator extends QueryAccumulator {
|
|
906
|
+
type;
|
|
907
|
+
constructor(type) {
|
|
908
|
+
super();
|
|
909
|
+
this.type = type;
|
|
910
|
+
}
|
|
911
|
+
simplify() {
|
|
912
|
+
return this;
|
|
913
|
+
}
|
|
914
|
+
keyPaths() {
|
|
915
|
+
return [];
|
|
916
|
+
}
|
|
917
|
+
mapKey(callback) {
|
|
918
|
+
return this;
|
|
919
|
+
}
|
|
920
|
+
evalType(schema, className) {
|
|
921
|
+
switch (this.type) {
|
|
922
|
+
case '$count': return 'number';
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
class QueryExprAccumulator extends QueryAccumulator {
|
|
927
|
+
type;
|
|
928
|
+
expr;
|
|
929
|
+
constructor(type, expr) {
|
|
930
|
+
super();
|
|
931
|
+
this.type = type;
|
|
932
|
+
this.expr = expr;
|
|
933
|
+
}
|
|
934
|
+
simplify() {
|
|
935
|
+
return new QueryExprAccumulator(this.type, this.expr.simplify());
|
|
936
|
+
}
|
|
937
|
+
keyPaths() {
|
|
938
|
+
return this.expr?.keyPaths() ?? [];
|
|
939
|
+
}
|
|
940
|
+
mapKey(callback) {
|
|
941
|
+
return new QueryExprAccumulator(this.type, this.expr.mapKey(callback));
|
|
942
|
+
}
|
|
943
|
+
evalType(schema, className) {
|
|
944
|
+
const [dataType] = this.expr?.evalType(schema, className) ?? [];
|
|
945
|
+
if (_.isNil(dataType))
|
|
946
|
+
return;
|
|
947
|
+
switch (this.type) {
|
|
948
|
+
case '$max': return index._isTypeof(dataType, ['number', 'decimal', 'string', 'date']) ? dataType : undefined;
|
|
949
|
+
case '$min': return index._isTypeof(dataType, ['number', 'decimal', 'string', 'date']) ? dataType : undefined;
|
|
950
|
+
case '$avg': return index._isTypeof(dataType, ['number', 'decimal']) ? dataType : undefined;
|
|
951
|
+
case '$sum': return index._isTypeof(dataType, ['number', 'decimal']) ? dataType : undefined;
|
|
952
|
+
case '$stdDevPop': return index._isTypeof(dataType, ['number', 'decimal']) ? dataType : undefined;
|
|
953
|
+
case '$stdDevSamp': return index._isTypeof(dataType, ['number', 'decimal']) ? dataType : undefined;
|
|
954
|
+
case '$varPop': return index._isTypeof(dataType, ['number', 'decimal']) ? dataType : undefined;
|
|
955
|
+
case '$varSamp': return index._isTypeof(dataType, ['number', 'decimal']) ? dataType : undefined;
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
//
|
|
961
|
+
// validator.ts
|
|
962
|
+
//
|
|
963
|
+
// The MIT License
|
|
964
|
+
// Copyright (c) 2021 - 2025 O2ter Limited. All rights reserved.
|
|
965
|
+
//
|
|
966
|
+
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
967
|
+
// of this software and associated documentation files (the "Software"), to deal
|
|
968
|
+
// in the Software without restriction, including without limitation the rights
|
|
969
|
+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
970
|
+
// copies of the Software, and to permit persons to whom the Software is
|
|
971
|
+
// furnished to do so, subject to the following conditions:
|
|
972
|
+
//
|
|
973
|
+
// The above copyright notice and this permission notice shall be included in
|
|
974
|
+
// all copies or substantial portions of the Software.
|
|
975
|
+
//
|
|
976
|
+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
977
|
+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
978
|
+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
979
|
+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
980
|
+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
981
|
+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
982
|
+
// THE SOFTWARE.
|
|
983
|
+
//
|
|
984
|
+
const recursiveCheck = (x, stack) => {
|
|
985
|
+
if (_.indexOf(stack, x) !== -1)
|
|
986
|
+
throw Error('Recursive data detected');
|
|
987
|
+
if (_.isRegExp(x) || index.isPrimitiveValue(x) || x instanceof index.TObject)
|
|
988
|
+
return;
|
|
989
|
+
const children = _.isArray(x) ? x : _.values(x);
|
|
990
|
+
children.forEach(v => recursiveCheck(v, [...stack, x]));
|
|
991
|
+
};
|
|
992
|
+
const resolveDataType = (schema, classname, path) => {
|
|
993
|
+
let fields = schema[classname].fields;
|
|
994
|
+
let last;
|
|
995
|
+
for (const key of _.toPath(path)) {
|
|
996
|
+
const dataType = fields[key];
|
|
997
|
+
if (_.isNil(dataType))
|
|
998
|
+
throw Error(`Invalid path: ${path}`);
|
|
999
|
+
if (index.isPrimitive(dataType) || index.isVector(dataType))
|
|
1000
|
+
return dataType;
|
|
1001
|
+
if (index.isShape(dataType)) {
|
|
1002
|
+
fields = dataType.shape;
|
|
1003
|
+
continue;
|
|
1004
|
+
}
|
|
1005
|
+
if (_.isNil(schema[dataType.target]))
|
|
1006
|
+
throw Error(`Invalid path: ${path}`);
|
|
1007
|
+
fields = schema[dataType.target].fields;
|
|
1008
|
+
last = dataType;
|
|
1009
|
+
}
|
|
1010
|
+
return last;
|
|
1011
|
+
};
|
|
1012
|
+
const resolveColumn = (schema, className, path) => {
|
|
1013
|
+
const _schema = schema[className] ?? {};
|
|
1014
|
+
let [colname, ...subpath] = path.split('.');
|
|
1015
|
+
let dataType = _schema.fields[colname];
|
|
1016
|
+
while (dataType && !_.isEmpty(subpath) && index.isShape(dataType)) {
|
|
1017
|
+
const [key, ...remain] = subpath;
|
|
1018
|
+
if (!dataType.shape[key])
|
|
1019
|
+
break;
|
|
1020
|
+
dataType = dataType.shape[key];
|
|
1021
|
+
colname = `${colname}.${key}`;
|
|
1022
|
+
subpath = remain;
|
|
1023
|
+
}
|
|
1024
|
+
return {
|
|
1025
|
+
paths: [colname, ...subpath],
|
|
1026
|
+
dataType,
|
|
1027
|
+
};
|
|
1028
|
+
};
|
|
1029
|
+
class QueryValidator {
|
|
1030
|
+
proto;
|
|
1031
|
+
acls;
|
|
1032
|
+
options;
|
|
1033
|
+
static patterns = {
|
|
1034
|
+
path: /^[a-z_][\w-]*(\[\d+\]|\.\d*|\.[a-z_][\w-]*)*$/gi,
|
|
1035
|
+
className: /^[a-z_][\w]*$/gi,
|
|
1036
|
+
fieldName: /^[a-z_][\w-]*$/gi,
|
|
1037
|
+
digits: /^\d+$/g,
|
|
1038
|
+
};
|
|
1039
|
+
_rperm(className) {
|
|
1040
|
+
if (this.options.master)
|
|
1041
|
+
return [];
|
|
1042
|
+
const check = _.intersection(this.schema[className]?.additionalObjectPermissions?.read, this.acls);
|
|
1043
|
+
if (!_.isEmpty(check))
|
|
1044
|
+
return [];
|
|
1045
|
+
return [{ _rperm: { $intersect: this.acls } }];
|
|
1046
|
+
}
|
|
1047
|
+
_wperm(className) {
|
|
1048
|
+
if (this.options.master)
|
|
1049
|
+
return [];
|
|
1050
|
+
const check = _.intersection(this.schema[className]?.additionalObjectPermissions?.update, this.acls);
|
|
1051
|
+
if (!_.isEmpty(check))
|
|
1052
|
+
return [];
|
|
1053
|
+
return [{ _wperm: { $intersect: this.acls } }];
|
|
1054
|
+
}
|
|
1055
|
+
_expiredAt = { $or: [{ _expired_at: { $eq: null } }, { _expired_at: { $gt: new Date() } }] };
|
|
1056
|
+
constructor(proto, acls, options) {
|
|
1057
|
+
this.proto = proto;
|
|
1058
|
+
this.acls = _.uniq(['*', ...acls]);
|
|
1059
|
+
this.options = options;
|
|
1060
|
+
}
|
|
1061
|
+
get schema() {
|
|
1062
|
+
return this.proto.schema;
|
|
1063
|
+
}
|
|
1064
|
+
get objectIdSize() {
|
|
1065
|
+
return this.proto[_private.PVK].options.objectIdSize;
|
|
1066
|
+
}
|
|
1067
|
+
static recursiveCheck(...x) {
|
|
1068
|
+
recursiveCheck(x, []);
|
|
1069
|
+
}
|
|
1070
|
+
validateKeyPerm(key, type, schema) {
|
|
1071
|
+
key = _.first(key?.split('.')) ?? key;
|
|
1072
|
+
if (_.isEmpty(key) || (!_.has(schema.fields, key) && !index.TObject.defaultKeys.includes(key)))
|
|
1073
|
+
throw Error(`Invalid key: ${key}`);
|
|
1074
|
+
if (type === 'read' && index.TObject.defaultKeys.includes(key))
|
|
1075
|
+
return true;
|
|
1076
|
+
if (type !== 'read' && index.TObject.defaultReadonlyKeys.includes(key))
|
|
1077
|
+
return false;
|
|
1078
|
+
if (!this.options.disableSecurity && _.includes(schema.secureFields, key))
|
|
1079
|
+
return false;
|
|
1080
|
+
return this.options.master || !_.every(schema.fieldLevelPermissions?.[key]?.[type] ?? ['*'], x => !_.includes(this.acls, x));
|
|
1081
|
+
}
|
|
1082
|
+
validateCLPs(className, ...keys) {
|
|
1083
|
+
if (!_.has(this.schema, className))
|
|
1084
|
+
throw Error('No permission');
|
|
1085
|
+
return this.options.master || this.proto[_private.PVK].validateCLPs(className, this.acls, keys);
|
|
1086
|
+
}
|
|
1087
|
+
validateForeignField(dataType, type, errorMeg) {
|
|
1088
|
+
if (_.isNil(dataType.foreignField))
|
|
1089
|
+
return;
|
|
1090
|
+
const foreignField = resolveDataType(this.schema, dataType.target, dataType.foreignField);
|
|
1091
|
+
if (_.isNil(foreignField) || _.isString(foreignField))
|
|
1092
|
+
throw Error(errorMeg);
|
|
1093
|
+
if (index.isPrimitive(foreignField))
|
|
1094
|
+
throw Error(errorMeg);
|
|
1095
|
+
if (foreignField.type === 'relation' && !_.isNil(foreignField.foreignField))
|
|
1096
|
+
throw Error(errorMeg);
|
|
1097
|
+
if (!this.validateKeyPerm(dataType.foreignField, type, this.schema[dataType.target]))
|
|
1098
|
+
throw Error('No permission');
|
|
1099
|
+
}
|
|
1100
|
+
validateKey(className, key, type, validator) {
|
|
1101
|
+
const schema = this.schema[className] ?? {};
|
|
1102
|
+
const _key = _.isArray(key) ? key.join('.') : key;
|
|
1103
|
+
if (!_key.match(validator))
|
|
1104
|
+
throw Error(`Invalid key: ${_key}`);
|
|
1105
|
+
const [colname, ..._subpath] = _.toPath(_key);
|
|
1106
|
+
if (!this.validateKeyPerm(colname, type, schema))
|
|
1107
|
+
return false;
|
|
1108
|
+
if (_.isEmpty(_subpath) && index.TObject.defaultKeys.includes(colname))
|
|
1109
|
+
return true;
|
|
1110
|
+
if (_.isEmpty(_subpath))
|
|
1111
|
+
return true;
|
|
1112
|
+
const { paths: [_colname, ...subpath], dataType } = resolveColumn(this.schema, className, _key);
|
|
1113
|
+
const isElem = _.first(subpath)?.match(QueryValidator.patterns.digits);
|
|
1114
|
+
if (isElem) {
|
|
1115
|
+
if (dataType === 'array' || dataType === 'string[]')
|
|
1116
|
+
return true;
|
|
1117
|
+
if (!_.isString(dataType) && dataType.type !== 'relation')
|
|
1118
|
+
return false;
|
|
1119
|
+
}
|
|
1120
|
+
if (index.isPrimitive(dataType))
|
|
1121
|
+
return true;
|
|
1122
|
+
if (index.isVector(dataType))
|
|
1123
|
+
return true;
|
|
1124
|
+
const relations = [];
|
|
1125
|
+
if (index.isShape(dataType)) {
|
|
1126
|
+
for (const { type } of index.shapePaths(dataType)) {
|
|
1127
|
+
if (!index.isPrimitive(type) && !index.isVector(type))
|
|
1128
|
+
relations.push(type);
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
else {
|
|
1132
|
+
relations.push(dataType);
|
|
1133
|
+
}
|
|
1134
|
+
for (const relation of relations) {
|
|
1135
|
+
if (_.isNil(this.schema[relation.target]))
|
|
1136
|
+
return false;
|
|
1137
|
+
if (type === 'read' && !this.validateCLPs(relation.target, 'get'))
|
|
1138
|
+
return false;
|
|
1139
|
+
if (relation.type === 'relation')
|
|
1140
|
+
this.validateForeignField(relation, type, `Invalid key: ${_key}`);
|
|
1141
|
+
}
|
|
1142
|
+
if (index.isShape(dataType)) {
|
|
1143
|
+
if (!_.isEmpty(subpath))
|
|
1144
|
+
throw Error(`Invalid key: ${_key}`);
|
|
1145
|
+
return true;
|
|
1146
|
+
}
|
|
1147
|
+
const _sub = isElem ? subpath.slice(1) : subpath;
|
|
1148
|
+
return _.isEmpty(_sub) || this.validateKey(dataType.target, _sub, type, validator);
|
|
1149
|
+
}
|
|
1150
|
+
validateFields(className, values, type, validator) {
|
|
1151
|
+
const _values = { ...values };
|
|
1152
|
+
for (const key of _.keys(_values)) {
|
|
1153
|
+
if (!this.validateKey(className, key, type, validator))
|
|
1154
|
+
throw Error('No permission');
|
|
1155
|
+
}
|
|
1156
|
+
return _values;
|
|
1157
|
+
}
|
|
1158
|
+
decodeGroupMatches(className, groupMatches) {
|
|
1159
|
+
const result = _.mapValues(groupMatches, m => _.mapValues(m, x => QueryAccumulator.decode(x).simplify()));
|
|
1160
|
+
for (const [colname, group] of _.entries(result)) {
|
|
1161
|
+
const dataType = resolveDataType(this.schema, className, colname);
|
|
1162
|
+
if (!dataType || !index.isRelation(dataType))
|
|
1163
|
+
throw Error(`Invalid relation key: ${colname}`);
|
|
1164
|
+
for (const key of _.keys(group)) {
|
|
1165
|
+
if (!key.match(QueryValidator.patterns.fieldName))
|
|
1166
|
+
throw Error(`Invalid field name: ${key}`);
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
return result;
|
|
1170
|
+
}
|
|
1171
|
+
decodeIncludes(className, includes, groupMatches) {
|
|
1172
|
+
const schema = this.schema[className] ?? {};
|
|
1173
|
+
const _includes = [];
|
|
1174
|
+
const populates = {};
|
|
1175
|
+
for (const include of includes) {
|
|
1176
|
+
if (include === '*') {
|
|
1177
|
+
const primitive = _.pickBy(schema.fields, (v, k) => index.isPrimitive(v) && this.validateKeyPerm(k, 'read', schema));
|
|
1178
|
+
const shapedObject = _.pickBy(schema.fields, (v, k) => index.isShape(v) && this.validateKeyPerm(k, 'read', schema));
|
|
1179
|
+
_includes.push(..._.keys(primitive), ..._.flatMap(shapedObject, (v, k) => _.flatMap(index.shapePaths(v), x => index.isPrimitive(x.type) ? [`${k}.${x.path}`] : [])));
|
|
1180
|
+
}
|
|
1181
|
+
else {
|
|
1182
|
+
const { paths: [colname, ...subpath], dataType } = resolveColumn(this.schema, className, include);
|
|
1183
|
+
if (!this.validateKeyPerm(colname, 'read', schema))
|
|
1184
|
+
throw Error('No permission');
|
|
1185
|
+
if (index.isPointer(dataType) || index.isRelation(dataType)) {
|
|
1186
|
+
if (!this.validateCLPs(dataType.target, 'get'))
|
|
1187
|
+
throw Error('No permission');
|
|
1188
|
+
if (dataType.type === 'relation')
|
|
1189
|
+
this.validateForeignField(dataType, 'read', `Invalid include: ${include}`);
|
|
1190
|
+
const isDigit = _.first(subpath)?.match(QueryValidator.patterns.digits);
|
|
1191
|
+
const _subpath = index.isRelation(dataType) && isDigit ? _.slice(subpath, 1) : subpath;
|
|
1192
|
+
populates[colname] = populates[colname] ?? { className: dataType.target, subpaths: [], groupMatches: {} };
|
|
1193
|
+
const s = _.first(_subpath);
|
|
1194
|
+
if (!s || !groupMatches[colname]?.[s]) {
|
|
1195
|
+
populates[colname].subpaths.push(_.isEmpty(_subpath) ? '*' : _subpath.join('.'));
|
|
1196
|
+
populates[colname].groupMatches = _.mapKeys(_.pickBy(groupMatches, (x, k) => _.startsWith(k, `${colname}.`)), (x, k) => k.slice(colname.length + 1));
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
else if (_.isEmpty(subpath) && index.isShape(dataType)) {
|
|
1200
|
+
for (const { path, type } of index.shapePaths(dataType)) {
|
|
1201
|
+
if (index.isPrimitive(type) || index.isVector(type)) {
|
|
1202
|
+
_includes.push(`${colname}.${path}`);
|
|
1203
|
+
}
|
|
1204
|
+
else {
|
|
1205
|
+
if (!this.validateCLPs(type.target, 'get'))
|
|
1206
|
+
throw Error('No permission');
|
|
1207
|
+
if (type.type === 'relation')
|
|
1208
|
+
this.validateForeignField(type, 'read', `Invalid include: ${include}`);
|
|
1209
|
+
populates[`${colname}.${path}`] = populates[`${colname}.${path}`] ?? { className: type.target, subpaths: [], groupMatches: {} };
|
|
1210
|
+
populates[`${colname}.${path}`].subpaths.push('*');
|
|
1211
|
+
populates[`${colname}.${path}`].groupMatches = _.mapKeys(_.pickBy(groupMatches, (x, k) => _.startsWith(k, `${colname}.${path}.`)), (x, k) => k.slice(`${colname}.${path}`.length + 1));
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
else if (_.isEmpty(subpath) || _.includes(['object', 'array'], index._typeof(dataType))) {
|
|
1216
|
+
_includes.push(colname);
|
|
1217
|
+
}
|
|
1218
|
+
else {
|
|
1219
|
+
throw Error(`Invalid include: ${include}`);
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
for (const [key, populate] of _.toPairs(populates)) {
|
|
1224
|
+
const subpaths = this.decodeIncludes(populate.className, populate.subpaths, populate.groupMatches);
|
|
1225
|
+
_includes.push(..._.map(subpaths, x => `${key}.${x}`));
|
|
1226
|
+
}
|
|
1227
|
+
_includes.push(...index.TObject.defaultKeys);
|
|
1228
|
+
return _.uniq(_includes);
|
|
1229
|
+
}
|
|
1230
|
+
decodeSort(sort) {
|
|
1231
|
+
if (_.isArray(sort)) {
|
|
1232
|
+
return _.map(sort, s => ({
|
|
1233
|
+
order: s.order,
|
|
1234
|
+
expr: QueryExpression.decode(s.expr, false).simplify(),
|
|
1235
|
+
}));
|
|
1236
|
+
}
|
|
1237
|
+
return sort;
|
|
1238
|
+
}
|
|
1239
|
+
decodeMatches(className, matches, includes) {
|
|
1240
|
+
const schema = this.schema[className] ?? {};
|
|
1241
|
+
const _matches = {};
|
|
1242
|
+
const _includes = _.groupBy(_.map(includes, x => resolveColumn(this.schema, className, x)), ({ paths: [colname] }) => colname);
|
|
1243
|
+
for (const [colname, [{ dataType }]] of _.entries(_includes)) {
|
|
1244
|
+
if (!this.validateKeyPerm(colname, 'read', schema))
|
|
1245
|
+
continue;
|
|
1246
|
+
if (index.isPrimitive(dataType) || index.isVector(dataType) || index.isShape(dataType))
|
|
1247
|
+
continue;
|
|
1248
|
+
_matches[colname] = {
|
|
1249
|
+
matches: this.decodeMatches(dataType.target, {}, includes.filter(x => x.startsWith(`${colname}.`)).map(x => x.slice(colname.length + 1))),
|
|
1250
|
+
};
|
|
1251
|
+
}
|
|
1252
|
+
for (const [colname, match] of _.toPairs(matches)) {
|
|
1253
|
+
if (!this.validateKeyPerm(colname, 'read', schema))
|
|
1254
|
+
throw Error('No permission');
|
|
1255
|
+
const { paths: [_colname, ...subpath], dataType } = resolveColumn(this.schema, className, colname);
|
|
1256
|
+
if (index.isPointer(dataType) && !_.isEmpty(subpath)) {
|
|
1257
|
+
_matches[_colname] = {
|
|
1258
|
+
matches: this.decodeMatches(dataType.target, { [subpath.join('.')]: match }, includes.filter(x => x.startsWith(`${_colname}.`)).map(x => x.slice(_colname.length + 1))),
|
|
1259
|
+
};
|
|
1260
|
+
}
|
|
1261
|
+
else if (index.isRelation(dataType)) {
|
|
1262
|
+
if (!this.validateCLPs(dataType.target, 'get'))
|
|
1263
|
+
throw Error('No permission');
|
|
1264
|
+
this.validateForeignField(dataType, 'read', `Invalid match: ${colname}`);
|
|
1265
|
+
const groupMatches = this.decodeGroupMatches(dataType.target, match.groupMatches ?? {});
|
|
1266
|
+
_matches[_colname] = {
|
|
1267
|
+
...match,
|
|
1268
|
+
groupMatches,
|
|
1269
|
+
filter: QuerySelector.decode(_.castArray(match.filter)).simplify(),
|
|
1270
|
+
matches: this.decodeMatches(dataType.target, match.matches ?? {}, includes.filter(x => x.startsWith(`${_colname}.`)).map(x => x.slice(_colname.length + 1))),
|
|
1271
|
+
sort: match.sort && this.decodeSort(match.sort),
|
|
1272
|
+
};
|
|
1273
|
+
}
|
|
1274
|
+
else {
|
|
1275
|
+
throw Error(`Invalid match: ${colname}`);
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
return _matches;
|
|
1279
|
+
}
|
|
1280
|
+
validateRelatedBy(className, relation) {
|
|
1281
|
+
if (!this.validateCLPs(relation.className, 'get'))
|
|
1282
|
+
throw Error('No permission');
|
|
1283
|
+
if (!this.validateKey(relation.className, relation.key, 'read', QueryValidator.patterns.path))
|
|
1284
|
+
throw Error('No permission');
|
|
1285
|
+
const { dataType } = resolveColumn(this.schema, relation.className, relation.key);
|
|
1286
|
+
if (!index.isPointer(dataType) && !index.isRelation(dataType))
|
|
1287
|
+
throw Error(`Invalid relation key: ${relation.key}`);
|
|
1288
|
+
if (className && dataType.target !== className)
|
|
1289
|
+
throw Error(`Invalid relation key: ${relation.key}`);
|
|
1290
|
+
if (index.isRelation(dataType) && dataType.foreignField) {
|
|
1291
|
+
this.validateForeignField(dataType, 'read', `Invalid relation key: ${relation.key}`);
|
|
1292
|
+
this.validateRelatedBy(null, { className: dataType.target, key: dataType.foreignField });
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
decodeQuery(query, action) {
|
|
1296
|
+
if ('relatedBy' in query && query.relatedBy)
|
|
1297
|
+
this.validateRelatedBy(query.className, query.relatedBy);
|
|
1298
|
+
const filter = QuerySelector.decode([
|
|
1299
|
+
...action === 'read' ? this._rperm(query.className) : this._wperm(query.className),
|
|
1300
|
+
..._.castArray(query.filter),
|
|
1301
|
+
this._expiredAt,
|
|
1302
|
+
]).simplify();
|
|
1303
|
+
const groupMatches = this.decodeGroupMatches(query.className, query.groupMatches ?? {});
|
|
1304
|
+
const matchKeyPaths = (matches) => _.flatMap(matches, (match, key) => [
|
|
1305
|
+
..._.keys(match.sort),
|
|
1306
|
+
...QuerySelector.decode(match.filter ?? []).keyPaths(),
|
|
1307
|
+
...matchKeyPaths(match.matches ?? {}),
|
|
1308
|
+
..._.keys(match.groupMatches),
|
|
1309
|
+
..._.flatMap(_.values(match.groupMatches), x => QueryAccumulator.decode(x).keyPaths()),
|
|
1310
|
+
].map(x => `${key}.${x}`));
|
|
1311
|
+
const sort = query.sort && this.decodeSort(query.sort);
|
|
1312
|
+
const keyPaths = _.uniq([
|
|
1313
|
+
...query.includes ?? ['*'],
|
|
1314
|
+
..._.isArray(sort) ? _.flatMap(sort, s => s.expr.keyPaths()) : _.keys(sort),
|
|
1315
|
+
...filter.keyPaths(),
|
|
1316
|
+
...matchKeyPaths(query.matches ?? {}),
|
|
1317
|
+
..._.keys(groupMatches),
|
|
1318
|
+
..._.flatMap(_.values(groupMatches), m => _.flatMap(_.values(m), x => x.keyPaths())),
|
|
1319
|
+
]);
|
|
1320
|
+
const includes = this.decodeIncludes(query.className, keyPaths, groupMatches);
|
|
1321
|
+
const matches = this.decodeMatches(query.className, query.matches ?? {}, includes);
|
|
1322
|
+
return {
|
|
1323
|
+
...query,
|
|
1324
|
+
groupMatches,
|
|
1325
|
+
filter,
|
|
1326
|
+
matches,
|
|
1327
|
+
includes,
|
|
1328
|
+
sort,
|
|
1329
|
+
objectIdSize: this.objectIdSize,
|
|
1330
|
+
extraFilter: (className) => QuerySelector.decode([...this._rperm(className), this._expiredAt]).simplify(),
|
|
1331
|
+
};
|
|
1332
|
+
}
|
|
1333
|
+
isGetMethod(query) {
|
|
1334
|
+
const objectIds = [];
|
|
1335
|
+
if (query instanceof QueryCoditionalSelector && query.type === '$and') {
|
|
1336
|
+
for (const expr of query.exprs) {
|
|
1337
|
+
if (expr instanceof QueryFieldSelector &&
|
|
1338
|
+
expr.field === '_id' &&
|
|
1339
|
+
expr.expr.type === '$eq') {
|
|
1340
|
+
if (!_.isString(expr.expr.value))
|
|
1341
|
+
return false;
|
|
1342
|
+
objectIds.push(expr.expr.value);
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
else if (query instanceof QueryFieldSelector &&
|
|
1347
|
+
query.field === '_id' &&
|
|
1348
|
+
query.expr.type === '$eq') {
|
|
1349
|
+
if (!_.isString(query.expr.value))
|
|
1350
|
+
return false;
|
|
1351
|
+
objectIds.push(query.expr.value);
|
|
1352
|
+
}
|
|
1353
|
+
return _.uniq(objectIds).length === 1;
|
|
1354
|
+
}
|
|
1355
|
+
}
|
|
1356
|
+
|
|
777
1357
|
exports.FieldSelectorExpression = FieldSelectorExpression;
|
|
778
1358
|
exports.QueryArrayExpression = QueryArrayExpression;
|
|
779
1359
|
exports.QueryCoditionalExpression = QueryCoditionalExpression;
|
|
780
1360
|
exports.QueryCoditionalSelector = QueryCoditionalSelector;
|
|
781
1361
|
exports.QueryComparisonExpression = QueryComparisonExpression;
|
|
782
1362
|
exports.QueryDistanceExpression = QueryDistanceExpression;
|
|
783
|
-
exports.
|
|
1363
|
+
exports.QueryExprAccumulator = QueryExprAccumulator;
|
|
784
1364
|
exports.QueryExpressionSelector = QueryExpressionSelector;
|
|
785
1365
|
exports.QueryFieldSelector = QueryFieldSelector;
|
|
786
1366
|
exports.QueryKeyExpression = QueryKeyExpression;
|
|
1367
|
+
exports.QueryNoParamAccumulator = QueryNoParamAccumulator;
|
|
787
1368
|
exports.QueryNotExpression = QueryNotExpression;
|
|
788
1369
|
exports.QuerySelector = QuerySelector;
|
|
1370
|
+
exports.QueryValidator = QueryValidator;
|
|
789
1371
|
exports.QueryValueExpression = QueryValueExpression;
|
|
790
|
-
|
|
1372
|
+
exports.resolveColumn = resolveColumn;
|
|
1373
|
+
exports.resolveDataType = resolveDataType;
|
|
1374
|
+
//# sourceMappingURL=validator-DoRPoIs2.js.map
|