Browse Source

Implements multivalue column

Yann Weber 8 years ago
parent
commit
cb5f2f7460

+ 7
- 9
DataSource/MySQL/fieldtypes.py View File

@@ -17,7 +17,7 @@ import EditorialModel.fieldtypes.rel2type
17 17
 ## @brief Returns column specs from fieldtype
18 18
 # @param emfieldtype EmFieldType : An EmFieldType insance
19 19
 # @todo escape default value
20
-def singlevaluefieldtype_db_init_specs(emfieldtype):
20
+def singlevaluefieldtype_db_init_specs(emfieldtype, noauto_inc = False):
21 21
     colspec = ''
22 22
     if not emfieldtype.nullable:
23 23
         colspec = 'NOT NULL'
@@ -28,7 +28,7 @@ def singlevaluefieldtype_db_init_specs(emfieldtype):
28 28
         else:
29 29
             colspec += emfieldtype.default  # ESCAPE VALUE HERE !!!!
30 30
 
31
-    if emfieldtype.name == 'pk':
31
+    if emfieldtype.name == 'pk' and not noauto_inc:
32 32
         colspec += ' AUTO_INCREMENT'
33 33
 
34 34
     return colspec
@@ -46,11 +46,11 @@ def singlevaluefieldtype_db_init_specs(emfieldtype):
46 46
 #  - the third tuple item is a tuple(column_type, column_spec)
47 47
 # @param fieldtype GenericFieldType : A FieldType instance
48 48
 # @return a tuple (instruction_type, infos)
49
-def fieldtype_db_init(fieldtype):
49
+def fieldtype_db_init(fieldtype, noauto_inc = False):
50 50
     if isinstance(fieldtype, EditorialModel.fieldtypes.rel2type.EmFieldType):
51 51
         return (None, None, None)
52 52
     elif isinstance(fieldtype, SingleValueFieldType):
53
-        res = [ 'column', None, singlevaluefieldtype_db_init_specs(fieldtype) ]
53
+        res = [ 'column', None, singlevaluefieldtype_db_init_specs(fieldtype, noauto_inc) ]
54 54
         # We will create a column
55 55
         if isinstance(fieldtype, EditorialModel.fieldtypes.integer.EmFieldType):
56 56
             res[1] = 'INT'
@@ -66,15 +66,13 @@ def fieldtype_db_init(fieldtype):
66 66
             res[1] = 'INT'
67 67
         else:
68 68
             raise RuntimeError("Unsupported fieldtype : ", fieldtype)
69
-        return tuple(res)
70 69
     elif isinstance(fieldtype, MultiValueFieldType):
71 70
         res = [ 'table', None, None ]
72
-        key_type, _ = fieldtype_db_init(fieldtype.key_fieldtype)
73
-        key_name = fieldtype.keyname
74
-        res[1] = (key_name, key_type)
75
-        res[2] = fieldtype_db_init(fieldtype.value_fieldtype)
71
+        res[1] = (fieldtype.keyname, fieldtype.key_fieldtype)
72
+        res[2] = fieldtype.value_fieldtype
76 73
     else:
77 74
         raise NotImplementedError("Not yet implemented")
75
+    return tuple(res)
78 76
             
79 77
     
80 78
 

+ 50
- 26
DataSource/MySQL/migrationhandler.py View File

@@ -64,6 +64,11 @@ class MysqlMigrationHandler(DummyMigrationHandler):
64 64
         self._create_default_tables(self.drop_if_exists)
65 65
 
66 66
     ## @brief Modify the db given an EM change
67
+    #
68
+    # @note Here we don't care about the relation parameter of _add_column() method because the
69
+    # only case in wich we want to add a field that is linked with the relation table is for rel2type
70
+    # attr creation. The relation parameter is set to True in the add_relationnal_field() method
71
+    # 
67 72
     # @param em model : The EditorialModel.model object to provide the global context
68 73
     # @param uid int : The uid of the change EmComponent
69 74
     # @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.
@@ -120,12 +125,19 @@ class MysqlMigrationHandler(DummyMigrationHandler):
120 125
         pkname, pkftype = self._relation_pk
121 126
 
122 127
         #If not exists create a relational table
123
-        self._create_table(tname, pkname, pkftype, self.db_engine, if_exists='nothing')
128
+        self._create_table(
129
+                            tname,
130
+                            pkname,
131
+                            pkftype,
132
+                            self.db_engine,
133
+                            if_exists='nothing',
134
+                            noauto_inc = True,
135
+                        )
124 136
         #Add a foreign key if wanted
125 137
         if self.foreign_keys:
126 138
             self._add_fk(tname, utils.common_tables['relation'], pkname, pkname)
127 139
         #Add the column
128
-        self._add_column(tname, emfield.name, emfield.fieldtype_instance())
140
+        self._add_column(tname, emfield.name, emfield.fieldtype_instance(), relation=True)
129 141
         #Update table triggers
130 142
         self._generate_triggers(tname, self._r2type2cols(edmod, r2tf))
131 143
 
@@ -175,9 +187,13 @@ class MysqlMigrationHandler(DummyMigrationHandler):
175 187
             raise ValueError("The given uid is not an EmClass uid")
176 188
         pkname, pktype = self._object_pk
177 189
         table_name = utils.object_table_name(emclass.name)
178
-
179
-        self._create_table(table_name, pkname, pktype, engine=engine)
180
-
190
+        self._create_table(
191
+                            table_name,
192
+                            pkname,
193
+                            pktype,
194
+                            engine=engine,
195
+                            noauto_inc = True
196
+        )
181 197
         if self.foreign_keys:
182 198
             self._add_fk(table_name, utils.common_tables['object'], pkname, pkname)
183 199
 
@@ -258,7 +274,7 @@ class MysqlMigrationHandler(DummyMigrationHandler):
258 274
         cols = {fname: self._common_field_to_ftype(fname) for fname in EditorialModel.classtypes.common_fields}
259 275
         for fname, ftype in cols.items():
260 276
             if fname != pk_name:
261
-                self._add_column(tname, fname, ftype)
277
+                self._add_column(tname, fname, ftype, relation=False)
262 278
         #Creating triggers
263 279
         self._generate_triggers(tname, cols)
264 280
         object_tname = tname
@@ -269,7 +285,7 @@ class MysqlMigrationHandler(DummyMigrationHandler):
269 285
         self._create_table(tname, pk_name, pk_ftype, engine=self.db_engine, if_exists=if_exists)
270 286
         #Adding columns
271 287
         for fname, ftype in self._relation_cols.items():
272
-            self._add_column(tname, fname, ftype)
288
+            self._add_column(tname, fname, ftype, relation=True)
273 289
         #Creating triggers
274 290
         self._generate_triggers(tname, self._relation_cols)
275 291
 
@@ -297,7 +313,8 @@ class MysqlMigrationHandler(DummyMigrationHandler):
297 313
     # @param engine str : The engine to use with this table
298 314
     # @param charset str : The charset of this table
299 315
     # @param if_exist str : takes values in ['nothing', 'drop']
300
-    def _create_table(self, table_name, pk_name, pk_ftype, engine, charset='utf8', if_exists='nothing'):
316
+    # @param noauto_inc bool : if True forbids autoincrement on PK
317
+    def _create_table(self, table_name, pk_name, pk_ftype, engine, charset='utf8', if_exists='nothing', noauto_inc = False):
301 318
         #Escaped table name
302 319
         etname = utils.escape_idname(table_name)
303 320
         if not isinstance(pk_name, tuple):
@@ -308,17 +325,17 @@ class MysqlMigrationHandler(DummyMigrationHandler):
308 325
             raise ValueError("You have to give as many pk_name as pk_ftype")
309 326
         
310 327
         pk_instr_cols = ''
311
-        pk_format = '{pk_name} {pk_type} {pk_specs},'
328
+        pk_format = "{pk_name} {pk_type} {pk_specs},\n"
312 329
         for i in range(len(pk_name)):
313
-            instr_type, pk_type, pk_specs = fieldtypes_utils.fieldtype_db_init(pk_ftype[i])
330
+            instr_type, pk_type, pk_specs = fieldtypes_utils.fieldtype_db_init(pk_ftype[i], noauto_inc)
314 331
             if instr_type != 'column':
315 332
                 raise ValueError("Migration handler doesn't support MultiValueFieldType as primary keys")
316 333
             pk_instr_cols += pk_format.format(
317
-                                                pk_name = pk_name[i],
334
+                                                pk_name = utils.escape_idname(pk_name[i]),
318 335
                                                 pk_type = pk_type,
319 336
                                                 pk_specs = pk_specs
320 337
                                             )
321
-        pk_instr_cols += "\nPRIMARY KEY("+(','.join([utils.escape_idname(pkn) for pkn in pk_name]))+')\n'
338
+        pk_instr_cols += "PRIMARY KEY("+(','.join([utils.escape_idname(pkn) for pkn in pk_name]))+')'
322 339
 
323 340
         if if_exists == 'drop':
324 341
             self._query("""DROP TABLE IF EXISTS {table_name};""".format(table_name=etname))
@@ -337,19 +354,21 @@ class MysqlMigrationHandler(DummyMigrationHandler):
337 354
     # @param table_name str : The table name
338 355
     # @param col_name str : The columns name
339 356
     # @param col_fieldtype EmFieldype the fieldtype
357
+    # @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 )
340 358
     # @return True if the column was added else return False
341
-    def _add_column(self, table_name, col_name, col_fieldtype, drop_if_exists=False):
342
-
359
+    def _add_column(self, table_name, col_name, col_fieldtype, drop_if_exists=False, relation=False):
343 360
         instr, col_type, col_specs = fieldtypes_utils.fieldtype_db_init(col_fieldtype)
344 361
 
345 362
         if instr == 'table':
346 363
             # multivalue field. We are not going to add a column in this table
347 364
             # but in corresponding multivalue table
348 365
             self._add_column_multivalue(
349
-                                            table_name,
366
+                                            ref_table_name = table_name,
350 367
                                             key_infos = col_type,
351
-                                            column_infos = (col_name, col_specs)
368
+                                            column_infos = (col_name, col_specs),
369
+                                            relation = relation
352 370
                                         )
371
+            return True
353 372
 
354 373
         col_name = utils.column_name(col_name)
355 374
 
@@ -414,21 +433,25 @@ ADD COLUMN {col_name} {col_type} {col_specs};"""
414 433
     # @param ref_table_name str : Referenced table name
415 434
     # @param key_infos tuple : tuple(key_name, key_fieldtype)
416 435
     # @param column_infos tuple : tuple(col_name, col_fieldtype)
417
-    def _add_column_multivalue(ref_table_name, key_info, column_infos):
436
+    def _add_column_multivalue(self, ref_table_name, key_infos, column_infos, relation):
418 437
         key_name, key_ftype = key_infos
419 438
         col_name, col_ftype = column_infos
420 439
         table_name = utils.multivalue_table_name(ref_table_name, key_name)
440
+        if relation:
441
+            pk_infos = self._relation_pk
442
+        else:
443
+            pk_infos = self._object_pk
421 444
         # table creation
422 445
         self._create_table(
423
-                            table_name,
424
-                            key_name,
425
-                            key_ftype,
426
-                            self.db_engine,
427
-                            if_exists = 'nothing'
446
+                            table_name = table_name,
447
+                            pk_name = (key_name, pk_infos[0]),
448
+                            pk_ftype = (key_ftype, pk_infos[1]),
449
+                            engine = self.db_engine,
450
+                            if_exists = 'nothing',
451
+                            noauto_inc = True
428 452
         )
429 453
         # with FK
430
-        self._del_fk(table_name, dst_table_name)
431
-        self._add_fk(table_name, dst_table_name, key_name, utils._object_pk[0])
454
+        self._add_fk(table_name, ref_table_name, pk_infos[0], pk_infos[0])
432 455
         # adding the column
433 456
         self._add_column(table_name, col_name, col_ftype)
434 457
 
@@ -465,12 +488,13 @@ FOREIGN KEY ({src_col}) references {dst_table}({dst_col});""".format(
465 488
     # @warning fails silently
466 489
     def _del_fk(self, src_table_name, dst_table_name, fk_name=None):
467 490
         if fk_name is None:
468
-            fk_name = utils.escape_idname(utils.get_fk_name(src_table_name, dst_table_name))
491
+            fk_name = utils.get_fk_name(src_table_name, dst_table_name)
492
+        fk_name = utils.escape_idname(fk_name)
469 493
         try:
470 494
             self._query("""ALTER TABLE {src_table}
471 495
 DROP FOREIGN KEY {fk_name}""".format(
472 496
     src_table=utils.escape_idname(src_table_name),
473
-    fk_name=utils.escape_idname(fk_name)
497
+    fk_name=fk_name
474 498
 ))
475 499
         except self._dbmodule.err.InternalError:
476 500
             # If the FK don't exists we do not care

+ 1
- 1
EditorialModel/fieldtypes/i18n.py View File

@@ -3,7 +3,7 @@
3 3
 from .generic import MultiValueFieldType
4 4
 from . import char
5 5
 
6
-class EmFieldType(MutliValueFieldType):
6
+class EmFieldType(MultiValueFieldType):
7 7
     
8 8
     help = 'Fieldtype designed to handle translations'
9 9
     

+ 2
- 7
EditorialModel/test/me.json View File

@@ -24,17 +24,14 @@
24 24
   "string": "{\"fre\": \"Personnes\"}"
25 25
  },
26 26
  "4": {
27
-  "nullable": true,
28 27
   "date_update": "Fri Oct 16 11:05:04 2015",
29
-  "optional": false,
30 28
   "icon": "0",
31
-  "uniq": false,
32 29
   "component": "EmField",
33 30
   "string": "{\"fre\": \"Titre\"}",
34 31
   "class_id": 1,
35 32
   "date_create": "Fri Oct 16 11:05:04 2015",
36 33
   "rank": 1,
37
-  "fieldtype": "char",
34
+  "fieldtype": "i18n",
38 35
   "help_text": "",
39 36
   "internal": false,
40 37
   "rel_field_id": null,
@@ -77,17 +74,15 @@
77 74
   "sortcolumn": "rank"
78 75
  },
79 76
  "7": {
80
-  "nullable": true,
81 77
   "date_update": "Fri Oct 16 11:05:04 2015",
82 78
   "optional": true,
83 79
   "icon": "0",
84
-  "uniq": false,
85 80
   "component": "EmField",
86 81
   "string": "{\"fre\": \"Sous-titre\"}",
87 82
   "class_id": 1,
88 83
   "date_create": "Fri Oct 16 11:05:04 2015",
89 84
   "rank": 2,
90
-  "fieldtype": "char",
85
+  "fieldtype": "i18n",
91 86
   "help_text": "",
92 87
   "internal": false,
93 88
   "rel_field_id": null,

Loading…
Cancel
Save