diff --git a/happybase/table.py b/happybase/table.py index 3cb26b7..9534217 100644 --- a/happybase/table.py +++ b/happybase/table.py @@ -7,7 +7,7 @@ from operator import attrgetter from struct import Struct -from .hbase.ttypes import TScan +from .hbase.ttypes import TScan, TIncrement from .util import thrift_type_to_dict, str_increment, OrderedDict from .batch import Batch @@ -568,3 +568,24 @@ def counter_dec(self, row, column, value=1): :rtype: int """ return self.counter_inc(row, column, -value) + + def counters_inc(self, row, data): + """ + + This method increments (or decrements) the counter columns in the row + specified by `row`. The `data` argument is a dictionary that + maps columns and its counter values, e.g. + {"cf:col": 1, "cf:col2": 2}. + + Note that unlike `counter_inc`, does not return value after + incrementing. + + :param str row: the row key + :param dict data: the dictionary that maps columns to numeric counter values + """ + if not isinstance(data, dict): + raise TypeError("'data' must be a dictionary") + + self.connection.client.incrementRows( + [TIncrement(table=self.name, row=row, column=column, ammount=value) + for column, value in data.iteritems()]) diff --git a/tests/test_api.py b/tests/test_api.py index 292ee3f..79ea2c0 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -183,6 +183,34 @@ def test_atomic_counters(): assert_equal(10, table.counter_dec(row, column, -7)) +def test_multiple_counters(): + row = 'row-with-counters' + columns = ['cf1:counter1', 'cf1:counter2', 'cf1:counter3'] + + table.counters_inc(row, dict(zip(columns, [0, 0, 0]))) + assert_equal([0, 0, 0], [table.counter_get(row, c) for c in columns]) + + table.counters_inc(row, dict(zip(columns, [1, 3, 5]))) + assert_equal([1, 3, 5], [table.counter_get(row, c) for c in columns]) + + table.counters_inc(row, dict(zip(columns, [-1, -3, -5]))) + assert_equal([0, 0, 0], [table.counter_get(row, c) for c in columns]) + + for col, delta in dict(zip(columns, [1, 3, 5])): + table.counters_inc(row, [(col, delta)]) + assert_equal(delta, table.counter_get(row, col)) + table.counter_dec(row, [(col, -delta)]) + assert_equal(0, table.counter_get(row, col)) + + table.counters_inc(row, dict(zip(columns, [1, 3, 5]))) + table.counters_inc(row, dict(zip(columns, [1, 3, 5]))) + assert_equal([2, 6, 10], [table.counter_get(row, c) for c in columns]) + + table.counters_inc(row, dict(zip(columns, [-1, -3, -5]))) + table.counters_inc(row, dict(zip(columns, [-1, -3, -5]))) + assert_equal([0, 0, 0], [table.counter_get(row, c) for c in columns]) + + def test_batch(): with assert_raises(TypeError): table.batch(timestamp='invalid')