Skip to content

Commit 94f3c34

Browse files
Add getDoc() (#3133)
1 parent 1b0230e commit 94f3c34

File tree

13 files changed

+181
-70
lines changed

13 files changed

+181
-70
lines changed

integration/firestore/gulpfile.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/**
22
* @license
3-
* Copyright 2017 Google Inc.
3+
* Copyright 2017 Google LLC
44
*
55
* Licensed under the Apache License, Version 2.0 (the "License");
66
* you may not use this file except in compliance with the License.
@@ -51,6 +51,7 @@ function copyTests() {
5151
testBase + '/integration/api/*.ts',
5252
testBase + '/integration/util/events_accumulator.ts',
5353
testBase + '/integration/util/helpers.ts',
54+
testBase + '/integration/util/settings.ts',
5455
testBase + '/util/equality_matcher.ts',
5556
testBase + '/util/promise.ts'
5657
],

packages/firestore/lite/index.node.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ export {
3434
CollectionReference,
3535
collection,
3636
doc,
37-
parent
37+
parent,
38+
getDoc
3839
} from './src/api/reference';
3940

4041
// TOOD(firestorelite): Add tests when setDoc() is available

packages/firestore/lite/src/api/database.ts

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,19 @@ import { FirebaseApp } from '@firebase/app-types-exp';
2222
import { Provider } from '@firebase/component';
2323

2424
import { Code, FirestoreError } from '../../../src/util/error';
25-
import { DatabaseId } from '../../../src/core/database_info';
25+
import { DatabaseId, DatabaseInfo } from '../../../src/core/database_info';
2626
import { FirebaseAuthInternalName } from '@firebase/auth-interop-types';
2727
import {
2828
CredentialsProvider,
2929
FirebaseCredentialsProvider
3030
} from '../../../src/api/credentials';
31+
import { Datastore, newDatastore } from '../../../src/remote/datastore';
32+
import { PlatformSupport } from '../../../src/platform/platform';
33+
import { Deferred } from '../../../src/util/promise';
34+
35+
// settings() defaults:
36+
const DEFAULT_HOST = 'firestore.googleapis.com';
37+
const DEFAULT_SSL = true;
3138

3239
// TODO(firestorelite): Depend on FirebaseService once #3112 is merged
3340

@@ -38,7 +45,10 @@ export class Firestore implements firestore.FirebaseFirestore {
3845
readonly _databaseId: DatabaseId;
3946
private readonly _firebaseApp: FirebaseApp;
4047
private readonly _credentials: CredentialsProvider;
41-
private _settings?: firestore.Settings;
48+
49+
// Assigned via _configureClient()/_ensureClientConfigured()
50+
_settings?: firestore.Settings;
51+
private readonly _datastoreDeferred = new Deferred<Datastore>();
4252

4353
constructor(
4454
app: FirebaseApp,
@@ -63,12 +73,41 @@ export class Firestore implements firestore.FirebaseFirestore {
6373
);
6474
}
6575
this._settings = settings;
76+
77+
const databaseInfo = this._makeDatabaseInfo(settings);
78+
79+
// Kick off initializing the datastore but don't actually wait for it.
80+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
81+
PlatformSupport.getPlatform()
82+
.loadConnection(databaseInfo)
83+
.then(connection => {
84+
const serializer = PlatformSupport.getPlatform().newSerializer(
85+
databaseInfo.databaseId
86+
);
87+
const datastore = newDatastore(
88+
connection,
89+
this._credentials,
90+
serializer
91+
);
92+
this._datastoreDeferred.resolve(datastore);
93+
});
6694
}
6795

68-
_ensureClientConfigured(): void {
96+
_ensureClientConfigured(): Promise<Datastore> {
6997
if (!this._settings) {
7098
this._settings = {};
7199
}
100+
return this._datastoreDeferred.promise;
101+
}
102+
103+
private _makeDatabaseInfo(settings: firestore.Settings): DatabaseInfo {
104+
return new DatabaseInfo(
105+
this._databaseId,
106+
/* persistenceKey= */ 'unsupported',
107+
settings.host ?? DEFAULT_HOST,
108+
settings.ssl ?? DEFAULT_SSL,
109+
/* forceLongPolling= */ false
110+
);
72111
}
73112

74113
private static databaseIdFromApp(app: FirebaseApp): DatabaseId {

packages/firestore/lite/src/api/reference.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,17 @@
1717

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

20+
import { Document } from '../../../src/model/document';
2021
import { DocumentKey } from '../../../src/model/document_key';
2122
import { Firestore } from './database';
2223
import { DocumentKeyReference } from '../../../src/api/user_data_reader';
2324
import { Query as InternalQuery } from '../../../src/core/query';
2425
import { FirebaseFirestore, FirestoreDataConverter } from '../../index';
2526
import { ResourcePath } from '../../../src/model/path';
2627
import { AutoId } from '../../../src/util/misc';
28+
import { DocumentSnapshot } from './snapshot';
29+
import { invokeBatchGetDocumentsRpc } from '../../../src/remote/datastore';
30+
import { hardAssert } from '../../../src/util/assert';
2731
import { cast } from './util';
2832
import {
2933
validateArgType,
@@ -245,3 +249,20 @@ export function parent<T>(
245249
);
246250
}
247251
}
252+
253+
export function getDoc<T>(
254+
reference: firestore.DocumentReference<T>
255+
): Promise<firestore.DocumentSnapshot<T>> {
256+
const ref = cast(reference, DocumentReference) as DocumentReference<T>;
257+
return ref.firestore._ensureClientConfigured().then(async datastore => {
258+
const result = await invokeBatchGetDocumentsRpc(datastore, [ref._key]);
259+
hardAssert(result.length === 1, 'Expected a single document result');
260+
const maybeDocument = result[0];
261+
return new DocumentSnapshot<T>(
262+
ref.firestore,
263+
ref._key,
264+
maybeDocument instanceof Document ? maybeDocument : null,
265+
ref._converter
266+
);
267+
});
268+
}

packages/firestore/lite/test/helpers.ts

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,41 @@
1717

1818
import { initializeApp } from '@firebase/app-exp';
1919

20-
import { Firestore, getFirestore } from '../src/api/database';
20+
import * as firestore from '../index';
2121

22-
// eslint-disable-next-line @typescript-eslint/no-require-imports
23-
const PROJECT_CONFIG = require('../../../../config/project.json');
24-
25-
export const DEFAULT_PROJECT_ID = PROJECT_CONFIG.projectId;
22+
import { initializeFirestore } from '../src/api/database';
23+
import { doc, collection } from '../src/api/reference';
24+
import {
25+
DEFAULT_PROJECT_ID,
26+
DEFAULT_SETTINGS
27+
} from '../../test/integration/util/settings';
2628

2729
let appCount = 0;
2830

29-
export async function withTestDb(
30-
fn: (db: Firestore) => void | Promise<void>
31+
export async function withTestDbSettings(
32+
projectId: string,
33+
settings: firestore.Settings,
34+
fn: (db: firestore.FirebaseFirestore) => void | Promise<void>
3135
): Promise<void> {
3236
const app = initializeApp(
33-
{ apiKey: 'fake-api-key', projectId: DEFAULT_PROJECT_ID },
37+
{ apiKey: 'fake-api-key', projectId },
3438
'test-app-' + appCount++
3539
);
3640

37-
const firestore = getFirestore(app);
41+
const firestore = initializeFirestore(app, settings);
3842
return fn(firestore);
3943
}
44+
45+
export function withTestDb(
46+
fn: (db: firestore.FirebaseFirestore) => void | Promise<void>
47+
): Promise<void> {
48+
return withTestDbSettings(DEFAULT_PROJECT_ID, DEFAULT_SETTINGS, fn);
49+
}
50+
51+
export function withTestDoc(
52+
fn: (doc: firestore.DocumentReference) => void | Promise<void>
53+
): Promise<void> {
54+
return withTestDb(db => {
55+
return fn(doc(collection(db, 'test-collection')));
56+
});
57+
}

packages/firestore/lite/test/integration.test.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,14 @@ import {
2323
getFirestore,
2424
initializeFirestore
2525
} from '../src/api/database';
26-
import { withTestDb } from './helpers';
26+
import { withTestDb, withTestDoc } from './helpers';
2727
import {
2828
parent,
2929
collection,
3030
CollectionReference,
3131
doc,
32-
DocumentReference
32+
DocumentReference,
33+
getDoc
3334
} from '../src/api/reference';
3435
import { expectEqual, expectNotEqual } from '../../test/util/helpers';
3536
import { FieldValue } from '../../src/api/field_value';
@@ -159,6 +160,17 @@ describe('parent', () => {
159160
});
160161
});
161162

163+
describe('getDoc()', () => {
164+
it('can get a non-existing document', () => {
165+
return withTestDoc(async docRef => {
166+
const docSnap = await getDoc(docRef);
167+
expect(docSnap.exists()).to.be.false;
168+
});
169+
});
170+
171+
// TODO(firestorelite): Expand test coverage once we can write docs
172+
});
173+
162174
describe('FieldValue', () => {
163175
it('support equality checking with isEqual()', () => {
164176
expectEqual(FieldValue.delete(), FieldValue.delete());

packages/firestore/test/integration/api/database.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,13 @@ import { EventsAccumulator } from '../util/events_accumulator';
2525
import firebase from '../util/firebase_export';
2626
import {
2727
apiDescribe,
28-
DEFAULT_SETTINGS,
2928
withTestCollection,
3029
withTestDb,
3130
withTestDbs,
3231
withTestDoc,
3332
withTestDocAndInitialData
3433
} from '../util/helpers';
34+
import { DEFAULT_SETTINGS } from '../util/settings';
3535

3636
// tslint:disable:no-floating-promises
3737

packages/firestore/test/integration/api/fields.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,13 @@ import { expect } from 'chai';
1919
import firebase from '../util/firebase_export';
2020
import {
2121
apiDescribe,
22-
DEFAULT_SETTINGS,
2322
toDataArray,
2423
withTestCollection,
2524
withTestCollectionSettings,
2625
withTestDoc,
2726
withTestDocAndSettings
2827
} from '../util/helpers';
28+
import { DEFAULT_SETTINGS } from '../util/settings';
2929

3030
const FieldPath = firebase.firestore!.FieldPath;
3131
const FieldValue = firebase.firestore!.FieldValue;

packages/firestore/test/integration/api/validation.test.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,12 @@ import { expect } from 'chai';
2121
import { Deferred } from '../../util/promise';
2222
import firebase from '../util/firebase_export';
2323
import {
24-
ALT_PROJECT_ID,
2524
apiDescribe,
26-
DEFAULT_PROJECT_ID,
2725
withAlternateTestDb,
2826
withTestCollection,
2927
withTestDb
3028
} from '../util/helpers';
29+
import { ALT_PROJECT_ID, DEFAULT_PROJECT_ID } from '../util/settings';
3130

3231
// tslint:disable:no-floating-promises
3332

packages/firestore/test/integration/browser/webchannel.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import { expect } from 'chai';
1919
import { DatabaseId, DatabaseInfo } from '../../../src/core/database_info';
2020
import { WebChannelConnection } from '../../../src/platform_browser/webchannel_connection';
2121
import * as api from '../../../src/protos/firestore_proto_api';
22-
import { DEFAULT_PROJECT_ID } from '../util/helpers';
22+
import { DEFAULT_PROJECT_ID } from '../util/settings';
2323
import { getDefaultDatabaseInfo } from '../util/internal_helpers';
2424

2525
/* eslint-disable no-restricted-globals */

packages/firestore/test/integration/util/helpers.ts

Lines changed: 5 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -17,53 +17,14 @@
1717

1818
import * as firestore from '@firebase/firestore-types';
1919
import firebase from './firebase_export';
20+
import {
21+
ALT_PROJECT_ID,
22+
DEFAULT_PROJECT_ID,
23+
DEFAULT_SETTINGS
24+
} from './settings';
2025

2126
/* eslint-disable no-restricted-globals */
2227

23-
/**
24-
* NOTE: These helpers are used by api/ tests and therefore may not have any
25-
* dependencies on src/ files.
26-
*/
27-
// __karma__ is an untyped global
28-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
29-
declare const __karma__: any;
30-
31-
// eslint-disable-next-line @typescript-eslint/no-require-imports
32-
const PROJECT_CONFIG = require('../../../../../config/project.json');
33-
34-
const EMULATOR_PORT = process.env.FIRESTORE_EMULATOR_PORT;
35-
const EMULATOR_PROJECT_ID = process.env.FIRESTORE_EMULATOR_PROJECT_ID;
36-
export const USE_EMULATOR = !!EMULATOR_PORT;
37-
38-
const EMULATOR_FIRESTORE_SETTING = {
39-
host: `localhost:${EMULATOR_PORT}`,
40-
ssl: false
41-
};
42-
43-
const PROD_FIRESTORE_SETTING = {
44-
host: 'firestore.googleapis.com',
45-
ssl: true
46-
};
47-
48-
export const DEFAULT_SETTINGS = getDefaultSettings();
49-
50-
// eslint-disable-next-line no-console
51-
console.log(`Default Settings: ${JSON.stringify(DEFAULT_SETTINGS)}`);
52-
53-
function getDefaultSettings(): firestore.Settings {
54-
const karma = typeof __karma__ !== 'undefined' ? __karma__ : undefined;
55-
if (karma && karma.config.firestoreSettings) {
56-
return karma.config.firestoreSettings;
57-
} else {
58-
return USE_EMULATOR ? EMULATOR_FIRESTORE_SETTING : PROD_FIRESTORE_SETTING;
59-
}
60-
}
61-
62-
export const DEFAULT_PROJECT_ID = USE_EMULATOR
63-
? EMULATOR_PROJECT_ID
64-
: PROJECT_CONFIG.projectId;
65-
export const ALT_PROJECT_ID = 'test-db2';
66-
6728
function isIeOrEdge(): boolean {
6829
if (!window.navigator) {
6930
return false;

packages/firestore/test/integration/util/internal_helpers.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,9 @@ import {
2828
import { Firestore } from '../../../src/api/database';
2929
import { PlatformSupport } from '../../../src/platform/platform';
3030
import { AsyncQueue } from '../../../src/util/async_queue';
31-
import {
32-
DEFAULT_PROJECT_ID,
33-
DEFAULT_SETTINGS,
34-
withTestDbsSettings
35-
} from './helpers';
31+
import { withTestDbsSettings } from './helpers';
3632
import { User } from '../../../src/auth/user';
33+
import { DEFAULT_PROJECT_ID, DEFAULT_SETTINGS } from './settings';
3734

3835
/** Helper to retrieve the AsyncQueue for a give FirebaseFirestore instance. */
3936
export function asyncQueue(db: firestore.FirebaseFirestore): AsyncQueue {

0 commit comments

Comments
 (0)