Skip to content

Commit

Permalink
Make FieldPath a Compat class
Browse files Browse the repository at this point in the history
  • Loading branch information
schmidt-sebastian committed Sep 21, 2020
1 parent 4c4b2d1 commit a5fb4d7
Show file tree
Hide file tree
Showing 7 changed files with 152 additions and 159 deletions.
104 changes: 36 additions & 68 deletions packages/firestore/exp/test/shim.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,10 @@ import * as exp from '../index';

import {
addDoc,
arrayRemove,
arrayUnion,
clearIndexedDbPersistence,
collection,
collectionGroup,
deleteDoc,
deleteField,
disableNetwork,
doc,
DocumentReference as DocumentReferenceExp,
Expand All @@ -43,15 +40,13 @@ import {
getDocs,
getDocsFromCache,
getDocsFromServer,
increment,
initializeFirestore,
onSnapshot,
onSnapshotsInSync,
query,
queryEqual,
refEqual,
runTransaction,
serverTimestamp,
setDoc,
snapshotEqual,
terminate,
Expand All @@ -71,18 +66,20 @@ import {
import { UntypedFirestoreDataConverter } from '../../src/api/user_data_reader';
import { isPartialObserver, PartialObserver } from '../../src/api/observer';
import { isPlainObject } from '../../src/util/input_validation';
import { Compat } from '../../src/compat/compat';

export { GeoPoint, Timestamp } from '../index';
export { FieldValue } from '../../src/compat/field_value';

/* eslint-disable @typescript-eslint/no-explicit-any */

// This module defines a shim layer that implements the legacy API on top
// of the experimental SDK. This shim is used to run integration tests against
// both SDK versions.

export class FirebaseApp implements FirebaseAppLegacy {
constructor(readonly _delegate: FirebaseAppExp) {}

export class FirebaseApp
extends Compat<FirebaseAppExp>
implements FirebaseAppLegacy {
name = this._delegate.name;
options = this._delegate.options;
automaticDataCollectionEnabled = this._delegate
Expand All @@ -93,9 +90,9 @@ export class FirebaseApp implements FirebaseAppLegacy {
}
}

export class FirebaseFirestore implements legacy.FirebaseFirestore {
constructor(private readonly _delegate: exp.FirebaseFirestore) {}

export class FirebaseFirestore
extends Compat<exp.FirebaseFirestore>
implements legacy.FirebaseFirestore {
app = new FirebaseApp(this._delegate.app);

settings(settings: legacy.Settings): void {
Expand Down Expand Up @@ -170,11 +167,15 @@ export class FirebaseFirestore implements legacy.FirebaseFirestore {
};
}

export class Transaction implements legacy.Transaction {
export class Transaction
extends Compat<exp.Transaction>
implements legacy.Transaction {
constructor(
private readonly _firestore: FirebaseFirestore,
private readonly _delegate: exp.Transaction
) {}
private readonly delegate: exp.Transaction
) {
super(delegate);
}

get<T>(documentRef: DocumentReference<T>): Promise<DocumentSnapshot<T>> {
return this._delegate
Expand Down Expand Up @@ -231,9 +232,9 @@ export class Transaction implements legacy.Transaction {
}
}

export class WriteBatch implements legacy.WriteBatch {
constructor(private readonly _delegate: exp.WriteBatch) {}

export class WriteBatch
extends Compat<exp.WriteBatch>
implements legacy.WriteBatch {
set<T>(
documentRef: DocumentReference<T>,
data: T,
Expand Down Expand Up @@ -288,11 +289,14 @@ export class WriteBatch implements legacy.WriteBatch {
}

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

readonly id = this._delegate.id;
readonly path = this._delegate.path;
Expand Down Expand Up @@ -407,11 +411,14 @@ export class DocumentReference<T = legacy.DocumentData>
}

export class DocumentSnapshot<T = legacy.DocumentData>
extends Compat<exp.DocumentSnapshot<T>>
implements legacy.DocumentSnapshot<T> {
constructor(
private readonly _firestore: FirebaseFirestore,
readonly _delegate: exp.DocumentSnapshot<T>
) {}
delegate: exp.DocumentSnapshot<T>
) {
super(delegate);
}

readonly ref = new DocumentReference<T>(this._firestore, this._delegate.ref);
readonly id = this._delegate.id;
Expand Down Expand Up @@ -449,11 +456,12 @@ export class QueryDocumentSnapshot<T = legacy.DocumentData>
}
}

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

where(
fieldPath: string | FieldPath,
Expand Down Expand Up @@ -680,34 +688,6 @@ export class CollectionReference<T = legacy.DocumentData>
}
}

export class FieldValue implements legacy.FieldValue {
constructor(readonly _delegate: exp.FieldValue) {}

static serverTimestamp(): FieldValue {
return new FieldValue(serverTimestamp());
}

static delete(): FieldValue {
return new FieldValue(deleteField());
}

static arrayUnion(...elements: any[]): FieldValue {
return new FieldValue(arrayUnion(...unwrap(elements)));
}

static arrayRemove(...elements: any[]): FieldValue {
return new FieldValue(arrayRemove(...unwrap(elements)));
}

static increment(n: number): FieldValue {
return new FieldValue(increment(n));
}

isEqual(other: FieldValue): boolean {
return this._delegate.isEqual(other._delegate);
}
}

export class FieldPath implements legacy.FieldPath {
private readonly fieldNames: string[];

Expand All @@ -728,9 +708,7 @@ export class FieldPath implements legacy.FieldPath {
}
}

export class Blob implements legacy.Blob {
constructor(readonly _delegate: BytesExp) {}

export class Blob extends Compat<BytesExp> implements legacy.Blob {
static fromBase64String(base64: string): Blob {
return new Blob(BytesExp.fromBase64String(base64));
}
Expand Down Expand Up @@ -790,17 +768,7 @@ function wrap(value: any): any {
function unwrap(value: any): any {
if (Array.isArray(value)) {
return value.map(v => unwrap(v));
} else if (value instanceof FieldPath) {
return value._delegate;
} else if (value instanceof FieldValue) {
return value._delegate;
} else if (value instanceof Blob) {
return value._delegate;
} else if (value instanceof DocumentReference) {
return value._delegate;
} else if (value instanceof DocumentSnapshot) {
return value._delegate;
} else if (value instanceof QueryDocumentSnapshot) {
} else if (value instanceof Compat) {
return value._delegate;
} else if (isPlainObject(value)) {
const obj: any = {};
Expand Down
95 changes: 5 additions & 90 deletions packages/firestore/src/api/field_value.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,6 @@
* limitations under the License.
*/

import { FieldValue as PublicFieldValue } from '@firebase/firestore-types';
import {
validateArgType,
validateAtLeastNumberOfArgs,
validateExactNumberOfArgs,
validateNoArgs
} from '../util/input_validation';
import { FieldTransform } from '../model/mutation';
import {
ArrayRemoveTransformOperation,
Expand Down Expand Up @@ -81,7 +74,7 @@ export class DeleteFieldValueImpl extends _SerializableFieldValue {
return null;
}

isEqual(other: FieldValue): boolean {
isEqual(other: DeleteFieldValueImpl): boolean {
return other instanceof DeleteFieldValueImpl;
}
}
Expand Down Expand Up @@ -129,7 +122,7 @@ export class ServerTimestampFieldValueImpl extends _SerializableFieldValue {
return new FieldTransform(context.path!, new ServerTimestampTransform());
}

isEqual(other: FieldValue): boolean {
isEqual(other: ServerTimestampFieldValueImpl): boolean {
return other instanceof ServerTimestampFieldValueImpl;
}
}
Expand All @@ -155,7 +148,7 @@ export class ArrayUnionFieldValueImpl extends _SerializableFieldValue {
return new FieldTransform(context.path!, arrayUnion);
}

isEqual(other: FieldValue): boolean {
isEqual(other: ArrayUnionFieldValueImpl): boolean {
// TODO(mrschmidt): Implement isEquals
return this === other;
}
Expand All @@ -179,7 +172,7 @@ export class ArrayRemoveFieldValueImpl extends _SerializableFieldValue {
return new FieldTransform(context.path!, arrayUnion);
}

isEqual(other: FieldValue): boolean {
isEqual(other: ArrayRemoveFieldValueImpl): boolean {
// TODO(mrschmidt): Implement isEquals
return this === other;
}
Expand All @@ -198,86 +191,8 @@ export class NumericIncrementFieldValueImpl extends _SerializableFieldValue {
return new FieldTransform(context.path!, numericIncrement);
}

isEqual(other: FieldValue): boolean {
isEqual(other: NumericIncrementFieldValueImpl): boolean {
// TODO(mrschmidt): Implement isEquals
return this === other;
}
}

/** The public FieldValue class of the lite API. */
export abstract class FieldValue
extends _SerializableFieldValue
implements PublicFieldValue {
protected constructor() {
super();
}

static delete(): PublicFieldValue {
validateNoArgs('FieldValue.delete', arguments);
return new FieldValueDelegate(
new DeleteFieldValueImpl('FieldValue.delete')
);
}

static serverTimestamp(): PublicFieldValue {
validateNoArgs('FieldValue.serverTimestamp', arguments);
return new FieldValueDelegate(
new ServerTimestampFieldValueImpl('FieldValue.serverTimestamp')
);
}

static arrayUnion(...elements: unknown[]): PublicFieldValue {
validateAtLeastNumberOfArgs('FieldValue.arrayUnion', arguments, 1);
// NOTE: We don't actually parse the data until it's used in set() or
// update() since we'd need the Firestore instance to do this.
return new FieldValueDelegate(
new ArrayUnionFieldValueImpl('FieldValue.arrayUnion', elements)
);
}

static arrayRemove(...elements: unknown[]): PublicFieldValue {
validateAtLeastNumberOfArgs('FieldValue.arrayRemove', arguments, 1);
// NOTE: We don't actually parse the data until it's used in set() or
// update() since we'd need the Firestore instance to do this.
return new FieldValueDelegate(
new ArrayRemoveFieldValueImpl('FieldValue.arrayRemove', elements)
);
}

static increment(n: number): PublicFieldValue {
validateArgType('FieldValue.increment', 'number', 1, n);
validateExactNumberOfArgs('FieldValue.increment', arguments, 1);
return new FieldValueDelegate(
new NumericIncrementFieldValueImpl('FieldValue.increment', n)
);
}
}

/**
* A delegate class that allows the FieldValue implementations returned by
* deleteField(), serverTimestamp(), arrayUnion(), arrayRemove() and
* increment() to be an instance of the legacy FieldValue class declared above.
*
* We don't directly subclass `FieldValue` in the various field value
* implementations as the base FieldValue class differs between the lite, full
* and legacy SDK.
*/
class FieldValueDelegate extends FieldValue implements PublicFieldValue {
readonly _methodName: string;

constructor(readonly _delegate: _SerializableFieldValue) {
super();
this._methodName = _delegate._methodName;
}

_toFieldTransform(context: ParseContext): FieldTransform | null {
return this._delegate._toFieldTransform(context);
}

isEqual(other: PublicFieldValue): boolean {
if (!(other instanceof FieldValueDelegate)) {
return false;
}
return this._delegate.isEqual(other._delegate);
}
}
7 changes: 7 additions & 0 deletions packages/firestore/src/api/user_data_reader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import { DeleteFieldValueImpl, _SerializableFieldValue } from './field_value';
import { GeoPoint } from './geo_point';
import { newSerializer } from '../platform/serializer';
import { Bytes } from '../../lite/src/api/bytes';
import { Compat } from '../compat/compat';

const RESERVED_FIELD_REGEX = /^__.*__$/;

Expand Down Expand Up @@ -566,6 +567,12 @@ export function parseData(
input: unknown,
context: ParseContext
): ProtoValue | null {
// Unwrap the API type from the Compat SDK. This will return the API type
// from firestore-exp.
if (input instanceof Compat) {
input = input._delegate;
}

if (looksLikeJsonObject(input)) {
validatePlainObject('Unsupported field value:', context, input);
return parseObject(input, context);
Expand Down

0 comments on commit a5fb4d7

Please sign in to comment.