Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add transactions #1

Draft
wants to merge 11 commits into
base: master
Choose a base branch
from
Draft

feat: add transactions #1

wants to merge 11 commits into from

Conversation

jsgalarraga
Copy link
Owner

@jsgalarraga jsgalarraga commented Jul 5, 2024

Dummy PR to make easier to see changes


This PR introduces Firestore transactions to the package.

Why

Transactions are a powerful feature to have in the backend. This is an effort to have a more complete feature set for a dart backend.

It has been requested by users in cachapa#63 and cachapa#126.

Inspiration

The work here has been inspired by:

Implementation notes

  • The new Transaction class, does not extend the existing Reference even though it needs some of its methods because a Transaction does not have a predefined path. The _fullPath and _encodeMap methods have been adapted.
  • The mutations in a Transaction have to be exposed for the FirestoreGateway to have access to them and run the transaction commit. To safely do this, it is kept as an UnmodifiableListView to prevent the end user from modifying it.
  • When multiple transaction operations are run in parallel, some of them fail to keep the database consistent. When this happens, a GrpcError with StatusCode.aborted is thrown. In this PR, the error handling is implemented to retry the transaction up to 5 times by default (as the other firestore SDKs do).

Examples

To ensure transactions are working and keeping the database consistent with all the write operations performed in parallel, the following test has been run: Increase a value multiple times both with and without transactions. As we can see, when running with transactions, the numbers are increased correctly 3 times, but the number is only increased by 1 when ran without transactions.

transactions-example.mov

With transactions

void main(List<String> args) async {
  Firestore.initialize('project-id');

  await Future.wait([
    increaseValueWithTransaction(Firestore.instance),
    increaseValueWithTransaction(Firestore.instance),
    increaseValueWithTransaction(Firestore.instance),
  ]);

  firestore.close();
}

Future<void> increaseValueWithTransaction(Firestore firestore) async {
  await firestore.runTransaction(
    (transaction) async {
      final doc = await transaction.get('testing/test');
      final value = doc.map['key'];
      transaction.update('testing/test', {'key': value + 1});
    },
  );
}

Without transactions

void main(List<String> args) async {
  Firestore.initialize('project-id');

  await Future.wait([
    increaseValue(Firestore.instance),
    increaseValue(Firestore.instance),
    increaseValue(Firestore.instance),
  ]);

  firestore.close();
}

Future<void> increaseValue(Firestore firestore) async {
  final doc = await firestore.document('testing/test').get();
  final value = doc.map['key'];
  await firestore.document('testing/test').set({'key': value + 1});
}

@jsgalarraga jsgalarraga self-assigned this Jul 5, 2024
@evandrobubiak
Copy link

When will this feature be merged?

@jsgalarraga
Copy link
Owner Author

@evandrobubiak
This repository is just a fork of the original one in which I developed the feature to create the PR.

You can see the progress (or I should say lack of progress 🥲) on the PR opened in the official repo.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants