Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add database archiving #1060

Merged
merged 6 commits into from
Dec 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/stores/databaseV2/clients/dexie.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ export class DexieClient implements AbstractDBClient {
queryCollection<T>(endpoint: IDBEndpoint, queryOpts: DBQueryOptions) {
return this._processQuery<T>(endpoint, queryOpts)
}
deleteDoc(endpoint: IDBEndpoint, docId: string) {
return db.table(endpoint).delete(docId)
}

/************************************************************************
* Additional Methods - specific only to dexie
Expand Down
6 changes: 6 additions & 0 deletions src/stores/databaseV2/clients/firestore.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ export class FirestoreClient implements AbstractDBClient {
const data = await ref.get()
return data.empty ? [] : data.docs.map(doc => doc.data() as T)
}
deleteDoc(endpoint: IDBEndpoint, docId: string) {
return db
.collection(endpoint)
.doc(docId)
.delete()
}

/************************************************************************
* Additional Methods - specific only to firestore
Expand Down
3 changes: 3 additions & 0 deletions src/stores/databaseV2/clients/rtdb.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ export class RealtimeDBClient implements AbstractDBClient {
// eslint-disable-next-line
return []
}
deleteDoc(endpoint: IDBEndpoint, docId: string) {
return db.ref(`${endpoint}/${docId}`).remove()
}

/************************************************************************
* Additional Methods - specific only to firebase realtime DB
Expand Down
38 changes: 33 additions & 5 deletions src/stores/databaseV2/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,24 @@ class CollectionReference<T> {
console.groupEnd()
obs.next(allDocs)
})
// 4. Check for any document deletes, and remove as appropriate
// Assume archive will have been checked after last updated record sync
const lastArchive = latest
serverDB.streamCollection!(`_archived/${endpoint}/summary`, {
order: 'asc',
where: { field: '_archived', operator: '>', value: lastArchive },
}).subscribe(async docs => {
const archiveIds = docs.map(d => d._id)
for (const docId of archiveIds) {
try {
cacheDB.deleteDoc(endpoint, docId)
} catch (error) {
// might already be deleted so ignore error
}
}
const allDocs = await cacheDB.getCollection<T>(endpoint)
obs.next(allDocs)
})
},
)
const subscription = observer.subscribe(value => onUpdate(value))
Expand Down Expand Up @@ -227,13 +245,23 @@ class DocReference<T> {
}

/**
* Documents are artificially deleted by replacing all contents with basic metadata and
* `_deleted:true` property. This is so that other users can also sync the doc with their cache
* TODO - schedule server permanent delete and find more elegant solution to notify users
* to delete docs from their cache.
* Documents are artificially deleted by moving to an `_archived` collection, with separate entries
* for a metadata summary and the raw doc. This is required so that other users can sync deleted docs
* and delete from their own caches accordingly.
* TODO - add rules to restrict access to archive full docs, and schedule for permanent deletion
* TODO - let a user restore their own archived docs
*/
async delete() {
return this.set({ _deleted: true } as any)
const { serverDB, serverCacheDB } = this.clients
const doc = (await this.get()) as any
await serverDB.setDoc(`_archived/${this.endpoint}/summary`, {
_archived: new Date().toISOString(),
_id: this.id,
_createdBy: doc._createdBy || null,
})
await serverDB.setDoc(`_archived/${this.endpoint}/docs`, doc)
await serverDB.deleteDoc(this.endpoint, this.id)
await serverCacheDB.deleteDoc(this.endpoint, this.id)
}

batchDoc(data: any) {
Expand Down
2 changes: 2 additions & 0 deletions src/stores/databaseV2/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ export abstract class AbstractDBClient {
endpoint: string,
queryOpts?: DBQueryOptions,
): Observable<(T & DBDoc)[]>

deleteDoc(endpoint: string, docId: string): Promise<void>
}

/**
Expand Down