Skip to content

Commit

Permalink
refactor: rename unbind() to stop()
Browse files Browse the repository at this point in the history
BREAKING CHANGE: Composables like `useDocument()` no longer return an
`unbind()` method. The method is now named `stop()` to better reflect
that they also stop the Vue watcher on top of stopping the Firebase data
subscription.
  • Loading branch information
posva committed Nov 15, 2022
1 parent 3c08b19 commit 37d3f67
Show file tree
Hide file tree
Showing 15 changed files with 91 additions and 82 deletions.
26 changes: 12 additions & 14 deletions src/database/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import { databaseUnbinds } from './optionsApi'
import {
bindAsArray,
bindAsObject,
rtdbOptions,
databaseOptionsDefaults,
_DatabaseRefOptions,
} from './subscribe'
import {
Expand Down Expand Up @@ -54,8 +54,8 @@ export function _useDatabaseRef(
reference: _MaybeRef<_Nullable<DatabaseReference | Query>>,
localOptions: UseDatabaseRefOptions = {}
) {
let _unbind!: UnbindWithReset
const options = Object.assign({}, rtdbOptions, localOptions)
let unbind!: UnbindWithReset
const options = Object.assign({}, databaseOptionsDefaults, localOptions)
const initialSourceValue = unref(reference)

const data = options.target || ref<unknown | null>()
Expand All @@ -74,13 +74,13 @@ export function _useDatabaseRef(

const p = new Promise<unknown | null>((resolve, reject) => {
if (!referenceValue) {
_unbind = noop
unbind = noop
// resolve to avoid an ever pending promise
return resolve(null)
}

if (Array.isArray(data.value)) {
_unbind = bindAsArray(
unbind = bindAsArray(
{
target: data,
collection: referenceValue,
Expand All @@ -91,7 +91,7 @@ export function _useDatabaseRef(
options
)
} else {
_unbind = bindAsObject(
unbind = bindAsObject(
{
target: data,
document: referenceValue,
Expand Down Expand Up @@ -132,30 +132,28 @@ export function _useDatabaseRef(
}

if (hasCurrentScope) {
onScopeDispose(unbind)
onScopeDispose(stop)

// wait for the promise on SSR
if (getCurrentInstance()) {
onServerPrefetch(() => promise.value)
}
}

// TODO: rename to stop
function unbind(reset: ResetOption = options.reset) {
function stop(reset: ResetOption = options.reset) {
stopWatcher()
removePendingPromise()
_unbind(reset)
unbind(reset)
}

return Object.defineProperties(data as _RefDatabase<unknown>, {
// allow destructuring without interfering with the ref itself
data: { get: () => data },
error: { get: () => error },
pending: { get: () => error },

pending: { get: () => pending },
promise: { get: () => promise },
unbind: { get: () => unbind },
}) as _RefDatabase<unknown | null>
stop: { get: () => stop },
})
}

export function internalUnbind(
Expand Down
11 changes: 5 additions & 6 deletions src/database/optionsApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,12 @@ import { useFirebaseApp } from '../app'
import { getGlobalScope } from '../globals'
import { ResetOption, UnbindWithReset } from '../shared'
import { internalUnbind, _useDatabaseRef } from './index'
import { _DatabaseRefOptions, _GlobalDatabaseRefOptions } from './subscribe'
import { _DatabaseRefOptions } from './subscribe'

/**
* Options for the Firebase Database Plugin that enables the Options API such as `$rtdbBind` and `$rtdbUnbind`.
* Options for the Firebase Database Plugin that enables the Options API such as `$databaseBind` and `$databaseUnbind`.
*/
export interface DatabasePluginOptions
extends Partial<_GlobalDatabaseRefOptions> {
export interface DatabasePluginOptions extends _DatabaseRefOptions {
/**
* @deprecated: was largely unused and not very useful. Please open an issue with use cases if you need this.
*/
Expand All @@ -25,7 +24,7 @@ export interface DatabasePluginOptions
}

const databasePluginDefaults: Readonly<
Required<Omit<DatabasePluginOptions, keyof _GlobalDatabaseRefOptions>>
Required<Omit<DatabasePluginOptions, keyof _DatabaseRefOptions>>
> = {
bindName: '$databaseBind',
unbindName: '$databaseUnbind',
Expand Down Expand Up @@ -109,7 +108,7 @@ export function databasePlugin(
effectScope()
)!

const { promise, unbind: _unbind } = scope.run(() =>
const { promise, stop: _unbind } = scope.run(() =>
_useDatabaseRef(source, { target, ...options })
)!

Expand Down
21 changes: 15 additions & 6 deletions src/database/subscribe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@ import {
indexForKey,
DatabaseSnapshotSerializer,
} from './utils'
import { OperationsType, ResetOption, _DataSourceOptions } from '../shared'
import {
noop,
OperationsType,
ResetOption,
_DataSourceOptions,
} from '../shared'
import { ref, Ref, unref } from 'vue-demi'
import type { Query, DatabaseReference } from 'firebase/database'
import {
Expand All @@ -14,12 +19,17 @@ import {
onChildRemoved,
} from 'firebase/database'

// TODO: rename to match where it's used
/**
* Global option type when binding one database reference
*/
export interface _DatabaseRefOptions extends _DataSourceOptions {
serialize?: DatabaseSnapshotSerializer
}

export interface _GlobalDatabaseRefOptions extends _DatabaseRefOptions {
/**
* Global defaults type override options for all database bindings.
*/
interface _DefaultsDatabaseRefOptions extends _DatabaseRefOptions {
/**
* @defaultValue `false`
*/
Expand All @@ -32,14 +42,13 @@ export interface _GlobalDatabaseRefOptions extends _DatabaseRefOptions {
serialize: DatabaseSnapshotSerializer
}

const DEFAULT_OPTIONS: _GlobalDatabaseRefOptions = {
const DEFAULT_OPTIONS: _DefaultsDatabaseRefOptions = {
reset: false,
serialize: createRecordFromDatabaseSnapshot,
wait: true,
}

// TODO: rename rtdbDefaults databaseDefaults
export { DEFAULT_OPTIONS as rtdbOptions }
export { DEFAULT_OPTIONS as databaseOptionsDefaults }

interface CommonBindOptionsParameter {
target: Ref<any>
Expand Down
21 changes: 10 additions & 11 deletions src/firestore/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import { firestoreUnbinds } from './optionsApi'
import {
bindCollection,
bindDocument,
firestoreOptions,
firestoreOptionsDefaults,
FirestoreRefOptions,
} from './subscribe'

Expand All @@ -63,8 +63,8 @@ export function _useFirestoreRef(
>,
localOptions?: _UseFirestoreRefOptions
) {
let _unbind: UnbindWithReset = noop
const options = Object.assign({}, firestoreOptions, localOptions)
let unbind: UnbindWithReset = noop
const options = Object.assign({}, firestoreOptionsDefaults, localOptions)
const initialSourceValue = unref(docOrCollectionRef)

const data = options.target || ref<unknown | null>()
Expand All @@ -83,12 +83,12 @@ export function _useFirestoreRef(

const p = new Promise<unknown | null>((resolve, reject) => {
// stop the previous subscription
_unbind(options.reset)
unbind(options.reset)
// skip if the ref is null or undefined
// we still want to create the new promise
if (!docRefValue) {
_unbind = noop
// TODO: maybe we shouldn't resolve this at all?
unbind = noop
// resolve to avoid an ever pending promise
return resolve(null)
}

Expand All @@ -100,7 +100,7 @@ export function _useFirestoreRef(
}

// FIXME: force once on server
_unbind = (isDocumentRef(docRefValue) ? bindDocument : bindCollection)(
unbind = (isDocumentRef(docRefValue) ? bindDocument : bindCollection)(
// @ts-expect-error: cannot type with the ternary
data,
docRefValue,
Expand Down Expand Up @@ -142,19 +142,18 @@ export function _useFirestoreRef(
// should take an option like once: true to not setting up any listener

if (hasCurrentScope) {
onScopeDispose(unbind)
onScopeDispose(stop)
if (getCurrentInstance()) {
// wait for the promise during SSR
// TODO: configurable ssrKey: false to disable this
onServerPrefetch(() => promise.value)
}
}

// TODO: rename to stop
function unbind(reset: ResetOption = options.reset) {
function stop(reset: ResetOption = options.reset) {
stopWatcher()
removePendingPromise()
_unbind(reset)
unbind(reset)
}

// allow to destructure the returned value
Expand Down
9 changes: 4 additions & 5 deletions src/firestore/optionsApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import type {
} from 'firebase/firestore'
import { App, ComponentPublicInstance, effectScope, toRef } from 'vue'
import { isVue3 } from 'vue-demi'
import { FirestoreRefOptions, _GlobalFirestoreRefOptions } from './subscribe'
import { FirestoreRefOptions } from './subscribe'
import { internalUnbind, _useFirestoreRef } from '.'
import { ResetOption, UnbindWithReset, _FirestoreDataSource } from '../shared'
import { FirebaseApp } from 'firebase/app'
Expand All @@ -27,8 +27,7 @@ export const firestoreUnbinds = new WeakMap<
* Options for the Firebase Database Plugin that enables the Options API such as `$firestoreBind` and
* `$firestoreUnbind`.
*/
export interface FirestorePluginOptions
extends Partial<_GlobalFirestoreRefOptions> {
export interface FirestorePluginOptions extends FirestoreRefOptions {
/**
* @deprecated: was largely unused and not very useful. Please open an issue with use cases if you need this.
*/
Expand All @@ -41,7 +40,7 @@ export interface FirestorePluginOptions
}

const firestorePluginDefaults: Readonly<
Required<Omit<FirestorePluginOptions, keyof _GlobalFirestoreRefOptions>>
Required<Omit<FirestorePluginOptions, keyof FirestoreRefOptions>>
> = {
bindName: '$firestoreBind',
unbindName: '$firestoreUnbind',
Expand Down Expand Up @@ -104,7 +103,7 @@ export const firestorePlugin = function firestorePlugin(
effectScope()
)!

const { promise, unbind: _unbind } = scope.run(() =>
const { promise, stop: _unbind } = scope.run(() =>
_useFirestoreRef(docOrCollectionRef, {
target,
...options,
Expand Down
17 changes: 11 additions & 6 deletions src/firestore/subscribe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,18 @@ export interface FirestoreRefOptions extends _DataSourceOptions {
* @inheritDoc {SnapshotListenOptions}
*/
snapshotListenOptions?: SnapshotListenOptions

/**
* Default Firestore converter to use with snapshots.
*/
converter?: FirestoreDataConverter<unknown>
}

/**
* Type of the global options for firestore refs. Some values cannot be `undefined`.
* @internal
*/
export interface _GlobalFirestoreRefOptions extends FirestoreRefOptions {
interface _DefaultsFirestoreRefOptions extends FirestoreRefOptions {
/**
* @defaultValue `false`
*/
Expand All @@ -65,13 +70,13 @@ export interface _GlobalFirestoreRefOptions extends FirestoreRefOptions {
converter: FirestoreDataConverter<unknown>
}

const DEFAULT_OPTIONS: _GlobalFirestoreRefOptions = {
const DEFAULT_OPTIONS: _DefaultsFirestoreRefOptions = {
reset: false,
wait: true,
maxRefDepth: 2,
converter: firestoreDefaultConverter,
}
export { DEFAULT_OPTIONS as firestoreOptions }
export { DEFAULT_OPTIONS as firestoreOptionsDefaults }

interface FirestoreSubscription {
unsub: () => void
Expand All @@ -89,7 +94,7 @@ function unsubscribeAll(subs: Record<string, FirestoreSubscription>) {
}

function updateDataFromDocumentSnapshot<T>(
options: _GlobalFirestoreRefOptions,
options: _DefaultsFirestoreRefOptions,
target: Ref<T>,
path: string,
snapshot: DocumentSnapshot<T>,
Expand Down Expand Up @@ -120,7 +125,7 @@ interface SubscribeToDocumentParameter {

function subscribeToDocument(
{ ref, target, path, depth, resolve, ops }: SubscribeToDocumentParameter,
options: _GlobalFirestoreRefOptions
options: _DefaultsFirestoreRefOptions
) {
const subs = Object.create(null)
const unbind = onSnapshot(ref, (snapshot) => {
Expand Down Expand Up @@ -151,7 +156,7 @@ function subscribeToDocument(
// first one is calling the other on every ref and subscribeToDocument may call
// updateDataFromDocumentSnapshot which may call subscribeToRefs as well
function subscribeToRefs(
options: _GlobalFirestoreRefOptions,
options: _DefaultsFirestoreRefOptions,
target: Ref<unknown>,
path: string | number,
subs: Record<string, FirestoreSubscription>,
Expand Down
9 changes: 5 additions & 4 deletions src/shared.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { DatabaseReference, Query as DatabaseQuery } from 'firebase/database'
import type {
import {
CollectionReference,
DocumentData,
DocumentReference,
DocumentSnapshot,
Query as FirestoreQuery,
QuerySnapshot,
Timestamp,
} from 'firebase/firestore'
import type { Ref, ShallowRef } from 'vue-demi'

Expand Down Expand Up @@ -33,7 +34,7 @@ export interface OperationsType {
export type ResetOption = boolean | (() => unknown)

/**
* Return type of `$rtdbBind()` and `$firestoreBind()`
* Return type of `$databaseBind()` and `$firestoreBind()`
*/
export type UnbindWithReset = (reset?: ResetOption) => void

Expand Down Expand Up @@ -94,7 +95,7 @@ export function isObject(o: any): o is Record<any, unknown> {
* Checks if a variable is a Date
* @param o
*/
export function isTimestamp(o: any): o is Date {
export function isTimestamp(o: any): o is Timestamp {
return o.toDate
}

Expand Down Expand Up @@ -206,7 +207,7 @@ export interface _RefWithState<T, E = Error> extends Ref<T> {
/**
* Stops listening to the data changes and stops the Vue watcher.
*/
unbind: (reset?: ResetOption) => void
stop: (reset?: ResetOption) => void
}

/**
Expand Down
Loading

0 comments on commit 37d3f67

Please sign in to comment.