Skip to content

Commit bf72ef0

Browse files
authored
REFACTOR bulkRemove (#6634)
* REFACTOR bulkRemove * FIX docs
1 parent 9b845b6 commit bf72ef0

File tree

4 files changed

+58
-93
lines changed

4 files changed

+58
-93
lines changed

docs-src/docs/rx-collection.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,15 @@ const result = await myCollection.bulkRemove([
125125
// }
126126
```
127127

128+
Instead of providing the document ids, you can also use the [RxDocument](./rx-document.md) instances. This can have better performance if your code knows them already at the moment of removing them:
129+
```js
130+
const result = await myCollection.bulkRemove([
131+
myRxDocument1,
132+
myRxDocument2,
133+
/* ... */
134+
]);
135+
```
136+
128137
### upsert()
129138
Inserts the document if it does not exist within the collection, otherwise it will overwrite it. Returns the new or overwritten RxDocument.
130139
```js

src/rx-collection.ts

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,12 @@ export class RxCollectionBase<
436436
}
437437

438438
async bulkRemove(
439-
ids: string[]
439+
/**
440+
* You can either remove the documents by their ids
441+
* or by directly providing the RxDocument instances
442+
* if you have them already. This improves performance a bit.
443+
*/
444+
idsOrDocs: string[] | RxDocument<RxDocumentType>[]
440445
): Promise<{
441446
success: RxDocument<RxDocumentType, OrmMethods>[];
442447
error: RxStorageWriteError<RxDocumentType>[];
@@ -447,14 +452,21 @@ export class RxCollectionBase<
447452
* Optimization shortcut,
448453
* do nothing when called with an empty array
449454
*/
450-
if (ids.length === 0) {
455+
if (idsOrDocs.length === 0) {
451456
return {
452457
success: [],
453458
error: []
454459
};
455460
}
456461

457-
const rxDocumentMap = await this.findByIds(ids).exec();
462+
let rxDocumentMap: Map<string, RxDocument<RxDocumentType, OrmMethods>>;
463+
if (typeof idsOrDocs[0] === 'string') {
464+
rxDocumentMap = await this.findByIds(idsOrDocs as string[]).exec();
465+
} else {
466+
rxDocumentMap = new Map();
467+
(idsOrDocs as RxDocument<RxDocumentType, OrmMethods>[]).forEach(d => rxDocumentMap.set(d.primary, d));
468+
}
469+
458470
const docsData: RxDocumentData<RxDocumentType>[] = [];
459471
const docsMap: Map<string, RxDocumentData<RxDocumentType>> = new Map();
460472
Array.from(rxDocumentMap.values()).forEach(rxDocument => {
@@ -488,7 +500,14 @@ export class RxCollectionBase<
488500
removeDocs,
489501
results
490502
);
491-
const successIds: string[] = success.map(d => d[primaryPath] as string);
503+
504+
const deletedRxDocuments: RxDocument<RxDocumentType, OrmMethods>[] = [];
505+
const successIds: string[] = success.map(d => {
506+
const id = d[primaryPath] as string;
507+
const doc = this._docCache.getCachedRxDocument(d);
508+
deletedRxDocuments.push(doc);
509+
return id;
510+
});
492511

493512
// run hooks
494513
await Promise.all(
@@ -502,10 +521,9 @@ export class RxCollectionBase<
502521
})
503522
);
504523

505-
const rxDocuments = successIds.map(id => getFromMapOrThrow(rxDocumentMap, id));
506524

507525
return {
508-
success: rxDocuments,
526+
success: deletedRxDocuments,
509527
error: results.error
510528
};
511529
}

src/rx-document.ts

Lines changed: 11 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import {
1717
RXJS_SHARE_REPLAY_DEFAULTS,
1818
getProperty,
1919
getFromMapOrCreate,
20-
getFromMapOrThrow,
2120
ensureNotFalsy
2221
} from './plugins/utils/index.ts';
2322
import {
@@ -34,9 +33,7 @@ import type {
3433
RxDocumentWriteData,
3534
UpdateQuery,
3635
CRDTEntry,
37-
ModifyFunction,
38-
BulkWriteRow,
39-
RxStorageWriteError
36+
ModifyFunction
4037
} from './types/index.d.ts';
4138
import { getDocumentDataOfRxChangeEvent } from './rx-change-event.ts';
4239
import { overwritable } from './overwritable.ts';
@@ -371,21 +368,24 @@ export const basePrototype = {
371368
* instead deleted documents get flagged with _deleted=true.
372369
*/
373370
async remove(this: RxDocument): Promise<RxDocument> {
374-
const collection = this.collection;
375371
if (this.deleted) {
376372
return Promise.reject(newRxError('DOC13', {
377373
document: this,
378374
id: this.primary
379375
}));
380376
}
381377

382-
const removeResult = await removeRxDocuments([this]);
383-
if (removeResult.errors.length > 0) {
384-
const error = removeResult.errors[0];
385-
const deletedData = getFromMapOrThrow(removeResult.deleteDataById, this.primary);
386-
throwIfIsStorageWriteError(collection, this.primary, deletedData, error);
378+
const removeResult = await this.collection.bulkRemove([this]);
379+
if (removeResult.error.length > 0) {
380+
const error = removeResult.error[0];
381+
throwIfIsStorageWriteError(
382+
this.collection,
383+
this.primary,
384+
this._data,
385+
error
386+
);
387387
}
388-
return removeResult.docs[0];
388+
return removeResult.success[0];
389389
},
390390
incrementalRemove(this: RxDocument): Promise<RxDocument> {
391391
return this.incrementalModify(async (docData) => {
@@ -537,63 +537,3 @@ function getDocumentProperty(doc: RxDocument, objPath: string): any | null {
537537
}
538538
);
539539
};
540-
541-
542-
543-
/**
544-
* To remove documents we use a bulk operations
545-
* to have a better performance on RxQuery.find().remove();
546-
*/
547-
export async function removeRxDocuments<RxDocType>(
548-
docs: RxDocument<RxDocType>[]
549-
): Promise<{
550-
errors: RxStorageWriteError<RxDocType>[];
551-
docs: RxDocument<RxDocType>[];
552-
deleteDataById: Map<string, RxDocumentData<RxDocType>>;
553-
}> {
554-
if (docs.length === 0) {
555-
throw newRxError('SNH');
556-
}
557-
const collection = docs[0].collection;
558-
const primaryPath = collection.schema.primaryPath;
559-
const writeRows: BulkWriteRow<RxDocType>[] = [];
560-
const docsById = new Map<string, RxDocument<RxDocType>>();
561-
const deleteDataById = new Map<string, RxDocumentData<RxDocType>>();
562-
await Promise.all(
563-
docs.map(async (doc) => {
564-
docsById.set(doc.primary, doc);
565-
const deletedData = flatClone(doc._data);
566-
await collection._runHooks('pre', 'remove', deletedData, doc);
567-
deletedData._deleted = true;
568-
deleteDataById.set(doc.primary, deletedData);
569-
const writeRow = {
570-
previous: doc._data,
571-
document: deletedData
572-
};
573-
writeRows.push(writeRow);
574-
})
575-
);
576-
const writeResult = await collection.storageInstance.bulkWrite(writeRows, 'rx-document-remove');
577-
const errors: RxStorageWriteError<RxDocType>[] = writeResult.error;
578-
const writtenDocsData = getWrittenDocumentsFromBulkWriteResponse(
579-
primaryPath,
580-
writeRows,
581-
writeResult
582-
);
583-
const returnDocs: RxDocument<RxDocType>[] = [];
584-
await Promise.all(
585-
writtenDocsData.map(async (writtenDocData) => {
586-
const id = writtenDocData[primaryPath] as string;
587-
const doc = getFromMapOrThrow(docsById, id);
588-
const deletedData = getFromMapOrThrow(deleteDataById, id);
589-
await collection._runHooks('post', 'remove', deletedData, doc);
590-
returnDocs.push(collection._docCache.getCachedRxDocument(writtenDocData));
591-
})
592-
);
593-
594-
return {
595-
docs: returnDocs,
596-
errors,
597-
deleteDataById
598-
};
599-
}

src/rx-query.ts

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ import {
2323
appendToArray
2424
} from './plugins/utils/index.ts';
2525
import {
26-
newRxError
26+
newRxError,
27+
rxStorageWriteErrorToRxError
2728
} from './rx-error.ts';
2829
import {
2930
runPluginHooks
@@ -53,7 +54,6 @@ import {
5354

5455
} from './rx-query-helper.ts';
5556
import { RxQuerySingleResult } from './rx-query-single-result.ts';
56-
import { removeRxDocuments } from './rx-document.ts';
5757

5858
let _queryCount = 0;
5959
const newQueryID = function (): number {
@@ -379,20 +379,18 @@ export class RxQueryBase<
379379
* deletes all found documents
380380
* @return promise with deleted documents
381381
*/
382-
remove(): Promise<RxQueryResult> {
383-
return this
384-
.exec()
385-
.then(docs => {
386-
if (Array.isArray(docs)) {
387-
if (docs.length === 0) {
388-
return [];
389-
} else {
390-
return removeRxDocuments(docs).then(r => r.docs);
391-
}
392-
} else {
393-
return (docs as any).remove();
394-
}
395-
});
382+
async remove(): Promise<RxQueryResult> {
383+
const docs = await this.exec();
384+
if (Array.isArray(docs)) {
385+
const result = await this.collection.bulkRemove(docs);
386+
if (result.error.length > 0) {
387+
throw rxStorageWriteErrorToRxError(result.error[0]);
388+
} else {
389+
return result.success as any;
390+
}
391+
} else {
392+
return (docs as any).remove();
393+
}
396394
}
397395
incrementalRemove(): Promise<RxQueryResult> {
398396
return runQueryUpdateFunction(

0 commit comments

Comments
 (0)