def validate_commit_req(self, req):
        """Validates a normalized CommitRequest.

    Args:
      req: a googledatastore.CommitRequest

    Raises:
      ValidationError: if the request is invalid
    """
        _assert_initialized(req)
        if (req.mode == googledatastore.CommitRequest.MODE_UNSPECIFIED
                or req.mode == googledatastore.CommitRequest.TRANSACTIONAL):
            _assert_condition(req.WhichOneof('transaction_selector'),
                              'Transactional commit requires a transaction.')
            if req.WhichOneof('transaction_selector') == 'transaction':
                _assert_condition(
                    req.transaction, 'a transaction cannot be the empty '
                    'string.')

            seen_base_versions = {}
            for mutation in req.mutations:
                v1_key, _ = datastore_pbs.get_v1_mutation_key_and_entity(
                    mutation)
                if datastore_pbs.is_complete_v1_key(v1_key):
                    mutation_base_version = None
                    if mutation.HasField('base_version'):
                        mutation_base_version = mutation.base_version

                    key = datastore_types.ReferenceToKeyValue(
                        v1_key, self.__id_resolver)
                    if key in seen_base_versions:
                        _assert_condition(
                            seen_base_versions[key] == mutation_base_version,
                            'Mutations for the same entity must have the '
                            'same base version.')
                    seen_base_versions[key] = mutation_base_version

        elif req.mode == googledatastore.CommitRequest.NON_TRANSACTIONAL:
            _assert_condition(
                not req.WhichOneof('transaction_selector'),
                'Non-transactional commit cannot specify a '
                'transaction.')

            seen_complete_keys = set()
            for mutation in req.mutations:
                v1_key, _ = datastore_pbs.get_v1_mutation_key_and_entity(
                    mutation)
                if datastore_pbs.is_complete_v1_key(v1_key):
                    key = datastore_types.ReferenceToKeyValue(
                        v1_key, self.__id_resolver)
                    _assert_condition(
                        key not in seen_complete_keys,
                        'A non-transactional commit may not contain '
                        'multiple mutations affecting the same entity.')
                    seen_complete_keys.add(key)

        for mutation in req.mutations:
            self.__validate_mutation(mutation)
  def validate_commit_req(self, req):
    """Validates a normalized CommitRequest.

    Args:
      req: a googledatastore.CommitRequest

    Raises:
      ValidationError: if the request is invalid
    """
    _assert_initialized(req)
    if (req.mode == googledatastore.CommitRequest.MODE_UNSPECIFIED or
        req.mode == googledatastore.CommitRequest.TRANSACTIONAL):
      _assert_condition(req.WhichOneof('transaction_selector'),
                        'Transactional commit requires a transaction.')
      if req.WhichOneof('transaction_selector') == 'transaction':
        _assert_condition(req.transaction, 'a transaction cannot be the empty '
                                           'string.')


      seen_base_versions = {}
      for mutation in req.mutations:
        v1_key, _ = datastore_pbs.get_v1_mutation_key_and_entity(mutation)
        if datastore_pbs.is_complete_v1_key(v1_key):
          mutation_base_version = None
          if mutation.HasField('base_version'):
            mutation_base_version = mutation.base_version

          key = datastore_types.ReferenceToKeyValue(v1_key, self.__id_resolver)
          if key in seen_base_versions:
            _assert_condition(seen_base_versions[key] == mutation_base_version,
                              'Mutations for the same entity must have the '
                              'same base version.')
          seen_base_versions[key] = mutation_base_version

    elif req.mode == googledatastore.CommitRequest.NON_TRANSACTIONAL:
      _assert_condition(not req.WhichOneof('transaction_selector'),
                        'Non-transactional commit cannot specify a '
                        'transaction.')

      seen_complete_keys = set()
      for mutation in req.mutations:
        v1_key, _ = datastore_pbs.get_v1_mutation_key_and_entity(mutation)
        if datastore_pbs.is_complete_v1_key(v1_key):
          key = datastore_types.ReferenceToKeyValue(v1_key, self.__id_resolver)
          _assert_condition(key not in seen_complete_keys,
                            'A non-transactional commit may not contain '
                            'multiple mutations affecting the same entity.')
          seen_complete_keys.add(key)

    for mutation in req.mutations:
      self.__validate_mutation(mutation)
    def __commit(self, v1_mutations, v1_txn, resp):
        """Commits a list of v1 mutations.

    Args:
      v1_mutations: the list of mutations to apply and commit
      v1_txn: required v1 transaction handle in which to apply the mutations
      resp: a v1 CommitResponse to update with the result of this commit
    """

        mutation_keys = []

        seen_keys = set()

        allocated_keys = {}

        conflict_cache = {}

        version_cache = {}

        for i, mutation in enumerate(v1_mutations):
            v1_key, v1_entity = datastore_pbs.get_v1_mutation_key_and_entity(mutation)
            key = datastore_types.ReferenceToKeyValue(v1_key, self._id_resolver)
            if not datastore_pbs.is_complete_v1_key(v1_key):

                v1_key = self.__put_v1_entity(v1_entity, v1_txn)
                key = datastore_types.ReferenceToKeyValue(v1_key, self._id_resolver)
                allocated_keys[key] = v1_key
            elif key not in conflict_cache:

                base_version = None
                if mutation.HasField("base_version") and key not in seen_keys:
                    base_version = mutation.base_version

                conflict_version = self.__apply_v1_mutation(mutation, base_version, v1_txn, version_cache)
                if conflict_version is not None:
                    conflict_cache[key] = conflict_version

            mutation_keys.append(key)
            seen_keys.add(key)

        v3_txn = datastore_pb.Transaction()
        self.__service_converter.v1_to_v3_txn(v1_txn, v3_txn)
        v3_resp = datastore_pb.CommitResponse()
        self.__make_v3_call("Commit", v3_txn, v3_resp)
        resp.index_updates = v3_resp.cost().index_writes()

        mutation_versions = {}
        for version in v3_resp.version_list():
            key = datastore_types.ReferenceToKeyValue(version.root_entity_key())
            mutation_versions[key] = version.version()

        for key in mutation_keys:
            mutation_result = resp.mutation_results.add()
            if key in allocated_keys:
                mutation_result.key.CopyFrom(allocated_keys[key])
            if key in conflict_cache:
                mutation_result.conflict_detected = True
                mutation_result.version = conflict_cache[key]
            else:
                mutation_result.version = mutation_versions[key]
  def __apply_v1_mutation(self, v1_mutation, base_version, v1_txn,
                          version_cache):
    """Applies a v1 Mutation in a transaction.

    Args:
      v1_mutation: a googledatastore.Mutation, must be for a complete key.
      base_version: optional, the version the entity is expected to be at. If
          the entity has a different version number, the mutation does not
          apply. If None, then this check is skipped.
      v1_txn: a v1 transaction handle
      version_cache: a cache of entity keys to version, for entities that have
          been mutated previously in this transaction.
    """
    v1_key, v1_entity = datastore_pbs.get_v1_mutation_key_and_entity(
        v1_mutation)
    key = datastore_types.ReferenceToKeyValue(v1_key, self._id_resolver)



    if (v1_mutation.HasField('insert') or v1_mutation.HasField('update') or
        base_version is not None) and key not in version_cache:
      version_cache[key] = self.__get_v1_entity_version(v1_key, v1_txn)

    if v1_mutation.HasField('insert'):
      if base_version is not None and base_version != _NO_VERSION:
        raise apiproxy_errors.ApplicationError(datastore_pb.Error.BAD_REQUEST,
                                               'Cannot insert an entity with a '
                                               'base version greater than zero')
      elif version_cache[key] != _NO_VERSION:
        raise apiproxy_errors.ApplicationError(datastore_pb.Error.BAD_REQUEST,
                                               'Entity already exists.')
    elif v1_mutation.HasField('update'):
      if base_version is not None and base_version == _NO_VERSION:
        raise apiproxy_errors.ApplicationError(datastore_pb.Error.BAD_REQUEST,
                                               'Cannot update an entity with a '
                                               'base version set to zero')
      elif version_cache[key] == _NO_VERSION:
        raise apiproxy_errors.ApplicationError(datastore_pb.Error.BAD_REQUEST,
                                               'Entity does not exist.')


    if base_version is not None:
      persisted_version = version_cache[key]
      if persisted_version != _NO_VERSION and persisted_version < base_version:
        raise apiproxy_errors.ApplicationError(datastore_pb.Error.BAD_REQUEST,
                                               'Invalid base version, it is '
                                               'greater than the stored '
                                               'version')
      if persisted_version != base_version:
        return persisted_version


    if v1_mutation.HasField('delete'):
      self.__delete_v1_key(v1_key, v1_txn)
      version_cache[key] = _NO_VERSION
    else:
      self.__put_v1_entity(v1_entity, v1_txn)
      version_cache[key] = _MINIMUM_VERSION
  def __commit(self, v1_mutations, v1_txn, resp):
    """Commits a list of v1 mutations.

    Args:
      v1_mutations: the list of mutations to apply and commit
      v1_txn: required v1 transaction handle in which to apply the mutations
      resp: a v1 CommitResponse to update with the result of this commit
    """


    mutation_keys = []


    seen_keys = set()


    allocated_keys = {}


    conflict_cache = {}


    version_cache = {}

    for i, mutation in enumerate(v1_mutations):
      v1_key, v1_entity = datastore_pbs.get_v1_mutation_key_and_entity(mutation)
      key = datastore_types.ReferenceToKeyValue(v1_key, self._id_resolver)
      if not datastore_pbs.is_complete_v1_key(v1_key):

        v1_key = self.__put_v1_entity(v1_entity, v1_txn)
        key = datastore_types.ReferenceToKeyValue(v1_key, self._id_resolver)
        allocated_keys[key] = v1_key
      elif key not in conflict_cache:


        base_version = None
        if mutation.HasField('base_version') and key not in seen_keys:
          base_version = mutation.base_version

        conflict_version = self.__apply_v1_mutation(mutation, base_version,
                                                    v1_txn, version_cache)
        if conflict_version is not None:
          conflict_cache[key] = conflict_version

      mutation_keys.append(key)
      seen_keys.add(key)

    v3_txn = datastore_pb.Transaction()
    self.__service_converter.v1_to_v3_txn(v1_txn, v3_txn)
    v3_resp = datastore_pb.CommitResponse()
    self.__make_v3_call('Commit', v3_txn, v3_resp)
    resp.index_updates = v3_resp.cost().index_writes()



    mutation_versions = {}
    for version in v3_resp.version_list():
      key = datastore_types.ReferenceToKeyValue(version.root_entity_key())
      mutation_versions[key] = version.version()

    for key in mutation_keys:
      mutation_result = resp.mutation_results.add()
      if key in allocated_keys:
        mutation_result.key.CopyFrom(allocated_keys[key])
      if key in conflict_cache:
        mutation_result.conflict_detected = True
        mutation_result.version = conflict_cache[key]
      else:
        mutation_result.version = mutation_versions[key]