@omegup/msync 0.0.29 → 0.0.32-test1

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 +8 -2
  2. package/index.esm.js +153 -124
  3. package/index.js +153 -124
  4. package/package.json +1 -1
package/index.d.ts CHANGED
@@ -55,7 +55,7 @@ declare const root: <T extends O>() => Field<T, T, unknown>;
55
55
  declare const ctx: <T>() => <K extends string>(k: K) => Field<unknown, T, RORec<K, T>>;
56
56
 
57
57
  declare const QueryRaw: unique symbol;
58
- type QueryRaw<T, C> = RawObj & {
58
+ type QueryRaw<T, C = unknown> = RawObj & {
59
59
  [Type]?(x: typeof QueryRaw, y: T, c: C): void;
60
60
  };
61
61
  declare const Query: unique symbol;
@@ -316,6 +316,12 @@ declare global {
316
316
  race<T extends readonly unknown[] | []>(values: T): Promise<Awaited<T[number]>>;
317
317
  }
318
318
  }
319
+ declare module 'synchronous-promise' {
320
+ interface SynchronousPromiseConstructor {
321
+ any<T extends readonly unknown[] | [], _ extends 0 = 0>(values: AppMap<PromiseHKT, T>): SynchronousPromise<T[number]>;
322
+ any<T extends readonly unknown[] | []>(values: T): SynchronousPromise<Awaited<T[number]>>;
323
+ }
324
+ }
319
325
 
320
326
  declare const RawStage: unique symbol;
321
327
  declare module 'mongodb' {
@@ -472,7 +478,7 @@ declare const $set: <V extends O>() => <R extends O, C = unknown>(fields: MapO<V
472
478
  declare const $replaceWith: <T extends O, V extends O>(expr: Expr<V, T>) => DeltaStages<O, T, V> & LinStages<O, T, V>;
473
479
 
474
480
  type s$1 = string;
475
- declare const $unwindDelta: <K1 extends s$1, T extends doc, K2 extends s$1, U extends doc>(k1: AsLiteral<K1>, k2: AsLiteral<K2>, k: K1 | K2 | false) => RawStages<Delta<Rec<K1, T>>, Delta<Rec<K1, T> & Rec<K2, Arr<U>>>, Delta<Rec<K1, T> & Rec<K2, U> & ID>>;
481
+ declare const $unwindDelta: <K1 extends s$1, T extends doc, K2 extends s$1, U extends doc, Null extends null = never>(k1: AsLiteral<K1>, k2: AsLiteral<K2>, k: K1 | K2 | false, includeNull?: Null) => RawStages<Delta<Rec<K1, T>>, Delta<Rec<K1, T> & Rec<K2, Arr<U>>>, Delta<Rec<K1, T> & Rec<K2, U | Null> & ID>>;
476
482
 
477
483
  type s = string;
478
484
  declare const $unwind: <T extends doc, K extends s, U extends doc>(k: AsLiteral<K>, dict: RORec<K, "key">) => DeltaStages<O, T & Rec<K, Arr<U>>, T & Rec<K, U>>;
package/index.esm.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { SynchronousPromise } from 'synchronous-promise';
1
2
  import { UUID, MongoClient } from 'mongodb';
2
3
  import crypto$1 from 'crypto';
3
4
  import { writeFile } from 'fs/promises';
@@ -464,7 +465,12 @@ const $replaceWith1 = (expr) => f => {
464
465
  { $replaceWith: parts.reduce((v, k) => ({ [k]: v }), expr.raw(f()).get()) },
465
466
  ]);
466
467
  };
467
- const $unwind1 = (k) => f => asStages([{ $unwind: `$${f().of(k).str()}` }]);
468
+ const $unwind1 = (k, includeNull) => f => {
469
+ const path = `$${f().of(k).str()}`;
470
+ return asStages([
471
+ { $unwind: path },
472
+ ]);
473
+ };
468
474
  const $group1 = (id, args) => (f) => asStages([
469
475
  {
470
476
  $group: {
@@ -495,7 +501,7 @@ const $simpleLookup1 = (args) => f => {
495
501
  const $match_ = (query) => $match1(query)(root);
496
502
  const $set_ = (updater) => $set1(updater)(root);
497
503
  const $replaceWith_ = (expr) => $replaceWith1(expr)(root);
498
- const $unwind_ = (k) => $unwind1(k)(root);
504
+ const $unwind_ = (k, includeNull) => $unwind1(k)(root);
499
505
  const $group_ = () => (id, args) => $group1(id, args)(root);
500
506
  const $project_ = $project1;
501
507
  const $simpleLookup_ = (args) => $simpleLookup1(args)(root);
@@ -611,29 +617,6 @@ const $groupMerge = (id, args, out, gid, extra, idPrefix = '') => ({
611
617
  const $groupId = (id, args, out, extra) => $groupMerge(id, args, { into: out, whenNotMatched: 'fail' }, '_id', extra);
612
618
  const $group = (id, args, out, extra, idPrefix = '') => $groupMerge(id, args, { into: out, whenNotMatched: 'insert' }, '_grp', extra, idPrefix);
613
619
 
614
- const $expr = (expr) => ({
615
- raw: f => ({ $expr: expr.raw(f).get() }),
616
- });
617
-
618
- const $lookupRaw = ({ field1, field2 }, { coll, exec, input }, k2, k) => (f) => {
619
- root().of('_id').expr();
620
- root().of(k2).of('_id').expr();
621
- return link()
622
- .with($simpleLookup1({
623
- coll,
624
- k: k2,
625
- vars: map1('local', root().with(field1).expr()),
626
- pipeline: link()
627
- .with(input)
628
- .with($match_($expr(eq(ctx()('local').expr())(root().of('before').with(field2).expr()))))
629
- .with(exec)
630
- .with($replaceWith_(root().of('before').expr())).stages,
631
- })(f))
632
- .with($unwind1(k2)(f))
633
- .with(link().stages
634
- ).stages;
635
- };
636
-
637
620
  const deltaExpr = (expr) => (field) => {
638
621
  return ite(eqTyped($ifNull(root().of(field).expr(), nil), nil), nil, expr(field));
639
622
  };
@@ -663,7 +646,82 @@ const $setDelta = (updater) => {
663
646
  .with($setEach(k => to(nil), dict)).stages;
664
647
  };
665
648
 
666
- const $unwindDelta = (k1, k2, k) => {
649
+ const $unwindDelta = (k1, k2, k, includeNull) => {
650
+ const outer = includeNull === null;
651
+ const newItems = {
652
+ $filter: {
653
+ input: { $ifNull: [`$after.${k2}`, []] },
654
+ as: 'a',
655
+ cond: {
656
+ $not: {
657
+ $in: [
658
+ '$$a._id',
659
+ {
660
+ $map: {
661
+ input: { $ifNull: [`$before.${k2}`, []] },
662
+ as: 'b',
663
+ in: '$$b._id',
664
+ },
665
+ },
666
+ ],
667
+ },
668
+ },
669
+ },
670
+ };
671
+ const oldItems = {
672
+ $filter: {
673
+ input: {
674
+ $map: {
675
+ input: { $ifNull: [`$before.${k2}`, []] },
676
+ as: 'b',
677
+ in: {
678
+ before: '$$b',
679
+ after: {
680
+ $ifNull: [
681
+ {
682
+ $first: {
683
+ $filter: {
684
+ input: `$after.${k2}`,
685
+ as: 'a',
686
+ cond: { $eq: ['$$a._id', '$$b._id'] },
687
+ },
688
+ },
689
+ },
690
+ null,
691
+ ],
692
+ },
693
+ },
694
+ },
695
+ },
696
+ as: 'a',
697
+ cond: { $ne: ['$$a.before', '$$a.after'] },
698
+ },
699
+ };
700
+ const ifNull = (k, part, str = `$${[k1, k2].sort()[0]}.${part}._id`) => outer && k == k2 ? { $ifNull: [str, 'null'] } : str;
701
+ const interDot = ([a, b]) => [a, '.', b];
702
+ const partReplace = (part) => ({
703
+ $cond: {
704
+ if: { $or: [{ $eq: [`$${k1}.${part}`, null] }, { $eq: [`$${k2}.${part}`, null] }] },
705
+ then: null,
706
+ else: {
707
+ _id: k
708
+ ? `$${k}.${part}._id`
709
+ : {
710
+ $concat: interDot([k1, k2].sort().map(k => ifNull(k, part))),
711
+ },
712
+ [k1]: `$${k1}.${part}`,
713
+ [k2]: outer
714
+ ? {
715
+ $cond: {
716
+ if: `$${k2}.${part}._id`,
717
+ then: `$${k2}.${part}`,
718
+ else: null,
719
+ },
720
+ }
721
+ : `$${k2}.${part}`,
722
+ },
723
+ },
724
+ });
667
725
  const stages = link()
668
726
  .with(asStages([
669
727
  {
@@ -674,51 +732,34 @@ const $unwindDelta = (k1, k2, k) => {
674
732
  },
675
733
  [k2]: {
676
734
  $concatArrays: [
677
- {
678
- $map: {
679
- input: { $ifNull: [`$before.${k2}`, []] },
680
- as: 'b',
681
- in: {
682
- before: '$$b',
683
- after: {
684
- $ifNull: [
685
- {
686
- $first: {
687
- $filter: {
688
- input: `$after.${k2}`,
689
- as: 'a',
690
- cond: { $eq: ['$$a._id', '$$b._id'] },
691
- },
692
- },
693
- },
694
- null,
695
- ],
735
+ outer
736
+ ? {
737
+ $cond: {
738
+ if: { $eq: [`$before.${k2}`, []] },
739
+ then: {
740
+ $cond: {
741
+ if: { $eq: [`$after.${k2}`, []] },
742
+ then: [],
743
+ else: [{ before: {}, after: null }],
744
+ },
696
745
  },
746
+ else: oldItems,
697
747
  },
698
- },
699
- },
748
+ }
749
+ : oldItems,
700
750
  {
701
751
  $map: {
702
- input: {
703
- $filter: {
704
- input: { $ifNull: [`$after.${k2}`, []] },
705
- as: 'a',
706
- cond: {
707
- $not: {
708
- $in: [
709
- '$$a._id',
710
- {
711
- $map: {
712
- input: { $ifNull: [`$before.${k2}`, []] },
713
- as: 'b',
714
- in: '$$b._id',
715
- },
716
- },
717
- ],
752
+ input: outer
753
+ ? {
754
+ $cond: {
755
+ if: {
756
+ $and: [{ $ne: [`$before.${k2}`, []] }, { $eq: [`$after.${k2}`, []] }],
718
757
  },
758
+ then: [{}],
759
+ else: newItems,
719
760
  },
720
- },
721
- },
761
+ }
762
+ : newItems,
722
763
  as: 'a',
723
764
  in: { before: null, after: '$$a' },
724
765
  },
@@ -732,45 +773,9 @@ const $unwindDelta = (k1, k2, k) => {
732
773
  .with(asStages([
733
774
  {
734
775
  $replaceWith: {
735
- _id: "$_id",
736
- before: {
737
- $cond: {
738
- if: { $or: [{ $eq: [`$${k1}.before`, null] }, { $eq: [`$${k2}.before`, null] }] },
739
- then: null,
740
- else: {
741
- _id: {
742
- $concat: k
743
- ? `$${k}.before._id`
744
- : [
745
- `$${[k1, k2].sort()[0]}.before._id`,
746
- '.',
747
- `$${[k1, k2].sort()[1]}.before._id`,
748
- ],
749
- },
750
- [k1]: `$${k1}.before`,
751
- [k2]: `$${k2}.before`,
752
- },
753
- },
754
- },
755
- after: {
756
- $cond: {
757
- if: { $or: [{ $eq: [`$${k1}.after`, null] }, { $eq: [`$${k2}.after`, null] }] },
758
- then: null,
759
- else: {
760
- _id: {
761
- $concat: k
762
- ? `$${k}.after._id`
763
- : [
764
- `$${[k1, k2].sort()[0]}.after._id`,
765
- '.',
766
- `$${[k1, k2].sort()[1]}.after._id`,
767
- ],
768
- },
769
- [k1]: `$${k1}.after`,
770
- [k2]: `$${k2}.after`,
771
- },
772
- },
773
- },
776
+ _id: '$_id',
777
+ before: partReplace('before'),
778
+ after: partReplace('after'),
774
779
  },
775
780
  },
776
781
  ])).stages;
@@ -790,7 +795,7 @@ const $unwind = (k, dict) => ({
790
795
  raw: $unwind1(k),
791
796
  });
792
797
 
793
- const $lookupDelta = ({ field1, field2 }, { coll, exec, input }, k1, k2, k) => {
798
+ const $lookupDelta = ({ field1, field2 }, { coll, exec, input }, k1, k2, k, includeNull) => {
794
799
  return link()
795
800
  .with($replaceWithDelta(field(map1(k1, root().expr()))))
796
801
  .with($simpleLookup_({
@@ -819,8 +824,30 @@ const $lookupDelta = ({ field1, field2 }, { coll, exec, input }, k1, k2, k) => {
819
824
  const a = root().of(f1).of('before').expr();
820
825
  const part = root().of(f);
821
826
  return ite(eq(root().of(f).expr())(nil), nil, field(omit.backward(mergeExpr(omit.forward(map1(k2, a)), map1(k1, part.of(k1).expr())))));
822
- }))
823
- .with($unwindDelta(k1, k2, k)).stages;
827
+ })).with($unwindDelta(k1, k2, k, includeNull)).stages;
828
+ };
829
+
830
+ const $expr = (expr) => ({
831
+ raw: f => ({ $expr: expr.raw(f).get() }),
832
+ });
833
+
834
+ const $lookupRaw = ({ field1, field2 }, { coll, exec, input }, k2, k) => (f) => {
835
+ root().of('_id').expr();
836
+ root().of(k2).of('_id').expr();
837
+ return link()
838
+ .with($simpleLookup1({
839
+ coll,
840
+ k: k2,
841
+ vars: map1('local', root().with(field1).expr()),
842
+ pipeline: link()
843
+ .with(input)
844
+ .with($match_($expr(eq(ctx()('local').expr())(root().of('before').with(field2).expr()))))
845
+ .with(exec)
846
+ .with($replaceWith_(root().of('before').expr())).stages,
847
+ })(f))
848
+ .with($unwind1(k2)(f))
849
+ .with(link().stages
850
+ ).stages;
824
851
  };
825
852
 
826
853
  const asBefore = (f) => f(() => root().of('before'));
@@ -848,18 +875,20 @@ const patch = (x, k, v) => ({ ...x, [k]: v });
848
875
  const restart = (sources) => {
849
876
  return map(sources, x => x.stop());
850
877
  };
851
- const race = async (sources) => {
878
+ const race = (sources) => {
852
879
  const promises = Object.values(map(sources, ({ next }, key) => next.then(frame => ({ key, sources, frame }))));
853
- return Promise.race(promises);
880
+ return SynchronousPromise.any(promises);
854
881
  };
855
882
 
856
- const nextWinner = async (previousWinner, previousWinnerNextFrame, sources, interrupt) => {
883
+ const nextWinner = (previousWinner, previousWinnerNextFrame, sources, interrupt) => {
857
884
  const { frame: previousFrame, key } = previousWinner;
858
885
  if (!interrupt?.(key) && previousFrame.info.job) {
859
- const previousFrameSuccessor = await previousWinnerNextFrame;
860
- if (previousFrame.info.job === previousFrameSuccessor.info.job) {
861
- return { frame: previousFrameSuccessor, key };
862
- }
886
+ return previousWinnerNextFrame.then((previousFrameSuccessor) => {
887
+ if (previousFrameSuccessor.info.job) {
888
+ return { frame: previousFrameSuccessor, key };
889
+ }
890
+ return race(sources);
891
+ });
863
892
  }
864
893
  return race(sources);
865
894
  };
@@ -921,7 +950,7 @@ class Machine {
921
950
  return runCont(run(), cb);
922
951
  }
923
952
  }
924
- const wrap = (root) => new Machine(root.runner());
953
+ const wrap = (root) => root;
925
954
  const runCont = async ({ next }, cb) => {
926
955
  const { cont, info } = await next;
927
956
  const stopped = cb?.(info);
@@ -934,9 +963,9 @@ const runCont = async ({ next }, cb) => {
934
963
  };
935
964
 
936
965
  const merge = ({ lsource: L, rsource: R, }) => mergeIterators({ sources: { L, R } });
937
- const join = ({ lField, rField, left, right, as }, leftSnapshot, rightSnapshot, stagesUntilNextLookup) => {
938
- createIndex(leftSnapshot.coll, { [lField.str()]: 1 }).catch(e => e.code == 86 || Promise.reject(e));
939
- createIndex(rightSnapshot.coll, { [rField.str()]: 1 }).catch(e => e.code == 86 || Promise.reject(e));
966
+ const join = ({ lField, rField, left, right, as }, leftSnapshot, rightSnapshot, stagesUntilNextLookup, includeNull) => {
967
+ createIndex(leftSnapshot.coll, { [`before.${lField.str()}`]: 1 }).catch(e => e.code == 86 || Promise.reject(e));
968
+ createIndex(rightSnapshot.coll, { [`before.${rField.str()}`]: 1 }).catch(e => e.code == 86 || Promise.reject(e));
940
969
  const rightJoinField = { field1: lField, field2: rField };
941
970
  const joinId = 'left';
942
971
  const joinR_Snapshot = asBefore($lookupRaw(rightJoinField, rightSnapshot, as));
@@ -949,7 +978,7 @@ const join = ({ lField, rField, left, right, as }, leftSnapshot, rightSnapshot,
949
978
  out: (finalInput) => {
950
979
  const leftJoinField = { field1: rField, field2: lField };
951
980
  const joinL_Delta = $lookupDelta(leftJoinField, leftSnapshot, 'right', 'left', joinId);
952
- const joinR_Delta = $lookupDelta(rightJoinField, rightSnapshot, 'left', 'right', joinId);
981
+ const joinR_Delta = $lookupDelta(rightJoinField, rightSnapshot, 'left', 'right', joinId, includeNull);
953
982
  const mergeForeignIntoDoc = concatStages($replaceWithDelta(mergeObjects(root().of('left').expr(), fieldM({ a: root().of('right').expr(), b: root().of('_id').expr() }, dictId))), stagesUntilNextLookup.delta);
954
983
  const lRunnerInput = concatStages(joinR_Delta, mergeForeignIntoDoc);
955
984
  const rRunnerInput = concatStages(joinL_Delta, mergeForeignIntoDoc);
@@ -1183,7 +1212,7 @@ const makeWatchStream = (db, { collection, projection: p, hardMatch: m }, startA
1183
1212
  };
1184
1213
 
1185
1214
  const actions = {
1186
- updateMany: (c, args) => [c.updateMany(...args), [`db['${c.collectionName}'].updateMany(`, ...args, ')']],
1215
+ updateMany: (c, args) => [c.updateMany(...args), [`db['${c.collectionName}'].updateMany(...`, args, ')']],
1187
1216
  };
1188
1217
  const streamNames = {};
1189
1218
  const executes$1 = (view, input, streamName) => {
@@ -1242,7 +1271,7 @@ const executes$1 = (view, input, streamName) => {
1242
1271
  params: x.params,
1243
1272
  })),
1244
1273
  };
1245
- const step0 = () => Promise.resolve(next(step1, 'empty new collection'));
1274
+ const step0 = () => SynchronousPromise.resolve(next(step1, 'empty new collection'));
1246
1275
  const stop = withStop(step0);
1247
1276
  const step1 = async () => {
1248
1277
  await snapshotCollection.updateMany({ updated: true }, { $set: { updated: false, after: null } });
@@ -1263,9 +1292,9 @@ const executes$1 = (view, input, streamName) => {
1263
1292
  params: p,
1264
1293
  };
1265
1294
  const [action, out] = actions[method](collection, params);
1266
- log('teardown', `db.['${snapshotCollection.collectionName}'].drop()`, ...out);
1295
+ log('teardown', `db['${snapshotCollection.collectionName}'].drop()`, ...out);
1267
1296
  await Promise.all([snapshotCollection.drop(), action]);
1268
- log('teardown done', `db.['${snapshotCollection.collectionName}'].drop()`, ...out);
1297
+ log('teardown done', `db['${snapshotCollection.collectionName}'].drop()`, ...out);
1269
1298
  };
1270
1299
  if (exists && !same)
1271
1300
  await handleTeardown(exists);
@@ -1405,7 +1434,7 @@ const executes = (view, input, streamName) => {
1405
1434
  params: x.params,
1406
1435
  })),
1407
1436
  };
1408
- const step0 = () => Promise.resolve(next(step1, 'get last update'));
1437
+ const step0 = () => SynchronousPromise.resolve(next(step1, 'get last update'));
1409
1438
  const stop = withStop(step0);
1410
1439
  const step1 = () => Promise.all([
1411
1440
  last.findOne({ _id: streamName, data }),
package/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  'use strict';
2
2
 
3
+ var synchronousPromise = require('synchronous-promise');
3
4
  var mongodb = require('mongodb');
4
5
  var crypto$1 = require('crypto');
5
6
  var promises = require('fs/promises');
@@ -466,7 +467,12 @@ const $replaceWith1 = (expr) => f => {
466
467
  { $replaceWith: parts.reduce((v, k) => ({ [k]: v }), expr.raw(f()).get()) },
467
468
  ]);
468
469
  };
469
- const $unwind1 = (k) => f => asStages([{ $unwind: `$${f().of(k).str()}` }]);
470
+ const $unwind1 = (k, includeNull) => f => {
471
+ const path = `$${f().of(k).str()}`;
472
+ return asStages([
473
+ { $unwind: path },
474
+ ]);
475
+ };
470
476
  const $group1 = (id, args) => (f) => asStages([
471
477
  {
472
478
  $group: {
@@ -497,7 +503,7 @@ const $simpleLookup1 = (args) => f => {
497
503
  const $match_ = (query) => $match1(query)(root);
498
504
  const $set_ = (updater) => $set1(updater)(root);
499
505
  const $replaceWith_ = (expr) => $replaceWith1(expr)(root);
500
- const $unwind_ = (k) => $unwind1(k)(root);
506
+ const $unwind_ = (k, includeNull) => $unwind1(k)(root);
501
507
  const $group_ = () => (id, args) => $group1(id, args)(root);
502
508
  const $project_ = $project1;
503
509
  const $simpleLookup_ = (args) => $simpleLookup1(args)(root);
@@ -613,29 +619,6 @@ const $groupMerge = (id, args, out, gid, extra, idPrefix = '') => ({
613
619
  const $groupId = (id, args, out, extra) => $groupMerge(id, args, { into: out, whenNotMatched: 'fail' }, '_id', extra);
614
620
  const $group = (id, args, out, extra, idPrefix = '') => $groupMerge(id, args, { into: out, whenNotMatched: 'insert' }, '_grp', extra, idPrefix);
615
621
 
616
- const $expr = (expr) => ({
617
- raw: f => ({ $expr: expr.raw(f).get() }),
618
- });
619
-
620
- const $lookupRaw = ({ field1, field2 }, { coll, exec, input }, k2, k) => (f) => {
621
- root().of('_id').expr();
622
- root().of(k2).of('_id').expr();
623
- return link()
624
- .with($simpleLookup1({
625
- coll,
626
- k: k2,
627
- vars: map1('local', root().with(field1).expr()),
628
- pipeline: link()
629
- .with(input)
630
- .with($match_($expr(eq(ctx()('local').expr())(root().of('before').with(field2).expr()))))
631
- .with(exec)
632
- .with($replaceWith_(root().of('before').expr())).stages,
633
- })(f))
634
- .with($unwind1(k2)(f))
635
- .with(link().stages
636
- ).stages;
637
- };
638
-
639
622
  const deltaExpr = (expr) => (field) => {
640
623
  return ite(eqTyped($ifNull(root().of(field).expr(), nil), nil), nil, expr(field));
641
624
  };
@@ -665,7 +648,82 @@ const $setDelta = (updater) => {
665
648
  .with($setEach(k => to(nil), dict)).stages;
666
649
  };
667
650
 
668
- const $unwindDelta = (k1, k2, k) => {
651
+ const $unwindDelta = (k1, k2, k, includeNull) => {
652
+ const outer = includeNull === null;
653
+ const newItems = {
654
+ $filter: {
655
+ input: { $ifNull: [`$after.${k2}`, []] },
656
+ as: 'a',
657
+ cond: {
658
+ $not: {
659
+ $in: [
660
+ '$$a._id',
661
+ {
662
+ $map: {
663
+ input: { $ifNull: [`$before.${k2}`, []] },
664
+ as: 'b',
665
+ in: '$$b._id',
666
+ },
667
+ },
668
+ ],
669
+ },
670
+ },
671
+ },
672
+ };
673
+ const oldItems = {
674
+ $filter: {
675
+ input: {
676
+ $map: {
677
+ input: { $ifNull: [`$before.${k2}`, []] },
678
+ as: 'b',
679
+ in: {
680
+ before: '$$b',
681
+ after: {
682
+ $ifNull: [
683
+ {
684
+ $first: {
685
+ $filter: {
686
+ input: `$after.${k2}`,
687
+ as: 'a',
688
+ cond: { $eq: ['$$a._id', '$$b._id'] },
689
+ },
690
+ },
691
+ },
692
+ null,
693
+ ],
694
+ },
695
+ },
696
+ },
697
+ },
698
+ as: 'a',
699
+ cond: { $ne: ['$$a.before', '$$a.after'] },
700
+ },
701
+ };
702
+ const ifNull = (k, part, str = `$${[k1, k2].sort()[0]}.${part}._id`) => outer && k == k2 ? { $ifNull: [str, 'null'] } : str;
703
+ const interDot = ([a, b]) => [a, '.', b];
704
+ const partReplace = (part) => ({
705
+ $cond: {
706
+ if: { $or: [{ $eq: [`$${k1}.${part}`, null] }, { $eq: [`$${k2}.${part}`, null] }] },
707
+ then: null,
708
+ else: {
709
+ _id: k
710
+ ? `$${k}.${part}._id`
711
+ : {
712
+ $concat: interDot([k1, k2].sort().map(k => ifNull(k, part))),
713
+ },
714
+ [k1]: `$${k1}.${part}`,
715
+ [k2]: outer
716
+ ? {
717
+ $cond: {
718
+ if: `$${k2}.${part}._id`,
719
+ then: `$${k2}.${part}`,
720
+ else: null,
721
+ },
722
+ }
723
+ : `$${k2}.${part}`,
724
+ },
725
+ },
726
+ });
669
727
  const stages = link()
670
728
  .with(asStages([
671
729
  {
@@ -676,51 +734,34 @@ const $unwindDelta = (k1, k2, k) => {
676
734
  },
677
735
  [k2]: {
678
736
  $concatArrays: [
679
- {
680
- $map: {
681
- input: { $ifNull: [`$before.${k2}`, []] },
682
- as: 'b',
683
- in: {
684
- before: '$$b',
685
- after: {
686
- $ifNull: [
687
- {
688
- $first: {
689
- $filter: {
690
- input: `$after.${k2}`,
691
- as: 'a',
692
- cond: { $eq: ['$$a._id', '$$b._id'] },
693
- },
694
- },
695
- },
696
- null,
697
- ],
737
+ outer
738
+ ? {
739
+ $cond: {
740
+ if: { $eq: [`$before.${k2}`, []] },
741
+ then: {
742
+ $cond: {
743
+ if: { $eq: [`$after.${k2}`, []] },
744
+ then: [],
745
+ else: [{ before: {}, after: null }],
746
+ },
698
747
  },
748
+ else: oldItems,
699
749
  },
700
- },
701
- },
750
+ }
751
+ : oldItems,
702
752
  {
703
753
  $map: {
704
- input: {
705
- $filter: {
706
- input: { $ifNull: [`$after.${k2}`, []] },
707
- as: 'a',
708
- cond: {
709
- $not: {
710
- $in: [
711
- '$$a._id',
712
- {
713
- $map: {
714
- input: { $ifNull: [`$before.${k2}`, []] },
715
- as: 'b',
716
- in: '$$b._id',
717
- },
718
- },
719
- ],
754
+ input: outer
755
+ ? {
756
+ $cond: {
757
+ if: {
758
+ $and: [{ $ne: [`$before.${k2}`, []] }, { $eq: [`$after.${k2}`, []] }],
720
759
  },
760
+ then: [{}],
761
+ else: newItems,
721
762
  },
722
- },
723
- },
763
+ }
764
+ : newItems,
724
765
  as: 'a',
725
766
  in: { before: null, after: '$$a' },
726
767
  },
@@ -734,45 +775,9 @@ const $unwindDelta = (k1, k2, k) => {
734
775
  .with(asStages([
735
776
  {
736
777
  $replaceWith: {
737
- _id: "$_id",
738
- before: {
739
- $cond: {
740
- if: { $or: [{ $eq: [`$${k1}.before`, null] }, { $eq: [`$${k2}.before`, null] }] },
741
- then: null,
742
- else: {
743
- _id: {
744
- $concat: k
745
- ? `$${k}.before._id`
746
- : [
747
- `$${[k1, k2].sort()[0]}.before._id`,
748
- '.',
749
- `$${[k1, k2].sort()[1]}.before._id`,
750
- ],
751
- },
752
- [k1]: `$${k1}.before`,
753
- [k2]: `$${k2}.before`,
754
- },
755
- },
756
- },
757
- after: {
758
- $cond: {
759
- if: { $or: [{ $eq: [`$${k1}.after`, null] }, { $eq: [`$${k2}.after`, null] }] },
760
- then: null,
761
- else: {
762
- _id: {
763
- $concat: k
764
- ? `$${k}.after._id`
765
- : [
766
- `$${[k1, k2].sort()[0]}.after._id`,
767
- '.',
768
- `$${[k1, k2].sort()[1]}.after._id`,
769
- ],
770
- },
771
- [k1]: `$${k1}.after`,
772
- [k2]: `$${k2}.after`,
773
- },
774
- },
775
- },
778
+ _id: '$_id',
779
+ before: partReplace('before'),
780
+ after: partReplace('after'),
776
781
  },
777
782
  },
778
783
  ])).stages;
@@ -792,7 +797,7 @@ const $unwind = (k, dict) => ({
792
797
  raw: $unwind1(k),
793
798
  });
794
799
 
795
- const $lookupDelta = ({ field1, field2 }, { coll, exec, input }, k1, k2, k) => {
800
+ const $lookupDelta = ({ field1, field2 }, { coll, exec, input }, k1, k2, k, includeNull) => {
796
801
  return link()
797
802
  .with($replaceWithDelta(field(map1(k1, root().expr()))))
798
803
  .with($simpleLookup_({
@@ -821,8 +826,30 @@ const $lookupDelta = ({ field1, field2 }, { coll, exec, input }, k1, k2, k) => {
821
826
  const a = root().of(f1).of('before').expr();
822
827
  const part = root().of(f);
823
828
  return ite(eq(root().of(f).expr())(nil), nil, field(omit.backward(mergeExpr(omit.forward(map1(k2, a)), map1(k1, part.of(k1).expr())))));
824
- }))
825
- .with($unwindDelta(k1, k2, k)).stages;
829
+ })).with($unwindDelta(k1, k2, k, includeNull)).stages;
830
+ };
831
+
832
+ const $expr = (expr) => ({
833
+ raw: f => ({ $expr: expr.raw(f).get() }),
834
+ });
835
+
836
+ const $lookupRaw = ({ field1, field2 }, { coll, exec, input }, k2, k) => (f) => {
837
+ root().of('_id').expr();
838
+ root().of(k2).of('_id').expr();
839
+ return link()
840
+ .with($simpleLookup1({
841
+ coll,
842
+ k: k2,
843
+ vars: map1('local', root().with(field1).expr()),
844
+ pipeline: link()
845
+ .with(input)
846
+ .with($match_($expr(eq(ctx()('local').expr())(root().of('before').with(field2).expr()))))
847
+ .with(exec)
848
+ .with($replaceWith_(root().of('before').expr())).stages,
849
+ })(f))
850
+ .with($unwind1(k2)(f))
851
+ .with(link().stages
852
+ ).stages;
826
853
  };
827
854
 
828
855
  const asBefore = (f) => f(() => root().of('before'));
@@ -850,18 +877,20 @@ const patch = (x, k, v) => ({ ...x, [k]: v });
850
877
  const restart = (sources) => {
851
878
  return map(sources, x => x.stop());
852
879
  };
853
- const race = async (sources) => {
880
+ const race = (sources) => {
854
881
  const promises = Object.values(map(sources, ({ next }, key) => next.then(frame => ({ key, sources, frame }))));
855
- return Promise.race(promises);
882
+ return synchronousPromise.SynchronousPromise.any(promises);
856
883
  };
857
884
 
858
- const nextWinner = async (previousWinner, previousWinnerNextFrame, sources, interrupt) => {
885
+ const nextWinner = (previousWinner, previousWinnerNextFrame, sources, interrupt) => {
859
886
  const { frame: previousFrame, key } = previousWinner;
860
887
  if (!interrupt?.(key) && previousFrame.info.job) {
861
- const previousFrameSuccessor = await previousWinnerNextFrame;
862
- if (previousFrame.info.job === previousFrameSuccessor.info.job) {
863
- return { frame: previousFrameSuccessor, key };
864
- }
888
+ return previousWinnerNextFrame.then((previousFrameSuccessor) => {
889
+ if (previousFrameSuccessor.info.job) {
890
+ return { frame: previousFrameSuccessor, key };
891
+ }
892
+ return race(sources);
893
+ });
865
894
  }
866
895
  return race(sources);
867
896
  };
@@ -923,7 +952,7 @@ class Machine {
923
952
  return runCont(run(), cb);
924
953
  }
925
954
  }
926
- const wrap = (root) => new Machine(root.runner());
955
+ const wrap = (root) => root;
927
956
  const runCont = async ({ next }, cb) => {
928
957
  const { cont, info } = await next;
929
958
  const stopped = cb?.(info);
@@ -936,9 +965,9 @@ const runCont = async ({ next }, cb) => {
936
965
  };
937
966
 
938
967
  const merge = ({ lsource: L, rsource: R, }) => mergeIterators({ sources: { L, R } });
939
- const join = ({ lField, rField, left, right, as }, leftSnapshot, rightSnapshot, stagesUntilNextLookup) => {
940
- createIndex(leftSnapshot.coll, { [lField.str()]: 1 }).catch(e => e.code == 86 || Promise.reject(e));
941
- createIndex(rightSnapshot.coll, { [rField.str()]: 1 }).catch(e => e.code == 86 || Promise.reject(e));
968
+ const join = ({ lField, rField, left, right, as }, leftSnapshot, rightSnapshot, stagesUntilNextLookup, includeNull) => {
969
+ createIndex(leftSnapshot.coll, { [`before.${lField.str()}`]: 1 }).catch(e => e.code == 86 || Promise.reject(e));
970
+ createIndex(rightSnapshot.coll, { [`before.${rField.str()}`]: 1 }).catch(e => e.code == 86 || Promise.reject(e));
942
971
  const rightJoinField = { field1: lField, field2: rField };
943
972
  const joinId = 'left';
944
973
  const joinR_Snapshot = asBefore($lookupRaw(rightJoinField, rightSnapshot, as));
@@ -951,7 +980,7 @@ const join = ({ lField, rField, left, right, as }, leftSnapshot, rightSnapshot,
951
980
  out: (finalInput) => {
952
981
  const leftJoinField = { field1: rField, field2: lField };
953
982
  const joinL_Delta = $lookupDelta(leftJoinField, leftSnapshot, 'right', 'left', joinId);
954
- const joinR_Delta = $lookupDelta(rightJoinField, rightSnapshot, 'left', 'right', joinId);
983
+ const joinR_Delta = $lookupDelta(rightJoinField, rightSnapshot, 'left', 'right', joinId, includeNull);
955
984
  const mergeForeignIntoDoc = concatStages($replaceWithDelta(mergeObjects(root().of('left').expr(), fieldM({ a: root().of('right').expr(), b: root().of('_id').expr() }, dictId))), stagesUntilNextLookup.delta);
956
985
  const lRunnerInput = concatStages(joinR_Delta, mergeForeignIntoDoc);
957
986
  const rRunnerInput = concatStages(joinL_Delta, mergeForeignIntoDoc);
@@ -1185,7 +1214,7 @@ const makeWatchStream = (db, { collection, projection: p, hardMatch: m }, startA
1185
1214
  };
1186
1215
 
1187
1216
  const actions = {
1188
- updateMany: (c, args) => [c.updateMany(...args), [`db['${c.collectionName}'].updateMany(`, ...args, ')']],
1217
+ updateMany: (c, args) => [c.updateMany(...args), [`db['${c.collectionName}'].updateMany(...`, args, ')']],
1189
1218
  };
1190
1219
  const streamNames = {};
1191
1220
  const executes$1 = (view, input, streamName) => {
@@ -1244,7 +1273,7 @@ const executes$1 = (view, input, streamName) => {
1244
1273
  params: x.params,
1245
1274
  })),
1246
1275
  };
1247
- const step0 = () => Promise.resolve(next(step1, 'empty new collection'));
1276
+ const step0 = () => synchronousPromise.SynchronousPromise.resolve(next(step1, 'empty new collection'));
1248
1277
  const stop = withStop(step0);
1249
1278
  const step1 = async () => {
1250
1279
  await snapshotCollection.updateMany({ updated: true }, { $set: { updated: false, after: null } });
@@ -1265,9 +1294,9 @@ const executes$1 = (view, input, streamName) => {
1265
1294
  params: p,
1266
1295
  };
1267
1296
  const [action, out] = actions[method](collection, params);
1268
- log('teardown', `db.['${snapshotCollection.collectionName}'].drop()`, ...out);
1297
+ log('teardown', `db['${snapshotCollection.collectionName}'].drop()`, ...out);
1269
1298
  await Promise.all([snapshotCollection.drop(), action]);
1270
- log('teardown done', `db.['${snapshotCollection.collectionName}'].drop()`, ...out);
1299
+ log('teardown done', `db['${snapshotCollection.collectionName}'].drop()`, ...out);
1271
1300
  };
1272
1301
  if (exists && !same)
1273
1302
  await handleTeardown(exists);
@@ -1407,7 +1436,7 @@ const executes = (view, input, streamName) => {
1407
1436
  params: x.params,
1408
1437
  })),
1409
1438
  };
1410
- const step0 = () => Promise.resolve(next(step1, 'get last update'));
1439
+ const step0 = () => synchronousPromise.SynchronousPromise.resolve(next(step1, 'get last update'));
1411
1440
  const stop = withStop(step0);
1412
1441
  const step1 = () => Promise.all([
1413
1442
  last.findOne({ _id: streamName, data }),
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.29",
6
+ "version": "0.0.32-test1",
7
7
  "dependencies": {
8
8
  "dayjs": "^1.11.9",
9
9
  "dotenv": "^16.3.1",