Builder/Provider/Database/generate.js
[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     print(JSON.stringify(dirs, null,4));
153     Seed.quit();
154     dirs.forEach(function(d) {
155         // this currently misses the web.*/Pman/XXXX/DataObjects..
156         var path = GLib.get_home_dir() + '/gitlive/' + d + '/DataObjects';
157         if (!File.isDirectory(path)) {
158             path = GLib.get_home_dir() + '/gitlive/' + d + '/Pman/DataObjects';
159         }
160         
161         if (!File.isDirectory(path)) {
162             return; //skip
163         }
164         var inis = File.list(path).filter(
165             function(e) { return e.match(/\.links\.ini$/); }
166         );
167         if (!inis.length) {
168             return;
169         }
170         
171         inis.forEach(function(i) {
172             readIni(path + '/' + i); 
173             
174         })
175  
176     });
177     // look at web.XXXX/Pman/XXX/DataObjects/*.ini
178     var inis = File.list(cfg.INI).filter(
179         function(e) { return e.match(/\.links\.ini$/); }
180     )
181     
182      inis.forEach(function(i) {
183         readIni(path + '/' + i); 
184         
185     })
186     
187     
188 }
189 print(JSON.stringify(ini, null,4));
190  //console.dump(ini);
191
192
193  //Seed.quit();
194
195 //GLib.key_file_load_from_file (key_file, String file, KeyFileFlags flags) : Boolean
196
197
198
199  
200
201 var tables = Gda.execute_select_command(cnc, "SHOW TABLES").fetchAll();
202 var readers = [];
203 tables.forEach(function(table) {
204     //print(table);
205     var schema = Gda.execute_select_command(cnc, "DESCRIBE `" + table+'`').fetchAll();
206     var reader = []; 
207     var colmodel = []; 
208     var combofields= [ { name : 'id', type: 'int' } ]; // technically the primary key..
209          
210     var form = {}
211        
212     var firstTxtCol = '';
213     
214     //print(JSON.stringify(schema, null,4));
215     
216     schema.forEach(function(e)  {
217         var type = e.Type.match(/([^(]+)\(([^\)]+)\)/);
218         var row  = { }; 
219         if (type) {
220             e.Type = type[1];
221             e.Size = type[2];
222         }
223         
224         
225         
226         row.name = e.Field;
227         
228         
229         if (typeof(map[e.Type]) == 'undefined') {
230            console.dump(e);
231            throw {
232                 name: "ArgumentError", 
233                 message: "Unknown mapping for type : " + e.Type
234             };
235         }
236         row.type = map[e.Type];
237         
238         if (row.type == 'string' && !firstTxtCol.length) {
239             firstTxtCol = row.name;
240         }
241         
242         if (row.type == 'date') {
243             row.dateFormat = 'Y-m-d';
244         }
245         reader.push(row);
246         
247         if (combofields.length == 1 && row.type == 'string') {
248             combofields.push(row);
249         }
250         
251         
252         var title = row.name.replace(/_id/, '').replace(/_/g, ' ');
253         title  = title[0].toUpperCase() + title.substring(1);
254         
255         colmodel.push({
256             "xtype": "ColumnModel",
257             "header": title,
258             "width":  row.type == 'string' ? 200 : 75,
259             "dataIndex": row.name,
260             "|renderer": row.type != 'date' ? 
261                     "function(v) { return String.format('{0}', v); }" :
262                     "function(v) { return String.format('{0}', v ? v.format('d/M/Y') : ''); }" , // special for date
263             "|xns": "Roo.grid",
264             "*prop": "colModel[]"
265         });
266         var xtype = 'TextField';
267         if (row.type == 'number') {
268             xtype = 'NumberField';
269         }
270         if (row.type == 'date') {
271             xtype = 'DateField';
272         }
273         if (e.Type == 'text') {
274             xtype = 'TextArea';
275         }
276         if (e.name == 'id') {
277             xtype = 'Hidden';
278         }
279         // what about booleans.. -> checkboxes..
280         
281         
282         
283         form[row.name] = {
284             fieldLabel : title,
285             name : row.name,
286             width : row.type == 'string' ? 200 : 75,
287             '|xns' : 'Roo.form',
288             xtype : xtype
289         }
290         if (xtype == 'TextArea') {
291             form[row.name].height = 100;
292         }
293         
294         
295     });
296     
297     var combo = {
298         '|xns' : 'Roo.form',
299         xtype: 'ComboBox',
300         allowBlank : 'false',
301         editable : 'false',
302         emptyText : 'Select ' + table,
303         forceSelection : true,
304         listWidth : 400,
305         loadingText: 'Searching...',
306         minChars : 2,
307         pageSize : 20,
308         qtip: 'Select ' + table,
309         selectOnFocus: true,
310         triggerAction : 'all',
311         typeAhead: true,
312         
313         width: 300,
314         
315         
316         
317         tpl : '<div class="x-grid-cell-text x-btn button"><b>{name}</b> </div>', // SET WHEN USED
318         queryParam : '',// SET WHEN USED
319         fieldLabel : table,  // SET WHEN USED
320         valueField : 'id',
321         displayField : '', // SET WHEN USED eg. project_id_name
322         hiddenName : '', // SET WHEN USED eg. project_id
323         name : '', // SET WHEN USED eg. project_id_name
324         items : [
325             {
326                     
327                 '*prop' : 'store',
328                 'xtype' : 'Store',
329                 '|xns' : 'Roo.data',
330                 listeners : {
331                     '|beforeload' : 'function (_self, o)' +
332                     "{\n" +
333                     "    o.params = o.params || {};\n" +
334                     "    // set more here\n" +
335                     "}\n"
336                 },
337                 items : [
338                     {
339                         '*prop' : 'proxy',
340                         'xtype' : 'HttpProxy',
341                         'method' : 'GET',
342                         '|xns' : 'Roo.data',
343                         '|url' : "baseURL + '/Roo/" + table + ".php'",
344                     },
345                     
346                     {
347                         '*prop' : 'reader',
348                         'xtype' : 'JsonReader',
349                         '|xns' : 'Roo.data',
350                         'id' : 'id',
351                         'root' : 'data',
352                         'totalProperty' : 'total',
353                         '|fields' : JSON.stringify(combofields)
354                         
355                     }
356                 ]
357             }
358         ]
359     }
360     
361     
362     
363     
364     //print(JSON.stringify(reader,null,4));
365     readers.push({
366         table : table ,
367         combo : combo,
368         combofields : combofields,
369         reader :  reader,
370         oreader : JSON.parse(JSON.stringify(reader)), // dupe it..
371         colmodel : colmodel,
372         firstTxtCol : firstTxtCol,
373         form : form
374     });
375     
376     //console.dump(schema );
377     
378      
379 });
380
381
382
383 // merge in the linked tables..
384 readers.forEach(function(reader) {
385     if (typeof(ini[reader.table]) == 'undefined') {
386      
387         return;
388     }
389     print("OVERLAY - " + reader.table);
390     // we have a map..
391     for (var col in ini[reader.table]) {
392         var kv = ini[reader.table][col].split(':');
393         var add = readers.filter(function(r) { return r.table == kv[0] })[0];
394         
395         // merge in data (eg. project_id => project_id_*****
396      
397         add.oreader.forEach(function(or) {
398             reader.reader.push({
399                 name : col + '_' + or.name,
400                 type : or.type
401             });
402         });
403         
404         // col is mapped to something..
405         var combofields = add.combofields;
406         if (add.combofields.length < 2) {
407             continue;
408         }
409         if (typeof(reader.form[col]) == 'undefined') {
410             print("missing linked column " + col);
411             continue;
412         }
413         
414         var combofields_name = add.combofields[1].name;
415         var old =   reader.form[col];
416         reader.form[col] = JSON.parse(JSON.stringify(add.combo)); // clone
417         reader.form[col].queryParam  = 'query[' + combofields_name + ']';// SET WHEN USED
418         reader.form[col].fieldLabel = old.fieldLabel;  // SET WHEN USED
419         reader.form[col].hiddenName = old.name; // SET WHEN USED eg. project_id
420         reader.form[col].displayField = combofields_name; // SET WHEN USED eg. project_id
421         reader.form[col].name  = old.name + '_' + combofields_name; // SET WHEN USED eg. project_id_name
422         reader.form[col].tpl = '<div class="x-grid-cell-text x-btn button"><b>{' + combofields_name +'}</b> </div>'; // SET WHEN USED
423         
424              
425     };
426     
427     
428 });
429
430 //readers.forEach(function(reader) {
431 //    delete reader.oreader;
432 //});
433
434  
435
436
437
438 //print(JSON.stringify(readers, null, 4));
439
440 readers.forEach(function(reader) {
441     
442
443     var dir = GLib.get_home_dir() + '/.Builder/Roo.data.JsonReader'; 
444     if (!File.isDirectory(dir)) {
445         File.mkdir(dir);
446     }
447     
448     // READERS
449     print("WRITE: " +  dir + '/' + cfg.DB_NAME + '_' + reader.table + '.json');
450     
451                 
452     var jreader = {
453         '|xns' : 'Roo.data',
454         xtype : "JsonReader",
455         totalProperty : "total",
456         root : "data",
457         '*prop' : "reader",
458         id : 'id', // maybe no..
459         '|fields' :  JSON.stringify(reader.reader, null,4).replace(/"/g,"'")
460     };
461     
462     File.write(
463         dir + '/' + cfg.DB_NAME + '_' + reader.table + '.json',
464         JSON.stringify(jreader, null, 4)
465     )
466     
467     
468     // GRIDS
469     dir = GLib.get_home_dir() + '/.Builder/Roo.GridPanel'; 
470     if (!File.isDirectory(dir)) {
471         File.mkdir(dir);
472     }
473     
474
475     print("WRITE: " +  dir + '/' + cfg.DB_NAME + '_' + reader.table + '.json');
476     
477     File.write(
478         dir + '/' + cfg.DB_NAME + '_' + reader.table + '.json',
479             
480        
481         JSON.stringify({
482             '|xns' : 'Roo',
483             xtype : "GridPanel",
484             "title": reader.table,
485             "fitToframe": true,
486             "fitContainer": true,
487             "tableName": reader.table,
488             "background": true,
489             "listeners": {
490                 "|activate": "function() {\n    _this.panel = this;\n    if (_this.grid) {\n        _this.grid.footer.onClick('first');\n    }\n}"
491             },
492             "items": [
493                 {
494                     "*prop": "grid",
495                     "xtype": "Grid",
496                     "autoExpandColumn": reader.firstTxtCol,
497                     "loadMask": true,
498                     "listeners": {
499                         "|render": "function() \n" +
500                             "{\n" +
501                             "   _this.grid = this; \n" +
502                             "    //_this.dialog = Pman.Dialog.FILL_IN\n" +
503                             "    if (_this.panel.active) {\n" +
504                             "       this.footer.onClick('first');\n" +
505                             "    }\n" +
506                             "}"
507                     },
508                     "|xns": "Roo.grid",
509
510                     "items": [
511                         {
512                             "*prop": "dataSource",
513                             "xtype": "Store",
514                             
515                             "|xns": "Roo.data",
516                             "items": [
517                                 
518                                 {
519                                     "*prop": "proxy",
520                                     "xtype": "HttpProxy",
521                                     "method": "GET",
522                                     "|url": "baseURL + '/Roo/" + reader.table + ".php'",
523                                     "|xns": "Roo.data"
524                                 },
525                                 jreader
526                             ]
527                         },
528                         {
529                             "*prop": "footer",
530                             "xtype": "PagingToolbar",
531                             "pageSize": 25,
532                             "displayInfo": true,
533                             "displayMsg": "Displaying " + reader.table + "{0} - {1} of {2}",
534                             "emptyMsg": "No " + reader.table + " found",
535                             "|xns": "Roo"
536                         },
537                         {
538                             "*prop": "toolbar",
539                             "xtype": "Toolbar",
540                             "|xns": "Roo",
541                             "items": [
542                                 {
543                                     "text": "Add",
544                                     "xtype": "Button",
545                                     "cls": "x-btn-text-icon",
546                                     "|icon": "Roo.rootURL + 'images/default/dd/drop-add.gif'",
547                                     "listeners": {
548                                         "|click": "function()\n"+
549                                             "{\n"+
550                                             "   //yourdialog.show( { id : 0 } , function() {\n"+
551                                             "   //  _this.grid.footer.onClick('first');\n"+
552                                             "   //}); \n"+
553                                             "}\n"
554                                     },
555                                     "|xns": "Roo"
556                                 },
557                                 {
558                                     "text": "Edit",
559                                     "xtype": "Button",
560                                     "cls": "x-btn-text-icon",
561                                     "|icon": "Roo.rootURL + 'images/default/tree/leaf.gif'",
562                                     "listeners": {
563                                         "|click": "function()\n"+
564                                             "{\n"+
565                                             "    var s = _this.grid.getSelectionModel().getSelections();\n"+
566                                             "    if (!s.length || (s.length > 1))  {\n"+
567                                             "        Roo.MessageBox.alert(\"Error\", s.length ? \"Select only one Row\" : \"Select a Row\");\n"+
568                                             "        return;\n"+
569                                             "    }\n"+
570                                             "    \n"+
571                                             "    //_this.dialog.show(s[0].data, function() {\n"+
572                                             "    //    _this.grid.footer.onClick('first');\n"+
573                                             "    //   }); \n"+
574                                             "    \n"+
575                                             "}\n" 
576                                         
577                                     },
578                                     "|xns": "Roo"
579                                 },
580                                 {
581                                     "text": "Delete",
582                                     "cls": "x-btn-text-icon",
583                                     "|icon": "rootURL + '/Pman/templates/images/trash.gif'",
584                                     "xtype": "Button",
585                                     "listeners": {
586                                         "|click": "function()\n"+
587                                             "{\n"+
588                                             "   //Pman.genericDelete(_this, _this.grid.tableName); \n"+
589                                             "}\n"+
590                                             "        "
591                                     },
592                                     "|xns": "Roo"
593                                 }
594                             ]
595                         }, // end toolbar
596                     ].concat( reader.colmodel)
597                 }
598             ]
599             
600             
601         }, null, 4)
602     )
603     
604     /// FORMS..
605     
606     dir = GLib.get_home_dir() + '/.Builder/Roo.form.Form'; 
607     if (!File.isDirectory(dir)) {
608         File.mkdir(dir);
609     }
610     var formElements = [];
611     for (var k in reader.form) {
612         if (k == 'id') { // should really do primary key testing..
613             continue;
614         }
615         formElements.push(reader.form[k]);
616     }
617     formElements.push(reader.form['id']);
618
619     print("WRITE: " +  dir + '/' + cfg.DB_NAME + '_' + reader.table + '.json');
620     
621     File.write(
622         dir + '/' + cfg.DB_NAME + '_' + reader.table + '.json',
623             
624        
625         JSON.stringify({
626             '|xns' : 'Roo.form',
627             xtype : "Form",
628             listeners : {
629                 "|actioncomplete" : "function(_self,action)\n"+
630                     "{\n"+
631                     "    if (action.type == 'setdata') {\n"+
632                     "       //_this.dialog.el.mask(\"Loading\");\n"+
633                     "       //this.load({ method: 'GET', params: { '_id' : _this.data.id }});\n"+
634                     "       return;\n"+
635                     "    }\n"+
636                     "    if (action.type == 'load') {\n"+
637                     "        _this.dialog.el.unmask();\n"+
638                     "        return;\n"+
639                     "    }\n"+
640                     "    if (action.type =='submit') {\n"+
641                     "    \n"+
642                     "        _this.dialog.el.unmask();\n"+
643                     "        _this.dialog.hide();\n"+
644                     "    \n"+
645                     "         if (_this.callback) {\n"+
646                     "            _this.callback.call(_this, _this.form.getValues());\n"+
647                     "         }\n"+
648                     "         _this.form.reset();\n"+
649                     "         return;\n"+
650                     "    }\n"+
651                     "}\n",
652                 
653                 "|rendered" : "function (form)\n"+
654                     "{\n"+
655                     "    _this.form= form;\n"+
656                     "}\n"
657             },
658             method : "POST",
659             style : "margin:10px;",
660             "|url" : "baseURL + '/Roo/" + reader.table + ".php'",
661             items : formElements
662         }, null, 4)
663     );
664             
665             
666    
667    
668    
669      /// COMBO..
670     
671     dir = GLib.get_home_dir() + '/.Builder/Roo.form.ComboBox'; 
672     if (!File.isDirectory(dir)) {
673         File.mkdir(dir);
674     }
675    
676     print("WRITE: " +  dir + '/' + cfg.DB_NAME + '_' + reader.table + '.json');
677     
678     File.write(
679         dir + '/' + cfg.DB_NAME + '_' + reader.table + '.json',
680             
681        
682         JSON.stringify(reader.combo, null, 4)
683     );
684             
685    
686    
687    
688    
689    
690    
691    
692    
693    
694 });              
695
696
697
698