mirror of
https://github.com/Infinidat/infi.clickhouse_orm.git
synced 2025-07-17 19:42:25 +03:00
Finished Release v1.0.1
This commit is contained in:
commit
238fd11d6b
|
@ -1,6 +1,12 @@
|
||||||
Change Log
|
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
|
v1.0.0
|
||||||
------
|
------
|
||||||
- Add support for compound filters with Q objects (desile)
|
- Add support for compound filters with Q objects (desile)
|
||||||
|
|
|
@ -5,7 +5,6 @@ download-cache = .cache
|
||||||
develop = .
|
develop = .
|
||||||
parts =
|
parts =
|
||||||
relative-paths = true
|
relative-paths = true
|
||||||
extensions = buildout.wheel
|
|
||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = infi.clickhouse_orm
|
name = infi.clickhouse_orm
|
||||||
|
|
|
@ -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])
|
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
|
Working with materialized and alias fields
|
||||||
------------------------------------------
|
------------------------------------------
|
||||||
|
|
||||||
|
|
|
@ -79,6 +79,22 @@ class Field(object):
|
||||||
else:
|
else:
|
||||||
return self.db_type
|
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):
|
class StringField(Field):
|
||||||
|
|
||||||
|
@ -347,6 +363,8 @@ class ArrayField(Field):
|
||||||
class_default = []
|
class_default = []
|
||||||
|
|
||||||
def __init__(self, inner_field, default=None, alias=None, materialized=None, readonly=None):
|
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
|
self.inner_field = inner_field
|
||||||
super(ArrayField, self).__init__(default, alias, materialized, readonly)
|
super(ArrayField, self).__init__(default, alias, materialized, readonly)
|
||||||
|
|
||||||
|
@ -385,12 +403,12 @@ class NullableField(Field):
|
||||||
super(NullableField, self).__init__(default, alias, materialized, readonly=None)
|
super(NullableField, self).__init__(default, alias, materialized, readonly=None)
|
||||||
|
|
||||||
def to_python(self, value, timezone_in_use):
|
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 None
|
||||||
return self.inner_field.to_python(value, timezone_in_use)
|
return self.inner_field.to_python(value, timezone_in_use)
|
||||||
|
|
||||||
def validate(self, value):
|
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):
|
def to_db_string(self, value, quote=True):
|
||||||
if value in self._null_values:
|
if value in self._null_values:
|
||||||
|
@ -398,5 +416,4 @@ class NullableField(Field):
|
||||||
return self.inner_field.to_db_string(value, quote=quote)
|
return self.inner_field.to_db_string(value, quote=quote)
|
||||||
|
|
||||||
def get_sql(self, with_default_expression=True):
|
def get_sql(self, with_default_expression=True):
|
||||||
from .utils import escape
|
|
||||||
return 'Nullable(%s)' % self.inner_field.get_sql(with_default_expression=False)
|
return 'Nullable(%s)' % self.inner_field.get_sql(with_default_expression=False)
|
||||||
|
|
|
@ -21,7 +21,7 @@ class ArrayFieldsTest(unittest.TestCase):
|
||||||
instance = ModelWithArrays(
|
instance = ModelWithArrays(
|
||||||
date_field='2016-08-30',
|
date_field='2016-08-30',
|
||||||
arr_str=['goodbye,', 'cruel', 'world', 'special chars: ,"\\\'` \n\t\\[]'],
|
arr_str=['goodbye,', 'cruel', 'world', 'special chars: ,"\\\'` \n\t\\[]'],
|
||||||
arr_date=['2010-01-01']
|
arr_date=['2010-01-01'],
|
||||||
)
|
)
|
||||||
self.database.insert([instance])
|
self.database.insert([instance])
|
||||||
query = 'SELECT * from $db.modelwitharrays ORDER BY date_field'
|
query = 'SELECT * from $db.modelwitharrays ORDER BY date_field'
|
||||||
|
@ -62,6 +62,11 @@ class ArrayFieldsTest(unittest.TestCase):
|
||||||
with self.assertRaises(ValueError):
|
with self.assertRaises(ValueError):
|
||||||
parse_array(s)
|
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):
|
class ModelWithArrays(Model):
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ class MigrationsTestCase(unittest.TestCase):
|
||||||
# Adding, removing and altering simple fields
|
# Adding, removing and altering simple fields
|
||||||
self.assertEquals(self.getTableFields(Model1), [('date', 'Date'), ('f1', 'Int32'), ('f2', 'String')])
|
self.assertEquals(self.getTableFields(Model1), [('date', 'Date'), ('f1', 'Int32'), ('f2', 'String')])
|
||||||
self.database.migrate('tests.sample_migrations', 4)
|
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.database.migrate('tests.sample_migrations', 5)
|
||||||
self.assertEquals(self.getTableFields(Model3), [('date', 'Date'), ('f1', 'Int64'), ('f3', 'Float64'), ('f4', 'String')])
|
self.assertEquals(self.getTableFields(Model3), [('date', 'Date'), ('f1', 'Int64'), ('f3', 'Float64'), ('f4', 'String')])
|
||||||
# Altering enum fields
|
# Altering enum fields
|
||||||
|
@ -121,6 +121,7 @@ class Model2(Model):
|
||||||
f3 = Float32Field()
|
f3 = Float32Field()
|
||||||
f2 = StringField()
|
f2 = StringField()
|
||||||
f4 = StringField()
|
f4 = StringField()
|
||||||
|
f5 = ArrayField(UInt64Field()) # addition of an array field
|
||||||
|
|
||||||
engine = MergeTree('date', ('date',))
|
engine = MergeTree('date', ('date',))
|
||||||
|
|
||||||
|
|
|
@ -73,6 +73,22 @@ class NullableFieldsTest(unittest.TestCase):
|
||||||
else:
|
else:
|
||||||
self.assertEquals(python_value, value)
|
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):
|
def _insert_sample_data(self):
|
||||||
dt = date(1970, 1, 1)
|
dt = date(1970, 1, 1)
|
||||||
self.database.insert([
|
self.database.insert([
|
||||||
|
|
Loading…
Reference in New Issue
Block a user