Skip to content

Add getDocFromCache() & getDocFromServer() #3285

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

Merged
merged 11 commits into from
Jun 26, 2020
7 changes: 7 additions & 0 deletions packages/firestore/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,13 @@ module.exports = {
rules: {
'import/no-extraneous-dependencies': 'off'
}
},
// TODO(firestoreexp): Remove this exception when app-exp is published
{
files: ['exp/**/*.ts'],
rules: {
'import/no-extraneous-dependencies': 'off'
}
}
]
};
2 changes: 1 addition & 1 deletion packages/firestore/exp/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,6 @@ export interface FirestoreError {

declare module '@firebase/component' {
interface NameServiceMapping {
'firestore/lite': FirebaseFirestore;
'firestore-exp': FirebaseFirestore;
}
}
50 changes: 50 additions & 0 deletions packages/firestore/exp/index.node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,37 @@
* limitations under the License.
*/

import { version } from '../package.json';
import { _registerComponent, registerVersion } from '@firebase/app-exp';
import { Component, ComponentType } from '@firebase/component';
import { Firestore } from './src/api/database';

export { FieldPath, documentId } from '../lite/src/api/field_path';

export {
Firestore,
initializeFirestore,
getFirestore
} from './src/api/database';

export { DocumentSnapshot, QueryDocumentSnapshot } from './src/api/snapshot';

export { SnapshotMetadata } from '../src/api/database';

export {
DocumentReference,
CollectionReference,
Query,
doc,
collection,
collectionGroup,
parent
} from '../lite/src/api/reference';

export { runTransaction, Transaction } from '../lite/src/api/transaction';

export { getDoc, getDocFromCache, getDocFromServer } from './src/api/reference';

export {
FieldValue,
deleteField,
Expand All @@ -33,3 +62,24 @@ export { Blob } from '../src/api/blob';
export { GeoPoint } from '../src/api/geo_point';

export { Timestamp } from '../src/api/timestamp';

export { refEqual, queryEqual } from '../lite/src/api/reference';

export function registerFirestore(): void {
_registerComponent(
new Component(
'firestore-exp',
container => {
const app = container.getProvider('app-exp').getImmediate()!;
return ((app, auth) => new Firestore(app, auth))(
app,
container.getProvider('auth-internal')
);
},
ComponentType.PUBLIC
)
);
registerVersion('firestore-exp', version, 'node');
}

registerFirestore();
108 changes: 108 additions & 0 deletions packages/firestore/exp/src/api/database.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/**
* @license
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import * as firestore from '../../index';

import { _getProvider } from '@firebase/app-exp';
import { FirebaseApp, _FirebaseService } from '@firebase/app-types-exp';
import { Provider } from '@firebase/component';

import { FirebaseAuthInternalName } from '@firebase/auth-interop-types';
import { FirestoreClient } from '../../../src/core/firestore_client';
import { AsyncQueue } from '../../../src/util/async_queue';
import {
ComponentProvider,
MemoryComponentProvider
} from '../../../src/core/component_provider';

import { Firestore as LiteFirestore } from '../../../lite/src/api/database';

/**
* The root reference to the Firestore database and the entry point for the
* tree-shakeable SDK.
*/
export class Firestore extends LiteFirestore
implements firestore.FirebaseFirestore, _FirebaseService {
private readonly _queue = new AsyncQueue();
private readonly _persistenceKey: string;
private _componentProvider: ComponentProvider = new MemoryComponentProvider();

// Assigned via _getFirestoreClient()
private _firestoreClientPromise?: Promise<FirestoreClient>;

// We override the Settings property of the Lite SDK since the full Firestore
// SDK supports more settings.
protected _settings?: firestore.Settings;

constructor(
app: FirebaseApp,
authProvider: Provider<FirebaseAuthInternalName>
) {
super(app, authProvider);
this._persistenceKey = app.name;
}

_getSettings(): firestore.Settings {
if (!this._settings) {
this._settings = {};
}
return this._settings;
}

_getFirestoreClient(): Promise<FirestoreClient> {
if (!this._firestoreClientPromise) {
const settings = this._getSettings();
const databaseInfo = this._makeDatabaseInfo(
settings.host,
settings.ssl,
settings.experimentalForceLongPolling
);

const firestoreClient = new FirestoreClient(
databaseInfo,
this._credentials,
this._queue
);

this._firestoreClientPromise = firestoreClient
.start(this._componentProvider, { durable: false })
.then(() => firestoreClient);
}

return this._firestoreClientPromise;
}

async delete(): Promise<void> {
// TODO(firestoreexp): Call terminate() once implemented
}
}

export function initializeFirestore(
app: FirebaseApp,
settings: firestore.Settings
): Firestore {
const firestore = _getProvider(
app,
'firestore-exp'
).getImmediate() as Firestore;
firestore._configureClient(settings);
return firestore;
}

export function getFirestore(app: FirebaseApp): Firestore {
return _getProvider(app, 'firestore-exp').getImmediate() as Firestore;
}
108 changes: 108 additions & 0 deletions packages/firestore/exp/src/api/reference.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/**
* @license
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

// See https://github.com/typescript-eslint/typescript-eslint/issues/363
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import * as firestore from '../../index';

import { Firestore } from './database';
import { DocumentKeyReference } from '../../../src/api/user_data_reader';
import { debugAssert } from '../../../src/util/assert';
import { cast } from '../../../lite/src/api/util';
import { DocumentSnapshot } from './snapshot';
import {
getDocViaSnapshotListener,
SnapshotMetadata
} from '../../../src/api/database';
import { ViewSnapshot } from '../../../src/core/view_snapshot';
import { DocumentReference } from '../../../lite/src/api/reference';
import { Document } from '../../../src/model/document';

export function getDoc<T>(
reference: firestore.DocumentReference<T>
): Promise<firestore.DocumentSnapshot<T>> {
const ref = cast<DocumentReference<T>>(reference, DocumentReference);
const firestore = cast<Firestore>(ref.firestore, Firestore);
return firestore._getFirestoreClient().then(async firestoreClient => {
const viewSnapshot = await getDocViaSnapshotListener(
firestoreClient,
ref._key
);
return convertToDocSnapshot(firestore, ref, viewSnapshot);
});
}

// TODO(firestorexp): Make sure we don't include Datastore/RemoteStore in builds
// that only include `getDocFromCache`.
export function getDocFromCache<T>(
reference: firestore.DocumentReference<T>
): Promise<firestore.DocumentSnapshot<T>> {
const ref = cast<DocumentReference<T>>(reference, DocumentReference);
const firestore = cast<Firestore>(ref.firestore, Firestore);
return firestore._getFirestoreClient().then(async firestoreClient => {
const doc = await firestoreClient.getDocumentFromLocalCache(ref._key);
return new DocumentSnapshot(
firestore,
ref._key,
doc,
ref._converter,
new SnapshotMetadata(
doc instanceof Document ? doc.hasLocalMutations : false,
/* fromCache= */ true
)
);
});
}

export function getDocFromServer<T>(
reference: firestore.DocumentReference<T>
): Promise<firestore.DocumentSnapshot<T>> {
const ref = cast<DocumentReference<T>>(reference, DocumentReference);
const firestore = cast<Firestore>(ref.firestore, Firestore);
return firestore._getFirestoreClient().then(async firestoreClient => {
const viewSnapshot = await getDocViaSnapshotListener(
firestoreClient,
ref._key,
{ source: 'server' }
);
return convertToDocSnapshot(firestore, ref, viewSnapshot);
});
}

/**
* Converts a ViewSnapshot that contains the single document specified by `ref`
* to a DocumentSnapshot.
*/
function convertToDocSnapshot<T>(
firestore: Firestore,
ref: DocumentKeyReference<T>,
snapshot: ViewSnapshot
): DocumentSnapshot<T> {
debugAssert(
snapshot.docs.size <= 1,
'Too many documents returned on a document query'
);
const doc = snapshot.docs.get(ref._key);

return new DocumentSnapshot(
firestore,
ref._key,
doc,
ref._converter,
new SnapshotMetadata(snapshot.hasPendingWrites, snapshot.fromCache)
);
}
Loading