Skip to content

Commit

Permalink
Add skipPoll support for json1 ops, instead of throwing errors for them
Browse files Browse the repository at this point in the history
  • Loading branch information
ericyhwang committed Jan 9, 2023
1 parent e72c6bb commit 234384e
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 3 deletions.
44 changes: 41 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -1044,10 +1044,44 @@ function getInnerFields(params, fields) {
function opContainsAnyField(op, fields) {
for (var i = 0; i < op.length; i++) {
var component = op[i];
if (component.p.length === 0) {
return true;
} else if (fields[component.p[0]]) {
if (Array.isArray(component.p)) {
// json0 op component:
//
// Each op component has its own array of `p` path segments from doc root.
if (component.p.length === 0) {
return true;
} else if (fields[component.p[0]]) {
return true;
}
} else if (typeof component === 'string') {
// json1 field descent from root:
//
// First string in top-level array means all subsequent operations will be
// underneath that top-level field, no need to continue iterating.
return fields[component];
} else if (hasOwnProperty(component, 'p') ||
hasOwnProperty(component, 'r') ||
hasOwnProperty(component, 'd') ||
hasOwnProperty(component, 'i') ||
hasOwnProperty(component, 'e')) {
// json1 root-level operation:
//
// If we encounter an operation at top level prior to encountering a string,
// (field descent) then the operation affects the entire document.
return true;
} else if (Array.isArray(component)) {
// json1 child operation list:
//
// In a canonical json1 op, if we encounter a child op prior to encountering
// a string (field descent), then the child should start with a field descent.
// If that weren't the case, the op would be pulled up to the top-level array.
var descendant = component;
while (typeof descendant[0] !== 'string') {
descendant = descendant[0];
}
if (fields[descendant[0]]) {
return true;
}
}
}
return false;
Expand Down Expand Up @@ -1457,6 +1491,10 @@ function isPlainObject(value) {
);
}

function hasOwnProperty(obj, prop) {
return Object.prototype.hasOwnProperty.call(obj, prop);
}

// Convert a simple map of fields that we want into a mongo projection. This
// depends on the data being stored at the top level of the document. It will
// only work properly for json documents--which are the only types for which
Expand Down
46 changes: 46 additions & 0 deletions test/test_skip_poll.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
var expect = require('chai').expect;
var json1 = require('ot-json1');
var ShareDbMongo = require('../index');

describe('skipPoll', function() {
Expand Down Expand Up @@ -111,6 +112,51 @@ describe('skipPoll', function() {
assertNotSkips({op: [{p: ['a'], dummyOp: 1}, {p: [], dummyOp: 1}]}, query);
assertNotSkips({op: [{p: [], dummyOp: 1}, {p: ['x'], dummyOp: 1}]}, query);
});

it('json1 root-level changes', function() {
// Root-level doc changes should always cause a query poll.
assertNotSkips({op: json1.insertOp('', {brandNew: 'value'})}, query);
assertNotSkips({op: json1.removeOp('')}, query);
});

it('json1 ops not affecting queried fields', function() {
assertSkips({op: json1.insertOp(['notQueried'], 'hello')}, query);
assertSkips({op: json1.moveOp(['notQueried'], ['alsoNotQueried'])}, query);
assertSkips({op: json1.removeOp(['notQueried'], 'hello')}, query);
});

it('json1 insert ops', function() {
assertIfSkips({op: json1.insertOp(['a'], 'hello')}, query, !has(fields, 'a'));
assertIfSkips({op: json1.insertOp(['a', 'b'], 'hello')}, query, !has(fields, 'a'));
assertIfSkips({op: json1.insertOp(['a', 0], 'hello')}, query, !has(fields, 'a'));
});

it('json1 remove ops', function() {
assertIfSkips({op: json1.removeOp(['a'], 'hello')}, query, !has(fields, 'a'));
assertIfSkips({op: json1.removeOp(['a', 'b'], 'hello')}, query, !has(fields, 'a'));
assertIfSkips({op: json1.removeOp(['a', 0], 'hello')}, query, !has(fields, 'a'));
});

it('json1 move ops', function() {
assertIfSkips({op: json1.moveOp(['a'], ['x'])}, query, !has(fields, 'a') && !has(fields, 'x'));
assertIfSkips({op: json1.moveOp(['x'], ['a'])}, query, !has(fields, 'x') && !has(fields, 'a'));
assertIfSkips({op: json1.moveOp(['a'], ['notQueried'])}, query, !has(fields, 'a'));
assertIfSkips({op: json1.moveOp(['notQueried'], ['a'])}, query, !has(fields, 'a'));
assertSkips({op: json1.moveOp(['notQueried'], ['alsoNotQueried'])}, query);
});

it('json1 composed ops', function() {
var compositeNotQueried = json1.type.compose(
json1.insertOp(['notQueried1'], 'hello'),
json1.moveOp(['notQueried2'], ['notQueried3'])
);
assertSkips({op: compositeNotQueried}, query);
var compositeQueried = json1.type.compose(
json1.insertOp(['notQueried1'], 'hello'),
json1.moveOp(['notQueried2'], ['a'])
);
assertIfSkips({op: compositeQueried}, query, !has(fields, 'a'));
});
});
}
});
Expand Down

0 comments on commit 234384e

Please sign in to comment.