from __future__ import unicode_literals import unittest from datetime import date from infi.clickhouse_orm.database import Database from infi.clickhouse_orm.models import Model from infi.clickhouse_orm.fields import * from infi.clickhouse_orm.engines import * class MaterializedFieldsTest(unittest.TestCase): def setUp(self): self.database = Database('test-db', log_statements=True) self.database.create_table(ModelWithMaterializedFields) def tearDown(self): self.database.drop_database() def test_insert_and_select(self): instance = ModelWithMaterializedFields( date_time_field='2016-08-30 11:00:00', int_field=-10, str_field='TEST' ) self.database.insert([instance]) # We can't select * from table, as it doesn't select materialized and alias fields query = 'SELECT date_time_field, int_field, str_field, mat_int, mat_date, mat_str' \ ' FROM $db.%s ORDER BY mat_date' % ModelWithMaterializedFields.table_name() for model_cls in (ModelWithMaterializedFields, None): results = list(self.database.select(query, model_cls)) self.assertEqual(len(results), 1) self.assertEqual(results[0].date_time_field, instance.date_time_field) self.assertEqual(results[0].int_field, instance.int_field) self.assertEqual(results[0].str_field, instance.str_field) self.assertEqual(results[0].mat_int, abs(instance.int_field)) self.assertEqual(results[0].mat_str, instance.str_field.lower()) self.assertEqual(results[0].mat_date, instance.date_time_field.date()) def test_assignment_error(self): # I can't prevent assigning at all, in case db.select statements with model provided sets model fields. instance = ModelWithMaterializedFields() for value in ('x', [date.today()], ['aaa'], [None]): with self.assertRaises(ValueError): instance.mat_date = value def test_wrong_field(self): with self.assertRaises(AssertionError): StringField(materialized=123) def test_duplicate_default(self): with self.assertRaises(AssertionError): StringField(materialized='str_field', default='with default') with self.assertRaises(AssertionError): StringField(materialized='str_field', alias='str_field') class ModelWithMaterializedFields(Model): int_field = Int32Field() date_time_field = DateTimeField() str_field = StringField() mat_str = StringField(materialized='lower(str_field)') mat_int = Int32Field(materialized='abs(int_field)') mat_date = DateField(materialized=u'toDate(date_time_field)') engine = MergeTree('mat_date', ('mat_date',))