Skip to content

Commit 96b1d2a

Browse files
feat: Add support for environment variable FIRESTORE_PREFER_REST (#1848)
Add support for environment variable FIRESTORE_PREFER_REST
1 parent b64e0c1 commit 96b1d2a

File tree

7 files changed

+187
-6
lines changed

7 files changed

+187
-6
lines changed

Diff for: dev/src/index.ts

+17-1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ import {
6060
isPermanentRpcError,
6161
requestTag,
6262
wrapError,
63+
tryGetPreferRestEnvironmentVariable,
6364
} from './util';
6465
import {
6566
validateBoolean,
@@ -534,7 +535,12 @@ export class Firestore implements firestore.Firestore {
534535
* for communication from that point forward. Currently the only operation
535536
* that requires gRPC is creating a snapshot listener with the method
536537
* `DocumentReference<T>.onSnapshot()`, `CollectionReference<T>.onSnapshot()`, or
537-
* `Query<T>.onSnapshot()`.
538+
* `Query<T>.onSnapshot()`. If specified, this setting value will take precedent over the
539+
* environment variable `FIRESTORE_PREFER_REST`. If not specified, the
540+
* SDK will use the value specified in the environment variable `FIRESTORE_PREFER_REST`.
541+
* Valid values of `FIRESTORE_PREFER_REST` are `true` ('1') or `false` (`0`). Values are
542+
* not case-sensitive. Any other value for the environment variable will be ignored and
543+
* a warning will be logged to the console.
538544
*/
539545
constructor(settings?: firestore.Settings) {
540546
const libraryHeader = {
@@ -663,6 +669,16 @@ export class Firestore implements firestore.Firestore {
663669

664670
let url: URL | null = null;
665671

672+
// If preferRest is not specified in settings, but is set as environment variable,
673+
// then use the environment variable value.
674+
const preferRestEnvValue = tryGetPreferRestEnvironmentVariable();
675+
if (settings.preferRest === undefined && preferRestEnvValue !== undefined) {
676+
settings = {
677+
...settings,
678+
preferRest: preferRestEnvValue,
679+
};
680+
}
681+
666682
// If the environment variable is set, it should always take precedence
667683
// over any user passed in settings.
668684
if (process.env.FIRESTORE_EMULATOR_HOST) {

Diff for: dev/src/util.ts

+29
Original file line numberDiff line numberDiff line change
@@ -217,3 +217,32 @@ export function wrapError(err: Error, stack: string): Error {
217217
err.stack += '\nCaused by: ' + stack;
218218
return err;
219219
}
220+
221+
/**
222+
* Parses the value of the environment variable FIRESTORE_PREFER_REST, and
223+
* returns a value indicating if the environment variable enables or disables
224+
* preferRest.
225+
*
226+
* This function will warn to the console if the environment variable is set
227+
* to an unsupported value.
228+
*
229+
* @return `true` if the environment variable enables `preferRest`,
230+
* `false` if the environment variable disables `preferRest`, or `undefined`
231+
* if the environment variable is not set or is set to an unsupported value.
232+
*/
233+
export function tryGetPreferRestEnvironmentVariable(): boolean | undefined {
234+
const rawValue = process.env.FIRESTORE_PREFER_REST?.trim().toLowerCase();
235+
if (rawValue === undefined) {
236+
return undefined;
237+
} else if (rawValue === '1' || rawValue === 'true') {
238+
return true;
239+
} else if (rawValue === '0' || rawValue === 'false') {
240+
return false;
241+
} else {
242+
// eslint-disable-next-line no-console
243+
console.warn(
244+
`An unsupported value was specified for the environment variable FIRESTORE_PREFER_REST. Value ${rawValue} is unsupported.`
245+
);
246+
return undefined;
247+
}
248+
}

Diff for: dev/system-test/firestore.ts

-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,6 @@ if (process.env.NODE_ENV === 'DEBUG') {
8484
function getTestRoot(settings: Settings = {}) {
8585
const firestore = new Firestore({
8686
...settings,
87-
preferRest: !!process.env.USE_REST_FALLBACK,
8887
});
8988
return firestore.collection(`node_${version}_${autoId()}`);
9089
}

Diff for: dev/test/index.ts

+56
Original file line numberDiff line numberDiff line change
@@ -639,6 +639,62 @@ describe('instantiation', () => {
639639
);
640640
});
641641

642+
describe('preferRest configuration', () => {
643+
let originalValue: string | undefined;
644+
645+
beforeEach(() => {
646+
originalValue = process.env.FIRESTORE_PREFER_REST;
647+
});
648+
649+
afterEach(() => {
650+
if (originalValue === undefined) {
651+
delete process.env.FIRESTORE_PREFER_REST;
652+
} else {
653+
process.env.FIRESTORE_PREFER_REST = originalValue;
654+
}
655+
});
656+
657+
it('preferRest is disabled (falsy) by default', async () => {
658+
delete process.env.FIRESTORE_PREFER_REST;
659+
const firestore = new Firestore.Firestore({});
660+
// Convention with settings is to leave undefined settings as
661+
// undefined. We could test for undefined here, but converting
662+
// to boolean and testing for falsy-ness is consistent with the
663+
// code that consumes settings.
664+
expect(!!firestore['_settings'].preferRest).to.be.false;
665+
});
666+
667+
it('preferRest can be enabled by setting', async () => {
668+
delete process.env.FIRESTORE_PREFER_REST;
669+
const firestore = new Firestore.Firestore({
670+
preferRest: true,
671+
});
672+
expect(firestore['_settings'].preferRest).to.be.true;
673+
});
674+
675+
it('preferRest can be enabled by environment variable', async () => {
676+
process.env.FIRESTORE_PREFER_REST = 'true';
677+
const firestore = new Firestore.Firestore({});
678+
expect(firestore['_settings'].preferRest).to.be.true;
679+
});
680+
681+
it('the preferRest value from settings takes precedent over the environment var - disable', async () => {
682+
process.env.FIRESTORE_PREFER_REST = 'true';
683+
const firestore = new Firestore.Firestore({
684+
preferRest: false,
685+
});
686+
expect(firestore['_settings'].preferRest).to.be.false;
687+
});
688+
689+
it('the preferRest value from settings takes precedent over the environment var - enable', async () => {
690+
process.env.FIRESTORE_PREFER_REST = 'false';
691+
const firestore = new Firestore.Firestore({
692+
preferRest: true,
693+
});
694+
expect(firestore['_settings'].preferRest).to.be.true;
695+
});
696+
});
697+
642698
it('exports all types', () => {
643699
// Ordering as per firestore.d.ts
644700
expect(Firestore.Firestore).to.exist;

Diff for: dev/test/util.ts

+69-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414

1515
import {describe, it} from 'mocha';
1616
import {expect} from 'chai';
17-
import {isPlainObject} from '../src/util';
17+
import {isPlainObject, tryGetPreferRestEnvironmentVariable} from '../src/util';
18+
import * as sinon from 'sinon';
1819

1920
describe('isPlainObject()', () => {
2021
it('allows Object.create()', () => {
@@ -33,4 +34,71 @@ describe('isPlainObject()', () => {
3334
expect(isPlainObject(new Foo())).to.be.false;
3435
expect(isPlainObject(Object.create(new Foo()))).to.be.false;
3536
});
37+
38+
describe('tryGetPreferRestEnvironmentVariable', () => {
39+
const sandbox = sinon.createSandbox();
40+
41+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
42+
let warnSpy: any;
43+
let originalValue: string | undefined;
44+
45+
beforeEach(() => {
46+
warnSpy = sandbox.spy(console, 'warn');
47+
originalValue = process.env.FIRESTORE_PREFER_REST;
48+
});
49+
50+
afterEach(() => {
51+
sandbox.restore();
52+
if (originalValue === undefined) {
53+
delete process.env.FIRESTORE_PREFER_REST;
54+
} else {
55+
process.env.FIRESTORE_PREFER_REST = originalValue;
56+
}
57+
});
58+
59+
it('reads true', async () => {
60+
process.env.FIRESTORE_PREFER_REST = 'true';
61+
expect(tryGetPreferRestEnvironmentVariable()).to.be.true;
62+
});
63+
64+
it('reads 1', async () => {
65+
process.env.FIRESTORE_PREFER_REST = '1';
66+
expect(tryGetPreferRestEnvironmentVariable()).to.be.true;
67+
});
68+
69+
it('reads false', async () => {
70+
process.env.FIRESTORE_PREFER_REST = 'false';
71+
expect(tryGetPreferRestEnvironmentVariable()).to.be.false;
72+
});
73+
74+
it('reads 0', async () => {
75+
process.env.FIRESTORE_PREFER_REST = '0';
76+
expect(tryGetPreferRestEnvironmentVariable()).to.be.false;
77+
});
78+
79+
it('ignores case', async () => {
80+
process.env.FIRESTORE_PREFER_REST = 'True';
81+
expect(tryGetPreferRestEnvironmentVariable()).to.be.true;
82+
});
83+
84+
it('trims whitespace', async () => {
85+
process.env.FIRESTORE_PREFER_REST = ' true ';
86+
expect(tryGetPreferRestEnvironmentVariable()).to.be.true;
87+
});
88+
89+
it('returns undefined when the environment variable is not set', async () => {
90+
delete process.env.FIRESTORE_PREFER_REST;
91+
expect(tryGetPreferRestEnvironmentVariable()).to.be.undefined;
92+
expect(warnSpy.calledOnce).to.be.false;
93+
});
94+
95+
it('returns undefined and warns when the environment variable is set to an unsupported value', async () => {
96+
process.env.FIRESTORE_PREFER_REST = 'enable';
97+
expect(tryGetPreferRestEnvironmentVariable()).to.be.undefined;
98+
expect(warnSpy.calledOnce).to.be.true;
99+
expect(warnSpy.getCall(0).args[0]).to.match(
100+
/unsupported value.*FIRESTORE_PREFER_REST/
101+
);
102+
});
103+
});
36104
});

Diff for: dev/test/util/helpers.ts

+14-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ import {GapicClient} from '../../src/types';
3535
import api = proto.google.firestore.v1;
3636

3737
let SSL_CREDENTIALS: grpc.ChannelCredentials | null = null;
38-
if (!process.env.USE_REST_FALLBACK) {
38+
if (!isPreferRest()) {
3939
const grpc = require('google-gax').grpc;
4040
SSL_CREDENTIALS = grpc.credentials.createInsecure();
4141
}
@@ -444,3 +444,16 @@ export async function collect<T, TReturn, TNext>(
444444
}
445445
return values;
446446
}
447+
448+
/**
449+
* Returns a value indicating whether preferRest is enabled
450+
* via the environment variable `FIRESTORE_PREFER_REST`.
451+
*
452+
* @return `true` if preferRest is enabled via the environment variable `FIRESTORE_PREFER_REST`.
453+
*/
454+
export function isPreferRest(): boolean {
455+
return (
456+
process.env.FIRESTORE_PREFER_REST === '1' ||
457+
process.env.FIRESTORE_PREFER_REST === 'true'
458+
);
459+
}

Diff for: package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@
3030
"scripts": {
3131
"predocs": "npm run compile",
3232
"docs": "jsdoc -c .jsdoc.js",
33-
"system-test:rest": "USE_REST_FALLBACK=YES mocha build/system-test --timeout 600000",
33+
"system-test:rest": "FIRESTORE_PREFER_REST=true mocha build/system-test --timeout 600000",
3434
"system-test:grpc": "mocha build/system-test --timeout 600000",
35-
"system-test:emulator:rest": "FIRESTORE_EMULATOR_HOST=localhost:8080 USE_REST_FALLBACK=YES mocha build/system-test --timeout 600000",
35+
"system-test:emulator:rest": "FIRESTORE_EMULATOR_HOST=localhost:8080 FIRESTORE_PREFER_REST=true mocha build/system-test --timeout 600000",
3636
"system-test:emulator:grpc": "FIRESTORE_EMULATOR_HOST=localhost:8080 mocha build/system-test --timeout 600000",
3737
"system-test": "npm run system-test:grpc && npm run system-test:rest",
3838
"system-test:emulator": "npm run system-test:emulator:grpc && npm run system-test:emulator:rest",

0 commit comments

Comments
 (0)