Uh oh!
There was an error while loading. Please reload this page.
This repository was archived by the owner on May 7, 2026. It is now read-only.
- Notifications
You must be signed in to change notification settings - Fork 45
feat: add new_transaction support#499
Merged
Uh oh!
There was an error while loading. Please reload this page.
Merged
Changes from all commits
Commits
Show all changes
47 commits
Select commit
Hold shift + click to select a range
d7fe72d
added begin_later flag
daniel-sanche 14942e0
refactoring
daniel-sanche 8ce4654
got tests passing
daniel-sanche 18d6a34
improved docstring
daniel-sanche af92f68
added helper tests
daniel-sanche 11cedac
fixed type in docstring
daniel-sanche 27454d5
added client test
daniel-sanche b952b8d
handle context manager close
daniel-sanche 81108df
removed extra indents
daniel-sanche defd080
added transaction tests
daniel-sanche 2063f71
added system tests
daniel-sanche 648204d
fixed lint
daniel-sanche 087eaaf
refactor using wrappers
daniel-sanche cbb2c0a
added functools.wraps
daniel-sanche 471ead2
fixed mypy
daniel-sanche 439604c
Merge branch 'main' into new_transaction
daniel-sanche 8da9e00
fixed mypy
daniel-sanche 95797e9
added test
daniel-sanche 09d945f
default begin_later to False
daniel-sanche 3409196
Merge branch 'main' into new_transaction
daniel-sanche 210c5d8
Merge branch 'main' into new_transaction
daniel-sanche d63cb90
Merge branch 'main' into new_transaction
daniel-sanche 982b998
added new_transaction to query and aggregation classes
daniel-sanche e7b8b9a
chore(deps): update all dependencies (#505)
renovate-bot 026c934
build: update actions/checkout and actions/setup-python (#507)
gcf-owl-bot[bot] a001d5f
chore(main): release 2.19.0 (#481)
release-please[bot] aef3bef
chore(deps): update dependency google-cloud-datastore to v2.19.0 (#508)
renovate-bot 3c2e4a7
build: update actions/upload-artifact and actions/download-artifact (…
gcf-owl-bot[bot] 3ac41ea
got tests passing
daniel-sanche 7e8bb6e
🦉 Updates from OwlBot post-processor
gcf-owl-bot[bot] 78bdba6
Merge branch 'main' into new_transaction
daniel-sanche 4ad1071
🦉 Updates from OwlBot post-processor
gcf-owl-bot[bot] ce9e335
remove begin from put and delete
daniel-sanche 28f6d10
fixed jinja version
daniel-sanche 61237b3
fixed tests
daniel-sanche 77e410a
🦉 Updates from OwlBot post-processor
gcf-owl-bot[bot] f4512ba
remove unused decorator
daniel-sanche b2012a8
removed unneeded delete override
daniel-sanche cfa11db
fixed commit without begin call
daniel-sanche efc8e8d
improved tests
daniel-sanche 6872fcf
refactored out helper function
daniel-sanche 19ed6e9
fixed lint
daniel-sanche 4682186
added comment
daniel-sanche abf29e3
added tests for helper
daniel-sanche 8061202
Merge branch 'main' into new_transaction
daniel-sanche c90da29
Merge branch 'main' into new_transaction
daniel-sanche 4b40a87
Merge branch 'main' into new_transaction
daniel-sanche File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Jump to file
Failed to load files.
Loading
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -192,6 +192,19 @@ def mutations(self): | ||
| """ | ||
| return self._mutations | ||
| def _allow_mutations(self) -> bool: | ||
| """ | ||
| This method is called to see if the batch is in a proper state to allow | ||
| `put` and `delete` operations. | ||
| the Transaction subclass overrides this method to support | ||
| the `begin_later` flag. | ||
| :rtype: bool | ||
| :returns: True if the batch is in a state to allow mutations. | ||
| """ | ||
| return self._status == self._IN_PROGRESS | ||
| def put(self, entity): | ||
| """Remember an entity's state to be saved during :meth:`commit`. | ||
| @@ -218,7 +231,7 @@ def put(self, entity): | ||
| progress, if entity has no key assigned, or if the key's | ||
| ``project`` does not match ours. | ||
| """ | ||
| if self._status != self._IN_PROGRESS: | ||
| if not self._allow_mutations(): | ||
| raise ValueError("Batch must be in progress to put()") | ||
| if entity.key is None: | ||
| @@ -248,7 +261,7 @@ def delete(self, key): | ||
| progress, if key is not complete, or if the key's | ||
| ``project`` does not match ours. | ||
| """ | ||
| if self._status != self._IN_PROGRESS: | ||
| if not self._allow_mutations(): | ||
bhshkh marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| raise ValueError("Batch must be in progress to delete()") | ||
| if key.is_partial: | ||
| @@ -370,10 +383,12 @@ def __enter__(self): | ||
| def __exit__(self, exc_type, exc_val, exc_tb): | ||
| try: | ||
| if exc_type is None: | ||
| self.commit() | ||
| else: | ||
| self.rollback() | ||
| # commit or rollback if not in terminal state | ||
| if self._status not in (self._ABORTED, self._FINISHED): | ||
| if exc_type is None: | ||
| self.commit() | ||
| else: | ||
| self.rollback() | ||
| finally: | ||
| self._client._pop_batch() | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -122,7 +122,7 @@ def _extended_lookup( | ||
| missing=None, | ||
danieljbruce marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| deferred=None, | ||
| eventual=False, | ||
| transaction_id=None, | ||
| transaction=None, | ||
| retry=None, | ||
| timeout=None, | ||
| read_time=None, | ||
| @@ -158,10 +158,10 @@ def _extended_lookup( | ||
| consistency. If True, request ``EVENTUAL`` read | ||
| consistency. | ||
| :type transaction_id: str | ||
| :param transaction_id: If passed, make the request in the scope of | ||
| the given transaction. Incompatible with | ||
| ``eventual==True`` or ``read_time``. | ||
| :type transaction: Transaction | ||
| :param transaction: If passed, make the request in the scope of | ||
| the given transaction. Incompatible with | ||
| ``eventual==True`` or ``read_time``. | ||
| :type retry: :class:`google.api_core.retry.Retry` | ||
| :param retry: | ||
| @@ -177,7 +177,7 @@ def _extended_lookup( | ||
| :type read_time: datetime | ||
| :param read_time: | ||
| (Optional) Read time to use for read consistency. Incompatible with | ||
| ``eventual==True`` or ``transaction_id``. | ||
| ``eventual==True`` or ``transaction``. | ||
| This feature is in private preview. | ||
| :type database: str | ||
| @@ -199,8 +199,14 @@ def _extended_lookup( | ||
| results = [] | ||
| transaction_id = None | ||
| transaction_id, new_transaction_options = helpers.get_transaction_options( | ||
| transaction | ||
| ) | ||
| read_options = helpers.get_read_options( | ||
| eventual, transaction_id, read_time, new_transaction_options | ||
| ) | ||
| loop_num = 0 | ||
| read_options = helpers.get_read_options(eventual, transaction_id, read_time) | ||
| while loop_num < _MAX_LOOPS: # loop against possible deferred. | ||
| loop_num += 1 | ||
| request = { | ||
danieljbruce marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| @@ -214,6 +220,10 @@ def _extended_lookup( | ||
| **kwargs, | ||
| ) | ||
| # set new transaction id if we just started a transaction | ||
| if transaction and lookup_response.transaction: | ||
danieljbruce marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| transaction._begin_with_id(lookup_response.transaction) | ||
| # Accumulate the new results. | ||
| results.extend(result.entity for result in lookup_response.found) | ||
| @@ -570,7 +580,7 @@ def get_multi( | ||
| eventual=eventual, | ||
| missing=missing, | ||
| deferred=deferred, | ||
| transaction_id=transaction and transaction.id, | ||
| transaction=transaction, | ||
| retry=retry, | ||
| timeout=timeout, | ||
| read_time=read_time, | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -230,7 +230,9 @@ def entity_to_protobuf(entity): | ||
| return entity_pb | ||
| def get_read_options(eventual, transaction_id, read_time=None): | ||
| def get_read_options( | ||
| eventual, transaction_id, read_time=None, new_transaction_options=None | ||
| ): | ||
| """Validate rules for read options, and assign to the request. | ||
| Helper method for ``lookup()`` and ``run_query``. | ||
| @@ -245,33 +247,55 @@ def get_read_options(eventual, transaction_id, read_time=None): | ||
| :type read_time: datetime | ||
| :param read_time: Read data from the specified time (may be null). This feature is in private preview. | ||
| :type new_transaction_options: :class:`google.cloud.datastore_v1.types.TransactionOptions` | ||
| :param new_transaction_options: Options for a new transaction. | ||
| :rtype: :class:`.datastore_pb2.ReadOptions` | ||
| :returns: The read options corresponding to the inputs. | ||
| :raises: :class:`ValueError` if more than one of ``eventual==True``, | ||
| ``transaction``, and ``read_time`` is specified. | ||
| ``transaction_id``, ``read_time``, and ``new_transaction_options`` is specified. | ||
| """ | ||
| if transaction_id is None: | ||
| if eventual: | ||
| if read_time is not None: | ||
| raise ValueError("eventual must be False when read_time is specified") | ||
| else: | ||
| return datastore_pb2.ReadOptions( | ||
| read_consistency=datastore_pb2.ReadOptions.ReadConsistency.EVENTUAL | ||
| ) | ||
| else: | ||
| if read_time is None: | ||
| return datastore_pb2.ReadOptions() | ||
| else: | ||
| read_time_pb = timestamp_pb2.Timestamp() | ||
| read_time_pb.FromDatetime(read_time) | ||
| return datastore_pb2.ReadOptions(read_time=read_time_pb) | ||
| else: | ||
| if eventual: | ||
| raise ValueError("eventual must be False when in a transaction") | ||
| elif read_time is not None: | ||
| raise ValueError("transaction and read_time are mutual exclusive") | ||
| else: | ||
| return datastore_pb2.ReadOptions(transaction=transaction_id) | ||
| is_set = [ | ||
| bool(x) for x in (eventual, transaction_id, read_time, new_transaction_options) | ||
| ] | ||
| if sum(is_set) > 1: | ||
| raise ValueError( | ||
| "At most one of eventual, transaction, or read_time is allowed." | ||
danieljbruce marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| ) | ||
| new_options = datastore_pb2.ReadOptions() | ||
| if transaction_id is not None: | ||
| new_options.transaction = transaction_id | ||
| if read_time is not None: | ||
| read_time_pb = timestamp_pb2.Timestamp() | ||
| read_time_pb.FromDatetime(read_time) | ||
| new_options.read_time = read_time_pb | ||
| if new_transaction_options is not None: | ||
| new_options.new_transaction = new_transaction_options | ||
| if eventual: | ||
| new_options.read_consistency = ( | ||
| datastore_pb2.ReadOptions.ReadConsistency.EVENTUAL | ||
| ) | ||
| return new_options | ||
| def get_transaction_options(transaction): | ||
| """ | ||
| Get the transaction_id or new_transaction_options field from an active transaction object, | ||
| for use in get_read_options | ||
| These are mutually-exclusive fields, so one or both will be None. | ||
| :rtype: Tuple[Optional[bytes], Optional[google.cloud.datastore_v1.types.TransactionOptions]] | ||
| :returns: The transaction_id and new_transaction_options fields from the transaction object. | ||
| """ | ||
| transaction_id, new_transaction_options = None, None | ||
| if transaction is not None: | ||
| if transaction.id is not None: | ||
| transaction_id = transaction.id | ||
| elif transaction._begin_later and transaction._status == transaction._INITIAL: | ||
| # If the transaction has not yet been begun, we can use the new_transaction_options field. | ||
| new_transaction_options = transaction._options | ||
| return transaction_id, new_transaction_options | ||
| def key_from_protobuf(pb): | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.