1
0
mirror of https://github.com/musix-org/musix-oss synced 2025-09-06 04:33:20 +00:00
This commit is contained in:
MatteZ02
2019-10-10 16:43:04 +03:00
parent 6f6ac8a6fa
commit 50b9bed483
9432 changed files with 1988816 additions and 167 deletions

285
node_modules/@firebase/firestore/CHANGELOG.md generated vendored Normal file
View File

@@ -0,0 +1,285 @@
# Unreleased (1.5.0)
- [feature] Added a `Firestore.waitForPendingWrites()` method that
allows users to wait until all pending writes are acknowledged by the
Firestore backend.
- [feature] Added a `Firestore.terminate()` method which terminates
the instance, releasing any held resources. Once it completes, you can
optionally call `Firestore.clearPersistence()` to wipe persisted Firestore
data from disk.
- [changed] Improved performance for queries with filters that only return a
small subset of the documents in a collection.
- [fixed] Fixed a race condition between authenticating and initializing
Firestore that could result in initial writes to the database being dropped.
# 1.4.10
- [changed] Transactions now perform exponential backoff before retrying.
This means transactions on highly contended documents are more likely to
succeed.
# 1.4.6
- [changed] Transactions are now more flexible. Some sequences of operations
that were previously incorrectly disallowed are now allowed. For example,
after reading a document that doesn't exist, you can now set it multiple
times successfully in a transaction.
# 1.4.5
- [fixed] Fixed an issue where query results were temporarily missing
documents that previously had not matched but had been updated to now
match the query (https://github.com/firebase/firebase-android-sdk/issues/155).
# 1.4.4
>>>>>>> master
- [fixed] Fixed an internal assertion that was triggered when an update
with a `FieldValue.serverTimestamp()` and an update with a
`FieldValue.increment()` were pending for the same document.
# 1.4.0
- [changed] Added logging and a custom error message to help users hitting
https://bugs.webkit.org/show_bug.cgi?id=197050 (a bug in iOS 12.2 causing
the SDK to potentially crash when persistence is enabled).
- [fixed] Fixed an issue for environments missing `window.addEventListener`,
such as in React Native with Expo (#1824).
# 1.3.5
- [feature] Added `clearPersistence()`, which clears the persistent storage
including pending writes and cached documents. This is intended to help
write reliable tests (#449).
# 1.3.3
- [changed] Firestore now recovers more quickly after network connectivity
changes (airplane mode, Wi-Fi availability, etc.).
# 1.3.0
- [changed] Deprecated the `experimentalTabSynchronization` setting in favor of
`synchronizeTabs`. If you use multi-tab synchronization, it is recommended
that you update your call to `enablePersistence()`. Firestore logs an error
if you continue to use `experimentalTabSynchronization`.
- [feature] You can now query across all collections in your database with a
given collection ID using the `FirebaseFirestore.collectionGroup()` method.
# 1.1.4
- [feature] Added an `experimentalForceLongPolling` setting that that can be
used to work around proxies that prevent the Firestore client from connecting
to the Firestore backend.
# 1.1.1
- [changed] Increased a connection timeout that could lead to large writes
perputually retrying without ever succeeding (#1447).
- [fixed] Fixed an issue with IndexedDb persistence that triggered an internal
assert for Queries that use nested DocumentReferences in where() clauses
(#1524, #1596).
- [fixed] Fixed an issue where transactions in a Node.JS app could be sent
without auth credentials, leading to Permission Denied errors.
# 1.1.0
- [feature] Added `FieldValue.increment()`, which can be used in `update()`
and `set(..., {merge:true})` to increment or decrement numeric field
values safely without transactions.
- [changed] Prepared the persistence layer to support collection group queries.
While this feature is not yet available, all schema changes are included
in this release. Once you upgrade, you will not be able to use an older version
of the Firestore SDK with persistence enabled.
# 1.0.5
- [changed] Improved performance when querying over documents that contain
subcollections.
# 1.0.4
- [fixed] Fixed an uncaught promise error occurring when `enablePersistence()`
was called in a second tab (#1531).
# 1.0.0
- [changed] The `timestampsInSnapshots` setting is now enabled by default.
Timestamp fields that read from a `DocumentSnapshot` are now returned as
`Timestamp` objects instead of `Date` objects. This is a breaking change;
developers must update any code that expects to receive a `Date` object. See
https://firebase.google.com/docs/reference/js/firebase.firestore.Settings#~timestampsInSnapshots
for more details.
- [fixed] Fixed a crash that could happen when the app is shut down after
a write has been sent to the server but before it has been received on
a listener.
# 0.9.2
- [fixed] Fixed a regression introduced in 5.7.0 that caused apps using
experimentalTabSynchronization to hit an exception for "Failed to obtain
primary lease for action 'Collect garbage'".
# 0.9.1
- [changed] Added a custom error for schema downgrades.
# 0.9.0
- [changed] Removed eval()-based fallback for JSON parsing, allowing SDK to
be used in environments that prohibit eval().
- [feature] Added a garbage collection process to on-disk persistence that
removes older documents. This is enabled automatically if persistence is
enabled, and the SDK will attempt to periodically clean up older, unused
documents once the on-disk cache passes a threshold size (default: 40 MB).
This threshold can be configured by changing the setting `cacheSizeBytes` in
the settings passed to `Firestore.settings()`. It must be set to a minimum of
1 MB. The garbage collection process can be disabled entirely by setting
`cacheSizeBytes` to `CACHE_SIZE_UNLIMITED`.
# 0.8.3
- [fixed] Fixed an issue that prevented query synchronization between multiple
tabs.
# 0.8.2
- [fixed] Fixed an issue where native ES6 module loading was not working.
# 0.8.1
- [fixed] Fixed an issue where typings are created in the wrong location.
# 0.8.0
- [feature] Access to offline persistence is no longer limited to a single tab.
You can opt into this new experimental mode by invoking `enablePersistence()`
with `{experimentalTabSynchronization: true}`. All tabs accessing persistence
must use the same setting for this flag.
- [fixed] Fixed an issue where the first `get()` call made after being offline
could incorrectly return cached data without attempting to reach the backend.
- [changed] Changed `get()` to only make one attempt to reach the backend before
returning cached data, potentially reducing delays while offline.
- [fixed] Fixed an issue that caused Firebase to drop empty objects from calls
to `set(..., { merge: true })`.
- [changed] Improved argument validation for several API methods.
# 0.7.3
- [changed] Changed the internal handling for locally updated documents that
haven't yet been read back from Firestore. This can lead to slight behavior
changes and may affect the `SnapshotMetadata.hasPendingWrites` metadata flag.
- [changed] Eliminated superfluous update events for locally cached documents
that are known to lag behind the server version. Instead, we buffer these
events until the client has caught up with the server.
# 0.7.2
- [fixed] Fixed a regression that prevented use of Firestore on ReactNative's
Expo platform (#1138).
# 0.7.0
- [fixed] Fixed `get({source: 'cache'})` to be able to return nonexistent
documents from cache.
- [changed] Prepared the persistence layer to allow shared access from multiple
tabs. While this feature is not yet available, all schema changes are included
in this release. Once you upgrade, you will not be able to use an older version
of the Firestore SDK with persistence enabled.
- [fixed] Fixed an issue where changes to custom authentication claims did not
take effect until you did a full sign-out and sign-in.
(firebase/firebase-ios-sdk#1499)
# 0.6.1
- [changed] Improved how Firestore handles idle queries to reduce the cost of
re-listening within 30 minutes.
- [changed] Improved offline performance with many outstanding writes.
# 0.6.0
- [fixed] Fixed an issue where queries returned fewer results than they should,
caused by documents that were cached as deleted when they should not have
been (firebase/firebase-ios-sdk#1548). Because some cache data is cleared,
clients might use extra bandwidth the first time they launch with this
version of the SDK.
- [feature] Added `firebase.firestore.FieldValue.arrayUnion()` and
`firebase.firestore.FieldValue.arrayRemove()` to atomically add and remove
elements from an array field in a document.
- [feature] Added `'array-contains'` query operator for use with `.where()` to
find documents where an array field contains a specific element.
# 0.5.0
- [changed] Merged the `includeQueryMetadataChanges` and
`includeDocumentMetadataChanges` options passed to `Query.onSnapshot()` into
a single `includeMetadataChanges` option.
- [changed] `QuerySnapshot.docChanges()` is now a method that optionally takes
an `includeMetadataChanges` option. By default, even when listening to a query
with `{ includeMetadataChanges:true }`, metadata-only document changes are
suppressed in `docChanges()`.
- [feature] Added new `{ mergeFields: (string|FieldPath)[] }` option to `set()`
which allows merging of a reduced subset of fields.
# 0.4.1
- [fixed] Fixed a regression in Firebase JS release 4.13.0 regarding the
loading of proto files, causing Node.JS support to break.
# 0.4.0
- [feature] Added a new `Timestamp` class to represent timestamp fields,
currently supporting up to microsecond precision. It can be passed to API
methods anywhere a JS Date object is currently accepted. To make
`DocumentSnapshot`s read timestamp fields back as `Timestamp`s instead of
Dates, you can set the newly added flag `timestampsInSnapshots` in
`FirestoreSettings` to `true`. Note that the current behavior
(`DocumentSnapshot`s returning JS Date objects) will be removed in a future
release. `Timestamp` supports higher precision than JS Date.
- [feature] Added ability to control whether DocumentReference.get() and
Query.get() should fetch from server only, (by passing { source: 'server' }),
cache only (by passing { source: 'cache' }), or attempt server and fall back
to the cache (which was the only option previously, and is now the default).
# 0.3.7
- [fixed] Fixed a regression in the Firebase JS release 4.11.0 that could
cause get() requests made while offline to be delayed by up to 10
seconds (rather than returning from cache immediately).
# 0.3.6
- [fixed] Fixed a regression in the Firebase JS release 4.11.0 that could
cause a crash if a user signs out while the client is offline, resulting in
an error of "Attempted to schedule multiple operations with timer id
listen_stream_connection_backoff".
# 0.3.5
- [changed] If the SDK's attempt to connect to the Cloud Firestore backend
neither succeeds nor fails within 10 seconds, the SDK will consider itself
"offline", causing get() calls to resolve with cached results, rather than
continuing to wait.
- [fixed] Fixed a potential race condition after calling `enableNetwork()` that
could result in a "Mutation batchIDs must be acknowledged in order" assertion
crash.
# 0.3.2
- [fixed] Fixed a regression in Firebase JS release 4.9.0 that could in certain
cases result in an "OnlineState should not affect limbo documents." assertion
crash when the client loses its network connection.
# 0.3.1
- [changed] Snapshot listeners (with the `includeMetadataChanges` option
enabled) now receive an event with `snapshot.metadata.fromCache` set to
`true` if the SDK loses its connection to the backend. A new event with
`snapshot.metadata.fromCache` set to false will be raised once the
connection is restored and the query is in sync with the backend again.
- [feature] Added `SnapshotOptions` API to control how DocumentSnapshots
return unresolved server timestamps.
- [feature] Added `disableNetwork()` and `enableNetwork()` methods to
`Firestore` class, allowing for explicit network management.
- [changed] For non-existing documents, `DocumentSnapshot.data()` now returns
`undefined` instead of throwing an exception. A new
`QueryDocumentSnapshot` class is introduced for Queries to reduce the number
of undefined-checks in your code.
- [added] Added `isEqual` API to `GeoPoint`, `Blob`, `SnapshotMetadata`,
`DocumentSnapshot`, `QuerySnapshot`, `CollectionReference`, `FieldValue`
and `FieldPath`.
- [changed] A "Could not reach Firestore backend." message will be
logged when the initial connection to the Firestore backend fails.
- [changed] A "Using maximum backoff delay to prevent overloading the
backend." message will be logged when we get a resource-exhausted
error from the backend.
# v0.2.1
- [feature] Added Node.js support for Cloud Firestore (with the exception of
the offline persistence feature).
- [changed] Webchannel requests use $httpHeaders URL parameter rather than
normal HTTP headers to avoid an extra CORS preflight request when initiating
streams / RPCs.
# v0.1.4
- [changed] Network streams are automatically closed after 60 seconds of
idleness.
- [changed] We no longer log 'RPC failed' messages for expected failures.
# v0.1.2
- [changed] We now support `FieldValue.delete()` sentinels in `set()` calls
with `{merge:true}`.
- [fixed] Fixed validation of nested arrays to allow indirect nesting
# v0.1.1
- [fixed] Fixed an issue causing exceptions when trying to use
`firebase.firestore.FieldPath.documentId()` in an `orderBy()` or `where()`
clause in a query.
# v0.1.0
- Initial public release.

47
node_modules/@firebase/firestore/README.md generated vendored Normal file
View File

@@ -0,0 +1,47 @@
# @firebase/firestore
This is the [Cloud Firestore](https://firebase.google.com/docs/firestore/) component of the
[Firebase JS SDK](https://www.npmjs.com/package/firebase).
**This package is not intended for direct usage, and should only be used via the officially
supported [firebase](https://www.npmjs.com/package/firebase) package.**
If you are developing a Node.js application that requires administrative access to Cloud Firestore,
use the [`@google-cloud/firestore`](https://www.npmjs.com/package/@google-cloud/firestore) Server
SDK with your developer credentials.
## Usage
You can then use the firebase namespace exposed by this package as illustrated
below:
**ES Modules**
```javascript
import firebase from '@firebase/app';
import '@firebase/firestore'
// Do stuff w/ `firebase` and `firebase.firestore`
```
**CommonJS Modules**
```javascript
const firebase = require('@firebase/app').default;
require('@firebase/firestore');
// Do stuff with `firebase` and `firebase.firestore`
```
## Documentation
For comprehensive documentation please see the [Firebase Reference
Docs][reference-docs].
[reference-docs]: https://firebase.google.com/docs/reference/js/
## Contributing
See [Contributing to the Firebase SDK](../../CONTRIBUTING.md) for general
information about contributing to the firebase-js-sdk repo and
[Contributing to the Cloud Firestore Component](./CONTRIBUTING.md) for
details specific to the Cloud Firestore code and tests.

22486
node_modules/@firebase/firestore/dist/index.cjs.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

44
node_modules/@firebase/firestore/dist/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,44 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { FirebaseNamespace } from '@firebase/app-types';
import './src/platform_browser/browser_init';
import * as types from '@firebase/firestore-types';
export declare function registerFirestore(instance: FirebaseNamespace): void;
declare module '@firebase/app-types' {
interface FirebaseNamespace {
firestore?: {
(app?: FirebaseApp): types.FirebaseFirestore;
Blob: typeof types.Blob;
CollectionReference: typeof types.CollectionReference;
DocumentReference: typeof types.DocumentReference;
DocumentSnapshot: typeof types.DocumentSnapshot;
FieldPath: typeof types.FieldPath;
FieldValue: typeof types.FieldValue;
Firestore: typeof types.FirebaseFirestore;
GeoPoint: typeof types.GeoPoint;
Query: typeof types.Query;
QuerySnapshot: typeof types.QuerySnapshot;
Timestamp: typeof types.Timestamp;
Transaction: typeof types.Transaction;
WriteBatch: typeof types.WriteBatch;
setLogLevel: typeof types.setLogLevel;
};
}
interface FirebaseApp {
firestore?(): types.FirebaseFirestore;
}
}

22480
node_modules/@firebase/firestore/dist/index.esm.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

20818
node_modules/@firebase/firestore/dist/index.esm2017.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

22351
node_modules/@firebase/firestore/dist/index.node.cjs.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

44
node_modules/@firebase/firestore/dist/index.node.d.ts generated vendored Normal file
View File

@@ -0,0 +1,44 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { FirebaseNamespace } from '@firebase/app-types';
import * as types from '@firebase/firestore-types';
import './src/platform_node/node_init';
export declare function registerFirestore(instance: FirebaseNamespace): void;
declare module '@firebase/app-types' {
interface FirebaseNamespace {
firestore?: {
(app?: FirebaseApp): types.FirebaseFirestore;
Blob: typeof types.Blob;
CollectionReference: typeof types.CollectionReference;
DocumentReference: typeof types.DocumentReference;
DocumentSnapshot: typeof types.DocumentSnapshot;
FieldPath: typeof types.FieldPath;
FieldValue: typeof types.FieldValue;
Firestore: typeof types.FirebaseFirestore;
GeoPoint: typeof types.GeoPoint;
Query: typeof types.Query;
QuerySnapshot: typeof types.QuerySnapshot;
Timestamp: typeof types.Timestamp;
Transaction: typeof types.Transaction;
WriteBatch: typeof types.WriteBatch;
setLogLevel: typeof types.setLogLevel;
};
}
interface FirebaseApp {
firestore?(): types.FirebaseFirestore;
}
}

View File

@@ -0,0 +1,39 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
/**
* Immutable class holding a blob (binary data).
* This class is directly exposed in the public API.
*
* Note that while you can't hide the constructor in JavaScript code, we are
* using the hack above to make sure no-one outside this module can call it.
*/
export declare class Blob {
private _binaryString;
private constructor();
static fromBase64String(base64: string): Blob;
static fromUint8Array(array: Uint8Array): Blob;
toBase64(): string;
toUint8Array(): Uint8Array;
toString(): string;
isEqual(other: Blob): boolean;
/**
* Actually private to JS consumers of our API, so this function is prefixed
* with an underscore.
*/
_compareTo(other: Blob): number;
}
export declare const PublicBlob: typeof Blob;

View File

@@ -0,0 +1,147 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { FirebaseApp } from '@firebase/app-types';
import { User } from '../auth/user';
export interface FirstPartyCredentialsSettings {
type: 'gapi';
client: unknown;
sessionIndex: string;
}
export interface ProviderCredentialsSettings {
type: 'provider';
client: CredentialsProvider;
}
/** Settings for private credentials */
export declare type CredentialsSettings = FirstPartyCredentialsSettings | ProviderCredentialsSettings;
export declare type TokenType = 'OAuth' | 'FirstParty';
export interface Token {
/** Type of token. */
type: TokenType;
/**
* The user with which the token is associated (used for persisting user
* state on disk, etc.).
*/
user: User;
/** Extra header values to be passed along with a request */
authHeaders: {
[header: string]: string;
};
}
export declare class OAuthToken implements Token {
user: User;
type: TokenType;
authHeaders: {
[header: string]: string;
};
constructor(value: string, user: User);
}
/**
* A Listener for credential change events. The listener should fetch a new
* token and may need to invalidate other state if the current user has also
* changed.
*/
export declare type CredentialChangeListener = (user: User) => void;
/**
* Provides methods for getting the uid and token for the current user and
* listening for changes.
*/
export interface CredentialsProvider {
/** Requests a token for the current user. */
getToken(): Promise<Token | null>;
/**
* Marks the last retrieved token as invalid, making the next GetToken request
* force-refresh the token.
*/
invalidateToken(): void;
/**
* Specifies a listener to be notified of credential changes
* (sign-in / sign-out, token changes). It is immediately called once with the
* initial user.
*/
setChangeListener(changeListener: CredentialChangeListener): void;
/** Removes the previously-set change listener. */
removeChangeListener(): void;
}
/** A CredentialsProvider that always yields an empty token. */
export declare class EmptyCredentialsProvider implements CredentialsProvider {
/**
* Stores the listener registered with setChangeListener()
* This isn't actually necessary since the UID never changes, but we use this
* to verify the listen contract is adhered to in tests.
*/
private changeListener;
getToken(): Promise<Token | null>;
invalidateToken(): void;
setChangeListener(changeListener: CredentialChangeListener): void;
removeChangeListener(): void;
}
export declare class FirebaseCredentialsProvider implements CredentialsProvider {
private readonly app;
/**
* The auth token listener registered with FirebaseApp, retained here so we
* can unregister it.
*/
private tokenListener;
/** Tracks the current User. */
private currentUser;
/**
* Counter used to detect if the token changed while a getToken request was
* outstanding.
*/
private tokenCounter;
/** The listener registered with setChangeListener(). */
private changeListener;
private forceRefresh;
constructor(app: FirebaseApp);
getToken(): Promise<Token | null>;
invalidateToken(): void;
setChangeListener(changeListener: CredentialChangeListener): void;
removeChangeListener(): void;
private getUser;
}
interface Gapi {
auth: {
getAuthHeaderValueForFirstParty: (userIdentifiers: Array<{
[key: string]: string;
}>) => string | null;
};
}
export declare class FirstPartyToken implements Token {
private gapi;
private sessionIndex;
type: TokenType;
user: User;
constructor(gapi: Gapi, sessionIndex: string);
readonly authHeaders: {
[header: string]: string;
};
}
export declare class FirstPartyCredentialsProvider implements CredentialsProvider {
private gapi;
private sessionIndex;
constructor(gapi: Gapi, sessionIndex: string);
getToken(): Promise<Token | null>;
setChangeListener(changeListener: CredentialChangeListener): void;
removeChangeListener(): void;
invalidateToken(): void;
}
/**
* Builds a CredentialsProvider depending on the type of
* the credentials passed in.
*/
export declare function makeCredentialsProvider(credentials?: CredentialsSettings): CredentialsProvider;
export {};

View File

@@ -0,0 +1,255 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import * as firestore from '@firebase/firestore-types';
import { FirebaseApp } from '@firebase/app-types';
import { FirebaseService } from '@firebase/app-types/private';
import { DatabaseId } from '../core/database_info';
import { FirestoreClient } from '../core/firestore_client';
import { Query as InternalQuery } from '../core/query';
import { Transaction as InternalTransaction } from '../core/transaction';
import { ViewSnapshot } from '../core/view_snapshot';
import { Document } from '../model/document';
import { DocumentKey } from '../model/document_key';
import { ResourcePath } from '../model/path';
import { AsyncQueue } from '../util/async_queue';
import { FieldPath as ExternalFieldPath } from './field_path';
import { CompleteFn, ErrorFn, NextFn, PartialObserver, Unsubscribe } from './observer';
import { UserDataConverter } from './user_data_converter';
/**
* Constant used to indicate the LRU garbage collection should be disabled.
* Set this value as the `cacheSizeBytes` on the settings passed to the
* `Firestore` instance.
*/
export declare const CACHE_SIZE_UNLIMITED = -1;
/**
* Options that can be provided in the Firestore constructor when not using
* Firebase (aka standalone mode).
*/
export interface FirestoreDatabase {
projectId: string;
database?: string;
}
/**
* The root reference to the database.
*/
export declare class Firestore implements firestore.FirebaseFirestore, FirebaseService {
readonly _databaseId: DatabaseId;
private readonly _persistenceKey;
private _credentials;
private readonly _firebaseApp;
private _settings;
private _firestoreClient;
readonly _queue: AsyncQueue;
readonly _dataConverter: UserDataConverter;
constructor(databaseIdOrApp: FirestoreDatabase | FirebaseApp);
settings(settingsLiteral: firestore.Settings): void;
enableNetwork(): Promise<void>;
disableNetwork(): Promise<void>;
enablePersistence(settings?: firestore.PersistenceSettings): Promise<void>;
clearPersistence(): Promise<void>;
terminate(): Promise<void>;
readonly _isTerminated: boolean;
waitForPendingWrites(): Promise<void>;
ensureClientConfigured(): FirestoreClient;
private makeDatabaseInfo;
private configureClient;
private createDataConverter;
private static databaseIdFromApp;
readonly app: FirebaseApp;
INTERNAL: {
delete: () => Promise<void>;
};
collection(pathString: string): firestore.CollectionReference;
doc(pathString: string): firestore.DocumentReference;
collectionGroup(collectionId: string): firestore.Query;
runTransaction<T>(updateFunction: (transaction: firestore.Transaction) => Promise<T>): Promise<T>;
batch(): firestore.WriteBatch;
static readonly logLevel: firestore.LogLevel;
static setLogLevel(level: firestore.LogLevel): void;
_areTimestampsInSnapshotsEnabled(): boolean;
}
/**
* A reference to a transaction.
*/
export declare class Transaction implements firestore.Transaction {
private _firestore;
private _transaction;
constructor(_firestore: Firestore, _transaction: InternalTransaction);
get(documentRef: firestore.DocumentReference): Promise<firestore.DocumentSnapshot>;
set(documentRef: firestore.DocumentReference, value: firestore.DocumentData, options?: firestore.SetOptions): Transaction;
update(documentRef: firestore.DocumentReference, value: firestore.UpdateData): Transaction;
update(documentRef: firestore.DocumentReference, field: string | ExternalFieldPath, value: unknown, ...moreFieldsAndValues: unknown[]): Transaction;
delete(documentRef: firestore.DocumentReference): Transaction;
}
export declare class WriteBatch implements firestore.WriteBatch {
private _firestore;
private _mutations;
private _committed;
constructor(_firestore: Firestore);
set(documentRef: firestore.DocumentReference, value: firestore.DocumentData, options?: firestore.SetOptions): WriteBatch;
update(documentRef: firestore.DocumentReference, value: firestore.UpdateData): WriteBatch;
update(documentRef: firestore.DocumentReference, field: string | ExternalFieldPath, value: unknown, ...moreFieldsAndValues: unknown[]): WriteBatch;
delete(documentRef: firestore.DocumentReference): WriteBatch;
commit(): Promise<void>;
private verifyNotCommitted;
}
/**
* A reference to a particular document in a collection in the database.
*/
export declare class DocumentReference implements firestore.DocumentReference {
_key: DocumentKey;
readonly firestore: Firestore;
private _firestoreClient;
constructor(_key: DocumentKey, firestore: Firestore);
static forPath(path: ResourcePath, firestore: Firestore): DocumentReference;
readonly id: string;
readonly parent: firestore.CollectionReference;
readonly path: string;
collection(pathString: string): firestore.CollectionReference;
isEqual(other: firestore.DocumentReference): boolean;
set(value: firestore.DocumentData, options?: firestore.SetOptions): Promise<void>;
update(value: firestore.UpdateData): Promise<void>;
update(field: string | ExternalFieldPath, value: unknown, ...moreFieldsAndValues: unknown[]): Promise<void>;
delete(): Promise<void>;
onSnapshot(observer: PartialObserver<firestore.DocumentSnapshot>): Unsubscribe;
onSnapshot(options: firestore.SnapshotListenOptions, observer: PartialObserver<firestore.DocumentSnapshot>): Unsubscribe;
onSnapshot(onNext: NextFn<firestore.DocumentSnapshot>, onError?: ErrorFn, onCompletion?: CompleteFn): Unsubscribe;
onSnapshot(options: firestore.SnapshotListenOptions, onNext: NextFn<firestore.DocumentSnapshot>, onError?: ErrorFn, onCompletion?: CompleteFn): Unsubscribe;
private onSnapshotInternal;
get(options?: firestore.GetOptions): Promise<firestore.DocumentSnapshot>;
private getViaSnapshotListener;
}
/**
* Options interface that can be provided to configure the deserialization of
* DocumentSnapshots.
*/
export interface SnapshotOptions extends firestore.SnapshotOptions {
}
export declare class DocumentSnapshot implements firestore.DocumentSnapshot {
private _firestore;
private _key;
_document: Document | null;
private _fromCache;
private _hasPendingWrites;
constructor(_firestore: Firestore, _key: DocumentKey, _document: Document | null, _fromCache: boolean, _hasPendingWrites: boolean);
data(options?: firestore.SnapshotOptions): firestore.DocumentData | undefined;
get(fieldPath: string | ExternalFieldPath, options?: firestore.SnapshotOptions): unknown;
readonly id: string;
readonly ref: firestore.DocumentReference;
readonly exists: boolean;
readonly metadata: firestore.SnapshotMetadata;
isEqual(other: firestore.DocumentSnapshot): boolean;
private convertObject;
private convertValue;
private convertArray;
}
export declare class QueryDocumentSnapshot extends DocumentSnapshot implements firestore.QueryDocumentSnapshot {
data(options?: SnapshotOptions): firestore.DocumentData;
}
export declare class Query implements firestore.Query {
_query: InternalQuery;
readonly firestore: Firestore;
constructor(_query: InternalQuery, firestore: Firestore);
where(field: string | ExternalFieldPath, opStr: firestore.WhereFilterOp, value: unknown): firestore.Query;
orderBy(field: string | ExternalFieldPath, directionStr?: firestore.OrderByDirection): firestore.Query;
limit(n: number): firestore.Query;
startAt(docOrField: unknown | firestore.DocumentSnapshot, ...fields: unknown[]): firestore.Query;
startAfter(docOrField: unknown | firestore.DocumentSnapshot, ...fields: unknown[]): firestore.Query;
endBefore(docOrField: unknown | firestore.DocumentSnapshot, ...fields: unknown[]): firestore.Query;
endAt(docOrField: unknown | firestore.DocumentSnapshot, ...fields: unknown[]): firestore.Query;
isEqual(other: firestore.Query): boolean;
/** Helper function to create a bound from a document or fields */
private boundFromDocOrFields;
/**
* Create a Bound from a query and a document.
*
* Note that the Bound will always include the key of the document
* and so only the provided document will compare equal to the returned
* position.
*
* Will throw if the document does not contain all fields of the order by
* of the query or if any of the fields in the order by are an uncommitted
* server timestamp.
*/
private boundFromDocument;
/**
* Converts a list of field values to a Bound for the given query.
*/
private boundFromFields;
onSnapshot(observer: PartialObserver<firestore.QuerySnapshot>): Unsubscribe;
onSnapshot(options: firestore.SnapshotListenOptions, observer: PartialObserver<firestore.QuerySnapshot>): Unsubscribe;
onSnapshot(onNext: NextFn<firestore.QuerySnapshot>, onError?: ErrorFn, onCompletion?: CompleteFn): Unsubscribe;
onSnapshot(options: firestore.SnapshotListenOptions, onNext: NextFn<firestore.QuerySnapshot>, onError?: ErrorFn, onCompletion?: CompleteFn): Unsubscribe;
private onSnapshotInternal;
get(options?: firestore.GetOptions): Promise<firestore.QuerySnapshot>;
private getViaSnapshotListener;
/**
* Parses the given documentIdValue into a ReferenceValue, throwing
* appropriate errors if the value is anything other than a DocumentReference
* or String, or if the string is malformed.
*/
private parseDocumentIdValue;
/**
* Validates that the value passed into a disjunctrive filter satisfies all
* array requirements.
*/
private validateDisjunctiveFilterElements;
private validateNewFilter;
private validateNewOrderBy;
private validateOrderByAndInequalityMatch;
}
export declare class QuerySnapshot implements firestore.QuerySnapshot {
private _firestore;
private _originalQuery;
private _snapshot;
private _cachedChanges;
private _cachedChangesIncludeMetadataChanges;
readonly metadata: firestore.SnapshotMetadata;
constructor(_firestore: Firestore, _originalQuery: InternalQuery, _snapshot: ViewSnapshot);
readonly docs: firestore.QueryDocumentSnapshot[];
readonly empty: boolean;
readonly size: number;
forEach(callback: (result: firestore.QueryDocumentSnapshot) => void, thisArg?: unknown): void;
readonly query: firestore.Query;
docChanges(options?: firestore.SnapshotListenOptions): firestore.DocumentChange[];
/** Check the equality. The call can be very expensive. */
isEqual(other: firestore.QuerySnapshot): boolean;
private convertToDocumentImpl;
}
export declare class CollectionReference extends Query implements firestore.CollectionReference {
constructor(path: ResourcePath, firestore: Firestore);
readonly id: string;
readonly parent: firestore.DocumentReference | null;
readonly path: string;
doc(pathString?: string): firestore.DocumentReference;
add(value: firestore.DocumentData): Promise<firestore.DocumentReference>;
}
/**
* Calculates the array of firestore.DocumentChange's for a given ViewSnapshot.
*
* Exported for testing.
*/
export declare function changesFromSnapshot(firestore: Firestore, includeMetadataChanges: boolean, snapshot: ViewSnapshot): firestore.DocumentChange[];
export declare const PublicFirestore: typeof Firestore;
export declare const PublicTransaction: typeof Transaction;
export declare const PublicWriteBatch: typeof WriteBatch;
export declare const PublicDocumentReference: typeof DocumentReference;
export declare const PublicDocumentSnapshot: typeof DocumentSnapshot;
export declare const PublicQueryDocumentSnapshot: typeof QueryDocumentSnapshot;
export declare const PublicQuery: typeof Query;
export declare const PublicQuerySnapshot: typeof QuerySnapshot;
export declare const PublicCollectionReference: typeof CollectionReference;

View File

@@ -0,0 +1,47 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import * as firestore from '@firebase/firestore-types';
import { FieldPath as InternalFieldPath } from '../model/path';
/**
* A FieldPath refers to a field in a document. The path may consist of a single
* field name (referring to a top-level field in the document), or a list of
* field names (referring to a nested field in the document).
*/
export declare class FieldPath implements firestore.FieldPath {
/** Internal representation of a Firestore field path. */
_internalPath: InternalFieldPath;
/**
* Creates a FieldPath from the provided field names. If more than one field
* name is provided, the path will point to a nested field in a document.
*
* @param fieldNames A list of field names.
*/
constructor(...fieldNames: string[]);
/**
* Internal Note: The backend doesn't technically support querying by
* document ID. Instead it queries by the entire document name (full path
* included), but in the cases we currently support documentId(), the net
* effect is the same.
*/
private static readonly _DOCUMENT_ID;
static documentId(): FieldPath;
isEqual(other: firestore.FieldPath): boolean;
}
/**
* Parses a field path string into a FieldPath, treating dots as separators.
*/
export declare function fromDotSeparatedString(path: string): FieldPath;

View File

@@ -0,0 +1,54 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import * as firestore from '@firebase/firestore-types';
/**
* An opaque base class for FieldValue sentinel objects in our public API,
* with public static methods for creating said sentinel objects.
*/
export declare abstract class FieldValueImpl implements firestore.FieldValue {
readonly _methodName: string;
protected constructor(_methodName: string);
static delete(): FieldValueImpl;
static serverTimestamp(): FieldValueImpl;
static arrayUnion(...elements: unknown[]): FieldValueImpl;
static arrayRemove(...elements: unknown[]): FieldValueImpl;
static increment(n: number): FieldValueImpl;
isEqual(other: FieldValueImpl): boolean;
}
export declare class DeleteFieldValueImpl extends FieldValueImpl {
private constructor();
/** Singleton instance. */
static instance: DeleteFieldValueImpl;
}
export declare class ServerTimestampFieldValueImpl extends FieldValueImpl {
private constructor();
/** Singleton instance. */
static instance: ServerTimestampFieldValueImpl;
}
export declare class ArrayUnionFieldValueImpl extends FieldValueImpl {
readonly _elements: unknown[];
constructor(_elements: unknown[]);
}
export declare class ArrayRemoveFieldValueImpl extends FieldValueImpl {
readonly _elements: unknown[];
constructor(_elements: unknown[]);
}
export declare class NumericIncrementFieldValueImpl extends FieldValueImpl {
readonly _operand: number;
constructor(_operand: number);
}
export declare const PublicFieldValue: typeof FieldValueImpl;

View File

@@ -0,0 +1,39 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
/**
* Immutable class representing a geo point as latitude-longitude pair.
* This class is directly exposed in the public API, including its constructor.
*/
export declare class GeoPoint {
private _lat;
private _long;
constructor(latitude: number, longitude: number);
/**
* Returns the latitude of this geo point, a number between -90 and 90.
*/
readonly latitude: number;
/**
* Returns the longitude of this geo point, a number between -180 and 180.
*/
readonly longitude: number;
isEqual(other: GeoPoint): boolean;
/**
* Actually private to JS consumers of our API, so this function is prefixed
* with an underscore.
*/
_compareTo(other: GeoPoint): number;
}

View File

@@ -0,0 +1,31 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
/**
* Observer/Subscribe interfaces.
*/
export declare type NextFn<T> = (value: T) => void;
export declare type ErrorFn = (error: Error) => void;
export declare type CompleteFn = () => void;
export interface PartialObserver<T> {
next?: NextFn<T>;
error?: ErrorFn;
complete?: CompleteFn;
}
export interface Unsubscribe {
(): void;
}
export declare function isPartialObserver(obj: unknown): boolean;

View File

@@ -0,0 +1,29 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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 declare class Timestamp {
readonly seconds: number;
readonly nanoseconds: number;
static now(): Timestamp;
static fromDate(date: Date): Timestamp;
static fromMillis(milliseconds: number): Timestamp;
constructor(seconds: number, nanoseconds: number);
toDate(): Date;
toMillis(): number;
_compareTo(other: Timestamp): number;
isEqual(other: Timestamp): boolean;
toString(): string;
}

View File

@@ -0,0 +1,114 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import * as firestore from '@firebase/firestore-types';
import { DatabaseId } from '../core/database_info';
import { DocumentKey } from '../model/document_key';
import { FieldValue, ObjectValue } from '../model/field_value';
import { FieldMask, FieldTransform, Mutation, Precondition } from '../model/mutation';
import { FieldPath } from '../model/path';
import { FieldPath as ExternalFieldPath } from './field_path';
/** The result of parsing document data (e.g. for a setData call). */
export declare class ParsedSetData {
readonly data: ObjectValue;
readonly fieldMask: FieldMask | null;
readonly fieldTransforms: FieldTransform[];
constructor(data: ObjectValue, fieldMask: FieldMask | null, fieldTransforms: FieldTransform[]);
toMutations(key: DocumentKey, precondition: Precondition): Mutation[];
}
/** The result of parsing "update" data (i.e. for an updateData call). */
export declare class ParsedUpdateData {
readonly data: ObjectValue;
readonly fieldMask: FieldMask;
readonly fieldTransforms: FieldTransform[];
constructor(data: ObjectValue, fieldMask: FieldMask, fieldTransforms: FieldTransform[]);
toMutations(key: DocumentKey, precondition: Precondition): Mutation[];
}
/**
* An interface that allows arbitrary pre-converting of user data. This
* abstraction allows for, e.g.:
* * The public API to convert DocumentReference objects to DocRef objects,
* avoiding a circular dependency between user_data_converter.ts and
* database.ts
* * Tests to convert test-only sentinels (e.g. '<DELETE>') into types
* compatible with UserDataConverter.
*
* Returns the converted value (can return back the input to act as a no-op).
*
* It can also throw an Error which will be wrapped into a friendly message.
*/
export declare type DataPreConverter = (input: unknown) => unknown;
/**
* A placeholder object for DocumentReferences in this file, in order to
* avoid a circular dependency. See the comments for `DataPreConverter` for
* the full context.
*/
export declare class DocumentKeyReference {
databaseId: DatabaseId;
key: DocumentKey;
constructor(databaseId: DatabaseId, key: DocumentKey);
}
/**
* Helper for parsing raw user input (provided via the API) into internal model
* classes.
*/
export declare class UserDataConverter {
private preConverter;
constructor(preConverter: DataPreConverter);
/** Parse document data from a non-merge set() call. */
parseSetData(methodName: string, input: unknown): ParsedSetData;
/** Parse document data from a set() call with '{merge:true}'. */
parseMergeData(methodName: string, input: unknown, fieldPaths?: Array<string | firestore.FieldPath>): ParsedSetData;
/** Parse update data from an update() call. */
parseUpdateData(methodName: string, input: unknown): ParsedUpdateData;
/** Parse update data from a list of field/value arguments. */
parseUpdateVarargs(methodName: string, field: string | ExternalFieldPath, value: unknown, moreFieldsAndValues: unknown[]): ParsedUpdateData;
/**
* Parse a "query value" (e.g. value in a where filter or a value in a cursor
* bound).
*/
parseQueryValue(methodName: string, input: unknown): FieldValue;
/** Sends data through this.preConverter, handling any thrown errors. */
private runPreConverter;
/**
* Internal helper for parsing user data.
*
* @param input Data to be parsed.
* @param context A context object representing the current path being parsed,
* the source of the data being parsed, etc.
* @return The parsed value, or null if the value was a FieldValue sentinel
* that should not be included in the resulting parsed data.
*/
private parseData;
private parseObject;
private parseArray;
/**
* "Parses" the provided FieldValueImpl, adding any necessary transforms to
* context.fieldTransforms.
*/
private parseSentinelFieldValue;
/**
* Helper to parse a scalar value (i.e. not an Object, Array, or FieldValue)
*
* @return The parsed value
*/
private parseScalarValue;
private parseArrayTransformElements;
}
/**
* Helper that calls fromDotSeparatedString() but wraps any error thrown.
*/
export declare function fieldPathFromArgument(methodName: string, path: string | ExternalFieldPath): FieldPath;

View File

@@ -0,0 +1,35 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
/**
* Simple wrapper around a nullable UID. Mostly exists to make code more
* readable.
*/
export declare class User {
readonly uid: string | null;
/** A user with a null UID. */
static readonly UNAUTHENTICATED: User;
static readonly GOOGLE_CREDENTIALS: User;
static readonly FIRST_PARTY: User;
constructor(uid: string | null);
isAuthenticated(): boolean;
/**
* Returns a key representing this user, suitable for inclusion in a
* dictionary.
*/
toKey(): string;
isEqual(otherUser: User): boolean;
}

View File

@@ -0,0 +1,45 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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 declare class DatabaseInfo {
readonly databaseId: DatabaseId;
readonly persistenceKey: string;
readonly host: string;
readonly ssl: boolean;
readonly forceLongPolling: boolean;
/**
* Constructs a DatabaseInfo using the provided host, databaseId and
* persistenceKey.
*
* @param databaseId The database to use.
* @param persistenceKey A unique identifier for this Firestore's local
* storage (used in conjunction with the databaseId).
* @param host The Firestore backend host to connect to.
* @param ssl Whether to use SSL when connecting.
* @param forceLongPolling Whether to use the forceLongPolling option
* when using WebChannel as the network transport.
*/
constructor(databaseId: DatabaseId, persistenceKey: string, host: string, ssl: boolean, forceLongPolling: boolean);
}
/** Represents the database ID a Firestore client is associated with. */
export declare class DatabaseId {
readonly projectId: string;
readonly database: string;
constructor(projectId: string, database?: string);
readonly isDefaultDatabase: boolean;
isEqual(other: {}): boolean;
compareTo(other: DatabaseId): number;
}

View File

@@ -0,0 +1,78 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { EventHandler } from '../util/misc';
import { Query } from './query';
import { SyncEngine, SyncEngineListener } from './sync_engine';
import { OnlineState, TargetId } from './types';
import { ViewSnapshot } from './view_snapshot';
/**
* Interface for handling events from the EventManager.
*/
export interface Observer<T> {
next: EventHandler<T>;
error: EventHandler<Error>;
}
/**
* EventManager is responsible for mapping queries to query event emitters.
* It handles "fan-out". -- Identical queries will re-use the same watch on the
* backend.
*/
export declare class EventManager implements SyncEngineListener {
private syncEngine;
private queries;
private onlineState;
constructor(syncEngine: SyncEngine);
listen(listener: QueryListener): Promise<TargetId>;
unlisten(listener: QueryListener): Promise<void>;
onWatchChange(viewSnaps: ViewSnapshot[]): void;
onWatchError(query: Query, error: Error): void;
onOnlineStateChange(onlineState: OnlineState): void;
}
export interface ListenOptions {
/** Raise events even when only the metadata changes */
readonly includeMetadataChanges?: boolean;
/**
* Wait for a sync with the server when online, but still raise events while
* offline.
*/
readonly waitForSyncWhenOnline?: boolean;
}
/**
* QueryListener takes a series of internal view snapshots and determines
* when to raise the event.
*
* It uses an Observer to dispatch events.
*/
export declare class QueryListener {
readonly query: Query;
private queryObserver;
/**
* Initial snapshots (e.g. from cache) may not be propagated to the wrapped
* observer. This flag is set to true once we've actually raised an event.
*/
private raisedInitialEvent;
private options;
private snap;
private onlineState;
constructor(query: Query, queryObserver: Observer<ViewSnapshot>, options?: ListenOptions);
onViewSnapshot(snap: ViewSnapshot): void;
onError(error: Error): void;
applyOnlineStateChange(onlineState: OnlineState): void;
private shouldRaiseInitialEvent;
private shouldRaiseEvent;
private raiseInitialEvent;
}

View File

@@ -0,0 +1,176 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { CredentialsProvider } from '../api/credentials';
import { Document } from '../model/document';
import { DocumentKey } from '../model/document_key';
import { Mutation } from '../model/mutation';
import { Platform } from '../platform/platform';
import { AsyncQueue } from '../util/async_queue';
import { ListenOptions, Observer, QueryListener } from './event_manager';
import { LruParams } from '../local/lru_garbage_collector';
import { DatabaseId, DatabaseInfo } from './database_info';
import { Query } from './query';
import { Transaction } from './transaction';
import { ViewSnapshot } from './view_snapshot';
export declare class IndexedDbPersistenceSettings {
readonly cacheSizeBytes: number;
readonly synchronizeTabs: boolean;
constructor(cacheSizeBytes: number, synchronizeTabs: boolean);
lruParams(): LruParams;
}
export declare class MemoryPersistenceSettings {
}
export declare type InternalPersistenceSettings = IndexedDbPersistenceSettings | MemoryPersistenceSettings;
/**
* FirestoreClient is a top-level class that constructs and owns all of the
* pieces of the client SDK architecture. It is responsible for creating the
* async queue that is shared by all of the other components in the system.
*/
export declare class FirestoreClient {
private platform;
private databaseInfo;
private credentials;
/**
* Asynchronous queue responsible for all of our internal processing. When
* we get incoming work from the user (via public API) or the network
* (incoming GRPC messages), we should always schedule onto this queue.
* This ensures all of our work is properly serialized (e.g. we don't
* start processing a new operation while the previous one is waiting for
* an async I/O to complete).
*/
private asyncQueue;
private eventMgr;
private persistence;
private localStore;
private remoteStore;
private syncEngine;
private sharedClientState;
private lruScheduler?;
private readonly clientId;
constructor(platform: Platform, databaseInfo: DatabaseInfo, credentials: CredentialsProvider,
/**
* Asynchronous queue responsible for all of our internal processing. When
* we get incoming work from the user (via public API) or the network
* (incoming GRPC messages), we should always schedule onto this queue.
* This ensures all of our work is properly serialized (e.g. we don't
* start processing a new operation while the previous one is waiting for
* an async I/O to complete).
*/
asyncQueue: AsyncQueue);
/**
* Starts up the FirestoreClient, returning only whether or not enabling
* persistence succeeded.
*
* The intent here is to "do the right thing" as far as users are concerned.
* Namely, in cases where offline persistence is requested and possible,
* enable it, but otherwise fall back to persistence disabled. For the most
* part we expect this to succeed one way or the other so we don't expect our
* users to actually wait on the firestore.enablePersistence Promise since
* they generally won't care.
*
* Of course some users actually do care about whether or not persistence
* was successfully enabled, so the Promise returned from this method
* indicates this outcome.
*
* This presents a problem though: even before enablePersistence resolves or
* rejects, users may have made calls to e.g. firestore.collection() which
* means that the FirestoreClient in there will be available and will be
* enqueuing actions on the async queue.
*
* Meanwhile any failure of an operation on the async queue causes it to
* panic and reject any further work, on the premise that unhandled errors
* are fatal.
*
* Consequently the fallback is handled internally here in start, and if the
* fallback succeeds we signal success to the async queue even though the
* start() itself signals failure.
*
* @param persistenceSettings Settings object to configure offline
* persistence.
* @returns A deferred result indicating the user-visible result of enabling
* offline persistence. This method will reject this if IndexedDB fails to
* start for any reason. If usePersistence is false this is
* unconditionally resolved.
*/
start(persistenceSettings: InternalPersistenceSettings): Promise<void>;
/** Enables the network connection and requeues all pending operations. */
enableNetwork(): Promise<void>;
/**
* Initializes persistent storage, attempting to use IndexedDB if
* usePersistence is true or memory-only if false.
*
* If IndexedDB fails because it's already open in another tab or because the
* platform can't possibly support our implementation then this method rejects
* the persistenceResult and falls back on memory-only persistence.
*
* @param persistenceSettings Settings object to configure offline persistence
* @param persistenceResult A deferred result indicating the user-visible
* result of enabling offline persistence. This method will reject this if
* IndexedDB fails to start for any reason. If usePersistence is false
* this is unconditionally resolved.
* @returns a Promise indicating whether or not initialization should
* continue, i.e. that one of the persistence implementations actually
* succeeded.
*/
private initializePersistence;
/**
* Decides whether the provided error allows us to gracefully disable
* persistence (as opposed to crashing the client).
*/
private canFallback;
/**
* Checks that the client has not been terminated. Ensures that other methods on
* this class cannot be called after the client is terminated.
*/
private verifyNotTerminated;
/**
* Starts IndexedDB-based persistence.
*
* @returns A promise indicating success or failure.
*/
private startIndexedDbPersistence;
/**
* Starts Memory-backed persistence. In practice this cannot fail.
*
* @returns A promise that will successfully resolve.
*/
private startMemoryPersistence;
/**
* Initializes the rest of the FirestoreClient, assuming the initial user
* has been obtained from the credential provider and some persistence
* implementation is available in this.persistence.
*/
private initializeRest;
private handleCredentialChange;
/** Disables the network connection. Pending operations will not complete. */
disableNetwork(): Promise<void>;
terminate(): Promise<void>;
/**
* Returns a Promise that resolves when all writes that were pending at the time this
* method was called received server acknowledgement. An acknowledgement can be either acceptance
* or rejection.
*/
waitForPendingWrites(): Promise<void>;
listen(query: Query, observer: Observer<ViewSnapshot>, options: ListenOptions): QueryListener;
unlisten(listener: QueryListener): void;
getDocumentFromLocalCache(docKey: DocumentKey): Promise<Document | null>;
getDocumentsFromLocalCache(query: Query): Promise<ViewSnapshot>;
write(mutations: Mutation[]): Promise<void>;
databaseId(): DatabaseId;
readonly clientTerminated: boolean;
transaction<T>(updateFunction: (transaction: Transaction) => Promise<T>): Promise<T>;
}

View File

@@ -0,0 +1,39 @@
/**
* @license
* Copyright 2018 Google Inc.
*
* 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.
*/
import { ListenSequenceNumber } from './types';
/**
* `SequenceNumberSyncer` defines the methods required to keep multiple instances of a
* `ListenSequence` in sync.
*/
export interface SequenceNumberSyncer {
writeSequenceNumber(sequenceNumber: ListenSequenceNumber): void;
sequenceNumberHandler: ((sequenceNumber: ListenSequenceNumber) => void) | null;
}
/**
* `ListenSequence` is a monotonic sequence. It is initialized with a minimum value to
* exceed. All subsequent calls to next will return increasing values. If provided with a
* `SequenceNumberSyncer`, it will additionally bump its next value when told of a new value, as
* well as write out sequence numbers that it produces via `next()`.
*/
export declare class ListenSequence {
private previousValue;
static readonly INVALID: ListenSequenceNumber;
private writeNewSequenceNumber?;
constructor(previousValue: ListenSequenceNumber, sequenceNumberSyncer?: SequenceNumberSyncer);
private setPreviousValue;
next(): ListenSequenceNumber;
}

View File

@@ -0,0 +1,184 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { Document } from '../model/document';
import { ArrayValue, FieldValue } from '../model/field_value';
import { FieldPath, ResourcePath } from '../model/path';
export declare class Query {
readonly path: ResourcePath;
readonly collectionGroup: string | null;
readonly explicitOrderBy: OrderBy[];
readonly filters: Filter[];
readonly limit: number | null;
readonly startAt: Bound | null;
readonly endAt: Bound | null;
static atPath(path: ResourcePath): Query;
private memoizedCanonicalId;
private memoizedOrderBy;
/**
* Initializes a Query with a path and optional additional query constraints.
* Path must currently be empty if this is a collection group query.
*/
constructor(path: ResourcePath, collectionGroup?: string | null, explicitOrderBy?: OrderBy[], filters?: Filter[], limit?: number | null, startAt?: Bound | null, endAt?: Bound | null);
readonly orderBy: OrderBy[];
addFilter(filter: Filter): Query;
addOrderBy(orderBy: OrderBy): Query;
withLimit(limit: number | null): Query;
withStartAt(bound: Bound): Query;
withEndAt(bound: Bound): Query;
/**
* Helper to convert a collection group query into a collection query at a
* specific path. This is used when executing collection group queries, since
* we have to split the query into a set of collection queries at multiple
* paths.
*/
asCollectionQueryAtPath(path: ResourcePath): Query;
canonicalId(): string;
toString(): string;
isEqual(other: Query): boolean;
docComparator(d1: Document, d2: Document): number;
matches(doc: Document): boolean;
hasLimit(): boolean;
getFirstOrderByField(): FieldPath | null;
getInequalityFilterField(): FieldPath | null;
findFilterOperator(operators: Operator[]): Operator | null;
isDocumentQuery(): boolean;
isCollectionGroupQuery(): boolean;
private matchesPathAndCollectionGroup;
/**
* A document must have a value for every ordering clause in order to show up
* in the results.
*/
private matchesOrderBy;
private matchesFilters;
/**
* Makes sure a document is within the bounds, if provided.
*/
private matchesBounds;
private assertValidBound;
}
export declare abstract class Filter {
abstract matches(doc: Document): boolean;
abstract canonicalId(): string;
abstract isEqual(filter: Filter): boolean;
}
export declare class Operator {
name: string;
static LESS_THAN: Operator;
static LESS_THAN_OR_EQUAL: Operator;
static EQUAL: Operator;
static GREATER_THAN: Operator;
static GREATER_THAN_OR_EQUAL: Operator;
static ARRAY_CONTAINS: Operator;
static IN: Operator;
static ARRAY_CONTAINS_ANY: Operator;
static fromString(op: string): Operator;
constructor(name: string);
toString(): string;
isEqual(other: Operator): boolean;
}
export declare class FieldFilter extends Filter {
field: FieldPath;
op: Operator;
value: FieldValue;
protected constructor(field: FieldPath, op: Operator, value: FieldValue);
/**
* Creates a filter based on the provided arguments.
*/
static create(field: FieldPath, op: Operator, value: FieldValue): FieldFilter;
matches(doc: Document): boolean;
protected matchesComparison(comparison: number): boolean;
isInequality(): boolean;
canonicalId(): string;
isEqual(other: Filter): boolean;
toString(): string;
}
/** Filter that matches on key fields (i.e. '__name__'). */
export declare class KeyFieldFilter extends FieldFilter {
matches(doc: Document): boolean;
}
/** Filter that matches on key fields within an array. */
export declare class KeyFieldInFilter extends FieldFilter {
value: ArrayValue;
constructor(field: FieldPath, value: ArrayValue);
matches(doc: Document): boolean;
}
/** A Filter that implements the array-contains operator. */
export declare class ArrayContainsFilter extends FieldFilter {
constructor(field: FieldPath, value: FieldValue);
matches(doc: Document): boolean;
}
/** A Filter that implements the IN operator. */
export declare class InFilter extends FieldFilter {
value: ArrayValue;
constructor(field: FieldPath, value: ArrayValue);
matches(doc: Document): boolean;
}
/** A Filter that implements the array-contains-any operator. */
export declare class ArrayContainsAnyFilter extends FieldFilter {
value: ArrayValue;
constructor(field: FieldPath, value: ArrayValue);
matches(doc: Document): boolean;
}
/**
* The direction of sorting in an order by.
*/
export declare class Direction {
name: string;
static ASCENDING: Direction;
static DESCENDING: Direction;
private constructor();
toString(): string;
}
/**
* Represents a bound of a query.
*
* The bound is specified with the given components representing a position and
* whether it's just before or just after the position (relative to whatever the
* query order is).
*
* The position represents a logical index position for a query. It's a prefix
* of values for the (potentially implicit) order by clauses of a query.
*
* Bound provides a function to determine whether a document comes before or
* after a bound. This is influenced by whether the position is just before or
* just after the provided values.
*/
export declare class Bound {
readonly position: FieldValue[];
readonly before: boolean;
constructor(position: FieldValue[], before: boolean);
canonicalId(): string;
/**
* Returns true if a document sorts before a bound using the provided sort
* order.
*/
sortsBeforeDocument(orderBy: OrderBy[], doc: Document): boolean;
isEqual(other: Bound | null): boolean;
}
/**
* An ordering on a field, in some Direction. Direction defaults to ASCENDING.
*/
export declare class OrderBy {
readonly field: FieldPath;
readonly dir: Direction;
private readonly isKeyOrderBy;
constructor(field: FieldPath, dir?: Direction);
compare(d1: Document, d2: Document): number;
canonicalId(): string;
toString(): string;
isEqual(other: OrderBy): boolean;
}

View File

@@ -0,0 +1,35 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { Timestamp } from '../api/timestamp';
/**
* A version of a document in Firestore. This corresponds to the version
* timestamp, such as update_time or read_time.
*/
export declare class SnapshotVersion {
private timestamp;
static readonly MIN: SnapshotVersion;
static fromMicroseconds(value: number): SnapshotVersion;
static fromTimestamp(value: Timestamp): SnapshotVersion;
static forDeletedDoc(): SnapshotVersion;
private constructor();
compareTo(other: SnapshotVersion): number;
isEqual(other: SnapshotVersion): boolean;
/** Returns a number representation of the version for use in spec tests. */
toMicroseconds(): number;
toString(): string;
toTimestamp(): Timestamp;
}

View File

@@ -0,0 +1,181 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { User } from '../auth/user';
import { LocalStore } from '../local/local_store';
import { DocumentKeySet } from '../model/collections';
import { DocumentKey } from '../model/document_key';
import { Mutation } from '../model/mutation';
import { MutationBatchResult } from '../model/mutation_batch';
import { RemoteEvent } from '../remote/remote_event';
import { RemoteStore } from '../remote/remote_store';
import { RemoteSyncer } from '../remote/remote_syncer';
import { FirestoreError } from '../util/error';
import { Deferred } from '../util/promise';
import { SortedMap } from '../util/sorted_map';
import { ClientId, SharedClientState } from '../local/shared_client_state';
import { QueryTargetState, SharedClientStateSyncer } from '../local/shared_client_state_syncer';
import { Query } from './query';
import { Transaction } from './transaction';
import { BatchId, MutationBatchState, OnlineState, OnlineStateSource, TargetId } from './types';
import { ViewSnapshot } from './view_snapshot';
import { AsyncQueue } from '../util/async_queue';
/**
* Interface implemented by EventManager to handle notifications from
* SyncEngine.
*/
export interface SyncEngineListener {
/** Handles new view snapshots. */
onWatchChange(snapshots: ViewSnapshot[]): void;
/** Handles the failure of a query. */
onWatchError(query: Query, error: Error): void;
/** Handles a change in online state. */
onOnlineStateChange(onlineState: OnlineState): void;
}
/**
* SyncEngine is the central controller in the client SDK architecture. It is
* the glue code between the EventManager, LocalStore, and RemoteStore. Some of
* SyncEngine's responsibilities include:
* 1. Coordinating client requests and remote events between the EventManager
* and the local and remote data stores.
* 2. Managing a View object for each query, providing the unified view between
* the local and remote data stores.
* 3. Notifying the RemoteStore when the LocalStore has new mutations in its
* queue that need sending to the backend.
*
* The SyncEngines methods should only ever be called by methods running in the
* global async queue.
*/
export declare class SyncEngine implements RemoteSyncer, SharedClientStateSyncer {
private localStore;
private remoteStore;
private sharedClientState;
private currentUser;
private syncEngineListener;
private queryViewsByQuery;
private queryViewsByTarget;
private limboTargetsByKey;
private limboResolutionsByTarget;
private limboDocumentRefs;
/** Stores user completion handlers, indexed by User and BatchId. */
private mutationUserCallbacks;
/** Stores user callbacks waiting for all pending writes to be acknowledged. */
private pendingWritesCallbacks;
private limboTargetIdGenerator;
private isPrimary;
private onlineState;
constructor(localStore: LocalStore, remoteStore: RemoteStore, sharedClientState: SharedClientState, currentUser: User);
readonly isPrimaryClient: boolean;
/** Subscribes to SyncEngine notifications. Has to be called exactly once. */
subscribe(syncEngineListener: SyncEngineListener): void;
/**
* Initiates the new listen, resolves promise when listen enqueued to the
* server. All the subsequent view snapshots or errors are sent to the
* subscribed handlers. Returns the targetId of the query.
*/
listen(query: Query): Promise<TargetId>;
/**
* Registers a view for a previously unknown query and computes its initial
* snapshot.
*/
private initializeViewAndComputeSnapshot;
/**
* Reconcile the list of synced documents in an existing view with those
* from persistence.
*/
private synchronizeViewAndComputeSnapshot;
/** Stops listening to the query. */
unlisten(query: Query): Promise<void>;
/**
* Initiates the write of local mutation batch which involves adding the
* writes to the mutation queue, notifying the remote store about new
* mutations and raising events for any changes this write caused.
*
* The promise returned by this call is resolved when the above steps
* have completed, *not* when the write was acked by the backend. The
* userCallback is resolved once the write was acked/rejected by the
* backend (or failed locally for any other reason).
*/
write(batch: Mutation[], userCallback: Deferred<void>): Promise<void>;
/**
* Takes an updateFunction in which a set of reads and writes can be performed
* atomically. In the updateFunction, the client can read and write values
* using the supplied transaction object. After the updateFunction, all
* changes will be committed. If a retryable error occurs (ex: some other
* client has changed any of the data referenced), then the updateFunction
* will be called again after a backoff. If the updateFunction still fails
* after all retries, then the transaction will be rejected.
*
* The transaction object passed to the updateFunction contains methods for
* accessing documents and collections. Unlike other datastore access, data
* accessed with the transaction will not reflect local changes that have not
* been committed. For this reason, it is required that all reads are
* performed before any writes. Transactions must be performed while online.
*
* The Deferred input is resolved when the transaction is fully committed.
*/
runTransaction<T>(asyncQueue: AsyncQueue, updateFunction: (transaction: Transaction) => Promise<T>, deferred: Deferred<T>): void;
applyRemoteEvent(remoteEvent: RemoteEvent): Promise<void>;
/**
* Applies an OnlineState change to the sync engine and notifies any views of
* the change.
*/
applyOnlineStateChange(onlineState: OnlineState, source: OnlineStateSource): void;
rejectListen(targetId: TargetId, err: FirestoreError): Promise<void>;
applyBatchState(batchId: BatchId, batchState: MutationBatchState, error?: FirestoreError): Promise<void>;
applySuccessfulWrite(mutationBatchResult: MutationBatchResult): Promise<void>;
rejectFailedWrite(batchId: BatchId, error: FirestoreError): Promise<void>;
/**
* Registers a user callback that resolves when all pending mutations at the moment of calling
* are acknowledged .
*/
registerPendingWritesCallback(callback: Deferred<void>): Promise<void>;
/**
* Triggers the callbacks that are waiting for this batch id to get acknowledged by server,
* if there are any.
*/
private triggerPendingWritesCallbacks;
/** Reject all outstanding callbacks waiting for pending writes to complete. */
private rejectOutstandingPendingWritesCallbacks;
private addMutationCallback;
/**
* Resolves or rejects the user callback for the given batch and then discards
* it.
*/
private processUserCallback;
private removeAndCleanupQuery;
private removeLimboTarget;
private updateTrackedLimbos;
private trackLimboChange;
currentLimboDocs(): SortedMap<DocumentKey, TargetId>;
private emitNewSnapsAndNotifyLocalStore;
private assertSubscribed;
handleCredentialChange(user: User): Promise<void>;
applyPrimaryState(isPrimary: boolean): Promise<void>;
private resetLimboDocuments;
/**
* Reconcile the query views of the provided query targets with the state from
* persistence. Raises snapshots for any changes that affect the local
* client and returns the updated state of all target's query data.
*/
private synchronizeQueryViewsAndRaiseSnapshots;
getActiveClients(): Promise<ClientId[]>;
applyTargetState(targetId: TargetId, state: QueryTargetState, error?: FirestoreError): Promise<void>;
applyActiveTargetsChange(added: TargetId[], removed: TargetId[]): Promise<void>;
enableNetwork(): Promise<void>;
disableNetwork(): Promise<void>;
getRemoteKeysForTarget(targetId: TargetId): DocumentKeySet;
}

View File

@@ -0,0 +1,49 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { TargetId } from './types';
/**
* Generates monotonically increasing target IDs for sending targets to the
* watch stream.
*
* The client constructs two generators, one for the query cache (via
* forQueryCache()), and one for limbo documents (via forSyncEngine()). These
* two generators produce non-overlapping IDs (by using even and odd IDs
* respectively).
*
* By separating the target ID space, the query cache can generate target IDs
* that persist across client restarts, while sync engine can independently
* generate in-memory target IDs that are transient and can be reused after a
* restart.
*/
export declare class TargetIdGenerator {
private generatorId;
private nextId;
/**
* Instantiates a new TargetIdGenerator. If a seed is provided, the generator
* will use the seed value as the next target ID.
*/
constructor(generatorId: number, seed?: number);
next(): TargetId;
/**
* Returns the ID that follows the given ID. Subsequent calls to `next()`
* use the newly returned target ID as their base.
*/
after(targetId: TargetId): TargetId;
private seek;
static forQueryCache(): TargetIdGenerator;
static forSyncEngine(): TargetIdGenerator;
}

View File

@@ -0,0 +1,60 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { ParsedSetData, ParsedUpdateData } from '../api/user_data_converter';
import { MaybeDocument } from '../model/document';
import { DocumentKey } from '../model/document_key';
import { Datastore } from '../remote/datastore';
/**
* Internal transaction object responsible for accumulating the mutations to
* perform and the base versions for any documents read.
*/
export declare class Transaction {
private datastore;
private readVersions;
private mutations;
private committed;
/**
* A deferred usage error that occurred previously in this transaction that
* will cause the transaction to fail once it actually commits.
*/
private lastWriteError;
/**
* Set of documents that have been written in the transaction.
*
* When there's more than one write to the same key in a transaction, any
* writes after hte first are handled differently.
*/
private writtenDocs;
constructor(datastore: Datastore);
lookup(keys: DocumentKey[]): Promise<MaybeDocument[]>;
set(key: DocumentKey, data: ParsedSetData): void;
update(key: DocumentKey, data: ParsedUpdateData): void;
delete(key: DocumentKey): void;
commit(): Promise<void>;
private recordVersion;
/**
* Returns the version of this document when it was read in this transaction,
* as a precondition, or no precondition if it was not read.
*/
private precondition;
/**
* Returns the precondition for a document if the operation is an update.
*/
private preconditionForUpdate;
private write;
private ensureCommitNotCalled;
}

View File

@@ -0,0 +1,39 @@
/**
* @license
* Copyright 2019 Google Inc.
*
* 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.
*/
import { Deferred } from '../util/promise';
import { AsyncQueue } from '../util/async_queue';
import { Transaction } from './transaction';
import { RemoteStore } from '../remote/remote_store';
/**
* TransactionRunner encapsulates the logic needed to run and retry transactions
* with backoff.
*/
export declare class TransactionRunner<T> {
private readonly asyncQueue;
private readonly remoteStore;
private readonly updateFunction;
private readonly deferred;
private retries;
private backoff;
constructor(asyncQueue: AsyncQueue, remoteStore: RemoteStore, updateFunction: (transaction: Transaction) => Promise<T>, deferred: Deferred<T>);
/** Runs the transaction and sets the result on deferred. */
run(): void;
private runWithBackOff;
private tryRunUpdateFunction;
private handleTransactionError;
private isRetryableTransactionError;
}

View File

@@ -0,0 +1,63 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
/**
* BatchID is a locally assigned ID for a batch of mutations that have been
* applied.
*/
export declare type BatchId = number;
/**
* A locally-assigned ID used to refer to a target being watched via the
* Watch service.
*/
export declare type TargetId = number;
export declare type ListenSequenceNumber = number;
export declare type ProtoByteString = Uint8Array | string;
/** The different states of a mutation batch. */
export declare type MutationBatchState = 'pending' | 'acknowledged' | 'rejected';
/**
* Describes the online state of the Firestore client. Note that this does not
* indicate whether or not the remote store is trying to connect or not. This is
* primarily used by the View / EventManager code to change their behavior while
* offline (e.g. get() calls shouldn't wait for data from the server and
* snapshot events should set metadata.isFromCache=true).
*/
export declare enum OnlineState {
/**
* The Firestore client is in an unknown online state. This means the client
* is either not actively trying to establish a connection or it is currently
* trying to establish a connection, but it has not succeeded or failed yet.
* Higher-level components should not operate in offline mode.
*/
Unknown = 0,
/**
* The client is connected and the connections are healthy. This state is
* reached after a successful connection and there has been at least one
* successful message received from the backends.
*/
Online = 1,
/**
* The client is either trying to establish a connection but failing, or it
* has been explicitly marked offline via a call to disableNetwork().
* Higher-level components should operate in offline mode.
*/
Offline = 2
}
/** The source of an online state event. */
export declare enum OnlineStateSource {
RemoteStore = 0,
SharedClientState = 1
}

View File

@@ -0,0 +1,18 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
/** The semver (www.semver.org) version of the SDK. */
export declare const SDK_VERSION: string;

View File

@@ -0,0 +1,145 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { DocumentKeySet, MaybeDocumentMap } from '../model/collections';
import { DocumentKey } from '../model/document_key';
import { DocumentSet } from '../model/document_set';
import { TargetChange } from '../remote/remote_event';
import { Query } from './query';
import { OnlineState } from './types';
import { DocumentChangeSet, ViewSnapshot } from './view_snapshot';
export declare type LimboDocumentChange = AddedLimboDocument | RemovedLimboDocument;
export declare class AddedLimboDocument {
key: DocumentKey;
constructor(key: DocumentKey);
}
export declare class RemovedLimboDocument {
key: DocumentKey;
constructor(key: DocumentKey);
}
/** The result of applying a set of doc changes to a view. */
export interface ViewDocumentChanges {
/** The new set of docs that should be in the view. */
documentSet: DocumentSet;
/** The diff of these docs with the previous set of docs. */
changeSet: DocumentChangeSet;
/**
* Whether the set of documents passed in was not sufficient to calculate the
* new state of the view and there needs to be another pass based on the
* local cache.
*/
needsRefill: boolean;
mutatedKeys: DocumentKeySet;
}
export interface ViewChange {
snapshot?: ViewSnapshot;
limboChanges: LimboDocumentChange[];
}
/**
* View is responsible for computing the final merged truth of what docs are in
* a query. It gets notified of local and remote changes to docs, and applies
* the query filters and limits to determine the most correct possible results.
*/
export declare class View {
private query;
/** Documents included in the remote target */
private _syncedDocuments;
private syncState;
/**
* A flag whether the view is current with the backend. A view is considered
* current after it has seen the current flag from the backend and did not
* lose consistency within the watch stream (e.g. because of an existence
* filter mismatch).
*/
private current;
private documentSet;
/** Documents in the view but not in the remote target */
private limboDocuments;
/** Document Keys that have local changes */
private mutatedKeys;
constructor(query: Query,
/** Documents included in the remote target */
_syncedDocuments: DocumentKeySet);
/**
* The set of remote documents that the server has told us belongs to the target associated with
* this view.
*/
readonly syncedDocuments: DocumentKeySet;
/**
* Iterates over a set of doc changes, applies the query limit, and computes
* what the new results should be, what the changes were, and whether we may
* need to go back to the local cache for more results. Does not make any
* changes to the view.
* @param docChanges The doc changes to apply to this view.
* @param previousChanges If this is being called with a refill, then start
* with this set of docs and changes instead of the current view.
* @return a new set of docs, changes, and refill flag.
*/
computeDocChanges(docChanges: MaybeDocumentMap, previousChanges?: ViewDocumentChanges): ViewDocumentChanges;
private shouldWaitForSyncedDocument;
/**
* Updates the view with the given ViewDocumentChanges and optionally updates
* limbo docs and sync state from the provided target change.
* @param docChanges The set of changes to make to the view's docs.
* @param updateLimboDocuments Whether to update limbo documents based on this
* change.
* @param targetChange A target change to apply for computing limbo docs and
* sync state.
* @return A new ViewChange with the given docs, changes, and sync state.
*/
applyChanges(docChanges: ViewDocumentChanges, updateLimboDocuments: boolean, targetChange?: TargetChange): ViewChange;
/**
* Applies an OnlineState change to the view, potentially generating a
* ViewChange if the view's syncState changes as a result.
*/
applyOnlineStateChange(onlineState: OnlineState): ViewChange;
/**
* Returns whether the doc for the given key should be in limbo.
*/
private shouldBeInLimbo;
/**
* Updates syncedDocuments, current, and limbo docs based on the given change.
* Returns the list of changes to which docs are in limbo.
*/
private applyTargetChange;
private updateLimboDocuments;
/**
* Update the in-memory state of the current view with the state read from
* persistence.
*
* We update the query view whenever a client's primary status changes:
* - When a client transitions from primary to secondary, it can miss
* LocalStorage updates and its query views may temporarily not be
* synchronized with the state on disk.
* - For secondary to primary transitions, the client needs to update the list
* of `syncedDocuments` since secondary clients update their query views
* based purely on synthesized RemoteEvents.
*
* @param localDocs - The documents that match the query according to the
* LocalStore.
* @param remoteKeys - The keys of the documents that match the query
* according to the backend.
*
* @return The ViewChange that resulted from this synchronization.
*/
synchronizeWithPersistedState(localDocs: MaybeDocumentMap, remoteKeys: DocumentKeySet): ViewChange;
/**
* Returns a view snapshot as if this query was just listened to. Contains
* a document add for every existing document and the `fromCache` and
* `hasPendingWrites` status of the already established view.
*/
computeInitialSnapshot(): ViewSnapshot;
}

View File

@@ -0,0 +1,58 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { Document } from '../model/document';
import { DocumentSet } from '../model/document_set';
import { DocumentKeySet } from '../model/collections';
import { Query } from './query';
export declare enum ChangeType {
Added = 0,
Removed = 1,
Modified = 2,
Metadata = 3
}
export interface DocumentViewChange {
type: ChangeType;
doc: Document;
}
export declare enum SyncState {
Local = 0,
Synced = 1
}
/**
* DocumentChangeSet keeps track of a set of changes to docs in a query, merging
* duplicate events for the same doc.
*/
export declare class DocumentChangeSet {
private changeMap;
track(change: DocumentViewChange): void;
getChanges(): DocumentViewChange[];
}
export declare class ViewSnapshot {
readonly query: Query;
readonly docs: DocumentSet;
readonly oldDocs: DocumentSet;
readonly docChanges: DocumentViewChange[];
readonly mutatedKeys: DocumentKeySet;
readonly fromCache: boolean;
readonly syncStateChanged: boolean;
readonly excludesMetadataChanges: boolean;
constructor(query: Query, docs: DocumentSet, oldDocs: DocumentSet, docChanges: DocumentViewChange[], mutatedKeys: DocumentKeySet, fromCache: boolean, syncStateChanged: boolean, excludesMetadataChanges: boolean);
/** Returns a view snapshot as if all documents in the snapshot were added. */
static fromInitialDocuments(query: Query, documents: DocumentSet, mutatedKeys: DocumentKeySet, fromCache: boolean): ViewSnapshot;
readonly hasPendingWrites: boolean;
isEqual(other: ViewSnapshot): boolean;
}

View File

@@ -0,0 +1,86 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { ResourcePath } from '../model/path';
/**
* Helpers for dealing with resource paths stored in IndexedDB.
*
* Resource paths in their canonical string form do not sort as the server
* sorts them. Specifically the server splits paths into segments first and then
* sorts, putting end-of-segment before any character. In a UTF-8 string
* encoding the slash ('/') that denotes the end-of-segment naturally comes
* after other characters so the intent here is to encode the path delimiters in
* such a way that the resulting strings sort naturally.
*
* Resource paths are also used for prefix scans so it's important to
* distinguish whole segments from any longer segments of which they might be a
* prefix. For example, it's important to make it possible to scan documents in
* a collection "foo" without encountering documents in a collection "foobar".
*
* Separate from the concerns about resource path ordering and separation,
* On Android, SQLite imposes additional restrictions since it does not handle
* keys with embedded NUL bytes particularly well. Rather than change the
* implementation we keep the encoding identical to keep the ports similar.
*
* Taken together this means resource paths when encoded for storage in
* IndexedDB have the following characteristics:
*
* * Segment separators ("/") sort before everything else.
* * All paths have a trailing separator.
* * NUL bytes do not exist in the output, since IndexedDB doesn't treat them
* well.
*
* Therefore resource paths are encoded into string form using the following
* rules:
*
* * '\x01' is used as an escape character.
* * Path separators are encoded as "\x01\x01"
* * NUL bytes are encoded as "\x01\x10"
* * '\x01' is encoded as "\x01\x11"
*
* This encoding leaves some room between path separators and the NUL byte
* just in case we decide to support integer document ids after all.
*
* Note that characters treated specially by the backend ('.', '/', and '~')
* are not treated specially here. This class assumes that any unescaping of
* resource path strings into actual ResourcePath objects will handle these
* characters there.
*/
export declare type EncodedResourcePath = string;
/**
* Encodes a resource path into a IndexedDb-compatible string form.
*/
export declare function encode(path: ResourcePath): EncodedResourcePath;
/**
* Decodes the given IndexedDb-compatible string form of a resource path into
* a ResourcePath instance. Note that this method is not suitable for use with
* decoding resource names from the server; those are One Platform format
* strings.
*/
export declare function decode(path: EncodedResourcePath): ResourcePath;
/**
* Computes the prefix successor of the given path, computed by encode above.
* A prefix successor is the first key that cannot be prefixed by the given
* path. It's useful for defining the end of a prefix scan such that all keys
* in the scan have the same prefix.
*
* Note that this is not a general prefix successor implementation, which is
* tricky to get right with Strings, given that they encode down to UTF-8.
* Instead this relies on the fact that all paths encoded by this class are
* always terminated with a separator, and so a successor can always be
* cheaply computed by incrementing the last character of the path.
*/
export declare function prefixSuccessor(path: EncodedResourcePath): EncodedResourcePath;

View File

@@ -0,0 +1,43 @@
/**
* @license
* Copyright 2019 Google Inc.
*
* 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.
*/
import { ResourcePath } from '../model/path';
import { PersistenceTransaction } from './persistence';
import { PersistencePromise } from './persistence_promise';
/**
* Represents a set of indexes that are used to execute queries efficiently.
*
* Currently the only index is a [collection id] => [parent path] index, used
* to execute Collection Group queries.
*/
export interface IndexManager {
/**
* Creates an index entry mapping the collectionId (last segment of the path)
* to the parent path (either the containing document location or the empty
* path for root-level collections). Index entries can be retrieved via
* getCollectionParents().
*
* NOTE: Currently we don't remove index entries. If this ends up being an
* issue we can devise some sort of GC strategy.
*/
addToCollectionParentIndex(transaction: PersistenceTransaction, collectionPath: ResourcePath): PersistencePromise<void>;
/**
* Retrieves all parent locations containing the given collectionId, as a
* list of paths (each path being either a document location or the empty
* path for a root-level collection).
*/
getCollectionParents(transaction: PersistenceTransaction, collectionId: string): PersistencePromise<ResourcePath[]>;
}

View File

@@ -0,0 +1,35 @@
/**
* @license
* Copyright 2019 Google Inc.
*
* 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.
*/
import { ResourcePath } from '../model/path';
import { IndexManager } from './index_manager';
import { PersistenceTransaction } from './persistence';
import { PersistencePromise } from './persistence_promise';
/**
* A persisted implementation of IndexManager.
*/
export declare class IndexedDbIndexManager implements IndexManager {
/**
* An in-memory copy of the index entries we've already written since the SDK
* launched. Used to avoid re-writing the same entry repeatedly.
*
* This is *NOT* a complete cache of what's in persistence and so can never be used to
* satisfy reads.
*/
private collectionParentsCache;
addToCollectionParentIndex(transaction: PersistenceTransaction, collectionPath: ResourcePath): PersistencePromise<void>;
getCollectionParents(transaction: PersistenceTransaction, collectionId: string): PersistencePromise<ResourcePath[]>;
}

View File

@@ -0,0 +1,93 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { Timestamp } from '../api/timestamp';
import { User } from '../auth/user';
import { Query } from '../core/query';
import { BatchId, ProtoByteString } from '../core/types';
import { DocumentKeySet } from '../model/collections';
import { DocumentKey } from '../model/document_key';
import { Mutation } from '../model/mutation';
import { MutationBatch } from '../model/mutation_batch';
import { SortedMap } from '../util/sorted_map';
import { IndexManager } from './index_manager';
import { LocalSerializer } from './local_serializer';
import { MutationQueue } from './mutation_queue';
import { PersistenceTransaction, ReferenceDelegate } from './persistence';
import { PersistencePromise } from './persistence_promise';
import { SimpleDbTransaction } from './simple_db';
/** A mutation queue for a specific user, backed by IndexedDB. */
export declare class IndexedDbMutationQueue implements MutationQueue {
/**
* The normalized userId (e.g. null UID => "" userId) used to store /
* retrieve mutations.
*/
private userId;
private readonly serializer;
private readonly indexManager;
private readonly referenceDelegate;
/**
* Caches the document keys for pending mutation batches. If the mutation
* has been removed from IndexedDb, the cached value may continue to
* be used to retrieve the batch's document keys. To remove a cached value
* locally, `removeCachedMutationKeys()` should be invoked either directly
* or through `removeMutationBatches()`.
*
* With multi-tab, when the primary client acknowledges or rejects a mutation,
* this cache is used by secondary clients to invalidate the local
* view of the documents that were previously affected by the mutation.
*/
private documentKeysByBatchId;
constructor(
/**
* The normalized userId (e.g. null UID => "" userId) used to store /
* retrieve mutations.
*/
userId: string, serializer: LocalSerializer, indexManager: IndexManager, referenceDelegate: ReferenceDelegate);
/**
* Creates a new mutation queue for the given user.
* @param user The user for which to create a mutation queue.
* @param serializer The serializer to use when persisting to IndexedDb.
*/
static forUser(user: User, serializer: LocalSerializer, indexManager: IndexManager, referenceDelegate: ReferenceDelegate): IndexedDbMutationQueue;
checkEmpty(transaction: PersistenceTransaction): PersistencePromise<boolean>;
acknowledgeBatch(transaction: PersistenceTransaction, batch: MutationBatch, streamToken: ProtoByteString): PersistencePromise<void>;
getLastStreamToken(transaction: PersistenceTransaction): PersistencePromise<ProtoByteString>;
setLastStreamToken(transaction: PersistenceTransaction, streamToken: ProtoByteString): PersistencePromise<void>;
addMutationBatch(transaction: PersistenceTransaction, localWriteTime: Timestamp, baseMutations: Mutation[], mutations: Mutation[]): PersistencePromise<MutationBatch>;
lookupMutationBatch(transaction: PersistenceTransaction, batchId: BatchId): PersistencePromise<MutationBatch | null>;
lookupMutationKeys(transaction: PersistenceTransaction, batchId: BatchId): PersistencePromise<DocumentKeySet | null>;
getNextMutationBatchAfterBatchId(transaction: PersistenceTransaction, batchId: BatchId): PersistencePromise<MutationBatch | null>;
getHighestUnacknowledgedBatchId(transaction: PersistenceTransaction): PersistencePromise<BatchId>;
getAllMutationBatches(transaction: PersistenceTransaction): PersistencePromise<MutationBatch[]>;
getAllMutationBatchesAffectingDocumentKey(transaction: PersistenceTransaction, documentKey: DocumentKey): PersistencePromise<MutationBatch[]>;
getAllMutationBatchesAffectingDocumentKeys(transaction: PersistenceTransaction, documentKeys: SortedMap<DocumentKey, unknown>): PersistencePromise<MutationBatch[]>;
getAllMutationBatchesAffectingQuery(transaction: PersistenceTransaction, query: Query): PersistencePromise<MutationBatch[]>;
private lookupMutationBatches;
removeMutationBatch(transaction: PersistenceTransaction, batch: MutationBatch): PersistencePromise<void>;
removeCachedMutationKeys(batchId: BatchId): void;
performConsistencyCheck(txn: PersistenceTransaction): PersistencePromise<void>;
containsKey(txn: PersistenceTransaction, key: DocumentKey): PersistencePromise<boolean>;
/** Returns the mutation queue's metadata from IndexedDb. */
private getMutationQueueMetadata;
}
/** Returns true if any mutation queue contains the given document. */
export declare function mutationQueuesContainKey(txn: PersistenceTransaction, docKey: DocumentKey): PersistencePromise<boolean>;
/**
* Delete a mutation batch and the associated document mutations.
* @return A PersistencePromise of the document mutations that were removed.
*/
export declare function removeMutationBatch(txn: SimpleDbTransaction, userId: string, batch: MutationBatch): PersistencePromise<DocumentKey[]>;

View File

@@ -0,0 +1,279 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { User } from '../auth/user';
import { DatabaseInfo } from '../core/database_info';
import { SequenceNumberSyncer } from '../core/listen_sequence';
import { ListenSequenceNumber } from '../core/types';
import { DocumentKey } from '../model/document_key';
import { Platform } from '../platform/platform';
import { JsonProtoSerializer } from '../remote/serializer';
import { AsyncQueue } from '../util/async_queue';
import { FirestoreError } from '../util/error';
import { IndexedDbIndexManager } from './indexeddb_index_manager';
import { IndexedDbQueryCache } from './indexeddb_query_cache';
import { IndexedDbRemoteDocumentCache } from './indexeddb_remote_document_cache';
import { ActiveTargets, LruDelegate, LruGarbageCollector, LruParams } from './lru_garbage_collector';
import { MutationQueue } from './mutation_queue';
import { Persistence, PersistenceTransaction, PrimaryStateListener, ReferenceDelegate } from './persistence';
import { PersistencePromise } from './persistence_promise';
import { QueryData } from './query_data';
import { ReferenceSet } from './reference_set';
import { ClientId } from './shared_client_state';
import { SimpleDbStore, SimpleDbTransaction } from './simple_db';
export declare class IndexedDbTransaction extends PersistenceTransaction {
readonly simpleDbTransaction: SimpleDbTransaction;
readonly currentSequenceNumber: ListenSequenceNumber;
constructor(simpleDbTransaction: SimpleDbTransaction, currentSequenceNumber: ListenSequenceNumber);
}
/**
* An IndexedDB-backed instance of Persistence. Data is stored persistently
* across sessions.
*
* On Web only, the Firestore SDKs support shared access to its persistence
* layer. This allows multiple browser tabs to read and write to IndexedDb and
* to synchronize state even without network connectivity. Shared access is
* currently optional and not enabled unless all clients invoke
* `enablePersistence()` with `{synchronizeTabs:true}`.
*
* In multi-tab mode, if multiple clients are active at the same time, the SDK
* will designate one client as the “primary client”. An effort is made to pick
* a visible, network-connected and active client, and this client is
* responsible for letting other clients know about its presence. The primary
* client writes a unique client-generated identifier (the client ID) to
* IndexedDbs “owner” store every 4 seconds. If the primary client fails to
* update this entry, another client can acquire the lease and take over as
* primary.
*
* Some persistence operations in the SDK are designated as primary-client only
* operations. This includes the acknowledgment of mutations and all updates of
* remote documents. The effects of these operations are written to persistence
* and then broadcast to other tabs via LocalStorage (see
* `WebStorageSharedClientState`), which then refresh their state from
* persistence.
*
* Similarly, the primary client listens to notifications sent by secondary
* clients to discover persistence changes written by secondary clients, such as
* the addition of new mutations and query targets.
*
* If multi-tab is not enabled and another tab already obtained the primary
* lease, IndexedDbPersistence enters a failed state and all subsequent
* operations will automatically fail.
*
* Additionally, there is an optimization so that when a tab is closed, the
* primary lease is released immediately (this is especially important to make
* sure that a refreshed tab is able to immediately re-acquire the primary
* lease). Unfortunately, IndexedDB cannot be reliably used in window.unload
* since it is an asynchronous API. So in addition to attempting to give up the
* lease, the leaseholder writes its client ID to a "zombiedClient" entry in
* LocalStorage which acts as an indicator that another tab should go ahead and
* take the primary lease immediately regardless of the current lease timestamp.
*
* TODO(b/114226234): Remove `synchronizeTabs` section when multi-tab is no
* longer optional.
*/
export interface MultiClientParams {
sequenceNumberSyncer: SequenceNumberSyncer;
}
export declare class IndexedDbPersistence implements Persistence {
private readonly persistenceKey;
private readonly clientId;
private readonly queue;
private readonly multiClientParams?;
static getStore<Key extends IDBValidKey, Value>(txn: PersistenceTransaction, store: string): SimpleDbStore<Key, Value>;
/**
* The name of the main (and currently only) IndexedDB database. this name is
* appended to the prefix provided to the IndexedDbPersistence constructor.
*/
static MAIN_DATABASE: string;
static createIndexedDbPersistence(persistenceKey: string, clientId: ClientId, platform: Platform, queue: AsyncQueue, serializer: JsonProtoSerializer, lruParams: LruParams): Promise<IndexedDbPersistence>;
static createMultiClientIndexedDbPersistence(persistenceKey: string, clientId: ClientId, platform: Platform, queue: AsyncQueue, serializer: JsonProtoSerializer, lruParams: LruParams, multiClientParams: MultiClientParams): Promise<IndexedDbPersistence>;
private readonly document;
private readonly window;
private simpleDb;
private listenSequence;
private _started;
private isPrimary;
private networkEnabled;
private dbName;
/** Our window.unload handler, if registered. */
private windowUnloadHandler;
private inForeground;
private serializer;
/** Our 'visibilitychange' listener if registered. */
private documentVisibilityHandler;
/** The client metadata refresh task. */
private clientMetadataRefresher;
/** The last time we garbage collected the Remote Document Changelog. */
private lastGarbageCollectionTime;
/** Whether to allow shared multi-tab access to the persistence layer. */
private allowTabSynchronization;
/** A listener to notify on primary state changes. */
private primaryStateListener;
private readonly queryCache;
private readonly indexManager;
private readonly remoteDocumentCache;
private readonly webStorage;
readonly referenceDelegate: IndexedDbLruDelegate;
private constructor();
/**
* Attempt to start IndexedDb persistence.
*
* @return {Promise<void>} Whether persistence was enabled.
*/
private start;
private startRemoteDocumentCache;
setPrimaryStateListener(primaryStateListener: PrimaryStateListener): Promise<void>;
setDatabaseDeletedListener(databaseDeletedListener: () => Promise<void>): void;
setNetworkEnabled(networkEnabled: boolean): void;
/**
* Updates the client metadata in IndexedDb and attempts to either obtain or
* extend the primary lease for the local client. Asynchronously notifies the
* primary state listener if the client either newly obtained or released its
* primary lease.
*/
private updateClientMetadataAndTryBecomePrimary;
private verifyPrimaryLease;
private removeClientMetadata;
/**
* If the garbage collection threshold has passed, prunes the
* RemoteDocumentChanges and the ClientMetadata store based on the last update
* time of all clients.
*/
private maybeGarbageCollectMultiClientState;
/**
* Schedules a recurring timer to update the client metadata and to either
* extend or acquire the primary lease if the client is eligible.
*/
private scheduleClientMetadataAndPrimaryLeaseRefreshes;
/** Checks whether `client` is the local client. */
private isLocalClient;
/**
* Evaluate the state of all active clients and determine whether the local
* client is or can act as the holder of the primary lease. Returns whether
* the client is eligible for the lease, but does not actually acquire it.
* May return 'false' even if there is no active leaseholder and another
* (foreground) client should become leaseholder instead.
*/
private canActAsPrimary;
shutdown(): Promise<void>;
/**
* Returns clients that are not zombied and have an updateTime within the
* provided threshold.
*/
private filterActiveClients;
getActiveClients(): Promise<ClientId[]>;
static clearPersistence(persistenceKey: string): Promise<void>;
readonly started: boolean;
getMutationQueue(user: User): MutationQueue;
getQueryCache(): IndexedDbQueryCache;
getRemoteDocumentCache(): IndexedDbRemoteDocumentCache;
getIndexManager(): IndexedDbIndexManager;
runTransaction<T>(action: string, mode: 'readonly' | 'readwrite' | 'readwrite-primary', transactionOperation: (transaction: PersistenceTransaction) => PersistencePromise<T>): Promise<T>;
/**
* Verifies that the current tab is the primary leaseholder or alternatively
* that the leaseholder has opted into multi-tab synchronization.
*/
private verifyAllowTabSynchronization;
/**
* Obtains or extends the new primary lease for the local client. This
* method does not verify that the client is eligible for this lease.
*/
private acquireOrExtendPrimaryLease;
static isAvailable(): boolean;
/**
* Generates a string used as a prefix when storing data in IndexedDB and
* LocalStorage.
*/
static buildStoragePrefix(databaseInfo: DatabaseInfo): string;
/** Checks the primary lease and removes it if we are the current primary. */
private releasePrimaryLeaseIfHeld;
/** Verifies that `updateTimeMs` is within `maxAgeMs`. */
private isWithinAge;
private attachVisibilityHandler;
private detachVisibilityHandler;
/**
* Attaches a window.unload handler that will synchronously write our
* clientId to a "zombie client id" location in LocalStorage. This can be used
* by tabs trying to acquire the primary lease to determine that the lease
* is no longer valid even if the timestamp is recent. This is particularly
* important for the refresh case (so the tab correctly re-acquires the
* primary lease). LocalStorage is used for this rather than IndexedDb because
* it is a synchronous API and so can be used reliably from an unload
* handler.
*/
private attachWindowUnloadHook;
private detachWindowUnloadHook;
/**
* Returns whether a client is "zombied" based on its LocalStorage entry.
* Clients become zombied when their tab closes without running all of the
* cleanup logic in `shutdown()`.
*/
private isClientZombied;
/**
* Record client as zombied (a client that had its tab closed). Zombied
* clients are ignored during primary tab selection.
*/
private markClientZombied;
/** Removes the zombied client entry if it exists. */
private removeClientZombiedEntry;
private zombiedClientLocalStorageKey;
}
/**
* Verifies the error thrown by a LocalStore operation. If a LocalStore
* operation fails because the primary lease has been taken by another client,
* we ignore the error (the persistence layer will immediately call
* `applyPrimaryLease` to propagate the primary state change). All other errors
* are re-thrown.
*
* @param err An error returned by a LocalStore operation.
* @return A Promise that resolves after we recovered, or the original error.
*/
export declare function ignoreIfPrimaryLeaseLoss(err: FirestoreError): Promise<void>;
/** Provides LRU functionality for IndexedDB persistence. */
export declare class IndexedDbLruDelegate implements ReferenceDelegate, LruDelegate {
private readonly db;
private inMemoryPins;
readonly garbageCollector: LruGarbageCollector;
constructor(db: IndexedDbPersistence, params: LruParams);
getSequenceNumberCount(txn: PersistenceTransaction): PersistencePromise<number>;
private orphanedDocmentCount;
forEachTarget(txn: PersistenceTransaction, f: (q: QueryData) => void): PersistencePromise<void>;
forEachOrphanedDocumentSequenceNumber(txn: PersistenceTransaction, f: (sequenceNumber: ListenSequenceNumber) => void): PersistencePromise<void>;
setInMemoryPins(inMemoryPins: ReferenceSet): void;
addReference(txn: PersistenceTransaction, key: DocumentKey): PersistencePromise<void>;
removeReference(txn: PersistenceTransaction, key: DocumentKey): PersistencePromise<void>;
removeTargets(txn: PersistenceTransaction, upperBound: ListenSequenceNumber, activeTargetIds: ActiveTargets): PersistencePromise<number>;
removeMutationReference(txn: PersistenceTransaction, key: DocumentKey): PersistencePromise<void>;
/**
* Returns true if anything would prevent this document from being garbage
* collected, given that the document in question is not present in any
* targets and has a sequence number less than or equal to the upper bound for
* the collection run.
*/
private isPinned;
removeOrphanedDocuments(txn: PersistenceTransaction, upperBound: ListenSequenceNumber): PersistencePromise<number>;
removeTarget(txn: PersistenceTransaction, queryData: QueryData): PersistencePromise<void>;
updateLimboDocument(txn: PersistenceTransaction, key: DocumentKey): PersistencePromise<void>;
/**
* Call provided function for each document in the cache that is 'orphaned'. Orphaned
* means not a part of any target, so the only entry in the target-document index for
* that document will be the sentinel row (targetId 0), which will also have the sequence
* number for the last time the document was accessed.
*/
private forEachOrphanedDocument;
getCacheSize(txn: PersistenceTransaction): PersistencePromise<number>;
}

View File

@@ -0,0 +1,75 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { Query } from '../core/query';
import { SnapshotVersion } from '../core/snapshot_version';
import { ListenSequenceNumber, TargetId } from '../core/types';
import { DocumentKeySet } from '../model/collections';
import { DocumentKey } from '../model/document_key';
import { IndexedDbLruDelegate } from './indexeddb_persistence';
import { DbTargetDocument, DbTargetDocumentKey } from './indexeddb_schema';
import { LocalSerializer } from './local_serializer';
import { ActiveTargets } from './lru_garbage_collector';
import { PersistenceTransaction } from './persistence';
import { PersistencePromise } from './persistence_promise';
import { QueryCache } from './query_cache';
import { QueryData } from './query_data';
import { SimpleDbStore, SimpleDbTransaction } from './simple_db';
export declare class IndexedDbQueryCache implements QueryCache {
private readonly referenceDelegate;
private serializer;
constructor(referenceDelegate: IndexedDbLruDelegate, serializer: LocalSerializer);
private targetIdGenerator;
allocateTargetId(transaction: PersistenceTransaction): PersistencePromise<TargetId>;
getLastRemoteSnapshotVersion(transaction: PersistenceTransaction): PersistencePromise<SnapshotVersion>;
getHighestSequenceNumber(transaction: PersistenceTransaction): PersistencePromise<ListenSequenceNumber>;
setTargetsMetadata(transaction: PersistenceTransaction, highestListenSequenceNumber: number, lastRemoteSnapshotVersion?: SnapshotVersion): PersistencePromise<void>;
addQueryData(transaction: PersistenceTransaction, queryData: QueryData): PersistencePromise<void>;
updateQueryData(transaction: PersistenceTransaction, queryData: QueryData): PersistencePromise<void>;
removeQueryData(transaction: PersistenceTransaction, queryData: QueryData): PersistencePromise<void>;
/**
* Drops any targets with sequence number less than or equal to the upper bound, excepting those
* present in `activeTargetIds`. Document associations for the removed targets are also removed.
* Returns the number of targets removed.
*/
removeTargets(txn: PersistenceTransaction, upperBound: ListenSequenceNumber, activeTargetIds: ActiveTargets): PersistencePromise<number>;
/**
* Call provided function with each `QueryData` that we have cached.
*/
forEachTarget(txn: PersistenceTransaction, f: (q: QueryData) => void): PersistencePromise<void>;
private retrieveMetadata;
private saveMetadata;
private saveQueryData;
/**
* In-place updates the provided metadata to account for values in the given
* QueryData. Saving is done separately. Returns true if there were any
* changes to the metadata.
*/
private updateMetadataFromQueryData;
getQueryCount(transaction: PersistenceTransaction): PersistencePromise<number>;
getQueryData(transaction: PersistenceTransaction, query: Query): PersistencePromise<QueryData | null>;
addMatchingKeys(txn: PersistenceTransaction, keys: DocumentKeySet, targetId: TargetId): PersistencePromise<void>;
removeMatchingKeys(txn: PersistenceTransaction, keys: DocumentKeySet, targetId: TargetId): PersistencePromise<void>;
removeMatchingKeysForTargetId(txn: PersistenceTransaction, targetId: TargetId): PersistencePromise<void>;
getMatchingKeysForTargetId(txn: PersistenceTransaction, targetId: TargetId): PersistencePromise<DocumentKeySet>;
containsKey(txn: PersistenceTransaction, key: DocumentKey): PersistencePromise<boolean>;
getQueryDataForTarget(transaction: PersistenceTransaction, targetId: TargetId): PersistencePromise<QueryData | null>;
}
export declare function getHighestListenSequenceNumber(txn: SimpleDbTransaction): PersistencePromise<ListenSequenceNumber>;
/**
* Helper to get a typed SimpleDbStore for the document target object store.
*/
export declare function documentTargetStore(txn: PersistenceTransaction): SimpleDbStore<DbTargetDocumentKey, DbTargetDocument>;

View File

@@ -0,0 +1,118 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { Query } from '../core/query';
import { DocumentKeySet, DocumentMap, DocumentSizeEntries, DocumentSizeEntry, MaybeDocumentMap, NullableMaybeDocumentMap } from '../model/collections';
import { MaybeDocument } from '../model/document';
import { DocumentKey } from '../model/document_key';
import { FirestoreError } from '../util/error';
import { IndexManager } from './index_manager';
import { DbRemoteDocument } from './indexeddb_schema';
import { LocalSerializer } from './local_serializer';
import { PersistenceTransaction } from './persistence';
import { PersistencePromise } from './persistence_promise';
import { RemoteDocumentCache } from './remote_document_cache';
import { RemoteDocumentChangeBuffer } from './remote_document_change_buffer';
import { SimpleDbTransaction } from './simple_db';
export declare class IndexedDbRemoteDocumentCache implements RemoteDocumentCache {
readonly serializer: LocalSerializer;
private readonly indexManager;
private readonly keepDocumentChangeLog;
/** The last id read by `getNewDocumentChanges()`. */
private _lastProcessedDocumentChangeId;
/**
* @param {LocalSerializer} serializer The document serializer.
* @param {IndexManager} indexManager The query indexes that need to be maintained.
* @param keepDocumentChangeLog Whether to keep a document change log in
* IndexedDb. This change log is required for Multi-Tab synchronization, but
* not needed in clients that don't share access to their remote document
* cache.
*/
constructor(serializer: LocalSerializer, indexManager: IndexManager, keepDocumentChangeLog: boolean);
readonly lastProcessedDocumentChangeId: number;
/**
* Starts up the remote document cache.
*
* Reads the ID of the last document change from the documentChanges store.
* Existing changes will not be returned as part of
* `getNewDocumentChanges()`.
*/
start(transaction: SimpleDbTransaction): PersistencePromise<void>;
/**
* Adds the supplied entries to the cache.
*
* All calls of `addEntry` are required to go through the RemoteDocumentChangeBuffer
* returned by `newChangeBuffer()` to ensure proper accounting of metadata.
*/
private addEntry;
/**
* Removes a document from the cache.
*
* All calls of `removeEntry` are required to go through the RemoteDocumentChangeBuffer
* returned by `newChangeBuffer()` to ensure proper accounting of metadata.
*/
private removeEntry;
/**
* Updates the document change log and adds the given delta to the cached current size.
* Callers to `addEntry()` and `removeEntry()` *must* call this afterwards to update the
* cache's metadata.
*/
private updateMetadata;
getEntry(transaction: PersistenceTransaction, documentKey: DocumentKey): PersistencePromise<MaybeDocument | null>;
/**
* Looks up an entry in the cache.
*
* @param documentKey The key of the entry to look up.
* @return The cached MaybeDocument entry and its size, or null if we have nothing cached.
*/
getSizedEntry(transaction: PersistenceTransaction, documentKey: DocumentKey): PersistencePromise<DocumentSizeEntry | null>;
getEntries(transaction: PersistenceTransaction, documentKeys: DocumentKeySet): PersistencePromise<NullableMaybeDocumentMap>;
/**
* Looks up several entries in the cache.
*
* @param documentKeys The set of keys entries to look up.
* @return A map of MaybeDocuments indexed by key (if a document cannot be
* found, the key will be mapped to null) and a map of sizes indexed by
* key (zero if the key cannot be found).
*/
getSizedEntries(transaction: PersistenceTransaction, documentKeys: DocumentKeySet): PersistencePromise<DocumentSizeEntries>;
private forEachDbEntry;
getDocumentsMatchingQuery(transaction: PersistenceTransaction, query: Query): PersistencePromise<DocumentMap>;
getNewDocumentChanges(transaction: PersistenceTransaction): PersistencePromise<MaybeDocumentMap>;
/**
* Removes all changes in the remote document changelog through `changeId`
* (inclusive).
*/
removeDocumentChangesThroughChangeId(transaction: PersistenceTransaction, changeId: number): PersistencePromise<void>;
private synchronizeLastDocumentChangeId;
newChangeBuffer(): RemoteDocumentChangeBuffer;
getSize(txn: PersistenceTransaction): PersistencePromise<number>;
private getMetadata;
private setMetadata;
/**
* Handles the details of adding and updating documents in the IndexedDbRemoteDocumentCache.
*
* Unlike the MemoryRemoteDocumentChangeBuffer, the IndexedDb implementation computes the size
* delta for all submitted changes. This avoids having to re-read all documents from IndexedDb
* when we apply the changes.
*/
private static RemoteDocumentChangeBuffer;
}
export declare function isDocumentChangeMissingError(err: FirestoreError): boolean;
/**
* Retrusn an approximate size for the given document.
*/
export declare function dbDocumentSize(doc: DbRemoteDocument): number;

View File

@@ -0,0 +1,770 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { BatchId, TargetId } from '../core/types';
import { ResourcePath } from '../model/path';
import * as api from '../protos/firestore_proto_api';
import { EncodedResourcePath } from './encoded_resource_path';
import { LocalSerializer } from './local_serializer';
import { PersistencePromise } from './persistence_promise';
import { SimpleDbSchemaConverter, SimpleDbTransaction } from './simple_db';
/**
* Schema Version for the Web client:
* 1. Initial version including Mutation Queue, Query Cache, and Remote Document
* Cache
* 2. Used to ensure a targetGlobal object exists and add targetCount to it. No
* longer required because migration 3 unconditionally clears it.
* 3. Dropped and re-created Query Cache to deal with cache corruption related
* to limbo resolution. Addresses
* https://github.com/firebase/firebase-ios-sdk/issues/1548
* 4. Multi-Tab Support.
* 5. Removal of held write acks.
* 6. Create document global for tracking document cache size.
* 7. Ensure every cached document has a sentinel row with a sequence number.
* 8. Add collection-parent index for Collection Group queries.
*/
export declare const SCHEMA_VERSION = 8;
/** Performs database creation and schema upgrades. */
export declare class SchemaConverter implements SimpleDbSchemaConverter {
private readonly serializer;
constructor(serializer: LocalSerializer);
/**
* Performs database creation and schema upgrades.
*
* Note that in production, this method is only ever used to upgrade the schema
* to SCHEMA_VERSION. Different values of toVersion are only used for testing
* and local feature development.
*/
createOrUpgrade(db: IDBDatabase, txn: SimpleDbTransaction, fromVersion: number, toVersion: number): PersistencePromise<void>;
private addDocumentGlobal;
private removeAcknowledgedMutations;
/**
* Ensures that every document in the remote document cache has a corresponding sentinel row
* with a sequence number. Missing rows are given the most recently used sequence number.
*/
private ensureSequenceNumbers;
private createCollectionParentIndex;
}
/**
* Wrapper class to store timestamps (seconds and nanos) in IndexedDb objects.
*/
export declare class DbTimestamp {
seconds: number;
nanoseconds: number;
constructor(seconds: number, nanoseconds: number);
}
export declare type DbPrimaryClientKey = typeof DbPrimaryClient.key;
/**
* A singleton object to be stored in the 'owner' store in IndexedDb.
*
* A given database can have a single primary tab assigned at a given time. That
* tab must validate that it is still holding the primary lease before every
* operation that requires locked access. The primary tab should regularly
* write an updated timestamp to this lease to prevent other tabs from
* "stealing" the primary lease
*/
export declare class DbPrimaryClient {
ownerId: string;
/** Whether to allow shared access from multiple tabs. */
allowTabSynchronization: boolean;
leaseTimestampMs: number;
/**
* Name of the IndexedDb object store.
*
* Note that the name 'owner' is chosen to ensure backwards compatibility with
* older clients that only supported single locked access to the persistence
* layer.
*/
static store: string;
/**
* The key string used for the single object that exists in the
* DbPrimaryClient store.
*/
static key: string;
constructor(ownerId: string,
/** Whether to allow shared access from multiple tabs. */
allowTabSynchronization: boolean, leaseTimestampMs: number);
}
/** Object keys in the 'mutationQueues' store are userId strings. */
export declare type DbMutationQueueKey = string;
/**
* An object to be stored in the 'mutationQueues' store in IndexedDb.
*
* Each user gets a single queue of MutationBatches to apply to the server.
* DbMutationQueue tracks the metadata about the queue.
*/
export declare class DbMutationQueue {
/**
* The normalized user ID to which this queue belongs.
*/
userId: string;
/**
* An identifier for the highest numbered batch that has been acknowledged
* by the server. All MutationBatches in this queue with batchIds less
* than or equal to this value are considered to have been acknowledged by
* the server.
*
* NOTE: this is deprecated and no longer used by the code.
*/
lastAcknowledgedBatchId: number;
/**
* A stream token that was previously sent by the server.
*
* See StreamingWriteRequest in datastore.proto for more details about
* usage.
*
* After sending this token, earlier tokens may not be used anymore so
* only a single stream token is retained.
*/
lastStreamToken: string;
/** Name of the IndexedDb object store. */
static store: string;
/** Keys are automatically assigned via the userId property. */
static keyPath: string;
constructor(
/**
* The normalized user ID to which this queue belongs.
*/
userId: string,
/**
* An identifier for the highest numbered batch that has been acknowledged
* by the server. All MutationBatches in this queue with batchIds less
* than or equal to this value are considered to have been acknowledged by
* the server.
*
* NOTE: this is deprecated and no longer used by the code.
*/
lastAcknowledgedBatchId: number,
/**
* A stream token that was previously sent by the server.
*
* See StreamingWriteRequest in datastore.proto for more details about
* usage.
*
* After sending this token, earlier tokens may not be used anymore so
* only a single stream token is retained.
*/
lastStreamToken: string);
}
/** The 'mutations' store is keyed by batch ID. */
export declare type DbMutationBatchKey = BatchId;
/**
* An object to be stored in the 'mutations' store in IndexedDb.
*
* Represents a batch of user-level mutations intended to be sent to the server
* in a single write. Each user-level batch gets a separate DbMutationBatch
* with a new batchId.
*/
export declare class DbMutationBatch {
/**
* The normalized user ID to which this batch belongs.
*/
userId: string;
/**
* An identifier for this batch, allocated using an auto-generated key.
*/
batchId: BatchId;
/**
* The local write time of the batch, stored as milliseconds since the
* epoch.
*/
localWriteTimeMs: number;
/**
* A list of "mutations" that represent a partial base state from when this
* write batch was initially created. During local application of the write
* batch, these baseMutations are applied prior to the real writes in order
* to override certain document fields from the remote document cache. This
* is necessary in the case of non-idempotent writes (e.g. `increment()`
* transforms) to make sure that the local view of the modified documents
* doesn't flicker if the remote document cache receives the result of the
* non-idempotent write before the write is removed from the queue.
*
* These mutations are never sent to the backend.
*/
baseMutations: api.Write[] | undefined;
/**
* A list of mutations to apply. All mutations will be applied atomically.
*
* Mutations are serialized via JsonProtoSerializer.toMutation().
*/
mutations: api.Write[];
/** Name of the IndexedDb object store. */
static store: string;
/** Keys are automatically assigned via the userId, batchId properties. */
static keyPath: string;
/** The index name for lookup of mutations by user. */
static userMutationsIndex: string;
/** The user mutations index is keyed by [userId, batchId] pairs. */
static userMutationsKeyPath: string[];
constructor(
/**
* The normalized user ID to which this batch belongs.
*/
userId: string,
/**
* An identifier for this batch, allocated using an auto-generated key.
*/
batchId: BatchId,
/**
* The local write time of the batch, stored as milliseconds since the
* epoch.
*/
localWriteTimeMs: number,
/**
* A list of "mutations" that represent a partial base state from when this
* write batch was initially created. During local application of the write
* batch, these baseMutations are applied prior to the real writes in order
* to override certain document fields from the remote document cache. This
* is necessary in the case of non-idempotent writes (e.g. `increment()`
* transforms) to make sure that the local view of the modified documents
* doesn't flicker if the remote document cache receives the result of the
* non-idempotent write before the write is removed from the queue.
*
* These mutations are never sent to the backend.
*/
baseMutations: api.Write[] | undefined,
/**
* A list of mutations to apply. All mutations will be applied atomically.
*
* Mutations are serialized via JsonProtoSerializer.toMutation().
*/
mutations: api.Write[]);
}
/**
* The key for a db document mutation, which is made up of a userID, path, and
* batchId. Note that the path must be serialized into a form that indexedDB can
* sort.
*/
export declare type DbDocumentMutationKey = [string, EncodedResourcePath, BatchId];
/**
* An object to be stored in the 'documentMutations' store in IndexedDb.
*
* A manually maintained index of all the mutation batches that affect a given
* document key. The rows in this table are references based on the contents of
* DbMutationBatch.mutations.
*/
export declare class DbDocumentMutation {
static store: string;
/**
* Creates a [userId] key for use in the DbDocumentMutations index to iterate
* over all of a user's document mutations.
*/
static prefixForUser(userId: string): [string];
/**
* Creates a [userId, encodedPath] key for use in the DbDocumentMutations
* index to iterate over all at document mutations for a given path or lower.
*/
static prefixForPath(userId: string, path: ResourcePath): [string, EncodedResourcePath];
/**
* Creates a full index key of [userId, encodedPath, batchId] for inserting
* and deleting into the DbDocumentMutations index.
*/
static key(userId: string, path: ResourcePath, batchId: BatchId): DbDocumentMutationKey;
/**
* Because we store all the useful information for this store in the key,
* there is no useful information to store as the value. The raw (unencoded)
* path cannot be stored because IndexedDb doesn't store prototype
* information.
*/
static PLACEHOLDER: DbDocumentMutation;
private constructor();
}
/**
* A key in the 'remoteDocuments' object store is a string array containing the
* segments that make up the path.
*/
export declare type DbRemoteDocumentKey = string[];
/**
* Represents the known absence of a document at a particular version.
* Stored in IndexedDb as part of a DbRemoteDocument object.
*/
export declare class DbNoDocument {
path: string[];
readTime: DbTimestamp;
constructor(path: string[], readTime: DbTimestamp);
}
/**
* Represents a document that is known to exist but whose data is unknown.
* Stored in IndexedDb as part of a DbRemoteDocument object.
*/
export declare class DbUnknownDocument {
path: string[];
version: DbTimestamp;
constructor(path: string[], version: DbTimestamp);
}
/**
* An object to be stored in the 'remoteDocuments' store in IndexedDb.
* It represents either:
*
* - A complete document.
* - A "no document" representing a document that is known not to exist (at
* some version).
* - An "unknown document" representing a document that is known to exist (at
* some version) but whose contents are unknown.
*
* Note: This is the persisted equivalent of a MaybeDocument and could perhaps
* be made more general if necessary.
*/
export declare class DbRemoteDocument {
/**
* Set to an instance of DbUnknownDocument if the data for a document is
* not known, but it is known that a document exists at the specified
* version (e.g. it had a successful update applied to it)
*/
unknownDocument: DbUnknownDocument | null | undefined;
/**
* Set to an instance of a DbNoDocument if it is known that no document
* exists.
*/
noDocument: DbNoDocument | null;
/**
* Set to an instance of a Document if there's a cached version of the
* document.
*/
document: api.Document | null;
/**
* Documents that were written to the remote document store based on
* a write acknowledgment are marked with `hasCommittedMutations`. These
* documents are potentially inconsistent with the backend's copy and use
* the write's commit version as their document version.
*/
hasCommittedMutations: boolean | undefined;
static store: string;
constructor(
/**
* Set to an instance of DbUnknownDocument if the data for a document is
* not known, but it is known that a document exists at the specified
* version (e.g. it had a successful update applied to it)
*/
unknownDocument: DbUnknownDocument | null | undefined,
/**
* Set to an instance of a DbNoDocument if it is known that no document
* exists.
*/
noDocument: DbNoDocument | null,
/**
* Set to an instance of a Document if there's a cached version of the
* document.
*/
document: api.Document | null,
/**
* Documents that were written to the remote document store based on
* a write acknowledgment are marked with `hasCommittedMutations`. These
* documents are potentially inconsistent with the backend's copy and use
* the write's commit version as their document version.
*/
hasCommittedMutations: boolean | undefined);
}
/**
* Contains a single entry that has metadata about the remote document cache.
*/
export declare class DbRemoteDocumentGlobal {
byteSize: number;
static store: string;
static key: string;
/**
* @param byteSize Approximately the total size in bytes of all the documents in the document
* cache.
*/
constructor(byteSize: number);
}
export declare type DbRemoteDocumentGlobalKey = typeof DbRemoteDocumentGlobal.key;
/**
* A key in the 'targets' object store is a targetId of the query.
*/
export declare type DbTargetKey = TargetId;
/**
* The persisted type for a query nested with in the 'targets' store in
* IndexedDb. We use the proto definitions for these two kinds of queries in
* order to avoid writing extra serialization logic.
*/
export declare type DbQuery = api.QueryTarget | api.DocumentsTarget;
/**
* An object to be stored in the 'targets' store in IndexedDb.
*
* This is based on and should be kept in sync with the proto used in the iOS
* client.
*
* Each query the client listens to against the server is tracked on disk so
* that the query can be efficiently resumed on restart.
*/
export declare class DbTarget {
/**
* An auto-generated sequential numeric identifier for the query.
*
* Queries are stored using their canonicalId as the key, but these
* canonicalIds can be quite long so we additionally assign a unique
* queryId which can be used by referenced data structures (e.g.
* indexes) to minimize the on-disk cost.
*/
targetId: TargetId;
/**
* The canonical string representing this query. This is not unique.
*/
canonicalId: string;
/**
* The last readTime received from the Watch Service for this query.
*
* This is the same value as TargetChange.read_time in the protos.
*/
readTime: DbTimestamp;
/**
* An opaque, server-assigned token that allows watching a query to be
* resumed after disconnecting without retransmitting all the data
* that matches the query. The resume token essentially identifies a
* point in time from which the server should resume sending results.
*
* This is related to the snapshotVersion in that the resumeToken
* effectively also encodes that value, but the resumeToken is opaque
* and sometimes encodes additional information.
*
* A consequence of this is that the resumeToken should be used when
* asking the server to reason about where this client is in the watch
* stream, but the client should use the snapshotVersion for its own
* purposes.
*
* This is the same value as TargetChange.resume_token in the protos.
*/
resumeToken: string;
/**
* A sequence number representing the last time this query was
* listened to, used for garbage collection purposes.
*
* Conventionally this would be a timestamp value, but device-local
* clocks are unreliable and they must be able to create new listens
* even while disconnected. Instead this should be a monotonically
* increasing number that's incremented on each listen call.
*
* This is different from the queryId since the queryId is an
* immutable identifier assigned to the Query on first use while
* lastListenSequenceNumber is updated every time the query is
* listened to.
*/
lastListenSequenceNumber: number;
/**
* The query for this target.
*
* Because canonical ids are not unique we must store the actual query. We
* use the proto to have an object we can persist without having to
* duplicate translation logic to and from a `Query` object.
*/
query: DbQuery;
static store: string;
/** Keys are automatically assigned via the targetId property. */
static keyPath: string;
/** The name of the queryTargets index. */
static queryTargetsIndexName: string;
/**
* The index of all canonicalIds to the targets that they match. This is not
* a unique mapping because canonicalId does not promise a unique name for all
* possible queries, so we append the targetId to make the mapping unique.
*/
static queryTargetsKeyPath: string[];
constructor(
/**
* An auto-generated sequential numeric identifier for the query.
*
* Queries are stored using their canonicalId as the key, but these
* canonicalIds can be quite long so we additionally assign a unique
* queryId which can be used by referenced data structures (e.g.
* indexes) to minimize the on-disk cost.
*/
targetId: TargetId,
/**
* The canonical string representing this query. This is not unique.
*/
canonicalId: string,
/**
* The last readTime received from the Watch Service for this query.
*
* This is the same value as TargetChange.read_time in the protos.
*/
readTime: DbTimestamp,
/**
* An opaque, server-assigned token that allows watching a query to be
* resumed after disconnecting without retransmitting all the data
* that matches the query. The resume token essentially identifies a
* point in time from which the server should resume sending results.
*
* This is related to the snapshotVersion in that the resumeToken
* effectively also encodes that value, but the resumeToken is opaque
* and sometimes encodes additional information.
*
* A consequence of this is that the resumeToken should be used when
* asking the server to reason about where this client is in the watch
* stream, but the client should use the snapshotVersion for its own
* purposes.
*
* This is the same value as TargetChange.resume_token in the protos.
*/
resumeToken: string,
/**
* A sequence number representing the last time this query was
* listened to, used for garbage collection purposes.
*
* Conventionally this would be a timestamp value, but device-local
* clocks are unreliable and they must be able to create new listens
* even while disconnected. Instead this should be a monotonically
* increasing number that's incremented on each listen call.
*
* This is different from the queryId since the queryId is an
* immutable identifier assigned to the Query on first use while
* lastListenSequenceNumber is updated every time the query is
* listened to.
*/
lastListenSequenceNumber: number,
/**
* The query for this target.
*
* Because canonical ids are not unique we must store the actual query. We
* use the proto to have an object we can persist without having to
* duplicate translation logic to and from a `Query` object.
*/
query: DbQuery);
}
/**
* The key for a DbTargetDocument, containing a targetId and an encoded resource
* path.
*/
export declare type DbTargetDocumentKey = [TargetId, EncodedResourcePath];
/**
* An object representing an association between a target and a document, or a
* sentinel row marking the last sequence number at which a document was used.
* Each document cached must have a corresponding sentinel row before lru
* garbage collection is enabled.
*
* The target associations and sentinel rows are co-located so that orphaned
* documents and their sequence numbers can be identified efficiently via a scan
* of this store.
*/
export declare class DbTargetDocument {
/**
* The targetId identifying a target or 0 for a sentinel row.
*/
targetId: TargetId;
/**
* The path to the document, as encoded in the key.
*/
path: EncodedResourcePath;
/**
* If this is a sentinel row, this should be the sequence number of the last
* time the document specified by `path` was used. Otherwise, it should be
* `undefined`.
*/
sequenceNumber?: number | undefined;
/** Name of the IndexedDb object store. */
static store: string;
/** Keys are automatically assigned via the targetId, path properties. */
static keyPath: string[];
/** The index name for the reverse index. */
static documentTargetsIndex: string;
/** We also need to create the reverse index for these properties. */
static documentTargetsKeyPath: string[];
constructor(
/**
* The targetId identifying a target or 0 for a sentinel row.
*/
targetId: TargetId,
/**
* The path to the document, as encoded in the key.
*/
path: EncodedResourcePath,
/**
* If this is a sentinel row, this should be the sequence number of the last
* time the document specified by `path` was used. Otherwise, it should be
* `undefined`.
*/
sequenceNumber?: number | undefined);
}
/**
* The type to represent the single allowed key for the DbTargetGlobal store.
*/
export declare type DbTargetGlobalKey = typeof DbTargetGlobal.key;
/**
* A record of global state tracked across all Targets, tracked separately
* to avoid the need for extra indexes.
*
* This should be kept in-sync with the proto used in the iOS client.
*/
export declare class DbTargetGlobal {
/**
* The highest numbered target id across all targets.
*
* See DbTarget.targetId.
*/
highestTargetId: TargetId;
/**
* The highest numbered lastListenSequenceNumber across all targets.
*
* See DbTarget.lastListenSequenceNumber.
*/
highestListenSequenceNumber: number;
/**
* A global snapshot version representing the last consistent snapshot we
* received from the backend. This is monotonically increasing and any
* snapshots received from the backend prior to this version (e.g. for
* targets resumed with a resumeToken) should be suppressed (buffered)
* until the backend has caught up to this snapshot version again. This
* prevents our cache from ever going backwards in time.
*/
lastRemoteSnapshotVersion: DbTimestamp;
/**
* The number of targets persisted.
*/
targetCount: number;
/**
* The key string used for the single object that exists in the
* DbTargetGlobal store.
*/
static key: string;
static store: string;
constructor(
/**
* The highest numbered target id across all targets.
*
* See DbTarget.targetId.
*/
highestTargetId: TargetId,
/**
* The highest numbered lastListenSequenceNumber across all targets.
*
* See DbTarget.lastListenSequenceNumber.
*/
highestListenSequenceNumber: number,
/**
* A global snapshot version representing the last consistent snapshot we
* received from the backend. This is monotonically increasing and any
* snapshots received from the backend prior to this version (e.g. for
* targets resumed with a resumeToken) should be suppressed (buffered)
* until the backend has caught up to this snapshot version again. This
* prevents our cache from ever going backwards in time.
*/
lastRemoteSnapshotVersion: DbTimestamp,
/**
* The number of targets persisted.
*/
targetCount: number);
}
/**
* The key for a DbCollectionParent entry, containing the collection ID
* and the parent path that contains it. Note that the parent path will be an
* empty path in the case of root-level collections.
*/
export declare type DbCollectionParentKey = [string, EncodedResourcePath];
/**
* An object representing an association between a Collection id (e.g. 'messages')
* to a parent path (e.g. '/chats/123') that contains it as a (sub)collection.
* This is used to efficiently find all collections to query when performing
* a Collection Group query.
*/
export declare class DbCollectionParent {
/**
* The collectionId (e.g. 'messages')
*/
collectionId: string;
/**
* The path to the parent (either a document location or an empty path for
* a root-level collection).
*/
parent: EncodedResourcePath;
/** Name of the IndexedDb object store. */
static store: string;
/** Keys are automatically assigned via the collectionId, parent properties. */
static keyPath: string[];
constructor(
/**
* The collectionId (e.g. 'messages')
*/
collectionId: string,
/**
* The path to the parent (either a document location or an empty path for
* a root-level collection).
*/
parent: EncodedResourcePath);
}
/**
* An object store to store the keys of changed documents. This is used to
* facilitate storing document changelogs in the Remote Document Cache.
*
* PORTING NOTE: This is used for change propagation during multi-tab syncing
* and not needed on iOS and Android.
*/
export declare class DbRemoteDocumentChanges {
/** The keys of the changed documents. */
changes: EncodedResourcePath[];
/** Name of the IndexedDb object store. */
static store: string;
/** Keys are auto-generated via the `id` property. */
static keyPath: string;
/** The auto-generated key of this entry. */
id?: number;
constructor(
/** The keys of the changed documents. */
changes: EncodedResourcePath[]);
}
export declare type DbRemoteDocumentChangesKey = number;
/**
* A record of the metadata state of each client.
*
* PORTING NOTE: This is used to synchronize multi-tab state and does not need
* to be ported to iOS or Android.
*/
export declare class DbClientMetadata {
/** The auto-generated client id assigned at client startup. */
clientId: string;
/** The last time this state was updated. */
updateTimeMs: number;
/** Whether the client's network connection is enabled. */
networkEnabled: boolean;
/** Whether this client is running in a foreground tab. */
inForeground: boolean;
/**
* The last change read from the DbRemoteDocumentChanges store.
* Can be undefined for backwards compatibility.
*/
lastProcessedDocumentChangeId: number | undefined;
/** Name of the IndexedDb object store. */
static store: string;
/** Keys are automatically assigned via the clientId properties. */
static keyPath: string;
constructor(
/** The auto-generated client id assigned at client startup. */
clientId: string,
/** The last time this state was updated. */
updateTimeMs: number,
/** Whether the client's network connection is enabled. */
networkEnabled: boolean,
/** Whether this client is running in a foreground tab. */
inForeground: boolean,
/**
* The last change read from the DbRemoteDocumentChanges store.
* Can be undefined for backwards compatibility.
*/
lastProcessedDocumentChangeId: number | undefined);
}
/** Object keys in the 'clientMetadata' store are clientId strings. */
export declare type DbClientMetadataKey = string;
export declare const V1_STORES: string[];
export declare const V3_STORES: string[];
export declare const V4_STORES: string[];
export declare const V6_STORES: string[];
export declare const V8_STORES: string[];
/**
* The list of all default IndexedDB stores used throughout the SDK. This is
* used when creating transactions so that access across all stores is done
* atomically.
*/
export declare const ALL_STORES: string[];

View File

@@ -0,0 +1,65 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { Query } from '../core/query';
import { DocumentKeySet, DocumentMap, MaybeDocumentMap, NullableMaybeDocumentMap } from '../model/collections';
import { MaybeDocument } from '../model/document';
import { DocumentKey } from '../model/document_key';
import { IndexManager } from './index_manager';
import { MutationQueue } from './mutation_queue';
import { PersistenceTransaction } from './persistence';
import { PersistencePromise } from './persistence_promise';
import { RemoteDocumentCache } from './remote_document_cache';
/**
* A readonly view of the local state of all documents we're tracking (i.e. we
* have a cached version in remoteDocumentCache or local mutations for the
* document). The view is computed by applying the mutations in the
* MutationQueue to the RemoteDocumentCache.
*/
export declare class LocalDocumentsView {
private remoteDocumentCache;
private mutationQueue;
private indexManager;
constructor(remoteDocumentCache: RemoteDocumentCache, mutationQueue: MutationQueue, indexManager: IndexManager);
/**
* Get the local view of the document identified by `key`.
*
* @return Local view of the document or null if we don't have any cached
* state for it.
*/
getDocument(transaction: PersistenceTransaction, key: DocumentKey): PersistencePromise<MaybeDocument | null>;
/** Internal version of `getDocument` that allows reusing batches. */
private getDocumentInternal;
private applyLocalMutationsToDocuments;
/**
* Gets the local view of the documents identified by `keys`.
*
* If we don't have cached state for a document in `keys`, a NoDocument will
* be stored for that key in the resulting set.
*/
getDocuments(transaction: PersistenceTransaction, keys: DocumentKeySet): PersistencePromise<MaybeDocumentMap>;
/**
* Similar to `getDocuments`, but creates the local view from the given
* `baseDocs` without retrieving documents from the local store.
*/
getLocalViewOfDocuments(transaction: PersistenceTransaction, baseDocs: NullableMaybeDocumentMap): PersistencePromise<MaybeDocumentMap>;
/** Performs a query against the local view of all documents. */
getDocumentsMatchingQuery(transaction: PersistenceTransaction, query: Query): PersistencePromise<DocumentMap>;
private getDocumentsMatchingDocumentQuery;
private getDocumentsMatchingCollectionGroupQuery;
private getDocumentsMatchingCollectionQuery;
private addMissingBaseDocuments;
}

View File

@@ -0,0 +1,45 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { MaybeDocument } from '../model/document';
import { MutationBatch } from '../model/mutation_batch';
import { JsonProtoSerializer } from '../remote/serializer';
import { DocumentKeySet } from '../model/collections';
import { EncodedResourcePath } from './encoded_resource_path';
import { DbMutationBatch, DbRemoteDocument, DbTarget } from './indexeddb_schema';
import { QueryData } from './query_data';
/** Serializer for values stored in the LocalStore. */
export declare class LocalSerializer {
private remoteSerializer;
constructor(remoteSerializer: JsonProtoSerializer);
/** Decodes a remote document from storage locally to a Document. */
fromDbRemoteDocument(remoteDoc: DbRemoteDocument): MaybeDocument;
/** Encodes a document for storage locally. */
toDbRemoteDocument(maybeDoc: MaybeDocument): DbRemoteDocument;
private toDbTimestamp;
private fromDbTimestamp;
/** Encodes a batch of mutations into a DbMutationBatch for local storage. */
toDbMutationBatch(userId: string, batch: MutationBatch): DbMutationBatch;
/** Decodes a DbMutationBatch into a MutationBatch */
fromDbMutationBatch(dbBatch: DbMutationBatch): MutationBatch;
toDbResourcePaths(keys: DocumentKeySet): EncodedResourcePath[];
/** Decodes an array of EncodedResourcePaths into a set of document keys. */
fromDbResourcePaths(encodedPaths: EncodedResourcePath[]): DocumentKeySet;
/** Decodes a DbTarget into QueryData */
fromDbTarget(dbTarget: DbTarget): QueryData;
/** Encodes QueryData into a DbTarget for storage locally. */
toDbTarget(queryData: QueryData): DbTarget;
}

View File

@@ -0,0 +1,244 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { User } from '../auth/user';
import { Query } from '../core/query';
import { SnapshotVersion } from '../core/snapshot_version';
import { BatchId, ProtoByteString, TargetId } from '../core/types';
import { DocumentKeySet, DocumentMap, MaybeDocumentMap } from '../model/collections';
import { MaybeDocument } from '../model/document';
import { DocumentKey } from '../model/document_key';
import { Mutation } from '../model/mutation';
import { MutationBatch, MutationBatchResult } from '../model/mutation_batch';
import { RemoteEvent } from '../remote/remote_event';
import { LocalViewChanges } from './local_view_changes';
import { LruGarbageCollector, LruResults } from './lru_garbage_collector';
import { Persistence } from './persistence';
import { QueryData } from './query_data';
import { ClientId } from './shared_client_state';
/** The result of a write to the local store. */
export interface LocalWriteResult {
batchId: BatchId;
changes: MaybeDocumentMap;
}
/** The result of a user-change operation in the local store. */
export interface UserChangeResult {
readonly affectedDocuments: MaybeDocumentMap;
readonly removedBatchIds: BatchId[];
readonly addedBatchIds: BatchId[];
}
/**
* Local storage in the Firestore client. Coordinates persistence components
* like the mutation queue and remote document cache to present a
* latency-compensated view of stored data.
*
* The LocalStore is responsible for accepting mutations from the Sync Engine.
* Writes from the client are put into a queue as provisional Mutations until
* they are processed by the RemoteStore and confirmed as having been written
* to the server.
*
* The local store provides the local version of documents that have been
* modified locally. It maintains the constraint:
*
* LocalDocument = RemoteDocument + Active(LocalMutations)
*
* (Active mutations are those that are enqueued and have not been previously
* acknowledged or rejected).
*
* The RemoteDocument ("ground truth") state is provided via the
* applyChangeBatch method. It will be some version of a server-provided
* document OR will be a server-provided document PLUS acknowledged mutations:
*
* RemoteDocument' = RemoteDocument + Acknowledged(LocalMutations)
*
* Note that this "dirty" version of a RemoteDocument will not be identical to a
* server base version, since it has LocalMutations added to it pending getting
* an authoritative copy from the server.
*
* Since LocalMutations can be rejected by the server, we have to be able to
* revert a LocalMutation that has already been applied to the LocalDocument
* (typically done by replaying all remaining LocalMutations to the
* RemoteDocument to re-apply).
*
* The LocalStore is responsible for the garbage collection of the documents it
* contains. For now, it every doc referenced by a view, the mutation queue, or
* the RemoteStore.
*
* It also maintains the persistence of mapping queries to resume tokens and
* target ids. It needs to know this data about queries to properly know what
* docs it would be allowed to garbage collect.
*
* The LocalStore must be able to efficiently execute queries against its local
* cache of the documents, to provide the initial set of results before any
* remote changes have been received.
*
* Note: In TypeScript, most methods return Promises since the implementation
* may rely on fetching data from IndexedDB which is async.
* These Promises will only be rejected on an I/O error or other internal
* (unexpected) failure (e.g. failed assert) and always represent an
* unrecoverable error (should be caught / reported by the async_queue).
*/
export declare class LocalStore {
/** Manages our in-memory or durable persistence. */
private persistence;
/**
* The maximum time to leave a resume token buffered without writing it out.
* This value is arbitrary: it's long enough to avoid several writes
* (possibly indefinitely if updates come more frequently than this) but
* short enough that restarting after crashing will still have a pretty
* recent resume token.
*/
private static readonly RESUME_TOKEN_MAX_AGE_MICROS;
/**
* The set of all mutations that have been sent but not yet been applied to
* the backend.
*/
private mutationQueue;
/** The set of all cached remote documents. */
private remoteDocuments;
/**
* The "local" view of all documents (layering mutationQueue on top of
* remoteDocumentCache).
*/
private localDocuments;
/**
* The set of document references maintained by any local views.
*/
private localViewReferences;
/** Maps a query to the data about that query. */
private queryCache;
/** Maps a targetID to data about its query. */
private queryDataByTarget;
constructor(
/** Manages our in-memory or durable persistence. */
persistence: Persistence, initialUser: User);
/**
* Tells the LocalStore that the currently authenticated user has changed.
*
* In response the local store switches the mutation queue to the new user and
* returns any resulting document changes.
*/
handleUserChange(user: User): Promise<UserChangeResult>;
localWrite(mutations: Mutation[]): Promise<LocalWriteResult>;
/** Returns the local view of the documents affected by a mutation batch. */
lookupMutationDocuments(batchId: BatchId): Promise<MaybeDocumentMap | null>;
/**
* Acknowledge the given batch.
*
* On the happy path when a batch is acknowledged, the local store will
*
* + remove the batch from the mutation queue;
* + apply the changes to the remote document cache;
* + recalculate the latency compensated view implied by those changes (there
* may be mutations in the queue that affect the documents but haven't been
* acknowledged yet); and
* + give the changed documents back the sync engine
*
* @returns The resulting (modified) documents.
*/
acknowledgeBatch(batchResult: MutationBatchResult): Promise<MaybeDocumentMap>;
/**
* Remove mutations from the MutationQueue for the specified batch;
* LocalDocuments will be recalculated.
*
* @returns The resulting modified documents.
*/
rejectBatch(batchId: BatchId): Promise<MaybeDocumentMap>;
/**
* Returns the largest (latest) batch id in mutation queue that is pending server response.
* Returns `BATCHID_UNKNOWN` if the queue is empty.
*/
getHighestUnacknowledgedBatchId(): Promise<BatchId>;
/** Returns the last recorded stream token for the current user. */
getLastStreamToken(): Promise<ProtoByteString>;
/**
* Sets the stream token for the current user without acknowledging any
* mutation batch. This is usually only useful after a stream handshake or in
* response to an error that requires clearing the stream token.
*/
setLastStreamToken(streamToken: ProtoByteString): Promise<void>;
/**
* Returns the last consistent snapshot processed (used by the RemoteStore to
* determine whether to buffer incoming snapshots from the backend).
*/
getLastRemoteSnapshotVersion(): Promise<SnapshotVersion>;
/**
* Update the "ground-state" (remote) documents. We assume that the remote
* event reflects any write batches that have been acknowledged or rejected
* (i.e. we do not re-apply local mutations to updates from this event).
*
* LocalDocuments are re-calculated if there are remaining mutations in the
* queue.
*/
applyRemoteEvent(remoteEvent: RemoteEvent): Promise<MaybeDocumentMap>;
/**
* Returns true if the newQueryData should be persisted during an update of
* an active target. QueryData should always be persisted when a target is
* being released and should not call this function.
*
* While the target is active, QueryData updates can be omitted when nothing
* about the target has changed except metadata like the resume token or
* snapshot version. Occasionally it's worth the extra write to prevent these
* values from getting too stale after a crash, but this doesn't have to be
* too frequent.
*/
private static shouldPersistQueryData;
/**
* Notify local store of the changed views to locally pin documents.
*/
notifyLocalViewChanges(viewChanges: LocalViewChanges[]): Promise<void>;
/**
* Gets the mutation batch after the passed in batchId in the mutation queue
* or null if empty.
* @param afterBatchId If provided, the batch to search after.
* @returns The next mutation or null if there wasn't one.
*/
nextMutationBatch(afterBatchId?: BatchId): Promise<MutationBatch | null>;
/**
* Read the current value of a Document with a given key or null if not
* found - used for testing.
*/
readDocument(key: DocumentKey): Promise<MaybeDocument | null>;
/**
* Assigns the given query an internal ID so that its results can be pinned so
* they don't get GC'd. A query must be allocated in the local store before
* the store can be used to manage its view.
*/
allocateQuery(query: Query): Promise<QueryData>;
/**
* Unpin all the documents associated with the given query. If
* `keepPersistedQueryData` is set to false and Eager GC enabled, the method
* directly removes the associated query data from the query cache.
*/
releaseQuery(query: Query, keepPersistedQueryData: boolean): Promise<void>;
/**
* Runs the specified query against all the documents in the local store and
* returns the results.
*/
executeQuery(query: Query): Promise<DocumentMap>;
/**
* Returns the keys of the documents that are associated with the given
* target id in the remote table.
*/
remoteDocumentKeys(targetId: TargetId): Promise<DocumentKeySet>;
getActiveClients(): Promise<ClientId[]>;
removeCachedMutationBatchMetadata(batchId: BatchId): void;
setNetworkEnabled(networkEnabled: boolean): void;
private applyWriteToRemoteDocuments;
collectGarbage(garbageCollector: LruGarbageCollector): Promise<LruResults>;
getQueryForTarget(targetId: TargetId): Promise<Query | null>;
getNewDocumentChanges(): Promise<MaybeDocumentMap>;
}

View File

@@ -0,0 +1,31 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { TargetId } from '../core/types';
import { ViewSnapshot } from '../core/view_snapshot';
import { DocumentKeySet } from '../model/collections';
/**
* A set of changes to what documents are currently in view and out of view for
* a given query. These changes are sent to the LocalStore by the View (via
* the SyncEngine) and are used to pin / unpin documents as appropriate.
*/
export declare class LocalViewChanges {
readonly targetId: TargetId;
readonly addedKeys: DocumentKeySet;
readonly removedKeys: DocumentKeySet;
constructor(targetId: TargetId, addedKeys: DocumentKeySet, removedKeys: DocumentKeySet);
static fromSnapshot(targetId: TargetId, viewSnapshot: ViewSnapshot): LocalViewChanges;
}

View File

@@ -0,0 +1,125 @@
/**
* @license
* Copyright 2018 Google Inc.
*
* 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.
*/
import { ListenSequenceNumber } from '../core/types';
import { AsyncQueue } from '../util/async_queue';
import { LocalStore } from './local_store';
import { PersistenceTransaction } from './persistence';
import { PersistencePromise } from './persistence_promise';
import { QueryData } from './query_data';
/**
* Persistence layers intending to use LRU Garbage collection should have reference delegates that
* implement this interface. This interface defines the operations that the LRU garbage collector
* needs from the persistence layer.
*/
export interface LruDelegate {
readonly garbageCollector: LruGarbageCollector;
/** Enumerates all the targets in the QueryCache. */
forEachTarget(txn: PersistenceTransaction, f: (target: QueryData) => void): PersistencePromise<void>;
getSequenceNumberCount(txn: PersistenceTransaction): PersistencePromise<number>;
/**
* Enumerates sequence numbers for documents not associated with a target.
* Note that this may include duplicate sequence numbers.
*/
forEachOrphanedDocumentSequenceNumber(txn: PersistenceTransaction, f: (sequenceNumber: ListenSequenceNumber) => void): PersistencePromise<void>;
/**
* Removes all targets that have a sequence number less than or equal to `upperBound`, and are not
* present in the `activeTargetIds` set.
*
* @return the number of targets removed.
*/
removeTargets(txn: PersistenceTransaction, upperBound: ListenSequenceNumber, activeTargetIds: ActiveTargets): PersistencePromise<number>;
/**
* Removes all unreferenced documents from the cache that have a sequence number less than or
* equal to the given `upperBound`.
*
* @return the number of documents removed.
*/
removeOrphanedDocuments(txn: PersistenceTransaction, upperBound: ListenSequenceNumber): PersistencePromise<number>;
getCacheSize(txn: PersistenceTransaction): PersistencePromise<number>;
}
/**
* Describes an object whose keys are active target ids. We do not care about the type of the
* values.
*/
export interface ActiveTargets {
[id: number]: unknown;
}
/**
* Describes the results of a garbage collection run. `didRun` will be set to
* `false` if collection was skipped (either it is disabled or the cache size
* has not hit the threshold). If collection ran, the other fields will be
* filled in with the details of the results.
*/
export interface LruResults {
readonly didRun: boolean;
readonly sequenceNumbersCollected: number;
readonly targetsRemoved: number;
readonly documentsRemoved: number;
}
export declare class LruParams {
readonly cacheSizeCollectionThreshold: number;
readonly percentileToCollect: number;
readonly maximumSequenceNumbersToCollect: number;
static readonly COLLECTION_DISABLED = -1;
static readonly MINIMUM_CACHE_SIZE_BYTES: number;
static readonly DEFAULT_CACHE_SIZE_BYTES: number;
private static readonly DEFAULT_COLLECTION_PERCENTILE;
private static readonly DEFAULT_MAX_SEQUENCE_NUMBERS_TO_COLLECT;
static withCacheSize(cacheSize: number): LruParams;
static readonly DEFAULT: LruParams;
static readonly DISABLED: LruParams;
constructor(cacheSizeCollectionThreshold: number, percentileToCollect: number, maximumSequenceNumbersToCollect: number);
}
/**
* This class is responsible for the scheduling of LRU garbage collection. It handles checking
* whether or not GC is enabled, as well as which delay to use before the next run.
*/
export declare class LruScheduler {
private readonly garbageCollector;
private readonly asyncQueue;
private readonly localStore;
private hasRun;
private gcTask;
constructor(garbageCollector: LruGarbageCollector, asyncQueue: AsyncQueue, localStore: LocalStore);
start(): void;
stop(): void;
readonly started: boolean;
private scheduleGC;
}
/** Implements the steps for LRU garbage collection. */
export declare class LruGarbageCollector {
private readonly delegate;
readonly params: LruParams;
constructor(delegate: LruDelegate, params: LruParams);
/** Given a percentile of target to collect, returns the number of targets to collect. */
calculateTargetCount(txn: PersistenceTransaction, percentile: number): PersistencePromise<number>;
/** Returns the nth sequence number, counting in order from the smallest. */
nthSequenceNumber(txn: PersistenceTransaction, n: number): PersistencePromise<ListenSequenceNumber>;
/**
* Removes targets with a sequence number equal to or less than the given upper bound, and removes
* document associations with those targets.
*/
removeTargets(txn: PersistenceTransaction, upperBound: ListenSequenceNumber, activeTargetIds: ActiveTargets): PersistencePromise<number>;
/**
* Removes documents that have a sequence number equal to or less than the upper bound and are not
* otherwise pinned.
*/
removeOrphanedDocuments(txn: PersistenceTransaction, upperBound: ListenSequenceNumber): PersistencePromise<number>;
collect(txn: PersistenceTransaction, activeTargetIds: ActiveTargets): PersistencePromise<LruResults>;
getCacheSize(txn: PersistenceTransaction): PersistencePromise<number>;
private runGarbageCollection;
}

View File

@@ -0,0 +1,38 @@
/**
* @license
* Copyright 2019 Google Inc.
*
* 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.
*/
import { ResourcePath } from '../model/path';
import { IndexManager } from './index_manager';
import { PersistenceTransaction } from './persistence';
import { PersistencePromise } from './persistence_promise';
/**
* An in-memory implementation of IndexManager.
*/
export declare class MemoryIndexManager implements IndexManager {
private collectionParentIndex;
addToCollectionParentIndex(transaction: PersistenceTransaction, collectionPath: ResourcePath): PersistencePromise<void>;
getCollectionParents(transaction: PersistenceTransaction, collectionId: string): PersistencePromise<ResourcePath[]>;
}
/**
* Internal implementation of the collection-parent index exposed by MemoryIndexManager.
* Also used for in-memory caching by IndexedDbIndexManager and initial index population
* in indexeddb_schema.ts
*/
export declare class MemoryCollectionParentIndex {
private index;
add(collectionPath: ResourcePath): boolean;
getEntries(collectionId: string): ResourcePath[];
}

View File

@@ -0,0 +1,89 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { Timestamp } from '../api/timestamp';
import { Query } from '../core/query';
import { BatchId, ProtoByteString } from '../core/types';
import { DocumentKeySet } from '../model/collections';
import { DocumentKey } from '../model/document_key';
import { Mutation } from '../model/mutation';
import { MutationBatch } from '../model/mutation_batch';
import { SortedMap } from '../util/sorted_map';
import { IndexManager } from './index_manager';
import { MutationQueue } from './mutation_queue';
import { PersistenceTransaction, ReferenceDelegate } from './persistence';
import { PersistencePromise } from './persistence_promise';
export declare class MemoryMutationQueue implements MutationQueue {
private readonly indexManager;
private readonly referenceDelegate;
/**
* The set of all mutations that have been sent but not yet been applied to
* the backend.
*/
private mutationQueue;
/** Next value to use when assigning sequential IDs to each mutation batch. */
private nextBatchId;
/** The last received stream token from the server, used to acknowledge which
* responses the client has processed. Stream tokens are opaque checkpoint
* markers whose only real value is their inclusion in the next request.
*/
private lastStreamToken;
/** An ordered mapping between documents and the mutations batch IDs. */
private batchesByDocumentKey;
constructor(indexManager: IndexManager, referenceDelegate: ReferenceDelegate);
checkEmpty(transaction: PersistenceTransaction): PersistencePromise<boolean>;
acknowledgeBatch(transaction: PersistenceTransaction, batch: MutationBatch, streamToken: ProtoByteString): PersistencePromise<void>;
getLastStreamToken(transaction: PersistenceTransaction): PersistencePromise<ProtoByteString>;
setLastStreamToken(transaction: PersistenceTransaction, streamToken: ProtoByteString): PersistencePromise<void>;
addMutationBatch(transaction: PersistenceTransaction, localWriteTime: Timestamp, baseMutations: Mutation[], mutations: Mutation[]): PersistencePromise<MutationBatch>;
lookupMutationBatch(transaction: PersistenceTransaction, batchId: BatchId): PersistencePromise<MutationBatch | null>;
lookupMutationKeys(transaction: PersistenceTransaction, batchId: BatchId): PersistencePromise<DocumentKeySet | null>;
getNextMutationBatchAfterBatchId(transaction: PersistenceTransaction, batchId: BatchId): PersistencePromise<MutationBatch | null>;
getHighestUnacknowledgedBatchId(): PersistencePromise<BatchId>;
getAllMutationBatches(transaction: PersistenceTransaction): PersistencePromise<MutationBatch[]>;
getAllMutationBatchesAffectingDocumentKey(transaction: PersistenceTransaction, documentKey: DocumentKey): PersistencePromise<MutationBatch[]>;
getAllMutationBatchesAffectingDocumentKeys(transaction: PersistenceTransaction, documentKeys: SortedMap<DocumentKey, unknown>): PersistencePromise<MutationBatch[]>;
getAllMutationBatchesAffectingQuery(transaction: PersistenceTransaction, query: Query): PersistencePromise<MutationBatch[]>;
private findMutationBatches;
removeMutationBatch(transaction: PersistenceTransaction, batch: MutationBatch): PersistencePromise<void>;
removeCachedMutationKeys(batchId: BatchId): void;
containsKey(txn: PersistenceTransaction, key: DocumentKey): PersistencePromise<boolean>;
performConsistencyCheck(txn: PersistenceTransaction): PersistencePromise<void>;
/**
* Finds the index of the given batchId in the mutation queue and asserts that
* the resulting index is within the bounds of the queue.
*
* @param batchId The batchId to search for
* @param action A description of what the caller is doing, phrased in passive
* form (e.g. "acknowledged" in a routine that acknowledges batches).
*/
private indexOfExistingBatchId;
/**
* Finds the index of the given batchId in the mutation queue. This operation
* is O(1).
*
* @return The computed index of the batch with the given batchId, based on
* the state of the queue. Note this index can be negative if the requested
* batchId has already been remvoed from the queue or past the end of the
* queue if the batchId is larger than the last added batch.
*/
private indexOfBatchId;
/**
* A version of lookupMutationBatch that doesn't return a promise, this makes
* other functions that uses this code easier to read and more efficent.
*/
private findMutationBatch;
}

View File

@@ -0,0 +1,124 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { User } from '../auth/user';
import { MaybeDocument } from '../model/document';
import { DocumentKey } from '../model/document_key';
import { JsonProtoSerializer } from '../remote/serializer';
import { LocalSerializer } from './local_serializer';
import { ActiveTargets, LruDelegate, LruGarbageCollector, LruParams } from './lru_garbage_collector';
import { ListenSequenceNumber } from '../core/types';
import { MemoryIndexManager } from './memory_index_manager';
import { MemoryQueryCache } from './memory_query_cache';
import { MemoryRemoteDocumentCache } from './memory_remote_document_cache';
import { MutationQueue } from './mutation_queue';
import { Persistence, PersistenceTransaction, PrimaryStateListener, ReferenceDelegate } from './persistence';
import { PersistencePromise } from './persistence_promise';
import { QueryData } from './query_data';
import { ReferenceSet } from './reference_set';
import { ClientId } from './shared_client_state';
/**
* A memory-backed instance of Persistence. Data is stored only in RAM and
* not persisted across sessions.
*/
export declare class MemoryPersistence implements Persistence {
private readonly clientId;
/**
* Note that these are retained here to make it easier to write tests
* affecting both the in-memory and IndexedDB-backed persistence layers. Tests
* can create a new LocalStore wrapping this Persistence instance and this
* will make the in-memory persistence layer behave as if it were actually
* persisting values.
*/
private readonly indexManager;
private mutationQueues;
private readonly remoteDocumentCache;
private readonly queryCache;
private readonly listenSequence;
private _started;
readonly referenceDelegate: MemoryLruDelegate | MemoryEagerDelegate;
static createLruPersistence(clientId: ClientId, serializer: JsonProtoSerializer, params: LruParams): MemoryPersistence;
static createEagerPersistence(clientId: ClientId): MemoryPersistence;
/**
* The constructor accepts a factory for creating a reference delegate. This
* allows both the delegate and this instance to have strong references to
* each other without having nullable fields that would then need to be
* checked or asserted on every access.
*/
private constructor();
shutdown(): Promise<void>;
readonly started: boolean;
getActiveClients(): Promise<ClientId[]>;
setPrimaryStateListener(primaryStateListener: PrimaryStateListener): Promise<void>;
setDatabaseDeletedListener(): void;
setNetworkEnabled(networkEnabled: boolean): void;
getIndexManager(): MemoryIndexManager;
getMutationQueue(user: User): MutationQueue;
getQueryCache(): MemoryQueryCache;
getRemoteDocumentCache(): MemoryRemoteDocumentCache;
runTransaction<T>(action: string, mode: 'readonly' | 'readwrite' | 'readwrite-primary', transactionOperation: (transaction: PersistenceTransaction) => PersistencePromise<T>): Promise<T>;
mutationQueuesContainKey(transaction: PersistenceTransaction, key: DocumentKey): PersistencePromise<boolean>;
}
/**
* Memory persistence is not actually transactional, but future implementations
* may have transaction-scoped state.
*/
export declare class MemoryTransaction implements PersistenceTransaction {
readonly currentSequenceNumber: ListenSequenceNumber;
constructor(currentSequenceNumber: ListenSequenceNumber);
}
export declare class MemoryEagerDelegate implements ReferenceDelegate {
private readonly persistence;
private inMemoryPins;
private _orphanedDocuments;
constructor(persistence: MemoryPersistence);
private readonly orphanedDocuments;
setInMemoryPins(inMemoryPins: ReferenceSet): void;
addReference(txn: PersistenceTransaction, key: DocumentKey): PersistencePromise<void>;
removeReference(txn: PersistenceTransaction, key: DocumentKey): PersistencePromise<void>;
removeMutationReference(txn: PersistenceTransaction, key: DocumentKey): PersistencePromise<void>;
removeTarget(txn: PersistenceTransaction, queryData: QueryData): PersistencePromise<void>;
onTransactionStarted(): void;
onTransactionCommitted(txn: PersistenceTransaction): PersistencePromise<void>;
updateLimboDocument(txn: PersistenceTransaction, key: DocumentKey): PersistencePromise<void>;
documentSize(doc: MaybeDocument): number;
private isReferenced;
}
export declare class MemoryLruDelegate implements ReferenceDelegate, LruDelegate {
private readonly persistence;
private readonly serializer;
private inMemoryPins;
private orphanedSequenceNumbers;
readonly garbageCollector: LruGarbageCollector;
constructor(persistence: MemoryPersistence, serializer: LocalSerializer, lruParams: LruParams);
onTransactionStarted(): void;
onTransactionCommitted(txn: PersistenceTransaction): PersistencePromise<void>;
forEachTarget(txn: PersistenceTransaction, f: (q: QueryData) => void): PersistencePromise<void>;
getSequenceNumberCount(txn: PersistenceTransaction): PersistencePromise<number>;
private orphanedDocumentCount;
forEachOrphanedDocumentSequenceNumber(txn: PersistenceTransaction, f: (sequenceNumber: ListenSequenceNumber) => void): PersistencePromise<void>;
setInMemoryPins(inMemoryPins: ReferenceSet): void;
removeTargets(txn: PersistenceTransaction, upperBound: ListenSequenceNumber, activeTargetIds: ActiveTargets): PersistencePromise<number>;
removeOrphanedDocuments(txn: PersistenceTransaction, upperBound: ListenSequenceNumber): PersistencePromise<number>;
removeMutationReference(txn: PersistenceTransaction, key: DocumentKey): PersistencePromise<void>;
removeTarget(txn: PersistenceTransaction, queryData: QueryData): PersistencePromise<void>;
addReference(txn: PersistenceTransaction, key: DocumentKey): PersistencePromise<void>;
removeReference(txn: PersistenceTransaction, key: DocumentKey): PersistencePromise<void>;
updateLimboDocument(txn: PersistenceTransaction, key: DocumentKey): PersistencePromise<void>;
documentSize(maybeDoc: MaybeDocument): number;
private isPinned;
getCacheSize(txn: PersistenceTransaction): PersistencePromise<number>;
}

View File

@@ -0,0 +1,67 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { Query } from '../core/query';
import { SnapshotVersion } from '../core/snapshot_version';
import { ListenSequenceNumber, TargetId } from '../core/types';
import { DocumentKeySet } from '../model/collections';
import { DocumentKey } from '../model/document_key';
import { ActiveTargets } from './lru_garbage_collector';
import { MemoryPersistence } from './memory_persistence';
import { PersistenceTransaction } from './persistence';
import { PersistencePromise } from './persistence_promise';
import { QueryCache } from './query_cache';
import { QueryData } from './query_data';
export declare class MemoryQueryCache implements QueryCache {
private readonly persistence;
/**
* Maps a query to the data about that query
*/
private queries;
/** The last received snapshot version. */
private lastRemoteSnapshotVersion;
/** The highest numbered target ID encountered. */
private highestTargetId;
/** The highest sequence number encountered. */
private highestSequenceNumber;
/**
* A ordered bidirectional mapping between documents and the remote target
* IDs.
*/
private references;
private targetCount;
private targetIdGenerator;
constructor(persistence: MemoryPersistence);
getTargetCount(txn: PersistenceTransaction): PersistencePromise<number>;
forEachTarget(txn: PersistenceTransaction, f: (q: QueryData) => void): PersistencePromise<void>;
getLastRemoteSnapshotVersion(transaction: PersistenceTransaction): PersistencePromise<SnapshotVersion>;
getHighestSequenceNumber(transaction: PersistenceTransaction): PersistencePromise<ListenSequenceNumber>;
allocateTargetId(transaction: PersistenceTransaction): PersistencePromise<TargetId>;
setTargetsMetadata(transaction: PersistenceTransaction, highestListenSequenceNumber: number, lastRemoteSnapshotVersion?: SnapshotVersion): PersistencePromise<void>;
private saveQueryData;
addQueryData(transaction: PersistenceTransaction, queryData: QueryData): PersistencePromise<void>;
updateQueryData(transaction: PersistenceTransaction, queryData: QueryData): PersistencePromise<void>;
removeQueryData(transaction: PersistenceTransaction, queryData: QueryData): PersistencePromise<void>;
removeTargets(transaction: PersistenceTransaction, upperBound: ListenSequenceNumber, activeTargetIds: ActiveTargets): PersistencePromise<number>;
getQueryCount(transaction: PersistenceTransaction): PersistencePromise<number>;
getQueryData(transaction: PersistenceTransaction, query: Query): PersistencePromise<QueryData | null>;
getQueryDataForTarget(transaction: PersistenceTransaction, targetId: TargetId): never;
addMatchingKeys(txn: PersistenceTransaction, keys: DocumentKeySet, targetId: TargetId): PersistencePromise<void>;
removeMatchingKeys(txn: PersistenceTransaction, keys: DocumentKeySet, targetId: TargetId): PersistencePromise<void>;
removeMatchingKeysForTargetId(txn: PersistenceTransaction, targetId: TargetId): PersistencePromise<void>;
getMatchingKeysForTargetId(txn: PersistenceTransaction, targetId: TargetId): PersistencePromise<DocumentKeySet>;
containsKey(txn: PersistenceTransaction, key: DocumentKey): PersistencePromise<boolean>;
}

View File

@@ -0,0 +1,63 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { Query } from '../core/query';
import { DocumentKeySet, DocumentMap, MaybeDocumentMap, NullableMaybeDocumentMap } from '../model/collections';
import { MaybeDocument } from '../model/document';
import { DocumentKey } from '../model/document_key';
import { IndexManager } from './index_manager';
import { PersistenceTransaction } from './persistence';
import { PersistencePromise } from './persistence_promise';
import { RemoteDocumentCache } from './remote_document_cache';
import { RemoteDocumentChangeBuffer } from './remote_document_change_buffer';
export declare type DocumentSizer = (doc: MaybeDocument) => number;
export declare class MemoryRemoteDocumentCache implements RemoteDocumentCache {
private readonly indexManager;
private readonly sizer;
private docs;
private newDocumentChanges;
private size;
/**
* @param sizer Used to assess the size of a document. For eager GC, this is expected to just
* return 0 to avoid unnecessarily doing the work of calculating the size.
*/
constructor(indexManager: IndexManager, sizer: DocumentSizer);
/**
* Adds the supplied entry to the cache and updates the cache size as appropriate.
*
* All calls of `addEntry` are required to go through the RemoteDocumentChangeBuffer
* returned by `newChangeBuffer()`.
*/
private addEntry;
/**
* Removes the specified entry from the cache and updates the cache size as appropriate.
*
* All calls of `removeEntry` are required to go through the RemoteDocumentChangeBuffer
* returned by `newChangeBuffer()`.
*/
private removeEntry;
getEntry(transaction: PersistenceTransaction, documentKey: DocumentKey): PersistencePromise<MaybeDocument | null>;
getEntries(transaction: PersistenceTransaction, documentKeys: DocumentKeySet): PersistencePromise<NullableMaybeDocumentMap>;
getDocumentsMatchingQuery(transaction: PersistenceTransaction, query: Query): PersistencePromise<DocumentMap>;
forEachDocumentKey(transaction: PersistenceTransaction, f: (key: DocumentKey) => PersistencePromise<void>): PersistencePromise<void>;
getNewDocumentChanges(transaction: PersistenceTransaction): PersistencePromise<MaybeDocumentMap>;
newChangeBuffer(): RemoteDocumentChangeBuffer;
getSize(txn: PersistenceTransaction): PersistencePromise<number>;
/**
* Handles the details of adding and updating documents in the MemoryRemoteDocumentCache.
*/
private static RemoteDocumentChangeBuffer;
}

View File

@@ -0,0 +1,146 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { Timestamp } from '../api/timestamp';
import { Query } from '../core/query';
import { BatchId, ProtoByteString } from '../core/types';
import { DocumentKeySet } from '../model/collections';
import { DocumentKey } from '../model/document_key';
import { Mutation } from '../model/mutation';
import { MutationBatch } from '../model/mutation_batch';
import { SortedMap } from '../util/sorted_map';
import { PersistenceTransaction } from './persistence';
import { PersistencePromise } from './persistence_promise';
/** A queue of mutations to apply to the remote store. */
export interface MutationQueue {
/** Returns true if this queue contains no mutation batches. */
checkEmpty(transaction: PersistenceTransaction): PersistencePromise<boolean>;
/**
* Acknowledges the given batch.
*/
acknowledgeBatch(transaction: PersistenceTransaction, batch: MutationBatch, streamToken: ProtoByteString): PersistencePromise<void>;
/** Returns the current stream token for this mutation queue. */
getLastStreamToken(transaction: PersistenceTransaction): PersistencePromise<ProtoByteString>;
/** Sets the stream token for this mutation queue. */
setLastStreamToken(transaction: PersistenceTransaction, streamToken: ProtoByteString): PersistencePromise<void>;
/**
* Creates a new mutation batch and adds it to this mutation queue.
*
* @param transaction The transaction this operation is scoped to.
* @param localWriteTime The original write time of this mutation.
* @param baseMutations Mutations that are used to populate the base values
* when this mutation is applied locally. These mutations are used to locally
* overwrite values that are persisted in the remote document cache.
* @param mutations The user-provided mutations in this mutation batch.
*/
addMutationBatch(transaction: PersistenceTransaction, localWriteTime: Timestamp, baseMutations: Mutation[], mutations: Mutation[]): PersistencePromise<MutationBatch>;
/**
* Loads the mutation batch with the given batchId.
*/
lookupMutationBatch(transaction: PersistenceTransaction, batchId: BatchId): PersistencePromise<MutationBatch | null>;
/**
* Returns the document keys for the mutation batch with the given batchId.
* For primary clients, this method returns `null` after
* `removeMutationBatches()` has been called. Secondary clients return a
* cached result until `removeCachedMutationKeys()` is invoked.
*/
lookupMutationKeys(transaction: PersistenceTransaction, batchId: BatchId): PersistencePromise<DocumentKeySet | null>;
/**
* Gets the first unacknowledged mutation batch after the passed in batchId
* in the mutation queue or null if empty.
*
* @param batchId The batch to search after, or BATCHID_UNKNOWN for the first
* mutation in the queue.
*
* @return the next mutation or null if there wasn't one.
*/
getNextMutationBatchAfterBatchId(transaction: PersistenceTransaction, batchId: BatchId): PersistencePromise<MutationBatch | null>;
/**
* Gets the largest (latest) batch id in mutation queue for the current user that is pending
* server response, returns `BATCHID_UNKNOWN` if the queue is empty.
*
* @return the largest batch id in the mutation queue that is not acknowledged.
*/
getHighestUnacknowledgedBatchId(transaction: PersistenceTransaction): PersistencePromise<BatchId>;
/** Gets all mutation batches in the mutation queue. */
getAllMutationBatches(transaction: PersistenceTransaction): PersistencePromise<MutationBatch[]>;
/**
* Finds all mutation batches that could possibly affect the given
* document key. Not all mutations in a batch will necessarily affect the
* document key, so when looping through the batch you'll need to check that
* the mutation itself matches the key.
*
* Batches are guaranteed to be in sorted order.
*
* Note that because of this requirement implementations are free to return
* mutation batches that don't contain the document key at all if it's
* convenient.
*/
getAllMutationBatchesAffectingDocumentKey(transaction: PersistenceTransaction, documentKey: DocumentKey): PersistencePromise<MutationBatch[]>;
/**
* Finds all mutation batches that could possibly affect the given set of
* document keys. Not all mutations in a batch will necessarily affect each
* key, so when looping through the batch you'll need to check that the
* mutation itself matches the key.
*
* Batches are guaranteed to be in sorted order.
*
* Note that because of this requirement implementations are free to return
* mutation batches that don't contain any of the document keys at all if it's
* convenient.
*/
getAllMutationBatchesAffectingDocumentKeys(transaction: PersistenceTransaction, documentKeys: SortedMap<DocumentKey, unknown>): PersistencePromise<MutationBatch[]>;
/**
* Finds all mutation batches that could affect the results for the given
* query. Not all mutations in a batch will necessarily affect the query, so
* when looping through the batch you'll need to check that the mutation
* itself matches the query.
*
* Batches are guaranteed to be in sorted order.
*
* Note that because of this requirement implementations are free to return
* mutation batches that don't match the query at all if it's convenient.
*
* NOTE: A PatchMutation does not need to include all fields in the query
* filter criteria in order to be a match (but any fields it does contain do
* need to match).
*/
getAllMutationBatchesAffectingQuery(transaction: PersistenceTransaction, query: Query): PersistencePromise<MutationBatch[]>;
/**
* Removes the given mutation batch from the queue. This is useful in two
* circumstances:
*
* + Removing an applied mutation from the head of the queue
* + Removing a rejected mutation from anywhere in the queue
*
* Multi-Tab Note: This operation should only be called by the primary client.
*/
removeMutationBatch(transaction: PersistenceTransaction, batch: MutationBatch): PersistencePromise<void>;
/**
* Clears the cached keys for a mutation batch. This method should be
* called by secondary clients after they process mutation updates.
*
* Note that this method does not have to be called from primary clients as
* the corresponding cache entries are cleared when an acknowledged or
* rejected batch is removed from the mutation queue.
*/
removeCachedMutationKeys(batchId: BatchId): void;
/**
* Performs a consistency check, examining the mutation queue for any
* leaks, if possible.
*/
performConsistencyCheck(transaction: PersistenceTransaction): PersistencePromise<void>;
}

View File

@@ -0,0 +1,216 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { User } from '../auth/user';
import { ListenSequenceNumber } from '../core/types';
import { DocumentKey } from '../model/document_key';
import { IndexManager } from './index_manager';
import { MutationQueue } from './mutation_queue';
import { PersistencePromise } from './persistence_promise';
import { QueryCache } from './query_cache';
import { QueryData } from './query_data';
import { ReferenceSet } from './reference_set';
import { RemoteDocumentCache } from './remote_document_cache';
import { ClientId } from './shared_client_state';
/**
* Opaque interface representing a persistence transaction.
*
* When you call Persistence.runTransaction(), it will create a transaction and
* pass it to your callback. You then pass it to any method that operates
* on persistence.
*/
export declare abstract class PersistenceTransaction {
abstract readonly currentSequenceNumber: ListenSequenceNumber;
}
/**
* Callback type for primary state notifications. This callback can be
* registered with the persistence layer to get notified when we transition from
* primary to secondary state and vice versa.
*
* Note: Instances can only toggle between Primary and Secondary state if
* IndexedDB persistence is enabled and multiple clients are active. If this
* listener is registered with MemoryPersistence, the callback will be called
* exactly once marking the current instance as Primary.
*/
export declare type PrimaryStateListener = (isPrimary: boolean) => Promise<void>;
/**
* A ReferenceDelegate instance handles all of the hooks into the document-reference lifecycle. This
* includes being added to a target, being removed from a target, being subject to mutation, and
* being mutated by the user.
*
* Different implementations may do different things with each of these events. Not every
* implementation needs to do something with every lifecycle hook.
*
* PORTING NOTE: since sequence numbers are attached to transactions in this
* client, the ReferenceDelegate does not need to deal in transactional
* semantics (onTransactionStarted/Committed()), nor does it need to track and
* generate sequence numbers (getCurrentSequenceNumber()).
*/
export interface ReferenceDelegate {
/**
* Registers a ReferenceSet of documents that should be considered 'referenced' and not eligible
* for removal during garbage collection.
*/
setInMemoryPins(pins: ReferenceSet): void;
/** Notify the delegate that the given document was added to a target. */
addReference(txn: PersistenceTransaction, doc: DocumentKey): PersistencePromise<void>;
/** Notify the delegate that the given document was removed from a target. */
removeReference(txn: PersistenceTransaction, doc: DocumentKey): PersistencePromise<void>;
/**
* Notify the delegate that a target was removed. The delegate may, but is not obligated to,
* actually delete the target and associated data.
*/
removeTarget(txn: PersistenceTransaction, queryData: QueryData): PersistencePromise<void>;
/** Notify the delegate that a document is no longer being mutated by the user. */
removeMutationReference(txn: PersistenceTransaction, doc: DocumentKey): PersistencePromise<void>;
/** Notify the delegate that a limbo document was updated. */
updateLimboDocument(txn: PersistenceTransaction, doc: DocumentKey): PersistencePromise<void>;
}
/**
* Persistence is the lowest-level shared interface to persistent storage in
* Firestore.
*
* Persistence is used to create MutationQueue and RemoteDocumentCache
* instances backed by persistence (which might be in-memory or LevelDB).
*
* Persistence also exposes an API to create and run PersistenceTransactions
* against persistence. All read / write operations must be wrapped in a
* transaction. Implementations of PersistenceTransaction / Persistence only
* need to guarantee that writes made against the transaction are not made to
* durable storage until the transaction resolves its PersistencePromise.
* Since memory-only storage components do not alter durable storage, they are
* free to ignore the transaction.
*
* This contract is enough to allow the LocalStore be be written
* independently of whether or not the stored state actually is durably
* persisted. If persistent storage is enabled, writes are grouped together to
* avoid inconsistent state that could cause crashes.
*
* Concretely, when persistent storage is enabled, the persistent versions of
* MutationQueue, RemoteDocumentCache, and others (the mutators) will
* defer their writes into a transaction. Once the local store has completed
* one logical operation, it commits the transaction.
*
* When persistent storage is disabled, the non-persistent versions of the
* mutators ignore the transaction. This short-cut is allowed because
* memory-only storage leaves no state so it cannot be inconsistent.
*
* This simplifies the implementations of the mutators and allows memory-only
* implementations to supplement the persistent ones without requiring any
* special dual-store implementation of Persistence. The cost is that the
* LocalStore needs to be slightly careful about the order of its reads and
* writes in order to avoid relying on being able to read back uncommitted
* writes.
*/
export interface Persistence {
/**
* Whether or not this persistence instance has been started.
*/
readonly started: boolean;
readonly referenceDelegate: ReferenceDelegate;
/**
* Releases any resources held during eager shutdown.
*/
shutdown(): Promise<void>;
/**
* Registers a listener that gets called when the primary state of the
* instance changes. Upon registering, this listener is invoked immediately
* with the current primary state.
*
* PORTING NOTE: This is only used for Web multi-tab.
*/
setPrimaryStateListener(primaryStateListener: PrimaryStateListener): Promise<void>;
/**
* Registers a listener that gets called when the database receives a
* version change event indicating that it has deleted.
*
* PORTING NOTE: This is only used for Web multi-tab.
*/
setDatabaseDeletedListener(databaseDeletedListener: () => Promise<void>): void;
/**
* Adjusts the current network state in the client's metadata, potentially
* affecting the primary lease.
*
* PORTING NOTE: This is only used for Web multi-tab.
*/
setNetworkEnabled(networkEnabled: boolean): void;
/**
* Returns the IDs of the clients that are currently active. If multi-tab
* is not supported, returns an array that only contains the local client's
* ID.
*
* PORTING NOTE: This is only used for Web multi-tab.
*/
getActiveClients(): Promise<ClientId[]>;
/**
* Returns a MutationQueue representing the persisted mutations for the
* given user.
*
* Note: The implementation is free to return the same instance every time
* this is called for a given user. In particular, the memory-backed
* implementation does this to emulate the persisted implementation to the
* extent possible (e.g. in the case of uid switching from
* sally=>jack=>sally, sally's mutation queue will be preserved).
*/
getMutationQueue(user: User): MutationQueue;
/**
* Returns a QueryCache representing the persisted cache of queries.
*
* Note: The implementation is free to return the same instance every time
* this is called. In particular, the memory-backed implementation does this
* to emulate the persisted implementation to the extent possible.
*/
getQueryCache(): QueryCache;
/**
* Returns a RemoteDocumentCache representing the persisted cache of remote
* documents.
*
* Note: The implementation is free to return the same instance every time
* this is called. In particular, the memory-backed implementation does this
* to emulate the persisted implementation to the extent possible.
*/
getRemoteDocumentCache(): RemoteDocumentCache;
/**
* Returns an IndexManager instance that manages our persisted query indexes.
*
* Note: The implementation is free to return the same instance every time
* this is called. In particular, the memory-backed implementation does this
* to emulate the persisted implementation to the extent possible.
*/
getIndexManager(): IndexManager;
/**
* Performs an operation inside a persistence transaction. Any reads or writes
* against persistence must be performed within a transaction. Writes will be
* committed atomically once the transaction completes.
*
* Persistence operations are asynchronous and therefore the provided
* transactionOperation must return a PersistencePromise. When it is resolved,
* the transaction will be committed and the Promise returned by this method
* will resolve.
*
* @param action A description of the action performed by this transaction,
* used for logging.
* @param mode The underlying mode of the IndexedDb transaction. Can be
* 'readonly`, 'readwrite' or 'readwrite-primary'. Transactions marked
* 'readwrite-primary' can only be executed by the primary client. In this
* mode, the transactionOperation will not be run if the primary lease cannot
* be acquired and the returned promise will be rejected with a
* FAILED_PRECONDITION error.
* @param transactionOperation The operation to run inside a transaction.
* @return A promise that is resolved once the transaction completes.
*/
runTransaction<T>(action: string, mode: 'readonly' | 'readwrite' | 'readwrite-primary', transactionOperation: (transaction: PersistenceTransaction) => PersistencePromise<T>): Promise<T>;
}

View File

@@ -0,0 +1,72 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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 declare type FulfilledHandler<T, R> = ((result: T) => R | PersistencePromise<R>) | null;
export declare type RejectedHandler<R> = ((reason: Error) => R | PersistencePromise<R>) | null;
export declare type Resolver<T> = (value?: T) => void;
export declare type Rejector = (error: Error) => void;
/**
* PersistencePromise<> is essentially a re-implementation of Promise<> except
* it has a .next() method instead of .then() and .next() and .catch() callbacks
* are executed synchronously when a PersistencePromise resolves rather than
* asynchronously (Promise<> implementations use setImmediate() or similar).
*
* This is necessary to interoperate with IndexedDB which will automatically
* commit transactions if control is returned to the event loop without
* synchronously initiating another operation on the transaction.
*
* NOTE: .then() and .catch() only allow a single consumer, unlike normal
* Promises.
*/
export declare class PersistencePromise<T> {
private nextCallback;
private catchCallback;
private result;
private error;
private isDone;
private callbackAttached;
constructor(callback: (resolve: Resolver<T>, reject: Rejector) => void);
catch<R>(fn: (error: Error) => R | PersistencePromise<R>): PersistencePromise<R>;
next<R>(nextFn?: FulfilledHandler<T, R>, catchFn?: RejectedHandler<R>): PersistencePromise<R>;
toPromise(): Promise<T>;
private wrapUserFunction;
private wrapSuccess;
private wrapFailure;
static resolve(): PersistencePromise<void>;
static resolve<R>(result: R): PersistencePromise<R>;
static reject<R>(error: Error): PersistencePromise<R>;
static waitFor(all: {
forEach: (cb: (el: PersistencePromise<any>) => void) => void;
}): PersistencePromise<void>;
/**
* Given an array of predicate functions that asynchronously evaluate to a
* boolean, implements a short-circuiting `or` between the results. Predicates
* will be evaluated until one of them returns `true`, then stop. The final
* result will be whether any of them returned `true`.
*/
static or(predicates: Array<() => PersistencePromise<boolean>>): PersistencePromise<boolean>;
/**
* Given an iterable, call the given function on each element in the
* collection and wait for all of the resulting concurrent PersistencePromises
* to resolve.
*/
static forEach<R, S>(collection: {
forEach: (cb: (r: R, s: S) => void) => void;
}, f: ((r: R, s: S) => PersistencePromise<void>) | ((r: R) => PersistencePromise<void>)): PersistencePromise<void>;
static forEach<R>(collection: {
forEach: (cb: (r: R) => void) => void;
}, f: (r: R) => PersistencePromise<void>): PersistencePromise<void>;
}

View File

@@ -0,0 +1,137 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { Query } from '../core/query';
import { SnapshotVersion } from '../core/snapshot_version';
import { ListenSequenceNumber, TargetId } from '../core/types';
import { DocumentKeySet } from '../model/collections';
import { DocumentKey } from '../model/document_key';
import { PersistenceTransaction } from './persistence';
import { PersistencePromise } from './persistence_promise';
import { QueryData } from './query_data';
/**
* Represents cached queries received from the remote backend.
*
* The cache is keyed by Query and entries in the cache are QueryData instances.
*/
export interface QueryCache {
/**
* A global snapshot version representing the last consistent snapshot we
* received from the backend. This is monotonically increasing and any
* snapshots received from the backend prior to this version (e.g. for targets
* resumed with a resume_token) should be suppressed (buffered) until the
* backend has caught up to this snapshot version again. This prevents our
* cache from ever going backwards in time.
*
* This is updated whenever our we get a TargetChange with a read_time and
* empty target_ids.
*/
getLastRemoteSnapshotVersion(transaction: PersistenceTransaction): PersistencePromise<SnapshotVersion>;
/**
* @return The highest sequence number observed, including any that might be
* persisted on-disk.
*/
getHighestSequenceNumber(transaction: PersistenceTransaction): PersistencePromise<ListenSequenceNumber>;
/**
* Call provided function with each `QueryData` that we have cached.
*/
forEachTarget(txn: PersistenceTransaction, f: (q: QueryData) => void): PersistencePromise<void>;
/**
* Set the highest listen sequence number and optionally updates the
* snapshot version of the last consistent snapshot received from the backend
* (see getLastRemoteSnapshotVersion() for more details).
*
* @param highestListenSequenceNumber The new maximum listen sequence number.
* @param lastRemoteSnapshotVersion The new snapshot version. Optional.
*/
setTargetsMetadata(transaction: PersistenceTransaction, highestListenSequenceNumber: number, lastRemoteSnapshotVersion?: SnapshotVersion): PersistencePromise<void>;
/**
* Adds an entry in the cache.
*
* The cache key is extracted from `queryData.query`. The key must not already
* exist in the cache.
*
* @param queryData A QueryData instance to put in the cache.
*/
addQueryData(transaction: PersistenceTransaction, queryData: QueryData): PersistencePromise<void>;
/**
* Updates an entry in the cache.
*
* The cache key is extracted from `queryData.query`. The entry must already
* exist in the cache, and it will be replaced.
* @param {QueryData} queryData The QueryData to be replaced into the cache.
*/
updateQueryData(transaction: PersistenceTransaction, queryData: QueryData): PersistencePromise<void>;
/**
* Removes the cached entry for the given query data. It is an error to remove
* a query data that does not exist.
*
* Multi-Tab Note: This operation should only be called by the primary client.
*/
removeQueryData(transaction: PersistenceTransaction, queryData: QueryData): PersistencePromise<void>;
/**
* The number of targets currently in the cache.
*/
getQueryCount(transaction: PersistenceTransaction): PersistencePromise<number>;
/**
* Looks up a QueryData entry by query.
*
* @param query The query corresponding to the entry to look up.
* @return The cached QueryData entry, or null if the cache has no entry for
* the query.
*/
getQueryData(transaction: PersistenceTransaction, query: Query): PersistencePromise<QueryData | null>;
/**
* Looks up a QueryData entry by target ID.
*
* @param targetId The target ID of the QueryData entry to look up.
* @return The cached QueryData entry, or null if the cache has no entry for
* the query.
*/
getQueryDataForTarget(txn: PersistenceTransaction, targetId: TargetId): PersistencePromise<QueryData | null>;
/**
* Adds the given document keys to cached query results of the given target
* ID.
*
* Multi-Tab Note: This operation should only be called by the primary client.
*/
addMatchingKeys(transaction: PersistenceTransaction, keys: DocumentKeySet, targetId: TargetId): PersistencePromise<void>;
/**
* Removes the given document keys from the cached query results of the
* given target ID.
*
* Multi-Tab Note: This operation should only be called by the primary client.
*/
removeMatchingKeys(transaction: PersistenceTransaction, keys: DocumentKeySet, targetId: TargetId): PersistencePromise<void>;
/**
* Removes all the keys in the query results of the given target ID.
*
* Multi-Tab Note: This operation should only be called by the primary client.
*/
removeMatchingKeysForTargetId(transaction: PersistenceTransaction, targetId: TargetId): PersistencePromise<void>;
/**
* Returns the document keys that match the provided target ID.
*/
getMatchingKeysForTargetId(transaction: PersistenceTransaction, targetId: TargetId): PersistencePromise<DocumentKeySet>;
/**
* Returns a new target ID that is higher than any query in the cache. If
* there are no queries in the cache, returns the first valid target ID.
* Allocated target IDs are persisted and `allocateTargetId()` will never
* return the same ID twice.
*/
allocateTargetId(transaction: PersistenceTransaction): PersistencePromise<TargetId>;
containsKey(transaction: PersistenceTransaction, key: DocumentKey): PersistencePromise<boolean>;
}

View File

@@ -0,0 +1,86 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { Query } from '../core/query';
import { SnapshotVersion } from '../core/snapshot_version';
import { ListenSequenceNumber, ProtoByteString, TargetId } from '../core/types';
/** An enumeration of the different purposes we have for queries. */
export declare enum QueryPurpose {
/** A regular, normal query. */
Listen = 0,
/**
* The query was used to refill a query after an existence filter mismatch.
*/
ExistenceFilterMismatch = 1,
/** The query was used to resolve a limbo document. */
LimboResolution = 2
}
/**
* An immutable set of metadata that the local store tracks for each query.
*/
export declare class QueryData {
/** The query being listened to. */
readonly query: Query;
/**
* The target ID to which the query corresponds; Assigned by the
* LocalStore for user listens and by the SyncEngine for limbo watches.
*/
readonly targetId: TargetId;
/** The purpose of the query. */
readonly purpose: QueryPurpose;
/** The sequence number of the last transaction during which this query data was modified */
readonly sequenceNumber: ListenSequenceNumber;
/** The latest snapshot version seen for this target. */
readonly snapshotVersion: SnapshotVersion;
/**
* An opaque, server-assigned token that allows watching a query to be
* resumed after disconnecting without retransmitting all the data that
* matches the query. The resume token essentially identifies a point in
* time from which the server should resume sending results.
*/
readonly resumeToken: ProtoByteString;
constructor(
/** The query being listened to. */
query: Query,
/**
* The target ID to which the query corresponds; Assigned by the
* LocalStore for user listens and by the SyncEngine for limbo watches.
*/
targetId: TargetId,
/** The purpose of the query. */
purpose: QueryPurpose,
/** The sequence number of the last transaction during which this query data was modified */
sequenceNumber: ListenSequenceNumber,
/** The latest snapshot version seen for this target. */
snapshotVersion?: SnapshotVersion,
/**
* An opaque, server-assigned token that allows watching a query to be
* resumed after disconnecting without retransmitting all the data that
* matches the query. The resume token essentially identifies a point in
* time from which the server should resume sending results.
*/
resumeToken?: ProtoByteString);
/**
* Creates a new query data instance with an updated snapshot version and
* resume token.
*/
copy(overwrite: {
resumeToken?: ProtoByteString;
snapshotVersion?: SnapshotVersion;
sequenceNumber?: ListenSequenceNumber;
}): QueryData;
isEqual(other: QueryData): boolean;
}

View File

@@ -0,0 +1,68 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { BatchId, TargetId } from '../core/types';
import { DocumentKeySet } from '../model/collections';
import { DocumentKey } from '../model/document_key';
/**
* A collection of references to a document from some kind of numbered entity
* (either a target ID or batch ID). As references are added to or removed from
* the set corresponding events are emitted to a registered garbage collector.
*
* Each reference is represented by a DocumentReference object. Each of them
* contains enough information to uniquely identify the reference. They are all
* stored primarily in a set sorted by key. A document is considered garbage if
* there's no references in that set (this can be efficiently checked thanks to
* sorting by key).
*
* ReferenceSet also keeps a secondary set that contains references sorted by
* IDs. This one is used to efficiently implement removal of all references by
* some target ID.
*/
export declare class ReferenceSet {
private refsByKey;
private refsByTarget;
/** Returns true if the reference set contains no references. */
isEmpty(): boolean;
/** Adds a reference to the given document key for the given ID. */
addReference(key: DocumentKey, id: TargetId | BatchId): void;
/** Add references to the given document keys for the given ID. */
addReferences(keys: DocumentKeySet, id: TargetId | BatchId): void;
/**
* Removes a reference to the given document key for the given
* ID.
*/
removeReference(key: DocumentKey, id: TargetId | BatchId): void;
removeReferences(keys: DocumentKeySet, id: TargetId | BatchId): void;
/**
* Clears all references with a given ID. Calls removeRef() for each key
* removed.
*/
removeReferencesForId(id: TargetId | BatchId): DocumentKey[];
removeAllReferences(): void;
private removeRef;
referencesForId(id: TargetId | BatchId): DocumentKeySet;
containsKey(key: DocumentKey): boolean;
}
export declare class DocReference {
key: DocumentKey;
targetOrBatchId: TargetId | BatchId;
constructor(key: DocumentKey, targetOrBatchId: TargetId | BatchId);
/** Compare by key then by ID */
static compareByKey(left: DocReference, right: DocReference): number;
/** Compare by ID then by key */
static compareByTargetId(left: DocReference, right: DocReference): number;
}

View File

@@ -0,0 +1,83 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { Query } from '../core/query';
import { DocumentKeySet, DocumentMap, MaybeDocumentMap, NullableMaybeDocumentMap } from '../model/collections';
import { MaybeDocument } from '../model/document';
import { DocumentKey } from '../model/document_key';
import { PersistenceTransaction } from './persistence';
import { PersistencePromise } from './persistence_promise';
import { RemoteDocumentChangeBuffer } from './remote_document_change_buffer';
/**
* Represents cached documents received from the remote backend.
*
* The cache is keyed by DocumentKey and entries in the cache are MaybeDocument
* instances, meaning we can cache both Document instances (an actual document
* with data) as well as NoDocument instances (indicating that the document is
* known to not exist).
*/
export interface RemoteDocumentCache {
/**
* Looks up an entry in the cache.
*
* @param documentKey The key of the entry to look up.
* @return The cached Document or NoDocument entry, or null if we have nothing
* cached.
*/
getEntry(transaction: PersistenceTransaction, documentKey: DocumentKey): PersistencePromise<MaybeDocument | null>;
/**
* Looks up a set of entries in the cache.
*
* @param documentKeys The keys of the entries to look up.
* @return The cached Document or NoDocument entries indexed by key. If an entry is not cached,
* the corresponding key will be mapped to a null value.
*/
getEntries(transaction: PersistenceTransaction, documentKeys: DocumentKeySet): PersistencePromise<NullableMaybeDocumentMap>;
/**
* Executes a query against the cached Document entries.
*
* Implementations may return extra documents if convenient. The results
* should be re-filtered by the consumer before presenting them to the user.
*
* Cached NoDocument entries have no bearing on query results.
*
* @param query The query to match documents against.
* @return The set of matching documents.
*/
getDocumentsMatchingQuery(transaction: PersistenceTransaction, query: Query): PersistencePromise<DocumentMap>;
/**
* Returns the set of documents that have been updated since the last call.
* If this is the first call, returns the set of changes since client
* initialization.
*
* If the changelog was garbage collected and can no longer be replayed,
* `getNewDocumentChanges` will reject the returned Promise. Further
* invocations will return document changes since the point of rejection.
*/
getNewDocumentChanges(transaction: PersistenceTransaction): PersistencePromise<MaybeDocumentMap>;
/**
* Provides access to add or update the contents of the cache. The buffer
* handles proper size accounting for the change.
*
* Multi-Tab Note: This should only be called by the primary client.
*/
newChangeBuffer(): RemoteDocumentChangeBuffer;
/**
* Get an estimate of the size of the document cache. Note that for eager
* garbage collection, we don't track sizes so this will return 0.
*/
getSize(transaction: PersistenceTransaction): PersistencePromise<number>;
}

View File

@@ -0,0 +1,88 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { DocumentKeySet, NullableMaybeDocumentMap } from '../model/collections';
import { MaybeDocument } from '../model/document';
import { DocumentKey } from '../model/document_key';
import { ObjectMap } from '../util/obj_map';
import { PersistenceTransaction } from './persistence';
import { PersistencePromise } from './persistence_promise';
/**
* An in-memory buffer of entries to be written to a RemoteDocumentCache.
* It can be used to batch up a set of changes to be written to the cache, but
* additionally supports reading entries back with the `getEntry()` method,
* falling back to the underlying RemoteDocumentCache if no entry is
* buffered.
*
* Entries added to the cache *must* be read first. This is to facilitate
* calculating the size delta of the pending changes.
*
* PORTING NOTE: This class was implemented then removed from other platforms.
* If byte-counting ends up being needed on the other platforms, consider
* porting this class as part of that implementation work.
*/
export declare abstract class RemoteDocumentChangeBuffer {
protected changes: ObjectMap<DocumentKey, MaybeDocument | null>;
private changesApplied;
protected abstract getFromCache(transaction: PersistenceTransaction, documentKey: DocumentKey): PersistencePromise<MaybeDocument | null>;
protected abstract getAllFromCache(transaction: PersistenceTransaction, documentKeys: DocumentKeySet): PersistencePromise<NullableMaybeDocumentMap>;
protected abstract applyChanges(transaction: PersistenceTransaction): PersistencePromise<void>;
/**
* Buffers a `RemoteDocumentCache.addEntry()` call.
*
* You can only modify documents that have already been retrieved via
* `getEntry()/getEntries()` (enforced via IndexedDbs `apply()`).
*/
addEntry(maybeDocument: MaybeDocument): void;
/**
* Buffers a `RemoteDocumentCache.removeEntry()` call.
*
* You can only remove documents that have already been retrieved via
* `getEntry()/getEntries()` (enforced via IndexedDbs `apply()`).
*/
removeEntry(key: DocumentKey): void;
/**
* Looks up an entry in the cache. The buffered changes will first be checked,
* and if no buffered change applies, this will forward to
* `RemoteDocumentCache.getEntry()`.
*
* @param transaction The transaction in which to perform any persistence
* operations.
* @param documentKey The key of the entry to look up.
* @return The cached Document or NoDocument entry, or null if we have nothing
* cached.
*/
getEntry(transaction: PersistenceTransaction, documentKey: DocumentKey): PersistencePromise<MaybeDocument | null>;
/**
* Looks up several entries in the cache, forwarding to
* `RemoteDocumentCache.getEntry()`.
*
* @param transaction The transaction in which to perform any persistence
* operations.
* @param documentKeys The keys of the entries to look up.
* @return A map of cached `Document`s or `NoDocument`s, indexed by key. If an
* entry cannot be found, the corresponding key will be mapped to a null
* value.
*/
getEntries(transaction: PersistenceTransaction, documentKeys: DocumentKeySet): PersistencePromise<NullableMaybeDocumentMap>;
/**
* Applies buffered changes to the underlying RemoteDocumentCache, using
* the provided transaction.
*/
apply(transaction: PersistenceTransaction): PersistencePromise<void>;
/** Helper to assert this.changes is not null */
protected assertNotApplied(): void;
}

View File

@@ -0,0 +1,317 @@
/**
* @license
* Copyright 2018 Google Inc.
*
* 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.
*/
import { User } from '../auth/user';
import { BatchId, ListenSequenceNumber, MutationBatchState, OnlineState, TargetId } from '../core/types';
import { TargetIdSet } from '../model/collections';
import { Platform } from '../platform/platform';
import { AsyncQueue } from '../util/async_queue';
import { FirestoreError } from '../util/error';
import { SortedSet } from '../util/sorted_set';
import { QueryTargetState, SharedClientStateSyncer } from './shared_client_state_syncer';
/**
* A randomly-generated key assigned to each Firestore instance at startup.
*/
export declare type ClientId = string;
/**
* A `SharedClientState` keeps track of the global state of the mutations
* and query targets for all active clients with the same persistence key (i.e.
* project ID and FirebaseApp name). It relays local changes to other clients
* and updates its local state as new state is observed.
*
* `SharedClientState` is primarily used for synchronization in Multi-Tab
* environments. Each tab is responsible for registering its active query
* targets and mutations. `SharedClientState` will then notify the listener
* assigned to `.syncEngine` for updates to mutations and queries that
* originated in other clients.
*
* To receive notifications, `.syncEngine` and `.onlineStateHandler` has to be
* assigned before calling `start()`.
*/
export interface SharedClientState {
syncEngine: SharedClientStateSyncer | null;
onlineStateHandler: ((onlineState: OnlineState) => void) | null;
sequenceNumberHandler: ((sequenceNumber: ListenSequenceNumber) => void) | null;
/** Registers the Mutation Batch ID of a newly pending mutation. */
addPendingMutation(batchId: BatchId): void;
/**
* Records that a pending mutation has been acknowledged or rejected.
* Called by the primary client to notify secondary clients of mutation
* results as they come back from the backend.
*/
updateMutationState(batchId: BatchId, state: 'acknowledged' | 'rejected', error?: FirestoreError): void;
/**
* Associates a new Query Target ID with the local Firestore client. Returns
* the new query state for the query (which can be 'current' if the query is
* already associated with another tab).
*/
addLocalQueryTarget(targetId: TargetId): QueryTargetState;
/** Removes the Query Target ID association from the local client. */
removeLocalQueryTarget(targetId: TargetId): void;
/** Checks whether the target is associated with the local client. */
isLocalQueryTarget(targetId: TargetId): boolean;
/**
* Processes an update to a query target.
*
* Called by the primary client to notify secondary clients of document
* changes or state transitions that affect the provided query target.
*/
updateQueryState(targetId: TargetId, state: QueryTargetState, error?: FirestoreError): void;
/**
* Removes the target's metadata entry.
*
* Called by the primary client when all clients stopped listening to a query
* target.
*/
clearQueryState(targetId: TargetId): void;
/**
* Gets the active Query Targets IDs for all active clients.
*
* The implementation for this may require O(n) runtime, where 'n' is the size
* of the result set.
*/
getAllActiveQueryTargets(): SortedSet<TargetId>;
/**
* Checks whether the provided target ID is currently being listened to by
* any of the active clients.
*
* The implementation may require O(n*log m) runtime, where 'n' is the number
* of clients and 'm' the number of targets.
*/
isActiveQueryTarget(targetId: TargetId): boolean;
/**
* Starts the SharedClientState, reads existing client data and registers
* listeners for updates to new and existing clients.
*/
start(): Promise<void>;
/** Shuts down the `SharedClientState` and its listeners. */
shutdown(): void;
/**
* Changes the active user and removes all existing user-specific data. The
* user change does not call back into SyncEngine (for example, no mutations
* will be marked as removed).
*/
handleUserChange(user: User, removedBatchIds: BatchId[], addedBatchIds: BatchId[]): void;
/** Changes the shared online state of all clients. */
setOnlineState(onlineState: OnlineState): void;
writeSequenceNumber(sequenceNumber: ListenSequenceNumber): void;
}
/**
* Holds the state of a mutation batch, including its user ID, batch ID and
* whether the batch is 'pending', 'acknowledged' or 'rejected'.
*/
export declare class MutationMetadata {
readonly user: User;
readonly batchId: BatchId;
readonly state: MutationBatchState;
readonly error?: FirestoreError | undefined;
constructor(user: User, batchId: BatchId, state: MutationBatchState, error?: FirestoreError | undefined);
/**
* Parses a MutationMetadata from its JSON representation in WebStorage.
* Logs a warning and returns null if the format of the data is not valid.
*/
static fromWebStorageEntry(user: User, batchId: BatchId, value: string): MutationMetadata | null;
toWebStorageJSON(): string;
}
/**
* Holds the state of a query target, including its target ID and whether the
* target is 'not-current', 'current' or 'rejected'.
*/
export declare class QueryTargetMetadata {
readonly targetId: TargetId;
readonly state: QueryTargetState;
readonly error?: FirestoreError | undefined;
constructor(targetId: TargetId, state: QueryTargetState, error?: FirestoreError | undefined);
/**
* Parses a QueryTargetMetadata from its JSON representation in WebStorage.
* Logs a warning and returns null if the format of the data is not valid.
*/
static fromWebStorageEntry(targetId: TargetId, value: string): QueryTargetMetadata | null;
toWebStorageJSON(): string;
}
/**
* Metadata state of a single client denoting the query targets it is actively
* listening to.
*/
export interface ClientState {
readonly activeTargetIds: TargetIdSet;
}
/**
* The JSON representation of the system's online state, as written by the
* primary client.
*/
export interface SharedOnlineStateSchema {
/**
* The clientId of the client that wrote this onlineState value. Tracked so
* that on startup, clients can check if this client is still active when
* determining whether to apply this value or not.
*/
readonly clientId: string;
readonly onlineState: string;
}
/**
* This class represents the online state for all clients participating in
* multi-tab. The online state is only written to by the primary client, and
* used in secondary clients to update their query views.
*/
export declare class SharedOnlineState {
readonly clientId: string;
readonly onlineState: OnlineState;
constructor(clientId: string, onlineState: OnlineState);
/**
* Parses a SharedOnlineState from its JSON representation in WebStorage.
* Logs a warning and returns null if the format of the data is not valid.
*/
static fromWebStorageEntry(value: string): SharedOnlineState | null;
}
/**
* Metadata state of the local client. Unlike `RemoteClientState`, this class is
* mutable and keeps track of all pending mutations, which allows us to
* update the range of pending mutation batch IDs as new mutations are added or
* removed.
*
* The data in `LocalClientState` is not read from WebStorage and instead
* updated via its instance methods. The updated state can be serialized via
* `toWebStorageJSON()`.
*/
export declare class LocalClientState implements ClientState {
activeTargetIds: SortedSet<number>;
addQueryTarget(targetId: TargetId): void;
removeQueryTarget(targetId: TargetId): void;
/**
* Converts this entry into a JSON-encoded format we can use for WebStorage.
* Does not encode `clientId` as it is part of the key in WebStorage.
*/
toWebStorageJSON(): string;
}
/**
* `WebStorageSharedClientState` uses WebStorage (window.localStorage) as the
* backing store for the SharedClientState. It keeps track of all active
* clients and supports modifications of the local client's data.
*/
export declare class WebStorageSharedClientState implements SharedClientState {
private readonly queue;
private readonly platform;
private readonly persistenceKey;
private readonly localClientId;
syncEngine: SharedClientStateSyncer | null;
onlineStateHandler: ((onlineState: OnlineState) => void) | null;
sequenceNumberHandler: ((sequenceNumber: ListenSequenceNumber) => void) | null;
private readonly storage;
private readonly localClientStorageKey;
private readonly sequenceNumberKey;
private readonly activeClients;
private readonly storageListener;
private readonly onlineStateKey;
private readonly clientStateKeyRe;
private readonly mutationBatchKeyRe;
private readonly queryTargetKeyRe;
private started;
private currentUser;
/**
* Captures WebStorage events that occur before `start()` is called. These
* events are replayed once `WebStorageSharedClientState` is started.
*/
private earlyEvents;
constructor(queue: AsyncQueue, platform: Platform, persistenceKey: string, localClientId: ClientId, initialUser: User);
/** Returns 'true' if WebStorage is available in the current environment. */
static isAvailable(platform: Platform): boolean;
start(): Promise<void>;
writeSequenceNumber(sequenceNumber: ListenSequenceNumber): void;
getAllActiveQueryTargets(): TargetIdSet;
isActiveQueryTarget(targetId: TargetId): boolean;
addPendingMutation(batchId: BatchId): void;
updateMutationState(batchId: BatchId, state: 'acknowledged' | 'rejected', error?: FirestoreError): void;
addLocalQueryTarget(targetId: TargetId): QueryTargetState;
removeLocalQueryTarget(targetId: TargetId): void;
isLocalQueryTarget(targetId: TargetId): boolean;
clearQueryState(targetId: TargetId): void;
updateQueryState(targetId: TargetId, state: QueryTargetState, error?: FirestoreError): void;
handleUserChange(user: User, removedBatchIds: BatchId[], addedBatchIds: BatchId[]): void;
setOnlineState(onlineState: OnlineState): void;
shutdown(): void;
private getItem;
private setItem;
private removeItem;
private handleWebStorageEvent;
private readonly localClientState;
private persistClientState;
private persistMutationState;
private removeMutationState;
private persistOnlineState;
private persistQueryTargetState;
/** Assembles the key for a client state in WebStorage */
private toWebStorageClientStateKey;
/** Assembles the key for a query state in WebStorage */
private toWebStorageQueryTargetMetadataKey;
/** Assembles the key for a mutation batch in WebStorage */
private toWebStorageMutationBatchKey;
/**
* Parses a client state key in WebStorage. Returns null if the key does not
* match the expected key format.
*/
private fromWebStorageClientStateKey;
/**
* Parses a client state in WebStorage. Returns 'null' if the value could not
* be parsed.
*/
private fromWebStorageClientState;
/**
* Parses a mutation batch state in WebStorage. Returns 'null' if the value
* could not be parsed.
*/
private fromWebStorageMutationMetadata;
/**
* Parses a query target state from WebStorage. Returns 'null' if the value
* could not be parsed.
*/
private fromWebStorageQueryTargetMetadata;
/**
* Parses an online state from WebStorage. Returns 'null' if the value
* could not be parsed.
*/
private fromWebStorageOnlineState;
private handleMutationBatchEvent;
private handleQueryTargetEvent;
private handleClientStateEvent;
private handleOnlineStateEvent;
}
/**
* `MemorySharedClientState` is a simple implementation of SharedClientState for
* clients using memory persistence. The state in this class remains fully
* isolated and no synchronization is performed.
*/
export declare class MemorySharedClientState implements SharedClientState {
private localState;
private queryState;
syncEngine: SharedClientStateSyncer | null;
onlineStateHandler: ((onlineState: OnlineState) => void) | null;
sequenceNumberHandler: ((sequenceNumber: ListenSequenceNumber) => void) | null;
addPendingMutation(batchId: BatchId): void;
updateMutationState(batchId: BatchId, state: 'acknowledged' | 'rejected', error?: FirestoreError): void;
addLocalQueryTarget(targetId: TargetId): QueryTargetState;
updateQueryState(targetId: TargetId, state: QueryTargetState, error?: FirestoreError): void;
removeLocalQueryTarget(targetId: TargetId): void;
isLocalQueryTarget(targetId: TargetId): boolean;
clearQueryState(targetId: TargetId): void;
getAllActiveQueryTargets(): TargetIdSet;
isActiveQueryTarget(targetId: TargetId): boolean;
start(): Promise<void>;
handleUserChange(user: User, removedBatchIds: BatchId[], addedBatchIds: BatchId[]): void;
setOnlineState(onlineState: OnlineState): void;
shutdown(): void;
writeSequenceNumber(sequenceNumber: ListenSequenceNumber): void;
}

View File

@@ -0,0 +1,35 @@
/**
* @license
* Copyright 2018 Google Inc.
*
* 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.
*/
import { BatchId, MutationBatchState, TargetId } from '../core/types';
import { FirestoreError } from '../util/error';
import { ClientId } from './shared_client_state';
/** The different states of a watch target. */
export declare type QueryTargetState = 'not-current' | 'current' | 'rejected';
/**
* An interface that describes the actions the SharedClientState class needs to
* perform on a cooperating synchronization engine.
*/
export interface SharedClientStateSyncer {
/** Applies a mutation state to an existing batch. */
applyBatchState(batchId: BatchId, state: MutationBatchState, error?: FirestoreError): Promise<void>;
/** Applies a query target change from a different tab. */
applyTargetState(targetId: TargetId, state: QueryTargetState, error?: FirestoreError): Promise<void>;
/** Adds or removes Watch targets for queries from different tabs. */
applyActiveTargetsChange(added: TargetId[], removed: TargetId[]): Promise<void>;
/** Returns the IDs of the clients that are currently active. */
getActiveClients(): Promise<ClientId[]>;
}

View File

@@ -0,0 +1,202 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { PersistencePromise } from './persistence_promise';
export interface SimpleDbSchemaConverter {
createOrUpgrade(db: IDBDatabase, txn: SimpleDbTransaction, fromVersion: number, toVersion: number): PersistencePromise<void>;
}
/**
* Provides a wrapper around IndexedDb with a simplified interface that uses
* Promise-like return values to chain operations. Real promises cannot be used
* since .then() continuations are executed asynchronously (e.g. via
* .setImmediate), which would cause IndexedDB to end the transaction.
* See PersistencePromise for more details.
*/
export declare class SimpleDb {
private db;
/**
* Opens the specified database, creating or upgrading it if necessary.
*
* Note that `version` must not be a downgrade. IndexedDB does not support downgrading the schema
* version. We currently do not support any way to do versioning outside of IndexedDB's versioning
* mechanism, as only version-upgrade transactions are allowed to do things like create
* objectstores.
*/
static openOrCreate(name: string, version: number, schemaConverter: SimpleDbSchemaConverter): Promise<SimpleDb>;
/** Deletes the specified database. */
static delete(name: string): Promise<void>;
/** Returns true if IndexedDB is available in the current environment. */
static isAvailable(): boolean;
/** Helper to get a typed SimpleDbStore from a transaction. */
static getStore<KeyType extends IDBValidKey, ValueType extends unknown>(txn: SimpleDbTransaction, store: string): SimpleDbStore<KeyType, ValueType>;
/** Parse User Agent to determine iOS version. Returns -1 if not found. */
static getIOSVersion(ua: string): number;
/** Parse User Agent to determine Android version. Returns -1 if not found. */
static getAndroidVersion(ua: string): number;
constructor(db: IDBDatabase);
setVersionChangeListener(versionChangeListener: (event: IDBVersionChangeEvent) => void): void;
runTransaction<T>(mode: 'readonly' | 'readwrite', objectStores: string[], transactionFn: (transaction: SimpleDbTransaction) => PersistencePromise<T>): Promise<T>;
close(): void;
}
/**
* A controller for iterating over a key range or index. It allows an iterate
* callback to delete the currently-referenced object, or jump to a new key
* within the key range or index.
*/
export declare class IterationController {
private dbCursor;
private shouldStop;
private nextKey;
constructor(dbCursor: IDBCursorWithValue);
readonly isDone: boolean;
readonly skipToKey: IDBValidKey | null;
cursor: IDBCursorWithValue;
/**
* This function can be called to stop iteration at any point.
*/
done(): void;
/**
* This function can be called to skip to that next key, which could be
* an index or a primary key.
*/
skip(key: IDBValidKey): void;
/**
* Delete the current cursor value from the object store.
*
* NOTE: You CANNOT do this with a keysOnly query.
*/
delete(): PersistencePromise<void>;
}
/**
* Callback used with iterate() method.
*/
export declare type IterateCallback<KeyType, ValueType> = (key: KeyType, value: ValueType, control: IterationController) => void | PersistencePromise<void>;
/** Options available to the iterate() method. */
export interface IterateOptions {
/** Index to iterate over (else primary keys will be iterated) */
index?: string;
/** IndxedDB Range to iterate over (else entire store will be iterated) */
range?: IDBKeyRange;
/** If true, values aren't read while iterating. */
keysOnly?: boolean;
/** If true, iterate over the store in reverse. */
reverse?: boolean;
}
/**
* Wraps an IDBTransaction and exposes a store() method to get a handle to a
* specific object store.
*/
export declare class SimpleDbTransaction {
private readonly transaction;
private aborted;
/**
* A promise that resolves with the result of the IndexedDb transaction.
*/
private readonly completionDeferred;
static open(db: IDBDatabase, mode: IDBTransactionMode, objectStoreNames: string[]): SimpleDbTransaction;
constructor(transaction: IDBTransaction);
readonly completionPromise: Promise<void>;
abort(error?: Error): void;
/**
* Returns a SimpleDbStore<KeyType, ValueType> for the specified store. All
* operations performed on the SimpleDbStore happen within the context of this
* transaction and it cannot be used anymore once the transaction is
* completed.
*
* Note that we can't actually enforce that the KeyType and ValueType are
* correct, but they allow type safety through the rest of the consuming code.
*/
store<KeyType extends IDBValidKey, ValueType extends unknown>(storeName: string): SimpleDbStore<KeyType, ValueType>;
}
/**
* A wrapper around an IDBObjectStore providing an API that:
*
* 1) Has generic KeyType / ValueType parameters to provide strongly-typed
* methods for acting against the object store.
* 2) Deals with IndexedDB's onsuccess / onerror event callbacks, making every
* method return a PersistencePromise instead.
* 3) Provides a higher-level API to avoid needing to do excessive wrapping of
* intermediate IndexedDB types (IDBCursorWithValue, etc.)
*/
export declare class SimpleDbStore<KeyType extends IDBValidKey, ValueType extends unknown> {
private store;
constructor(store: IDBObjectStore);
/**
* Writes a value into the Object Store.
*
* @param key Optional explicit key to use when writing the object, else the
* key will be auto-assigned (e.g. via the defined keyPath for the store).
* @param value The object to write.
*/
put(value: ValueType): PersistencePromise<void>;
put(key: KeyType, value: ValueType): PersistencePromise<void>;
/**
* Adds a new value into an Object Store and returns the new key. Similar to
* IndexedDb's `add()`, this method will fail on primary key collisions.
*
* @param value The object to write.
* @return The key of the value to add.
*/
add(value: ValueType): PersistencePromise<KeyType>;
/**
* Gets the object with the specified key from the specified store, or null
* if no object exists with the specified key.
*
* @key The key of the object to get.
* @return The object with the specified key or null if no object exists.
*/
get(key: KeyType): PersistencePromise<ValueType | null>;
delete(key: KeyType | IDBKeyRange): PersistencePromise<void>;
/**
* If we ever need more of the count variants, we can add overloads. For now,
* all we need is to count everything in a store.
*
* Returns the number of rows in the store.
*/
count(): PersistencePromise<number>;
loadAll(): PersistencePromise<ValueType[]>;
loadAll(range: IDBKeyRange): PersistencePromise<ValueType[]>;
loadAll(index: string, range: IDBKeyRange): PersistencePromise<ValueType[]>;
deleteAll(): PersistencePromise<void>;
deleteAll(range: IDBKeyRange): PersistencePromise<void>;
deleteAll(index: string, range: IDBKeyRange): PersistencePromise<void>;
/**
* Iterates over keys and values in an object store.
*
* @param options Options specifying how to iterate the objects in the store.
* @param callback will be called for each iterated object. Iteration can be
* canceled at any point by calling the doneFn passed to the callback.
* The callback can return a PersistencePromise if it performs async
* operations but note that iteration will continue without waiting for them
* to complete.
* @returns A PersistencePromise that resolves once all PersistencePromises
* returned by callbacks resolve.
*/
iterate(callback: IterateCallback<KeyType, ValueType>): PersistencePromise<void>;
iterate(options: IterateOptions, callback: IterateCallback<KeyType, ValueType>): PersistencePromise<void>;
/**
* Iterates over a store, but waits for the given callback to complete for
* each entry before iterating the next entry. This allows the callback to do
* asynchronous work to determine if this iteration should continue.
*
* The provided callback should return `true` to continue iteration, and
* `false` otherwise.
*/
iterateSerial(callback: (k: KeyType, v: ValueType) => PersistencePromise<boolean>): PersistencePromise<void>;
private iterateCursor;
private options;
private cursor;
}

View File

@@ -0,0 +1,43 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { SnapshotVersion } from '../core/snapshot_version';
import { SortedMap } from '../util/sorted_map';
import { SortedSet } from '../util/sorted_set';
import { TargetId } from '../core/types';
import { Document, MaybeDocument } from './document';
import { DocumentKey } from './document_key';
/** Miscellaneous collection types / constants. */
export interface DocumentSizeEntry {
maybeDocument: MaybeDocument;
size: number;
}
export declare type MaybeDocumentMap = SortedMap<DocumentKey, MaybeDocument>;
export declare function maybeDocumentMap(): MaybeDocumentMap;
export declare type NullableMaybeDocumentMap = SortedMap<DocumentKey, MaybeDocument | null>;
export declare function nullableMaybeDocumentMap(): NullableMaybeDocumentMap;
export interface DocumentSizeEntries {
maybeDocuments: NullableMaybeDocumentMap;
sizeMap: SortedMap<DocumentKey, number>;
}
export declare type DocumentMap = SortedMap<DocumentKey, Document>;
export declare function documentMap(): DocumentMap;
export declare type DocumentVersionMap = SortedMap<DocumentKey, SnapshotVersion>;
export declare function documentVersionMap(): DocumentVersionMap;
export declare type DocumentKeySet = SortedSet<DocumentKey>;
export declare function documentKeySet(...keys: DocumentKey[]): DocumentKeySet;
export declare type TargetIdSet = SortedSet<TargetId>;
export declare function targetIdSet(): SortedSet<TargetId>;

View File

@@ -0,0 +1,92 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { SnapshotVersion } from '../core/snapshot_version';
import { DocumentKey } from './document_key';
import { FieldValue, JsonObject, ObjectValue } from './field_value';
import { FieldPath } from './path';
import * as api from '../protos/firestore_proto_api';
export interface DocumentOptions {
hasLocalMutations?: boolean;
hasCommittedMutations?: boolean;
}
/**
* The result of a lookup for a given path may be an existing document or a
* marker that this document does not exist at a given version.
*/
export declare abstract class MaybeDocument {
readonly key: DocumentKey;
readonly version: SnapshotVersion;
constructor(key: DocumentKey, version: SnapshotVersion);
static compareByKey(d1: MaybeDocument, d2: MaybeDocument): number;
/**
* Whether this document had a local mutation applied that has not yet been
* acknowledged by Watch.
*/
abstract readonly hasPendingWrites: boolean;
abstract isEqual(other: MaybeDocument | null | undefined): boolean;
abstract toString(): string;
}
/**
* Represents a document in Firestore with a key, version, data and whether the
* data has local mutations applied to it.
*/
export declare class Document extends MaybeDocument {
private objectValue?;
readonly proto?: api.firestoreV1ApiClientInterfaces.Document | undefined;
private readonly converter?;
readonly hasLocalMutations: boolean;
readonly hasCommittedMutations: boolean;
/**
* A cache of canonicalized FieldPaths to FieldValues that have already been
* deserialized in `getField()`.
*/
private fieldValueCache?;
constructor(key: DocumentKey, version: SnapshotVersion, options: DocumentOptions, objectValue?: ObjectValue | undefined, proto?: api.firestoreV1ApiClientInterfaces.Document | undefined, converter?: ((value: api.firestoreV1ApiClientInterfaces.Value) => FieldValue) | undefined);
field(path: FieldPath): FieldValue | null;
data(): ObjectValue;
value(): JsonObject<unknown>;
isEqual(other: MaybeDocument | null | undefined): boolean;
toString(): string;
readonly hasPendingWrites: boolean;
/**
* Returns the nested Protobuf value for 'path`. Can only be called if
* `proto` was provided at construction time.
*/
private getProtoField;
static compareByField(field: FieldPath, d1: Document, d2: Document): number;
}
/**
* A class representing a deleted document.
* Version is set to 0 if we don't point to any specific time, otherwise it
* denotes time we know it didn't exist at.
*/
export declare class NoDocument extends MaybeDocument {
readonly hasCommittedMutations: boolean;
constructor(key: DocumentKey, version: SnapshotVersion, options?: DocumentOptions);
toString(): string;
readonly hasPendingWrites: boolean;
isEqual(other: MaybeDocument | null | undefined): boolean;
}
/**
* A class representing an existing document whose data is unknown (e.g. a
* document that was updated without a known base document).
*/
export declare class UnknownDocument extends MaybeDocument {
toString(): string;
readonly hasPendingWrites: boolean;
isEqual(other: MaybeDocument | null | undefined): boolean;
}

View File

@@ -0,0 +1,19 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { Document } from './document';
export declare type DocumentComparator = (doc1: Document, doc2: Document) => number;
export declare function compareByKey(doc1: Document, doc2: Document): number;

View File

@@ -0,0 +1,43 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { ResourcePath } from './path';
export declare class DocumentKey {
readonly path: ResourcePath;
constructor(path: ResourcePath);
/** Returns true if the document is in the specified collectionId. */
hasCollectionId(collectionId: string): boolean;
isEqual(other: DocumentKey | null): boolean;
toString(): string;
static EMPTY: DocumentKey;
static comparator(k1: DocumentKey, k2: DocumentKey): number;
static isDocumentKey(path: ResourcePath): boolean;
/**
* Creates and returns a new document key with the given segments.
*
* @param path The segments of the path to the document
* @return A new instance of DocumentKey
*/
static fromSegments(segments: string[]): DocumentKey;
/**
* Creates and returns a new document key using '/' to split the string into
* segments.
*
* @param path The slash-separated path string to the document
* @return A new instance of DocumentKey
*/
static fromPathString(path: string): DocumentKey;
}

View File

@@ -0,0 +1,57 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { Document } from './document';
import { DocumentComparator } from './document_comparator';
import { DocumentKey } from './document_key';
/**
* DocumentSet is an immutable (copy-on-write) collection that holds documents
* in order specified by the provided comparator. We always add a document key
* comparator on top of what is provided to guarantee document equality based on
* the key.
*/
export declare class DocumentSet {
/**
* Returns an empty copy of the existing DocumentSet, using the same
* comparator.
*/
static emptySet(oldSet: DocumentSet): DocumentSet;
private comparator;
private keyedMap;
private sortedSet;
/** The default ordering is by key if the comparator is omitted */
constructor(comp?: DocumentComparator);
has(key: DocumentKey): boolean;
get(key: DocumentKey): Document | null;
first(): Document | null;
last(): Document | null;
isEmpty(): boolean;
/**
* Returns the index of the provided key in the document set, or -1 if the
* document key is not present in the set;
*/
indexOf(key: DocumentKey): number;
readonly size: number;
/** Iterates documents in order defined by "comparator" */
forEach(cb: (doc: Document) => void): void;
/** Inserts or updates a document with the same key */
add(doc: Document): DocumentSet;
/** Deletes a document with a given key */
delete(key: DocumentKey): DocumentSet;
isEqual(other: DocumentSet | null | undefined): boolean;
toString(): string;
private copy;
}

View File

@@ -0,0 +1,229 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { Blob } from '../api/blob';
import { SnapshotOptions } from '../api/database';
import { GeoPoint } from '../api/geo_point';
import { Timestamp } from '../api/timestamp';
import { DatabaseId } from '../core/database_info';
import { DocumentKey } from './document_key';
import { FieldMask } from './mutation';
import { FieldPath } from './path';
import { SortedMap } from '../util/sorted_map';
/**
* Supported data value types:
* - Null
* - Boolean
* - Long
* - Double
* - String
* - Object
* - Array
* - Binary
* - Timestamp
* - ServerTimestamp (a sentinel used in uncommitted writes)
* - GeoPoint
* - (Document) References
*/
export interface JsonObject<T> {
[name: string]: T;
}
export declare enum TypeOrder {
NullValue = 0,
BooleanValue = 1,
NumberValue = 2,
TimestampValue = 3,
StringValue = 4,
BlobValue = 5,
RefValue = 6,
GeoPointValue = 7,
ArrayValue = 8,
ObjectValue = 9
}
/** Defines the return value for pending server timestamps. */
export declare enum ServerTimestampBehavior {
Default = 0,
Estimate = 1,
Previous = 2
}
/** Holds properties that define field value deserialization options. */
export declare class FieldValueOptions {
readonly serverTimestampBehavior: ServerTimestampBehavior;
readonly timestampsInSnapshots: boolean;
constructor(serverTimestampBehavior: ServerTimestampBehavior, timestampsInSnapshots: boolean);
static fromSnapshotOptions(options: SnapshotOptions, timestampsInSnapshots: boolean): FieldValueOptions;
}
/**
* Potential types returned by FieldValue.value(). This could be stricter
* (instead of using {}), but there's little benefit.
*
* Note that currently we use AnyJs (which is identical except includes
* undefined) for incoming user data as a convenience to the calling code (but
* we'll throw if the data contains undefined). This should probably be changed
* to use FieldType, but all consuming code will have to be updated to
* explicitly handle undefined and then cast to FieldType or similar. Perhaps
* we should tackle this when adding robust argument validation to the API.
*/
export declare type FieldType = null | boolean | number | string | {};
/**
* A field value represents a datatype as stored by Firestore.
*/
export declare abstract class FieldValue {
abstract readonly typeOrder: TypeOrder;
abstract value(options?: FieldValueOptions): FieldType;
abstract isEqual(other: FieldValue): boolean;
abstract compareTo(other: FieldValue): number;
toString(): string;
defaultCompareTo(other: FieldValue): number;
}
export declare class NullValue extends FieldValue {
typeOrder: TypeOrder;
readonly internalValue: null;
private constructor();
value(options?: FieldValueOptions): null;
isEqual(other: FieldValue): boolean;
compareTo(other: FieldValue): number;
static INSTANCE: NullValue;
}
export declare class BooleanValue extends FieldValue {
readonly internalValue: boolean;
typeOrder: TypeOrder;
private constructor();
value(options?: FieldValueOptions): boolean;
isEqual(other: FieldValue): boolean;
compareTo(other: FieldValue): number;
static of(value: boolean): BooleanValue;
static TRUE: BooleanValue;
static FALSE: BooleanValue;
}
/** Base class for IntegerValue and DoubleValue. */
export declare abstract class NumberValue extends FieldValue {
readonly internalValue: number;
typeOrder: TypeOrder;
constructor(internalValue: number);
value(options?: FieldValueOptions): number;
compareTo(other: FieldValue): number;
}
export declare class IntegerValue extends NumberValue {
isEqual(other: FieldValue): boolean;
}
export declare class DoubleValue extends NumberValue {
static NAN: DoubleValue;
static POSITIVE_INFINITY: DoubleValue;
static NEGATIVE_INFINITY: DoubleValue;
isEqual(other: FieldValue): boolean;
}
export declare class StringValue extends FieldValue {
readonly internalValue: string;
typeOrder: TypeOrder;
constructor(internalValue: string);
value(options?: FieldValueOptions): string;
isEqual(other: FieldValue): boolean;
compareTo(other: FieldValue): number;
}
export declare class TimestampValue extends FieldValue {
readonly internalValue: Timestamp;
typeOrder: TypeOrder;
constructor(internalValue: Timestamp);
value(options?: FieldValueOptions): Date | Timestamp;
isEqual(other: FieldValue): boolean;
compareTo(other: FieldValue): number;
}
/**
* Represents a locally-applied ServerTimestamp.
*
* Notes:
* - ServerTimestampValue instances are created as the result of applying a
* TransformMutation (see TransformMutation.applyTo()). They can only exist in
* the local view of a document. Therefore they do not need to be parsed or
* serialized.
* - When evaluated locally (e.g. for snapshot.data()), they by default
* evaluate to `null`. This behavior can be configured by passing custom
* FieldValueOptions to value().
* - With respect to other ServerTimestampValues, they sort by their
* localWriteTime.
*/
export declare class ServerTimestampValue extends FieldValue {
readonly localWriteTime: Timestamp;
readonly previousValue: FieldValue | null;
typeOrder: TypeOrder;
constructor(localWriteTime: Timestamp, previousValue: FieldValue | null);
value(options?: FieldValueOptions): FieldType;
isEqual(other: FieldValue): boolean;
compareTo(other: FieldValue): number;
toString(): string;
}
export declare class BlobValue extends FieldValue {
readonly internalValue: Blob;
typeOrder: TypeOrder;
constructor(internalValue: Blob);
value(options?: FieldValueOptions): Blob;
isEqual(other: FieldValue): boolean;
compareTo(other: FieldValue): number;
}
export declare class RefValue extends FieldValue {
readonly databaseId: DatabaseId;
readonly key: DocumentKey;
typeOrder: TypeOrder;
constructor(databaseId: DatabaseId, key: DocumentKey);
value(options?: FieldValueOptions): DocumentKey;
isEqual(other: FieldValue): boolean;
compareTo(other: FieldValue): number;
}
export declare class GeoPointValue extends FieldValue {
readonly internalValue: GeoPoint;
typeOrder: TypeOrder;
constructor(internalValue: GeoPoint);
value(options?: FieldValueOptions): GeoPoint;
isEqual(other: FieldValue): boolean;
compareTo(other: FieldValue): number;
}
export declare class ObjectValue extends FieldValue {
readonly internalValue: SortedMap<string, FieldValue>;
typeOrder: TypeOrder;
constructor(internalValue: SortedMap<string, FieldValue>);
value(options?: FieldValueOptions): JsonObject<FieldType>;
forEach(action: (key: string, value: FieldValue) => void): void;
isEqual(other: FieldValue): boolean;
compareTo(other: FieldValue): number;
set(path: FieldPath, to: FieldValue): ObjectValue;
delete(path: FieldPath): ObjectValue;
contains(path: FieldPath): boolean;
field(path: FieldPath): FieldValue | null;
/**
* Returns a FieldMask built from all FieldPaths starting from this ObjectValue,
* including paths from nested objects.
*/
fieldMask(): FieldMask;
toString(): string;
private child;
private setChild;
static EMPTY: ObjectValue;
}
export declare class ArrayValue extends FieldValue {
readonly internalValue: FieldValue[];
typeOrder: TypeOrder;
constructor(internalValue: FieldValue[]);
value(options?: FieldValueOptions): FieldType[];
/**
* Returns true if the given value is contained in this array.
*/
contains(value: FieldValue): boolean;
forEach(action: (value: FieldValue) => void): void;
isEqual(other: FieldValue): boolean;
compareTo(other: FieldValue): number;
toString(): string;
}

View File

@@ -0,0 +1,345 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { Timestamp } from '../api/timestamp';
import { SnapshotVersion } from '../core/snapshot_version';
import { SortedSet } from '../util/sorted_set';
import { MaybeDocument } from './document';
import { DocumentKey } from './document_key';
import { FieldValue, ObjectValue } from './field_value';
import { FieldPath } from './path';
import { TransformOperation } from './transform_operation';
/**
* Provides a set of fields that can be used to partially patch a document.
* FieldMask is used in conjunction with ObjectValue.
* Examples:
* foo - Overwrites foo entirely with the provided value. If foo is not
* present in the companion ObjectValue, the field is deleted.
* foo.bar - Overwrites only the field bar of the object foo.
* If foo is not an object, foo is replaced with an object
* containing foo
*/
export declare class FieldMask {
readonly fields: SortedSet<FieldPath>;
constructor(fields: SortedSet<FieldPath>);
static fromSet(fields: SortedSet<FieldPath>): FieldMask;
static fromArray(fields: FieldPath[]): FieldMask;
/**
* Verifies that `fieldPath` is included by at least one field in this field
* mask.
*
* This is an O(n) operation, where `n` is the size of the field mask.
*/
covers(fieldPath: FieldPath): boolean;
isEqual(other: FieldMask): boolean;
}
/** A field path and the TransformOperation to perform upon it. */
export declare class FieldTransform {
readonly field: FieldPath;
readonly transform: TransformOperation;
constructor(field: FieldPath, transform: TransformOperation);
isEqual(other: FieldTransform): boolean;
}
/** The result of successfully applying a mutation to the backend. */
export declare class MutationResult {
/**
* The version at which the mutation was committed:
*
* - For most operations, this is the updateTime in the WriteResult.
* - For deletes, the commitTime of the WriteResponse (because deletes are
* not stored and have no updateTime).
*
* Note that these versions can be different: No-op writes will not change
* the updateTime even though the commitTime advances.
*/
readonly version: SnapshotVersion;
/**
* The resulting fields returned from the backend after a
* TransformMutation has been committed. Contains one FieldValue for each
* FieldTransform that was in the mutation.
*
* Will be null if the mutation was not a TransformMutation.
*/
readonly transformResults: Array<FieldValue | null> | null;
constructor(
/**
* The version at which the mutation was committed:
*
* - For most operations, this is the updateTime in the WriteResult.
* - For deletes, the commitTime of the WriteResponse (because deletes are
* not stored and have no updateTime).
*
* Note that these versions can be different: No-op writes will not change
* the updateTime even though the commitTime advances.
*/
version: SnapshotVersion,
/**
* The resulting fields returned from the backend after a
* TransformMutation has been committed. Contains one FieldValue for each
* FieldTransform that was in the mutation.
*
* Will be null if the mutation was not a TransformMutation.
*/
transformResults: Array<FieldValue | null> | null);
}
export declare enum MutationType {
Set = 0,
Patch = 1,
Transform = 2,
Delete = 3
}
/**
* Encodes a precondition for a mutation. This follows the model that the
* backend accepts with the special case of an explicit "empty" precondition
* (meaning no precondition).
*/
export declare class Precondition {
readonly updateTime?: SnapshotVersion | undefined;
readonly exists?: boolean | undefined;
static readonly NONE: Precondition;
private constructor();
/** Creates a new Precondition with an exists flag. */
static exists(exists: boolean): Precondition;
/** Creates a new Precondition based on a version a document exists at. */
static updateTime(version: SnapshotVersion): Precondition;
/** Returns whether this Precondition is empty. */
readonly isNone: boolean;
/**
* Returns true if the preconditions is valid for the given document
* (or null if no document is available).
*/
isValidFor(maybeDoc: MaybeDocument | null): boolean;
isEqual(other: Precondition): boolean;
}
/**
* A mutation describes a self-contained change to a document. Mutations can
* create, replace, delete, and update subsets of documents.
*
* Mutations not only act on the value of the document but also it version.
*
* For local mutations (mutations that haven't been committed yet), we preserve
* the existing version for Set, Patch, and Transform mutations. For Delete
* mutations, we reset the version to 0.
*
* Here's the expected transition table.
*
* MUTATION APPLIED TO RESULTS IN
*
* SetMutation Document(v3) Document(v3)
* SetMutation NoDocument(v3) Document(v0)
* SetMutation null Document(v0)
* PatchMutation Document(v3) Document(v3)
* PatchMutation NoDocument(v3) NoDocument(v3)
* PatchMutation null null
* TransformMutation Document(v3) Document(v3)
* TransformMutation NoDocument(v3) NoDocument(v3)
* TransformMutation null null
* DeleteMutation Document(v3) NoDocument(v0)
* DeleteMutation NoDocument(v3) NoDocument(v0)
* DeleteMutation null NoDocument(v0)
*
* For acknowledged mutations, we use the updateTime of the WriteResponse as
* the resulting version for Set, Patch, and Transform mutations. As deletes
* have no explicit update time, we use the commitTime of the WriteResponse for
* Delete mutations.
*
* If a mutation is acknowledged by the backend but fails the precondition check
* locally, we return an `UnknownDocument` and rely on Watch to send us the
* updated version.
*
* Note that TransformMutations don't create Documents (in the case of being
* applied to a NoDocument), even though they would on the backend. This is
* because the client always combines the TransformMutation with a SetMutation
* or PatchMutation and we only want to apply the transform if the prior
* mutation resulted in a Document (always true for a SetMutation, but not
* necessarily for a PatchMutation).
*
* ## Subclassing Notes
*
* Subclasses of Mutation need to implement applyToRemoteDocument() and
* applyToLocalView() to implement the actual behavior of applying the mutation
* to some source document.
*/
export declare abstract class Mutation {
abstract readonly type: MutationType;
abstract readonly key: DocumentKey;
abstract readonly precondition: Precondition;
/**
* Applies this mutation to the given MaybeDocument or null for the purposes
* of computing a new remote document. If the input document doesn't match the
* expected state (e.g. it is null or outdated), an `UnknownDocument` can be
* returned.
*
* @param maybeDoc The document to mutate. The input document can be null if
* the client has no knowledge of the pre-mutation state of the document.
* @param mutationResult The result of applying the mutation from the backend.
* @return The mutated document. The returned document may be an
* UnknownDocument if the mutation could not be applied to the locally
* cached base document.
*/
abstract applyToRemoteDocument(maybeDoc: MaybeDocument | null, mutationResult: MutationResult): MaybeDocument;
/**
* Applies this mutation to the given MaybeDocument or null for the purposes
* of computing the new local view of a document. Both the input and returned
* documents can be null.
*
* @param maybeDoc The document to mutate. The input document can be null if
* the client has no knowledge of the pre-mutation state of the document.
* @param baseDoc The state of the document prior to this mutation batch. The
* input document can be null if the client has no knowledge of the
* pre-mutation state of the document.
* @param localWriteTime A timestamp indicating the local write time of the
* batch this mutation is a part of.
* @return The mutated document. The returned document may be null, but only
* if maybeDoc was null and the mutation would not create a new document.
*/
abstract applyToLocalView(maybeDoc: MaybeDocument | null, baseDoc: MaybeDocument | null, localWriteTime: Timestamp): MaybeDocument | null;
/**
* If this mutation is not idempotent, returns the base value to persist with
* this mutation. If a base value is returned, the mutation is always applied
* to this base value, even if document has already been updated.
*
* The base value is a sparse object that consists of only the document
* fields for which this mutation contains a non-idempotent transformation
* (e.g. a numeric increment). The provided alue guarantees consistent
* behavior for non-idempotent transforms and allow us to return the same
* latency-compensated value even if the backend has already applied the
* mutation. The base value is null for idempotent mutations, as they can be
* re-played even if the backend has already applied them.
*
* @return a base value to store along with the mutation, or null for
* idempotent mutations.
*/
abstract extractBaseValue(maybeDoc: MaybeDocument | null): ObjectValue | null;
abstract isEqual(other: Mutation): boolean;
protected verifyKeyMatches(maybeDoc: MaybeDocument | null): void;
/**
* Returns the version from the given document for use as the result of a
* mutation. Mutations are defined to return the version of the base document
* only if it is an existing document. Deleted and unknown documents have a
* post-mutation version of SnapshotVersion.MIN.
*/
protected static getPostMutationVersion(maybeDoc: MaybeDocument | null): SnapshotVersion;
}
/**
* A mutation that creates or replaces the document at the given key with the
* object value contents.
*/
export declare class SetMutation extends Mutation {
readonly key: DocumentKey;
readonly value: ObjectValue;
readonly precondition: Precondition;
constructor(key: DocumentKey, value: ObjectValue, precondition: Precondition);
readonly type: MutationType;
applyToRemoteDocument(maybeDoc: MaybeDocument | null, mutationResult: MutationResult): MaybeDocument;
applyToLocalView(maybeDoc: MaybeDocument | null, baseDoc: MaybeDocument | null, localWriteTime: Timestamp): MaybeDocument | null;
extractBaseValue(maybeDoc: MaybeDocument | null): null;
isEqual(other: Mutation): boolean;
}
/**
* A mutation that modifies fields of the document at the given key with the
* given values. The values are applied through a field mask:
*
* * When a field is in both the mask and the values, the corresponding field
* is updated.
* * When a field is in neither the mask nor the values, the corresponding
* field is unmodified.
* * When a field is in the mask but not in the values, the corresponding field
* is deleted.
* * When a field is not in the mask but is in the values, the values map is
* ignored.
*/
export declare class PatchMutation extends Mutation {
readonly key: DocumentKey;
readonly data: ObjectValue;
readonly fieldMask: FieldMask;
readonly precondition: Precondition;
constructor(key: DocumentKey, data: ObjectValue, fieldMask: FieldMask, precondition: Precondition);
readonly type: MutationType;
applyToRemoteDocument(maybeDoc: MaybeDocument | null, mutationResult: MutationResult): MaybeDocument;
applyToLocalView(maybeDoc: MaybeDocument | null, baseDoc: MaybeDocument | null, localWriteTime: Timestamp): MaybeDocument | null;
extractBaseValue(maybeDoc: MaybeDocument | null): null;
isEqual(other: Mutation): boolean;
/**
* Patches the data of document if available or creates a new document. Note
* that this does not check whether or not the precondition of this patch
* holds.
*/
private patchDocument;
private patchObject;
}
/**
* A mutation that modifies specific fields of the document with transform
* operations. Currently the only supported transform is a server timestamp, but
* IP Address, increment(n), etc. could be supported in the future.
*
* It is somewhat similar to a PatchMutation in that it patches specific fields
* and has no effect when applied to a null or NoDocument (see comment on
* Mutation for rationale).
*/
export declare class TransformMutation extends Mutation {
readonly key: DocumentKey;
readonly fieldTransforms: FieldTransform[];
readonly type: MutationType;
readonly precondition: Precondition;
constructor(key: DocumentKey, fieldTransforms: FieldTransform[]);
applyToRemoteDocument(maybeDoc: MaybeDocument | null, mutationResult: MutationResult): MaybeDocument;
applyToLocalView(maybeDoc: MaybeDocument | null, baseDoc: MaybeDocument | null, localWriteTime: Timestamp): MaybeDocument | null;
extractBaseValue(maybeDoc: MaybeDocument | null): ObjectValue | null;
isEqual(other: Mutation): boolean;
/**
* Asserts that the given MaybeDocument is actually a Document and verifies
* that it matches the key for this mutation. Since we only support
* transformations with precondition exists this method is guaranteed to be
* safe.
*/
private requireDocument;
/**
* Creates a list of "transform results" (a transform result is a field value
* representing the result of applying a transform) for use after a
* TransformMutation has been acknowledged by the server.
*
* @param baseDoc The document prior to applying this mutation batch.
* @param serverTransformResults The transform results received by the server.
* @return The transform results list.
*/
private serverTransformResults;
/**
* Creates a list of "transform results" (a transform result is a field value
* representing the result of applying a transform) for use when applying a
* TransformMutation locally.
*
* @param localWriteTime The local time of the transform mutation (used to
* generate ServerTimestampValues).
* @param maybeDoc The current state of the document after applying all
* previous mutations.
* @param baseDoc The document prior to applying this mutation batch.
* @return The transform results list.
*/
private localTransformResults;
private transformObject;
}
/** A mutation that deletes the document at the given key. */
export declare class DeleteMutation extends Mutation {
readonly key: DocumentKey;
readonly precondition: Precondition;
constructor(key: DocumentKey, precondition: Precondition);
readonly type: MutationType;
applyToRemoteDocument(maybeDoc: MaybeDocument | null, mutationResult: MutationResult): MaybeDocument;
applyToLocalView(maybeDoc: MaybeDocument | null, baseDoc: MaybeDocument | null, localWriteTime: Timestamp): MaybeDocument | null;
extractBaseValue(maybeDoc: MaybeDocument | null): null;
isEqual(other: Mutation): boolean;
}

View File

@@ -0,0 +1,89 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { Timestamp } from '../api/timestamp';
import { SnapshotVersion } from '../core/snapshot_version';
import { BatchId, ProtoByteString } from '../core/types';
import { DocumentKeySet, DocumentVersionMap, MaybeDocumentMap } from './collections';
import { MaybeDocument } from './document';
import { DocumentKey } from './document_key';
import { Mutation, MutationResult } from './mutation';
export declare const BATCHID_UNKNOWN = -1;
/**
* A batch of mutations that will be sent as one unit to the backend.
*/
export declare class MutationBatch {
batchId: BatchId;
localWriteTime: Timestamp;
baseMutations: Mutation[];
mutations: Mutation[];
/**
* @param batchId The unique ID of this mutation batch.
* @param localWriteTime The original write time of this mutation.
* @param baseMutations Mutations that are used to populate the base
* values when this mutation is applied locally. This can be used to locally
* overwrite values that are persisted in the remote document cache. Base
* mutations are never sent to the backend.
* @param mutations The user-provided mutations in this mutation batch.
* User-provided mutations are applied both locally and remotely on the
* backend.
*/
constructor(batchId: BatchId, localWriteTime: Timestamp, baseMutations: Mutation[], mutations: Mutation[]);
/**
* Applies all the mutations in this MutationBatch to the specified document
* to create a new remote document
*
* @param docKey The key of the document to apply mutations to.
* @param maybeDoc The document to apply mutations to.
* @param batchResult The result of applying the MutationBatch to the
* backend.
*/
applyToRemoteDocument(docKey: DocumentKey, maybeDoc: MaybeDocument | null, batchResult: MutationBatchResult): MaybeDocument | null;
/**
* Computes the local view of a document given all the mutations in this
* batch.
*
* @param docKey The key of the document to apply mutations to.
* @param maybeDoc The document to apply mutations to.
*/
applyToLocalView(docKey: DocumentKey, maybeDoc: MaybeDocument | null): MaybeDocument | null;
/**
* Computes the local view for all provided documents given the mutations in
* this batch.
*/
applyToLocalDocumentSet(maybeDocs: MaybeDocumentMap): MaybeDocumentMap;
keys(): DocumentKeySet;
isEqual(other: MutationBatch): boolean;
}
/** The result of applying a mutation batch to the backend. */
export declare class MutationBatchResult {
readonly batch: MutationBatch;
readonly commitVersion: SnapshotVersion;
readonly mutationResults: MutationResult[];
readonly streamToken: ProtoByteString;
/**
* A pre-computed mapping from each mutated document to the resulting
* version.
*/
readonly docVersions: DocumentVersionMap;
private constructor();
/**
* Creates a new MutationBatchResult for the given batch and results. There
* must be one result for each mutation in the batch. This static factory
* caches a document=>version mapping (docVersions).
*/
static from(batch: MutationBatch, commitVersion: SnapshotVersion, results: MutationResult[], streamToken: ProtoByteString): MutationBatchResult;
}

View File

@@ -0,0 +1,100 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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 declare const DOCUMENT_KEY_NAME = "__name__";
/**
* Path represents an ordered sequence of string segments.
*/
declare abstract class BasePath<B extends BasePath<B>> {
private segments;
private offset;
private len;
constructor(segments: string[], offset?: number, length?: number);
/**
* Abstract constructor method to construct an instance of B with the given
* parameters.
*/
protected abstract construct(segments: string[], offset?: number, length?: number): B;
/**
* Returns a String representation.
*
* Implementing classes are required to provide deterministic implementations as
* the String representation is used to obtain canonical Query IDs.
*/
abstract toString(): string;
readonly length: number;
isEqual(other: B): boolean;
child(nameOrPath: string | B): B;
/** The index of one past the last segment of the path. */
private limit;
popFirst(size?: number): B;
popLast(): B;
firstSegment(): string;
lastSegment(): string;
get(index: number): string;
isEmpty(): boolean;
isPrefixOf(other: this): boolean;
isImmediateParentOf(potentialChild: this): boolean;
forEach(fn: (segment: string) => void): void;
toArray(): string[];
static comparator<T extends BasePath<T>>(p1: BasePath<T>, p2: BasePath<T>): number;
}
/**
* A slash-separated path for navigating resources (documents and collections)
* within Firestore.
*/
export declare class ResourcePath extends BasePath<ResourcePath> {
protected construct(segments: string[], offset?: number, length?: number): ResourcePath;
canonicalString(): string;
toString(): string;
/**
* Creates a resource path from the given slash-delimited string.
*/
static fromString(path: string): ResourcePath;
static EMPTY_PATH: ResourcePath;
}
/** A dot-separated path for navigating sub-objects within a document. */
export declare class FieldPath extends BasePath<FieldPath> {
protected construct(segments: string[], offset?: number, length?: number): FieldPath;
/**
* Returns true if the string could be used as a segment in a field path
* without escaping.
*/
private static isValidIdentifier;
canonicalString(): string;
toString(): string;
/**
* Returns true if this field references the key of a document.
*/
isKeyField(): boolean;
/**
* The field designating the key of a document.
*/
static keyField(): FieldPath;
/**
* Parses a field string from the given server-formatted string.
*
* - Splitting the empty string is not allowed (for now at least).
* - Empty segments within the string (e.g. if there are two consecutive
* separators) are not allowed.
*
* TODO(b/37244157): we should make this more strict. Right now, it allows
* non-identifier path components, even if they aren't escaped.
*/
static fromServerFormat(path: string): FieldPath;
static EMPTY_PATH: FieldPath;
}
export {};

View File

@@ -0,0 +1,95 @@
/**
* @license
* Copyright 2018 Google Inc.
*
* 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.
*/
import { Timestamp } from '../api/timestamp';
import { FieldValue, NumberValue } from './field_value';
/** Represents a transform within a TransformMutation. */
export interface TransformOperation {
/**
* Computes the local transform result against the provided `previousValue`,
* optionally using the provided localWriteTime.
*/
applyToLocalView(previousValue: FieldValue | null, localWriteTime: Timestamp): FieldValue;
/**
* Computes a final transform result after the transform has been acknowledged
* by the server, potentially using the server-provided transformResult.
*/
applyToRemoteDocument(previousValue: FieldValue | null, transformResult: FieldValue | null): FieldValue;
/**
* If this transform operation is not idempotent, returns the base value to
* persist for this transform. If a base value is returned, the transform
* operation is always applied to this base value, even if document has
* already been updated.
*
* Base values provide consistent behavior for non-idempotent transforms and
* allow us to return the same latency-compensated value even if the backend
* has already applied the transform operation. The base value is null for
* idempotent transforms, as they can be re-played even if the backend has
* already applied them.
*
* @return a base value to store along with the mutation, or null for
* idempotent transforms.
*/
computeBaseValue(previousValue: FieldValue | null): FieldValue | null;
isEqual(other: TransformOperation): boolean;
}
/** Transforms a value into a server-generated timestamp. */
export declare class ServerTimestampTransform implements TransformOperation {
private constructor();
static instance: ServerTimestampTransform;
applyToLocalView(previousValue: FieldValue | null, localWriteTime: Timestamp): FieldValue;
applyToRemoteDocument(previousValue: FieldValue | null, transformResult: FieldValue | null): FieldValue;
computeBaseValue(previousValue: FieldValue | null): FieldValue | null;
isEqual(other: TransformOperation): boolean;
}
/** Transforms an array value via a union operation. */
export declare class ArrayUnionTransformOperation implements TransformOperation {
readonly elements: FieldValue[];
constructor(elements: FieldValue[]);
applyToLocalView(previousValue: FieldValue | null, localWriteTime: Timestamp): FieldValue;
applyToRemoteDocument(previousValue: FieldValue | null, transformResult: FieldValue | null): FieldValue;
private apply;
computeBaseValue(previousValue: FieldValue | null): FieldValue | null;
isEqual(other: TransformOperation): boolean;
}
/** Transforms an array value via a remove operation. */
export declare class ArrayRemoveTransformOperation implements TransformOperation {
readonly elements: FieldValue[];
constructor(elements: FieldValue[]);
applyToLocalView(previousValue: FieldValue | null, localWriteTime: Timestamp): FieldValue;
applyToRemoteDocument(previousValue: FieldValue | null, transformResult: FieldValue | null): FieldValue;
private apply;
computeBaseValue(previousValue: FieldValue | null): FieldValue | null;
isEqual(other: TransformOperation): boolean;
}
/**
* Implements the backend semantics for locally computed NUMERIC_ADD (increment)
* transforms. Converts all field values to integers or doubles, but unlike the
* backend does not cap integer values at 2^63. Instead, JavaScript number
* arithmetic is used and precision loss can occur for values greater than 2^53.
*/
export declare class NumericIncrementTransformOperation implements TransformOperation {
readonly operand: NumberValue;
constructor(operand: NumberValue);
applyToLocalView(previousValue: FieldValue | null, localWriteTime: Timestamp): FieldValue;
applyToRemoteDocument(previousValue: FieldValue | null, transformResult: FieldValue | null): FieldValue;
/**
* Inspects the provided value, returning the provided value if it is already
* a NumberValue, otherwise returning a coerced IntegerValue of 0.
*/
computeBaseValue(previousValue: FieldValue | null): NumberValue;
isEqual(other: TransformOperation): boolean;
}

View File

@@ -0,0 +1,29 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { FirebaseNamespace } from '@firebase/app-types';
/**
* Configures Firestore as part of the Firebase SDK by calling registerService.
*/
export declare function configureForFirebase(firebase: FirebaseNamespace): void;
/**
* Exports the Firestore namespace into the provided `exportObject` object under
* the key 'firestore'. This is used for wrapped binary that exposes Firestore
* as a goog module.
*/
export declare function configureForStandalone(exportObject: {
[key: string]: {};
}): void;

View File

@@ -0,0 +1,60 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { DatabaseId, DatabaseInfo } from '../core/database_info';
import { ProtoByteString } from '../core/types';
import { Connection } from '../remote/connection';
import { JsonProtoSerializer } from '../remote/serializer';
import { ConnectivityMonitor } from './../remote/connectivity_monitor';
/**
* Provides a common interface to load anything platform dependent, e.g.
* the connection implementation.
*
* An implementation of this must be provided at compile time for the platform.
*/
export interface Platform {
loadConnection(databaseInfo: DatabaseInfo): Promise<Connection>;
newConnectivityMonitor(): ConnectivityMonitor;
newSerializer(databaseId: DatabaseId): JsonProtoSerializer;
/** Formats an object as a JSON string, suitable for logging. */
formatJSON(value: unknown): string;
/** Converts a Base64 encoded string to a binary string. */
atob(encoded: string): string;
/** Converts a binary string to a Base64 encoded string. */
btoa(raw: string): string;
/** The Platform's 'window' implementation or null if not available. */
readonly window: Window | null;
/** The Platform's 'document' implementation or null if not available. */
readonly document: Document | null;
/** True if and only if the Base64 conversion functions are available. */
readonly base64Available: boolean;
readonly emptyByteString: ProtoByteString;
}
/**
* Provides singleton helpers where setup code can inject a platform at runtime.
* setPlatform needs to be set before Firestore is used and must be set exactly
* once.
*/
export declare class PlatformSupport {
private static platform;
static setPlatform(platform: Platform): void;
static getPlatform(): Platform;
}
/**
* Returns the representation of an empty "proto" byte string for the
* platform.
*/
export declare function emptyByteString(): ProtoByteString;

View File

@@ -0,0 +1,33 @@
/**
* @license
* Copyright 2019 Google Inc.
*
* 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.
*/
import { ConnectivityMonitor, NetworkStatus } from './../remote/connectivity_monitor';
/**
* Browser implementation of ConnectivityMonitor.
*/
export declare class BrowserConnectivityMonitor implements ConnectivityMonitor {
private readonly networkAvailableListener;
private readonly networkUnavailableListener;
private callbacks;
constructor();
addCallback(callback: (status: NetworkStatus) => void): void;
shutdown(): void;
private configureNetworkMonitoring;
private onNetworkAvailable;
private onNetworkUnavailable;
/** Checks that all used attributes of window are available. */
static isAvailable(): boolean;
}

View File

@@ -0,0 +1,17 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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 {};

View File

@@ -0,0 +1,34 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { DatabaseId, DatabaseInfo } from '../core/database_info';
import { Platform } from '../platform/platform';
import { Connection } from '../remote/connection';
import { JsonProtoSerializer } from '../remote/serializer';
import { ConnectivityMonitor } from './../remote/connectivity_monitor';
export declare class BrowserPlatform implements Platform {
readonly base64Available: boolean;
readonly emptyByteString = "";
constructor();
readonly document: Document | null;
readonly window: Window | null;
loadConnection(databaseInfo: DatabaseInfo): Promise<Connection>;
newConnectivityMonitor(): ConnectivityMonitor;
newSerializer(databaseId: DatabaseId): JsonProtoSerializer;
formatJSON(value: unknown): string;
atob(encoded: string): string;
btoa(raw: string): string;
}

View File

@@ -0,0 +1,34 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { Token } from '../api/credentials';
import { DatabaseInfo } from '../core/database_info';
import { Connection, Stream } from '../remote/connection';
export declare class WebChannelConnection implements Connection {
private readonly databaseId;
private readonly baseUrl;
private readonly forceLongPolling;
constructor(info: DatabaseInfo);
/**
* Modifies the headers for a request, adding any authorization token if
* present and any additional headers for the request.
*/
private modifyHeadersForRequest;
invokeRPC<Req, Resp>(rpcName: string, request: Req, token: Token | null): Promise<Resp>;
invokeStreamingRPC<Req, Resp>(rpcName: string, request: Req, token: Token | null): Promise<Resp[]>;
openStream<Req, Resp>(rpcName: string, token: Token | null): Stream<Req, Resp>;
makeUrl(rpcName: string): string;
}

View File

@@ -0,0 +1,33 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import * as grpc from 'grpc';
import { Token } from '../api/credentials';
import { DatabaseInfo } from '../core/database_info';
import { Connection, Stream } from '../remote/connection';
/**
* A Connection implemented by GRPC-Node.
*/
export declare class GrpcConnection implements Connection {
private databaseInfo;
private firestore;
private cachedStub;
constructor(protos: grpc.GrpcObject, databaseInfo: DatabaseInfo);
private ensureActiveStub;
invokeRPC<Req, Resp>(rpcName: string, request: Req, token: Token | null): Promise<Resp>;
invokeStreamingRPC<Req, Resp>(rpcName: string, request: Req, token: Token | null): Promise<Resp[]>;
openStream<Req, Resp>(rpcName: string, token: Token | null): Stream<Req, Resp>;
}

View File

@@ -0,0 +1,28 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import * as grpc from 'grpc';
import * as ProtobufJS from 'protobufjs';
/** Used by tests so we can match @grpc/proto-loader behavior. */
export declare const protoLoaderOptions: ProtobufJS.IConversionOptions;
/**
* Loads the protocol buffer definitions for Firestore.
*
* @returns The GrpcObject representing our protos.
*/
export declare function loadProtos(): grpc.GrpcObject;
/** Used by tests so we can directly create ProtobufJS proto message objects from JSON protos. */
export declare function loadRawProtos(): ProtobufJS.Root;

View File

@@ -0,0 +1,17 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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 {};

View File

@@ -0,0 +1,33 @@
/**
* @license
* Copyright 2017 Google Inc.
*
* 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.
*/
import { DatabaseId, DatabaseInfo } from '../core/database_info';
import { Platform } from '../platform/platform';
import { Connection } from '../remote/connection';
import { JsonProtoSerializer } from '../remote/serializer';
import { ConnectivityMonitor } from './../remote/connectivity_monitor';
export declare class NodePlatform implements Platform {
readonly base64Available = true;
readonly emptyByteString: Uint8Array;
readonly document: null;
readonly window: Window | null;
loadConnection(databaseInfo: DatabaseInfo): Promise<Connection>;
newConnectivityMonitor(): ConnectivityMonitor;
newSerializer(partitionId: DatabaseId): JsonProtoSerializer;
formatJSON(value: unknown): string;
atob(encoded: string): string;
btoa(raw: string): string;
}

View File

@@ -0,0 +1,2 @@
These protos are copied from https://github.com/googleapis/googleapis and
https://github.com/google/protobuf. Run update.sh to update them.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,31 @@
// Copyright (c) 2015, Google Inc.
//
// 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.
syntax = "proto3";
package google.api;
import "google/api/http.proto";
import "google/protobuf/descriptor.proto";
option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations";
option java_multiple_files = true;
option java_outer_classname = "AnnotationsProto";
option java_package = "com.google.api";
option objc_class_prefix = "GAPI";
extend google.protobuf.MethodOptions {
// See `HttpRule`.
HttpRule http = 72295728;
}

View File

@@ -0,0 +1,370 @@
// Copyright 2018 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.
//
syntax = "proto3";
package google.api;
option cc_enable_arenas = true;
option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations";
option java_multiple_files = true;
option java_outer_classname = "HttpProto";
option java_package = "com.google.api";
option objc_class_prefix = "GAPI";
// Defines the HTTP configuration for an API service. It contains a list of
// [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method
// to one or more HTTP REST API methods.
message Http {
// A list of HTTP configuration rules that apply to individual API methods.
//
// **NOTE:** All service configuration rules follow "last one wins" order.
repeated HttpRule rules = 1;
// When set to true, URL path parmeters will be fully URI-decoded except in
// cases of single segment matches in reserved expansion, where "%2F" will be
// left encoded.
//
// The default behavior is to not decode RFC 6570 reserved characters in multi
// segment matches.
bool fully_decode_reserved_expansion = 2;
}
// # gRPC Transcoding
//
// gRPC Transcoding is a feature for mapping between a gRPC method and one or
// more HTTP REST endpoints. It allows developers to build a single API service
// that supports both gRPC APIs and REST APIs. Many systems, including [Google
// APIs](https://github.com/googleapis/googleapis),
// [Cloud Endpoints](https://cloud.google.com/endpoints), [gRPC
// Gateway](https://github.com/grpc-ecosystem/grpc-gateway),
// and [Envoy](https://github.com/envoyproxy/envoy) proxy support this feature
// and use it for large scale production services.
//
// `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies
// how different portions of the gRPC request message are mapped to the URL
// path, URL query parameters, and HTTP request body. It also controls how the
// gRPC response message is mapped to the HTTP response body. `HttpRule` is
// typically specified as an `google.api.http` annotation on the gRPC method.
//
// Each mapping specifies a URL path template and an HTTP method. The path
// template may refer to one or more fields in the gRPC request message, as long
// as each field is a non-repeated field with a primitive (non-message) type.
// The path template controls how fields of the request message are mapped to
// the URL path.
//
// Example:
//
// service Messaging {
// rpc GetMessage(GetMessageRequest) returns (Message) {
// option (google.api.http) = {
// get: "/v1/{name=messages/*}"
// };
// }
// }
// message GetMessageRequest {
// string name = 1; // Mapped to URL path.
// }
// message Message {
// string text = 1; // The resource content.
// }
//
// This enables an HTTP REST to gRPC mapping as below:
//
// HTTP | gRPC
// -----|-----
// `GET /v1/messages/123456` | `GetMessage(name: "messages/123456")`
//
// Any fields in the request message which are not bound by the path template
// automatically become HTTP query parameters if there is no HTTP request body.
// For example:
//
// service Messaging {
// rpc GetMessage(GetMessageRequest) returns (Message) {
// option (google.api.http) = {
// get:"/v1/messages/{message_id}"
// };
// }
// }
// message GetMessageRequest {
// message SubMessage {
// string subfield = 1;
// }
// string message_id = 1; // Mapped to URL path.
// int64 revision = 2; // Mapped to URL query parameter `revision`.
// SubMessage sub = 3; // Mapped to URL query parameter `sub.subfield`.
// }
//
// This enables a HTTP JSON to RPC mapping as below:
//
// HTTP | gRPC
// -----|-----
// `GET /v1/messages/123456?revision=2&sub.subfield=foo` | `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: "foo"))`
//
// Note that fields which are mapped to URL query parameters must have a
// primitive type or a repeated primitive type or a non-repeated message type.
// In the case of a repeated type, the parameter can be repeated in the URL
// as `...?param=A&param=B`. In the case of a message type, each field of the
// message is mapped to a separate parameter, such as
// `...?foo.a=A&foo.b=B&foo.c=C`.
//
// For HTTP methods that allow a request body, the `body` field
// specifies the mapping. Consider a REST update method on the
// message resource collection:
//
// service Messaging {
// rpc UpdateMessage(UpdateMessageRequest) returns (Message) {
// option (google.api.http) = {
// patch: "/v1/messages/{message_id}"
// body: "message"
// };
// }
// }
// message UpdateMessageRequest {
// string message_id = 1; // mapped to the URL
// Message message = 2; // mapped to the body
// }
//
// The following HTTP JSON to RPC mapping is enabled, where the
// representation of the JSON in the request body is determined by
// protos JSON encoding:
//
// HTTP | gRPC
// -----|-----
// `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: "123456" message { text: "Hi!" })`
//
// The special name `*` can be used in the body mapping to define that
// every field not bound by the path template should be mapped to the
// request body. This enables the following alternative definition of
// the update method:
//
// service Messaging {
// rpc UpdateMessage(Message) returns (Message) {
// option (google.api.http) = {
// patch: "/v1/messages/{message_id}"
// body: "*"
// };
// }
// }
// message Message {
// string message_id = 1;
// string text = 2;
// }
//
//
// The following HTTP JSON to RPC mapping is enabled:
//
// HTTP | gRPC
// -----|-----
// `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: "123456" text: "Hi!")`
//
// Note that when using `*` in the body mapping, it is not possible to
// have HTTP parameters, as all fields not bound by the path end in
// the body. This makes this option more rarely used in practice when
// defining REST APIs. The common usage of `*` is in custom methods
// which don't use the URL at all for transferring data.
//
// It is possible to define multiple HTTP methods for one RPC by using
// the `additional_bindings` option. Example:
//
// service Messaging {
// rpc GetMessage(GetMessageRequest) returns (Message) {
// option (google.api.http) = {
// get: "/v1/messages/{message_id}"
// additional_bindings {
// get: "/v1/users/{user_id}/messages/{message_id}"
// }
// };
// }
// }
// message GetMessageRequest {
// string message_id = 1;
// string user_id = 2;
// }
//
// This enables the following two alternative HTTP JSON to RPC mappings:
//
// HTTP | gRPC
// -----|-----
// `GET /v1/messages/123456` | `GetMessage(message_id: "123456")`
// `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: "123456")`
//
// ## Rules for HTTP mapping
//
// 1. Leaf request fields (recursive expansion nested messages in the request
// message) are classified into three categories:
// - Fields referred by the path template. They are passed via the URL path.
// - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They are passed via the HTTP
// request body.
// - All other fields are passed via the URL query parameters, and the
// parameter name is the field path in the request message. A repeated
// field can be represented as multiple query parameters under the same
// name.
// 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL query parameter, all fields
// are passed via URL path and HTTP request body.
// 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP request body, all
// fields are passed via URL path and URL query parameters.
//
// ### Path template syntax
//
// Template = "/" Segments [ Verb ] ;
// Segments = Segment { "/" Segment } ;
// Segment = "*" | "**" | LITERAL | Variable ;
// Variable = "{" FieldPath [ "=" Segments ] "}" ;
// FieldPath = IDENT { "." IDENT } ;
// Verb = ":" LITERAL ;
//
// The syntax `*` matches a single URL path segment. The syntax `**` matches
// zero or more URL path segments, which must be the last part of the URL path
// except the `Verb`.
//
// The syntax `Variable` matches part of the URL path as specified by its
// template. A variable template must not contain other variables. If a variable
// matches a single path segment, its template may be omitted, e.g. `{var}`
// is equivalent to `{var=*}`.
//
// The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL`
// contains any reserved character, such characters should be percent-encoded
// before the matching.
//
// If a variable contains exactly one path segment, such as `"{var}"` or
// `"{var=*}"`, when such a variable is expanded into a URL path on the client
// side, all characters except `[-_.~0-9a-zA-Z]` are percent-encoded. The
// server side does the reverse decoding. Such variables show up in the
// [Discovery Document](https://developers.google.com/discovery/v1/reference/apis)
// as `{var}`.
//
// If a variable contains multiple path segments, such as `"{var=foo/*}"`
// or `"{var=**}"`, when such a variable is expanded into a URL path on the
// client side, all characters except `[-_.~/0-9a-zA-Z]` are percent-encoded.
// The server side does the reverse decoding, except "%2F" and "%2f" are left
// unchanged. Such variables show up in the
// [Discovery Document](https://developers.google.com/discovery/v1/reference/apis)
// as `{+var}`.
//
// ## Using gRPC API Service Configuration
//
// gRPC API Service Configuration (service config) is a configuration language
// for configuring a gRPC service to become a user-facing product. The
// service config is simply the YAML representation of the `google.api.Service`
// proto message.
//
// As an alternative to annotating your proto file, you can configure gRPC
// transcoding in your service config YAML files. You do this by specifying a
// `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same
// effect as the proto annotation. This can be particularly useful if you
// have a proto that is reused in multiple services. Note that any transcoding
// specified in the service config will override any matching transcoding
// configuration in the proto.
//
// Example:
//
// http:
// rules:
// # Selects a gRPC method and applies HttpRule to it.
// - selector: example.v1.Messaging.GetMessage
// get: /v1/messages/{message_id}/{sub.subfield}
//
// ## Special notes
//
// When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the
// proto to JSON conversion must follow the [proto3
// specification](https://developers.google.com/protocol-buffers/docs/proto3#json).
//
// While the single segment variable follows the semantics of
// [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 Simple String
// Expansion, the multi segment variable **does not** follow RFC 6570 Section
// 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion
// does not expand special characters like `?` and `#`, which would lead
// to invalid URLs. As the result, gRPC Transcoding uses a custom encoding
// for multi segment variables.
//
// The path variables **must not** refer to any repeated or mapped field,
// because client libraries are not capable of handling such variable expansion.
//
// The path variables **must not** capture the leading "/" character. The reason
// is that the most common use case "{var}" does not capture the leading "/"
// character. For consistency, all path variables must share the same behavior.
//
// Repeated message fields must not be mapped to URL query parameters, because
// no client library can support such complicated mapping.
//
// If an API needs to use a JSON array for request or response body, it can map
// the request or response body to a repeated field. However, some gRPC
// Transcoding implementations may not support this feature.
message HttpRule {
// Selects a method to which this rule applies.
//
// Refer to [selector][google.api.DocumentationRule.selector] for syntax details.
string selector = 1;
// Determines the URL pattern is matched by this rules. This pattern can be
// used with any of the {get|put|post|delete|patch} methods. A custom method
// can be defined using the 'custom' field.
oneof pattern {
// Maps to HTTP GET. Used for listing and getting information about
// resources.
string get = 2;
// Maps to HTTP PUT. Used for replacing a resource.
string put = 3;
// Maps to HTTP POST. Used for creating a resource or performing an action.
string post = 4;
// Maps to HTTP DELETE. Used for deleting a resource.
string delete = 5;
// Maps to HTTP PATCH. Used for updating a resource.
string patch = 6;
// The custom pattern is used for specifying an HTTP method that is not
// included in the `pattern` field, such as HEAD, or "*" to leave the
// HTTP method unspecified for this rule. The wild-card rule is useful
// for services that provide content to Web (HTML) clients.
CustomHttpPattern custom = 8;
}
// The name of the request field whose value is mapped to the HTTP request
// body, or `*` for mapping all request fields not captured by the path
// pattern to the HTTP body, or omitted for not having any HTTP request body.
//
// NOTE: the referred field must be present at the top-level of the request
// message type.
string body = 7;
// Optional. The name of the response field whose value is mapped to the HTTP
// response body. When omitted, the entire response message will be used
// as the HTTP response body.
//
// NOTE: The referred field must be present at the top-level of the response
// message type.
string response_body = 12;
// Additional HTTP bindings for the selector. Nested bindings must
// not contain an `additional_bindings` field themselves (that is,
// the nesting may only be one level deep).
repeated HttpRule additional_bindings = 11;
}
// A custom pattern is used for defining custom HTTP verb.
message CustomHttpPattern {
// The name of this custom HTTP verb.
string kind = 1;
// The path matched by this custom verb.
string path = 2;
}

View File

@@ -0,0 +1,84 @@
// Copyright 2018 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.
//
syntax = "proto3";
package google.firestore.v1;
import "google/api/annotations.proto";
import "google/protobuf/timestamp.proto";
option csharp_namespace = "Google.Cloud.Firestore.V1";
option go_package = "google.golang.org/genproto/googleapis/firestore/v1;firestore";
option java_multiple_files = true;
option java_outer_classname = "CommonProto";
option java_package = "com.google.firestore.v1";
option objc_class_prefix = "GCFS";
option php_namespace = "Google\\Cloud\\Firestore\\V1";
// A set of field paths on a document.
// Used to restrict a get or update operation on a document to a subset of its
// fields.
// This is different from standard field masks, as this is always scoped to a
// [Document][google.firestore.v1.Document], and takes in account the dynamic nature of [Value][google.firestore.v1.Value].
message DocumentMask {
// The list of field paths in the mask. See [Document.fields][google.firestore.v1.Document.fields] for a field
// path syntax reference.
repeated string field_paths = 1;
}
// A precondition on a document, used for conditional operations.
message Precondition {
// The type of precondition.
oneof condition_type {
// When set to `true`, the target document must exist.
// When set to `false`, the target document must not exist.
bool exists = 1;
// When set, the target document must exist and have been last updated at
// that time.
google.protobuf.Timestamp update_time = 2;
}
}
// Options for creating a new transaction.
message TransactionOptions {
// Options for a transaction that can be used to read and write documents.
message ReadWrite {
// An optional transaction to retry.
bytes retry_transaction = 1;
}
// Options for a transaction that can only be used to read documents.
message ReadOnly {
// The consistency mode for this transaction. If not set, defaults to strong
// consistency.
oneof consistency_selector {
// Reads documents at the given time.
// This may not be older than 60 seconds.
google.protobuf.Timestamp read_time = 2;
}
}
// The mode of the transaction.
oneof mode {
// The transaction can only be used for read operations.
ReadOnly read_only = 2;
// The transaction can be used for both read and write operations.
ReadWrite read_write = 3;
}
}

View File

@@ -0,0 +1,151 @@
// Copyright 2018 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.
//
syntax = "proto3";
package google.firestore.v1;
import "google/api/annotations.proto";
import "google/protobuf/struct.proto";
import "google/protobuf/timestamp.proto";
import "google/type/latlng.proto";
option csharp_namespace = "Google.Cloud.Firestore.V1";
option go_package = "google.golang.org/genproto/googleapis/firestore/v1;firestore";
option java_multiple_files = true;
option java_outer_classname = "DocumentProto";
option java_package = "com.google.firestore.v1";
option objc_class_prefix = "GCFS";
option php_namespace = "Google\\Cloud\\Firestore\\V1";
// A Firestore document.
//
// Must not exceed 1 MiB - 4 bytes.
message Document {
// The resource name of the document, for example
// `projects/{project_id}/databases/{database_id}/documents/{document_path}`.
string name = 1;
// The document's fields.
//
// The map keys represent field names.
//
// A simple field name contains only characters `a` to `z`, `A` to `Z`,
// `0` to `9`, or `_`, and must not start with `0` to `9`. For example,
// `foo_bar_17`.
//
// Field names matching the regular expression `__.*__` are reserved. Reserved
// field names are forbidden except in certain documented contexts. The map
// keys, represented as UTF-8, must not exceed 1,500 bytes and cannot be
// empty.
//
// Field paths may be used in other contexts to refer to structured fields
// defined here. For `map_value`, the field path is represented by the simple
// or quoted field names of the containing fields, delimited by `.`. For
// example, the structured field
// `"foo" : { map_value: { "x&y" : { string_value: "hello" }}}` would be
// represented by the field path `foo.x&y`.
//
// Within a field path, a quoted field name starts and ends with `` ` `` and
// may contain any character. Some characters, including `` ` ``, must be
// escaped using a `\`. For example, `` `x&y` `` represents `x&y` and
// `` `bak\`tik` `` represents `` bak`tik ``.
map<string, Value> fields = 2;
// Output only. The time at which the document was created.
//
// This value increases monotonically when a document is deleted then
// recreated. It can also be compared to values from other documents and
// the `read_time` of a query.
google.protobuf.Timestamp create_time = 3;
// Output only. The time at which the document was last changed.
//
// This value is initially set to the `create_time` then increases
// monotonically with each change to the document. It can also be
// compared to values from other documents and the `read_time` of a query.
google.protobuf.Timestamp update_time = 4;
}
// A message that can hold any of the supported value types.
message Value {
// Must have a value set.
oneof value_type {
// A null value.
google.protobuf.NullValue null_value = 11;
// A boolean value.
bool boolean_value = 1;
// An integer value.
int64 integer_value = 2;
// A double value.
double double_value = 3;
// A timestamp value.
//
// Precise only to microseconds. When stored, any additional precision is
// rounded down.
google.protobuf.Timestamp timestamp_value = 10;
// A string value.
//
// The string, represented as UTF-8, must not exceed 1 MiB - 89 bytes.
// Only the first 1,500 bytes of the UTF-8 representation are considered by
// queries.
string string_value = 17;
// A bytes value.
//
// Must not exceed 1 MiB - 89 bytes.
// Only the first 1,500 bytes are considered by queries.
bytes bytes_value = 18;
// A reference to a document. For example:
// `projects/{project_id}/databases/{database_id}/documents/{document_path}`.
string reference_value = 5;
// A geo point value representing a point on the surface of Earth.
google.type.LatLng geo_point_value = 8;
// An array value.
//
// Cannot directly contain another array value, though can contain an
// map which contains another array.
ArrayValue array_value = 9;
// A map value.
MapValue map_value = 6;
}
}
// An array value.
message ArrayValue {
// Values in the array.
repeated Value values = 1;
}
// A map value.
message MapValue {
// The map's fields.
//
// The map keys represent field names. Field names matching the regular
// expression `__.*__` are reserved. Reserved field names are forbidden except
// in certain documented contexts. The map keys, represented as UTF-8, must
// not exceed 1,500 bytes and cannot be empty.
map<string, Value> fields = 1;
}

View File

@@ -0,0 +1,761 @@
// Copyright 2018 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.
//
syntax = "proto3";
package google.firestore.v1;
import "google/api/annotations.proto";
import "google/firestore/v1/common.proto";
import "google/firestore/v1/document.proto";
import "google/firestore/v1/query.proto";
import "google/firestore/v1/write.proto";
import "google/protobuf/empty.proto";
import "google/protobuf/timestamp.proto";
import "google/rpc/status.proto";
option csharp_namespace = "Google.Cloud.Firestore.V1";
option go_package = "google.golang.org/genproto/googleapis/firestore/v1;firestore";
option java_multiple_files = true;
option java_outer_classname = "FirestoreProto";
option java_package = "com.google.firestore.v1";
option objc_class_prefix = "GCFS";
option php_namespace = "Google\\Cloud\\Firestore\\V1";
// Specification of the Firestore API.
// The Cloud Firestore service.
//
// This service exposes several types of comparable timestamps:
//
// * `create_time` - The time at which a document was created. Changes only
// when a document is deleted, then re-created. Increases in a strict
// monotonic fashion.
// * `update_time` - The time at which a document was last updated. Changes
// every time a document is modified. Does not change when a write results
// in no modifications. Increases in a strict monotonic fashion.
// * `read_time` - The time at which a particular state was observed. Used
// to denote a consistent snapshot of the database or the time at which a
// Document was observed to not exist.
// * `commit_time` - The time at which the writes in a transaction were
// committed. Any read with an equal or greater `read_time` is guaranteed
// to see the effects of the transaction.
service Firestore {
// Gets a single document.
rpc GetDocument(GetDocumentRequest) returns (Document) {
option (google.api.http) = {
get: "/v1/{name=projects/*/databases/*/documents/*/**}"
};
}
// Lists documents.
rpc ListDocuments(ListDocumentsRequest) returns (ListDocumentsResponse) {
option (google.api.http) = {
get: "/v1/{parent=projects/*/databases/*/documents/*/**}/{collection_id}"
};
}
// Creates a new document.
rpc CreateDocument(CreateDocumentRequest) returns (Document) {
option (google.api.http) = {
post: "/v1/{parent=projects/*/databases/*/documents/**}/{collection_id}"
body: "document"
};
}
// Updates or inserts a document.
rpc UpdateDocument(UpdateDocumentRequest) returns (Document) {
option (google.api.http) = {
patch: "/v1/{document.name=projects/*/databases/*/documents/*/**}"
body: "document"
};
}
// Deletes a document.
rpc DeleteDocument(DeleteDocumentRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {
delete: "/v1/{name=projects/*/databases/*/documents/*/**}"
};
}
// Gets multiple documents.
//
// Documents returned by this method are not guaranteed to be returned in the
// same order that they were requested.
rpc BatchGetDocuments(BatchGetDocumentsRequest) returns (stream BatchGetDocumentsResponse) {
option (google.api.http) = {
post: "/v1/{database=projects/*/databases/*}/documents:batchGet"
body: "*"
};
}
// Starts a new transaction.
rpc BeginTransaction(BeginTransactionRequest) returns (BeginTransactionResponse) {
option (google.api.http) = {
post: "/v1/{database=projects/*/databases/*}/documents:beginTransaction"
body: "*"
};
}
// Commits a transaction, while optionally updating documents.
rpc Commit(CommitRequest) returns (CommitResponse) {
option (google.api.http) = {
post: "/v1/{database=projects/*/databases/*}/documents:commit"
body: "*"
};
}
// Rolls back a transaction.
rpc Rollback(RollbackRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {
post: "/v1/{database=projects/*/databases/*}/documents:rollback"
body: "*"
};
}
// Runs a query.
rpc RunQuery(RunQueryRequest) returns (stream RunQueryResponse) {
option (google.api.http) = {
post: "/v1/{parent=projects/*/databases/*/documents}:runQuery"
body: "*"
additional_bindings {
post: "/v1/{parent=projects/*/databases/*/documents/*/**}:runQuery"
body: "*"
}
};
}
// Streams batches of document updates and deletes, in order.
rpc Write(stream WriteRequest) returns (stream WriteResponse) {
option (google.api.http) = {
post: "/v1/{database=projects/*/databases/*}/documents:write"
body: "*"
};
}
// Listens to changes.
rpc Listen(stream ListenRequest) returns (stream ListenResponse) {
option (google.api.http) = {
post: "/v1/{database=projects/*/databases/*}/documents:listen"
body: "*"
};
}
// Lists all the collection IDs underneath a document.
rpc ListCollectionIds(ListCollectionIdsRequest) returns (ListCollectionIdsResponse) {
option (google.api.http) = {
post: "/v1/{parent=projects/*/databases/*/documents}:listCollectionIds"
body: "*"
additional_bindings {
post: "/v1/{parent=projects/*/databases/*/documents/*/**}:listCollectionIds"
body: "*"
}
};
}
}
// The request for [Firestore.GetDocument][google.firestore.v1.Firestore.GetDocument].
message GetDocumentRequest {
// The resource name of the Document to get. In the format:
// `projects/{project_id}/databases/{database_id}/documents/{document_path}`.
string name = 1;
// The fields to return. If not set, returns all fields.
//
// If the document has a field that is not present in this mask, that field
// will not be returned in the response.
DocumentMask mask = 2;
// The consistency mode for this transaction.
// If not set, defaults to strong consistency.
oneof consistency_selector {
// Reads the document in a transaction.
bytes transaction = 3;
// Reads the version of the document at the given time.
// This may not be older than 60 seconds.
google.protobuf.Timestamp read_time = 5;
}
}
// The request for [Firestore.ListDocuments][google.firestore.v1.Firestore.ListDocuments].
message ListDocumentsRequest {
// The parent resource name. In the format:
// `projects/{project_id}/databases/{database_id}/documents` or
// `projects/{project_id}/databases/{database_id}/documents/{document_path}`.
// For example:
// `projects/my-project/databases/my-database/documents` or
// `projects/my-project/databases/my-database/documents/chatrooms/my-chatroom`
string parent = 1;
// The collection ID, relative to `parent`, to list. For example: `chatrooms`
// or `messages`.
string collection_id = 2;
// The maximum number of documents to return.
int32 page_size = 3;
// The `next_page_token` value returned from a previous List request, if any.
string page_token = 4;
// The order to sort results by. For example: `priority desc, name`.
string order_by = 6;
// The fields to return. If not set, returns all fields.
//
// If a document has a field that is not present in this mask, that field
// will not be returned in the response.
DocumentMask mask = 7;
// The consistency mode for this transaction.
// If not set, defaults to strong consistency.
oneof consistency_selector {
// Reads documents in a transaction.
bytes transaction = 8;
// Reads documents as they were at the given time.
// This may not be older than 60 seconds.
google.protobuf.Timestamp read_time = 10;
}
// If the list should show missing documents. A missing document is a
// document that does not exist but has sub-documents. These documents will
// be returned with a key but will not have fields, [Document.create_time][google.firestore.v1.Document.create_time],
// or [Document.update_time][google.firestore.v1.Document.update_time] set.
//
// Requests with `show_missing` may not specify `where` or
// `order_by`.
bool show_missing = 12;
}
// The response for [Firestore.ListDocuments][google.firestore.v1.Firestore.ListDocuments].
message ListDocumentsResponse {
// The Documents found.
repeated Document documents = 1;
// The next page token.
string next_page_token = 2;
}
// The request for [Firestore.CreateDocument][google.firestore.v1.Firestore.CreateDocument].
message CreateDocumentRequest {
// The parent resource. For example:
// `projects/{project_id}/databases/{database_id}/documents` or
// `projects/{project_id}/databases/{database_id}/documents/chatrooms/{chatroom_id}`
string parent = 1;
// The collection ID, relative to `parent`, to list. For example: `chatrooms`.
string collection_id = 2;
// The client-assigned document ID to use for this document.
//
// Optional. If not specified, an ID will be assigned by the service.
string document_id = 3;
// The document to create. `name` must not be set.
Document document = 4;
// The fields to return. If not set, returns all fields.
//
// If the document has a field that is not present in this mask, that field
// will not be returned in the response.
DocumentMask mask = 5;
}
// The request for [Firestore.UpdateDocument][google.firestore.v1.Firestore.UpdateDocument].
message UpdateDocumentRequest {
// The updated document.
// Creates the document if it does not already exist.
Document document = 1;
// The fields to update.
// None of the field paths in the mask may contain a reserved name.
//
// If the document exists on the server and has fields not referenced in the
// mask, they are left unchanged.
// Fields referenced in the mask, but not present in the input document, are
// deleted from the document on the server.
DocumentMask update_mask = 2;
// The fields to return. If not set, returns all fields.
//
// If the document has a field that is not present in this mask, that field
// will not be returned in the response.
DocumentMask mask = 3;
// An optional precondition on the document.
// The request will fail if this is set and not met by the target document.
Precondition current_document = 4;
}
// The request for [Firestore.DeleteDocument][google.firestore.v1.Firestore.DeleteDocument].
message DeleteDocumentRequest {
// The resource name of the Document to delete. In the format:
// `projects/{project_id}/databases/{database_id}/documents/{document_path}`.
string name = 1;
// An optional precondition on the document.
// The request will fail if this is set and not met by the target document.
Precondition current_document = 2;
}
// The request for [Firestore.BatchGetDocuments][google.firestore.v1.Firestore.BatchGetDocuments].
message BatchGetDocumentsRequest {
// The database name. In the format:
// `projects/{project_id}/databases/{database_id}`.
string database = 1;
// The names of the documents to retrieve. In the format:
// `projects/{project_id}/databases/{database_id}/documents/{document_path}`.
// The request will fail if any of the document is not a child resource of the
// given `database`. Duplicate names will be elided.
repeated string documents = 2;
// The fields to return. If not set, returns all fields.
//
// If a document has a field that is not present in this mask, that field will
// not be returned in the response.
DocumentMask mask = 3;
// The consistency mode for this transaction.
// If not set, defaults to strong consistency.
oneof consistency_selector {
// Reads documents in a transaction.
bytes transaction = 4;
// Starts a new transaction and reads the documents.
// Defaults to a read-only transaction.
// The new transaction ID will be returned as the first response in the
// stream.
TransactionOptions new_transaction = 5;
// Reads documents as they were at the given time.
// This may not be older than 60 seconds.
google.protobuf.Timestamp read_time = 7;
}
}
// The streamed response for [Firestore.BatchGetDocuments][google.firestore.v1.Firestore.BatchGetDocuments].
message BatchGetDocumentsResponse {
// A single result.
// This can be empty if the server is just returning a transaction.
oneof result {
// A document that was requested.
Document found = 1;
// A document name that was requested but does not exist. In the format:
// `projects/{project_id}/databases/{database_id}/documents/{document_path}`.
string missing = 2;
}
// The transaction that was started as part of this request.
// Will only be set in the first response, and only if
// [BatchGetDocumentsRequest.new_transaction][google.firestore.v1.BatchGetDocumentsRequest.new_transaction] was set in the request.
bytes transaction = 3;
// The time at which the document was read.
// This may be monotically increasing, in this case the previous documents in
// the result stream are guaranteed not to have changed between their
// read_time and this one.
google.protobuf.Timestamp read_time = 4;
}
// The request for [Firestore.BeginTransaction][google.firestore.v1.Firestore.BeginTransaction].
message BeginTransactionRequest {
// The database name. In the format:
// `projects/{project_id}/databases/{database_id}`.
string database = 1;
// The options for the transaction.
// Defaults to a read-write transaction.
TransactionOptions options = 2;
}
// The response for [Firestore.BeginTransaction][google.firestore.v1.Firestore.BeginTransaction].
message BeginTransactionResponse {
// The transaction that was started.
bytes transaction = 1;
}
// The request for [Firestore.Commit][google.firestore.v1.Firestore.Commit].
message CommitRequest {
// The database name. In the format:
// `projects/{project_id}/databases/{database_id}`.
string database = 1;
// The writes to apply.
//
// Always executed atomically and in order.
repeated Write writes = 2;
// If set, applies all writes in this transaction, and commits it.
bytes transaction = 3;
}
// The response for [Firestore.Commit][google.firestore.v1.Firestore.Commit].
message CommitResponse {
// The result of applying the writes.
//
// This i-th write result corresponds to the i-th write in the
// request.
repeated WriteResult write_results = 1;
// The time at which the commit occurred.
google.protobuf.Timestamp commit_time = 2;
}
// The request for [Firestore.Rollback][google.firestore.v1.Firestore.Rollback].
message RollbackRequest {
// The database name. In the format:
// `projects/{project_id}/databases/{database_id}`.
string database = 1;
// The transaction to roll back.
bytes transaction = 2;
}
// The request for [Firestore.RunQuery][google.firestore.v1.Firestore.RunQuery].
message RunQueryRequest {
// The parent resource name. In the format:
// `projects/{project_id}/databases/{database_id}/documents` or
// `projects/{project_id}/databases/{database_id}/documents/{document_path}`.
// For example:
// `projects/my-project/databases/my-database/documents` or
// `projects/my-project/databases/my-database/documents/chatrooms/my-chatroom`
string parent = 1;
// The query to run.
oneof query_type {
// A structured query.
StructuredQuery structured_query = 2;
}
// The consistency mode for this transaction.
// If not set, defaults to strong consistency.
oneof consistency_selector {
// Reads documents in a transaction.
bytes transaction = 5;
// Starts a new transaction and reads the documents.
// Defaults to a read-only transaction.
// The new transaction ID will be returned as the first response in the
// stream.
TransactionOptions new_transaction = 6;
// Reads documents as they were at the given time.
// This may not be older than 60 seconds.
google.protobuf.Timestamp read_time = 7;
}
}
// The response for [Firestore.RunQuery][google.firestore.v1.Firestore.RunQuery].
message RunQueryResponse {
// The transaction that was started as part of this request.
// Can only be set in the first response, and only if
// [RunQueryRequest.new_transaction][google.firestore.v1.RunQueryRequest.new_transaction] was set in the request.
// If set, no other fields will be set in this response.
bytes transaction = 2;
// A query result.
// Not set when reporting partial progress.
Document document = 1;
// The time at which the document was read. This may be monotonically
// increasing; in this case, the previous documents in the result stream are
// guaranteed not to have changed between their `read_time` and this one.
//
// If the query returns no results, a response with `read_time` and no
// `document` will be sent, and this represents the time at which the query
// was run.
google.protobuf.Timestamp read_time = 3;
// The number of results that have been skipped due to an offset between
// the last response and the current response.
int32 skipped_results = 4;
}
// The request for [Firestore.Write][google.firestore.v1.Firestore.Write].
//
// The first request creates a stream, or resumes an existing one from a token.
//
// When creating a new stream, the server replies with a response containing
// only an ID and a token, to use in the next request.
//
// When resuming a stream, the server first streams any responses later than the
// given token, then a response containing only an up-to-date token, to use in
// the next request.
message WriteRequest {
// The database name. In the format:
// `projects/{project_id}/databases/{database_id}`.
// This is only required in the first message.
string database = 1;
// The ID of the write stream to resume.
// This may only be set in the first message. When left empty, a new write
// stream will be created.
string stream_id = 2;
// The writes to apply.
//
// Always executed atomically and in order.
// This must be empty on the first request.
// This may be empty on the last request.
// This must not be empty on all other requests.
repeated Write writes = 3;
// A stream token that was previously sent by the server.
//
// The client should set this field to the token from the most recent
// [WriteResponse][google.firestore.v1.WriteResponse] it has received. This acknowledges that the client has
// received responses up to this token. After sending this token, earlier
// tokens may not be used anymore.
//
// The server may close the stream if there are too many unacknowledged
// responses.
//
// Leave this field unset when creating a new stream. To resume a stream at
// a specific point, set this field and the `stream_id` field.
//
// Leave this field unset when creating a new stream.
bytes stream_token = 4;
// Labels associated with this write request.
map<string, string> labels = 5;
}
// The response for [Firestore.Write][google.firestore.v1.Firestore.Write].
message WriteResponse {
// The ID of the stream.
// Only set on the first message, when a new stream was created.
string stream_id = 1;
// A token that represents the position of this response in the stream.
// This can be used by a client to resume the stream at this point.
//
// This field is always set.
bytes stream_token = 2;
// The result of applying the writes.
//
// This i-th write result corresponds to the i-th write in the
// request.
repeated WriteResult write_results = 3;
// The time at which the commit occurred.
google.protobuf.Timestamp commit_time = 4;
}
// A request for [Firestore.Listen][google.firestore.v1.Firestore.Listen]
message ListenRequest {
// The database name. In the format:
// `projects/{project_id}/databases/{database_id}`.
string database = 1;
// The supported target changes.
oneof target_change {
// A target to add to this stream.
Target add_target = 2;
// The ID of a target to remove from this stream.
int32 remove_target = 3;
}
// Labels associated with this target change.
map<string, string> labels = 4;
}
// The response for [Firestore.Listen][google.firestore.v1.Firestore.Listen].
message ListenResponse {
// The supported responses.
oneof response_type {
// Targets have changed.
TargetChange target_change = 2;
// A [Document][google.firestore.v1.Document] has changed.
DocumentChange document_change = 3;
// A [Document][google.firestore.v1.Document] has been deleted.
DocumentDelete document_delete = 4;
// A [Document][google.firestore.v1.Document] has been removed from a target (because it is no longer
// relevant to that target).
DocumentRemove document_remove = 6;
// A filter to apply to the set of documents previously returned for the
// given target.
//
// Returned when documents may have been removed from the given target, but
// the exact documents are unknown.
ExistenceFilter filter = 5;
}
}
// A specification of a set of documents to listen to.
message Target {
// A target specified by a set of documents names.
message DocumentsTarget {
// The names of the documents to retrieve. In the format:
// `projects/{project_id}/databases/{database_id}/documents/{document_path}`.
// The request will fail if any of the document is not a child resource of
// the given `database`. Duplicate names will be elided.
repeated string documents = 2;
}
// A target specified by a query.
message QueryTarget {
// The parent resource name. In the format:
// `projects/{project_id}/databases/{database_id}/documents` or
// `projects/{project_id}/databases/{database_id}/documents/{document_path}`.
// For example:
// `projects/my-project/databases/my-database/documents` or
// `projects/my-project/databases/my-database/documents/chatrooms/my-chatroom`
string parent = 1;
// The query to run.
oneof query_type {
// A structured query.
StructuredQuery structured_query = 2;
}
}
// The type of target to listen to.
oneof target_type {
// A target specified by a query.
QueryTarget query = 2;
// A target specified by a set of document names.
DocumentsTarget documents = 3;
}
// When to start listening.
//
// If not specified, all matching Documents are returned before any
// subsequent changes.
oneof resume_type {
// A resume token from a prior [TargetChange][google.firestore.v1.TargetChange] for an identical target.
//
// Using a resume token with a different target is unsupported and may fail.
bytes resume_token = 4;
// Start listening after a specific `read_time`.
//
// The client must know the state of matching documents at this time.
google.protobuf.Timestamp read_time = 11;
}
// A client provided target ID.
//
// If not set, the server will assign an ID for the target.
//
// Used for resuming a target without changing IDs. The IDs can either be
// client-assigned or be server-assigned in a previous stream. All targets
// with client provided IDs must be added before adding a target that needs
// a server-assigned id.
int32 target_id = 5;
// If the target should be removed once it is current and consistent.
bool once = 6;
}
// Targets being watched have changed.
message TargetChange {
// The type of change.
enum TargetChangeType {
// No change has occurred. Used only to send an updated `resume_token`.
NO_CHANGE = 0;
// The targets have been added.
ADD = 1;
// The targets have been removed.
REMOVE = 2;
// The targets reflect all changes committed before the targets were added
// to the stream.
//
// This will be sent after or with a `read_time` that is greater than or
// equal to the time at which the targets were added.
//
// Listeners can wait for this change if read-after-write semantics
// are desired.
CURRENT = 3;
// The targets have been reset, and a new initial state for the targets
// will be returned in subsequent changes.
//
// After the initial state is complete, `CURRENT` will be returned even
// if the target was previously indicated to be `CURRENT`.
RESET = 4;
}
// The type of change that occurred.
TargetChangeType target_change_type = 1;
// The target IDs of targets that have changed.
//
// If empty, the change applies to all targets.
//
// For `target_change_type=ADD`, the order of the target IDs matches the order
// of the requests to add the targets. This allows clients to unambiguously
// associate server-assigned target IDs with added targets.
//
// For other states, the order of the target IDs is not defined.
repeated int32 target_ids = 2;
// The error that resulted in this change, if applicable.
google.rpc.Status cause = 3;
// A token that can be used to resume the stream for the given `target_ids`,
// or all targets if `target_ids` is empty.
//
// Not set on every target change.
bytes resume_token = 4;
// The consistent `read_time` for the given `target_ids` (omitted when the
// target_ids are not at a consistent snapshot).
//
// The stream is guaranteed to send a `read_time` with `target_ids` empty
// whenever the entire stream reaches a new consistent snapshot. ADD,
// CURRENT, and RESET messages are guaranteed to (eventually) result in a
// new consistent snapshot (while NO_CHANGE and REMOVE messages are not).
//
// For a given stream, `read_time` is guaranteed to be monotonically
// increasing.
google.protobuf.Timestamp read_time = 6;
}
// The request for [Firestore.ListCollectionIds][google.firestore.v1.Firestore.ListCollectionIds].
message ListCollectionIdsRequest {
// The parent document. In the format:
// `projects/{project_id}/databases/{database_id}/documents/{document_path}`.
// For example:
// `projects/my-project/databases/my-database/documents/chatrooms/my-chatroom`
string parent = 1;
// The maximum number of results to return.
int32 page_size = 2;
// A page token. Must be a value from
// [ListCollectionIdsResponse][google.firestore.v1.ListCollectionIdsResponse].
string page_token = 3;
}
// The response from [Firestore.ListCollectionIds][google.firestore.v1.Firestore.ListCollectionIds].
message ListCollectionIdsResponse {
// The collection ids.
repeated string collection_ids = 1;
// A page token that may be used to continue the list.
string next_page_token = 2;
}

View File

@@ -0,0 +1,244 @@
// Copyright 2019 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.
//
syntax = "proto3";
package google.firestore.v1;
import "google/api/annotations.proto";
import "google/firestore/v1/document.proto";
import "google/protobuf/wrappers.proto";
option csharp_namespace = "Google.Cloud.Firestore.V1";
option go_package = "google.golang.org/genproto/googleapis/firestore/v1;firestore";
option java_multiple_files = true;
option java_outer_classname = "QueryProto";
option java_package = "com.google.firestore.v1";
option objc_class_prefix = "GCFS";
option php_namespace = "Google\\Cloud\\Firestore\\V1";
// A Firestore query.
message StructuredQuery {
// A selection of a collection, such as `messages as m1`.
message CollectionSelector {
// The collection ID.
// When set, selects only collections with this ID.
string collection_id = 2;
// When false, selects only collections that are immediate children of
// the `parent` specified in the containing `RunQueryRequest`.
// When true, selects all descendant collections.
bool all_descendants = 3;
}
// A filter.
message Filter {
// The type of filter.
oneof filter_type {
// A composite filter.
CompositeFilter composite_filter = 1;
// A filter on a document field.
FieldFilter field_filter = 2;
// A filter that takes exactly one argument.
UnaryFilter unary_filter = 3;
}
}
// A filter that merges multiple other filters using the given operator.
message CompositeFilter {
// A composite filter operator.
enum Operator {
// Unspecified. This value must not be used.
OPERATOR_UNSPECIFIED = 0;
// The results are required to satisfy each of the combined filters.
AND = 1;
}
// The operator for combining multiple filters.
Operator op = 1;
// The list of filters to combine.
// Must contain at least one filter.
repeated Filter filters = 2;
}
// A filter on a specific field.
message FieldFilter {
// A field filter operator.
enum Operator {
// Unspecified. This value must not be used.
OPERATOR_UNSPECIFIED = 0;
// Less than. Requires that the field come first in `order_by`.
LESS_THAN = 1;
// Less than or equal. Requires that the field come first in `order_by`.
LESS_THAN_OR_EQUAL = 2;
// Greater than. Requires that the field come first in `order_by`.
GREATER_THAN = 3;
// Greater than or equal. Requires that the field come first in
// `order_by`.
GREATER_THAN_OR_EQUAL = 4;
// Equal.
EQUAL = 5;
// Contains. Requires that the field is an array.
ARRAY_CONTAINS = 7;
// In. Requires that `value` is a non-empty ArrayValue with at most 10
// values.
IN = 8;
// Contains any. Requires that the field is an array and
// `value` is a non-empty ArrayValue with at most 10 values.
ARRAY_CONTAINS_ANY = 9;
}
// The field to filter by.
FieldReference field = 1;
// The operator to filter by.
Operator op = 2;
// The value to compare to.
Value value = 3;
}
// A filter with a single operand.
message UnaryFilter {
// A unary operator.
enum Operator {
// Unspecified. This value must not be used.
OPERATOR_UNSPECIFIED = 0;
// Test if a field is equal to NaN.
IS_NAN = 2;
// Test if an exprestion evaluates to Null.
IS_NULL = 3;
}
// The unary operator to apply.
Operator op = 1;
// The argument to the filter.
oneof operand_type {
// The field to which to apply the operator.
FieldReference field = 2;
}
}
// An order on a field.
message Order {
// The field to order by.
FieldReference field = 1;
// The direction to order by. Defaults to `ASCENDING`.
Direction direction = 2;
}
// A reference to a field, such as `max(messages.time) as max_time`.
message FieldReference {
string field_path = 2;
}
// The projection of document's fields to return.
message Projection {
// The fields to return.
//
// If empty, all fields are returned. To only return the name
// of the document, use `['__name__']`.
repeated FieldReference fields = 2;
}
// A sort direction.
enum Direction {
// Unspecified.
DIRECTION_UNSPECIFIED = 0;
// Ascending.
ASCENDING = 1;
// Descending.
DESCENDING = 2;
}
// The projection to return.
Projection select = 1;
// The collections to query.
repeated CollectionSelector from = 2;
// The filter to apply.
Filter where = 3;
// The order to apply to the query results.
//
// Firestore guarantees a stable ordering through the following rules:
//
// * Any field required to appear in `order_by`, that is not already
// specified in `order_by`, is appended to the order in field name order
// by default.
// * If an order on `__name__` is not specified, it is appended by default.
//
// Fields are appended with the same sort direction as the last order
// specified, or 'ASCENDING' if no order was specified. For example:
//
// * `SELECT * FROM Foo ORDER BY A` becomes
// `SELECT * FROM Foo ORDER BY A, __name__`
// * `SELECT * FROM Foo ORDER BY A DESC` becomes
// `SELECT * FROM Foo ORDER BY A DESC, __name__ DESC`
// * `SELECT * FROM Foo WHERE A > 1` becomes
// `SELECT * FROM Foo WHERE A > 1 ORDER BY A, __name__`
repeated Order order_by = 4;
// A starting point for the query results.
Cursor start_at = 7;
// A end point for the query results.
Cursor end_at = 8;
// The number of results to skip.
//
// Applies before limit, but after all other constraints. Must be >= 0 if
// specified.
int32 offset = 6;
// The maximum number of results to return.
//
// Applies after all other constraints.
// Must be >= 0 if specified.
google.protobuf.Int32Value limit = 5;
}
// A position in a query result set.
message Cursor {
// The values that represent a position, in the order they appear in
// the order by clause of a query.
//
// Can contain fewer values than specified in the order by clause.
repeated Value values = 1;
// If the position is just before or just after the given values, relative
// to the sort order defined by the query.
bool before = 2;
}

View File

@@ -0,0 +1,255 @@
// Copyright 2018 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.
//
syntax = "proto3";
package google.firestore.v1;
import "google/api/annotations.proto";
import "google/firestore/v1/common.proto";
import "google/firestore/v1/document.proto";
import "google/protobuf/timestamp.proto";
option csharp_namespace = "Google.Cloud.Firestore.V1";
option go_package = "google.golang.org/genproto/googleapis/firestore/v1;firestore";
option java_multiple_files = true;
option java_outer_classname = "WriteProto";
option java_package = "com.google.firestore.v1";
option objc_class_prefix = "GCFS";
option php_namespace = "Google\\Cloud\\Firestore\\V1";
// A write on a document.
message Write {
// The operation to execute.
oneof operation {
// A document to write.
Document update = 1;
// A document name to delete. In the format:
// `projects/{project_id}/databases/{database_id}/documents/{document_path}`.
string delete = 2;
// Applies a tranformation to a document.
// At most one `transform` per document is allowed in a given request.
// An `update` cannot follow a `transform` on the same document in a given
// request.
DocumentTransform transform = 6;
}
// The fields to update in this write.
//
// This field can be set only when the operation is `update`.
// If the mask is not set for an `update` and the document exists, any
// existing data will be overwritten.
// If the mask is set and the document on the server has fields not covered by
// the mask, they are left unchanged.
// Fields referenced in the mask, but not present in the input document, are
// deleted from the document on the server.
// The field paths in this mask must not contain a reserved field name.
DocumentMask update_mask = 3;
// An optional precondition on the document.
//
// The write will fail if this is set and not met by the target document.
Precondition current_document = 4;
}
// A transformation of a document.
message DocumentTransform {
// A transformation of a field of the document.
message FieldTransform {
// A value that is calculated by the server.
enum ServerValue {
// Unspecified. This value must not be used.
SERVER_VALUE_UNSPECIFIED = 0;
// The time at which the server processed the request, with millisecond
// precision.
REQUEST_TIME = 1;
}
// The path of the field. See [Document.fields][google.firestore.v1.Document.fields] for the field path syntax
// reference.
string field_path = 1;
// The transformation to apply on the field.
oneof transform_type {
// Sets the field to the given server value.
ServerValue set_to_server_value = 2;
// Adds the given value to the field's current value.
//
// This must be an integer or a double value.
// If the field is not an integer or double, or if the field does not yet
// exist, the transformation will set the field to the given value.
// If either of the given value or the current field value are doubles,
// both values will be interpreted as doubles. Double arithmetic and
// representation of double values follow IEEE 754 semantics.
// If there is positive/negative integer overflow, the field is resolved
// to the largest magnitude positive/negative integer.
Value increment = 3;
// Sets the field to the maximum of its current value and the given value.
//
// This must be an integer or a double value.
// If the field is not an integer or double, or if the field does not yet
// exist, the transformation will set the field to the given value.
// If a maximum operation is applied where the field and the input value
// are of mixed types (that is - one is an integer and one is a double)
// the field takes on the type of the larger operand. If the operands are
// equivalent (e.g. 3 and 3.0), the field does not change.
// 0, 0.0, and -0.0 are all zero. The maximum of a zero stored value and
// zero input value is always the stored value.
// The maximum of any numeric value x and NaN is NaN.
Value maximum = 4;
// Sets the field to the minimum of its current value and the given value.
//
// This must be an integer or a double value.
// If the field is not an integer or double, or if the field does not yet
// exist, the transformation will set the field to the input value.
// If a minimum operation is applied where the field and the input value
// are of mixed types (that is - one is an integer and one is a double)
// the field takes on the type of the smaller operand. If the operands are
// equivalent (e.g. 3 and 3.0), the field does not change.
// 0, 0.0, and -0.0 are all zero. The minimum of a zero stored value and
// zero input value is always the stored value.
// The minimum of any numeric value x and NaN is NaN.
Value minimum = 5;
// Append the given elements in order if they are not already present in
// the current field value.
// If the field is not an array, or if the field does not yet exist, it is
// first set to the empty array.
//
// Equivalent numbers of different types (e.g. 3L and 3.0) are
// considered equal when checking if a value is missing.
// NaN is equal to NaN, and Null is equal to Null.
// If the input contains multiple equivalent values, only the first will
// be considered.
//
// The corresponding transform_result will be the null value.
ArrayValue append_missing_elements = 6;
// Remove all of the given elements from the array in the field.
// If the field is not an array, or if the field does not yet exist, it is
// set to the empty array.
//
// Equivalent numbers of the different types (e.g. 3L and 3.0) are
// considered equal when deciding whether an element should be removed.
// NaN is equal to NaN, and Null is equal to Null.
// This will remove all equivalent values if there are duplicates.
//
// The corresponding transform_result will be the null value.
ArrayValue remove_all_from_array = 7;
}
}
// The name of the document to transform.
string document = 1;
// The list of transformations to apply to the fields of the document, in
// order.
// This must not be empty.
repeated FieldTransform field_transforms = 2;
}
// The result of applying a write.
message WriteResult {
// The last update time of the document after applying the write. Not set
// after a `delete`.
//
// If the write did not actually change the document, this will be the
// previous update_time.
google.protobuf.Timestamp update_time = 1;
// The results of applying each [DocumentTransform.FieldTransform][google.firestore.v1.DocumentTransform.FieldTransform], in the
// same order.
repeated Value transform_results = 2;
}
// A [Document][google.firestore.v1.Document] has changed.
//
// May be the result of multiple [writes][google.firestore.v1.Write], including deletes, that
// ultimately resulted in a new value for the [Document][google.firestore.v1.Document].
//
// Multiple [DocumentChange][google.firestore.v1.DocumentChange] messages may be returned for the same logical
// change, if multiple targets are affected.
message DocumentChange {
// The new state of the [Document][google.firestore.v1.Document].
//
// If `mask` is set, contains only fields that were updated or added.
Document document = 1;
// A set of target IDs of targets that match this document.
repeated int32 target_ids = 5;
// A set of target IDs for targets that no longer match this document.
repeated int32 removed_target_ids = 6;
}
// A [Document][google.firestore.v1.Document] has been deleted.
//
// May be the result of multiple [writes][google.firestore.v1.Write], including updates, the
// last of which deleted the [Document][google.firestore.v1.Document].
//
// Multiple [DocumentDelete][google.firestore.v1.DocumentDelete] messages may be returned for the same logical
// delete, if multiple targets are affected.
message DocumentDelete {
// The resource name of the [Document][google.firestore.v1.Document] that was deleted.
string document = 1;
// A set of target IDs for targets that previously matched this entity.
repeated int32 removed_target_ids = 6;
// The read timestamp at which the delete was observed.
//
// Greater or equal to the `commit_time` of the delete.
google.protobuf.Timestamp read_time = 4;
}
// A [Document][google.firestore.v1.Document] has been removed from the view of the targets.
//
// Sent if the document is no longer relevant to a target and is out of view.
// Can be sent instead of a DocumentDelete or a DocumentChange if the server
// can not send the new value of the document.
//
// Multiple [DocumentRemove][google.firestore.v1.DocumentRemove] messages may be returned for the same logical
// write or delete, if multiple targets are affected.
message DocumentRemove {
// The resource name of the [Document][google.firestore.v1.Document] that has gone out of view.
string document = 1;
// A set of target IDs for targets that previously matched this document.
repeated int32 removed_target_ids = 2;
// The read timestamp at which the remove was observed.
//
// Greater or equal to the `commit_time` of the change/delete/remove.
google.protobuf.Timestamp read_time = 4;
}
// A digest of all the documents that match a given target.
message ExistenceFilter {
// The target ID to which this filter applies.
int32 target_id = 1;
// The total count of documents that match [target_id][google.firestore.v1.ExistenceFilter.target_id].
//
// If different from the count of documents in the client that match, the
// client must manually determine which documents no longer match the target.
int32 count = 2;
}

View File

@@ -0,0 +1,155 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
package google.protobuf;
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
option go_package = "github.com/golang/protobuf/ptypes/any";
option java_package = "com.google.protobuf";
option java_outer_classname = "AnyProto";
option java_multiple_files = true;
option objc_class_prefix = "GPB";
// `Any` contains an arbitrary serialized protocol buffer message along with a
// URL that describes the type of the serialized message.
//
// Protobuf library provides support to pack/unpack Any values in the form
// of utility functions or additional generated methods of the Any type.
//
// Example 1: Pack and unpack a message in C++.
//
// Foo foo = ...;
// Any any;
// any.PackFrom(foo);
// ...
// if (any.UnpackTo(&foo)) {
// ...
// }
//
// Example 2: Pack and unpack a message in Java.
//
// Foo foo = ...;
// Any any = Any.pack(foo);
// ...
// if (any.is(Foo.class)) {
// foo = any.unpack(Foo.class);
// }
//
// Example 3: Pack and unpack a message in Python.
//
// foo = Foo(...)
// any = Any()
// any.Pack(foo)
// ...
// if any.Is(Foo.DESCRIPTOR):
// any.Unpack(foo)
// ...
//
// Example 4: Pack and unpack a message in Go
//
// foo := &pb.Foo{...}
// any, err := ptypes.MarshalAny(foo)
// ...
// foo := &pb.Foo{}
// if err := ptypes.UnmarshalAny(any, foo); err != nil {
// ...
// }
//
// The pack methods provided by protobuf library will by default use
// 'type.googleapis.com/full.type.name' as the type URL and the unpack
// methods only use the fully qualified type name after the last '/'
// in the type URL, for example "foo.bar.com/x/y.z" will yield type
// name "y.z".
//
//
// JSON
// ====
// The JSON representation of an `Any` value uses the regular
// representation of the deserialized, embedded message, with an
// additional field `@type` which contains the type URL. Example:
//
// package google.profile;
// message Person {
// string first_name = 1;
// string last_name = 2;
// }
//
// {
// "@type": "type.googleapis.com/google.profile.Person",
// "firstName": <string>,
// "lastName": <string>
// }
//
// If the embedded message type is well-known and has a custom JSON
// representation, that representation will be embedded adding a field
// `value` which holds the custom JSON in addition to the `@type`
// field. Example (for message [google.protobuf.Duration][]):
//
// {
// "@type": "type.googleapis.com/google.protobuf.Duration",
// "value": "1.212s"
// }
//
message Any {
// A URL/resource name that uniquely identifies the type of the serialized
// protocol buffer message. This string must contain at least
// one "/" character. The last segment of the URL's path must represent
// the fully qualified name of the type (as in
// `path/google.protobuf.Duration`). The name should be in a canonical form
// (e.g., leading "." is not accepted).
//
// In practice, teams usually precompile into the binary all types that they
// expect it to use in the context of Any. However, for URLs which use the
// scheme `http`, `https`, or no scheme, one can optionally set up a type
// server that maps type URLs to message definitions as follows:
//
// * If no scheme is provided, `https` is assumed.
// * An HTTP GET on the URL must yield a [google.protobuf.Type][]
// value in binary format, or produce an error.
// * Applications are allowed to cache lookup results based on the
// URL, or have them precompiled into a binary to avoid any
// lookup. Therefore, binary compatibility needs to be preserved
// on changes to types. (Use versioned type names to manage
// breaking changes.)
//
// Note: this functionality is not currently available in the official
// protobuf release, and it is not used for type URLs beginning with
// type.googleapis.com.
//
// Schemes other than `http`, `https` (or the empty scheme) might be
// used with implementation specific semantics.
//
string type_url = 1;
// Must be a valid serialized protocol buffer of the above specified type.
bytes value = 2;
}

View File

@@ -0,0 +1,882 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: kenton@google.com (Kenton Varda)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
//
// The messages in this file describe the definitions found in .proto files.
// A valid .proto file can be translated directly to a FileDescriptorProto
// without any other information (e.g. without reading its imports).
syntax = "proto2";
package google.protobuf;
option go_package = "github.com/golang/protobuf/protoc-gen-go/descriptor;descriptor";
option java_package = "com.google.protobuf";
option java_outer_classname = "DescriptorProtos";
option csharp_namespace = "Google.Protobuf.Reflection";
option objc_class_prefix = "GPB";
option cc_enable_arenas = true;
// descriptor.proto must be optimized for speed because reflection-based
// algorithms don't work during bootstrapping.
option optimize_for = SPEED;
// The protocol compiler can output a FileDescriptorSet containing the .proto
// files it parses.
message FileDescriptorSet {
repeated FileDescriptorProto file = 1;
}
// Describes a complete .proto file.
message FileDescriptorProto {
optional string name = 1; // file name, relative to root of source tree
optional string package = 2; // e.g. "foo", "foo.bar", etc.
// Names of files imported by this file.
repeated string dependency = 3;
// Indexes of the public imported files in the dependency list above.
repeated int32 public_dependency = 10;
// Indexes of the weak imported files in the dependency list.
// For Google-internal migration only. Do not use.
repeated int32 weak_dependency = 11;
// All top-level definitions in this file.
repeated DescriptorProto message_type = 4;
repeated EnumDescriptorProto enum_type = 5;
repeated ServiceDescriptorProto service = 6;
repeated FieldDescriptorProto extension = 7;
optional FileOptions options = 8;
// This field contains optional information about the original source code.
// You may safely remove this entire field without harming runtime
// functionality of the descriptors -- the information is needed only by
// development tools.
optional SourceCodeInfo source_code_info = 9;
// The syntax of the proto file.
// The supported values are "proto2" and "proto3".
optional string syntax = 12;
}
// Describes a message type.
message DescriptorProto {
optional string name = 1;
repeated FieldDescriptorProto field = 2;
repeated FieldDescriptorProto extension = 6;
repeated DescriptorProto nested_type = 3;
repeated EnumDescriptorProto enum_type = 4;
message ExtensionRange {
optional int32 start = 1;
optional int32 end = 2;
optional ExtensionRangeOptions options = 3;
}
repeated ExtensionRange extension_range = 5;
repeated OneofDescriptorProto oneof_decl = 8;
optional MessageOptions options = 7;
// Range of reserved tag numbers. Reserved tag numbers may not be used by
// fields or extension ranges in the same message. Reserved ranges may
// not overlap.
message ReservedRange {
optional int32 start = 1; // Inclusive.
optional int32 end = 2; // Exclusive.
}
repeated ReservedRange reserved_range = 9;
// Reserved field names, which may not be used by fields in the same message.
// A given name may only be reserved once.
repeated string reserved_name = 10;
}
message ExtensionRangeOptions {
// The parser stores options it doesn't recognize here. See above.
repeated UninterpretedOption uninterpreted_option = 999;
// Clients can define custom options in extensions of this message. See above.
extensions 1000 to max;
}
// Describes a field within a message.
message FieldDescriptorProto {
enum Type {
// 0 is reserved for errors.
// Order is weird for historical reasons.
TYPE_DOUBLE = 1;
TYPE_FLOAT = 2;
// Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if
// negative values are likely.
TYPE_INT64 = 3;
TYPE_UINT64 = 4;
// Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if
// negative values are likely.
TYPE_INT32 = 5;
TYPE_FIXED64 = 6;
TYPE_FIXED32 = 7;
TYPE_BOOL = 8;
TYPE_STRING = 9;
// Tag-delimited aggregate.
// Group type is deprecated and not supported in proto3. However, Proto3
// implementations should still be able to parse the group wire format and
// treat group fields as unknown fields.
TYPE_GROUP = 10;
TYPE_MESSAGE = 11; // Length-delimited aggregate.
// New in version 2.
TYPE_BYTES = 12;
TYPE_UINT32 = 13;
TYPE_ENUM = 14;
TYPE_SFIXED32 = 15;
TYPE_SFIXED64 = 16;
TYPE_SINT32 = 17; // Uses ZigZag encoding.
TYPE_SINT64 = 18; // Uses ZigZag encoding.
}
enum Label {
// 0 is reserved for errors
LABEL_OPTIONAL = 1;
LABEL_REQUIRED = 2;
LABEL_REPEATED = 3;
}
optional string name = 1;
optional int32 number = 3;
optional Label label = 4;
// If type_name is set, this need not be set. If both this and type_name
// are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP.
optional Type type = 5;
// For message and enum types, this is the name of the type. If the name
// starts with a '.', it is fully-qualified. Otherwise, C++-like scoping
// rules are used to find the type (i.e. first the nested types within this
// message are searched, then within the parent, on up to the root
// namespace).
optional string type_name = 6;
// For extensions, this is the name of the type being extended. It is
// resolved in the same manner as type_name.
optional string extendee = 2;
// For numeric types, contains the original text representation of the value.
// For booleans, "true" or "false".
// For strings, contains the default text contents (not escaped in any way).
// For bytes, contains the C escaped value. All bytes >= 128 are escaped.
// TODO(kenton): Base-64 encode?
optional string default_value = 7;
// If set, gives the index of a oneof in the containing type's oneof_decl
// list. This field is a member of that oneof.
optional int32 oneof_index = 9;
// JSON name of this field. The value is set by protocol compiler. If the
// user has set a "json_name" option on this field, that option's value
// will be used. Otherwise, it's deduced from the field's name by converting
// it to camelCase.
optional string json_name = 10;
optional FieldOptions options = 8;
}
// Describes a oneof.
message OneofDescriptorProto {
optional string name = 1;
optional OneofOptions options = 2;
}
// Describes an enum type.
message EnumDescriptorProto {
optional string name = 1;
repeated EnumValueDescriptorProto value = 2;
optional EnumOptions options = 3;
// Range of reserved numeric values. Reserved values may not be used by
// entries in the same enum. Reserved ranges may not overlap.
//
// Note that this is distinct from DescriptorProto.ReservedRange in that it
// is inclusive such that it can appropriately represent the entire int32
// domain.
message EnumReservedRange {
optional int32 start = 1; // Inclusive.
optional int32 end = 2; // Inclusive.
}
// Range of reserved numeric values. Reserved numeric values may not be used
// by enum values in the same enum declaration. Reserved ranges may not
// overlap.
repeated EnumReservedRange reserved_range = 4;
// Reserved enum value names, which may not be reused. A given name may only
// be reserved once.
repeated string reserved_name = 5;
}
// Describes a value within an enum.
message EnumValueDescriptorProto {
optional string name = 1;
optional int32 number = 2;
optional EnumValueOptions options = 3;
}
// Describes a service.
message ServiceDescriptorProto {
optional string name = 1;
repeated MethodDescriptorProto method = 2;
optional ServiceOptions options = 3;
}
// Describes a method of a service.
message MethodDescriptorProto {
optional string name = 1;
// Input and output type names. These are resolved in the same way as
// FieldDescriptorProto.type_name, but must refer to a message type.
optional string input_type = 2;
optional string output_type = 3;
optional MethodOptions options = 4;
// Identifies if client streams multiple client messages
optional bool client_streaming = 5 [default = false];
// Identifies if server streams multiple server messages
optional bool server_streaming = 6 [default = false];
}
// ===================================================================
// Options
// Each of the definitions above may have "options" attached. These are
// just annotations which may cause code to be generated slightly differently
// or may contain hints for code that manipulates protocol messages.
//
// Clients may define custom options as extensions of the *Options messages.
// These extensions may not yet be known at parsing time, so the parser cannot
// store the values in them. Instead it stores them in a field in the *Options
// message called uninterpreted_option. This field must have the same name
// across all *Options messages. We then use this field to populate the
// extensions when we build a descriptor, at which point all protos have been
// parsed and so all extensions are known.
//
// Extension numbers for custom options may be chosen as follows:
// * For options which will only be used within a single application or
// organization, or for experimental options, use field numbers 50000
// through 99999. It is up to you to ensure that you do not use the
// same number for multiple options.
// * For options which will be published and used publicly by multiple
// independent entities, e-mail protobuf-global-extension-registry@google.com
// to reserve extension numbers. Simply provide your project name (e.g.
// Objective-C plugin) and your project website (if available) -- there's no
// need to explain how you intend to use them. Usually you only need one
// extension number. You can declare multiple options with only one extension
// number by putting them in a sub-message. See the Custom Options section of
// the docs for examples:
// https://developers.google.com/protocol-buffers/docs/proto#options
// If this turns out to be popular, a web service will be set up
// to automatically assign option numbers.
message FileOptions {
// Sets the Java package where classes generated from this .proto will be
// placed. By default, the proto package is used, but this is often
// inappropriate because proto packages do not normally start with backwards
// domain names.
optional string java_package = 1;
// If set, all the classes from the .proto file are wrapped in a single
// outer class with the given name. This applies to both Proto1
// (equivalent to the old "--one_java_file" option) and Proto2 (where
// a .proto always translates to a single class, but you may want to
// explicitly choose the class name).
optional string java_outer_classname = 8;
// If set true, then the Java code generator will generate a separate .java
// file for each top-level message, enum, and service defined in the .proto
// file. Thus, these types will *not* be nested inside the outer class
// named by java_outer_classname. However, the outer class will still be
// generated to contain the file's getDescriptor() method as well as any
// top-level extensions defined in the file.
optional bool java_multiple_files = 10 [default = false];
// This option does nothing.
optional bool java_generate_equals_and_hash = 20 [deprecated=true];
// If set true, then the Java2 code generator will generate code that
// throws an exception whenever an attempt is made to assign a non-UTF-8
// byte sequence to a string field.
// Message reflection will do the same.
// However, an extension field still accepts non-UTF-8 byte sequences.
// This option has no effect on when used with the lite runtime.
optional bool java_string_check_utf8 = 27 [default = false];
// Generated classes can be optimized for speed or code size.
enum OptimizeMode {
SPEED = 1; // Generate complete code for parsing, serialization,
// etc.
CODE_SIZE = 2; // Use ReflectionOps to implement these methods.
LITE_RUNTIME = 3; // Generate code using MessageLite and the lite runtime.
}
optional OptimizeMode optimize_for = 9 [default = SPEED];
// Sets the Go package where structs generated from this .proto will be
// placed. If omitted, the Go package will be derived from the following:
// - The basename of the package import path, if provided.
// - Otherwise, the package statement in the .proto file, if present.
// - Otherwise, the basename of the .proto file, without extension.
optional string go_package = 11;
// Should generic services be generated in each language? "Generic" services
// are not specific to any particular RPC system. They are generated by the
// main code generators in each language (without additional plugins).
// Generic services were the only kind of service generation supported by
// early versions of google.protobuf.
//
// Generic services are now considered deprecated in favor of using plugins
// that generate code specific to your particular RPC system. Therefore,
// these default to false. Old code which depends on generic services should
// explicitly set them to true.
optional bool cc_generic_services = 16 [default = false];
optional bool java_generic_services = 17 [default = false];
optional bool py_generic_services = 18 [default = false];
optional bool php_generic_services = 42 [default = false];
// Is this file deprecated?
// Depending on the target platform, this can emit Deprecated annotations
// for everything in the file, or it will be completely ignored; in the very
// least, this is a formalization for deprecating files.
optional bool deprecated = 23 [default = false];
// Enables the use of arenas for the proto messages in this file. This applies
// only to generated classes for C++.
optional bool cc_enable_arenas = 31 [default = false];
// Sets the objective c class prefix which is prepended to all objective c
// generated classes from this .proto. There is no default.
optional string objc_class_prefix = 36;
// Namespace for generated classes; defaults to the package.
optional string csharp_namespace = 37;
// By default Swift generators will take the proto package and CamelCase it
// replacing '.' with underscore and use that to prefix the types/symbols
// defined. When this options is provided, they will use this value instead
// to prefix the types/symbols defined.
optional string swift_prefix = 39;
// Sets the php class prefix which is prepended to all php generated classes
// from this .proto. Default is empty.
optional string php_class_prefix = 40;
// Use this option to change the namespace of php generated classes. Default
// is empty. When this option is empty, the package name will be used for
// determining the namespace.
optional string php_namespace = 41;
// Use this option to change the namespace of php generated metadata classes.
// Default is empty. When this option is empty, the proto file name will be
// used for determining the namespace.
optional string php_metadata_namespace = 44;
// Use this option to change the package of ruby generated classes. Default
// is empty. When this option is not set, the package name will be used for
// determining the ruby package.
optional string ruby_package = 45;
// The parser stores options it doesn't recognize here.
// See the documentation for the "Options" section above.
repeated UninterpretedOption uninterpreted_option = 999;
// Clients can define custom options in extensions of this message.
// See the documentation for the "Options" section above.
extensions 1000 to max;
reserved 38;
}
message MessageOptions {
// Set true to use the old proto1 MessageSet wire format for extensions.
// This is provided for backwards-compatibility with the MessageSet wire
// format. You should not use this for any other reason: It's less
// efficient, has fewer features, and is more complicated.
//
// The message must be defined exactly as follows:
// message Foo {
// option message_set_wire_format = true;
// extensions 4 to max;
// }
// Note that the message cannot have any defined fields; MessageSets only
// have extensions.
//
// All extensions of your type must be singular messages; e.g. they cannot
// be int32s, enums, or repeated messages.
//
// Because this is an option, the above two restrictions are not enforced by
// the protocol compiler.
optional bool message_set_wire_format = 1 [default = false];
// Disables the generation of the standard "descriptor()" accessor, which can
// conflict with a field of the same name. This is meant to make migration
// from proto1 easier; new code should avoid fields named "descriptor".
optional bool no_standard_descriptor_accessor = 2 [default = false];
// Is this message deprecated?
// Depending on the target platform, this can emit Deprecated annotations
// for the message, or it will be completely ignored; in the very least,
// this is a formalization for deprecating messages.
optional bool deprecated = 3 [default = false];
// Whether the message is an automatically generated map entry type for the
// maps field.
//
// For maps fields:
// map<KeyType, ValueType> map_field = 1;
// The parsed descriptor looks like:
// message MapFieldEntry {
// option map_entry = true;
// optional KeyType key = 1;
// optional ValueType value = 2;
// }
// repeated MapFieldEntry map_field = 1;
//
// Implementations may choose not to generate the map_entry=true message, but
// use a native map in the target language to hold the keys and values.
// The reflection APIs in such implementations still need to work as
// if the field is a repeated message field.
//
// NOTE: Do not set the option in .proto files. Always use the maps syntax
// instead. The option should only be implicitly set by the proto compiler
// parser.
optional bool map_entry = 7;
reserved 8; // javalite_serializable
reserved 9; // javanano_as_lite
// The parser stores options it doesn't recognize here. See above.
repeated UninterpretedOption uninterpreted_option = 999;
// Clients can define custom options in extensions of this message. See above.
extensions 1000 to max;
}
message FieldOptions {
// The ctype option instructs the C++ code generator to use a different
// representation of the field than it normally would. See the specific
// options below. This option is not yet implemented in the open source
// release -- sorry, we'll try to include it in a future version!
optional CType ctype = 1 [default = STRING];
enum CType {
// Default mode.
STRING = 0;
CORD = 1;
STRING_PIECE = 2;
}
// The packed option can be enabled for repeated primitive fields to enable
// a more efficient representation on the wire. Rather than repeatedly
// writing the tag and type for each element, the entire array is encoded as
// a single length-delimited blob. In proto3, only explicit setting it to
// false will avoid using packed encoding.
optional bool packed = 2;
// The jstype option determines the JavaScript type used for values of the
// field. The option is permitted only for 64 bit integral and fixed types
// (int64, uint64, sint64, fixed64, sfixed64). A field with jstype JS_STRING
// is represented as JavaScript string, which avoids loss of precision that
// can happen when a large value is converted to a floating point JavaScript.
// Specifying JS_NUMBER for the jstype causes the generated JavaScript code to
// use the JavaScript "number" type. The behavior of the default option
// JS_NORMAL is implementation dependent.
//
// This option is an enum to permit additional types to be added, e.g.
// goog.math.Integer.
optional JSType jstype = 6 [default = JS_NORMAL];
enum JSType {
// Use the default type.
JS_NORMAL = 0;
// Use JavaScript strings.
JS_STRING = 1;
// Use JavaScript numbers.
JS_NUMBER = 2;
}
// Should this field be parsed lazily? Lazy applies only to message-type
// fields. It means that when the outer message is initially parsed, the
// inner message's contents will not be parsed but instead stored in encoded
// form. The inner message will actually be parsed when it is first accessed.
//
// This is only a hint. Implementations are free to choose whether to use
// eager or lazy parsing regardless of the value of this option. However,
// setting this option true suggests that the protocol author believes that
// using lazy parsing on this field is worth the additional bookkeeping
// overhead typically needed to implement it.
//
// This option does not affect the public interface of any generated code;
// all method signatures remain the same. Furthermore, thread-safety of the
// interface is not affected by this option; const methods remain safe to
// call from multiple threads concurrently, while non-const methods continue
// to require exclusive access.
//
//
// Note that implementations may choose not to check required fields within
// a lazy sub-message. That is, calling IsInitialized() on the outer message
// may return true even if the inner message has missing required fields.
// This is necessary because otherwise the inner message would have to be
// parsed in order to perform the check, defeating the purpose of lazy
// parsing. An implementation which chooses not to check required fields
// must be consistent about it. That is, for any particular sub-message, the
// implementation must either *always* check its required fields, or *never*
// check its required fields, regardless of whether or not the message has
// been parsed.
optional bool lazy = 5 [default = false];
// Is this field deprecated?
// Depending on the target platform, this can emit Deprecated annotations
// for accessors, or it will be completely ignored; in the very least, this
// is a formalization for deprecating fields.
optional bool deprecated = 3 [default = false];
// For Google-internal migration only. Do not use.
optional bool weak = 10 [default = false];
// The parser stores options it doesn't recognize here. See above.
repeated UninterpretedOption uninterpreted_option = 999;
// Clients can define custom options in extensions of this message. See above.
extensions 1000 to max;
reserved 4; // removed jtype
}
message OneofOptions {
// The parser stores options it doesn't recognize here. See above.
repeated UninterpretedOption uninterpreted_option = 999;
// Clients can define custom options in extensions of this message. See above.
extensions 1000 to max;
}
message EnumOptions {
// Set this option to true to allow mapping different tag names to the same
// value.
optional bool allow_alias = 2;
// Is this enum deprecated?
// Depending on the target platform, this can emit Deprecated annotations
// for the enum, or it will be completely ignored; in the very least, this
// is a formalization for deprecating enums.
optional bool deprecated = 3 [default = false];
reserved 5; // javanano_as_lite
// The parser stores options it doesn't recognize here. See above.
repeated UninterpretedOption uninterpreted_option = 999;
// Clients can define custom options in extensions of this message. See above.
extensions 1000 to max;
}
message EnumValueOptions {
// Is this enum value deprecated?
// Depending on the target platform, this can emit Deprecated annotations
// for the enum value, or it will be completely ignored; in the very least,
// this is a formalization for deprecating enum values.
optional bool deprecated = 1 [default = false];
// The parser stores options it doesn't recognize here. See above.
repeated UninterpretedOption uninterpreted_option = 999;
// Clients can define custom options in extensions of this message. See above.
extensions 1000 to max;
}
message ServiceOptions {
// Note: Field numbers 1 through 32 are reserved for Google's internal RPC
// framework. We apologize for hoarding these numbers to ourselves, but
// we were already using them long before we decided to release Protocol
// Buffers.
// Is this service deprecated?
// Depending on the target platform, this can emit Deprecated annotations
// for the service, or it will be completely ignored; in the very least,
// this is a formalization for deprecating services.
optional bool deprecated = 33 [default = false];
// The parser stores options it doesn't recognize here. See above.
repeated UninterpretedOption uninterpreted_option = 999;
// Clients can define custom options in extensions of this message. See above.
extensions 1000 to max;
}
message MethodOptions {
// Note: Field numbers 1 through 32 are reserved for Google's internal RPC
// framework. We apologize for hoarding these numbers to ourselves, but
// we were already using them long before we decided to release Protocol
// Buffers.
// Is this method deprecated?
// Depending on the target platform, this can emit Deprecated annotations
// for the method, or it will be completely ignored; in the very least,
// this is a formalization for deprecating methods.
optional bool deprecated = 33 [default = false];
// Is this method side-effect-free (or safe in HTTP parlance), or idempotent,
// or neither? HTTP based RPC implementation may choose GET verb for safe
// methods, and PUT verb for idempotent methods instead of the default POST.
enum IdempotencyLevel {
IDEMPOTENCY_UNKNOWN = 0;
NO_SIDE_EFFECTS = 1; // implies idempotent
IDEMPOTENT = 2; // idempotent, but may have side effects
}
optional IdempotencyLevel idempotency_level = 34
[default = IDEMPOTENCY_UNKNOWN];
// The parser stores options it doesn't recognize here. See above.
repeated UninterpretedOption uninterpreted_option = 999;
// Clients can define custom options in extensions of this message. See above.
extensions 1000 to max;
}
// A message representing a option the parser does not recognize. This only
// appears in options protos created by the compiler::Parser class.
// DescriptorPool resolves these when building Descriptor objects. Therefore,
// options protos in descriptor objects (e.g. returned by Descriptor::options(),
// or produced by Descriptor::CopyTo()) will never have UninterpretedOptions
// in them.
message UninterpretedOption {
// The name of the uninterpreted option. Each string represents a segment in
// a dot-separated name. is_extension is true iff a segment represents an
// extension (denoted with parentheses in options specs in .proto files).
// E.g.,{ ["foo", false], ["bar.baz", true], ["qux", false] } represents
// "foo.(bar.baz).qux".
message NamePart {
required string name_part = 1;
required bool is_extension = 2;
}
repeated NamePart name = 2;
// The value of the uninterpreted option, in whatever type the tokenizer
// identified it as during parsing. Exactly one of these should be set.
optional string identifier_value = 3;
optional uint64 positive_int_value = 4;
optional int64 negative_int_value = 5;
optional double double_value = 6;
optional bytes string_value = 7;
optional string aggregate_value = 8;
}
// ===================================================================
// Optional source code info
// Encapsulates information about the original source file from which a
// FileDescriptorProto was generated.
message SourceCodeInfo {
// A Location identifies a piece of source code in a .proto file which
// corresponds to a particular definition. This information is intended
// to be useful to IDEs, code indexers, documentation generators, and similar
// tools.
//
// For example, say we have a file like:
// message Foo {
// optional string foo = 1;
// }
// Let's look at just the field definition:
// optional string foo = 1;
// ^ ^^ ^^ ^ ^^^
// a bc de f ghi
// We have the following locations:
// span path represents
// [a,i) [ 4, 0, 2, 0 ] The whole field definition.
// [a,b) [ 4, 0, 2, 0, 4 ] The label (optional).
// [c,d) [ 4, 0, 2, 0, 5 ] The type (string).
// [e,f) [ 4, 0, 2, 0, 1 ] The name (foo).
// [g,h) [ 4, 0, 2, 0, 3 ] The number (1).
//
// Notes:
// - A location may refer to a repeated field itself (i.e. not to any
// particular index within it). This is used whenever a set of elements are
// logically enclosed in a single code segment. For example, an entire
// extend block (possibly containing multiple extension definitions) will
// have an outer location whose path refers to the "extensions" repeated
// field without an index.
// - Multiple locations may have the same path. This happens when a single
// logical declaration is spread out across multiple places. The most
// obvious example is the "extend" block again -- there may be multiple
// extend blocks in the same scope, each of which will have the same path.
// - A location's span is not always a subset of its parent's span. For
// example, the "extendee" of an extension declaration appears at the
// beginning of the "extend" block and is shared by all extensions within
// the block.
// - Just because a location's span is a subset of some other location's span
// does not mean that it is a descendant. For example, a "group" defines
// both a type and a field in a single declaration. Thus, the locations
// corresponding to the type and field and their components will overlap.
// - Code which tries to interpret locations should probably be designed to
// ignore those that it doesn't understand, as more types of locations could
// be recorded in the future.
repeated Location location = 1;
message Location {
// Identifies which part of the FileDescriptorProto was defined at this
// location.
//
// Each element is a field number or an index. They form a path from
// the root FileDescriptorProto to the place where the definition. For
// example, this path:
// [ 4, 3, 2, 7, 1 ]
// refers to:
// file.message_type(3) // 4, 3
// .field(7) // 2, 7
// .name() // 1
// This is because FileDescriptorProto.message_type has field number 4:
// repeated DescriptorProto message_type = 4;
// and DescriptorProto.field has field number 2:
// repeated FieldDescriptorProto field = 2;
// and FieldDescriptorProto.name has field number 1:
// optional string name = 1;
//
// Thus, the above path gives the location of a field name. If we removed
// the last element:
// [ 4, 3, 2, 7 ]
// this path refers to the whole field declaration (from the beginning
// of the label to the terminating semicolon).
repeated int32 path = 1 [packed = true];
// Always has exactly three or four elements: start line, start column,
// end line (optional, otherwise assumed same as start line), end column.
// These are packed into a single field for efficiency. Note that line
// and column numbers are zero-based -- typically you will want to add
// 1 to each before displaying to a user.
repeated int32 span = 2 [packed = true];
// If this SourceCodeInfo represents a complete declaration, these are any
// comments appearing before and after the declaration which appear to be
// attached to the declaration.
//
// A series of line comments appearing on consecutive lines, with no other
// tokens appearing on those lines, will be treated as a single comment.
//
// leading_detached_comments will keep paragraphs of comments that appear
// before (but not connected to) the current element. Each paragraph,
// separated by empty lines, will be one comment element in the repeated
// field.
//
// Only the comment content is provided; comment markers (e.g. //) are
// stripped out. For block comments, leading whitespace and an asterisk
// will be stripped from the beginning of each line other than the first.
// Newlines are included in the output.
//
// Examples:
//
// optional int32 foo = 1; // Comment attached to foo.
// // Comment attached to bar.
// optional int32 bar = 2;
//
// optional string baz = 3;
// // Comment attached to baz.
// // Another line attached to baz.
//
// // Comment attached to qux.
// //
// // Another line attached to qux.
// optional double qux = 4;
//
// // Detached comment for corge. This is not leading or trailing comments
// // to qux or corge because there are blank lines separating it from
// // both.
//
// // Detached comment for corge paragraph 2.
//
// optional string corge = 5;
// /* Block comment attached
// * to corge. Leading asterisks
// * will be removed. */
// /* Block comment attached to
// * grault. */
// optional int32 grault = 6;
//
// // ignored detached comments.
optional string leading_comments = 3;
optional string trailing_comments = 4;
repeated string leading_detached_comments = 6;
}
}
// Describes the relationship between generated code and its original source
// file. A GeneratedCodeInfo message is associated with only one generated
// source file, but may contain references to different source .proto files.
message GeneratedCodeInfo {
// An Annotation connects some span of text in generated code to an element
// of its generating .proto file.
repeated Annotation annotation = 1;
message Annotation {
// Identifies the element in the original source .proto file. This field
// is formatted the same as SourceCodeInfo.Location.path.
repeated int32 path = 1 [packed = true];
// Identifies the filesystem path to the original source .proto.
optional string source_file = 2;
// Identifies the starting offset in bytes in the generated code
// that relates to the identified object.
optional int32 begin = 3;
// Identifies the ending offset in bytes in the generated code that
// relates to the identified offset. The end offset should be one past
// the last relevant byte (so the length of the text = end - begin).
optional int32 end = 4;
}
}

View File

@@ -0,0 +1,52 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
package google.protobuf;
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
option go_package = "github.com/golang/protobuf/ptypes/empty";
option java_package = "com.google.protobuf";
option java_outer_classname = "EmptyProto";
option java_multiple_files = true;
option objc_class_prefix = "GPB";
option cc_enable_arenas = true;
// A generic empty message that you can re-use to avoid defining duplicated
// empty messages in your APIs. A typical example is to use it as the request
// or the response type of an API method. For instance:
//
// service Foo {
// rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);
// }
//
// The JSON representation for `Empty` is empty JSON object `{}`.
message Empty {}

View File

@@ -0,0 +1,96 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
package google.protobuf;
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
option cc_enable_arenas = true;
option go_package = "github.com/golang/protobuf/ptypes/struct;structpb";
option java_package = "com.google.protobuf";
option java_outer_classname = "StructProto";
option java_multiple_files = true;
option objc_class_prefix = "GPB";
// `Struct` represents a structured data value, consisting of fields
// which map to dynamically typed values. In some languages, `Struct`
// might be supported by a native representation. For example, in
// scripting languages like JS a struct is represented as an
// object. The details of that representation are described together
// with the proto support for the language.
//
// The JSON representation for `Struct` is JSON object.
message Struct {
// Unordered map of dynamically typed values.
map<string, Value> fields = 1;
}
// `Value` represents a dynamically typed value which can be either
// null, a number, a string, a boolean, a recursive struct value, or a
// list of values. A producer of value is expected to set one of that
// variants, absence of any variant indicates an error.
//
// The JSON representation for `Value` is JSON value.
message Value {
// The kind of value.
oneof kind {
// Represents a null value.
NullValue null_value = 1;
// Represents a double value.
double number_value = 2;
// Represents a string value.
string string_value = 3;
// Represents a boolean value.
bool bool_value = 4;
// Represents a structured value.
Struct struct_value = 5;
// Represents a repeated `Value`.
ListValue list_value = 6;
}
}
// `NullValue` is a singleton enumeration to represent the null value for the
// `Value` type union.
//
// The JSON representation for `NullValue` is JSON `null`.
enum NullValue {
// Null value.
NULL_VALUE = 0;
}
// `ListValue` is a wrapper around a repeated field of values.
//
// The JSON representation for `ListValue` is JSON array.
message ListValue {
// Repeated field of dynamically typed values.
repeated Value values = 1;
}

View File

@@ -0,0 +1,137 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
package google.protobuf;
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
option cc_enable_arenas = true;
option go_package = "github.com/golang/protobuf/ptypes/timestamp";
option java_package = "com.google.protobuf";
option java_outer_classname = "TimestampProto";
option java_multiple_files = true;
option objc_class_prefix = "GPB";
// A Timestamp represents a point in time independent of any time zone or local
// calendar, encoded as a count of seconds and fractions of seconds at
// nanosecond resolution. The count is relative to an epoch at UTC midnight on
// January 1, 1970, in the proleptic Gregorian calendar which extends the
// Gregorian calendar backwards to year one.
//
// All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap
// second table is needed for interpretation, using a [24-hour linear
// smear](https://developers.google.com/time/smear).
//
// The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By
// restricting to that range, we ensure that we can convert to and from [RFC
// 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings.
//
// # Examples
//
// Example 1: Compute Timestamp from POSIX `time()`.
//
// Timestamp timestamp;
// timestamp.set_seconds(time(NULL));
// timestamp.set_nanos(0);
//
// Example 2: Compute Timestamp from POSIX `gettimeofday()`.
//
// struct timeval tv;
// gettimeofday(&tv, NULL);
//
// Timestamp timestamp;
// timestamp.set_seconds(tv.tv_sec);
// timestamp.set_nanos(tv.tv_usec * 1000);
//
// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`.
//
// FILETIME ft;
// GetSystemTimeAsFileTime(&ft);
// UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
//
// // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z
// // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z.
// Timestamp timestamp;
// timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL));
// timestamp.set_nanos((INT32) ((ticks % 10000000) * 100));
//
// Example 4: Compute Timestamp from Java `System.currentTimeMillis()`.
//
// long millis = System.currentTimeMillis();
//
// Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000)
// .setNanos((int) ((millis % 1000) * 1000000)).build();
//
//
// Example 5: Compute Timestamp from current time in Python.
//
// timestamp = Timestamp()
// timestamp.GetCurrentTime()
//
// # JSON Mapping
//
// In JSON format, the Timestamp type is encoded as a string in the
// [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the
// format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z"
// where {year} is always expressed using four digits while {month}, {day},
// {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional
// seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution),
// are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone
// is required. A proto3 JSON serializer should always use UTC (as indicated by
// "Z") when printing the Timestamp type and a proto3 JSON parser should be
// able to accept both UTC and other timezones (as indicated by an offset).
//
// For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past
// 01:30 UTC on January 15, 2017.
//
// In JavaScript, one can convert a Date object to this format using the
// standard [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString)
// method. In Python, a standard `datetime.datetime` object can be converted
// to this format using [`strftime`](https://docs.python.org/2/library/time.html#time.strftime)
// with the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one
// can use the Joda Time's [`ISODateTimeFormat.dateTime()`](
// http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime%2D%2D
// ) to obtain a formatter capable of generating timestamps in this format.
//
//
message Timestamp {
// Represents seconds of UTC time since Unix epoch
// 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
// 9999-12-31T23:59:59Z inclusive.
int64 seconds = 1;
// Non-negative fractions of a second at nanosecond resolution. Negative
// second values with fractions must still have non-negative nanos values
// that count forward in time. Must be from 0 to 999,999,999
// inclusive.
int32 nanos = 2;
}

View File

@@ -0,0 +1,123 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Wrappers for primitive (non-message) types. These types are useful
// for embedding primitives in the `google.protobuf.Any` type and for places
// where we need to distinguish between the absence of a primitive
// typed field and its default value.
//
// These wrappers have no meaningful use within repeated fields as they lack
// the ability to detect presence on individual elements.
// These wrappers have no meaningful use within a map or a oneof since
// individual entries of a map or fields of a oneof can already detect presence.
syntax = "proto3";
package google.protobuf;
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
option cc_enable_arenas = true;
option go_package = "github.com/golang/protobuf/ptypes/wrappers";
option java_package = "com.google.protobuf";
option java_outer_classname = "WrappersProto";
option java_multiple_files = true;
option objc_class_prefix = "GPB";
// Wrapper message for `double`.
//
// The JSON representation for `DoubleValue` is JSON number.
message DoubleValue {
// The double value.
double value = 1;
}
// Wrapper message for `float`.
//
// The JSON representation for `FloatValue` is JSON number.
message FloatValue {
// The float value.
float value = 1;
}
// Wrapper message for `int64`.
//
// The JSON representation for `Int64Value` is JSON string.
message Int64Value {
// The int64 value.
int64 value = 1;
}
// Wrapper message for `uint64`.
//
// The JSON representation for `UInt64Value` is JSON string.
message UInt64Value {
// The uint64 value.
uint64 value = 1;
}
// Wrapper message for `int32`.
//
// The JSON representation for `Int32Value` is JSON number.
message Int32Value {
// The int32 value.
int32 value = 1;
}
// Wrapper message for `uint32`.
//
// The JSON representation for `UInt32Value` is JSON number.
message UInt32Value {
// The uint32 value.
uint32 value = 1;
}
// Wrapper message for `bool`.
//
// The JSON representation for `BoolValue` is JSON `true` and `false`.
message BoolValue {
// The bool value.
bool value = 1;
}
// Wrapper message for `string`.
//
// The JSON representation for `StringValue` is JSON string.
message StringValue {
// The string value.
string value = 1;
}
// Wrapper message for `bytes`.
//
// The JSON representation for `BytesValue` is JSON string.
message BytesValue {
// The bytes value.
bytes value = 1;
}

Some files were not shown because too many files have changed in this diff Show More