Browse Source

Implements multivalue column

Yann Weber 8 years ago
parent
commit
cb5f2f7460

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

17
 ## @brief Returns column specs from fieldtype
17
 ## @brief Returns column specs from fieldtype
18
 # @param emfieldtype EmFieldType : An EmFieldType insance
18
 # @param emfieldtype EmFieldType : An EmFieldType insance
19
 # @todo escape default value
19
 # @todo escape default value
20
-def singlevaluefieldtype_db_init_specs(emfieldtype):
20
+def singlevaluefieldtype_db_init_specs(emfieldtype, noauto_inc = False):
21
     colspec = ''
21
     colspec = ''
22
     if not emfieldtype.nullable:
22
     if not emfieldtype.nullable:
23
         colspec = 'NOT NULL'
23
         colspec = 'NOT NULL'
28
         else:
28
         else:
29
             colspec += emfieldtype.default  # ESCAPE VALUE HERE !!!!
29
             colspec += emfieldtype.default  # ESCAPE VALUE HERE !!!!
30
 
30
 
31
-    if emfieldtype.name == 'pk':
31
+    if emfieldtype.name == 'pk' and not noauto_inc:
32
         colspec += ' AUTO_INCREMENT'
32
         colspec += ' AUTO_INCREMENT'
33
 
33
 
34
     return colspec
34
     return colspec
46
 #  - the third tuple item is a tuple(column_type, column_spec)
46
 #  - the third tuple item is a tuple(column_type, column_spec)
47
 # @param fieldtype GenericFieldType : A FieldType instance
47
 # @param fieldtype GenericFieldType : A FieldType instance
48
 # @return a tuple (instruction_type, infos)
48
 # @return a tuple (instruction_type, infos)
49
-def fieldtype_db_init(fieldtype):
49
+def fieldtype_db_init(fieldtype, noauto_inc = False):
50
     if isinstance(fieldtype, EditorialModel.fieldtypes.rel2type.EmFieldType):
50
     if isinstance(fieldtype, EditorialModel.fieldtypes.rel2type.EmFieldType):
51
         return (None, None, None)
51
         return (None, None, None)
52
     elif isinstance(fieldtype, SingleValueFieldType):
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
         # We will create a column
54
         # We will create a column
55
         if isinstance(fieldtype, EditorialModel.fieldtypes.integer.EmFieldType):
55
         if isinstance(fieldtype, EditorialModel.fieldtypes.integer.EmFieldType):
56
             res[1] = 'INT'
56
             res[1] = 'INT'
66
             res[1] = 'INT'
66
             res[1] = 'INT'
67
         else:
67
         else:
68
             raise RuntimeError("Unsupported fieldtype : ", fieldtype)
68
             raise RuntimeError("Unsupported fieldtype : ", fieldtype)
69
-        return tuple(res)
70
     elif isinstance(fieldtype, MultiValueFieldType):
69
     elif isinstance(fieldtype, MultiValueFieldType):
71
         res = [ 'table', None, None ]
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
     else:
73
     else:
77
         raise NotImplementedError("Not yet implemented")
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
         self._create_default_tables(self.drop_if_exists)
64
         self._create_default_tables(self.drop_if_exists)
65
 
65
 
66
     ## @brief Modify the db given an EM change
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
     # @param em model : The EditorialModel.model object to provide the global context
72
     # @param em model : The EditorialModel.model object to provide the global context
68
     # @param uid int : The uid of the change EmComponent
73
     # @param uid int : The uid of the change EmComponent
69
     # @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.
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
         pkname, pkftype = self._relation_pk
125
         pkname, pkftype = self._relation_pk
121
 
126
 
122
         #If not exists create a relational table
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
         #Add a foreign key if wanted
136
         #Add a foreign key if wanted
125
         if self.foreign_keys:
137
         if self.foreign_keys:
126
             self._add_fk(tname, utils.common_tables['relation'], pkname, pkname)
138
             self._add_fk(tname, utils.common_tables['relation'], pkname, pkname)
127
         #Add the column
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
         #Update table triggers
141
         #Update table triggers
130
         self._generate_triggers(tname, self._r2type2cols(edmod, r2tf))
142
         self._generate_triggers(tname, self._r2type2cols(edmod, r2tf))
131
 
143
 
175
             raise ValueError("The given uid is not an EmClass uid")
187
             raise ValueError("The given uid is not an EmClass uid")
176
         pkname, pktype = self._object_pk
188
         pkname, pktype = self._object_pk
177
         table_name = utils.object_table_name(emclass.name)
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
         if self.foreign_keys:
197
         if self.foreign_keys:
182
             self._add_fk(table_name, utils.common_tables['object'], pkname, pkname)
198
             self._add_fk(table_name, utils.common_tables['object'], pkname, pkname)
183
 
199
 
258
         cols = {fname: self._common_field_to_ftype(fname) for fname in EditorialModel.classtypes.common_fields}
274
         cols = {fname: self._common_field_to_ftype(fname) for fname in EditorialModel.classtypes.common_fields}
259
         for fname, ftype in cols.items():
275
         for fname, ftype in cols.items():
260
             if fname != pk_name:
276
             if fname != pk_name:
261
-                self._add_column(tname, fname, ftype)
277
+                self._add_column(tname, fname, ftype, relation=False)
262
         #Creating triggers
278
         #Creating triggers
263
         self._generate_triggers(tname, cols)
279
         self._generate_triggers(tname, cols)
264
         object_tname = tname
280
         object_tname = tname
269
         self._create_table(tname, pk_name, pk_ftype, engine=self.db_engine, if_exists=if_exists)
285
         self._create_table(tname, pk_name, pk_ftype, engine=self.db_engine, if_exists=if_exists)
270
         #Adding columns
286
         #Adding columns
271
         for fname, ftype in self._relation_cols.items():
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
         #Creating triggers
289
         #Creating triggers
274
         self._generate_triggers(tname, self._relation_cols)
290
         self._generate_triggers(tname, self._relation_cols)
275
 
291
 
297
     # @param engine str : The engine to use with this table
313
     # @param engine str : The engine to use with this table
298
     # @param charset str : The charset of this table
314
     # @param charset str : The charset of this table
299
     # @param if_exist str : takes values in ['nothing', 'drop']
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
         #Escaped table name
318
         #Escaped table name
302
         etname = utils.escape_idname(table_name)
319
         etname = utils.escape_idname(table_name)
303
         if not isinstance(pk_name, tuple):
320
         if not isinstance(pk_name, tuple):
308
             raise ValueError("You have to give as many pk_name as pk_ftype")
325
             raise ValueError("You have to give as many pk_name as pk_ftype")
309
         
326
         
310
         pk_instr_cols = ''
327
         pk_instr_cols = ''
311
-        pk_format = '{pk_name} {pk_type} {pk_specs},'
328
+        pk_format = "{pk_name} {pk_type} {pk_specs},\n"
312
         for i in range(len(pk_name)):
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
             if instr_type != 'column':
331
             if instr_type != 'column':
315
                 raise ValueError("Migration handler doesn't support MultiValueFieldType as primary keys")
332
                 raise ValueError("Migration handler doesn't support MultiValueFieldType as primary keys")
316
             pk_instr_cols += pk_format.format(
333
             pk_instr_cols += pk_format.format(
317
-                                                pk_name = pk_name[i],
334
+                                                pk_name = utils.escape_idname(pk_name[i]),
318
                                                 pk_type = pk_type,
335
                                                 pk_type = pk_type,
319
                                                 pk_specs = pk_specs
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
         if if_exists == 'drop':
340
         if if_exists == 'drop':
324
             self._query("""DROP TABLE IF EXISTS {table_name};""".format(table_name=etname))
341
             self._query("""DROP TABLE IF EXISTS {table_name};""".format(table_name=etname))
337
     # @param table_name str : The table name
354
     # @param table_name str : The table name
338
     # @param col_name str : The columns name
355
     # @param col_name str : The columns name
339
     # @param col_fieldtype EmFieldype the fieldtype
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
     # @return True if the column was added else return False
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
         instr, col_type, col_specs = fieldtypes_utils.fieldtype_db_init(col_fieldtype)
360
         instr, col_type, col_specs = fieldtypes_utils.fieldtype_db_init(col_fieldtype)
344
 
361
 
345
         if instr == 'table':
362
         if instr == 'table':
346
             # multivalue field. We are not going to add a column in this table
363
             # multivalue field. We are not going to add a column in this table
347
             # but in corresponding multivalue table
364
             # but in corresponding multivalue table
348
             self._add_column_multivalue(
365
             self._add_column_multivalue(
349
-                                            table_name,
366
+                                            ref_table_name = table_name,
350
                                             key_infos = col_type,
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
         col_name = utils.column_name(col_name)
373
         col_name = utils.column_name(col_name)
355
 
374
 
414
     # @param ref_table_name str : Referenced table name
433
     # @param ref_table_name str : Referenced table name
415
     # @param key_infos tuple : tuple(key_name, key_fieldtype)
434
     # @param key_infos tuple : tuple(key_name, key_fieldtype)
416
     # @param column_infos tuple : tuple(col_name, col_fieldtype)
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
         key_name, key_ftype = key_infos
437
         key_name, key_ftype = key_infos
419
         col_name, col_ftype = column_infos
438
         col_name, col_ftype = column_infos
420
         table_name = utils.multivalue_table_name(ref_table_name, key_name)
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
         # table creation
444
         # table creation
422
         self._create_table(
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
         # with FK
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
         # adding the column
455
         # adding the column
433
         self._add_column(table_name, col_name, col_ftype)
456
         self._add_column(table_name, col_name, col_ftype)
434
 
457
 
465
     # @warning fails silently
488
     # @warning fails silently
466
     def _del_fk(self, src_table_name, dst_table_name, fk_name=None):
489
     def _del_fk(self, src_table_name, dst_table_name, fk_name=None):
467
         if fk_name is None:
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
         try:
493
         try:
470
             self._query("""ALTER TABLE {src_table}
494
             self._query("""ALTER TABLE {src_table}
471
 DROP FOREIGN KEY {fk_name}""".format(
495
 DROP FOREIGN KEY {fk_name}""".format(
472
     src_table=utils.escape_idname(src_table_name),
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
         except self._dbmodule.err.InternalError:
499
         except self._dbmodule.err.InternalError:
476
             # If the FK don't exists we do not care
500
             # If the FK don't exists we do not care

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

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

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

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

Loading…
Cancel
Save