Skip to content

Revive Node.JS Support for Cloud Firestore (fixes #221). #319

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 7 commits into from
Nov 20, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions packages/firestore/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@
"license": "Apache-2.0",
"dependencies": {
"@firebase/webchannel-wrapper": "^0.2.4",
"grpc": "^1.7.1",
"protobufjs": "^5.0.0"
"grpc": "^1.7.1"
},
"peerDependencies": {
"@firebase/app": "^0.1.0"
Expand Down
7 changes: 2 additions & 5 deletions packages/firestore/src/platform_node/grpc_connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
*/

import * as grpc from 'grpc';
import * as protobufjs from 'protobufjs';

import firebase from '@firebase/app';
const SDK_VERSION = firebase.SDK_VERSION;
Expand All @@ -32,7 +31,6 @@ import { FirestoreError } from '../util/error';
import * as log from '../util/log';
import { AnyJs } from '../util/misc';
import { NodeCallback, nodePromise } from '../util/node_api';
import { ProtobufProtoBuilder } from './load_protos';
import { Deferred } from '../util/promise';

const LOG_TAG = 'Connection';
Expand Down Expand Up @@ -117,11 +115,10 @@ export class GrpcConnection implements Connection {
private cachedStub: CachedStub | null = null;

constructor(
builder: ProtobufProtoBuilder,
protos: grpc.GrpcObject,
private databaseInfo: DatabaseInfo
) {
const protos = grpc.loadObject(builder.ns);
this.firestore = protos.google.firestore.v1beta1;
this.firestore = protos['google']['firestore']['v1beta1'];
}

private sameToken(tokenA: Token | null, tokenB: Token | null): boolean {
Expand Down
39 changes: 7 additions & 32 deletions packages/firestore/src/platform_node/load_protos.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,48 +14,23 @@
* limitations under the License.
*/

const dynamicRequire = require;
const protobufjs = dynamicRequire('protobufjs');
export type ProtobufProtoBuilder = any;

import { NodeCallback, nodePromise } from '../util/node_api';

export function loadProtosAsync(): Promise<ProtobufProtoBuilder> {
return nodePromise((callback: NodeCallback<ProtobufProtoBuilder>) => {
loadProtos(callback);
});
}
import * as grpc from 'grpc';

/**
* Loads the protocol buffer definitions for the datastore. This is a thin
* wrapper around protobufjs.loadProtoFile which knows the location of the
* proto files.
* Loads the protocol buffer definitions for Firestore.
*
* @param callback if specified, the load is performed asynchronously and
* the protos are supplied to the callback.
* @returns the ProtoBuilder if the callback is unspecified.
* @returns The GrpcObject representing our protos.
*/
export function loadProtos(
callback?: NodeCallback<ProtobufProtoBuilder>
): ProtobufProtoBuilder | undefined {
const builder = protobufjs.newBuilder({
export function loadProtos(): grpc.GrpcObject {
const options = {
// Beware that converting fields to camel case does not convert the tag
// fields in oneof groups (!!!).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this refer to valueType? ProtobufJS 6.x+ is now doing this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting. I tried to go down the route of depending directly on protobufjs again and upgrading to 6.x, but it did not seem straightforward (the entire way we're consuming protobufjs has changed an doesn't seem to be documented in the release notes, etc.). So I'm punting on this for now. I did update the comment to mention that upgrading to protobufjs 6.x would resolve this though.

convertFieldsToCamelCase: true
});
};
const root = __dirname + '/../protos';
const firestoreProtoFile = {
root: root,
file: 'google/firestore/v1beta1/firestore.proto'
};
if (callback === undefined) {
// Synchronous load
return protobufjs.loadProtoFile(firestoreProtoFile, undefined, builder);
} else {
// Load the protos asynchronously
protobufjs.loadProtoFile(firestoreProtoFile, callback, builder);
// We are using the callback so no return value, but we need to explicitly
// return undefined
return undefined;
}
return grpc.load(firestoreProtoFile, /*format=*/'proto', options);
}
7 changes: 3 additions & 4 deletions packages/firestore/src/platform_node/node_platform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { JsonProtoSerializer } from '../remote/serializer';
import { Code, FirestoreError } from '../util/error';

import { GrpcConnection } from './grpc_connection';
import { loadProtosAsync } from './load_protos';
import { loadProtos } from './load_protos';
import { AnyJs } from '../util/misc';

export class NodePlatform implements Platform {
Expand All @@ -32,9 +32,8 @@ export class NodePlatform implements Platform {
readonly emptyByteString = new Uint8Array(0);

loadConnection(databaseInfo: DatabaseInfo): Promise<Connection> {
return loadProtosAsync().then(protos => {
return new GrpcConnection(protos, databaseInfo);
});
const protos = loadProtos();
return Promise.resolve(new GrpcConnection(protos, databaseInfo));
}

newSerializer(partitionId: DatabaseId): JsonProtoSerializer {
Expand Down
8 changes: 4 additions & 4 deletions packages/firestore/test/unit/remote/node/serializer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ describe('Serializer', () => {
const partition = new DatabaseId('p', 'd');
const s = new JsonProtoSerializer(partition, { useProto3Json: false });
const emptyResumeToken = new Uint8Array(0);
const protos: any = loadProtos().build();
const ds = protos.google.firestore.v1beta1;
const protos = loadProtos();
const ds = protos['google']['firestore']['v1beta1'];

/**
* Wraps the given query in QueryData. This is useful because the APIs we're
Expand Down Expand Up @@ -205,7 +205,7 @@ describe('Serializer', () => {
const expected = { timestampValue: expectedJson[i] };
expect(obj).to.deep.equal(expected);
expectValue(obj, 'timestampValue').to.deep.equal(
new protos.google.protobuf.Timestamp(expectedJson[i]),
new protos['google']['protobuf'].Timestamp(expectedJson[i]),
'for date ' + example
);
}
Expand All @@ -224,7 +224,7 @@ describe('Serializer', () => {
const obj = s.toValue(new fieldValue.GeoPointValue(example));
expect(obj).to.deep.equal(expected);
expectValue(obj, 'geoPointValue').to.deep.equal(
new protos.google.type.LatLng(1.23, 4.56)
new protos['google']['type'].LatLng(1.23, 4.56)
);
});

Expand Down