Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compat class for DocumentReference #4043

Merged
merged 9 commits into from
Nov 9, 2020
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.
5 changes: 4 additions & 1 deletion packages-exp/auth-exp/index.webworker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ registerAuth(ClientPlatform.WORKER);
export function getAuth(app = getApp()): Auth {
// Unlike the other environments, we need to explicitly check if indexedDb is
// available. That means doing the whole rigamarole
const auth = _getProvider(app, _ComponentName.AUTH).getImmediate() as AuthImpl;
const auth = _getProvider(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these changes to auth and database intended?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No - they keep showing up though due to the Presubmit hook. I will revert them before merging.

app,
_ComponentName.AUTH
).getImmediate() as AuthImpl;

// This promise is intended to float; auth initialization happens in the
// background, meanwhile the auth object may be used by the app.
Expand Down
7 changes: 5 additions & 2 deletions packages/database/src/api/Database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,14 +157,17 @@ export class Database implements FirebaseService {
validateUrl(apiName, 1, parsedURL);

const repoInfo = parsedURL.repoInfo;
if (!repoInfo.isCustomHost() && repoInfo.host !== this.repo_.repoInfo_.host) {
if (
!repoInfo.isCustomHost() &&
repoInfo.host !== this.repo_.repoInfo_.host
) {
fatal(
apiName +
': Host name does not match the current database: ' +
'(found ' +
repoInfo.host +
' but expected ' +
this.repo_.repoInfo_.host+
this.repo_.repoInfo_.host +
')'
);
}
Expand Down
13 changes: 10 additions & 3 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,8 @@ import {
removeSnapshotsInSyncListener
} from '../../../src/core/event_manager';
import { FirestoreError } from '../../../src/util/error';
import { Compat } from '../../../src/compat/compat';
import { _BaseFieldPath } from '../../../src/api/field_path';

/**
* An options object that can be passed to {@link onSnapshot()} and {@link
Expand Down Expand Up @@ -374,10 +375,16 @@ 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' ||
fieldOrUpdateData instanceof FieldPath
fieldOrUpdateData instanceof _BaseFieldPath
) {
parsed = parseUpdateVarargs(
dataReader,
Expand Down Expand Up @@ -821,7 +828,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 {};
}
Loading