1
0
mirror of https://github.com/musix-org/musix-oss synced 2025-06-17 20:15:59 +00:00
This commit is contained in:
MatteZ02
2020-03-03 22:30:50 +02:00
parent edfcc6f474
commit 30022c7634
11800 changed files with 1984416 additions and 1 deletions

View File

@ -0,0 +1,40 @@
/**
* @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;
_approximateByteSize(): number;
/**
* 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,149 @@
/**
* @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 { FirebaseAuthInternalName } from '@firebase/auth-interop-types';
import { Provider } from '@firebase/component';
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 {
/**
* The auth token listener registered with FirebaseApp, retained here so we
* can unregister it.
*/
private tokenListener;
/** Tracks the current User. */
private currentUser;
private receivedInitialUser;
/**
* 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;
private auth;
constructor(authProvider: Provider<FirebaseAuthInternalName>);
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);
get 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,270 @@
/**
* @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';
import { FirebaseAuthInternalName } from '@firebase/auth-interop-types';
import { Provider } from '@firebase/component';
/**
* 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, authProvider: Provider<FirebaseAuthInternalName>);
settings(settingsLiteral: firestore.Settings): void;
enableNetwork(): Promise<void>;
disableNetwork(): Promise<void>;
enablePersistence(settings?: firestore.PersistenceSettings): Promise<void>;
clearPersistence(): Promise<void>;
terminate(): Promise<void>;
get _isTerminated(): boolean;
waitForPendingWrites(): Promise<void>;
onSnapshotsInSync(observer: PartialObserver<void>): Unsubscribe;
onSnapshotsInSync(onSync: () => void): Unsubscribe;
private onSnapshotsInSyncInternal;
ensureClientConfigured(): FirestoreClient;
private makeDatabaseInfo;
private configureClient;
private createDataConverter;
private static databaseIdFromApp;
get 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 get 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<T>(documentRef: firestore.DocumentReference<T>): Promise<firestore.DocumentSnapshot<T>>;
set<T>(documentRef: firestore.DocumentReference<T>, value: T, options?: firestore.SetOptions): Transaction;
update(documentRef: firestore.DocumentReference<unknown>, value: firestore.UpdateData): Transaction;
update(documentRef: firestore.DocumentReference<unknown>, field: string | ExternalFieldPath, value: unknown, ...moreFieldsAndValues: unknown[]): Transaction;
delete(documentRef: firestore.DocumentReference<unknown>): Transaction;
}
export declare class WriteBatch implements firestore.WriteBatch {
private _firestore;
private _mutations;
private _committed;
constructor(_firestore: Firestore);
set<T>(documentRef: firestore.DocumentReference<T>, value: T, options?: firestore.SetOptions): WriteBatch;
update(documentRef: firestore.DocumentReference<unknown>, value: firestore.UpdateData): WriteBatch;
update(documentRef: firestore.DocumentReference<unknown>, field: string | ExternalFieldPath, value: unknown, ...moreFieldsAndValues: unknown[]): WriteBatch;
delete(documentRef: firestore.DocumentReference<unknown>): WriteBatch;
commit(): Promise<void>;
private verifyNotCommitted;
}
/**
* A reference to a particular document in a collection in the database.
*/
export declare class DocumentReference<T = firestore.DocumentData> implements firestore.DocumentReference<T> {
_key: DocumentKey;
readonly firestore: Firestore;
readonly _converter?: firestore.FirestoreDataConverter<T> | undefined;
private _firestoreClient;
constructor(_key: DocumentKey, firestore: Firestore, _converter?: firestore.FirestoreDataConverter<T> | undefined);
static forPath<U>(path: ResourcePath, firestore: Firestore, converter?: firestore.FirestoreDataConverter<U>): DocumentReference<U>;
get id(): string;
get parent(): firestore.CollectionReference<T>;
get path(): string;
collection(pathString: string): firestore.CollectionReference<firestore.DocumentData>;
isEqual(other: firestore.DocumentReference<T>): 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<T>>): Unsubscribe;
onSnapshot(options: firestore.SnapshotListenOptions, observer: PartialObserver<firestore.DocumentSnapshot<T>>): Unsubscribe;
onSnapshot(onNext: NextFn<firestore.DocumentSnapshot<T>>, onError?: ErrorFn, onCompletion?: CompleteFn): Unsubscribe;
onSnapshot(options: firestore.SnapshotListenOptions, onNext: NextFn<firestore.DocumentSnapshot<T>>, onError?: ErrorFn, onCompletion?: CompleteFn): Unsubscribe;
private onSnapshotInternal;
get(options?: firestore.GetOptions): Promise<firestore.DocumentSnapshot<T>>;
private getViaSnapshotListener;
withConverter<U>(converter: firestore.FirestoreDataConverter<U>): firestore.DocumentReference<U>;
}
/**
* Options interface that can be provided to configure the deserialization of
* DocumentSnapshots.
*/
export interface SnapshotOptions extends firestore.SnapshotOptions {
}
export declare class DocumentSnapshot<T = firestore.DocumentData> implements firestore.DocumentSnapshot<T> {
private _firestore;
private _key;
_document: Document | null;
private _fromCache;
private _hasPendingWrites;
private readonly _converter?;
constructor(_firestore: Firestore, _key: DocumentKey, _document: Document | null, _fromCache: boolean, _hasPendingWrites: boolean, _converter?: firestore.FirestoreDataConverter<T> | undefined);
data(options?: firestore.SnapshotOptions): T | undefined;
get(fieldPath: string | ExternalFieldPath, options?: firestore.SnapshotOptions): unknown;
get id(): string;
get ref(): firestore.DocumentReference<T>;
get exists(): boolean;
get metadata(): firestore.SnapshotMetadata;
isEqual(other: firestore.DocumentSnapshot<T>): boolean;
private toJSObject;
private toJSValue;
private toJSArray;
}
export declare class QueryDocumentSnapshot<T = firestore.DocumentData> extends DocumentSnapshot<T> implements firestore.QueryDocumentSnapshot<T> {
data(options?: SnapshotOptions): T;
}
export declare class Query<T = firestore.DocumentData> implements firestore.Query<T> {
_query: InternalQuery;
readonly firestore: Firestore;
protected readonly _converter?: firestore.FirestoreDataConverter<T> | undefined;
constructor(_query: InternalQuery, firestore: Firestore, _converter?: firestore.FirestoreDataConverter<T> | undefined);
where(field: string | ExternalFieldPath, opStr: firestore.WhereFilterOp, value: unknown): firestore.Query<T>;
orderBy(field: string | ExternalFieldPath, directionStr?: firestore.OrderByDirection): firestore.Query<T>;
limit(n: number): firestore.Query<T>;
limitToLast(n: number): firestore.Query<T>;
startAt(docOrField: unknown | firestore.DocumentSnapshot<unknown>, ...fields: unknown[]): firestore.Query<T>;
startAfter(docOrField: unknown | firestore.DocumentSnapshot<unknown>, ...fields: unknown[]): firestore.Query<T>;
endBefore(docOrField: unknown | firestore.DocumentSnapshot<unknown>, ...fields: unknown[]): firestore.Query<T>;
endAt(docOrField: unknown | firestore.DocumentSnapshot<unknown>, ...fields: unknown[]): firestore.Query<T>;
isEqual(other: firestore.Query<T>): boolean;
withConverter<U>(converter: firestore.FirestoreDataConverter<U>): firestore.Query<U>;
/** 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<T>>): Unsubscribe;
onSnapshot(options: firestore.SnapshotListenOptions, observer: PartialObserver<firestore.QuerySnapshot<T>>): Unsubscribe;
onSnapshot(onNext: NextFn<firestore.QuerySnapshot<T>>, onError?: ErrorFn, onCompletion?: CompleteFn): Unsubscribe;
onSnapshot(options: firestore.SnapshotListenOptions, onNext: NextFn<firestore.QuerySnapshot<T>>, onError?: ErrorFn, onCompletion?: CompleteFn): Unsubscribe;
private onSnapshotInternal;
private validateHasExplicitOrderByForLimitToLast;
get(options?: firestore.GetOptions): Promise<firestore.QuerySnapshot<T>>;
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<T = firestore.DocumentData> implements firestore.QuerySnapshot<T> {
private readonly _firestore;
private readonly _originalQuery;
private readonly _snapshot;
private readonly _converter?;
private _cachedChanges;
private _cachedChangesIncludeMetadataChanges;
readonly metadata: firestore.SnapshotMetadata;
constructor(_firestore: Firestore, _originalQuery: InternalQuery, _snapshot: ViewSnapshot, _converter?: firestore.FirestoreDataConverter<T> | undefined);
get docs(): Array<firestore.QueryDocumentSnapshot<T>>;
get empty(): boolean;
get size(): number;
forEach(callback: (result: firestore.QueryDocumentSnapshot<T>) => void, thisArg?: unknown): void;
get query(): firestore.Query<T>;
docChanges(options?: firestore.SnapshotListenOptions): Array<firestore.DocumentChange<T>>;
/** Check the equality. The call can be very expensive. */
isEqual(other: firestore.QuerySnapshot<T>): boolean;
private convertToDocumentImpl;
}
export declare class CollectionReference<T = firestore.DocumentData> extends Query<T> implements firestore.CollectionReference<T> {
readonly _path: ResourcePath;
constructor(_path: ResourcePath, firestore: Firestore, _converter?: firestore.FirestoreDataConverter<T>);
get id(): string;
get parent(): firestore.DocumentReference<firestore.DocumentData> | null;
get path(): string;
doc(pathString?: string): firestore.DocumentReference<T>;
add(value: T): Promise<firestore.DocumentReference<T>>;
withConverter<U>(converter: firestore.FirestoreDataConverter<U>): firestore.CollectionReference<U>;
}
/**
* Calculates the array of firestore.DocumentChange's for a given ViewSnapshot.
*
* Exported for testing.
*/
export declare function changesFromSnapshot<T>(firestore: Firestore, includeMetadataChanges: boolean, snapshot: ViewSnapshot, converter?: firestore.FirestoreDataConverter<T>): Array<firestore.DocumentChange<T>>;
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.
*/
get latitude(): number;
/**
* Returns the longitude of this geo point, a number between -180 and 180.
*/
get 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,117 @@
/**
* @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).
*
* @param allowArrays Whether the query value is an array that may directly
* contain additional arrays (e.g. the operand of an `in` query).
*/
parseQueryValue(methodName: string, input: unknown, allowArrays?: boolean): 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);
get isDefaultDatabase(): boolean;
isEqual(other: {}): boolean;
compareTo(other: DatabaseId): number;
}

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 { 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;
private snapshotsInSyncListeners;
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;
addSnapshotsInSyncListener(observer: Observer<void>): void;
removeSnapshotsInSyncListener(observer: Observer<void>): void;
private raiseSnapshotsInSyncEvent;
}
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);
/**
* Applies the new ViewSnapshot to this listener, raising a user-facing event
* if applicable (depending on what changed, whether the user has opted into
* metadata-only changes, etc.). Returns true if a user-facing event was
* indeed raised.
*/
onViewSnapshot(snap: ViewSnapshot): boolean;
onError(error: Error): void;
/** Returns whether a snapshot was raised. */
applyOnlineStateChange(onlineState: OnlineState): boolean;
private shouldRaiseInitialEvent;
private shouldRaiseEvent;
private raiseInitialEvent;
}

View File

@ -0,0 +1,178 @@
/**
* @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;
addSnapshotsInSyncListener(observer: Observer<void>): void;
removeSnapshotsInSyncListener(observer: Observer<void>): void;
get 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,207 @@
/**
* @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';
import { Target } from './target';
export declare enum LimitType {
First = "F",
Last = "L"
}
/**
* Query encapsulates all the query attributes we support in the SDK. It can
* be run against the LocalStore, as well as be converted to a `Target` to
* query the RemoteStore results.
*/
export declare class Query {
readonly path: ResourcePath;
readonly collectionGroup: string | null;
readonly explicitOrderBy: OrderBy[];
readonly filters: Filter[];
readonly limit: number | null;
readonly limitType: LimitType;
readonly startAt: Bound | null;
readonly endAt: Bound | null;
static atPath(path: ResourcePath): Query;
private memoizedOrderBy;
private memoizedTarget;
/**
* 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, limitType?: LimitType, startAt?: Bound | null, endAt?: Bound | null);
get orderBy(): OrderBy[];
addFilter(filter: Filter): Query;
addOrderBy(orderBy: OrderBy): Query;
withLimitToFirst(limit: number | null): Query;
withLimitToLast(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;
/**
* Returns true if this query does not specify any query constraints that
* could remove results.
*/
matchesAllDocuments(): boolean;
canonicalId(): string;
toString(): string;
isEqual(other: Query): boolean;
docComparator(d1: Document, d2: Document): number;
matches(doc: Document): boolean;
hasLimitToFirst(): boolean;
hasLimitToLast(): boolean;
getFirstOrderByField(): FieldPath | null;
getInequalityFilterField(): FieldPath | null;
findFilterOperator(operators: Operator[]): Operator | null;
isDocumentQuery(): boolean;
isCollectionGroupQuery(): boolean;
/**
* Converts this `Query` instance to it's corresponding `Target`
* representation.
*/
toTarget(): Target;
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,192 @@
/**
* @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 queriesByTarget;
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);
get 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 removeAndCleanupTarget;
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;
/**
* Creates a `Query` object from the specified `Target`. There is no way to
* obtain the original `Query`, so we synthesize a `Query` from the `Target`
* object.
*
* The synthesized result might be different from the original `Query`, but
* since the synthesized `Query` should return the same results as the
* original one (only the presentation of results might differ), the potential
* difference will not cause issues.
*/
private synthesizeTargetToQuery;
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,48 @@
/**
* @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 { Bound, Filter, OrderBy } from './query';
/**
* A Target represents the WatchTarget representation of a Query, which is used
* by the LocalStore and the RemoteStore to keep track of and to execute
* backend queries. While a Query can represent multiple Targets, each Targets
* maps to a single WatchTarget in RemoteStore and a single TargetData entry
* in persistence.
*/
export declare class Target {
readonly path: ResourcePath;
readonly collectionGroup: string | null;
readonly orderBy: OrderBy[];
readonly filters: Filter[];
readonly limit: number | null;
readonly startAt: Bound | null;
readonly endAt: Bound | null;
private memoizedCanonicalId;
/**
* Initializes a Target with a path and optional additional query constraints.
* Path must currently be empty if this is a collection group query.
*
* NOTE: you should always construct `Target` from `Query.toTarget` instead of
* using this constructor, because `Query` provides an implicit `orderBy`
* property.
*/
constructor(path: ResourcePath, collectionGroup?: string | null, orderBy?: OrderBy[], filters?: Filter[], limit?: number | null, startAt?: Bound | null, endAt?: Bound | null);
canonicalId(): string;
toString(): string;
isEqual(other: Target): boolean;
isDocumentQuery(): boolean;
}

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 forTargetCache(): 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 the 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,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 { QueryResult } from '../local/local_store';
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.
*/
get 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 queryResult.documents - The documents that match the query according
* to the LocalStore.
* @param queryResult.remoteKeys - The keys of the documents that match the
* query according to the backend.
*
* @return The ViewChange that resulted from this synchronization.
*/
synchronizeWithPersistedState(queryResult: QueryResult): 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;
get 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,61 @@
/**
* @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 { QueryEngine } from './query_engine';
import { LocalDocumentsView } from './local_documents_view';
import { PersistenceTransaction } from './persistence';
import { PersistencePromise } from './persistence_promise';
import { Query } from '../core/query';
import { SnapshotVersion } from '../core/snapshot_version';
import { DocumentKeySet, DocumentMap } from '../model/collections';
/**
* A query engine that takes advantage of the target document mapping in the
* QueryCache. The IndexFreeQueryEngine optimizes query execution by only
* reading the documents that previously matched a query plus any documents that were
* edited after the query was last listened to.
*
* There are some cases where Index-Free queries are not guaranteed to produce
* the same results as full collection scans. In these cases, the
* IndexFreeQueryEngine falls back to full query processing. These cases are:
*
* - Limit queries where a document that matched the query previously no longer
* matches the query.
*
* - Limit queries where a document edit may cause the document to sort below
* another document that is in the local cache.
*
* - Queries that have never been CURRENT or free of Limbo documents.
*/
export declare class IndexFreeQueryEngine implements QueryEngine {
private localDocumentsView;
setLocalDocumentsView(localDocuments: LocalDocumentsView): void;
getDocumentsMatchingQuery(transaction: PersistenceTransaction, query: Query, lastLimboFreeSnapshotVersion: SnapshotVersion, remoteKeys: DocumentKeySet): PersistencePromise<DocumentMap>;
/** Applies the query filter and sorting to the provided documents. */
private applyQuery;
/**
* Determines if a limit query needs to be refilled from cache, making it
* ineligible for index-free execution.
*
* @param sortedPreviousResults The documents that matched the query when it
* was last synchronized, sorted by the query's comparator.
* @param remoteKeys The document keys that matched the query at the last
* snapshot.
* @param limboFreeSnapshotVersion The version of the snapshot when the query
* was last synchronized.
*/
private needsRefill;
private executeFullCollectionScan;
}

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,42 @@
/**
* @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;
/**
* Adds a new entry to the collection parent index.
*
* Repeated calls for the same collectionPath should be avoided within a
* transaction as IndexedDbIndexManager only caches writes once a transaction
* has been committed.
*/
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,270 @@
/**
* @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 { IndexedDbIndexManager } from './indexeddb_index_manager';
import { IndexedDbRemoteDocumentCache } from './indexeddb_remote_document_cache';
import { IndexedDbTargetCache } from './indexeddb_target_cache';
import { ActiveTargets, LruDelegate, LruGarbageCollector, LruParams } from './lru_garbage_collector';
import { MutationQueue } from './mutation_queue';
import { Persistence, PersistenceTransaction, PersistenceTransactionMode, PrimaryStateListener, ReferenceDelegate } from './persistence';
import { PersistencePromise } from './persistence_promise';
import { ReferenceSet } from './reference_set';
import { ClientId } from './shared_client_state';
import { TargetData } from './target_data';
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 declare class IndexedDbPersistence implements Persistence {
private readonly allowTabSynchronization;
private readonly persistenceKey;
private readonly clientId;
private readonly queue;
private readonly sequenceNumberSyncer;
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(options: {
allowTabSynchronization: boolean;
persistenceKey: string;
clientId: ClientId;
platform: Platform;
lruParams: LruParams;
queue: AsyncQueue;
serializer: JsonProtoSerializer;
sequenceNumberSyncer: SequenceNumberSyncer;
}): 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 client metadata object store. */
private lastGarbageCollectionTime;
/** A listener to notify on primary state changes. */
private primaryStateListener;
private readonly targetCache;
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;
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>;
get started(): boolean;
getMutationQueue(user: User): MutationQueue;
getTargetCache(): IndexedDbTargetCache;
getRemoteDocumentCache(): IndexedDbRemoteDocumentCache;
getIndexManager(): IndexedDbIndexManager;
runTransaction<T>(action: string, mode: PersistenceTransactionMode, 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;
}
/** 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: TargetData) => 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, targetData: TargetData): 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,106 @@
/**
* @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 { SnapshotVersion } from '../core/snapshot_version';
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';
export declare class IndexedDbRemoteDocumentCache implements RemoteDocumentCache {
readonly serializer: LocalSerializer;
private readonly indexManager;
/**
* @param {LocalSerializer} serializer The document serializer.
* @param {IndexManager} indexManager The query indexes that need to be maintained.
*/
constructor(serializer: LocalSerializer, indexManager: IndexManager);
/**
* 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 current cache 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, sinceReadTime: SnapshotVersion): PersistencePromise<DocumentMap>;
getNewDocumentChanges(transaction: PersistenceTransaction, sinceReadTime: SnapshotVersion): PersistencePromise<{
changedDocs: MaybeDocumentMap;
readTime: SnapshotVersion;
}>;
getLastReadTime(transaction: PersistenceTransaction): PersistencePromise<SnapshotVersion>;
newChangeBuffer(options?: {
trackRemovals: boolean;
}): RemoteDocumentChangeBuffer;
getSize(txn: PersistenceTransaction): PersistencePromise<number>;
private getMetadata;
private setMetadata;
/**
* Decodes `remoteDoc` and returns the document (or null, if the document
* corresponds to the format used for sentinel deletes).
*/
private maybeDecodeDocument;
/**
* 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;
}
/**
* Retrusn an approximate size for the given document.
*/
export declare function dbDocumentSize(doc: DbRemoteDocument): number;

View File

@ -0,0 +1,792 @@
/**
* @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 } 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.
* 9. Change RemoteDocumentChanges store to be keyed by readTime rather than
* an auto-incrementing ID. This is required for Index-Free queries.
*/
export declare const SCHEMA_VERSION = 9;
/** 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: IDBTransaction, 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);
}
/** A timestamp type that can be used in IndexedDb keys. */
export declare type DbTimestampKey = [/* seconds */ number, /* nanos */ 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;
/**
* When the document was read from the backend. Undefined for data written
* prior to schema version 9.
*/
readTime: DbTimestampKey | undefined;
/**
* The path of the collection this document is part of. Undefined for data
* written prior to schema version 9.
*/
parentPath: string[] | undefined;
static store: string;
/**
* An index that provides access to all entries sorted by read time (which
* corresponds to the last modification time of each row).
*
* This index is used to provide a changelog for Multi-Tab.
*/
static readTimeIndex: string;
static readTimeIndexPath: string;
/**
* An index that provides access to documents in a collection sorted by read
* time.
*
* This index is used to allow the RemoteDocumentCache to fetch newly changed
* documents in a collection.
*/
static collectionReadTimeIndex: string;
static collectionReadTimeIndexPath: 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,
/**
* When the document was read from the backend. Undefined for data written
* prior to schema version 9.
*/
readTime: DbTimestampKey | undefined,
/**
* The path of the collection this document is part of. Undefined for data
* written prior to schema version 9.
*/
parentPath: string[] | 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;
/**
* Denotes the maximum snapshot version at which the associated query view
* contained no limbo documents. Undefined for data written prior to
* schema version 9.
*/
lastLimboFreeSnapshotVersion: DbTimestamp | undefined;
/**
* 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,
/**
* Denotes the maximum snapshot version at which the associated query view
* contained no limbo documents. Undefined for data written prior to
* schema version 9.
*/
lastLimboFreeSnapshotVersion: DbTimestamp | undefined,
/**
* 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);
}
/**
* 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;
/** 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);
}
/** 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,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 { 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 { TargetCache } from './target_cache';
import { TargetData } from './target_data';
import { SimpleDbStore, SimpleDbTransaction } from './simple_db';
import { Target } from '../core/target';
export declare class IndexedDbTargetCache implements TargetCache {
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>;
addTargetData(transaction: PersistenceTransaction, targetData: TargetData): PersistencePromise<void>;
updateTargetData(transaction: PersistenceTransaction, targetData: TargetData): PersistencePromise<void>;
removeTargetData(transaction: PersistenceTransaction, targetData: TargetData): 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 `TargetData` that we have cached.
*/
forEachTarget(txn: PersistenceTransaction, f: (q: TargetData) => void): PersistencePromise<void>;
private retrieveMetadata;
private saveMetadata;
private saveTargetData;
/**
* In-place updates the provided metadata to account for values in the given
* TargetData. Saving is done separately. Returns true if there were any
* changes to the metadata.
*/
private updateMetadataFromTargetData;
getTargetCount(transaction: PersistenceTransaction): PersistencePromise<number>;
getTargetData(transaction: PersistenceTransaction, target: Target): PersistencePromise<TargetData | 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>;
getTargetDataForTarget(transaction: PersistenceTransaction, targetId: TargetId): PersistencePromise<TargetData | 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,73 @@
/**
* @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 { 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 {
readonly remoteDocumentCache: RemoteDocumentCache;
readonly mutationQueue: MutationQueue;
readonly indexManager: 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.
*
* @param transaction The persistence transaction.
* @param query The query to match documents against.
* @param sinceReadTime If not set to SnapshotVersion.MIN, return only
* documents that have been read since this snapshot version (exclusive).
*/
getDocumentsMatchingQuery(transaction: PersistenceTransaction, query: Query, sinceReadTime: SnapshotVersion): PersistencePromise<DocumentMap>;
private getDocumentsMatchingDocumentQuery;
private getDocumentsMatchingCollectionGroupQuery;
private getDocumentsMatchingCollectionQuery;
private addMissingBaseDocuments;
}

View File

@ -0,0 +1,48 @@
/**
* @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 { 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, DbTimestampKey } from './indexeddb_schema';
import { TargetData } from './target_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, readTime: SnapshotVersion): DbRemoteDocument;
toDbTimestampKey(snapshotVersion: SnapshotVersion): DbTimestampKey;
fromDbTimestampKey(dbTimestampKey: DbTimestampKey): SnapshotVersion;
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 TargetData */
fromDbTarget(dbTarget: DbTarget): TargetData;
/** Encodes TargetData into a DbTarget for storage locally. */
toDbTarget(targetData: TargetData): DbTarget;
}

View File

@ -0,0 +1,306 @@
/**
* @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 { Target } from '../core/target';
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 { FirestoreError } from '../util/error';
import { LocalViewChanges } from './local_view_changes';
import { LruGarbageCollector, LruResults } from './lru_garbage_collector';
import { Persistence, PersistenceTransaction } from './persistence';
import { PersistencePromise } from './persistence_promise';
import { QueryEngine } from './query_engine';
import { ClientId } from './shared_client_state';
import { TargetData } from './target_data';
/** 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[];
}
/** The result of executing a query against the local store. */
export interface QueryResult {
readonly documents: DocumentMap;
readonly remoteKeys: DocumentKeySet;
}
/**
* 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;
private queryEngine;
/**
* 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 target to its `TargetData`. */
private targetCache;
/**
* Maps a targetID to data about its target.
*
* PORTING NOTE: We are using an immutable data structure on Web to make re-runs
* of `applyRemoteEvent()` idempotent.
*/
private targetDataByTarget;
/** Maps a target to its targetID. */
private targetIdByTarget;
/**
* The read time of the last entry processed by `getNewDocumentChanges()`.
*
* PORTING NOTE: This is only used for multi-tab synchronization.
*/
private lastDocumentChangeReadTime;
constructor(
/** Manages our in-memory or durable persistence. */
persistence: Persistence, queryEngine: QueryEngine, initialUser: User);
/** Starts the LocalStore. */
start(): Promise<void>;
/**
* 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 newTargetData should be persisted during an update of
* an active target. TargetData should always be persisted when a target is
* being released and should not call this function.
*
* While the target is active, TargetData 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 shouldPersistTargetData;
/**
* 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 target an internal ID so that its results can be pinned so
* they don't get GC'd. A target must be allocated in the local store before
* the store can be used to manage its view.
*
* Allocating an already allocated `Target` will return the existing `TargetData`
* for that `Target`.
*/
allocateTarget(target: Target): Promise<TargetData>;
/**
* Returns the TargetData as seen by the LocalStore, including updates that may
* have not yet been persisted to the TargetCache.
*/
getTargetData(transaction: PersistenceTransaction, target: Target): PersistencePromise<TargetData | null>;
/**
* Unpin all the documents associated with the given target. If
* `keepPersistedTargetData` is set to false and Eager GC enabled, the method
* directly removes the associated target data from the target cache.
*
* Releasing a non-existing `Target` is a no-op.
*/
releaseTarget(targetId: number, keepPersistedTargetData: boolean): Promise<void>;
/**
* Runs the specified query against the local store and returns the results,
* potentially taking advantage of query data from previous executions (such
* as the set of remote keys).
*
* @param usePreviousResults Whether results from previous executions can
* be used to optimize this query execution.
*/
executeQuery(query: Query, usePreviousResults: boolean): Promise<QueryResult>;
/**
* 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>;
getTarget(targetId: TargetId): Promise<Target | null>;
/**
* 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. Further invocations will return document changes since
* the point of rejection.
*/
getNewDocumentChanges(): Promise<MaybeDocumentMap>;
/**
* Reads the newest document change from persistence and forwards the internal
* synchronization marker so that calls to `getNewDocumentChanges()`
* only return changes that happened after client initialization.
*/
synchronizeLastDocumentChangeReadTime(): Promise<void>;
}
/**
* 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>;

View File

@ -0,0 +1,32 @@
/**
* @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 fromCache: boolean;
readonly addedKeys: DocumentKeySet;
readonly removedKeys: DocumentKeySet;
constructor(targetId: TargetId, fromCache: boolean, addedKeys: DocumentKeySet, removedKeys: DocumentKeySet);
static fromSnapshot(targetId: TargetId, viewSnapshot: ViewSnapshot): LocalViewChanges;
}

View File

@ -0,0 +1,124 @@
/**
* @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, TargetId } from '../core/types';
import { AsyncQueue } from '../util/async_queue';
import { SortedMap } from '../util/sorted_map';
import { LocalStore } from './local_store';
import { PersistenceTransaction } from './persistence';
import { PersistencePromise } from './persistence_promise';
import { TargetData } from './target_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 TargetCache. */
forEachTarget(txn: PersistenceTransaction, f: (target: TargetData) => 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 a map whose keys are active target ids. We do not care about the type of the
* values.
*/
export declare type ActiveTargets = SortedMap<TargetId, 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;
get 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,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 { 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;
has(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,121 @@
/**
* @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 { ActiveTargets, LruDelegate, LruGarbageCollector, LruParams } from './lru_garbage_collector';
import { ListenSequenceNumber } from '../core/types';
import { MemoryIndexManager } from './memory_index_manager';
import { MemoryRemoteDocumentCache } from './memory_remote_document_cache';
import { MemoryTargetCache } from './memory_target_cache';
import { MutationQueue } from './mutation_queue';
import { Persistence, PersistenceTransaction, PersistenceTransactionMode, PrimaryStateListener, ReferenceDelegate } from './persistence';
import { PersistencePromise } from './persistence_promise';
import { ReferenceSet } from './reference_set';
import { ClientId } from './shared_client_state';
import { TargetData } from './target_data';
/**
* 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 targetCache;
private readonly listenSequence;
private _started;
readonly referenceDelegate: MemoryLruDelegate | MemoryEagerDelegate;
static createLruPersistence(clientId: ClientId, 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>;
get started(): boolean;
getActiveClients(): Promise<ClientId[]>;
setPrimaryStateListener(primaryStateListener: PrimaryStateListener): Promise<void>;
setDatabaseDeletedListener(): void;
setNetworkEnabled(networkEnabled: boolean): void;
getIndexManager(): MemoryIndexManager;
getMutationQueue(user: User): MutationQueue;
getTargetCache(): MemoryTargetCache;
getRemoteDocumentCache(): MemoryRemoteDocumentCache;
runTransaction<T>(action: string, mode: PersistenceTransactionMode, 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 extends PersistenceTransaction {
readonly currentSequenceNumber: ListenSequenceNumber;
constructor(currentSequenceNumber: ListenSequenceNumber);
}
export declare class MemoryEagerDelegate implements ReferenceDelegate {
private readonly persistence;
private inMemoryPins;
private _orphanedDocuments;
constructor(persistence: MemoryPersistence);
private get 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, targetData: TargetData): 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 inMemoryPins;
private orphanedSequenceNumbers;
readonly garbageCollector: LruGarbageCollector;
constructor(persistence: MemoryPersistence, lruParams: LruParams);
onTransactionStarted(): void;
onTransactionCommitted(txn: PersistenceTransaction): PersistencePromise<void>;
forEachTarget(txn: PersistenceTransaction, f: (q: TargetData) => 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, targetData: TargetData): 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,71 @@
/**
* @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 { SnapshotVersion } from '../core/snapshot_version';
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;
/** Underlying cache of documents and their read times. */
private docs;
/** Size of all cached documents. */
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, sinceReadTime: SnapshotVersion): PersistencePromise<DocumentMap>;
forEachDocumentKey(transaction: PersistenceTransaction, f: (key: DocumentKey) => PersistencePromise<void>): PersistencePromise<void>;
getNewDocumentChanges(transaction: PersistenceTransaction, sinceReadTime: SnapshotVersion): PersistencePromise<{
changedDocs: MaybeDocumentMap;
readTime: SnapshotVersion;
}>;
getLastReadTime(transaction: PersistenceTransaction): PersistencePromise<SnapshotVersion>;
newChangeBuffer(options?: {
trackRemovals: boolean;
}): 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,66 @@
/**
* @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 { 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 { TargetCache } from './target_cache';
import { TargetData } from './target_data';
import { Target } from '../core/target';
export declare class MemoryTargetCache implements TargetCache {
private readonly persistence;
/**
* Maps a target to the data about that target
*/
private targets;
/** 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);
forEachTarget(txn: PersistenceTransaction, f: (q: TargetData) => 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 saveTargetData;
addTargetData(transaction: PersistenceTransaction, targetData: TargetData): PersistencePromise<void>;
updateTargetData(transaction: PersistenceTransaction, targetData: TargetData): PersistencePromise<void>;
removeTargetData(transaction: PersistenceTransaction, targetData: TargetData): PersistencePromise<void>;
removeTargets(transaction: PersistenceTransaction, upperBound: ListenSequenceNumber, activeTargetIds: ActiveTargets): PersistencePromise<number>;
getTargetCount(transaction: PersistenceTransaction): PersistencePromise<number>;
getTargetData(transaction: PersistenceTransaction, target: Target): PersistencePromise<TargetData | null>;
getTargetDataForTarget(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,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,223 @@
/**
* @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 { TargetCache } from './target_cache';
import { ReferenceSet } from './reference_set';
import { RemoteDocumentCache } from './remote_document_cache';
import { ClientId } from './shared_client_state';
import { TargetData } from './target_data';
export declare const PRIMARY_LEASE_LOST_ERROR_MSG: string;
/**
* A base class representing a persistence transaction, encapsulating both the
* transaction's sequence numbers as well as a list of onCommitted listeners.
*
* 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 {
private readonly onCommittedListeners;
abstract readonly currentSequenceNumber: ListenSequenceNumber;
addOnCommittedListener(listener: () => void): void;
raiseOnCommittedEvent(): void;
}
/** The different modes supported by `IndexedDbPersistence.runTransaction()`. */
export declare type PersistenceTransactionMode = 'readonly' | 'readwrite' | 'readwrite-primary' | 'readonly-idempotent' | 'readwrite-idempotent' | 'readwrite-primary-idempotent';
/**
* 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, targetData: TargetData): 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 TargetCache representing the persisted cache of targets.
*
* 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.
*/
getTargetCache(): TargetCache;
/**
* 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: PersistenceTransactionMode, 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,32 @@
/**
* @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 { SnapshotVersion } from '../core/snapshot_version';
import { Query } from '../core/query';
import { DocumentKeySet, DocumentMap } from '../model/collections';
import { LocalDocumentsView } from './local_documents_view';
import { PersistenceTransaction } from './persistence';
import { PersistencePromise } from './persistence_promise';
/**
* Represents a query engine capable of performing queries over the local
* document cache. You must call `setLocalDocumentsView()` before using.
*/
export interface QueryEngine {
/** Sets the document view to query against. */
setLocalDocumentsView(localDocuments: LocalDocumentsView): void;
/** Returns all local documents matching the specified query. */
getDocumentsMatchingQuery(transaction: PersistenceTransaction, query: Query, lastLimboFreeSnapshotVersion: SnapshotVersion, remoteKeys: DocumentKeySet): PersistencePromise<DocumentMap>;
}

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,95 @@
/**
* @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';
import { SnapshotVersion } from '../core/snapshot_version';
/**
* 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.
* @param sinceReadTime If not set to SnapshotVersion.MIN, return only
* documents that have been read since this snapshot version (exclusive).
* @return The set of matching documents.
*/
getDocumentsMatchingQuery(transaction: PersistenceTransaction, query: Query, sinceReadTime: SnapshotVersion): PersistencePromise<DocumentMap>;
/**
* Returns the set of documents that have changed since the specified read
* time.
*/
getNewDocumentChanges(transaction: PersistenceTransaction, sinceReadTime: SnapshotVersion): PersistencePromise<{
changedDocs: MaybeDocumentMap;
readTime: SnapshotVersion;
}>;
/**
* Returns the read time of the most recently read document in the cache, or
* SnapshotVersion.MIN if not available.
*/
getLastReadTime(transaction: PersistenceTransaction): PersistencePromise<SnapshotVersion>;
/**
* 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.
*
* @param options.trackRemovals Whether to create sentinel entries for
* removed documents, which allows removals to be tracked by
* `getNewDocumentChanges()`.
*/
newChangeBuffer(options?: {
trackRemovals: boolean;
}): 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,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 { 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';
import { SnapshotVersion } from '../core/snapshot_version';
/**
* 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 _readTime;
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>;
protected set readTime(value: SnapshotVersion);
protected get readTime(): SnapshotVersion;
/**
* 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, readTime: SnapshotVersion): 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, readTime?: SnapshotVersion): 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,301 @@
/**
* @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).
*
* If the target id is already associated with local client, the method simply
* returns its `QueryTargetState`.
*/
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;
}
/**
* 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 get localClientState();
private persistClientState;
private persistMutationState;
private removeMutationState;
private persistOnlineState;
private persistQueryTargetState;
/**
* 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,82 @@
/**
* @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 { BatchId, MutationBatchState, TargetId } from '../core/types';
import { QueryTargetState } from './shared_client_state_syncer';
import { ClientId } from './shared_client_state';
import { User } from '../auth/user';
export declare const CLIENT_STATE_KEY_PREFIX = "firestore_clients";
/** Assembles the key for a client state in WebStorage */
export declare function createWebStorageClientStateKey(persistenceKey: string, clientId: ClientId): string;
/**
* The JSON representation of a clients's metadata as used during WebStorage
* serialization. The ClientId is omitted here as it is encoded as part of the
* key.
*/
export interface ClientStateSchema {
activeTargetIds: number[];
updateTimeMs: number;
}
export declare const MUTATION_BATCH_KEY_PREFIX = "firestore_mutations";
/** Assembles the key for a mutation batch in WebStorage */
export declare function createWebStorageMutationBatchKey(persistenceKey: string, user: User, batchId: BatchId): string;
/**
* The JSON representation of a mutation batch's metadata as used during
* WebStorage serialization. The UserId and BatchId is omitted as it is
* encoded as part of the key.
*/
export interface MutationMetadataSchema {
state: MutationBatchState;
error?: {
code: string;
message: string;
};
updateTimeMs: number;
}
export declare const QUERY_TARGET_KEY_PREFIX = "firestore_targets";
/** Assembles the key for a query state in WebStorage */
export declare function createWebStorageQueryTargetMetadataKey(persistenceKey: string, targetId: TargetId): string;
/**
* The JSON representation of a query target's state as used during WebStorage
* serialization. The TargetId is omitted as it is encoded as part of the key.
*/
export interface QueryTargetStateSchema {
state: QueryTargetState;
error?: {
code: string;
message: string;
};
updateTimeMs: number;
}
export declare const ONLINE_STATE_KEY_PREFIX = "firestore_online_state";
/** Assembles the key for the online state of the primary tab. */
export declare function createWebStorageOnlineStateKey(persistenceKey: string): string;
/**
* 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;
}
export declare const SEQUENCE_NUMBER_KEY_PREFIX = "firestore_sequence_number";
/** Assembles the key for the current sequence number. */
export declare function createWebStorageSequenceNumberKey(persistenceKey: string): string;

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,209 @@
/**
* @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';
declare type SimpleDbTransactionMode = 'readonly' | 'readwrite' | 'readonly-idempotent' | 'readwrite-idempotent';
export interface SimpleDbSchemaConverter {
createOrUpgrade(db: IDBDatabase, txn: IDBTransaction, 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;
/**
* Returns true if the backing IndexedDB store is the Node IndexedDBShim
* (see https://github.com/axemclion/IndexedDBShim).
*/
static isMockPersistence(): 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: SimpleDbTransactionMode, 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);
get isDone(): boolean;
get skipToKey(): IDBValidKey | null;
set cursor(value: 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);
get 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;
}
export {};

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 { SnapshotVersion } from '../core/snapshot_version';
import { Query } from '../core/query';
import { DocumentKeySet, DocumentMap } from '../model/collections';
import { LocalDocumentsView } from './local_documents_view';
import { QueryEngine } from './query_engine';
import { PersistenceTransaction } from './persistence';
import { PersistencePromise } from './persistence_promise';
/**
* A naive implementation of QueryEngine that just loads all the documents in
* the queried collection and then filters them in memory.
*/
export declare class SimpleQueryEngine implements QueryEngine {
private localDocumentsView;
setLocalDocumentsView(localDocuments: LocalDocumentsView): void;
/** Returns all local documents matching the specified query. */
getDocumentsMatchingQuery(transaction: PersistenceTransaction, query: Query, lastLimboFreeSnapshotVersion: SnapshotVersion, remoteKeys: DocumentKeySet): PersistencePromise<DocumentMap>;
}

View File

@ -0,0 +1,138 @@
/**
* @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 { 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 { TargetData } from './target_data';
import { Target } from '../core/target';
/**
* Represents cached targets received from the remote backend.
*
* The cache is keyed by `Target` and entries in the cache are `TargetData`
* instances.
*/
export interface TargetCache {
/**
* 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 `TargetData` that we have cached.
*/
forEachTarget(txn: PersistenceTransaction, f: (q: TargetData) => 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 `targetData.target`. The key must not already
* exist in the cache.
*
* @param targetData A TargetData instance to put in the cache.
*/
addTargetData(transaction: PersistenceTransaction, targetData: TargetData): PersistencePromise<void>;
/**
* Updates an entry in the cache.
*
* The cache key is extracted from `targetData.target`. The entry must already
* exist in the cache, and it will be replaced.
* @param {TargetData} targetData The TargetData to be replaced into the cache.
*/
updateTargetData(transaction: PersistenceTransaction, targetData: TargetData): PersistencePromise<void>;
/**
* Removes the cached entry for the given target data. It is an error to remove
* a target data that does not exist.
*
* Multi-Tab Note: This operation should only be called by the primary client.
*/
removeTargetData(transaction: PersistenceTransaction, targetData: TargetData): PersistencePromise<void>;
/**
* The number of targets currently in the cache.
*/
getTargetCount(transaction: PersistenceTransaction): PersistencePromise<number>;
/**
* Looks up a TargetData entry by target.
*
* @param target The query target corresponding to the entry to look up.
* @return The cached TargetData entry, or null if the cache has no entry for
* the target.
*/
getTargetData(transaction: PersistenceTransaction, target: Target): PersistencePromise<TargetData | null>;
/**
* Looks up a TargetData entry by target ID.
*
* @param targetId The target ID of the TargetData entry to look up.
* @return The cached TargetData entry, or null if the cache has no entry for
* the target.
*/
getTargetDataForTarget(txn: PersistenceTransaction, targetId: TargetId): PersistencePromise<TargetData | 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,105 @@
/**
* @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 { Target } from '../core/target';
import { ListenSequenceNumber, ProtoByteString, TargetId } from '../core/types';
/** An enumeration of the different purposes we have for targets. */
export declare enum TargetPurpose {
/** A regular, normal query target. */
Listen = 0,
/**
* The query target was used to refill a query after an existence filter mismatch.
*/
ExistenceFilterMismatch = 1,
/** The query target was used to resolve a limbo document. */
LimboResolution = 2
}
/**
* An immutable set of metadata that the local store tracks for each target.
*/
export declare class TargetData {
/** The target being listened to. */
readonly target: Target;
/**
* The target ID to which the target corresponds; Assigned by the
* LocalStore for user listens and by the SyncEngine for limbo watches.
*/
readonly targetId: TargetId;
/** The purpose of the target. */
readonly purpose: TargetPurpose;
/**
* The sequence number of the last transaction during which this target data
* was modified.
*/
readonly sequenceNumber: ListenSequenceNumber;
/** The latest snapshot version seen for this target. */
readonly snapshotVersion: SnapshotVersion;
/**
* The maximum snapshot version at which the associated view
* contained no limbo documents.
*/
readonly lastLimboFreeSnapshotVersion: SnapshotVersion;
/**
* An opaque, server-assigned token that allows watching a target to be
* resumed after disconnecting without retransmitting all the data that
* matches the target. The resume token essentially identifies a point in
* time from which the server should resume sending results.
*/
readonly resumeToken: ProtoByteString;
constructor(
/** The target being listened to. */
target: Target,
/**
* The target ID to which the target corresponds; Assigned by the
* LocalStore for user listens and by the SyncEngine for limbo watches.
*/
targetId: TargetId,
/** The purpose of the target. */
purpose: TargetPurpose,
/**
* The sequence number of the last transaction during which this target data
* was modified.
*/
sequenceNumber: ListenSequenceNumber,
/** The latest snapshot version seen for this target. */
snapshotVersion?: SnapshotVersion,
/**
* The maximum snapshot version at which the associated view
* contained no limbo documents.
*/
lastLimboFreeSnapshotVersion?: SnapshotVersion,
/**
* An opaque, server-assigned token that allows watching a target to be
* resumed after disconnecting without retransmitting all the data that
* matches the target. The resume token essentially identifies a point in
* time from which the server should resume sending results.
*/
resumeToken?: ProtoByteString);
/** Creates a new target data instance with an updated sequence number. */
withSequenceNumber(sequenceNumber: number): TargetData;
/**
* Creates a new target data instance with an updated resume token and
* snapshot version.
*/
withResumeToken(resumeToken: ProtoByteString, snapshotVersion: SnapshotVersion): TargetData;
/**
* Creates a new target data instance with an updated last limbo free
* snapshot version number.
*/
withLastLimboFreeSnapshotVersion(lastLimboFreeSnapshotVersion: SnapshotVersion): TargetData;
isEqual(other: TargetData): boolean;
}

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 get 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;
get 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;
get 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;
get 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;
get 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,248 @@
/**
* @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;
/**
* Returns an approximate (and wildly inaccurate) in-memory size for the field
* value.
*
* The memory size takes into account only the actual user data as it resides
* in memory and ignores object overhead.
*/
abstract approximateByteSize(): 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;
approximateByteSize(): 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;
approximateByteSize(): 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;
approximateByteSize(): 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;
approximateByteSize(): 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;
approximateByteSize(): 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;
approximateByteSize(): number;
}
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;
approximateByteSize(): 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;
approximateByteSize(): 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;
approximateByteSize(): 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;
approximateByteSize(): number;
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;
approximateByteSize(): number;
toString(): string;
}

View File

@ -0,0 +1,363 @@
/**
* @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,
Verify = 4
}
/**
* 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. */
get 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 its 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 value 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;
}
/**
* A mutation that verifies the existence of the document at the given key with
* the provided precondition.
*
* The `verify` operation is only used in Transactions, and this class serves
* primarily to facilitate serialization into protos.
*/
export declare class VerifyMutation 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;
get 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,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,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();
get document(): Document | null;
get 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;
get 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,260 @@
// 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;
// The name of a document on which to verify the `current_document`
// precondition.
// This only requires read access to the document.
string verify = 5;
// 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;
}

View File

@ -0,0 +1,92 @@
// 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.
syntax = "proto3";
package google.rpc;
import "google/protobuf/any.proto";
option go_package = "google.golang.org/genproto/googleapis/rpc/status;status";
option java_multiple_files = true;
option java_outer_classname = "StatusProto";
option java_package = "com.google.rpc";
option objc_class_prefix = "RPC";
// The `Status` type defines a logical error model that is suitable for different
// programming environments, including REST APIs and RPC APIs. It is used by
// [gRPC](https://github.com/grpc). The error model is designed to be:
//
// - Simple to use and understand for most users
// - Flexible enough to meet unexpected needs
//
// # Overview
//
// The `Status` message contains three pieces of data: error code, error message,
// and error details. The error code should be an enum value of
// [google.rpc.Code][google.rpc.Code], but it may accept additional error codes if needed. The
// error message should be a developer-facing English message that helps
// developers *understand* and *resolve* the error. If a localized user-facing
// error message is needed, put the localized message in the error details or
// localize it in the client. The optional error details may contain arbitrary
// information about the error. There is a predefined set of error detail types
// in the package `google.rpc` that can be used for common error conditions.
//
// # Language mapping
//
// The `Status` message is the logical representation of the error model, but it
// is not necessarily the actual wire format. When the `Status` message is
// exposed in different client libraries and different wire protocols, it can be
// mapped differently. For example, it will likely be mapped to some exceptions
// in Java, but more likely mapped to some error codes in C.
//
// # Other uses
//
// The error model and the `Status` message can be used in a variety of
// environments, either with or without APIs, to provide a
// consistent developer experience across different environments.
//
// Example uses of this error model include:
//
// - Partial errors. If a service needs to return partial errors to the client,
// it may embed the `Status` in the normal response to indicate the partial
// errors.
//
// - Workflow errors. A typical workflow has multiple steps. Each step may
// have a `Status` message for error reporting.
//
// - Batch operations. If a client uses batch request and batch response, the
// `Status` message should be used directly inside batch response, one for
// each error sub-response.
//
// - Asynchronous operations. If an API call embeds asynchronous operation
// results in its response, the status of those operations should be
// represented directly using the `Status` message.
//
// - Logging. If some API errors are stored in logs, the message `Status` could
// be used directly after any stripping needed for security/privacy reasons.
message Status {
// The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code].
int32 code = 1;
// A developer-facing error message, which should be in English. Any
// user-facing error message should be localized and sent in the
// [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client.
string message = 2;
// A list of messages that carry the error details. There is a common set of
// message types for APIs to use.
repeated google.protobuf.Any details = 3;
}

View File

@ -0,0 +1,71 @@
// Copyright 2016 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.type;
option go_package = "google.golang.org/genproto/googleapis/type/latlng;latlng";
option java_multiple_files = true;
option java_outer_classname = "LatLngProto";
option java_package = "com.google.type";
option objc_class_prefix = "GTP";
// An object representing a latitude/longitude pair. This is expressed as a pair
// of doubles representing degrees latitude and degrees longitude. Unless
// specified otherwise, this must conform to the
// <a href="http://www.unoosa.org/pdf/icg/2012/template/WGS_84.pdf">WGS84
// standard</a>. Values must be within normalized ranges.
//
// Example of normalization code in Python:
//
// def NormalizeLongitude(longitude):
// """Wraps decimal degrees longitude to [-180.0, 180.0]."""
// q, r = divmod(longitude, 360.0)
// if r > 180.0 or (r == 180.0 and q <= -1.0):
// return r - 360.0
// return r
//
// def NormalizeLatLng(latitude, longitude):
// """Wraps decimal degrees latitude and longitude to
// [-90.0, 90.0] and [-180.0, 180.0], respectively."""
// r = latitude % 360.0
// if r <= 90.0:
// return r, NormalizeLongitude(longitude)
// elif r >= 270.0:
// return r - 360, NormalizeLongitude(longitude)
// else:
// return 180 - r, NormalizeLongitude(longitude + 180.0)
//
// assert 180.0 == NormalizeLongitude(180.0)
// assert -180.0 == NormalizeLongitude(-180.0)
// assert -179.0 == NormalizeLongitude(181.0)
// assert (0.0, 0.0) == NormalizeLatLng(360.0, 0.0)
// assert (0.0, 0.0) == NormalizeLatLng(-360.0, 0.0)
// assert (85.0, 180.0) == NormalizeLatLng(95.0, 0.0)
// assert (-85.0, -170.0) == NormalizeLatLng(-95.0, 10.0)
// assert (90.0, 10.0) == NormalizeLatLng(90.0, 10.0)
// assert (-90.0, -10.0) == NormalizeLatLng(-90.0, -10.0)
// assert (0.0, -170.0) == NormalizeLatLng(-180.0, 10.0)
// assert (0.0, -170.0) == NormalizeLatLng(180.0, 10.0)
// assert (-90.0, 10.0) == NormalizeLatLng(270.0, 10.0)
// assert (90.0, 10.0) == NormalizeLatLng(-270.0, 10.0)
message LatLng {
// The latitude in degrees. It must be in the range [-90.0, +90.0].
double latitude = 1;
// The longitude in degrees. It must be in the range [-180.0, +180.0].
double longitude = 2;
}

View File

@ -0,0 +1,61 @@
#!/bin/bash
# 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.
set -euo pipefail
IFS=$'\n\t'
# Variables
PROTOS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
WORK_DIR=`mktemp -d`
# deletes the temp directory on exit
function cleanup {
rm -rf "$WORK_DIR"
echo "Deleted temp working directory $WORK_DIR"
}
# register the cleanup function to be called on the EXIT signal
trap cleanup EXIT
# Enter work dir
pushd "$WORK_DIR"
# Clone necessary git repos.
git clone https://github.com/googleapis/googleapis.git
git clone https://github.com/google/protobuf.git
# Copy necessary protos.
mkdir -p "${PROTOS_DIR}/google/api"
cp googleapis/google/api/{annotations.proto,http.proto} \
"${PROTOS_DIR}/google/api/"
mkdir -p "${PROTOS_DIR}/google/firestore/v1"
cp googleapis/google/firestore/v1/*.proto \
"${PROTOS_DIR}/google/firestore/v1/"
mkdir -p "${PROTOS_DIR}/google/rpc"
cp googleapis/google/rpc/status.proto \
"${PROTOS_DIR}/google/rpc/"
mkdir -p "${PROTOS_DIR}/google/type"
cp googleapis/google/type/latlng.proto \
"${PROTOS_DIR}/google/type/"
mkdir -p "${PROTOS_DIR}/google/protobuf"
cp protobuf/src/google/protobuf/{any,empty,struct,timestamp,wrappers,descriptor}.proto \
"${PROTOS_DIR}/google/protobuf/"
popd

View File

@ -0,0 +1,105 @@
/**
* @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 { AsyncQueue, TimerId } from '../util/async_queue';
/**
* A helper for running delayed tasks following an exponential backoff curve
* between attempts.
*
* Each delay is made up of a "base" delay which follows the exponential
* backoff curve, and a +/- 50% "jitter" that is calculated and added to the
* base delay. This prevents clients from accidentally synchronizing their
* delays causing spikes of load to the backend.
*/
export declare class ExponentialBackoff {
/**
* The AsyncQueue to run backoff operations on.
*/
private readonly queue;
/**
* The ID to use when scheduling backoff operations on the AsyncQueue.
*/
private readonly timerId;
/**
* The initial delay (used as the base delay on the first retry attempt).
* Note that jitter will still be applied, so the actual delay could be as
* little as 0.5*initialDelayMs.
*/
private readonly initialDelayMs;
/**
* The multiplier to use to determine the extended base delay after each
* attempt.
*/
private readonly backoffFactor;
/**
* The maximum base delay after which no further backoff is performed.
* Note that jitter will still be applied, so the actual delay could be as
* much as 1.5*maxDelayMs.
*/
private readonly maxDelayMs;
private currentBaseMs;
private timerPromise;
/** The last backoff attempt, as epoch milliseconds. */
private lastAttemptTime;
constructor(
/**
* The AsyncQueue to run backoff operations on.
*/
queue: AsyncQueue,
/**
* The ID to use when scheduling backoff operations on the AsyncQueue.
*/
timerId: TimerId,
/**
* The initial delay (used as the base delay on the first retry attempt).
* Note that jitter will still be applied, so the actual delay could be as
* little as 0.5*initialDelayMs.
*/
initialDelayMs?: number,
/**
* The multiplier to use to determine the extended base delay after each
* attempt.
*/
backoffFactor?: number,
/**
* The maximum base delay after which no further backoff is performed.
* Note that jitter will still be applied, so the actual delay could be as
* much as 1.5*maxDelayMs.
*/
maxDelayMs?: number);
/**
* Resets the backoff delay.
*
* The very next backoffAndWait() will have no delay. If it is called again
* (i.e. due to an error), initialDelayMs (plus jitter) will be used, and
* subsequent ones will increase according to the backoffFactor.
*/
reset(): void;
/**
* Resets the backoff delay to the maximum delay (e.g. for use after a
* RESOURCE_EXHAUSTED error).
*/
resetToMax(): void;
/**
* Returns a promise that resolves after currentDelayMs, and increases the
* delay for any subsequent attempts. If there was a pending backoff operation
* already, it will be canceled.
*/
backoffAndRun(op: () => Promise<void>): void;
cancel(): void;
/** Returns a random value in the range [-currentBaseMs/2, currentBaseMs/2] */
private jitterDelayMs;
}

View File

@ -0,0 +1,77 @@
/**
* @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 { FirestoreError } from '../util/error';
/**
* A connected RPC interface to a remote Datastore.
*
* Responsible for maintaining a connection to the backend (and informing when
* that connection state changes via onConnectionStateChange) and sending RPCs
* when possible.
*
* The Connection is not responsible for queueing RPCs to the backend when
* the connection is down.
*
* RPC messages are expected to be JavaScript objects representing the JSON that
* would be sent over the REST/JSON API to Datastore or used as input to
* creating the equivalent protocol buffers for GRPC.
*/
export interface Connection {
/**
* Invokes an RPC by name, given a request message as a JavaScript object
* representing the JSON to send.
*
* @param rpcName the name of the RPC to invoke
* @param request the Raw JSON object encoding of the request message
* @param token the Token to use for the RPC.
* @return a Promise containing the JSON object encoding of the response
*/
invokeRPC<Req, Resp>(rpcName: string, request: Req, token: Token | null): Promise<Resp>;
/**
* Invokes a streaming RPC by name, given a request message as a JavaScript
* object representing the JSON to send. The responses will be consumed to
* completion and then returned as an array.
*
* @param rpcName the name of the RPC to invoke
* @param request the Raw JSON object encoding of the request message
* @param token the Token to use for the RPC.
* @return a Promise containing an array with the JSON object encodings of the
* responses
*/
invokeStreamingRPC<Req, Resp>(rpcName: string, request: Req, token: Token | null): Promise<Resp[]>;
/**
* Opens a stream to the given stream RPC endpoint. Returns a stream which
* will try to open itself.
* @param rpcName the name of the RPC to open the stream on
* @param token the Token to use for the RPC.
*/
openStream<Req, Resp>(rpcName: string, token: Token | null): Stream<Req, Resp>;
}
/**
* A bidirectional stream that can be used to send an receive messages.
*
* A stream can be closed locally with close() or can be closed remotely or
* through network errors. onClose is guaranteed to be called. onOpen will only
* be called if the stream successfully established a connection.
*/
export interface Stream<I, O> {
onOpen(callback: () => void): void;
onClose(callback: (err?: FirestoreError) => void): void;
onMessage(callback: (msg: O) => void): void;
send(msg: I): void;
close(): void;
}

View File

@ -0,0 +1,47 @@
/**
* @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.
*/
/**
* The set of network states is deliberately simplified -- we only care about
* states such that transition between them should break currently
* established connections.
*/
export declare const enum NetworkStatus {
AVAILABLE = 0,
UNAVAILABLE = 1
}
export declare type ConnectivityMonitorCallback = (status: NetworkStatus) => void;
/**
* A base class for monitoring changes in network connectivity; it is expected
* that each platform will have its own system-dependent implementation.
*/
export interface ConnectivityMonitor {
/**
* Adds a callback to be called when connectivity changes.
*
* Callbacks are not made on the initial state of connectivity, since this
* monitor is primarily used for resetting backoff in the remote store when
* connectivity changes. As such, the initial connectivity state is
* irrelevant here.
*/
addCallback(callback: ConnectivityMonitorCallback): void;
/**
* Stops monitoring connectivity. After this call completes, no further
* callbacks will be triggered. After shutdown() is called, no further calls
* are allowed on this instance.
*/
shutdown(): void;
}

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