private IEnumerator PerformTransaction()

in firestore/testapp/Assets/Firebase/Sample/Firestore/UIHandler.cs [399:506]


    private IEnumerator PerformTransaction() {
      DocumentReference doc1 = db.Collection("col3").Document("txn_doc1");
      DocumentReference doc2 = db.Collection("col3").Document("txn_doc2");
      DocumentReference doc3 = db.Collection("col3").Document("txn_doc3");

      // Initialize doc1 and doc2 with some data.
      var initialData = new Dictionary<string, object>{
        {"field", "value"},
      };
      yield return new WaitForTaskCompletion(this, doc1.SetAsync(initialData));
      yield return new WaitForTaskCompletion(this, doc2.SetAsync(initialData));

      // Perform transaction that reads doc1, deletes doc1, updates doc2, and overwrites doc3.
      DebugLog("INFO: Going to perform the following three operations in a transaction:");
      DebugLog("\tDelete col3/txn_doc1");
      DebugLog("\tUpdate col3/txn_doc2");
      DebugLog("\tOverwrite col3/txn_doc3");
      var txnTask = doc1.Firestore.RunTransactionAsync<string>((transaction) => {
        return transaction.GetSnapshotAsync(doc1).ContinueWith((getTask) => {
          transaction.Delete(doc1);
          transaction.Update(doc2, new Dictionary<string, object> { { "field2", "value2" } });
          transaction.Update(doc2, new Dictionary<FieldPath, object> { { new FieldPath("field3"), "value3" } });
          transaction.Update(doc2, "field4", "value4");
          transaction.Set(doc3, initialData);
          // Since RunTransactionAsync<string> is used, we can return a string here, which can be
          // accessed via Task.Result when the task is completed.
          return "SUCCESS";
        });
      });
      yield return new WaitForTaskCompletion(this, txnTask);
      if (txnTask.IsCanceled) {
        DebugLog("INFO: Transaction operation was cancelled.");
      } else if (txnTask.IsFaulted) {
        DebugLog("ERROR: An error occurred while performing the transaction.");
        DebugLog("ERROR: " + txnTask.Exception.ToString());
      } else {
        string result = txnTask.Result;
        DebugLog("INFO: Transaction completed with status: " + result);
      }

      if (!(txnTask.IsFaulted || txnTask.IsCanceled)) {
        DebugLog("INFO: Checking the resulting documents.");

        Task<DocumentSnapshot> get1 = doc1.GetSnapshotAsync();
        yield return new WaitForTaskCompletion(this, get1);
        if (get1.IsCanceled) {
          DebugLog("INFO: Read operation for txn_doc1 was cancelled.");
        } else if (get1.IsFaulted) {
          DebugLog("ERROR: An error occurred while retrieving col3/txn_doc1.");
          DebugLog("ERROR: " + get1.Exception.ToString());
        } else {
          DocumentSnapshot snap = get1.Result;
          if(snap.Exists) {
            DebugLog("ERROR: col3/txn_doc1 should have been deleted.");
          } else {
            DebugLog("Success: col3/txn_doc1 does not exist.");
          }
        }

        Task<DocumentSnapshot> get2 = doc2.GetSnapshotAsync();
        yield return new WaitForTaskCompletion(this, get2);
        if (get2.IsCanceled) {
          DebugLog("INFO: Read operation for txn_doc2 was cancelled.");
        } else if (get2.IsFaulted) {
          DebugLog("ERROR: An error occurred while retrieving col3/txn_doc2.");
          DebugLog("ERROR: " + get2.Exception.ToString());
        } else {
          DocumentSnapshot snap = get2.Result;
          if(snap.Exists) {
            bool deepEquals = ObjectDeepEquals(snap.ToDictionary(),
            new Dictionary<string, object> {
              { "field", "value" },
              { "field2", "value2" },
              { "field3", "value3" },
              { "field4", "value4" },
            });
            if(deepEquals) {
              DebugLog("Success: col3/txn_doc2 content is as expected.");
            } else {
              DebugLog("ERROR: col3/txn_doc2 has incorrect content.");
            }
          } else {
            DebugLog("ERROR: col3/txn_doc2 does not exist.");
          }
        }

        Task<DocumentSnapshot> get3 = doc3.GetSnapshotAsync();
        yield return new WaitForTaskCompletion(this, get3);
        if (get3.IsCanceled) {
          DebugLog("INFO: Read operation for txn_doc3 was cancelled.");
        } else if (get3.IsFaulted) {
          DebugLog("ERROR: An error occurred while retrieving col3/txn_doc3");
          DebugLog("ERROR: " + get3.Exception.ToString());
        } else {
          DocumentSnapshot snap = get3.Result;
          if(snap.Exists) {
            bool deepEquals = ObjectDeepEquals(snap.ToDictionary(), initialData);
            if(deepEquals) {
              DebugLog("Success: col3/txn_doc3 content is as expected.");
            } else {
              DebugLog("ERROR: col3/txn_doc3 has incorrect content.");
            }
          } else {
            DebugLog("ERROR: col3/txn_doc3 does not exist.");
          }
        }
      }
    }