proto.io 0.0.164 → 0.0.165

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 (49) hide show
  1. package/dist/adapters/file/database.d.ts +2 -2
  2. package/dist/adapters/file/database.js.map +1 -1
  3. package/dist/adapters/file/database.mjs +2 -2
  4. package/dist/adapters/file/database.mjs.map +1 -1
  5. package/dist/adapters/file/filesystem.d.ts +2 -2
  6. package/dist/adapters/file/filesystem.js.map +1 -1
  7. package/dist/adapters/file/filesystem.mjs.map +1 -1
  8. package/dist/adapters/file/google-cloud-storage.d.ts +2 -2
  9. package/dist/adapters/file/google-cloud-storage.js.map +1 -1
  10. package/dist/adapters/file/google-cloud-storage.mjs.map +1 -1
  11. package/dist/adapters/storage/progres.d.ts +16 -13
  12. package/dist/adapters/storage/progres.js +136 -81
  13. package/dist/adapters/storage/progres.js.map +1 -1
  14. package/dist/adapters/storage/progres.mjs +138 -83
  15. package/dist/adapters/storage/progres.mjs.map +1 -1
  16. package/dist/client.d.ts +3 -3
  17. package/dist/client.mjs +3 -3
  18. package/dist/index.d.ts +7 -12
  19. package/dist/index.js +24 -23
  20. package/dist/index.js.map +1 -1
  21. package/dist/index.mjs +28 -27
  22. package/dist/index.mjs.map +1 -1
  23. package/dist/internals/{index-ByfpVHca.mjs → index-BYbMU-Ao.mjs} +2 -2
  24. package/dist/internals/{index-ByfpVHca.mjs.map → index-BYbMU-Ao.mjs.map} +1 -1
  25. package/dist/internals/{index-S5Bq-KsU.mjs → index-BejQNqvC.mjs} +2 -2
  26. package/dist/internals/{index-S5Bq-KsU.mjs.map → index-BejQNqvC.mjs.map} +1 -1
  27. package/dist/internals/{index-BoP4kl2R.mjs → index-BibByOcU.mjs} +2 -2
  28. package/dist/internals/{index-BoP4kl2R.mjs.map → index-BibByOcU.mjs.map} +1 -1
  29. package/dist/internals/index-BqFdBhFc.js.map +1 -1
  30. package/dist/internals/index-CSNRyhjB.js.map +1 -1
  31. package/dist/internals/index-CVutVPmd.js.map +1 -1
  32. package/dist/internals/{index-BeV63sFw.d.ts → index-DaDfXlay.d.ts} +2 -2
  33. package/dist/internals/index-DaDfXlay.d.ts.map +1 -0
  34. package/dist/internals/index-Dz3jvqxZ.js.map +1 -1
  35. package/dist/internals/{index-YdOGTHp1.d.ts → index-RPh4TX0T.d.ts} +3 -2
  36. package/dist/internals/index-RPh4TX0T.d.ts.map +1 -0
  37. package/dist/internals/{index-BsuUdR0W.d.ts → index-bCACA0cS.d.ts} +2 -2
  38. package/dist/internals/index-bCACA0cS.d.ts.map +1 -0
  39. package/dist/internals/index-be1VYBY2.mjs.map +1 -1
  40. package/dist/internals/{random-w8WDYQEe.mjs → random-B1P0EZO5.mjs} +5 -10
  41. package/dist/internals/random-B1P0EZO5.mjs.map +1 -0
  42. package/dist/internals/{random-uT4D0y_q.js → random-q0PeamQE.js} +3 -8
  43. package/dist/internals/random-q0PeamQE.js.map +1 -0
  44. package/package.json +20 -20
  45. package/dist/internals/index-BeV63sFw.d.ts.map +0 -1
  46. package/dist/internals/index-BsuUdR0W.d.ts.map +0 -1
  47. package/dist/internals/index-YdOGTHp1.d.ts.map +0 -1
  48. package/dist/internals/random-uT4D0y_q.js.map +0 -1
  49. package/dist/internals/random-w8WDYQEe.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-CSNRyhjB.js');
13
13
  require('@o2ter/crypto-js');
14
- var random$1 = require('../../internals/random-uT4D0y_q.js');
14
+ var random$1 = require('../../internals/random-q0PeamQE.js');
15
15
  var _private = require('../../internals/private-CSB1Ep4g.js');
16
16
 
17
17
  //
@@ -224,12 +224,14 @@ class QueryCompiler {
224
224
  dialect;
225
225
  selectLock;
226
226
  isUpdate;
227
+ extraFilter;
227
228
  idx = 0;
228
- constructor(schema, dialect, selectLock, isUpdate) {
229
- this.schema = schema;
230
- this.dialect = dialect;
231
- this.selectLock = selectLock;
232
- this.isUpdate = isUpdate;
229
+ constructor(options) {
230
+ this.schema = options.schema;
231
+ this.dialect = options.dialect;
232
+ this.selectLock = options.selectLock;
233
+ this.isUpdate = options.isUpdate;
234
+ this.extraFilter = options.extraFilter;
233
235
  }
234
236
  nextIdx() {
235
237
  return this.idx++;
@@ -286,11 +288,11 @@ class QueryCompiler {
286
288
  }
287
289
  _baseSelectQuery(query, options) {
288
290
  const context = this._makeContext(query);
289
- const _stages = _.mapValues(context.populates, (populate) => this.dialect.encodePopulate(this, context, populate));
291
+ const _stages = _.mapValues(context.populates, (populate) => this.dialect.encodePopulate(this, populate));
290
292
  const stages = _.fromPairs(_.flatMap(_.values(_stages), (p) => _.toPairs(p)));
291
293
  const fetchName = `_fetch_$${query.className.toLowerCase()}`;
292
294
  const parent = { className: query.className, name: fetchName };
293
- const baseFilter = this._encodeFilter(context, parent, query.filter);
295
+ const baseFilter = this._encodeFilter(parent, query.filter);
294
296
  const populates = this._selectPopulateMap(context, query.className, fetchName);
295
297
  const joins = _.compact(_.map(populates, ({ join }) => join));
296
298
  const includes = {
@@ -304,7 +306,7 @@ class QueryCompiler {
304
306
  const filter = _.compact([
305
307
  baseFilter,
306
308
  _options?.extraFilter,
307
- query.relatedBy && this.dialect.encodeRelation(this, context, parent, query.relatedBy),
309
+ query.relatedBy && this.dialect.encodeRelation(this, parent, query.relatedBy),
308
310
  ]);
309
311
  return {
310
312
  stages,
@@ -325,9 +327,9 @@ class QueryCompiler {
325
327
  `,
326
328
  };
327
329
  }
328
- _refetch(name, query, context) {
330
+ _refetch(name, query) {
329
331
  const _context = this._encodeIncludes(query.className, query.includes, query.matches);
330
- const populates = _.mapValues(_context.populates, (populate) => this.dialect.encodePopulate(this, context, populate, { className: query.className, name }));
332
+ const populates = _.mapValues(_context.populates, (populate) => this.dialect.encodePopulate(this, populate, { className: query.className, name }));
331
333
  const stages = _.fromPairs(_.flatMap(_.values(populates), (p) => _.toPairs(p)));
332
334
  const _populates = this._selectPopulateMap(_context, query.className, name);
333
335
  const _joins = _.compact(_.map(_populates, ({ join }) => join));
@@ -398,8 +400,8 @@ class QueryCompiler {
398
400
  }
399
401
  return result;
400
402
  }
401
- _encodeCoditionalSelector(parent, filter, context) {
402
- const queries = _.compact(_.map(filter.exprs, x => this._encodeFilter(context, parent, x)));
403
+ _encodeCoditionalSelector(parent, filter) {
404
+ const queries = _.compact(_.map(filter.exprs, x => this._encodeFilter(parent, x)));
403
405
  if (_.isEmpty(queries))
404
406
  return;
405
407
  switch (filter.type) {
@@ -408,12 +410,12 @@ class QueryCompiler {
408
410
  case '$or': return sql `(${{ literal: _.map(queries, x => sql `(${x})`), separator: ' OR ' }})`;
409
411
  }
410
412
  }
411
- _encodeFilter(context, parent, filter) {
413
+ _encodeFilter(parent, filter) {
412
414
  if (filter instanceof index$1.QueryCoditionalSelector) {
413
- return this._encodeCoditionalSelector(parent, filter, context);
415
+ return this._encodeCoditionalSelector(parent, filter);
414
416
  }
415
417
  if (filter instanceof index$1.QueryFieldSelector) {
416
- return this.dialect.encodeFieldExpression(this, context, parent, filter.field, filter.expr);
418
+ return this.dialect.encodeFieldExpression(this, parent, filter.field, filter.expr);
417
419
  }
418
420
  if (filter instanceof index$1.QueryExpressionSelector) {
419
421
  return this.dialect.encodeQueryExpression(this, parent, filter.expr);
@@ -454,7 +456,7 @@ class QueryCompiler {
454
456
  });
455
457
  const name = `_insert_$${options.className.toLowerCase()}`;
456
458
  const context = this._makeContext(options);
457
- const populates = _.mapValues(context.populates, (populate) => this.dialect.encodePopulate(this, context, populate));
459
+ const populates = _.mapValues(context.populates, (populate) => this.dialect.encodePopulate(this, populate));
458
460
  const stages = _.fromPairs(_.flatMap(_.values(populates), (p) => _.toPairs(p)));
459
461
  const _populates = this._selectPopulateMap(context, options.className, name);
460
462
  const joins = _.compact(_.map(_populates, ({ join }) => join));
@@ -489,7 +491,7 @@ class QueryCompiler {
489
491
  `;
490
492
  }
491
493
  updateOne(query, update) {
492
- return this._modifyQuery({ ...query, limit: 1 }, (fetchName, context) => {
494
+ return this._modifyQuery({ ...query, limit: 1 }, (fetchName) => {
493
495
  const name = `_update_$${query.className.toLowerCase()}`;
494
496
  return sql `
495
497
  , ${{ identifier: name }} AS (
@@ -499,7 +501,7 @@ class QueryCompiler {
499
501
  WHERE ${{ identifier: query.className }}._id IN (SELECT ${{ identifier: fetchName }}._id FROM ${{ identifier: fetchName }})
500
502
  RETURNING *
501
503
  )
502
- ${this._refetch(name, query, context)}
504
+ ${this._refetch(name, query)}
503
505
  `;
504
506
  });
505
507
  }
@@ -508,7 +510,7 @@ class QueryCompiler {
508
510
  ..._defaultInsertOpts(query),
509
511
  ...this._encodeObjectAttrs(query.className, setOnInsert),
510
512
  });
511
- return this._modifyQuery({ ...query, limit: 1 }, (fetchName, context) => {
513
+ return this._modifyQuery({ ...query, limit: 1 }, (fetchName) => {
512
514
  const updateName = `_update_$${query.className.toLowerCase()}`;
513
515
  const insertName = `_insert_$${query.className.toLowerCase()}`;
514
516
  const upsertName = `_upsert_$${query.className.toLowerCase()}`;
@@ -532,7 +534,7 @@ class QueryCompiler {
532
534
  UNION
533
535
  SELECT * FROM ${{ identifier: insertName }}
534
536
  )
535
- ${this._refetch(upsertName, query, context)}
537
+ ${this._refetch(upsertName, query)}
536
538
  `;
537
539
  });
538
540
  }
@@ -667,12 +669,21 @@ class SqlStorage {
667
669
  }
668
670
  return obj;
669
671
  }
672
+ _makeCompiler(isUpdate, extraFilter) {
673
+ return new QueryCompiler({
674
+ schema: this.schema,
675
+ dialect: this.dialect,
676
+ selectLock: this.selectLock(),
677
+ isUpdate,
678
+ extraFilter,
679
+ });
680
+ }
670
681
  async explain(query) {
671
- const compiler = new QueryCompiler(this.schema, this.dialect, this.selectLock(), false);
682
+ const compiler = this._makeCompiler(false, query.extraFilter);
672
683
  return this._explain(compiler, query);
673
684
  }
674
685
  async count(query) {
675
- const compiler = new QueryCompiler(this.schema, this.dialect, this.selectLock(), false);
686
+ const compiler = this._makeCompiler(false, query.extraFilter);
676
687
  const [{ count: _count }] = await this.query(compiler._selectQuery(query, {
677
688
  select: sql `COUNT(*) AS count`,
678
689
  }));
@@ -681,7 +692,7 @@ class SqlStorage {
681
692
  }
682
693
  find(query) {
683
694
  const self = this;
684
- const compiler = new QueryCompiler(self.schema, self.dialect, self.selectLock(), false);
695
+ const compiler = self._makeCompiler(false, query.extraFilter);
685
696
  const _query = compiler._selectQuery(query);
686
697
  return (async function* () {
687
698
  const objects = self.query(_query);
@@ -692,7 +703,7 @@ class SqlStorage {
692
703
  }
693
704
  random(query, opts) {
694
705
  const self = this;
695
- const compiler = new QueryCompiler(self.schema, self.dialect, self.selectLock(), false);
706
+ const compiler = self._makeCompiler(false, query.extraFilter);
696
707
  const _query = compiler._selectQuery({ ...query, sort: {} }, {
697
708
  sort: sql `ORDER BY ${self.dialect.random(opts ?? {})}`,
698
709
  });
@@ -719,7 +730,7 @@ class SqlStorage {
719
730
  }
720
731
  nonrefs(query) {
721
732
  const self = this;
722
- const compiler = new QueryCompiler(self.schema, self.dialect, self.selectLock(), false);
733
+ const compiler = self._makeCompiler(false, query.extraFilter);
723
734
  const _query = compiler._selectQuery(query, ({ fetchName }) => ({
724
735
  extraFilter: sql `
725
736
  NOT EXISTS (${this._refs(this.schema, query.className, ['_id'], sql `(${{ quote: query.className + '$' }} || ${{ identifier: fetchName }}.${{ identifier: '_id' }})`)})
@@ -733,32 +744,32 @@ class SqlStorage {
733
744
  })();
734
745
  }
735
746
  async insert(options, attrs) {
736
- const compiler = new QueryCompiler(this.schema, this.dialect, this.selectLock(), true);
747
+ const compiler = this._makeCompiler(true);
737
748
  const result = _.first(await this.query(compiler.insert(options, attrs)));
738
749
  return _.isNil(result) ? undefined : this._decodeObject(options.className, result);
739
750
  }
740
751
  async insertMany(options, values) {
741
- const compiler = new QueryCompiler(this.schema, this.dialect, this.selectLock(), true);
752
+ const compiler = this._makeCompiler(true);
742
753
  const result = await this.query(compiler.insertMany(options, values));
743
754
  return result.length;
744
755
  }
745
756
  async updateOne(query, update) {
746
- const compiler = new QueryCompiler(this.schema, this.dialect, this.selectLock(), true);
757
+ const compiler = this._makeCompiler(true, query.extraFilter);
747
758
  const updated = _.first(await this.query(compiler.updateOne(query, update)));
748
759
  return _.isNil(updated) ? undefined : this._decodeObject(query.className, updated);
749
760
  }
750
761
  async upsertOne(query, update, setOnInsert) {
751
- const compiler = new QueryCompiler(this.schema, this.dialect, this.selectLock(), true);
762
+ const compiler = this._makeCompiler(true, query.extraFilter);
752
763
  const upserted = _.first(await this.query(compiler.upsertOne(query, update, setOnInsert)));
753
764
  return _.isNil(upserted) ? undefined : this._decodeObject(query.className, upserted);
754
765
  }
755
766
  async deleteOne(query) {
756
- const compiler = new QueryCompiler(this.schema, this.dialect, this.selectLock(), true);
767
+ const compiler = this._makeCompiler(true, query.extraFilter);
757
768
  const deleted = _.first(await this.query(compiler.deleteOne(query)));
758
769
  return _.isNil(deleted) ? undefined : this._decodeObject(query.className, deleted);
759
770
  }
760
771
  async deleteMany(query) {
761
- const compiler = new QueryCompiler(this.schema, this.dialect, this.selectLock(), true);
772
+ const compiler = this._makeCompiler(true, query.extraFilter);
762
773
  const deleted = await this.query(compiler.deleteMany(query));
763
774
  return deleted.length;
764
775
  }
@@ -1114,10 +1125,55 @@ class PostgresClientDriver {
1114
1125
  });
1115
1126
  }
1116
1127
  }
1128
+ class PostgresPubSub {
1129
+ client;
1130
+ subscribers = {};
1131
+ channels = [];
1132
+ constructor(client) {
1133
+ this.client = client;
1134
+ (async () => {
1135
+ try {
1136
+ (await client).on('notification', ({ channel, payload }) => {
1137
+ if (!payload)
1138
+ return;
1139
+ try {
1140
+ const _payload = index._decodeValue(JSON.parse(payload));
1141
+ for (const subscriber of this.subscribers[_.toUpper(channel)]) {
1142
+ subscriber(_payload);
1143
+ }
1144
+ }
1145
+ catch (e) {
1146
+ console.error(`Unknown payload: ${e}`);
1147
+ }
1148
+ });
1149
+ }
1150
+ catch (e) {
1151
+ console.error(e);
1152
+ }
1153
+ })();
1154
+ }
1155
+ async shutdown() {
1156
+ (await this.client).release();
1157
+ }
1158
+ async listen(channel) {
1159
+ this.channels.push(channel);
1160
+ await (await this.client).query(`LISTEN ${channel}`);
1161
+ }
1162
+ subscribe(channel, callback) {
1163
+ if (_.isNil(this.subscribers[channel]))
1164
+ this.subscribers[channel] = [];
1165
+ this.subscribers[channel].push(callback);
1166
+ return () => {
1167
+ this.subscribers[channel] = this.subscribers[channel].filter(x => x !== callback);
1168
+ };
1169
+ }
1170
+ isEmpty() {
1171
+ return _.every(_.values(this.subscribers), x => _.isEmpty(x));
1172
+ }
1173
+ }
1117
1174
  class PostgresDriver extends PostgresClientDriver {
1118
1175
  database;
1119
1176
  pubsub;
1120
- subscribers = [];
1121
1177
  constructor(config) {
1122
1178
  if (_.isEmpty(config))
1123
1179
  throw Error('Invalid postgre config.');
@@ -1130,26 +1186,11 @@ class PostgresDriver extends PostgresClientDriver {
1130
1186
  await this._release_pubsub();
1131
1187
  await this.database.end();
1132
1188
  }
1133
- async _init_pubsub() {
1189
+ _init_pubsub() {
1134
1190
  if (this.pubsub)
1135
1191
  return;
1136
1192
  try {
1137
- this.pubsub = this.database.connect();
1138
- const pubsub = await this.pubsub;
1139
- pubsub.on('notification', ({ channel, payload }) => {
1140
- if (_.toUpper(channel) !== PROTO_POSTGRES_MSG || !payload)
1141
- return;
1142
- try {
1143
- const _payload = index._decodeValue(JSON.parse(payload));
1144
- for (const subscriber of this.subscribers) {
1145
- subscriber(_payload);
1146
- }
1147
- }
1148
- catch (e) {
1149
- console.error(`Unknown payload: ${e}`);
1150
- }
1151
- });
1152
- await pubsub.query(`LISTEN ${PROTO_POSTGRES_MSG}`);
1193
+ this.pubsub = new PostgresPubSub(this.database.connect());
1153
1194
  }
1154
1195
  catch (e) {
1155
1196
  console.error(e);
@@ -1158,18 +1199,22 @@ class PostgresDriver extends PostgresClientDriver {
1158
1199
  async _release_pubsub() {
1159
1200
  const pubsub = this.pubsub;
1160
1201
  this.pubsub = undefined;
1161
- await (await pubsub)?.release();
1202
+ await pubsub?.shutdown();
1162
1203
  }
1163
- subscribe(callback) {
1204
+ _subscribe(channel, callback) {
1164
1205
  this._init_pubsub();
1165
- this.subscribers.push(callback);
1206
+ if (!_.includes(this.pubsub.channels, channel))
1207
+ this.pubsub.listen(channel);
1208
+ const release = this.pubsub.subscribe(channel, callback);
1166
1209
  return () => {
1167
- this.subscribers = this.subscribers.filter(x => x !== callback);
1168
- if (_.isEmpty(this.subscribers)) {
1210
+ release();
1211
+ if (this.pubsub?.isEmpty())
1169
1212
  this._release_pubsub();
1170
- }
1171
1213
  };
1172
1214
  }
1215
+ subscribe(callback) {
1216
+ return this._subscribe(PROTO_POSTGRES_MSG, callback);
1217
+ }
1173
1218
  }
1174
1219
 
1175
1220
  //
@@ -1857,7 +1902,7 @@ const encodeQueryExpression = (compiler, parent, expr) => {
1857
1902
  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1858
1903
  // THE SOFTWARE.
1859
1904
  //
1860
- const encodeFieldExpression = (compiler, context, parent, field, expr) => {
1905
+ const encodeFieldExpression = (compiler, parent, field, expr) => {
1861
1906
  const [colname] = _.toPath(field);
1862
1907
  const { element, dataType, relation } = fetchElement(compiler, parent, field);
1863
1908
  const encodeValue = (value) => dataType ? encodeType(colname, dataType, value) : _encodeJsonValue(index._encodeValue(value));
@@ -2086,7 +2131,7 @@ const encodeFieldExpression = (compiler, context, parent, field, expr) => {
2086
2131
  {
2087
2132
  if (!(expr.value instanceof index$1.FieldSelectorExpression))
2088
2133
  break;
2089
- return sql `NOT (${encodeFieldExpression(compiler, context, parent, field, expr.value)})`;
2134
+ return sql `NOT (${encodeFieldExpression(compiler, parent, field, expr.value)})`;
2090
2135
  }
2091
2136
  case '$pattern':
2092
2137
  {
@@ -2178,7 +2223,7 @@ const encodeFieldExpression = (compiler, context, parent, field, expr) => {
2178
2223
  if (!(expr.value instanceof index$1.QuerySelector))
2179
2224
  break;
2180
2225
  const tempName = `_expr_$${compiler.nextIdx()}`;
2181
- const filter = compiler._encodeFilter(context, { name: tempName, className: relation?.target }, expr.value);
2226
+ const filter = compiler._encodeFilter({ name: tempName, className: relation?.target }, expr.value);
2182
2227
  if (!filter)
2183
2228
  break;
2184
2229
  if (relation) {
@@ -2205,7 +2250,7 @@ const encodeFieldExpression = (compiler, context, parent, field, expr) => {
2205
2250
  if (!(expr.value instanceof index$1.QuerySelector))
2206
2251
  break;
2207
2252
  const tempName = `_expr_$${compiler.nextIdx()}`;
2208
- const filter = compiler._encodeFilter(context, { name: tempName, className: relation?.target }, expr.value);
2253
+ const filter = compiler._encodeFilter({ name: tempName, className: relation?.target }, expr.value);
2209
2254
  if (!filter)
2210
2255
  break;
2211
2256
  if (relation) {
@@ -2299,31 +2344,36 @@ const selectPopulate = (compiler, parent, populate, field) => {
2299
2344
  const _local = (field) => sql `${{ identifier: parent.name }}.${{ identifier: field }}`;
2300
2345
  const _foreign = (field) => sql `${{ identifier: populate.name }}.${{ identifier: field }}`;
2301
2346
  const subpaths = resolveSubpaths(compiler, populate);
2347
+ const cond = [];
2348
+ if (compiler.extraFilter) {
2349
+ const filter = compiler.extraFilter(populate.className);
2350
+ cond.push(compiler._encodeFilter(populate, filter));
2351
+ }
2302
2352
  if (populate.type === 'pointer') {
2353
+ cond.push(sql `${sql `(${{ quote: populate.className + '$' }} || ${_foreign('_id')})`} = ${_local(field)}`);
2303
2354
  return {
2304
2355
  columns: _.map(subpaths, ({ path }) => sql `${{ identifier: populate.name }}.${{ identifier: path }} AS ${{ identifier: `${field}.${path}` }}`),
2305
2356
  join: sql `
2306
2357
  LEFT JOIN ${{ identifier: populate.name }}
2307
- ON ${sql `(${{ quote: populate.className + '$' }} || ${_foreign('_id')})`} = ${_local(field)}
2358
+ ON ${{ literal: _.map(_.compact(cond), x => sql `(${x})`), separator: ' AND ' }}
2308
2359
  `,
2309
2360
  };
2310
2361
  }
2311
- let cond;
2312
2362
  if (_.isNil(populate.foreignField)) {
2313
- cond = sql `${sql `(${{ quote: populate.className + '$' }} || ${_foreign('_id')})`} = ANY(${_local(field)})`;
2363
+ cond.push(sql `${sql `(${{ quote: populate.className + '$' }} || ${_foreign('_id')})`} = ANY(${_local(field)})`);
2314
2364
  }
2315
2365
  else if (_isPointer(compiler.schema, populate.className, populate.foreignField)) {
2316
- cond = sql `${sql `(${{ quote: parent.className + '$' }} || ${_local('_id')})`} = ${_foreign(populate.colname)}`;
2366
+ cond.push(sql `${sql `(${{ quote: parent.className + '$' }} || ${_local('_id')})`} = ${_foreign(populate.colname)}`);
2317
2367
  }
2318
2368
  else {
2319
- cond = sql `${sql `(${{ quote: parent.className + '$' }} || ${_local('_id')})`} = ANY(${_foreign(populate.colname)})`;
2369
+ cond.push(sql `${sql `(${{ quote: parent.className + '$' }} || ${_local('_id')})`} = ANY(${_foreign(populate.colname)})`);
2320
2370
  }
2321
2371
  return {
2322
2372
  columns: [sql `
2323
2373
  ARRAY(
2324
2374
  SELECT to_jsonb(${{ identifier: populate.name }}) FROM (
2325
2375
  SELECT ${_.map(subpaths, ({ path, type }) => _encodePopulateInclude(populate.name, path, type))}
2326
- FROM ${{ identifier: populate.name }} WHERE ${cond}
2376
+ FROM ${{ identifier: populate.name }} WHERE ${{ literal: _.map(_.compact(cond), x => sql `(${x})`), separator: ' AND ' }}
2327
2377
  ${!_.isEmpty(populate.sort) ? sql `ORDER BY ${compiler._encodeSort(populate.sort, { className: populate.className, name: populate.name })}` : sql ``}
2328
2378
  ${populate.limit ? sql `LIMIT ${{ literal: `${populate.limit}` }}` : sql ``}
2329
2379
  ${populate.skip ? sql `OFFSET ${{ literal: `${populate.skip}` }}` : sql ``}
@@ -2336,13 +2386,13 @@ const selectPopulate = (compiler, parent, populate, field) => {
2336
2386
  const encodeRemix = (parent, remix) => sql `${remix?.className === parent.className ? sql `
2337
2387
  (SELECT * FROM ${{ identifier: remix.name }} UNION SELECT * FROM ${{ identifier: parent.className }})
2338
2388
  ` : { identifier: parent.className }}`;
2339
- const encodeForeignField = (compiler, context, parent, foreignField, remix) => {
2389
+ const encodeForeignField = (compiler, parent, foreignField, remix) => {
2340
2390
  const { paths: [colname, ...subpath], dataType } = random$1.resolveColumn(compiler.schema, parent.className, foreignField);
2341
2391
  const tempName = `_populate_$${compiler.nextIdx()}`;
2342
2392
  const _local = (field) => sql `${{ identifier: parent.name }}.${{ identifier: field }}`;
2343
2393
  const _foreign = (field) => sql `${{ identifier: tempName }}.${{ identifier: field }}`;
2344
2394
  if (_.isEmpty(subpath) && index.isRelation(dataType) && dataType.foreignField) {
2345
- const { joins, field, rows, array } = encodeForeignField(compiler, context, { className: dataType.target, name: tempName }, dataType.foreignField, remix);
2395
+ const { joins, field, rows, array } = encodeForeignField(compiler, { className: dataType.target, name: tempName }, dataType.foreignField, remix);
2346
2396
  return {
2347
2397
  joins: [],
2348
2398
  field: sql `(
@@ -2365,27 +2415,32 @@ const encodeForeignField = (compiler, context, parent, foreignField, remix) => {
2365
2415
  }
2366
2416
  if (!index.isPointer(dataType) && !index.isRelation(dataType))
2367
2417
  throw Error(`Invalid path: ${foreignField}`);
2368
- const { joins, field, rows, array } = encodeForeignField(compiler, context, { className: dataType.target, name: tempName }, subpath.join('.'), remix);
2418
+ const { joins, field, rows, array } = encodeForeignField(compiler, { className: dataType.target, name: tempName }, subpath.join('.'), remix);
2419
+ const cond = [];
2420
+ if (compiler.extraFilter) {
2421
+ const filter = compiler.extraFilter(dataType.target);
2422
+ cond.push(compiler._encodeFilter({ className: dataType.target, name: tempName }, filter));
2423
+ }
2369
2424
  if (index.isPointer(dataType)) {
2425
+ cond.push(sql `${sql `(${{ quote: dataType.target + '$' }} || ${_foreign('_id')})`} = ${_local(colname)}`);
2370
2426
  return {
2371
2427
  joins: [sql `
2372
2428
  LEFT JOIN ${encodeRemix({ className: dataType.target }, remix)} AS ${{ identifier: tempName }}
2373
- ON ${sql `(${{ quote: dataType.target + '$' }} || ${_foreign('_id')})`} = ${_local(colname)}
2429
+ ON ${{ literal: _.map(_.compact(cond), x => sql `(${x})`), separator: ' AND ' }}
2374
2430
  `, ...joins],
2375
2431
  field,
2376
2432
  array,
2377
2433
  rows,
2378
2434
  };
2379
2435
  }
2380
- let cond;
2381
2436
  if (_.isNil(dataType.foreignField)) {
2382
- cond = sql `${sql `(${{ quote: dataType.target + '$' }} || ${_foreign('_id')})`} = ANY(${_local(colname)})`;
2437
+ cond.push(sql `${sql `(${{ quote: dataType.target + '$' }} || ${_foreign('_id')})`} = ANY(${_local(colname)})`);
2383
2438
  }
2384
2439
  else if (_isPointer(compiler.schema, dataType.target, dataType.foreignField)) {
2385
- cond = sql `${sql `(${{ quote: parent.className + '$' }} || ${_local('_id')})`} = ${_foreign(dataType.foreignField)}`;
2440
+ cond.push(sql `${sql `(${{ quote: parent.className + '$' }} || ${_local('_id')})`} = ${_foreign(dataType.foreignField)}`);
2386
2441
  }
2387
2442
  else {
2388
- cond = sql `${sql `(${{ quote: parent.className + '$' }} || ${_local('_id')})`} = ANY(${_foreign(dataType.foreignField)})`;
2443
+ cond.push(sql `${sql `(${{ quote: parent.className + '$' }} || ${_local('_id')})`} = ANY(${_foreign(dataType.foreignField)})`);
2389
2444
  }
2390
2445
  return {
2391
2446
  joins: [],
@@ -2393,23 +2448,23 @@ const encodeForeignField = (compiler, context, parent, foreignField, remix) => {
2393
2448
  SELECT ${array ? sql `UNNEST(${field})` : field}
2394
2449
  FROM ${encodeRemix({ className: dataType.target }, remix)} AS ${{ identifier: tempName }}
2395
2450
  ${!_.isEmpty(joins) ? { literal: joins, separator: '\n' } : sql ``}
2396
- WHERE ${cond}
2451
+ WHERE ${{ literal: _.map(_.compact(cond), x => sql `(${x})`), separator: ' AND ' }}
2397
2452
  )`,
2398
2453
  array: false,
2399
2454
  rows: true,
2400
2455
  };
2401
2456
  };
2402
- const encodePopulate = (compiler, context, parent, remix) => {
2403
- const _filter = compiler._encodeFilter(context, parent, parent.filter);
2457
+ const encodePopulate = (compiler, parent, remix) => {
2458
+ const _filter = parent.filter && compiler._encodeFilter(parent, parent.filter);
2404
2459
  const _populates = _.map(parent.populates, (populate, field) => selectPopulate(compiler, parent, populate, field));
2405
2460
  const _joins = _.compact(_.map(_populates, ({ join }) => join));
2406
2461
  const _includes = _.pickBy(parent.includes, v => index.isPrimitive(v));
2407
- const { joins: _joins2 = [], field: _foreignField = undefined, rows = false, } = parent.foreignField ? encodeForeignField(compiler, context, {
2462
+ const { joins: _joins2 = [], field: _foreignField = undefined, rows = false, } = parent.foreignField ? encodeForeignField(compiler, {
2408
2463
  className: parent.className,
2409
2464
  name: parent.name,
2410
2465
  }, parent.foreignField, remix) : {};
2411
2466
  return _.reduce(parent.populates, (acc, populate) => ({
2412
- ...encodePopulate(compiler, context, populate, remix),
2467
+ ...encodePopulate(compiler, populate, remix),
2413
2468
  ...acc,
2414
2469
  }), {
2415
2470
  [parent.name]: sql `
@@ -2454,11 +2509,11 @@ const encodePopulate = (compiler, context, parent, remix) => {
2454
2509
  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2455
2510
  // THE SOFTWARE.
2456
2511
  //
2457
- const encodeRelation = (compiler, context, parent, relatedBy) => {
2512
+ const encodeRelation = (compiler, parent, relatedBy) => {
2458
2513
  const name = `_relation_$${relatedBy.className.toLowerCase()}`;
2459
2514
  const _local = (field) => sql `${{ identifier: parent.name }}.${{ identifier: field }}`;
2460
2515
  const _foreign = (field) => sql `${{ identifier: name }}.${{ identifier: field }}`;
2461
- const { joins, field } = encodeForeignField(compiler, context, { className: relatedBy.className, name }, relatedBy.key);
2516
+ const { joins, field } = encodeForeignField(compiler, { className: relatedBy.className, name }, relatedBy.key);
2462
2517
  return sql `EXISTS (
2463
2518
  SELECT 1
2464
2519
  FROM ${{ identifier: relatedBy.className }} AS ${{ identifier: name }}