Skip to content

Commit 1915705

Browse files
Compat and @exp class for DataSnapshot
1 parent 13686cb commit 1915705

File tree

17 files changed

+842
-209
lines changed

17 files changed

+842
-209
lines changed

common/api-review/firestore-exp.api.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ export class CollectionReference<T = DocumentData> extends Query<T> {
5353
get path(): string;
5454
// (undocumented)
5555
readonly type = "collection";
56+
withConverter(converter: null): CollectionReference<DocumentData>;
57+
// (undocumented)
5658
withConverter<U>(converter: FirestoreDataConverter<U>): CollectionReference<U>;
5759
}
5860

@@ -101,6 +103,8 @@ export class DocumentReference<T = DocumentData> {
101103
get parent(): CollectionReference<T>;
102104
get path(): string;
103105
readonly type = "document";
106+
withConverter(converter: null): DocumentReference<DocumentData>;
107+
// (undocumented)
104108
withConverter<U>(converter: FirestoreDataConverter<U>): DocumentReference<U>;
105109
}
106110

@@ -318,6 +322,8 @@ export class Query<T = DocumentData> {
318322
protected constructor();
319323
readonly firestore: FirebaseFirestore;
320324
readonly type: 'query' | 'collection';
325+
withConverter(converter: null): Query<DocumentData>;
326+
// (undocumented)
321327
withConverter<U>(converter: FirestoreDataConverter<U>): Query<U>;
322328
}
323329

common/api-review/firestore-lite.api.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ export class CollectionReference<T = DocumentData> extends Query<T> {
4747
get path(): string;
4848
// (undocumented)
4949
readonly type = "collection";
50+
withConverter(converter: null): CollectionReference<DocumentData>;
51+
// (undocumented)
5052
withConverter<U>(converter: FirestoreDataConverter<U>): CollectionReference<U>;
5153
}
5254

@@ -81,6 +83,8 @@ export class DocumentReference<T = DocumentData> {
8183
get parent(): CollectionReference<T>;
8284
get path(): string;
8385
readonly type = "document";
86+
withConverter(converter: null): DocumentReference<DocumentData>;
87+
// (undocumented)
8488
withConverter<U>(converter: FirestoreDataConverter<U>): DocumentReference<U>;
8589
}
8690

@@ -195,6 +199,8 @@ export class Query<T = DocumentData> {
195199
protected constructor();
196200
readonly firestore: FirebaseFirestore;
197201
readonly type: 'query' | 'collection';
202+
withConverter(converter: null): Query<DocumentData>;
203+
// (undocumented)
198204
withConverter<U>(converter: FirestoreDataConverter<U>): Query<U>;
199205
}
200206

packages/database/exp/index.ts

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,48 @@ import { Component, ComponentType } from '@firebase/component';
2222
import { version } from '../package.json';
2323
import { FirebaseDatabase } from '../src/exp/Database';
2424

25-
export { getDatabase, ServerValue } from '../src/exp/Database';
26-
export { enableLogging } from '../src/core/util/util';
25+
export {
26+
enableLogging,
27+
getDatabase,
28+
goOffline,
29+
goOnline,
30+
ref,
31+
refFromURL,
32+
useDatabaseEmulator
33+
} from '../src/exp/Database';
34+
export {
35+
OnDisconnect,
36+
Reference,
37+
ThenableReference
38+
} from '../src/exp/Reference';
39+
export { DataSnapshot } from '../src/exp/DataSnapshot';
40+
export {
41+
ListenOptions,
42+
Query,
43+
QueryConstraint,
44+
Unsubscribe,
45+
endAt,
46+
endBefore,
47+
equalTo,
48+
get,
49+
limitToFirst,
50+
limitToLast,
51+
off,
52+
onChildAdded,
53+
onChildChanged,
54+
onChildMoved,
55+
onChildRemoved,
56+
onValue,
57+
orderByChild,
58+
orderByKey,
59+
orderByPriority,
60+
orderByValue,
61+
query,
62+
startAfter,
63+
startAt
64+
} from '../src/exp/Query';
65+
export { increment, serverTimestamp } from '../src/exp/ServerValue';
66+
export { runTransaction, TransactionOptions } from '../src/exp/Transaction';
2767

2868
declare module '@firebase/component' {
2969
interface NameServiceMapping {

packages/database/src/api/DataSnapshot.ts

Lines changed: 22 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -17,28 +17,19 @@
1717

1818
import { validateArgCount, validateCallback } from '@firebase/util';
1919
import { validatePathString } from '../core/util/validation';
20-
import { Path } from '../core/util/Path';
21-
import { PRIORITY_INDEX } from '../core/snap/indexes/PriorityIndex';
22-
import { Node } from '../core/snap/Node';
2320
import { Reference } from './Reference';
24-
import { Index } from '../core/snap/indexes/Index';
25-
import { ChildrenNode } from '../core/snap/ChildrenNode';
21+
import { DataSnapshot as ExpDataSnapshot } from '../exp/DataSnapshot';
2622

23+
// TODO(databaseexp): Import Compat from @firebase/util
24+
export interface Compat<T> {
25+
readonly _delegate: T;
26+
}
2727
/**
2828
* Class representing a firebase data snapshot. It wraps a SnapshotNode and
2929
* surfaces the public methods (val, forEach, etc.) we want to expose.
3030
*/
31-
export class DataSnapshot {
32-
/**
33-
* @param node_ A SnapshotNode to wrap.
34-
* @param ref_ The ref of the location this snapshot came from.
35-
* @param index_ The iteration order for this snapshot
36-
*/
37-
constructor(
38-
private readonly node_: Node,
39-
private readonly ref_: Reference,
40-
private readonly index_: Index
41-
) {}
31+
export class DataSnapshot implements Compat<ExpDataSnapshot> {
32+
constructor(readonly _delegate: ExpDataSnapshot) {}
4233

4334
/**
4435
* Retrieves the snapshot contents as JSON. Returns null if the snapshot is
@@ -48,7 +39,7 @@ export class DataSnapshot {
4839
*/
4940
val(): unknown {
5041
validateArgCount('DataSnapshot.val', 0, 0, arguments.length);
51-
return this.node_.val();
42+
return this._delegate.val();
5243
}
5344

5445
/**
@@ -58,15 +49,15 @@ export class DataSnapshot {
5849
*/
5950
exportVal(): unknown {
6051
validateArgCount('DataSnapshot.exportVal', 0, 0, arguments.length);
61-
return this.node_.val(true);
52+
return this._delegate.exportVal();
6253
}
6354

6455
// Do not create public documentation. This is intended to make JSON serialization work but is otherwise unnecessary
6556
// for end-users
6657
toJSON(): unknown {
6758
// Optional spacer argument is unnecessary because we're depending on recursion rather than stringifying the content
6859
validateArgCount('DataSnapshot.toJSON', 0, 1, arguments.length);
69-
return this.exportVal();
60+
return this._delegate.toJSON();
7061
}
7162

7263
/**
@@ -76,7 +67,7 @@ export class DataSnapshot {
7667
*/
7768
exists(): boolean {
7869
validateArgCount('DataSnapshot.exists', 0, 0, arguments.length);
79-
return !this.node_.isEmpty();
70+
return this._delegate.exists();
8071
}
8172

8273
/**
@@ -90,14 +81,7 @@ export class DataSnapshot {
9081
// Ensure the childPath is a string (can be a number)
9182
childPathString = String(childPathString);
9283
validatePathString('DataSnapshot.child', 1, childPathString, false);
93-
94-
const childPath = new Path(childPathString);
95-
const childRef = this.ref_.child(childPath);
96-
return new DataSnapshot(
97-
this.node_.getChild(childPath),
98-
childRef,
99-
PRIORITY_INDEX
100-
);
84+
return new DataSnapshot(this._delegate.child(childPathString));
10185
}
10286

10387
/**
@@ -109,9 +93,7 @@ export class DataSnapshot {
10993
hasChild(childPathString: string): boolean {
11094
validateArgCount('DataSnapshot.hasChild', 1, 1, arguments.length);
11195
validatePathString('DataSnapshot.hasChild', 1, childPathString, false);
112-
113-
const childPath = new Path(childPathString);
114-
return !this.node_.getChild(childPath).isEmpty();
96+
return this._delegate.hasChild(childPathString);
11597
}
11698

11799
/**
@@ -121,9 +103,7 @@ export class DataSnapshot {
121103
*/
122104
getPriority(): string | number | null {
123105
validateArgCount('DataSnapshot.getPriority', 0, 0, arguments.length);
124-
125-
// typecast here because we never return deferred values or internal priorities (MAX_PRIORITY)
126-
return this.node_.getPriority().val() as string | number | null;
106+
return this._delegate.priority;
127107
}
128108

129109
/**
@@ -134,21 +114,12 @@ export class DataSnapshot {
134114
* @return True if forEach was canceled by action returning true for
135115
* one of the child nodes.
136116
*/
137-
forEach(action: (d: DataSnapshot) => boolean | void): boolean {
117+
forEach(action: (snapshot: DataSnapshot) => boolean | void): boolean {
138118
validateArgCount('DataSnapshot.forEach', 1, 1, arguments.length);
139119
validateCallback('DataSnapshot.forEach', 1, action, false);
140-
141-
if (this.node_.isLeafNode()) {
142-
return false;
143-
}
144-
145-
const childrenNode = this.node_ as ChildrenNode;
146-
// Sanitize the return value to a boolean. ChildrenNode.forEachChild has a weird return type...
147-
return !!childrenNode.forEachChild(this.index_, (key, node) => {
148-
return action(
149-
new DataSnapshot(node, this.ref_.child(key), PRIORITY_INDEX)
150-
);
151-
});
120+
return this._delegate.forEach(expDataSnapshot =>
121+
action(new DataSnapshot(expDataSnapshot))
122+
);
152123
}
153124

154125
/**
@@ -157,16 +128,11 @@ export class DataSnapshot {
157128
*/
158129
hasChildren(): boolean {
159130
validateArgCount('DataSnapshot.hasChildren', 0, 0, arguments.length);
160-
161-
if (this.node_.isLeafNode()) {
162-
return false;
163-
} else {
164-
return !this.node_.isEmpty();
165-
}
131+
return this._delegate.hasChildren();
166132
}
167133

168134
get key() {
169-
return this.ref_.getKey();
135+
return this._delegate.key;
170136
}
171137

172138
/**
@@ -175,8 +141,7 @@ export class DataSnapshot {
175141
*/
176142
numChildren(): number {
177143
validateArgCount('DataSnapshot.numChildren', 0, 0, arguments.length);
178-
179-
return this.node_.numChildren();
144+
return this._delegate.size;
180145
}
181146

182147
/**
@@ -185,8 +150,7 @@ export class DataSnapshot {
185150
*/
186151
getRef(): Reference {
187152
validateArgCount('DataSnapshot.ref', 0, 0, arguments.length);
188-
189-
return this.ref_;
153+
return new Reference(this._delegate.ref._repo, this._delegate.ref._path);
190154
}
191155

192156
get ref() {

packages/database/src/api/Query.ts

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
* limitations under the License.
1616
*/
1717

18+
import { DataSnapshot as ExpDataSnapshot } from '../exp/DataSnapshot';
19+
import { Reference as ExpReference } from '../exp/Reference';
1820
import {
1921
assert,
2022
Deferred,
@@ -45,6 +47,7 @@ import {
4547
import {
4648
ChildEventRegistration,
4749
EventRegistration,
50+
ExpSnapshotCallback,
4851
ValueEventRegistration
4952
} from '../core/view/EventRegistration';
5053

@@ -71,7 +74,7 @@ import { DataSnapshot } from './DataSnapshot';
7174
let __referenceConstructor: new (repo: Repo, path: Path) => Query;
7275

7376
export interface SnapshotCallback {
74-
(a: DataSnapshot, b?: string | null): unknown;
77+
(dataSnapshot: DataSnapshot, previousChildName?: string | null): unknown;
7578
}
7679

7780
/**
@@ -215,19 +218,19 @@ export class Query {
215218
cancelCallbackOrContext,
216219
context
217220
);
218-
221+
const expCallback = new ExpSnapshotCallback(callback);
219222
if (eventType === 'value') {
220-
this.onValueEvent(callback, ret.cancel, ret.context);
223+
this.onValueEvent(expCallback, ret.cancel, ret.context);
221224
} else {
222-
const callbacks: { [k: string]: typeof callback } = {};
223-
callbacks[eventType] = callback;
225+
const callbacks: { [k: string]: ExpSnapshotCallback } = {};
226+
callbacks[eventType] = expCallback;
224227
this.onChildEvent(callbacks, ret.cancel, ret.context);
225228
}
226229
return callback;
227230
}
228231

229232
protected onValueEvent(
230-
callback: (a: DataSnapshot) => void,
233+
callback: ExpSnapshotCallback,
231234
cancelCallback: ((a: Error) => void) | null,
232235
context: object | null
233236
) {
@@ -239,8 +242,8 @@ export class Query {
239242
repoAddEventCallbackForQuery(this.repo, this, container);
240243
}
241244

242-
onChildEvent(
243-
callbacks: { [k: string]: SnapshotCallback },
245+
protected onChildEvent(
246+
callbacks: { [k: string]: ExpSnapshotCallback },
244247
cancelCallback: ((a: Error) => unknown) | null,
245248
context: object | null
246249
) {
@@ -261,20 +264,20 @@ export class Query {
261264
validateEventType('Query.off', 1, eventType, true);
262265
validateCallback('Query.off', 2, callback, true);
263266
validateContextObject('Query.off', 3, context, true);
264-
265267
let container: EventRegistration | null = null;
266-
let callbacks: { [k: string]: typeof callback } | null = null;
268+
let callbacks: { [k: string]: ExpSnapshotCallback } | null = null;
269+
270+
const expCallback = callback ? new ExpSnapshotCallback(callback) : null;
267271
if (eventType === 'value') {
268-
const valueCallback = callback || null;
269272
container = new ValueEventRegistration(
270-
valueCallback,
273+
expCallback,
271274
null,
272275
context || null
273276
);
274277
} else if (eventType) {
275278
if (callback) {
276279
callbacks = {};
277-
callbacks[eventType] = callback;
280+
callbacks[eventType] = expCallback;
278281
}
279282
container = new ChildEventRegistration(callbacks, null, context || null);
280283
}
@@ -285,7 +288,15 @@ export class Query {
285288
* Get the server-value for this query, or return a cached value if not connected.
286289
*/
287290
get(): Promise<DataSnapshot> {
288-
return repoGetValue(this.repo, this);
291+
return repoGetValue(this.repo, this).then(node => {
292+
return new DataSnapshot(
293+
new ExpDataSnapshot(
294+
node,
295+
new ExpReference(this.getRef().repo, this.getRef().path),
296+
this.getQueryParams().getIndex()
297+
)
298+
);
299+
});
289300
}
290301

291302
/**

0 commit comments

Comments
 (0)