diff --git a/packages/database/src/api/DataSnapshot.ts b/packages/database/src/api/DataSnapshot.ts index 61b5558d7e0..44ea483a239 100644 --- a/packages/database/src/api/DataSnapshot.ts +++ b/packages/database/src/api/DataSnapshot.ts @@ -17,28 +17,20 @@ import { validateArgCount, validateCallback } from '@firebase/util'; import { validatePathString } from '../core/util/validation'; -import { Path } from '../core/util/Path'; -import { PRIORITY_INDEX } from '../core/snap/indexes/PriorityIndex'; -import { Node } from '../core/snap/Node'; import { Reference } from './Reference'; -import { Index } from '../core/snap/indexes/Index'; -import { ChildrenNode } from '../core/snap/ChildrenNode'; +import { DataSnapshot as ExpDataSnapshot } from '../exp/DataSnapshot'; + +// TODO(databaseexp): Import Compat from @firebase/util +export interface Compat { + readonly _delegate: T; +} /** * Class representing a firebase data snapshot. It wraps a SnapshotNode and * surfaces the public methods (val, forEach, etc.) we want to expose. */ -export class DataSnapshot { - /** - * @param node_ A SnapshotNode to wrap. - * @param ref_ The ref of the location this snapshot came from. - * @param index_ The iteration order for this snapshot - */ - constructor( - private readonly node_: Node, - private readonly ref_: Reference, - private readonly index_: Index - ) {} +export class DataSnapshot implements Compat { + constructor(readonly _delegate: ExpDataSnapshot) {} /** * Retrieves the snapshot contents as JSON. Returns null if the snapshot is @@ -48,7 +40,7 @@ export class DataSnapshot { */ val(): unknown { validateArgCount('DataSnapshot.val', 0, 0, arguments.length); - return this.node_.val(); + return this._delegate.val(); } /** @@ -58,7 +50,7 @@ export class DataSnapshot { */ exportVal(): unknown { validateArgCount('DataSnapshot.exportVal', 0, 0, arguments.length); - return this.node_.val(true); + return this._delegate.exportVal(); } // Do not create public documentation. This is intended to make JSON serialization work but is otherwise unnecessary @@ -66,7 +58,7 @@ export class DataSnapshot { toJSON(): unknown { // Optional spacer argument is unnecessary because we're depending on recursion rather than stringifying the content validateArgCount('DataSnapshot.toJSON', 0, 1, arguments.length); - return this.exportVal(); + return this._delegate.toJSON(); } /** @@ -76,7 +68,7 @@ export class DataSnapshot { */ exists(): boolean { validateArgCount('DataSnapshot.exists', 0, 0, arguments.length); - return !this.node_.isEmpty(); + return this._delegate.exists(); } /** @@ -90,14 +82,7 @@ export class DataSnapshot { // Ensure the childPath is a string (can be a number) childPathString = String(childPathString); validatePathString('DataSnapshot.child', 1, childPathString, false); - - const childPath = new Path(childPathString); - const childRef = this.ref_.child(childPath); - return new DataSnapshot( - this.node_.getChild(childPath), - childRef, - PRIORITY_INDEX - ); + return new DataSnapshot(this._delegate.child(childPathString)); } /** @@ -109,9 +94,7 @@ export class DataSnapshot { hasChild(childPathString: string): boolean { validateArgCount('DataSnapshot.hasChild', 1, 1, arguments.length); validatePathString('DataSnapshot.hasChild', 1, childPathString, false); - - const childPath = new Path(childPathString); - return !this.node_.getChild(childPath).isEmpty(); + return this._delegate.hasChild(childPathString); } /** @@ -121,9 +104,7 @@ export class DataSnapshot { */ getPriority(): string | number | null { validateArgCount('DataSnapshot.getPriority', 0, 0, arguments.length); - - // typecast here because we never return deferred values or internal priorities (MAX_PRIORITY) - return this.node_.getPriority().val() as string | number | null; + return this._delegate.priority; } /** @@ -134,21 +115,12 @@ export class DataSnapshot { * @return True if forEach was canceled by action returning true for * one of the child nodes. */ - forEach(action: (d: DataSnapshot) => boolean | void): boolean { + forEach(action: (snapshot: DataSnapshot) => boolean | void): boolean { validateArgCount('DataSnapshot.forEach', 1, 1, arguments.length); validateCallback('DataSnapshot.forEach', 1, action, false); - - if (this.node_.isLeafNode()) { - return false; - } - - const childrenNode = this.node_ as ChildrenNode; - // Sanitize the return value to a boolean. ChildrenNode.forEachChild has a weird return type... - return !!childrenNode.forEachChild(this.index_, (key, node) => { - return action( - new DataSnapshot(node, this.ref_.child(key), PRIORITY_INDEX) - ); - }); + return this._delegate.forEach(expDataSnapshot => + action(new DataSnapshot(expDataSnapshot)) + ); } /** @@ -157,16 +129,11 @@ export class DataSnapshot { */ hasChildren(): boolean { validateArgCount('DataSnapshot.hasChildren', 0, 0, arguments.length); - - if (this.node_.isLeafNode()) { - return false; - } else { - return !this.node_.isEmpty(); - } + return this._delegate.hasChildren(); } get key() { - return this.ref_.getKey(); + return this._delegate.key; } /** @@ -175,8 +142,7 @@ export class DataSnapshot { */ numChildren(): number { validateArgCount('DataSnapshot.numChildren', 0, 0, arguments.length); - - return this.node_.numChildren(); + return this._delegate.size; } /** @@ -185,8 +151,7 @@ export class DataSnapshot { */ getRef(): Reference { validateArgCount('DataSnapshot.ref', 0, 0, arguments.length); - - return this.ref_; + return new Reference(this._delegate.ref._repo, this._delegate.ref._path); } get ref() { diff --git a/packages/database/src/api/Query.ts b/packages/database/src/api/Query.ts index fd9164555d9..986c7778991 100644 --- a/packages/database/src/api/Query.ts +++ b/packages/database/src/api/Query.ts @@ -15,6 +15,8 @@ * limitations under the License. */ +import { DataSnapshot as ExpDataSnapshot } from '../exp/DataSnapshot'; +import { Reference as ExpReference } from '../exp/Reference'; import { assert, Deferred, @@ -45,6 +47,7 @@ import { import { ChildEventRegistration, EventRegistration, + ExpSnapshotCallback, ValueEventRegistration } from '../core/view/EventRegistration'; @@ -71,7 +74,7 @@ import { DataSnapshot } from './DataSnapshot'; let __referenceConstructor: new (repo: Repo, path: Path) => Query; export interface SnapshotCallback { - (a: DataSnapshot, b?: string | null): unknown; + (dataSnapshot: DataSnapshot, previousChildName?: string | null): unknown; } /** @@ -215,19 +218,19 @@ export class Query { cancelCallbackOrContext, context ); - + const expCallback = new ExpSnapshotCallback(callback); if (eventType === 'value') { - this.onValueEvent(callback, ret.cancel, ret.context); + this.onValueEvent(expCallback, ret.cancel, ret.context); } else { - const callbacks: { [k: string]: typeof callback } = {}; - callbacks[eventType] = callback; + const callbacks: { [k: string]: ExpSnapshotCallback } = {}; + callbacks[eventType] = expCallback; this.onChildEvent(callbacks, ret.cancel, ret.context); } return callback; } protected onValueEvent( - callback: (a: DataSnapshot) => void, + callback: ExpSnapshotCallback, cancelCallback: ((a: Error) => void) | null, context: object | null ) { @@ -239,8 +242,8 @@ export class Query { repoAddEventCallbackForQuery(this.repo, this, container); } - onChildEvent( - callbacks: { [k: string]: SnapshotCallback }, + protected onChildEvent( + callbacks: { [k: string]: ExpSnapshotCallback }, cancelCallback: ((a: Error) => unknown) | null, context: object | null ) { @@ -261,20 +264,20 @@ export class Query { validateEventType('Query.off', 1, eventType, true); validateCallback('Query.off', 2, callback, true); validateContextObject('Query.off', 3, context, true); - let container: EventRegistration | null = null; - let callbacks: { [k: string]: typeof callback } | null = null; + let callbacks: { [k: string]: ExpSnapshotCallback } | null = null; + + const expCallback = callback ? new ExpSnapshotCallback(callback) : null; if (eventType === 'value') { - const valueCallback = callback || null; container = new ValueEventRegistration( - valueCallback, + expCallback, null, context || null ); } else if (eventType) { if (callback) { callbacks = {}; - callbacks[eventType] = callback; + callbacks[eventType] = expCallback; } container = new ChildEventRegistration(callbacks, null, context || null); } @@ -285,7 +288,15 @@ export class Query { * Get the server-value for this query, or return a cached value if not connected. */ get(): Promise { - return repoGetValue(this.repo, this); + return repoGetValue(this.repo, this).then(node => { + return new DataSnapshot( + new ExpDataSnapshot( + node, + new ExpReference(this.getRef().repo, this.getRef().path), + this.getQueryParams().getIndex() + ) + ); + }); } /** diff --git a/packages/database/src/api/Reference.ts b/packages/database/src/api/Reference.ts index 09258089b4d..5d734b55bfd 100644 --- a/packages/database/src/api/Reference.ts +++ b/packages/database/src/api/Reference.ts @@ -15,6 +15,9 @@ * limitations under the License. */ +import { DataSnapshot as ExpDataSnapshot } from '../exp/DataSnapshot'; +import { Node } from '../core/snap/Node'; +import { Reference as ExpReference } from '../exp/Reference'; import { OnDisconnect } from './onDisconnect'; import { TransactionResult } from './TransactionResult'; import { warn } from '../core/util/util'; @@ -51,6 +54,7 @@ import { Deferred, validateArgCount, validateCallback } from '@firebase/util'; import { syncPointSetReferenceConstructor } from '../core/SyncPoint'; import { Database } from './Database'; import { DataSnapshot } from './DataSnapshot'; +import { PRIORITY_INDEX } from '../core/snap/indexes/PriorityIndex'; export interface ReferenceConstructor { new (repo: Repo, path: Path): Reference; @@ -232,7 +236,11 @@ export class Reference extends Query { transaction( transactionUpdate: (a: unknown) => unknown, - onComplete?: (a: Error | null, b: boolean, c: DataSnapshot | null) => void, + onComplete?: ( + error: Error | null, + committed: boolean, + dataSnapshot: DataSnapshot | null + ) => void, applyLocally?: boolean ): Promise { validateArgCount('Reference.transaction', 1, 3, arguments.length); @@ -260,18 +268,26 @@ export class Reference extends Query { deferred.promise.catch(() => {}); } - const promiseComplete = function ( + const promiseComplete = ( error: Error, committed: boolean, - snapshot: DataSnapshot - ) { + node: Node | null + ) => { + let dataSnapshot: DataSnapshot | null = null; if (error) { deferred.reject(error); } else { - deferred.resolve(new TransactionResult(committed, snapshot)); + dataSnapshot = new DataSnapshot( + new ExpDataSnapshot( + node, + new ExpReference(this.repo, this.path), + PRIORITY_INDEX + ) + ); + deferred.resolve(new TransactionResult(committed, dataSnapshot)); } if (typeof onComplete === 'function') { - onComplete(error, committed, snapshot); + onComplete(error, committed, dataSnapshot); } }; repoStartTransaction( diff --git a/packages/database/src/core/Repo.ts b/packages/database/src/core/Repo.ts index 99f719a7f4b..8dc4ebe79b0 100644 --- a/packages/database/src/core/Repo.ts +++ b/packages/database/src/core/Repo.ts @@ -105,7 +105,6 @@ import { } from './util/Tree'; import { isValidPriority, validateFirebaseData } from './util/validation'; import { ChildrenNode } from './snap/ChildrenNode'; -import { PRIORITY_INDEX } from './snap/indexes/PriorityIndex'; import { Reference } from '../api/Reference'; import { FirebaseAppLike } from './RepoManager'; @@ -143,7 +142,7 @@ const enum TransactionStatus { interface Transaction { path: Path; update: (a: unknown) => unknown; - onComplete: (a: Error | null, b: boolean, c: DataSnapshot | null) => void; + onComplete: (error: Error, committed: boolean, node: Node | null) => void; status: TransactionStatus; order: number; applyLocally: boolean; @@ -450,17 +449,11 @@ function repoGetNextWriteId(repo: Repo): number { * * @param query - The query to surface a value for. */ -export function repoGetValue(repo: Repo, query: Query): Promise { +export function repoGetValue(repo: Repo, query: Query): Promise { // Only active queries are cached. There is no persisted cache. const cached = syncTreeGetServerValue(repo.serverSyncTree_, query); if (cached != null) { - return Promise.resolve( - new DataSnapshot( - cached, - query.getRef(), - query.getQueryParams().getIndex() - ) - ); + return Promise.resolve(cached); } return repo.server_.get(query).then( payload => { @@ -471,13 +464,7 @@ export function repoGetValue(repo: Repo, query: Query): Promise { node ); eventQueueRaiseEventsAtPath(repo.eventQueue_, query.path, events); - return Promise.resolve( - new DataSnapshot( - node, - query.getRef(), - query.getQueryParams().getIndex() - ) - ); + return Promise.resolve(node); }, err => { repoLog(repo, 'get for query ' + stringify(query) + ' failed: ' + err); @@ -883,7 +870,9 @@ export function repoStartTransaction( repo: Repo, path: Path, transactionUpdate: (a: unknown) => unknown, - onComplete: ((a: Error, b: boolean, c: DataSnapshot) => void) | null, + onComplete: + | ((error: Error, committed: boolean, node: Node | null) => void) + | null, applyLocally: boolean ): void { repoLog(repo, 'transaction on ' + path); @@ -930,13 +919,7 @@ export function repoStartTransaction( transaction.currentOutputSnapshotRaw = null; transaction.currentOutputSnapshotResolved = null; if (transaction.onComplete) { - // We just set the input snapshot, so this cast should be safe - const snapshot = new DataSnapshot( - transaction.currentInputSnapshot, - new Reference(repo, transaction.path), - PRIORITY_INDEX - ); - transaction.onComplete(null, false, snapshot); + transaction.onComplete(null, false, transaction.currentInputSnapshot); } } else { validateFirebaseData( @@ -1115,11 +1098,7 @@ function repoSendTransactionQueue( // We never unset the output snapshot, and given that this // transaction is complete, it should be set const node = queue[i].currentOutputSnapshotResolved as Node; - const ref = new Reference(repo, queue[i].path); - const snapshot = new DataSnapshot(node, ref, PRIORITY_INDEX); - callbacks.push( - queue[i].onComplete.bind(null, null, true, snapshot) - ); + callbacks.push(() => queue[i].onComplete(null, true, node)); } queue[i].unwatcher(); } @@ -1329,11 +1308,10 @@ function repoRerunTransactionQueue( const ref = new Reference(repo, queue[i].path); // We set this field immediately, so it's safe to cast to an actual snapshot const lastInput /** @type {!Node} */ = queue[i].currentInputSnapshot; - const snapshot = new DataSnapshot(lastInput, ref, PRIORITY_INDEX); - callbacks.push(queue[i].onComplete.bind(null, null, false, snapshot)); + callbacks.push(() => queue[i].onComplete(null, false, lastInput)); } else { - callbacks.push( - queue[i].onComplete.bind(null, new Error(abortReason), false, null) + callbacks.push(() => + queue[i].onComplete(new Error(abortReason), false, null) ); } } diff --git a/packages/database/src/core/view/Event.ts b/packages/database/src/core/view/Event.ts index 1c9b8f70f8c..82bd1350de2 100644 --- a/packages/database/src/core/view/Event.ts +++ b/packages/database/src/core/view/Event.ts @@ -18,7 +18,7 @@ import { stringify } from '@firebase/util'; import { Path } from '../util/Path'; import { EventRegistration } from './EventRegistration'; -import { DataSnapshot } from '../../api/DataSnapshot'; +import { DataSnapshot as ExpDataSnapshot } from '../../exp/DataSnapshot'; /** * Encapsulates the data needed to raise an event @@ -54,7 +54,7 @@ export class DataEvent implements Event { constructor( public eventType: EventType, public eventRegistration: EventRegistration, - public snapshot: DataSnapshot, + public snapshot: ExpDataSnapshot, public prevName?: string | null ) {} @@ -62,11 +62,11 @@ export class DataEvent implements Event { * @inheritDoc */ getPath(): Path { - const ref = this.snapshot.getRef(); + const ref = this.snapshot.ref; if (this.eventType === 'value') { - return ref.path; + return ref._path; } else { - return ref.getParent().path; + return ref.parent._path; } } diff --git a/packages/database/src/core/view/EventRegistration.ts b/packages/database/src/core/view/EventRegistration.ts index 646019ba0c4..106b7dc29ec 100644 --- a/packages/database/src/core/view/EventRegistration.ts +++ b/packages/database/src/core/view/EventRegistration.ts @@ -15,13 +15,40 @@ * limitations under the License. */ -import { DataSnapshot } from '../../api/DataSnapshot'; +import { DataSnapshot as ExpDataSnapshot } from '../../exp/DataSnapshot'; +import { Reference as ExpReference } from '../../exp/Reference'; import { DataEvent, CancelEvent, Event, EventType } from './Event'; import { contains, assert } from '@firebase/util'; import { Path } from '../util/Path'; import { Change } from './Change'; -import { Query } from '../../api/Query'; +import { Query, SnapshotCallback } from '../../api/Query'; +import { DataSnapshot } from '../../api/DataSnapshot'; + +/** + * A wrapper class that converts events from the database@exp SDK to the legacy + * Database SDK. Events are not converted directly as event registration relies + * on reference comparison of the original user callback (see `matches()`). + */ +export class ExpSnapshotCallback { + constructor(private readonly _userCallback: SnapshotCallback) {} + + callback( + thisArg: unknown, + expDataSnapshot: ExpDataSnapshot, + previousChildName?: string | null + ): unknown { + return this._userCallback.call( + thisArg, + new DataSnapshot(expDataSnapshot), + previousChildName + ); + } + + matches(exp: ExpSnapshotCallback): boolean { + return this._userCallback === exp._userCallback; + } +} /** * An EventRegistration is basically an event type ('value', 'child_added', etc.) and a callback @@ -64,7 +91,7 @@ export interface EventRegistration { */ export class ValueEventRegistration implements EventRegistration { constructor( - private callback_: ((d: DataSnapshot) => void) | null, + private callback_: ExpSnapshotCallback | null, private cancelCallback_: ((e: Error) => void) | null, private context_: {} | null ) {} @@ -84,7 +111,11 @@ export class ValueEventRegistration implements EventRegistration { return new DataEvent( 'value', this, - new DataSnapshot(change.snapshotNode, query.getRef(), index) + new ExpDataSnapshot( + change.snapshotNode, + new ExpReference(query.getRef().repo, query.getRef().path), + index + ) ); } @@ -106,7 +137,7 @@ export class ValueEventRegistration implements EventRegistration { } else { const cb = this.callback_; return function () { - cb.call(ctx, (eventData as DataEvent).snapshot); + cb.callback(ctx, (eventData as DataEvent).snapshot); }; } } @@ -133,7 +164,8 @@ export class ValueEventRegistration implements EventRegistration { return true; } else { return ( - other.callback_ === this.callback_ && other.context_ === this.context_ + other.callback_.matches(this.callback_) && + other.context_ === this.context_ ); } } @@ -155,7 +187,7 @@ export class ValueEventRegistration implements EventRegistration { export class ChildEventRegistration implements EventRegistration { constructor( private callbacks_: { - [k: string]: (d: DataSnapshot, s?: string | null) => void; + [child: string]: ExpSnapshotCallback; } | null, private cancelCallback_: ((e: Error) => void) | null, private context_?: {} @@ -193,7 +225,11 @@ export class ChildEventRegistration implements EventRegistration { return new DataEvent( change.type as EventType, this, - new DataSnapshot(change.snapshotNode, ref, index), + new ExpDataSnapshot( + change.snapshotNode, + new ExpReference(ref.repo, ref.path), + index + ), change.prevName ); } @@ -216,7 +252,7 @@ export class ChildEventRegistration implements EventRegistration { } else { const cb = this.callbacks_[(eventData as DataEvent).eventType]; return function () { - cb.call( + cb.callback( ctx, (eventData as DataEvent).snapshot, (eventData as DataEvent).prevName @@ -249,7 +285,7 @@ export class ChildEventRegistration implements EventRegistration { thisKey === otherKey && (!other.callbacks_[otherKey] || !this.callbacks_[thisKey] || - other.callbacks_[otherKey] === this.callbacks_[thisKey]) + other.callbacks_[otherKey].matches(this.callbacks_[thisKey])) ); } else { // Exact match on each key. diff --git a/packages/database/src/exp/DataSnapshot.ts b/packages/database/src/exp/DataSnapshot.ts index b2a3ea9dd60..f696aa264d3 100644 --- a/packages/database/src/exp/DataSnapshot.ts +++ b/packages/database/src/exp/DataSnapshot.ts @@ -15,54 +15,90 @@ * limitations under the License. */ -import { Reference } from './Reference'; +import { child, Reference } from './Reference'; +import { Node } from '../core/snap/Node'; +import { Index } from '../core/snap/indexes/Index'; +import { Path } from '../core/util/Path'; +import { PRIORITY_INDEX } from '../core/snap/indexes/PriorityIndex'; +import { ChildrenNode } from '../core/snap/ChildrenNode'; export class DataSnapshot { - private constructor() {} - priority: string | number | null; - size: number; - key: string | null; - ref: Reference; + /** + * @param _node A SnapshotNode to wrap. + * @param ref The ref of the location this snapshot came from. + * @param _index The iteration order for this snapshot + */ + constructor( + readonly _node: Node, + readonly ref: Reference, + readonly _index: Index + ) {} + + get priority(): string | number | null { + // typecast here because we never return deferred values or internal priorities (MAX_PRIORITY) + return this._node.getPriority().val() as string | number | null; + } + + get key(): string | null { + return this.ref.key; + } + + get size(): number { + return this._node.numChildren(); + } child(path: string): DataSnapshot { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - return {} as any; + const childPath = new Path(path); + const childRef = child(this.ref, path); + return new DataSnapshot( + this._node.getChild(childPath), + childRef, + PRIORITY_INDEX + ); } exists(): boolean { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - return {} as any; + return !this._node.isEmpty(); } // eslint-disable-next-line @typescript-eslint/no-explicit-any exportVal(): any { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - return {} as any; + return this._node.val(true); } forEach(action: (child: DataSnapshot) => boolean | void): boolean { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - return {} as any; + if (this._node.isLeafNode()) { + return false; + } + + const childrenNode = this._node as ChildrenNode; + // Sanitize the return value to a boolean. ChildrenNode.forEachChild has a weird return type... + return !!childrenNode.forEachChild(this._index, (key, node) => { + return action( + new DataSnapshot(node, child(this.ref, key), PRIORITY_INDEX) + ); + }); } hasChild(path: string): boolean { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - return {} as any; + const childPath = new Path(path); + return !this._node.getChild(childPath).isEmpty(); } hasChildren(): boolean { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - return {} as any; + if (this._node.isLeafNode()) { + return false; + } else { + return !this._node.isEmpty(); + } } toJSON(): object | null { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - return {} as any; + return this.exportVal(); } // eslint-disable-next-line @typescript-eslint/no-explicit-any val(): any { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - return {} as any; + return this._node.val(); } } diff --git a/packages/database/src/exp/Reference.ts b/packages/database/src/exp/Reference.ts index 278e0cce361..88d751b5fb8 100644 --- a/packages/database/src/exp/Reference.ts +++ b/packages/database/src/exp/Reference.ts @@ -16,15 +16,34 @@ */ import { Query } from './Query'; +import { Repo } from '../core/Repo'; +import { + Path, + pathChild, + pathGetBack, + pathIsEmpty, + pathParent +} from '../core/util/Path'; export class Reference extends Query { - private constructor() { + root: Reference; + + constructor(readonly _repo: Repo, readonly _path: Path) { super(); } - key: string | null; - parent: Reference | null; - root: Reference; + get key(): string | null { + if (pathIsEmpty(this._path)) { + return null; + } else { + return pathGetBack(this._path); + } + } + + get parent(): Reference | null { + const parentPath = pathParent(this._path); + return parentPath === null ? null : new Reference(this._repo, parentPath); + } } export interface OnDisconnect { @@ -43,8 +62,8 @@ export interface ThenableReference Pick, 'then' | 'catch'> {} export function child(ref: Reference, path: string): Reference { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - return {} as any; + // TODO: Accept Compat class + return new Reference(ref._repo, pathChild(ref._path, path)); } export function onDisconnect(ref: Reference): OnDisconnect { diff --git a/packages/database/test/datasnapshot.test.ts b/packages/database/test/datasnapshot.test.ts index e19602dbb41..98ffe093bbe 100644 --- a/packages/database/test/datasnapshot.test.ts +++ b/packages/database/test/datasnapshot.test.ts @@ -15,6 +15,8 @@ * limitations under the License. */ +import { DataSnapshot as ExpDataSnapshot } from '../src/exp/DataSnapshot'; +import { Reference as ExpReference } from '../src/exp/Reference'; import { expect } from 'chai'; import { nodeFromJSON } from '../src/core/snap/nodeFromJSON'; import { PRIORITY_INDEX } from '../src/core/snap/indexes/PriorityIndex'; @@ -26,7 +28,13 @@ describe('DataSnapshot Tests', () => { /** @return {!DataSnapshot} */ const snapshotForJSON = function (json) { const dummyRef = getRandomNode() as Reference; - return new DataSnapshot(nodeFromJSON(json), dummyRef, PRIORITY_INDEX); + return new DataSnapshot( + new ExpDataSnapshot( + nodeFromJSON(json), + new ExpReference(dummyRef.repo, dummyRef.path), + PRIORITY_INDEX + ) + ); }; it('DataSnapshot.hasChildren() works.', () => {