def test_delete_entities_txn(self):
    app = 'guestbook'
    txn_hash = {'root_key': 1}
    txn_str = '1'.zfill(ID_KEY_LENGTH)
    entity = self.get_new_entity_proto(app, *self.BASIC_ENTITY[1:])

    db_batch = flexmock()
    db_batch.should_receive('valid_data_version').and_return(True)
    dd = DatastoreDistributed(db_batch, None)

    keys = [entity.key()]
    prefix = dd.get_table_prefix(entity.key())
    entity_key = get_entity_key(prefix, entity.key().path())
    encoded_path = str(encode_index_pb(entity.key().path()))
    txn_keys = [dd._SEPARATOR.join([app, txn_str, '', encoded_path])]
    txn_values = {
      txn_keys[0]: {
        dbconstants.TRANSACTIONS_SCHEMA[0]: dbconstants.TxnActions.DELETE,
        dbconstants.TRANSACTIONS_SCHEMA[1]: entity_key,
        dbconstants.TRANSACTIONS_SCHEMA[2]: ''
      }
    }

    flexmock(dd).should_receive('get_root_key').and_return('root_key')

    db_batch.should_receive('batch_put_entity').with_args(
      dbconstants.TRANSACTIONS_TABLE,
      txn_keys,
      dbconstants.TRANSACTIONS_SCHEMA,
      txn_values,
      ttl=TX_TIMEOUT * 2
    )
    dd.delete_entities_txn(app, keys, txn_hash)
  def test_extract_entities_from_composite_indexes(self):
    project_id = 'guestbook'
    props = ['prop1', 'prop2']
    db_batch = flexmock()
    db_batch.should_receive('valid_data_version_sync').and_return(True)
    transaction_manager = flexmock()
    dd = DatastoreDistributed(db_batch, transaction_manager,
                              self.get_zookeeper())
    query = datastore_pb.Query()
    for prop_name in props:
      query.add_property_name(prop_name)

    index = query.add_composite_index()
    definition = index.mutable_definition()
    for prop_name in props:
      prop = definition.add_property()
      prop.set_name(prop_name)

    entity_id = 1524699263329044
    val1 = entity_pb.PropertyValue()
    val1.set_int64value(5)
    val2 = entity_pb.PropertyValue()
    val2.set_stringvalue('test')
    index_key = '\x00'.join(
      [project_id, 'namespace', 'index1', str(encode_index_pb(val1)),
       str(encode_index_pb(val2)), 'Greeting:{}\x01'.format(entity_id)])

    index_results = [{index_key: {'reference': 'ignored-ref'}}]
    entities = dd._extract_entities_from_composite_indexes(
      query, index_results, index)
    self.assertEqual(len(entities), 1)
    returned_entity = entity_pb.EntityProto(entities[0])
    self.assertEqual(returned_entity.property_size(), 2)
    self.assertEqual(returned_entity.key().path().element(0).type(), 'Greeting')
    self.assertEqual(returned_entity.key().path().element(0).id(), entity_id)
    self.assertEqual(returned_entity.property(0).name(), 'prop1')
    self.assertEqual(returned_entity.property(0).value().int64value(), 5)
    self.assertEqual(returned_entity.property(1).name(), 'prop2')
    self.assertEqual(returned_entity.property(1).value().stringvalue(), 'test')
Beispiel #3
0
    def restrict_to_path(self, path):
        """ Narrows the range to a specific entity path.

    Args:
      path: An entity_pb.Path object.
    """
        start_key = self.prefix + str(encode_index_pb(path))
        end_key = ''.join([start_key, TERMINATING_STRING])
        if start_key < self._range[0] or end_key > self._range[-1]:
            raise BadRequest('Restriction must be within range')

        if self._cursor.key > end_key:
            raise BadRequest('Cursor already exceeds new range')

        self._range = (start_key, end_key)
        self._cursor.key = max(start_key, self._cursor.key)
Beispiel #4
0
    def set_cursor(self, path, inclusive):
        """ Changes the range's cursor position.

    Args:
      path: An entity_pb.Path object.
      inclusive: A boolean specifying that the next result can include the
        given path.
    Raises:
      BadRequest if unable to set the cursor to the given path.
    """
        range_start, range_end = self._range
        cursor = Cursor(self.prefix + str(encode_index_pb(path)), inclusive)

        if cursor.key < self._cursor.key:
            raise BadRequest('Cursor cannot be moved backwards '
                             '({} < {})'.format(repr(cursor.key),
                                                repr(self._cursor.key)))

        if cursor.key < range_start or cursor.key > range_end:
            raise BadRequest('Cursor outside range: {}'.format(self._range))

        self._cursor = cursor
Beispiel #5
0
 def prefix(self):
     """ The encoded reference without the path element. """
     return KEY_DELIMITER.join([
         self.project_id, self.namespace, self.kind, self.prop_name,
         str(encode_index_pb(self._value))
     ])