Skip to content

Commit 3d5972d

Browse files
committed
Merge pull request #1276 from dhermes/bigtable-table-create
Implementing Bigtable Table.create().
2 parents f0e4858 + 6ecb9e1 commit 3d5972d

File tree

2 files changed

+125
-0
lines changed

2 files changed

+125
-0
lines changed

gcloud/bigtable/table.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,31 @@
1515
"""User friendly container for Google Cloud Bigtable Table."""
1616

1717

18+
from gcloud.bigtable._generated import (
19+
bigtable_table_service_messages_pb2 as messages_pb2)
1820
from gcloud.bigtable.column_family import ColumnFamily
1921
from gcloud.bigtable.row import Row
2022

2123

2224
class Table(object):
2325
"""Representation of a Google Cloud Bigtable Table.
2426
27+
.. note::
28+
29+
We don't define any properties on a table other than the name. As
30+
the proto says, in a request:
31+
32+
The ``name`` field of the Table and all of its ColumnFamilies must
33+
be left blank, and will be populated in the response.
34+
35+
This leaves only the ``current_operation`` and ``granularity``
36+
fields. The ``current_operation`` is only used for responses while
37+
``granularity`` is an enum with only one value.
38+
39+
We can use a :class:`Table` to:
40+
41+
* :meth:`create` the table
42+
2543
:type table_id: str
2644
:param table_id: The ID of the table.
2745
@@ -64,3 +82,40 @@ def __eq__(self, other):
6482

6583
def __ne__(self, other):
6684
return not self.__eq__(other)
85+
86+
def create(self, initial_split_keys=None):
87+
"""Creates this table.
88+
89+
.. note::
90+
91+
Though a :class:`._generated.bigtable_table_data_pb2.Table` is also
92+
allowed (as the ``table`` property) in a create table request, we
93+
do not support it in this method. As mentioned in the
94+
:class:`Table` docstring, the name is the only useful property in
95+
the table proto.
96+
97+
.. note::
98+
99+
A create request returns a
100+
:class:`._generated.bigtable_table_data_pb2.Table` but we don't use
101+
this response. The proto definition allows for the inclusion of a
102+
``current_operation`` in the response, but it does not appear that
103+
the Cloud Bigtable API returns any operation.
104+
105+
:type initial_split_keys: list
106+
:param initial_split_keys: (Optional) List of row keys that will be
107+
used to initially split the table into
108+
several tablets (Tablets are similar to
109+
HBase regions). Given two split keys,
110+
``"s1"`` and ``"s2"``, three tablets will be
111+
created, spanning the key ranges:
112+
``[, s1)``, ``[s1, s2)``, ``[s2, )``.
113+
"""
114+
request_pb = messages_pb2.CreateTableRequest(
115+
initial_split_keys=initial_split_keys or [],
116+
name=self._cluster.name,
117+
table_id=self.table_id,
118+
)
119+
client = self._cluster._client
120+
# We expect a `._generated.bigtable_table_data_pb2.Table`
121+
client._table_stub.CreateTable(request_pb, client.timeout_seconds)

gcloud/bigtable/test_table.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,73 @@ def test___ne__(self):
8181
table1 = self._makeOne('table_id1', 'cluster1')
8282
table2 = self._makeOne('table_id2', 'cluster2')
8383
self.assertNotEqual(table1, table2)
84+
85+
def _create_test_helper(self, initial_split_keys):
86+
from gcloud.bigtable._generated import (
87+
bigtable_table_data_pb2 as data_pb2)
88+
from gcloud.bigtable._generated import (
89+
bigtable_table_service_messages_pb2 as messages_pb2)
90+
from gcloud.bigtable._testing import _FakeStub
91+
92+
project_id = 'project-id'
93+
zone = 'zone'
94+
cluster_id = 'cluster-id'
95+
table_id = 'table-id'
96+
timeout_seconds = 150
97+
cluster_name = ('projects/' + project_id + '/zones/' + zone +
98+
'/clusters/' + cluster_id)
99+
100+
client = _Client(timeout_seconds=timeout_seconds)
101+
cluster = _Cluster(cluster_name, client=client)
102+
table = self._makeOne(table_id, cluster)
103+
104+
# Create request_pb
105+
request_pb = messages_pb2.CreateTableRequest(
106+
initial_split_keys=initial_split_keys,
107+
name=cluster_name,
108+
table_id=table_id,
109+
)
110+
111+
# Create response_pb
112+
response_pb = data_pb2.Table()
113+
114+
# Patch the stub used by the API method.
115+
client._table_stub = stub = _FakeStub(response_pb)
116+
117+
# Create expected_result.
118+
expected_result = None # create() has no return value.
119+
120+
# Perform the method and check the result.
121+
result = table.create(initial_split_keys=initial_split_keys)
122+
self.assertEqual(result, expected_result)
123+
self.assertEqual(stub.method_calls, [(
124+
'CreateTable',
125+
(request_pb, timeout_seconds),
126+
{},
127+
)])
128+
129+
def test_create(self):
130+
initial_split_keys = None
131+
self._create_test_helper(initial_split_keys)
132+
133+
def test_create_with_split_keys(self):
134+
initial_split_keys = ['s1', 's2']
135+
self._create_test_helper(initial_split_keys)
136+
137+
138+
class _Client(object):
139+
140+
data_stub = None
141+
cluster_stub = None
142+
operations_stub = None
143+
table_stub = None
144+
145+
def __init__(self, timeout_seconds=None):
146+
self.timeout_seconds = timeout_seconds
147+
148+
149+
class _Cluster(object):
150+
151+
def __init__(self, name, client=None):
152+
self.name = name
153+
self._client = client

0 commit comments

Comments
 (0)