mirror of
https://github.com/Infinidat/infi.clickhouse_orm.git
synced 2024-11-25 18:23:44 +03:00
1) Removed database params for working with SystemPart operations
2) Added _database attribute to each model, got through select
This commit is contained in:
parent
64f6288fdb
commit
f3e75cfae3
|
@ -94,7 +94,7 @@ class Database(object):
|
||||||
field_types = parse_tsv(next(lines))
|
field_types = parse_tsv(next(lines))
|
||||||
model_class = model_class or ModelBase.create_ad_hoc_model(zip(field_names, field_types))
|
model_class = model_class or ModelBase.create_ad_hoc_model(zip(field_names, field_types))
|
||||||
for line in lines:
|
for line in lines:
|
||||||
yield model_class.from_tsv(line, field_names, self.server_timezone)
|
yield model_class.from_tsv(line, field_names, self.server_timezone, self)
|
||||||
|
|
||||||
def raw(self, query, settings=None, stream=False):
|
def raw(self, query, settings=None, stream=False):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -79,6 +79,9 @@ class Model(with_metaclass(ModelBase)):
|
||||||
Unrecognized field names will cause an AttributeError.
|
Unrecognized field names will cause an AttributeError.
|
||||||
'''
|
'''
|
||||||
super(Model, self).__init__()
|
super(Model, self).__init__()
|
||||||
|
|
||||||
|
self._database = None
|
||||||
|
|
||||||
# Assign field values from keyword arguments
|
# Assign field values from keyword arguments
|
||||||
for name, value in kwargs.items():
|
for name, value in kwargs.items():
|
||||||
field = self.get_field(name)
|
field = self.get_field(name)
|
||||||
|
@ -102,6 +105,17 @@ class Model(with_metaclass(ModelBase)):
|
||||||
field.validate(value)
|
field.validate(value)
|
||||||
super(Model, self).__setattr__(name, value)
|
super(Model, self).__setattr__(name, value)
|
||||||
|
|
||||||
|
def set_database(self, db):
|
||||||
|
"""
|
||||||
|
Sets _database attribute for current model instance
|
||||||
|
:param db: Database instance
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
# This can not be imported globally due to circular import
|
||||||
|
from .database import Database
|
||||||
|
assert isinstance(db, Database), "database must be database.Database instance"
|
||||||
|
self._database = db
|
||||||
|
|
||||||
def get_field(self, name):
|
def get_field(self, name):
|
||||||
'''
|
'''
|
||||||
Get a Field instance given its name, or None if not found.
|
Get a Field instance given its name, or None if not found.
|
||||||
|
@ -138,11 +152,12 @@ class Model(with_metaclass(ModelBase)):
|
||||||
return 'DROP TABLE IF EXISTS `%s`.`%s`' % (db_name, cls.table_name())
|
return 'DROP TABLE IF EXISTS `%s`.`%s`' % (db_name, cls.table_name())
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_tsv(cls, line, field_names=None, timezone_in_use=pytz.utc):
|
def from_tsv(cls, line, field_names=None, timezone_in_use=pytz.utc, database=None):
|
||||||
'''
|
'''
|
||||||
Create a model instance from a tab-separated line. The line may or may not include a newline.
|
Create a model instance from a tab-separated line. The line may or may not include a newline.
|
||||||
The field_names list must match the fields defined in the model, but does not have to include all of them.
|
The field_names list must match the fields defined in the model, but does not have to include all of them.
|
||||||
If omitted, it is assumed to be the names of all fields in the model, in order of definition.
|
If omitted, it is assumed to be the names of all fields in the model, in order of definition.
|
||||||
|
:param database: if given, model receives database
|
||||||
'''
|
'''
|
||||||
from six import next
|
from six import next
|
||||||
field_names = field_names or [name for name, field in cls._fields]
|
field_names = field_names or [name for name, field in cls._fields]
|
||||||
|
@ -151,7 +166,12 @@ class Model(with_metaclass(ModelBase)):
|
||||||
for name in field_names:
|
for name in field_names:
|
||||||
field = getattr(cls, name)
|
field = getattr(cls, name)
|
||||||
kwargs[name] = field.to_python(next(values), timezone_in_use)
|
kwargs[name] = field.to_python(next(values), timezone_in_use)
|
||||||
return cls(**kwargs)
|
|
||||||
|
obj = cls(**kwargs)
|
||||||
|
if database is not None:
|
||||||
|
obj.set_database(database)
|
||||||
|
|
||||||
|
return obj
|
||||||
|
|
||||||
def to_tsv(self, include_readonly=True):
|
def to_tsv(self, include_readonly=True):
|
||||||
'''
|
'''
|
||||||
|
|
|
@ -2,10 +2,9 @@
|
||||||
This file contains system readonly models that can be got from database
|
This file contains system readonly models that can be got from database
|
||||||
https://clickhouse.yandex/reference_en.html#System tables
|
https://clickhouse.yandex/reference_en.html#System tables
|
||||||
"""
|
"""
|
||||||
from .database import Database # Can't import it globally, due to circular import
|
from .database import Database
|
||||||
from .fields import *
|
from .fields import *
|
||||||
from .models import Model
|
from .models import Model
|
||||||
from .engines import MergeTree
|
|
||||||
|
|
||||||
|
|
||||||
class SystemPart(Model):
|
class SystemPart(Model):
|
||||||
|
@ -51,7 +50,7 @@ class SystemPart(Model):
|
||||||
Next methods return SQL for some operations, which can be done with partitions
|
Next methods return SQL for some operations, which can be done with partitions
|
||||||
https://clickhouse.yandex/reference_en.html#Manipulations with partitions and parts
|
https://clickhouse.yandex/reference_en.html#Manipulations with partitions and parts
|
||||||
"""
|
"""
|
||||||
def _partition_operation_sql(self, db, operation, settings=None, from_part=None):
|
def _partition_operation_sql(self, operation, settings=None, from_part=None):
|
||||||
"""
|
"""
|
||||||
Performs some operation over partition
|
Performs some operation over partition
|
||||||
:param db: Database object to execute operation on
|
:param db: Database object to execute operation on
|
||||||
|
@ -61,56 +60,51 @@ class SystemPart(Model):
|
||||||
"""
|
"""
|
||||||
operation = operation.upper()
|
operation = operation.upper()
|
||||||
assert operation in self.OPERATIONS, "operation must be in [%s]" % ', '.join(self.OPERATIONS)
|
assert operation in self.OPERATIONS, "operation must be in [%s]" % ', '.join(self.OPERATIONS)
|
||||||
sql = "ALTER TABLE `%s`.`%s` %s PARTITION '%s'" % (db.db_name, self.table, operation, self.partition)
|
sql = "ALTER TABLE `%s`.`%s` %s PARTITION '%s'" % (self._database.db_name, self.table, operation, self.partition)
|
||||||
if from_part is not None:
|
if from_part is not None:
|
||||||
sql += " FROM %s" % from_part
|
sql += " FROM %s" % from_part
|
||||||
db.raw(sql, settings=settings, stream=False)
|
self._database.raw(sql, settings=settings, stream=False)
|
||||||
|
|
||||||
def detach(self, database, settings=None):
|
def detach(self, settings=None):
|
||||||
"""
|
"""
|
||||||
Move a partition to the 'detached' directory and forget it.
|
Move a partition to the 'detached' directory and forget it.
|
||||||
:param database: Database object to execute operation on
|
|
||||||
:param settings: Settings for executing request to ClickHouse over db.raw() method
|
:param settings: Settings for executing request to ClickHouse over db.raw() method
|
||||||
:return: SQL Query
|
:return: SQL Query
|
||||||
"""
|
"""
|
||||||
return self._partition_operation_sql(database, 'DETACH', settings=settings)
|
return self._partition_operation_sql('DETACH', settings=settings)
|
||||||
|
|
||||||
def drop(self, database, settings=None):
|
def drop(self, settings=None):
|
||||||
"""
|
"""
|
||||||
Delete a partition
|
Delete a partition
|
||||||
:param database: Database object to execute operation on
|
|
||||||
:param settings: Settings for executing request to ClickHouse over db.raw() method
|
:param settings: Settings for executing request to ClickHouse over db.raw() method
|
||||||
:return: SQL Query
|
:return: SQL Query
|
||||||
"""
|
"""
|
||||||
return self._partition_operation_sql(database, 'DROP', settings=settings)
|
return self._partition_operation_sql('DROP', settings=settings)
|
||||||
|
|
||||||
def attach(self, database, settings=None):
|
def attach(self, settings=None):
|
||||||
"""
|
"""
|
||||||
Add a new part or partition from the 'detached' directory to the table.
|
Add a new part or partition from the 'detached' directory to the table.
|
||||||
:param database: Database object to execute operation on
|
|
||||||
:param settings: Settings for executing request to ClickHouse over db.raw() method
|
:param settings: Settings for executing request to ClickHouse over db.raw() method
|
||||||
:return: SQL Query
|
:return: SQL Query
|
||||||
"""
|
"""
|
||||||
return self._partition_operation_sql(database, 'ATTACH', settings=settings)
|
return self._partition_operation_sql('ATTACH', settings=settings)
|
||||||
|
|
||||||
def freeze(self, database, settings=None):
|
def freeze(self, settings=None):
|
||||||
"""
|
"""
|
||||||
Create a backup of a partition.
|
Create a backup of a partition.
|
||||||
:param database: Database object to execute operation on
|
|
||||||
:param settings: Settings for executing request to ClickHouse over db.raw() method
|
:param settings: Settings for executing request to ClickHouse over db.raw() method
|
||||||
:return: SQL Query
|
:return: SQL Query
|
||||||
"""
|
"""
|
||||||
return self._partition_operation_sql(database, 'FREEZE', settings=settings)
|
return self._partition_operation_sql('FREEZE', settings=settings)
|
||||||
|
|
||||||
def fetch(self, database, zookeeper_path, settings=None):
|
def fetch(self, zookeeper_path, settings=None):
|
||||||
"""
|
"""
|
||||||
Download a partition from another server.
|
Download a partition from another server.
|
||||||
:param database: Database object to execute operation on
|
|
||||||
:param zookeeper_path: Path in zookeeper to fetch from
|
:param zookeeper_path: Path in zookeeper to fetch from
|
||||||
:param settings: Settings for executing request to ClickHouse over db.raw() method
|
:param settings: Settings for executing request to ClickHouse over db.raw() method
|
||||||
:return: SQL Query
|
:return: SQL Query
|
||||||
"""
|
"""
|
||||||
return self._partition_operation_sql(database, 'FETCH', settings=settings, from_part=zookeeper_path)
|
return self._partition_operation_sql('FETCH', settings=settings, from_part=zookeeper_path)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get(cls, database, conditions=""):
|
def get(cls, database, conditions=""):
|
||||||
|
|
|
@ -32,7 +32,7 @@ class SystemPartTest(unittest.TestCase):
|
||||||
def test_get_active(self):
|
def test_get_active(self):
|
||||||
parts = list(SystemPart.get_active(self.database))
|
parts = list(SystemPart.get_active(self.database))
|
||||||
self.assertEqual(len(parts), 1)
|
self.assertEqual(len(parts), 1)
|
||||||
parts[0].detach(self.database)
|
parts[0].detach()
|
||||||
self.assertEqual(len(list(SystemPart.get_active(self.database))), 0)
|
self.assertEqual(len(list(SystemPart.get_active(self.database))), 0)
|
||||||
|
|
||||||
def test_get_conditions(self):
|
def test_get_conditions(self):
|
||||||
|
@ -44,21 +44,21 @@ class SystemPartTest(unittest.TestCase):
|
||||||
def test_attach_detach(self):
|
def test_attach_detach(self):
|
||||||
parts = list(SystemPart.get_active(self.database))
|
parts = list(SystemPart.get_active(self.database))
|
||||||
self.assertEqual(len(parts), 1)
|
self.assertEqual(len(parts), 1)
|
||||||
parts[0].detach(self.database)
|
parts[0].detach()
|
||||||
self.assertEqual(len(list(SystemPart.get_active(self.database))), 0)
|
self.assertEqual(len(list(SystemPart.get_active(self.database))), 0)
|
||||||
parts[0].attach(self.database)
|
parts[0].attach()
|
||||||
self.assertEqual(len(list(SystemPart.get_active(self.database))), 1)
|
self.assertEqual(len(list(SystemPart.get_active(self.database))), 1)
|
||||||
|
|
||||||
def test_drop(self):
|
def test_drop(self):
|
||||||
parts = list(SystemPart.get_active(self.database))
|
parts = list(SystemPart.get_active(self.database))
|
||||||
parts[0].drop(self.database)
|
parts[0].drop()
|
||||||
self.assertEqual(len(list(SystemPart.get_active(self.database))), 0)
|
self.assertEqual(len(list(SystemPart.get_active(self.database))), 0)
|
||||||
|
|
||||||
def test_freeze(self):
|
def test_freeze(self):
|
||||||
parts = list(SystemPart.get(self.database))
|
parts = list(SystemPart.get(self.database))
|
||||||
# There can be other backups in the folder
|
# There can be other backups in the folder
|
||||||
prev_backups = set(self._get_backups())
|
prev_backups = set(self._get_backups())
|
||||||
parts[0].freeze(self.database)
|
parts[0].freeze()
|
||||||
backups = set(self._get_backups())
|
backups = set(self._get_backups())
|
||||||
self.assertEqual(len(backups), len(prev_backups) + 1)
|
self.assertEqual(len(backups), len(prev_backups) + 1)
|
||||||
# Clean created backup
|
# Clean created backup
|
||||||
|
|
Loading…
Reference in New Issue
Block a user