From 0887f1969d77c4ee5272b3200345ff307e85fc51 Mon Sep 17 00:00:00 2001 From: Sasha Koss Date: Thu, 16 Apr 2020 14:31:48 +0300 Subject: [PATCH] Make the browser adaptor lazy --- CHANGELOG.md | 6 + package.json | 2 +- src/adaptor/browser.ts | 40 ------- src/adaptor/browser/index.ts | 40 +++++++ src/adaptor/browser/lazy.ts | 41 +++++++ src/adaptor/browser/package.json | 3 + src/adaptor/node.ts | 22 ++-- src/add/index.ts | 7 +- src/all/index.ts | 9 +- src/batch/index.ts | 92 +++++++++------ src/data/index.ts | 34 +++--- src/field/index.ts | 2 +- src/get/index.ts | 9 +- src/get/test.ts | 8 +- src/getMany/index.ts | 18 ++- src/onAll/index.ts | 30 +++-- src/onGet/index.ts | 36 +++--- src/onGet/test.ts | 20 ++-- src/onQuery/index.ts | 188 ++++++++++++++++--------------- src/query/index.ts | 13 ++- src/ref/index.ts | 25 ++-- src/ref/test.ts | 12 +- src/remove/index.ts | 7 +- src/remove/test.ts | 6 +- src/set/index.ts | 9 +- src/transaction/index.ts | 37 +++--- src/update/index.ts | 9 +- src/update/test.ts | 40 +++---- src/upset/index.ts | 17 ++- 29 files changed, 438 insertions(+), 344 deletions(-) delete mode 100644 src/adaptor/browser.ts create mode 100644 src/adaptor/browser/index.ts create mode 100644 src/adaptor/browser/lazy.ts create mode 100644 src/adaptor/browser/package.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 37de4253..4ca5fe0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,12 +21,18 @@ This change log follows the format documented in [Keep a CHANGELOG]. - **BREAKING**: `ModelUpdate` renamed to `UpdateModel` for consitency with `SetModel` and `MergeModel`. +- **BREAKING**: `ref` now don't generate id if the second argument is omitted, use `id` function to generate new id instead. + - `update` now allows passing partial data into nested fields. Previously only root fields were optional. +- Now the browser adaptor imports `firebase/app` and `firebase/firestore` on-demand (using ESM's `import()`) rather than in the root level of the library. That dramatically improves initial paint time and helps with bundle caching. Now every time you make a small change in the app, the user won't have to download `firestore` modules as well. + ### Added - Added new `upset`, `batch.set` and `transaction.set` functions that sets or updates the value of given document. It replaces `merge` option available in the previous version of Typesaurus. +- + ## 5.4.0 - 2020-04-14 ### Fixes diff --git a/package.json b/package.json index 6daaa1a1..5219d121 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "typesaurus", - "version": "5.4.0", + "version": "6.0.0-alpha.1", "description": "Type-safe ODM for Firestore", "keywords": [ "Firebase", diff --git a/src/adaptor/browser.ts b/src/adaptor/browser.ts deleted file mode 100644 index 1537bb9d..00000000 --- a/src/adaptor/browser.ts +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Browser Firestore adaptor. - */ - -import * as firebase from 'firebase/app' -import 'firebase/firestore' -import { getAll } from './utils' - -export default function store() { - const firestore = firebase.firestore() - // At the moment, the browser's Firestore adaptor doesn't support getAll. - // Get rid of the fallback when the issue is closed: - // https://github.com/firebase/firebase-js-sdk/issues/1176 - if (!('getAll' in firestore)) return Object.assign(firestore, { getAll }) - return firestore -} - -export function consts() { - return { - DocumentReference: firebase.firestore.DocumentReference, - Timestamp: firebase.firestore.Timestamp, - FieldValue: firebase.firestore.FieldValue - } -} - -export function injectAdaptor() { - throw new Error( - 'Injecting adaptor is not supported in the browser environment' - ) -} - -export type FirestoreQuery = firebase.firestore.Query -export type FirestoreDocumentReference = firebase.firestore.DocumentReference -export type FirestoreDocumentData = firebase.firestore.DocumentData -export type FirestoreTimestamp = firebase.firestore.Timestamp -export type FirestoreCollectionReference = firebase.firestore.CollectionReference -export type FirestoreOrderByDirection = firebase.firestore.OrderByDirection -export type FirestoreWhereFilterOp = firebase.firestore.WhereFilterOp -export type FirestoreTransaction = firebase.firestore.Transaction -export type FirebaseWriteBatch = firebase.firestore.WriteBatch diff --git a/src/adaptor/browser/index.ts b/src/adaptor/browser/index.ts new file mode 100644 index 00000000..96fefba4 --- /dev/null +++ b/src/adaptor/browser/index.ts @@ -0,0 +1,40 @@ +/** + * Browser Firestore adaptor. + */ + +import * as firebase from 'firebase/app' +import 'firebase/firestore' +import { getAll } from '../utils' + +export default async function adaptor() { + const firestore = firebase.firestore() + // At the moment, the browser's Firestore adaptor doesn't support getAll. + // Get rid of the fallback when the issue is closed: + // https://github.com/firebase/firebase-js-sdk/issues/1176 + if (!('getAll' in firestore)) return Object.assign(firestore, { getAll }) + + return { + firestore, + consts: { + DocumentReference: firebase.firestore.DocumentReference, + Timestamp: firebase.firestore.Timestamp, + FieldValue: firebase.firestore.FieldValue + } + } +} + +export function injectAdaptor() { + throw new Error( + 'Injecting adaptor is not supported in the browser environment' + ) +} + +// export type FirestoreQuery = firebase.firestore.Query +// export type FirestoreDocumentReference = firebase.firestore.DocumentReference +// export type FirestoreDocumentData = firebase.firestore.DocumentData +// export type FirestoreTimestamp = firebase.firestore.Timestamp +// export type FirestoreCollectionReference = firebase.firestore.CollectionReference +// export type FirestoreOrderByDirection = firebase.firestore.OrderByDirection +// export type FirestoreWhereFilterOp = firebase.firestore.WhereFilterOp +// export type FirestoreTransaction = firebase.firestore.Transaction +// export type FirebaseWriteBatch = firebase.firestore.WriteBatch diff --git a/src/adaptor/browser/lazy.ts b/src/adaptor/browser/lazy.ts new file mode 100644 index 00000000..ac3f144e --- /dev/null +++ b/src/adaptor/browser/lazy.ts @@ -0,0 +1,41 @@ +/** + * Lazy browser Firestore adaptor. + */ + +import { getAll } from '../utils' + +export default async function adaptor() { + const { default: firebase } = await import('firebase/app') + await import('firebase/firestore') + + const firestore = firebase.firestore() + // At the moment, the browser's Firestore adaptor doesn't support getAll. + // Get rid of the fallback when the issue is closed: + // https://github.com/firebase/firebase-js-sdk/issues/1176 + if (!('getAll' in firestore)) return Object.assign(firestore, { getAll }) + + return { + firestore, + consts: { + DocumentReference: firebase.firestore.DocumentReference, + Timestamp: firebase.firestore.Timestamp, + FieldValue: firebase.firestore.FieldValue + } + } +} + +export function injectAdaptor() { + throw new Error( + 'Injecting adaptor is not supported in the browser environment' + ) +} + +// export type FirestoreQuery = type import('firebase').firestore.Query +// export type FirestoreDocumentReference = firebase.firestore.DocumentReference +// export type FirestoreDocumentData = firebase.firestore.DocumentData +// export type FirestoreTimestamp = firebase.firestore.Timestamp +// export type FirestoreCollectionReference = firebase.firestore.CollectionReference +// export type FirestoreOrderByDirection = firebase.firestore.OrderByDirection +// export type FirestoreWhereFilterOp = firebase.firestore.WhereFilterOp +// export type FirestoreTransaction = firebase.firestore.Transaction +// export type FirebaseWriteBatch = firebase.firestore.WriteBatch diff --git a/src/adaptor/browser/package.json b/src/adaptor/browser/package.json new file mode 100644 index 00000000..f627c070 --- /dev/null +++ b/src/adaptor/browser/package.json @@ -0,0 +1,3 @@ +{ + "module": "./lazy" +} diff --git a/src/adaptor/node.ts b/src/adaptor/node.ts index 666d04f9..f6b8156d 100644 --- a/src/adaptor/node.ts +++ b/src/adaptor/node.ts @@ -5,21 +5,22 @@ import * as firestore from '@google-cloud/firestore' import * as admin from 'firebase-admin' -export type AdaptorFirestore = () => admin.firestore.Firestore - -const adminFirestore = () => admin.firestore() -let currentFirestore: AdaptorFirestore = adminFirestore - -export default function store() { - return currentFirestore() +export type Adaptor = { + firestore: admin.firestore.Firestore + consts: AdaptorConsts } +export type AdaptorFirestore = () => admin.firestore.Firestore + export type AdaptorConsts = { DocumentReference: typeof admin.firestore.DocumentReference Timestamp: typeof admin.firestore.Timestamp FieldValue: typeof admin.firestore.FieldValue } +const adminFirestore = () => admin.firestore() +let currentFirestore: AdaptorFirestore = adminFirestore + const adminConsts = { DocumentReference: admin.firestore.DocumentReference, Timestamp: admin.firestore.Timestamp, @@ -27,8 +28,11 @@ const adminConsts = { } let currentConsts: AdaptorConsts = adminConsts -export function consts(): AdaptorConsts { - return currentConsts +export default async function adaptor() { + return { + firestore: currentFirestore(), + consts: currentConsts + } } export function injectAdaptor( diff --git a/src/add/index.ts b/src/add/index.ts index 0d05060a..24e6f611 100644 --- a/src/add/index.ts +++ b/src/add/index.ts @@ -1,4 +1,4 @@ -import firestore from '../adaptor' +import adaptor from '../adaptor' import { Collection } from '../collection' import { unwrapData } from '../data' import { ref } from '../ref' @@ -36,8 +36,9 @@ export default async function add( collection: Collection, data: AddModel ) { - const firebaseDoc = await firestore() + const a = await adaptor() + const firebaseDoc = await a.firestore .collection(collection.path) - .add(unwrapData(data)) + .add(unwrapData(a, data)) return ref(collection, firebaseDoc.id) } diff --git a/src/all/index.ts b/src/all/index.ts index bba9902f..6f1525f3 100644 --- a/src/all/index.ts +++ b/src/all/index.ts @@ -1,5 +1,5 @@ import { Collection } from '../collection' -import firestore from '../adaptor' +import adaptor from '../adaptor' import { doc, Doc } from '../doc' import { ref } from '../ref' import { wrapData } from '../data' @@ -29,10 +29,9 @@ import { wrapData } from '../data' export default async function all( collection: Collection ): Promise[]> { - const firebaseSnap = await firestore() - .collection(collection.path) - .get() + const a = await adaptor() + const firebaseSnap = await a.firestore.collection(collection.path).get() return firebaseSnap.docs.map(d => - doc(ref(collection, d.id), wrapData(d.data()) as Model) + doc(ref(collection, d.id), wrapData(a, d.data()) as Model) ) } diff --git a/src/batch/index.ts b/src/batch/index.ts index a4c4f0bf..9c64bc91 100644 --- a/src/batch/index.ts +++ b/src/batch/index.ts @@ -1,4 +1,4 @@ -import firestore from '../adaptor' +import adaptor, { Adaptor, FirebaseWriteBatch } from '../adaptor' import { Collection } from '../collection' import { Ref } from '../ref' import { unwrapData } from '../data' @@ -200,7 +200,12 @@ export interface Batch { * @returns The batch API object. */ export function batch(): Batch { - const firestoreBatch = firestore().batch() + const commands: BatchCommand[] = [] + + const firestoreBatch = lazy(async () => { + const { firestore } = await adaptor() + return firestore.batch() + }) function set( collectionOrRef: Collection | Ref, @@ -222,12 +227,12 @@ export function batch(): Batch { data = idOrData as SetModel } - const firestoreDoc = firestore() - .collection(collection.path) - .doc(id) - // ^ above - // TODO: Refactor code above and below because is all the same as in the regular set function - firestoreBatch.set(firestoreDoc, unwrapData(data)) + commands.push((adaptor, firestoreBatch) => { + const firestoreDoc = adaptor.firestore.collection(collection.path).doc(id) + // ^ above + // TODO: Refactor code above and below because is all the same as in the regular set function + firestoreBatch.set(firestoreDoc, unwrapData(adaptor, data)) + }) } function upset( @@ -250,12 +255,14 @@ export function batch(): Batch { data = idOrData as UpsetModel } - const firestoreDoc = firestore() - .collection(collection.path) - .doc(id) - // ^ above - // TODO: Refactor code above and below because is all the same as in the regular set function - firestoreBatch.set(firestoreDoc, unwrapData(data), { merge: true }) + commands.push((adaptor, firestoreBatch) => { + const firestoreDoc = adaptor.firestore.collection(collection.path).doc(id) + // ^ above + // TODO: Refactor code above and below because is all the same as in the regular set function + firestoreBatch.set(firestoreDoc, unwrapData(adaptor, data), { + merge: true + }) + }) } function update( @@ -278,21 +285,21 @@ export function batch(): Batch { data = idOrData as Model } - const firebaseDoc = firestore() - .collection(collection.path) - .doc(id) - const updateData = Array.isArray(data) - ? data.reduce( - (acc, { key, value }) => { - acc[Array.isArray(key) ? key.join('.') : key] = value - return acc - }, - {} as { [key: string]: any } - ) - : data - // ^ above - // TODO: Refactor code above because is all the same as in the regular update function - firestoreBatch.update(firebaseDoc, unwrapData(updateData)) + commands.push((adaptor, firestoreBatch) => { + const firebaseDoc = adaptor.firestore.collection(collection.path).doc(id) + const updateData = Array.isArray(data) + ? data.reduce( + (acc, { key, value }) => { + acc[Array.isArray(key) ? key.join('.') : key] = value + return acc + }, + {} as { [key: string]: any } + ) + : data + // ^ above + // TODO: Refactor code above because is all the same as in the regular update function + firestoreBatch.update(firebaseDoc, unwrapData(adaptor, updateData)) + }) } function remove( @@ -311,17 +318,30 @@ export function batch(): Batch { id = ref.id } - const firebaseDoc = firestore() - .collection(collection.path) - .doc(id) - // ^ above - // TODO: Refactor code above because is all the same as in the regular remove function - firestoreBatch.delete(firebaseDoc) + commands.push((adaptor, firestoreBatch) => { + const firebaseDoc = adaptor.firestore.collection(collection.path).doc(id) + // ^ above + // TODO: Refactor code above because is all the same as in the regular remove function + firestoreBatch.delete(firebaseDoc) + }) } async function commit() { - await firestoreBatch.commit() + const a = await adaptor() + const b = a.firestore.batch() + commands.forEach(fn => fn(a, b)) + await b.commit() } return { set, upset, update, remove, commit } } + +type BatchCommand = (adaptor: Adaptor, batch: FirebaseWriteBatch) => void + +function lazy(fn: () => Promise): () => Promise { + let instance: Type | undefined = undefined + return async () => { + if (instance === undefined) instance = await fn() + return instance + } +} diff --git a/src/data/index.ts b/src/data/index.ts index 1fb69524..d9776efb 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -1,33 +1,38 @@ -import { consts } from '../adaptor' import { pathToRef, Ref, refToFirestoreDocument } from '../ref' import { UpdateValue } from '../value' +import { Adaptor } from '../adaptor' /** * Converts Typesaurus data to Firestore format. It deeply traverse all the data and * converts values to compatible format. * + * @param adaptor - the adaptor * @param data - the data to convert */ -export function unwrapData(data: any): any { +export function unwrapData(adaptor: Adaptor, data: any): any { if (data && typeof data === 'object') { if (data.__type__ === 'ref') { - return refToFirestoreDocument(data as Ref) + return refToFirestoreDocument(adaptor, data as Ref) } else if (data.__type__ === 'value') { const fieldValue = data as UpdateValue switch (fieldValue.kind) { case 'remove': - return consts().FieldValue.delete() + return adaptor.consts.FieldValue.delete() case 'increment': - return consts().FieldValue.increment(fieldValue.number) + return adaptor.consts.FieldValue.increment(fieldValue.number) case 'arrayUnion': - return consts().FieldValue.arrayUnion(...unwrapData(fieldValue.values)) + return adaptor.consts.FieldValue.arrayUnion( + ...unwrapData(adaptor, fieldValue.values) + ) case 'arrayRemove': - return consts().FieldValue.arrayRemove(...unwrapData(fieldValue.values)) + return adaptor.consts.FieldValue.arrayRemove( + ...unwrapData(adaptor, fieldValue.values) + ) case 'serverDate': - return consts().FieldValue.serverTimestamp() + return adaptor.consts.FieldValue.serverTimestamp() } } else if (data instanceof Date) { - return consts().Timestamp.fromDate(data) + return adaptor.consts.Timestamp.fromDate(data) } const unwrappedObject: { [key: string]: any } = Object.assign( @@ -35,7 +40,7 @@ export function unwrapData(data: any): any { data ) Object.keys(unwrappedObject).forEach(key => { - unwrappedObject[key] = unwrapData(unwrappedObject[key]) + unwrappedObject[key] = unwrapData(adaptor, unwrappedObject[key]) }) return unwrappedObject } else if (data === undefined) { @@ -49,12 +54,13 @@ export function unwrapData(data: any): any { * Converts Firestore data to Typesaurus format. It deeply traverse all the * data and converts values to compatible format. * + * @param consts - the adaptor constants * @param data - the data to convert */ -export function wrapData(data: unknown) { - if (data instanceof consts().DocumentReference) { +export function wrapData(adaptor: Adaptor, data: unknown) { + if (data instanceof adaptor.consts.DocumentReference) { return pathToRef(data.path) - } else if (data instanceof consts().Timestamp) { + } else if (data instanceof adaptor.consts.Timestamp) { return data.toDate() } else if (data && typeof data === 'object') { const wrappedData: { [key: string]: any } = Object.assign( @@ -62,7 +68,7 @@ export function wrapData(data: unknown) { data ) Object.keys(wrappedData).forEach(key => { - wrappedData[key] = wrapData(wrappedData[key]) + wrappedData[key] = wrapData(adaptor, wrappedData[key]) }) return wrappedData } else { diff --git a/src/field/index.ts b/src/field/index.ts index 82a5058b..f21a99f5 100644 --- a/src/field/index.ts +++ b/src/field/index.ts @@ -1,4 +1,4 @@ -import { UpdateValue } from '../value/index' +import { UpdateValue } from '../value' /** * The field type. It contains path to the property and property value. diff --git a/src/get/index.ts b/src/get/index.ts index 5225a350..43c8cba1 100644 --- a/src/get/index.ts +++ b/src/get/index.ts @@ -1,8 +1,8 @@ -import firestore from '../adaptor' import { Collection } from '../collection' import { doc, Doc } from '../doc' import { ref, Ref } from '../ref' import { wrapData } from '../data' +import adaptor from '../adaptor' /** * @param ref - The reference to the document @@ -41,6 +41,7 @@ async function get( collectionOrRef: Collection | Ref, maybeId?: string ): Promise | null> { + const a = await adaptor() let collection: Collection let id: string @@ -53,12 +54,10 @@ async function get( id = ref.id } - const firestoreDoc = firestore() - .collection(collection.path) - .doc(id) + const firestoreDoc = a.firestore.collection(collection.path).doc(id) const firestoreSnap = await firestoreDoc.get() const firestoreData = firestoreSnap.data() - const data = firestoreData && (wrapData(firestoreData) as Model) + const data = firestoreData && (wrapData(a, firestoreData) as Model) return data ? doc(ref(collection, id), data) : null } diff --git a/src/get/test.ts b/src/get/test.ts index 50d1efa6..ccc75df2 100644 --- a/src/get/test.ts +++ b/src/get/test.ts @@ -18,17 +18,17 @@ describe('get', () => { it('allows to get by ref', async () => { const user = await add(users, { name: 'Sasha' }) - const userFromDB = await get(user.ref) + const userFromDB = await get(user) assert.deepEqual(userFromDB.data, { name: 'Sasha' }) }) it('expands references', async () => { const user = await add(users, { name: 'Sasha' }) const post = await add(posts, { - author: user.ref, + author: user, text: 'Hello!' }) - const postFromDB = await get(posts, post.ref.id) + const postFromDB = await get(posts, post.id) assert(postFromDB.data.author.__type__ === 'ref') const userFromDB = await get(users, postFromDB.data.author.id) assert.deepEqual(userFromDB.data, { name: 'Sasha' }) @@ -42,7 +42,7 @@ describe('get', () => { text: 'Hello!', date }) - const postFromDB = await get(posts, post.ref.id) + const postFromDB = await get(posts, post.id) assert(postFromDB.data.date.getTime() === date.getTime()) }) }) diff --git a/src/getMany/index.ts b/src/getMany/index.ts index d4158e6f..1ab9fb22 100644 --- a/src/getMany/index.ts +++ b/src/getMany/index.ts @@ -1,4 +1,4 @@ -import firestore from '../adaptor' +import adaptor from '../adaptor' import { Collection } from '../collection' import { doc, Doc } from '../doc' import { ref } from '../ref' @@ -28,24 +28,22 @@ import { wrapData } from '../data' * * @returns Promise to a list of found documents */ -async function getMany( +export default async function getMany( collection: Collection, ids: readonly string[], onMissing: ((id: string) => Model) | 'ignore' = id => { throw new Error(`Missing document with id ${id}`) } ): Promise[]> { + const a = await adaptor() + if (ids.length === 0) { // Firestore#getAll doesn't like empty lists return Promise.resolve([]) } - const firestoreSnaps = await firestore().getAll( - ...ids.map(id => - firestore() - .collection(collection.path) - .doc(id) - ) + const firestoreSnaps = await a.firestore.getAll( + ...ids.map(id => a.firestore.collection(collection.path).doc(id)) ) return firestoreSnaps @@ -62,10 +60,8 @@ async function getMany( } const firestoreData = firestoreSnap.data() - const data = firestoreData && (wrapData(firestoreData) as Model) + const data = firestoreData && (wrapData(a, firestoreData) as Model) return doc(ref(collection, firestoreSnap.id), data) }) .filter(doc => doc != null) as Doc[] } - -export default getMany diff --git a/src/onAll/index.ts b/src/onAll/index.ts index 00d10354..518369da 100644 --- a/src/onAll/index.ts +++ b/src/onAll/index.ts @@ -1,5 +1,5 @@ import { Collection } from '../collection' -import firestore from '../adaptor' +import adaptor from '../adaptor' import { doc, Doc } from '../doc' import { ref } from '../ref' import { wrapData } from '../data' @@ -33,12 +33,24 @@ export default function onAll( onResult: (docs: Doc[]) => any, onError?: (error: Error) => any ): () => void { - return firestore() - .collection(collection.path) - .onSnapshot(firebaseSnap => { - const docs = firebaseSnap.docs.map(d => - doc(ref(collection, d.id), wrapData(d.data()) as Model) - ) - onResult(docs) - }, onError) + let unsubCalled = false + let firebaseUnsub: () => void + const unsub = () => { + unsubCalled = true + firebaseUnsub && firebaseUnsub() + } + + adaptor().then(a => { + if (unsubCalled) return + firebaseUnsub = a.firestore + .collection(collection.path) + .onSnapshot(firebaseSnap => { + const docs = firebaseSnap.docs.map(d => + doc(ref(collection, d.id), wrapData(a, d.data()) as Model) + ) + onResult(docs) + }, onError) + }) + + return unsub } diff --git a/src/onGet/index.ts b/src/onGet/index.ts index 2c31642b..86c455c2 100644 --- a/src/onGet/index.ts +++ b/src/onGet/index.ts @@ -1,4 +1,4 @@ -import firestore from '../adaptor' +import adaptor from '../adaptor' import { Collection } from '../collection' import { doc, Doc } from '../doc' import { ref, Ref } from '../ref' @@ -14,7 +14,7 @@ type OnError = (error: Error) => any * the initial fetch is resolved or the document updates. * @param onError - The function is called with error when request fails. */ -function onGet( +export default function onGet( ref: Ref, onResult: OnResult, onError?: OnError @@ -27,7 +27,7 @@ function onGet( * the initial fetch is resolved or the document updates. * @param onError - The function is called with error when request fails. */ -function onGet( +export default function onGet( collection: Collection, id: string, onResult: OnResult, @@ -53,12 +53,19 @@ function onGet( * * @returns Function that unsubscribes the listener from the updates */ -function onGet( +export default function onGet( collectionOrRef: Collection | Ref, idOrOnResult: string | OnResult, onResultOrOnError?: OnResult | OnError, maybeOnError?: OnError ): () => void { + let unsubCalled = false + let firebaseUnsub: () => void + const unsub = () => { + unsubCalled = true + firebaseUnsub && firebaseUnsub() + } + let collection: Collection let id: string let onResult: OnResult @@ -77,14 +84,15 @@ function onGet( onError = onResultOrOnError as OnError | undefined } - const firestoreDoc = firestore() - .collection(collection.path) - .doc(id) - return firestoreDoc.onSnapshot(firestoreSnap => { - const firestoreData = firestoreSnap.data() - const data = firestoreData && (wrapData(firestoreData) as Model) - onResult((data && doc(ref(collection, id), data)) || null) - }, onError) -} + adaptor().then(a => { + if (unsubCalled) return + const firestoreDoc = a.firestore.collection(collection.path).doc(id) + firebaseUnsub = firestoreDoc.onSnapshot(firestoreSnap => { + const firestoreData = firestoreSnap.data() + const data = firestoreData && (wrapData(a, firestoreData) as Model) + onResult((data && doc(ref(collection, id), data)) || null) + }, onError) + }) -export default onGet + return unsub +} diff --git a/src/onGet/test.ts b/src/onGet/test.ts index 8131d165..53e00418 100644 --- a/src/onGet/test.ts +++ b/src/onGet/test.ts @@ -7,7 +7,7 @@ import add from '../add' import update from '../update' import sinon from 'sinon' -describe('get', () => { +describe('onGet', () => { type User = { name: string } type Post = { author: Ref; text: string; date?: Date } @@ -31,7 +31,7 @@ describe('get', () => { it('allows to get by ref', async () => { const user = await add(users, { name: 'Sasha' }) return new Promise(resolve => { - off = onGet(user.ref, userFromDB => { + off = onGet(user, userFromDB => { assert.deepEqual(userFromDB.data, { name: 'Sasha' }) resolve() }) @@ -41,11 +41,11 @@ describe('get', () => { it('expands references', async () => { const user = await add(users, { name: 'Sasha' }) const post = await add(posts, { - author: user.ref, + author: user, text: 'Hello!' }) return new Promise(resolve => { - off = onGet(posts, post.ref.id, async postFromDB => { + off = onGet(posts, post.id, async postFromDB => { assert(postFromDB.data.author.__type__ === 'ref') const userFromDB = await get(users, postFromDB.data.author.id) assert.deepEqual(userFromDB.data, { name: 'Sasha' }) @@ -63,7 +63,7 @@ describe('get', () => { date }) return new Promise(resolve => { - off = onGet(posts, post.ref.id, postFromDB => { + off = onGet(posts, post.id, postFromDB => { assert(postFromDB.data.date.getTime() === date.getTime()) resolve() }) @@ -75,11 +75,11 @@ describe('get', () => { const spy = sinon.spy() const user = await add(users, { name: 'Sasha' }) return new Promise(resolve => { - off = onGet(user.ref, async doc => { + off = onGet(user, async doc => { const { name } = doc.data spy(name) if (name === 'Sasha') { - await update(user.ref, { name: 'Sasha Koss' }) + await update(user, { name: 'Sasha Koss' }) } else if (name === 'Sasha Koss') { assert(spy.calledWith('Sasha')) assert(spy.calledWith('Sasha Koss')) @@ -96,7 +96,7 @@ describe('get', () => { const spy = sinon.spy() const user = await add(users, { name: 'Sasha' }) const on = () => { - off = onGet(user.ref, doc => { + off = onGet(user, doc => { const { name } = doc.data spy(name) if (name === 'Sasha Koss') { @@ -109,8 +109,8 @@ describe('get', () => { } on() off() - await update(user.ref, { name: 'Sashka' }) - await update(user.ref, { name: 'Sasha Koss' }) + await update(user, { name: 'Sashka' }) + await update(user, { name: 'Sasha Koss' }) on() }) }) diff --git a/src/onQuery/index.ts b/src/onQuery/index.ts index 387291d5..c67ada7c 100644 --- a/src/onQuery/index.ts +++ b/src/onQuery/index.ts @@ -1,4 +1,4 @@ -import firestore from '../adaptor' +import adaptor from '../adaptor' import { Collection } from '../collection' import { doc, Doc } from '../doc' import { ref, pathToRef } from '../ref' @@ -13,7 +13,7 @@ type FirebaseQuery = | FirebaseFirestore.CollectionReference | FirebaseFirestore.Query -// TODO: Refactor with onQuery +// TODO: Refactor with query /** * The query type. @@ -58,101 +58,111 @@ export default function onQuery( onResult: (docs: Doc[]) => any, onError?: (err: Error) => any ): () => void { - try { - const { firestoreQuery, cursors } = queries.reduce( - (acc, q) => { - switch (q.type) { - case 'order': { - const { field, method, cursors } = q - acc.firestoreQuery = acc.firestoreQuery.orderBy( - field.toString(), - method - ) - if (cursors) - acc.cursors = acc.cursors.concat( - cursors.map(({ method, value }) => ({ - method, - value: - typeof value === 'object' && - value !== null && - '__type__' in value && - value.__type__ === 'doc' - ? value.data[field] - : value - })) + let unsubCalled = false + let firebaseUnsub: () => void + const unsub = () => { + unsubCalled = true + firebaseUnsub && firebaseUnsub() + } + + adaptor() + .then(a => { + if (unsubCalled) return + + const { firestoreQuery, cursors } = queries.reduce( + (acc, q) => { + switch (q.type) { + case 'order': { + const { field, method, cursors } = q + acc.firestoreQuery = acc.firestoreQuery.orderBy( + field.toString(), + method ) - break - } + if (cursors) + acc.cursors = acc.cursors.concat( + cursors.map(({ method, value }) => ({ + method, + value: + typeof value === 'object' && + value !== null && + '__type__' in value && + value.__type__ === 'doc' + ? value.data[field] + : value + })) + ) + break + } - case 'where': { - const { field, filter, value } = q - const fieldName = Array.isArray(field) ? field.join('.') : field - acc.firestoreQuery = acc.firestoreQuery.where( - fieldName, - filter, - unwrapData(value) - ) - break - } + case 'where': { + const { field, filter, value } = q + const fieldName = Array.isArray(field) ? field.join('.') : field + acc.firestoreQuery = acc.firestoreQuery.where( + fieldName, + filter, + unwrapData(a, value) + ) + break + } - case 'limit': { - const { number } = q - acc.firestoreQuery = acc.firestoreQuery.limit(number) - break + case 'limit': { + const { number } = q + acc.firestoreQuery = acc.firestoreQuery.limit(number) + break + } } - } - - return acc - }, - { - firestoreQuery: - collection.__type__ === 'collectionGroup' - ? firestore().collectionGroup(collection.path) - : firestore().collection(collection.path), - cursors: [] - } as { - firestoreQuery: FirebaseQuery - cursors: Cursor[] - } - ) - const groupedCursors = cursors.reduce( - (acc, cursor) => { - let methodValues = acc.find(([method]) => method === cursor.method) - if (!methodValues) { - methodValues = [cursor.method, []] - acc.push(methodValues) + return acc + }, + { + firestoreQuery: + collection.__type__ === 'collectionGroup' + ? a.firestore.collectionGroup(collection.path) + : a.firestore.collection(collection.path), + cursors: [] + } as { + firestoreQuery: FirebaseQuery + cursors: Cursor[] } - methodValues[1].push(unwrapData(cursor.value)) - return acc - }, - [] as [CursorMethod, any[]][] - ) + ) + + const groupedCursors = cursors.reduce( + (acc, cursor) => { + let methodValues = acc.find(([method]) => method === cursor.method) + if (!methodValues) { + methodValues = [cursor.method, []] + acc.push(methodValues) + } + methodValues[1].push(unwrapData(a, cursor.value)) + return acc + }, + [] as [CursorMethod, any[]][] + ) - const paginatedFirestoreQuery = - cursors.length && cursors.every(cursor => cursor.value !== undefined) - ? groupedCursors.reduce((acc, [method, values]) => { - return acc[method](...values) - }, firestoreQuery) - : firestoreQuery + const paginatedFirestoreQuery = + cursors.length && cursors.every(cursor => cursor.value !== undefined) + ? groupedCursors.reduce((acc, [method, values]) => { + return acc[method](...values) + }, firestoreQuery) + : firestoreQuery - return paginatedFirestoreQuery.onSnapshot( - (firestoreSnap: FirebaseFirestore.QuerySnapshot) => { - onResult( - firestoreSnap.docs.map(d => - doc( - collection.__type__ === 'collectionGroup' - ? pathToRef(d.ref.path) - : ref(collection, d.id), - wrapData(d.data()) as Model + firebaseUnsub = paginatedFirestoreQuery.onSnapshot( + (firestoreSnap: FirebaseFirestore.QuerySnapshot) => { + onResult( + firestoreSnap.docs.map(d => + doc( + collection.__type__ === 'collectionGroup' + ? pathToRef(d.ref.path) + : ref(collection, d.id), + wrapData(a, d.data()) as Model + ) ) ) - ) - }, - onError - ) - } catch (err) { - setTimeout(() => onError && onError(err)) - return () => {} - } + }, + onError + ) + }) + .catch(onError) + + return unsub } diff --git a/src/query/index.ts b/src/query/index.ts index c6ef8f87..b9abb486 100644 --- a/src/query/index.ts +++ b/src/query/index.ts @@ -1,4 +1,4 @@ -import firestore from '../adaptor' +import adaptor from '../adaptor' import { Collection } from '../collection' import { doc, Doc } from '../doc' import { ref, pathToRef } from '../ref' @@ -53,6 +53,7 @@ export async function query( collection: Collection | CollectionGroup, queries: Query[] ): Promise[]> { + const a = await adaptor() const { firestoreQuery, cursors } = queries.reduce( (acc, q) => { switch (q.type) { @@ -84,7 +85,7 @@ export async function query( acc.firestoreQuery = acc.firestoreQuery.where( fieldName, filter, - unwrapData(value) + unwrapData(a, value) ) break } @@ -101,8 +102,8 @@ export async function query( { firestoreQuery: collection.__type__ === 'collectionGroup' - ? firestore().collectionGroup(collection.path) - : firestore().collection(collection.path), + ? a.firestore.collectionGroup(collection.path) + : a.firestore.collection(collection.path), cursors: [] } as { firestoreQuery: FirebaseQuery @@ -117,7 +118,7 @@ export async function query( methodValues = [cursor.method, []] acc.push(methodValues) } - methodValues[1].push(unwrapData(cursor.value)) + methodValues[1].push(unwrapData(a, cursor.value)) return acc }, [] as [CursorMethod, any[]][] @@ -137,7 +138,7 @@ export async function query( collection.__type__ === 'collectionGroup' ? pathToRef(d.ref.path) : ref(collection, d.id), - wrapData(d.data()) as Model + wrapData(a, d.data()) as Model ) ) } diff --git a/src/ref/index.ts b/src/ref/index.ts index d190679d..70198726 100644 --- a/src/ref/index.ts +++ b/src/ref/index.ts @@ -1,4 +1,4 @@ -import firestore from '../adaptor' +import adaptor, { Adaptor } from '../adaptor' import { Collection } from '../collection' /** @@ -46,16 +46,14 @@ export interface Ref { */ export function ref( collection: Collection, - id?: string + id: string ): Ref { - if (id) { - return { __type__: 'ref', collection, id } - } else { - const id = firestore() - .collection(collection.path) - .doc().id - return { __type__: 'ref', collection, id } - } + return { __type__: 'ref', collection, id } +} + +export async function id(collection: Collection) { + const a = await adaptor() + return a.firestore.collection(collection.path).doc().id } /** @@ -74,8 +72,11 @@ export function getRefPath(ref: Ref) { * @param ref - The reference to create Firestore document from * @returns Firestore document */ -export function refToFirestoreDocument(ref: Ref) { - return firestore().doc(getRefPath(ref)) +export function refToFirestoreDocument( + { firestore }: Adaptor, + ref: Ref +) { + return firestore.doc(getRefPath(ref)) } /** diff --git a/src/ref/test.ts b/src/ref/test.ts index 18a35e2e..2c88eb48 100644 --- a/src/ref/test.ts +++ b/src/ref/test.ts @@ -1,6 +1,6 @@ import assert from 'assert' import nanoid from 'nanoid' -import { getRefPath, ref, pathToRef } from '.' +import { getRefPath, ref, pathToRef, id } from '.' import { collection } from '../collection' describe('Ref', () => { @@ -17,11 +17,13 @@ describe('Ref', () => { collection: users }) }) + }) - it('creates ref object with id generated by Firebase', () => { - const userRef = ref(users) - assert(typeof userRef.id === 'string') - assert(userRef.id.length > 10) + describe('id', () => { + it('generates random id', async () => { + const userId = await id(users) + assert(typeof userId === 'string') + assert(userId.length > 10) }) }) diff --git a/src/remove/index.ts b/src/remove/index.ts index f4046bd4..e3108cf8 100644 --- a/src/remove/index.ts +++ b/src/remove/index.ts @@ -1,4 +1,4 @@ -import firestore from '../adaptor' +import adaptor from '../adaptor' import { Collection } from '../collection' import { Ref } from '../ref' @@ -34,6 +34,7 @@ async function remove( collectionOrRef: Collection | Ref, maybeId?: string ): Promise { + const a = await adaptor() let collection: Collection let id: string @@ -46,9 +47,7 @@ async function remove( id = ref.id } - const firebaseDoc = firestore() - .collection(collection.path) - .doc(id) + const firebaseDoc = a.firestore.collection(collection.path).doc(id) await firebaseDoc.delete() } diff --git a/src/remove/test.ts b/src/remove/test.ts index 25ef6a4c..832f4de1 100644 --- a/src/remove/test.ts +++ b/src/remove/test.ts @@ -10,7 +10,7 @@ describe('remove', () => { it('removes document', async () => { const user = await add(users, { name: 'Sasha' }) - const { id } = user.ref + const { id } = user await remove(users, id) const userFromDB = await get(users, id) assert(userFromDB === null) @@ -18,8 +18,8 @@ describe('remove', () => { it('allows removing by ref', async () => { const user = await add(users, { name: 'Sasha' }) - await remove(user.ref) - const userFromDB = await get(users, user.ref.id) + await remove(user) + const userFromDB = await get(users, user.id) assert(userFromDB === null) }) }) diff --git a/src/set/index.ts b/src/set/index.ts index a947b4c7..80e935b2 100644 --- a/src/set/index.ts +++ b/src/set/index.ts @@ -1,4 +1,4 @@ -import firestore from '../adaptor' +import adaptor from '../adaptor' import { Collection } from '../collection' import { unwrapData } from '../data' import { Ref } from '../ref' @@ -51,6 +51,7 @@ async function set( idOrData: string | SetModel, maybeData?: SetModel ): Promise { + const a = await adaptor() let collection: Collection let id: string let data: SetModel @@ -66,10 +67,8 @@ async function set( data = idOrData as SetModel } - const firestoreDoc = firestore() - .collection(collection.path) - .doc(id) - await firestoreDoc.set(unwrapData(data)) + const firestoreDoc = a.firestore.collection(collection.path).doc(id) + await firestoreDoc.set(unwrapData(a, data)) } export default set diff --git a/src/transaction/index.ts b/src/transaction/index.ts index 2953ca3d..da85f168 100644 --- a/src/transaction/index.ts +++ b/src/transaction/index.ts @@ -1,11 +1,11 @@ -import firestore from '../adaptor' +import adaptor from '../adaptor' import { Collection } from '../collection' import { unwrapData, wrapData } from '../data' import { Doc, doc } from '../doc' import { Field } from '../field' import { Ref, ref } from '../ref' -import { UpdateModel } from '../update' import { SetModel } from '../set' +import { UpdateModel } from '../update' import { UpsetModel } from '../upset' /** @@ -250,11 +250,12 @@ export type TransactionWriteFunction = ( * transaction write API with the data returned by the read function * @returns Promise that is resolved when transaction is closed */ -export function transaction( +export async function transaction( readFunction: TransactionReadFunction, writeFunction: TransactionWriteFunction ): Promise { - return firestore().runTransaction(t => { + const a = await adaptor() + return a.firestore.runTransaction(t => { async function get( collectionOrRef: Collection | Ref, maybeId?: string @@ -271,15 +272,13 @@ export function transaction( id = ref.id } - const firestoreDoc = firestore() - .collection(collection.path) - .doc(id) + const firestoreDoc = a.firestore.collection(collection.path).doc(id) // ^ above // TODO: Refactor code above and below because is all the same as in the regular get function const firestoreSnap = await t.get(firestoreDoc) // v below const firestoreData = firestoreSnap.data() - const data = firestoreData && (wrapData(firestoreData) as Model) + const data = firestoreData && (wrapData(a, firestoreData) as Model) return data ? doc(ref(collection, id), data) : null } @@ -303,12 +302,10 @@ export function transaction( data = idOrData as SetModel } - const firestoreDoc = firestore() - .collection(collection.path) - .doc(id) + const firestoreDoc = a.firestore.collection(collection.path).doc(id) // ^ above // TODO: Refactor code above and below because is all the same as in the regular set function - await t.set(firestoreDoc, unwrapData(data)) + await t.set(firestoreDoc, unwrapData(a, data)) } async function upset( @@ -331,12 +328,10 @@ export function transaction( data = idOrData as UpsetModel } - const firestoreDoc = firestore() - .collection(collection.path) - .doc(id) + const firestoreDoc = a.firestore.collection(collection.path).doc(id) // ^ above // TODO: Refactor code above and below because is all the same as in the regular set function - await t.set(firestoreDoc, unwrapData(data), { merge: true }) + await t.set(firestoreDoc, unwrapData(a, data), { merge: true }) } async function update( @@ -359,9 +354,7 @@ export function transaction( data = idOrData as Model } - const firebaseDoc = firestore() - .collection(collection.path) - .doc(id) + const firebaseDoc = a.firestore.collection(collection.path).doc(id) const updateData = Array.isArray(data) ? data.reduce( (acc, { key, value }) => { @@ -373,7 +366,7 @@ export function transaction( : data // ^ above // TODO: Refactor code above because is all the same as in the regular update function - await t.update(firebaseDoc, unwrapData(updateData)) + await t.update(firebaseDoc, unwrapData(a, updateData)) } async function remove( @@ -392,9 +385,7 @@ export function transaction( id = ref.id } - const firebaseDoc = firestore() - .collection(collection.path) - .doc(id) + const firebaseDoc = a.firestore.collection(collection.path).doc(id) // ^ above // TODO: Refactor code above because is all the same as in the regular update function await t.delete(firebaseDoc) diff --git a/src/update/index.ts b/src/update/index.ts index d35242d7..16ed6e0e 100644 --- a/src/update/index.ts +++ b/src/update/index.ts @@ -1,4 +1,4 @@ -import firestore from '../adaptor' +import adaptor from '../adaptor' import { Collection } from '../collection' import { UpdateValue } from '../value' import { Field } from '../field' @@ -85,6 +85,7 @@ async function update( idOrData: string | Field[] | UpdateModel, maybeData?: Field[] | UpdateModel ): Promise { + const a = await adaptor() let collection: Collection let id: string let data: UpdateModel @@ -100,9 +101,7 @@ async function update( data = idOrData as UpdateModel } - const firebaseDoc = firestore() - .collection(collection.path) - .doc(id) + const firebaseDoc = a.firestore.collection(collection.path).doc(id) const updateData = Array.isArray(data) ? data.reduce( (acc, { key, value }) => { @@ -112,7 +111,7 @@ async function update( {} as { [key: string]: any } ) : data - await firebaseDoc.update(unwrapData(updateData)) + await firebaseDoc.update(unwrapData(a, updateData)) } export default update diff --git a/src/update/test.ts b/src/update/test.ts index 8169b454..3897cb0c 100644 --- a/src/update/test.ts +++ b/src/update/test.ts @@ -5,7 +5,7 @@ import add from '../add' import { collection } from '../collection' import field from '../field' import get from '../get' -import { ref, Ref } from '../ref' +import { ref, Ref, id } from '../ref' import set from '../set' import { value } from '../value' @@ -28,7 +28,7 @@ describe('update', () => { address: { city: 'Omsk' }, visits: 0 }) - const { id } = user.ref + const { id } = user await update(users, id, { name: 'Sasha Koss' }) const userFromDB = await get(users, id) assert.deepEqual(userFromDB.data, { @@ -44,12 +44,12 @@ describe('update', () => { address: { city: 'Omsk' }, visits: 0 }) - await update(user.ref, { name: 'Sasha Koss' }) - await update(user.ref, [ + await update(user, { name: 'Sasha Koss' }) + await update(user, [ field('name', 'Sasha Koss'), field(['address', 'city'], 'Moscow') ]) - const userFromDB = await get(users, user.ref.id) + const userFromDB = await get(users, user.id) assert.deepEqual(userFromDB.data, { name: 'Sasha Koss', address: { city: 'Moscow' }, @@ -63,7 +63,7 @@ describe('update', () => { address: { city: 'Omsk' }, visits: 0 }) - const { id } = user.ref + const { id } = user await update(users, id, [ field('name', 'Sasha Koss'), field(['address', 'city'], 'Dimitrovgrad'), @@ -108,7 +108,7 @@ describe('update', () => { visits: 0, guest: true }) - const { id } = user.ref + const { id } = user await update(users, id, { guest: value('remove') }) const userFromDB = await get(users, id) assert.deepEqual(userFromDB.data, { @@ -124,7 +124,7 @@ describe('update', () => { address: { city: 'Omsk' }, visits: 0 }) - const { id } = user.ref + const { id } = user await update(users, id, { visits: value('increment', 2) }) const userFromDB = await get(users, id) assert.deepEqual(userFromDB.data, { @@ -141,7 +141,7 @@ describe('update', () => { birthday: new Date(1987, 2, 11), visits: 0 }) - const { id } = user.ref + const { id } = user await update(users, id, { birthday: new Date(1987, 1, 11) }) const userFromDB = await get(users, id) assert.deepEqual(userFromDB.data, { @@ -159,7 +159,7 @@ describe('update', () => { birthday: new Date(1987, 2, 11), visits: 0 }) - const { id } = user.ref + const { id } = user await update(users, id, { birthday: value('serverDate') }) const userFromDB = await get(users, id) const dateFromDB = userFromDB.data.birthday @@ -185,7 +185,7 @@ describe('update', () => { 'The Mom Test' ] }) - const { id } = fav.ref + const { id } = fav await update(favorites, id, { favorites: value('arrayUnion', [ "Harry Potter and the Sorcerer's Stone", @@ -215,7 +215,7 @@ describe('update', () => { 'The Mom Test' ] }) - const { id } = fav.ref + const { id } = fav await update(favorites, id, { favorites: value('arrayRemove', [ 'The 22 Immutable Laws of Marketing', @@ -230,17 +230,17 @@ describe('update', () => { }) it('union update references', async () => { - const user1 = ref(users) - const user2 = ref(users) + const user1 = ref(users, await id(users)) + const user2 = ref(users, await id(users)) const movie = await add(movies, { title: "Harry Potter and the Sorcerer's Stone", likedBy: [user1] }) - await update(movie.ref, { + await update(movie, { likedBy: value('arrayUnion', [user2]) }) - const movieFromDB = await get(movie.ref) + const movieFromDB = await get(movie) assert.deepEqual(movieFromDB.data, { title: "Harry Potter and the Sorcerer's Stone", likedBy: [user1, user2] @@ -248,17 +248,17 @@ describe('update', () => { }) it('remove update references', async () => { - const user1 = ref(users) - const user2 = ref(users) + const user1 = ref(users, await id(users)) + const user2 = ref(users, await id(users)) const movie = await add(movies, { title: 'Harry Potter and the Chamber of Secrets', likedBy: [user1, user2] }) - await update(movie.ref, { + await update(movie, { likedBy: value('arrayRemove', [user2]) }) - const bookFromDB = await get(movie.ref) + const bookFromDB = await get(movie) assert.deepEqual(bookFromDB.data, { title: 'Harry Potter and the Chamber of Secrets', likedBy: [user1] diff --git a/src/upset/index.ts b/src/upset/index.ts index 31083090..c12a4082 100644 --- a/src/upset/index.ts +++ b/src/upset/index.ts @@ -1,4 +1,4 @@ -import firestore from '../adaptor' +import adaptor from '../adaptor' import { Collection } from '../collection' import { unwrapData } from '../data' import { Ref } from '../ref' @@ -18,7 +18,7 @@ export type UpsetModel = { * @param ref - the reference to the document to set or update * @param data - the document data */ -async function upset( +export default async function upset( ref: Ref, data: UpsetModel ): Promise @@ -28,7 +28,7 @@ async function upset( * @param id - the id of the document to set or update * @param data - the document data */ -async function upset( +export default async function upset( collection: Collection, id: string, data: UpsetModel @@ -51,11 +51,12 @@ async function upset( * //=> { name: 'Sasha Koss', deleted: true } * ``` */ -async function upset( +export default async function upset( collectionOrRef: Collection | Ref, idOrData: string | UpsetModel, maybeData?: UpsetModel ): Promise { + const a = await adaptor() let collection: Collection let id: string let data: UpsetModel @@ -71,10 +72,6 @@ async function upset( data = idOrData as UpsetModel } - const firestoreDoc = firestore() - .collection(collection.path) - .doc(id) - await firestoreDoc.set(unwrapData(data), { merge: true }) + const firestoreDoc = a.firestore.collection(collection.path).doc(id) + await firestoreDoc.set(unwrapData(a, data), { merge: true }) } - -export default upset