Skip to content

Commit

Permalink
Smart list strategy updates paginated metadata (#33)
Browse files Browse the repository at this point in the history
  • Loading branch information
daffl committed Sep 5, 2016
1 parent 8576504 commit 69622be
Show file tree
Hide file tree
Showing 2 changed files with 155 additions and 39 deletions.
71 changes: 50 additions & 21 deletions src/strategies.js
Expand Up @@ -21,8 +21,7 @@ export default function(Rx) {
events.updated,
events.patched
).flatMap(() => {
const result = _super(...args);
const source = Rx.Observable.fromPromise(result);
const source = Rx.Observable.fromPromise(_super(...args));

return source.map(sortAndTrim);
})
Expand All @@ -37,37 +36,67 @@ export default function(Rx) {
// A function that sorts a limits a result (paginated or not)
const sortAndTrim = options.sorter(query, options);
const onCreated = eventData => {
return items => {
const result = items.concat(eventData);
// result.total = 1;
return result;
return page => {
const isPaginated = !!page[options.dataField];
const process = data => data.concat(eventData);

if(isPaginated) {
return Object.assign({}, page, {
total: page.total + 1,
[options.dataField]: process(page[options.dataField])
});
}

return process(page);
};
};
const onRemoved = eventData => {
return items => items.filter(current =>
eventData[options.idField] !== current[options.idField]
);
return page => {
const isPaginated = !!page[options.dataField];
const process = data => data.filter(current =>
eventData[options.idField] !== current[options.idField]
);

if(isPaginated) {
return Object.assign({}, page, {
total: matches(eventData) ? page.total - 1 : page.total,
[options.dataField]: process(page[options.dataField])
});
}

return process(page);
};
};
const onUpdated = eventData => {
return items => items.filter(current =>
eventData[options.idField] !== current[options.idField]
).concat(eventData).filter(matches);
return page => {
const isPaginated = !!page[options.dataField];
const length = isPaginated ? page[options.dataField].length :
page.length;
const process = data =>
data.filter(current =>
eventData[options.idField] !== current[options.idField]
).concat(eventData).filter(matches);

if(isPaginated) {
const processed = process(page[options.dataField]);
return Object.assign({}, page, {
// Total can be either decreased or increased based
// on if the update removed or added the item to the list
total: page.total - (length - processed.length),
[options.dataField]: processed
});
}

return process(page);
};
};

return source.concat(source.exhaustMap(data =>
Rx.Observable.merge(
events.created.filter(matches).map(onCreated),
events.removed.map(onRemoved),
Rx.Observable.merge(events.updated, events.patched).map(onUpdated)
).scan((current, callback) => {
const isPaginated = !!current[options.dataField];
if (isPaginated) {
current[options.dataField] = callback(current[options.dataField]);
} else {
current = callback(current);
}
return sortAndTrim(current);
}, data)
).scan((current, callback) => sortAndTrim(callback(current)), data)
));
}
};
Expand Down
123 changes: 105 additions & 18 deletions test/list.test.js
Expand Up @@ -336,25 +336,112 @@ describe('reactive lists', () => {

function paginationTests (id) {
it('removes items if the data length is past the limit', done => {
Promise.all([
service.create({ text: 'first' }),
service.create({ text: 'second' }),
]).then(() => {
const expect = [
{text: 'A test message', [id]: 0},
{text: 'first', [id]: 1},
{text: 'second', [id]: 2}
];
const result = service.find();

result.take(2).subscribe(messages => {
assert.deepEqual(messages.data, expect);
}, () => {}, () => done());
const expect = [
{ text: 'A test message', [id]: 0 },
{ text: 'first', [id]: 1 },
{ text: 'second', [id]: 2 }
];
const result = service.find();

result.skip(3).subscribe(messages => {
assert.deepEqual(messages.data, expect);
done();
}, done);

setTimeout(() => {
service.create({text: 'third'});
}, 20);
});
setTimeout(() => {
service.create({ text: 'first' });
service.create({ text: 'second' });
service.create({text: 'third'});
}, 20);
});

it('.create updates total', done => {
service.find().first().subscribe(data => {
assert.deepEqual(data, {
total: 1,
limit: 3,
skip: 0,
data: [
{ text: 'A test message', id: 0 }
]
});
}, done);

service.find().skip(2).subscribe(data => {
assert.deepEqual(data, {
total: 3,
limit: 3,
skip: 0,
data: [
{ text: 'A test message', [id]: 0 },
{ text: 'first', [id]: 1 },
{ text: 'second', [id]: 2 }
]
});
done();
}, done);

setTimeout(() => {
service.create({ text: 'first' });
service.create({ text: 'second' });
}, 20);
});

it('.remove updates total', done => {
service.find().first().subscribe(data => {
assert.deepEqual(data, {
total: 1,
limit: 3,
skip: 0,
data: [
{ text: 'A test message', id: 0 }
]
});
}, done);

service.find().skip(1).subscribe(data => {
assert.deepEqual(data, {
total: 0,
limit: 3,
skip: 0,
data: []
});
done();
}, done);

setTimeout(() => service.remove(0), 20);
});

it('update to matching query updates total', done => {
const empty = {
total: 0,
limit: 3,
skip: 0,
data: []
};
const text = 'updated text';

service.find({ query: { text } }).first()
.subscribe(data => assert.deepEqual(data, empty), done);

service.find({ query: { text } }).skip(1).first().subscribe(data => {
assert.deepEqual(data, {
total: 1,
limit: 3,
skip: 0,
data: [
{ [id]: 0, text: 'updated text' }
]
});
setTimeout(() => service.patch(0, { text: 'changed again' }));
}, done);

service.find({ query: { text } }).skip(2).first().subscribe(data => {
assert.deepEqual(data, empty);
done();
}, done);

setTimeout(() => service.patch(0, { text }));
});
}
});

0 comments on commit 69622be

Please sign in to comment.