@omegup/msync 0.0.54 → 0.0.56

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 (4) hide show
  1. package/index.d.ts +28 -29
  2. package/index.esm.js +54 -45
  3. package/index.js +54 -45
  4. package/package.json +1 -1
package/index.d.ts CHANGED
@@ -449,31 +449,6 @@ declare const $groupMerge: <T extends O, Grp extends notArr, V extends O, GG ext
449
449
  declare const $groupId: <T extends O, V extends O, EE = {}, Out extends Loose<string, V, "_id"> = Loose<string, V, "_id">>(id: Expr<string, T>, args: DeltaAccumulators<T, O & Omit<V, Denied>>, out: RWCollection<Replace<Out, Strict<string, V, "_id", EE>>, Out>, extra: ExprsExact<Omit<EE, IdAndTsKeys | keyof Omit<V, IdAndTsKeys>>, doc & Omit<V, IdAndTsKeys>>) => StreamRunnerParam<Delta<T>, "out">;
450
450
  declare const $group: <T extends O, Grp extends notArr, V extends O, EE = {}, Out extends Loose<Grp, V, "_grp"> = Loose<Grp, V, "_grp">>(id: Expr<Grp, T>, args: DeltaAccumulators<T, O & Omit<V, Denied<"_grp">>>, out: RWCollection<Strict<Grp, V, "_grp", EE>, Out>, extra: ExprsExact<Omit<EE, IdAndTsKeys | "_grp" | keyof Omit<V, IdAndTsKeys | "_grp">>, Rec<"_grp", Grp> & Omit<V, IdAndTsKeys | "_grp">>, idPrefix?: string) => StreamRunnerParam<Delta<T>, "out">;
451
451
 
452
- declare const size: <T, D, C>(expr: Expr<Arr<T>, D, C>) => Expr<number, D, C>;
453
- declare const filterDefined: <T, D, C = unknown>(expr: Expr<Arr<T | N>, D, C>) => Expr<Arr<T>, D, C>;
454
- declare const filter: <T, D, K extends string, C = unknown>({ as, cond, expr, limit, }: {
455
- expr: Expr<Arr<T>, D, C>;
456
- as: K;
457
- cond: Expr<unknown, D, C & RORec<K, T>>;
458
- limit?: Expr<number, D, C>;
459
- }) => Expr<Arr<T>, D, C>;
460
- declare const sortArray: <T, D, C, K extends keyof T>({ sortBy, expr, order, }: {
461
- expr: Expr<Arr<T>, D, C>;
462
- sortBy: K;
463
- order?: 1 | -1;
464
- }) => Expr<Arr<T>, D, C>;
465
- declare const isArray: <T extends notArr, D, C, F extends HKT<T | Arr<T>>>(expr: Expr<T | Arr<T>, D & (App<F, T> | App<F, Arr<T>>), C>) => BoolExpr<D & App<F, Arr<T>>, D & App<F, T>, C>;
466
- declare const array: <T, D, C = unknown>(...exprs: Expr<T, D, C>[]) => Expr<Arr<T>, D, C>;
467
- declare const concatArray: <T, D, C>(...exprs: Expr<Arr<T>, D, C>[]) => Expr<Arr<T>, D, C>;
468
- declare const first: <T, D, C>(expr: Expr<Arr<T>, D, C>) => Expr<T | null, D, C>;
469
- declare const firstSure: <T, D, C>(expr: Expr<Arr<T>, D, C>) => Expr<T, D, C>;
470
- declare const last: <T, D, C>(expr: Expr<Arr<T>, D, C>) => Expr<T | null, D, C>;
471
- type NullToOBJ<N extends null> = N extends null ? O : N;
472
- declare const mergeObjects: <T1, T2, D, C = unknown, N extends null = never>(exprs_0: Expr<T1 | N, D, C>, exprs_1: Expr<T2, D, C>) => Expr<(T1 | NullToOBJ<N>) & T2, D, C>;
473
- declare const inArray: <T, D, C = unknown>(exprs_0: Expr<T, D, C>, exprs_1: Expr<Arr<T>, D, C>) => Expr<boolean, D, C>;
474
- declare const slice: <T, D, C>(array: Expr<Arr<T>, D, C>, start: Expr<number, D, C>, end: Expr<number, D, C>) => Expr<Arr<T>, D, C>;
475
- declare const except: <T, D, C>(a: Expr<Arr<T>, D, C>, b: Expr<Arr<T>, D, C>) => Expr<Arr<T>, D, C>;
476
-
477
452
  type Params<As extends string, LQ extends O, RQ extends O, RE extends RQ, S extends notArr> = {
478
453
  localField: Field<LQ, S>;
479
454
  foreignField: Field<RQ, S>;
@@ -481,10 +456,9 @@ type Params<As extends string, LQ extends O, RQ extends O, RE extends RQ, S exte
481
456
  as: AsLiteral<As>;
482
457
  };
483
458
  declare const $lookup: <As extends string, LQ extends doc, RQ extends O, RE extends RQ & doc, S extends notArr>(p: Params<As, LQ, RQ, RE, S>) => <LE extends LQ>(l: SnapshotStream<LQ, LE>) => SnapshotStream<LQ, LE & RORec<As, RE>>;
484
- declare const $outerLookup: <As extends string, LQ extends doc, RQ extends O, RE extends RQ & doc, S extends notArr, LNull extends null = never, RNull extends null = never>(p: Params<As, LQ, RQ, RE, S>, outer: {
485
- left?: LNull;
486
- right?: RNull;
487
- }) => <LE extends LQ>(l: SnapshotStream<LQ, LE>) => SnapshotStream<LQ | NullToOBJ<RNull>, (LE | NullToOBJ<RNull>) & RORec<As, RE | LNull>>;
459
+ declare const $outerLookup: <As extends string, LQ extends doc, RQ extends O, RE extends RQ & doc, S extends notArr, Null extends null = never>(p: Params<As, LQ, RQ, RE, S>, outer?: {
460
+ left?: Null;
461
+ }) => <LE extends LQ>(l: SnapshotStream<LQ, LE>) => SnapshotStream<LQ, LE & RORec<As, RE | Null>>;
488
462
 
489
463
  declare const $matchDelta: <T extends doc>(query: Expr<boolean, T>) => RawStages<unknown, Delta<T>, Delta<T>, unknown, number>;
490
464
 
@@ -576,6 +550,31 @@ declare function floor<D, C>(expr: Expr<Num, D, C>): Expr<Num, D, C>;
576
550
  declare function ceil<D, C>(expr: Expr<number, D, C>): Expr<number, D, C>;
577
551
  declare function ceil<D, C>(expr: Expr<Num, D, C>): Expr<Num, D, C>;
578
552
 
553
+ declare const size: <T, D, C>(expr: Expr<Arr<T>, D, C>) => Expr<number, D, C>;
554
+ declare const filterDefined: <T, D, C = unknown>(expr: Expr<Arr<T | N>, D, C>) => Expr<Arr<T>, D, C>;
555
+ declare const filter: <T, D, K extends string, C = unknown>({ as, cond, expr, limit, }: {
556
+ expr: Expr<Arr<T>, D, C>;
557
+ as: K;
558
+ cond: Expr<unknown, D, C & RORec<K, T>>;
559
+ limit?: Expr<number, D, C>;
560
+ }) => Expr<Arr<T>, D, C>;
561
+ declare const sortArray: <T, D, C, K extends keyof T>({ sortBy, expr, order, }: {
562
+ expr: Expr<Arr<T>, D, C>;
563
+ sortBy: K;
564
+ order?: 1 | -1;
565
+ }) => Expr<Arr<T>, D, C>;
566
+ declare const isArray: <T extends notArr, D, C, F extends HKT<T | Arr<T>>>(expr: Expr<T | Arr<T>, D & (App<F, T> | App<F, Arr<T>>), C>) => BoolExpr<D & App<F, Arr<T>>, D & App<F, T>, C>;
567
+ declare const array: <T, D, C = unknown>(...exprs: Expr<T, D, C>[]) => Expr<Arr<T>, D, C>;
568
+ declare const concatArray: <T, D, C>(...exprs: Expr<Arr<T>, D, C>[]) => Expr<Arr<T>, D, C>;
569
+ declare const first: <T, D, C>(expr: Expr<Arr<T>, D, C>) => Expr<T | null, D, C>;
570
+ declare const firstSure: <T, D, C>(expr: Expr<Arr<T>, D, C>) => Expr<T, D, C>;
571
+ declare const last: <T, D, C>(expr: Expr<Arr<T>, D, C>) => Expr<T | null, D, C>;
572
+ type NullToOBJ<N extends null> = N extends null ? O : N;
573
+ declare const mergeObjects: <T1, T2, D, C = unknown, N extends null = never>(exprs_0: Expr<T1 | N, D, C>, exprs_1: Expr<T2, D, C>) => Expr<(T1 | NullToOBJ<N>) & T2, D, C>;
574
+ declare const inArray: <T, D, C = unknown>(exprs_0: Expr<T, D, C>, exprs_1: Expr<Arr<T>, D, C>) => Expr<boolean, D, C>;
575
+ declare const slice: <T, D, C>(array: Expr<Arr<T>, D, C>, start: Expr<number, D, C>, end: Expr<number, D, C>) => Expr<Arr<T>, D, C>;
576
+ declare const except: <T, D, C>(a: Expr<Arr<T>, D, C>, b: Expr<Arr<T>, D, C>) => Expr<Arr<T>, D, C>;
577
+
579
578
  declare const dayAndMonthPart: <D, C>(date: Expr<Date, D, C>) => Expr<string, D, C>;
580
579
  declare const now: <D, C>() => Expr<Date, D, C>;
581
580
  declare const monthPart: <D, C>(date: Expr<Date, D, C>) => Expr<string, D, C>;
package/index.esm.js CHANGED
@@ -468,7 +468,7 @@ const $replaceWith1 = (expr) => f => {
468
468
  const $unwind1 = (k, includeNull) => f => {
469
469
  const path = `$${f().of(k).str()}`;
470
470
  return asStages([
471
- { $unwind: path },
471
+ { $unwind: includeNull === null ? { path, preserveNullAndEmptyArrays: true } : path },
472
472
  ]);
473
473
  };
474
474
  const $group1 = (id, args) => (f) => asStages([
@@ -501,7 +501,7 @@ const $simpleLookup1 = (args) => f => {
501
501
  const $match_ = (query) => $match1(query)(root);
502
502
  const $set_ = (updater) => $set1(updater)(root);
503
503
  const $replaceWith_ = (expr) => $replaceWith1(expr)(root);
504
- const $unwind_ = (k, includeNull) => $unwind1(k)(root);
504
+ const $unwind_ = (k, includeNull) => $unwind1(k, includeNull)(root);
505
505
  const $group_ = () => (id, args) => $group1(id, args)(root);
506
506
  const $project_ = $project1;
507
507
  const $simpleLookup_ = (args) => $simpleLookup1(args)(root);
@@ -1086,9 +1086,8 @@ const $lookupDelta = ({ field1, field2 }, { coll, exec, input }, k1, k2, k, incl
1086
1086
  })).with($unwindDelta(k1, k2, k, includeNull)).stages;
1087
1087
  };
1088
1088
 
1089
- const $lookupRaw = ({ field1, field2 }, { coll, exec, input }, k2, k) => (f) => {
1089
+ const $lookupRaw = ({ field1, field2 }, { coll, exec, input }, k2, k, includeNull) => (f) => {
1090
1090
  root().of('_id').expr();
1091
- root().of(k2).of('_id').expr();
1092
1091
  return link()
1093
1092
  .with($simpleLookup1({
1094
1093
  coll,
@@ -1100,7 +1099,7 @@ const $lookupRaw = ({ field1, field2 }, { coll, exec, input }, k2, k) => (f) =>
1100
1099
  .with(exec)
1101
1100
  .with($replaceWith_(root().of('before').expr())).stages,
1102
1101
  })(f))
1103
- .with($unwind1(k2)(f))
1102
+ .with($unwind1(k2, includeNull)(f))
1104
1103
  .with(link().stages
1105
1104
  ).stages;
1106
1105
  };
@@ -1113,7 +1112,7 @@ const createIndex = async (collection, indexSpec, options) => {
1113
1112
  await collection.createIndex(indexSpec, options);
1114
1113
  }
1115
1114
  catch (e) {
1116
- if (e.code == 85) {
1115
+ if ([85, 276].includes(e.code)) {
1117
1116
  break;
1118
1117
  }
1119
1118
  if (e.code == 12587) {
@@ -1235,12 +1234,12 @@ const runCont = async (it, cb) => {
1235
1234
  };
1236
1235
 
1237
1236
  const merge = ({ lsource: L, rsource: R, }) => mergeIterators({ sources: { L, R } });
1238
- const join = ({ lField, rField, left, right, as }, leftSnapshot, rightSnapshot, stagesUntilNextLookup, outerLeft, outerRight) => {
1237
+ const join = ({ lField, rField, left, right, as }, leftSnapshot, rightSnapshot, stagesUntilNextLookup, outerLeft) => {
1239
1238
  createIndex(leftSnapshot.coll, { [`before.${lField.str()}`]: 1 }).catch(e => e.code == 86 || Promise.reject(e));
1240
1239
  createIndex(rightSnapshot.coll, { [`before.${rField.str()}`]: 1 }).catch(e => e.code == 86 || Promise.reject(e));
1241
1240
  const rightJoinField = { field1: lField, field2: rField };
1242
1241
  const joinId = 'left';
1243
- const joinR_Snapshot = asBefore($lookupRaw(rightJoinField, rightSnapshot, as));
1242
+ const joinR_Snapshot = asBefore($lookupRaw(rightJoinField, rightSnapshot, as, joinId, outerLeft));
1244
1243
  const resultingSnapshot = concatTStages(leftSnapshot, joinR_Snapshot);
1245
1244
  const dict = { [as]: 'a' };
1246
1245
  const idB = { _id: 'b' };
@@ -1249,7 +1248,7 @@ const join = ({ lField, rField, left, right, as }, leftSnapshot, rightSnapshot,
1249
1248
  stages: consume => consume(concatTStages(resultingSnapshot, asBefore(stagesUntilNextLookup.raw))),
1250
1249
  out: (finalInput) => {
1251
1250
  const leftJoinField = { field1: rField, field2: lField };
1252
- const joinL_Delta = $lookupDelta(leftJoinField, leftSnapshot, 'right', 'left', joinId, outerRight);
1251
+ const joinL_Delta = $lookupDelta(leftJoinField, leftSnapshot, 'right', 'left', joinId);
1253
1252
  const joinR_Delta = $lookupDelta(rightJoinField, rightSnapshot, 'left', 'right', joinId, outerLeft);
1254
1253
  const mergeForeignIntoDoc = concatStages($replaceWithDelta(mergeObjects(root().of('left').expr(), fieldM({ a: root().of('right').expr(), b: root().of('_id').expr() }, dictId))), stagesUntilNextLookup.delta);
1255
1254
  const lRunnerInput = concatStages(joinR_Delta, mergeForeignIntoDoc);
@@ -1264,7 +1263,7 @@ const join = ({ lField, rField, left, right, as }, leftSnapshot, rightSnapshot,
1264
1263
  },
1265
1264
  };
1266
1265
  };
1267
- const $lookup1 = (p, outer) => (input) => p.left.stages((lStages) => p.right.stages((rStages) => join(p, lStages, rStages, input, outer?.left, outer?.right)));
1266
+ const $lookup1 = (p, outerLeft) => (input) => p.left.stages((lStages) => p.right.stages((rStages) => join(p, lStages, rStages, input, outerLeft)));
1268
1267
  const $lookup = (p) => (l) => $lookup1({
1269
1268
  right: p.from,
1270
1269
  as: p.as,
@@ -1278,7 +1277,7 @@ const $outerLookup = (p, outer) => (l) => $lookup1({
1278
1277
  lField: p.localField,
1279
1278
  rField: p.foreignField,
1280
1279
  left: l(emptyDelta()),
1281
- }, outer);
1280
+ }, outer?.left);
1282
1281
 
1283
1282
  const filterUndefined = (applyOperator) => {
1284
1283
  return (op, args) => applyOperator(op, args.filter(defined));
@@ -1392,8 +1391,9 @@ const aggregate = (streamName, input, snapshot = true, start = Date.now()) => in
1392
1391
  };
1393
1392
  log('exec', streamName, req);
1394
1393
  return coll.s.db.command(req).then(result => {
1395
- log('execed', streamName, req, result, 'took', Date.now() - start);
1396
- return result;
1394
+ const r = result;
1395
+ log('execed', streamName, (replace) => replace(JSON.stringify(req).replaceAll('$$CLUSTER_TIME', JSON.stringify(r.cursor.atClusterTime))), result, 'took', Date.now() - start);
1396
+ return r;
1397
1397
  }, err => {
1398
1398
  log('err', req, err);
1399
1399
  throw new Error(err);
@@ -1444,23 +1444,21 @@ const makeWatchStream = (db, { collection, projection: p, hardMatch: m }, startA
1444
1444
  },
1445
1445
  });
1446
1446
  pipeline.push({
1447
- $replaceWith: {
1448
- _id: "$_id",
1449
- ts: {
1450
- $cond: {
1451
- if: {
1452
- $or: [
1453
- { $ne: ['$fullDocument', '$fullDocumentBeforeChange'] },
1454
- { $and: changeKeys.map(k => ({ $eq: [k, null] })) },
1455
- ],
1456
- },
1457
- then: null,
1458
- else: '$clusterTime',
1459
- },
1460
- },
1447
+ $match: {
1448
+ $or: [
1449
+ { $expr: { $ne: ['$fullDocument', '$fullDocumentBeforeChange'] } },
1450
+ Object.fromEntries(changeKeys.map(k => [k, null])),
1451
+ ],
1452
+ },
1453
+ });
1454
+ pipeline.push({
1455
+ $project: {
1456
+ _id: 1,
1461
1457
  },
1462
1458
  });
1463
- const stream = db.collection(collection.collectionName).watch(pipeline, {
1459
+ const stream = db
1460
+ .collection(collection.collectionName)
1461
+ .watch(pipeline, {
1464
1462
  fullDocument: 'required',
1465
1463
  fullDocumentBeforeChange: 'required',
1466
1464
  startAtOperationTime: startAt,
@@ -1483,7 +1481,7 @@ const actions = {
1483
1481
  ],
1484
1482
  };
1485
1483
  const streamNames = {};
1486
- const executes$1 = (view, input, streamName) => {
1484
+ const executes$1 = (view, input, streamName, skip = false) => {
1487
1485
  const hash = crypto$1
1488
1486
  .createHash('md5')
1489
1487
  .update(new Error().stack + '')
@@ -1536,6 +1534,8 @@ const executes$1 = (view, input, streamName) => {
1536
1534
  input: input.delta,
1537
1535
  finalInputFirst: finalInput.raw(true),
1538
1536
  finalInput: finalInput.raw(false),
1537
+ match: view.match?.raw(root()).get(),
1538
+ project: projection,
1539
1539
  teardown: finalInput.teardown((x) => ({
1540
1540
  collection: x.collection.collectionName,
1541
1541
  method: x.method,
@@ -1571,13 +1571,17 @@ const executes$1 = (view, input, streamName) => {
1571
1571
  await Promise.all([snapshotCollection.drop(), action]);
1572
1572
  log('teardown done', `db['${snapshotCollection.collectionName}'].drop()`, ...out);
1573
1573
  };
1574
- if (exists && !same)
1574
+ if (exists && !same) {
1575
1575
  await handleTeardown(exists);
1576
- return next(step3(same), 'clone into new collection');
1576
+ }
1577
+ return nextData([])(async () => {
1578
+ await new Promise(resolve => setTimeout(resolve, 1000));
1579
+ return step3(same)();
1580
+ }, 'clone into new collection');
1577
1581
  };
1578
1582
  const step3 = (lastTS) => async () => {
1579
1583
  const hardQuery = $and(lastTS
1580
- ? root().of('touchedAt').has($gteTs(lastTS.ts))
1584
+ ? root().of('touchedAt').has($gtTs(lastTS.ts))
1581
1585
  : root().of('deletedAt').has($eq(null)), lastTS ? null : match && $expr(match), hardMatch);
1582
1586
  const notDeleted = eq($ifNull(root().of('deletedAt').expr(), nil))(nil);
1583
1587
  const query = match ? and(notDeleted, match) : notDeleted;
@@ -1655,13 +1659,11 @@ const executes$1 = (view, input, streamName) => {
1655
1659
  log('restarting', err);
1656
1660
  return { ts: null };
1657
1661
  })
1658
- .then(doc => doc
1659
- ? doc.ts
1660
- ? next(step7({ ...l, ts: doc.ts }), 'nothing changed')
1661
- : next(step2, 'restart')
1662
- : step8(l)), 'wait for change');
1662
+ .then(doc => (doc ? next(step3({ _id: streamName, ts: l.ts }), 'restart') : step8(l))), 'wait for change');
1663
1663
  };
1664
- return stop;
1664
+ return skip
1665
+ ? withStop(() => SynchronousPromise.resolve(next(step3(null), 'clone into new collection')))
1666
+ : stop;
1665
1667
  };
1666
1668
  const hasBefore = root().of('before').has($ne(null));
1667
1669
  return {
@@ -1684,7 +1686,9 @@ const executes = (view, input, streamName) => {
1684
1686
  streamNames[streamName] = hash;
1685
1687
  else if (streamNames[streamName] != hash)
1686
1688
  throw new Error('streamName already used');
1687
- const { collection, projection, hardMatch, match } = view;
1689
+ const { collection, projection, hardMatch: pre, match } = view;
1690
+ const removeNotYetSynchronizedFields = Object.values(mapExactToObject(projection, (_, k) => k.startsWith('_') ? root().of(k).has($exists(true)) : null));
1691
+ const hardMatch = $and(pre, ...removeNotYetSynchronizedFields);
1688
1692
  const job = {};
1689
1693
  const db = collection.s.db, coll = collection.collectionName;
1690
1694
  db.command({
@@ -1715,6 +1719,8 @@ const executes = (view, input, streamName) => {
1715
1719
  input: input,
1716
1720
  finalInputFirst: finalInput.raw(true),
1717
1721
  finalInput: finalInput.raw(false),
1722
+ match: view.match?.raw(root()).get(),
1723
+ project: projection,
1718
1724
  teardown: finalInput.teardown((x) => ({
1719
1725
  collection: x.collection.collectionName,
1720
1726
  method: x.method,
@@ -1744,7 +1750,14 @@ const executes = (view, input, streamName) => {
1744
1750
  };
1745
1751
  if (exists && !same)
1746
1752
  await handleTeardown(exists);
1747
- return next(step4(same), 'clone into new collection');
1753
+ return {
1754
+ cont: withStop(async () => {
1755
+ await new Promise(resolve => setTimeout(resolve, 1000));
1756
+ return step4(same)();
1757
+ }),
1758
+ data: [],
1759
+ info: { debug: 'clone into new collection', job: undefined },
1760
+ };
1748
1761
  };
1749
1762
  const makeStream = (startAt) => makeWatchStream(db, view, startAt, streamName);
1750
1763
  const step4 = (lastTS) => async () => {
@@ -1770,11 +1783,7 @@ const executes = (view, input, streamName) => {
1770
1783
  info: { job: undefined, debug: 'wait for change' },
1771
1784
  cont: withStop(() => l.stream
1772
1785
  .tryNext()
1773
- .then(doc => doc
1774
- ? doc.ts
1775
- ? next(step7({ ...l, ts: doc.ts }), 'nothing changed')
1776
- : next(step1, 'restart')
1777
- : step8(l))),
1786
+ .then(doc => (doc ? next(step4({ _id: streamName, ts: l.ts }), 'restart') : step8(l)))),
1778
1787
  };
1779
1788
  };
1780
1789
  return stop;
package/index.js CHANGED
@@ -470,7 +470,7 @@ const $replaceWith1 = (expr) => f => {
470
470
  const $unwind1 = (k, includeNull) => f => {
471
471
  const path = `$${f().of(k).str()}`;
472
472
  return asStages([
473
- { $unwind: path },
473
+ { $unwind: includeNull === null ? { path, preserveNullAndEmptyArrays: true } : path },
474
474
  ]);
475
475
  };
476
476
  const $group1 = (id, args) => (f) => asStages([
@@ -503,7 +503,7 @@ const $simpleLookup1 = (args) => f => {
503
503
  const $match_ = (query) => $match1(query)(root);
504
504
  const $set_ = (updater) => $set1(updater)(root);
505
505
  const $replaceWith_ = (expr) => $replaceWith1(expr)(root);
506
- const $unwind_ = (k, includeNull) => $unwind1(k)(root);
506
+ const $unwind_ = (k, includeNull) => $unwind1(k, includeNull)(root);
507
507
  const $group_ = () => (id, args) => $group1(id, args)(root);
508
508
  const $project_ = $project1;
509
509
  const $simpleLookup_ = (args) => $simpleLookup1(args)(root);
@@ -1088,9 +1088,8 @@ const $lookupDelta = ({ field1, field2 }, { coll, exec, input }, k1, k2, k, incl
1088
1088
  })).with($unwindDelta(k1, k2, k, includeNull)).stages;
1089
1089
  };
1090
1090
 
1091
- const $lookupRaw = ({ field1, field2 }, { coll, exec, input }, k2, k) => (f) => {
1091
+ const $lookupRaw = ({ field1, field2 }, { coll, exec, input }, k2, k, includeNull) => (f) => {
1092
1092
  root().of('_id').expr();
1093
- root().of(k2).of('_id').expr();
1094
1093
  return link()
1095
1094
  .with($simpleLookup1({
1096
1095
  coll,
@@ -1102,7 +1101,7 @@ const $lookupRaw = ({ field1, field2 }, { coll, exec, input }, k2, k) => (f) =>
1102
1101
  .with(exec)
1103
1102
  .with($replaceWith_(root().of('before').expr())).stages,
1104
1103
  })(f))
1105
- .with($unwind1(k2)(f))
1104
+ .with($unwind1(k2, includeNull)(f))
1106
1105
  .with(link().stages
1107
1106
  ).stages;
1108
1107
  };
@@ -1115,7 +1114,7 @@ const createIndex = async (collection, indexSpec, options) => {
1115
1114
  await collection.createIndex(indexSpec, options);
1116
1115
  }
1117
1116
  catch (e) {
1118
- if (e.code == 85) {
1117
+ if ([85, 276].includes(e.code)) {
1119
1118
  break;
1120
1119
  }
1121
1120
  if (e.code == 12587) {
@@ -1237,12 +1236,12 @@ const runCont = async (it, cb) => {
1237
1236
  };
1238
1237
 
1239
1238
  const merge = ({ lsource: L, rsource: R, }) => mergeIterators({ sources: { L, R } });
1240
- const join = ({ lField, rField, left, right, as }, leftSnapshot, rightSnapshot, stagesUntilNextLookup, outerLeft, outerRight) => {
1239
+ const join = ({ lField, rField, left, right, as }, leftSnapshot, rightSnapshot, stagesUntilNextLookup, outerLeft) => {
1241
1240
  createIndex(leftSnapshot.coll, { [`before.${lField.str()}`]: 1 }).catch(e => e.code == 86 || Promise.reject(e));
1242
1241
  createIndex(rightSnapshot.coll, { [`before.${rField.str()}`]: 1 }).catch(e => e.code == 86 || Promise.reject(e));
1243
1242
  const rightJoinField = { field1: lField, field2: rField };
1244
1243
  const joinId = 'left';
1245
- const joinR_Snapshot = asBefore($lookupRaw(rightJoinField, rightSnapshot, as));
1244
+ const joinR_Snapshot = asBefore($lookupRaw(rightJoinField, rightSnapshot, as, joinId, outerLeft));
1246
1245
  const resultingSnapshot = concatTStages(leftSnapshot, joinR_Snapshot);
1247
1246
  const dict = { [as]: 'a' };
1248
1247
  const idB = { _id: 'b' };
@@ -1251,7 +1250,7 @@ const join = ({ lField, rField, left, right, as }, leftSnapshot, rightSnapshot,
1251
1250
  stages: consume => consume(concatTStages(resultingSnapshot, asBefore(stagesUntilNextLookup.raw))),
1252
1251
  out: (finalInput) => {
1253
1252
  const leftJoinField = { field1: rField, field2: lField };
1254
- const joinL_Delta = $lookupDelta(leftJoinField, leftSnapshot, 'right', 'left', joinId, outerRight);
1253
+ const joinL_Delta = $lookupDelta(leftJoinField, leftSnapshot, 'right', 'left', joinId);
1255
1254
  const joinR_Delta = $lookupDelta(rightJoinField, rightSnapshot, 'left', 'right', joinId, outerLeft);
1256
1255
  const mergeForeignIntoDoc = concatStages($replaceWithDelta(mergeObjects(root().of('left').expr(), fieldM({ a: root().of('right').expr(), b: root().of('_id').expr() }, dictId))), stagesUntilNextLookup.delta);
1257
1256
  const lRunnerInput = concatStages(joinR_Delta, mergeForeignIntoDoc);
@@ -1266,7 +1265,7 @@ const join = ({ lField, rField, left, right, as }, leftSnapshot, rightSnapshot,
1266
1265
  },
1267
1266
  };
1268
1267
  };
1269
- const $lookup1 = (p, outer) => (input) => p.left.stages((lStages) => p.right.stages((rStages) => join(p, lStages, rStages, input, outer?.left, outer?.right)));
1268
+ const $lookup1 = (p, outerLeft) => (input) => p.left.stages((lStages) => p.right.stages((rStages) => join(p, lStages, rStages, input, outerLeft)));
1270
1269
  const $lookup = (p) => (l) => $lookup1({
1271
1270
  right: p.from,
1272
1271
  as: p.as,
@@ -1280,7 +1279,7 @@ const $outerLookup = (p, outer) => (l) => $lookup1({
1280
1279
  lField: p.localField,
1281
1280
  rField: p.foreignField,
1282
1281
  left: l(emptyDelta()),
1283
- }, outer);
1282
+ }, outer?.left);
1284
1283
 
1285
1284
  const filterUndefined = (applyOperator) => {
1286
1285
  return (op, args) => applyOperator(op, args.filter(defined));
@@ -1394,8 +1393,9 @@ const aggregate = (streamName, input, snapshot = true, start = Date.now()) => in
1394
1393
  };
1395
1394
  log('exec', streamName, req);
1396
1395
  return coll.s.db.command(req).then(result => {
1397
- log('execed', streamName, req, result, 'took', Date.now() - start);
1398
- return result;
1396
+ const r = result;
1397
+ log('execed', streamName, (replace) => replace(JSON.stringify(req).replaceAll('$$CLUSTER_TIME', JSON.stringify(r.cursor.atClusterTime))), result, 'took', Date.now() - start);
1398
+ return r;
1399
1399
  }, err => {
1400
1400
  log('err', req, err);
1401
1401
  throw new Error(err);
@@ -1446,23 +1446,21 @@ const makeWatchStream = (db, { collection, projection: p, hardMatch: m }, startA
1446
1446
  },
1447
1447
  });
1448
1448
  pipeline.push({
1449
- $replaceWith: {
1450
- _id: "$_id",
1451
- ts: {
1452
- $cond: {
1453
- if: {
1454
- $or: [
1455
- { $ne: ['$fullDocument', '$fullDocumentBeforeChange'] },
1456
- { $and: changeKeys.map(k => ({ $eq: [k, null] })) },
1457
- ],
1458
- },
1459
- then: null,
1460
- else: '$clusterTime',
1461
- },
1462
- },
1449
+ $match: {
1450
+ $or: [
1451
+ { $expr: { $ne: ['$fullDocument', '$fullDocumentBeforeChange'] } },
1452
+ Object.fromEntries(changeKeys.map(k => [k, null])),
1453
+ ],
1454
+ },
1455
+ });
1456
+ pipeline.push({
1457
+ $project: {
1458
+ _id: 1,
1463
1459
  },
1464
1460
  });
1465
- const stream = db.collection(collection.collectionName).watch(pipeline, {
1461
+ const stream = db
1462
+ .collection(collection.collectionName)
1463
+ .watch(pipeline, {
1466
1464
  fullDocument: 'required',
1467
1465
  fullDocumentBeforeChange: 'required',
1468
1466
  startAtOperationTime: startAt,
@@ -1485,7 +1483,7 @@ const actions = {
1485
1483
  ],
1486
1484
  };
1487
1485
  const streamNames = {};
1488
- const executes$1 = (view, input, streamName) => {
1486
+ const executes$1 = (view, input, streamName, skip = false) => {
1489
1487
  const hash = crypto$1
1490
1488
  .createHash('md5')
1491
1489
  .update(new Error().stack + '')
@@ -1538,6 +1536,8 @@ const executes$1 = (view, input, streamName) => {
1538
1536
  input: input.delta,
1539
1537
  finalInputFirst: finalInput.raw(true),
1540
1538
  finalInput: finalInput.raw(false),
1539
+ match: view.match?.raw(root()).get(),
1540
+ project: projection,
1541
1541
  teardown: finalInput.teardown((x) => ({
1542
1542
  collection: x.collection.collectionName,
1543
1543
  method: x.method,
@@ -1573,13 +1573,17 @@ const executes$1 = (view, input, streamName) => {
1573
1573
  await Promise.all([snapshotCollection.drop(), action]);
1574
1574
  log('teardown done', `db['${snapshotCollection.collectionName}'].drop()`, ...out);
1575
1575
  };
1576
- if (exists && !same)
1576
+ if (exists && !same) {
1577
1577
  await handleTeardown(exists);
1578
- return next(step3(same), 'clone into new collection');
1578
+ }
1579
+ return nextData([])(async () => {
1580
+ await new Promise(resolve => setTimeout(resolve, 1000));
1581
+ return step3(same)();
1582
+ }, 'clone into new collection');
1579
1583
  };
1580
1584
  const step3 = (lastTS) => async () => {
1581
1585
  const hardQuery = $and(lastTS
1582
- ? root().of('touchedAt').has($gteTs(lastTS.ts))
1586
+ ? root().of('touchedAt').has($gtTs(lastTS.ts))
1583
1587
  : root().of('deletedAt').has($eq(null)), lastTS ? null : match && $expr(match), hardMatch);
1584
1588
  const notDeleted = eq($ifNull(root().of('deletedAt').expr(), nil))(nil);
1585
1589
  const query = match ? and(notDeleted, match) : notDeleted;
@@ -1657,13 +1661,11 @@ const executes$1 = (view, input, streamName) => {
1657
1661
  log('restarting', err);
1658
1662
  return { ts: null };
1659
1663
  })
1660
- .then(doc => doc
1661
- ? doc.ts
1662
- ? next(step7({ ...l, ts: doc.ts }), 'nothing changed')
1663
- : next(step2, 'restart')
1664
- : step8(l)), 'wait for change');
1664
+ .then(doc => (doc ? next(step3({ _id: streamName, ts: l.ts }), 'restart') : step8(l))), 'wait for change');
1665
1665
  };
1666
- return stop;
1666
+ return skip
1667
+ ? withStop(() => synchronousPromise.SynchronousPromise.resolve(next(step3(null), 'clone into new collection')))
1668
+ : stop;
1667
1669
  };
1668
1670
  const hasBefore = root().of('before').has($ne(null));
1669
1671
  return {
@@ -1686,7 +1688,9 @@ const executes = (view, input, streamName) => {
1686
1688
  streamNames[streamName] = hash;
1687
1689
  else if (streamNames[streamName] != hash)
1688
1690
  throw new Error('streamName already used');
1689
- const { collection, projection, hardMatch, match } = view;
1691
+ const { collection, projection, hardMatch: pre, match } = view;
1692
+ const removeNotYetSynchronizedFields = Object.values(mapExactToObject(projection, (_, k) => k.startsWith('_') ? root().of(k).has($exists(true)) : null));
1693
+ const hardMatch = $and(pre, ...removeNotYetSynchronizedFields);
1690
1694
  const job = {};
1691
1695
  const db = collection.s.db, coll = collection.collectionName;
1692
1696
  db.command({
@@ -1717,6 +1721,8 @@ const executes = (view, input, streamName) => {
1717
1721
  input: input,
1718
1722
  finalInputFirst: finalInput.raw(true),
1719
1723
  finalInput: finalInput.raw(false),
1724
+ match: view.match?.raw(root()).get(),
1725
+ project: projection,
1720
1726
  teardown: finalInput.teardown((x) => ({
1721
1727
  collection: x.collection.collectionName,
1722
1728
  method: x.method,
@@ -1746,7 +1752,14 @@ const executes = (view, input, streamName) => {
1746
1752
  };
1747
1753
  if (exists && !same)
1748
1754
  await handleTeardown(exists);
1749
- return next(step4(same), 'clone into new collection');
1755
+ return {
1756
+ cont: withStop(async () => {
1757
+ await new Promise(resolve => setTimeout(resolve, 1000));
1758
+ return step4(same)();
1759
+ }),
1760
+ data: [],
1761
+ info: { debug: 'clone into new collection', job: undefined },
1762
+ };
1750
1763
  };
1751
1764
  const makeStream = (startAt) => makeWatchStream(db, view, startAt, streamName);
1752
1765
  const step4 = (lastTS) => async () => {
@@ -1772,11 +1785,7 @@ const executes = (view, input, streamName) => {
1772
1785
  info: { job: undefined, debug: 'wait for change' },
1773
1786
  cont: withStop(() => l.stream
1774
1787
  .tryNext()
1775
- .then(doc => doc
1776
- ? doc.ts
1777
- ? next(step7({ ...l, ts: doc.ts }), 'nothing changed')
1778
- : next(step1, 'restart')
1779
- : step8(l))),
1788
+ .then(doc => (doc ? next(step4({ _id: streamName, ts: l.ts }), 'restart') : step8(l)))),
1780
1789
  };
1781
1790
  };
1782
1791
  return stop;
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.54",
6
+ "version": "0.0.56",
7
7
  "dependencies": {
8
8
  "dayjs": "^1.11.9",
9
9
  "dotenv": "^16.3.1",