322e3be0144a113a1b58229556e41f867ed726a5
[app.Builder.js] / Builder / Provider / Database / generate.js
1 //<script type="text/javascript">
2
3 /**
4  * 
5  * Let's see if libgda can be used to generate our Readers for roo...
6  * 
7  * Concept - conect to database..
8  * 
9  * list tables
10  * 
11  * extra schemas..
12  * 
13  * write readers..
14  * 
15  * usage: seed generate.js  '{"DB_NAME":"XXX","USERNAME":"YYY","PASSWORD":"ZZZ","INI":"/path/to/mydb.ini"}'
16  * 
17  */
18 Gda  = imports.gi.Gda;
19 GObject = imports.gi.GObject;
20
21 GLib = imports.gi.GLib;
22
23 console = imports['../../../console.js'];
24 File = imports['../../../File.js'].File;
25 Gda.init();
26
27 var prov = Gda.Config.list_providers ();
28 //print(prov.dump_as_string());
29 var args = Array.prototype.slice.call(Seed.argv);
30 args.shift();args.shift();// remove first 2
31 print(args.length );
32 if (args.length < 1) {
33     var sample = {
34         DB_NAME : "XXX",
35         USERNAME : "YYY",
36         PASSWORD: "ZZZ",
37         INI : "/path/to/mydb.ini",
38     }
39     print("Usage : seed generate.js  '" + JSON.stringify(sample) +"'");
40     Seed.quit();
41 }
42 var cfg = JSON.parse(args[0]);
43
44 var   cnc = Gda.Connection.open_from_string ("MySQL", "DB_NAME=" + cfg.DB_NAME, 
45                                               "USERNAME=" + cfg.USERNAME + ';PASSWORD=' + cfg.PASSWORD,
46                                               Gda.ConnectionOptions.NONE, null);
47
48
49
50                                               
51
52  
53 Gda.DataSelect.prototype.fetchAll = function()
54 {
55     var cols = [];
56     
57     for (var i =0;i < this.get_n_columns(); i++) {
58         cols.push(this.get_column_name(i));
59     }
60     //print(JSON.stringify(cols, null,4));
61     var iter = this.create_iter();
62     var res = [];
63     //print(this.get_n_rows());
64     var _this = this;
65     for (var r = 0; r < this.get_n_rows(); r++) {
66         
67         // single clo..
68         //print("GOT ROW");
69         if (cols.length == 1) {
70             res.push(this.get_value_at(0,r).get_string());
71             continue;
72         }
73         var add = { };
74         
75         cols.forEach(function(n,i) {
76             var val = _this.get_value_at(i,r);
77             var type = GObject.type_name(val.g_type) ;
78             var vs = type == 'GdaBinary' ? val.value.to_string(1024) : val.value;
79             //print(n + " : TYPE: " + GObject.type_name(val.g_type) + " : " + vs);
80             //print (n + '=' + iter.get_value_at(i).value);
81             add[n] = vs;
82         });
83         
84         res.push(add);
85         
86     }
87     return res;
88
89 }
90
91 var map = {
92     'date' : 'date',
93     'datetime' : 'string',
94     'int' : 'int',
95     'bigint' : 'int',
96     'char' : 'int',
97     'tinyint' : 'int',
98     'decimal' : 'float',
99     'float' : 'float',
100     'varchar' : 'string',
101     'text' : 'string',
102     'longtext' : 'string',
103     'mediumtext' : 'string',
104     'enum' : 'string',
105     
106     
107 }
108
109 var ini = { }
110
111 function readIni(fn)
112 {
113     var key_file = new GLib.KeyFile.c_new();
114     if (!key_file.load_from_file (fn , GLib.KeyFileFlags.NONE )) {
115         return;
116     }
117    
118     var groups = key_file.get_groups();
119     groups.forEach(function(g) {
120         ini[g] = {}
121            
122         var keys = key_file.get_keys(g);
123         keys.forEach(function(k) {
124             ini[g][k] = key_file.get_value(g,k);
125         })
126     })
127     
128 }
129 if (File.isFile(cfg.INI)) {
130     if (cfg.INI.match(/links\.ini$/)) {
131         readIni(cfg.INI);
132     } else {
133         readIni(cfg.INI.replace(/\.ini$/, ".links.ini"));
134     }
135 }
136
137 if (File.isDirectory(cfg.INI)) {
138         
139
140     //--- load ini files..
141     // this is very specific.
142     
143     var dirs = File.list( cfg.INI + '/Pman').filter( 
144         function(e) { 
145             if (!File.isDirectory(cfg.INI + '/Pman/' + e + '/DataObjects')) {
146                 return false;
147             }
148             return true;
149         }
150     );
151     
152      
153     dirs.forEach(function(d) {
154         // this currently misses the web.*/Pman/XXXX/DataObjects..
155         var path = cfg.INI + '/Pman/' + d + '/DataObjects';
156          
157         if (!File.isDirectory(path)) {
158             return; //skip
159         }
160         var inis = File.list(path).filter(
161             function(e) { return e.match(/\.links\.ini$/); }
162         );
163         if (!inis.length) {
164             return;
165         }
166         
167         inis.forEach(function(i) {
168             readIni(path + '/' + i); 
169             
170         })
171  
172     });
173     // look at web.XXXX/Pman/XXX/DataObjects/*.ini
174     var inis = File.list(cfg.INI).filter(
175         function(e) { return e.match(/\.links\.ini$/); }
176     )
177     
178      inis.forEach(function(i) {
179         readIni(path + '/' + i); 
180         
181     })
182     
183     
184 }
185 print(JSON.stringify(ini, null,4));
186  //console.dump(ini);
187
188
189  //Seed.quit();
190
191 //GLib.key_file_load_from_file (key_file, String file, KeyFileFlags flags) : Boolean
192
193
194
195  
196
197 var tables = Gda.execute_select_command(cnc, "SHOW TABLES").fetchAll();
198 var readers = [];
199 tables.forEach(function(table) {
200     //print(table);
201     var schema = Gda.execute_select_command(cnc, "DESCRIBE `" + table+'`').fetchAll();
202     var reader = []; 
203     var colmodel = []; 
204     var combofields= [ { name : 'id', type: 'int' } ]; // technically the primary key..
205          
206     var form = {}
207        
208     var firstTxtCol = '';
209     
210     print(JSON.stringify(schema, null,4));
211     
212     schema.forEach(function(e)  {
213         var type = e.Type.match(/([^(]+)\(([^\)]+)\)/);
214         var row  = { }; 
215         if (type) {
216             e.Type = type[1];
217             e.Size = type[2];
218         }
219         
220         
221         
222         row.name = e.Field;
223         
224         
225         if (typeof(map[e.Type]) == 'undefined') {
226            console.dump(e);
227            throw {
228                 name: "ArgumentError", 
229                 message: "Unknown mapping for type : " + e.Type
230             };
231         }
232         row.type = map[e.Type];
233         
234         if (row.type == 'string' && !firstTxtCol.length) {
235             firstTxtCol = row.name;
236         }
237         
238         if (row.type == 'date') {
239             row.dateFormat = 'Y-m-d';
240         }
241         reader.push(row);
242         
243         if (combofields.length == 1 && row.type == 'string') {
244             combofields.push(row);
245         }
246         
247         
248         var title = row.name.replace(/_id/, '').replace(/_/g, ' ');
249         title  = title[0].toUpperCase() + title.substring(1);
250         
251         colmodel.push({
252             "xtype": "ColumnModel",
253             "header": title,
254             "width":  row.type == 'string' ? 200 : 75,
255             "dataIndex": row.name,
256             "|renderer": row.type != 'date' ? 
257                     "function(v) { return String.format('{0}', v); }" :
258                     "function(v) { return String.format('{0}', v ? v.format('d/M/Y') : ''); }" , // special for date
259             "|xns": "Roo.grid",
260             "*prop": "colModel[]"
261         });
262         var xtype = 'TextField';
263         if (row.type == 'number') {
264             xtype = 'NumberField';
265         }
266         if (row.type == 'date') {
267             xtype = 'DateField';
268         }
269         if (e.Type == 'text') {
270             xtype = 'TextArea';
271         }
272         if (e.name == 'id') {
273             xtype = 'Hidden';
274         }
275         // what about booleans.. -> checkboxes..
276         
277         
278         
279         form[row.name] = {
280             fieldLabel : title,
281             name : row.name,
282             width : row.type == 'string' ? 200 : 75,
283             '|xns' : 'Roo.form',
284             xtype : xtype
285         }
286         if (xtype == 'TextArea') {
287             form[row.name].height = 100;
288         }
289         
290         
291     });
292     
293     var combo = {
294         '|xns' : 'Roo.form',
295         xtype: 'ComboBox',
296         allowBlank : 'false',
297         editable : 'false',
298         emptyText : 'Select ' + table,
299         forceSelection : true,
300         listWidth : 400,
301         loadingText: 'Searching...',
302         minChars : 2,
303         pageSize : 20,
304         qtip: 'Select ' + table,
305         selectOnFocus: true,
306         triggerAction : 'all',
307         typeAhead: true,
308         
309         width: 300,
310         
311         
312         
313         tpl : '<div class="x-grid-cell-text x-btn button"><b>{name}</b> </div>', // SET WHEN USED
314         queryParam : '',// SET WHEN USED
315         fieldLabel : table,  // SET WHEN USED
316         valueField : 'id',
317         displayField : '', // SET WHEN USED eg. project_id_name
318         hiddenName : '', // SET WHEN USED eg. project_id
319         name : '', // SET WHEN USED eg. project_id_name
320         items : [
321             {
322                     
323                 '*prop' : 'store',
324                 'xtype' : 'Store',
325                 '|xns' : 'Roo.data',
326                 listeners : {
327                     '|beforeload' : 'function (_self, o)' +
328                     "{\n" +
329                     "    o.params = o.params || {};\n" +
330                     "    // set more here\n" +
331                     "}\n"
332                 },
333                 items : [
334                     {
335                         '*prop' : 'proxy',
336                         'xtype' : 'HttpProxy',
337                         'method' : 'GET',
338                         '|xns' : 'Roo.data',
339                         '|url' : "baseURL + '/Roo/" + table + ".php'",
340                     },
341                     
342                     {
343                         '*prop' : 'reader',
344                         'xtype' : 'JsonReader',
345                         '|xns' : 'Roo.data',
346                         'id' : 'id',
347                         'root' : 'data',
348                         'totalProperty' : 'total',
349                         '|fields' : JSON.stringify(combofields)
350                         
351                     }
352                 ]
353             }
354         ]
355     }
356     
357     
358     
359     
360     //print(JSON.stringify(reader,null,4));
361     readers.push({
362         table : table ,
363         combo : combo,
364         combofields : combofields,
365         reader :  reader,
366         oreader : JSON.parse(JSON.stringify(reader)), // dupe it..
367         colmodel : colmodel,
368         firstTxtCol : firstTxtCol,
369         form : form
370     });
371     
372     //console.dump(schema );
373     
374      
375 });
376
377
378
379 // merge in the linked tables..
380 readers.forEach(function(reader) {
381     if (typeof(ini[reader.table]) == 'undefined') {
382      
383         return;
384     }
385     print("OVERLAY - " + reader.table);
386     // we have a map..
387     for (var col in ini[reader.table]) {
388         var kv = ini[reader.table][col].split(':');
389         var add = readers.filter(function(r) { return r.table == kv[0] })[0];
390         
391         // merge in data (eg. project_id => project_id_*****
392      
393         add.oreader.forEach(function(or) {
394             reader.reader.push({
395                 name : col + '_' + or.name,
396                 type : or.type
397             });
398         });
399         
400         // col is mapped to something..
401         var combofields = add.combofields;
402         if (add.combofields.length < 2) {
403             continue;
404         }
405         if (typeof(reader.form[col]) == 'undefined') {
406             print("missing linked column " + col);
407             continue;
408         }
409         
410         var combofields_name = add.combofields[1].name;
411         var old =   reader.form[col];
412         reader.form[col] = JSON.parse(JSON.stringify(add.combo)); // clone
413         reader.form[col].queryParam  = 'query[' + combofields_name + ']';// SET WHEN USED
414         reader.form[col].fieldLabel = old.fieldLabel;  // SET WHEN USED
415         reader.form[col].hiddenName = old.name; // SET WHEN USED eg. project_id
416         reader.form[col].displayField = combofields_name; // SET WHEN USED eg. project_id
417         reader.form[col].name  = old.name + '_' + combofields_name; // SET WHEN USED eg. project_id_name
418         reader.form[col].tpl = '<div class="x-grid-cell-text x-btn button"><b>{' + combofields_name +'}</b> </div>'; // SET WHEN USED
419         
420              
421     };
422     
423     
424 });
425
426 //readers.forEach(function(reader) {
427 //    delete reader.oreader;
428 //});
429
430  
431
432
433
434 //print(JSON.stringify(readers, null, 4));
435
436 readers.forEach(function(reader) {
437     
438
439     var dir = GLib.get_home_dir() + '/.Builder/Roo.data.JsonReader'; 
440     if (!File.isDirectory(dir)) {
441         File.mkdir(dir);
442     }
443     
444     // READERS
445     print("WRITE: " +  dir + '/' + cfg.DB_NAME + '_' + reader.table + '.json');
446     
447                 
448     var jreader = {
449         '|xns' : 'Roo.data',
450         xtype : "JsonReader",
451         totalProperty : "total",
452         root : "data",
453         '*prop' : "reader",
454         id : 'id', // maybe no..
455         '|fields' :  JSON.stringify(reader.reader, null,4).replace(/"/g,"'")
456     };
457     
458     File.write(
459         dir + '/' + cfg.DB_NAME + '_' + reader.table + '.json',
460         JSON.stringify(jreader, null, 4)
461     )
462     
463     
464     // GRIDS
465     dir = GLib.get_home_dir() + '/.Builder/Roo.GridPanel'; 
466     if (!File.isDirectory(dir)) {
467         File.mkdir(dir);
468     }
469     
470
471     print("WRITE: " +  dir + '/' + cfg.DB_NAME + '_' + reader.table + '.json');
472     
473     File.write(
474         dir + '/' + cfg.DB_NAME + '_' + reader.table + '.json',
475             
476        
477         JSON.stringify({
478             '|xns' : 'Roo',
479             xtype : "GridPanel",
480             "title": reader.table,
481             "fitToframe": true,
482             "fitContainer": true,
483             "tableName": reader.table,
484             "background": true,
485             "listeners": {
486                 "|activate": "function() {\n    _this.panel = this;\n    if (_this.grid) {\n        _this.grid.footer.onClick('first');\n    }\n}"
487             },
488             "items": [
489                 {
490                     "*prop": "grid",
491                     "xtype": "Grid",
492                     "autoExpandColumn": reader.firstTxtCol,
493                     "loadMask": true,
494                     "listeners": {
495                         "|render": "function() \n" +
496                             "{\n" +
497                             "   _this.grid = this; \n" +
498                             "    //_this.dialog = Pman.Dialog.FILL_IN\n" +
499                             "    if (_this.panel.active) {\n" +
500                             "       this.footer.onClick('first');\n" +
501                             "    }\n" +
502                             "}"
503                     },
504                     "|xns": "Roo.grid",
505
506                     "items": [
507                         {
508                             "*prop": "dataSource",
509                             "xtype": "Store",
510                             
511                             "|xns": "Roo.data",
512                             "items": [
513                                 
514                                 {
515                                     "*prop": "proxy",
516                                     "xtype": "HttpProxy",
517                                     "method": "GET",
518                                     "|url": "baseURL + '/Roo/" + reader.table + ".php'",
519                                     "|xns": "Roo.data"
520                                 },
521                                 jreader
522                             ]
523                         },
524                         {
525                             "*prop": "footer",
526                             "xtype": "PagingToolbar",
527                             "pageSize": 25,
528                             "displayInfo": true,
529                             "displayMsg": "Displaying " + reader.table + "{0} - {1} of {2}",
530                             "emptyMsg": "No " + reader.table + " found",
531                             "|xns": "Roo"
532                         },
533                         {
534                             "*prop": "toolbar",
535                             "xtype": "Toolbar",
536                             "|xns": "Roo",
537                             "items": [
538                                 {
539                                     "text": "Add",
540                                     "xtype": "Button",
541                                     "cls": "x-btn-text-icon",
542                                     "|icon": "Roo.rootURL + 'images/default/dd/drop-add.gif'",
543                                     "listeners": {
544                                         "|click": "function()\n"+
545                                             "{\n"+
546                                             "   //yourdialog.show( { id : 0 } , function() {\n"+
547                                             "   //  _this.grid.footer.onClick('first');\n"+
548                                             "   //}); \n"+
549                                             "}\n"
550                                     },
551                                     "|xns": "Roo"
552                                 },
553                                 {
554                                     "text": "Edit",
555                                     "xtype": "Button",
556                                     "cls": "x-btn-text-icon",
557                                     "|icon": "Roo.rootURL + 'images/default/tree/leaf.gif'",
558                                     "listeners": {
559                                         "|click": "function()\n"+
560                                             "{\n"+
561                                             "    var s = _this.grid.getSelectionModel().getSelections();\n"+
562                                             "    if (!s.length || (s.length > 1))  {\n"+
563                                             "        Roo.MessageBox.alert(\"Error\", s.length ? \"Select only one Row\" : \"Select a Row\");\n"+
564                                             "        return;\n"+
565                                             "    }\n"+
566                                             "    \n"+
567                                             "    //_this.dialog.show(s[0].data, function() {\n"+
568                                             "    //    _this.grid.footer.onClick('first');\n"+
569                                             "    //   }); \n"+
570                                             "    \n"+
571                                             "}\n" 
572                                         
573                                     },
574                                     "|xns": "Roo"
575                                 },
576                                 {
577                                     "text": "Delete",
578                                     "cls": "x-btn-text-icon",
579                                     "|icon": "rootURL + '/Pman/templates/images/trash.gif'",
580                                     "xtype": "Button",
581                                     "listeners": {
582                                         "|click": "function()\n"+
583                                             "{\n"+
584                                             "   //Pman.genericDelete(_this, _this.grid.tableName); \n"+
585                                             "}\n"+
586                                             "        "
587                                     },
588                                     "|xns": "Roo"
589                                 }
590                             ]
591                         }, // end toolbar
592                     ].concat( reader.colmodel)
593                 }
594             ]
595             
596             
597         }, null, 4)
598     )
599     
600     /// FORMS..
601     
602     dir = GLib.get_home_dir() + '/.Builder/Roo.form.Form'; 
603     if (!File.isDirectory(dir)) {
604         File.mkdir(dir);
605     }
606     var formElements = [];
607     for (var k in reader.form) {
608         if (k == 'id') { // should really do primary key testing..
609             continue;
610         }
611         formElements.push(reader.form[k]);
612     }
613     formElements.push(reader.form['id']);
614
615     print("WRITE: " +  dir + '/' + cfg.DB_NAME + '_' + reader.table + '.json');
616     
617     File.write(
618         dir + '/' + cfg.DB_NAME + '_' + reader.table + '.json',
619             
620        
621         JSON.stringify({
622             '|xns' : 'Roo.form',
623             xtype : "Form",
624             listeners : {
625                 "|actioncomplete" : "function(_self,action)\n"+
626                     "{\n"+
627                     "    if (action.type == 'setdata') {\n"+
628                     "       //_this.dialog.el.mask(\"Loading\");\n"+
629                     "       //this.load({ method: 'GET', params: { '_id' : _this.data.id }});\n"+
630                     "       return;\n"+
631                     "    }\n"+
632                     "    if (action.type == 'load') {\n"+
633                     "        _this.dialog.el.unmask();\n"+
634                     "        return;\n"+
635                     "    }\n"+
636                     "    if (action.type =='submit') {\n"+
637                     "    \n"+
638                     "        _this.dialog.el.unmask();\n"+
639                     "        _this.dialog.hide();\n"+
640                     "    \n"+
641                     "         if (_this.callback) {\n"+
642                     "            _this.callback.call(_this, _this.form.getValues());\n"+
643                     "         }\n"+
644                     "         _this.form.reset();\n"+
645                     "         return;\n"+
646                     "    }\n"+
647                     "}\n",
648                 
649                 "|rendered" : "function (form)\n"+
650                     "{\n"+
651                     "    _this.form= form;\n"+
652                     "}\n"
653             },
654             method : "POST",
655             style : "margin:10px;",
656             "|url" : "baseURL + '/Roo/" + reader.table + ".php'",
657             items : formElements
658         }, null, 4)
659     );
660             
661             
662    
663    
664    
665      /// COMBO..
666     
667     dir = GLib.get_home_dir() + '/.Builder/Roo.form.ComboBox'; 
668     if (!File.isDirectory(dir)) {
669         File.mkdir(dir);
670     }
671    
672     print("WRITE: " +  dir + '/' + cfg.DB_NAME + '_' + reader.table + '.json');
673     
674     File.write(
675         dir + '/' + cfg.DB_NAME + '_' + reader.table + '.json',
676             
677        
678         JSON.stringify(reader.combo, null, 4)
679     );
680             
681    
682    
683    
684    
685    
686    
687    
688    
689    
690 });              
691
692
693
694