├── .editorconfig ├── .gitattributes ├── .gitignore ├── .travis.yml ├── CONTRIBUTING.md ├── LICENCE ├── README.md ├── clear.sh ├── cli.js ├── configs ├── color.js ├── constants.js ├── message.js ├── route.js ├── to.js └── toHtmlAttribute.js ├── examples ├── use_function_mongo.js ├── use_function_mysql.js └── use_function_pg.js ├── generator ├── mongodb │ └── compiler_mongo.js ├── mysql │ ├── compiler_mysql.js │ └── compiler_sqlfile_mysql.js ├── postgres │ └── compiler_pg.js └── save.js ├── genviews ├── components.js ├── crud.js ├── crud │ ├── create.hbs │ ├── edit.hbs │ ├── index.hbs │ └── show.hbs └── view.js ├── index.js ├── package.json └── scanners ├── data.json └── scanner_mysql.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = tab 5 | end_of_line = lf 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | 10 | [{package.json,*.yml}] 11 | indent_style = space 12 | indent_size = 2 13 | 14 | [*.md] 15 | trim_trailing_whitespace = false 16 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | test/api 2 | test 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directories 30 | node_modules 31 | jspm_packages 32 | 33 | # Optional npm cache directory 34 | .npm 35 | 36 | # Optional REPL history 37 | .node_repl_history 38 | 39 | test/api 40 | test 41 | 42 | yarn.lock 43 | controllers/ 44 | models/ 45 | views/ 46 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - 'stable' 5 | - '0.12' 6 | - '0.10' 7 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # See [first-contributions](https://github.com/multunus/first-contributions) -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright © 2016 Julian David (@anlijudavid) 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | this software and associated documentation files (the “Software”), to deal in the 6 | Software without restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | Software, and to permit persons to whom the Software is furnished to do so, 9 | subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 16 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 17 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 18 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![enter image description here](http://sailsjs.org/images/bkgd_squiddy.png) 2 | 3 | # Automated generator models, views and controllers for SailsJS & WaterLine 4 | 5 | [![Build Status](https://travis-ci.org/juliandavidmr/sails-inverse-model.svg?branch=master)](https://travis-ci.org/juliandavidmr/sails-inverse-model) 6 | 7 | **Sails Inverse Model** helps you build models, controllers and views JS Sails from any database. In addition, you can quickly and individually generate each model, view, controller or all three at the same time. 8 | 9 | > Available for **PostgreSQL**, **MySQL** and **MongoDB** 10 | 11 | - [Installation](#installation) 12 | - [Individual generation](#individual-generation) 13 | - [Generator](#generator) 14 | - [Import](#import) 15 | 16 | -------------------------------------------------------------------------------- 17 | 18 | ## Installation 19 | 20 | Linux or MacOS 21 | 22 | ```bash 23 | $ sudo npm install sails-inverse-model@next -g 24 | ``` 25 | 26 | Microsoft Windows 27 | 28 | ```bash 29 | $ npm install sails-inverse-model@next -g 30 | ``` 31 | 32 | ## Individual generation 33 | 34 | You can quickly generate a model, a controller, a view or these three at the same time simply define the attributes of your model. Let's look at an example: 35 | 36 | ```bash 37 | # Generate model 38 | $ sails-inverse-model -g model --name Pet -a "name:string:r:u owner:string" 39 | 40 | # Generate Controller 41 | $ sails-inverse-model -g controller --name Pet -a "" 42 | 43 | # Generate View 44 | $ sails-inverse-model -g view --name Pet -a "name:string:r owner:string" 45 | 46 | # Generate all (Model, View and Controller) 47 | $ sails-inverse-model -g all --name Pet -a "name:string:r:k owner:string" 48 | ``` 49 | 50 | ## Detail 51 | 52 | |Param | Description | 53 | |------------------:|:------------------------------------| 54 | |g | Generate view, model, controller | 55 | |name | Name: model, driver, and view folder| 56 | |a | Content of the element to generate | 57 | |name:string:params | Attribute name: data type: params | 58 | 59 | Specifies the type of data that will be stored in this attribute. [Here](http://sailsjs.com/documentation/concepts/models-and-orm/attributes) 60 | 61 | ## Params 62 | 63 | |Param | Description | Example | 64 | |------:|:--------------|:------------------| 65 | |r | Required | catname:string:r | 66 | |u | Unique | catname:string:u | 67 | |a | Autoincrement | index:integer:a | 68 | |k | Primary Key | index:integer:k | 69 | 70 | You can also set all three parameters at the same time, for example: __index:integer:a:u:r__ 71 | 72 | ## Example 73 | 74 | ```bash 75 | sails-inverse-model -g model --name Pet -a "index:integer:r:u:a name:string:r:u owner:string:r" 76 | 77 | => 78 | module.exports = { 79 | attributes: { 80 | index: { -> index 81 | type: 'integer', -> :integer 82 | required: true, -> :r 83 | unique: true, -> :u 84 | autoincrement: true -> :a 85 | }, 86 | name: { 87 | type: 'string', 88 | required: true, 89 | unique: true 90 | }, 91 | owner: { 92 | type: 'string', 93 | required: true 94 | } 95 | } 96 | }; 97 | ``` 98 | 99 | ## Generator (from Database) 100 | 101 | ```bash 102 | $ sails-inverse-model --help 103 | 104 | Sails Inverse Model helps you build models, controllers and views JS Sails from any database. In addition, you can quickly and individually generate each model, view, controller or all three at the same time. 105 | 106 | .-..-. 107 | 108 | Sails-inverse-model<| .-..-. 2.x.x 109 | | 110 | ~ ~ ~ /|. 111 | ~ ~ / || 112 | ~ ~ ,' |' 113 | .-'.-==|/_--' 114 | `--'-------' 115 | _--__--_---__---___--__---__--___ 116 | __---__--__---___--__---___--_-_---___ 117 | ---------------------------------------------------------- 118 | :: Sat Feb 04 2017 22:43:52 GMT-0500 (COT) 119 | ---------------------------------------------------------- 120 | Example: 121 | $ mkdir sails-output 122 | $ cd sails-output 123 | $ sails-inverse-model -u postgres -p root -d almacen -t pg -m -v -c 124 | 125 | User : postgres 126 | Password : root 127 | Database : almacen 128 | Host : localhost 129 | Models : /home/julian/Documents/sails-output/models 130 | Views : /home/julian/Documents/sails-output/views 131 | Controllers : /home/julian/Documents/sails-output/controllers 132 | DB : pg 133 | Schema (pg) : public 134 | ===================================== 135 | Views [OK] 136 | ===================================== 137 | Models [OK] 138 | ===================================== 139 | Controllers [OK] 140 | 141 | Note: Copy models => your/project_sails/api 142 | Copy controllers => your/project_sails/api 143 | Copy views/* => your/project_sails/views/ 144 | Then: 145 | $ cd your/project_sails/ 146 | $ sails lift 147 | 148 | More info: https://github.com/juliandavidmr/sails-inverse-model 149 | --------------------------------------------------------------- 150 | Options: 151 | -u, --user User of database 152 | -p, --pass Password of database 153 | -d, --database Database name 154 | -h, --host Host server Default: localhost 155 | -m, --models Folder output models Default: Folder actual 156 | -c, --controllers Folder output controllers Default: Folder actual 157 | -v, --views Folder output views Default: Folder actual (Experimental) 158 | -t, --type Type gestor database: mysql|postgres|mongodb Default: mysql 159 | -s, --schema (Only PostgreSQL) Schema database postgres: Default: public 160 | -f, --file (Only MySQL) .sql file path entry (Experimental) 161 | 162 | 163 | ====================== Individual generation ================== 164 | You can quickly generate a model, a controller, a view or these three at the same time. 165 | # Generate model 166 | $ sails-inverse-model -g model --name Pet -a "name:string:r:u owner:string" 167 | 168 | # Generate Controller 169 | $ sails-inverse-model -g controller --name Pet -a "name:string:r:u owner:string" 170 | 171 | # Generate View 172 | $ sails-inverse-model -g view --name Pet -a "name:string:r owner:string" 173 | 174 | # Generate all (Model, View and Controller) 175 | $ sails-inverse-model -g all --name Pet -a "name:string:r:k owner:string" 176 | 177 | Where: 178 | -------------------------------------------- 179 | |Param | Description | Example | 180 | |------|---------------|-------------------| 181 | | r | Required | catname:string:r | 182 | | u | Unique | catname:string:u | 183 | | a | Autoincrement | index:integer:a | 184 | | k | Primary Key | index:integer:k | 185 | -------------------------------------------- 186 | You can also set all three parameters at the same time, for example: index:integer:a:u:r 187 | 188 | ``` 189 | 190 | ## MySQL 191 | 192 | ```bash 193 | sails-inverse-model -u root -p root -d mydbmysql -m -v -c 194 | ``` 195 | 196 | ### MySQL from file .sql 197 | 198 | ```bash 199 | sails-inverse-model -f /your/path/to/script.sql -m -v -c 200 | ``` 201 | 202 | ## PostgreSQL 203 | 204 | ```bash 205 | sails-inverse-model -u postgres -p root -d almacen -t pg -m -v -c 206 | ``` 207 | 208 | ## MongoDB 209 | 210 | ```bash 211 | sails-inverse-model -d blog_db -t mg -m -v -c 212 | ``` 213 | 214 | # Import 215 | 216 | ## Install package 217 | 218 | ```bash 219 | npm install sails-inverse-model --save 220 | ``` 221 | 222 | ## Generate from **MySQL** 223 | 224 | ```js 225 | var sim = require('sails-inverse-model'); 226 | 227 | var config = { 228 | host: "localhost", 229 | database: "almacen", 230 | user: "root", 231 | pass: "root", 232 | port: 3306 233 | } 234 | 235 | var folder_controllers = "/your/project/sails/api/"; //if folder_models == "" then: no generate controllers 236 | var folder_models = "/your/project/sails/api/"; //if folder_models == "" then: no generate models 237 | var folder_views = "/your/project/sails/"; //if folder_models == "" then: no generate views 238 | 239 | sim.generatemy(config, folder_models, folder_controllers, folder_views, plurallang); 240 | ``` 241 | 242 | ### Generate from **PostgreSQL** 243 | 244 | ```js 245 | var sim = require('sails-inverse-model'); 246 | 247 | var config = { 248 | host: "localhost", 249 | database: "example", 250 | user: "postgres", 251 | pass: "root", 252 | port: 5432, 253 | schema: "public" 254 | } 255 | 256 | var folder_controllers = "/your/project/sails/api/"; //if folder_models == "" then: no generate controllers 257 | var folder_models = "/your/project/sails/api/"; //if folder_models == "" then: no generate models 258 | var folder_views = "/your/project/sails/"; //if folder_models == "" then: no generate views 259 | 260 | sim.generatepg(config, folder_models, folder_controllers, folder_views, plurallang); 261 | ``` 262 | 263 | ### Generate from **MongoDB** 264 | 265 | ```js 266 | var sim = require('sails-inverse-model'); 267 | 268 | var folder_controllers = "/your/project/sails/api/"; //if folder_models == "" then: no generate controllers 269 | var folder_models = "/your/project/sails/api/"; //if folder_models == "" then: no generate models 270 | var folder_views = "/your/project/sails/"; //if folder_models == "" then: no generate views 271 | 272 | // host port database views models controllers 273 | sim.generatemg('localhost', 27017, 'my_name_collection', folder_views, folder_models, folder_controllers); 274 | ``` 275 | 276 | ### Then navigate to the output folder and can find the js generated. 277 | 278 | # [Contributions](/CONTRIBUTING.md) -------------------------------------------------------------------------------- /clear.sh: -------------------------------------------------------------------------------- 1 | rm -rf controllers 2 | rm -rf models 3 | rm -rf views 4 | 5 | rm *.lock -------------------------------------------------------------------------------- /cli.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | 'use strict'; 4 | 5 | var meow = require('meow'); 6 | var ansi = require('ansi-styles'); 7 | var assert = require('assert'); 8 | 9 | require('./configs/color'); 10 | require('./configs/route'); 11 | require('./generator/save'); 12 | 13 | var convert = require('./configs/toHtmlAttribute'); 14 | 15 | var generate_my_transpile = require('./generator/mysql/compiler_sqlfile_mysql'); 16 | var generate_my = require('./generator/mysql/compiler_mysql'); 17 | var generate_pg = require('./generator/postgres/compiler_pg'); 18 | var generate_mg = require('./generator/mongodb/compiler_mongo'); 19 | var generate_view = require('./genviews/view'); 20 | 21 | var exitsfile = require('is-existing-file'); 22 | var message = require('./configs/message'); 23 | var constants = require('./configs/constants'); 24 | 25 | var cli = meow(message.show); 26 | 27 | var g = cli.flags.g || cli.flags.generate; 28 | 29 | if (g) { 30 | /** 31 | * Generator manual 32 | * Input standar 33 | */ 34 | var name = cli.flags.n || cli.flags.name; // Name model, controller and view 35 | 36 | var Model = []; // ArrayList of models 37 | var option = (g === true) // Option default 38 | ? 'all' // Option Controller, Views & Models 39 | : g; // Select by user 40 | 41 | var attributes = cli.flags.attributes || cli.flags.a; // Attributes 42 | 43 | var split_attr = attributes.split(' '); 44 | // console.log("attributes: ", JSON.stringify(split_attr, null, 3)); 45 | 46 | let aux_item_model = []; // Item Model 47 | let aux_item_view = []; // Item View 48 | 49 | // Example: [xyz:string, abc:number] 50 | split_attr.map((item) => { 51 | let separate = item.split(':'); 52 | 53 | paramSearchFill(separate, function (result) { 54 | // console.log('=>',result); 55 | 56 | var _aux_item = separate[0] + ": { type: '" + separate[1] + "', "; 57 | aux_item_model.push(_aux_item + result + "}"); 58 | 59 | var content_view = { 60 | required: result.indexOf(constants.REQUIRED) !== -1, // Index string required for view input 61 | default_value: 0, 62 | name: separate[0], 63 | type: convert.SailstoHtmlAtt(separate[1]) 64 | }; 65 | 66 | aux_item_view.push(JSON.stringify(content_view)); 67 | }); 68 | }); 69 | 70 | Model.push({ 71 | model_name: name || 'Name'.concat(parseInt(Math.random(20) * 100)), // Name file model, controller, and folder view 72 | content: "attributes: { " + aux_item_model + " }", 73 | view_content: aux_item_view 74 | }); 75 | 76 | // console.log('Attri: => ', JSON.stringify(Model, null, 4)); 77 | 78 | switch (option) { 79 | case 'view': 80 | generate_view.generate(Model, concat(process.cwd(), 'Views')); 81 | break; 82 | case 'model': 83 | saveModels(concat(process.cwd(), 'Models'), Model); 84 | break; 85 | case 'controller': 86 | saveControllers(concat(process.cwd(), 'Controllers'), Model); 87 | break; 88 | case 'all': 89 | saveModels(concat(process.cwd(), 'Models'), Model); 90 | saveControllers(concat(process.cwd(), 'Controllers'), Model); 91 | generate_view.generate(Model, concat(process.cwd(), 'Views')); 92 | break; 93 | } 94 | } else { 95 | /** 96 | * Generator automatic 97 | * Databases 98 | */ 99 | var user, // Option user database 100 | pass, // Option password database 101 | db, // Option name database 102 | host, // Option host database 103 | port, // Option port database 104 | folder_models, // Option path folder models 105 | folder_controllers, // Option path folder controllers 106 | folder_views, // Option path folder views 107 | schema, // Option schema database => postgres 108 | type, // Option type gestor database: mysql, postgres, mongodb 109 | filesql; // Option path file .sql 110 | 111 | //User 112 | user = cli.flags.u || cli.flags.user; 113 | if (user == true || user == "true") { 114 | user = undefined; // Method concat: see configs/route.js 115 | } 116 | 117 | //Password 118 | var pass = (cli.flags.p || cli.flags.pass); 119 | if (pass === true) { 120 | pass = undefined; 121 | console.warn("Missing password database"); 122 | process.exit(1); 123 | } else if (pass) { 124 | pass = pass.toString(); 125 | } 126 | 127 | //Database 128 | db = cli.flags.d || cli.flags.database; 129 | 130 | //Host 131 | host = cli.flags.h || cli.flags.host || "localhost"; 132 | if (host === true) { 133 | host = undefined; 134 | } else if (host) { 135 | host = host.toString(); 136 | } 137 | 138 | //Type gestor database mysql | postgres | mongo 139 | type = cli.flags.t || cli.flags.type || "mysql"; // Default Mysql 140 | console.log(">>", type); 141 | if (type === true || type == "true") { 142 | type = "mysql"; 143 | } 144 | 145 | //Schema database postgres 146 | schema = cli.flags.s || cli.flags.schema || "public"; // Default public 147 | if (schema === true || schema == "true") { 148 | schema = "public"; 149 | } 150 | 151 | //Folder models 152 | folder_models = cli.flags.m || cli.flags.models; 153 | if (folder_models === true || folder_models == "true") { 154 | folder_models = concat(process.cwd(), "models"); // Method concat: see configs/route.js 155 | } 156 | 157 | //Folder Controllers 158 | folder_controllers = cli.flags.c || cli.flags.controllers; 159 | if (folder_controllers === true || folder_controllers == "true") { 160 | folder_controllers = concat(process.cwd(), "controllers"); // Method concat: see configs/route.js 161 | } 162 | 163 | //Folder views 164 | folder_views = cli.flags.v || cli.flags.views; 165 | if (folder_views === true || folder_views == "true") { 166 | folder_views = concat(process.cwd(), "views"); // Method concat: see configs/route.js 167 | } 168 | 169 | //file .sql 170 | filesql = cli.flags.f || cli.flags.file; 171 | if (filesql === true || filesql == "true") { 172 | filesql = undefined; // Method concat: see configs/route.js 173 | } 174 | 175 | // Mysql, postgres & mongo connect config. 176 | var config = { 177 | user: user, 178 | password: pass, 179 | host: host, 180 | database: db, 181 | schema: schema, 182 | port: 3306 183 | }; 184 | 185 | info(); // Show message info 186 | if (filesql) { 187 | exitsfile(filesql, function (exits) { 188 | if (exits) { 189 | generate_my_transpile.generate(filesql, folder_models, folder_controllers, folder_views); 190 | } else { 191 | console.log(color("\nERROR: No exits '" + filesql + "'. \nEnter 'sails-inverse-model --help'", "red")); 192 | } 193 | }); 194 | } else { 195 | if (db && host) { 196 | type = type.toLowerCase(); //pg, postgres, mysql 197 | 198 | if (type.indexOf("pg") != -1 || type.indexOf("postgres") != -1) { //pg, postgres 199 | config.port = 5432; 200 | generate_pg.generate(config, folder_models, folder_controllers, folder_views); 201 | } else if (type.indexOf("my") != -1 || type.indexOf("mysql") != -1) { //my, mysql 202 | delete config.schema; 203 | generate_my.generate(config, folder_models, folder_controllers, folder_views); 204 | } else if (type.indexOf("mg") != -1 || type.indexOf("mongo") != -1) { 205 | //mg, mongo 206 | generate_mg 207 | .generate(config.host, 27017, config.database, folder_views, folder_models, folder_controllers) 208 | .then((value) => { 209 | console.log(color("[OK]", "green") + " Mongo"); 210 | }, (err) => { 211 | console.log("Error"); 212 | console.error(color(err, "red")); 213 | }); 214 | } 215 | } else { 216 | console.log(color("Missing parameters: enter 'sails-inverse-model --help'", "red")); 217 | } 218 | } 219 | } 220 | 221 | /** 222 | * Menu info console 223 | */ 224 | function info() { 225 | console.log("User :", color(user || "Not used", "green")); 226 | console.log("Password :", color(pass || "Not used", "green")); 227 | console.log("Database :", color(db || "Not used", "green")); 228 | console.log("Host :", color(host || "Not used", "green")); 229 | console.log("Models :", color((folder_models || "Not generate"), "green")); 230 | console.log("Views :", color((folder_views || "Not generate"), "green")); 231 | console.log("Controllers:", color((folder_controllers || "Not generate"), "green")); 232 | console.log("DB :", color((type), "green")); 233 | console.log("Schema (pg):", color((schema), "green")); 234 | } 235 | 236 | /** 237 | * Search params 238 | * 239 | * @param {array} params 240 | * @param {function} cb 241 | * @returns string 242 | */ 243 | function paramSearchFill(params, cb) { 244 | var output = ''; 245 | 246 | for (var i = 2; i < params.length; i++) { 247 | var element = params[i]; 248 | 249 | if (element == 'r' || element == 'required') { 250 | output += constants.REQUIRED; 251 | } else if (element == 'u' || element == 'unique') { 252 | output += constants.UNIQUE; 253 | } else if (element == 'a' || element == 'autoincrement') { 254 | output += constants.AUTOINC; 255 | } else if (element == 'k' || element == 'primarykey') { 256 | output += constants.PRIMARYKEY; 257 | } 258 | } 259 | 260 | if (output.endsWith(',')) { 261 | output = output.substring(0, output.length - 1); 262 | } 263 | 264 | return cb(output); 265 | } 266 | 267 | -------------------------------------------------------------------------------- /configs/color.js: -------------------------------------------------------------------------------- 1 | const ansi = require('ansi-styles'); 2 | 3 | // Color text with ansi-styles 4 | color = function(text, color_) { 5 | color_ = color_.toLowerCase(); 6 | if(color_ == "white") { 7 | return ansi.white.open + (text) + ansi.white.close; 8 | } else if (color_ == "red") { 9 | return ansi.red.open + (text) + ansi.red.close; 10 | } else if (color_ == "green") { 11 | return ansi.green.open + (text) + ansi.green.close; 12 | } else if (color_ == "yellow") { 13 | return ansi.yellow.open + (text) + ansi.yellow.close; 14 | } else if (color_ == "blue") { 15 | return ansi.blue.open + (text) + ansi.blue.close; 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /configs/constants.js: -------------------------------------------------------------------------------- 1 | exports.REQUIRED = 'required: true,'; 2 | exports.UNIQUE = 'unique: true,'; 3 | exports.AUTOINC = 'autoincrement: true,'; 4 | exports.PRIMARYKEY = 'primaryKey: true,'; -------------------------------------------------------------------------------- /configs/message.js: -------------------------------------------------------------------------------- 1 | require('./color'); 2 | 3 | exports.show = [ 4 | color(" .-..-. ", "blue"), 5 | " ", 6 | color("Sails", "yellow") + color("-inverse", "blue") + color("-model", "red") + color("<| .-..-. " + require('../package.json').version, "green"), 7 | color(" |\ ", "green"), 8 | color(" ~ ~ ~ /|.\ ", "green"), 9 | color(" ~ ~ / || \ ", "green"), 10 | color(" ~ ~ ,' |' \ ", "green"), 11 | color(" .-'.-==|/_--' ", "green"), 12 | color(" `--'-------' ", "green"), 13 | color(" _--__--_---__---___--__---__--___ ", "blue"), 14 | color(" __---__--__---___--__---___--_-_---___ ", "blue"), 15 | " ----------------------------------------------------------", 16 | " :: " + (new Date()).toString(), 17 | " ----------------------------------------------------------", 18 | 'Example:', 19 | ' $ mkdir sails-output', 20 | ' $ cd sails-output', 21 | ' $ sails-inverse-model -u postgres -p root -d almacen -t pg -m -v -c', 22 | '', 23 | 'User : postgres', 24 | 'Password : root', 25 | 'Database : almacen', 26 | 'Host : localhost', 27 | 'Models : /home/julian/Documents/sails-output/models', 28 | 'Views : /home/julian/Documents/sails-output/views', 29 | 'Controllers : /home/julian/Documents/sails-output/controllers', 30 | 'DB : pg', 31 | 'Schema (pg) : public', 32 | '=====================================', 33 | 'Views [OK]', 34 | '=====================================', 35 | 'Models [OK]', 36 | '=====================================', 37 | 'Controllers [OK]', 38 | '', 39 | ' Note: Copy models => your/project_sails/api', 40 | ' Copy controllers => your/project_sails/api', 41 | ' Copy views/* => your/project_sails/views/', 42 | ' Then: ', 43 | ' $ cd your/project_sails/', 44 | ' $ sails lift', 45 | '', 46 | ' More info: https://github.com/juliandavidmr/sails-inverse-model', 47 | " ---------------------------------------------------------------", 48 | 'Options:', 49 | ' -u, --user User of database', 50 | ' -p, --pass Password of database', 51 | ' -d, --database Database name', 52 | ' -h, --host Host server Default: localhost', 53 | ' -m, --models Folder output models Default: Folder actual', 54 | ' -c, --controllers Folder output controllers Default: Folder actual', 55 | ' -v, --views Folder output views Default: Folder actual ' + color('(Experimental)', 'yellow'), 56 | ' -t, --type Type gestor database: mysql|postgres|mongodb Default: mysql', 57 | ' -s, --schema (Only PostgreSQL) Schema database postgres: Default: public', 58 | ' -f, --file (Only MySQL) .sql file path entry' + color(' (Experimental)', 'yellow'), 59 | '\n', 60 | '====================== Individual generation ==================', 61 | 'You can quickly generate a model, a controller, a view or these three at the sam' + 62 | 'e time.', 63 | '# Generate model', 64 | '$ sails-inverse-model -g model --name Pet -a "name:string:r:u owner:string"', 65 | '', 66 | '# Generate Controller', 67 | '$ sails-inverse-model -g controller --name Pet -a "name:string:r:u owner:string"', 68 | '', 69 | '# Generate View', 70 | '$ sails-inverse-model -g view --name Pet -a "name:string:r owner:string"', 71 | '', 72 | '# Generate all (Model, View and Controller)', 73 | '$ sails-inverse-model -g all --name Pet -a "name:string:r:k owner:string"', 74 | '', 75 | 'Where:', 76 | '--------------------------------------------', 77 | '|Param | Description | Example |', 78 | '|------|--------------|-------------------|', 79 | '| r | Required | catname:string:r |', 80 | '| u | Unique | catname:string:u |', 81 | '| a | Autoincrement | index:integer:a |', 82 | '| k | Primary Key | index:integer:k |', 83 | '--------------------------------------------', 84 | 'You can also set all three parameters at the same time, for example: index:integer:a:u:r' 85 | ]; -------------------------------------------------------------------------------- /configs/route.js: -------------------------------------------------------------------------------- 1 | // Concat text 2 | concat = function (text1, text2) { 3 | if (process.platform === 'win32') { 4 | if(text1.search(/^[a=zA-Z]:/gm) > -1 ){ 5 | if(text1.search(/\genviews$/gm) > -1 ){ 6 | return text1.concat("\\").concat(text2); 7 | } 8 | return text2; 9 | }else{ 10 | return text1.concat("\\").concat(text2); 11 | } 12 | } else { 13 | return text1.concat("/").concat(text2); 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /configs/to.js: -------------------------------------------------------------------------------- 1 | /** 2 | * to.js 3 | * @autor Julian David (@anlijudavid) 4 | * @version 1.0.0 5 | * 2016 6 | */ 7 | const to = require('../configs/to'); 8 | 9 | /** 10 | * [toModel simple json to model sails] 11 | * @param {[type]} model_basic [description] 12 | * @return {[string]} [string] 13 | */ 14 | exports.toModel = function (model_basic) { 15 | var out = []; 16 | out.push("/**"); 17 | out.push("\tGenerated by sails-inverse-model"); 18 | out.push("\tDate:" + (new Date()).toString()); 19 | out.push("*/\n"); 20 | out.push("module.exports = {"); 21 | //console.log(model_basic); 22 | out.push(model_basic); 23 | out.push("};"); 24 | return out.join("\n"); 25 | }; 26 | 27 | exports.saveController = function(name) { 28 | var name_cap = exports.capitalize(name); 29 | return [ 30 | "/**", 31 | "* " + name_cap, 32 | "*", 33 | "* @description :: Server-side logic for managing " + name_cap, 34 | "* @help :: See http://sailsjs.org/#!/documentation/concepts/Controllers", 35 | "*/", 36 | "module.exports = {", 37 | " index: function(req, res, next) {", 38 | " " + name_cap + ".find().exec(function(err, list) {", 39 | " if (err) return Error('Error');", 40 | " return res.view({", 41 | " result: list", 42 | " });", 43 | " });", 44 | " },", 45 | "", 46 | " show: function(req, res, next) {", 47 | " " + name_cap + ".findOneById(req.param('id'), function Founded(err, value) {", 48 | " if (err) {", 49 | " return next(err);", 50 | " }", 51 | " res.view({", 52 | " element: value", 53 | " });", 54 | " });", 55 | " },", 56 | "", 57 | " edit: function(req, res, next) {", 58 | " " + name_cap + ".findOne(req.param('id'), function Founded(err, value) {", 59 | " if (err) {", 60 | " return next(err);", 61 | " }", 62 | " res.view({", 63 | " element: value", 64 | " });", 65 | " });", 66 | " },", 67 | "", 68 | " update: function(req, res, next) {", 69 | " " + name_cap + ".update(req.param('id'), req.body, function Update(err, value) {", 70 | " if(err) {", 71 | " return next(err);", 72 | " }", 73 | " return res.redirect('" + name + "/show/' + req.param('id'));", 74 | " });", 75 | " },", 76 | "", 77 | " delete: function(req, res, next) {", 78 | " " + name_cap + ".destroy(req.param('id'), function Update(err, value) {", 79 | " if (err) {", 80 | " return next(err);", 81 | " }", 82 | " return res.redirect('/" + name + "');", 83 | " });", 84 | " },", 85 | "", 86 | "};" 87 | ].join("\n"); 88 | }; 89 | 90 | exports.capitalize = function(word) { 91 | return word.replace(/(^|\s)([a-z])/g, function(m, p1, p2) { 92 | return p1 + p2.toUpperCase(); 93 | }); 94 | }; 95 | -------------------------------------------------------------------------------- /configs/toHtmlAttribute.js: -------------------------------------------------------------------------------- 1 | exports.SailstoHtmlAtt = function (type_data) { 2 | switch (type_data) { 3 | case 'text': 4 | case 'string': 5 | case 'mediumtext': 6 | case 'longtext': 7 | case 'array': 8 | case 'json': 9 | return 'text'; 10 | case 'float': 11 | case 'integer': 12 | case 'objectid': 13 | return 'number'; 14 | case 'boolean': 15 | case 'binary': 16 | return 'checkbox'; 17 | default: 18 | return type_data; 19 | } 20 | } -------------------------------------------------------------------------------- /examples/use_function_mongo.js: -------------------------------------------------------------------------------- 1 | var sim = require('../index'); 2 | 3 | var folder_controllers = "/your/project/sails/api/"; //if folder_models == "" then: no generate controllers 4 | var folder_models = "/your/project/sails/api/"; //if folder_models == "" then: no generate models 5 | var folder_views = "/your/project/sails/"; //if folder_models == "" then: no generate views 6 | 7 | // host port database views models controllers 8 | sim.generatemg('localhost', 27017, 'my_name_collection', folder_views, folder_models, folder_controllers); 9 | -------------------------------------------------------------------------------- /examples/use_function_mysql.js: -------------------------------------------------------------------------------- 1 | var sim = require('../index'); 2 | 3 | var config = { 4 | host: "localhost", 5 | database: "almacen", 6 | user: "root", 7 | password: "root", 8 | port: 3306 9 | }; 10 | 11 | var folder_controllers = "/your/project/sails/api/"; //if folder_models == "" then: no generate controllers 12 | var folder_models = "/your/project/sails/api/"; //if folder_models == "" then: no generate models 13 | var folder_views = "/your/project/sails/"; //if folder_models == "" then: no generate views 14 | 15 | sim.generatemy(config, folder_models, folder_controllers, folder_views); 16 | -------------------------------------------------------------------------------- /examples/use_function_pg.js: -------------------------------------------------------------------------------- 1 | var sim = require('../index'); 2 | 3 | var config = { 4 | host: "localhost", 5 | database: "example", 6 | user: "postgres", 7 | pass: "root", 8 | port: 5432, 9 | schema: "public" 10 | }; 11 | 12 | var folder_controllers = "/your/project/sails/api/"; //if folder_models == "" then: no generate controllers 13 | var folder_models = "/your/project/sails/api/"; //if folder_models == "" then: no generate models 14 | var folder_views = "/your/project/sails/"; //if folder_models == "" then: no generate views 15 | 16 | sim.generatepg(config, folder_models, folder_controllers, folder_views); 17 | -------------------------------------------------------------------------------- /generator/mongodb/compiler_mongo.js: -------------------------------------------------------------------------------- 1 | /** 2 | * compiler_mongo.js 3 | * @autor Julian David (@anlijudavid) 4 | * 2016 5 | * 6 | * Mysql to models waterline 7 | */ 8 | 9 | var mondongo = require('mondongo'); 10 | var s = require("underscore.string"); 11 | 12 | var view = require('../../genviews/view'); 13 | 14 | // Connection URL var url = 'mongodb://localhost:27017/blog_db'; 15 | 16 | exports.generate = function (host, port, database, folder_views, folder_models, folder_controllers) { 17 | return new Promise(function (resolve, reject) { 18 | exports 19 | .generateModels(host, port, database) 20 | .then((Models) => { 21 | console.log([ 22 | Models.length, Models.length > 0 23 | ? "tables" 24 | : 'table' 25 | ].join(" ")); 26 | 27 | //console.log(JSON.stringify(Models, null, 4)); 28 | if (folder_models !== "" && folder_models) { 29 | saveModels(folder_models, Models); 30 | } 31 | if (folder_controllers !== "" && folder_controllers) { 32 | saveControllers(folder_controllers, Models); 33 | } 34 | if (folder_views !== "" && folder_views) { 35 | view.generate(Models, folder_views); 36 | } 37 | }, (err) => { 38 | console.log(err); 39 | return reject(err); 40 | }); 41 | }); 42 | }; 43 | 44 | exports.generateModels = function (host, port, database) { 45 | return new Promise(function (resolve, reject) { 46 | createURL(host, port, database, function (err, connection_url) { 47 | if (err) 48 | return reject(err); 49 | 50 | var Models = []; 51 | mondongo 52 | .describe(connection_url) 53 | .then((described) => { 54 | described.forEach(elem => { 55 | if (elem.collection !== 'system.indexes' && elem.count > 0) { 56 | var attributes_sails = [], 57 | view_contents = []; 58 | elem 59 | .describe 60 | .forEach(item_descr => { 61 | var result = toSailsAttribute(item_descr.type, item_descr.key, item_descr.isID); 62 | attributes_sails.push(result.model_content); 63 | view_contents.push(result.view_content); 64 | }); 65 | 66 | Models.push({ 67 | model_name: s.camelize(elem.collection), 68 | content: "attributes: { " + (attributes_sails.join(", ")) + " }", 69 | view_content: view_contents 70 | }); 71 | } 72 | }); 73 | return resolve(Models); 74 | }); 75 | }); 76 | }); 77 | }; 78 | 79 | function createURL(host, port, database, cb) { 80 | if (host && port && database) { 81 | return cb(null, 'mongodb://' + host + ':' + port + '/' + database + ''); 82 | } else { 83 | var ms = []; 84 | if (!host) { 85 | ms.push("host"); 86 | } 87 | if (!port) { 88 | ms.push("port"); 89 | } 90 | if (!database) { 91 | ms.push("database"); 92 | } 93 | return cb("Missing parameters: " + ms.join(", "), null); 94 | } 95 | } 96 | 97 | function toSailsAttribute(type, name_attribute, isid) { 98 | type = type 99 | .toLowerCase() 100 | .trim(); 101 | 102 | var sails_attribute = []; 103 | var content_view = { 104 | required: false, 105 | default_value: undefined, 106 | name: name_attribute, 107 | type: undefined 108 | }; 109 | 110 | if (type == "object") { 111 | content_view.required = true; 112 | if (isid && isid === true) { 113 | content_view.type = "number"; 114 | sails_attribute.push("type: 'integer'"); 115 | } else { 116 | content_view.type = "text"; 117 | sails_attribute.push("type: 'text'"); 118 | } 119 | } else { 120 | content_view.type = type; 121 | sails_attribute.push("type: '" + type + "'"); 122 | } 123 | 124 | var result = { 125 | model_content: (name_attribute.toLowerCase() + ": {" + sails_attribute.join(',') + "}"), 126 | view_content: JSON.stringify(content_view) 127 | }; 128 | 129 | return result; 130 | } 131 | 132 | /* 133 | Mondongo: 134 | 135 | this.generate('localhost', 27017, 'blog_db').then((Models) => { 136 | console.log("Output:\n", JSON.stringify(Models, null, 2)); 137 | }, (error) => { 138 | console.log(error); 139 | }); 140 | */ 141 | -------------------------------------------------------------------------------- /generator/mysql/compiler_mysql.js: -------------------------------------------------------------------------------- 1 | /** 2 | * compiler_mysql.js 3 | * 2016 4 | * 5 | * Process mysql to models waterline 6 | */ 7 | var mysqldesc = require('mysqldesc'); 8 | var s = require("underscore.string"); 9 | 10 | var to = require('../../configs/to'); 11 | var view = require('../../genviews/view'); 12 | var async = require("async"); 13 | 14 | require('../save'); 15 | require('../../configs/color'); 16 | 17 | const FK_IDENTIFIER = "id"; 18 | 19 | exports.generate = function(config, folder_models, folder_controllers, folder_views) { 20 | // Describe connected database 21 | mysqldesc(config, function(err, data) { 22 | if (err) { 23 | console.log("ERROR: ", err); 24 | } else { 25 | var Models = [], 26 | count = 1; 27 | 28 | async.forEachOf(data, function(value, table, callback) { 29 | if (data.hasOwnProperty(table)) { 30 | console.log(color("[" + (count++) + " Generating]", "blue") + " " + table + " table ..."); 31 | var tableCloumnsData = data[table].columns ? data[table].columns : data[table]; 32 | var attributes_sails = [], 33 | view_contents = []; 34 | mysqldesc.keyColumnUsage(config, config.database, table, function(err, data2) { 35 | for (var colum in tableCloumnsData) { 36 | //console.log(table + "=>" + colum); 37 | var reference_fk = undefined; 38 | if (data2[colum] && data2[colum]["REFERENCED_TABLE_NAME"]) { 39 | reference_fk = { 40 | table: data2[colum].REFERENCED_TABLE_NAME, 41 | column: data2[colum].REFERENCED_COLUMN_NAME 42 | }; 43 | //console.log(table + "=>" + JSON.stringify(data2[colum], null, 4)); 44 | } 45 | var attributes = tableCloumnsData[colum]; 46 | //console.log(attributes); 47 | var result = transpile(attributes, colum, reference_fk); 48 | view_contents.push(result.view_content); 49 | attributes_sails.push(result.model_content); 50 | } 51 | //console.log("-------------"); 52 | Models.push({ 53 | model_name: s.camelize(table).trim(), 54 | content: "attributes: { " + attributes_sails + " }", 55 | view_content: view_contents 56 | }); 57 | //console.log(table + " = " + JSON.stringify(table, null, 4)); 58 | callback(null, table); 59 | }); 60 | } 61 | }, function(err) { 62 | console.log([Models.length, "tables"].join(" ")); 63 | 64 | //console.log(Models); 65 | if (folder_views !== "" && folder_views) { 66 | view.generate(Models, folder_views); 67 | } 68 | if (folder_models !== "" && folder_models) { 69 | saveModels(folder_models, Models); 70 | } 71 | if (folder_controllers !== "" && folder_controllers) { 72 | saveControllers(folder_controllers, Models); 73 | } 74 | }); 75 | } 76 | }); 77 | }; 78 | 79 | /** 80 | * [transpile: convert all attributes mysql to orm sailsjs] 81 | * @param {[type]} attributes [description] 82 | * @param {[type]} name_attribute [description] 83 | * @param {[type]} reference_fk [description] 84 | * @return {[type]} [description] 85 | */ 86 | function transpile(attributes, name_attribute, reference_fk) { 87 | //console.log("attributes " + JSON.stringify(attributes, null, 4)); 88 | var type_ = attributes["Type"]; 89 | var default_value_ = attributes["Default"]; 90 | var is_nullable_ = attributes["Null"]; 91 | var key_ = attributes["Key"]; 92 | 93 | //console.log(JSON.stringify(attributes)); 94 | return exports.toSailsAttribute(type_, name_attribute, default_value_, is_nullable_, key_, reference_fk); 95 | } 96 | 97 | exports.toSailsAttribute = function(Type, attrib, default_value_, is_nullable_, key_, reference_fk) { 98 | var content_view = { 99 | required: false, 100 | default_value: default_value_, 101 | name: attrib, 102 | type: undefined 103 | }; 104 | 105 | var attribute = []; 106 | 107 | var type = Type.toLowerCase(); 108 | var typeSplit = type.match(/(enum)\((.+)\)/); 109 | if(!typeSplit) var typeSplit = type.match(/(\w+)\((\d+),(\d+)\)/); 110 | if(!typeSplit) var typeSplit = type.match(/(\w+)\((\d+)\)/); 111 | if(!typeSplit) var typeSplit = type.match(/(\w+)/); 112 | 113 | if(typeSplit[1] === 'enum') { 114 | attribute.push(getEnum(typeSplit[2])); 115 | content_view.type = "text"; 116 | } else if(typeSplit[1] === 'json') { 117 | attribute.push(getJson(typeSplit[2])); 118 | content_view.type = "text"; 119 | } else if(['varchar', 'char', 'tinytext', 'text', 'mediumtext', 'longtext', 'time'].indexOf(typeSplit[1]) > -1) { 120 | attribute.push(getString(typeSplit[1], typeSplit[2])); 121 | content_view.type = "text"; 122 | } else if(['int', 'smallint', 'tinyint', 'bigint'].indexOf(typeSplit[1]) > -1) { 123 | attribute.push(getInteger(typeSplit[1], typeSplit[2])); 124 | content_view.type = "number"; 125 | } else if(['decimal', 'double', 'real', 'float'].indexOf(typeSplit[1]) > -1) { 126 | attribute.push(getNumber(typeSplit[1], typeSplit[2])); 127 | content_view.type = "number"; 128 | } else if(['bool', 'bit'].indexOf(typeSplit[1]) > -1) { 129 | attribute.push(getBoolean(typeSplit[1])); 130 | content_view.type = "checkbox"; 131 | } else if(typeSplit[1] === 'year') { 132 | attribute.push(getInteger(typeSplit[1], typeSplit[2])); 133 | content_view.type = "number"; 134 | } else if(typeSplit[1] === 'date') { 135 | attribute.push(getString(typeSplit[1])); 136 | content_view.type = "text"; 137 | } else if(typeSplit[1] === 'datetime', 'timestamp') { 138 | attribute.push(getString(typeSplit[1])); 139 | content_view.type = "text"; 140 | } 141 | 142 | if (key_ === "PRI") { 143 | // attribute.push(getPK()); 144 | content_view.required = true; 145 | } else if (key_ === "MUL") { 146 | if (reference_fk) { 147 | attrib = attrib.replace(FK_IDENTIFIER, ""); 148 | //attrib = reference_fk.table; 149 | //attribute.push('model: ' + reference_fk.table); 150 | attribute = [`model: "${s.camelize(reference_fk.table).trim()}"`]; 151 | } 152 | } else if (key_ === "UNI") { 153 | attribute.push(getUnique()); 154 | } 155 | if (default_value_ !== "" && default_value_ !== null) { 156 | var def = "defaultsTo: "; 157 | if (content_view.type == "text") { 158 | def += `"${default_value_}"`; 159 | } else { 160 | def += default_value_; 161 | } 162 | attribute.push(def); 163 | } 164 | else if (is_nullable_ === "NO") { 165 | attribute.push(getRequired()); 166 | content_view.required = true; 167 | } 168 | 169 | var result = { 170 | model_content: attrib + ": {" + attribute.join(',') + "}", 171 | view_content: JSON.stringify(content_view) 172 | }; 173 | return result; 174 | }; 175 | 176 | function getRequired() { 177 | return "required: true"; 178 | } 179 | 180 | function getUnique() { 181 | return "unique: true"; 182 | } 183 | 184 | function getString(type, length) { 185 | var out = []; 186 | out.push('type: "string"'); 187 | out.push(`columnType: "${type}"`); 188 | if (length) { 189 | out.push(`maxLength: ${length}`); 190 | } 191 | return quitComma(out.join(",")); 192 | } 193 | 194 | function getInteger(type, length) { 195 | var out = []; 196 | out.push('type: "number"'); 197 | out.push(`columnType: "${type}"`); 198 | out.push(`isInteger: true`); 199 | // if (length) { 200 | // out.push(`maxLength: ${length}`); 201 | // } 202 | return quitComma(out.join(",")); 203 | } 204 | 205 | function getNumber(type, length) { 206 | var out = []; 207 | out.push('type: "number"'); 208 | out.push(`columnType: "${type}"`); 209 | // if (length) { 210 | // out.push(`maxLength: ${length}`); 211 | // } 212 | return quitComma(out.join(",")); 213 | } 214 | 215 | function getBoolean(type) { 216 | var out = []; 217 | out.push('type: "boolean"'); 218 | out.push(`columnType: "${type}"`); 219 | return quitComma(out.join(",")); 220 | } 221 | 222 | // TODO: Mejorar la detección de items con una expresion regular 223 | function getEnum(enums) { 224 | var outEnums = []; 225 | var line = enums.split(/['|"](.*?)['|"],*/); 226 | line.map((item) => { 227 | if (item !== "") { 228 | outEnums.push(`"${item}"`); 229 | } 230 | }); 231 | var out = []; 232 | out.push('type: "string"'); 233 | out.push('columnType: "enum"'); 234 | out.push(`isIn: [${quitComma(outEnums.join(","))}]`); 235 | return quitComma(out.join(",")); 236 | } 237 | 238 | function getJson(length) { 239 | var out = []; 240 | out.push('type: "json"'); 241 | if (length) { 242 | out.push(`maxLength: ${length}`); 243 | } 244 | return quitComma(out.join(",")); 245 | } 246 | 247 | function quitComma(str) { 248 | if (str.trim().endsWith(",")) { 249 | return str.trim().substr(0, str.length - 1); 250 | } 251 | return str; 252 | } 253 | 254 | exports.quitComma = quitComma; 255 | -------------------------------------------------------------------------------- /generator/mysql/compiler_sqlfile_mysql.js: -------------------------------------------------------------------------------- 1 | var scanner = require('../../scanners/scanner_mysql'); 2 | var compiler_mysql = require('./compiler_mysql'); 3 | var view = require('../../genviews/view'); 4 | var to = require('../../configs/to'); 5 | var s = require("underscore.string"); 6 | require('../save'); 7 | 8 | exports.generate = function(pathsql, folder_models, folder_controllers, folder_views) { 9 | this.createModels(pathsql, function(err, Models) { 10 | //console.log(JSON.stringify(Models, null, 2)); 11 | if (folder_views !== "" && folder_views) { 12 | view.generate(Models, folder_views); 13 | } 14 | if (folder_models !== "" && folder_models) { 15 | saveModels(folder_models, Models); 16 | } 17 | if (folder_controllers !== "" && folder_controllers) { 18 | saveControllers(folder_controllers, Models); 19 | } 20 | }); 21 | }; 22 | 23 | exports.createModels = function(pathsql, cb) { 24 | scanner.generate(pathsql, function(err, described) { 25 | if (err) { 26 | cb(err, null); 27 | } else { 28 | var Models = []; 29 | described.map((table, i) => { 30 | //console.log(table); 31 | var attributes_sails = [], 32 | view_contents = []; 33 | table.atr.map((attr) => { 34 | var transp = transpile(attr); 35 | attributes_sails.push(transp.model_content); 36 | view_contents.push(transp.view_content); 37 | }); 38 | 39 | Models.push({ 40 | model_name: s.camelize(table.table_name), 41 | content: "attributes: { " + (attributes_sails.join(", ")) + " }", 42 | view_content: view_contents 43 | }); 44 | }); 45 | cb(null, Models); 46 | } 47 | }); 48 | }; 49 | 50 | function transpile(attributes) { 51 | //console.log("attributes " + JSON.stringify(attributes, null, 4)); 52 | var type_ = attributes["Type"]; 53 | var is_nullable_ = attributes["NotNull"]; 54 | var size_ = attributes["Size"]; 55 | var ai_ = attributes["AI"]; 56 | var name_ = attributes["Name"]; 57 | 58 | //console.log(JSON.stringify(attributes)); 59 | return compiler_mysql.toSailsAttribute(type_, name_, null, is_nullable_); 60 | } 61 | 62 | /* 63 | { 64 | "table_name": "tipo_notificacion", 65 | "atr": [ 66 | { 67 | "Name": "tntf_idtiponotif", 68 | "Type": "int", 69 | "Size": "11", 70 | "NotNull": true, 71 | "AI": true 72 | }, 73 | { 74 | "Name": "tntf_nombre", 75 | "Type": "varchar", 76 | "Size": "45", 77 | "NotNull": true, 78 | "AI": false 79 | }, 80 | { 81 | "Name": "tntf_descripcion", 82 | "Type": "text", 83 | "Size": "", 84 | "NotNull": true, 85 | "AI": false 86 | } 87 | ] 88 | }, 89 | ... 90 | */ 91 | -------------------------------------------------------------------------------- /generator/postgres/compiler_pg.js: -------------------------------------------------------------------------------- 1 | /** 2 | * compiler_mysql.js 3 | * @autor Julian David (@anlijudavid) 4 | * 2016 5 | * 6 | * Process mysql to models waterline 7 | */ 8 | var ProgressBar = require('progress'); 9 | var s = require("underscore.string"); 10 | 11 | var to = require('../../configs/to'); 12 | var view = require('../../genviews/view'); 13 | require('../save'); 14 | 15 | var PostgresSchema = require('pg-json-schema-export'); 16 | 17 | exports.generate = function(config, folder_models, folder_controllers, folder_views) { 18 | PostgresSchema.toJSON(config, config.schema) 19 | .then(function(schemas) { 20 | //console.log(JSON.stringify(schemas, null, 4)); 21 | var Models = []; 22 | 23 | //Tables 24 | for (var table in schemas.tables) { 25 | //console.log("Table: ", table); 26 | 27 | if (schemas.tables.hasOwnProperty(table)) { //confirm data of tables 28 | var attrs = schemas.tables[table]["columns"]; 29 | //console.log(attrs); 30 | var attributes_sails = [], view_contents = []; 31 | for (var attr in attrs) { // attributes of a table 32 | if (attrs.hasOwnProperty(attr)) { // attr => name of attribute 33 | //console.log("\n------>>", properties_attribute); 34 | var result = transpile(attrs[attr]); 35 | attributes_sails.push(result.model_content); 36 | view_contents.push(result.view_content); 37 | } 38 | } 39 | 40 | //console.log(view_content); 41 | Models.push({ 42 | model_name:s.camelize(table).trim(), 43 | content: "attributes: { " + (attributes_sails.join(", ")) + " }", 44 | view_content: view_contents 45 | }); 46 | } 47 | } 48 | 49 | /*for (var constraint in schemas.constraints) { 50 | console.log(JSON.stringify(constraint)); 51 | }*/ 52 | 53 | console.log([Models.length, "tables"].join(" ")); 54 | //console.log(JSON.stringify(Models, null, 4)); 55 | 56 | if (folder_models !== "" && folder_models) { 57 | saveModels(folder_models, Models); 58 | } 59 | if (folder_controllers !== "" && folder_controllers) { 60 | saveControllers(folder_controllers, Models); 61 | } 62 | if (folder_views !== "" && folder_views) { 63 | view.generate(Models, folder_views); 64 | } 65 | }) 66 | .catch(function(error) { 67 | console.log(error); 68 | // handle error 69 | }); 70 | }; 71 | 72 | /** 73 | * [transpile: convert all attributes postgres to sailsjs] 74 | * @param {[type]} attributes [description] 75 | * @return {[type]} [description] 76 | */ 77 | function transpile(attributes) { 78 | var type_ = attributes["data_type"]; 79 | var column_name_ = attributes["column_name"]; 80 | var default_value_ = attributes["column_default"]; 81 | var is_nullable_ = attributes["is_nullable"]; 82 | 83 | //console.log(JSON.stringify(attributes)); 84 | return toSailsAttribute(type_, column_name_, default_value_, is_nullable_); 85 | } 86 | 87 | /** 88 | * [toSailsAttribute convert a attribute postgres to sailsjs] 89 | * @param {string} type_ [type object: varying, bigint...] 90 | * @param {string} attrib [name of attribute: mail, id, pet...] 91 | * @param {string} default_value_ [value for default: if boolean --> default: false | true] 92 | * @param {Boolean} is_nullable_ [required?] 93 | * @return {string} [result; attribute sailsjs] 94 | */ 95 | function toSailsAttribute(type_, attrib, default_value_, is_nullable_) { 96 | var sails_attribute_children = []; 97 | var content_view = { 98 | required: (is_nullable_ == "true" || is_nullable_ === true), 99 | default_value: undefined, 100 | name: attrib, 101 | type: undefined 102 | }; 103 | 104 | //console.log(attrib); 105 | if (type_.toLowerCase().indexOf('varying') > -1 || 106 | type_.toLowerCase().indexOf('character') > -1) { 107 | sails_attribute_children.push("type: 'string'"); 108 | content_view.type = "text"; 109 | } else if (type_.toLowerCase().indexOf('int') > -1 || 110 | type_.toLowerCase().indexOf('small') > -1) { //Include smallint 111 | sails_attribute_children.push("type: 'integer'"); 112 | content_view.type = "number"; 113 | } else if (type_.toLowerCase().indexOf('bool') > -1 || 114 | type_.toLowerCase().indexOf('bit') > -1) { 115 | sails_attribute_children.push("type: 'boolean'"); 116 | content_view.type = "checkbox"; 117 | } else if (type_.toLowerCase().indexOf('float') > -1 || 118 | type_.toLowerCase().indexOf('dec') > -1 || //Include decimal 119 | type_.toLowerCase().indexOf('numeric') > -1 || 120 | type_.toLowerCase().indexOf('real') > -1 || 121 | type_.toLowerCase().indexOf('precision') > -1) { 122 | sails_attribute_children.push('type: "float"'); 123 | content_view.type = "number"; 124 | } else if (type_.toLowerCase().indexOf('enum') > -1) { 125 | //sails_attribute_children.push(getEnum(type_)); 126 | } else if (type_.toLowerCase().indexOf('datetime') > -1 || 127 | type_.toLowerCase().indexOf('timestamp') > -1) { 128 | sails_attribute_children.push("type: 'datetime'"); 129 | content_view.type = "datetime"; 130 | } else if (type_.toLowerCase().indexOf('date') > -1) { 131 | sails_attribute_children.push("type: 'date'"); 132 | content_view.type = "date"; 133 | } else if (type_.toLowerCase().indexOf('json') > -1) { 134 | sails_attribute_children.push('type: "json"'); 135 | content_view.type = "textarea"; 136 | } else if (type_.toLowerCase().indexOf('text') > -1) { 137 | sails_attribute_children.push("type: 'text'"); 138 | } else if (type_.toLowerCase().indexOf('bigint') > -1) { //Include smallint 139 | sails_attribute_children.push([ 140 | "type: 'integer',", 141 | 'size: 20' 142 | ].join(" ")); 143 | content_view.type = "number"; 144 | } 145 | 146 | if (default_value_ !== "" && default_value_ !== null) { 147 | default_value_ = default_value_ + ""; 148 | if (!default_value_.startsWith("nextval")) { //No contains nextval 149 | sails_attribute_children.push("default: " + default_value_); 150 | content_view.default_value = default_value_; 151 | } 152 | } 153 | 154 | if (is_nullable_ == "true" || is_nullable_ === true) { 155 | sails_attribute_children.push("required: " + true); 156 | } else { 157 | sails_attribute_children.push("required: " + false); 158 | } 159 | 160 | //console.log(JSON.stringify(content_view)); 161 | 162 | var result = { 163 | model_content: (attrib.toLowerCase() + ": {" + sails_attribute_children.join(',') + "}"), 164 | view_content: JSON.stringify(content_view) 165 | }; 166 | 167 | //console.log("==>",result.model_content); 168 | return result; 169 | } 170 | 171 | // TODO: Detect 172 | function foreignkeys(constraints) { 173 | 174 | } 175 | -------------------------------------------------------------------------------- /generator/save.js: -------------------------------------------------------------------------------- 1 | var ProgressBar = require('progress'); 2 | var to = require('../configs/to'); 3 | require('../configs/color'); 4 | 5 | var gencode = require('gencode'); 6 | var mkdir = require("mkdir-promise"); 7 | var s = require("underscore.string"); 8 | 9 | var Beautifier = require('node-js-beautify'); 10 | var b = new Beautifier(); 11 | 12 | /** 13 | * [save models in the folder Models] 14 | * @param {[type]} dir_folder_controllers [path folder] 15 | * @param {[type]} Models [array json] 16 | * @return {void} [none] 17 | */ 18 | saveControllers = function (dir_folder_controllers, Models) { 19 | var bar2 = new ProgressBar(':bar', { 20 | total: Models.length 21 | }); 22 | 23 | mkdir(dir_folder_controllers).then(() => { 24 | Models.map((model) => { 25 | var name_c = to 26 | .capitalize(model.model_name) 27 | .trim() 28 | .concat("Controller.js"); 29 | gencode.save(b.beautify_js(to.saveController(s.camelize(model.model_name))), dir_folder_controllers, name_c).then((value) => { 30 | bar2.tick(); 31 | if (bar2.complete) { 32 | console.log('Controllers ' + color("[OK]", "green")); 33 | } 34 | }, (err) => { 35 | console.warn([ansi.red.open, "ERROR", err, ansi.red.close].join("\n")); 36 | }); 37 | }); 38 | }, (ex) => { 39 | console.error(ex); 40 | }); 41 | }; 42 | 43 | /** 44 | * [saveModels save models in the folder Models] 45 | * @param {string} dir_folder_model [description] 46 | * @param {array of models: {model_name & content}} Models [Array of models postgres] 47 | */ 48 | saveModels = function (dir_folder_model, Models) { 49 | var bar = new ProgressBar(':bar', { 50 | total: Models.length 51 | }); 52 | 53 | //console.log(Models); 54 | mkdir(dir_folder_model).then(() => { 55 | Models.map((model) => { 56 | //console.log(model); 57 | var name_m = to 58 | .capitalize(model.model_name) 59 | .trim() + ".js"; 60 | gencode.save(b.beautify_js(to.toModel(model.content)), dir_folder_model, name_m).then((value) => { 61 | bar.tick(); 62 | if (bar.complete) { 63 | console.log('Models ' + color("[OK]", "green")); 64 | } 65 | }, (err) => { 66 | console.error(color(err, "red")); 67 | }); 68 | }); 69 | }, (ex) => { 70 | console.error(ex); 71 | }); 72 | }; 73 | -------------------------------------------------------------------------------- /genviews/components.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | require('../configs/route'); 3 | 4 | // content create.hbs 5 | exports.create = function (cb) { 6 | return read("/crud/create.hbs", function (content) { 7 | cb(content); 8 | }); 9 | }; 10 | 11 | // content index.hbs 12 | exports.index = function (cb) { 13 | return read("/crud/index.hbs", function (content) { 14 | cb(content); 15 | }); 16 | }; 17 | 18 | // content update.hbs 19 | exports.edit = function (cb) { 20 | return read("/crud/edit.hbs", function (content) { 21 | cb(content); 22 | }); 23 | }; 24 | 25 | // content show.hbs 26 | exports.show = function (cb) { 27 | return read("/crud/show.hbs", function (content) { 28 | cb(content); 29 | }); 30 | }; 31 | 32 | //Read file hbs and return code 33 | function read(name, cb) { 34 | fs.readFile(concat(__dirname, name), 'utf8', (err, data) => { 35 | if (err) 36 | throw err; 37 | cb(data.toString()); 38 | }); 39 | } -------------------------------------------------------------------------------- /genviews/crud.js: -------------------------------------------------------------------------------- 1 | var Handlebars = require('handlebars'); 2 | var components = require('./components'); 3 | 4 | //Generic function 5 | function op(title, author, model) { 6 | return new Promise(function (resolve, reject) { 7 | var data_create = { 8 | title: title, 9 | author: author, 10 | name: model.model_name, 11 | elements: [] 12 | }; 13 | 14 | model 15 | .view_content 16 | .map((item) => { 17 | var element = JSON.parse(item); 18 | //element => '{"required":true,"name":"descripcion","type":"text"}', 19 | data_create 20 | .elements 21 | .push(element) 22 | }); 23 | 24 | return resolve(data_create); 25 | }); 26 | }; 27 | 28 | //Create "create" html from handlebars 29 | create = function (title, author, model) { 30 | return new Promise(function (resolve, reject) { 31 | var data_create = { 32 | title: title, 33 | author: author, 34 | name: model.model_name, 35 | elements: [] 36 | }; 37 | 38 | model 39 | .view_content 40 | .map((item) => { 41 | var element = JSON.parse(item); 42 | // element => '{"required":true,"name":"descripcion","type":"text"}', 43 | data_create 44 | .elements 45 | .push(element) 46 | }); 47 | 48 | components.create(function (hbs) { 49 | var template = Handlebars.compile(hbs); 50 | var html = template(data_create); 51 | //console.log(html); 52 | resolve(html); 53 | }); 54 | }); 55 | }; 56 | 57 | //Create "edit" html from handlebars 58 | edit = function (title, author, model) { 59 | return new Promise(function (resolve, reject) { 60 | var data_create = { 61 | title: title, 62 | author: author, 63 | name: model.model_name, 64 | elements: [] 65 | }; 66 | 67 | model 68 | .view_content 69 | .map((item) => { 70 | var element = JSON.parse(item); 71 | //element => '{"required":true,"name":"descripcion","type":"text"}', 72 | data_create 73 | .elements 74 | .push(element) 75 | }); 76 | 77 | components.edit(function (hbs) { 78 | var template = Handlebars.compile(hbs); 79 | var html = template(data_create); 80 | //console.log(html); 81 | resolve(html); 82 | }); 83 | }); 84 | }; 85 | 86 | //Create "index" html from handlebars 87 | index = function (title, author, model) { 88 | return new Promise(function (resolve, reject) { 89 | var data_list = { 90 | title: title, 91 | author: author, 92 | name: model.model_name, 93 | elements: [] 94 | }; 95 | 96 | model 97 | .view_content 98 | .map((item) => { 99 | var element = JSON.parse(item); 100 | //element => '{"required":true,"name":"descripcion","type":"text"}', 101 | data_list 102 | .elements 103 | .push(element) 104 | }); 105 | 106 | components.index(function (hbs) { 107 | var template = Handlebars.compile(hbs); 108 | var html = template(data_list); 109 | //console.log(html); 110 | resolve(html); 111 | }); 112 | }); 113 | }; 114 | 115 | //Create "show" html from handlebars 116 | show = function (title, author, model) { 117 | return new Promise(function (resolve, reject) { 118 | var data_list = { 119 | title: title, 120 | author: author, 121 | name: model.model_name, 122 | elements: [] 123 | }; 124 | 125 | model 126 | .view_content 127 | .map((item) => { 128 | var element = JSON.parse(item); 129 | //element => '{"required":true,"name":"descripcion","type":"text"}', 130 | data_list 131 | .elements 132 | .push(element) 133 | }); 134 | 135 | components.show(function (hbs) { 136 | var template = Handlebars.compile(hbs); 137 | var html = template(data_list); 138 | //console.log(html); 139 | resolve(html); 140 | }); 141 | }); 142 | }; 143 | 144 | /* 145 | EXAMPLE: 146 | { 147 | model_name: 'tareasNoRealizadas', 148 | content: 'attributes: { id_tarea: {type: \'integer\',required: true}, descripcion: {type: \'string\',required: true}, fecha_registro: {type: \'datetime\',required: true}, fecha_realizado: {type: \'datetime\',required: true}, realizado: {type: \'boolean\',required: true}, fk_persona_empleado: {type: \'integer\',required: true}, categoria: {type: \'string\',required: true} }', 149 | view_content: ['{"required":true,"name":"id_tarea","type":"number"}', 150 | '{"required":true,"name":"descripcion","type":"text"}', 151 | '{"required":true,"name":"fecha_registro","type":"datetime"}', 152 | '{"required":true,"name":"fecha_realizado","type":"datetime"}', 153 | '{"required":true,"name":"realizado","type":"boolean"}', 154 | '{"required":true,"name":"fk_persona_empleado","type":"number"}', 155 | '{"required":true,"name":"categoria","type":"text"}' 156 | ] 157 | } 158 | */ -------------------------------------------------------------------------------- /genviews/crud/create.hbs: -------------------------------------------------------------------------------- 1 |
2 |

New {{title}}

3 |
By {{author}}
4 | 5 |
6 |
7 | {{#each elements}} 8 |
9 | 10 | 11 |
12 | {{/each}} 13 | 14 |
15 |
16 | Index 17 |
18 |
19 | -------------------------------------------------------------------------------- /genviews/crud/edit.hbs: -------------------------------------------------------------------------------- 1 |
2 |

New {{title}}

3 | 4 |
5 |
6 | 7 | {{#each elements}} 8 |
9 | 10 | 11 |
12 | {{/each}} 13 | 14 |
15 |
16 | Index 17 |
18 |
-------------------------------------------------------------------------------- /genviews/crud/index.hbs: -------------------------------------------------------------------------------- 1 |

{{title}}

2 | 3 | 4 | <% if (result.length == 0) { %> 5 |

6 | 0 {{title}} 7 |

8 | <% } else { %> 9 | 10 | 11 | 12 | 13 | {{#each elements}} 14 | 15 | {{/each}} 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | <% result.forEach((item, i) => { %> 24 | 25 | 28 | 31 | {{#each elements}} 32 | 35 | {{/each}} 36 | 39 | 42 | 45 | 48 | 51 | 52 | <% }) %> 53 | 54 |
#id{{name}}created atupdated at
26 | <%= (i + 1) %> 27 | 29 | <%= item.id %> 30 | 33 | <%= item.{{name}} %> 34 | 37 | <%= item.createdAt %> 38 | 40 | <%= item.updatedAt %> 41 | 43 | Show 44 | 46 | Delete 47 | 49 | Edit 50 |
55 | 56 | <% } %> 57 | 58 |
59 | New -------------------------------------------------------------------------------- /genviews/crud/show.hbs: -------------------------------------------------------------------------------- 1 |

Show {{title}}

2 | 3 | {{#each elements}} 4 |

5 | {{name}}: 6 | <%= element.{{name}} %> 7 |

8 | {{/each}} 9 | 10 |
11 | Edit 12 | New 13 | Back 14 | -------------------------------------------------------------------------------- /genviews/view.js: -------------------------------------------------------------------------------- 1 | var gencode = require('gencode'); 2 | var ansi = require('ansi-styles'); 3 | var mkdir = require("mkdir-promise"); 4 | var ProgressBar = require('progress'); 5 | 6 | require('./crud'); 7 | require('../configs/route'); 8 | require('../configs/color'); 9 | 10 | var author = "sails-inverse-model"; 11 | 12 | exports.generate = function(Models, folder_views) { 13 | mkdir(folder_views).then(() => { 14 | var bar3 = new ProgressBar(':bar', { 15 | total: Models.length 16 | }); 17 | 18 | Models.forEach(model => { 19 | var route = concat(folder_views, model.model_name); 20 | 21 | mkdir(route).then(() => { 22 | create(model.model_name, author, model).then((html) => { 23 | //console.log(html); 24 | gencode.save(html, route, "create.ejs").then((value) => { 25 | //console.log(value); 26 | }, (err) => { 27 | console.log([ansi.red.open, "ERROR", err, ansi.red.close].join("\n")); 28 | }); 29 | }); 30 | 31 | edit(model.model_name, author, model).then((html) => { 32 | gencode.save(html, route, "edit.ejs").then((value) => { 33 | //console.log(value); 34 | }, (err) => { 35 | console.log([ansi.red.open, "ERROR", err, ansi.red.close].join("\n")); 36 | }); 37 | }); 38 | 39 | index(model.model_name, author, model).then((html) => { 40 | gencode.save(html, route, "index.ejs").then((value) => { 41 | //console.log(value); 42 | }, (err) => { 43 | console.log([ansi.red.open, "ERROR", err, ansi.red.close].join("\n")); 44 | }); 45 | }); 46 | 47 | show(model.model_name, author, model).then((html) => { 48 | gencode.save(html, route, "show.ejs").then((value) => { 49 | //console.log(value); 50 | }, (err) => { 51 | console.log([ansi.red.open, "ERROR", err, ansi.red.close].join("\n")); 52 | }); 53 | }); 54 | }); 55 | 56 | bar3.tick(); 57 | if (bar3.complete) { 58 | console.log('Views ' + color("[OK]", "green")); 59 | } 60 | }); 61 | }); 62 | }; 63 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var compiler_my = require('./generator/mysql/compiler_mysql'); 2 | var compiler_pg = require('./generator/postgres/compiler_pg'); 3 | var compiler_mg = require('./generator/mongodb/compiler_mongo'); 4 | 5 | /** 6 | * [generatepg generate mvc from PostgreSQL] 7 | * @param {json} config [config database PostgreSQL; user, password, host, database, schema, port] 8 | * @param {string} folder_models [dir folder models] 9 | * @param {string} folder_controllers [dir folder controllers] 10 | * @param {string} folder_views [dir folder views] 11 | * @return {void} [none] 12 | */ 13 | exports.generatepg = function (config, folder_models, folder_controllers, folder_views) { 14 | compiler_pg.generate(config, folder_models, folder_controllers, folder_views); 15 | }; 16 | 17 | /** 18 | * [generatemy generate mvc from MySQL] 19 | * @param {[json]} config [config database MySQL; user, password, host, database, port] 20 | * @param {string} folder_models [dir folder models] 21 | * @param {string} folder_controllers [dir folder controllers] 22 | * @param {string} folder_views [dir folder views] 23 | * @return {[void]} [none] 24 | */ 25 | exports.generatemy = function (config, folder_models, folder_controllers, folder_views) { 26 | compiler_my.generate(config, folder_models, folder_controllers, folder_views); 27 | }; 28 | 29 | /** 30 | * [generatemg MongoDB] 31 | * @param {string} host [description] 32 | * @param {[number]} port [description] 33 | * @param {string} database [description] 34 | * @param {string} folder_views [description] 35 | * @param {string} folder_models [description] 36 | * @param {string} folder_controllers [description] 37 | * @return {[none]} [description] 38 | */ 39 | exports.generatemg = function (host, port, database, folder_views, folder_models, folder_controllers) { 40 | compiler_mg.generate(host, port, database, folder_views, folder_models, folder_controllers); 41 | }; 42 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sails-inverse-model", 3 | "version": "2.0.7", 4 | "description": "Sails Inverse Model helps you build models, controllers and views JS Sails from any database. In addition, you can quickly and individually generate each model, view, controller or all three at the same time.", 5 | "license": "MIT", 6 | "repository": "https://github.com/juliandavidmr/sails-inverse-model", 7 | "main": "index.js", 8 | "bin": { 9 | "sails-inverse-model": "cli.js" 10 | }, 11 | "author": { 12 | "name": "Julian David", 13 | "url": "https://github.com/juliandavidmr" 14 | }, 15 | "engines": { 16 | "node": ">=0.10.0" 17 | }, 18 | "scripts": { 19 | "test": "", 20 | "publish": "np --no-yarn --no-cleanup" 21 | }, 22 | "files": [ 23 | "index.js", 24 | "cli.js", 25 | "generator/", 26 | "configs/", 27 | "genviews/", 28 | "scanners/" 29 | ], 30 | "keywords": [ 31 | "cli-app", 32 | "sailsjs", 33 | "generator", 34 | "model", 35 | "controller", 36 | "views", 37 | "hbs", 38 | "json", 39 | "mysql", 40 | "prompt", 41 | "auto", 42 | "models", 43 | "generate", 44 | "file", 45 | "sql", 46 | "api", 47 | "waterline" 48 | ], 49 | "dependencies": { 50 | "ansi-styles": "^3.2.1", 51 | "async": "^2.6.1", 52 | "gencode": "^1.0.4", 53 | "handlebars": "^4.0.12", 54 | "meow": "^3.5.0", 55 | "mkdir-promise": "^1.0.0", 56 | "mondongo": "^1.0.0", 57 | "mysqldesc": "^1.1.4", 58 | "node-js-beautify": "^0.1.0", 59 | "pg-json-schema-export": "^0.13.7", 60 | "progress": "^2.0.1", 61 | "underscore.string": "^3.3.5" 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /scanners/data.json: -------------------------------------------------------------------------------- 1 | { 2 | "ignore": [ 3 | "/*", 4 | "--", 5 | "create database", 6 | "use", 7 | "set", 8 | "@", 9 | "delimiter", 10 | "create trigger", 11 | "after", 12 | "call", 13 | "for", 14 | "each", 15 | "row", 16 | "begin", 17 | "call", 18 | "new", 19 | "end", 20 | "create definer", 21 | "declare", 22 | "leave", 23 | "if", 24 | "open", 25 | "fetch", 26 | "close" 27 | ], 28 | "start": [ 29 | "create table if not exists", 30 | "create table" 31 | ], 32 | "contains": [ 33 | "enum(", 34 | "primary key (", 35 | "unique key" 36 | ], 37 | "attr": [ 38 | "primary key (", 39 | "key", 40 | "unique key", 41 | "constraint" 42 | ] 43 | } 44 | -------------------------------------------------------------------------------- /scanners/scanner_mysql.js: -------------------------------------------------------------------------------- 1 | var gencode = require('gencode'); 2 | var data = require('./data.json'); 3 | 4 | exports.generate = function (pathsql, cb) { 5 | gencode 6 | .utils 7 | .toArray(pathsql, 'utf8', '\n') 8 | .then((value) => { //Too: \n, \t, -, etc. 9 | var allData = ""; 10 | var tables = [], 11 | dataValid = []; 12 | value.map((item) => { 13 | item = item 14 | .toString() 15 | .trim() 16 | .toLowerCase(); 17 | 18 | if (!isComment(item)) { 19 | allData += item; 20 | } 21 | }); 22 | var splits = allData.split(";"); 23 | for (var i = 0; i < splits.length; i++) { 24 | if (isValid(splits[i])) { 25 | dataValid.push(splits[i]); 26 | } 27 | } 28 | 29 | for (var i = 0; i < dataValid.length; i++) { 30 | if (dataValid[i].toString().toLowerCase().trim().startsWith('create table')) { 31 | tables.push(verifyContains(dataValid[i].toString())); 32 | } 33 | } 34 | getTablesJSON(tables, function (err, result) { 35 | //console.log(":>", JSON.stringify(result, null, 2)); 36 | cb(err, result); 37 | }); 38 | 39 | }, (error) => { 40 | cb(error, null); 41 | //console.log("ERROR=>", error); 42 | }); 43 | }; 44 | 45 | //exports.generate("../test/script.sql"); 46 | 47 | function verifyContains(item) { 48 | var result = ""; 49 | var state = true; 50 | var start, 51 | end = 0; 52 | var add; 53 | for (var i = 0; i < data.contains.length; i++) { 54 | result = ""; 55 | state = true; 56 | while (state) { 57 | start = item.indexOf(data.contains[i]); 58 | if (start != -1) { 59 | end = item 60 | .substring(start, item.length) 61 | .indexOf(")") + start; 62 | result += item.substring(0, start); 63 | add = item.substring(start, end); 64 | while (add.indexOf(",") != -1) { 65 | add = add.replace(",", "-"); 66 | } 67 | result += add; 68 | item = item.substring(end, item.length); 69 | } else { 70 | state = false; 71 | } 72 | } 73 | result += item; 74 | item = result; 75 | } 76 | return result; 77 | } 78 | 79 | function cleanItem(item) { 80 | var line = item; 81 | for (var i = 0; i < data.start.length; i++) { 82 | if (item.startsWith(data.start[i])) { 83 | line = item.substring(data.start[i].length + 1, item.length); 84 | break; 85 | } 86 | } 87 | return line; 88 | } 89 | 90 | function getTableName(item) { 91 | var firstLine = item.indexOf('('); 92 | var name = item 93 | .substring(0, firstLine) 94 | .trim() 95 | .replace('`', '') 96 | .replace('`', ''); 97 | return name; 98 | } 99 | 100 | function isAtribute(line) { 101 | for (var j = 0; j < data.attr.length; j++) { 102 | if (line.toString().trim().startsWith(data.attr[j])) { 103 | return false; 104 | } 105 | } 106 | return true; 107 | } 108 | 109 | function getAtributes(item) { 110 | var attrLines = item.indexOf('('); 111 | item = item.substring(attrLines + 1, item.length); 112 | var atributes = []; 113 | var lines = item.split(','); 114 | var split; 115 | for (var i = 0; i < lines.length; i++) { 116 | lines[i] = lines[i].replace("not null", "not_null"); 117 | if (isAtribute(lines[i])) { 118 | 119 | split = lines[i] != "" 120 | ? lines[i].split(" ") 121 | : ""; 122 | atributes.push({ 123 | Name: getValue(0, split), 124 | Type: getValue(1, split), 125 | Size: getValue(2, split), 126 | NotNull: split.length > 2, 127 | AI: split.length > 3 128 | }); 129 | } 130 | } 131 | return atributes; 132 | } 133 | 134 | function getValue(pos, values) { 135 | var result = ""; 136 | 137 | switch (pos) { 138 | case 0: 139 | result = values[pos] 140 | .replace('`', '') 141 | .replace('`', ''); 142 | break; 143 | case 1: 144 | var val = values[pos]; 145 | if (!val.startsWith("enum")) { 146 | var start = val.indexOf("("); 147 | result = start == -1 148 | ? val 149 | : val.substring(0, start); 150 | } else { 151 | result = val; 152 | } 153 | break; 154 | case 2: 155 | var val = values[1]; 156 | if (!val.startsWith("enum")) { 157 | var start = val.indexOf("("); 158 | result = start == -1 159 | ? "" 160 | : val.substring(start + 1, val.indexOf(")")); 161 | } else { 162 | result = ""; 163 | } 164 | break; 165 | default: 166 | } 167 | return result; 168 | } 169 | 170 | function getTablesJSON(tables, cb) { 171 | var tablesJSON = []; 172 | var item, 173 | line; 174 | for (var i = 0; i < tables.length; i++) { 175 | item = tables[i] 176 | .toString() 177 | .toLowerCase(); 178 | tables[i] = cleanItem(item); 179 | 180 | tablesJSON.push({ 181 | table_name: getTableName(tables[i]), 182 | atr: getAtributes(tables[i]) 183 | }); 184 | } 185 | console.log("d: " + tablesJSON.length); 186 | //console.log(JSON.stringify(tablesJSON, null, 4)); 187 | cb(null, tablesJSON); 188 | } 189 | 190 | function isComment(line) { 191 | return line 192 | .trim() 193 | .startsWith('--'); 194 | } 195 | 196 | function isValid(line) { 197 | if (line !== "") { 198 | for (var i = 0; i < data.ignore.length; i++) { 199 | if (line.startsWith(data.ignore[i])) { 200 | return false; 201 | } 202 | } 203 | } else { 204 | return false; 205 | } 206 | return true; 207 | } --------------------------------------------------------------------------------