Finished Release v1.0.1

This commit is contained in:
Itai Shirav 2018-08-13 08:46:10 +03:00
commit 238fd11d6b
7 changed files with 52 additions and 6 deletions

View File

@ -1,6 +1,12 @@
Change Log
==========
v1.0.1
------
- NullableField: take extra_null_values into account in `validate` and `to_python`
- Added `Field.isinstance` method
- Validate the inner field passed to `ArrayField`
v1.0.0
------
- Add support for compound filters with Q objects (desile)

View File

@ -5,7 +5,6 @@ download-cache = .cache
develop = .
parts =
relative-paths = true
extensions = buildout.wheel
[project]
name = infi.clickhouse_orm

View File

@ -82,6 +82,8 @@ class SensorData(models.Model):
data = SensorData(date=date.today(), temperatures=[25.5, 31.2, 28.7], humidity_levels=[41, 39, 66])
```
Note that multidimensional arrays are not supported yet by the ORM.
Working with materialized and alias fields
------------------------------------------

View File

@ -79,6 +79,22 @@ class Field(object):
else:
return self.db_type
def isinstance(self, types):
"""
Checks if the instance if one of the types provided or if any of the inner_field child is one of the types
provided, returns True if field or any inner_field is one of ths provided, False otherwise
:param types: Iterable of types to check inclusion of instance
:return: Boolean
"""
if isinstance(self, types):
return True
inner_field = getattr(self, 'inner_field', None)
while inner_field:
if isinstance(inner_field, types):
return True
inner_field = getattr(inner_field, 'inner_field', None)
return False
class StringField(Field):
@ -347,6 +363,8 @@ class ArrayField(Field):
class_default = []
def __init__(self, inner_field, default=None, alias=None, materialized=None, readonly=None):
assert isinstance(inner_field, Field), "The first argument of ArrayField must be a Field instance"
assert not isinstance(inner_field, ArrayField), "Multidimensional array fields are not supported by the ORM"
self.inner_field = inner_field
super(ArrayField, self).__init__(default, alias, materialized, readonly)
@ -385,12 +403,12 @@ class NullableField(Field):
super(NullableField, self).__init__(default, alias, materialized, readonly=None)
def to_python(self, value, timezone_in_use):
if value == '\\N' or value is None:
if value == '\\N' or value in self._null_values:
return None
return self.inner_field.to_python(value, timezone_in_use)
def validate(self, value):
value is None or self.inner_field.validate(value)
value in self._null_values or self.inner_field.validate(value)
def to_db_string(self, value, quote=True):
if value in self._null_values:
@ -398,5 +416,4 @@ class NullableField(Field):
return self.inner_field.to_db_string(value, quote=quote)
def get_sql(self, with_default_expression=True):
from .utils import escape
return 'Nullable(%s)' % self.inner_field.get_sql(with_default_expression=False)

View File

@ -21,7 +21,7 @@ class ArrayFieldsTest(unittest.TestCase):
instance = ModelWithArrays(
date_field='2016-08-30',
arr_str=['goodbye,', 'cruel', 'world', 'special chars: ,"\\\'` \n\t\\[]'],
arr_date=['2010-01-01']
arr_date=['2010-01-01'],
)
self.database.insert([instance])
query = 'SELECT * from $db.modelwitharrays ORDER BY date_field'
@ -62,6 +62,11 @@ class ArrayFieldsTest(unittest.TestCase):
with self.assertRaises(ValueError):
parse_array(s)
def test_invalid_inner_field(self):
for x in (DateField, None, "", ArrayField(Int32Field())):
with self.assertRaises(AssertionError):
ArrayField(x)
class ModelWithArrays(Model):

View File

@ -49,7 +49,7 @@ class MigrationsTestCase(unittest.TestCase):
# Adding, removing and altering simple fields
self.assertEquals(self.getTableFields(Model1), [('date', 'Date'), ('f1', 'Int32'), ('f2', 'String')])
self.database.migrate('tests.sample_migrations', 4)
self.assertEquals(self.getTableFields(Model2), [('date', 'Date'), ('f1', 'Int32'), ('f3', 'Float32'), ('f2', 'String'), ('f4', 'String')])
self.assertEquals(self.getTableFields(Model2), [('date', 'Date'), ('f1', 'Int32'), ('f3', 'Float32'), ('f2', 'String'), ('f4', 'String'), ('f5', 'Array(UInt64)')])
self.database.migrate('tests.sample_migrations', 5)
self.assertEquals(self.getTableFields(Model3), [('date', 'Date'), ('f1', 'Int64'), ('f3', 'Float64'), ('f4', 'String')])
# Altering enum fields
@ -121,6 +121,7 @@ class Model2(Model):
f3 = Float32Field()
f2 = StringField()
f4 = StringField()
f5 = ArrayField(UInt64Field()) # addition of an array field
engine = MergeTree('date', ('date',))

View File

@ -73,6 +73,22 @@ class NullableFieldsTest(unittest.TestCase):
else:
self.assertEquals(python_value, value)
def test_isinstance(self):
for field in (StringField, UInt8Field, Float32Field, DateTimeField):
f = NullableField(field())
self.assertTrue(f.isinstance(field))
self.assertTrue(f.isinstance(NullableField))
for field in (Int8Field, Int16Field, Int32Field, Int64Field, UInt8Field, UInt16Field, UInt32Field, UInt64Field):
f = NullableField(field())
self.assertTrue(f.isinstance(BaseIntField))
for field in (Float32Field, Float64Field):
f = NullableField(field())
self.assertTrue(f.isinstance(BaseFloatField))
f = NullableField(NullableField(UInt32Field()))
self.assertTrue(f.isinstance(BaseIntField))
self.assertTrue(f.isinstance(NullableField))
self.assertFalse(f.isinstance(BaseFloatField))
def _insert_sample_data(self):
dt = date(1970, 1, 1)
self.database.insert([