@omegup/msync 0.0.48 → 0.0.49

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.
package/index.d.ts CHANGED
@@ -645,6 +645,7 @@ type MongoTypes = {
645
645
  };
646
646
  type MongoTypeNames = keyof MongoTypes;
647
647
  declare const $type: <T extends keyof MongoTypes>(operand: rawItem & readonly T[]) => Predicate<N | MongoTypes[T]>;
648
+ declare const $exists: <T extends keyof MongoTypes>(operand: rawItem & boolean) => Predicate<unknown>;
648
649
 
649
650
  declare const $expr: <D extends O, C>(expr: Expr<boolean, D, C>) => Query<D, C>;
650
651
 
@@ -675,4 +676,4 @@ declare const enablePreAndPostImages: <T extends doc>(coll: Collection<T>) => Pr
675
676
  declare const prepare: (testName?: string) => Promise<MongoClient$1>;
676
677
  declare const makeCol: <T extends ID>(docs: readonly OptionalUnlessRequiredId<T>[], database: Db, name?: string) => Promise<Collection<T>>;
677
678
 
678
- export { $accumulator, $and, $countDict, $entries, $eq, $expr, $getField, $group, $groupId, $groupMerge, $gt, $gtTs, $gte, $gteTs, $ifNull, $in, $insert, $insertX, $keys, $let, $lookup, $lt, $lte, $map, $map1, $match, $matchDelta, $merge, $merge_, $ne, $nin, $nor, $or, $outerLookup, $pushDict, $rand, $replaceWith, $set, $simpleInsert, $simpleMerge, $sum, $type, $unwind, $unwindDelta, type Accumulators, type Arr, type AsLiteral, type Delta, type DeltaAccumulator, type DeltaAccumulators, Expr, type ExprHKT, type Exprs, type ExprsExact, type ExprsExactHKT, type ExprsPart, Field, type ID, type Loose, Machine, type Merge, type MergeArgs, type MergeInto, type MergeMapOArgs, type Model, type MongoTypeNames, type N, type NoRaw, type NullToOBJ, type O, type OPick, type OPickD, type RONoRaw, type RORec, type RawStages, type Rec, type Replace, type SnapshotStreamExecutionResult, type StrKey, type Strict, type TS, Type, type WriteonlyCollection, add, and, array, ceil, comp, concat, concatArray, createIndex, ctx, current, dateAdd, dateDiff, dateLt, datePart, dayAndMonthPart, divide, type doc, enablePreAndPostImages, eq, eqTyped, except, exprMapVal, field, fieldF, fieldM, filter, filterDefined, first, firstSure, floor, from, func, gt, gte, inArray, isArray, ite, last, log, lt, lte, makeCol, map1, mapVal, max, maxDate, mergeExact, mergeExact0, mergeExpr, mergeObjects, minDate, monthPart, multiply, ne, nil, noop, type notArr, notNull, now, or, pair, prepare, rand, range, root, set, setField, size, slice, sortArray, staging, startOf, str, sub, subtract, to, toInt, val, weekPart, wrap, year };
679
+ export { $accumulator, $and, $countDict, $entries, $eq, $exists, $expr, $getField, $group, $groupId, $groupMerge, $gt, $gtTs, $gte, $gteTs, $ifNull, $in, $insert, $insertX, $keys, $let, $lookup, $lt, $lte, $map, $map1, $match, $matchDelta, $merge, $merge_, $ne, $nin, $nor, $or, $outerLookup, $pushDict, $rand, $replaceWith, $set, $simpleInsert, $simpleMerge, $sum, $type, $unwind, $unwindDelta, type Accumulators, type Arr, type AsLiteral, type Delta, type DeltaAccumulator, type DeltaAccumulators, Expr, type ExprHKT, type Exprs, type ExprsExact, type ExprsExactHKT, type ExprsPart, Field, type ID, type Loose, Machine, type Merge, type MergeArgs, type MergeInto, type MergeMapOArgs, type Model, type MongoTypeNames, type N, type NoRaw, type NullToOBJ, type O, type OPick, type OPickD, type RONoRaw, type RORec, type RawStages, type Rec, type Replace, type SnapshotStreamExecutionResult, type StrKey, type Strict, type TS, Type, type WriteonlyCollection, add, and, array, ceil, comp, concat, concatArray, createIndex, ctx, current, dateAdd, dateDiff, dateLt, datePart, dayAndMonthPart, divide, type doc, enablePreAndPostImages, eq, eqTyped, except, exprMapVal, field, fieldF, fieldM, filter, filterDefined, first, firstSure, floor, from, func, gt, gte, inArray, isArray, ite, last, log, lt, lte, makeCol, map1, mapVal, max, maxDate, mergeExact, mergeExact0, mergeExpr, mergeObjects, minDate, monthPart, multiply, ne, nil, noop, type notArr, notNull, now, or, pair, prepare, rand, range, root, set, setField, size, slice, sortArray, staging, startOf, str, sub, subtract, to, toInt, val, weekPart, wrap, year };
package/index.esm.js CHANGED
@@ -1,7 +1,6 @@
1
1
  import { UUID, MongoClient } from 'mongodb';
2
2
  import { SynchronousPromise } from 'synchronous-promise';
3
3
  import crypto$1 from 'crypto';
4
- import { log as log$1 } from 'console';
5
4
  import { writeFile } from 'fs/promises';
6
5
 
7
6
  const asExprRaw = (raw) => ({ get: () => raw });
@@ -900,6 +899,7 @@ const dateLt = comp('$lt');
900
899
  const $gte = comp('$gte');
901
900
  const $lte = comp('$lte');
902
901
  const $type = operator()('$type');
902
+ const $exists = operator()('$exists');
903
903
 
904
904
  const $expr = (expr) => ({
905
905
  raw: f => ({ $expr: expr.raw(f).get() }),
@@ -1382,16 +1382,16 @@ const replace = (s) => s.replace(/\{"\$timestamp":"(\d+)"\}/g, (_, d) => T(d));
1382
1382
  const json = (a) => replace(JSON.stringify(a));
1383
1383
  const log = (...args) => console.log(new Date(), ...args.map(a => (typeof a === 'function' ? a(replace) : a && typeof a === 'object' ? json(a) : a)));
1384
1384
 
1385
- const aggregate = (input, snapshot = true, start = Date.now()) => input(({ coll, input }) => {
1385
+ const aggregate = (streamName, input, snapshot = true, start = Date.now()) => input(({ coll, input }) => {
1386
1386
  const req = {
1387
1387
  aggregate: coll.collectionName,
1388
1388
  pipeline: input,
1389
1389
  cursor: {},
1390
1390
  ...(snapshot && { readConcern: { level: 'snapshot' } }),
1391
1391
  };
1392
- log('exec', req);
1392
+ log('exec', streamName, req);
1393
1393
  return coll.s.db.command(req).then(result => {
1394
- log('execed', req, result, 'took', Date.now() - start);
1394
+ log('execed', streamName, req, result, 'took', Date.now() - start);
1395
1395
  return result;
1396
1396
  }, err => {
1397
1397
  log('err', req, err);
@@ -1443,11 +1443,19 @@ const makeWatchStream = (db, { collection, projection: p, hardMatch: m }, startA
1443
1443
  },
1444
1444
  });
1445
1445
  pipeline.push({
1446
- $match: {
1447
- $or: [
1448
- { $expr: { $ne: ['$fullDocument', '$fullDocumentBeforeChange'] } },
1449
- Object.fromEntries(changeKeys.map(k => [k, null])),
1450
- ],
1446
+ $replaceWith: {
1447
+ ts: {
1448
+ $cond: {
1449
+ if: {
1450
+ $or: [
1451
+ { $ne: ['$fullDocument', '$fullDocumentBeforeChange'] },
1452
+ { $and: changeKeys.map(k => ({ $eq: [k, null] })) },
1453
+ ],
1454
+ },
1455
+ then: '$clusterTime',
1456
+ else: null,
1457
+ },
1458
+ },
1451
1459
  },
1452
1460
  });
1453
1461
  const stream = db.collection(collection.collectionName).watch(pipeline, {
@@ -1460,7 +1468,7 @@ const makeWatchStream = (db, { collection, projection: p, hardMatch: m }, startA
1460
1468
  if (doc)
1461
1469
  await new Promise(resolve => setTimeout(resolve, 100));
1462
1470
  if (doc)
1463
- log$1('detected', streamName, collection.collectionName, doc);
1471
+ log('detected', streamName, collection.collectionName, doc);
1464
1472
  return doc;
1465
1473
  };
1466
1474
  return { tryNext, close: () => stream.close() };
@@ -1483,12 +1491,7 @@ const executes$1 = (view, input, streamName) => {
1483
1491
  else if (streamNames[streamName] != hash)
1484
1492
  throw new Error(`streamName ${streamName} already used`);
1485
1493
  const { collection, projection, hardMatch: pre, match } = view;
1486
- const types = Array.from({ length: 19 }).map((_, i) => i + 1);
1487
- const removeNotYetSynchronizedFields = Object.values(mapExactToObject(projection, (_, k) => k.startsWith('_')
1488
- ? root()
1489
- .of(k)
1490
- .has($type(types.filter(x => x != 10)))
1491
- : null));
1494
+ const removeNotYetSynchronizedFields = Object.values(mapExactToObject(projection, (_, k) => k.startsWith('_') ? root().of(k).has($exists(true)) : null));
1492
1495
  const hardMatch = $and(pre, ...removeNotYetSynchronizedFields);
1493
1496
  const job = {};
1494
1497
  const db = collection.s.db, coll = collection.collectionName;
@@ -1591,7 +1594,7 @@ const executes$1 = (view, input, streamName) => {
1591
1594
  whenMatched: 'merge',
1592
1595
  whenNotMatched: 'insert',
1593
1596
  })).stages;
1594
- const r = await aggregate(c => c({ coll: collection, input: cloneIntoNew }));
1597
+ const r = await aggregate(streamName, c => c({ coll: collection, input: cloneIntoNew }));
1595
1598
  await snapshotCollection.deleteMany({ updated: true, after: null, before: null });
1596
1599
  return next(step4({ result: r, ts: lastTS?.ts }), 'run the aggregation');
1597
1600
  };
@@ -1599,7 +1602,7 @@ const executes$1 = (view, input, streamName) => {
1599
1602
  const step4 = ({ result, ts }) => async () => {
1600
1603
  const start = Date.now();
1601
1604
  await snapshotCollection.updateMany({ before: null }, { $set: { before: null } });
1602
- const aggResult = await aggregate(c => c({
1605
+ const aggResult = await aggregate(streamName, c => c({
1603
1606
  coll: snapshotCollection,
1604
1607
  input: link()
1605
1608
  .with($match_(root().of('updated').has($eq(true))))
@@ -1608,7 +1611,7 @@ const executes$1 = (view, input, streamName) => {
1608
1611
  .with(finalInput.raw(ts === undefined)).stages,
1609
1612
  }), false, start);
1610
1613
  const stream = makeStream(result.cursor.atClusterTime);
1611
- return next(step5({ result, aggResult, stream }), 'remove handled deleted updated', () => stream.close());
1614
+ return next(step5({ ts: result.cursor.atClusterTime, aggResult, stream }), 'remove handled deleted updated', () => stream.close());
1612
1615
  };
1613
1616
  const step5 = (l) => async () => {
1614
1617
  log(`remove handled deleted updated db['${snapshotCollection.collectionName}'].deleteMany({ updated: true, after: null })`);
@@ -1633,7 +1636,7 @@ const executes$1 = (view, input, streamName) => {
1633
1636
  const step7 = (l) => async () => {
1634
1637
  await last.updateOne({ _id: streamName }, {
1635
1638
  $set: {
1636
- ts: l.result.cursor.atClusterTime,
1639
+ ts: l.ts,
1637
1640
  data,
1638
1641
  },
1639
1642
  }, { upsert: true });
@@ -1642,11 +1645,15 @@ const executes$1 = (view, input, streamName) => {
1642
1645
  const step8 = (l) => {
1643
1646
  return nextData(l.aggResult.cursor.firstBatch)(() => l.stream
1644
1647
  .tryNext()
1645
- .catch(err => {
1648
+ .catch((err) => {
1646
1649
  log('restarting', err);
1647
- return 1;
1650
+ return { ts: null };
1648
1651
  })
1649
- .then(doc => (doc ? next(step2, 'restart') : step8(l))), 'wait for change');
1652
+ .then(doc => doc
1653
+ ? doc.ts
1654
+ ? next(step7({ ...l, ts: doc.ts }), 'nothing changed')
1655
+ : next(step2, 'restart')
1656
+ : step8(l)), 'wait for change');
1650
1657
  };
1651
1658
  return stop;
1652
1659
  };
@@ -1736,7 +1743,7 @@ const executes = (view, input, streamName) => {
1736
1743
  const makeStream = (startAt) => makeWatchStream(db, view, startAt, streamName);
1737
1744
  const step4 = (lastTS) => async () => {
1738
1745
  const hardQuery = $and(lastTS && root().of('touchedAt').has($gteTs(lastTS.ts)), hardMatch, notDeleted, match && $expr(match));
1739
- const aggResult = await aggregate(c => c({
1746
+ const aggResult = await aggregate(streamName, c => c({
1740
1747
  coll: collection,
1741
1748
  input: link()
1742
1749
  .with($match_(hardQuery))
@@ -1745,17 +1752,23 @@ const executes = (view, input, streamName) => {
1745
1752
  .with(finalInput.raw(lastTS === null)).stages,
1746
1753
  }));
1747
1754
  const stream = makeStream(aggResult.cursor.atClusterTime);
1748
- return next(step7({ aggResult, result: aggResult, stream }), 'update __last', () => stream.close());
1755
+ return next(step7({ aggResult, ts: aggResult.cursor.atClusterTime, stream }), 'update __last', () => stream.close());
1749
1756
  };
1750
1757
  const step7 = (l) => async () => {
1751
- await last.updateOne({ _id: streamName }, { $set: { ts: l.result.cursor.atClusterTime, data } }, { upsert: true });
1758
+ await last.updateOne({ _id: streamName }, { $set: { ts: l.ts, data } }, { upsert: true });
1752
1759
  return step8(l);
1753
1760
  };
1754
1761
  const step8 = (l) => {
1755
1762
  return {
1756
1763
  data: l.aggResult.cursor.firstBatch,
1757
1764
  info: { job: undefined, debug: 'wait for change' },
1758
- cont: withStop(() => l.stream.tryNext().then(doc => (doc ? next(step1, 'restart') : step8(l)))),
1765
+ cont: withStop(() => l.stream
1766
+ .tryNext()
1767
+ .then(doc => doc
1768
+ ? doc.ts
1769
+ ? next(step7({ ...l, ts: doc.ts }), 'nothing changed')
1770
+ : next(step1, 'restart')
1771
+ : step8(l))),
1759
1772
  };
1760
1773
  };
1761
1774
  return stop;
@@ -1810,4 +1823,4 @@ const makeCol = async (docs, database, name) => {
1810
1823
  }
1811
1824
  };
1812
1825
 
1813
- export { $accumulator, $and, $countDict, $entries, $eq, $expr, $getField, $group, $groupId, $groupMerge, $gt, $gtTs, $gte, $gteTs, $ifNull, $in, $insert, $insertX, $keys, $let, $lookup, $lt, $lte, $map, $map1, $match, $matchDelta, $merge, $merge_, $ne, $nin, $nor, $or, $outerLookup, $pushDict, $rand, $replaceWith, $set, $simpleInsert, $simpleMerge, $sum, $type, $unwind, $unwindDelta, Field, Machine, add, and, array, ceil, comp, concat$1 as concat, concatArray, createIndex, ctx, current, dateAdd, dateDiff, dateLt, datePart, dayAndMonthPart, divide, enablePreAndPostImages, eq, eqTyped, except, exprMapVal, field, fieldF, fieldM, filter, filterDefined, first$1 as first, firstSure, floor, from, func, gt, gte, inArray, isArray, ite, last, log, lt, lte, makeCol, map1, mapVal, max, maxDate, mergeExact, mergeExact0, mergeExpr, mergeObjects, minDate, monthPart, multiply, ne, nil, noop, notNull, now, or, pair, prepare, rand, range, root, set, setField, size, slice, sortArray, staging, startOf, str, sub, subtract, to, toInt, val, weekPart, wrap, year };
1826
+ export { $accumulator, $and, $countDict, $entries, $eq, $exists, $expr, $getField, $group, $groupId, $groupMerge, $gt, $gtTs, $gte, $gteTs, $ifNull, $in, $insert, $insertX, $keys, $let, $lookup, $lt, $lte, $map, $map1, $match, $matchDelta, $merge, $merge_, $ne, $nin, $nor, $or, $outerLookup, $pushDict, $rand, $replaceWith, $set, $simpleInsert, $simpleMerge, $sum, $type, $unwind, $unwindDelta, Field, Machine, add, and, array, ceil, comp, concat$1 as concat, concatArray, createIndex, ctx, current, dateAdd, dateDiff, dateLt, datePart, dayAndMonthPart, divide, enablePreAndPostImages, eq, eqTyped, except, exprMapVal, field, fieldF, fieldM, filter, filterDefined, first$1 as first, firstSure, floor, from, func, gt, gte, inArray, isArray, ite, last, log, lt, lte, makeCol, map1, mapVal, max, maxDate, mergeExact, mergeExact0, mergeExpr, mergeObjects, minDate, monthPart, multiply, ne, nil, noop, notNull, now, or, pair, prepare, rand, range, root, set, setField, size, slice, sortArray, staging, startOf, str, sub, subtract, to, toInt, val, weekPart, wrap, year };
package/index.js CHANGED
@@ -3,7 +3,6 @@
3
3
  var mongodb = require('mongodb');
4
4
  var synchronousPromise = require('synchronous-promise');
5
5
  var crypto$1 = require('crypto');
6
- var console$1 = require('console');
7
6
  var promises = require('fs/promises');
8
7
 
9
8
  const asExprRaw = (raw) => ({ get: () => raw });
@@ -902,6 +901,7 @@ const dateLt = comp('$lt');
902
901
  const $gte = comp('$gte');
903
902
  const $lte = comp('$lte');
904
903
  const $type = operator()('$type');
904
+ const $exists = operator()('$exists');
905
905
 
906
906
  const $expr = (expr) => ({
907
907
  raw: f => ({ $expr: expr.raw(f).get() }),
@@ -1384,16 +1384,16 @@ const replace = (s) => s.replace(/\{"\$timestamp":"(\d+)"\}/g, (_, d) => T(d));
1384
1384
  const json = (a) => replace(JSON.stringify(a));
1385
1385
  const log = (...args) => console.log(new Date(), ...args.map(a => (typeof a === 'function' ? a(replace) : a && typeof a === 'object' ? json(a) : a)));
1386
1386
 
1387
- const aggregate = (input, snapshot = true, start = Date.now()) => input(({ coll, input }) => {
1387
+ const aggregate = (streamName, input, snapshot = true, start = Date.now()) => input(({ coll, input }) => {
1388
1388
  const req = {
1389
1389
  aggregate: coll.collectionName,
1390
1390
  pipeline: input,
1391
1391
  cursor: {},
1392
1392
  ...(snapshot && { readConcern: { level: 'snapshot' } }),
1393
1393
  };
1394
- log('exec', req);
1394
+ log('exec', streamName, req);
1395
1395
  return coll.s.db.command(req).then(result => {
1396
- log('execed', req, result, 'took', Date.now() - start);
1396
+ log('execed', streamName, req, result, 'took', Date.now() - start);
1397
1397
  return result;
1398
1398
  }, err => {
1399
1399
  log('err', req, err);
@@ -1445,11 +1445,19 @@ const makeWatchStream = (db, { collection, projection: p, hardMatch: m }, startA
1445
1445
  },
1446
1446
  });
1447
1447
  pipeline.push({
1448
- $match: {
1449
- $or: [
1450
- { $expr: { $ne: ['$fullDocument', '$fullDocumentBeforeChange'] } },
1451
- Object.fromEntries(changeKeys.map(k => [k, null])),
1452
- ],
1448
+ $replaceWith: {
1449
+ ts: {
1450
+ $cond: {
1451
+ if: {
1452
+ $or: [
1453
+ { $ne: ['$fullDocument', '$fullDocumentBeforeChange'] },
1454
+ { $and: changeKeys.map(k => ({ $eq: [k, null] })) },
1455
+ ],
1456
+ },
1457
+ then: '$clusterTime',
1458
+ else: null,
1459
+ },
1460
+ },
1453
1461
  },
1454
1462
  });
1455
1463
  const stream = db.collection(collection.collectionName).watch(pipeline, {
@@ -1462,7 +1470,7 @@ const makeWatchStream = (db, { collection, projection: p, hardMatch: m }, startA
1462
1470
  if (doc)
1463
1471
  await new Promise(resolve => setTimeout(resolve, 100));
1464
1472
  if (doc)
1465
- console$1.log('detected', streamName, collection.collectionName, doc);
1473
+ log('detected', streamName, collection.collectionName, doc);
1466
1474
  return doc;
1467
1475
  };
1468
1476
  return { tryNext, close: () => stream.close() };
@@ -1485,12 +1493,7 @@ const executes$1 = (view, input, streamName) => {
1485
1493
  else if (streamNames[streamName] != hash)
1486
1494
  throw new Error(`streamName ${streamName} already used`);
1487
1495
  const { collection, projection, hardMatch: pre, match } = view;
1488
- const types = Array.from({ length: 19 }).map((_, i) => i + 1);
1489
- const removeNotYetSynchronizedFields = Object.values(mapExactToObject(projection, (_, k) => k.startsWith('_')
1490
- ? root()
1491
- .of(k)
1492
- .has($type(types.filter(x => x != 10)))
1493
- : null));
1496
+ const removeNotYetSynchronizedFields = Object.values(mapExactToObject(projection, (_, k) => k.startsWith('_') ? root().of(k).has($exists(true)) : null));
1494
1497
  const hardMatch = $and(pre, ...removeNotYetSynchronizedFields);
1495
1498
  const job = {};
1496
1499
  const db = collection.s.db, coll = collection.collectionName;
@@ -1593,7 +1596,7 @@ const executes$1 = (view, input, streamName) => {
1593
1596
  whenMatched: 'merge',
1594
1597
  whenNotMatched: 'insert',
1595
1598
  })).stages;
1596
- const r = await aggregate(c => c({ coll: collection, input: cloneIntoNew }));
1599
+ const r = await aggregate(streamName, c => c({ coll: collection, input: cloneIntoNew }));
1597
1600
  await snapshotCollection.deleteMany({ updated: true, after: null, before: null });
1598
1601
  return next(step4({ result: r, ts: lastTS?.ts }), 'run the aggregation');
1599
1602
  };
@@ -1601,7 +1604,7 @@ const executes$1 = (view, input, streamName) => {
1601
1604
  const step4 = ({ result, ts }) => async () => {
1602
1605
  const start = Date.now();
1603
1606
  await snapshotCollection.updateMany({ before: null }, { $set: { before: null } });
1604
- const aggResult = await aggregate(c => c({
1607
+ const aggResult = await aggregate(streamName, c => c({
1605
1608
  coll: snapshotCollection,
1606
1609
  input: link()
1607
1610
  .with($match_(root().of('updated').has($eq(true))))
@@ -1610,7 +1613,7 @@ const executes$1 = (view, input, streamName) => {
1610
1613
  .with(finalInput.raw(ts === undefined)).stages,
1611
1614
  }), false, start);
1612
1615
  const stream = makeStream(result.cursor.atClusterTime);
1613
- return next(step5({ result, aggResult, stream }), 'remove handled deleted updated', () => stream.close());
1616
+ return next(step5({ ts: result.cursor.atClusterTime, aggResult, stream }), 'remove handled deleted updated', () => stream.close());
1614
1617
  };
1615
1618
  const step5 = (l) => async () => {
1616
1619
  log(`remove handled deleted updated db['${snapshotCollection.collectionName}'].deleteMany({ updated: true, after: null })`);
@@ -1635,7 +1638,7 @@ const executes$1 = (view, input, streamName) => {
1635
1638
  const step7 = (l) => async () => {
1636
1639
  await last.updateOne({ _id: streamName }, {
1637
1640
  $set: {
1638
- ts: l.result.cursor.atClusterTime,
1641
+ ts: l.ts,
1639
1642
  data,
1640
1643
  },
1641
1644
  }, { upsert: true });
@@ -1644,11 +1647,15 @@ const executes$1 = (view, input, streamName) => {
1644
1647
  const step8 = (l) => {
1645
1648
  return nextData(l.aggResult.cursor.firstBatch)(() => l.stream
1646
1649
  .tryNext()
1647
- .catch(err => {
1650
+ .catch((err) => {
1648
1651
  log('restarting', err);
1649
- return 1;
1652
+ return { ts: null };
1650
1653
  })
1651
- .then(doc => (doc ? next(step2, 'restart') : step8(l))), 'wait for change');
1654
+ .then(doc => doc
1655
+ ? doc.ts
1656
+ ? next(step7({ ...l, ts: doc.ts }), 'nothing changed')
1657
+ : next(step2, 'restart')
1658
+ : step8(l)), 'wait for change');
1652
1659
  };
1653
1660
  return stop;
1654
1661
  };
@@ -1738,7 +1745,7 @@ const executes = (view, input, streamName) => {
1738
1745
  const makeStream = (startAt) => makeWatchStream(db, view, startAt, streamName);
1739
1746
  const step4 = (lastTS) => async () => {
1740
1747
  const hardQuery = $and(lastTS && root().of('touchedAt').has($gteTs(lastTS.ts)), hardMatch, notDeleted, match && $expr(match));
1741
- const aggResult = await aggregate(c => c({
1748
+ const aggResult = await aggregate(streamName, c => c({
1742
1749
  coll: collection,
1743
1750
  input: link()
1744
1751
  .with($match_(hardQuery))
@@ -1747,17 +1754,23 @@ const executes = (view, input, streamName) => {
1747
1754
  .with(finalInput.raw(lastTS === null)).stages,
1748
1755
  }));
1749
1756
  const stream = makeStream(aggResult.cursor.atClusterTime);
1750
- return next(step7({ aggResult, result: aggResult, stream }), 'update __last', () => stream.close());
1757
+ return next(step7({ aggResult, ts: aggResult.cursor.atClusterTime, stream }), 'update __last', () => stream.close());
1751
1758
  };
1752
1759
  const step7 = (l) => async () => {
1753
- await last.updateOne({ _id: streamName }, { $set: { ts: l.result.cursor.atClusterTime, data } }, { upsert: true });
1760
+ await last.updateOne({ _id: streamName }, { $set: { ts: l.ts, data } }, { upsert: true });
1754
1761
  return step8(l);
1755
1762
  };
1756
1763
  const step8 = (l) => {
1757
1764
  return {
1758
1765
  data: l.aggResult.cursor.firstBatch,
1759
1766
  info: { job: undefined, debug: 'wait for change' },
1760
- cont: withStop(() => l.stream.tryNext().then(doc => (doc ? next(step1, 'restart') : step8(l)))),
1767
+ cont: withStop(() => l.stream
1768
+ .tryNext()
1769
+ .then(doc => doc
1770
+ ? doc.ts
1771
+ ? next(step7({ ...l, ts: doc.ts }), 'nothing changed')
1772
+ : next(step1, 'restart')
1773
+ : step8(l))),
1761
1774
  };
1762
1775
  };
1763
1776
  return stop;
@@ -1817,6 +1830,7 @@ exports.$and = $and;
1817
1830
  exports.$countDict = $countDict;
1818
1831
  exports.$entries = $entries;
1819
1832
  exports.$eq = $eq;
1833
+ exports.$exists = $exists;
1820
1834
  exports.$expr = $expr;
1821
1835
  exports.$getField = $getField;
1822
1836
  exports.$group = $group;
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "module": "index.esm.js",
4
4
  "typings": "index.d.ts",
5
5
  "name": "@omegup/msync",
6
- "version": "0.0.48",
6
+ "version": "0.0.49",
7
7
  "dependencies": {
8
8
  "dayjs": "^1.11.9",
9
9
  "dotenv": "^16.3.1",