proto.io 0.0.158 → 0.0.160

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.
@@ -50,11 +50,9 @@ declare class PostgresDriver extends PostgresClientDriver {
50
50
  type Populate = {
51
51
  name: string;
52
52
  className: string;
53
+ colname: string;
53
54
  type: TSchema.Relation;
54
- foreignField?: {
55
- colname: string;
56
- type: TSchema.Relation;
57
- };
55
+ foreignField?: string;
58
56
  subpaths: string[];
59
57
  filter: QuerySelector;
60
58
  includes: Record<string, TSchema.DataType>;
@@ -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-CSNRyhjB.js');
13
13
  require('@o2ter/crypto-js');
14
- var random$1 = require('../../internals/random-CPI-IjeV.js');
14
+ var random$1 = require('../../internals/random-uT4D0y_q.js');
15
15
  var _private = require('../../internals/private-CSB1Ep4g.js');
16
16
 
17
17
  //
@@ -244,7 +244,7 @@ class QueryCompiler {
244
244
  const names = {};
245
245
  const populates = {};
246
246
  for (const include of includes) {
247
- const { paths: [colname, ...subpath], dataType } = random$1._resolveColumn(this.schema, className, include);
247
+ const { paths: [colname, ...subpath], dataType } = random$1.resolveColumn(this.schema, className, include);
248
248
  names[colname] = dataType;
249
249
  if (index.isPointer(dataType) || index.isRelation(dataType)) {
250
250
  if (_.isEmpty(subpath))
@@ -261,13 +261,12 @@ class QueryCompiler {
261
261
  colname,
262
262
  };
263
263
  if (index.isRelation(dataType) && dataType.foreignField) {
264
- const targetType = this.schema[dataType.target].fields[dataType.foreignField];
264
+ const targetType = random$1.resolveDataType(this.schema, dataType.target, dataType.foreignField);
265
+ if (_.isNil(targetType))
266
+ throw Error(`Invalid path: ${include}`);
265
267
  if (!index.isPointer(targetType) && !index.isRelation(targetType))
266
268
  throw Error(`Invalid path: ${include}`);
267
- populates[colname].foreignField = {
268
- colname: dataType.foreignField,
269
- type: targetType.type,
270
- };
269
+ populates[colname].foreignField = dataType.foreignField;
271
270
  }
272
271
  populates[colname].subpaths.push(subpath.join('.'));
273
272
  }
@@ -362,7 +361,7 @@ class QueryCompiler {
362
361
  _encodeUpdateAttrs(className, attrs) {
363
362
  const updates = [];
364
363
  for (const [path, op] of _.toPairs(attrs)) {
365
- const { paths: [column, ...subpath], dataType } = random$1._resolveColumn(this.schema, className, path);
364
+ const { paths: [column, ...subpath], dataType } = random$1.resolveColumn(this.schema, className, path);
366
365
  if (index.isShape(dataType)) {
367
366
  const [_op, value] = index.decodeUpdateOp(op);
368
367
  if (_op !== '$set')
@@ -382,7 +381,7 @@ class QueryCompiler {
382
381
  _encodeObjectAttrs(className, attrs) {
383
382
  const result = {};
384
383
  for (const [key, value] of _.toPairs(attrs)) {
385
- const { paths: [column, ...subpath], dataType } = random$1._resolveColumn(this.schema, className, key);
384
+ const { paths: [column, ...subpath], dataType } = random$1.resolveColumn(this.schema, className, key);
386
385
  if (!_.isEmpty(subpath))
387
386
  throw Error(`Invalid insert key: ${key}`);
388
387
  if (index.isShape(dataType)) {
@@ -788,6 +787,34 @@ class SqlStorage {
788
787
  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
789
788
  // THE SOFTWARE.
790
789
  //
790
+ const foreignFieldType = (schema, className, path) => {
791
+ let fields = schema[className].fields;
792
+ let last;
793
+ let result = false;
794
+ for (const key of _.toPath(path)) {
795
+ const dataType = fields[key];
796
+ if (_.isNil(dataType))
797
+ return;
798
+ if (index.isPrimitive(dataType) || index.isVector(dataType))
799
+ return;
800
+ if (index.isShape(dataType)) {
801
+ fields = dataType.shape;
802
+ continue;
803
+ }
804
+ if (_.isNil(schema[dataType.target]))
805
+ return;
806
+ if (dataType.type === 'relation')
807
+ result = true;
808
+ fields = schema[dataType.target].fields;
809
+ last = dataType;
810
+ }
811
+ if (!last)
812
+ return;
813
+ return {
814
+ target: last.target,
815
+ type: result ? 'relation' : last.type,
816
+ };
817
+ };
791
818
  const _fetchElement = (parent, colname, subpath, dataType) => {
792
819
  const element = sql `${{ identifier: parent.name }}.${{ identifier: parent.name.startsWith('_expr_$') ? '$' : colname }}`;
793
820
  if (!parent.className) {
@@ -828,7 +855,7 @@ const _fetchElement = (parent, colname, subpath, dataType) => {
828
855
  return { element, json: false };
829
856
  };
830
857
  const resolvePaths = (compiler, className, paths) => {
831
- const { paths: [colname, ...subpath], dataType } = random$1._resolveColumn(compiler.schema, className, paths.join('.'));
858
+ const { paths: [colname, ...subpath], dataType } = random$1.resolveColumn(compiler.schema, className, paths.join('.'));
832
859
  if (!_.isEmpty(subpath) && index.isVector(dataType)) {
833
860
  if (subpath.length !== 1)
834
861
  throw Error(`Invalid key: ${paths.join('.')}`);
@@ -854,14 +881,38 @@ const resolvePaths = (compiler, className, paths) => {
854
881
  const fetchElement = (compiler, parent, field) => {
855
882
  if (parent.className) {
856
883
  const { dataType, colname, subpath } = resolvePaths(compiler, parent.className, _.toPath(field));
884
+ const { element, json } = _fetchElement(parent, colname, subpath, dataType);
885
+ if (!_.isEmpty(subpath)) {
886
+ const foreignField = foreignFieldType(compiler.schema, parent.className, field);
887
+ if (foreignField) {
888
+ return {
889
+ element,
890
+ dataType: foreignField,
891
+ relation: {
892
+ target: foreignField.target,
893
+ sql: (callback) => sql `SELECT
894
+ ${callback(sql `UNNEST`)}
895
+ FROM UNNEST(${{ identifier: parent.name }}.${{ identifier: colname }})`,
896
+ },
897
+ };
898
+ }
899
+ }
857
900
  if (index.isPointer(dataType))
858
901
  return { element: sql `${{ identifier: parent.name }}.${{ identifier: `${colname}._id` }}`, dataType };
859
- const { element, json } = _fetchElement(parent, colname, subpath, dataType);
860
- return { element, json, dataType: json ? null : dataType, relation: index.isRelation(dataType) ? dataType : null };
902
+ return {
903
+ element,
904
+ dataType: json ? null : dataType,
905
+ relation: index.isRelation(dataType) ? {
906
+ target: dataType.target,
907
+ sql: (callback) => sql `SELECT
908
+ ${callback(sql `${json ? sql `VALUE` : sql `UNNEST`}`)}
909
+ FROM ${json ? sql `jsonb_array_elements(${element})` : sql `UNNEST(${element})`}`,
910
+ } : null,
911
+ };
861
912
  }
862
913
  const [colname, ...subpath] = _.toPath(field);
863
- const { element, json } = _fetchElement(parent, colname, subpath);
864
- return { element, json, dataType: null, relation: null };
914
+ const { element } = _fetchElement(parent, colname, subpath);
915
+ return { element, dataType: null, relation: null };
865
916
  };
866
917
 
867
918
  //
@@ -1807,7 +1858,7 @@ const encodeQueryExpression = (compiler, parent, expr) => {
1807
1858
  //
1808
1859
  const encodeFieldExpression = (compiler, context, parent, field, expr) => {
1809
1860
  const [colname] = _.toPath(field);
1810
- const { element, json, dataType, relation } = fetchElement(compiler, parent, field);
1861
+ const { element, dataType, relation } = fetchElement(compiler, parent, field);
1811
1862
  const encodeValue = (value) => dataType ? encodeType(colname, dataType, value) : _encodeJsonValue(index._encodeValue(value));
1812
1863
  switch (expr.type) {
1813
1864
  case '$eq':
@@ -1967,10 +2018,10 @@ const encodeFieldExpression = (compiler, context, parent, field, expr) => {
1967
2018
  if (dataType === 'array' || (!_.isString(dataType) && dataType?.type === 'array')) {
1968
2019
  return sql `${element} <@ ${{ value: index._encodeValue(expr.value) }}`;
1969
2020
  }
1970
- else if (!_.isString(dataType) && dataType?.type === 'relation') {
2021
+ else if (relation) {
1971
2022
  if (!_.every(expr.value, x => x instanceof index.TObject && x.objectId))
1972
2023
  break;
1973
- return sql `ARRAY(SELECT (UNNEST ->> '_id') FROM UNNEST(${element})) <@ ARRAY[${_.map(expr.value, (x) => sql `${{ value: x.objectId }}`)}]`;
2024
+ return sql `ARRAY(${relation.sql((v) => sql `${v} ->> '_id'`)}) <@ ARRAY[${_.map(expr.value, (x) => sql `${{ value: x.objectId }}`)}]`;
1974
2025
  }
1975
2026
  else if (!dataType) {
1976
2027
  return sql `jsonb_typeof(${element}) ${nullSafeEqual()} 'array' AND ${element} <@ ${_encodeJsonValue(index._encodeValue(expr.value))}`;
@@ -1985,10 +2036,10 @@ const encodeFieldExpression = (compiler, context, parent, field, expr) => {
1985
2036
  if (dataType === 'array' || (!_.isString(dataType) && dataType?.type === 'array')) {
1986
2037
  return sql `${element} @> ${{ value: index._encodeValue(expr.value) }}`;
1987
2038
  }
1988
- else if (!_.isString(dataType) && dataType?.type === 'relation') {
2039
+ else if (relation) {
1989
2040
  if (!_.every(expr.value, x => x instanceof index.TObject && x.objectId))
1990
2041
  break;
1991
- return sql `ARRAY(SELECT (UNNEST ->> '_id') FROM UNNEST(${element})) @> ARRAY[${_.map(expr.value, (x) => sql `${{ value: x.objectId }}`)}]`;
2042
+ return sql `ARRAY(${relation.sql((v) => sql `${v} ->> '_id'`)}) @> ARRAY[${_.map(expr.value, (x) => sql `${{ value: x.objectId }}`)}]`;
1992
2043
  }
1993
2044
  else if (!dataType) {
1994
2045
  return sql `jsonb_typeof(${element}) ${nullSafeEqual()} 'array' AND ${element} @> ${_encodeJsonValue(index._encodeValue(expr.value))}`;
@@ -2003,10 +2054,10 @@ const encodeFieldExpression = (compiler, context, parent, field, expr) => {
2003
2054
  if (dataType === 'array' || (!_.isString(dataType) && dataType?.type === 'array')) {
2004
2055
  return sql `NOT ${element} && ${{ value: index._encodeValue(expr.value) }}`;
2005
2056
  }
2006
- else if (!_.isString(dataType) && dataType?.type === 'relation') {
2057
+ else if (relation) {
2007
2058
  if (!_.every(expr.value, x => x instanceof index.TObject && x.objectId))
2008
2059
  break;
2009
- return sql `NOT ARRAY(SELECT (UNNEST ->> '_id') FROM UNNEST(${element})) && ARRAY[${_.map(expr.value, (x) => sql `${{ value: x.objectId }}`)}]`;
2060
+ return sql `NOT ARRAY(${relation.sql((v) => sql `${v} ->> '_id'`)}) && ARRAY[${_.map(expr.value, (x) => sql `${{ value: x.objectId }}`)}]`;
2010
2061
  }
2011
2062
  else if (!dataType) {
2012
2063
  return sql `jsonb_typeof(${element}) ${nullSafeEqual()} 'array' AND NOT ${element} && ${_encodeJsonValue(index._encodeValue(expr.value))}`;
@@ -2021,10 +2072,10 @@ const encodeFieldExpression = (compiler, context, parent, field, expr) => {
2021
2072
  if (dataType === 'array' || (!_.isString(dataType) && dataType?.type === 'array')) {
2022
2073
  return sql `${element} && ${{ value: index._encodeValue(expr.value) }}`;
2023
2074
  }
2024
- else if (!_.isString(dataType) && dataType?.type === 'relation') {
2075
+ else if (relation) {
2025
2076
  if (!_.every(expr.value, x => x instanceof index.TObject && x.objectId))
2026
2077
  break;
2027
- return sql `ARRAY(SELECT (UNNEST ->> '_id') FROM UNNEST(${element})) && ARRAY[${_.map(expr.value, (x) => sql `${{ value: x.objectId }}`)}]`;
2078
+ return sql `ARRAY(${relation.sql((v) => sql `${v} ->> '_id'`)}) && ARRAY[${_.map(expr.value, (x) => sql `${{ value: x.objectId }}`)}]`;
2028
2079
  }
2029
2080
  else if (!dataType) {
2030
2081
  return sql `jsonb_typeof(${element}) ${nullSafeEqual()} 'array' AND ${element} && ${_encodeJsonValue(index._encodeValue(expr.value))}`;
@@ -2131,11 +2182,7 @@ const encodeFieldExpression = (compiler, context, parent, field, expr) => {
2131
2182
  break;
2132
2183
  if (relation) {
2133
2184
  return sql `NOT EXISTS(
2134
- SELECT * FROM (
2135
- SELECT
2136
- ${json ? sql `VALUE` : sql `UNNEST`} AS "$"
2137
- FROM ${json ? sql `jsonb_array_elements(${element})` : sql `UNNEST(${element})`}
2138
- ) AS ${{ identifier: tempName }}
2185
+ SELECT * FROM (${relation.sql((v) => sql `${v} AS "$"`)}) AS ${{ identifier: tempName }}
2139
2186
  WHERE NOT (${filter})
2140
2187
  )`;
2141
2188
  }
@@ -2162,11 +2209,7 @@ const encodeFieldExpression = (compiler, context, parent, field, expr) => {
2162
2209
  break;
2163
2210
  if (relation) {
2164
2211
  return sql `EXISTS(
2165
- SELECT * FROM (
2166
- SELECT
2167
- ${json ? sql `VALUE` : sql `UNNEST`} AS "$"
2168
- FROM ${json ? sql `jsonb_array_elements(${element})` : sql `UNNEST(${element})`}
2169
- ) AS ${{ identifier: tempName }}
2212
+ SELECT * FROM (${relation.sql((v) => sql `${v} AS "$"`)}) AS ${{ identifier: tempName }}
2170
2213
  WHERE ${filter}
2171
2214
  )`;
2172
2215
  }
@@ -2229,6 +2272,28 @@ const resolveSubpaths = (compiler, populate) => {
2229
2272
  }
2230
2273
  return subpaths;
2231
2274
  };
2275
+ const _isPointer = (schema, className, path) => {
2276
+ let fields = schema[className].fields;
2277
+ let last;
2278
+ for (const key of _.toPath(path)) {
2279
+ const dataType = fields[key];
2280
+ if (_.isNil(dataType))
2281
+ throw Error(`Invalid path: ${path}`);
2282
+ if (index.isPrimitive(dataType) || index.isVector(dataType))
2283
+ throw Error(`Invalid path: ${path}`);
2284
+ if (index.isShape(dataType)) {
2285
+ fields = dataType.shape;
2286
+ continue;
2287
+ }
2288
+ if (dataType.type !== 'pointer')
2289
+ return false;
2290
+ if (_.isNil(schema[dataType.target]))
2291
+ throw Error(`Invalid path: ${path}`);
2292
+ fields = schema[dataType.target].fields;
2293
+ last = dataType;
2294
+ }
2295
+ return last?.type === 'pointer';
2296
+ };
2232
2297
  const selectPopulate = (compiler, parent, populate, field) => {
2233
2298
  const _local = (field) => sql `${{ identifier: parent.name }}.${{ identifier: field }}`;
2234
2299
  const _foreign = (field) => sql `${{ identifier: populate.name }}.${{ identifier: field }}`;
@@ -2246,11 +2311,11 @@ const selectPopulate = (compiler, parent, populate, field) => {
2246
2311
  if (_.isNil(populate.foreignField)) {
2247
2312
  cond = sql `${sql `(${{ quote: populate.className + '$' }} || ${_foreign('_id')})`} = ANY(${_local(field)})`;
2248
2313
  }
2249
- else if (populate.foreignField.type === 'pointer') {
2250
- cond = sql `${sql `(${{ quote: parent.className + '$' }} || ${_local('_id')})`} = ${_foreign(populate.foreignField.colname)}`;
2314
+ else if (_isPointer(compiler.schema, populate.className, populate.foreignField)) {
2315
+ cond = sql `${sql `(${{ quote: parent.className + '$' }} || ${_local('_id')})`} = ${_foreign(populate.colname)}`;
2251
2316
  }
2252
2317
  else {
2253
- cond = sql `${sql `(${{ quote: parent.className + '$' }} || ${_local('_id')})`} = ANY(${_foreign(populate.foreignField.colname)})`;
2318
+ cond = sql `${sql `(${{ quote: parent.className + '$' }} || ${_local('_id')})`} = ANY(${_foreign(populate.colname)})`;
2254
2319
  }
2255
2320
  return {
2256
2321
  columns: [sql `
@@ -2267,11 +2332,81 @@ const selectPopulate = (compiler, parent, populate, field) => {
2267
2332
  `],
2268
2333
  };
2269
2334
  };
2335
+ const encodeRemix = (parent, remix) => sql `${remix?.className === parent.className ? sql `
2336
+ (SELECT * FROM ${{ identifier: remix.name }} UNION SELECT * FROM ${{ identifier: parent.className }})
2337
+ ` : { identifier: parent.className }}`;
2338
+ const encodeForeignField = (compiler, context, parent, foreignField, remix) => {
2339
+ const { paths: [colname, ...subpath], dataType } = random$1.resolveColumn(compiler.schema, parent.className, foreignField);
2340
+ const tempName = `_populate_$${compiler.nextIdx()}`;
2341
+ const _local = (field) => sql `${{ identifier: parent.name }}.${{ identifier: field }}`;
2342
+ const _foreign = (field) => sql `${{ identifier: tempName }}.${{ identifier: field }}`;
2343
+ if (_.isEmpty(subpath) && index.isRelation(dataType) && dataType.foreignField) {
2344
+ const { joins, field, rows, array } = encodeForeignField(compiler, context, { className: dataType.target, name: tempName }, dataType.foreignField, remix);
2345
+ return {
2346
+ joins: [],
2347
+ field: sql `(
2348
+ SELECT ${sql `(${{ quote: dataType.target + '$' }} || ${_foreign('_id')})`}
2349
+ FROM ${encodeRemix({ className: dataType.target }, remix)} AS ${{ identifier: tempName }}
2350
+ ${!_.isEmpty(joins) ? { literal: joins, separator: '\n' } : sql ``}
2351
+ WHERE ${sql `(${{ quote: parent.className + '$' }} || ${_local('_id')})`} = ${array || rows ? sql `ANY(${field})` : field}
2352
+ )`,
2353
+ array: false,
2354
+ rows: true,
2355
+ };
2356
+ }
2357
+ if (_.isEmpty(subpath)) {
2358
+ return {
2359
+ joins: [],
2360
+ field: sql `${{ identifier: parent.name }}.${{ identifier: foreignField }}`,
2361
+ array: index.isRelation(dataType),
2362
+ rows: false,
2363
+ };
2364
+ }
2365
+ if (!index.isPointer(dataType) && !index.isRelation(dataType))
2366
+ throw Error(`Invalid path: ${foreignField}`);
2367
+ const { joins, field, rows, array } = encodeForeignField(compiler, context, { className: dataType.target, name: tempName }, subpath.join('.'), remix);
2368
+ if (index.isPointer(dataType)) {
2369
+ return {
2370
+ joins: [sql `
2371
+ LEFT JOIN ${encodeRemix({ className: dataType.target }, remix)} AS ${{ identifier: tempName }}
2372
+ ON ${sql `(${{ quote: dataType.target + '$' }} || ${_foreign('_id')})`} = ${_local(colname)}
2373
+ `, ...joins],
2374
+ field,
2375
+ array,
2376
+ rows,
2377
+ };
2378
+ }
2379
+ let cond;
2380
+ if (_.isNil(dataType.foreignField)) {
2381
+ cond = sql `${sql `(${{ quote: dataType.target + '$' }} || ${_foreign('_id')})`} = ANY(${_local(colname)})`;
2382
+ }
2383
+ else if (_isPointer(compiler.schema, dataType.target, dataType.foreignField)) {
2384
+ cond = sql `${sql `(${{ quote: parent.className + '$' }} || ${_local('_id')})`} = ${_foreign(dataType.foreignField)}`;
2385
+ }
2386
+ else {
2387
+ cond = sql `${sql `(${{ quote: parent.className + '$' }} || ${_local('_id')})`} = ANY(${_foreign(dataType.foreignField)})`;
2388
+ }
2389
+ return {
2390
+ joins: [],
2391
+ field: sql `(
2392
+ SELECT ${array ? sql `UNNEST(${field})` : field}
2393
+ FROM ${encodeRemix({ className: dataType.target }, remix)} AS ${{ identifier: tempName }}
2394
+ ${!_.isEmpty(joins) ? { literal: joins, separator: '\n' } : sql ``}
2395
+ WHERE ${cond}
2396
+ )`,
2397
+ array: false,
2398
+ rows: true,
2399
+ };
2400
+ };
2270
2401
  const encodePopulate = (compiler, context, parent, remix) => {
2271
2402
  const _filter = compiler._encodeFilter(context, parent, parent.filter);
2272
2403
  const _populates = _.map(parent.populates, (populate, field) => selectPopulate(compiler, parent, populate, field));
2273
2404
  const _joins = _.compact(_.map(_populates, ({ join }) => join));
2274
2405
  const _includes = _.pickBy(parent.includes, v => index.isPrimitive(v));
2406
+ const { joins: _joins2 = [], field: _foreignField = undefined, rows = false, } = parent.foreignField ? encodeForeignField(compiler, context, {
2407
+ className: parent.className,
2408
+ name: parent.name,
2409
+ }, parent.foreignField, remix) : {};
2275
2410
  return _.reduce(parent.populates, (acc, populate) => ({
2276
2411
  ...encodePopulate(compiler, context, populate, remix),
2277
2412
  ...acc,
@@ -2282,14 +2417,12 @@ const encodePopulate = (compiler, context, parent, remix) => {
2282
2417
  ${{
2283
2418
  literal: [
2284
2419
  ..._.map(_.keys(_includes), colname => sql `${{ identifier: parent.name }}.${{ identifier: colname }}`),
2285
- ...parent.foreignField ? [sql `${{ identifier: parent.name }}.${{ identifier: parent.foreignField.colname }}`] : [],
2286
2420
  ..._.flatMap(_populates, ({ columns: column }) => column),
2421
+ ..._foreignField ? [sql `${rows ? sql `ARRAY(${_foreignField})` : _foreignField} AS ${{ identifier: parent.colname }}`] : [],
2287
2422
  ], separator: ',\n'
2288
2423
  }}
2289
- FROM ${remix?.className === parent.className ? sql `
2290
- (SELECT * FROM ${{ identifier: remix.name }} UNION SELECT * FROM ${{ identifier: parent.className }})
2291
- ` : { identifier: parent.className }} AS ${{ identifier: parent.name }}
2292
- ${!_.isEmpty(_joins) ? { literal: _joins, separator: '\n' } : sql ``}
2424
+ FROM ${encodeRemix(parent, remix)} AS ${{ identifier: parent.name }}
2425
+ ${!_.isEmpty(_joins) || !_.isEmpty(_joins2) ? { literal: [..._joins, ..._joins2], separator: '\n' } : sql ``}
2293
2426
  ) AS ${{ identifier: parent.name }}
2294
2427
  ${_filter ? sql `WHERE ${_filter}` : sql ``}
2295
2428
  `,
@@ -2324,13 +2457,13 @@ const encodeRelation = (compiler, context, parent, relatedBy) => {
2324
2457
  const name = `_relation_$${relatedBy.className.toLowerCase()}`;
2325
2458
  const _local = (field) => sql `${{ identifier: parent.name }}.${{ identifier: field }}`;
2326
2459
  const _foreign = (field) => sql `${{ identifier: name }}.${{ identifier: field }}`;
2327
- return sql `
2328
- EXISTS (
2460
+ const { joins, field } = encodeForeignField(compiler, context, { className: relatedBy.className, name }, relatedBy.key);
2461
+ return sql `EXISTS (
2329
2462
  SELECT 1
2330
2463
  FROM ${{ identifier: relatedBy.className }} AS ${{ identifier: name }}
2331
- WHERE ${_foreign('_id')} = ${{ value: relatedBy.objectId }} AND ${sql `(${{ quote: parent.className + '$' }} || ${_local('_id')})`} = ANY(${_foreign(relatedBy.key)})
2332
- )
2333
- `;
2464
+ ${!_.isEmpty(joins) ? { literal: joins, separator: '\n' } : sql ``}
2465
+ WHERE ${_foreign('_id')} = ${{ value: relatedBy.objectId }} AND ${sql `(${{ quote: parent.className + '$' }} || ${_local('_id')})`} = ANY(${field})
2466
+ )`;
2334
2467
  };
2335
2468
 
2336
2469
  //