watch.d.ts 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. /*!
  2. * Copyright 2017 Google Inc. All Rights Reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. import * as firestore from '@google-cloud/firestore';
  17. import { google } from '../protos/firestore_v1_proto_api';
  18. import { QueryDocumentSnapshot } from './document';
  19. import { DocumentChange } from './document-change';
  20. import { DocumentReference, Firestore, Query } from './index';
  21. import { Timestamp } from './timestamp';
  22. import api = google.firestore.v1;
  23. /*!
  24. * Idle timeout used to detect Watch streams that stall (see
  25. * https://github.com/googleapis/nodejs-firestore/issues/1057, b/156308554).
  26. * Under normal load, the Watch backend will send a TARGET_CHANGE message
  27. * roughly every 30 seconds. As discussed with the backend team, we reset the
  28. * Watch stream if we do not receive any message within 120 seconds.
  29. */
  30. export declare const WATCH_IDLE_TIMEOUT_MS: number;
  31. /**
  32. * @private
  33. * @internal
  34. * @callback docsCallback
  35. * @returns {Array.<QueryDocumentSnapshot>} An ordered list of documents.
  36. */
  37. /**
  38. * @private
  39. * @internal
  40. * @callback changeCallback
  41. * @returns {Array.<DocumentChange>} An ordered list of document
  42. * changes.
  43. */
  44. /**
  45. * onSnapshot() callback that receives the updated query state.
  46. *
  47. * @private
  48. * @internal
  49. * @callback watchSnapshotCallback
  50. *
  51. * @param {Timestamp} readTime The time at which this snapshot was obtained.
  52. * @param {number} size The number of documents in the result set.
  53. * @param {docsCallback} docs A callback that returns the ordered list of
  54. * documents stored in this snapshot.
  55. * @param {changeCallback} changes A callback that returns the list of
  56. * changed documents since the last snapshot delivered for this watch.
  57. */
  58. type DocumentComparator<AppModelType, DbModelType extends firestore.DocumentData> = (l: QueryDocumentSnapshot<AppModelType, DbModelType>, r: QueryDocumentSnapshot<AppModelType, DbModelType>) => number;
  59. /**
  60. * Watch provides listen functionality and exposes the 'onSnapshot' observer. It
  61. * can be used with a valid Firestore Listen target.
  62. *
  63. * @class
  64. * @private
  65. * @internal
  66. */
  67. declare abstract class Watch<AppModelType = firestore.DocumentData, DbModelType extends firestore.DocumentData = firestore.DocumentData> {
  68. readonly _converter: firestore.FirestoreDataConverter<AppModelType, DbModelType>;
  69. protected readonly firestore: Firestore;
  70. private readonly backoff;
  71. private readonly requestTag;
  72. /**
  73. * Indicates whether we are interested in data from the stream. Set to false in the
  74. * 'unsubscribe()' callback.
  75. * @private
  76. * @internal
  77. */
  78. private isActive;
  79. /**
  80. * The current stream to the backend.
  81. * @private
  82. * @internal
  83. */
  84. private currentStream;
  85. /**
  86. * The server assigns and updates the resume token.
  87. * @private
  88. * @internal
  89. */
  90. private resumeToken;
  91. /**
  92. * A map of document names to QueryDocumentSnapshots for the last sent snapshot.
  93. * @private
  94. * @internal
  95. */
  96. private docMap;
  97. /**
  98. * The accumulated map of document changes (keyed by document name) for the
  99. * current snapshot.
  100. * @private
  101. * @internal
  102. */
  103. private changeMap;
  104. /**
  105. * The current state of the query results. *
  106. * @private
  107. * @internal
  108. */
  109. private current;
  110. /**
  111. * The sorted tree of QueryDocumentSnapshots as sent in the last snapshot.
  112. * We only look at the keys.
  113. * @private
  114. * @internal
  115. */
  116. private docTree;
  117. /**
  118. * We need this to track whether we've pushed an initial set of changes,
  119. * since we should push those even when there are no changes, if there
  120. * aren't docs.
  121. * @private
  122. * @internal
  123. */
  124. private hasPushed;
  125. /**
  126. * The handler used to restart the Watch stream if it has been idle for more
  127. * than WATCH_IDLE_TIMEOUT_MS.
  128. */
  129. private idleTimeoutHandle?;
  130. private onNext;
  131. private onError;
  132. /**
  133. * @private
  134. * @internal
  135. *
  136. * @param firestore The Firestore Database client.
  137. */
  138. constructor(firestore: Firestore, _converter?: firestore.FirestoreDataConverter<AppModelType, DbModelType>);
  139. /** Returns a 'Target' proto denoting the target to listen on. */
  140. protected abstract getTarget(resumeToken?: Uint8Array): api.ITarget;
  141. /**
  142. * Returns a comparator for QueryDocumentSnapshots that is used to order the
  143. * document snapshots returned by this watch.
  144. */
  145. protected abstract getComparator(): DocumentComparator<AppModelType, DbModelType>;
  146. /**
  147. * Starts a watch and attaches a listener for document change events.
  148. *
  149. * @private
  150. * @internal
  151. * @param onNext A callback to be called every time a new snapshot is
  152. * available.
  153. * @param onError A callback to be called if the listen fails or is cancelled.
  154. * No further callbacks will occur.
  155. *
  156. * @returns An unsubscribe function that can be called to cancel the snapshot
  157. * listener.
  158. */
  159. onSnapshot(onNext: (readTime: Timestamp, size: number, docs: () => Array<QueryDocumentSnapshot<AppModelType, DbModelType>>, changes: () => Array<DocumentChange<AppModelType, DbModelType>>) => void, onError: (error: Error) => void): () => void;
  160. /**
  161. * Returns the current count of all documents, including the changes from
  162. * the current changeMap.
  163. * @private
  164. * @internal
  165. */
  166. private currentSize;
  167. /**
  168. * Splits up document changes into removals, additions, and updates.
  169. * @private
  170. * @internal
  171. */
  172. private extractCurrentChanges;
  173. /**
  174. * Helper to clear the docs on RESET or filter mismatch.
  175. * @private
  176. * @internal
  177. */
  178. private resetDocs;
  179. /**
  180. * Closes the stream and calls onError() if the stream is still active.
  181. * @private
  182. * @internal
  183. */
  184. private closeStream;
  185. /**
  186. * Re-opens the stream unless the specified error is considered permanent.
  187. * Clears the change map.
  188. * @private
  189. * @internal
  190. */
  191. private maybeReopenStream;
  192. /**
  193. * Cancels the current idle timeout and reschedules a new timer.
  194. *
  195. * @private
  196. * @internal
  197. */
  198. private resetIdleTimeout;
  199. /**
  200. * Helper to restart the outgoing stream to the backend.
  201. * @private
  202. * @internal
  203. */
  204. private resetStream;
  205. /**
  206. * Initializes a new stream to the backend with backoff.
  207. * @private
  208. * @internal
  209. */
  210. private initStream;
  211. /**
  212. * Handles 'data' events and closes the stream if the response type is
  213. * invalid.
  214. * @private
  215. * @internal
  216. */
  217. private onData;
  218. /**
  219. * Checks if the current target id is included in the list of target ids.
  220. * If no targetIds are provided, returns true.
  221. * @private
  222. * @internal
  223. */
  224. private affectsTarget;
  225. /**
  226. * Assembles a new snapshot from the current set of changes and invokes the
  227. * user's callback. Clears the current changes on completion.
  228. * @private
  229. * @internal
  230. */
  231. private pushSnapshot;
  232. /**
  233. * Applies a document delete to the document tree and the document map.
  234. * Returns the corresponding DocumentChange event.
  235. * @private
  236. * @internal
  237. */
  238. private deleteDoc;
  239. /**
  240. * Applies a document add to the document tree and the document map. Returns
  241. * the corresponding DocumentChange event.
  242. * @private
  243. * @internal
  244. */
  245. private addDoc;
  246. /**
  247. * Applies a document modification to the document tree and the document map.
  248. * Returns the DocumentChange event for successful modifications.
  249. * @private
  250. * @internal
  251. */
  252. private modifyDoc;
  253. /**
  254. * Applies the mutations in changeMap to both the document tree and the
  255. * document lookup map. Modified docMap in-place and returns the updated
  256. * state.
  257. * @private
  258. * @internal
  259. */
  260. private computeSnapshot;
  261. /**
  262. * Determines whether a watch error is considered permanent and should not be
  263. * retried. Errors that don't provide a GRPC error code are always considered
  264. * transient in this context.
  265. *
  266. * @private
  267. * @internal
  268. * @param error An error object.
  269. * @return Whether the error is permanent.
  270. */
  271. private isPermanentWatchError;
  272. /**
  273. * Determines whether we need to initiate a longer backoff due to system
  274. * overload.
  275. *
  276. * @private
  277. * @internal
  278. * @param error A GRPC Error object that exposes an error code.
  279. * @return Whether we need to back off our retries.
  280. */
  281. private isResourceExhaustedError;
  282. /** Closes the stream and clears all timeouts. */
  283. private shutdown;
  284. }
  285. /**
  286. * Creates a new Watch instance to listen on DocumentReferences.
  287. *
  288. * @private
  289. * @internal
  290. */
  291. export declare class DocumentWatch<AppModelType = firestore.DocumentData, DbModelType extends firestore.DocumentData = firestore.DocumentData> extends Watch<AppModelType, DbModelType> {
  292. private readonly ref;
  293. constructor(firestore: Firestore, ref: DocumentReference<AppModelType, DbModelType>);
  294. getComparator(): DocumentComparator<AppModelType, DbModelType>;
  295. getTarget(resumeToken?: Uint8Array): google.firestore.v1.ITarget;
  296. }
  297. /**
  298. * Creates a new Watch instance to listen on Queries.
  299. *
  300. * @private
  301. * @internal
  302. */
  303. export declare class QueryWatch<AppModelType = firestore.DocumentData, DbModelType extends firestore.DocumentData = firestore.DocumentData> extends Watch<AppModelType, DbModelType> {
  304. private readonly query;
  305. private comparator;
  306. constructor(firestore: Firestore, query: Query<AppModelType, DbModelType>, converter?: firestore.FirestoreDataConverter<AppModelType, DbModelType>);
  307. getComparator(): DocumentComparator<AppModelType, DbModelType>;
  308. getTarget(resumeToken?: Uint8Array): google.firestore.v1.ITarget;
  309. }
  310. export {};