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.
Files changed (44) 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 +2 -2
  4. package/dist/adapters/file/database.js.map +1 -1
  5. package/dist/adapters/file/database.mjs +1 -1
  6. package/dist/adapters/file/filesystem.d.ts +3 -3
  7. package/dist/adapters/file/google-cloud-storage.d.ts +3 -3
  8. package/dist/adapters/storage/progres.d.ts +1 -1
  9. package/dist/adapters/storage/progres.js +111 -82
  10. package/dist/adapters/storage/progres.js.map +1 -1
  11. package/dist/adapters/storage/progres.mjs +73 -44
  12. package/dist/adapters/storage/progres.mjs.map +1 -1
  13. package/dist/client.d.ts +3 -3
  14. package/dist/index.d.ts +3 -3
  15. package/dist/index.js +42 -42
  16. package/dist/index.js.map +1 -1
  17. package/dist/index.mjs +2 -2
  18. package/dist/internals/{base-CZGalGrd.d.ts → base-E1b8J-Fs.d.ts} +2 -2
  19. package/dist/internals/base-E1b8J-Fs.d.ts.map +1 -0
  20. package/dist/internals/{chunk-BsT9SYny.d.ts → chunk-D1bD7otk.d.ts} +3 -3
  21. package/dist/internals/chunk-D1bD7otk.d.ts.map +1 -0
  22. package/dist/internals/{index-Boxwkqe0.d.ts → index-CbjY-gJ7.d.ts} +6 -8
  23. package/dist/internals/index-CbjY-gJ7.d.ts.map +1 -0
  24. package/dist/internals/{index-NF-U_3zG.d.ts → index-SSEdPyhp.d.ts} +2 -2
  25. package/dist/internals/index-SSEdPyhp.d.ts.map +1 -0
  26. package/dist/internals/random-CYjWDvex.mjs +37 -0
  27. package/dist/internals/random-CYjWDvex.mjs.map +1 -0
  28. package/dist/internals/random-nkOQ9U6S.js +39 -0
  29. package/dist/internals/random-nkOQ9U6S.js.map +1 -0
  30. package/dist/internals/{index-D8O7SinR.js → validator-DoRPoIs2.js} +586 -2
  31. package/dist/internals/validator-DoRPoIs2.js.map +1 -0
  32. package/dist/internals/{index-DG9HHO_U.mjs → validator-Dxmbwa3P.mjs} +583 -3
  33. package/dist/internals/validator-Dxmbwa3P.mjs.map +1 -0
  34. package/package.json +1 -1
  35. package/dist/internals/base-CZGalGrd.d.ts.map +0 -1
  36. package/dist/internals/chunk-BsT9SYny.d.ts.map +0 -1
  37. package/dist/internals/index-Boxwkqe0.d.ts.map +0 -1
  38. package/dist/internals/index-D8O7SinR.js.map +0 -1
  39. package/dist/internals/index-DG9HHO_U.mjs.map +0 -1
  40. package/dist/internals/index-NF-U_3zG.d.ts.map +0 -1
  41. package/dist/internals/random-CufRbivU.mjs +0 -526
  42. package/dist/internals/random-CufRbivU.mjs.map +0 -1
  43. package/dist/internals/random-DzvxbWAc.js +0 -532
  44. 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.QueryExpression = QueryExpression;
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
- //# sourceMappingURL=index-D8O7SinR.js.map
1372
+ exports.resolveColumn = resolveColumn;
1373
+ exports.resolveDataType = resolveDataType;
1374
+ //# sourceMappingURL=validator-DoRPoIs2.js.map