Skip to content

Commit

Permalink
api: any msgpack supported type as a request key
Browse files Browse the repository at this point in the history
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
  • Loading branch information
DifferentialOrange committed Oct 13, 2022
1 parent fc81b36 commit c3faa88
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 23 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Update documentation index, quick start and guide pages (#67).

### Fixed
- Allow any MessagePack supported type as a request key (#240).

## 0.9.0 - 2022-06-20

Expand Down
8 changes: 4 additions & 4 deletions tarantool/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,9 @@
)
from tarantool.schema import Schema
from tarantool.utils import (
check_key,
greeting_decode,
version_id,
wrap_key,
ENCODING_DEFAULT,
)

Expand Down Expand Up @@ -1202,7 +1202,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):
Expand Down Expand Up @@ -1331,7 +1331,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):
Expand Down Expand Up @@ -1516,7 +1516,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
Expand Down
29 changes: 12 additions & 17 deletions tarantool/utils.py
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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)


Expand Down
17 changes: 16 additions & 1 deletion test/suites/test_datetime.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,22 @@ def setUpClass(self):

self.adm = self.srv.admin
self.adm(r"""
_, datetime = pcall(require, 'datetime')
is_supported, datetime = pcall(require, 'datetime')
box.schema.space.create('test')
box.space['test']:create_index('primary', {
type = 'tree',
parts = {1, 'string'},
unique = true})
if is_supported then
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')
Expand Down Expand Up @@ -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()
Expand Down
14 changes: 14 additions & 0 deletions test/suites/test_decimal.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ def setUpClass(self):
parts = {1, 'string'},
unique = true})
box.schema.space.create('test_pk')
box.space['test_pk']:create_index('primary', {
type = 'tree',
parts = {1, 'decimal'},
unique = true})
box.schema.user.create('test', {password = 'test', if_not_exists = true})
box.schema.user.grant('test', 'read,write,execute', 'universe')
""")
Expand Down Expand Up @@ -421,6 +427,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()
Expand Down
18 changes: 17 additions & 1 deletion test/suites/test_uuid.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,22 @@ def setUpClass(self):

self.adm = self.srv.admin
self.adm(r"""
_, uuid = pcall(require, 'uuid')
is_supported, uuid = pcall(require, 'uuid')
box.schema.space.create('test')
box.space['test']:create_index('primary', {
type = 'tree',
parts = {1, 'string'},
unique = true})
if is_supported then
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')
""")
Expand Down Expand Up @@ -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()
Expand Down

0 comments on commit c3faa88

Please sign in to comment.