Skip to content
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

Release Firestore Bundles as a prototype patched feature. #4168

Merged
merged 13 commits into from
Dec 8, 2020
7 changes: 7 additions & 0 deletions .changeset/old-lobsters-pull.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"firebase": minor
"@firebase/firestore-types": minor
"@firebase/firestore": minor
---

Release Firestore Bundles as a prototype patched feature.
Copy link
Contributor

Choose a reason for hiding this comment

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

You should describe in your Release Notes what this is ("bundles" is not a term that developers will understand - at least not yet) and how they can use it (mention the additional import). The Prototype Patching is an implementation detail that doesn't need to go into the release notes. We should focus on usage.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

2 changes: 1 addition & 1 deletion config/webpack.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ module.exports = {
},
resolve: {
modules: ['node_modules', path.resolve(__dirname, '../../node_modules')],
mainFields: ['browser', 'module', 'main'],
mainFields: ['esm2017', 'browser', 'module', 'main'],
extensions: ['.js', '.ts'],
symlinks: false
},
Expand Down
1 change: 1 addition & 0 deletions integration/firestore/firebase_export.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import firebase from '@firebase/app';
import '@firebase/firestore';
import '@firebase/firestore/bundle';
import { FirebaseApp } from '@firebase/app-types';
import { Settings, FirebaseFirestore } from '@firebase/firestore-types';

Expand Down
1 change: 1 addition & 0 deletions integration/firestore/firebase_export_memory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import firebase from '@firebase/app';
import '@firebase/firestore/memory';
import '@firebase/firestore/memory-bundle';
import { FirebaseApp } from '@firebase/app-types';
import { Settings, FirebaseFirestore } from '@firebase/firestore-types';

Expand Down
2 changes: 1 addition & 1 deletion integration/firestore/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"test": "yarn build:memory; karma start --single-run; yarn build:persistence; karma start --single-run;",
"test:ci": "node ../../scripts/run_tests_in_ci.js -s test",
"test:persistence": " yarn build:persistence; karma start --single-run",
"test:persistence:debug:": "yarn build:persistence; karma start --auto-watch --browsers Chrome",
"test:persistence:debug": "yarn build:persistence; karma start --auto-watch --browsers Chrome",
"test:memory": "yarn build:memory; karma start --single-run",
"test:memory:debug": "yarn build:memory; karma start --auto-watch --browsers Chrome"
},
Expand Down
1 change: 1 addition & 0 deletions packages/firebase/firestore/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@
*/

import '@firebase/firestore';
import '@firebase/firestore/bundle';
1 change: 1 addition & 0 deletions packages/firebase/firestore/memory/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@
*/

import '@firebase/firestore/memory';
import '@firebase/firestore/memory-bundle';
97 changes: 97 additions & 0 deletions packages/firebase/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8289,12 +8289,109 @@ declare namespace firebase.firestore {
*/
terminate(): Promise<void>;

/**
* Loads a Firestore bundle into the local cache.
*
* @param bundleData
* An object representing the bundle to be loaded. Valid objects are `ArrayBuffer`,
* `ReadableStream<Uint8Array>` or `string`.
*
* @return
* A `LoadBundleTask` object, which notifies callers with progress updates, and completion
* or error events. It can be used as a `Promise<LoadBundleTaskProgress>`.
*/
loadBundle(
bundleData: ArrayBuffer | ReadableStream<Uint8Array> | string
): LoadBundleTask;

/**
* Reads a Firestore `Query` from local cache, identified by the given name.
*
* The named queries are packaged into bundles on the server side (along
* with resulting documents), and loaded to local cache using `loadBundle`. Once in local
* cache, use this method to extract a `Query` by name.
*/
namedQuery(name: string): Promise<Query<DocumentData> | null>;

/**
* @hidden
*/
INTERNAL: { delete: () => Promise<void> };
}

/**
* Represents the task of loading a Firestore bundle. It provides progress of bundle
* loading, as well as task completion and error events.
*
* The API is compatible with `Promise<LoadBundleTaskProgress>`.
*/
export interface LoadBundleTask extends PromiseLike<LoadBundleTaskProgress> {
Copy link
Contributor

Choose a reason for hiding this comment

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

Need to create entries in https://github.com/firebase/firebase-js-sdk/blob/master/scripts/docgen/content-sources/js/toc.yaml for 2 new interfaces, LoadBundleTask and LoadBundleTaskProgress

Can just insert this alphabetically in the Firestore section:

  - title: "LoadBundleTask"
    path: /docs/reference/js/firebase.firestore.LoadBundleTask
  - title: "LoadBundleTaskProgress"
    path: /docs/reference/js/firebase.firestore.LoadBundleTaskProgress

If this is available for Node, also here:
https://github.com/firebase/firebase-js-sdk/blob/master/scripts/docgen/content-sources/node/toc.yaml

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

/**
* Registers functions to listen to bundle loading progress events.
* @param next
* Called when there is a progress update from bundle loading. Typically `next` calls occur
* each time a Firestore document is loaded from the bundle.
* @param error
* Called when an error occurs during bundle loading. The task aborts after reporting the
* error, and there should be no more updates after this.
* @param complete
* Called when the loading task is complete.
*/
onProgress(
next?: (progress: LoadBundleTaskProgress) => any,
error?: (error: Error) => any,
complete?: () => void
): void;

/**
* Implements the `Promise<LoadBundleTaskProgress>.then` interface.
*
* @param onFulfilled
* Called on the completion of the loading task with a final `LoadBundleTaskProgress` update.
* The update will always have its `taskState` set to `"Success"`.
* @param onRejected
* Called when an error occurs during bundle loading.
*/
then<T, R>(
onFulfilled?: (a: LoadBundleTaskProgress) => T | PromiseLike<T>,
onRejected?: (a: Error) => R | PromiseLike<R>
): Promise<T | R>;

/**
* Implements the `Promise<LoadBundleTaskProgress>.catch` interface.
*
* @param onRejected
* Called when an error occurs during bundle loading.
*/
catch<R>(
onRejected: (a: Error) => R | PromiseLike<R>
): Promise<R | LoadBundleTaskProgress>;
}

/**
* Represents a progress update or a final state from loading bundles.
*/
export interface LoadBundleTaskProgress {
/** How many documents have been loaded. */
documentsLoaded: number;
/** How many documents are in the bundle being loaded. */
totalDocuments: number;
/** How many bytes have been loaded. */
bytesLoaded: number;
/** How many bytes are in the bundle being loaded. */
totalBytes: number;
/** Current task state. */
taskState: TaskState;
}

/**
* Represents the state of bundle loading tasks.
*
* Both 'Error' and 'Success' are sinking state: task will abort or complete and there will
* be no more updates after they are reported.
*/
export type TaskState = 'Error' | 'Running' | 'Success';

/**
* An immutable object representing a geo point in Firestore. The geo point
* is represented as latitude/longitude pair.
Expand Down
33 changes: 33 additions & 0 deletions packages/firestore-types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,42 @@ export class FirebaseFirestore {

terminate(): Promise<void>;

loadBundle(
bundleData: ArrayBuffer | ReadableStream<Uint8Array> | string
): LoadBundleTask;

namedQuery(name: string): Promise<Query<DocumentData> | null>;

INTERNAL: { delete: () => Promise<void> };
}

export interface LoadBundleTask extends PromiseLike<LoadBundleTaskProgress> {
onProgress(
next?: (progress: LoadBundleTaskProgress) => any,
error?: (error: Error) => any,
complete?: () => void
): void;

then<T, R>(
onFulfilled?: (a: LoadBundleTaskProgress) => T | PromiseLike<T>,
onRejected?: (a: Error) => R | PromiseLike<R>
): Promise<T | R>;

catch<R>(
onRejected: (a: Error) => R | PromiseLike<R>
): Promise<R | LoadBundleTaskProgress>;
}

export interface LoadBundleTaskProgress {
documentsLoaded: number;
totalDocuments: number;
bytesLoaded: number;
totalBytes: number;
taskState: TaskState;
}

export type TaskState = 'Error' | 'Running' | 'Success';

export class GeoPoint {
constructor(latitude: number, longitude: number);

Expand Down
10 changes: 10 additions & 0 deletions packages/firestore/bundle/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "@firebase/firestore/bundle",
"description": "Firestore bundle",
"main": "../dist/node-cjs/bundle.js",
"main-esm2017": "../dist/node-esm2017/bundle.js",
"react-native": "../dist/rn/bundle.js",
"browser": "../dist/esm5/bundle.js",
"module": "../dist/esm5/bundle.js",
"esm2017": "../dist/esm2017/bundle.js"
}
12 changes: 6 additions & 6 deletions packages/firestore/exp/src/api/snapshot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,9 +176,9 @@ export interface DocumentChange<T = DocumentData> {
* access will return 'undefined'. You can use the `exists()` method to
* explicitly verify a document's existence.
*/
export class DocumentSnapshot<
T = DocumentData
> extends LiteDocumentSnapshot<T> {
export class DocumentSnapshot<T = DocumentData> extends LiteDocumentSnapshot<
T
> {
private readonly _firestoreImpl: FirebaseFirestore;

/**
Expand Down Expand Up @@ -291,9 +291,9 @@ export class DocumentSnapshot<
* `exists` property will always be true and `data()` will never return
* 'undefined'.
*/
export class QueryDocumentSnapshot<
T = DocumentData
> extends DocumentSnapshot<T> {
export class QueryDocumentSnapshot<T = DocumentData> extends DocumentSnapshot<
T
> {
/**
* Retrieves all fields in the document as an `Object`.
*
Expand Down
39 changes: 39 additions & 0 deletions packages/firestore/export.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* @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.
*/

export { Blob } from './src/api/blob';
export {
CollectionReference,
DocumentReference,
DocumentSnapshot,
Firestore,
Query,
QueryDocumentSnapshot,
QuerySnapshot,
IndexedDbPersistenceProvider,
MemoryPersistenceProvider,
Transaction,
WriteBatch,
setLogLevel,
CACHE_SIZE_UNLIMITED
} from './src/api/database';
export { GeoPoint } from './src/api/geo_point';
export { FieldPath } from './src/api/field_path';
export { FieldValue } from './src/compat/field_value';
export { Timestamp } from './src/api/timestamp';
export { FirebaseFirestore as ExpFirebaseFirestore } from './exp/src/api/database';
export { loadBundle, namedQuery } from './src/api/bundle';
1 change: 1 addition & 0 deletions packages/firestore/externs.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"packages/webchannel-wrapper/src/index.d.ts",
"packages/util/dist/src/crypt.d.ts",
"packages/util/dist/src/environment.d.ts",
"packages/firestore/export.ts",
"packages/firestore/src/protos/firestore_bundle_proto.ts",
"packages/firestore/src/protos/firestore_proto_api.ts",
"packages/firestore/src/util/error.ts",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,24 @@
* limitations under the License.
*/

import * as path from 'path';
import memoryPkg from './memory/package.json';
import { Firestore, loadBundle, namedQuery } from './export';

const util = require('./rollup.shared');
/**
* Prototype patches bundle loading to Firestore.
*/
export function registerBundle(instance: typeof Firestore): void {
instance.prototype.loadBundle = function (
this: Firestore,
data: ArrayBuffer | ReadableStream<Uint8Array> | string
) {
return loadBundle(this, data);
};
instance.prototype.namedQuery = function (
this: Firestore,
queryName: string
) {
return namedQuery(this, queryName);
};
}

export default {
input: 'index.rn.memory.ts',
output: {
file: path.resolve('./memory', memoryPkg['react-native']),
format: 'es',
sourcemap: true
},
plugins: util.es2017Plugins('rn', /* mangled= */ true),
external: util.resolveBrowserExterns,
treeshake: {
moduleSideEffects: false
}
};
registerBundle(Firestore);
9 changes: 6 additions & 3 deletions packages/firestore/index.memory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@
import firebase from '@firebase/app';
import { FirebaseNamespace } from '@firebase/app-types';

import { Firestore, MemoryPersistenceProvider } from './src/api/database';
import { FirebaseFirestore } from './exp/src/api/database';
import {
Firestore,
MemoryPersistenceProvider,
ExpFirebaseFirestore
} from './export';
import { configureForFirebase } from './src/config';

import './register-module';
Expand All @@ -35,7 +38,7 @@ export function registerFirestore(instance: FirebaseNamespace): void {
(app, auth) =>
new Firestore(
app,
new FirebaseFirestore(app, auth),
new ExpFirebaseFirestore(app, auth),
new MemoryPersistenceProvider()
)
);
Expand Down
7 changes: 5 additions & 2 deletions packages/firestore/index.rn.memory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@
import firebase from '@firebase/app';
import { FirebaseNamespace } from '@firebase/app-types';

import { FirebaseFirestore as ExpFirebaseFirestore } from './exp/src/api/database';
import { Firestore, MemoryPersistenceProvider } from './src/api/database';
import {
Firestore,
MemoryPersistenceProvider,
ExpFirebaseFirestore
} from './export';
import { configureForFirebase } from './src/config';

import './register-module';
Expand Down
7 changes: 5 additions & 2 deletions packages/firestore/index.rn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,12 @@
import firebase from '@firebase/app';
import { FirebaseNamespace } from '@firebase/app-types';

import { Firestore, IndexedDbPersistenceProvider } from './src/api/database';
import {
Firestore,
IndexedDbPersistenceProvider,
ExpFirebaseFirestore
} from './export';
import { configureForFirebase } from './src/config';
import { FirebaseFirestore as ExpFirebaseFirestore } from './exp/src/api/database';

import './register-module';
import { name, version } from './package.json';
Expand Down
7 changes: 5 additions & 2 deletions packages/firestore/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@
import firebase from '@firebase/app';
import { FirebaseNamespace } from '@firebase/app-types';

import { Firestore, IndexedDbPersistenceProvider } from './src/api/database';
import { FirebaseFirestore as ExpFirebaseFirestore } from './exp/src/api/database';
import {
Firestore,
IndexedDbPersistenceProvider,
ExpFirebaseFirestore
} from './export';
import { configureForFirebase } from './src/config';
import { name, version } from './package.json';

Expand Down
Loading