Skip to content

Commit 5cf39ab

Browse files
Add terminate() to Lite SDK (#3157)
1 parent e593601 commit 5cf39ab

File tree

4 files changed

+78
-4
lines changed

4 files changed

+78
-4
lines changed

packages/firestore/lite/index.node.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ import '../src/platform_node/node_init';
2525
export {
2626
Firestore,
2727
initializeFirestore,
28-
getFirestore
28+
getFirestore,
29+
terminate
2930
} from './src/api/database';
3031

3132
export {
@@ -42,6 +43,9 @@ export {
4243
addDoc
4344
} from './src/api/reference';
4445

46+
// TOOD(firestorelite): Add tests when Queries are usable
47+
export { FieldPath, documentId } from './src/api/field_path';
48+
4549
// TOOD(firestorelite): Add tests when setDoc() is available
4650
export {
4751
FieldValue,

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

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,14 @@ import {
2828
CredentialsProvider,
2929
FirebaseCredentialsProvider
3030
} from '../../../src/api/credentials';
31-
import { Datastore, newDatastore } from '../../../src/remote/datastore';
31+
import {
32+
Datastore,
33+
newDatastore,
34+
terminateDatastore
35+
} from '../../../src/remote/datastore';
3236
import { PlatformSupport } from '../../../src/platform/platform';
3337
import { Deferred } from '../../../src/util/promise';
38+
import { cast } from './util';
3439

3540
// settings() defaults:
3641
const DEFAULT_HOST = 'firestore.googleapis.com';
@@ -137,3 +142,13 @@ export function initializeFirestore(
137142
export function getFirestore(app: FirebaseApp): Firestore {
138143
return _getProvider(app, 'firestore/lite').getImmediate() as Firestore;
139144
}
145+
146+
export function terminate(
147+
firestore: firestore.FirebaseFirestore
148+
): Promise<void> {
149+
// TODO(firestorelite): Call _removeServiceInstance when available
150+
const firestoreClient = cast(firestore, Firestore);
151+
return firestoreClient
152+
._ensureClientConfigured()
153+
.then(datastore => terminateDatastore(datastore));
154+
}

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

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,15 @@
1515
* limitations under the License.
1616
*/
1717

18-
import { expect } from 'chai';
18+
import { expect, use } from 'chai';
19+
import * as chaiAsPromised from 'chai-as-promised';
1920

2021
import { initializeApp } from '@firebase/app-exp';
2122
import {
2223
Firestore,
2324
getFirestore,
24-
initializeFirestore
25+
initializeFirestore,
26+
terminate
2527
} from '../src/api/database';
2628
import {
2729
withTestCollection,
@@ -50,6 +52,8 @@ import {
5052
import { expectEqual, expectNotEqual } from '../../test/util/helpers';
5153
import { FieldValue } from '../../src/api/field_value';
5254

55+
use(chaiAsPromised);
56+
5357
describe('Firestore', () => {
5458
it('can provide setting', () => {
5559
const app = initializeApp(
@@ -82,6 +86,39 @@ describe('Firestore', () => {
8286
'Firestore has already been started and its settings can no longer be changed.'
8387
);
8488
});
89+
90+
it('cannot use once terminated', () => {
91+
const app = initializeApp(
92+
{ apiKey: 'fake-api-key', projectId: 'test-project' },
93+
'test-app-terminated'
94+
);
95+
const firestore = initializeFirestore(app, {
96+
host: 'localhost',
97+
ssl: false
98+
});
99+
100+
// We don't await the Promise. Any operation enqueued after should be
101+
// rejected.
102+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
103+
terminate(firestore);
104+
105+
return expect(
106+
getDoc(doc(firestore, 'coll/doc'))
107+
).to.be.eventually.rejectedWith('The client has already been terminated.');
108+
});
109+
110+
it('can call terminate() multiple times', () => {
111+
const app = initializeApp(
112+
{ apiKey: 'fake-api-key', projectId: 'test-project' },
113+
'test-app-multi-terminate'
114+
);
115+
const firestore = initializeFirestore(app, {
116+
host: 'localhost',
117+
ssl: false
118+
});
119+
120+
return terminate(firestore).then(() => terminate(firestore));
121+
});
85122
});
86123

87124
describe('doc', () => {

packages/firestore/src/remote/datastore.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ export class Datastore {
4949
* consumption.
5050
*/
5151
class DatastoreImpl extends Datastore {
52+
terminated = false;
53+
5254
constructor(
5355
public readonly connection: Connection,
5456
public readonly credentials: CredentialsProvider,
@@ -57,8 +59,18 @@ class DatastoreImpl extends Datastore {
5759
super();
5860
}
5961

62+
private verifyNotTerminated(): void {
63+
if (this.terminated) {
64+
throw new FirestoreError(
65+
Code.FAILED_PRECONDITION,
66+
'The client has already been terminated.'
67+
);
68+
}
69+
}
70+
6071
/** Gets an auth token and invokes the provided RPC. */
6172
invokeRPC<Req, Resp>(rpcName: string, request: Req): Promise<Resp> {
73+
this.verifyNotTerminated();
6274
return this.credentials
6375
.getToken()
6476
.then(token => {
@@ -77,6 +89,7 @@ class DatastoreImpl extends Datastore {
7789
rpcName: string,
7890
request: Req
7991
): Promise<Resp[]> {
92+
this.verifyNotTerminated();
8093
return this.credentials
8194
.getToken()
8295
.then(token => {
@@ -199,3 +212,8 @@ export function newPersistentWatchStream(
199212
listener
200213
);
201214
}
215+
216+
export function terminateDatastore(datastore: Datastore): void {
217+
const datastoreImpl = debugCast(datastore, DatastoreImpl);
218+
datastoreImpl.terminated = true;
219+
}

0 commit comments

Comments
 (0)