-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SQL Generation #31
SQL Generation #31
Changes from all commits
0f46477
70b3e00
80522d4
e834b0b
228ebc4
b3c23d1
c435d44
5821399
e059f22
da01305
3cb409a
3110924
9c5fb29
a45b93f
31ce282
431e786
9ee0209
5cd2536
e8dd68a
ad3139b
5b08cf6
aff1574
0f670c8
35f96ad
3296cab
743656a
f6a61b5
b2d42f6
b7c8d8d
f3b5da6
866aae6
e11d697
a8f20c0
4b16cda
22f8643
208b982
d4f8fea
a57d5d3
cd802d4
d9eefed
ae66662
cc62b23
ea3daca
9b05448
19889da
2148f3f
273bc9c
7389e59
281c883
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,3 +3,4 @@ node_modules | |
coverage | ||
npm-debug.log | ||
.eslintrc* | ||
config.env |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
verbose: false | ||
instrumentation: | ||
root: ./src | ||
excludes: [] | ||
include-all-sources: true | ||
check: | ||
global: | ||
branches : 100 | ||
functions : 100 | ||
lines : 100 | ||
statements : 100 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
'use strict'; | ||
|
||
var Hapi = require('hapi'); | ||
var Abase = require('../lib/index.js'); | ||
var server = new Hapi.Server(); | ||
var config = require('./config.json'); | ||
|
||
require('env2')('config.env'); | ||
|
||
server.connection({ port: process.env.PORT || 8888 }); | ||
|
||
server.register({ | ||
register: Abase, options: config | ||
}, function (err) { | ||
if (err) { | ||
throw err; | ||
} | ||
|
||
server.start(function () { | ||
server.log('Server started'); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,25 +1,25 @@ | ||
'use strict'; | ||
|
||
/** | ||
* Initialse with the default values the schema if they are not defined Yet | ||
* Write schema in the file if the default values are added | ||
* @param {object} schema - the user schema object | ||
* @return {boolean} - any changes apply to the schema | ||
*/ | ||
var defaultSchema = { | ||
email: { | ||
type: 'email' | ||
}, | ||
password: { | ||
type: 'password' | ||
} | ||
email: { type: 'email' }, | ||
password: { type: 'password' } | ||
}; | ||
|
||
module.exports = function (schema) { | ||
var anyChanges = false; | ||
Object.keys(defaultSchema).forEach(function(field) { | ||
if(!schema.hasOwnProperty(field)){ | ||
|
||
Object.keys(defaultSchema).forEach(function (field) { | ||
if (!schema.hasOwnProperty(field)) { | ||
schema[field] = defaultSchema[field]; | ||
anyChanges = true; | ||
}; | ||
} | ||
}); | ||
|
||
return anyChanges; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
'use strict'; | ||
|
||
var Joi = require('joi'); | ||
|
||
var mapObj = require('./create_table_map.js').mapObj; | ||
|
||
// non empty, alphanumeric, no leading number, less than 64 | ||
var dbNameRegEx = /^[A-Za-z_]\w{0,62}$/; | ||
var fieldTypes = Object.keys(mapObj); | ||
|
||
var fieldSchema = Joi.object() | ||
.keys({ type: Joi.any().valid(fieldTypes) }) | ||
.unknown() | ||
; | ||
var configSchema = Joi.object().keys({ | ||
table_name: Joi.string().regex(dbNameRegEx).required(), // eslint-disable-line | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. purely out of curiosity, why do these lines need to be disabled for eslint? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @nelsonic because there's a rule that says max of 2 chained method calls per line. Bit annoying in this case. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, lame. although for |
||
fields: Joi.object().pattern(dbNameRegEx, fieldSchema).required() // eslint-disable-line | ||
}); | ||
|
||
module.exports = function (config) { | ||
return Joi.assert(config, configSchema); | ||
}; | ||
|
||
module.exports.dbNameRegEx = dbNameRegEx; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
'use strict'; | ||
|
||
var mapObj = { | ||
number: function (opts) { | ||
return opts.integer ? 'BIGINT' : 'DOUBLE PRECISION'; | ||
}, | ||
string: function (opts) { | ||
var length = opts.max || 80; | ||
|
||
return 'VARCHAR(' + length + ')'; | ||
}, | ||
boolean: function () { | ||
return 'BOOLEAN'; | ||
}, | ||
date: function (opts) { | ||
return opts.timestamp ? 'TIMESTAMP' : 'DATE'; | ||
} | ||
}; | ||
|
||
function mapper (name, type, options) { | ||
var opts = options || {}; | ||
|
||
return name + ' ' + mapObj[type](opts); | ||
} | ||
|
||
module.exports = mapper; | ||
module.exports.mapObj = mapObj; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
'use strict'; | ||
|
||
var sqlGen = require('./sql_gen.js'); | ||
var configValidator = require('./config_validator.js'); | ||
|
||
var methods = { init: function (client, config, _, cb) { | ||
configValidator(config); | ||
|
||
return client.query(sqlGen.init(config), cb); | ||
} }; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. does this pass the linter? |
||
|
||
['select', 'update', 'delete', 'insert'].forEach(function (method) { | ||
methods[method] = function (client, config, options, cb) { | ||
var tableName = config.table_name; | ||
var args = sqlGen[method](tableName, options).concat([cb]); | ||
|
||
return client.query.apply(client, args); | ||
}; | ||
}); | ||
|
||
module.exports = methods; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,28 +1,30 @@ | ||
'use strict'; | ||
|
||
var addDefaultValues = require('./add_default_values.js'); | ||
var loadSchema = require('./load_schema.js'); | ||
var updateSchema = require('./update_schema.js'); | ||
var fs = require('fs'); | ||
|
||
module.exports = function (server, options, next) { | ||
if (!options.hasOwnProperty('user_schema_path')) { | ||
return next('Error: user_schema_path is not defined, please define a user_schema_path'); | ||
return next(new Error('user_schema_path is not defined')); | ||
} | ||
|
||
loadSchema(options.user_schema_path, function(errorLoad, schema) { | ||
return loadSchema(options.user_schema_path, function (errorLoad, schema) { | ||
if (errorLoad) { | ||
return next(errorLoad); | ||
} | ||
|
||
if (addDefaultValues(schema)) { | ||
updateSchema(options.user_schema_path, schema, function(errorUpdateSchema) { | ||
return next(errorUpdateSchema); | ||
}); | ||
} else { | ||
if (!addDefaultValues(schema)) { | ||
return next(); | ||
} | ||
|
||
return updateSchema( | ||
options.user_schema_path, | ||
schema, | ||
function (errorUpdateSchema) { | ||
return next(errorUpdateSchema); | ||
}); | ||
}); | ||
}; | ||
|
||
module.exports.attributes = { | ||
name: 'Abase' | ||
}; | ||
module.exports.attributes = { name: 'Abase' }; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,20 +1,30 @@ | ||
'use strict'; | ||
|
||
var fs = require('fs'); | ||
|
||
/** | ||
* load the shema user | ||
* load the schema user | ||
* @param {sting} schemaPath - the file path of the schema | ||
* @param {function} cb - callback with error and the schema object | ||
* @returns {void} | ||
*/ | ||
var fs = require('fs'); | ||
|
||
module.exports = function (schemaPath, cb) { | ||
fs.readFile(schemaPath, function (err, data) { | ||
var schema; | ||
|
||
if (err) { | ||
return cb('Error: sorry impossible to read the file at ' + schemaPath); | ||
} | ||
|
||
try { | ||
var schema = JSON.parse(data); | ||
schema = JSON.parse(data); | ||
} catch (parseError) { | ||
return cb('Error: the schema user file contains unconventianal type, please make sure an schema object is defined'); | ||
return cb( | ||
'Error: the schema user file contains unconventianal type,' | ||
+ 'please make sure an schema object is defined' | ||
); | ||
} | ||
return cb(undefined, schema); | ||
|
||
return cb(null, schema); | ||
}); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
'use strict'; | ||
|
||
var mapper = require('./create_table_map.js'); | ||
var _ = require('./utils.js'); | ||
|
||
|
||
function paramStr (columns, opts) { | ||
var offset = (opts && opts.offset) || 0; | ||
var assign = (opts && opts.assign) || false; | ||
|
||
return columns.map(function (k, i) { | ||
var suff = '$' + (1 + i + (offset || 0)); | ||
var pref = assign ? k + '=' : ''; | ||
|
||
return pref + suff; | ||
}); | ||
} | ||
|
||
|
||
function processWhere (where, query, values) { | ||
var keys = Object.keys(where); | ||
var conds = paramStr(keys, { | ||
offset: values.length, assign: true | ||
}); | ||
var vals = _.values(where, keys); | ||
|
||
return { | ||
query: query.concat('WHERE').concat(conds.join(', ')), | ||
values: values.concat(vals) | ||
}; | ||
} | ||
|
||
|
||
exports.init = function init (config) { | ||
var tableName = config.table_name; | ||
var fields = config.fields; | ||
|
||
var columns = Object.keys(fields).map(function (key) { | ||
var type = fields[key].type; | ||
var opts = _.except(['type'], fields[key]); | ||
|
||
return mapper(key, type, opts); | ||
}); | ||
|
||
return ['CREATE TABLE IF NOT EXISTS "' + tableName + '"'] | ||
.concat('(' + columns.join(', ') + ')') | ||
.join(' ') | ||
.trim(); | ||
}; | ||
|
||
|
||
exports.select = function select (tableName, options) { | ||
var columns = options.select || ['*']; | ||
var values = []; | ||
var query = ['SELECT'] | ||
.concat(columns.join(', ')) | ||
.concat('FROM') | ||
.concat('"' + tableName + '"'); | ||
var result; | ||
|
||
if (options.where) { | ||
result = processWhere(options.where, query, values); | ||
query = result.query; | ||
values = result.values; | ||
} | ||
|
||
query = query.join(' ').trim(); | ||
|
||
return [query, values]; | ||
}; | ||
|
||
|
||
exports.insert = function insert (tableName, options) { | ||
var fields = options.fields || {}; | ||
var columns = Object.keys(fields); | ||
var values = _.values(fields, columns); | ||
var params = paramStr(columns); | ||
|
||
var query = ['INSERT INTO "' + tableName + '"'] | ||
.concat('(' + columns.join(', ') + ')') | ||
.concat('VALUES') | ||
.concat('(' + params.join(', ') + ')') | ||
.join(' ') | ||
.trim(); | ||
|
||
return [query, values]; | ||
}; | ||
|
||
|
||
exports.update = function update (tableName, options) { | ||
var fields = options.fields || {}; | ||
var columns = Object.keys(fields); | ||
var conditions = paramStr(columns, { assign: true }); | ||
var values = _.values(fields, columns); | ||
|
||
var query = ['UPDATE "' + tableName + '"'] | ||
.concat('SET') | ||
.concat(conditions.join(', ')); | ||
var result; | ||
|
||
if (options.where) { | ||
result = processWhere(options.where, query, values); | ||
query = result.query; | ||
values = result.values; | ||
} | ||
|
||
query = query.join(' ').trim(); | ||
|
||
return [query, values]; | ||
}; | ||
|
||
|
||
exports.delete = function _delete (tableName, options) { | ||
var query = ['DELETE FROM "' + tableName + '"']; | ||
var values = []; | ||
var result = processWhere(options.where, query, values); | ||
|
||
query = result.query; | ||
values = result.values; | ||
|
||
query = query.join(' ').trim(); | ||
|
||
return [query, values]; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,14 @@ | ||
'use strict'; | ||
|
||
var fs = require('fs'); | ||
|
||
/** | ||
* Update the schema json file | ||
* @param {string} user_schema_path, the path of the schema file | ||
* @param {string} userSchemaPath, the path of the schema file | ||
* @param {object} schema - the schema user object | ||
* @param {function} cb - callback with error | ||
* @returns {void} | ||
*/ | ||
|
||
var fs = require('fs'); | ||
module.exports = function (user_schema_path, schema, cb) { | ||
fs.writeFile(user_schema_path, JSON.stringify(schema), 'utf8', cb); | ||
module.exports = function (userSchemaPath, schema, cb) { | ||
fs.writeFile(userSchemaPath, JSON.stringify(schema), 'utf8', cb); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would like a comment here explaining this regex
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
WIll do!