Skip to content

Commit

Permalink
Merge pull request #2845 from qinyang912/master
Browse files Browse the repository at this point in the history
Feat RxCollection support bulkRemove
  • Loading branch information
pubkey authored Feb 4, 2021
2 parents 9babeaf + 57632a8 commit 31b93f8
Show file tree
Hide file tree
Showing 6 changed files with 176 additions and 3 deletions.
2 changes: 2 additions & 0 deletions docs-src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@
* [Functions](./rx-collection.md#functions)
* [$](./rx-collection.md#observe-)
* [insert()](./rx-collection.md#insert)
* [bulkInsert()](./rx-collection.md#bulkinsert)
* [bulkRemove()](./rx-collection.md#bulkremove)
* [newDocument()](./rx-collection.md#newdocument)
* [upsert()](./rx-collection.md#upsert)
* [atomicUpsert()](./rx-collection.md#atomicupsert)
Expand Down
16 changes: 16 additions & 0 deletions docs-src/rx-collection.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,22 @@ const result = await myCollection.bulkInsert([{

NOTICE: `bulkInsert` will not fail on update conflicts and you cannot expect that on failure the other documents are not inserted.

### bulkRemove()

When you want to remove many documents at once, use bulk remove. Returns an object with a `success`- and `error`-array.

```js
const result = await myCollection.bulkRemove([
'primary1',
'primary2'
]);

// > {
// success: [RxDocument, RxDocument],
// error: []
// }
```

### newDocument()
Sometimes it can be helpful to spawn and use documents before saving them into the database.
This is useful especially when you want to use the ORM methods or prefill values from form data.
Expand Down
78 changes: 76 additions & 2 deletions src/rx-collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ import {
createInsertEvent,
RxChangeEventInsert,
RxChangeEventUpdate,
RxChangeEventDelete
RxChangeEventDelete,
createDeleteEvent
} from './rx-change-event';
import {
newRxError,
Expand Down Expand Up @@ -84,7 +85,8 @@ import type {
RxDumpCollectionAny,
MangoQuery,
MangoQueryNoLimit,
RxCacheReplacementPolicy
RxCacheReplacementPolicy,
WithPouchMeta
} from './types';
import type {
RxGraphQLReplicationState
Expand Down Expand Up @@ -465,6 +467,78 @@ export class RxCollectionBase<
});
}

async bulkRemove(
ids: string[]
): Promise<{
success: RxDocument<RxDocumentType, OrmMethods>[],
error: any[]
}> {
const rxDocumentMap = await this.findByIds(ids);
const docsData: WithPouchMeta<RxDocumentType>[] = [];
const docsMap: Map<string, WithPouchMeta<RxDocumentType>> = new Map();
Array.from(rxDocumentMap.values()).forEach(rxDocument => {
const data = rxDocument.toJSON(true);
docsData.push(data);
docsMap.set(rxDocument.primary, data);
});

await Promise.all(
docsData.map(doc => {
const primary = (doc as any)[this.schema.primaryPath];
return this._runHooks('pre', 'remove', doc, rxDocumentMap.get(primary));
})
);

docsData.forEach(doc => doc._deleted = true);

const removeDocs = docsData.map(doc => this._handleToPouch(doc));

let startTime: number;

const results = await this.database.lockedRun(async () => {
startTime = now();
const bulkResults = await this.pouch.bulkDocs(removeDocs);
return bulkResults;
});

const endTime = now();

const okResults = results.filter(r => r.ok);

await Promise.all(
okResults.map(r => {
return this._runHooks(
'post',
'remove',
docsMap.get(r.id),
rxDocumentMap.get(r.id)
);
})
);

okResults.forEach(r => {
const rxDocument = rxDocumentMap.get(r.id) as RxDocument<RxDocumentType, OrmMethods>;
const emitEvent = createDeleteEvent(
this as any,
docsMap.get(r.id) as any,
rxDocument._data,
startTime,
endTime,
rxDocument as any,
);
this.$emit(emitEvent);
});

const rxDocuments: any[] = okResults.map(r => {
return rxDocumentMap.get(r.id);
});

return {
success: rxDocuments,
error: okResults.filter(r => !r.ok)
};
}

/**
* same as insert but overwrites existing document with same primary
*/
Expand Down
33 changes: 33 additions & 0 deletions test/unit/hooks.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,23 @@ config.parallel('hooks.test.js', () => {
assert.strictEqual(doc2.get('passportId'), human.passportId);
c.database.destroy();
});
it('should call pre remove hook before bulkRemove', async () => {
const c = await humansCollection.create(5);
const docList = await c.find().exec();
const primaryList = docList.map(doc => doc.primary);

let count = 0;
c.preRemove((data, instance) => {
assert.ok(isRxDocument(instance));
assert.ok(data.age);
count++;
}, true);

await c.bulkRemove(primaryList);
assert.strictEqual(count, 5);

c.database.destroy();
});
});
describe('negative', () => { });
});
Expand Down Expand Up @@ -416,6 +433,22 @@ config.parallel('hooks.test.js', () => {
assert.ok(hasRun);
c.database.destroy();
});
it('should call post remove hook after bulkRemove', async () => {
const c = await humansCollection.create(5);
const docList = await c.find().exec();
const primaryList = docList.map(doc => doc.primary);

let count = 0;
c.postRemove((data, instance) => {
assert.ok(isRxDocument(instance));
assert.ok(data.age);
count++;
}, true);
await c.bulkRemove(primaryList);
assert.strictEqual(count, 5);

c.database.destroy();
});
});
describe('negative', () => { });
});
Expand Down
31 changes: 30 additions & 1 deletion test/unit/reactive-collection.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import AsyncTestUtil from 'async-test-util';
import {
first
} from 'rxjs/operators';
import { RxChangeEvent } from '../../src/rx-change-event';
import { RxChangeEvent, RxChangeEventDelete } from '../../src/rx-change-event';

config.parallel('reactive-collection.test.js', () => {
describe('.insert()', () => {
Expand Down Expand Up @@ -97,6 +97,35 @@ config.parallel('reactive-collection.test.js', () => {
});
});
});
describe('.bulkRemove()', () => {
describe('positive', () => {
it('should fire on bulk remove', async () => {
const c = await humansCollection.create(10);

const emittedCollection: RxChangeEventDelete[] = [];
const colSub = c.remove$.subscribe((ce) => {
emittedCollection.push(ce);
});

const docList = await c.find().exec();
const primaryList = docList.map(doc => doc.primary);

await c.bulkRemove(primaryList);

const changeEvent = emittedCollection[0];

assert.strictEqual(changeEvent.operation, 'DELETE');
assert.strictEqual(changeEvent.collectionName, 'human');
assert.strictEqual(changeEvent.documentId, docList[0].primary);
assert.ok(isRxDocument(changeEvent.rxDocument));
assert.ok(changeEvent.documentData);
assert.ok(changeEvent.previousData);

colSub.unsubscribe();
c.database.destroy();
});
});
});
describe('.remove()', () => {
describe('positive', () => {
it('should fire on remove', async () => {
Expand Down
19 changes: 19 additions & 0 deletions test/unit/rx-collection.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,25 @@ config.parallel('rx-collection.test.js', () => {

});
});
describe('.bulkRemove()', () => {
describe('positive', () => {
it('should remove some humans', async () => {
const c = await humansCollection.create(10);
const docList = await c.find().exec();

assert.strictEqual(docList.length, 10);

const primaryList = docList.map(doc => doc.primary);
const ret = await c.bulkRemove(primaryList);
assert.strictEqual(ret.success.length, 10);

const finalList = await c.find().exec();
assert.strictEqual(finalList.length, 0);

c.database.destroy();
});
});
});
describe('.find()', () => {
describe('find all', () => {
describe('positive', () => {
Expand Down

0 comments on commit 31b93f8

Please sign in to comment.