Skip to content

Commit

Permalink
Compat class for DocumentReference (#4043)
Browse files Browse the repository at this point in the history
  • Loading branch information
schmidt-sebastian committed Nov 9, 2020
1 parent 6be9225 commit 484e90a
Show file tree
Hide file tree
Showing 13 changed files with 266 additions and 424 deletions.
5 changes: 5 additions & 0 deletions .changeset/short-mangos-beg.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@firebase/firestore": patch
---

Internal changes to support upcoming modular API.
10 changes: 8 additions & 2 deletions packages/firestore/exp/src/api/reference.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@

import { FirebaseFirestore } from './database';
import {
_DocumentKeyReference,
ParsedUpdateData,
parseSetData,
parseUpdateData,
Expand Down Expand Up @@ -80,6 +79,7 @@ import {
removeSnapshotsInSyncListener
} from '../../../src/core/event_manager';
import { FirestoreError } from '../../../src/util/error';
import { Compat } from '../../../src/compat/compat';

/**
* An options object that can be passed to {@link onSnapshot()} and {@link
Expand Down Expand Up @@ -374,6 +374,12 @@ export function updateDoc(

const dataReader = newUserDataReader(firestore);

// For Compat types, we have to "extract" the underlying types before
// performing validation.
if (fieldOrUpdateData instanceof Compat) {
fieldOrUpdateData = fieldOrUpdateData._delegate;
}

let parsed: ParsedUpdateData;
if (
typeof fieldOrUpdateData === 'string' ||
Expand Down Expand Up @@ -821,7 +827,7 @@ export function executeWrite(
*/
function convertToDocSnapshot<T>(
firestore: FirebaseFirestore,
ref: _DocumentKeyReference<T>,
ref: DocumentReference<T>,
snapshot: ViewSnapshot
): DocumentSnapshot<T> {
debugAssert(
Expand Down
9 changes: 2 additions & 7 deletions packages/firestore/exp/src/api/snapshot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -238,11 +238,7 @@ export class DocumentSnapshot<T = DocumentData> extends LiteDocumentSnapshot<
this._firestoreImpl._databaseId,
options?.serverTimestamps || DEFAULT_SERVER_TIMESTAMP_BEHAVIOR,
key =>
new DocumentReference(
this._firestore,
/* converter= */ null,
key.path
),
new DocumentReference(this._firestore, /* converter= */ null, key),
bytes => new Bytes(bytes)
);
return userDataWriter.convertValue(this._document.toProto()) as T;
Expand Down Expand Up @@ -276,8 +272,7 @@ export class DocumentSnapshot<T = DocumentData> extends LiteDocumentSnapshot<
const userDataWriter = new UserDataWriter(
this._firestoreImpl._databaseId,
options.serverTimestamps || DEFAULT_SERVER_TIMESTAMP_BEHAVIOR,
key =>
new DocumentReference(this._firestore, this._converter, key.path),
key => new DocumentReference(this._firestore, this._converter, key),
bytes => new Bytes(bytes)
);
return userDataWriter.convertValue(value);
Expand Down
197 changes: 6 additions & 191 deletions packages/firestore/exp/test/shim.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,16 @@ import * as exp from '../index';

import {
addDoc,
collection,
deleteDoc,
doc,
DocumentReference as DocumentReferenceExp,
FieldPath as FieldPathExp,
getDoc,
getDocFromCache,
getDocFromServer,
getDocs,
getDocsFromCache,
getDocsFromServer,
onSnapshot,
query,
queryEqual,
refEqual,
setDoc,
snapshotEqual,
updateDoc,
endAt,
endBefore,
startAfter,
Expand All @@ -49,13 +41,17 @@ import {
Bytes as BytesExp
} from '../../exp/index';
import { UntypedFirestoreDataConverter } from '../../src/api/user_data_reader';
import { isPartialObserver, PartialObserver } from '../../src/api/observer';
import {
isPlainObject,
validateSetOptions
} from '../../src/util/input_validation';
import { Compat } from '../../src/compat/compat';
import { Firestore } from '../../src/api/database';
import {
Firestore,
DocumentReference,
wrapObserver,
extractSnapshotOptions
} from '../../src/api/database';

export { GeoPoint, Timestamp } from '../index';

Expand Down Expand Up @@ -188,129 +184,6 @@ export class WriteBatch
}
}

export class DocumentReference<T = legacy.DocumentData>
extends Compat<exp.DocumentReference<T>>
implements legacy.DocumentReference<T> {
constructor(
readonly firestore: Firestore,
delegate: exp.DocumentReference<T>
) {
super(delegate);
}

readonly id = this._delegate.id;
readonly path = this._delegate.path;

get parent(): legacy.CollectionReference<T> {
return new CollectionReference<T>(this.firestore, this._delegate.parent);
}

collection(
collectionPath: string
): legacy.CollectionReference<legacy.DocumentData> {
return new CollectionReference(
this.firestore,
collection(this._delegate, collectionPath)
);
}

isEqual(other: DocumentReference<T>): boolean {
return refEqual(this._delegate, other._delegate);
}

set(data: Partial<T>, options?: legacy.SetOptions): Promise<void> {
if (options) {
validateSetOptions('DocumentReference.set', options);
return setDoc(this._delegate, unwrap(data), options);
} else {
return setDoc(this._delegate, unwrap(data));
}
}

update(data: legacy.UpdateData): Promise<void>;
update(
field: string | FieldPath,
value: any,
...moreFieldsAndValues: any[]
): Promise<void>;
update(
dataOrField: any,
value?: any,
...moreFieldsAndValues: any[]
): Promise<void> {
if (arguments.length === 1) {
return updateDoc(this._delegate, unwrap(dataOrField));
} else {
return updateDoc(
this._delegate,
unwrap(dataOrField),
unwrap(value),
...unwrap(moreFieldsAndValues)
);
}
}

delete(): Promise<void> {
return deleteDoc(this._delegate);
}

get(options?: legacy.GetOptions): Promise<DocumentSnapshot<T>> {
let snap: Promise<exp.DocumentSnapshot<T>>;
if (options?.source === 'cache') {
snap = getDocFromCache(this._delegate);
} else if (options?.source === 'server') {
snap = getDocFromServer(this._delegate);
} else {
snap = getDoc(this._delegate);
}
return snap.then(result => new DocumentSnapshot(this.firestore, result));
}

onSnapshot(observer: {
next?: (snapshot: DocumentSnapshot<T>) => void;
error?: (error: legacy.FirestoreError) => void;
complete?: () => void;
}): () => void;
onSnapshot(
options: legacy.SnapshotListenOptions,
observer: {
next?: (snapshot: DocumentSnapshot<T>) => void;
error?: (error: legacy.FirestoreError) => void;
complete?: () => void;
}
): () => void;
onSnapshot(
onNext: (snapshot: DocumentSnapshot<T>) => void,
onError?: (error: legacy.FirestoreError) => void,
onCompletion?: () => void
): () => void;
onSnapshot(
options: legacy.SnapshotListenOptions,
onNext: (snapshot: DocumentSnapshot<T>) => void,
onError?: (error: legacy.FirestoreError) => void,
onCompletion?: () => void
): () => void;
onSnapshot(...args: any): () => void {
const options = extractSnapshotOptions(args);
const observer = wrapObserver<DocumentSnapshot<T>, exp.DocumentSnapshot<T>>(
args,
snap => new DocumentSnapshot(this.firestore, snap)
);
return onSnapshot(this._delegate, options, observer);
}

withConverter<U>(
converter: legacy.FirestoreDataConverter<U>
): DocumentReference<U> {
return new DocumentReference<U>(
this.firestore,
this._delegate.withConverter(
converter as UntypedFirestoreDataConverter<U>
)
);
}
}

export class DocumentSnapshot<T = legacy.DocumentData>
extends Compat<exp.DocumentSnapshot<T>>
implements legacy.DocumentSnapshot<T> {
Expand Down Expand Up @@ -634,8 +507,6 @@ function wrap(firestore: Firestore, value: any): any {
return new FieldPath(...value._internalPath.toArray());
} else if (value instanceof BytesExp) {
return new Blob(value);
} else if (value instanceof DocumentReferenceExp) {
return new DocumentReference(firestore, value);
} else if (isPlainObject(value)) {
const obj: any = {};
for (const key in value) {
Expand Down Expand Up @@ -672,59 +543,3 @@ function unwrap(value: any): any {
return value;
}
}

/**
* Creates an observer that can be passed to the firestore-exp SDK. The
* observer converts all observed values into the format expected by the shim.
*
* @param args The list of arguments from an `onSnapshot` call.
* @param wrapper The function that converts the firestore-exp type into the
* type used by this shim.
*/
function wrapObserver<ShimType, ExpType>(
args: any,
wrapper: (val: ExpType) => ShimType
): PartialObserver<ExpType> {
let userObserver: PartialObserver<ShimType>;
if (isPartialObserver(args[0])) {
userObserver = args[0] as PartialObserver<ShimType>;
} else if (isPartialObserver(args[1])) {
userObserver = args[1];
} else if (typeof args[0] === 'function') {
userObserver = {
next: args[0],
error: args[1],
complete: args[2]
};
} else {
userObserver = {
next: args[1],
error: args[2],
complete: args[3]
};
}

return {
next: val => {
if (userObserver!.next) {
userObserver!.next(wrapper(val));
}
},
error: userObserver.error?.bind(userObserver),
complete: userObserver.complete?.bind(userObserver)
};
}

/**
* Iterates the list of arguments from an `onSnapshot` call and returns the
* first argument that may be an `SnapshotListenOptions` object. Returns an
* empty object if none is found.
*/
function extractSnapshotOptions(args: any): exp.SnapshotListenOptions {
for (const arg of args) {
if (typeof arg === 'object' && !isPartialObserver(arg)) {
return arg as exp.SnapshotListenOptions;
}
}
return {};
}

0 comments on commit 484e90a

Please sign in to comment.