|
@@ -18,15 +18,22 @@ import EditorialModel
|
18
|
18
|
# - EmClass deletion (untested)
|
19
|
19
|
# - EmField creation
|
20
|
20
|
# - EmField deletion (untested)
|
|
21
|
+# - rel2type attribute creation
|
|
22
|
+# - rel2type attribute deletion (unstested)
|
21
|
23
|
#
|
22
|
24
|
# Unsupported operations :
|
23
|
25
|
# - EmClass rename
|
24
|
26
|
# - EmField rename
|
|
27
|
+# - rel2type field rename
|
|
28
|
+# - rel2type attribute rename
|
|
29
|
+#
|
25
|
30
|
|
26
|
31
|
## @brief Modify a MySQL database given editorial model changes
|
27
|
32
|
class MysqlMigrationHandler(EditorialModel.migrationhandler.dummy.DummyMigrationHandler):
|
28
|
33
|
|
|
34
|
+ ## @brief Object table name
|
29
|
35
|
_object_tname = 'object'
|
|
36
|
+ ## @brief Relation table name
|
30
|
37
|
_relation_tname = 'relation'
|
31
|
38
|
|
32
|
39
|
## @brief Construct a MysqlMigrationHandler
|
|
@@ -59,17 +66,25 @@ class MysqlMigrationHandler(EditorialModel.migrationhandler.dummy.DummyMigration
|
59
|
66
|
self.delete_emclass_table(em, uid)
|
60
|
67
|
elif isinstance(em.component(uid), EditorialModel.fields.EmField):
|
61
|
68
|
emfield = em.component(uid)
|
62
|
|
- if initial_state is None:
|
63
|
|
- #EmField creation
|
64
|
|
- if not(emfield.name in EditorialModel.classtypes.common_fields.keys()):
|
65
|
|
- self.add_col_from_emfield(em,uid)
|
66
|
|
- elif new_state is None:
|
67
|
|
- #EmField deletion
|
68
|
|
- if not (emfield.name in EditorialModel.classtypes.common_fields.keys()):
|
69
|
|
- self.del_col_from_emfield(em, uid)
|
70
|
|
- pass
|
71
|
|
- pass
|
72
|
|
-
|
|
69
|
+ if emfield.rel_field_id is None:
|
|
70
|
+ #non rlationnal field
|
|
71
|
+ if initial_state is None:
|
|
72
|
+ #non relationnal EmField creation
|
|
73
|
+ if not(emfield.name in EditorialModel.classtypes.common_fields.keys()):
|
|
74
|
+ self.add_col_from_emfield(em,uid)
|
|
75
|
+ elif new_state is None:
|
|
76
|
+ #non relationnal EmField deletion
|
|
77
|
+ if not (emfield.name in EditorialModel.classtypes.common_fields.keys()):
|
|
78
|
+ self.del_col_from_emfield(em, uid)
|
|
79
|
+ else:
|
|
80
|
+ #relationnal field
|
|
81
|
+ if initial_state is None:
|
|
82
|
+ #Rel2type attr creation
|
|
83
|
+ self.add_relationnal_field(em, uid)
|
|
84
|
+ elif new_state is None:
|
|
85
|
+ #Rel2type attr deletion
|
|
86
|
+ self.del_relationnal_field(em, uid)
|
|
87
|
+ ## @brief dumdumdummy
|
73
|
88
|
def register_model_state(self, em, state_hash):
|
74
|
89
|
pass
|
75
|
90
|
|
|
@@ -80,6 +95,53 @@ class MysqlMigrationHandler(EditorialModel.migrationhandler.dummy.DummyMigration
|
80
|
95
|
if not self.dryrun:
|
81
|
96
|
self.db.query(query)
|
82
|
97
|
|
|
98
|
+ ## @brief Add a relationnal field
|
|
99
|
+ #
|
|
100
|
+ # Add a rel2type attribute
|
|
101
|
+ # @note this function handles the table creation
|
|
102
|
+ # @param em Model : EditorialModel.model.Model instance
|
|
103
|
+ # @param rfuid int : Relationnal field uid
|
|
104
|
+ def add_relationnal_field(self, em, rfuid):
|
|
105
|
+ emfield = em.component(rfuid)
|
|
106
|
+ if not isinstance(emfield, EditorialModel.fields.EmField):
|
|
107
|
+ raise ValueError("The given uid is not an EmField uid")
|
|
108
|
+
|
|
109
|
+ r2tf = em.component(emfield.rel_field_id)
|
|
110
|
+ tname = self._r2t2table_name(em, r2tf)
|
|
111
|
+ pkname, pkftype = self._relation_pk
|
|
112
|
+
|
|
113
|
+ #If not exists create a relational table
|
|
114
|
+ self._create_table(tname, pkname, pkftype, self.db_engine, if_exists = 'nothing')
|
|
115
|
+ #Add a foreign key if wanted
|
|
116
|
+ if self.foreign_keys:
|
|
117
|
+ self._add_fk(tname, self._relation_tname, pkname, pkname)
|
|
118
|
+ #Add the column
|
|
119
|
+ self._add_column(tname, emfield.name, emfield.fieldtype_instance())
|
|
120
|
+ #Update table triggers
|
|
121
|
+ self._generate_triggers(tname, self._r2type2cols(em, r2tf))
|
|
122
|
+
|
|
123
|
+ ## @brief Delete a rel2type attribute
|
|
124
|
+ #
|
|
125
|
+ # Delete a rel2type attribute
|
|
126
|
+ # @note this method handles the table deletion
|
|
127
|
+ # @param em Model : EditorialModel.model.Model instance
|
|
128
|
+ # @param rfuid int : Relationnal field uid
|
|
129
|
+ def del_relationnal_field(self, em, rfuid):
|
|
130
|
+ emfield = em.component(rfuid)
|
|
131
|
+ if not isinstance(emfield, EditorialModel.fields.EmField):
|
|
132
|
+ raise ValueError("The given uid is not an EmField uid")
|
|
133
|
+
|
|
134
|
+ r2tf = em.component(emfield.rel_field_id)
|
|
135
|
+ tname = self._r2t2table_name(em, r2tf)
|
|
136
|
+
|
|
137
|
+ if len(self._r2type2cols(em, r2tf)) == 1:
|
|
138
|
+ #The table can be deleted (no more attribute for this rel2type)
|
|
139
|
+ self._query("""DROP TABLE {table_name}""".format(table_name = tname))
|
|
140
|
+ else:
|
|
141
|
+ self._del_column(tname, emfield.name)
|
|
142
|
+ #Update table triggers
|
|
143
|
+ self._generate_triggers(tname, self._r2type2cols(em, r2tf))
|
|
144
|
+
|
83
|
145
|
## @brief Given an EmField uid add a column to the corresponding table
|
84
|
146
|
# @param em Model : A Model instance
|
85
|
147
|
# @param uid int : An EmField uid
|
|
@@ -152,8 +214,23 @@ class MysqlMigrationHandler(EditorialModel.migrationhandler.dummy.DummyMigration
|
152
|
214
|
# @return a table name
|
153
|
215
|
def _emclass2table_name(self, emclass):
|
154
|
216
|
return "class_%s"%emclass.name
|
|
217
|
+
|
|
218
|
+ ## @brief Construct a table name given a rela2type EmField instance
|
|
219
|
+ # @param em Model : A Model instance
|
|
220
|
+ # @param emfield EmField : An EmField instance
|
|
221
|
+ # @return a table name
|
|
222
|
+ def _r2t2table_name(self, em, emfield):
|
|
223
|
+ emclass = emfield.em_class
|
|
224
|
+ emtype = em.component(emfield.rel_to_type_id)
|
|
225
|
+ return "%s_%s_%s"%(emclass.name, emtype.name, emfield.name)
|
|
226
|
+
|
|
227
|
+ ## @brief Generate a columns_fieldtype dict given a rel2type EmField
|
|
228
|
+ # @param em Model : an @ref EditorialModel.model.Model instance
|
|
229
|
+ # @param emfield EmField : and @ref EditorialModel.fields.EmField instance
|
|
230
|
+ def _r2type2cols(self, em, emfield):
|
|
231
|
+ return { f.name: f.fieldtype_instance() for f in em.components('EmField') if f.rel_field_id == emfield.uid }
|
155
|
232
|
|
156
|
|
- ## @brief Generate a columns_fieldtype dict given an EmClass uid
|
|
233
|
+ ## @brief Generate a columns_fieldtype dict given an EmClass
|
157
|
234
|
# @param emclass EmClass : An EmClass instance
|
158
|
235
|
# @return A dict with column name as key and EmFieldType instance as value
|
159
|
236
|
def _class2cols(self, emclass):
|
|
@@ -350,32 +427,12 @@ FOR EACH ROW SET {col_val_list};""".format(
|
350
|
427
|
self._query(trig_q)
|
351
|
428
|
|
352
|
429
|
## @brief Identifier escaping
|
|
430
|
+ # @param idname str : An SQL identifier
|
353
|
431
|
def _idname_escape(self, idname):
|
354
|
432
|
if '`' in idname:
|
355
|
433
|
raise ValueError("Invalid name : '%s'"%idname)
|
356
|
434
|
return '`%s`'%idname
|
357
|
435
|
|
358
|
|
- ## @brief Forge a create table query
|
359
|
|
- # @param table_name str : The name of the table we want to create
|
360
|
|
- # @param colspecs list : List of tuple (fieldname, EmFieldTypes)
|
361
|
|
- # @return A MySQL create table query
|
362
|
|
- #def _create_table_query(self, table_name, colspecs):
|
363
|
|
- # pass
|
364
|
|
-
|
365
|
|
- ## @brief Forge a drop column query
|
366
|
|
- # @param table_name str : The name of the concerned table
|
367
|
|
- # @param colname str : The name of the column we want to drop
|
368
|
|
- # @return A MySQL drop column query
|
369
|
|
- def _drop_column_query(self, table_name, colname):
|
370
|
|
- pass
|
371
|
|
-
|
372
|
|
- ## @brief Forge an add column query
|
373
|
|
- # @param table_name str : The name of the concerned table
|
374
|
|
- # @param colspec tuple : A tuple (colname, EmFieldType)
|
375
|
|
- # @return A MySQL add column query
|
376
|
|
- def _add_colum_query(self, table_name, colspec):
|
377
|
|
- pass
|
378
|
|
-
|
379
|
436
|
## @brief Returns column specs from fieldtype
|
380
|
437
|
# @param emfieldtype EmFieldType : An EmFieldType insance
|
381
|
438
|
# @todo escape default value
|
|
@@ -440,7 +497,8 @@ FOR EACH ROW SET {col_val_list};""".format(
|
440
|
497
|
@property
|
441
|
498
|
def _relation_pk(self):
|
442
|
499
|
return ('id_relation', EditorialModel.fieldtypes.pk.EmFieldType())
|
443
|
|
-
|
|
500
|
+
|
|
501
|
+ ## @brief Returns a dict { colname:fieldtype } of relation table columns
|
444
|
502
|
@property
|
445
|
503
|
def _relation_cols(self):
|
446
|
504
|
from_name = EditorialModel.fieldtypes.generic.GenericFieldType.from_name
|