proto.io 0.0.158 → 0.0.159

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.
@@ -7,7 +7,7 @@ import Decimal from 'decimal.js';
7
7
  import { escapeLiteral, escapeIdentifier } from 'pg/lib/utils';
8
8
  import { a as QueryCoditionalSelector, b as QueryFieldSelector, c as QueryExpressionSelector, d as QueryDistanceExpression, e as QueryCoditionalExpression, f as QueryComparisonExpression, g as QueryNotExpression, h as QueryArrayExpression, i as QueryValueExpression, j as QueryKeyExpression, Q as QuerySelector, F as FieldSelectorExpression } from '../../internals/index-tU-lsQqj.mjs';
9
9
  import '@o2ter/crypto-js';
10
- import { _ as _resolveColumn, g as generateId, Q as QueryValidator } from '../../internals/random-DLFngtjg.mjs';
10
+ import { a as resolveColumn, r as resolveDataType, g as generateId, Q as QueryValidator } from '../../internals/random-Dst9-WVo.mjs';
11
11
  import { P as PVK } from '../../internals/private-BUpLAMZi.mjs';
12
12
 
13
13
  //
@@ -240,7 +240,7 @@ class QueryCompiler {
240
240
  const names = {};
241
241
  const populates = {};
242
242
  for (const include of includes) {
243
- const { paths: [colname, ...subpath], dataType } = _resolveColumn(this.schema, className, include);
243
+ const { paths: [colname, ...subpath], dataType } = resolveColumn(this.schema, className, include);
244
244
  names[colname] = dataType;
245
245
  if (isPointer(dataType) || isRelation(dataType)) {
246
246
  if (_.isEmpty(subpath))
@@ -257,13 +257,12 @@ class QueryCompiler {
257
257
  colname,
258
258
  };
259
259
  if (isRelation(dataType) && dataType.foreignField) {
260
- const targetType = this.schema[dataType.target].fields[dataType.foreignField];
260
+ const targetType = resolveDataType(this.schema, dataType.target, dataType.foreignField);
261
+ if (_.isNil(targetType))
262
+ throw Error(`Invalid path: ${include}`);
261
263
  if (!isPointer(targetType) && !isRelation(targetType))
262
264
  throw Error(`Invalid path: ${include}`);
263
- populates[colname].foreignField = {
264
- colname: dataType.foreignField,
265
- type: targetType.type,
266
- };
265
+ populates[colname].foreignField = dataType.foreignField;
267
266
  }
268
267
  populates[colname].subpaths.push(subpath.join('.'));
269
268
  }
@@ -358,7 +357,7 @@ class QueryCompiler {
358
357
  _encodeUpdateAttrs(className, attrs) {
359
358
  const updates = [];
360
359
  for (const [path, op] of _.toPairs(attrs)) {
361
- const { paths: [column, ...subpath], dataType } = _resolveColumn(this.schema, className, path);
360
+ const { paths: [column, ...subpath], dataType } = resolveColumn(this.schema, className, path);
362
361
  if (isShape(dataType)) {
363
362
  const [_op, value] = decodeUpdateOp(op);
364
363
  if (_op !== '$set')
@@ -378,7 +377,7 @@ class QueryCompiler {
378
377
  _encodeObjectAttrs(className, attrs) {
379
378
  const result = {};
380
379
  for (const [key, value] of _.toPairs(attrs)) {
381
- const { paths: [column, ...subpath], dataType } = _resolveColumn(this.schema, className, key);
380
+ const { paths: [column, ...subpath], dataType } = resolveColumn(this.schema, className, key);
382
381
  if (!_.isEmpty(subpath))
383
382
  throw Error(`Invalid insert key: ${key}`);
384
383
  if (isShape(dataType)) {
@@ -784,6 +783,34 @@ class SqlStorage {
784
783
  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
785
784
  // THE SOFTWARE.
786
785
  //
786
+ const foreignFieldType = (schema, className, path) => {
787
+ let fields = schema[className].fields;
788
+ let last;
789
+ let result = false;
790
+ for (const key of _.toPath(path)) {
791
+ const dataType = fields[key];
792
+ if (_.isNil(dataType))
793
+ return;
794
+ if (isPrimitive(dataType) || isVector(dataType))
795
+ return;
796
+ if (isShape(dataType)) {
797
+ fields = dataType.shape;
798
+ continue;
799
+ }
800
+ if (_.isNil(schema[dataType.target]))
801
+ return;
802
+ if (dataType.type === 'relation')
803
+ result = true;
804
+ fields = schema[dataType.target].fields;
805
+ last = dataType;
806
+ }
807
+ if (!last)
808
+ return;
809
+ return {
810
+ target: last.target,
811
+ type: result ? 'relation' : last.type,
812
+ };
813
+ };
787
814
  const _fetchElement = (parent, colname, subpath, dataType) => {
788
815
  const element = sql `${{ identifier: parent.name }}.${{ identifier: parent.name.startsWith('_expr_$') ? '$' : colname }}`;
789
816
  if (!parent.className) {
@@ -824,7 +851,7 @@ const _fetchElement = (parent, colname, subpath, dataType) => {
824
851
  return { element, json: false };
825
852
  };
826
853
  const resolvePaths = (compiler, className, paths) => {
827
- const { paths: [colname, ...subpath], dataType } = _resolveColumn(compiler.schema, className, paths.join('.'));
854
+ const { paths: [colname, ...subpath], dataType } = resolveColumn(compiler.schema, className, paths.join('.'));
828
855
  if (!_.isEmpty(subpath) && isVector(dataType)) {
829
856
  if (subpath.length !== 1)
830
857
  throw Error(`Invalid key: ${paths.join('.')}`);
@@ -850,14 +877,38 @@ const resolvePaths = (compiler, className, paths) => {
850
877
  const fetchElement = (compiler, parent, field) => {
851
878
  if (parent.className) {
852
879
  const { dataType, colname, subpath } = resolvePaths(compiler, parent.className, _.toPath(field));
880
+ const { element, json } = _fetchElement(parent, colname, subpath, dataType);
881
+ if (!_.isEmpty(subpath)) {
882
+ const foreignField = foreignFieldType(compiler.schema, parent.className, field);
883
+ if (foreignField) {
884
+ return {
885
+ element,
886
+ dataType: foreignField,
887
+ relation: {
888
+ target: foreignField.target,
889
+ sql: (callback) => sql `SELECT
890
+ ${callback(sql `UNNEST`)}
891
+ FROM UNNEST(${{ identifier: parent.name }}.${{ identifier: colname }})`,
892
+ },
893
+ };
894
+ }
895
+ }
853
896
  if (isPointer(dataType))
854
897
  return { element: sql `${{ identifier: parent.name }}.${{ identifier: `${colname}._id` }}`, dataType };
855
- const { element, json } = _fetchElement(parent, colname, subpath, dataType);
856
- return { element, json, dataType: json ? null : dataType, relation: isRelation(dataType) ? dataType : null };
898
+ return {
899
+ element,
900
+ dataType: json ? null : dataType,
901
+ relation: isRelation(dataType) ? {
902
+ target: dataType.target,
903
+ sql: (callback) => sql `SELECT
904
+ ${callback(sql `${json ? sql `VALUE` : sql `UNNEST`}`)}
905
+ FROM ${json ? sql `jsonb_array_elements(${element})` : sql `UNNEST(${element})`}`,
906
+ } : null,
907
+ };
857
908
  }
858
909
  const [colname, ...subpath] = _.toPath(field);
859
- const { element, json } = _fetchElement(parent, colname, subpath);
860
- return { element, json, dataType: null, relation: null };
910
+ const { element } = _fetchElement(parent, colname, subpath);
911
+ return { element, dataType: null, relation: null };
861
912
  };
862
913
 
863
914
  //
@@ -1803,7 +1854,7 @@ const encodeQueryExpression = (compiler, parent, expr) => {
1803
1854
  //
1804
1855
  const encodeFieldExpression = (compiler, context, parent, field, expr) => {
1805
1856
  const [colname] = _.toPath(field);
1806
- const { element, json, dataType, relation } = fetchElement(compiler, parent, field);
1857
+ const { element, dataType, relation } = fetchElement(compiler, parent, field);
1807
1858
  const encodeValue = (value) => dataType ? encodeType(colname, dataType, value) : _encodeJsonValue(_encodeValue(value));
1808
1859
  switch (expr.type) {
1809
1860
  case '$eq':
@@ -1963,10 +2014,10 @@ const encodeFieldExpression = (compiler, context, parent, field, expr) => {
1963
2014
  if (dataType === 'array' || (!_.isString(dataType) && dataType?.type === 'array')) {
1964
2015
  return sql `${element} <@ ${{ value: _encodeValue(expr.value) }}`;
1965
2016
  }
1966
- else if (!_.isString(dataType) && dataType?.type === 'relation') {
2017
+ else if (relation) {
1967
2018
  if (!_.every(expr.value, x => x instanceof TObject && x.objectId))
1968
2019
  break;
1969
- return sql `ARRAY(SELECT (UNNEST ->> '_id') FROM UNNEST(${element})) <@ ARRAY[${_.map(expr.value, (x) => sql `${{ value: x.objectId }}`)}]`;
2020
+ return sql `ARRAY(${relation.sql((v) => sql `${v} ->> '_id'`)}) <@ ARRAY[${_.map(expr.value, (x) => sql `${{ value: x.objectId }}`)}]`;
1970
2021
  }
1971
2022
  else if (!dataType) {
1972
2023
  return sql `jsonb_typeof(${element}) ${nullSafeEqual()} 'array' AND ${element} <@ ${_encodeJsonValue(_encodeValue(expr.value))}`;
@@ -1981,10 +2032,10 @@ const encodeFieldExpression = (compiler, context, parent, field, expr) => {
1981
2032
  if (dataType === 'array' || (!_.isString(dataType) && dataType?.type === 'array')) {
1982
2033
  return sql `${element} @> ${{ value: _encodeValue(expr.value) }}`;
1983
2034
  }
1984
- else if (!_.isString(dataType) && dataType?.type === 'relation') {
2035
+ else if (relation) {
1985
2036
  if (!_.every(expr.value, x => x instanceof TObject && x.objectId))
1986
2037
  break;
1987
- return sql `ARRAY(SELECT (UNNEST ->> '_id') FROM UNNEST(${element})) @> ARRAY[${_.map(expr.value, (x) => sql `${{ value: x.objectId }}`)}]`;
2038
+ return sql `ARRAY(${relation.sql((v) => sql `${v} ->> '_id'`)}) @> ARRAY[${_.map(expr.value, (x) => sql `${{ value: x.objectId }}`)}]`;
1988
2039
  }
1989
2040
  else if (!dataType) {
1990
2041
  return sql `jsonb_typeof(${element}) ${nullSafeEqual()} 'array' AND ${element} @> ${_encodeJsonValue(_encodeValue(expr.value))}`;
@@ -1999,10 +2050,10 @@ const encodeFieldExpression = (compiler, context, parent, field, expr) => {
1999
2050
  if (dataType === 'array' || (!_.isString(dataType) && dataType?.type === 'array')) {
2000
2051
  return sql `NOT ${element} && ${{ value: _encodeValue(expr.value) }}`;
2001
2052
  }
2002
- else if (!_.isString(dataType) && dataType?.type === 'relation') {
2053
+ else if (relation) {
2003
2054
  if (!_.every(expr.value, x => x instanceof TObject && x.objectId))
2004
2055
  break;
2005
- return sql `NOT ARRAY(SELECT (UNNEST ->> '_id') FROM UNNEST(${element})) && ARRAY[${_.map(expr.value, (x) => sql `${{ value: x.objectId }}`)}]`;
2056
+ return sql `NOT ARRAY(${relation.sql((v) => sql `${v} ->> '_id'`)}) && ARRAY[${_.map(expr.value, (x) => sql `${{ value: x.objectId }}`)}]`;
2006
2057
  }
2007
2058
  else if (!dataType) {
2008
2059
  return sql `jsonb_typeof(${element}) ${nullSafeEqual()} 'array' AND NOT ${element} && ${_encodeJsonValue(_encodeValue(expr.value))}`;
@@ -2017,10 +2068,10 @@ const encodeFieldExpression = (compiler, context, parent, field, expr) => {
2017
2068
  if (dataType === 'array' || (!_.isString(dataType) && dataType?.type === 'array')) {
2018
2069
  return sql `${element} && ${{ value: _encodeValue(expr.value) }}`;
2019
2070
  }
2020
- else if (!_.isString(dataType) && dataType?.type === 'relation') {
2071
+ else if (relation) {
2021
2072
  if (!_.every(expr.value, x => x instanceof TObject && x.objectId))
2022
2073
  break;
2023
- return sql `ARRAY(SELECT (UNNEST ->> '_id') FROM UNNEST(${element})) && ARRAY[${_.map(expr.value, (x) => sql `${{ value: x.objectId }}`)}]`;
2074
+ return sql `ARRAY(${relation.sql((v) => sql `${v} ->> '_id'`)}) && ARRAY[${_.map(expr.value, (x) => sql `${{ value: x.objectId }}`)}]`;
2024
2075
  }
2025
2076
  else if (!dataType) {
2026
2077
  return sql `jsonb_typeof(${element}) ${nullSafeEqual()} 'array' AND ${element} && ${_encodeJsonValue(_encodeValue(expr.value))}`;
@@ -2127,11 +2178,7 @@ const encodeFieldExpression = (compiler, context, parent, field, expr) => {
2127
2178
  break;
2128
2179
  if (relation) {
2129
2180
  return sql `NOT EXISTS(
2130
- SELECT * FROM (
2131
- SELECT
2132
- ${json ? sql `VALUE` : sql `UNNEST`} AS "$"
2133
- FROM ${json ? sql `jsonb_array_elements(${element})` : sql `UNNEST(${element})`}
2134
- ) AS ${{ identifier: tempName }}
2181
+ SELECT * FROM (${relation.sql((v) => sql `${v} AS "$"`)}) AS ${{ identifier: tempName }}
2135
2182
  WHERE NOT (${filter})
2136
2183
  )`;
2137
2184
  }
@@ -2158,11 +2205,7 @@ const encodeFieldExpression = (compiler, context, parent, field, expr) => {
2158
2205
  break;
2159
2206
  if (relation) {
2160
2207
  return sql `EXISTS(
2161
- SELECT * FROM (
2162
- SELECT
2163
- ${json ? sql `VALUE` : sql `UNNEST`} AS "$"
2164
- FROM ${json ? sql `jsonb_array_elements(${element})` : sql `UNNEST(${element})`}
2165
- ) AS ${{ identifier: tempName }}
2208
+ SELECT * FROM (${relation.sql((v) => sql `${v} AS "$"`)}) AS ${{ identifier: tempName }}
2166
2209
  WHERE ${filter}
2167
2210
  )`;
2168
2211
  }
@@ -2225,6 +2268,28 @@ const resolveSubpaths = (compiler, populate) => {
2225
2268
  }
2226
2269
  return subpaths;
2227
2270
  };
2271
+ const _isPointer = (schema, className, path) => {
2272
+ let fields = schema[className].fields;
2273
+ let last;
2274
+ for (const key of _.toPath(path)) {
2275
+ const dataType = fields[key];
2276
+ if (_.isNil(dataType))
2277
+ throw Error(`Invalid path: ${path}`);
2278
+ if (isPrimitive(dataType) || isVector(dataType))
2279
+ throw Error(`Invalid path: ${path}`);
2280
+ if (isShape(dataType)) {
2281
+ fields = dataType.shape;
2282
+ continue;
2283
+ }
2284
+ if (dataType.type !== 'pointer')
2285
+ return false;
2286
+ if (_.isNil(schema[dataType.target]))
2287
+ throw Error(`Invalid path: ${path}`);
2288
+ fields = schema[dataType.target].fields;
2289
+ last = dataType;
2290
+ }
2291
+ return last?.type === 'pointer';
2292
+ };
2228
2293
  const selectPopulate = (compiler, parent, populate, field) => {
2229
2294
  const _local = (field) => sql `${{ identifier: parent.name }}.${{ identifier: field }}`;
2230
2295
  const _foreign = (field) => sql `${{ identifier: populate.name }}.${{ identifier: field }}`;
@@ -2242,11 +2307,11 @@ const selectPopulate = (compiler, parent, populate, field) => {
2242
2307
  if (_.isNil(populate.foreignField)) {
2243
2308
  cond = sql `${sql `(${{ quote: populate.className + '$' }} || ${_foreign('_id')})`} = ANY(${_local(field)})`;
2244
2309
  }
2245
- else if (populate.foreignField.type === 'pointer') {
2246
- cond = sql `${sql `(${{ quote: parent.className + '$' }} || ${_local('_id')})`} = ${_foreign(populate.foreignField.colname)}`;
2310
+ else if (_isPointer(compiler.schema, populate.className, populate.foreignField)) {
2311
+ cond = sql `${sql `(${{ quote: parent.className + '$' }} || ${_local('_id')})`} = ${_foreign(populate.colname)}`;
2247
2312
  }
2248
2313
  else {
2249
- cond = sql `${sql `(${{ quote: parent.className + '$' }} || ${_local('_id')})`} = ANY(${_foreign(populate.foreignField.colname)})`;
2314
+ cond = sql `${sql `(${{ quote: parent.className + '$' }} || ${_local('_id')})`} = ANY(${_foreign(populate.colname)})`;
2250
2315
  }
2251
2316
  return {
2252
2317
  columns: [sql `
@@ -2263,11 +2328,80 @@ const selectPopulate = (compiler, parent, populate, field) => {
2263
2328
  `],
2264
2329
  };
2265
2330
  };
2331
+ const encodeRemix = (parent, remix) => sql `${remix?.className === parent.className ? sql `
2332
+ (SELECT * FROM ${{ identifier: remix.name }} UNION SELECT * FROM ${{ identifier: parent.className }})
2333
+ ` : { identifier: parent.className }}`;
2334
+ const encodeForeignField = (compiler, context, parent, foreignField, remix) => {
2335
+ const { paths: [colname, ...subpath], dataType } = resolveColumn(compiler.schema, parent.className, foreignField);
2336
+ const tempName = `_populate_$${compiler.nextIdx()}`;
2337
+ const _local = (field) => sql `${{ identifier: parent.name }}.${{ identifier: field }}`;
2338
+ const _foreign = (field) => sql `${{ identifier: tempName }}.${{ identifier: field }}`;
2339
+ if (_.isEmpty(subpath) && isRelation(dataType) && dataType.foreignField) {
2340
+ const { joins, field, rows, array } = encodeForeignField(compiler, context, { className: dataType.target, name: tempName }, dataType.foreignField, remix);
2341
+ return {
2342
+ joins: [],
2343
+ field: sql `(
2344
+ SELECT ${sql `(${{ quote: parent.className + '$' }} || ${_foreign('_id')})`}
2345
+ FROM ${encodeRemix(parent, remix)} AS ${{ identifier: tempName }}
2346
+ ${!_.isEmpty(joins) ? { literal: joins, separator: '\n' } : sql ``}
2347
+ WHERE ${sql `(${{ quote: parent.className + '$' }} || ${_local('_id')})`} = ${array || rows ? sql `ANY(${field})` : field}
2348
+ )`,
2349
+ array: false,
2350
+ rows: true,
2351
+ };
2352
+ }
2353
+ if (_.isEmpty(subpath)) {
2354
+ return {
2355
+ joins: [],
2356
+ field: sql `${{ identifier: parent.name }}.${{ identifier: foreignField }}`,
2357
+ array: isRelation(dataType),
2358
+ rows: false,
2359
+ };
2360
+ }
2361
+ if (!isPointer(dataType) && !isRelation(dataType))
2362
+ throw Error(`Invalid path: ${foreignField}`);
2363
+ const { joins, field, rows, array } = encodeForeignField(compiler, context, { className: dataType.target, name: tempName }, subpath.join('.'), remix);
2364
+ if (isPointer(dataType)) {
2365
+ return {
2366
+ joins: [sql `
2367
+ LEFT JOIN ${encodeRemix(parent, remix)} AS ${{ identifier: tempName }}
2368
+ ON ${sql `(${{ quote: dataType.target + '$' }} || ${_foreign('_id')})`} = ${_local(colname)}
2369
+ `, ...joins],
2370
+ field,
2371
+ array,
2372
+ rows,
2373
+ };
2374
+ }
2375
+ let cond;
2376
+ if (_.isNil(dataType.foreignField)) {
2377
+ cond = sql `${sql `(${{ quote: dataType.target + '$' }} || ${_foreign('_id')})`} = ANY(${_local(colname)})`;
2378
+ }
2379
+ else if (_isPointer(compiler.schema, dataType.target, dataType.foreignField)) {
2380
+ cond = sql `${sql `(${{ quote: parent.className + '$' }} || ${_local('_id')})`} = ${_foreign(dataType.foreignField)}`;
2381
+ }
2382
+ else {
2383
+ cond = sql `${sql `(${{ quote: parent.className + '$' }} || ${_local('_id')})`} = ANY(${_foreign(dataType.foreignField)})`;
2384
+ }
2385
+ return {
2386
+ joins: [],
2387
+ field: sql `(
2388
+ SELECT ${array ? sql `UNNEST(${field})` : field} FROM ${encodeRemix(parent, remix)} AS ${{ identifier: tempName }}
2389
+ ${!_.isEmpty(joins) ? { literal: joins, separator: '\n' } : sql ``}
2390
+ WHERE ${cond}
2391
+ )`,
2392
+ array: false,
2393
+ rows: true,
2394
+ };
2395
+ };
2266
2396
  const encodePopulate = (compiler, context, parent, remix) => {
2267
2397
  const _filter = compiler._encodeFilter(context, parent, parent.filter);
2268
2398
  const _populates = _.map(parent.populates, (populate, field) => selectPopulate(compiler, parent, populate, field));
2269
2399
  const _joins = _.compact(_.map(_populates, ({ join }) => join));
2270
2400
  const _includes = _.pickBy(parent.includes, v => isPrimitive(v));
2401
+ const { joins: _joins2 = [], field: _foreignField = undefined, rows = false, } = parent.foreignField ? encodeForeignField(compiler, context, {
2402
+ className: parent.className,
2403
+ name: parent.name,
2404
+ }, parent.foreignField, remix) : {};
2271
2405
  return _.reduce(parent.populates, (acc, populate) => ({
2272
2406
  ...encodePopulate(compiler, context, populate, remix),
2273
2407
  ...acc,
@@ -2278,14 +2412,12 @@ const encodePopulate = (compiler, context, parent, remix) => {
2278
2412
  ${{
2279
2413
  literal: [
2280
2414
  ..._.map(_.keys(_includes), colname => sql `${{ identifier: parent.name }}.${{ identifier: colname }}`),
2281
- ...parent.foreignField ? [sql `${{ identifier: parent.name }}.${{ identifier: parent.foreignField.colname }}`] : [],
2282
2415
  ..._.flatMap(_populates, ({ columns: column }) => column),
2416
+ ..._foreignField ? [sql `${rows ? sql `ARRAY(${_foreignField})` : _foreignField} AS ${{ identifier: parent.colname }}`] : [],
2283
2417
  ], separator: ',\n'
2284
2418
  }}
2285
- FROM ${remix?.className === parent.className ? sql `
2286
- (SELECT * FROM ${{ identifier: remix.name }} UNION SELECT * FROM ${{ identifier: parent.className }})
2287
- ` : { identifier: parent.className }} AS ${{ identifier: parent.name }}
2288
- ${!_.isEmpty(_joins) ? { literal: _joins, separator: '\n' } : sql ``}
2419
+ FROM ${encodeRemix(parent, remix)} AS ${{ identifier: parent.name }}
2420
+ ${!_.isEmpty(_joins) || !_.isEmpty(_joins2) ? { literal: [..._joins, ..._joins2], separator: '\n' } : sql ``}
2289
2421
  ) AS ${{ identifier: parent.name }}
2290
2422
  ${_filter ? sql `WHERE ${_filter}` : sql ``}
2291
2423
  `,
@@ -2320,13 +2452,13 @@ const encodeRelation = (compiler, context, parent, relatedBy) => {
2320
2452
  const name = `_relation_$${relatedBy.className.toLowerCase()}`;
2321
2453
  const _local = (field) => sql `${{ identifier: parent.name }}.${{ identifier: field }}`;
2322
2454
  const _foreign = (field) => sql `${{ identifier: name }}.${{ identifier: field }}`;
2323
- return sql `
2324
- EXISTS (
2455
+ const { joins, field } = encodeForeignField(compiler, context, { className: relatedBy.className, name }, relatedBy.key);
2456
+ return sql `EXISTS (
2325
2457
  SELECT 1
2326
2458
  FROM ${{ identifier: relatedBy.className }} AS ${{ identifier: name }}
2327
- WHERE ${_foreign('_id')} = ${{ value: relatedBy.objectId }} AND ${sql `(${{ quote: parent.className + '$' }} || ${_local('_id')})`} = ANY(${_foreign(relatedBy.key)})
2328
- )
2329
- `;
2459
+ ${!_.isEmpty(joins) ? { literal: joins, separator: '\n' } : sql ``}
2460
+ WHERE ${_foreign('_id')} = ${{ value: relatedBy.objectId }} AND ${sql `(${{ quote: parent.className + '$' }} || ${_local('_id')})`} = ANY(${field})
2461
+ )`;
2330
2462
  };
2331
2463
 
2332
2464
  //