diff --git a/README.rst b/README.rst index ce8c2b8..5627ab1 100644 --- a/README.rst +++ b/README.rst @@ -193,8 +193,14 @@ and for providing access to information about how the system is working. Usage example:: - >>>> from infi.clickhouse_orm import system_models - >>>> print(system_models.SystemPart.get(Database())) + from infi.clickhouse_orm.database import Database + from infi.clickhouse_orm.system_models import SystemPart + db = Database('my_test_db', db_url='http://192.168.1.1:8050', username='scott', password='tiger') + partitions = SystemPart.get_active(db, conditions='') # Getting all active partitions of the database + if len(partitions) > 0: + partitions = sorted(partitions, key=lambda obj: obj.name) # Partition name is YYYYMM, so we can sort so + partitions[0].freeze(db) # Make a backup in /opt/clickhouse/shadow directory + partitions[0].drop() # Dropped partition Currently the following system models are supported: diff --git a/src/infi/clickhouse_orm/database.py b/src/infi/clickhouse_orm/database.py index 48a7c91..6ef5d97 100644 --- a/src/infi/clickhouse_orm/database.py +++ b/src/infi/clickhouse_orm/database.py @@ -62,11 +62,11 @@ class Database(object): def gen(): yield self._substitute('INSERT INTO $table FORMAT TabSeparated\n', model_class).encode('utf-8') - yield (first_instance.to_tsv(insertable_only=True) + '\n').encode('utf-8') + yield (first_instance.to_tsv(include_readonly=False) + '\n').encode('utf-8') # Collect lines in batches of batch_size batch = [] for instance in i: - batch.append(instance.to_tsv(insertable_only=True)) + batch.append(instance.to_tsv(include_readonly=False)) if len(batch) >= batch_size: # Return the current batch of lines yield ('\n'.join(batch) + '\n').encode('utf-8') diff --git a/src/infi/clickhouse_orm/fields.py b/src/infi/clickhouse_orm/fields.py index 0d5b50d..1113dd6 100644 --- a/src/infi/clickhouse_orm/fields.py +++ b/src/infi/clickhouse_orm/fields.py @@ -16,8 +16,10 @@ class Field(object): def __init__(self, default=None, alias=None, materialized=None): assert (None, None) in {(default, alias), (alias, materialized), (default, materialized)}, \ "Only one of default, alias and materialized parameters can be given" - assert alias is None or isinstance(alias, str), "Alias field must be string field name, if given" - assert materialized is None or isinstance(materialized, str), "Materialized field must be string, if given" + assert alias is None or isinstance(alias, str) and alias != "",\ + "Alias field must be string field name, if given" + assert materialized is None or isinstance(materialized, str) and alias != "",\ + "Materialized field must be string, if given" self.creation_counter = Field.creation_counter Field.creation_counter += 1 @@ -72,7 +74,7 @@ class Field(object): @property def readonly(self): - return self.alias is not None or self.materialized is not None + return bool(self.alias or self.materialized) class StringField(Field): diff --git a/src/infi/clickhouse_orm/models.py b/src/infi/clickhouse_orm/models.py index 4248f89..80cafb9 100644 --- a/src/infi/clickhouse_orm/models.py +++ b/src/infi/clickhouse_orm/models.py @@ -153,27 +153,25 @@ class Model(with_metaclass(ModelBase)): kwargs[name] = field.to_python(next(values), timezone_in_use) return cls(**kwargs) - def to_tsv(self, insertable_only=False): + def to_tsv(self, include_readonly=True): ''' Returns the instance's column values as a tab-separated line. A newline is not included. - :param bool insertable_only: If True, returns only fields, that can be inserted into database + :param bool include_readonly: If False, returns only fields, that can be inserted into database ''' data = self.__dict__ - fields = self._fields - if insertable_only: - fields = [f for f in fields if not f[1].readonly] + fields = self._fields if include_readonly else [f for f in self._fields if not f[1].readonly] return '\t'.join(field.to_db_string(data[name], quote=False) for name, field in fields) - def to_dict(self, insertable_only=False, field_names=None, timezone_in_use=pytz.utc): + def to_dict(self, include_readonly=True, field_names=None): ''' Returns the instance's column values as a dict. - :param bool insertable_only: If True, returns only fields, that can be inserted into database + :param bool include_readonly: If False, returns only fields, that can be inserted into database :param field_names: An iterable of field names to return - :param timezone_in_use: timezone to convert DateField and DateTimeField. ''' - fields = [f for f in self._fields if not f[1].readonly] if insertable_only else self._fields + fields = self._fields if include_readonly else [f for f in self._fields if not f[1].readonly] + if field_names is not None: fields = [f for f in fields if f[0] in field_names] data = self.__dict__ - return {name: field.to_python(data[name], timezone_in_use) for name, field in fields} + return {name: data[name] for name, field in fields} diff --git a/tests/test_models.py b/tests/test_models.py index 239f0c8..b52a2c6 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -65,7 +65,7 @@ class ModelTestCase(unittest.TestCase): "alias_field": 0.0, 'str_field': 'dozo' }) - self.assertDictEqual(instance.to_dict(insertable_only=True), { + self.assertDictEqual(instance.to_dict(include_readonly=False), { "date_field": datetime.date(1973, 12, 6), "int_field": 100, "float_field": 7.0, @@ -73,7 +73,7 @@ class ModelTestCase(unittest.TestCase): 'str_field': 'dozo' }) self.assertDictEqual( - instance.to_dict(insertable_only=True, field_names=('int_field', 'alias_field', 'datetime_field')), { + instance.to_dict(include_readonly=False, field_names=('int_field', 'alias_field', 'datetime_field')), { "int_field": 100, "datetime_field": datetime.datetime(1970, 1, 1, 0, 0, 0, tzinfo=pytz.utc) })