mirror of
https://github.com/hanzoai/firebase-js-sdk.git
synced 2026-09-24 16:59:10 +00:00
Feat(Firestore) JSON serialization of types to improve SSR support. (#8926)
Support the ability to resume `onSnapshot` listeners in the CSR phase based on serialized `DataSnapshot`s and `QuerySnapshot`s built in the SSR phase. Allow Firestore result types to be serialized with `toJSON` and then deserialized with `fromJSON` methods on the objects. `DocumentSnapshot` and `QuerySnapshot` deserialization methods will be standalone, tree-shakable functions `dataSnapshotFromJSON` and `querySnapshotFromJSON`.
This commit is contained in:
@@ -68,9 +68,11 @@ export function average(field: string | FieldPath): AggregateField<number | null
|
||||
// @public
|
||||
export class Bytes {
|
||||
static fromBase64String(base64: string): Bytes;
|
||||
static fromJSON(json: object): Bytes;
|
||||
static fromUint8Array(array: Uint8Array): Bytes;
|
||||
isEqual(other: Bytes): boolean;
|
||||
toBase64(): string;
|
||||
toJSON(): object;
|
||||
toString(): string;
|
||||
toUint8Array(): Uint8Array;
|
||||
}
|
||||
@@ -135,9 +137,12 @@ export function documentId(): FieldPath;
|
||||
export class DocumentReference<AppModelType = DocumentData, DbModelType extends DocumentData = DocumentData> {
|
||||
readonly converter: FirestoreDataConverter<AppModelType, DbModelType> | null;
|
||||
readonly firestore: Firestore;
|
||||
static fromJSON(firestore: Firestore, json: object): DocumentReference;
|
||||
static fromJSON<NewAppModelType = DocumentData, NewDbModelType extends DocumentData = DocumentData>(firestore: Firestore, json: object, converter: FirestoreDataConverter<NewAppModelType, NewDbModelType>): DocumentReference<NewAppModelType, NewDbModelType>;
|
||||
get id(): string;
|
||||
get parent(): CollectionReference<AppModelType, DbModelType>;
|
||||
get path(): string;
|
||||
toJSON(): object;
|
||||
readonly type = "document";
|
||||
withConverter<NewAppModelType, NewDbModelType extends DocumentData = DocumentData>(converter: FirestoreDataConverter<NewAppModelType, NewDbModelType>): DocumentReference<NewAppModelType, NewDbModelType>;
|
||||
withConverter(converter: null): DocumentReference<DocumentData, DocumentData>;
|
||||
@@ -205,12 +210,14 @@ export type FirestoreErrorCode = 'cancelled' | 'unknown' | 'invalid-argument' |
|
||||
// @public
|
||||
export class GeoPoint {
|
||||
constructor(latitude: number, longitude: number);
|
||||
static fromJSON(json: object): GeoPoint;
|
||||
isEqual(other: GeoPoint): boolean;
|
||||
get latitude(): number;
|
||||
get longitude(): number;
|
||||
toJSON(): {
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
type: string;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -416,6 +423,7 @@ export class Timestamp {
|
||||
seconds: number,
|
||||
nanoseconds: number);
|
||||
static fromDate(date: Date): Timestamp;
|
||||
static fromJSON(json: object): Timestamp;
|
||||
static fromMillis(milliseconds: number): Timestamp;
|
||||
isEqual(other: Timestamp): boolean;
|
||||
readonly nanoseconds: number;
|
||||
@@ -425,6 +433,7 @@ export class Timestamp {
|
||||
toJSON(): {
|
||||
seconds: number;
|
||||
nanoseconds: number;
|
||||
type: string;
|
||||
};
|
||||
toMillis(): number;
|
||||
toString(): string;
|
||||
@@ -466,8 +475,10 @@ export function vector(values?: number[]): VectorValue;
|
||||
// @public
|
||||
export class VectorValue {
|
||||
/* Excluded from this release type: __constructor */
|
||||
static fromJSON(json: object): VectorValue;
|
||||
isEqual(other: VectorValue): boolean;
|
||||
toArray(): number[];
|
||||
toJSON(): object;
|
||||
}
|
||||
|
||||
// @public
|
||||
|
||||
@@ -68,9 +68,11 @@ export function average(field: string | FieldPath): AggregateField<number | null
|
||||
// @public
|
||||
export class Bytes {
|
||||
static fromBase64String(base64: string): Bytes;
|
||||
static fromJSON(json: object): Bytes;
|
||||
static fromUint8Array(array: Uint8Array): Bytes;
|
||||
isEqual(other: Bytes): boolean;
|
||||
toBase64(): string;
|
||||
toJSON(): object;
|
||||
toString(): string;
|
||||
toUint8Array(): Uint8Array;
|
||||
}
|
||||
@@ -161,9 +163,12 @@ export function documentId(): FieldPath;
|
||||
export class DocumentReference<AppModelType = DocumentData, DbModelType extends DocumentData = DocumentData> {
|
||||
readonly converter: FirestoreDataConverter<AppModelType, DbModelType> | null;
|
||||
readonly firestore: Firestore;
|
||||
static fromJSON(firestore: Firestore, json: object): DocumentReference;
|
||||
static fromJSON<NewAppModelType = DocumentData, NewDbModelType extends DocumentData = DocumentData>(firestore: Firestore, json: object, converter: FirestoreDataConverter<NewAppModelType, NewDbModelType>): DocumentReference<NewAppModelType, NewDbModelType>;
|
||||
get id(): string;
|
||||
get parent(): CollectionReference<AppModelType, DbModelType>;
|
||||
get path(): string;
|
||||
toJSON(): object;
|
||||
readonly type = "document";
|
||||
withConverter<NewAppModelType, NewDbModelType extends DocumentData = DocumentData>(converter: FirestoreDataConverter<NewAppModelType, NewDbModelType>): DocumentReference<NewAppModelType, NewDbModelType>;
|
||||
withConverter(converter: null): DocumentReference<DocumentData, DocumentData>;
|
||||
@@ -178,8 +183,15 @@ export class DocumentSnapshot<AppModelType = DocumentData, DbModelType extends D
|
||||
get id(): string;
|
||||
readonly metadata: SnapshotMetadata;
|
||||
get ref(): DocumentReference<AppModelType, DbModelType>;
|
||||
toJSON(): object;
|
||||
}
|
||||
|
||||
// @public
|
||||
export function documentSnapshotFromJSON(db: Firestore, json: object): DocumentSnapshot;
|
||||
|
||||
// @public
|
||||
export function documentSnapshotFromJSON<AppModelType, DbModelType extends DocumentData = DocumentData>(db: Firestore, json: object, converter: FirestoreDataConverter<AppModelType, DbModelType>): DocumentSnapshot<AppModelType, DbModelType>;
|
||||
|
||||
export { EmulatorMockTokenOptions }
|
||||
|
||||
// @public @deprecated
|
||||
@@ -264,12 +276,14 @@ export interface FirestoreSettings {
|
||||
// @public
|
||||
export class GeoPoint {
|
||||
constructor(latitude: number, longitude: number);
|
||||
static fromJSON(json: object): GeoPoint;
|
||||
isEqual(other: GeoPoint): boolean;
|
||||
get latitude(): number;
|
||||
get longitude(): number;
|
||||
toJSON(): {
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
type: string;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -459,6 +473,46 @@ export function onSnapshot<AppModelType, DbModelType extends DocumentData>(query
|
||||
// @public
|
||||
export function onSnapshot<AppModelType, DbModelType extends DocumentData>(query: Query<AppModelType, DbModelType>, options: SnapshotListenOptions, onNext: (snapshot: QuerySnapshot<AppModelType, DbModelType>) => void, onError?: (error: FirestoreError) => void, onCompletion?: () => void): Unsubscribe;
|
||||
|
||||
// @public
|
||||
export function onSnapshotResume<AppModelType, DbModelType extends DocumentData>(firestore: Firestore, snapshotJson: object, onNext: (snapshot: QuerySnapshot<AppModelType, DbModelType>) => void, onError?: (error: FirestoreError) => void, onCompletion?: () => void, converter?: FirestoreDataConverter<DbModelType>): Unsubscribe;
|
||||
|
||||
// @public
|
||||
export function onSnapshotResume<AppModelType, DbModelType extends DocumentData>(firestore: Firestore, snapshotJson: object, onNext: (snapshot: DocumentSnapshot<AppModelType, DbModelType>) => void, onError?: (error: FirestoreError) => void, onCompletion?: () => void, converter?: FirestoreDataConverter<DbModelType>): Unsubscribe;
|
||||
|
||||
// @public
|
||||
export function onSnapshotResume<AppModelType, DbModelType extends DocumentData>(firestore: Firestore, snapshotJson: object, options: SnapshotListenOptions, onNext: (snapshot: QuerySnapshot<AppModelType, DbModelType>) => void, onError?: (error: FirestoreError) => void, onCompletion?: () => void, converter?: FirestoreDataConverter<DbModelType>): Unsubscribe;
|
||||
|
||||
// @public
|
||||
export function onSnapshotResume<AppModelType, DbModelType extends DocumentData>(firestore: Firestore, snapshotJson: object, options: SnapshotListenOptions, onNext: (snapshot: DocumentSnapshot<AppModelType, DbModelType>) => void, onError?: (error: FirestoreError) => void, onCompletion?: () => void, converter?: FirestoreDataConverter<DbModelType>): Unsubscribe;
|
||||
|
||||
// @public
|
||||
export function onSnapshotResume<AppModelType, DbModelType extends DocumentData>(firestore: Firestore, snapshotJson: object, observer: {
|
||||
next: (snapshot: QuerySnapshot<AppModelType, DbModelType>) => void;
|
||||
error?: (error: FirestoreError) => void;
|
||||
complete?: () => void;
|
||||
}, converter?: FirestoreDataConverter<DbModelType>): Unsubscribe;
|
||||
|
||||
// @public
|
||||
export function onSnapshotResume<AppModelType, DbModelType extends DocumentData>(firestore: Firestore, snapshotJson: object, observer: {
|
||||
next: (snapshot: DocumentSnapshot<AppModelType, DbModelType>) => void;
|
||||
error?: (error: FirestoreError) => void;
|
||||
complete?: () => void;
|
||||
}, converter?: FirestoreDataConverter<DbModelType>): Unsubscribe;
|
||||
|
||||
// @public
|
||||
export function onSnapshotResume<AppModelType, DbModelType extends DocumentData>(firestore: Firestore, snapshotJson: object, options: SnapshotListenOptions, observer: {
|
||||
next: (snapshot: QuerySnapshot<AppModelType, DbModelType>) => void;
|
||||
error?: (error: FirestoreError) => void;
|
||||
complete?: () => void;
|
||||
}, converter?: FirestoreDataConverter<DbModelType>): Unsubscribe;
|
||||
|
||||
// @public
|
||||
export function onSnapshotResume<AppModelType, DbModelType extends DocumentData>(firestore: Firestore, snapshotJson: object, options: SnapshotListenOptions, observer: {
|
||||
next: (snapshot: DocumentSnapshot<AppModelType, DbModelType>) => void;
|
||||
error?: (error: FirestoreError) => void;
|
||||
complete?: () => void;
|
||||
}, converter?: FirestoreDataConverter<DbModelType>): Unsubscribe;
|
||||
|
||||
// @public
|
||||
export function onSnapshotsInSync(firestore: Firestore, observer: {
|
||||
next?: (value: void) => void;
|
||||
@@ -610,8 +664,15 @@ export class QuerySnapshot<AppModelType = DocumentData, DbModelType extends Docu
|
||||
readonly metadata: SnapshotMetadata;
|
||||
readonly query: Query<AppModelType, DbModelType>;
|
||||
get size(): number;
|
||||
toJSON(): object;
|
||||
}
|
||||
|
||||
// @public
|
||||
export function querySnapshotFromJSON(db: Firestore, json: object): QuerySnapshot;
|
||||
|
||||
// @public
|
||||
export function querySnapshotFromJSON<AppModelType, DbModelType extends DocumentData = DocumentData>(db: Firestore, json: object, converter: FirestoreDataConverter<AppModelType, DbModelType>): QuerySnapshot<AppModelType, DbModelType>;
|
||||
|
||||
// @public
|
||||
export class QueryStartAtConstraint extends QueryConstraint {
|
||||
readonly type: 'startAt' | 'startAfter';
|
||||
@@ -696,6 +757,7 @@ export class Timestamp {
|
||||
seconds: number,
|
||||
nanoseconds: number);
|
||||
static fromDate(date: Date): Timestamp;
|
||||
static fromJSON(json: object): Timestamp;
|
||||
static fromMillis(milliseconds: number): Timestamp;
|
||||
isEqual(other: Timestamp): boolean;
|
||||
readonly nanoseconds: number;
|
||||
@@ -705,6 +767,7 @@ export class Timestamp {
|
||||
toJSON(): {
|
||||
seconds: number;
|
||||
nanoseconds: number;
|
||||
type: string;
|
||||
};
|
||||
toMillis(): number;
|
||||
toString(): string;
|
||||
@@ -751,8 +814,10 @@ export function vector(values?: number[]): VectorValue;
|
||||
// @public
|
||||
export class VectorValue {
|
||||
/* Excluded from this release type: __constructor */
|
||||
static fromJSON(json: object): VectorValue;
|
||||
isEqual(other: VectorValue): boolean;
|
||||
toArray(): number[];
|
||||
toJSON(): object;
|
||||
}
|
||||
|
||||
// @public
|
||||
|
||||
@@ -23,9 +23,11 @@ export declare class Bytes
|
||||
| Method | Modifiers | Description |
|
||||
| --- | --- | --- |
|
||||
| [fromBase64String(base64)](./firestore_.bytes.md#bytesfrombase64string) | <code>static</code> | Creates a new <code>Bytes</code> object from the given Base64 string, converting it to bytes. |
|
||||
| [fromJSON(json)](./firestore_.bytes.md#bytesfromjson) | <code>static</code> | Builds a <code>Bytes</code> instance from a JSON object created by [Bytes.toJSON()](./firestore_.bytes.md#bytestojson)<!-- -->. |
|
||||
| [fromUint8Array(array)](./firestore_.bytes.md#bytesfromuint8array) | <code>static</code> | Creates a new <code>Bytes</code> object from the given Uint8Array. |
|
||||
| [isEqual(other)](./firestore_.bytes.md#bytesisequal) | | Returns true if this <code>Bytes</code> object is equal to the provided one. |
|
||||
| [toBase64()](./firestore_.bytes.md#bytestobase64) | | Returns the underlying bytes as a Base64-encoded string. |
|
||||
| [toJSON()](./firestore_.bytes.md#bytestojson) | | Returns a JSON-serializable representation of this <code>Bytes</code> instance. |
|
||||
| [toString()](./firestore_.bytes.md#bytestostring) | | Returns a string representation of the <code>Bytes</code> object. |
|
||||
| [toUint8Array()](./firestore_.bytes.md#bytestouint8array) | | Returns the underlying bytes in a new <code>Uint8Array</code>. |
|
||||
|
||||
@@ -49,6 +51,28 @@ static fromBase64String(base64: string): Bytes;
|
||||
|
||||
[Bytes](./firestore_.bytes.md#bytes_class)
|
||||
|
||||
## Bytes.fromJSON()
|
||||
|
||||
Builds a `Bytes` instance from a JSON object created by [Bytes.toJSON()](./firestore_.bytes.md#bytestojson)<!-- -->.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
static fromJSON(json: object): Bytes;
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| json | object | a JSON object represention of a <code>Bytes</code> instance |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
[Bytes](./firestore_.bytes.md#bytes_class)
|
||||
|
||||
an instance of [Bytes](./firestore_.bytes.md#bytes_class) if the JSON object could be parsed. Throws a [FirestoreError](./firestore_.firestoreerror.md#firestoreerror_class) if an error occurs.
|
||||
|
||||
## Bytes.fromUint8Array()
|
||||
|
||||
Creates a new `Bytes` object from the given Uint8Array.
|
||||
@@ -106,6 +130,21 @@ string
|
||||
|
||||
The Base64-encoded string created from the `Bytes` object.
|
||||
|
||||
## Bytes.toJSON()
|
||||
|
||||
Returns a JSON-serializable representation of this `Bytes` instance.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
toJSON(): object;
|
||||
```
|
||||
<b>Returns:</b>
|
||||
|
||||
object
|
||||
|
||||
a JSON representation of this object.
|
||||
|
||||
## Bytes.toString()
|
||||
|
||||
Returns a string representation of the `Bytes` object.
|
||||
|
||||
@@ -33,6 +33,9 @@ export declare class DocumentReference<AppModelType = DocumentData, DbModelType
|
||||
|
||||
| Method | Modifiers | Description |
|
||||
| --- | --- | --- |
|
||||
| [fromJSON(firestore, json)](./firestore_.documentreference.md#documentreferencefromjson) | <code>static</code> | Builds a <code>DocumentReference</code> instance from a JSON object created by [DocumentReference.toJSON()](./firestore_.documentreference.md#documentreferencetojson)<!-- -->. |
|
||||
| [fromJSON(firestore, json, converter)](./firestore_.documentreference.md#documentreferencefromjson) | <code>static</code> | Builds a <code>DocumentReference</code> instance from a JSON object created by [DocumentReference.toJSON()](./firestore_.documentreference.md#documentreferencetojson)<!-- -->. |
|
||||
| [toJSON()](./firestore_.documentreference.md#documentreferencetojson) | | Returns a JSON-serializable representation of this <code>DocumentReference</code> instance. |
|
||||
| [withConverter(converter)](./firestore_.documentreference.md#documentreferencewithconverter) | | Applies a custom data converter to this <code>DocumentReference</code>, allowing you to use your own custom model objects with Firestore. When you call [setDoc()](./firestore_lite.md#setdoc_ee215ad)<!-- -->, [getDoc()](./firestore_lite.md#getdoc_4569087)<!-- -->, etc. with the returned <code>DocumentReference</code> instance, the provided converter will convert between Firestore data of type <code>NewDbModelType</code> and your custom type <code>NewAppModelType</code>. |
|
||||
| [withConverter(converter)](./firestore_.documentreference.md#documentreferencewithconverter) | | Removes the current converter. |
|
||||
|
||||
@@ -96,6 +99,68 @@ The type of this Firestore reference.
|
||||
readonly type = "document";
|
||||
```
|
||||
|
||||
## DocumentReference.fromJSON()
|
||||
|
||||
Builds a `DocumentReference` instance from a JSON object created by [DocumentReference.toJSON()](./firestore_.documentreference.md#documentreferencetojson)<!-- -->.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
static fromJSON(firestore: Firestore, json: object): DocumentReference;
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| firestore | [Firestore](./firestore_.firestore.md#firestore_class) | The [Firestore](./firestore_.firestore.md#firestore_class) instance the snapshot should be loaded for. |
|
||||
| json | object | a JSON object represention of a <code>DocumentReference</code> instance |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
[DocumentReference](./firestore_.documentreference.md#documentreference_class)
|
||||
|
||||
an instance of [DocumentReference](./firestore_.documentreference.md#documentreference_class) if the JSON object could be parsed. Throws a [FirestoreError](./firestore_.firestoreerror.md#firestoreerror_class) if an error occurs.
|
||||
|
||||
## DocumentReference.fromJSON()
|
||||
|
||||
Builds a `DocumentReference` instance from a JSON object created by [DocumentReference.toJSON()](./firestore_.documentreference.md#documentreferencetojson)<!-- -->.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
static fromJSON<NewAppModelType = DocumentData, NewDbModelType extends DocumentData = DocumentData>(firestore: Firestore, json: object, converter: FirestoreDataConverter<NewAppModelType, NewDbModelType>): DocumentReference<NewAppModelType, NewDbModelType>;
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| firestore | [Firestore](./firestore_.firestore.md#firestore_class) | The [Firestore](./firestore_.firestore.md#firestore_class) instance the snapshot should be loaded for. |
|
||||
| json | object | a JSON object represention of a <code>DocumentReference</code> instance |
|
||||
| converter | [FirestoreDataConverter](./firestore_.firestoredataconverter.md#firestoredataconverter_interface)<!-- --><NewAppModelType, NewDbModelType> | Converts objects to and from Firestore. |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
[DocumentReference](./firestore_.documentreference.md#documentreference_class)<!-- --><NewAppModelType, NewDbModelType>
|
||||
|
||||
an instance of [DocumentReference](./firestore_.documentreference.md#documentreference_class) if the JSON object could be parsed. Throws a [FirestoreError](./firestore_.firestoreerror.md#firestoreerror_class) if an error occurs.
|
||||
|
||||
## DocumentReference.toJSON()
|
||||
|
||||
Returns a JSON-serializable representation of this `DocumentReference` instance.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
toJSON(): object;
|
||||
```
|
||||
<b>Returns:</b>
|
||||
|
||||
object
|
||||
|
||||
a JSON representation of this object.
|
||||
|
||||
## DocumentReference.withConverter()
|
||||
|
||||
Applies a custom data converter to this `DocumentReference`<!-- -->, allowing you to use your own custom model objects with Firestore. When you call [setDoc()](./firestore_lite.md#setdoc_ee215ad)<!-- -->, [getDoc()](./firestore_lite.md#getdoc_4569087)<!-- -->, etc. with the returned `DocumentReference` instance, the provided converter will convert between Firestore data of type `NewDbModelType` and your custom type `NewAppModelType`<!-- -->.
|
||||
|
||||
@@ -41,6 +41,7 @@ export declare class DocumentSnapshot<AppModelType = DocumentData, DbModelType e
|
||||
| [data(options)](./firestore_.documentsnapshot.md#documentsnapshotdata) | | Retrieves all fields in the document as an <code>Object</code>. Returns <code>undefined</code> if the document doesn't exist.<!-- -->By default, <code>serverTimestamp()</code> values that have not yet been set to their final value will be returned as <code>null</code>. You can override this by passing an options object. |
|
||||
| [exists()](./firestore_.documentsnapshot.md#documentsnapshotexists) | | Returns whether or not the data exists. True if the document exists. |
|
||||
| [get(fieldPath, options)](./firestore_.documentsnapshot.md#documentsnapshotget) | | Retrieves the field specified by <code>fieldPath</code>. Returns <code>undefined</code> if the document or field doesn't exist.<!-- -->By default, a <code>serverTimestamp()</code> that has not yet been set to its final value will be returned as <code>null</code>. You can override this by passing an options object. |
|
||||
| [toJSON()](./firestore_.documentsnapshot.md#documentsnapshottojson) | | Returns a JSON-serializable representation of this <code>DocumentSnapshot</code> instance. |
|
||||
|
||||
## DocumentSnapshot.(constructor)
|
||||
|
||||
@@ -144,3 +145,18 @@ any
|
||||
|
||||
The data at the specified field location or undefined if no such field exists in the document.
|
||||
|
||||
## DocumentSnapshot.toJSON()
|
||||
|
||||
Returns a JSON-serializable representation of this `DocumentSnapshot` instance.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
toJSON(): object;
|
||||
```
|
||||
<b>Returns:</b>
|
||||
|
||||
object
|
||||
|
||||
a JSON representation of this object. Throws a [FirestoreError](./firestore_.firestoreerror.md#firestoreerror_class) if this `DocumentSnapshot` has pending writes.
|
||||
|
||||
|
||||
@@ -37,8 +37,9 @@ export declare class GeoPoint
|
||||
|
||||
| Method | Modifiers | Description |
|
||||
| --- | --- | --- |
|
||||
| [fromJSON(json)](./firestore_.geopoint.md#geopointfromjson) | <code>static</code> | Builds a <code>GeoPoint</code> instance from a JSON object created by [GeoPoint.toJSON()](./firestore_.geopoint.md#geopointtojson)<!-- -->. |
|
||||
| [isEqual(other)](./firestore_.geopoint.md#geopointisequal) | | Returns true if this <code>GeoPoint</code> is equal to the provided one. |
|
||||
| [toJSON()](./firestore_.geopoint.md#geopointtojson) | | Returns a JSON-serializable representation of this GeoPoint. |
|
||||
| [toJSON()](./firestore_.geopoint.md#geopointtojson) | | Returns a JSON-serializable representation of this <code>GeoPoint</code> instance. |
|
||||
|
||||
## GeoPoint.(constructor)
|
||||
|
||||
@@ -77,6 +78,28 @@ The longitude of this `GeoPoint` instance.
|
||||
get longitude(): number;
|
||||
```
|
||||
|
||||
## GeoPoint.fromJSON()
|
||||
|
||||
Builds a `GeoPoint` instance from a JSON object created by [GeoPoint.toJSON()](./firestore_.geopoint.md#geopointtojson)<!-- -->.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
static fromJSON(json: object): GeoPoint;
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| json | object | a JSON object represention of a <code>GeoPoint</code> instance |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
[GeoPoint](./firestore_.geopoint.md#geopoint_class)
|
||||
|
||||
an instance of [GeoPoint](./firestore_.geopoint.md#geopoint_class) if the JSON object could be parsed. Throws a [FirestoreError](./firestore_.firestoreerror.md#firestoreerror_class) if an error occurs.
|
||||
|
||||
## GeoPoint.isEqual()
|
||||
|
||||
Returns true if this `GeoPoint` is equal to the provided one.
|
||||
@@ -101,7 +124,7 @@ true if this `GeoPoint` is equal to the provided one.
|
||||
|
||||
## GeoPoint.toJSON()
|
||||
|
||||
Returns a JSON-serializable representation of this GeoPoint.
|
||||
Returns a JSON-serializable representation of this `GeoPoint` instance.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -109,9 +132,12 @@ Returns a JSON-serializable representation of this GeoPoint.
|
||||
toJSON(): {
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
type: string;
|
||||
};
|
||||
```
|
||||
<b>Returns:</b>
|
||||
|
||||
{ latitude: number; longitude: number; }
|
||||
{ latitude: number; longitude: number; type: string; }
|
||||
|
||||
a JSON representation of this object.
|
||||
|
||||
|
||||
@@ -19,6 +19,11 @@ https://github.com/firebase/firebase-js-sdk
|
||||
| [getFirestore(app)](./firestore_.md#getfirestore_cf608e1) | Returns the existing default [Firestore](./firestore_.firestore.md#firestore_class) instance that is associated with the provided [FirebaseApp](./app.firebaseapp.md#firebaseapp_interface)<!-- -->. If no instance exists, initializes a new instance with default settings. |
|
||||
| [getFirestore(app, databaseId)](./firestore_.md#getfirestore_48de6cb) | <b><i>(Public Preview)</i></b> Returns the existing named [Firestore](./firestore_.firestore.md#firestore_class) instance that is associated with the provided [FirebaseApp](./app.firebaseapp.md#firebaseapp_interface)<!-- -->. If no instance exists, initializes a new instance with default settings. |
|
||||
| [initializeFirestore(app, settings, databaseId)](./firestore_.md#initializefirestore_fc7d200) | Initializes a new instance of [Firestore](./firestore_.firestore.md#firestore_class) with the provided settings. Can only be called before any other function, including [getFirestore()](./firestore_.md#getfirestore)<!-- -->. If the custom settings are empty, this function is equivalent to calling [getFirestore()](./firestore_.md#getfirestore)<!-- -->. |
|
||||
| <b>function(db, ...)</b> |
|
||||
| [documentSnapshotFromJSON(db, json)](./firestore_.md#documentsnapshotfromjson_a318ff2) | Builds a <code>DocumentSnapshot</code> instance from a JSON object created by [DocumentSnapshot.toJSON()](./firestore_.documentsnapshot.md#documentsnapshottojson)<!-- -->. |
|
||||
| [documentSnapshotFromJSON(db, json, converter)](./firestore_.md#documentsnapshotfromjson_ddb369d) | Builds a <code>DocumentSnapshot</code> instance from a JSON object created by [DocumentSnapshot.toJSON()](./firestore_.documentsnapshot.md#documentsnapshottojson)<!-- -->. |
|
||||
| [querySnapshotFromJSON(db, json)](./firestore_.md#querysnapshotfromjson_a318ff2) | Builds a <code>QuerySnapshot</code> instance from a JSON object created by [QuerySnapshot.toJSON()](./firestore_.querysnapshot.md#querysnapshottojson)<!-- -->. |
|
||||
| [querySnapshotFromJSON(db, json, converter)](./firestore_.md#querysnapshotfromjson_ddb369d) | Builds a <code>QuerySnapshot</code> instance from a JSON object created by [QuerySnapshot.toJSON()](./firestore_.querysnapshot.md#querysnapshottojson)<!-- -->. |
|
||||
| <b>function(firestore, ...)</b> |
|
||||
| [clearIndexedDbPersistence(firestore)](./firestore_.md#clearindexeddbpersistence_231a8e0) | Clears the persistent storage. This includes pending writes and cached documents.<!-- -->Must be called while the [Firestore](./firestore_.firestore.md#firestore_class) instance is not started (after the app is terminated or when the app is first initialized). On startup, this function must be called before other functions (other than [initializeFirestore()](./firestore_.md#initializefirestore_fc7d200) or [getFirestore()](./firestore_.md#getfirestore)<!-- -->)). If the [Firestore](./firestore_.firestore.md#firestore_class) instance is still running, the promise will be rejected with the error code of <code>failed-precondition</code>.<!-- -->Note: <code>clearIndexedDbPersistence()</code> is primarily intended to help write reliable tests that use Cloud Firestore. It uses an efficient mechanism for dropping existing data but does not attempt to securely overwrite or otherwise make cached data unrecoverable. For applications that are sensitive to the disclosure of cached data in between user sessions, we strongly recommend not enabling persistence at all. |
|
||||
| [collection(firestore, path, pathSegments)](./firestore_.md#collection_1eb4c23) | Gets a <code>CollectionReference</code> instance that refers to the collection at the specified absolute path. |
|
||||
@@ -32,6 +37,14 @@ https://github.com/firebase/firebase-js-sdk
|
||||
| [getPersistentCacheIndexManager(firestore)](./firestore_.md#getpersistentcacheindexmanager_231a8e0) | Returns the PersistentCache Index Manager used by the given <code>Firestore</code> object. The <code>PersistentCacheIndexManager</code> instance, or <code>null</code> if local persistent storage is not in use. |
|
||||
| [loadBundle(firestore, bundleData)](./firestore_.md#loadbundle_bec5b75) | Loads a Firestore bundle into the local cache. |
|
||||
| [namedQuery(firestore, name)](./firestore_.md#namedquery_6438876) | Reads a Firestore [Query](./firestore_.query.md#query_class) from local cache, identified by the given name.<!-- -->The named queries are packaged into bundles on the server side (along with resulting documents), and loaded to local cache using <code>loadBundle</code>. Once in local cache, use this method to extract a [Query](./firestore_.query.md#query_class) by name. |
|
||||
| [onSnapshotResume(firestore, snapshotJson, onNext, onError, onCompletion, converter)](./firestore_.md#onsnapshotresume_7c84f5e) | Attaches a listener for <code>QuerySnapshot</code> events based on data generated by invoking [QuerySnapshot.toJSON()](./firestore_.querysnapshot.md#querysnapshottojson) You may either pass individual <code>onNext</code> and <code>onError</code> callbacks or pass a single observer object with <code>next</code> and <code>error</code> callbacks. The listener can be cancelled by calling the function that is returned when <code>onSnapshot</code> is called.<!-- -->NOTE: Although an <code>onCompletion</code> callback can be provided, it will never be called because the snapshot stream is never-ending. |
|
||||
| [onSnapshotResume(firestore, snapshotJson, onNext, onError, onCompletion, converter)](./firestore_.md#onsnapshotresume_712362a) | Attaches a listener for <code>DocumentSnapshot</code> events based on data generated by invoking [DocumentSnapshot.toJSON()](./firestore_.documentsnapshot.md#documentsnapshottojson)<!-- -->. You may either pass individual <code>onNext</code> and <code>onError</code> callbacks or pass a single observer object with <code>next</code> and <code>error</code> callbacks. The listener can be cancelled by calling the function that is returned when <code>onSnapshot</code> is called.<!-- -->NOTE: Although an <code>onCompletion</code> callback can be provided, it will never be called because the snapshot stream is never-ending. |
|
||||
| [onSnapshotResume(firestore, snapshotJson, options, onNext, onError, onCompletion, converter)](./firestore_.md#onsnapshotresume_8807e6e) | Attaches a listener for <code>QuerySnapshot</code> events based on data generated by invoking [QuerySnapshot.toJSON()](./firestore_.querysnapshot.md#querysnapshottojson)<!-- -->. You may either pass individual <code>onNext</code> and <code>onError</code> callbacks or pass a single observer object with <code>next</code> and <code>error</code> callbacks. The listener can be cancelled by calling the function that is returned when <code>onSnapshot</code> is called.<!-- -->NOTE: Although an <code>onCompletion</code> callback can be provided, it will never be called because the snapshot stream is never-ending. |
|
||||
| [onSnapshotResume(firestore, snapshotJson, options, onNext, onError, onCompletion, converter)](./firestore_.md#onsnapshotresume_301fcec) | Attaches a listener for <code>DocumentSnapshot</code> events based on data generated by invoking [DocumentSnapshot.toJSON()](./firestore_.documentsnapshot.md#documentsnapshottojson)<!-- -->. You may either pass individual <code>onNext</code> and <code>onError</code> callbacks or pass a single observer object with <code>next</code> and <code>error</code> callbacks. The listener can be cancelled by calling the function that is returned when <code>onSnapshot</code> is called.<!-- -->NOTE: Although an <code>onCompletion</code> callback can be provided, it will never be called because the snapshot stream is never-ending. |
|
||||
| [onSnapshotResume(firestore, snapshotJson, observer, converter)](./firestore_.md#onsnapshotresume_b8b5c9d) | Attaches a listener for <code>QuerySnapshot</code> events based on QuerySnapshot data generated by invoking [QuerySnapshot.toJSON()](./firestore_.querysnapshot.md#querysnapshottojson)<!-- -->. You may either pass individual <code>onNext</code> and <code>onError</code> callbacks or pass a single observer object with <code>next</code> and <code>error</code> callbacks. The listener can be cancelled by calling the function that is returned when <code>onSnapshot</code> is called.<!-- -->NOTE: Although an <code>onCompletion</code> callback can be provided, it will never be called because the snapshot stream is never-ending. |
|
||||
| [onSnapshotResume(firestore, snapshotJson, observer, converter)](./firestore_.md#onsnapshotresume_9b75d28) | Attaches a listener for <code>DocumentSnapshot</code> events based on data generated by invoking [DocumentSnapshot.toJSON()](./firestore_.documentsnapshot.md#documentsnapshottojson) You may either pass individual <code>onNext</code> and <code>onError</code> callbacks or pass a single observer object with <code>next</code> and <code>error</code> callbacks. The listener can be cancelled by calling the function that is returned when <code>onSnapshot</code> is called.<!-- -->NOTE: Although an <code>onCompletion</code> callback can be provided, it will never be called because the snapshot stream is never-ending. |
|
||||
| [onSnapshotResume(firestore, snapshotJson, options, observer, converter)](./firestore_.md#onsnapshotresume_fb80adf) | Attaches a listener for <code>QuerySnapshot</code> events based on QuerySnapshot data generated by invoking [QuerySnapshot.toJSON()](./firestore_.querysnapshot.md#querysnapshottojson) You may either pass individual <code>onNext</code> and <code>onError</code> callbacks or pass a single observer object with <code>next</code> and <code>error</code> callbacks. The listener can be cancelled by calling the function that is returned when <code>onSnapshot</code> is called.<!-- -->NOTE: Although an <code>onCompletion</code> callback can be provided, it will never be called because the snapshot stream is never-ending. |
|
||||
| [onSnapshotResume(firestore, snapshotJson, options, observer, converter)](./firestore_.md#onsnapshotresume_f76d912) | Attaches a listener for <code>DocumentSnapshot</code> events based on QuerySnapshot data generated by invoking [DocumentSnapshot.toJSON()](./firestore_.documentsnapshot.md#documentsnapshottojson) You may either pass individual <code>onNext</code> and <code>onError</code> callbacks or pass a single observer object with <code>next</code> and <code>error</code> callbacks. The listener can be cancelled by calling the function that is returned when <code>onSnapshot</code> is called.<!-- -->NOTE: Although an <code>onCompletion</code> callback can be provided, it will never be called because the snapshot stream is never-ending. |
|
||||
| [onSnapshotsInSync(firestore, observer)](./firestore_.md#onsnapshotsinsync_2f0dfa4) | Attaches a listener for a snapshots-in-sync event. The snapshots-in-sync event indicates that all listeners affected by a given change have fired, even if a single server-generated change affects multiple listeners.<!-- -->NOTE: The snapshots-in-sync event only indicates that listeners are in sync with each other, but does not relate to whether those snapshots are in sync with the server. Use SnapshotMetadata in the individual listeners to determine if a snapshot is from the cache or the server. |
|
||||
| [onSnapshotsInSync(firestore, onSync)](./firestore_.md#onsnapshotsinsync_1901c06) | Attaches a listener for a snapshots-in-sync event. The snapshots-in-sync event indicates that all listeners affected by a given change have fired, even if a single server-generated change affects multiple listeners.<!-- -->NOTE: The snapshots-in-sync event only indicates that listeners are in sync with each other, but does not relate to whether those snapshots are in sync with the server. Use <code>SnapshotMetadata</code> in the individual listeners to determine if a snapshot is from the cache or the server. |
|
||||
| [runTransaction(firestore, updateFunction, options)](./firestore_.md#runtransaction_6f03ec4) | Executes the given <code>updateFunction</code> and then attempts to commit the changes applied within the transaction. If any document read within the transaction has changed, Cloud Firestore retries the <code>updateFunction</code>. If it fails to commit after 5 attempts, the transaction fails.<!-- -->The maximum number of writes allowed in a single transaction is 500. |
|
||||
@@ -298,6 +311,102 @@ export declare function initializeFirestore(app: FirebaseApp, settings: Firestor
|
||||
|
||||
A newly initialized [Firestore](./firestore_.firestore.md#firestore_class) instance.
|
||||
|
||||
## function(db, ...)
|
||||
|
||||
### documentSnapshotFromJSON(db, json) {:#documentsnapshotfromjson_a318ff2}
|
||||
|
||||
Builds a `DocumentSnapshot` instance from a JSON object created by [DocumentSnapshot.toJSON()](./firestore_.documentsnapshot.md#documentsnapshottojson)<!-- -->.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare function documentSnapshotFromJSON(db: Firestore, json: object): DocumentSnapshot;
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| db | [Firestore](./firestore_.firestore.md#firestore_class) | |
|
||||
| json | object | a JSON object represention of a <code>DocumentSnapshot</code> instance. |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
[DocumentSnapshot](./firestore_.documentsnapshot.md#documentsnapshot_class)
|
||||
|
||||
an instance of [DocumentSnapshot](./firestore_.documentsnapshot.md#documentsnapshot_class) if the JSON object could be parsed. Throws a [FirestoreError](./firestore_.firestoreerror.md#firestoreerror_class) if an error occurs.
|
||||
|
||||
### documentSnapshotFromJSON(db, json, converter) {:#documentsnapshotfromjson_ddb369d}
|
||||
|
||||
Builds a `DocumentSnapshot` instance from a JSON object created by [DocumentSnapshot.toJSON()](./firestore_.documentsnapshot.md#documentsnapshottojson)<!-- -->.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare function documentSnapshotFromJSON<AppModelType, DbModelType extends DocumentData = DocumentData>(db: Firestore, json: object, converter: FirestoreDataConverter<AppModelType, DbModelType>): DocumentSnapshot<AppModelType, DbModelType>;
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| db | [Firestore](./firestore_.firestore.md#firestore_class) | |
|
||||
| json | object | a JSON object represention of a <code>DocumentSnapshot</code> instance. |
|
||||
| converter | [FirestoreDataConverter](./firestore_.firestoredataconverter.md#firestoredataconverter_interface)<!-- --><AppModelType, DbModelType> | Converts objects to and from Firestore. |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
[DocumentSnapshot](./firestore_.documentsnapshot.md#documentsnapshot_class)<!-- --><AppModelType, DbModelType>
|
||||
|
||||
an instance of [DocumentSnapshot](./firestore_.documentsnapshot.md#documentsnapshot_class) if the JSON object could be parsed. Throws a [FirestoreError](./firestore_.firestoreerror.md#firestoreerror_class) if an error occurs.
|
||||
|
||||
### querySnapshotFromJSON(db, json) {:#querysnapshotfromjson_a318ff2}
|
||||
|
||||
Builds a `QuerySnapshot` instance from a JSON object created by [QuerySnapshot.toJSON()](./firestore_.querysnapshot.md#querysnapshottojson)<!-- -->.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare function querySnapshotFromJSON(db: Firestore, json: object): QuerySnapshot;
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| db | [Firestore](./firestore_.firestore.md#firestore_class) | |
|
||||
| json | object | a JSON object represention of a <code>QuerySnapshot</code> instance. |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
[QuerySnapshot](./firestore_.querysnapshot.md#querysnapshot_class)
|
||||
|
||||
an instance of [QuerySnapshot](./firestore_.querysnapshot.md#querysnapshot_class) if the JSON object could be parsed. Throws a [FirestoreError](./firestore_.firestoreerror.md#firestoreerror_class) if an error occurs.
|
||||
|
||||
### querySnapshotFromJSON(db, json, converter) {:#querysnapshotfromjson_ddb369d}
|
||||
|
||||
Builds a `QuerySnapshot` instance from a JSON object created by [QuerySnapshot.toJSON()](./firestore_.querysnapshot.md#querysnapshottojson)<!-- -->.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare function querySnapshotFromJSON<AppModelType, DbModelType extends DocumentData = DocumentData>(db: Firestore, json: object, converter: FirestoreDataConverter<AppModelType, DbModelType>): QuerySnapshot<AppModelType, DbModelType>;
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| db | [Firestore](./firestore_.firestore.md#firestore_class) | |
|
||||
| json | object | a JSON object represention of a <code>QuerySnapshot</code> instance. |
|
||||
| converter | [FirestoreDataConverter](./firestore_.firestoredataconverter.md#firestoredataconverter_interface)<!-- --><AppModelType, DbModelType> | Converts objects to and from Firestore. |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
[QuerySnapshot](./firestore_.querysnapshot.md#querysnapshot_class)<!-- --><AppModelType, DbModelType>
|
||||
|
||||
an instance of [QuerySnapshot](./firestore_.querysnapshot.md#querysnapshot_class) if the JSON object could be parsed. Throws a [FirestoreError](./firestore_.firestoreerror.md#firestoreerror_class) if an error occurs.
|
||||
|
||||
## function(firestore, ...)
|
||||
|
||||
### clearIndexedDbPersistence(firestore) {:#clearindexeddbpersistence_231a8e0}
|
||||
@@ -617,6 +726,250 @@ Promise<[Query](./firestore_.query.md#query_class) \| null>
|
||||
|
||||
A `Promise` that is resolved with the Query or `null`<!-- -->.
|
||||
|
||||
### onSnapshotResume(firestore, snapshotJson, onNext, onError, onCompletion, converter) {:#onsnapshotresume_7c84f5e}
|
||||
|
||||
Attaches a listener for `QuerySnapshot` events based on data generated by invoking [QuerySnapshot.toJSON()](./firestore_.querysnapshot.md#querysnapshottojson) You may either pass individual `onNext` and `onError` callbacks or pass a single observer object with `next` and `error` callbacks. The listener can be cancelled by calling the function that is returned when `onSnapshot` is called.
|
||||
|
||||
NOTE: Although an `onCompletion` callback can be provided, it will never be called because the snapshot stream is never-ending.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare function onSnapshotResume<AppModelType, DbModelType extends DocumentData>(firestore: Firestore, snapshotJson: object, onNext: (snapshot: QuerySnapshot<AppModelType, DbModelType>) => void, onError?: (error: FirestoreError) => void, onCompletion?: () => void, converter?: FirestoreDataConverter<DbModelType>): Unsubscribe;
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| firestore | [Firestore](./firestore_.firestore.md#firestore_class) | The [Firestore](./firestore_.firestore.md#firestore_class) instance to enable the listener for. |
|
||||
| snapshotJson | object | A JSON object generated by invoking [QuerySnapshot.toJSON()](./firestore_.querysnapshot.md#querysnapshottojson)<!-- -->. |
|
||||
| onNext | (snapshot: [QuerySnapshot](./firestore_.querysnapshot.md#querysnapshot_class)<!-- --><AppModelType, DbModelType>) => void | A callback to be called every time a new <code>QuerySnapshot</code> is available. |
|
||||
| onError | (error: [FirestoreError](./firestore_.firestoreerror.md#firestoreerror_class)<!-- -->) => void | A callback to be called if the listen fails or is cancelled. No further callbacks will occur. |
|
||||
| onCompletion | () => void | Can be provided, but will not be called since streams are never ending. |
|
||||
| converter | [FirestoreDataConverter](./firestore_.firestoredataconverter.md#firestoredataconverter_interface)<!-- --><DbModelType> | An optional object that converts objects from Firestore before the onNext listener is invoked. |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
[Unsubscribe](./firestore_.unsubscribe.md#unsubscribe_interface)
|
||||
|
||||
An unsubscribe function that can be called to cancel the snapshot listener.
|
||||
|
||||
### onSnapshotResume(firestore, snapshotJson, onNext, onError, onCompletion, converter) {:#onsnapshotresume_712362a}
|
||||
|
||||
Attaches a listener for `DocumentSnapshot` events based on data generated by invoking [DocumentSnapshot.toJSON()](./firestore_.documentsnapshot.md#documentsnapshottojson)<!-- -->. You may either pass individual `onNext` and `onError` callbacks or pass a single observer object with `next` and `error` callbacks. The listener can be cancelled by calling the function that is returned when `onSnapshot` is called.
|
||||
|
||||
NOTE: Although an `onCompletion` callback can be provided, it will never be called because the snapshot stream is never-ending.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare function onSnapshotResume<AppModelType, DbModelType extends DocumentData>(firestore: Firestore, snapshotJson: object, onNext: (snapshot: DocumentSnapshot<AppModelType, DbModelType>) => void, onError?: (error: FirestoreError) => void, onCompletion?: () => void, converter?: FirestoreDataConverter<DbModelType>): Unsubscribe;
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| firestore | [Firestore](./firestore_.firestore.md#firestore_class) | The [Firestore](./firestore_.firestore.md#firestore_class) instance to enable the listener for. |
|
||||
| snapshotJson | object | A JSON object generated by invoking [DocumentSnapshot.toJSON()](./firestore_.documentsnapshot.md#documentsnapshottojson)<!-- -->. |
|
||||
| onNext | (snapshot: [DocumentSnapshot](./firestore_.documentsnapshot.md#documentsnapshot_class)<!-- --><AppModelType, DbModelType>) => void | A callback to be called every time a new <code>DocumentSnapshot</code> is available. |
|
||||
| onError | (error: [FirestoreError](./firestore_.firestoreerror.md#firestoreerror_class)<!-- -->) => void | A callback to be called if the listen fails or is cancelled. No further callbacks will occur. |
|
||||
| onCompletion | () => void | Can be provided, but will not be called since streams are never ending. |
|
||||
| converter | [FirestoreDataConverter](./firestore_.firestoredataconverter.md#firestoredataconverter_interface)<!-- --><DbModelType> | An optional object that converts objects from Firestore before the onNext listener is invoked. |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
[Unsubscribe](./firestore_.unsubscribe.md#unsubscribe_interface)
|
||||
|
||||
An unsubscribe function that can be called to cancel the snapshot listener.
|
||||
|
||||
### onSnapshotResume(firestore, snapshotJson, options, onNext, onError, onCompletion, converter) {:#onsnapshotresume_8807e6e}
|
||||
|
||||
Attaches a listener for `QuerySnapshot` events based on data generated by invoking [QuerySnapshot.toJSON()](./firestore_.querysnapshot.md#querysnapshottojson)<!-- -->. You may either pass individual `onNext` and `onError` callbacks or pass a single observer object with `next` and `error` callbacks. The listener can be cancelled by calling the function that is returned when `onSnapshot` is called.
|
||||
|
||||
NOTE: Although an `onCompletion` callback can be provided, it will never be called because the snapshot stream is never-ending.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare function onSnapshotResume<AppModelType, DbModelType extends DocumentData>(firestore: Firestore, snapshotJson: object, options: SnapshotListenOptions, onNext: (snapshot: QuerySnapshot<AppModelType, DbModelType>) => void, onError?: (error: FirestoreError) => void, onCompletion?: () => void, converter?: FirestoreDataConverter<DbModelType>): Unsubscribe;
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| firestore | [Firestore](./firestore_.firestore.md#firestore_class) | The [Firestore](./firestore_.firestore.md#firestore_class) instance to enable the listener for. |
|
||||
| snapshotJson | object | A JSON object generated by invoking [QuerySnapshot.toJSON()](./firestore_.querysnapshot.md#querysnapshottojson)<!-- -->. |
|
||||
| options | [SnapshotListenOptions](./firestore_.snapshotlistenoptions.md#snapshotlistenoptions_interface) | Options controlling the listen behavior. |
|
||||
| onNext | (snapshot: [QuerySnapshot](./firestore_.querysnapshot.md#querysnapshot_class)<!-- --><AppModelType, DbModelType>) => void | A callback to be called every time a new <code>QuerySnapshot</code> is available. |
|
||||
| onError | (error: [FirestoreError](./firestore_.firestoreerror.md#firestoreerror_class)<!-- -->) => void | A callback to be called if the listen fails or is cancelled. No further callbacks will occur. |
|
||||
| onCompletion | () => void | Can be provided, but will not be called since streams are never ending. |
|
||||
| converter | [FirestoreDataConverter](./firestore_.firestoredataconverter.md#firestoredataconverter_interface)<!-- --><DbModelType> | An optional object that converts objects from Firestore before the onNext listener is invoked. |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
[Unsubscribe](./firestore_.unsubscribe.md#unsubscribe_interface)
|
||||
|
||||
An unsubscribe function that can be called to cancel the snapshot listener.
|
||||
|
||||
### onSnapshotResume(firestore, snapshotJson, options, onNext, onError, onCompletion, converter) {:#onsnapshotresume_301fcec}
|
||||
|
||||
Attaches a listener for `DocumentSnapshot` events based on data generated by invoking [DocumentSnapshot.toJSON()](./firestore_.documentsnapshot.md#documentsnapshottojson)<!-- -->. You may either pass individual `onNext` and `onError` callbacks or pass a single observer object with `next` and `error` callbacks. The listener can be cancelled by calling the function that is returned when `onSnapshot` is called.
|
||||
|
||||
NOTE: Although an `onCompletion` callback can be provided, it will never be called because the snapshot stream is never-ending.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare function onSnapshotResume<AppModelType, DbModelType extends DocumentData>(firestore: Firestore, snapshotJson: object, options: SnapshotListenOptions, onNext: (snapshot: DocumentSnapshot<AppModelType, DbModelType>) => void, onError?: (error: FirestoreError) => void, onCompletion?: () => void, converter?: FirestoreDataConverter<DbModelType>): Unsubscribe;
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| firestore | [Firestore](./firestore_.firestore.md#firestore_class) | The [Firestore](./firestore_.firestore.md#firestore_class) instance to enable the listener for. |
|
||||
| snapshotJson | object | A JSON object generated by invoking [DocumentSnapshot.toJSON()](./firestore_.documentsnapshot.md#documentsnapshottojson)<!-- -->. |
|
||||
| options | [SnapshotListenOptions](./firestore_.snapshotlistenoptions.md#snapshotlistenoptions_interface) | Options controlling the listen behavior. |
|
||||
| onNext | (snapshot: [DocumentSnapshot](./firestore_.documentsnapshot.md#documentsnapshot_class)<!-- --><AppModelType, DbModelType>) => void | A callback to be called every time a new <code>DocumentSnapshot</code> is available. |
|
||||
| onError | (error: [FirestoreError](./firestore_.firestoreerror.md#firestoreerror_class)<!-- -->) => void | A callback to be called if the listen fails or is cancelled. No further callbacks will occur. |
|
||||
| onCompletion | () => void | Can be provided, but will not be called since streams are never ending. |
|
||||
| converter | [FirestoreDataConverter](./firestore_.firestoredataconverter.md#firestoredataconverter_interface)<!-- --><DbModelType> | An optional object that converts objects from Firestore before the onNext listener is invoked. |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
[Unsubscribe](./firestore_.unsubscribe.md#unsubscribe_interface)
|
||||
|
||||
An unsubscribe function that can be called to cancel the snapshot listener.
|
||||
|
||||
### onSnapshotResume(firestore, snapshotJson, observer, converter) {:#onsnapshotresume_b8b5c9d}
|
||||
|
||||
Attaches a listener for `QuerySnapshot` events based on QuerySnapshot data generated by invoking [QuerySnapshot.toJSON()](./firestore_.querysnapshot.md#querysnapshottojson)<!-- -->. You may either pass individual `onNext` and `onError` callbacks or pass a single observer object with `next` and `error` callbacks. The listener can be cancelled by calling the function that is returned when `onSnapshot` is called.
|
||||
|
||||
NOTE: Although an `onCompletion` callback can be provided, it will never be called because the snapshot stream is never-ending.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare function onSnapshotResume<AppModelType, DbModelType extends DocumentData>(firestore: Firestore, snapshotJson: object, observer: {
|
||||
next: (snapshot: QuerySnapshot<AppModelType, DbModelType>) => void;
|
||||
error?: (error: FirestoreError) => void;
|
||||
complete?: () => void;
|
||||
}, converter?: FirestoreDataConverter<DbModelType>): Unsubscribe;
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| firestore | [Firestore](./firestore_.firestore.md#firestore_class) | The [Firestore](./firestore_.firestore.md#firestore_class) instance to enable the listener for. |
|
||||
| snapshotJson | object | A JSON object generated by invoking [QuerySnapshot.toJSON()](./firestore_.querysnapshot.md#querysnapshottojson)<!-- -->. |
|
||||
| observer | { next: (snapshot: [QuerySnapshot](./firestore_.querysnapshot.md#querysnapshot_class)<!-- --><AppModelType, DbModelType>) => void; error?: (error: [FirestoreError](./firestore_.firestoreerror.md#firestoreerror_class)<!-- -->) => void; complete?: () => void; } | A single object containing <code>next</code> and <code>error</code> callbacks. |
|
||||
| converter | [FirestoreDataConverter](./firestore_.firestoredataconverter.md#firestoredataconverter_interface)<!-- --><DbModelType> | An optional object that converts objects from Firestore before the onNext listener is invoked. |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
[Unsubscribe](./firestore_.unsubscribe.md#unsubscribe_interface)
|
||||
|
||||
An unsubscribe function that can be called to cancel the snapshot listener.
|
||||
|
||||
### onSnapshotResume(firestore, snapshotJson, observer, converter) {:#onsnapshotresume_9b75d28}
|
||||
|
||||
Attaches a listener for `DocumentSnapshot` events based on data generated by invoking [DocumentSnapshot.toJSON()](./firestore_.documentsnapshot.md#documentsnapshottojson) You may either pass individual `onNext` and `onError` callbacks or pass a single observer object with `next` and `error` callbacks. The listener can be cancelled by calling the function that is returned when `onSnapshot` is called.
|
||||
|
||||
NOTE: Although an `onCompletion` callback can be provided, it will never be called because the snapshot stream is never-ending.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare function onSnapshotResume<AppModelType, DbModelType extends DocumentData>(firestore: Firestore, snapshotJson: object, observer: {
|
||||
next: (snapshot: DocumentSnapshot<AppModelType, DbModelType>) => void;
|
||||
error?: (error: FirestoreError) => void;
|
||||
complete?: () => void;
|
||||
}, converter?: FirestoreDataConverter<DbModelType>): Unsubscribe;
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| firestore | [Firestore](./firestore_.firestore.md#firestore_class) | The [Firestore](./firestore_.firestore.md#firestore_class) instance to enable the listener for. |
|
||||
| snapshotJson | object | A JSON object generated by invoking [DocumentSnapshot.toJSON()](./firestore_.documentsnapshot.md#documentsnapshottojson)<!-- -->. |
|
||||
| observer | { next: (snapshot: [DocumentSnapshot](./firestore_.documentsnapshot.md#documentsnapshot_class)<!-- --><AppModelType, DbModelType>) => void; error?: (error: [FirestoreError](./firestore_.firestoreerror.md#firestoreerror_class)<!-- -->) => void; complete?: () => void; } | A single object containing <code>next</code> and <code>error</code> callbacks. |
|
||||
| converter | [FirestoreDataConverter](./firestore_.firestoredataconverter.md#firestoredataconverter_interface)<!-- --><DbModelType> | An optional object that converts objects from Firestore before the onNext listener is invoked. |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
[Unsubscribe](./firestore_.unsubscribe.md#unsubscribe_interface)
|
||||
|
||||
An unsubscribe function that can be called to cancel the snapshot listener.
|
||||
|
||||
### onSnapshotResume(firestore, snapshotJson, options, observer, converter) {:#onsnapshotresume_fb80adf}
|
||||
|
||||
Attaches a listener for `QuerySnapshot` events based on QuerySnapshot data generated by invoking [QuerySnapshot.toJSON()](./firestore_.querysnapshot.md#querysnapshottojson) You may either pass individual `onNext` and `onError` callbacks or pass a single observer object with `next` and `error` callbacks. The listener can be cancelled by calling the function that is returned when `onSnapshot` is called.
|
||||
|
||||
NOTE: Although an `onCompletion` callback can be provided, it will never be called because the snapshot stream is never-ending.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare function onSnapshotResume<AppModelType, DbModelType extends DocumentData>(firestore: Firestore, snapshotJson: object, options: SnapshotListenOptions, observer: {
|
||||
next: (snapshot: QuerySnapshot<AppModelType, DbModelType>) => void;
|
||||
error?: (error: FirestoreError) => void;
|
||||
complete?: () => void;
|
||||
}, converter?: FirestoreDataConverter<DbModelType>): Unsubscribe;
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| firestore | [Firestore](./firestore_.firestore.md#firestore_class) | The [Firestore](./firestore_.firestore.md#firestore_class) instance to enable the listener for. |
|
||||
| snapshotJson | object | A JSON object generated by invoking [QuerySnapshot.toJSON()](./firestore_.querysnapshot.md#querysnapshottojson)<!-- -->. |
|
||||
| options | [SnapshotListenOptions](./firestore_.snapshotlistenoptions.md#snapshotlistenoptions_interface) | Options controlling the listen behavior. |
|
||||
| observer | { next: (snapshot: [QuerySnapshot](./firestore_.querysnapshot.md#querysnapshot_class)<!-- --><AppModelType, DbModelType>) => void; error?: (error: [FirestoreError](./firestore_.firestoreerror.md#firestoreerror_class)<!-- -->) => void; complete?: () => void; } | A single object containing <code>next</code> and <code>error</code> callbacks. |
|
||||
| converter | [FirestoreDataConverter](./firestore_.firestoredataconverter.md#firestoredataconverter_interface)<!-- --><DbModelType> | An optional object that converts objects from Firestore before the onNext listener is invoked. |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
[Unsubscribe](./firestore_.unsubscribe.md#unsubscribe_interface)
|
||||
|
||||
An unsubscribe function that can be called to cancel the snapshot listener.
|
||||
|
||||
### onSnapshotResume(firestore, snapshotJson, options, observer, converter) {:#onsnapshotresume_f76d912}
|
||||
|
||||
Attaches a listener for `DocumentSnapshot` events based on QuerySnapshot data generated by invoking [DocumentSnapshot.toJSON()](./firestore_.documentsnapshot.md#documentsnapshottojson) You may either pass individual `onNext` and `onError` callbacks or pass a single observer object with `next` and `error` callbacks. The listener can be cancelled by calling the function that is returned when `onSnapshot` is called.
|
||||
|
||||
NOTE: Although an `onCompletion` callback can be provided, it will never be called because the snapshot stream is never-ending.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare function onSnapshotResume<AppModelType, DbModelType extends DocumentData>(firestore: Firestore, snapshotJson: object, options: SnapshotListenOptions, observer: {
|
||||
next: (snapshot: DocumentSnapshot<AppModelType, DbModelType>) => void;
|
||||
error?: (error: FirestoreError) => void;
|
||||
complete?: () => void;
|
||||
}, converter?: FirestoreDataConverter<DbModelType>): Unsubscribe;
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| firestore | [Firestore](./firestore_.firestore.md#firestore_class) | The [Firestore](./firestore_.firestore.md#firestore_class) instance to enable the listener for. |
|
||||
| snapshotJson | object | A JSON object generated by invoking [DocumentSnapshot.toJSON()](./firestore_.documentsnapshot.md#documentsnapshottojson)<!-- -->. |
|
||||
| options | [SnapshotListenOptions](./firestore_.snapshotlistenoptions.md#snapshotlistenoptions_interface) | Options controlling the listen behavior. |
|
||||
| observer | { next: (snapshot: [DocumentSnapshot](./firestore_.documentsnapshot.md#documentsnapshot_class)<!-- --><AppModelType, DbModelType>) => void; error?: (error: [FirestoreError](./firestore_.firestoreerror.md#firestoreerror_class)<!-- -->) => void; complete?: () => void; } | A single object containing <code>next</code> and <code>error</code> callbacks. |
|
||||
| converter | [FirestoreDataConverter](./firestore_.firestoredataconverter.md#firestoredataconverter_interface)<!-- --><DbModelType> | An optional object that converts objects from Firestore before the onNext listener is invoked. |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
[Unsubscribe](./firestore_.unsubscribe.md#unsubscribe_interface)
|
||||
|
||||
An unsubscribe function that can be called to cancel the snapshot listener.
|
||||
|
||||
### onSnapshotsInSync(firestore, observer) {:#onsnapshotsinsync_2f0dfa4}
|
||||
|
||||
Attaches a listener for a snapshots-in-sync event. The snapshots-in-sync event indicates that all listeners affected by a given change have fired, even if a single server-generated change affects multiple listeners.
|
||||
|
||||
@@ -34,6 +34,7 @@ export declare class QuerySnapshot<AppModelType = DocumentData, DbModelType exte
|
||||
| --- | --- | --- |
|
||||
| [docChanges(options)](./firestore_.querysnapshot.md#querysnapshotdocchanges) | | Returns an array of the documents changes since the last snapshot. If this is the first snapshot, all documents will be in the list as 'added' changes. |
|
||||
| [forEach(callback, thisArg)](./firestore_.querysnapshot.md#querysnapshotforeach) | | Enumerates all of the documents in the <code>QuerySnapshot</code>. |
|
||||
| [toJSON()](./firestore_.querysnapshot.md#querysnapshottojson) | | Returns a JSON-serializable representation of this <code>QuerySnapshot</code> instance. |
|
||||
|
||||
## QuerySnapshot.docs
|
||||
|
||||
@@ -126,3 +127,18 @@ forEach(callback: (result: QueryDocumentSnapshot<AppModelType, DbModelType>) =>
|
||||
|
||||
void
|
||||
|
||||
## QuerySnapshot.toJSON()
|
||||
|
||||
Returns a JSON-serializable representation of this `QuerySnapshot` instance.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
toJSON(): object;
|
||||
```
|
||||
<b>Returns:</b>
|
||||
|
||||
object
|
||||
|
||||
a JSON representation of this object. Throws a [FirestoreError](./firestore_.firestoreerror.md#firestoreerror_class) if this `QuerySnapshot` has pending writes.
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ export declare class Timestamp
|
||||
| Method | Modifiers | Description |
|
||||
| --- | --- | --- |
|
||||
| [fromDate(date)](./firestore_.timestamp.md#timestampfromdate) | <code>static</code> | Creates a new timestamp from the given date. |
|
||||
| [fromJSON(json)](./firestore_.timestamp.md#timestampfromjson) | <code>static</code> | Builds a <code>Timestamp</code> instance from a JSON object created by [Timestamp.toJSON()](./firestore_.timestamp.md#timestamptojson)<!-- -->. |
|
||||
| [fromMillis(milliseconds)](./firestore_.timestamp.md#timestampfrommillis) | <code>static</code> | Creates a new timestamp from the given number of milliseconds. |
|
||||
| [isEqual(other)](./firestore_.timestamp.md#timestampisequal) | | Returns true if this <code>Timestamp</code> is equal to the provided one. |
|
||||
| [now()](./firestore_.timestamp.md#timestampnow) | <code>static</code> | Creates a new timestamp with the current date, with millisecond precision. |
|
||||
@@ -110,6 +111,26 @@ static fromDate(date: Date): Timestamp;
|
||||
|
||||
A new `Timestamp` representing the same point in time as the given date.
|
||||
|
||||
## Timestamp.fromJSON()
|
||||
|
||||
Builds a `Timestamp` instance from a JSON object created by [Timestamp.toJSON()](./firestore_.timestamp.md#timestamptojson)<!-- -->.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
static fromJSON(json: object): Timestamp;
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| json | object | |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
[Timestamp](./firestore_.timestamp.md#timestamp_class)
|
||||
|
||||
## Timestamp.fromMillis()
|
||||
|
||||
Creates a new timestamp from the given number of milliseconds.
|
||||
@@ -194,11 +215,12 @@ Returns a JSON-serializable representation of this `Timestamp`<!-- -->.
|
||||
toJSON(): {
|
||||
seconds: number;
|
||||
nanoseconds: number;
|
||||
type: string;
|
||||
};
|
||||
```
|
||||
<b>Returns:</b>
|
||||
|
||||
{ seconds: number; nanoseconds: number; }
|
||||
{ seconds: number; nanoseconds: number; type: string; }
|
||||
|
||||
## Timestamp.toMillis()
|
||||
|
||||
|
||||
@@ -24,8 +24,32 @@ export declare class VectorValue
|
||||
|
||||
| Method | Modifiers | Description |
|
||||
| --- | --- | --- |
|
||||
| [fromJSON(json)](./firestore_.vectorvalue.md#vectorvaluefromjson) | <code>static</code> | Builds a <code>VectorValue</code> instance from a JSON object created by [VectorValue.toJSON()](./firestore_.vectorvalue.md#vectorvaluetojson)<!-- -->. |
|
||||
| [isEqual(other)](./firestore_.vectorvalue.md#vectorvalueisequal) | | Returns <code>true</code> if the two <code>VectorValue</code> values have the same raw number arrays, returns <code>false</code> otherwise. |
|
||||
| [toArray()](./firestore_.vectorvalue.md#vectorvaluetoarray) | | Returns a copy of the raw number array form of the vector. |
|
||||
| [toJSON()](./firestore_.vectorvalue.md#vectorvaluetojson) | | Returns a JSON-serializable representation of this <code>VectorValue</code> instance. |
|
||||
|
||||
## VectorValue.fromJSON()
|
||||
|
||||
Builds a `VectorValue` instance from a JSON object created by [VectorValue.toJSON()](./firestore_.vectorvalue.md#vectorvaluetojson)<!-- -->.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
static fromJSON(json: object): VectorValue;
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| json | object | a JSON object represention of a <code>VectorValue</code> instance. |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
[VectorValue](./firestore_.vectorvalue.md#vectorvalue_class)
|
||||
|
||||
an instance of [VectorValue](./firestore_.vectorvalue.md#vectorvalue_class) if the JSON object could be parsed. Throws a [FirestoreError](./firestore_.firestoreerror.md#firestoreerror_class) if an error occurs.
|
||||
|
||||
## VectorValue.isEqual()
|
||||
|
||||
@@ -60,3 +84,18 @@ toArray(): number[];
|
||||
|
||||
number\[\]
|
||||
|
||||
## VectorValue.toJSON()
|
||||
|
||||
Returns a JSON-serializable representation of this `VectorValue` instance.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
toJSON(): object;
|
||||
```
|
||||
<b>Returns:</b>
|
||||
|
||||
object
|
||||
|
||||
a JSON representation of this object.
|
||||
|
||||
|
||||
@@ -23,9 +23,11 @@ export declare class Bytes
|
||||
| Method | Modifiers | Description |
|
||||
| --- | --- | --- |
|
||||
| [fromBase64String(base64)](./firestore_lite.bytes.md#bytesfrombase64string) | <code>static</code> | Creates a new <code>Bytes</code> object from the given Base64 string, converting it to bytes. |
|
||||
| [fromJSON(json)](./firestore_lite.bytes.md#bytesfromjson) | <code>static</code> | Builds a <code>Bytes</code> instance from a JSON object created by [Bytes.toJSON()](./firestore_.bytes.md#bytestojson)<!-- -->. |
|
||||
| [fromUint8Array(array)](./firestore_lite.bytes.md#bytesfromuint8array) | <code>static</code> | Creates a new <code>Bytes</code> object from the given Uint8Array. |
|
||||
| [isEqual(other)](./firestore_lite.bytes.md#bytesisequal) | | Returns true if this <code>Bytes</code> object is equal to the provided one. |
|
||||
| [toBase64()](./firestore_lite.bytes.md#bytestobase64) | | Returns the underlying bytes as a Base64-encoded string. |
|
||||
| [toJSON()](./firestore_lite.bytes.md#bytestojson) | | Returns a JSON-serializable representation of this <code>Bytes</code> instance. |
|
||||
| [toString()](./firestore_lite.bytes.md#bytestostring) | | Returns a string representation of the <code>Bytes</code> object. |
|
||||
| [toUint8Array()](./firestore_lite.bytes.md#bytestouint8array) | | Returns the underlying bytes in a new <code>Uint8Array</code>. |
|
||||
|
||||
@@ -49,6 +51,28 @@ static fromBase64String(base64: string): Bytes;
|
||||
|
||||
[Bytes](./firestore_lite.bytes.md#bytes_class)
|
||||
|
||||
## Bytes.fromJSON()
|
||||
|
||||
Builds a `Bytes` instance from a JSON object created by [Bytes.toJSON()](./firestore_.bytes.md#bytestojson)<!-- -->.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
static fromJSON(json: object): Bytes;
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| json | object | a JSON object represention of a <code>Bytes</code> instance |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
[Bytes](./firestore_lite.bytes.md#bytes_class)
|
||||
|
||||
an instance of [Bytes](./firestore_.bytes.md#bytes_class) if the JSON object could be parsed. Throws a [FirestoreError](./firestore_.firestoreerror.md#firestoreerror_class) if an error occurs.
|
||||
|
||||
## Bytes.fromUint8Array()
|
||||
|
||||
Creates a new `Bytes` object from the given Uint8Array.
|
||||
@@ -106,6 +130,21 @@ string
|
||||
|
||||
The Base64-encoded string created from the `Bytes` object.
|
||||
|
||||
## Bytes.toJSON()
|
||||
|
||||
Returns a JSON-serializable representation of this `Bytes` instance.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
toJSON(): object;
|
||||
```
|
||||
<b>Returns:</b>
|
||||
|
||||
object
|
||||
|
||||
a JSON representation of this object.
|
||||
|
||||
## Bytes.toString()
|
||||
|
||||
Returns a string representation of the `Bytes` object.
|
||||
|
||||
@@ -33,6 +33,9 @@ export declare class DocumentReference<AppModelType = DocumentData, DbModelType
|
||||
|
||||
| Method | Modifiers | Description |
|
||||
| --- | --- | --- |
|
||||
| [fromJSON(firestore, json)](./firestore_lite.documentreference.md#documentreferencefromjson) | <code>static</code> | Builds a <code>DocumentReference</code> instance from a JSON object created by [DocumentReference.toJSON()](./firestore_.documentreference.md#documentreferencetojson)<!-- -->. |
|
||||
| [fromJSON(firestore, json, converter)](./firestore_lite.documentreference.md#documentreferencefromjson) | <code>static</code> | Builds a <code>DocumentReference</code> instance from a JSON object created by [DocumentReference.toJSON()](./firestore_.documentreference.md#documentreferencetojson)<!-- -->. |
|
||||
| [toJSON()](./firestore_lite.documentreference.md#documentreferencetojson) | | Returns a JSON-serializable representation of this <code>DocumentReference</code> instance. |
|
||||
| [withConverter(converter)](./firestore_lite.documentreference.md#documentreferencewithconverter) | | Applies a custom data converter to this <code>DocumentReference</code>, allowing you to use your own custom model objects with Firestore. When you call [setDoc()](./firestore_lite.md#setdoc_ee215ad)<!-- -->, [getDoc()](./firestore_lite.md#getdoc_4569087)<!-- -->, etc. with the returned <code>DocumentReference</code> instance, the provided converter will convert between Firestore data of type <code>NewDbModelType</code> and your custom type <code>NewAppModelType</code>. |
|
||||
| [withConverter(converter)](./firestore_lite.documentreference.md#documentreferencewithconverter) | | Removes the current converter. |
|
||||
|
||||
@@ -96,6 +99,68 @@ The type of this Firestore reference.
|
||||
readonly type = "document";
|
||||
```
|
||||
|
||||
## DocumentReference.fromJSON()
|
||||
|
||||
Builds a `DocumentReference` instance from a JSON object created by [DocumentReference.toJSON()](./firestore_.documentreference.md#documentreferencetojson)<!-- -->.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
static fromJSON(firestore: Firestore, json: object): DocumentReference;
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| firestore | [Firestore](./firestore_lite.firestore.md#firestore_class) | The [Firestore](./firestore_.firestore.md#firestore_class) instance the snapshot should be loaded for. |
|
||||
| json | object | a JSON object represention of a <code>DocumentReference</code> instance |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
[DocumentReference](./firestore_lite.documentreference.md#documentreference_class)
|
||||
|
||||
an instance of [DocumentReference](./firestore_.documentreference.md#documentreference_class) if the JSON object could be parsed. Throws a [FirestoreError](./firestore_.firestoreerror.md#firestoreerror_class) if an error occurs.
|
||||
|
||||
## DocumentReference.fromJSON()
|
||||
|
||||
Builds a `DocumentReference` instance from a JSON object created by [DocumentReference.toJSON()](./firestore_.documentreference.md#documentreferencetojson)<!-- -->.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
static fromJSON<NewAppModelType = DocumentData, NewDbModelType extends DocumentData = DocumentData>(firestore: Firestore, json: object, converter: FirestoreDataConverter<NewAppModelType, NewDbModelType>): DocumentReference<NewAppModelType, NewDbModelType>;
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| firestore | [Firestore](./firestore_lite.firestore.md#firestore_class) | The [Firestore](./firestore_.firestore.md#firestore_class) instance the snapshot should be loaded for. |
|
||||
| json | object | a JSON object represention of a <code>DocumentReference</code> instance |
|
||||
| converter | [FirestoreDataConverter](./firestore_lite.firestoredataconverter.md#firestoredataconverter_interface)<!-- --><NewAppModelType, NewDbModelType> | Converts objects to and from Firestore. |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
[DocumentReference](./firestore_lite.documentreference.md#documentreference_class)<!-- --><NewAppModelType, NewDbModelType>
|
||||
|
||||
an instance of [DocumentReference](./firestore_.documentreference.md#documentreference_class) if the JSON object could be parsed. Throws a [FirestoreError](./firestore_.firestoreerror.md#firestoreerror_class) if an error occurs.
|
||||
|
||||
## DocumentReference.toJSON()
|
||||
|
||||
Returns a JSON-serializable representation of this `DocumentReference` instance.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
toJSON(): object;
|
||||
```
|
||||
<b>Returns:</b>
|
||||
|
||||
object
|
||||
|
||||
a JSON representation of this object.
|
||||
|
||||
## DocumentReference.withConverter()
|
||||
|
||||
Applies a custom data converter to this `DocumentReference`<!-- -->, allowing you to use your own custom model objects with Firestore. When you call [setDoc()](./firestore_lite.md#setdoc_ee215ad)<!-- -->, [getDoc()](./firestore_lite.md#getdoc_4569087)<!-- -->, etc. with the returned `DocumentReference` instance, the provided converter will convert between Firestore data of type `NewDbModelType` and your custom type `NewAppModelType`<!-- -->.
|
||||
|
||||
@@ -37,8 +37,9 @@ export declare class GeoPoint
|
||||
|
||||
| Method | Modifiers | Description |
|
||||
| --- | --- | --- |
|
||||
| [fromJSON(json)](./firestore_lite.geopoint.md#geopointfromjson) | <code>static</code> | Builds a <code>GeoPoint</code> instance from a JSON object created by [GeoPoint.toJSON()](./firestore_.geopoint.md#geopointtojson)<!-- -->. |
|
||||
| [isEqual(other)](./firestore_lite.geopoint.md#geopointisequal) | | Returns true if this <code>GeoPoint</code> is equal to the provided one. |
|
||||
| [toJSON()](./firestore_lite.geopoint.md#geopointtojson) | | Returns a JSON-serializable representation of this GeoPoint. |
|
||||
| [toJSON()](./firestore_lite.geopoint.md#geopointtojson) | | Returns a JSON-serializable representation of this <code>GeoPoint</code> instance. |
|
||||
|
||||
## GeoPoint.(constructor)
|
||||
|
||||
@@ -77,6 +78,28 @@ The longitude of this `GeoPoint` instance.
|
||||
get longitude(): number;
|
||||
```
|
||||
|
||||
## GeoPoint.fromJSON()
|
||||
|
||||
Builds a `GeoPoint` instance from a JSON object created by [GeoPoint.toJSON()](./firestore_.geopoint.md#geopointtojson)<!-- -->.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
static fromJSON(json: object): GeoPoint;
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| json | object | a JSON object represention of a <code>GeoPoint</code> instance |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
[GeoPoint](./firestore_lite.geopoint.md#geopoint_class)
|
||||
|
||||
an instance of [GeoPoint](./firestore_.geopoint.md#geopoint_class) if the JSON object could be parsed. Throws a [FirestoreError](./firestore_.firestoreerror.md#firestoreerror_class) if an error occurs.
|
||||
|
||||
## GeoPoint.isEqual()
|
||||
|
||||
Returns true if this `GeoPoint` is equal to the provided one.
|
||||
@@ -101,7 +124,7 @@ true if this `GeoPoint` is equal to the provided one.
|
||||
|
||||
## GeoPoint.toJSON()
|
||||
|
||||
Returns a JSON-serializable representation of this GeoPoint.
|
||||
Returns a JSON-serializable representation of this `GeoPoint` instance.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -109,9 +132,12 @@ Returns a JSON-serializable representation of this GeoPoint.
|
||||
toJSON(): {
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
type: string;
|
||||
};
|
||||
```
|
||||
<b>Returns:</b>
|
||||
|
||||
{ latitude: number; longitude: number; }
|
||||
{ latitude: number; longitude: number; type: string; }
|
||||
|
||||
a JSON representation of this object.
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ export declare class Timestamp
|
||||
| Method | Modifiers | Description |
|
||||
| --- | --- | --- |
|
||||
| [fromDate(date)](./firestore_lite.timestamp.md#timestampfromdate) | <code>static</code> | Creates a new timestamp from the given date. |
|
||||
| [fromJSON(json)](./firestore_lite.timestamp.md#timestampfromjson) | <code>static</code> | Builds a <code>Timestamp</code> instance from a JSON object created by [Timestamp.toJSON()](./firestore_.timestamp.md#timestamptojson)<!-- -->. |
|
||||
| [fromMillis(milliseconds)](./firestore_lite.timestamp.md#timestampfrommillis) | <code>static</code> | Creates a new timestamp from the given number of milliseconds. |
|
||||
| [isEqual(other)](./firestore_lite.timestamp.md#timestampisequal) | | Returns true if this <code>Timestamp</code> is equal to the provided one. |
|
||||
| [now()](./firestore_lite.timestamp.md#timestampnow) | <code>static</code> | Creates a new timestamp with the current date, with millisecond precision. |
|
||||
@@ -110,6 +111,26 @@ static fromDate(date: Date): Timestamp;
|
||||
|
||||
A new `Timestamp` representing the same point in time as the given date.
|
||||
|
||||
## Timestamp.fromJSON()
|
||||
|
||||
Builds a `Timestamp` instance from a JSON object created by [Timestamp.toJSON()](./firestore_.timestamp.md#timestamptojson)<!-- -->.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
static fromJSON(json: object): Timestamp;
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| json | object | |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
[Timestamp](./firestore_lite.timestamp.md#timestamp_class)
|
||||
|
||||
## Timestamp.fromMillis()
|
||||
|
||||
Creates a new timestamp from the given number of milliseconds.
|
||||
@@ -194,11 +215,12 @@ Returns a JSON-serializable representation of this `Timestamp`<!-- -->.
|
||||
toJSON(): {
|
||||
seconds: number;
|
||||
nanoseconds: number;
|
||||
type: string;
|
||||
};
|
||||
```
|
||||
<b>Returns:</b>
|
||||
|
||||
{ seconds: number; nanoseconds: number; }
|
||||
{ seconds: number; nanoseconds: number; type: string; }
|
||||
|
||||
## Timestamp.toMillis()
|
||||
|
||||
|
||||
@@ -24,8 +24,32 @@ export declare class VectorValue
|
||||
|
||||
| Method | Modifiers | Description |
|
||||
| --- | --- | --- |
|
||||
| [fromJSON(json)](./firestore_lite.vectorvalue.md#vectorvaluefromjson) | <code>static</code> | Builds a <code>VectorValue</code> instance from a JSON object created by [VectorValue.toJSON()](./firestore_.vectorvalue.md#vectorvaluetojson)<!-- -->. |
|
||||
| [isEqual(other)](./firestore_lite.vectorvalue.md#vectorvalueisequal) | | Returns <code>true</code> if the two <code>VectorValue</code> values have the same raw number arrays, returns <code>false</code> otherwise. |
|
||||
| [toArray()](./firestore_lite.vectorvalue.md#vectorvaluetoarray) | | Returns a copy of the raw number array form of the vector. |
|
||||
| [toJSON()](./firestore_lite.vectorvalue.md#vectorvaluetojson) | | Returns a JSON-serializable representation of this <code>VectorValue</code> instance. |
|
||||
|
||||
## VectorValue.fromJSON()
|
||||
|
||||
Builds a `VectorValue` instance from a JSON object created by [VectorValue.toJSON()](./firestore_.vectorvalue.md#vectorvaluetojson)<!-- -->.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
static fromJSON(json: object): VectorValue;
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| json | object | a JSON object represention of a <code>VectorValue</code> instance. |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
[VectorValue](./firestore_lite.vectorvalue.md#vectorvalue_class)
|
||||
|
||||
an instance of [VectorValue](./firestore_.vectorvalue.md#vectorvalue_class) if the JSON object could be parsed. Throws a [FirestoreError](./firestore_.firestoreerror.md#firestoreerror_class) if an error occurs.
|
||||
|
||||
## VectorValue.isEqual()
|
||||
|
||||
@@ -60,3 +84,18 @@ toArray(): number[];
|
||||
|
||||
number\[\]
|
||||
|
||||
## VectorValue.toJSON()
|
||||
|
||||
Returns a JSON-serializable representation of this `VectorValue` instance.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
toJSON(): object;
|
||||
```
|
||||
<b>Returns:</b>
|
||||
|
||||
object
|
||||
|
||||
a JSON representation of this object.
|
||||
|
||||
|
||||
@@ -89,9 +89,11 @@ export {
|
||||
DocumentChange,
|
||||
DocumentChangeType,
|
||||
DocumentSnapshot,
|
||||
documentSnapshotFromJSON,
|
||||
FirestoreDataConverter,
|
||||
QueryDocumentSnapshot,
|
||||
QuerySnapshot,
|
||||
querySnapshotFromJSON,
|
||||
snapshotEqual,
|
||||
SnapshotMetadata,
|
||||
SnapshotOptions
|
||||
@@ -161,6 +163,7 @@ export {
|
||||
getDocsFromServer,
|
||||
onSnapshot,
|
||||
onSnapshotsInSync,
|
||||
onSnapshotResume,
|
||||
setDoc,
|
||||
updateDoc
|
||||
} from './api/reference_impl';
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
import { getModularInstance } from '@firebase/util';
|
||||
|
||||
import { loadBundle, namedQuery } from '../api/database';
|
||||
import {
|
||||
CompleteFn,
|
||||
ErrorFn,
|
||||
@@ -59,14 +60,20 @@ import {
|
||||
parseUpdateVarargs
|
||||
} from '../lite-api/user_data_reader';
|
||||
import { AbstractUserDataWriter } from '../lite-api/user_data_writer';
|
||||
import { DocumentKey } from '../model/document_key';
|
||||
import { DeleteMutation, Mutation, Precondition } from '../model/mutation';
|
||||
import { debugAssert } from '../util/assert';
|
||||
import { ByteString } from '../util/byte_string';
|
||||
import { FirestoreError } from '../util/error';
|
||||
import { Code, FirestoreError } from '../util/error';
|
||||
import { cast } from '../util/input_validation';
|
||||
|
||||
import { ensureFirestoreConfigured, Firestore } from './database';
|
||||
import { DocumentSnapshot, QuerySnapshot, SnapshotMetadata } from './snapshot';
|
||||
import {
|
||||
DocumentSnapshot,
|
||||
FirestoreDataConverter,
|
||||
QuerySnapshot,
|
||||
SnapshotMetadata
|
||||
} from './snapshot';
|
||||
|
||||
/**
|
||||
* An options object that can be passed to {@link (onSnapshot:1)} and {@link
|
||||
@@ -483,12 +490,11 @@ export interface Unsubscribe {
|
||||
// integration tests
|
||||
|
||||
/**
|
||||
* Attaches a listener for `DocumentSnapshot` events. You may either pass
|
||||
* individual `onNext` and `onError` callbacks or pass a single observer
|
||||
* object with `next` and `error` callbacks.
|
||||
* Attaches a listener for `DocumentSnapshot` events. You may either pass individual `onNext` and
|
||||
* `onError` callbacks or pass a single observer object with `next` and `error` callbacks.
|
||||
*
|
||||
* NOTE: Although an `onCompletion` callback can be provided, it will
|
||||
* never be called because the snapshot stream is never-ending.
|
||||
* NOTE: Although an `onCompletion` callback can be provided, it will never be called because the
|
||||
* snapshot stream is never-ending.
|
||||
*
|
||||
* @param reference - A reference to the document to listen to.
|
||||
* @param observer - A single object containing `next` and `error` callbacks.
|
||||
@@ -504,12 +510,11 @@ export function onSnapshot<AppModelType, DbModelType extends DocumentData>(
|
||||
}
|
||||
): Unsubscribe;
|
||||
/**
|
||||
* Attaches a listener for `DocumentSnapshot` events. You may either pass
|
||||
* individual `onNext` and `onError` callbacks or pass a single observer
|
||||
* object with `next` and `error` callbacks.
|
||||
* Attaches a listener for `DocumentSnapshot` events. You may either pass individual `onNext` and
|
||||
* `onError` callbacks or pass a single observer object with `next` and `error` callbacks.
|
||||
*
|
||||
* NOTE: Although an `onCompletion` callback can be provided, it will
|
||||
* never be called because the snapshot stream is never-ending.
|
||||
* NOTE: Although an `onCompletion` callback can be provided, it will never be called because the
|
||||
* snapshot stream is never-ending.
|
||||
*
|
||||
* @param reference - A reference to the document to listen to.
|
||||
* @param options - Options controlling the listen behavior.
|
||||
@@ -527,22 +532,18 @@ export function onSnapshot<AppModelType, DbModelType extends DocumentData>(
|
||||
}
|
||||
): Unsubscribe;
|
||||
/**
|
||||
* Attaches a listener for `DocumentSnapshot` events. You may either pass
|
||||
* individual `onNext` and `onError` callbacks or pass a single observer
|
||||
* object with `next` and `error` callbacks.
|
||||
* Attaches a listener for `DocumentSnapshot` events. You may either pass individual `onNext` and
|
||||
* `onError` callbacks or pass a single observer object with `next` and `error` callbacks.
|
||||
*
|
||||
* NOTE: Although an `onCompletion` callback can be provided, it will
|
||||
* never be called because the snapshot stream is never-ending.
|
||||
* NOTE: Although an `onCompletion` callback can be provided, it will never be called because the
|
||||
* snapshot stream is never-ending.
|
||||
*
|
||||
* @param reference - A reference to the document to listen to.
|
||||
* @param onNext - A callback to be called every time a new `DocumentSnapshot`
|
||||
* is available.
|
||||
* @param onError - A callback to be called if the listen fails or is
|
||||
* cancelled. No further callbacks will occur.
|
||||
* @param onCompletion - Can be provided, but will not be called since streams are
|
||||
* never ending.
|
||||
* @returns An unsubscribe function that can be called to cancel
|
||||
* the snapshot listener.
|
||||
* @param onNext - A callback to be called every time a new `DocumentSnapshot` is available.
|
||||
* @param onError - A callback to be called if the listen fails or is cancelled. No further
|
||||
* callbacks will occur.
|
||||
* @param onCompletion - Can be provided, but will not be called since streams are never ending.
|
||||
* @returns An unsubscribe function that can be called to cancel the snapshot listener.
|
||||
*/
|
||||
export function onSnapshot<AppModelType, DbModelType extends DocumentData>(
|
||||
reference: DocumentReference<AppModelType, DbModelType>,
|
||||
@@ -551,23 +552,19 @@ export function onSnapshot<AppModelType, DbModelType extends DocumentData>(
|
||||
onCompletion?: () => void
|
||||
): Unsubscribe;
|
||||
/**
|
||||
* Attaches a listener for `DocumentSnapshot` events. You may either pass
|
||||
* individual `onNext` and `onError` callbacks or pass a single observer
|
||||
* object with `next` and `error` callbacks.
|
||||
* Attaches a listener for `DocumentSnapshot` events. You may either pass individual `onNext` and
|
||||
* `onError` callbacks or pass a single observer object with `next` and `error` callbacks.
|
||||
*
|
||||
* NOTE: Although an `onCompletion` callback can be provided, it will
|
||||
* never be called because the snapshot stream is never-ending.
|
||||
* NOTE: Although an `onCompletion` callback can be provided, it will never be called because the
|
||||
* snapshot stream is never-ending.
|
||||
*
|
||||
* @param reference - A reference to the document to listen to.
|
||||
* @param options - Options controlling the listen behavior.
|
||||
* @param onNext - A callback to be called every time a new `DocumentSnapshot`
|
||||
* is available.
|
||||
* @param onError - A callback to be called if the listen fails or is
|
||||
* cancelled. No further callbacks will occur.
|
||||
* @param onCompletion - Can be provided, but will not be called since streams are
|
||||
* never ending.
|
||||
* @returns An unsubscribe function that can be called to cancel
|
||||
* the snapshot listener.
|
||||
* @param onNext - A callback to be called every time a new `DocumentSnapshot` is available.
|
||||
* @param onError - A callback to be called if the listen fails or is cancelled. No further
|
||||
* callbacks will occur.
|
||||
* @param onCompletion - Can be provided, but will not be called since streams are never ending.
|
||||
* @returns An unsubscribe function that can be called to cancel the snapshot listener.
|
||||
*/
|
||||
export function onSnapshot<AppModelType, DbModelType extends DocumentData>(
|
||||
reference: DocumentReference<AppModelType, DbModelType>,
|
||||
@@ -577,18 +574,16 @@ export function onSnapshot<AppModelType, DbModelType extends DocumentData>(
|
||||
onCompletion?: () => void
|
||||
): Unsubscribe;
|
||||
/**
|
||||
* Attaches a listener for `QuerySnapshot` events. You may either pass
|
||||
* individual `onNext` and `onError` callbacks or pass a single observer
|
||||
* object with `next` and `error` callbacks. The listener can be cancelled by
|
||||
* calling the function that is returned when `onSnapshot` is called.
|
||||
* Attaches a listener for `QuerySnapshot` events. You may either pass individual `onNext` and
|
||||
* `onError` callbacks or pass a single observer object with `next` and `error` callbacks. The
|
||||
* listener can be cancelled by calling the function that is returned when `onSnapshot` is called.
|
||||
*
|
||||
* NOTE: Although an `onCompletion` callback can be provided, it will
|
||||
* never be called because the snapshot stream is never-ending.
|
||||
* NOTE: Although an `onCompletion` callback can be provided, it will never be called because the
|
||||
* snapshot stream is never-ending.
|
||||
*
|
||||
* @param query - The query to listen to.
|
||||
* @param observer - A single object containing `next` and `error` callbacks.
|
||||
* @returns An unsubscribe function that can be called to cancel
|
||||
* the snapshot listener.
|
||||
* @returns An unsubscribe function that can be called to cancel the snapshot listener.
|
||||
*/
|
||||
export function onSnapshot<AppModelType, DbModelType extends DocumentData>(
|
||||
query: Query<AppModelType, DbModelType>,
|
||||
@@ -599,19 +594,17 @@ export function onSnapshot<AppModelType, DbModelType extends DocumentData>(
|
||||
}
|
||||
): Unsubscribe;
|
||||
/**
|
||||
* Attaches a listener for `QuerySnapshot` events. You may either pass
|
||||
* individual `onNext` and `onError` callbacks or pass a single observer
|
||||
* object with `next` and `error` callbacks. The listener can be cancelled by
|
||||
* calling the function that is returned when `onSnapshot` is called.
|
||||
* Attaches a listener for `QuerySnapshot` events. You may either pass individual `onNext` and
|
||||
* `onError` callbacks or pass a single observer object with `next` and `error` callbacks. The
|
||||
* listener can be cancelled by calling the function that is returned when `onSnapshot` is called.
|
||||
*
|
||||
* NOTE: Although an `onCompletion` callback can be provided, it will
|
||||
* never be called because the snapshot stream is never-ending.
|
||||
* NOTE: Although an `onCompletion` callback can be provided, it will never be called because the
|
||||
* snapshot stream is never-ending.
|
||||
*
|
||||
* @param query - The query to listen to.
|
||||
* @param options - Options controlling the listen behavior.
|
||||
* @param observer - A single object containing `next` and `error` callbacks.
|
||||
* @returns An unsubscribe function that can be called to cancel
|
||||
* the snapshot listener.
|
||||
* @returns An unsubscribe function that can be called to cancel the snapshot listener.
|
||||
*/
|
||||
export function onSnapshot<AppModelType, DbModelType extends DocumentData>(
|
||||
query: Query<AppModelType, DbModelType>,
|
||||
@@ -623,23 +616,19 @@ export function onSnapshot<AppModelType, DbModelType extends DocumentData>(
|
||||
}
|
||||
): Unsubscribe;
|
||||
/**
|
||||
* Attaches a listener for `QuerySnapshot` events. You may either pass
|
||||
* individual `onNext` and `onError` callbacks or pass a single observer
|
||||
* object with `next` and `error` callbacks. The listener can be cancelled by
|
||||
* calling the function that is returned when `onSnapshot` is called.
|
||||
* Attaches a listener for `QuerySnapshot` events. You may either pass individual `onNext` and
|
||||
* `onError` callbacks or pass a single observer object with `next` and `error` callbacks. The
|
||||
* listener can be cancelled by calling the function that is returned when `onSnapshot` is called.
|
||||
*
|
||||
* NOTE: Although an `onCompletion` callback can be provided, it will
|
||||
* never be called because the snapshot stream is never-ending.
|
||||
* NOTE: Although an `onCompletion` callback can be provided, it will never be called because the
|
||||
* snapshot stream is never-ending.
|
||||
*
|
||||
* @param query - The query to listen to.
|
||||
* @param onNext - A callback to be called every time a new `QuerySnapshot`
|
||||
* is available.
|
||||
* @param onCompletion - Can be provided, but will not be called since streams are
|
||||
* never ending.
|
||||
* @param onError - A callback to be called if the listen fails or is
|
||||
* cancelled. No further callbacks will occur.
|
||||
* @returns An unsubscribe function that can be called to cancel
|
||||
* the snapshot listener.
|
||||
* @param onNext - A callback to be called every time a new `QuerySnapshot` is available.
|
||||
* @param onCompletion - Can be provided, but will not be called since streams are never ending.
|
||||
* @param onError - A callback to be called if the listen fails or is cancelled. No further
|
||||
* callbacks will occur.
|
||||
* @returns An unsubscribe function that can be called to cancel the snapshot listener.
|
||||
*/
|
||||
export function onSnapshot<AppModelType, DbModelType extends DocumentData>(
|
||||
query: Query<AppModelType, DbModelType>,
|
||||
@@ -648,24 +637,20 @@ export function onSnapshot<AppModelType, DbModelType extends DocumentData>(
|
||||
onCompletion?: () => void
|
||||
): Unsubscribe;
|
||||
/**
|
||||
* Attaches a listener for `QuerySnapshot` events. You may either pass
|
||||
* individual `onNext` and `onError` callbacks or pass a single observer
|
||||
* object with `next` and `error` callbacks. The listener can be cancelled by
|
||||
* calling the function that is returned when `onSnapshot` is called.
|
||||
* Attaches a listener for `QuerySnapshot` events. You may either pass individual `onNext` and
|
||||
* `onError` callbacks or pass a single observer object with `next` and `error` callbacks. The
|
||||
* listener can be cancelled by calling the function that is returned when `onSnapshot` is called.
|
||||
*
|
||||
* NOTE: Although an `onCompletion` callback can be provided, it will
|
||||
* never be called because the snapshot stream is never-ending.
|
||||
* NOTE: Although an `onCompletion` callback can be provided, it will never be called because the
|
||||
* snapshot stream is never-ending.
|
||||
*
|
||||
* @param query - The query to listen to.
|
||||
* @param options - Options controlling the listen behavior.
|
||||
* @param onNext - A callback to be called every time a new `QuerySnapshot`
|
||||
* is available.
|
||||
* @param onCompletion - Can be provided, but will not be called since streams are
|
||||
* never ending.
|
||||
* @param onError - A callback to be called if the listen fails or is
|
||||
* cancelled. No further callbacks will occur.
|
||||
* @returns An unsubscribe function that can be called to cancel
|
||||
* the snapshot listener.
|
||||
* @param onNext - A callback to be called every time a new `QuerySnapshot` is available.
|
||||
* @param onCompletion - Can be provided, but will not be called since streams are never ending.
|
||||
* @param onError - A callback to be called if the listen fails or is cancelled. No further
|
||||
* callbacks will occur.
|
||||
* @returns An unsubscribe function that can be called to cancel the snapshot listener.
|
||||
*/
|
||||
export function onSnapshot<AppModelType, DbModelType extends DocumentData>(
|
||||
query: Query<AppModelType, DbModelType>,
|
||||
@@ -680,16 +665,15 @@ export function onSnapshot<AppModelType, DbModelType extends DocumentData>(
|
||||
| DocumentReference<AppModelType, DbModelType>,
|
||||
...args: unknown[]
|
||||
): Unsubscribe {
|
||||
// onSnapshot for Query or Document.
|
||||
reference = getModularInstance(reference);
|
||||
|
||||
let options: SnapshotListenOptions = {
|
||||
includeMetadataChanges: false,
|
||||
source: 'default'
|
||||
};
|
||||
let currArg = 0;
|
||||
if (typeof args[currArg] === 'object' && !isPartialObserver(args[currArg])) {
|
||||
options = args[currArg] as SnapshotListenOptions;
|
||||
currArg++;
|
||||
options = args[currArg++] as SnapshotListenOptions;
|
||||
}
|
||||
|
||||
const internalOptions = {
|
||||
@@ -736,7 +720,6 @@ export function onSnapshot<AppModelType, DbModelType extends DocumentData>(
|
||||
firestore = cast(query.firestore, Firestore);
|
||||
internalQuery = query._query;
|
||||
const userDataWriter = new ExpUserDataWriter(firestore);
|
||||
|
||||
observer = {
|
||||
next: snapshot => {
|
||||
if (args[currArg]) {
|
||||
@@ -761,6 +744,340 @@ export function onSnapshot<AppModelType, DbModelType extends DocumentData>(
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches a listener for `QuerySnapshot` events based on data generated by invoking
|
||||
* {@link QuerySnapshot.toJSON} You may either pass individual `onNext` and `onError` callbacks or
|
||||
* pass a single observer object with `next` and `error` callbacks. The listener can be cancelled by
|
||||
* calling the function that is returned when `onSnapshot` is called.
|
||||
*
|
||||
* NOTE: Although an `onCompletion` callback can be provided, it will never be called because the
|
||||
* snapshot stream is never-ending.
|
||||
*
|
||||
* @param firestore - The {@link Firestore} instance to enable the listener for.
|
||||
* @param snapshotJson - A JSON object generated by invoking {@link QuerySnapshot.toJSON}.
|
||||
* @param onNext - A callback to be called every time a new `QuerySnapshot` is available.
|
||||
* @param onError - A callback to be called if the listen fails or is cancelled. No further
|
||||
* callbacks will occur.
|
||||
* @param onCompletion - Can be provided, but will not be called since streams are never ending.
|
||||
* @param converter - An optional object that converts objects from Firestore before the onNext
|
||||
* listener is invoked.
|
||||
* @returns An unsubscribe function that can be called to cancel the snapshot listener.
|
||||
*/
|
||||
export function onSnapshotResume<
|
||||
AppModelType,
|
||||
DbModelType extends DocumentData
|
||||
>(
|
||||
firestore: Firestore,
|
||||
snapshotJson: object,
|
||||
onNext: (snapshot: QuerySnapshot<AppModelType, DbModelType>) => void,
|
||||
onError?: (error: FirestoreError) => void,
|
||||
onCompletion?: () => void,
|
||||
converter?: FirestoreDataConverter<DbModelType>
|
||||
): Unsubscribe;
|
||||
/**
|
||||
* Attaches a listener for `DocumentSnapshot` events based on data generated by invoking
|
||||
* {@link DocumentSnapshot.toJSON}. You may either pass individual `onNext` and `onError` callbacks or
|
||||
* pass a single observer object with `next` and `error` callbacks. The listener can be cancelled by
|
||||
* calling the function that is returned when `onSnapshot` is called.
|
||||
*
|
||||
* NOTE: Although an `onCompletion` callback can be provided, it will never be called because the
|
||||
* snapshot stream is never-ending.
|
||||
*
|
||||
* @param firestore - The {@link Firestore} instance to enable the listener for.
|
||||
* @param snapshotJson - A JSON object generated by invoking {@link DocumentSnapshot.toJSON}.
|
||||
* @param onNext - A callback to be called every time a new `DocumentSnapshot` is available.
|
||||
* @param onError - A callback to be called if the listen fails or is cancelled. No further
|
||||
* callbacks will occur.
|
||||
* @param onCompletion - Can be provided, but will not be called since streams are
|
||||
* never ending.
|
||||
* @param converter - An optional object that converts objects from Firestore before the onNext
|
||||
* listener is invoked.
|
||||
* @returns An unsubscribe function that can be called to cancel the snapshot listener.
|
||||
*/
|
||||
export function onSnapshotResume<
|
||||
AppModelType,
|
||||
DbModelType extends DocumentData
|
||||
>(
|
||||
firestore: Firestore,
|
||||
snapshotJson: object,
|
||||
onNext: (snapshot: DocumentSnapshot<AppModelType, DbModelType>) => void,
|
||||
onError?: (error: FirestoreError) => void,
|
||||
onCompletion?: () => void,
|
||||
converter?: FirestoreDataConverter<DbModelType>
|
||||
): Unsubscribe;
|
||||
/**
|
||||
* Attaches a listener for `QuerySnapshot` events based on data generated by invoking
|
||||
* {@link QuerySnapshot.toJSON}. You may either pass individual `onNext` and `onError` callbacks or
|
||||
* pass a single observer object with `next` and `error` callbacks. The listener can be cancelled by
|
||||
* calling the function that is returned when `onSnapshot` is called.
|
||||
*
|
||||
* NOTE: Although an `onCompletion` callback can be provided, it will never be called because the
|
||||
* snapshot stream is never-ending.
|
||||
*
|
||||
* @param firestore - The {@link Firestore} instance to enable the listener for.
|
||||
* @param snapshotJson - A JSON object generated by invoking {@link QuerySnapshot.toJSON}.
|
||||
* @param options - Options controlling the listen behavior.
|
||||
* @param onNext - A callback to be called every time a new `QuerySnapshot` is available.
|
||||
* @param onError - A callback to be called if the listen fails or is cancelled. No further
|
||||
* callbacks will occur.
|
||||
* @param onCompletion - Can be provided, but will not be called since streams are never ending.
|
||||
* @param converter - An optional object that converts objects from Firestore before the onNext
|
||||
* listener is invoked.
|
||||
* @returns An unsubscribe function that can be called to cancel the snapshot listener.
|
||||
*/
|
||||
export function onSnapshotResume<
|
||||
AppModelType,
|
||||
DbModelType extends DocumentData
|
||||
>(
|
||||
firestore: Firestore,
|
||||
snapshotJson: object,
|
||||
options: SnapshotListenOptions,
|
||||
onNext: (snapshot: QuerySnapshot<AppModelType, DbModelType>) => void,
|
||||
onError?: (error: FirestoreError) => void,
|
||||
onCompletion?: () => void,
|
||||
converter?: FirestoreDataConverter<DbModelType>
|
||||
): Unsubscribe;
|
||||
/**
|
||||
* Attaches a listener for `DocumentSnapshot` events based on data generated by invoking
|
||||
* {@link DocumentSnapshot.toJSON}. You may either pass individual `onNext` and `onError` callbacks
|
||||
* or pass a single observer object with `next` and `error` callbacks. The listener can be cancelled
|
||||
* by calling the function that is returned when `onSnapshot` is called.
|
||||
*
|
||||
* NOTE: Although an `onCompletion` callback can be provided, it will never be called because the
|
||||
* snapshot stream is never-ending.
|
||||
*
|
||||
* @param firestore - The {@link Firestore} instance to enable the listener for.
|
||||
* @param snapshotJson - A JSON object generated by invoking {@link DocumentSnapshot.toJSON}.
|
||||
* @param options - Options controlling the listen behavior.
|
||||
* @param onNext - A callback to be called every time a new `DocumentSnapshot` is available.
|
||||
* @param onError - A callback to be called if the listen fails or is cancelled. No further
|
||||
* callbacks will occur.
|
||||
* @param onCompletion - Can be provided, but will not be called since streams are never ending.
|
||||
* @param converter - An optional object that converts objects from Firestore before the onNext
|
||||
* listener is invoked.
|
||||
* @returns An unsubscribe function that can be called to cancel
|
||||
* the snapshot listener.
|
||||
*/
|
||||
export function onSnapshotResume<
|
||||
AppModelType,
|
||||
DbModelType extends DocumentData
|
||||
>(
|
||||
firestore: Firestore,
|
||||
snapshotJson: object,
|
||||
options: SnapshotListenOptions,
|
||||
onNext: (snapshot: DocumentSnapshot<AppModelType, DbModelType>) => void,
|
||||
onError?: (error: FirestoreError) => void,
|
||||
onCompletion?: () => void,
|
||||
converter?: FirestoreDataConverter<DbModelType>
|
||||
): Unsubscribe;
|
||||
/**
|
||||
* Attaches a listener for `QuerySnapshot` events based on QuerySnapshot data generated by invoking
|
||||
* {@link QuerySnapshot.toJSON}. You may either pass individual `onNext` and `onError` callbacks or
|
||||
* pass a single observer object with `next` and `error` callbacks. The listener can be cancelled by
|
||||
* calling the function that is returned when `onSnapshot` is called.
|
||||
*
|
||||
* NOTE: Although an `onCompletion` callback can be provided, it will never be called because the
|
||||
* snapshot stream is never-ending.
|
||||
*
|
||||
* @param firestore - The {@link Firestore} instance to enable the listener for.
|
||||
* @param snapshotJson - A JSON object generated by invoking {@link QuerySnapshot.toJSON}.
|
||||
* @param observer - A single object containing `next` and `error` callbacks.
|
||||
* @param converter - An optional object that converts objects from Firestore before the onNext
|
||||
* listener is invoked.
|
||||
* @returns An unsubscribe function that can be called to cancel
|
||||
* the snapshot listener.
|
||||
*/
|
||||
export function onSnapshotResume<
|
||||
AppModelType,
|
||||
DbModelType extends DocumentData
|
||||
>(
|
||||
firestore: Firestore,
|
||||
snapshotJson: object,
|
||||
observer: {
|
||||
next: (snapshot: QuerySnapshot<AppModelType, DbModelType>) => void;
|
||||
error?: (error: FirestoreError) => void;
|
||||
complete?: () => void;
|
||||
},
|
||||
converter?: FirestoreDataConverter<DbModelType>
|
||||
): Unsubscribe;
|
||||
/**
|
||||
* Attaches a listener for `DocumentSnapshot` events based on data generated by invoking
|
||||
* {@link DocumentSnapshot.toJSON} You may either pass individual `onNext` and `onError` callbacks
|
||||
* or pass a single observer object with `next` and `error` callbacks. The listener can be cancelled
|
||||
* by calling the function that is returned when `onSnapshot` is called.
|
||||
*
|
||||
* NOTE: Although an `onCompletion` callback can be provided, it will never be called because the
|
||||
* snapshot stream is never-ending.
|
||||
*
|
||||
* @param firestore - The {@link Firestore} instance to enable the listener for.
|
||||
* @param snapshotJson - A JSON object generated by invoking {@link DocumentSnapshot.toJSON}.
|
||||
* @param observer - A single object containing `next` and `error` callbacks.
|
||||
* @param converter - An optional object that converts objects from Firestore before the onNext
|
||||
* listener is invoked.
|
||||
* @returns An unsubscribe function that can be called to cancel
|
||||
* the snapshot listener.
|
||||
*/
|
||||
export function onSnapshotResume<
|
||||
AppModelType,
|
||||
DbModelType extends DocumentData
|
||||
>(
|
||||
firestore: Firestore,
|
||||
snapshotJson: object,
|
||||
observer: {
|
||||
next: (snapshot: DocumentSnapshot<AppModelType, DbModelType>) => void;
|
||||
error?: (error: FirestoreError) => void;
|
||||
complete?: () => void;
|
||||
},
|
||||
converter?: FirestoreDataConverter<DbModelType>
|
||||
): Unsubscribe;
|
||||
/**
|
||||
* Attaches a listener for `QuerySnapshot` events based on QuerySnapshot data generated by invoking
|
||||
* {@link QuerySnapshot.toJSON} You may either pass individual `onNext` and `onError` callbacks or
|
||||
* pass a single observer object with `next` and `error` callbacks. The listener can be cancelled by
|
||||
* calling the function that is returned when `onSnapshot` is called.
|
||||
*
|
||||
* NOTE: Although an `onCompletion` callback can be provided, it will never be called because the
|
||||
* snapshot stream is never-ending.
|
||||
*
|
||||
* @param firestore - The {@link Firestore} instance to enable the listener for.
|
||||
* @param snapshotJson - A JSON object generated by invoking {@link QuerySnapshot.toJSON}.
|
||||
* @param options - Options controlling the listen behavior.
|
||||
* @param observer - A single object containing `next` and `error` callbacks.
|
||||
* @param converter - An optional object that converts objects from Firestore before the onNext
|
||||
* listener is invoked.
|
||||
* @returns An unsubscribe function that can be called to cancel
|
||||
* the snapshot listener.
|
||||
*/
|
||||
export function onSnapshotResume<
|
||||
AppModelType,
|
||||
DbModelType extends DocumentData
|
||||
>(
|
||||
firestore: Firestore,
|
||||
snapshotJson: object,
|
||||
options: SnapshotListenOptions,
|
||||
observer: {
|
||||
next: (snapshot: QuerySnapshot<AppModelType, DbModelType>) => void;
|
||||
error?: (error: FirestoreError) => void;
|
||||
complete?: () => void;
|
||||
},
|
||||
converter?: FirestoreDataConverter<DbModelType>
|
||||
): Unsubscribe;
|
||||
/**
|
||||
* Attaches a listener for `DocumentSnapshot` events based on QuerySnapshot data generated by
|
||||
* invoking {@link DocumentSnapshot.toJSON} You may either pass individual `onNext` and `onError`
|
||||
* callbacks or pass a single observer object with `next` and `error` callbacks. The listener can be
|
||||
* cancelled by calling the function that is returned when `onSnapshot` is called.
|
||||
*
|
||||
* NOTE: Although an `onCompletion` callback can be provided, it will never be called because the
|
||||
* snapshot stream is never-ending.
|
||||
*
|
||||
* @param firestore - The {@link Firestore} instance to enable the listener for.
|
||||
* @param snapshotJson - A JSON object generated by invoking {@link DocumentSnapshot.toJSON}.
|
||||
* @param options - Options controlling the listen behavior.
|
||||
* @param observer - A single object containing `next` and `error` callbacks.
|
||||
* @param converter - An optional object that converts objects from Firestore before the onNext
|
||||
* listener is invoked.
|
||||
* @returns An unsubscribe function that can be called to cancel the snapshot listener.
|
||||
*/
|
||||
export function onSnapshotResume<
|
||||
AppModelType,
|
||||
DbModelType extends DocumentData
|
||||
>(
|
||||
firestore: Firestore,
|
||||
snapshotJson: object,
|
||||
options: SnapshotListenOptions,
|
||||
observer: {
|
||||
next: (snapshot: DocumentSnapshot<AppModelType, DbModelType>) => void;
|
||||
error?: (error: FirestoreError) => void;
|
||||
complete?: () => void;
|
||||
},
|
||||
converter?: FirestoreDataConverter<DbModelType>
|
||||
): Unsubscribe;
|
||||
export function onSnapshotResume<
|
||||
AppModelType,
|
||||
DbModelType extends DocumentData
|
||||
>(reference: Firestore, snapshotJson: object, ...args: unknown[]): Unsubscribe {
|
||||
const db = getModularInstance(reference);
|
||||
const json = normalizeSnapshotJsonFields(snapshotJson);
|
||||
if (json.error) {
|
||||
throw new FirestoreError(Code.INVALID_ARGUMENT, json.error);
|
||||
}
|
||||
let curArg = 0;
|
||||
let options: SnapshotListenOptions | undefined = undefined;
|
||||
if (typeof args[curArg] === 'object' && !isPartialObserver(args[curArg])) {
|
||||
options = args[curArg++] as SnapshotListenOptions;
|
||||
}
|
||||
|
||||
if (json.bundleSource === 'QuerySnapshot') {
|
||||
let observer: {
|
||||
next: (snapshot: QuerySnapshot<AppModelType, DbModelType>) => void;
|
||||
error?: (error: FirestoreError) => void;
|
||||
complete?: () => void;
|
||||
} | null = null;
|
||||
if (typeof args[curArg] === 'object' && isPartialObserver(args[curArg])) {
|
||||
const userObserver = args[curArg++] as PartialObserver<
|
||||
QuerySnapshot<AppModelType, DbModelType>
|
||||
>;
|
||||
observer = {
|
||||
next: userObserver.next!,
|
||||
error: userObserver.error,
|
||||
complete: userObserver.complete
|
||||
};
|
||||
} else {
|
||||
observer = {
|
||||
next: args[curArg++] as (
|
||||
snapshot: QuerySnapshot<AppModelType, DbModelType>
|
||||
) => void,
|
||||
error: args[curArg++] as (error: FirestoreError) => void,
|
||||
complete: args[curArg++] as () => void
|
||||
};
|
||||
}
|
||||
return onSnapshotQuerySnapshotBundle(
|
||||
db,
|
||||
json,
|
||||
options,
|
||||
observer!,
|
||||
args[curArg] as FirestoreDataConverter<DbModelType>
|
||||
);
|
||||
} else if (json.bundleSource === 'DocumentSnapshot') {
|
||||
let observer: {
|
||||
next: (snapshot: DocumentSnapshot<AppModelType, DbModelType>) => void;
|
||||
error?: (error: FirestoreError) => void;
|
||||
complete?: () => void;
|
||||
} | null = null;
|
||||
if (typeof args[curArg] === 'object' && isPartialObserver(args[curArg])) {
|
||||
const userObserver = args[curArg++] as PartialObserver<
|
||||
DocumentSnapshot<AppModelType, DbModelType>
|
||||
>;
|
||||
observer = {
|
||||
next: userObserver.next!,
|
||||
error: userObserver.error,
|
||||
complete: userObserver.complete
|
||||
};
|
||||
} else {
|
||||
observer = {
|
||||
next: args[curArg++] as (
|
||||
snapshot: DocumentSnapshot<AppModelType, DbModelType>
|
||||
) => void,
|
||||
error: args[curArg++] as (error: FirestoreError) => void,
|
||||
complete: args[curArg++] as () => void
|
||||
};
|
||||
}
|
||||
return onSnapshotDocumentSnapshotBundle(
|
||||
db,
|
||||
json,
|
||||
options,
|
||||
observer!,
|
||||
args[curArg] as FirestoreDataConverter<DbModelType>
|
||||
);
|
||||
} else {
|
||||
throw new FirestoreError(
|
||||
Code.INVALID_ARGUMENT,
|
||||
`unsupported bundle source: ${json.bundleSource}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(firestorexp): Make sure these overloads are tested via the Firestore
|
||||
// integration tests
|
||||
|
||||
@@ -859,3 +1176,186 @@ function convertToDocSnapshot<AppModelType, DbModelType extends DocumentData>(
|
||||
ref.converter
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures the data required to construct an {@link onSnapshot} listener exist in a `snapshotJson`
|
||||
* object that originates from {@link DocumentSnapshot.toJSON} or {@link Querysnapshot.toJSON}. The
|
||||
* data is normalized into a typed object.
|
||||
*
|
||||
* @param snapshotJson - The JSON object that the app provided to {@link onSnapshot}.
|
||||
* @returns A normalized object that contains all of the required bundle JSON fields. If
|
||||
* {@link snapshotJson} doesn't contain the required fields, or if the fields exist as empty
|
||||
* strings, then the {@link snapshotJson.error} field will be a non empty string.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
function normalizeSnapshotJsonFields(snapshotJson: object): {
|
||||
bundle: string;
|
||||
bundleName: string;
|
||||
bundleSource: string;
|
||||
error?: string;
|
||||
} {
|
||||
const result: {
|
||||
bundle: string;
|
||||
bundleName: string;
|
||||
bundleSource: string;
|
||||
error?: string;
|
||||
} = {
|
||||
bundle: '',
|
||||
bundleName: '',
|
||||
bundleSource: ''
|
||||
};
|
||||
const requiredKeys = ['bundle', 'bundleName', 'bundleSource'];
|
||||
for (const key of requiredKeys) {
|
||||
if (!(key in snapshotJson)) {
|
||||
result.error = `snapshotJson missing required field: ${key}`;
|
||||
break;
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const value = (snapshotJson as any)[key];
|
||||
if (typeof value !== 'string') {
|
||||
result.error = `snapshotJson field '${key}' must be a string.`;
|
||||
break;
|
||||
}
|
||||
if (value.length === 0) {
|
||||
result.error = `snapshotJson field '${key}' cannot be an empty string.`;
|
||||
break;
|
||||
}
|
||||
if (key === 'bundle') {
|
||||
result.bundle = value;
|
||||
} else if (key === 'bundleName') {
|
||||
result.bundleName = value;
|
||||
} else if (key === 'bundleSource') {
|
||||
result.bundleSource = value;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the bundle in a separate task and then invokes {@link onSnapshot} with a
|
||||
* {@link DocumentReference} for the document in the bundle.
|
||||
*
|
||||
* @param firestore - The {@link Firestore} instance for the {@link onSnapshot} operation request.
|
||||
* @param json - The JSON bundle to load, produced by {@link DocumentSnapshot.toJSON}.
|
||||
* @param options - Options controlling the listen behavior.
|
||||
* @param observer - A single object containing `next` and `error` callbacks.
|
||||
* @param converter - An optional object that converts objects from Firestore before the onNext
|
||||
* listener is invoked.
|
||||
* @returns An unsubscribe function that can be called to cancel the snapshot
|
||||
* listener.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
function onSnapshotDocumentSnapshotBundle<
|
||||
AppModelType,
|
||||
DbModelType extends DocumentData
|
||||
>(
|
||||
db: Firestore,
|
||||
json: { bundle: string; bundleName: string; bundleSource: string },
|
||||
options: SnapshotListenOptions | undefined,
|
||||
observer: {
|
||||
next: (snapshot: DocumentSnapshot<AppModelType, DbModelType>) => void;
|
||||
error?: (error: FirestoreError) => void;
|
||||
complete?: () => void;
|
||||
},
|
||||
converter?: FirestoreDataConverter<DbModelType>
|
||||
): Unsubscribe {
|
||||
let unsubscribed: boolean = false;
|
||||
let internalUnsubscribe: Unsubscribe | undefined;
|
||||
const loadTask = loadBundle(db, json.bundle);
|
||||
loadTask
|
||||
.then(() => {
|
||||
if (!unsubscribed) {
|
||||
const docReference = new DocumentReference(
|
||||
db,
|
||||
converter ? converter : null,
|
||||
DocumentKey.fromPath(json.bundleName)
|
||||
);
|
||||
internalUnsubscribe = onSnapshot(
|
||||
docReference as DocumentReference<AppModelType, DbModelType>,
|
||||
options ? options : {},
|
||||
observer
|
||||
);
|
||||
}
|
||||
})
|
||||
.catch(e => {
|
||||
if (observer.error) {
|
||||
observer.error(e);
|
||||
}
|
||||
return () => {};
|
||||
});
|
||||
return () => {
|
||||
if (unsubscribed) {
|
||||
return;
|
||||
}
|
||||
unsubscribed = true;
|
||||
if (internalUnsubscribe) {
|
||||
internalUnsubscribe();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the bundle in a separate task and then invokes {@link onSnapshot} with a
|
||||
* {@link Query} that represents the Query in the bundle.
|
||||
*
|
||||
* @param firestore - The {@link Firestore} instance for the {@link onSnapshot} operation request.
|
||||
* @param json - The JSON bundle to load, produced by {@link QuerySnapshot.toJSON}.
|
||||
* @param options - Options controlling the listen behavior.
|
||||
* @param observer - A single object containing `next` and `error` callbacks.
|
||||
* @param converter - An optional object that converts objects from Firestore before the onNext
|
||||
* listener is invoked.
|
||||
* @returns An unsubscribe function that can be called to cancel the snapshot
|
||||
* listener.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
function onSnapshotQuerySnapshotBundle<
|
||||
AppModelType,
|
||||
DbModelType extends DocumentData
|
||||
>(
|
||||
db: Firestore,
|
||||
json: { bundle: string; bundleName: string; bundleSource: string },
|
||||
options: SnapshotListenOptions | undefined,
|
||||
observer: {
|
||||
next: (snapshot: QuerySnapshot<AppModelType, DbModelType>) => void;
|
||||
error?: (error: FirestoreError) => void;
|
||||
complete?: () => void;
|
||||
},
|
||||
converter?: FirestoreDataConverter<DbModelType>
|
||||
): Unsubscribe {
|
||||
let unsubscribed: boolean = false;
|
||||
let internalUnsubscribe: Unsubscribe | undefined;
|
||||
const loadTask = loadBundle(db, json.bundle);
|
||||
loadTask
|
||||
.then(() => namedQuery(db, json.bundleName))
|
||||
.then(query => {
|
||||
if (query && !unsubscribed) {
|
||||
const realQuery: Query = (query as Query)!;
|
||||
if (converter) {
|
||||
realQuery.withConverter(converter);
|
||||
}
|
||||
internalUnsubscribe = onSnapshot(
|
||||
query as Query<AppModelType, DbModelType>,
|
||||
options ? options : {},
|
||||
observer
|
||||
);
|
||||
}
|
||||
})
|
||||
.catch(e => {
|
||||
if (observer.error) {
|
||||
observer.error(e);
|
||||
}
|
||||
return () => {};
|
||||
});
|
||||
return () => {
|
||||
if (unsubscribed) {
|
||||
return;
|
||||
}
|
||||
unsubscribed = true;
|
||||
if (internalUnsubscribe) {
|
||||
internalUnsubscribe();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { BundleLoader } from '../core/bundle_impl';
|
||||
import { createBundleReaderSync } from '../core/firestore_client';
|
||||
import { newQueryComparator } from '../core/query';
|
||||
import { ChangeType, ViewSnapshot } from '../core/view_snapshot';
|
||||
import { FieldPath } from '../lite-api/field_path';
|
||||
@@ -26,6 +28,7 @@ import {
|
||||
SetOptions,
|
||||
WithFieldValue
|
||||
} from '../lite-api/reference';
|
||||
import { LiteUserDataWriter } from '../lite-api/reference_impl';
|
||||
import {
|
||||
DocumentSnapshot as LiteDocumentSnapshot,
|
||||
fieldPathFromArgument,
|
||||
@@ -33,14 +36,30 @@ import {
|
||||
} from '../lite-api/snapshot';
|
||||
import { UntypedFirestoreDataConverter } from '../lite-api/user_data_reader';
|
||||
import { AbstractUserDataWriter } from '../lite-api/user_data_writer';
|
||||
import { fromBundledQuery } from '../local/local_serializer';
|
||||
import { documentKeySet } from '../model/collections';
|
||||
import { Document } from '../model/document';
|
||||
import { DocumentKey } from '../model/document_key';
|
||||
import { DocumentSet } from '../model/document_set';
|
||||
import { ResourcePath } from '../model/path';
|
||||
import { newSerializer } from '../platform/serializer';
|
||||
import {
|
||||
buildQuerySnapshotJsonBundle,
|
||||
buildDocumentSnapshotJsonBundle
|
||||
} from '../platform/snapshot_to_json';
|
||||
import { fromDocument } from '../remote/serializer';
|
||||
import { debugAssert, fail } from '../util/assert';
|
||||
import { Code, FirestoreError } from '../util/error';
|
||||
// API extractor fails importing 'property' unless we also explicitly import 'Property'.
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars, unused-imports/no-unused-imports-ts
|
||||
import { Property, property, validateJSON } from '../util/json_validation';
|
||||
import { AutoId } from '../util/misc';
|
||||
|
||||
import { Firestore } from './database';
|
||||
import { SnapshotListenOptions } from './reference_impl';
|
||||
|
||||
const NOT_SUPPORTED = 'NOT SUPPORTED';
|
||||
|
||||
/**
|
||||
* Converter used by `withConverter()` to transform user objects of type
|
||||
* `AppModelType` into Firestore data of type `DbModelType`.
|
||||
@@ -496,6 +515,148 @@ export class DocumentSnapshot<
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
static _jsonSchemaVersion: string = 'firestore/documentSnapshot/1.0';
|
||||
static _jsonSchema = {
|
||||
type: property('string', DocumentSnapshot._jsonSchemaVersion),
|
||||
bundleSource: property('string', 'DocumentSnapshot'),
|
||||
bundleName: property('string'),
|
||||
bundle: property('string')
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a JSON-serializable representation of this `DocumentSnapshot` instance.
|
||||
*
|
||||
* @returns a JSON representation of this object. Throws a {@link FirestoreError} if this
|
||||
* `DocumentSnapshot` has pending writes.
|
||||
*/
|
||||
toJSON(): object {
|
||||
if (this.metadata.hasPendingWrites) {
|
||||
throw new FirestoreError(
|
||||
Code.FAILED_PRECONDITION,
|
||||
'DocumentSnapshot.toJSON() attempted to serialize a document with pending writes. ' +
|
||||
'Await waitForPendingWrites() before invoking toJSON().'
|
||||
);
|
||||
}
|
||||
const document = this._document;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const result: any = {};
|
||||
result['type'] = DocumentSnapshot._jsonSchemaVersion;
|
||||
result['bundle'] = '';
|
||||
result['bundleSource'] = 'DocumentSnapshot';
|
||||
result['bundleName'] = this._key.toString();
|
||||
|
||||
if (
|
||||
!document ||
|
||||
!document.isValidDocument() ||
|
||||
!document.isFoundDocument()
|
||||
) {
|
||||
return result;
|
||||
}
|
||||
const documentData = this._userDataWriter.convertObjectMap(
|
||||
document.data.value.mapValue.fields,
|
||||
'previous'
|
||||
);
|
||||
result['bundle'] = buildDocumentSnapshotJsonBundle(
|
||||
this._firestore,
|
||||
document,
|
||||
documentData,
|
||||
this.ref.path
|
||||
);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a `DocumentSnapshot` instance from a JSON object created by
|
||||
* {@link DocumentSnapshot.toJSON}.
|
||||
*
|
||||
* @param firestore - The {@link Firestore} instance the snapshot should be loaded for.
|
||||
* @param json - a JSON object represention of a `DocumentSnapshot` instance.
|
||||
* @returns an instance of {@link DocumentSnapshot} if the JSON object could be
|
||||
* parsed. Throws a {@link FirestoreError} if an error occurs.
|
||||
*/
|
||||
export function documentSnapshotFromJSON(
|
||||
db: Firestore,
|
||||
json: object
|
||||
): DocumentSnapshot;
|
||||
/**
|
||||
* Builds a `DocumentSnapshot` instance from a JSON object created by
|
||||
* {@link DocumentSnapshot.toJSON}.
|
||||
*
|
||||
* @param firestore - The {@link Firestore} instance the snapshot should be loaded for.
|
||||
* @param json - a JSON object represention of a `DocumentSnapshot` instance.
|
||||
* @param converter - Converts objects to and from Firestore.
|
||||
* @returns an instance of {@link DocumentSnapshot} if the JSON object could be
|
||||
* parsed. Throws a {@link FirestoreError} if an error occurs.
|
||||
*/
|
||||
export function documentSnapshotFromJSON<
|
||||
AppModelType,
|
||||
DbModelType extends DocumentData = DocumentData
|
||||
>(
|
||||
db: Firestore,
|
||||
json: object,
|
||||
converter: FirestoreDataConverter<AppModelType, DbModelType>
|
||||
): DocumentSnapshot<AppModelType, DbModelType>;
|
||||
export function documentSnapshotFromJSON<
|
||||
AppModelType,
|
||||
DbModelType extends DocumentData = DocumentData
|
||||
>(
|
||||
db: Firestore,
|
||||
json: object,
|
||||
converter?: FirestoreDataConverter<AppModelType, DbModelType>
|
||||
): DocumentSnapshot<AppModelType, DbModelType> {
|
||||
if (validateJSON(json, DocumentSnapshot._jsonSchema)) {
|
||||
if (json.bundle === NOT_SUPPORTED) {
|
||||
throw new FirestoreError(
|
||||
Code.INVALID_ARGUMENT,
|
||||
'The provided JSON object was created in a client environment, which is not supported.'
|
||||
);
|
||||
}
|
||||
// Parse the bundle data.
|
||||
const serializer = newSerializer(db._databaseId);
|
||||
const bundleReader = createBundleReaderSync(json.bundle, serializer);
|
||||
const elements = bundleReader.getElements();
|
||||
const bundleLoader: BundleLoader = new BundleLoader(
|
||||
bundleReader.getMetadata(),
|
||||
serializer
|
||||
);
|
||||
for (const element of elements) {
|
||||
bundleLoader.addSizedElement(element);
|
||||
}
|
||||
|
||||
// Ensure that we have the correct number of documents in the bundle.
|
||||
const bundledDocuments = bundleLoader.documents;
|
||||
if (bundledDocuments.length !== 1) {
|
||||
throw new FirestoreError(
|
||||
Code.INVALID_ARGUMENT,
|
||||
`Expected bundle data to contain 1 document, but it contains ${bundledDocuments.length} documents.`
|
||||
);
|
||||
}
|
||||
|
||||
// Build out the internal document data.
|
||||
const document = fromDocument(serializer, bundledDocuments[0].document!);
|
||||
const documentKey = new DocumentKey(
|
||||
ResourcePath.fromString(json.bundleName)
|
||||
);
|
||||
|
||||
// Return the external facing DocumentSnapshot.
|
||||
return new DocumentSnapshot(
|
||||
db,
|
||||
new LiteUserDataWriter(db),
|
||||
documentKey,
|
||||
document,
|
||||
new SnapshotMetadata(
|
||||
/* hasPendingWrites= */ false,
|
||||
/* fromCache= */ false
|
||||
),
|
||||
converter ? converter : null
|
||||
);
|
||||
}
|
||||
throw new FirestoreError(
|
||||
Code.INTERNAL,
|
||||
'Unexpected error creating DocumentSnapshot from JSON.'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -651,6 +812,171 @@ export class QuerySnapshot<
|
||||
|
||||
return this._cachedChanges;
|
||||
}
|
||||
|
||||
static _jsonSchemaVersion: string = 'firestore/querySnapshot/1.0';
|
||||
static _jsonSchema = {
|
||||
type: property('string', QuerySnapshot._jsonSchemaVersion),
|
||||
bundleSource: property('string', 'QuerySnapshot'),
|
||||
bundleName: property('string'),
|
||||
bundle: property('string')
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a JSON-serializable representation of this `QuerySnapshot` instance.
|
||||
*
|
||||
* @returns a JSON representation of this object. Throws a {@link FirestoreError} if this
|
||||
* `QuerySnapshot` has pending writes.
|
||||
*/
|
||||
toJSON(): object {
|
||||
if (this.metadata.hasPendingWrites) {
|
||||
throw new FirestoreError(
|
||||
Code.FAILED_PRECONDITION,
|
||||
'QuerySnapshot.toJSON() attempted to serialize a document with pending writes. ' +
|
||||
'Await waitForPendingWrites() before invoking toJSON().'
|
||||
);
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const result: any = {};
|
||||
result['type'] = QuerySnapshot._jsonSchemaVersion;
|
||||
result['bundleSource'] = 'QuerySnapshot';
|
||||
result['bundleName'] = AutoId.newId();
|
||||
|
||||
const databaseId = this._firestore._databaseId.database;
|
||||
const projectId = this._firestore._databaseId.projectId;
|
||||
const parent = `projects/${projectId}/databases/${databaseId}/documents`;
|
||||
const documents: Document[] = [];
|
||||
const documentData: DocumentData[] = [];
|
||||
const paths: string[] = [];
|
||||
|
||||
this.docs.forEach(doc => {
|
||||
if (doc._document === null) {
|
||||
return;
|
||||
}
|
||||
documents.push(doc._document);
|
||||
documentData.push(
|
||||
this._userDataWriter.convertObjectMap(
|
||||
doc._document.data.value.mapValue.fields,
|
||||
'previous'
|
||||
)
|
||||
);
|
||||
paths.push(doc.ref.path);
|
||||
});
|
||||
result['bundle'] = buildQuerySnapshotJsonBundle(
|
||||
this._firestore,
|
||||
this.query._query,
|
||||
result['bundleName'],
|
||||
parent,
|
||||
paths,
|
||||
documents,
|
||||
documentData
|
||||
);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a `QuerySnapshot` instance from a JSON object created by
|
||||
* {@link QuerySnapshot.toJSON}.
|
||||
*
|
||||
* @param firestore - The {@link Firestore} instance the snapshot should be loaded for.
|
||||
* @param json - a JSON object represention of a `QuerySnapshot` instance.
|
||||
* @returns an instance of {@link QuerySnapshot} if the JSON object could be
|
||||
* parsed. Throws a {@link FirestoreError} if an error occurs.
|
||||
*/
|
||||
export function querySnapshotFromJSON(
|
||||
db: Firestore,
|
||||
json: object
|
||||
): QuerySnapshot;
|
||||
/**
|
||||
* Builds a `QuerySnapshot` instance from a JSON object created by
|
||||
* {@link QuerySnapshot.toJSON}.
|
||||
*
|
||||
* @param firestore - The {@link Firestore} instance the snapshot should be loaded for.
|
||||
* @param json - a JSON object represention of a `QuerySnapshot` instance.
|
||||
* @param converter - Converts objects to and from Firestore.
|
||||
* @returns an instance of {@link QuerySnapshot} if the JSON object could be
|
||||
* parsed. Throws a {@link FirestoreError} if an error occurs.
|
||||
*/
|
||||
export function querySnapshotFromJSON<
|
||||
AppModelType,
|
||||
DbModelType extends DocumentData = DocumentData
|
||||
>(
|
||||
db: Firestore,
|
||||
json: object,
|
||||
converter: FirestoreDataConverter<AppModelType, DbModelType>
|
||||
): QuerySnapshot<AppModelType, DbModelType>;
|
||||
export function querySnapshotFromJSON<
|
||||
AppModelType,
|
||||
DbModelType extends DocumentData
|
||||
>(
|
||||
db: Firestore,
|
||||
json: object,
|
||||
converter?: FirestoreDataConverter<AppModelType, DbModelType>
|
||||
): QuerySnapshot<AppModelType, DbModelType> {
|
||||
if (validateJSON(json, QuerySnapshot._jsonSchema)) {
|
||||
if (json.bundle === NOT_SUPPORTED) {
|
||||
throw new FirestoreError(
|
||||
Code.INVALID_ARGUMENT,
|
||||
'The provided JSON object was created in a client environment, which is not supported.'
|
||||
);
|
||||
}
|
||||
// Parse the bundle data.
|
||||
const serializer = newSerializer(db._databaseId);
|
||||
const bundleReader = createBundleReaderSync(json.bundle, serializer);
|
||||
const elements = bundleReader.getElements();
|
||||
const bundleLoader: BundleLoader = new BundleLoader(
|
||||
bundleReader.getMetadata(),
|
||||
serializer
|
||||
);
|
||||
for (const element of elements) {
|
||||
bundleLoader.addSizedElement(element);
|
||||
}
|
||||
|
||||
if (bundleLoader.queries.length !== 1) {
|
||||
throw new FirestoreError(
|
||||
Code.INVALID_ARGUMENT,
|
||||
`Snapshot data expected 1 query but found ${bundleLoader.queries.length} queries.`
|
||||
);
|
||||
}
|
||||
|
||||
// Create an internal Query object from the named query in the bundle.
|
||||
const query = fromBundledQuery(bundleLoader.queries[0].bundledQuery!);
|
||||
|
||||
// Construct the arrays of document data for the query.
|
||||
const bundledDocuments = bundleLoader.documents;
|
||||
let documentSet = new DocumentSet();
|
||||
bundledDocuments.map(bundledDocument => {
|
||||
const document = fromDocument(serializer, bundledDocument.document!);
|
||||
documentSet = documentSet.add(document);
|
||||
});
|
||||
// Create a view snapshot of the query and documents.
|
||||
const viewSnapshot = ViewSnapshot.fromInitialDocuments(
|
||||
query,
|
||||
documentSet,
|
||||
documentKeySet() /* Zero mutated keys signifies no pending writes. */,
|
||||
/* fromCache= */ false,
|
||||
/* hasCachedResults= */ false
|
||||
);
|
||||
|
||||
// Create an external Query object, required to construct the QuerySnapshot.
|
||||
const externalQuery = new Query<AppModelType, DbModelType>(
|
||||
db,
|
||||
converter ? converter : null,
|
||||
query
|
||||
);
|
||||
|
||||
// Return a new QuerySnapshot with all of the collected data.
|
||||
return new QuerySnapshot<AppModelType, DbModelType>(
|
||||
db,
|
||||
new LiteUserDataWriter(db),
|
||||
externalQuery,
|
||||
viewSnapshot
|
||||
);
|
||||
}
|
||||
throw new FirestoreError(
|
||||
Code.INTERNAL,
|
||||
'Unexpected error creating QuerySnapshot from JSON.'
|
||||
);
|
||||
}
|
||||
|
||||
/** Calculates the array of `DocumentChange`s for a given `ViewSnapshot`. */
|
||||
|
||||
@@ -82,27 +82,42 @@ export class BundleConverterImpl implements BundleConverter {
|
||||
}
|
||||
|
||||
/**
|
||||
* A class to process the elements from a bundle, load them into local
|
||||
* A class to process the elements from a bundle, and optionally load them into local
|
||||
* storage and provide progress update while loading.
|
||||
*/
|
||||
export class BundleLoader {
|
||||
/** The current progress of loading */
|
||||
private progress: LoadBundleTaskProgress;
|
||||
/** Batched queries to be saved into storage */
|
||||
private queries: ProtoNamedQuery[] = [];
|
||||
private _queries: ProtoNamedQuery[] = [];
|
||||
/** Batched documents to be saved into storage */
|
||||
private documents: BundledDocuments = [];
|
||||
private _documents: BundledDocuments = [];
|
||||
/** The collection groups affected by this bundle. */
|
||||
private collectionGroups = new Set<string>();
|
||||
|
||||
constructor(
|
||||
private bundleMetadata: ProtoBundleMetadata,
|
||||
private localStore: LocalStore,
|
||||
private serializer: JsonProtoSerializer
|
||||
) {
|
||||
this.progress = bundleInitialProgress(bundleMetadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the named queries that have been parsed from the SizeBundleElements added by
|
||||
* calling {@link adSizedElement}.
|
||||
*/
|
||||
get queries(): ProtoNamedQuery[] {
|
||||
return this._queries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the BundledDocuments that have been parsed from the SizeBundleElements added by
|
||||
* calling {@link addSizedElement}.
|
||||
*/
|
||||
get documents(): BundledDocuments {
|
||||
return this._documents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an element from the bundle to the loader.
|
||||
*
|
||||
@@ -117,9 +132,9 @@ export class BundleLoader {
|
||||
let documentsLoaded = this.progress.documentsLoaded;
|
||||
|
||||
if (element.payload.namedQuery) {
|
||||
this.queries.push(element.payload.namedQuery);
|
||||
this._queries.push(element.payload.namedQuery);
|
||||
} else if (element.payload.documentMetadata) {
|
||||
this.documents.push({ metadata: element.payload.documentMetadata });
|
||||
this._documents.push({ metadata: element.payload.documentMetadata });
|
||||
if (!element.payload.documentMetadata.exists) {
|
||||
++documentsLoaded;
|
||||
}
|
||||
@@ -133,12 +148,12 @@ export class BundleLoader {
|
||||
this.collectionGroups.add(path.get(path.length - 2));
|
||||
} else if (element.payload.document) {
|
||||
debugAssert(
|
||||
this.documents.length > 0 &&
|
||||
this.documents[this.documents.length - 1].metadata.name ===
|
||||
this._documents.length > 0 &&
|
||||
this._documents[this._documents.length - 1].metadata.name ===
|
||||
element.payload.document.name,
|
||||
'The document being added does not match the stored metadata.'
|
||||
);
|
||||
this.documents[this.documents.length - 1].document =
|
||||
this._documents[this._documents.length - 1].document =
|
||||
element.payload.document;
|
||||
++documentsLoaded;
|
||||
}
|
||||
@@ -176,26 +191,28 @@ export class BundleLoader {
|
||||
/**
|
||||
* Update the progress to 'Success' and return the updated progress.
|
||||
*/
|
||||
async complete(): Promise<BundleLoadResult> {
|
||||
async completeAndStoreAsync(
|
||||
localStore: LocalStore
|
||||
): Promise<BundleLoadResult> {
|
||||
debugAssert(
|
||||
this.documents[this.documents.length - 1]?.metadata.exists !== true ||
|
||||
!!this.documents[this.documents.length - 1].document,
|
||||
this._documents[this._documents.length - 1]?.metadata.exists !== true ||
|
||||
!!this._documents[this._documents.length - 1].document,
|
||||
'Bundled documents end with a document metadata element instead of a document.'
|
||||
);
|
||||
debugAssert(!!this.bundleMetadata.id, 'Bundle ID must be set.');
|
||||
|
||||
const changedDocs = await localStoreApplyBundledDocuments(
|
||||
this.localStore,
|
||||
localStore,
|
||||
new BundleConverterImpl(this.serializer),
|
||||
this.documents,
|
||||
this._documents,
|
||||
this.bundleMetadata.id!
|
||||
);
|
||||
|
||||
const queryDocumentMap = this.getQueryDocumentMapping(this.documents);
|
||||
|
||||
for (const q of this.queries) {
|
||||
for (const q of this._queries) {
|
||||
await localStoreSaveNamedQuery(
|
||||
this.localStore,
|
||||
localStore,
|
||||
q,
|
||||
queryDocumentMap.get(q.name!)
|
||||
);
|
||||
|
||||
@@ -53,8 +53,9 @@ import { JsonProtoSerializer } from '../remote/serializer';
|
||||
import { debugAssert } from '../util/assert';
|
||||
import { AsyncObserver } from '../util/async_observer';
|
||||
import { AsyncQueue, wrapInUserErrorIfRecoverable } from '../util/async_queue';
|
||||
import { BundleReader } from '../util/bundle_reader';
|
||||
import { BundleReader, BundleReaderSync } from '../util/bundle_reader';
|
||||
import { newBundleReader } from '../util/bundle_reader_impl';
|
||||
import { newBundleReaderSync } from '../util/bundle_reader_sync_impl';
|
||||
import { Code, FirestoreError } from '../util/error';
|
||||
import { logDebug, logWarn } from '../util/log';
|
||||
import { AutoId } from '../util/misc';
|
||||
@@ -351,7 +352,7 @@ async function ensureOfflineComponents(
|
||||
return client._offlineComponents!;
|
||||
}
|
||||
|
||||
async function ensureOnlineComponents(
|
||||
export async function ensureOnlineComponents(
|
||||
client: FirestoreClient
|
||||
): Promise<OnlineComponentProvider> {
|
||||
if (!client._onlineComponents) {
|
||||
@@ -833,6 +834,13 @@ function createBundleReader(
|
||||
return newBundleReader(toByteStreamReader(content), serializer);
|
||||
}
|
||||
|
||||
export function createBundleReaderSync(
|
||||
bundleData: string,
|
||||
serializer: JsonProtoSerializer
|
||||
): BundleReaderSync {
|
||||
return newBundleReaderSync(bundleData, serializer);
|
||||
}
|
||||
|
||||
export function firestoreClientSetIndexConfiguration(
|
||||
client: FirestoreClient,
|
||||
indexes: FieldIndex[]
|
||||
|
||||
@@ -1697,11 +1697,7 @@ async function loadBundleImpl(
|
||||
|
||||
task._updateProgress(bundleInitialProgress(metadata));
|
||||
|
||||
const loader = new BundleLoader(
|
||||
metadata,
|
||||
syncEngine.localStore,
|
||||
reader.serializer
|
||||
);
|
||||
const loader = new BundleLoader(metadata, reader.serializer);
|
||||
let element = await reader.nextElement();
|
||||
while (element) {
|
||||
debugAssert(
|
||||
@@ -1716,7 +1712,7 @@ async function loadBundleImpl(
|
||||
element = await reader.nextElement();
|
||||
}
|
||||
|
||||
const result = await loader.complete();
|
||||
const result = await loader.completeAndStoreAsync(syncEngine.localStore);
|
||||
await syncEngineEmitNewSnapsAndNotifyLocalStore(
|
||||
syncEngine,
|
||||
result.changedDocs,
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
|
||||
import { ByteString } from '../util/byte_string';
|
||||
import { Code, FirestoreError } from '../util/error';
|
||||
// API extractor fails importing property unless we also explicitly import Property.
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars, unused-imports/no-unused-imports-ts
|
||||
import { Property, property, validateJSON } from '../util/json_validation';
|
||||
|
||||
/**
|
||||
* An immutable object representing an array of bytes.
|
||||
@@ -91,4 +94,39 @@ export class Bytes {
|
||||
isEqual(other: Bytes): boolean {
|
||||
return this._byteString.isEqual(other._byteString);
|
||||
}
|
||||
|
||||
static _jsonSchemaVersion: string = 'firestore/bytes/1.0';
|
||||
static _jsonSchema = {
|
||||
type: property('string', Bytes._jsonSchemaVersion),
|
||||
bytes: property('string')
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a JSON-serializable representation of this `Bytes` instance.
|
||||
*
|
||||
* @returns a JSON representation of this object.
|
||||
*/
|
||||
toJSON(): object {
|
||||
return {
|
||||
type: Bytes._jsonSchemaVersion,
|
||||
bytes: this.toBase64()
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a `Bytes` instance from a JSON object created by {@link Bytes.toJSON}.
|
||||
*
|
||||
* @param json a JSON object represention of a `Bytes` instance
|
||||
* @returns an instance of {@link Bytes} if the JSON object could be parsed. Throws a
|
||||
* {@link FirestoreError} if an error occurs.
|
||||
*/
|
||||
static fromJSON(json: object): Bytes {
|
||||
if (validateJSON(json, Bytes._jsonSchema)) {
|
||||
return Bytes.fromBase64String(json.bytes);
|
||||
}
|
||||
throw new FirestoreError(
|
||||
Code.INVALID_ARGUMENT,
|
||||
'Unexpected error creating Bytes from JSON.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
*/
|
||||
|
||||
import { Code, FirestoreError } from '../util/error';
|
||||
// API extractor fails importing 'property' unless we also explicitly import 'Property'.
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars, unused-imports/no-unused-imports-ts
|
||||
import { Property, property, validateJSON } from '../util/json_validation';
|
||||
import { primitiveComparator } from '../util/misc';
|
||||
|
||||
/**
|
||||
@@ -79,11 +82,6 @@ export class GeoPoint {
|
||||
return this._lat === other._lat && this._long === other._long;
|
||||
}
|
||||
|
||||
/** Returns a JSON-serializable representation of this GeoPoint. */
|
||||
toJSON(): { latitude: number; longitude: number } {
|
||||
return { latitude: this._lat, longitude: this._long };
|
||||
}
|
||||
|
||||
/**
|
||||
* Actually private to JS consumers of our API, so this function is prefixed
|
||||
* with an underscore.
|
||||
@@ -94,4 +92,41 @@ export class GeoPoint {
|
||||
primitiveComparator(this._long, other._long)
|
||||
);
|
||||
}
|
||||
|
||||
static _jsonSchemaVersion: string = 'firestore/geoPoint/1.0';
|
||||
static _jsonSchema = {
|
||||
type: property('string', GeoPoint._jsonSchemaVersion),
|
||||
latitude: property('number'),
|
||||
longitude: property('number')
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a JSON-serializable representation of this `GeoPoint` instance.
|
||||
*
|
||||
* @returns a JSON representation of this object.
|
||||
*/
|
||||
toJSON(): { latitude: number; longitude: number; type: string } {
|
||||
return {
|
||||
latitude: this._lat,
|
||||
longitude: this._long,
|
||||
type: GeoPoint._jsonSchemaVersion
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a `GeoPoint` instance from a JSON object created by {@link GeoPoint.toJSON}.
|
||||
*
|
||||
* @param json a JSON object represention of a `GeoPoint` instance
|
||||
* @returns an instance of {@link GeoPoint} if the JSON object could be parsed. Throws a
|
||||
* {@link FirestoreError} if an error occurs.
|
||||
*/
|
||||
static fromJSON(json: object): GeoPoint {
|
||||
if (validateJSON(json, GeoPoint._jsonSchema)) {
|
||||
return new GeoPoint(json.latitude, json.longitude);
|
||||
}
|
||||
throw new FirestoreError(
|
||||
Code.INVALID_ARGUMENT,
|
||||
'Unexpected error creating GeoPoint from JSON.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,9 @@ import {
|
||||
validateDocumentPath,
|
||||
validateNonEmptyArgument
|
||||
} from '../util/input_validation';
|
||||
// API extractor fails importing property unless we also explicitly import Property.
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars, unused-imports/no-unused-imports-ts
|
||||
import { Property, property, validateJSON } from '../util/json_validation';
|
||||
import { AutoId } from '../util/misc';
|
||||
|
||||
import { Firestore } from './database';
|
||||
@@ -278,6 +281,73 @@ export class DocumentReference<
|
||||
this._key
|
||||
);
|
||||
}
|
||||
|
||||
static _jsonSchemaVersion: string = 'firestore/documentReference/1.0';
|
||||
static _jsonSchema = {
|
||||
type: property('string', DocumentReference._jsonSchemaVersion),
|
||||
referencePath: property('string')
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a JSON-serializable representation of this `DocumentReference` instance.
|
||||
*
|
||||
* @returns a JSON representation of this object.
|
||||
*/
|
||||
toJSON(): object {
|
||||
return {
|
||||
type: DocumentReference._jsonSchemaVersion,
|
||||
referencePath: this._key.toString()
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a `DocumentReference` instance from a JSON object created by
|
||||
* {@link DocumentReference.toJSON}.
|
||||
*
|
||||
* @param firestore - The {@link Firestore} instance the snapshot should be loaded for.
|
||||
* @param json a JSON object represention of a `DocumentReference` instance
|
||||
* @returns an instance of {@link DocumentReference} if the JSON object could be parsed. Throws a
|
||||
* {@link FirestoreError} if an error occurs.
|
||||
*/
|
||||
static fromJSON(firestore: Firestore, json: object): DocumentReference;
|
||||
/**
|
||||
* Builds a `DocumentReference` instance from a JSON object created by
|
||||
* {@link DocumentReference.toJSON}.
|
||||
*
|
||||
* @param firestore - The {@link Firestore} instance the snapshot should be loaded for.
|
||||
* @param json a JSON object represention of a `DocumentReference` instance
|
||||
* @param converter - Converts objects to and from Firestore.
|
||||
* @returns an instance of {@link DocumentReference} if the JSON object could be parsed. Throws a
|
||||
* {@link FirestoreError} if an error occurs.
|
||||
*/
|
||||
static fromJSON<
|
||||
NewAppModelType = DocumentData,
|
||||
NewDbModelType extends DocumentData = DocumentData
|
||||
>(
|
||||
firestore: Firestore,
|
||||
json: object,
|
||||
converter: FirestoreDataConverter<NewAppModelType, NewDbModelType>
|
||||
): DocumentReference<NewAppModelType, NewDbModelType>;
|
||||
static fromJSON<
|
||||
NewAppModelType = DocumentData,
|
||||
NewDbModelType extends DocumentData = DocumentData
|
||||
>(
|
||||
firestore: Firestore,
|
||||
json: object,
|
||||
converter?: FirestoreDataConverter<NewAppModelType, NewDbModelType>
|
||||
): DocumentReference<NewAppModelType, NewDbModelType> {
|
||||
if (validateJSON(json, DocumentReference._jsonSchema)) {
|
||||
return new DocumentReference<NewAppModelType, NewDbModelType>(
|
||||
firestore,
|
||||
converter ? converter : null,
|
||||
new DocumentKey(ResourcePath.fromString(json.referencePath))
|
||||
);
|
||||
}
|
||||
throw new FirestoreError(
|
||||
Code.INVALID_ARGUMENT,
|
||||
'Unexpected error creating Bytes from JSON.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
*/
|
||||
|
||||
import { Code, FirestoreError } from '../util/error';
|
||||
// API extractor fails importing 'property' unless we also explicitly import 'Property'.
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars, unused-imports/no-unused-imports-ts
|
||||
import { Property, property, validateJSON } from '../util/json_validation';
|
||||
import { primitiveComparator } from '../util/misc';
|
||||
|
||||
// The earliest date supported by Firestore timestamps (0001-01-01T00:00:00Z).
|
||||
@@ -174,9 +177,35 @@ export class Timestamp {
|
||||
);
|
||||
}
|
||||
|
||||
/** Returns a JSON-serializable representation of this `Timestamp`. */
|
||||
toJSON(): { seconds: number; nanoseconds: number } {
|
||||
return { seconds: this.seconds, nanoseconds: this.nanoseconds };
|
||||
static _jsonSchemaVersion: string = 'firestore/timestamp/1.0';
|
||||
static _jsonSchema = {
|
||||
type: property('string', Timestamp._jsonSchemaVersion),
|
||||
seconds: property('number'),
|
||||
nanoseconds: property('number')
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a JSON-serializable representation of this `Timestamp`.
|
||||
*/
|
||||
toJSON(): { seconds: number; nanoseconds: number; type: string } {
|
||||
return {
|
||||
type: Timestamp._jsonSchemaVersion,
|
||||
seconds: this.seconds,
|
||||
nanoseconds: this.nanoseconds
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a `Timestamp` instance from a JSON object created by {@link Timestamp.toJSON}.
|
||||
*/
|
||||
static fromJSON(json: object): Timestamp {
|
||||
if (validateJSON(json, Timestamp._jsonSchema)) {
|
||||
return new Timestamp(json.seconds, json.nanoseconds);
|
||||
}
|
||||
throw new FirestoreError(
|
||||
Code.INVALID_ARGUMENT,
|
||||
'Unexpected error creating Timestamp from JSON.'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -780,7 +780,7 @@ export function parseData(
|
||||
}
|
||||
}
|
||||
|
||||
function parseObject(
|
||||
export function parseObject(
|
||||
obj: Dict<unknown>,
|
||||
context: ParseContextImpl
|
||||
): { mapValue: ProtoMapValue } {
|
||||
|
||||
@@ -16,6 +16,10 @@
|
||||
*/
|
||||
|
||||
import { isPrimitiveArrayEqual } from '../util/array';
|
||||
import { Code, FirestoreError } from '../util/error';
|
||||
// API extractor fails importing 'property' unless we also explicitly import 'Property'.
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars, unused-imports/no-unused-imports-ts
|
||||
import { Property, property, validateJSON } from '../util/json_validation';
|
||||
|
||||
/**
|
||||
* Represents a vector type in Firestore documents.
|
||||
@@ -48,4 +52,48 @@ export class VectorValue {
|
||||
isEqual(other: VectorValue): boolean {
|
||||
return isPrimitiveArrayEqual(this._values, other._values);
|
||||
}
|
||||
|
||||
static _jsonSchemaVersion: string = 'firestore/vectorValue/1.0';
|
||||
static _jsonSchema = {
|
||||
type: property('string', VectorValue._jsonSchemaVersion),
|
||||
vectorValues: property('object')
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a JSON-serializable representation of this `VectorValue` instance.
|
||||
*
|
||||
* @returns a JSON representation of this object.
|
||||
*/
|
||||
toJSON(): object {
|
||||
return {
|
||||
type: VectorValue._jsonSchemaVersion,
|
||||
vectorValues: this._values
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a `VectorValue` instance from a JSON object created by {@link VectorValue.toJSON}.
|
||||
*
|
||||
* @param json a JSON object represention of a `VectorValue` instance.
|
||||
* @returns an instance of {@link VectorValue} if the JSON object could be parsed. Throws a
|
||||
* {@link FirestoreError} if an error occurs.
|
||||
*/
|
||||
static fromJSON(json: object): VectorValue {
|
||||
if (validateJSON(json, VectorValue._jsonSchema)) {
|
||||
if (
|
||||
Array.isArray(json.vectorValues) &&
|
||||
json.vectorValues.every(element => typeof element === 'number')
|
||||
) {
|
||||
return new VectorValue(json.vectorValues);
|
||||
}
|
||||
throw new FirestoreError(
|
||||
Code.INVALID_ARGUMENT,
|
||||
"Expected 'vectorValues' field to be a number array"
|
||||
);
|
||||
}
|
||||
throw new FirestoreError(
|
||||
Code.INVALID_ARGUMENT,
|
||||
'Unexpected error creating Timestamp from JSON.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2025 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.
|
||||
*/
|
||||
|
||||
/** Return the Platform-specific build JSON bundle implementations. */
|
||||
import { Firestore } from '../../api/database';
|
||||
import { Query } from '../../core/query';
|
||||
import { DocumentData } from '../../lite-api/reference';
|
||||
import { Document } from '../../model/document';
|
||||
|
||||
export function buildDocumentSnapshotJsonBundle(
|
||||
db: Firestore,
|
||||
document: Document,
|
||||
docData: DocumentData,
|
||||
path: string
|
||||
): string {
|
||||
return 'NOT SUPPORTED';
|
||||
}
|
||||
|
||||
export function buildQuerySnapshotJsonBundle(
|
||||
db: Firestore,
|
||||
query: Query,
|
||||
bundleName: string,
|
||||
parent: string,
|
||||
paths: string[],
|
||||
docs: Document[],
|
||||
documentData: DocumentData[]
|
||||
): string {
|
||||
return 'NOT SUPPORTED';
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2025 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export * from '../browser/snapshot_to_json';
|
||||
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2025 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.
|
||||
*/
|
||||
|
||||
/** Return the Platform-specific build JSON bundle implementations. */
|
||||
import { Firestore } from '../../api/database';
|
||||
import { Query } from '../../core/query';
|
||||
import { DocumentData } from '../../lite-api/reference';
|
||||
import { Document } from '../../model/document';
|
||||
import {
|
||||
BundleBuilder,
|
||||
DocumentSnapshotBundleData,
|
||||
QuerySnapshotBundleData
|
||||
} from '../../util/bundle_builder_impl';
|
||||
import { AutoId } from '../../util/misc';
|
||||
|
||||
export function buildDocumentSnapshotJsonBundle(
|
||||
db: Firestore,
|
||||
document: Document,
|
||||
docData: DocumentData,
|
||||
path: string
|
||||
): string {
|
||||
const builder: BundleBuilder = new BundleBuilder(db, AutoId.newId());
|
||||
builder.addBundleDocument(
|
||||
documentToDocumentSnapshotBundleData(path, docData, document)
|
||||
);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
export function buildQuerySnapshotJsonBundle(
|
||||
db: Firestore,
|
||||
query: Query,
|
||||
bundleName: string,
|
||||
parent: string,
|
||||
paths: string[],
|
||||
docs: Document[],
|
||||
documentData: DocumentData[]
|
||||
): string {
|
||||
const docBundleDataArray: DocumentSnapshotBundleData[] = [];
|
||||
for (let i = 0; i < docs.length; i++) {
|
||||
docBundleDataArray.push(
|
||||
documentToDocumentSnapshotBundleData(paths[i], documentData[i], docs[i])
|
||||
);
|
||||
}
|
||||
const bundleData: QuerySnapshotBundleData = {
|
||||
name: bundleName,
|
||||
query,
|
||||
parent,
|
||||
docBundleDataArray
|
||||
};
|
||||
const builder: BundleBuilder = new BundleBuilder(db, bundleName);
|
||||
builder.addBundleQuery(bundleData);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
// Formats Document data for bundling a DocumentSnapshot.
|
||||
function documentToDocumentSnapshotBundleData(
|
||||
path: string,
|
||||
documentData: DocumentData,
|
||||
document: Document
|
||||
): DocumentSnapshotBundleData {
|
||||
return {
|
||||
documentData,
|
||||
documentKey: document.mutableCopy().key,
|
||||
documentPath: path,
|
||||
documentExists: true,
|
||||
createdTime: document.createTime.toTimestamp(),
|
||||
readTime: document.readTime.toTimestamp(),
|
||||
versionTime: document.version.toTimestamp()
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2025 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export * from '../node/snapshot_to_json';
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2025 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export {
|
||||
buildDocumentSnapshotJsonBundle,
|
||||
buildQuerySnapshotJsonBundle
|
||||
} from '../browser/snapshot_to_json';
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2020 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { toByteStreamReader } from '../browser/byte_stream_reader';
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2025 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.
|
||||
*/
|
||||
|
||||
import { Firestore } from '../api/database';
|
||||
import { Query } from '../core/query';
|
||||
import { DocumentData } from '../lite-api/reference';
|
||||
import { Document } from '../model/document';
|
||||
|
||||
// This file is only used under ts-node.
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
const platform = require(`./${
|
||||
process.env.TEST_PLATFORM ?? 'node'
|
||||
}/snapshot_to_json`);
|
||||
|
||||
/**
|
||||
* Constructs the bundle data for a DocumentSnapshot used in its toJSON serialization.
|
||||
*/
|
||||
export function buildDocumentSnapshotJsonBundle(
|
||||
db: Firestore,
|
||||
document: Document,
|
||||
docData: DocumentData,
|
||||
path: string
|
||||
): string {
|
||||
return platform.buildDocumentSnapshotJsonBundle(db, document, docData, path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the bundle data for a QuerySnapshot used in its toJSON serialization.
|
||||
*/
|
||||
export function buildQuerySnapshotJsonBundle(
|
||||
db: Firestore,
|
||||
query: Query,
|
||||
bundleName: string,
|
||||
parent: string,
|
||||
paths: string[],
|
||||
docs: Document[],
|
||||
documentData: DocumentData[]
|
||||
): string {
|
||||
return platform.buildQuerySnapshotJsonBundle(
|
||||
db,
|
||||
query,
|
||||
bundleName,
|
||||
parent,
|
||||
paths,
|
||||
docs,
|
||||
documentData
|
||||
);
|
||||
}
|
||||
@@ -226,7 +226,10 @@ export function toTimestamp(
|
||||
}
|
||||
}
|
||||
|
||||
function fromTimestamp(date: ProtoTimestamp): Timestamp {
|
||||
/**
|
||||
* Returns a Timestamp typed object given protobuf timestamp value.
|
||||
*/
|
||||
export function fromTimestamp(date: ProtoTimestamp): Timestamp {
|
||||
const timestamp = normalizeTimestamp(date);
|
||||
return new Timestamp(timestamp.seconds, timestamp.nanos);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,284 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2025 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.
|
||||
*/
|
||||
|
||||
import {
|
||||
JsonProtoSerializer,
|
||||
fromTimestamp,
|
||||
toName,
|
||||
toQueryTarget,
|
||||
toTimestamp
|
||||
} from '../../src/remote/serializer';
|
||||
import { encoder } from '../../test/unit/util/bundle_data';
|
||||
import { Firestore } from '../api/database';
|
||||
import { DatabaseId } from '../core/database_info';
|
||||
import { Query, queryToTarget } from '../core/query';
|
||||
import { DocumentData } from '../lite-api/reference';
|
||||
import { Timestamp } from '../lite-api/timestamp';
|
||||
import {
|
||||
parseObject,
|
||||
UserDataReader,
|
||||
UserDataSource
|
||||
} from '../lite-api/user_data_reader';
|
||||
import { DocumentKey } from '../model/document_key';
|
||||
import {
|
||||
BundledDocumentMetadata as ProtoBundledDocumentMetadata,
|
||||
BundleElement as ProtoBundleElement,
|
||||
BundleMetadata as ProtoBundleMetadata,
|
||||
NamedQuery as ProtoNamedQuery
|
||||
} from '../protos/firestore_bundle_proto';
|
||||
import {
|
||||
Document as ProtoDocument,
|
||||
Document
|
||||
} from '../protos/firestore_proto_api';
|
||||
|
||||
const BUNDLE_VERSION = 1;
|
||||
|
||||
/**
|
||||
* Builds a Firestore data bundle with results from the given document and query snapshots.
|
||||
*/
|
||||
export class BundleBuilder {
|
||||
// Resulting documents for the bundle, keyed by full document path.
|
||||
private documents: Map<string, BundledDocument> = new Map();
|
||||
// Named queries saved in the bundle, keyed by query name.
|
||||
private namedQueries: Map<string, ProtoNamedQuery> = new Map();
|
||||
|
||||
// The latest read time among all bundled documents and queries.
|
||||
private latestReadTime = new Timestamp(0, 0);
|
||||
|
||||
// Database identifier which is part of the serialized bundle.
|
||||
private databaseId: DatabaseId;
|
||||
|
||||
// Tools to convert public data types into their serialized form.
|
||||
private readonly serializer: JsonProtoSerializer;
|
||||
private readonly userDataReader: UserDataReader;
|
||||
|
||||
constructor(private firestore: Firestore, readonly bundleId: string) {
|
||||
this.databaseId = firestore._databaseId;
|
||||
|
||||
// useProto3Json is true because the objects will be serialized to JSON string
|
||||
// before being written to the bundle buffer.
|
||||
this.serializer = new JsonProtoSerializer(
|
||||
this.databaseId,
|
||||
/*useProto3Json=*/ true
|
||||
);
|
||||
|
||||
this.userDataReader = new UserDataReader(
|
||||
this.databaseId,
|
||||
true,
|
||||
this.serializer
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds data from a DocumentSnapshot to the bundle.
|
||||
* @internal
|
||||
* @param docBundleData A DocumentSnapshotBundleData containing information from the
|
||||
* DocumentSnapshot. Note we cannot accept a DocumentSnapshot directly due to a circular
|
||||
* dependency error.
|
||||
* @param queryName The name of the QuerySnapshot if this document is part of a Query.
|
||||
*/
|
||||
addBundleDocument(
|
||||
docBundleData: DocumentSnapshotBundleData,
|
||||
queryName?: string
|
||||
): void {
|
||||
const originalDocument = this.documents.get(docBundleData.documentPath);
|
||||
const originalQueries = originalDocument?.metadata.queries;
|
||||
const docReadTime: Timestamp | undefined = docBundleData.readTime;
|
||||
const origDocReadTime: Timestamp | null = !!originalDocument?.metadata
|
||||
.readTime
|
||||
? fromTimestamp(originalDocument.metadata.readTime)
|
||||
: null;
|
||||
|
||||
const neitherHasReadTime: boolean = !docReadTime && origDocReadTime == null;
|
||||
const docIsNewer: boolean =
|
||||
docReadTime !== undefined &&
|
||||
(origDocReadTime == null || origDocReadTime < docReadTime);
|
||||
if (neitherHasReadTime || docIsNewer) {
|
||||
// Store document.
|
||||
this.documents.set(docBundleData.documentPath, {
|
||||
document: this.toBundleDocument(docBundleData),
|
||||
metadata: {
|
||||
name: toName(this.serializer, docBundleData.documentKey),
|
||||
readTime: !!docReadTime
|
||||
? toTimestamp(this.serializer, docReadTime) // Convert Timestamp to proto format.
|
||||
: undefined,
|
||||
exists: docBundleData.documentExists
|
||||
}
|
||||
});
|
||||
}
|
||||
if (docReadTime && docReadTime > this.latestReadTime) {
|
||||
this.latestReadTime = docReadTime;
|
||||
}
|
||||
// Update `queries` to include both original and `queryName`.
|
||||
if (queryName) {
|
||||
const newDocument = this.documents.get(docBundleData.documentPath)!;
|
||||
newDocument.metadata.queries = originalQueries || [];
|
||||
newDocument.metadata.queries!.push(queryName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds data from a QuerySnapshot to the bundle.
|
||||
* @internal
|
||||
* @param docBundleData A QuerySnapshotBundleData containing information from the
|
||||
* QuerySnapshot. Note we cannot accept a QuerySnapshot directly due to a circular
|
||||
* dependency error.
|
||||
*/
|
||||
addBundleQuery(queryBundleData: QuerySnapshotBundleData): void {
|
||||
if (this.namedQueries.has(queryBundleData.name)) {
|
||||
throw new Error(`Query name conflict: ${name} has already been added.`);
|
||||
}
|
||||
let latestReadTime = new Timestamp(0, 0);
|
||||
for (const docBundleData of queryBundleData.docBundleDataArray) {
|
||||
this.addBundleDocument(docBundleData, queryBundleData.name);
|
||||
if (docBundleData.readTime && docBundleData.readTime > latestReadTime) {
|
||||
latestReadTime = docBundleData.readTime;
|
||||
}
|
||||
}
|
||||
const queryTarget = toQueryTarget(
|
||||
this.serializer,
|
||||
queryToTarget(queryBundleData.query)
|
||||
);
|
||||
const bundledQuery = {
|
||||
parent: queryBundleData.parent,
|
||||
structuredQuery: queryTarget.queryTarget.structuredQuery
|
||||
};
|
||||
this.namedQueries.set(queryBundleData.name, {
|
||||
name: queryBundleData.name,
|
||||
bundledQuery,
|
||||
readTime: toTimestamp(this.serializer, latestReadTime)
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert data from a DocumentSnapshot into the serialized form within a bundle.
|
||||
* @private
|
||||
* @internal
|
||||
* @param docBundleData a DocumentSnapshotBundleData containing the data required to
|
||||
* serialize a document.
|
||||
*/
|
||||
private toBundleDocument(
|
||||
docBundleData: DocumentSnapshotBundleData
|
||||
): ProtoDocument {
|
||||
// a parse context is typically used for validating and parsing user data, but in this
|
||||
// case we are using it internally to convert DocumentData to Proto3 JSON
|
||||
const context = this.userDataReader.createContext(
|
||||
UserDataSource.ArrayArgument,
|
||||
'internal toBundledDocument'
|
||||
);
|
||||
const proto3Fields = parseObject(docBundleData.documentData, context);
|
||||
|
||||
return {
|
||||
name: toName(this.serializer, docBundleData.documentKey),
|
||||
fields: proto3Fields.mapValue.fields,
|
||||
updateTime: toTimestamp(this.serializer, docBundleData.versionTime),
|
||||
createTime: toTimestamp(this.serializer, docBundleData.createdTime)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a IBundleElement to a Buffer whose content is the length prefixed JSON representation
|
||||
* of the element.
|
||||
* @private
|
||||
* @internal
|
||||
* @param bundleElement A ProtoBundleElement that is expected to be Proto3 JSON compatible.
|
||||
*/
|
||||
private lengthPrefixedString(bundleElement: ProtoBundleElement): string {
|
||||
const str = JSON.stringify(bundleElement);
|
||||
// TODO: it's not ideal to have to re-encode all of these strings multiple times
|
||||
// It may be more performant to return a UInt8Array that is concatenated to other
|
||||
// UInt8Arrays instead of returning and concatenating strings and then
|
||||
// converting the full string to UInt8Array.
|
||||
const l = encoder.encode(str).byteLength;
|
||||
return `${l}${str}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a serialized string containing document and query information that has previously
|
||||
* been added to the BundleBuilder through the addBundleDocument and addBundleQuery methods.
|
||||
* @internal
|
||||
*/
|
||||
build(): string {
|
||||
let bundleString = '';
|
||||
|
||||
for (const namedQuery of this.namedQueries.values()) {
|
||||
bundleString += this.lengthPrefixedString({ namedQuery });
|
||||
}
|
||||
|
||||
for (const bundledDocument of this.documents.values()) {
|
||||
const documentMetadata: ProtoBundledDocumentMetadata =
|
||||
bundledDocument.metadata;
|
||||
|
||||
bundleString += this.lengthPrefixedString({ documentMetadata });
|
||||
// Write to the bundle if document exists.
|
||||
const document = bundledDocument.document;
|
||||
if (document) {
|
||||
bundleString += this.lengthPrefixedString({ document });
|
||||
}
|
||||
}
|
||||
|
||||
const metadata: ProtoBundleMetadata = {
|
||||
id: this.bundleId,
|
||||
createTime: toTimestamp(this.serializer, this.latestReadTime),
|
||||
version: BUNDLE_VERSION,
|
||||
totalDocuments: this.documents.size,
|
||||
// TODO: it's not ideal to have to re-encode all of these strings multiple times
|
||||
totalBytes: encoder.encode(bundleString).length
|
||||
};
|
||||
// Prepends the metadata element to the bundleBuffer: `bundleBuffer` is the second argument to `Buffer.concat`.
|
||||
bundleString = this.lengthPrefixedString({ metadata }) + bundleString;
|
||||
|
||||
return bundleString;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for an object that contains data required to bundle a DocumentSnapshot.
|
||||
* @internal
|
||||
*/
|
||||
export interface DocumentSnapshotBundleData {
|
||||
documentData: DocumentData;
|
||||
documentKey: DocumentKey;
|
||||
documentPath: string;
|
||||
documentExists: boolean;
|
||||
createdTime: Timestamp;
|
||||
readTime?: Timestamp;
|
||||
versionTime: Timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for an object that contains data required to bundle a QuerySnapshot.
|
||||
* @internal
|
||||
*/
|
||||
export interface QuerySnapshotBundleData {
|
||||
name: string;
|
||||
query: Query;
|
||||
parent: string;
|
||||
docBundleDataArray: DocumentSnapshotBundleData[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenient class to hold both the metadata and the actual content of a document to be bundled.
|
||||
* @private
|
||||
* @internal
|
||||
*/
|
||||
class BundledDocument {
|
||||
constructor(
|
||||
readonly metadata: ProtoBundledDocumentMetadata,
|
||||
readonly document?: Document
|
||||
) {}
|
||||
}
|
||||
@@ -65,3 +65,24 @@ export interface BundleReader {
|
||||
*/
|
||||
nextElement(): Promise<SizedBundleElement | null>;
|
||||
}
|
||||
|
||||
/**
|
||||
* A class representing a synchronized bundle reader.
|
||||
*
|
||||
* Takes a bundle string buffer, parses the data, and provides accessors to the data contained
|
||||
* within it.
|
||||
*/
|
||||
export interface BundleReaderSync {
|
||||
serializer: JsonProtoSerializer;
|
||||
|
||||
/**
|
||||
* Returns the metadata of the bundle.
|
||||
*/
|
||||
getMetadata(): BundleMetadata;
|
||||
|
||||
/**
|
||||
* Returns BundleElements parsed from the bundle. Returns an empty array if no bundle elements
|
||||
* exist.
|
||||
*/
|
||||
getElements(): SizedBundleElement[];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2025 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.
|
||||
*/
|
||||
|
||||
import { BundleMetadata } from '../protos/firestore_bundle_proto';
|
||||
import { JsonProtoSerializer } from '../remote/serializer';
|
||||
import { Code, FirestoreError } from '../util/error';
|
||||
|
||||
import { BundleReaderSync, SizedBundleElement } from './bundle_reader';
|
||||
|
||||
/**
|
||||
* A class that can parse a bundle form the string serialization of a bundle.
|
||||
*/
|
||||
export class BundleReaderSyncImpl implements BundleReaderSync {
|
||||
private metadata: BundleMetadata;
|
||||
private elements: SizedBundleElement[];
|
||||
private cursor: number;
|
||||
constructor(
|
||||
private bundleData: string,
|
||||
readonly serializer: JsonProtoSerializer
|
||||
) {
|
||||
this.cursor = 0;
|
||||
this.elements = [];
|
||||
|
||||
let element = this.nextElement();
|
||||
if (element && element.isBundleMetadata()) {
|
||||
this.metadata = element as BundleMetadata;
|
||||
} else {
|
||||
throw new Error(`The first element of the bundle is not a metadata object, it is
|
||||
${JSON.stringify(element?.payload)}`);
|
||||
}
|
||||
|
||||
do {
|
||||
element = this.nextElement();
|
||||
if (element !== null) {
|
||||
this.elements.push(element);
|
||||
}
|
||||
} while (element !== null);
|
||||
}
|
||||
|
||||
/* Returns the parsed metadata of the bundle. */
|
||||
getMetadata(): BundleMetadata {
|
||||
return this.metadata;
|
||||
}
|
||||
|
||||
/* Returns the DocumentSnapshot or NamedQuery elements of the bundle. */
|
||||
getElements(): SizedBundleElement[] {
|
||||
return this.elements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the next element of the bundle.
|
||||
*
|
||||
* @returns a SizedBundleElement representation of the next element in the bundle, or null if
|
||||
* no more elements exist.
|
||||
*/
|
||||
private nextElement(): SizedBundleElement | null {
|
||||
if (this.cursor === this.bundleData.length) {
|
||||
return null;
|
||||
}
|
||||
const length: number = this.readLength();
|
||||
const jsonString = this.readJsonString(length);
|
||||
return new SizedBundleElement(JSON.parse(jsonString), length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads from a specified position from the bundleData string, for a specified
|
||||
* number of bytes.
|
||||
*
|
||||
* @param length how many characters to read.
|
||||
* @returns a string parsed from the bundle.
|
||||
*/
|
||||
private readJsonString(length: number): string {
|
||||
if (this.cursor + length > this.bundleData.length) {
|
||||
throw new FirestoreError(
|
||||
Code.INTERNAL,
|
||||
'Reached the end of bundle when more is expected.'
|
||||
);
|
||||
}
|
||||
const result = this.bundleData.slice(this.cursor, (this.cursor += length));
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads from the current cursor until the first '{'.
|
||||
*
|
||||
* @returns A string to integer represention of the parsed value.
|
||||
* @throws An {@link Error} if the cursor has reached the end of the stream, since lengths
|
||||
* prefix bundle objects.
|
||||
*/
|
||||
private readLength(): number {
|
||||
const startIndex = this.cursor;
|
||||
let curIndex = this.cursor;
|
||||
while (curIndex < this.bundleData.length) {
|
||||
if (this.bundleData[curIndex] === '{') {
|
||||
if (curIndex === startIndex) {
|
||||
throw new Error('First character is a bracket and not a number');
|
||||
}
|
||||
this.cursor = curIndex;
|
||||
return Number(this.bundleData.slice(startIndex, curIndex));
|
||||
}
|
||||
curIndex++;
|
||||
}
|
||||
throw new Error('Reached the end of bundle when more is expected.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of BundleReader without exposing the BundleReaderSyncImpl class type.
|
||||
*/
|
||||
export function newBundleReaderSync(
|
||||
bundleData: string,
|
||||
serializer: JsonProtoSerializer
|
||||
): BundleReaderSync {
|
||||
return new BundleReaderSyncImpl(bundleData, serializer);
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2025 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.
|
||||
*/
|
||||
|
||||
import { isPlainObject } from '../util/input_validation';
|
||||
|
||||
import { Code, FirestoreError } from './error';
|
||||
|
||||
/**
|
||||
* A list of data types Firestore objects may serialize in their toJSON implemenetations.
|
||||
* @private
|
||||
* @internal
|
||||
*/
|
||||
export type JsonTypeDesc =
|
||||
| 'object'
|
||||
| 'string'
|
||||
| 'number'
|
||||
| 'boolean'
|
||||
| 'null'
|
||||
| 'undefined';
|
||||
|
||||
/**
|
||||
* An association of JsonTypeDesc values to their native types.
|
||||
* @private
|
||||
* @internal
|
||||
*/
|
||||
export type TSType<T extends JsonTypeDesc> = T extends 'object'
|
||||
? object
|
||||
: T extends 'string'
|
||||
? string
|
||||
: T extends 'number'
|
||||
? number
|
||||
: T extends 'boolean'
|
||||
? boolean
|
||||
: T extends 'null'
|
||||
? null
|
||||
: T extends 'undefined'
|
||||
? undefined
|
||||
: never;
|
||||
|
||||
/**
|
||||
* The representation of a JSON object property name and its type value.
|
||||
* @private
|
||||
* @internal
|
||||
*/
|
||||
export interface Property<T extends JsonTypeDesc> {
|
||||
value?: TSType<T>;
|
||||
typeString: JsonTypeDesc;
|
||||
}
|
||||
|
||||
/**
|
||||
* A type Firestore data types may use to define the fields used in their JSON serialization.
|
||||
* @private
|
||||
* @internal
|
||||
*/
|
||||
export interface JsonSchema {
|
||||
[key: string]: Property<JsonTypeDesc>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Associates the JSON property type to the native type and sets them to be Required.
|
||||
* @private
|
||||
* @internal
|
||||
*/
|
||||
export type Json<T extends JsonSchema> = {
|
||||
[K in keyof T]: Required<T[K]>['value'];
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper function to define a JSON schema {@link Property}.
|
||||
* @private
|
||||
* @internal
|
||||
*/
|
||||
export function property<T extends JsonTypeDesc>(
|
||||
typeString: T,
|
||||
optionalValue?: TSType<T>
|
||||
): Property<T> {
|
||||
const result: Property<T> = {
|
||||
typeString
|
||||
};
|
||||
if (optionalValue) {
|
||||
result.value = optionalValue;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the JSON object based on the provided schema, and narrows the type to the provided
|
||||
* JSON schema.
|
||||
* @private
|
||||
* @internal
|
||||
*
|
||||
* @param json A JSON object to validate.
|
||||
* @param scheme a {@link JsonSchema} that defines the properties to validate.
|
||||
* @returns true if the JSON schema exists within the object. Throws a FirestoreError otherwise.
|
||||
*/
|
||||
export function validateJSON<S extends JsonSchema>(
|
||||
json: object,
|
||||
schema: S
|
||||
): json is Json<S> {
|
||||
if (!isPlainObject(json)) {
|
||||
throw new FirestoreError(Code.INVALID_ARGUMENT, 'JSON must be an object');
|
||||
}
|
||||
let error: string | undefined = undefined;
|
||||
for (const key in schema) {
|
||||
if (schema[key]) {
|
||||
const typeString = schema[key].typeString;
|
||||
const value: { value: unknown } | undefined =
|
||||
'value' in schema[key] ? { value: schema[key].value } : undefined;
|
||||
if (!(key in json)) {
|
||||
error = `JSON missing required field: '${key}'`;
|
||||
break;
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const fieldValue = (json as any)[key];
|
||||
if (typeString && typeof fieldValue !== typeString) {
|
||||
error = `JSON field '${key}' must be a ${typeString}.`;
|
||||
break;
|
||||
} else if (value !== undefined && fieldValue !== value.value) {
|
||||
error = `Expected '${key}' field to equal '${value.value}'`;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (error) {
|
||||
throw new FirestoreError(Code.INVALID_ARGUMENT, error);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
import { deleteApp } from '@firebase/app';
|
||||
import { Deferred } from '@firebase/util';
|
||||
import { Deferred, isNode } from '@firebase/util';
|
||||
import { expect, use } from 'chai';
|
||||
import chaiAsPromised from 'chai-as-promised';
|
||||
|
||||
@@ -33,6 +33,7 @@ import {
|
||||
DocumentData,
|
||||
documentId,
|
||||
DocumentSnapshot,
|
||||
documentSnapshotFromJSON,
|
||||
enableIndexedDbPersistence,
|
||||
enableNetwork,
|
||||
getDoc,
|
||||
@@ -42,6 +43,7 @@ import {
|
||||
initializeFirestore,
|
||||
limit,
|
||||
onSnapshot,
|
||||
onSnapshotResume,
|
||||
onSnapshotsInSync,
|
||||
orderBy,
|
||||
query,
|
||||
@@ -66,6 +68,7 @@ import {
|
||||
newTestApp,
|
||||
FirestoreError,
|
||||
QuerySnapshot,
|
||||
querySnapshotFromJSON,
|
||||
vector,
|
||||
getDocsFromServer
|
||||
} from '../util/firebase_export';
|
||||
@@ -1206,6 +1209,429 @@ apiDescribe('Database', persistence => {
|
||||
});
|
||||
});
|
||||
|
||||
it('DocumentSnapshot events for snapshot created by a bundle', async () => {
|
||||
if (isNode()) {
|
||||
const initialData = { a: 1 };
|
||||
const finalData = { a: 2 };
|
||||
await withTestDocAndInitialData(
|
||||
persistence,
|
||||
initialData,
|
||||
async (docRef, db) => {
|
||||
const doc = await getDoc(docRef);
|
||||
const accumulator = new EventsAccumulator<DocumentSnapshot>();
|
||||
const unsubscribe = onSnapshotResume(
|
||||
db,
|
||||
doc.toJSON(),
|
||||
accumulator.storeEvent
|
||||
);
|
||||
await accumulator
|
||||
.awaitEvent()
|
||||
.then(snap => {
|
||||
console.error('DEDB accumulator event 1');
|
||||
expect(snap.exists()).to.be.true;
|
||||
expect(snap.data()).to.deep.equal(initialData);
|
||||
})
|
||||
.then(() => setDoc(docRef, finalData))
|
||||
.then(() => accumulator.awaitEvent())
|
||||
.then(snap => {
|
||||
expect(snap.exists()).to.be.true;
|
||||
expect(snap.data()).to.deep.equal(finalData);
|
||||
});
|
||||
unsubscribe();
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it('DocumentSnapshot updated doc events in snapshot created by a bundle accumulator', async () => {
|
||||
if (isNode()) {
|
||||
const initialData = { a: 1 };
|
||||
const finalData = { a: 2 };
|
||||
await withTestDocAndInitialData(
|
||||
persistence,
|
||||
initialData,
|
||||
async (docRef, db) => {
|
||||
const doc = await getDoc(docRef);
|
||||
const accumulator = new EventsAccumulator<DocumentSnapshot>();
|
||||
const unsubscribe = onSnapshotResume(
|
||||
db,
|
||||
doc.toJSON(),
|
||||
accumulator.storeEvent
|
||||
);
|
||||
await accumulator
|
||||
.awaitEvent()
|
||||
.then(snap => {
|
||||
expect(snap.exists()).to.be.true;
|
||||
expect(snap.data()).to.deep.equal(initialData);
|
||||
})
|
||||
.then(() => setDoc(docRef, finalData))
|
||||
.then(() => accumulator.awaitEvent())
|
||||
.then(snap => {
|
||||
expect(snap.exists()).to.be.true;
|
||||
expect(snap.data()).to.deep.equal(finalData);
|
||||
});
|
||||
unsubscribe();
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it('DocumentSnapshot observer events for snapshot created by a bundle', async () => {
|
||||
if (isNode()) {
|
||||
const initialData = { a: 1 };
|
||||
const finalData = { a: 2 };
|
||||
await withTestDocAndInitialData(
|
||||
persistence,
|
||||
initialData,
|
||||
async (docRef, db) => {
|
||||
const doc = await getDoc(docRef);
|
||||
const accumulator = new EventsAccumulator<DocumentSnapshot>();
|
||||
const unsubscribe = onSnapshotResume(db, doc.toJSON(), {
|
||||
next: accumulator.storeEvent
|
||||
});
|
||||
await accumulator
|
||||
.awaitEvent()
|
||||
.then(snap => {
|
||||
expect(snap.exists()).to.be.true;
|
||||
expect(snap.data()).to.deep.equal(initialData);
|
||||
})
|
||||
.then(() => setDoc(docRef, finalData))
|
||||
.then(() => accumulator.awaitEvent())
|
||||
.then(snap => {
|
||||
expect(snap.exists()).to.be.true;
|
||||
expect(snap.data()).to.deep.equal(finalData);
|
||||
});
|
||||
unsubscribe();
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it('DocumentSnapshot error events for snapshot created by a bundle', async () => {
|
||||
return withTestDb(persistence, async db => {
|
||||
const json = {
|
||||
bundle: 'BadData',
|
||||
bundleName: 'bundleName',
|
||||
bundleSource: 'DocumentSnapshot'
|
||||
};
|
||||
const deferred = new Deferred();
|
||||
const unsubscribe = onSnapshotResume(
|
||||
db,
|
||||
json,
|
||||
ds => {
|
||||
expect(ds).to.not.exist;
|
||||
deferred.resolve();
|
||||
},
|
||||
err => {
|
||||
expect(err.name).to.exist;
|
||||
expect(err.message).to.exist;
|
||||
deferred.resolve();
|
||||
}
|
||||
);
|
||||
await deferred.promise;
|
||||
unsubscribe();
|
||||
});
|
||||
});
|
||||
|
||||
it('DocumentSnapshot observer error events for snapshot created by a bundle', async () => {
|
||||
return withTestDb(persistence, async db => {
|
||||
const json = {
|
||||
bundle: 'BadData',
|
||||
bundleName: 'bundleName',
|
||||
bundleSource: 'QuerySnapshot'
|
||||
};
|
||||
const deferred = new Deferred();
|
||||
const unsubscribe = onSnapshotResume(db, json, {
|
||||
next: ds => {
|
||||
expect(ds).to.not.exist;
|
||||
deferred.resolve();
|
||||
},
|
||||
error: err => {
|
||||
expect(err.name).to.exist;
|
||||
expect(err.message).to.exist;
|
||||
deferred.resolve();
|
||||
}
|
||||
});
|
||||
await deferred.promise;
|
||||
unsubscribe();
|
||||
});
|
||||
});
|
||||
|
||||
it('DocumentSnapshot updated doc events in snapshot created by fromJSON bundle', async () => {
|
||||
if (isNode()) {
|
||||
const initialData = { a: 1 };
|
||||
const finalData = { a: 2 };
|
||||
await withTestDocAndInitialData(
|
||||
persistence,
|
||||
initialData,
|
||||
async (docRef, db) => {
|
||||
const doc = await getDoc(docRef);
|
||||
const fromJsonDoc = documentSnapshotFromJSON(db, doc.toJSON());
|
||||
const accumulator = new EventsAccumulator<DocumentSnapshot>();
|
||||
const unsubscribe = onSnapshotResume(
|
||||
db,
|
||||
fromJsonDoc.toJSON(),
|
||||
accumulator.storeEvent
|
||||
);
|
||||
await accumulator
|
||||
.awaitEvent()
|
||||
.then(snap => {
|
||||
expect(snap.exists()).to.be.true;
|
||||
expect(snap.data()).to.deep.equal(initialData);
|
||||
})
|
||||
.then(() => setDoc(docRef, finalData))
|
||||
.then(() => accumulator.awaitEvent())
|
||||
.then(snap => {
|
||||
expect(snap.exists()).to.be.true;
|
||||
expect(snap.data()).to.deep.equal(finalData);
|
||||
});
|
||||
unsubscribe();
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it('DocumentSnapshot updated doc events in snapshot created by fromJSON doc ref', async () => {
|
||||
if (isNode()) {
|
||||
const initialData = { a: 1 };
|
||||
const finalData = { a: 2 };
|
||||
await withTestDocAndInitialData(
|
||||
persistence,
|
||||
initialData,
|
||||
async (docRef, db) => {
|
||||
const doc = await getDoc(docRef);
|
||||
const fromJsonDoc = documentSnapshotFromJSON(db, doc.toJSON());
|
||||
const accumulator = new EventsAccumulator<DocumentSnapshot>();
|
||||
const unsubscribe = onSnapshot(
|
||||
fromJsonDoc.ref,
|
||||
accumulator.storeEvent
|
||||
);
|
||||
await accumulator
|
||||
.awaitEvent()
|
||||
.then(snap => {
|
||||
expect(snap.exists()).to.be.true;
|
||||
expect(snap.data()).to.deep.equal(initialData);
|
||||
})
|
||||
.then(() => setDoc(docRef, finalData))
|
||||
.then(() => accumulator.awaitEvent())
|
||||
.then(snap => {
|
||||
expect(snap.exists()).to.be.true;
|
||||
expect(snap.data()).to.deep.equal(finalData);
|
||||
});
|
||||
unsubscribe();
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it('Querysnapshot events for snapshot created by a bundle', async () => {
|
||||
if (isNode()) {
|
||||
const testDocs = {
|
||||
a: { foo: 1 },
|
||||
b: { bar: 2 }
|
||||
};
|
||||
await withTestCollection(persistence, testDocs, async (coll, db) => {
|
||||
const querySnap = await getDocs(query(coll, orderBy(documentId())));
|
||||
const accumulator = new EventsAccumulator<QuerySnapshot>();
|
||||
const unsubscribe = onSnapshotResume(
|
||||
db,
|
||||
querySnap.toJSON(),
|
||||
accumulator.storeEvent
|
||||
);
|
||||
await accumulator.awaitEvent().then(snap => {
|
||||
expect(snap.docs).not.to.be.null;
|
||||
expect(snap.docs.length).to.equal(2);
|
||||
expect(snap.docs[0].data()).to.deep.equal(testDocs.a);
|
||||
expect(snap.docs[1].data()).to.deep.equal(testDocs.b);
|
||||
});
|
||||
unsubscribe();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('Querysnapshot observer events for snapshot created by a bundle', async () => {
|
||||
if (isNode()) {
|
||||
const testDocs = {
|
||||
a: { foo: 1 },
|
||||
b: { bar: 2 }
|
||||
};
|
||||
await withTestCollection(persistence, testDocs, async (coll, db) => {
|
||||
const querySnap = await getDocs(query(coll, orderBy(documentId())));
|
||||
const accumulator = new EventsAccumulator<QuerySnapshot>();
|
||||
const unsubscribe = onSnapshotResume(db, querySnap.toJSON(), {
|
||||
next: accumulator.storeEvent
|
||||
});
|
||||
await accumulator.awaitEvent().then(snap => {
|
||||
expect(snap.docs).not.to.be.null;
|
||||
expect(snap.docs.length).to.equal(2);
|
||||
expect(snap.docs[0].data()).to.deep.equal(testDocs.a);
|
||||
expect(snap.docs[1].data()).to.deep.equal(testDocs.b);
|
||||
});
|
||||
unsubscribe();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('QuerySnapshot error events for snapshot created by a bundle', async () => {
|
||||
return withTestDb(persistence, async db => {
|
||||
const json = {
|
||||
bundle: 'BadData',
|
||||
bundleName: 'bundleName',
|
||||
bundleSource: 'QuerySnapshot'
|
||||
};
|
||||
const deferred = new Deferred();
|
||||
const unsubscribe = onSnapshotResume(
|
||||
db,
|
||||
json,
|
||||
qs => {
|
||||
expect(qs).to.not.exist;
|
||||
deferred.resolve();
|
||||
},
|
||||
err => {
|
||||
expect(err.name).to.exist;
|
||||
expect(err.message).to.exist;
|
||||
deferred.resolve();
|
||||
}
|
||||
);
|
||||
await deferred.promise;
|
||||
unsubscribe();
|
||||
});
|
||||
});
|
||||
|
||||
it('QuerySnapshot observer error events for snapshot created by a bundle', async () => {
|
||||
return withTestDb(persistence, async db => {
|
||||
const json = {
|
||||
bundle: 'BadData',
|
||||
bundleName: 'bundleName',
|
||||
bundleSource: 'QuerySnapshot'
|
||||
};
|
||||
const deferred = new Deferred();
|
||||
const unsubscribe = onSnapshotResume(db, json, {
|
||||
next: qs => {
|
||||
expect(qs).to.not.exist;
|
||||
deferred.resolve();
|
||||
},
|
||||
error: err => {
|
||||
expect(err.name).to.exist;
|
||||
expect(err.message).to.exist;
|
||||
deferred.resolve();
|
||||
}
|
||||
});
|
||||
await deferred.promise;
|
||||
unsubscribe();
|
||||
});
|
||||
});
|
||||
|
||||
it('QuerySnapshot updated doc events in snapshot created by a bundle', async () => {
|
||||
if (isNode()) {
|
||||
const testDocs = {
|
||||
a: { foo: 1 },
|
||||
b: { bar: 2 }
|
||||
};
|
||||
await withTestCollection(persistence, testDocs, async (coll, db) => {
|
||||
const querySnap = await getDocs(query(coll, orderBy(documentId())));
|
||||
const refForDocA = querySnap.docs[0].ref;
|
||||
const accumulator = new EventsAccumulator<QuerySnapshot>();
|
||||
const unsubscribe = onSnapshotResume(
|
||||
db,
|
||||
querySnap.toJSON(),
|
||||
accumulator.storeEvent
|
||||
);
|
||||
await accumulator
|
||||
.awaitEvent()
|
||||
.then(snap => {
|
||||
expect(snap.docs).not.to.be.null;
|
||||
expect(snap.docs.length).to.equal(2);
|
||||
expect(snap.docs[0].data()).to.deep.equal(testDocs.a);
|
||||
expect(snap.docs[1].data()).to.deep.equal(testDocs.b);
|
||||
})
|
||||
.then(() => setDoc(refForDocA, { foo: 0 }))
|
||||
.then(() => accumulator.awaitEvent())
|
||||
.then(snap => {
|
||||
expect(snap.docs).not.to.be.null;
|
||||
expect(snap.docs.length).to.equal(2);
|
||||
expect(snap.docs[0].data()).to.deep.equal({ foo: 0 });
|
||||
expect(snap.docs[1].data()).to.deep.equal(testDocs.b);
|
||||
});
|
||||
unsubscribe();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('QuerySnapshot updated doc events in snapshot created by fromJSON ', async () => {
|
||||
if (isNode()) {
|
||||
const testDocs = {
|
||||
a: { foo: 1 },
|
||||
b: { bar: 2 }
|
||||
};
|
||||
await withTestCollection(persistence, testDocs, async (coll, db) => {
|
||||
const querySnap = await getDocs(query(coll, orderBy(documentId())));
|
||||
const querySnapFromJson = querySnapshotFromJSON(db, querySnap.toJSON());
|
||||
const refForDocA = querySnapFromJson.docs[0].ref;
|
||||
const accumulator = new EventsAccumulator<QuerySnapshot>();
|
||||
|
||||
const unsubscribe = onSnapshotResume(
|
||||
db,
|
||||
querySnapFromJson.toJSON(),
|
||||
accumulator.storeEvent
|
||||
);
|
||||
await accumulator
|
||||
.awaitEvent()
|
||||
.then(snap => {
|
||||
expect(snap.docs).not.to.be.null;
|
||||
expect(snap.docs.length).to.equal(2);
|
||||
expect(snap.docs[0].data()).to.deep.equal(testDocs.a);
|
||||
expect(snap.docs[1].data()).to.deep.equal(testDocs.b);
|
||||
})
|
||||
.then(() => setDoc(refForDocA, { foo: 0 }))
|
||||
.then(() => accumulator.awaitEvent())
|
||||
.then(snap => {
|
||||
expect(snap.docs).not.to.be.null;
|
||||
expect(snap.docs.length).to.equal(2);
|
||||
expect(snap.docs[0].data()).to.deep.equal({ foo: 0 });
|
||||
expect(snap.docs[1].data()).to.deep.equal(testDocs.b);
|
||||
});
|
||||
unsubscribe();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('QuerySnapshot updated doc events in snapshot created by fromJSON query ref', async () => {
|
||||
if (isNode()) {
|
||||
const testDocs = {
|
||||
a: { foo: 1 },
|
||||
b: { bar: 2 }
|
||||
};
|
||||
await withTestCollection(persistence, testDocs, async (coll, db) => {
|
||||
const querySnap = await getDocs(query(coll, orderBy(documentId())));
|
||||
const querySnapFromJson = querySnapshotFromJSON(db, querySnap.toJSON());
|
||||
const refForDocA = querySnapFromJson.docs[0].ref;
|
||||
const accumulator = new EventsAccumulator<QuerySnapshot>();
|
||||
const unsubscribe = onSnapshot(
|
||||
querySnapFromJson.query,
|
||||
accumulator.storeEvent
|
||||
);
|
||||
await accumulator
|
||||
.awaitEvent()
|
||||
.then(snap => {
|
||||
expect(snap.docs).not.to.be.null;
|
||||
expect(snap.docs.length).to.equal(2);
|
||||
expect(snap.docs[0].data()).to.deep.equal(testDocs.a);
|
||||
expect(snap.docs[1].data()).to.deep.equal(testDocs.b);
|
||||
})
|
||||
.then(() => setDoc(refForDocA, { foo: 0 }))
|
||||
.then(() => accumulator.awaitEvent())
|
||||
.then(snap => {
|
||||
expect(snap.docs).not.to.be.null;
|
||||
expect(snap.docs.length).to.equal(2);
|
||||
expect(snap.docs[0].data()).to.deep.equal({ foo: 0 });
|
||||
expect(snap.docs[1].data()).to.deep.equal(testDocs.b);
|
||||
});
|
||||
unsubscribe();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('Metadata only changes are not fired when no options provided', () => {
|
||||
return withTestDoc(persistence, docRef => {
|
||||
const secondUpdateFound = new Deferred();
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { isNode } from '@firebase/util';
|
||||
import { expect } from 'chai';
|
||||
|
||||
import { addEqualityMatcher } from '../../util/equality_matcher';
|
||||
@@ -37,9 +38,11 @@ import {
|
||||
endAt,
|
||||
endBefore,
|
||||
GeoPoint,
|
||||
getDocFromCache,
|
||||
getDocs,
|
||||
limit,
|
||||
limitToLast,
|
||||
loadBundle,
|
||||
onSnapshot,
|
||||
or,
|
||||
orderBy,
|
||||
@@ -74,6 +77,47 @@ import { captureExistenceFilterMismatches } from '../util/testing_hooks_util';
|
||||
apiDescribe('Queries', persistence => {
|
||||
addEqualityMatcher();
|
||||
|
||||
it('QuerySnapshot.toJSON bundle getDocFromCache', async () => {
|
||||
if (isNode()) {
|
||||
let path: string | null = null;
|
||||
let jsonBundle: object | null = null;
|
||||
const testDocs = {
|
||||
a: { k: 'a' },
|
||||
b: { k: 'b' },
|
||||
c: { k: 'c' }
|
||||
};
|
||||
// Write an initial document in an isolated Firestore instance so it's not stored in the cache.
|
||||
await withTestCollection(persistence, testDocs, async collection => {
|
||||
await getDocs(query(collection)).then(querySnapshot => {
|
||||
expect(querySnapshot.docs.length).to.equal(3);
|
||||
// Find the path to a known doc.
|
||||
querySnapshot.docs.forEach(docSnapshot => {
|
||||
if (docSnapshot.ref.path.endsWith('a')) {
|
||||
path = docSnapshot.ref.path;
|
||||
}
|
||||
});
|
||||
expect(path).to.not.be.null;
|
||||
jsonBundle = querySnapshot.toJSON();
|
||||
});
|
||||
});
|
||||
expect(jsonBundle).to.not.be.null;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const json = (jsonBundle as any).bundle;
|
||||
expect(json).to.exist;
|
||||
expect(json.length).to.be.greaterThan(0);
|
||||
|
||||
if (path !== null) {
|
||||
await withTestDb(persistence, async db => {
|
||||
const docRef = doc(db, path!);
|
||||
await loadBundle(db, json);
|
||||
const docSnap = await getDocFromCache(docRef);
|
||||
expect(docSnap.exists);
|
||||
expect(docSnap.data()).to.deep.equal(testDocs.a);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('can issue limit queries', () => {
|
||||
const testDocs = {
|
||||
a: { k: 'a' },
|
||||
|
||||
@@ -423,6 +423,20 @@ describe('getDoc()', () => {
|
||||
expect(docSnap.exists()).to.be.true;
|
||||
});
|
||||
});
|
||||
|
||||
it('can get doc with a deserialized reference', () => {
|
||||
return withTestDocAndInitialData({ val: 1 }, async docRef => {
|
||||
const docSnap = await getDoc(docRef);
|
||||
expect(docSnap.exists()).to.be.true;
|
||||
const json = docRef.toJSON();
|
||||
const deserializedDocRef = DocumentReference.fromJSON(
|
||||
docSnap._firestore,
|
||||
json
|
||||
);
|
||||
const docSnap2 = await getDoc(deserializedDocRef);
|
||||
expect(docSnap2.exists()).to.be.true;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
|
||||
@@ -55,4 +55,52 @@ describe('Bytes', () => {
|
||||
expectEqual(blob(1, 2, 3), blob(1, 2, 3));
|
||||
expectNotEqual(blob(1, 2, 3), blob(4, 5, 6));
|
||||
});
|
||||
|
||||
it('fromJSON reconstructs the value from toJSON', () => {
|
||||
const bytes = Bytes.fromUint8Array(new Uint8Array([0, 1, 2, 3, 4, 5]));
|
||||
expect(() => {
|
||||
Bytes.fromJSON(bytes.toJSON());
|
||||
}).to.not.throw;
|
||||
expect(Bytes.fromJSON(bytes.toJSON()).isEqual(bytes)).to.be.true;
|
||||
});
|
||||
|
||||
it('fromJSON parameter order does not matter', () => {
|
||||
const type = 'firestore/bytes/1.0';
|
||||
const bytes = 'AA==';
|
||||
expect(() => {
|
||||
Bytes.fromJSON({ bytes, type });
|
||||
}).to.not.throw;
|
||||
expect(() => {
|
||||
Bytes.fromJSON({ type, bytes });
|
||||
}).to.not.throw;
|
||||
});
|
||||
|
||||
it('toJSON -> fromJSON bytes comparison', () => {
|
||||
Object.keys(base64Mappings).forEach(base64Str => {
|
||||
const bytesToSerialize = Bytes.fromBase64String(base64Str);
|
||||
const deserializedBytes = Bytes.fromJSON(bytesToSerialize.toJSON());
|
||||
expectEqual(bytesToSerialize, deserializedBytes);
|
||||
const expectedUint8Array = base64Mappings[base64Str];
|
||||
const actualUint8Array = deserializedBytes.toUint8Array();
|
||||
expect(actualUint8Array.length).to.equal(expectedUint8Array.length);
|
||||
for (let i = 0; i < actualUint8Array.length; i++) {
|
||||
expect(actualUint8Array[i]).to.equal(expectedUint8Array[i]);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('fromJSON misisng fields throws', () => {
|
||||
expect(() => {
|
||||
Bytes.fromJSON({ type: 'firestore/bytes/1.0' /* missing bytes data */ });
|
||||
}).to.throw;
|
||||
expect(() => {
|
||||
Bytes.fromJSON({ bytes: 'AA==' /* missing type */ });
|
||||
}).to.throw;
|
||||
expect(() => {
|
||||
Bytes.fromJSON({ type: 1, bytes: 'AA==' });
|
||||
}).to.throw;
|
||||
expect(() => {
|
||||
Bytes.fromJSON({ type: 'firestore/bytes/1.0', bytes: 1 });
|
||||
}).to.throw;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,10 +15,17 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { isNode } from '@firebase/util';
|
||||
import { expect } from 'chai';
|
||||
|
||||
import {
|
||||
DocumentReference,
|
||||
DocumentSnapshot,
|
||||
documentSnapshotFromJSON,
|
||||
QuerySnapshot,
|
||||
querySnapshotFromJSON,
|
||||
connectFirestoreEmulator,
|
||||
loadBundle,
|
||||
refEqual,
|
||||
snapshotEqual,
|
||||
queryEqual
|
||||
@@ -29,12 +36,22 @@ import {
|
||||
collectionReference,
|
||||
documentReference,
|
||||
documentSnapshot,
|
||||
firestore,
|
||||
newTestFirestore,
|
||||
query,
|
||||
querySnapshot
|
||||
} from '../../util/api_helpers';
|
||||
import { keys } from '../../util/helpers';
|
||||
|
||||
describe('Bundle', () => {
|
||||
it('loadBundle does not throw with an empty bundle string)', async () => {
|
||||
const db = newTestFirestore();
|
||||
expect(async () => {
|
||||
await loadBundle(db, '');
|
||||
}).to.not.throw;
|
||||
});
|
||||
});
|
||||
|
||||
describe('CollectionReference', () => {
|
||||
it('support equality checking with isEqual()', () => {
|
||||
expect(refEqual(collectionReference('foo'), collectionReference('foo'))).to
|
||||
@@ -61,6 +78,151 @@ describe('DocumentReference', () => {
|
||||
it('JSON.stringify() does not throw', () => {
|
||||
JSON.stringify(documentReference('foo/bar'));
|
||||
});
|
||||
|
||||
it('toJSON() does not throw', () => {
|
||||
expect(() => {
|
||||
documentReference('foo/bar').toJSON();
|
||||
}).to.not.throw;
|
||||
});
|
||||
|
||||
it('toJSON() includes correct JSON fields', () => {
|
||||
const docRef = documentReference('foo/bar');
|
||||
const json = docRef.toJSON();
|
||||
expect(json).to.deep.equal({
|
||||
type: 'firestore/documentReference/1.0',
|
||||
referencePath: 'foo/bar'
|
||||
});
|
||||
});
|
||||
|
||||
it('fromJSON() throws with invalid data', () => {
|
||||
const db = newTestFirestore();
|
||||
expect(() => {
|
||||
DocumentReference.fromJSON(db, {});
|
||||
}).to.throw("JSON missing required field: 'type'");
|
||||
});
|
||||
|
||||
it('fromJSON() throws with missing type data', () => {
|
||||
const db = newTestFirestore();
|
||||
expect(() => {
|
||||
documentSnapshotFromJSON(db, {
|
||||
bundleSource: 'DocumentSnapshot',
|
||||
bundleName: 'test name',
|
||||
bundle: 'test bundle'
|
||||
});
|
||||
}).to.throw("JSON missing required field: 'type'");
|
||||
});
|
||||
|
||||
it('fromJSON() throws with invalid type data', () => {
|
||||
const db = newTestFirestore();
|
||||
expect(() => {
|
||||
documentSnapshotFromJSON(db, {
|
||||
type: 1,
|
||||
bundleSource: 'DocumentSnapshot',
|
||||
bundleName: 'test name',
|
||||
bundle: 'test bundle'
|
||||
});
|
||||
}).to.throw("JSON field 'type' must be a string");
|
||||
});
|
||||
|
||||
it('fromJSON() throws with missing bundleSource', () => {
|
||||
const db = newTestFirestore();
|
||||
expect(() => {
|
||||
documentSnapshotFromJSON(db, {
|
||||
type: DocumentSnapshot._jsonSchemaVersion,
|
||||
bundleName: 'test name',
|
||||
bundle: 'test bundle'
|
||||
});
|
||||
}).to.throw("JSON missing required field: 'bundleSource'");
|
||||
});
|
||||
|
||||
it('fromJSON() throws with invalid bundleSource type', () => {
|
||||
const db = newTestFirestore();
|
||||
expect(() => {
|
||||
documentSnapshotFromJSON(db, {
|
||||
type: DocumentSnapshot._jsonSchemaVersion,
|
||||
bundleSource: 1,
|
||||
bundleName: 'test name',
|
||||
bundle: 'test bundle'
|
||||
});
|
||||
}).to.throw("JSON field 'bundleSource' must be a string");
|
||||
});
|
||||
|
||||
it('fromJSON() throws with invalid bundleSource value', () => {
|
||||
const db = newTestFirestore();
|
||||
expect(() => {
|
||||
documentSnapshotFromJSON(db, {
|
||||
type: DocumentSnapshot._jsonSchemaVersion,
|
||||
bundleSource: 'QuerySnapshot',
|
||||
bundleName: 'test name',
|
||||
bundle: 'test bundle'
|
||||
});
|
||||
}).to.throw("Expected 'bundleSource' field to equal 'DocumentSnapshot'");
|
||||
});
|
||||
|
||||
it('fromJSON() throws with missing bundleName', () => {
|
||||
const db = newTestFirestore();
|
||||
expect(() => {
|
||||
documentSnapshotFromJSON(db, {
|
||||
type: DocumentSnapshot._jsonSchemaVersion,
|
||||
bundleSource: 'DocumentSnapshot',
|
||||
bundle: 'test bundle'
|
||||
});
|
||||
}).to.throw("JSON missing required field: 'bundleName'");
|
||||
});
|
||||
|
||||
it('fromJSON() throws with invalid bundleName', () => {
|
||||
const db = newTestFirestore();
|
||||
expect(() => {
|
||||
documentSnapshotFromJSON(db, {
|
||||
type: DocumentSnapshot._jsonSchemaVersion,
|
||||
bundleSource: 'DocumentSnapshot',
|
||||
bundleName: 1,
|
||||
bundle: 'test bundle'
|
||||
});
|
||||
}).to.throw("JSON field 'bundleName' must be a string");
|
||||
});
|
||||
|
||||
it('fromJSON() throws with missing bundle', () => {
|
||||
const db = newTestFirestore();
|
||||
expect(() => {
|
||||
documentSnapshotFromJSON(db, {
|
||||
type: DocumentSnapshot._jsonSchemaVersion,
|
||||
bundleSource: 'DocumentSnapshot',
|
||||
bundleName: 'test name'
|
||||
});
|
||||
}).to.throw("JSON missing required field: 'bundle'");
|
||||
});
|
||||
|
||||
it('fromJSON() throws with invalid bundle', () => {
|
||||
const db = newTestFirestore();
|
||||
expect(() => {
|
||||
documentSnapshotFromJSON(db, {
|
||||
type: DocumentSnapshot._jsonSchemaVersion,
|
||||
bundleSource: 'DocumentSnapshot',
|
||||
bundleName: 'test name',
|
||||
bundle: 1
|
||||
});
|
||||
}).to.throw("JSON field 'bundle' must be a string");
|
||||
});
|
||||
|
||||
it('fromJSON() does not throw', () => {
|
||||
const db = newTestFirestore();
|
||||
const docRef = documentReference('foo/bar');
|
||||
const json = docRef.toJSON();
|
||||
expect(() => {
|
||||
DocumentReference.fromJSON(db, json);
|
||||
}).to.not.throw;
|
||||
});
|
||||
|
||||
it('fromJSON() equals original docRef', () => {
|
||||
const db = newTestFirestore();
|
||||
const docRef = documentReference('foo/bar');
|
||||
const json = docRef.toJSON();
|
||||
const deserializedDocRef = DocumentReference.fromJSON(db, json);
|
||||
expect(docRef.id).to.equal(deserializedDocRef.id);
|
||||
expect(docRef.path).to.equal(deserializedDocRef.path);
|
||||
expect(docRef.toJSON()).to.deep.equal(deserializedDocRef.toJSON());
|
||||
});
|
||||
});
|
||||
|
||||
describe('DocumentSnapshot', () => {
|
||||
@@ -107,6 +269,108 @@ describe('DocumentSnapshot', () => {
|
||||
it('JSON.stringify() does not throw', () => {
|
||||
JSON.stringify(documentSnapshot('foo/bar', { a: 1 }, true));
|
||||
});
|
||||
|
||||
it('toJSON returns a bundle', () => {
|
||||
const snapshotJson = documentSnapshot(
|
||||
'foo/bar',
|
||||
{ a: 1 },
|
||||
/*fromCache=*/ true
|
||||
).toJSON();
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const json = snapshotJson as any;
|
||||
expect(json.bundle).to.exist;
|
||||
expect(json.bundle.length).to.be.greaterThan(0);
|
||||
});
|
||||
|
||||
it('toJSON returns a bundle containing NOT_SUPPORTED in non-node environments', () => {
|
||||
if (!isNode()) {
|
||||
const snapshotJson = documentSnapshot(
|
||||
'foo/bar',
|
||||
{ a: 1 },
|
||||
/*fromCache=*/ true
|
||||
).toJSON();
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const json = snapshotJson as any;
|
||||
expect(json.bundle).to.exist;
|
||||
expect(json.bundle).to.equal('NOT SUPPORTED');
|
||||
}
|
||||
});
|
||||
|
||||
it('toJSON returns an empty bundle when there are no documents', () => {
|
||||
if (isNode()) {
|
||||
const snapshotJson = documentSnapshot(
|
||||
'foo/bar',
|
||||
/*data=*/ null,
|
||||
/*fromCache=*/ true
|
||||
).toJSON();
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const json = snapshotJson as any;
|
||||
expect(json.bundle).to.exist;
|
||||
expect(json.bundle.length).to.equal(0);
|
||||
}
|
||||
});
|
||||
|
||||
it('toJSON throws when there are pending writes', () => {
|
||||
expect(() => {
|
||||
documentSnapshot(
|
||||
'foo/bar',
|
||||
{},
|
||||
/*fromCache=*/ true,
|
||||
/*hasPendingWrites=*/ true
|
||||
).toJSON();
|
||||
}).to.throw(
|
||||
`DocumentSnapshot.toJSON() attempted to serialize a document with pending writes. ` +
|
||||
`Await waitForPendingWrites() before invoking toJSON().`
|
||||
);
|
||||
});
|
||||
|
||||
it('fromJSON throws when parsing client-side toJSON result', () => {
|
||||
if (!isNode()) {
|
||||
const docSnap = documentSnapshot(
|
||||
'foo/bar',
|
||||
{ a: 1 },
|
||||
/*fromCache=*/ true
|
||||
);
|
||||
expect(() => {
|
||||
documentSnapshotFromJSON(docSnap._firestore, docSnap.toJSON());
|
||||
}).to.throw;
|
||||
}
|
||||
});
|
||||
|
||||
it('fromJSON parses toJSON result', () => {
|
||||
if (isNode()) {
|
||||
const docSnap = documentSnapshot(
|
||||
'foo/bar',
|
||||
{ a: 1 },
|
||||
/*fromCache=*/ true
|
||||
);
|
||||
expect(() => {
|
||||
documentSnapshotFromJSON(docSnap._firestore, docSnap.toJSON());
|
||||
}).to.not.throw;
|
||||
}
|
||||
});
|
||||
|
||||
it('fromJSON produces valid snapshot data.', () => {
|
||||
if (isNode()) {
|
||||
const docSnap = documentSnapshot(
|
||||
'foo/bar',
|
||||
{ a: 1 },
|
||||
/*fromCache=*/ true
|
||||
);
|
||||
const db = firestore();
|
||||
const docSnapFromJSON = documentSnapshotFromJSON(db, docSnap.toJSON());
|
||||
expect(docSnapFromJSON).to.exist;
|
||||
const data = docSnapFromJSON.data();
|
||||
expect(docSnapFromJSON).to.not.be.undefined;
|
||||
expect(docSnapFromJSON).to.not.be.null;
|
||||
if (data) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
expect((data as any).a).to.exist;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
expect((data as any).a).to.equal(1);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('Query', () => {
|
||||
@@ -229,6 +493,259 @@ describe('QuerySnapshot', () => {
|
||||
querySnapshot('foo', {}, { a: { a: 1 } }, keys(), false, false)
|
||||
);
|
||||
});
|
||||
|
||||
it('toJSON returns a bundle', () => {
|
||||
const snapshotJson = querySnapshot(
|
||||
'foo',
|
||||
{},
|
||||
{ a: { a: 1 } },
|
||||
keys(), // An empty set of mutaded document keys signifies that there are no pending writes.
|
||||
false,
|
||||
false
|
||||
).toJSON();
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const json = snapshotJson as any;
|
||||
expect(json.bundle).to.exist;
|
||||
expect(json.bundle.length).to.be.greaterThan(0);
|
||||
});
|
||||
|
||||
it('toJSON returns a bundle containing NOT_SUPPORTED in non-node environments', () => {
|
||||
if (!isNode()) {
|
||||
const snapshotJson = querySnapshot(
|
||||
'foo',
|
||||
{},
|
||||
{ a: { a: 1 } },
|
||||
keys(), // An empty set of mutaded document keys signifies that there are no pending writes.
|
||||
false,
|
||||
false
|
||||
).toJSON();
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const json = snapshotJson as any;
|
||||
expect(json.bundle).to.exist;
|
||||
expect(json.bundle).to.equal('NOT SUPPORTED');
|
||||
}
|
||||
});
|
||||
|
||||
it('toJSON returns a bundle when there are no documents', () => {
|
||||
if (isNode()) {
|
||||
const snapshotJson = querySnapshot(
|
||||
'foo',
|
||||
{},
|
||||
{},
|
||||
keys(),
|
||||
false,
|
||||
false
|
||||
).toJSON();
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const json = snapshotJson as any;
|
||||
expect(json.bundle).to.exist;
|
||||
expect(json.bundle.length).to.be.greaterThan(0);
|
||||
}
|
||||
});
|
||||
|
||||
it('toJSON throws when there are pending writes', () => {
|
||||
expect(() =>
|
||||
querySnapshot(
|
||||
'foo',
|
||||
{},
|
||||
{ a: { a: 1 } },
|
||||
keys('foo/a'), // A non empty set of mutated keys signifies pending writes.
|
||||
false,
|
||||
false
|
||||
).toJSON()
|
||||
).to.throw(
|
||||
`QuerySnapshot.toJSON() attempted to serialize a document with pending writes. ` +
|
||||
`Await waitForPendingWrites() before invoking toJSON().`
|
||||
);
|
||||
});
|
||||
|
||||
it('fromJSON() throws with invalid data', () => {
|
||||
const db = newTestFirestore();
|
||||
expect(() => {
|
||||
querySnapshotFromJSON(db, {});
|
||||
}).to.throw("JSON missing required field: 'type'");
|
||||
});
|
||||
|
||||
it('fromJSON() throws with missing type data', () => {
|
||||
const db = newTestFirestore();
|
||||
expect(() => {
|
||||
querySnapshotFromJSON(db, {
|
||||
bundleSource: 'QuerySnapshot',
|
||||
bundleName: 'test name',
|
||||
bundle: 'test bundle'
|
||||
});
|
||||
}).to.throw("JSON missing required field: 'type'");
|
||||
});
|
||||
|
||||
it('fromJSON() throws with invalid type data', () => {
|
||||
const db = newTestFirestore();
|
||||
expect(() => {
|
||||
querySnapshotFromJSON(db, {
|
||||
type: 1,
|
||||
bundleSource: 'QuerySnapshot',
|
||||
bundleName: 'test name',
|
||||
bundle: 'test bundle'
|
||||
});
|
||||
}).to.throw("JSON field 'type' must be a string");
|
||||
});
|
||||
|
||||
it('fromJSON() throws with missing bundle source data', () => {
|
||||
const db = newTestFirestore();
|
||||
expect(() => {
|
||||
querySnapshotFromJSON(db, {
|
||||
type: QuerySnapshot._jsonSchemaVersion,
|
||||
bundleName: 'test name',
|
||||
bundle: 'test bundle'
|
||||
});
|
||||
}).to.throw("JSON missing required field: 'bundleSource'");
|
||||
});
|
||||
|
||||
it('fromJSON() throws with invalid bundleSource type', () => {
|
||||
const db = newTestFirestore();
|
||||
expect(() => {
|
||||
querySnapshotFromJSON(db, {
|
||||
type: QuerySnapshot._jsonSchemaVersion,
|
||||
bundleSource: 1,
|
||||
bundleName: 'test name',
|
||||
bundle: 'test bundle'
|
||||
});
|
||||
}).to.throw("JSON field 'bundleSource' must be a string");
|
||||
});
|
||||
|
||||
it('fromJSON() throws with invalid bundleSource value', () => {
|
||||
const db = newTestFirestore();
|
||||
expect(() => {
|
||||
querySnapshotFromJSON(db, {
|
||||
type: QuerySnapshot._jsonSchemaVersion,
|
||||
bundleSource: 'DocumentSnapshot',
|
||||
bundleName: 'test name',
|
||||
bundle: 'test bundle'
|
||||
});
|
||||
}).to.throw("Expected 'bundleSource' field to equal 'QuerySnapshot'");
|
||||
});
|
||||
|
||||
it('fromJSON() throws with missing bundleName', () => {
|
||||
const db = newTestFirestore();
|
||||
expect(() => {
|
||||
querySnapshotFromJSON(db, {
|
||||
type: QuerySnapshot._jsonSchemaVersion,
|
||||
bundleSource: 'QuerySnapshot',
|
||||
bundle: 'test bundle'
|
||||
});
|
||||
}).to.throw("JSON missing required field: 'bundleName'");
|
||||
});
|
||||
|
||||
it('fromJSON() throws with invalid bundleName', () => {
|
||||
const db = newTestFirestore();
|
||||
expect(() => {
|
||||
querySnapshotFromJSON(db, {
|
||||
type: QuerySnapshot._jsonSchemaVersion,
|
||||
bundleSource: 'QuerySnapshot',
|
||||
bundleName: 1,
|
||||
bundle: 'test bundle'
|
||||
});
|
||||
}).to.throw("JSON field 'bundleName' must be a string");
|
||||
});
|
||||
|
||||
it('fromJSON() throws with missing bundle field', () => {
|
||||
const db = newTestFirestore();
|
||||
expect(() => {
|
||||
querySnapshotFromJSON(db, {
|
||||
type: QuerySnapshot._jsonSchemaVersion,
|
||||
bundleSource: 'QuerySnapshot',
|
||||
bundleName: 'test name'
|
||||
});
|
||||
}).to.throw("JSON missing required field: 'bundle'");
|
||||
});
|
||||
|
||||
it('fromJSON() throws with invalid bundle field', () => {
|
||||
const db = newTestFirestore();
|
||||
expect(() => {
|
||||
querySnapshotFromJSON(db, {
|
||||
type: QuerySnapshot._jsonSchemaVersion,
|
||||
bundleSource: 'QuerySnapshot',
|
||||
bundleName: 'test name',
|
||||
bundle: 1
|
||||
});
|
||||
}).to.throw("JSON field 'bundle' must be a string");
|
||||
});
|
||||
|
||||
it('fromJSON does not throw', () => {
|
||||
if (isNode()) {
|
||||
const snapshot = querySnapshot(
|
||||
'foo',
|
||||
{},
|
||||
{
|
||||
a: { a: 1 },
|
||||
b: { bar: 2 }
|
||||
},
|
||||
keys(), // An empty set of mutaded document keys signifies that there are no pending writes.
|
||||
false,
|
||||
false
|
||||
);
|
||||
const db = firestore();
|
||||
expect(() => {
|
||||
querySnapshotFromJSON(db, snapshot.toJSON());
|
||||
}).to.not.throw;
|
||||
}
|
||||
});
|
||||
|
||||
it('fromJSON produces valid snapshot data', () => {
|
||||
if (isNode()) {
|
||||
const snapshot = querySnapshot(
|
||||
'foo',
|
||||
{},
|
||||
{
|
||||
a: { a: 1 },
|
||||
b: { bar: 2 }
|
||||
},
|
||||
keys(), // An empty set of mutaded document keys signifies that there are no pending writes.
|
||||
false,
|
||||
false
|
||||
);
|
||||
const db = firestore();
|
||||
const querySnap = querySnapshotFromJSON(db, snapshot.toJSON());
|
||||
expect(querySnap).to.exist;
|
||||
if (querySnap !== undefined) {
|
||||
const docs = querySnap.docs;
|
||||
expect(docs).to.not.be.undefined;
|
||||
expect(docs).to.not.be.null;
|
||||
if (docs) {
|
||||
expect(docs.length).to.equal(2);
|
||||
if (docs.length === 2) {
|
||||
let docData = docs[0].data();
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
let data = docData as any;
|
||||
expect(data.a).to.exist;
|
||||
expect(data.a).to.equal(1);
|
||||
|
||||
docData = docs[1].data();
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
data = docData as any;
|
||||
expect(data.bar).to.exist;
|
||||
expect(data.bar).to.equal(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('fromJSON throws when parsing client-side toJSON result', () => {
|
||||
if (!isNode()) {
|
||||
const querySnap = querySnapshot(
|
||||
'foo',
|
||||
{},
|
||||
{ a: { a: 1 } },
|
||||
keys(), // An empty set of mutaded document keys signifies that there are no pending writes.
|
||||
false,
|
||||
false
|
||||
);
|
||||
const json = querySnap.toJSON();
|
||||
expect(() => {
|
||||
querySnapshotFromJSON(querySnap._firestore, json);
|
||||
}).to.throw;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('SnapshotMetadata', () => {
|
||||
|
||||
@@ -105,15 +105,96 @@ describe('GeoPoint', () => {
|
||||
it('serializes to JSON', () => {
|
||||
expect(new GeoPoint(1, 2).toJSON()).to.deep.equal({
|
||||
latitude: 1,
|
||||
longitude: 2
|
||||
longitude: 2,
|
||||
'type': GeoPoint._jsonSchemaVersion
|
||||
});
|
||||
expect(new GeoPoint(0, 0).toJSON()).to.deep.equal({
|
||||
latitude: 0,
|
||||
longitude: 0
|
||||
longitude: 0,
|
||||
'type': GeoPoint._jsonSchemaVersion
|
||||
});
|
||||
expect(new GeoPoint(90, 180).toJSON()).to.deep.equal({
|
||||
latitude: 90,
|
||||
longitude: 180
|
||||
longitude: 180,
|
||||
'type': GeoPoint._jsonSchemaVersion
|
||||
});
|
||||
});
|
||||
it('fromJSON does not throw', () => {
|
||||
const geoPoint = new GeoPoint(1, 2);
|
||||
expect(() => {
|
||||
GeoPoint.fromJSON(geoPoint.toJSON());
|
||||
}).to.not.throw;
|
||||
});
|
||||
|
||||
it('fromJSON reconstructs seconds and nanoseconds', () => {
|
||||
const geoPoint = new GeoPoint(1, 2);
|
||||
const deserializedGeoPoint = GeoPoint.fromJSON(geoPoint.toJSON());
|
||||
expect(deserializedGeoPoint).to.exist;
|
||||
expect(geoPoint.latitude).to.equal(deserializedGeoPoint.latitude);
|
||||
expect(geoPoint.longitude).to.equal(deserializedGeoPoint.longitude);
|
||||
});
|
||||
|
||||
it('toJSON -> fromJSON timestamp comparison', () => {
|
||||
const geoPoint = new GeoPoint(1, 2);
|
||||
const deserializedGeoPoint = GeoPoint.fromJSON(geoPoint.toJSON());
|
||||
expect(deserializedGeoPoint.isEqual(geoPoint)).to.be.true;
|
||||
});
|
||||
|
||||
it('fromJSON parameter order does not matter', () => {
|
||||
const type = 'firestore/geopoint/1.0';
|
||||
const latitude = 90;
|
||||
const longitude = 180;
|
||||
const control = new GeoPoint(90, 180);
|
||||
expect(() => {
|
||||
expect(GeoPoint.fromJSON({ latitude, longitude, type }).isEqual(control))
|
||||
.to.be.true;
|
||||
}).to.not.throw;
|
||||
expect(() => {
|
||||
expect(GeoPoint.fromJSON({ longitude, type, latitude }).isEqual(control))
|
||||
.to.be.true;
|
||||
}).to.not.throw;
|
||||
expect(() => {
|
||||
expect(GeoPoint.fromJSON({ type, latitude, longitude }).isEqual(control))
|
||||
.to.be.true;
|
||||
}).to.not.throw;
|
||||
expect(() => {
|
||||
expect(GeoPoint.fromJSON({ latitude, type, longitude }).isEqual(control))
|
||||
.to.be.true;
|
||||
}).to.not.throw;
|
||||
});
|
||||
|
||||
it('fromJSON missing fields throws', () => {
|
||||
const type = 'firestore/geopoint/1.0';
|
||||
const latitude = 90;
|
||||
const longitude = 180;
|
||||
|
||||
expect(() => {
|
||||
GeoPoint.fromJSON({ type, latitude });
|
||||
}).to.throw;
|
||||
expect(() => {
|
||||
GeoPoint.fromJSON({ type, longitude });
|
||||
}).to.throw;
|
||||
expect(() => {
|
||||
GeoPoint.fromJSON({ latitude, longitude });
|
||||
}).to.throw;
|
||||
});
|
||||
|
||||
it('fromJSON field errant field type throws', () => {
|
||||
const type = 'firestore/geopoint/1.0';
|
||||
const latitude = 90;
|
||||
const longitude = 180;
|
||||
|
||||
expect(() => {
|
||||
GeoPoint.fromJSON({ type, latitude, longitude: 'wrong' });
|
||||
}).to.throw;
|
||||
expect(() => {
|
||||
GeoPoint.fromJSON({ type, longitude, latitude: 'wrong' });
|
||||
}).to.throw;
|
||||
expect(() => {
|
||||
GeoPoint.fromJSON({ latitude, longitude, type: 1 });
|
||||
}).to.throw;
|
||||
expect(() => {
|
||||
GeoPoint.fromJSON({ latitude, longitude, type: 'firestore/wrong/1.0' });
|
||||
}).to.throw;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -143,15 +143,101 @@ describe('Timestamp', () => {
|
||||
it('serializes to JSON', () => {
|
||||
expect(new Timestamp(123, 456).toJSON()).to.deep.equal({
|
||||
seconds: 123,
|
||||
nanoseconds: 456
|
||||
nanoseconds: 456,
|
||||
type: 'firestore/timestamp/1.0'
|
||||
});
|
||||
expect(new Timestamp(0, 0).toJSON()).to.deep.equal({
|
||||
seconds: 0,
|
||||
nanoseconds: 0
|
||||
nanoseconds: 0,
|
||||
type: 'firestore/timestamp/1.0'
|
||||
});
|
||||
expect(new Timestamp(-123, 456).toJSON()).to.deep.equal({
|
||||
seconds: -123,
|
||||
nanoseconds: 456
|
||||
nanoseconds: 456,
|
||||
type: 'firestore/timestamp/1.0'
|
||||
});
|
||||
});
|
||||
|
||||
it('fromJSON does not throw', () => {
|
||||
const timestamp = new Timestamp(123, 456);
|
||||
expect(() => {
|
||||
Timestamp.fromJSON(timestamp.toJSON());
|
||||
}).to.not.throw;
|
||||
});
|
||||
|
||||
it('fromJSON reconstructs seconds and nanoseconds', () => {
|
||||
const timestamp = new Timestamp(123, 456);
|
||||
const deserializedTimestamp = Timestamp.fromJSON(timestamp.toJSON());
|
||||
expect(deserializedTimestamp).to.exist;
|
||||
expect(timestamp.nanoseconds).to.equal(deserializedTimestamp.nanoseconds);
|
||||
expect(timestamp.seconds).to.equal(deserializedTimestamp.seconds);
|
||||
});
|
||||
|
||||
it('toJSON -> fromJSON timestamp comparison', () => {
|
||||
const timestamp = new Timestamp(123, 456);
|
||||
const deserializedTimestamp = Timestamp.fromJSON(timestamp.toJSON());
|
||||
expect(deserializedTimestamp.isEqual(timestamp)).to.be.true;
|
||||
});
|
||||
|
||||
it('fromJSON parameter order does not matter', () => {
|
||||
const type = 'firestore/timestamp/1.0';
|
||||
const seconds = 123;
|
||||
const nanoseconds = 456;
|
||||
const control = new Timestamp(seconds, nanoseconds);
|
||||
expect(() => {
|
||||
expect(
|
||||
Timestamp.fromJSON({ seconds, nanoseconds, type }).isEqual(control)
|
||||
).to.be.true;
|
||||
}).to.not.throw;
|
||||
expect(() => {
|
||||
expect(
|
||||
Timestamp.fromJSON({ nanoseconds, type, seconds }).isEqual(control)
|
||||
).to.be.true;
|
||||
}).to.not.throw;
|
||||
expect(() => {
|
||||
expect(
|
||||
Timestamp.fromJSON({ type, seconds, nanoseconds }).isEqual(control)
|
||||
).to.be.true;
|
||||
}).to.not.throw;
|
||||
expect(() => {
|
||||
expect(
|
||||
Timestamp.fromJSON({ seconds, type, nanoseconds }).isEqual(control)
|
||||
).to.be.true;
|
||||
}).to.not.throw;
|
||||
});
|
||||
|
||||
it('fromJSON missing fields throws', () => {
|
||||
const type = 'firestore/timestamp/1.0';
|
||||
const seconds = 123;
|
||||
const nanoseconds = 456;
|
||||
|
||||
expect(() => {
|
||||
Timestamp.fromJSON({ type, seconds });
|
||||
}).to.throw;
|
||||
expect(() => {
|
||||
Timestamp.fromJSON({ type, nanoseconds });
|
||||
}).to.throw;
|
||||
expect(() => {
|
||||
Timestamp.fromJSON({ seconds, nanoseconds });
|
||||
}).to.throw;
|
||||
});
|
||||
|
||||
it('fromJSON field errant field type throws', () => {
|
||||
const type = 'firestore/timestamp/1.0';
|
||||
const seconds = 123;
|
||||
const nanoseconds = 456;
|
||||
|
||||
expect(() => {
|
||||
Timestamp.fromJSON({ type, seconds, nanoseconds: 'wrong' });
|
||||
}).to.throw;
|
||||
expect(() => {
|
||||
Timestamp.fromJSON({ type, nanoseconds, seconds: 'wrong' });
|
||||
}).to.throw;
|
||||
expect(() => {
|
||||
Timestamp.fromJSON({ seconds, nanoseconds, type: 1 });
|
||||
}).to.throw;
|
||||
expect(() => {
|
||||
Timestamp.fromJSON({ seconds, nanoseconds, type: 'firestore/wrong/1.0' });
|
||||
}).to.throw;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2025 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.
|
||||
*/
|
||||
|
||||
import { expect } from 'chai';
|
||||
|
||||
import { VectorValue } from '../../../src';
|
||||
|
||||
describe('VectorValue', () => {
|
||||
it('fromJSON reconstructs the value from toJSON', () => {
|
||||
const num: number[] = [1, 2, 3];
|
||||
const vectorValue = new VectorValue(num);
|
||||
const json = vectorValue.toJSON();
|
||||
const parsedVectorValue = VectorValue.fromJSON(json);
|
||||
expect(vectorValue.isEqual(parsedVectorValue)).to.be.true;
|
||||
});
|
||||
|
||||
it('fromJSON parameter order does not matter', () => {
|
||||
const type = VectorValue._jsonSchemaVersion;
|
||||
const vectorValues = [1, 2, 3];
|
||||
const control = new VectorValue(vectorValues);
|
||||
|
||||
expect(() => {
|
||||
expect(VectorValue.fromJSON({ vectorValues, type }).isEqual(control)).to
|
||||
.be.true;
|
||||
}).to.not.throw;
|
||||
expect(() => {
|
||||
expect(VectorValue.fromJSON({ type, vectorValues }).isEqual(control)).to
|
||||
.be.true;
|
||||
}).to.not.throw;
|
||||
});
|
||||
|
||||
it('fromJSON empty array does not throw', () => {
|
||||
const type = VectorValue._jsonSchemaVersion;
|
||||
const vectorValues = [1, 2, 3];
|
||||
expect(() => {
|
||||
VectorValue.fromJSON({ type, vectorValues });
|
||||
}).to.not.throw;
|
||||
});
|
||||
|
||||
it('fromJSON missing fields throws', () => {
|
||||
const type = VectorValue._jsonSchemaVersion;
|
||||
const vectorValues = [1, 2, 3];
|
||||
expect(() => {
|
||||
VectorValue.fromJSON({ type /* missing data */ });
|
||||
}).to.throw;
|
||||
expect(() => {
|
||||
VectorValue.fromJSON({ vectorValues /* missing type */ });
|
||||
}).to.throw;
|
||||
expect(() => {
|
||||
VectorValue.fromJSON({ type: 1, vectorValues });
|
||||
}).to.throw;
|
||||
expect(() => {
|
||||
VectorValue.fromJSON({ type: 'firestore/bytes/1.0', vectorValues });
|
||||
}).to.throw;
|
||||
expect(() => {
|
||||
VectorValue.fromJSON({ type, vectorValues: 'not a number' });
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -316,10 +316,14 @@ describe('IndexedDbSchema: createOrUpgradeDb', () => {
|
||||
lastRemoteSnapshotVersion: { seconds: 1, nanoseconds: 1 },
|
||||
targetCount: 1
|
||||
};
|
||||
const timestamp = SnapshotVersion.min().toTimestamp();
|
||||
const resetTargetGlobal: DbTargetGlobal = {
|
||||
highestTargetId: 0,
|
||||
highestListenSequenceNumber: 0,
|
||||
lastRemoteSnapshotVersion: SnapshotVersion.min().toTimestamp(),
|
||||
lastRemoteSnapshotVersion: {
|
||||
seconds: timestamp.seconds,
|
||||
nanoseconds: timestamp.nanoseconds
|
||||
},
|
||||
targetCount: 0
|
||||
};
|
||||
|
||||
|
||||
@@ -79,8 +79,10 @@ export function documentReference(path: string): DocumentReference {
|
||||
export function documentSnapshot(
|
||||
path: string,
|
||||
data: JsonObject<unknown> | null,
|
||||
fromCache: boolean
|
||||
fromCache: boolean,
|
||||
hasPendingWrites?: boolean
|
||||
): DocumentSnapshot {
|
||||
hasPendingWrites = !!hasPendingWrites;
|
||||
const db = firestore();
|
||||
const userDataWriter = new ExpUserDataWriter(db);
|
||||
if (data) {
|
||||
@@ -89,7 +91,7 @@ export function documentSnapshot(
|
||||
userDataWriter,
|
||||
key(path),
|
||||
doc(path, 1, data),
|
||||
new SnapshotMetadata(/* hasPendingWrites= */ false, fromCache),
|
||||
new SnapshotMetadata(hasPendingWrites, fromCache),
|
||||
/* converter= */ null
|
||||
);
|
||||
} else {
|
||||
@@ -98,7 +100,7 @@ export function documentSnapshot(
|
||||
userDataWriter,
|
||||
key(path),
|
||||
null,
|
||||
new SnapshotMetadata(/* hasPendingWrites= */ false, fromCache),
|
||||
new SnapshotMetadata(hasPendingWrites, fromCache),
|
||||
/* converter= */ null
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user