UNPKG

@magnetarjs/plugin-firestore-admin

Version:

Magnetar plugin firestore-admin

82 lines (81 loc) 3.96 kB
import { getFirestoreCollectionPath, getFirestoreDocPath, } from '@magnetarjs/utils-firestore'; import { isString } from 'is-what'; import { docSnapshotToDocMetadata, getQueryInstance } from '../helpers/getFirestore.js'; export function streamActionFactory(firestorePluginOptions) { return function ({ payload, collectionPath, docId, pluginModuleConfig, mustExecuteOnRead, }) { const { added, modified, removed } = mustExecuteOnRead; const { db } = firestorePluginOptions; // Extract onFirstData callback from payload if provided const onFirstData = payload?.onFirstData; let resolveStream; let rejectStream; const streaming = new Promise((resolve, reject) => { resolveStream = resolve; rejectStream = reject; }); let closeStream; let firstDataReceived = false; // in case of a doc module if (isString(docId)) { const documentPath = getFirestoreDocPath(collectionPath, docId, pluginModuleConfig, firestorePluginOptions); // prettier-ignore closeStream = db .doc(documentPath) .onSnapshot((docSnapshot) => { // even if `docSnapshot.metadata.hasPendingWrites` // we should always execute `added/modified` // because `core` handles overlapping calls for us // Call onFirstData on first snapshot (whether doc exists or not) if (!firstDataReceived && onFirstData) { firstDataReceived = true; setTimeout(() => onFirstData({ empty: !docSnapshot.exists }), 0); } // do nothing if the doc doesn't exist if (!docSnapshot.exists) return; // serverChanges only const docData = docSnapshot.data(); const docMetadata = docSnapshotToDocMetadata(docSnapshot); if (docData) added(docData, docMetadata); }, rejectStream); } // in case of a collection module else if (!docId) { const _collectionPath = getFirestoreCollectionPath(collectionPath, pluginModuleConfig, firestorePluginOptions); // prettier-ignore const queryInstance = getQueryInstance(_collectionPath, pluginModuleConfig, db); closeStream = queryInstance.onSnapshot((querySnapshot) => { // even if `docSnapshot.metadata.hasPendingWrites` // we should always execute `added/modified` // because `core` handles overlapping calls for us // Call onFirstData on first snapshot (whether collection has docs or not) if (!firstDataReceived && onFirstData) { firstDataReceived = true; setTimeout(() => onFirstData({ empty: querySnapshot.empty }), 0); } // serverChanges only querySnapshot .docChanges() .forEach((docChange) => { const docSnapshot = docChange.doc; const docData = docSnapshot.data(); const docMetadata = docSnapshotToDocMetadata(docSnapshot); if (docChange.type === 'added' && docData) { added(docData, docMetadata); } if (docChange.type === 'modified' && docData) { modified(docData, docMetadata); } if (docChange.type === 'removed') { removed(docData, docMetadata); } }); }, rejectStream); } function stop() { if (resolveStream) resolveStream(); closeStream(); } return { stop, streaming }; }; }