internal static DocumentSnapshot ForMissingDocument(FirestoreDb db, string name, Timestamp readTime) => new DocumentSnapshot(db, name, null, readTime);
private DocumentSnapshot(FirestoreDb db, string resourceName, Document document, Timestamp readTime) { GaxPreconditions.CheckNotNull(db, nameof(db)); GaxPreconditions.CheckNotNull(resourceName, nameof(resourceName)); Reference = db.GetDocumentReferenceFromResourceName(resourceName); Document = document; CreateTime = Timestamp.FromProtoOrNull(document?.CreateTime); UpdateTime = Timestamp.FromProtoOrNull(document?.UpdateTime); ReadTime = readTime; }
internal static DocumentSnapshot ForDocument(FirestoreDb db, Document document, Timestamp readTime) => new DocumentSnapshot(db, document.Name, document, readTime);
// // CreateDocumentSnapshot(DocumentChange documentChange) // // Generate a DocumentSnapshot from a Document private DocumentSnapshot CreateDocumentSnapshot(Document document) { //Creation of DocumentSnapshots is internal so we are very much cheating and using reflection to access them var snapshotType = typeof(DocumentSnapshot); var forDocument = snapshotType.GetMethod("ForDocument", BindingFlags.Static | BindingFlags.NonPublic); //It's probably bad to use the current timestamp, but we don't seem to have access to the readTime in ListenResponse DocumentSnapshot snapshot = null; try { snapshot = forDocument.Invoke(null, new object[] { FirestoreDb, document, Timestamp.GetCurrentTimestamp() }) as DocumentSnapshot; } catch (Exception ex) { OnError(ex.ToString()); } return(snapshot); }
public async Task <WatchResponseResult> HandleResponseAsync(ListenResponse response, CancellationToken cancellationToken) { switch (response.ResponseTypeCase) { case ListenResponse.ResponseTypeOneofCase.TargetChange: TargetChange change = response.TargetChange; bool noTargetIds = change.TargetIds.Count == 0; switch (change.TargetChangeType) { case NoChange: if (noTargetIds && change.ReadTime != null && _current) { // This means everything is up-to-date, so emit the current set of docs as a snapshot, // if there were changes. await PushSnapshotAsync(Timestamp.FromProto(change.ReadTime), change.ResumeToken, cancellationToken).ConfigureAwait(false); } break; case Add: GaxPreconditions.CheckState(!noTargetIds && WatchStream.WatchTargetId == change.TargetIds[0], "Target ID must be 0x{0:x}", WatchStream.WatchTargetId); break; case Remove: GaxPreconditions.CheckState(!noTargetIds && WatchStream.WatchTargetId == change.TargetIds[0], "Target ID must be 0x{0:x}", WatchStream.WatchTargetId); // This may not be the right kind of exception to throw, but whatever we throw should be a permanent error. This is a reasonable starting point. throw new InvalidOperationException("Server removed watch target"); case Current: _current = true; break; case Reset: ResetDocs(); return(WatchResponseResult.Continue); default: throw new InvalidOperationException($"Encountered invalid target change type: {change.Cause.Message}"); } bool healthy = change.ResumeToken != null && (change.TargetIds.Count == 0 || change.TargetIds.Contains(WatchStream.WatchTargetId)); // Possibly tell the watch stream that it's now healthy (so reset backoff), or just continue. return(healthy ? WatchResponseResult.StreamHealthy : WatchResponseResult.Continue); case ListenResponse.ResponseTypeOneofCase.DocumentChange: // No other targetIds can show up here, but we still need to see if the targetId was in the // added list or removed list. var changed = response.DocumentChange.TargetIds.Contains(WatchStream.WatchTargetId); var removed = response.DocumentChange.RemovedTargetIds.Contains(WatchStream.WatchTargetId); Document document = response.DocumentChange.Document; DocumentReference docRef = CreateDocumentReference(document.Name); if (changed && removed) { throw new InvalidOperationException("Server error: document was both changed and removed"); } if (!changed && !removed) { // This is probably an error in the server, but we can follow protocol by just ignoring this response. return(WatchResponseResult.Continue); } _changeMap[docRef] = changed ? document : null; return(WatchResponseResult.Continue); case ListenResponse.ResponseTypeOneofCase.DocumentDelete: _changeMap[CreateDocumentReference(response.DocumentDelete.Document)] = null; return(WatchResponseResult.Continue); case ListenResponse.ResponseTypeOneofCase.DocumentRemove: _changeMap[CreateDocumentReference(response.DocumentRemove.Document)] = null; return(WatchResponseResult.Continue); case ListenResponse.ResponseTypeOneofCase.Filter: // TODO: Do we really want to create the change set itself, rather than just count? It seems a bit wasteful. ChangeSet changeSet = ExtractChanges(default); int currentSize = _documentSet.Count + changeSet.Adds.Count - changeSet.Deletes.Count; // Reset the stream if we don't have the right number of documents. if (response.Filter.Count != currentSize) { ResetDocs(); return(WatchResponseResult.ResetStream); } return(WatchResponseResult.Continue); default: throw new InvalidOperationException($"Encountered invalid listen response type: {response.ResponseTypeCase}"); } }
/// <summary> /// Creates a precondition that the document has the specified last update time. /// </summary> public static Precondition LastUpdated(Timestamp timestamp) => new Precondition(new V1Beta1.Precondition { UpdateTime = timestamp.ToProto() });
internal static WriteResult FromProto(V1Beta1.WriteResult result, wkt::Timestamp commitTime) { GaxPreconditions.CheckNotNull(result, nameof(result)); GaxPreconditions.CheckNotNull(commitTime, nameof(commitTime)); return(new WriteResult(Timestamp.FromProto(result.UpdateTime ?? commitTime))); }
private WriteResult(Timestamp updateTime) { UpdateTime = updateTime; }