mirror of
https://github.com/Infinidat/infi.clickhouse_orm.git
synced 2024-09-21 03:08:53 +03:00
Add AlterTableWithBuffer
migration operation
This commit is contained in:
parent
430872b958
commit
7bbcae574a
|
@ -1,6 +1,10 @@
|
||||||
Change Log
|
Change Log
|
||||||
==========
|
==========
|
||||||
|
|
||||||
|
Unreleased
|
||||||
|
----------
|
||||||
|
- Add `AlterTableWithBuffer` migration operation
|
||||||
|
|
||||||
v0.9.6
|
v0.9.6
|
||||||
------
|
------
|
||||||
- Fix python3 compatibility (TvoroG)
|
- Fix python3 compatibility (TvoroG)
|
||||||
|
|
|
@ -34,11 +34,13 @@ The following operations are supported:
|
||||||
|
|
||||||
**CreateTable**
|
**CreateTable**
|
||||||
|
|
||||||
A migration operation that creates a table for a given model class.
|
A migration operation that creates a table for a given model class. If the table already exists, the operation does nothing.
|
||||||
|
|
||||||
|
In case the model class is a `BufferModel`, the operation first creates the underlying on-disk table, and then creates the buffer table.
|
||||||
|
|
||||||
**DropTable**
|
**DropTable**
|
||||||
|
|
||||||
A migration operation that drops the table of a given model class.
|
A migration operation that drops the table of a given model class. If the table does not exist, the operation does nothing.
|
||||||
|
|
||||||
**AlterTable**
|
**AlterTable**
|
||||||
|
|
||||||
|
@ -50,6 +52,13 @@ A migration operation that compares the table of a given model class to the mode
|
||||||
|
|
||||||
Default values are not altered by this operation.
|
Default values are not altered by this operation.
|
||||||
|
|
||||||
|
**AlterTableWithBuffer**
|
||||||
|
|
||||||
|
A compound migration operation for altering a buffer table and its underlying on-disk table. The buffer table is dropped, the on-disk table is altered, and then the buffer table is re-created. This is the procedure recommended in the ClickHouse documentation for handling scenarios in which the underlying table needs to be modified.
|
||||||
|
|
||||||
|
Applying this migration operation to a regular table has the same effect as an `AlterTable` operation.
|
||||||
|
|
||||||
|
|
||||||
Running Migrations
|
Running Migrations
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
|
|
@ -82,6 +82,25 @@ class AlterTable(Operation):
|
||||||
self._alter_table(database, 'MODIFY COLUMN %s %s' % model_field)
|
self._alter_table(database, 'MODIFY COLUMN %s %s' % model_field)
|
||||||
|
|
||||||
|
|
||||||
|
class AlterTableWithBuffer(Operation):
|
||||||
|
'''
|
||||||
|
A migration operation for altering a buffer table and its underlying on-disk table.
|
||||||
|
The buffer table is dropped, the on-disk table is altered, and then the buffer table
|
||||||
|
is re-created.
|
||||||
|
'''
|
||||||
|
|
||||||
|
def __init__(self, model_class):
|
||||||
|
self.model_class = model_class
|
||||||
|
|
||||||
|
def apply(self, database):
|
||||||
|
if issubclass(self.model_class, BufferModel):
|
||||||
|
DropTable(self.model_class).apply(database)
|
||||||
|
AlterTable(self.model_class.engine.main_model).apply(database)
|
||||||
|
CreateTable(self.model_class).apply(database)
|
||||||
|
else:
|
||||||
|
AlterTable(self.model_class).apply(database)
|
||||||
|
|
||||||
|
|
||||||
class DropTable(Operation):
|
class DropTable(Operation):
|
||||||
'''
|
'''
|
||||||
A migration operation that drops the table of a given model class.
|
A migration operation that drops the table of a given model class.
|
||||||
|
@ -91,7 +110,7 @@ class DropTable(Operation):
|
||||||
self.model_class = model_class
|
self.model_class = model_class
|
||||||
|
|
||||||
def apply(self, database):
|
def apply(self, database):
|
||||||
logger.info(' Drop table %s', self.model_class.__name__)
|
logger.info(' Drop table %s', self.model_class.table_name())
|
||||||
database.drop_table(self.model_class)
|
database.drop_table(self.model_class)
|
||||||
|
|
||||||
|
|
||||||
|
|
6
tests/sample_migrations/0010.py
Normal file
6
tests/sample_migrations/0010.py
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
from infi.clickhouse_orm import migrations
|
||||||
|
from ..test_migrations import *
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateTable(Model4Buffer)
|
||||||
|
]
|
6
tests/sample_migrations/0011.py
Normal file
6
tests/sample_migrations/0011.py
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
from infi.clickhouse_orm import migrations
|
||||||
|
from ..test_migrations import *
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterTableWithBuffer(Model4Buffer_changed)
|
||||||
|
]
|
|
@ -2,7 +2,7 @@ from __future__ import unicode_literals
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from infi.clickhouse_orm.database import Database
|
from infi.clickhouse_orm.database import Database
|
||||||
from infi.clickhouse_orm.models import Model
|
from infi.clickhouse_orm.models import Model, BufferModel
|
||||||
from infi.clickhouse_orm.fields import *
|
from infi.clickhouse_orm.fields import *
|
||||||
from infi.clickhouse_orm.engines import *
|
from infi.clickhouse_orm.engines import *
|
||||||
from infi.clickhouse_orm.migrations import MigrationHistory
|
from infi.clickhouse_orm.migrations import MigrationHistory
|
||||||
|
@ -61,6 +61,7 @@ class MigrationsTestCase(unittest.TestCase):
|
||||||
self.assertTrue(self.tableExists(EnumModel1))
|
self.assertTrue(self.tableExists(EnumModel1))
|
||||||
self.assertEquals(self.getTableFields(EnumModel2),
|
self.assertEquals(self.getTableFields(EnumModel2),
|
||||||
[('date', 'Date'), ('f1', "Enum16('dog' = 1, 'cat' = 2, 'horse' = 3, 'pig' = 4)")])
|
[('date', 'Date'), ('f1', "Enum16('dog' = 1, 'cat' = 2, 'horse' = 3, 'pig' = 4)")])
|
||||||
|
# Materialized fields and alias fields
|
||||||
self.database.migrate('tests.sample_migrations', 8)
|
self.database.migrate('tests.sample_migrations', 8)
|
||||||
self.assertTrue(self.tableExists(MaterializedModel))
|
self.assertTrue(self.tableExists(MaterializedModel))
|
||||||
self.assertEquals(self.getTableFields(MaterializedModel),
|
self.assertEquals(self.getTableFields(MaterializedModel),
|
||||||
|
@ -69,6 +70,15 @@ class MigrationsTestCase(unittest.TestCase):
|
||||||
self.assertTrue(self.tableExists(AliasModel))
|
self.assertTrue(self.tableExists(AliasModel))
|
||||||
self.assertEquals(self.getTableFields(AliasModel),
|
self.assertEquals(self.getTableFields(AliasModel),
|
||||||
[('date', 'Date'), ('date_alias', "Date")])
|
[('date', 'Date'), ('date_alias', "Date")])
|
||||||
|
# Buffer models creation and alteration
|
||||||
|
self.database.migrate('tests.sample_migrations', 10)
|
||||||
|
self.assertTrue(self.tableExists(Model4))
|
||||||
|
self.assertTrue(self.tableExists(Model4Buffer))
|
||||||
|
self.assertEquals(self.getTableFields(Model4), [('date', 'Date'), ('f1', 'Int32'), ('f2', 'String')])
|
||||||
|
self.assertEquals(self.getTableFields(Model4Buffer), [('date', 'Date'), ('f1', 'Int32'), ('f2', 'String')])
|
||||||
|
self.database.migrate('tests.sample_migrations', 11)
|
||||||
|
self.assertEquals(self.getTableFields(Model4), [('date', 'Date'), ('f3', 'DateTime'), ('f2', 'String')])
|
||||||
|
self.assertEquals(self.getTableFields(Model4Buffer), [('date', 'Date'), ('f3', 'DateTime'), ('f2', 'String')])
|
||||||
|
|
||||||
|
|
||||||
# Several different models with the same table name, to simulate a table that changes over time
|
# Several different models with the same table name, to simulate a table that changes over time
|
||||||
|
@ -159,3 +169,47 @@ class AliasModel(Model):
|
||||||
@classmethod
|
@classmethod
|
||||||
def table_name(cls):
|
def table_name(cls):
|
||||||
return 'alias_date'
|
return 'alias_date'
|
||||||
|
|
||||||
|
|
||||||
|
class Model4(Model):
|
||||||
|
|
||||||
|
date = DateField()
|
||||||
|
f1 = Int32Field()
|
||||||
|
f2 = StringField()
|
||||||
|
|
||||||
|
engine = MergeTree('date', ('date',))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def table_name(cls):
|
||||||
|
return 'model4'
|
||||||
|
|
||||||
|
|
||||||
|
class Model4Buffer(BufferModel, Model4):
|
||||||
|
|
||||||
|
engine = Buffer(Model4)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def table_name(cls):
|
||||||
|
return 'model4buffer'
|
||||||
|
|
||||||
|
|
||||||
|
class Model4_changed(Model):
|
||||||
|
|
||||||
|
date = DateField()
|
||||||
|
f3 = DateTimeField()
|
||||||
|
f2 = StringField()
|
||||||
|
|
||||||
|
engine = MergeTree('date', ('date',))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def table_name(cls):
|
||||||
|
return 'model4'
|
||||||
|
|
||||||
|
|
||||||
|
class Model4Buffer_changed(BufferModel, Model4_changed):
|
||||||
|
|
||||||
|
engine = Buffer(Model4_changed)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def table_name(cls):
|
||||||
|
return 'model4buffer'
|
||||||
|
|
Loading…
Reference in New Issue
Block a user