From 0011ff6aaaa2c84b896f4263e7fa07914ddc1362 Mon Sep 17 00:00:00 2001 From: Georgy Moiseev Date: Tue, 11 Oct 2022 11:36:36 +0300 Subject: [PATCH] api: any msgpack supported type as a request key Inserting a tuple with connector does not have any type restrictions on its contents: any MessagePack supported type is allowed. If there are any type violations on the Tarantool side, server would return the corresponding error. There is no reason to do any explicit type checks for request keys. This patch fixed using extended types as keys. Tarantool 2.10 does not support indexing intervals, so there are no tests for INTERVAL extension type. Closes #240 --- CHANGELOG.md | 1 + tarantool/connection.py | 8 ++++---- tarantool/utils.py | 29 ++++++++++++----------------- test/suites/test_datetime.py | 15 +++++++++++++++ test/suites/test_decimal.py | 16 ++++++++++++++++ test/suites/test_uuid.py | 16 ++++++++++++++++ 6 files changed, 64 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eb9a1ee9..3e655e59 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -146,6 +146,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Package build (#238). +- Allow any MessagePack supported type as a request key (#240). ## 0.9.0 - 2022-06-20 diff --git a/tarantool/connection.py b/tarantool/connection.py index c86a89db..3fd1ed05 100644 --- a/tarantool/connection.py +++ b/tarantool/connection.py @@ -86,9 +86,9 @@ ) from tarantool.schema import Schema from tarantool.utils import ( - check_key, greeting_decode, version_id, + wrap_key, ENCODING_DEFAULT, ) @@ -1220,7 +1220,7 @@ def delete(self, space_name, key, *, index=0): .. _delete: https://www.tarantool.io/en/doc/latest/reference/reference_lua/box_space/delete/ """ - key = check_key(key) + key = wrap_key(key) if isinstance(space_name, str): space_name = self.schema.get_space(space_name).sid if isinstance(index, str): @@ -1349,7 +1349,7 @@ def update(self, space_name, key, op_list, *, index=0): .. _update: https://www.tarantool.io/en/doc/latest/reference/reference_lua/box_space/update/ """ - key = check_key(key) + key = wrap_key(key) if isinstance(space_name, str): space_name = self.schema.get_space(space_name).sid if isinstance(index, str): @@ -1534,7 +1534,7 @@ def select(self, space_name, key=None, *, offset=0, limit=0xffffffff, index=0, i # Perform smart type checking (scalar / list of scalars / list of # tuples) - key = check_key(key, select=True) + key = wrap_key(key, select=True) if isinstance(space_name, str): space_name = self.schema.get_space(space_name).sid diff --git a/tarantool/utils.py b/tarantool/utils.py index 3f8275ba..e5238707 100644 --- a/tarantool/utils.py +++ b/tarantool/utils.py @@ -1,8 +1,6 @@ import sys import uuid -supported_types = (int, str, bytes, float,) - ENCODING_DEFAULT = "utf-8" from base64 import decodebytes as base64_decode @@ -22,33 +20,30 @@ def strxor(rhs, lhs): return bytes([x ^ y for x, y in zip(rhs, lhs)]) -def check_key(*args, **kwargs): +def wrap_key(*args, first=True, select=False): """ - Validate request key types and map. + Wrap request key in list, if needed. :param args: Method args. :type args: :obj:`tuple` - :param kwargs: Method kwargs. - :type kwargs: :obj:`dict` + :param first: ``True`` if this is the first recursion iteration. + :type first: :obj:`bool` + + :param select: ``True`` if wrapping SELECT request key. + :type select: :obj:`bool` :rtype: :obj:`list` """ - if 'first' not in kwargs: - kwargs['first'] = True - if 'select' not in kwargs: - kwargs['select'] = False - if len(args) == 0 and kwargs['select']: + if len(args) == 0 and select: return [] if len(args) == 1: - if isinstance(args[0], (list, tuple)) and kwargs['first']: - kwargs['first'] = False - return check_key(*args[0], **kwargs) - elif args[0] is None and kwargs['select']: + if isinstance(args[0], (list, tuple)) and first: + return wrap_key(*args[0], first=False, select=select) + elif args[0] is None and select: return [] - for key in args: - assert isinstance(key, supported_types) + return list(args) diff --git a/test/suites/test_datetime.py b/test/suites/test_datetime.py index a6ce0341..3e4ee763 100644 --- a/test/suites/test_datetime.py +++ b/test/suites/test_datetime.py @@ -32,6 +32,14 @@ def setUpClass(self): parts = {1, 'string'}, unique = true}) + pcall(function() + box.schema.space.create('test_pk') + box.space['test_pk']:create_index('primary', { + type = 'tree', + parts = {1, 'datetime'}, + unique = true}) + end) + box.schema.user.create('test', {password = 'test', if_not_exists = true}) box.schema.user.grant('test', 'read,write,execute', 'universe') @@ -528,6 +536,13 @@ def test_tarantool_datetime_addition_winter_time_switch(self): [case['res']]) + @skip_or_run_datetime_test + def test_primary_key(self): + data = [tarantool.Datetime(year=1970, month=1, day=1), 'content'] + + self.assertSequenceEqual(self.con.insert('test_pk', data), [data]) + self.assertSequenceEqual(self.con.select('test_pk', data[0]), [data]) + @classmethod def tearDownClass(self): self.con.close() diff --git a/test/suites/test_decimal.py b/test/suites/test_decimal.py index 4745669f..8029d7b9 100644 --- a/test/suites/test_decimal.py +++ b/test/suites/test_decimal.py @@ -31,6 +31,14 @@ def setUpClass(self): parts = {1, 'string'}, unique = true}) + pcall(function() + box.schema.space.create('test_pk') + box.space['test_pk']:create_index('primary', { + type = 'tree', + parts = {1, 'decimal'}, + unique = true}) + end) + box.schema.user.create('test', {password = 'test', if_not_exists = true}) box.schema.user.grant('test', 'read,write,execute', 'universe') """) @@ -421,6 +429,14 @@ def test_tarantool_encode_with_precision_loss(self): self.assertSequenceEqual(self.con.eval(lua_eval), [True]) + @skip_or_run_decimal_test + def test_primary_key(self): + data = [decimal.Decimal('0'), 'content'] + + self.assertSequenceEqual(self.con.insert('test_pk', data), [data]) + self.assertSequenceEqual(self.con.select('test_pk', data[0]), [data]) + + @classmethod def tearDownClass(self): self.con.close() diff --git a/test/suites/test_uuid.py b/test/suites/test_uuid.py index a0203538..f81f1117 100644 --- a/test/suites/test_uuid.py +++ b/test/suites/test_uuid.py @@ -31,6 +31,14 @@ def setUpClass(self): parts = {1, 'string'}, unique = true}) + pcall(function() + box.schema.space.create('test_pk') + box.space['test_pk']:create_index('primary', { + type = 'tree', + parts = {1, 'uuid'}, + unique = true}) + end) + box.schema.user.create('test', {password = 'test', if_not_exists = true}) box.schema.user.grant('test', 'read,write,execute', 'universe') """) @@ -125,6 +133,14 @@ def test_tarantool_encode(self): self.assertSequenceEqual(self.con.eval(lua_eval), [True]) + @skip_or_run_UUID_test + def test_primary_key(self): + data = [uuid.UUID('ae28d4f6-076c-49dd-8227-7f9fae9592d0'), 'content'] + + self.assertSequenceEqual(self.con.insert('test_pk', data), [data]) + self.assertSequenceEqual(self.con.select('test_pk', data[0]), [data]) + + @classmethod def tearDownClass(self): self.con.close()