Addad ScalarList type, fixed NumberRangeType
This commit is contained in:
@@ -4,6 +4,13 @@ Changelog
|
|||||||
Here you can see the full list of changes between each SQLAlchemy-Utils release.
|
Here you can see the full list of changes between each SQLAlchemy-Utils release.
|
||||||
|
|
||||||
|
|
||||||
|
0.8.0 (2013-03-27)
|
||||||
|
^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
- Added ScalarList type
|
||||||
|
- Fixed NumberRange bind param and result value processing
|
||||||
|
|
||||||
|
|
||||||
0.7.7 (2013-03-27)
|
0.7.7 (2013-03-27)
|
||||||
^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
2
setup.py
2
setup.py
@@ -24,7 +24,7 @@ class PyTest(Command):
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='SQLAlchemy-Utils',
|
name='SQLAlchemy-Utils',
|
||||||
version='0.7.7',
|
version='0.8.0',
|
||||||
url='https://github.com/kvesteri/sqlalchemy-utils',
|
url='https://github.com/kvesteri/sqlalchemy-utils',
|
||||||
license='BSD',
|
license='BSD',
|
||||||
author='Konsta Vesterinen',
|
author='Konsta Vesterinen',
|
||||||
|
@@ -8,7 +8,9 @@ from .types import (
|
|||||||
NumberRange,
|
NumberRange,
|
||||||
NumberRangeException,
|
NumberRangeException,
|
||||||
NumberRangeRawType,
|
NumberRangeRawType,
|
||||||
NumberRangeType
|
NumberRangeType,
|
||||||
|
ScalarList,
|
||||||
|
ScalarListException,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -26,4 +28,6 @@ __all__ = (
|
|||||||
NumberRangeType,
|
NumberRangeType,
|
||||||
PhoneNumber,
|
PhoneNumber,
|
||||||
PhoneNumberType,
|
PhoneNumberType,
|
||||||
|
ScalarList,
|
||||||
|
ScalarListException,
|
||||||
)
|
)
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
import phonenumbers
|
import phonenumbers
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
|
import sqlalchemy as sa
|
||||||
from sqlalchemy.orm.collections import InstrumentedList as _InstrumentedList
|
from sqlalchemy.orm.collections import InstrumentedList as _InstrumentedList
|
||||||
from sqlalchemy import types
|
from sqlalchemy import types
|
||||||
|
|
||||||
@@ -82,6 +83,42 @@ class PhoneNumberType(types.TypeDecorator):
|
|||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
class ScalarListException(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ScalarList(types.TypeDecorator):
|
||||||
|
impl = sa.UnicodeText()
|
||||||
|
|
||||||
|
def __init__(self, coerce_func=unicode, separator=u','):
|
||||||
|
self.separator = unicode(separator)
|
||||||
|
self.coerce_func = coerce_func
|
||||||
|
|
||||||
|
def process_bind_param(self, value, dialect):
|
||||||
|
# Convert list of values to unicode separator-separated list
|
||||||
|
# Example: [1, 2, 3, 4] -> u'1, 2, 3, 4'
|
||||||
|
if value:
|
||||||
|
print value
|
||||||
|
if any(self.separator in unicode(item) for item in value):
|
||||||
|
raise ScalarListException(
|
||||||
|
"List values can't contain string '%s' (its being used as "
|
||||||
|
"separator. If you wish for scalar list values to contain "
|
||||||
|
"these strings, use a different separator string."
|
||||||
|
)
|
||||||
|
return self.separator.join(
|
||||||
|
map(unicode, value)
|
||||||
|
)
|
||||||
|
return value
|
||||||
|
|
||||||
|
def process_result_value(self, value, dialect):
|
||||||
|
if value:
|
||||||
|
# coerce each value
|
||||||
|
return map(
|
||||||
|
self.coerce_func, value.split(self.separator)
|
||||||
|
)
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
class NumberRangeRawType(types.UserDefinedType):
|
class NumberRangeRawType(types.UserDefinedType):
|
||||||
"""
|
"""
|
||||||
Raw number range type, only supports PostgreSQL for now.
|
Raw number range type, only supports PostgreSQL for now.
|
||||||
@@ -96,9 +133,12 @@ class NumberRangeType(types.TypeDecorator):
|
|||||||
def process_bind_param(self, value, dialect):
|
def process_bind_param(self, value, dialect):
|
||||||
if value:
|
if value:
|
||||||
return value.normalized
|
return value.normalized
|
||||||
|
return value
|
||||||
|
|
||||||
def process_result_value(self, value, dialect):
|
def process_result_value(self, value, dialect):
|
||||||
return NumberRange.from_normalized_str(value)
|
if value:
|
||||||
|
return NumberRange.from_normalized_str(value)
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
class NumberRangeException(Exception):
|
class NumberRangeException(Exception):
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
from pytest import raises, mark
|
from pytest import raises
|
||||||
from sqlalchemy_utils import NumberRangeType, NumberRange, NumberRangeException
|
from sqlalchemy_utils import NumberRangeType, NumberRange, NumberRangeException
|
||||||
from tests import DatabaseTestCase
|
from tests import DatabaseTestCase
|
||||||
|
|
||||||
|
61
tests/test_scalar_list.py
Normal file
61
tests/test_scalar_list.py
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
import sqlalchemy as sa
|
||||||
|
from sqlalchemy_utils import ScalarList
|
||||||
|
from pytest import raises
|
||||||
|
from tests import DatabaseTestCase
|
||||||
|
|
||||||
|
|
||||||
|
class TestScalarIntegerList(DatabaseTestCase):
|
||||||
|
def create_models(self):
|
||||||
|
class User(self.Base):
|
||||||
|
__tablename__ = 'user'
|
||||||
|
id = sa.Column(sa.Integer, primary_key=True)
|
||||||
|
some_list = sa.Column(ScalarList(int))
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return 'User(%r)' % self.id
|
||||||
|
|
||||||
|
self.User = User
|
||||||
|
|
||||||
|
def test_save_integer_list(self):
|
||||||
|
user = self.User(
|
||||||
|
some_list=[1, 2, 3, 4]
|
||||||
|
)
|
||||||
|
|
||||||
|
self.session.add(user)
|
||||||
|
self.session.commit()
|
||||||
|
|
||||||
|
user = self.session.query(self.User).first()
|
||||||
|
assert user.some_list == [1, 2, 3, 4]
|
||||||
|
|
||||||
|
|
||||||
|
class TestScalarUnicodeList(DatabaseTestCase):
|
||||||
|
def create_models(self):
|
||||||
|
class User(self.Base):
|
||||||
|
__tablename__ = 'user'
|
||||||
|
id = sa.Column(sa.Integer, primary_key=True)
|
||||||
|
some_list = sa.Column(ScalarList(unicode))
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return 'User(%r)' % self.id
|
||||||
|
|
||||||
|
self.User = User
|
||||||
|
|
||||||
|
def test_throws_exception_if_using_separator_in_list_values(self):
|
||||||
|
user = self.User(
|
||||||
|
some_list=[u',']
|
||||||
|
)
|
||||||
|
|
||||||
|
self.session.add(user)
|
||||||
|
with raises(sa.exc.StatementError):
|
||||||
|
self.session.commit()
|
||||||
|
|
||||||
|
def test_save_unicode_list(self):
|
||||||
|
user = self.User(
|
||||||
|
some_list=[u'1', u'2', u'3', u'4']
|
||||||
|
)
|
||||||
|
|
||||||
|
self.session.add(user)
|
||||||
|
self.session.commit()
|
||||||
|
|
||||||
|
user = self.session.query(self.User).first()
|
||||||
|
assert user.some_list == [u'1', u'2', u'3', u'4']
|
Reference in New Issue
Block a user