|
@@ -46,6 +46,8 @@ class MysqlMigrationHandler(DummyMigrationHandler):
|
46
|
46
|
## @brief Construct a MysqlMigrationHandler
|
47
|
47
|
# @param module : sql module
|
48
|
48
|
# @param conn_args dict : A dict containing connection options
|
|
49
|
+ # @param db_engine str : Name of a MySQL db engine (default is InnoDB, don't change it ! ;) )
|
|
50
|
+ # @param **kwargs : arguement given to the module.connect() method
|
49
|
51
|
def __init__(self, module=pymysql, conn_args=None, db_engine='InnoDB', **kwargs):
|
50
|
52
|
# Database connection
|
51
|
53
|
self._dbmodule = module
|
|
@@ -74,6 +76,7 @@ class MysqlMigrationHandler(DummyMigrationHandler):
|
74
|
76
|
# @param uid int : The uid of the change EmComponent
|
75
|
77
|
# @param initial_state dict | None : dict with field name as key and field value as value. Representing the original state. None mean creation of a new component.
|
76
|
78
|
# @param new_state dict | None : dict with field name as key and field value as value. Representing the new state. None mean component deletion
|
|
79
|
+ # @param engine str : Mysql db engine, should be "InnoDB"
|
77
|
80
|
# @throw EditorialModel.exceptions.MigrationHandlerChangeError if the change was refused
|
78
|
81
|
def register_change(self, em, uid, initial_state, new_state, engine=None):
|
79
|
82
|
if engine is None:
|
|
@@ -114,7 +117,7 @@ class MysqlMigrationHandler(DummyMigrationHandler):
|
114
|
117
|
## @brief Add a relationnal field
|
115
|
118
|
# Add a rel2type attribute
|
116
|
119
|
# @note this function handles the table creation
|
117
|
|
- # @param em Model : EditorialModel.model.Model instance
|
|
120
|
+ # @param edmod Model : EditorialModel.model.Model instance
|
118
|
121
|
# @param rfuid int : Relationnal field uid
|
119
|
122
|
def add_relationnal_field(self, edmod, rfuid):
|
120
|
123
|
emfield = edmod.component(rfuid)
|
|
@@ -146,7 +149,7 @@ class MysqlMigrationHandler(DummyMigrationHandler):
|
146
|
149
|
#
|
147
|
150
|
# Delete a rel2type attribute
|
148
|
151
|
# @note this method handles the table deletion
|
149
|
|
- # @param em Model : EditorialModel.model.Model instance
|
|
152
|
+ # @param edmod Model : EditorialModel.model.Model instance
|
150
|
153
|
# @param rfuid int : Relationnal field uid
|
151
|
154
|
def del_relationnal_field(self, edmod, rfuid):
|
152
|
155
|
emfield = edmod.component(rfuid)
|
|
@@ -165,7 +168,7 @@ class MysqlMigrationHandler(DummyMigrationHandler):
|
165
|
168
|
self._generate_triggers(tname, self._r2type2cols(edmod, r2tf))
|
166
|
169
|
|
167
|
170
|
## @brief Given an EmField uid add a column to the corresponding table
|
168
|
|
- # @param em Model : A Model instance
|
|
171
|
+ # @param edmod Model : A Model instance
|
169
|
172
|
# @param uid int : An EmField uid
|
170
|
173
|
def add_col_from_emfield(self, edmod, uid):
|
171
|
174
|
emfield = edmod.component(uid)
|
|
@@ -180,8 +183,9 @@ class MysqlMigrationHandler(DummyMigrationHandler):
|
180
|
183
|
self._generate_triggers(tname, cols_l)
|
181
|
184
|
|
182
|
185
|
## @brief Given a class uid create the coressponding table
|
183
|
|
- # @param em Model : A Model instance
|
|
186
|
+ # @param edmod Model : A Model instance
|
184
|
187
|
# @param uid int : An EmField uid
|
|
188
|
+ # @param engine str : Db engine (should be "InnoDB")
|
185
|
189
|
def create_emclass_table(self, edmod, uid, engine):
|
186
|
190
|
emclass = edmod.component(uid)
|
187
|
191
|
if not isinstance(emclass, EditorialModel.classes.EmClass):
|
|
@@ -199,7 +203,7 @@ class MysqlMigrationHandler(DummyMigrationHandler):
|
199
|
203
|
self._add_fk(table_name, utils.common_tables['object'], pkname, pkname)
|
200
|
204
|
|
201
|
205
|
## @brief Given an EmClass uid delete the corresponding table
|
202
|
|
- # @param em Model : A Model instance
|
|
206
|
+ # @param edmod Model : A Model instance
|
203
|
207
|
# @param uid int : An EmField uid
|
204
|
208
|
def delete_emclass_table(self, edmod, uid):
|
205
|
209
|
emclass = edmod.component(uid)
|
|
@@ -214,7 +218,7 @@ class MysqlMigrationHandler(DummyMigrationHandler):
|
214
|
218
|
self._query("""DROP TABLE {table_name};""".format(table_name=tname))
|
215
|
219
|
|
216
|
220
|
## @brief Given an EmField delete the corresponding column
|
217
|
|
- # @param em Model : an @ref EditorialModel.model.Model instance
|
|
221
|
+ # @param edmod Model : an @ref EditorialModel.model.Model instance
|
218
|
222
|
# @param uid int : an EmField uid
|
219
|
223
|
def delete_col_from_emfield(self, edmod, uid):
|
220
|
224
|
emfield = edmod.component(uid)
|
|
@@ -244,7 +248,7 @@ class MysqlMigrationHandler(DummyMigrationHandler):
|
244
|
248
|
self._query("""ALTER TABLE {table_name} DROP COLUMN {col_name};""".format(table_name=tname, col_name=fname))
|
245
|
249
|
|
246
|
250
|
## @brief Construct a table name given a rela2type EmField instance
|
247
|
|
- # @param em Model : A Model instance
|
|
251
|
+ # @param edmod Model : A Model instance
|
248
|
252
|
# @param emfield EmField : An EmField instance
|
249
|
253
|
# @return a table name
|
250
|
254
|
def _r2t2table_name(self, edmod, emfield):
|
|
@@ -253,7 +257,7 @@ class MysqlMigrationHandler(DummyMigrationHandler):
|
253
|
257
|
return utils.r2t_table_name(emclass.name, emtype.name)
|
254
|
258
|
|
255
|
259
|
## @brief Generate a columns_fieldtype dict given a rel2type EmField
|
256
|
|
- # @param em Model : an @ref EditorialModel.model.Model instance
|
|
260
|
+ # @param edmod Model : an @ref EditorialModel.model.Model instance
|
257
|
261
|
# @param emfield EmField : and @ref EditorialModel.fields.EmField instance
|
258
|
262
|
def _r2type2cols(self, edmod, emfield):
|
259
|
263
|
return {f.name: f.fieldtype_instance() for f in edmod.components('EmField') if f.rel_field_id == emfield.uid}
|
|
@@ -316,7 +320,7 @@ class MysqlMigrationHandler(DummyMigrationHandler):
|
316
|
320
|
# @param pk_ftype fieldtype | tuple : pk fieldtype (give a tuple for multi pk)
|
317
|
321
|
# @param engine str : The engine to use with this table
|
318
|
322
|
# @param charset str : The charset of this table
|
319
|
|
- # @param if_exist str : takes values in ['nothing', 'drop']
|
|
323
|
+ # @param if_exists str : takes values in ['nothing', 'drop']
|
320
|
324
|
# @param noauto_inc bool : if True forbids autoincrement on PK
|
321
|
325
|
def _create_table(self, table_name, pk_name, pk_ftype, engine, charset='utf8', if_exists='nothing', noauto_inc = False):
|
322
|
326
|
#Escaped table name
|
|
@@ -359,6 +363,7 @@ class MysqlMigrationHandler(DummyMigrationHandler):
|
359
|
363
|
# @param col_name str : The columns name
|
360
|
364
|
# @param col_fieldtype EmFieldype the fieldtype
|
361
|
365
|
# @param relation bool | None : a flag to indicate if we add a column in a table linked with an bject or with a relation (used only when the column is MultiValueFieldType )
|
|
366
|
+ # @param drop_if_exists bool : if True delete the column before re-adding it
|
362
|
367
|
# @return True if the column was added else return False
|
363
|
368
|
def _add_column(self, table_name, col_name, col_fieldtype, drop_if_exists=False, relation=False):
|
364
|
369
|
instr, col_type, col_specs = fieldtypes_utils.fieldtype_db_init(col_fieldtype)
|
|
@@ -437,6 +442,7 @@ ADD COLUMN {col_name} {col_type} {col_specs};"""
|
437
|
442
|
# @param ref_table_name str : Referenced table name
|
438
|
443
|
# @param key_infos tuple : tuple(key_name, key_fieldtype)
|
439
|
444
|
# @param column_infos tuple : tuple(col_name, col_fieldtype)
|
|
445
|
+ # @param relation bool : pass True if concern a LeRelation or False of concern a LeObject
|
440
|
446
|
def _add_column_multivalue(self, ref_table_name, key_infos, column_infos, relation):
|
441
|
447
|
key_name, key_ftype = key_infos
|
442
|
448
|
col_name, col_ftype = column_infos
|
|
@@ -481,6 +487,7 @@ ADD COLUMN {col_name} {col_type} {col_specs};"""
|
481
|
487
|
# @param dst_table_name str : The name of the table the FK will point on
|
482
|
488
|
# @param src_col_name str : The name of the concerned column in the src_table
|
483
|
489
|
# @param dst_col_name str : The name of the concerned column in the dst_table
|
|
490
|
+ # @param fk_name str|None : The foreign key name, if None the name will be generated (not a good idea)
|
484
|
491
|
def _add_fk(self, src_table_name, dst_table_name, src_col_name, dst_col_name, fk_name=None):
|
485
|
492
|
stname = utils.escape_idname(src_table_name)
|
486
|
493
|
dtname = utils.escape_idname(dst_table_name)
|
|
@@ -507,6 +514,7 @@ ON UPDATE CASCADE;""".format(
|
507
|
514
|
## @brief Given a source and a destination table, delete the corresponding FK
|
508
|
515
|
# @param src_table_name str : The name of the table where the FK is
|
509
|
516
|
# @param dst_table_name str : The name of the table the FK point on
|
|
517
|
+ # @param fk_name str|None : the foreign key name, if None try to guess it
|
510
|
518
|
# @warning fails silently
|
511
|
519
|
def _del_fk(self, src_table_name, dst_table_name, fk_name=None):
|
512
|
520
|
if fk_name is None:
|
|
@@ -543,11 +551,12 @@ DROP FOREIGN KEY {fk_name}""".format(
|
543
|
551
|
#
|
544
|
552
|
# Primarly designed to create trigger for DATETIME types
|
545
|
553
|
# The method generates triggers of the form
|
546
|
|
- #
|
547
|
|
- # CREATE TRIGGER BEFORE <moment> ON <table_name>
|
548
|
|
- # FOR EACH ROW SET <for colname, colval in cols_val>
|
549
|
|
- # NEW.<colname> = <colval>,
|
550
|
|
- # <endfor>;
|
|
554
|
+ # <pre>
|
|
555
|
+ # CREATE TRIGGER BEFORE <moment> ON <table_name>
|
|
556
|
+ # FOR EACH ROW SET lt;for colname, colval in <cols_val>
|
|
557
|
+ # NEW.lt;colname> = lt;colval>,
|
|
558
|
+ # lt;endfor>;
|
|
559
|
+ # </pre>
|
551
|
560
|
# @param table_name str : The table name
|
552
|
561
|
# @param moment str : can be 'update' or 'insert'
|
553
|
562
|
# @param cols_val dict : Dict with column name as key and column value as value
|
|
@@ -618,6 +627,7 @@ FOR EACH ROW SET {col_val_list};""".format(
|
618
|
627
|
self.db_conn.commit() # autocommit
|
619
|
628
|
|
620
|
629
|
## @brief Given a common field name return an EmFieldType instance
|
|
630
|
+ # @param cls
|
621
|
631
|
# @param cname str : Common field name
|
622
|
632
|
# @return An EmFieldType instance
|
623
|
633
|
@classmethod
|