proto.io 0.0.211 → 0.0.212

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 (48) hide show
  1. package/dist/adapters/file/aliyun-oss.d.ts +3 -3
  2. package/dist/adapters/file/database.d.ts +2 -2
  3. package/dist/adapters/file/database.js +1 -1
  4. package/dist/adapters/file/database.js.map +1 -1
  5. package/dist/adapters/file/database.mjs +2 -2
  6. package/dist/adapters/file/database.mjs.map +1 -1
  7. package/dist/adapters/file/filesystem.d.ts +3 -3
  8. package/dist/adapters/file/google-cloud-storage.d.ts +3 -3
  9. package/dist/adapters/storage/progres.d.ts +8 -6
  10. package/dist/adapters/storage/progres.js +142 -78
  11. package/dist/adapters/storage/progres.js.map +1 -1
  12. package/dist/adapters/storage/progres.mjs +143 -79
  13. package/dist/adapters/storage/progres.mjs.map +1 -1
  14. package/dist/client.d.ts +3 -3
  15. package/dist/client.js +1 -1
  16. package/dist/client.mjs +2 -2
  17. package/dist/index.d.ts +3 -3
  18. package/dist/index.js +8 -8
  19. package/dist/index.js.map +1 -1
  20. package/dist/index.mjs +10 -10
  21. package/dist/index.mjs.map +1 -1
  22. package/dist/internals/{base-BCWOHUaQ.d.ts → base-CZGalGrd.d.ts} +2 -2
  23. package/dist/internals/base-CZGalGrd.d.ts.map +1 -0
  24. package/dist/internals/{chunk-2pKgkO5-.d.ts → chunk-BsT9SYny.d.ts} +3 -3
  25. package/dist/internals/chunk-BsT9SYny.d.ts.map +1 -0
  26. package/dist/internals/{index-lTzbCO8S.d.ts → index-Boxwkqe0.d.ts} +32 -15
  27. package/dist/internals/index-Boxwkqe0.d.ts.map +1 -0
  28. package/dist/internals/{index-DPPLcZx8.mjs → index-DG9HHO_U.mjs} +2 -2
  29. package/dist/internals/{index-DPPLcZx8.mjs.map → index-DG9HHO_U.mjs.map} +1 -1
  30. package/dist/internals/{index-Btxxs0KS.js → index-DfnPpl1I.js} +16 -10
  31. package/dist/internals/index-DfnPpl1I.js.map +1 -0
  32. package/dist/internals/{index-8AdKlZUU.d.ts → index-NF-U_3zG.d.ts} +2 -2
  33. package/dist/internals/index-NF-U_3zG.d.ts.map +1 -0
  34. package/dist/internals/{index-CoeDMG5V.mjs → index-ZPbBr9Db.mjs} +16 -10
  35. package/dist/internals/index-ZPbBr9Db.mjs.map +1 -0
  36. package/dist/internals/{random-ycCeBd0S.mjs → random-CufRbivU.mjs} +121 -19
  37. package/dist/internals/random-CufRbivU.mjs.map +1 -0
  38. package/dist/internals/{random-CyU_Y2Ay.js → random-DzvxbWAc.js} +161 -58
  39. package/dist/internals/random-DzvxbWAc.js.map +1 -0
  40. package/package.json +1 -1
  41. package/dist/internals/base-BCWOHUaQ.d.ts.map +0 -1
  42. package/dist/internals/chunk-2pKgkO5-.d.ts.map +0 -1
  43. package/dist/internals/index-8AdKlZUU.d.ts.map +0 -1
  44. package/dist/internals/index-Btxxs0KS.js.map +0 -1
  45. package/dist/internals/index-CoeDMG5V.mjs.map +0 -1
  46. package/dist/internals/index-lTzbCO8S.d.ts.map +0 -1
  47. package/dist/internals/random-CyU_Y2Ay.js.map +0 -1
  48. package/dist/internals/random-ycCeBd0S.mjs.map +0 -1
@@ -11,7 +11,7 @@ var Decimal = require('decimal.js');
11
11
  var utils = require('pg/lib/utils');
12
12
  var index$1 = require('../../internals/index-D8O7SinR.js');
13
13
  require('@o2ter/crypto-js');
14
- var random$1 = require('../../internals/random-CyU_Y2Ay.js');
14
+ var random$1 = require('../../internals/random-DzvxbWAc.js');
15
15
  var _const = require('../../internals/const-C3I6cfav.js');
16
16
  var _private = require('../../internals/private-Ciddhure.js');
17
17
 
@@ -218,12 +218,12 @@ class QueryCompiler {
218
218
  _encodeIncludes(query) {
219
219
  const names = {};
220
220
  const populates = {};
221
- const countMatches = [];
221
+ const groupMatches = {};
222
222
  for (const include of query.includes) {
223
223
  const { paths: [colname, ...subpath], dataType } = random$1.resolveColumn(this.schema, query.className, include);
224
224
  names[colname] = dataType;
225
- if (index.isRelation(dataType) && _.includes(query.countMatches, colname))
226
- countMatches.push(colname);
225
+ if (index.isRelation(dataType) && !_.isNil(query.groupMatches[colname]))
226
+ groupMatches[colname] = query.groupMatches[colname];
227
227
  if (index.isPointer(dataType) || index.isRelation(dataType)) {
228
228
  if (_.isEmpty(subpath))
229
229
  throw Error(`Invalid path: ${include}`);
@@ -254,21 +254,26 @@ class QueryCompiler {
254
254
  }
255
255
  for (const [colname, populate] of _.toPairs(populates)) {
256
256
  const _matches = query.matches[colname];
257
- const { includes, populates, countMatches } = this._encodeIncludes({
257
+ const { includes, populates, groupMatches } = this._encodeIncludes({
258
258
  className: populate.className,
259
259
  includes: populate.subpaths,
260
260
  matches: _matches.matches,
261
- countMatches: [
262
- ..._.filter(query.countMatches, x => _.startsWith(x, `${colname}.`)).map(x => x.slice(colname.length + 1)),
263
- ..._matches.countMatches ?? [],
264
- ],
261
+ groupMatches: {
262
+ ..._.mapKeys(_.pickBy(query.groupMatches, (x, k) => _.startsWith(k, `${colname}.`)), (x, k) => k.slice(colname.length + 1)),
263
+ ..._matches.groupMatches ?? {},
264
+ },
265
265
  });
266
266
  populate.sort = _encodeSorting(includes, populates, _matches.sort);
267
267
  populate.includes = includes;
268
268
  populate.populates = populates;
269
- populate.countMatches = countMatches;
269
+ populate.groupMatches = groupMatches;
270
270
  }
271
- return { className: query.className, includes: names, populates, countMatches: _.uniq(countMatches) };
271
+ return {
272
+ className: query.className,
273
+ includes: names,
274
+ populates,
275
+ groupMatches,
276
+ };
272
277
  }
273
278
  _baseSelectQuery(query, options) {
274
279
  const fetchName = `_fetch_$${query.className.toLowerCase()}`;
@@ -409,7 +414,7 @@ class QueryCompiler {
409
414
  }
410
415
  _selectIncludes(className, includes) {
411
416
  const _includes = _.pickBy(includes, v => _.isString(v) || (v.type !== 'pointer' && v.type !== 'relation'));
412
- return _.map(_includes, (dataType, colname) => {
417
+ return _.flatMap(_includes, (dataType, colname) => {
413
418
  if (!_.isString(dataType) && index.isPrimitive(dataType) && !_.isNil(dataType.default)) {
414
419
  return sql `COALESCE(${{ identifier: className }}.${{ identifier: colname }}, ${{ value: dataType.default }}) AS ${{ identifier: colname }}`;
415
420
  }
@@ -430,7 +435,7 @@ class QueryCompiler {
430
435
  `)}`;
431
436
  }
432
437
  _selectPopulateMap(context) {
433
- return _.map(context.populates, (populate, field) => this.dialect.selectPopulate(this, context, populate, field, _.includes(context.countMatches, field)));
438
+ return _.map(context.populates, (populate, field) => this.dialect.selectPopulate(this, context, populate, field));
434
439
  }
435
440
  insert(options, values) {
436
441
  const _values = _.map(values, attr => ({
@@ -568,9 +573,15 @@ class SqlStorage {
568
573
  const { query, values } = sql.compile(this.dialect);
569
574
  return this._query(query, values);
570
575
  }
571
- _decodeShapedObject(dataType, value) {
576
+ _decodeMatchTypes(value, matchType) {
577
+ if (!_.isPlainObject(value))
578
+ return;
579
+ return _.mapValues(value, (v, k) => this.dialect.decodeType(matchType[k], v));
580
+ }
581
+ _decodeShapedObject(dataType, value, matchesType) {
572
582
  const result = {};
573
583
  for (const { path, type } of index.shapePaths(dataType)) {
584
+ const matchType = _.get(matchesType, path) ?? {};
574
585
  if (_.isString(type)) {
575
586
  const _value = this.dialect.decodeType(type, _.get(value, path));
576
587
  if (!_.isNil(_value))
@@ -579,17 +590,17 @@ class SqlStorage {
579
590
  else if (index.isPointer(type)) {
580
591
  const _value = _.get(value, path);
581
592
  if (_.isPlainObject(_value)) {
582
- const decoded = this._decodeObject(type.target, _value);
593
+ const decoded = this._decodeObject(type.target, _value, matchType);
583
594
  if (decoded.objectId)
584
595
  _.set(result, path, decoded);
585
596
  }
586
597
  }
587
598
  else if (index.isRelation(type)) {
588
599
  const _value = _.get(value, path);
589
- if (_.isString(_value) && _value.match(/^\d+$/g))
590
- _.set(result, path, parseInt(_value));
591
- else if (_.isArray(_value))
592
- _.set(result, path, _value.map(x => this._decodeObject(type.target, x)));
600
+ if (_.isArray(_value))
601
+ _.set(result, path, _value.map(x => this._decodeObject(type.target, x, matchType)));
602
+ else if (_.isPlainObject(_value))
603
+ _.set(result, path, this._decodeMatchTypes(_value, matchType));
593
604
  }
594
605
  else {
595
606
  const _value = this.dialect.decodeType(type.type, _.get(value, path)) ?? type.default;
@@ -599,7 +610,7 @@ class SqlStorage {
599
610
  }
600
611
  return result;
601
612
  }
602
- _decodeObject(className, attrs) {
613
+ _decodeObject(className, attrs, matchesType) {
603
614
  const fields = this.schema[className].fields;
604
615
  const obj = new index.TObject(className);
605
616
  const _attrs = {};
@@ -607,6 +618,7 @@ class SqlStorage {
607
618
  _.set(_attrs, key, value);
608
619
  }
609
620
  for (const [key, value] of _.toPairs(_attrs)) {
621
+ const matchType = matchesType[key] ?? {};
610
622
  const dataType = fields[key];
611
623
  if (!dataType)
612
624
  continue;
@@ -614,20 +626,20 @@ class SqlStorage {
614
626
  obj[_private.PVK].attributes[key] = this.dialect.decodeType(dataType, value);
615
627
  }
616
628
  else if (index.isShape(dataType)) {
617
- obj[_private.PVK].attributes[key] = this._decodeShapedObject(dataType, value);
629
+ obj[_private.PVK].attributes[key] = this._decodeShapedObject(dataType, value, matchType);
618
630
  }
619
631
  else if (index.isPointer(dataType)) {
620
632
  if (_.isPlainObject(value)) {
621
- const decoded = this._decodeObject(dataType.target, value);
633
+ const decoded = this._decodeObject(dataType.target, value, matchType);
622
634
  if (decoded.objectId)
623
635
  obj[_private.PVK].attributes[key] = decoded;
624
636
  }
625
637
  }
626
638
  else if (index.isRelation(dataType)) {
627
- if (_.isString(value) && value.match(/^\d+$/g))
628
- obj[_private.PVK].attributes[key] = parseInt(value);
629
- else if (_.isArray(value))
630
- obj[_private.PVK].attributes[key] = value.map(x => this._decodeObject(dataType.target, x));
639
+ if (_.isArray(value))
640
+ obj[_private.PVK].attributes[key] = value.map(x => this._decodeObject(dataType.target, x, matchType));
641
+ else if (_.isPlainObject(value))
642
+ obj[_private.PVK].attributes[key] = this._decodeMatchTypes(value, matchType);
631
643
  }
632
644
  else {
633
645
  obj[_private.PVK].attributes[key] = this.dialect.decodeType(dataType.type, value) ?? dataType.default;
@@ -656,6 +668,18 @@ class SqlStorage {
656
668
  const count = parseInt(_count);
657
669
  return _.isFinite(count) ? count : 0;
658
670
  }
671
+ _matchesType(options) {
672
+ const types = {};
673
+ for (const [key, match] of _.entries(options.matches)) {
674
+ types[key] = this._matchesType(match);
675
+ }
676
+ for (const [key, group] of _.entries(options.groupMatches)) {
677
+ for (const [field, expr] of _.entries(group)) {
678
+ _.set(types, `${key}.${field}`, random$1.accumulatorKeyTypes[expr.type]);
679
+ }
680
+ }
681
+ return types;
682
+ }
659
683
  find(query) {
660
684
  const self = this;
661
685
  const compiler = self._makeCompiler(false, query.extraFilter);
@@ -663,7 +687,7 @@ class SqlStorage {
663
687
  return (async function* () {
664
688
  const objects = self.query(_query);
665
689
  for await (const object of objects) {
666
- yield self._decodeObject(query.className, object);
690
+ yield self._decodeObject(query.className, object, self._matchesType(query));
667
691
  }
668
692
  })();
669
693
  }
@@ -676,7 +700,7 @@ class SqlStorage {
676
700
  return (async function* () {
677
701
  const objects = self.query(_query);
678
702
  for await (const object of objects) {
679
- yield self._decodeObject(query.className, object);
703
+ yield self._decodeObject(query.className, object, self._matchesType(query));
680
704
  }
681
705
  })();
682
706
  }
@@ -690,7 +714,7 @@ class SqlStorage {
690
714
  return (async function* () {
691
715
  const objects = self.query(query);
692
716
  for await (const { _class, ...object } of objects) {
693
- yield self._decodeObject(_class, object);
717
+ yield self._decodeObject(_class, object, {});
694
718
  }
695
719
  })();
696
720
  }
@@ -705,29 +729,29 @@ class SqlStorage {
705
729
  return (async function* () {
706
730
  const objects = self.query(_query);
707
731
  for await (const object of objects) {
708
- yield self._decodeObject(query.className, object);
732
+ yield self._decodeObject(query.className, object, self._matchesType(query));
709
733
  }
710
734
  })();
711
735
  }
712
736
  async insert(options, values) {
713
737
  const compiler = this._makeCompiler(true);
714
738
  const result = await this.query(compiler.insert(options, values));
715
- return _.map(result, x => this._decodeObject(options.className, x));
739
+ return _.map(result, x => this._decodeObject(options.className, x, this._matchesType(options)));
716
740
  }
717
741
  async update(query, update) {
718
742
  const compiler = this._makeCompiler(true, query.extraFilter);
719
743
  const updated = await this.query(compiler.update(query, update));
720
- return _.map(updated, x => this._decodeObject(query.className, x));
744
+ return _.map(updated, x => this._decodeObject(query.className, x, this._matchesType(query)));
721
745
  }
722
746
  async upsert(query, update, setOnInsert) {
723
747
  const compiler = this._makeCompiler(true, query.extraFilter);
724
748
  const upserted = await this.query(compiler.upsert(query, update, setOnInsert));
725
- return _.map(upserted, x => this._decodeObject(query.className, x));
749
+ return _.map(upserted, x => this._decodeObject(query.className, x, this._matchesType(query)));
726
750
  }
727
751
  async delete(query) {
728
752
  const compiler = this._makeCompiler(true, query.extraFilter);
729
753
  const deleted = await this.query(compiler.delete(query));
730
- return _.map(deleted, x => this._decodeObject(query.className, x));
754
+ return _.map(deleted, x => this._decodeObject(query.className, x, this._matchesType(query)));
731
755
  }
732
756
  }
733
757
 
@@ -773,7 +797,15 @@ const _fetchElement = (parent, colname, subpath, dataType) => {
773
797
  }
774
798
  else if (!_.isEmpty(subpath)) {
775
799
  const _subpath = sql `${_.map(subpath, x => sql `${{ quote: x.startsWith('$') ? `$${x}` : x }}`)}`;
776
- if (dataType && index._isTypeof(dataType, ['array', 'string[]', 'relation'])) {
800
+ const match = parent.groupMatches?.[colname]?.[subpath[0]];
801
+ if (dataType && index.isRelation(dataType) && subpath.length === 1 && match) {
802
+ return {
803
+ element: sql `${{ identifier: parent.name }}.${{ identifier: `${colname}.${subpath[0]}` }}`,
804
+ json: false,
805
+ dataType: random$1.accumulatorKeyTypes[match.type],
806
+ };
807
+ }
808
+ else if (dataType && index._isTypeof(dataType, ['array', 'string[]', 'relation'])) {
777
809
  return {
778
810
  element: sql `jsonb_extract_path(to_jsonb(${element}), ${_subpath})`,
779
811
  json: true,
@@ -833,7 +865,7 @@ const _resolvePopulate = (path, populates) => {
833
865
  const fetchElement = (compiler, parent, field) => {
834
866
  if (parent.className) {
835
867
  const { dataType, colname, subpath } = resolvePaths(compiler, parent.className, _.toPath(field));
836
- const { element, json } = _fetchElement(parent, colname, subpath, dataType);
868
+ const { element, json, dataType: _dataType } = _fetchElement(parent, colname, subpath, dataType);
837
869
  if (index.isPointer(dataType))
838
870
  return { element: sql `${{ identifier: parent.name }}.${{ identifier: `${colname}._id` }}`, dataType };
839
871
  const populate = index.isRelation(dataType) && _resolvePopulate(_.toPath(colname), parent.populates);
@@ -841,7 +873,7 @@ const fetchElement = (compiler, parent, field) => {
841
873
  return { element, dataType: json ? null : dataType };
842
874
  return {
843
875
  element,
844
- dataType: json ? null : dataType,
876
+ dataType: json ? null : _dataType ?? dataType,
845
877
  relation: {
846
878
  colname,
847
879
  target: dataType.target,
@@ -1181,7 +1213,7 @@ const _encodeJsonValue = (value) => {
1181
1213
  return sql `jsonb_build_object(${_.map(value, (v, k) => sql `${{ value: k }}, ${_encodeJsonValue(v)}`)})`;
1182
1214
  return sql `to_jsonb(${{ value }})`;
1183
1215
  };
1184
- const _encodePopulateInclude = (className, colname, dataType) => {
1216
+ const _jsonPopulateInclude = (className, colname, dataType) => {
1185
1217
  switch (index._typeof(dataType)) {
1186
1218
  case 'decimal':
1187
1219
  return sql `jsonb_build_object(
@@ -1896,10 +1928,13 @@ const _selectRelationPopulate = (compiler, parent, populate, field, encode) => {
1896
1928
  cond = sql `${sql `(${{ quote: parent.className + '$' }} || ${_local('_id')})`} = ANY(${_foreign(populate.colname)})`;
1897
1929
  }
1898
1930
  return sql `
1899
- SELECT ${_.compact(_.flatMap(subpaths, ({ path, type }) => [
1900
- encode && _encodePopulateInclude(populate.name, path, type),
1901
- !encode && sql `${{ identifier: populate.name }}.${{ identifier: path }}`,
1902
- !encode && index.isRelation(type) && sql `${{ identifier: populate.name }}.${{ identifier: `$${path}` }}`,
1931
+ SELECT ${_.compact(_.flatMap(subpaths, ({ path, type }) => encode ? [
1932
+ _jsonPopulateInclude(populate.name, path, type)
1933
+ ] : [
1934
+ ...(populate.groupMatches[path] ? _.map(_.keys(populate.groupMatches[path]), k => sql `${{ identifier: populate.name }}.${{ identifier: `${path}.${k}` }}`) : [
1935
+ sql `${{ identifier: populate.name }}.${{ identifier: path }}`
1936
+ ]),
1937
+ index.isRelation(type) && sql `${{ identifier: populate.name }}.${{ identifier: `$${path}` }}`,
1903
1938
  ]))}
1904
1939
  FROM ${{ identifier: populate.name }} WHERE ${cond}
1905
1940
  ${!_.isEmpty(populate.sort) ? sql `ORDER BY ${compiler._encodeSort(populate.sort, { className: populate.className, name: populate.name })}` : sql ``}
@@ -1908,33 +1943,68 @@ const _selectRelationPopulate = (compiler, parent, populate, field, encode) => {
1908
1943
  ${compiler.selectLock ? compiler.isUpdate ? sql `FOR UPDATE NOWAIT` : sql `FOR SHARE NOWAIT` : sql ``}
1909
1944
  `;
1910
1945
  };
1911
- const selectPopulate = (compiler, parent, populate, field, countMatches) => {
1946
+ const selectPopulate = (compiler, parent, populate, field) => {
1912
1947
  if (populate.type === 'relation') {
1913
- return {
1914
- columns: [
1915
- countMatches ? sql `
1916
- (
1917
- SELECT COUNT(*) FROM (
1918
- ${_selectRelationPopulate(compiler, parent, populate, field, false)}
1919
- ) ${{ identifier: populate.name }}
1920
- ) AS ${{ identifier: field }}
1921
- ` : sql `
1922
- ARRAY(
1923
- SELECT to_jsonb(${{ identifier: populate.name }}) FROM (
1924
- ${_selectRelationPopulate(compiler, parent, populate, field, true)}
1925
- ) ${{ identifier: populate.name }}
1926
- ) AS ${{ identifier: field }}
1927
- `,
1928
- sql `${{ identifier: parent.name }}.${{ identifier: field }} AS ${{ identifier: `$${field}` }}`
1929
- ],
1930
- };
1948
+ const { groupMatches } = parent;
1949
+ const columns = [
1950
+ sql `${{ identifier: parent.name }}.${{ identifier: field }} AS ${{ identifier: `$${field}` }}`,
1951
+ ];
1952
+ if (!_.isEmpty(groupMatches?.[field])) {
1953
+ for (const [key, { type, expr }] of _.entries(groupMatches[field])) {
1954
+ switch (type) {
1955
+ case '$count':
1956
+ columns.push(sql `
1957
+ (
1958
+ SELECT COUNT(*) FROM (
1959
+ ${_selectRelationPopulate(compiler, parent, populate, field, false)}
1960
+ ) ${{ identifier: populate.name }}
1961
+ ) AS ${{ identifier: `${field}.${key}` }}
1962
+ `);
1963
+ break;
1964
+ case '$avg':
1965
+ case '$sum':
1966
+ {
1967
+ const op = {
1968
+ '$avg': 'AVG',
1969
+ '$sum': 'SUM',
1970
+ }[type];
1971
+ if (!expr)
1972
+ throw Error('Invalid expression');
1973
+ const exprs = encodeTypedQueryExpression(compiler, populate, expr);
1974
+ const { sql: value } = (_.includes(['$avg'], type) ? _.find(exprs, e => e.type === 'number') : _.first(exprs)) ?? {};
1975
+ if (!value)
1976
+ throw Error('Invalid expression');
1977
+ columns.push(sql `
1978
+ (
1979
+ SELECT ${{ literal: op }}(${value}) FROM (
1980
+ ${_selectRelationPopulate(compiler, parent, populate, field, false)}
1981
+ ) ${{ identifier: populate.name }}
1982
+ ) AS ${{ identifier: `${field}.${key}` }}
1983
+ `);
1984
+ }
1985
+ break;
1986
+ }
1987
+ }
1988
+ }
1989
+ else {
1990
+ columns.push(sql `
1991
+ ARRAY(
1992
+ SELECT to_jsonb(${{ identifier: populate.name }}) FROM (
1993
+ ${_selectRelationPopulate(compiler, parent, populate, field, true)}
1994
+ ) ${{ identifier: populate.name }}
1995
+ ) AS ${{ identifier: field }}
1996
+ `);
1997
+ }
1998
+ return { columns };
1931
1999
  }
1932
2000
  const _local = (field) => sql `${{ identifier: parent.name }}.${{ identifier: field }}`;
1933
2001
  const _foreign = (field) => sql `${{ identifier: populate.name }}.${{ identifier: field }}`;
1934
2002
  const subpaths = resolveSubpaths(compiler, populate);
1935
2003
  return {
1936
2004
  columns: _.compact(_.flatMap(subpaths, ({ path, type }) => [
1937
- sql `${{ identifier: populate.name }}.${{ identifier: path }} AS ${{ identifier: `${field}.${path}` }}`,
2005
+ ...populate.groupMatches[path] ? _.map(_.keys(populate.groupMatches[path]), k => sql `${{ identifier: populate.name }}.${{ identifier: `${path}.${k}` }} AS ${{ identifier: `${field}.${path}.${k}` }}`) : [
2006
+ sql `${{ identifier: populate.name }}.${{ identifier: path }} AS ${{ identifier: `${field}.${path}` }}`
2007
+ ],
1938
2008
  index.isRelation(type) && sql `${{ identifier: populate.name }}.${{ identifier: `$${path}` }} AS ${{ identifier: `$${field}.${path}` }}`,
1939
2009
  ])),
1940
2010
  join: sql `
@@ -2019,9 +2089,8 @@ const encodePopulate = (compiler, parent, remix) => {
2019
2089
  parent.filter && compiler._encodeFilter(parent, parent.filter),
2020
2090
  compiler.extraFilter && compiler._encodeFilter(parent, compiler.extraFilter(parent.className)),
2021
2091
  ]);
2022
- const _populates = _.map(parent.populates, (populate, field) => selectPopulate(compiler, parent, populate, field, _.includes(parent.countMatches, field)));
2092
+ const _populates = _.map(parent.populates, (populate, field) => selectPopulate(compiler, parent, populate, field));
2023
2093
  const _joins = _.compact(_.map(_populates, ({ join }) => join));
2024
- const _includes = _.pickBy(parent.includes, v => index.isPrimitive(v));
2025
2094
  const { joins: _joins2 = [], field: _foreignField = undefined, rows = false, } = parent.foreignField ? encodeForeignField(compiler, {
2026
2095
  className: parent.className,
2027
2096
  name: parent.name,
@@ -2035,7 +2104,7 @@ const encodePopulate = (compiler, parent, remix) => {
2035
2104
  SELECT
2036
2105
  ${{
2037
2106
  literal: [
2038
- ..._.map(_.keys(_includes), colname => sql `${{ identifier: parent.name }}.${{ identifier: colname }}`),
2107
+ ...compiler._selectIncludes(parent.name, parent.includes),
2039
2108
  ..._.flatMap(_populates, ({ columns: column }) => column),
2040
2109
  ..._foreignField ? [sql `${rows ? sql `ARRAY(${_foreignField})` : _foreignField} AS ${{ identifier: parent.colname }}`] : [],
2041
2110
  ], separator: ',\n'
@@ -2088,9 +2157,6 @@ const encodeFieldExpression = (compiler, parent, field, expr) => {
2088
2157
  break;
2089
2158
  return sql `${element} ${nullSafeEqual()} ${{ value: expr.value.objectId }}`;
2090
2159
  }
2091
- if (relation && _.includes(parent.countMatches, relation.colname)) {
2092
- return sql `${element} ${nullSafeEqual()} ${encodeType(colname, 'number', expr.value)}`;
2093
- }
2094
2160
  return sql `${element} ${nullSafeEqual()} ${encodeValue(expr.value)}`;
2095
2161
  }
2096
2162
  case '$ne':
@@ -2104,9 +2170,6 @@ const encodeFieldExpression = (compiler, parent, field, expr) => {
2104
2170
  break;
2105
2171
  return sql `${element} ${nullSafeNotEqual()} ${{ value: expr.value.objectId }}`;
2106
2172
  }
2107
- if (relation && _.includes(parent.countMatches, relation.colname)) {
2108
- return sql `${element} ${nullSafeNotEqual()} ${encodeType(colname, 'number', expr.value)}`;
2109
- }
2110
2173
  return sql `${element} ${nullSafeNotEqual()} ${encodeValue(expr.value)}`;
2111
2174
  }
2112
2175
  case '$gt':
@@ -2150,9 +2213,6 @@ const encodeFieldExpression = (compiler, parent, field, expr) => {
2150
2213
  else if (!_.isString(dataType) && dataType?.type === 'pointer' && expr.value instanceof index.TObject && expr.value.objectId) {
2151
2214
  return sql `${element} ${{ literal: op }} ${{ value: expr.value.objectId }}`;
2152
2215
  }
2153
- else if (relation && _.includes(parent.countMatches, relation.colname)) {
2154
- return sql `${element} ${{ literal: op }} ${encodeType(colname, 'number', expr.value)}`;
2155
- }
2156
2216
  else if (!dataType) {
2157
2217
  if (expr.value instanceof Decimal || _.isNumber(expr.value)) {
2158
2218
  return sql `(
@@ -2343,8 +2403,10 @@ const encodeFieldExpression = (compiler, parent, field, expr) => {
2343
2403
  if (dataType && index._isTypeof(dataType, 'string')) {
2344
2404
  return sql `COALESCE(length(${element}), 0) = ${{ value: expr.value }}`;
2345
2405
  }
2346
- if (relation && _.includes(parent.countMatches, relation.colname)) {
2347
- return sql `${element} = ${{ value: expr.value }}`;
2406
+ if (relation && parent.className && parent.groupMatches?.[colname]) {
2407
+ const tempName = `_populate_expr_$${compiler.nextIdx()}`;
2408
+ const populate = _selectRelationPopulate(compiler, { className: parent.className, name: parent.name }, relation.populate, `$${field}`, false);
2409
+ return sql `(SELECT COUNT(*) FROM (${populate}) AS ${{ identifier: tempName }}) = ${{ value: expr.value }}`;
2348
2410
  }
2349
2411
  if (dataType && index._isTypeof(dataType, ['array', 'string[]', 'vector', 'relation'])) {
2350
2412
  return sql `COALESCE(array_length(${element}, 1), 0) = ${{ value: expr.value }}`;
@@ -2367,8 +2429,10 @@ const encodeFieldExpression = (compiler, parent, field, expr) => {
2367
2429
  if (dataType && index._isTypeof(dataType, 'string')) {
2368
2430
  return sql `COALESCE(length(${element}), 0) ${{ literal: expr.value ? '=' : '<>' }} 0`;
2369
2431
  }
2370
- if (relation && _.includes(parent.countMatches, relation.colname)) {
2371
- return sql `${element} ${{ literal: expr.value ? '=' : '<>' }} 0`;
2432
+ if (relation && parent.className && parent.groupMatches?.[colname]) {
2433
+ const tempName = `_populate_expr_$${compiler.nextIdx()}`;
2434
+ const populate = _selectRelationPopulate(compiler, { className: parent.className, name: parent.name }, relation.populate, `$${field}`, false);
2435
+ return sql `${{ literal: expr.value ? 'NOT EXISTS' : 'EXISTS' }}(SELECT * FROM (${populate}) AS ${{ identifier: tempName }})`;
2372
2436
  }
2373
2437
  if (dataType && index._isTypeof(dataType, ['array', 'string[]', 'vector', 'relation'])) {
2374
2438
  return sql `COALESCE(array_length(${element}, 1), 0) ${{ literal: expr.value ? '=' : '<>' }} 0`;