sql-ddl-sync
Advanced tools
Comparing version 0.1.4 to 0.3.11
@@ -9,4 +9,4 @@ var SQL = require("../SQL"); | ||
exports.hasCollection = function (db, name, cb) { | ||
db.query("SHOW TABLES LIKE ?", [ name ], function (err, rows) { | ||
exports.hasCollection = function (driver, name, cb) { | ||
driver.execQuery("SHOW TABLES LIKE ?", [ name ], function (err, rows) { | ||
if (err) return cb(err); | ||
@@ -18,4 +18,24 @@ | ||
exports.getCollectionProperties = function (db, name, cb) { | ||
db.query("SHOW COLUMNS FROM ??", [ name ], function (err, cols) { | ||
exports.addPrimaryKey = function(driver, tableName, columnName, cb){ | ||
var sql = "ALTER TABLE ?? ADD CONSTRAINT ?? PRIMARY KEY(??);" | ||
return driver.execQuery(sql, [tableName, columnName + "PK", columnName] , cb); | ||
}; | ||
exports.dropPrimaryKey = function(driver, tableName, columnName, cb){ | ||
var sql = "ALTER TABLE ?? DROP PRIMARY KEY;"; | ||
return driver.execQuery(sql, [tableName], cb); | ||
}; | ||
exports.addForeignKey = function(driver, tableName, options, cb){ | ||
var sql = " ALTER TABLE ?? ADD CONSTRAINT ?? FOREIGN KEY(??) REFERENCES ??(??)"; | ||
return driver.execQuery(sql, [tableName, options.name + "_fk", options.name, options.references.table, options.references.column], cb); | ||
}; | ||
exports.dropForeignKey = function(driver, tableName, columnName, cb){ | ||
var sql = "ALTER TABLE " + tableName + " DROP FOREIGN KEY "+ columnName + "_fk;"; | ||
return driver.execQuery(sql, [tableName, columnName + '_fk'], cb); | ||
}; | ||
exports.getCollectionProperties = function (driver, name, cb) { | ||
driver.execQuery("SHOW COLUMNS FROM ??", [ name ], function (err, cols) { | ||
if (err) return cb(err); | ||
@@ -60,4 +80,3 @@ | ||
case "INT": | ||
column.type = "number"; | ||
column.rational = false; | ||
column.type = "integer"; | ||
column.size = 4; // INT | ||
@@ -86,4 +105,3 @@ for (var k in columnSizes.integer) { | ||
} else { | ||
column.type = "number"; | ||
column.rational = false; | ||
column.type = "integer"; | ||
} | ||
@@ -128,18 +146,18 @@ break; | ||
exports.createCollection = function (db, name, columns, primary, cb) { | ||
return db.query(SQL.CREATE_TABLE({ | ||
exports.createCollection = function (driver, name, columns, keys, cb) { | ||
return driver.execQuery(SQL.CREATE_TABLE({ | ||
name : name, | ||
columns : columns, | ||
primary : primary | ||
}, exports), cb); | ||
keys : keys | ||
}, driver), cb); | ||
}; | ||
exports.dropCollection = function (db, name, cb) { | ||
return db.query(SQL.DROP_TABLE({ | ||
exports.dropCollection = function (driver, name, cb) { | ||
return driver.execQuery(SQL.DROP_TABLE({ | ||
name : name | ||
}, exports), cb); | ||
}, driver), cb); | ||
}; | ||
exports.addCollectionColumn = function (db, name, column, after_column, cb) { | ||
return db.query(SQL.ALTER_TABLE_ADD_COLUMN({ | ||
exports.addCollectionColumn = function (driver, name, column, after_column, cb) { | ||
return driver.execQuery(SQL.ALTER_TABLE_ADD_COLUMN({ | ||
name : name, | ||
@@ -149,21 +167,30 @@ column : column, | ||
first : !after_column | ||
}, exports), cb); | ||
}, driver), cb); | ||
}; | ||
exports.modifyCollectionColumn = function (db, name, column, cb) { | ||
return db.query(SQL.ALTER_TABLE_MODIFY_COLUMN({ | ||
exports.renameCollectionColumn = function (driver, name, oldColName, newColName, cb) { | ||
return cb("MySQL doesn't support simple column rename"); | ||
}; | ||
exports.modifyCollectionColumn = function (driver, name, column, cb) { | ||
return driver.execQuery(SQL.ALTER_TABLE_MODIFY_COLUMN({ | ||
name : name, | ||
column : column | ||
}, exports), cb); | ||
}, driver), cb); | ||
}; | ||
exports.dropCollectionColumn = function (db, name, column, cb) { | ||
return db.query(SQL.ALTER_TABLE_DROP_COLUMN({ | ||
exports.dropCollectionColumn = function (driver, name, column, cb) { | ||
return driver.execQuery(SQL.ALTER_TABLE_DROP_COLUMN({ | ||
name : name, | ||
column : column | ||
}, exports), cb); | ||
}, driver), cb); | ||
}; | ||
exports.getCollectionIndexes = function (db, name, cb) { | ||
db.query("SHOW INDEX FROM ??", [ name ], function (err, rows) { | ||
exports.getCollectionIndexes = function (driver, name, cb) { | ||
var q = ""; | ||
q += "SELECT index_name, column_name, non_unique "; | ||
q += "FROM information_schema.statistics "; | ||
q += "WHERE table_schema = ? AND table_name = ?"; | ||
driver.execQuery(q, [driver.config.database, name], function (err, rows) { | ||
if (err) return cb(err); | ||
@@ -175,21 +202,27 @@ | ||
exports.addIndex = function (db, name, unique, collection, columns, cb) { | ||
return db.query(SQL.CREATE_INDEX({ | ||
name : name, | ||
exports.addIndex = function (driver, indexName, unique, collection, columns, cb) { | ||
return driver.execQuery(SQL.CREATE_INDEX({ | ||
name : indexName, | ||
unique : unique, | ||
collection : collection, | ||
columns : columns | ||
}, exports), cb); | ||
}, driver), cb); | ||
}; | ||
exports.removeIndex = function (db, name, collection, cb) { | ||
return db.query(SQL.DROP_INDEX({ | ||
exports.removeIndex = function (driver, collection, name, cb) { | ||
return driver.execQuery(SQL.DROP_INDEX({ | ||
name : name, | ||
collection : collection | ||
}, exports), cb); | ||
}, driver), cb); | ||
}; | ||
exports.getType = function (collection, name, property) { | ||
var type = false; | ||
exports.getType = function (collection, property, driver) { | ||
var type = false; | ||
var customType = null; | ||
if (property.type == 'number' && property.rational === false) { | ||
property.type = 'integer'; | ||
delete property.rational; | ||
} | ||
switch (property.type) { | ||
@@ -203,8 +236,7 @@ case "text": | ||
break; | ||
case "integer": | ||
type = columnSizes.integer[property.size || 4]; | ||
break; | ||
case "number": | ||
if (property.rational) { | ||
type = columnSizes.floating[property.size || 4]; | ||
} else { | ||
type = columnSizes.integer[property.size || 4]; | ||
} | ||
type = columnSizes.floating[property.size || 4]; | ||
break; | ||
@@ -214,3 +246,3 @@ case "serial": | ||
property.serial = true; | ||
property.primary = true; | ||
property.key = true; | ||
type = "INT(11)"; | ||
@@ -237,3 +269,3 @@ break; | ||
case "enum": | ||
type = "ENUM (" + property.values.map(exports.escapeVal) + ")"; | ||
type = "ENUM (" + property.values.map(driver.query.escapeVal) + ")"; | ||
break; | ||
@@ -243,2 +275,7 @@ case "point": | ||
break; | ||
default: | ||
customType = driver.customTypes[property.type]; | ||
if (customType) { | ||
type = customType.datastoreType() | ||
} | ||
} | ||
@@ -259,3 +296,3 @@ | ||
if (property.hasOwnProperty("defaultValue")) { | ||
type += " DEFAULT " + exports.escapeVal(property.defaultValue); | ||
type += " DEFAULT " + driver.query.escapeVal(property.defaultValue); | ||
} | ||
@@ -269,55 +306,2 @@ | ||
exports.escapeId = function () { | ||
return Array.prototype.slice.apply(arguments).map(function (el) { | ||
return "`" + el.replace(/`/g, '``') + "`"; | ||
}).join("."); | ||
}; | ||
exports.escapeVal = function (val, timeZone) { | ||
if (val === undefined || val === null) { | ||
return 'NULL'; | ||
} | ||
if (Buffer.isBuffer(val)) { | ||
return bufferToString(val); | ||
} | ||
if (Array.isArray(val)) { | ||
return arrayToList(val, timeZone || "local"); | ||
} | ||
if (util.isDate(val)) { | ||
val = dateToString(val, timeZone || "local"); | ||
} else { | ||
switch (typeof val) { | ||
case 'boolean': | ||
return (val) ? 'true' : 'false'; | ||
case 'number': | ||
if (!isFinite(val)) { | ||
val = val.toString(); | ||
break; | ||
} | ||
return val + ''; | ||
case "object": | ||
return objectToValues(val, timeZone || "local"); | ||
case "function": | ||
return val(exports); | ||
} | ||
} | ||
val = val.replace(/[\0\n\r\b\t\\\'\"\x1a]/g, function(s) { | ||
switch(s) { | ||
case "\0": return "\\0"; | ||
case "\n": return "\\n"; | ||
case "\r": return "\\r"; | ||
case "\b": return "\\b"; | ||
case "\t": return "\\t"; | ||
case "\x1a": return "\\Z"; | ||
default: return "\\" + s; | ||
} | ||
}); | ||
return "'" + val + "'"; | ||
}; | ||
function convertIndexRows(rows) { | ||
@@ -327,13 +311,13 @@ var indexes = {}; | ||
for (var i = 0; i < rows.length; i++) { | ||
if (rows[i].Key_name == 'PRIMARY') { | ||
if (rows[i].index_name == 'PRIMARY') { | ||
continue; | ||
} | ||
if (!indexes.hasOwnProperty(rows[i].Key_name)) { | ||
indexes[rows[i].Key_name] = { | ||
if (!indexes.hasOwnProperty(rows[i].index_name)) { | ||
indexes[rows[i].index_name] = { | ||
columns : [], | ||
unique : (rows[i].Non_unique == 0) | ||
unique : (rows[i].non_unique == 0) | ||
}; | ||
} | ||
indexes[rows[i].Key_name].columns.push(rows[i].Column_name); | ||
indexes[rows[i].index_name].columns.push(rows[i].column_name); | ||
} | ||
@@ -344,24 +328,2 @@ | ||
function objectToValues(object, timeZone) { | ||
var values = []; | ||
for (var key in object) { | ||
var value = object[key]; | ||
if(typeof value === 'function') { | ||
continue; | ||
} | ||
values.push(exports.escapeId(key) + ' = ' + exports.escapeVal(value, timeZone)); | ||
} | ||
return values.join(', '); | ||
} | ||
function arrayToList(array, timeZone) { | ||
return "(" + array.map(function(v) { | ||
if (Array.isArray(v)) return arrayToList(v); | ||
return exports.escapeVal(v, timeZone); | ||
}).join(', ') + ")"; | ||
} | ||
function bufferToString(buffer) { | ||
@@ -368,0 +330,0 @@ var hex = ''; |
@@ -9,15 +9,14 @@ var util = require("util"); | ||
exports.hasCollection = function (db, name, cb) { | ||
db.query("SELECT * FROM information_schema.tables WHERE table_name = $1", [ name ], function (err, result) { | ||
exports.hasCollection = function (driver, name, cb) { | ||
driver.execQuery("SELECT * FROM information_schema.tables WHERE table_name = ?", [ name ], function (err, rows) { | ||
if (err) return cb(err); | ||
return cb(null, result.rows.length > 0); | ||
return cb(null, rows.length > 0); | ||
}); | ||
}; | ||
exports.getCollectionProperties = function (db, name, cb) { | ||
db.query("SELECT * FROM information_schema.columns WHERE table_name = $1", [ name ], function (err, result) { | ||
exports.getCollectionProperties = function (driver, name, cb) { | ||
driver.execQuery("SELECT * FROM information_schema.columns WHERE table_name = ?", [ name ], function (err, cols) { | ||
if (err) return cb(err); | ||
var cols = result.rows; | ||
var columns = {}, m; | ||
@@ -27,23 +26,27 @@ | ||
var column = {}; | ||
var dCol = cols[i]; | ||
if (cols[i].is_nullable.toUpperCase() == "NO") { | ||
if (dCol.is_nullable.toUpperCase() == "NO") { | ||
column.required = true; | ||
} | ||
if (cols[i].column_default !== null) { | ||
m = cols[i].column_default.match(/^'(.+)'::/); | ||
if (dCol.column_default !== null) { | ||
m = dCol.column_default.match(/^'(.+)'::/); | ||
if (m) { | ||
column.defaultValue = m[1]; | ||
} else { | ||
column.defaultValue = cols[i].column_default; | ||
column.defaultValue = dCol.column_default; | ||
} | ||
} | ||
switch (cols[i].data_type.toUpperCase()) { | ||
switch (dCol.data_type.toUpperCase()) { | ||
case "SMALLINT": | ||
case "INTEGER": | ||
case "BIGINT": | ||
column.type = "number"; | ||
column.rational = false; | ||
if (typeof dCol.column_default == 'string' && dCol.column_default.indexOf('nextval(') == 0) { | ||
column.type = "serial"; | ||
} else { | ||
column.type = "integer"; | ||
} | ||
for (var k in columnSizes.integer) { | ||
if (columnSizes.integer[k] == cols[i].data_type.toUpperCase()) { | ||
if (columnSizes.integer[k] == dCol.data_type.toUpperCase()) { | ||
column.size = k; | ||
@@ -59,3 +62,3 @@ break; | ||
for (var k in columnSizes.floating) { | ||
if (columnSizes.floating[k] == cols[i].data_type.toUpperCase()) { | ||
if (columnSizes.floating[k] == dCol.data_type.toUpperCase()) { | ||
column.size = k; | ||
@@ -77,10 +80,13 @@ break; | ||
break; | ||
case "TEXT": | ||
column.type = "text"; | ||
break; | ||
case "CHARACTER VARYING": | ||
column.type = "text"; | ||
if (cols[i].character_maximum_length) { | ||
column.size = cols[i].character_maximum_length; | ||
if (dCol.character_maximum_length) { | ||
column.size = dCol.character_maximum_length; | ||
} | ||
break; | ||
case "USER-DEFINED": | ||
if (cols[i].udt_name.match(/_enum_/)) { | ||
if (dCol.udt_name.match(/_enum_/)) { | ||
column.type = "enum"; | ||
@@ -91,34 +97,69 @@ column.values = []; | ||
default: | ||
console.log(cols[i]); | ||
return cb(new Error("Unknown column type '" + cols[i].data_type + "'")); | ||
return cb(new Error("Unknown column type '" + dCol.data_type + "'")); | ||
} | ||
columns[cols[i].column_name] = column; | ||
columns[dCol.column_name] = column; | ||
} | ||
return checkColumnTypes(db, name, columns, cb); | ||
return checkColumnTypes(driver, name, columns, cb); | ||
}); | ||
}; | ||
exports.createCollection = function (db, name, columns, primary, cb) { | ||
return db.query(SQL.CREATE_TABLE({ | ||
exports.createCollection = function (driver, name, columns, keys, cb) { | ||
return driver.execQuery(SQL.CREATE_TABLE({ | ||
driver : driver, | ||
name : name, | ||
columns : columns, | ||
primary : primary | ||
}, exports), cb); | ||
keys : keys | ||
}, driver), cb); | ||
}; | ||
exports.dropCollection = function (db, name, cb) { | ||
return db.query(SQL.DROP_TABLE({ | ||
exports.dropCollection = function (driver, name, cb) { | ||
return driver.execQuery(SQL.DROP_TABLE({ | ||
driver : driver, | ||
name : name | ||
}, exports), cb); | ||
}, driver), cb); | ||
}; | ||
exports.addCollectionColumn = function (db, name, column, after_column, cb) { | ||
var sql = "ALTER TABLE " + exports.escapeId(name) + " ADD " + column; | ||
exports.addPrimaryKey = function(driver, tableName, columnName, cb){ | ||
var sql = "ALTER TABLE ?? ADD CONSTRAINT ?? PRIMARY KEY(??);" | ||
return driver.execQuery(sql, [tableName, tableName + "_" + columnName + "_pk", columnName], cb); | ||
}; | ||
return db.query(sql, cb); | ||
exports.dropPrimaryKey = function(driver, tableName, columnName, cb){ | ||
var sql = "ALTER TABLE ?? DROP CONSTRAINT ??;" | ||
return driver.execQuery(sql, [tableName, tableName + "_" + columnName + "_pk"], cb); | ||
}; | ||
exports.modifyCollectionColumn = function (db, name, column, cb) { | ||
exports.addForeignKey = function(driver, tableName, options, cb){ | ||
var sql = "ALTER TABLE ?? ADD FOREIGN KEY(??) REFERENCES ?? (??);" | ||
return driver.execQuery(sql, [tableName, options.name, options.references.table, options.references.column], cb); | ||
}; | ||
exports.dropForeignKey = function(driver, tableName, columnName, cb){ | ||
var sql = "ALTER TABLE ?? DROP CONSTRAINT ??;"; | ||
return driver.execQuery(sql, [tableName, tableName + '_' + columnName + '_fkey'], cb); | ||
}; | ||
//exports.renameTable = function(driver, oldCollectionName, newCollectionName, cb) { | ||
// return driver.execQuery(SQL.RENAME_TABLE({ | ||
// oldCollectionName : oldCollectionName, | ||
// newCollectionName : newCollectionName | ||
// }, driver), cb); | ||
//} | ||
exports.addCollectionColumn = function (driver, name, column, afterColumn, cb) { | ||
var sql = "ALTER TABLE ?? ADD " + column + ";"; | ||
return driver.execQuery(sql, [name] , cb); | ||
}; | ||
exports.renameCollectionColumn = function (driver, name, oldColName, newColName, cb) { | ||
var sql = SQL.ALTER_TABLE_RENAME_COLUMN({ | ||
name: name, oldColName: oldColName, newColName: newColName | ||
}, driver); | ||
return driver.execQuery(sql , cb); | ||
}; | ||
exports.modifyCollectionColumn = function (driver, name, column, cb) { | ||
var p = column.indexOf(" "); | ||
@@ -141,3 +182,3 @@ var col_name = column.substr(0, p); | ||
queue.add(function (next) { | ||
return db.query("ALTER TABLE " + name + | ||
return driver.execQuery("ALTER TABLE " + name + | ||
" ALTER " + col_name + | ||
@@ -150,3 +191,3 @@ " TYPE " + col_type, next); | ||
queue.add(function (next) { | ||
return db.query("ALTER TABLE " + name + | ||
return driver.execQuery("ALTER TABLE " + name + | ||
" ALTER " + col_name + | ||
@@ -157,3 +198,3 @@ " SET NOT NULL", next); | ||
queue.add(function (next) { | ||
return db.query("ALTER TABLE " + name + | ||
return driver.execQuery("ALTER TABLE " + name + | ||
" ALTER " + col_name + | ||
@@ -166,3 +207,3 @@ " DROP NOT NULL", next); | ||
queue.add(function (next) { | ||
return db.query("ALTER TABLE " + name + | ||
return driver.execQuery("ALTER TABLE " + name + | ||
" ALTER " + col_name + | ||
@@ -177,25 +218,27 @@ " SET DEFAULT " + m[1], next); | ||
exports.dropCollectionColumn = function (db, name, column, cb) { | ||
return db.query(SQL.ALTER_TABLE_DROP_COLUMN({ | ||
exports.dropCollectionColumn = function (driver, name, column, cb) { | ||
return driver.execQuery(SQL.ALTER_TABLE_DROP_COLUMN({ | ||
driver : driver, | ||
name : name, | ||
column : column | ||
}, exports), cb); | ||
}, driver), cb); | ||
}; | ||
exports.getCollectionIndexes = function (db, name, cb) { | ||
db.query("SELECT t.relname, i.relname, a.attname, ix.indisunique, ix.indisprimary " + | ||
exports.getCollectionIndexes = function (driver, name, cb) { | ||
driver.execQuery("SELECT t.relname, i.relname, a.attname, ix.indisunique, ix.indisprimary " + | ||
"FROM pg_class t, pg_class i, pg_index ix, pg_attribute a " + | ||
"WHERE t.oid = ix.indrelid AND i.oid = ix.indexrelid " + | ||
"AND a.attrelid = t.oid AND a.attnum = ANY(ix.indkey) " + | ||
"AND t.relkind = 'r' AND t.relname = $1", | ||
"AND t.relkind = 'r' AND t.relname = ?", | ||
[ name ], | ||
function (err, result) { | ||
function (err, rows) { | ||
if (err) return cb(err); | ||
return cb(null, convertIndexRows(result.rows)); | ||
return cb(null, convertIndexRows(rows)); | ||
}); | ||
}; | ||
exports.addIndex = function (db, name, unique, collection, columns, cb) { | ||
return db.query(SQL.CREATE_INDEX({ | ||
exports.addIndex = function (driver, name, unique, collection, columns, cb) { | ||
return driver.execQuery(SQL.CREATE_INDEX({ | ||
driver : driver, | ||
name : name, | ||
@@ -205,7 +248,7 @@ unique : unique, | ||
columns : columns | ||
}, exports), cb); | ||
}, driver), cb); | ||
}; | ||
exports.removeIndex = function (db, name, collection, cb) { | ||
return db.query("DROP INDEX " + exports.escapeId(name), cb); | ||
exports.removeIndex = function (driver, collection, name, cb) { | ||
return driver.execQuery("DROP INDEX " + driver.query.escapeId(name), cb); | ||
}; | ||
@@ -221,6 +264,12 @@ | ||
exports.getType = function (collection, name, property) { | ||
exports.getType = function (collection, property, driver) { | ||
var type = false; | ||
var before = false; | ||
var customType = null; | ||
if (property.type == 'number' && property.rational === false) { | ||
property.type = 'integer'; | ||
delete property.rational; | ||
} | ||
if (property.serial) { | ||
@@ -233,11 +282,11 @@ type = "SERIAL"; | ||
break; | ||
case "integer": | ||
type = columnSizes.integer[property.size || 4]; | ||
break; | ||
case "number": | ||
if (property.rational) { | ||
type = columnSizes.floating[property.size || 4]; | ||
} else { | ||
type = columnSizes.integer[property.size || 4]; | ||
} | ||
type = columnSizes.floating[property.size || 4]; | ||
break; | ||
case "serial": | ||
property.serial = true; | ||
property.key = true; | ||
type = "SERIAL"; | ||
@@ -260,8 +309,8 @@ break; | ||
case "enum": | ||
type = collection + "_enum_" + name.toLowerCase(); | ||
before = function (db, cb) { | ||
var type = collection + "_enum_" + name.toLowerCase(); | ||
type = collection + "_enum_" + property.mapsTo.toLowerCase(); | ||
before = function (driver, cb) { | ||
var type = collection + "_enum_" + property.mapsTo.toLowerCase(); | ||
db.query("SELECT * FROM pg_catalog.pg_type WHERE typname = $1", [ type ], function (err, result) { | ||
if (!err && result.rows.length) { | ||
driver.execQuery("SELECT * FROM pg_catalog.pg_type WHERE typname = ?", [ type ], function (err, rows) { | ||
if (!err && rows.length) { | ||
return cb(); | ||
@@ -271,6 +320,6 @@ } | ||
var values = property.values.map(function (val) { | ||
return exports.escapeVal(val); | ||
return driver.query.escapeVal(val); | ||
}); | ||
return db.query("CREATE TYPE " + type + " " + | ||
return driver.execQuery("CREATE TYPE " + type + " " + | ||
"AS ENUM (" + values + ")", cb); | ||
@@ -288,2 +337,7 @@ }); | ||
break; | ||
default: | ||
customType = driver.customTypes[property.type]; | ||
if (customType) { | ||
type = customType.datastoreType() | ||
} | ||
} | ||
@@ -297,3 +351,7 @@ | ||
if (property.hasOwnProperty("defaultValue")) { | ||
type += " DEFAULT " + exports.escapeVal(property.defaultValue); | ||
if (property.type == 'date' && property.defaultValue === Date.now ){ | ||
type += " DEFAULT now()"; | ||
} else { | ||
type += " DEFAULT " + driver.query.escapeVal(property.defaultValue); | ||
} | ||
} | ||
@@ -308,47 +366,2 @@ } | ||
exports.escapeId = function () { | ||
return Array.prototype.slice.apply(arguments).map(function (el) { | ||
return el.split(".").map(function (ele) { | ||
return "\"" + ele.replace(/\"/g, "\"\"") + "\""; | ||
}).join("."); | ||
}).join("."); | ||
}; | ||
exports.escapeVal = function (val, timeZone) { | ||
if (val === undefined || val === null) { | ||
return 'NULL'; | ||
} | ||
if (Array.isArray(val)) { | ||
if (val.length === 1 && Array.isArray(val[0])) { | ||
return "(" + val[0].map(exports.escapeVal.bind(this)) + ")"; | ||
} | ||
return "(" + val.map(exports.escapeVal.bind(this)).join(", ") + ")"; | ||
} | ||
if (util.isDate(val)) { | ||
return "'" + dateToString(val, timeZone || "local") + "'"; | ||
} | ||
if (Buffer.isBuffer(val)) { | ||
return "'\\x" + val.toString("hex") + "'"; | ||
} | ||
switch (typeof val) { | ||
case "number": | ||
if (!isFinite(val)) { | ||
val = val.toString(); | ||
break; | ||
} | ||
return val; | ||
case "boolean": | ||
return val ? "true" : "false"; | ||
case "function": | ||
return val(exports); | ||
} | ||
// No need to escape backslashes with default PostgreSQL 9.1+ config. | ||
// Google 'postgresql standard_conforming_strings' for details. | ||
return "'" + val.replace(/\'/g, "''") + "'"; | ||
}; | ||
function convertIndexRows(rows) { | ||
@@ -375,3 +388,3 @@ var indexes = {}; | ||
function checkColumnTypes(db, collection, columns, cb) { | ||
function checkColumnTypes(driver, collection, columns, cb) { | ||
var queue = new Queue(function () { | ||
@@ -386,11 +399,11 @@ return cb(null, columns); | ||
db.query("SELECT t.typname, string_agg(e.enumlabel, '|' ORDER BY e.enumsortorder) AS enum_values " + | ||
driver.execQuery("SELECT t.typname, string_agg(e.enumlabel, '|' ORDER BY e.enumsortorder) AS enum_values " + | ||
"FROM pg_catalog.pg_type t JOIN pg_catalog.pg_enum e ON t.oid = e.enumtypid " + | ||
"WHERE t.typname = $1 GROUP BY 1", [ col_name ], | ||
function (err, result) { | ||
"WHERE t.typname = ? GROUP BY 1", [ col_name ], | ||
function (err, rows) { | ||
if (err) { | ||
return next(err); | ||
} | ||
if (result.rows.length) { | ||
col.values = result.rows[0].enum_values.split("|"); | ||
if (rows.length) { | ||
col.values = rows[0].enum_values.split("|"); | ||
} | ||
@@ -397,0 +410,0 @@ |
@@ -5,4 +5,4 @@ var Queue = require("../Queue").Queue; | ||
exports.hasCollection = function (db, name, cb) { | ||
db.all("SELECT * FROM sqlite_master " + | ||
exports.hasCollection = function (driver, name, cb) { | ||
driver.execQuery("SELECT * FROM sqlite_master " + | ||
"WHERE type = 'table' and name = ?", | ||
@@ -17,4 +17,24 @@ [ name ], | ||
exports.getCollectionProperties = function (db, name, cb) { | ||
db.all("PRAGMA table_info(" + exports.escapeId(name) + ")", function (err, cols) { | ||
exports.addPrimaryKey = function(driver, tableName, columnName, cb){ | ||
var sql = "ALTER TABLE ?? ADD CONSTRAINT ?? PRIMARY KEY(??);"; | ||
return driver.execQuery(sql, [tableName, columnName + "PK", columnName], cb); | ||
}; | ||
exports.dropPrimaryKey = function(driver, tableName, columnName, cb){ | ||
var sql = "ALTER TABLE ?? DROP CONSTRAINT ??;" | ||
return driver.execQuery(sql, [tableName, columnName + "PK"], cb); | ||
}; | ||
exports.addForeignKey = function(driver, tableName, options, cb){ | ||
var sql = "ALTER TABLE ?? ADD FOREIGN KEY(??) REFERENCES ??(??);"; | ||
return driver.execQuery(sql, [tableName, options.name, options.references.table, options.references.column], cb); | ||
}; | ||
exports.dropForeignKey = function(driver, tableName, columnName, cb){ | ||
var sql = "ALTER TABLE ?? DROP CONSTRAINT ??;" | ||
return driver.execQuery(sql, [tableName, tableName + "_" + columnName + "_fkey"], cb); | ||
}; | ||
exports.getCollectionProperties = function (driver, name, cb) { | ||
driver.execQuery("PRAGMA table_info(??)", [name], function (err, cols) { | ||
if (err) return cb(err); | ||
@@ -26,12 +46,13 @@ | ||
var column = {}; | ||
var dCol = cols[i]; | ||
if (cols[i].pk) { | ||
column.primary = true; | ||
if (dCol.pk) { | ||
column.key = true; | ||
} | ||
if (cols[i].notnull) { | ||
if (dCol.notnull) { | ||
column.required = true; | ||
} | ||
if (cols[i].dflt_value) { | ||
m = cols[i].dflt_value.match(/^'(.*)'$/); | ||
if (dCol.dflt_value) { | ||
m = dCol.dflt_value.match(/^'(.*)'$/); | ||
if (m) { | ||
@@ -44,7 +65,16 @@ column.defaultValue = m[1]; | ||
switch (cols[i].type.toUpperCase()) { | ||
switch (dCol.type.toUpperCase()) { | ||
case "INTEGER": | ||
column.type = "number"; | ||
column.rational = false; | ||
// In sqlite land, integer primary keys are autoincrement by default | ||
// weather you asked for this behaviour or not. | ||
// http://www.sqlite.org/faq.html#q1 | ||
if (dCol.pk == 1) { | ||
column.type = "serial"; | ||
} else { | ||
column.type = "integer"; | ||
} | ||
break; | ||
case "INTEGER UNSIGNED": | ||
column.type = "boolean"; | ||
break; | ||
case "REAL": | ||
@@ -66,6 +96,6 @@ column.type = "number"; | ||
default: | ||
return cb(new Error("Unknown column type '" + cols[i].Type + "'")); | ||
return cb(new Error("Unknown column type '" + dCol.type + "'")); | ||
} | ||
columns[cols[i].name] = column; | ||
columns[dCol.name] = column; | ||
} | ||
@@ -77,33 +107,40 @@ | ||
exports.createCollection = function (db, name, columns, primary, cb) { | ||
return db.all(SQL.CREATE_TABLE({ | ||
exports.createCollection = function (driver, name, columns, keys, cb) { | ||
return driver.execQuery(SQL.CREATE_TABLE({ | ||
name : name, | ||
columns : columns, | ||
primary : primary | ||
}, exports), cb); | ||
keys : keys | ||
}, driver), cb); | ||
}; | ||
exports.dropCollection = function (db, name, cb) { | ||
return db.query(SQL.DROP_TABLE({ | ||
exports.dropCollection = function (driver, name, cb) { | ||
return driver.execQuery(SQL.DROP_TABLE({ | ||
name : name | ||
}, exports), cb); | ||
}, driver), cb); | ||
}; | ||
exports.addCollectionColumn = function (db, name, column, after_column, cb) { | ||
return db.all(SQL.ALTER_TABLE_ADD_COLUMN({ | ||
exports.addCollectionColumn = function (driver, name, column, after_column, cb) { | ||
return driver.execQuery(SQL.ALTER_TABLE_ADD_COLUMN({ | ||
name : name, | ||
column : column, | ||
after : after_column, | ||
first : !after_column | ||
}, exports), cb); | ||
after : after_column | ||
}, driver), cb); | ||
}; | ||
exports.modifyCollectionColumn = function (db, name, column, cb) { | ||
return db.all(SQL.ALTER_TABLE_MODIFY_COLUMN({ | ||
exports.renameCollectionColumn = function (driver, name, oldColName, newColName, cb) { | ||
var sql = SQL.ALTER_TABLE_RENAME_COLUMN({ | ||
name: name, oldColName: oldColName, newColName: newColName | ||
}, driver); | ||
return driver.execQuery(sql , cb); | ||
}; | ||
exports.modifyCollectionColumn = function (driver, name, column, cb) { | ||
return driver.execQuery(SQL.ALTER_TABLE_MODIFY_COLUMN({ | ||
name : name, | ||
column : column | ||
}, exports), cb); | ||
}, driver), cb); | ||
}; | ||
exports.dropCollectionColumn = function (db, name, column, cb) { | ||
exports.dropCollectionColumn = function (driver, name, column, cb) { | ||
// sqlite does not support dropping columns | ||
@@ -113,4 +150,4 @@ return cb(); | ||
exports.getCollectionIndexes = function (db, name, cb) { | ||
db.all("PRAGMA index_list(" + exports.escapeId(name) + ")", function (err, rows) { | ||
exports.getCollectionIndexes = function (driver, name, cb) { | ||
driver.execQuery("PRAGMA index_list(" + driver.query.escapeId(name) + ")", function (err, rows) { | ||
if (err) return cb(err); | ||
@@ -129,3 +166,3 @@ | ||
queue.add(k, function (k, next) { | ||
db.all("PRAGMA index_info(" + exports.escapeVal(k) + ")", function (err, rows) { | ||
driver.execQuery("PRAGMA index_info(" + driver.query.escapeVal(k) + ")", function (err, rows) { | ||
if (err) return next(err); | ||
@@ -146,4 +183,4 @@ | ||
exports.addIndex = function (db, name, unique, collection, columns, cb) { | ||
return db.all(SQL.CREATE_INDEX({ | ||
exports.addIndex = function (driver, name, unique, collection, columns, cb) { | ||
return driver.execQuery(SQL.CREATE_INDEX({ | ||
name : name, | ||
@@ -153,15 +190,15 @@ unique : unique, | ||
columns : columns | ||
}, exports), cb); | ||
}, driver), cb); | ||
}; | ||
exports.removeIndex = function (db, name, collection, cb) { | ||
return db.all("DROP INDEX IF EXISTS " + exports.escapeId(name), cb); | ||
exports.removeIndex = function (driver, name, collection, cb) { | ||
return driver.execQuery("DROP INDEX IF EXISTS " + driver.query.escapeId(name), cb); | ||
}; | ||
exports.checkPrimary = function (primary) { | ||
if (primary.length === 1) { | ||
exports.processKeys = function (keys) { | ||
if (keys.length === 1) { | ||
return []; | ||
} | ||
return primary; | ||
return keys; | ||
}; | ||
@@ -178,5 +215,11 @@ | ||
exports.getType = function (collection, name, property) { | ||
var type = false; | ||
exports.getType = function (collection, property, driver) { | ||
var type = false; | ||
var customType = null; | ||
if (property.type == 'number' && property.rational === false) { | ||
property.type = 'integer'; | ||
delete property.rational; | ||
} | ||
switch (property.type) { | ||
@@ -186,16 +229,15 @@ case "text": | ||
break; | ||
case "integer": | ||
type = "INTEGER"; | ||
break; | ||
case "number": | ||
if (property.rational) { | ||
type = "REAL"; | ||
} else { | ||
type = "INTEGER"; | ||
} | ||
type = "REAL"; | ||
break; | ||
case "serial": | ||
property.serial = true; | ||
property.primary = true; | ||
property.key = true; | ||
type = "INTEGER"; | ||
break; | ||
case "boolean": | ||
type = "INTEGER"; | ||
type = "INTEGER UNSIGNED"; | ||
break; | ||
@@ -215,2 +257,7 @@ case "date": | ||
break; | ||
default: | ||
customType = driver.customTypes[property.type]; | ||
if (customType) { | ||
type = customType.datastoreType() | ||
} | ||
} | ||
@@ -223,3 +270,3 @@ | ||
} | ||
if (property.primary) { | ||
if (property.key) { | ||
if (!property.required) { | ||
@@ -234,3 +281,3 @@ // append if not set | ||
if (property.serial) { | ||
if (!property.primary) { | ||
if (!property.key) { | ||
type += " PRIMARY KEY"; | ||
@@ -241,3 +288,3 @@ } | ||
if (property.hasOwnProperty("defaultValue")) { | ||
type += " DEFAULT " + exports.escapeVal(property.defaultValue); | ||
type += " DEFAULT " + driver.query.escapeVal(property.defaultValue); | ||
} | ||
@@ -251,46 +298,2 @@ | ||
exports.escapeId = function () { | ||
return Array.prototype.slice.apply(arguments).map(function (el) { | ||
return "`" + el.replace(/`/g, '``') + "`"; | ||
}).join("."); | ||
}; | ||
exports.escapeVal = function (val, timeZone) { | ||
if (val === undefined || val === null) { | ||
return 'NULL'; | ||
} | ||
if (Array.isArray(val)) { | ||
if (val.length === 1 && Array.isArray(val[0])) { | ||
return "(" + val[0].map(exports.escapeVal.bind(this)) + ")"; | ||
} | ||
return "(" + val.map(exports.escapeVal.bind(this)).join(", ") + ")"; | ||
} | ||
if (util.isDate(val)) { | ||
return "'" + dateToString(val, timeZone || "local") + "'"; | ||
} | ||
if (Buffer.isBuffer(val)) { | ||
return "X'" + val.toString("hex") + "'"; | ||
} | ||
switch (typeof val) { | ||
case "number": | ||
if (!isFinite(val)) { | ||
val = val.toString(); | ||
break; | ||
} | ||
return val; | ||
case "boolean": | ||
return val ? 1 : 0; | ||
case "function": | ||
return val(exports); | ||
} | ||
// No need to escape backslashes with default PostgreSQL 9.1+ config. | ||
// Google 'postgresql standard_conforming_strings' for details. | ||
return "'" + val.replace(/\'/g, "''") + "'"; | ||
}; | ||
function convertIndexRows(rows) { | ||
@@ -297,0 +300,0 @@ var indexes = {}; |
@@ -1,7 +0,7 @@ | ||
exports.CREATE_TABLE = function (options, dialect) { | ||
var sql = "CREATE TABLE " + dialect.escapeId(options.name) + " (" + options.columns.join(", "); | ||
exports.CREATE_TABLE = function (options, driver) { | ||
var sql = "CREATE TABLE " + driver.query.escapeId(options.name) + " (" + options.columns.join(", "); | ||
if (options.primary && options.primary.length > 0) { | ||
sql += ", PRIMARY KEY (" + options.primary.map(function (val) { | ||
return dialect.escapeId(val); | ||
if (options.keys && options.keys.length > 0) { | ||
sql += ", PRIMARY KEY (" + options.keys.map(function (val) { | ||
return driver.query.escapeId(val); | ||
}).join(", ") + ")"; | ||
@@ -15,4 +15,4 @@ } | ||
exports.DROP_TABLE = function (options, dialect) { | ||
var sql = "DROP TABLE " + dialect.escapeId(options.name); | ||
exports.DROP_TABLE = function (options, driver) { | ||
var sql = "DROP TABLE " + driver.query.escapeId(options.name); | ||
@@ -22,8 +22,8 @@ return sql; | ||
exports.ALTER_TABLE_ADD_COLUMN = function (options, dialect) { | ||
var sql = "ALTER TABLE " + dialect.escapeId(options.name) + | ||
exports.ALTER_TABLE_ADD_COLUMN = function (options, driver) { | ||
var sql = "ALTER TABLE " + driver.query.escapeId(options.name) + | ||
" ADD " + options.column; | ||
if (options.after) { | ||
sql += " AFTER " + dialect.escapeId(options.after); | ||
sql += " AFTER " + driver.query.escapeId(options.after); | ||
} else if (options.first) { | ||
@@ -36,4 +36,12 @@ sql += " FIRST"; | ||
exports.ALTER_TABLE_MODIFY_COLUMN = function (options, dialect) { | ||
var sql = "ALTER TABLE " + dialect.escapeId(options.name) + | ||
exports.ALTER_TABLE_RENAME_COLUMN = function (opts, driver) { | ||
var eid = driver.query.escapeId; | ||
var sql = "ALTER TABLE " + eid(opts.name) + | ||
" RENAME COLUMN " + eid(opts.oldColName) + " TO " + eid(opts.newColName); | ||
return sql; | ||
} | ||
exports.ALTER_TABLE_MODIFY_COLUMN = function (options, driver) { | ||
var sql = "ALTER TABLE " + driver.query.escapeId(options.name) + | ||
" MODIFY " + options.column; | ||
@@ -44,5 +52,5 @@ | ||
exports.ALTER_TABLE_DROP_COLUMN = function (options, dialect) { | ||
var sql = "ALTER TABLE " + dialect.escapeId(options.name) + | ||
" DROP " + dialect.escapeId(options.column); | ||
exports.ALTER_TABLE_DROP_COLUMN = function (options, driver) { | ||
var sql = "ALTER TABLE " + driver.query.escapeId(options.name) + | ||
" DROP " + driver.query.escapeId(options.column); | ||
@@ -52,6 +60,6 @@ return sql; | ||
exports.CREATE_INDEX = function (options, dialect) { | ||
var sql = "CREATE" + (options.unique ? " UNIQUE" : "") + " INDEX " + dialect.escapeId(options.name) + | ||
" ON " + dialect.escapeId(options.collection) + | ||
" (" + options.columns.map(function (col) { return dialect.escapeId(col); }) + ")"; | ||
exports.CREATE_INDEX = function (options, driver) { | ||
var sql = "CREATE" + (options.unique ? " UNIQUE" : "") + " INDEX " + driver.query.escapeId(options.name) + | ||
" ON " + driver.query.escapeId(options.collection) + | ||
" (" + options.columns.map(function (col) { return driver.query.escapeId(col); }) + ")"; | ||
@@ -61,7 +69,11 @@ return sql; | ||
exports.DROP_INDEX = function (options, dialect) { | ||
var sql = "DROP INDEX " + dialect.escapeId(options.name) + | ||
" ON " + dialect.escapeId(options.collection); | ||
exports.DROP_INDEX = function (options, driver) { | ||
var sql = "DROP INDEX " + driver.query.escapeId(options.name) + | ||
" ON " + driver.query.escapeId(options.collection); | ||
return sql; | ||
}; | ||
//exports.RENAME_TABLE = function(options, driver) { | ||
// var sql = "ALTER TABLE " + options.oldCollectionName + " RENAME TO " + options.newCollectionName + " ;"; | ||
//} |
159
lib/Sync.js
@@ -8,5 +8,6 @@ var Queue = require("./Queue").Queue; | ||
function Sync(options) { | ||
var Dialect = require("./Dialects/" + options.dialect); | ||
var debug = options.debug || noOp; | ||
var db = options.db; | ||
var driver = options.driver; | ||
var Dialect = require("./Dialects/" + driver.dialect); | ||
var suppressColumnDrop = options.suppressColumnDrop; | ||
var collections = []; | ||
@@ -17,3 +18,3 @@ var types = {}; | ||
var processCollection = function (collection, cb) { | ||
Dialect.hasCollection(db, collection.name, function (err, has) { | ||
Dialect.hasCollection(driver, collection.name, function (err, has) { | ||
if (err) { | ||
@@ -24,6 +25,13 @@ return cb(err); | ||
if (!has) { | ||
return createCollection(collection, cb); | ||
return createCollection(collection, function (err) { | ||
if (err) return cb(err); | ||
return cb(null, true); | ||
}); | ||
} else { | ||
return cb(null, false); | ||
} | ||
Dialect.getCollectionProperties(db, collection.name, function (err, columns) { | ||
// I have concerns about the data integrity of the automatic sync process. | ||
// There has been lots of bugs and issues associated with it. | ||
/*Dialect.getCollectionProperties(driver, collection.name, function (err, columns) { | ||
if (err) { | ||
@@ -34,3 +42,3 @@ return cb(err); | ||
return syncCollection(collection, columns, cb); | ||
}); | ||
});*/ | ||
}); | ||
@@ -41,7 +49,8 @@ }; | ||
var columns = []; | ||
var primary = []; | ||
var keys = []; | ||
var before = []; | ||
var nextBefore = function () { | ||
if (before.length === 0) { | ||
return Dialect.createCollection(db, collection.name, columns, primary, function () { | ||
return Dialect.createCollection(driver, collection.name, columns, keys, function (err) { | ||
if (err) return cb(err); | ||
return syncIndexes(collection.name, getCollectionIndexes(collection), cb); | ||
@@ -53,3 +62,3 @@ }); | ||
next(db, function (err) { | ||
next(driver, function (err) { | ||
if (err) { | ||
@@ -64,4 +73,9 @@ return cb(err); | ||
for (var k in collection.properties) { | ||
var col = createColumn(collection.name, k, collection.properties[k]); | ||
var prop, col; | ||
prop = collection.properties[k]; | ||
prop.mapsTo = prop.mapsTo || k; | ||
col = createColumn(collection.name, prop); | ||
if (col === false) { | ||
@@ -71,4 +85,4 @@ return cb(new Error("Unknown type for property '" + k + "'")); | ||
if (collection.properties[k].primary) { | ||
primary.push(k); | ||
if (prop.key) { | ||
keys.push(prop.mapsTo); | ||
} | ||
@@ -85,4 +99,4 @@ | ||
if (typeof Dialect.checkPrimary == "function") { | ||
primary = Dialect.checkPrimary(primary); | ||
if (typeof Dialect.processKeys == "function") { | ||
keys = Dialect.processKeys(keys); | ||
} | ||
@@ -95,7 +109,11 @@ | ||
var createColumn = function (collection, name, property) { | ||
var type = types.hasOwnProperty(property.type) | ||
? types[property.type].datastoreType(property) | ||
: Dialect.getType(collection, name, property); | ||
var createColumn = function (collection, prop) { | ||
var type; | ||
if (types.hasOwnProperty(prop.type)) { | ||
type = types[prop.type].datastoreType(prop); | ||
} else { | ||
type = Dialect.getType(collection, prop, driver); | ||
} | ||
if (type === false) { | ||
@@ -108,4 +126,8 @@ return false; | ||
if (prop.mapsTo === undefined) { | ||
console.log("undefined prop.mapsTo", prop, (new Error()).stack) | ||
} | ||
return { | ||
value : Dialect.escapeId(name) + " " + type.value, | ||
value : driver.query.escapeId(prop.mapsTo) + " " + type.value, | ||
before : type.before | ||
@@ -123,3 +145,3 @@ }; | ||
if (!columns.hasOwnProperty(k)) { | ||
var col = createColumn(collection.name, k, collection.properties[k]); | ||
var col = createColumn(collection.name, collection.properties[k]); | ||
@@ -136,7 +158,7 @@ if (col === false) { | ||
queue.add(col, function (col, next) { | ||
col.before(db, function (err) { | ||
col.before(driver, function (err) { | ||
if (err) { | ||
return next(err); | ||
} | ||
return Dialect.addCollectionColumn(db, collection.name, col.value, last_k, next); | ||
return Dialect.addCollectionColumn(driver, collection.name, col.value, last_k, next); | ||
}); | ||
@@ -146,3 +168,3 @@ }); | ||
queue.add(function (next) { | ||
return Dialect.addCollectionColumn(db, collection.name, col.value, last_k, next); | ||
return Dialect.addCollectionColumn(driver, collection.name, col.value, last_k, next); | ||
}); | ||
@@ -163,7 +185,7 @@ } | ||
queue.add(col, function (col, next) { | ||
col.before(db, function (err) { | ||
col.before(driver, function (err) { | ||
if (err) { | ||
return next(err); | ||
} | ||
return Dialect.modifyCollectionColumn(db, collection.name, col.value, next); | ||
return Dialect.modifyCollectionColumn(driver, collection.name, col.value, next); | ||
}); | ||
@@ -173,3 +195,3 @@ }); | ||
queue.add(function (next) { | ||
return Dialect.modifyCollectionColumn(db, collection.name, col.value, next); | ||
return Dialect.modifyCollectionColumn(driver, collection.name, col.value, next); | ||
}); | ||
@@ -182,13 +204,15 @@ } | ||
for (var k in columns) { | ||
if (!collection.properties.hasOwnProperty(k)) { | ||
queue.add(function (next) { | ||
debug("Dropping column " + collection.name + "." + k); | ||
if ( !suppressColumnDrop ) { | ||
for (var k in columns) { | ||
if (!collection.properties.hasOwnProperty(k)) { | ||
queue.add(function (next) { | ||
debug("Dropping column " + collection.name + "." + k); | ||
total_changes += 1; | ||
total_changes += 1; | ||
return Dialect.dropCollectionColumn(db, collection.name, k, next); | ||
}); | ||
} | ||
} | ||
return Dialect.dropCollectionColumn(driver, collection.name, k, next); | ||
}); | ||
} | ||
} | ||
} | ||
@@ -206,16 +230,28 @@ var indexes = getCollectionIndexes(collection); | ||
var getIndexName = function (collection, prop) { | ||
var post = prop.unique ? 'unique' : 'index'; | ||
if (driver.dialect == 'sqlite') { | ||
return collection.name + '_' + prop.name + '_' + post; | ||
} else { | ||
return prop.name + '_' + post; | ||
} | ||
}; | ||
var getCollectionIndexes = function (collection) { | ||
var indexes = []; | ||
var found; | ||
var found, prop; | ||
for (var k in collection.properties) { | ||
if (collection.properties[k].unique) { | ||
if (!Array.isArray(collection.properties[k].unique)) { | ||
collection.properties[k].unique = [ collection.properties[k].unique ]; | ||
prop = collection.properties[k]; | ||
if (prop.unique) { | ||
if (!Array.isArray(prop.unique)) { | ||
prop.unique = [ prop.unique ]; | ||
} | ||
for (var i = 0; i < collection.properties[k].unique.length; i++) { | ||
if (collection.properties[k].unique[i] === true) { | ||
for (var i = 0; i < prop.unique.length; i++) { | ||
if (prop.unique[i] === true) { | ||
indexes.push({ | ||
name : k + "_unique", | ||
name : getIndexName(collection, prop), | ||
unique : true, | ||
@@ -228,3 +264,3 @@ columns : [ k ] | ||
for (var j = 0; j < indexes.length; j++) { | ||
if (indexes[j].name == collection.properties[k].unique[i]) { | ||
if (indexes[j].name == prop.unique[i]) { | ||
found = true; | ||
@@ -237,3 +273,3 @@ indexes[j].columns.push(k); | ||
indexes.push({ | ||
name : collection.properties[k].unique[i], | ||
name : prop.unique[i], | ||
unique : true, | ||
@@ -246,11 +282,11 @@ columns : [ k ] | ||
} | ||
if (collection.properties[k].index) { | ||
if (!Array.isArray(collection.properties[k].index)) { | ||
collection.properties[k].index = [ collection.properties[k].index ]; | ||
if (prop.index) { | ||
if (!Array.isArray(prop.index)) { | ||
prop.index = [ prop.index ]; | ||
} | ||
for (var i = 0; i < collection.properties[k].index.length; i++) { | ||
if (collection.properties[k].index[i] === true) { | ||
for (var i = 0; i < prop.index.length; i++) { | ||
if (prop.index[i] === true) { | ||
indexes.push({ | ||
name : k + "_index", | ||
name : getIndexName(collection, prop), | ||
columns : [ k ] | ||
@@ -262,3 +298,3 @@ }); | ||
for (var j = 0; j < indexes.length; j++) { | ||
if (indexes[j].name == collection.properties[k].index[i]) { | ||
if (indexes[j].name == prop.index[i]) { | ||
found = true; | ||
@@ -271,3 +307,3 @@ indexes[j].columns.push(k); | ||
indexes.push({ | ||
name : collection.properties[k].index[i], | ||
name : prop.index[i], | ||
columns : [ k ] | ||
@@ -289,3 +325,5 @@ }); | ||
var syncIndexes = function (name, indexes, cb) { | ||
Dialect.getCollectionIndexes(db, name, function (err, db_indexes) { | ||
if (indexes.length == 0) return cb(null); | ||
Dialect.getCollectionIndexes(driver, name, function (err, db_indexes) { | ||
if (err) return cb(err); | ||
@@ -302,3 +340,3 @@ | ||
queue.add(indexes[i], function (index, next) { | ||
return Dialect.addIndex(db, index.name, index.unique, name, index.columns, next); | ||
return Dialect.addIndex(driver, index.name, index.unique, name, index.columns, next); | ||
}); | ||
@@ -312,6 +350,6 @@ continue; | ||
queue.add(indexes[i], function (index, next) { | ||
return Dialect.removeIndex(db, index.name, name, next); | ||
return Dialect.removeIndex(driver, index.name, name, next); | ||
}); | ||
queue.add(indexes[i], function (index, next) { | ||
return Dialect.addIndex(db, index.name, index.unique, name, index.columns, next); | ||
return Dialect.addIndex(driver, index.name, index.unique, name, index.columns, next); | ||
}); | ||
@@ -328,3 +366,3 @@ } | ||
queue.add(i, function (index, next) { | ||
return Dialect.removeIndex(db, index, name, next); | ||
return Dialect.removeIndex(driver, index, name, next); | ||
}); | ||
@@ -352,3 +390,3 @@ } | ||
} | ||
if (property.required != column.required && !property.primary) { | ||
if (property.required != column.required && !property.key) { | ||
return true; | ||
@@ -359,9 +397,6 @@ } | ||
} | ||
if (property.type == "number") { | ||
if (property.type == "number" || property.type == "integer") { | ||
if (column.hasOwnProperty("size") && (property.size || 4) != column.size) { | ||
return true; | ||
} | ||
if (property.hasOwnProperty("rational") && property.rational != column.rational) { | ||
return true; | ||
} | ||
} | ||
@@ -368,0 +403,0 @@ if (property.type == "enum" && column.type == "enum") { |
@@ -6,3 +6,3 @@ { | ||
"keywords" : [ "sql", "ddl", "sync", "mysql", "postgres", "sqlite" ], | ||
"version" : "0.1.4", | ||
"version" : "0.3.11", | ||
"license" : "MIT", | ||
@@ -20,4 +20,5 @@ "repository" : "http://github.com/dresende/node-sql-ddl-sync.git", | ||
"should" : "2.0.2", | ||
"commander" : "~2.0.0" | ||
"commander" : "~2.0.0", | ||
"orm" : "2.1.23" | ||
} | ||
} |
@@ -20,9 +20,9 @@ ## NodeJS SQL DDL Synchronization | ||
This module is used by [ORM](http://dresende.github.com/node-orm2) to synchronize model tables in the different supported | ||
dialects. Sorry there is no API documentation for now but there are a couple of tests you can read and find out how to use | ||
it if you want. | ||
This module is part of [ORM](http://dresende.github.com/node-orm2). It's used synchronize model tables in supported dialects. | ||
Sorry there is no API documentation for now but there are a couple of tests you can read and find out how to use it if you want. | ||
## Example | ||
Install module and install `mysql`, create a file with the contents below and change line 2 to match valid credentials. | ||
Install `orm` & the required driver (eg: `mysql`). | ||
Create a file with the contents below and change insert your database credentials. | ||
Run once and you'll see table `ddl_sync_test` appear in your database. Then make some changes to it (add/drop/change columns) | ||
@@ -32,38 +32,42 @@ and run the code again. Your table should always return to the same structure. | ||
```js | ||
var mysql = require("mysql"); | ||
var db = mysql.createConnection("mysql://username:password@localhost/database"); | ||
var orm = require("orm"); | ||
var mysql = require("mysql"); | ||
var Sync = require("sql-ddl-sync").Sync; | ||
var Sync = require("sql-ddl-sync").Sync; | ||
var sync = new Sync({ | ||
dialect : "mysql", | ||
db : db, | ||
debug : function (text) { | ||
console.log("> %s", text); | ||
} | ||
}); | ||
orm.connect("mysql://username:password@localhost/database", function (err, db) { | ||
if (err) throw err; | ||
var driver = db.driver; | ||
sync.defineCollection("ddl_sync_test", { | ||
id : { type : "number", primary: true, serial: true }, | ||
name : { type : "text", required: true }, | ||
age : { type : "number", rational: true }, | ||
male : { type : "boolean" }, | ||
born : { type : "date", time: true }, | ||
born2 : { type : "date" }, | ||
int2 : { type : "number", size: 2 }, | ||
int4 : { type : "number", size: 4 }, | ||
int8 : { type : "number", size: 8 }, | ||
float4 : { type : "number", rational: true, size: 4 }, | ||
float8 : { type : "number", rational: true, size: 8 }, | ||
type : { type : "enum", values: [ 'dog', 'cat'], defaultValue: 'dog', required: true }, | ||
photo : { type : "binary" } | ||
}); | ||
var sync = new Sync({ | ||
dialect : "mysql", | ||
driver : driver, | ||
debug : function (text) { | ||
console.log("> %s", text); | ||
} | ||
}); | ||
sync.sync(function (err) { | ||
if (err) { | ||
console.log("> Sync Error"); | ||
console.log(err); | ||
} else { | ||
console.log("> Sync Done"); | ||
} | ||
process.exit(0); | ||
sync.defineCollection("ddl_sync_test", { | ||
id : { type: "serial", key: true, serial: true }, | ||
name : { type: "text", required: true }, | ||
age : { type: "integer" }, | ||
male : { type: "boolean" }, | ||
born : { type: "date", time: true }, | ||
born2 : { type: "date" }, | ||
int2 : { type: "integer", size: 2 }, | ||
int4 : { type: "integer", size: 4 }, | ||
int8 : { type: "integer", size: 8 }, | ||
float4 : { type: "number", size: 4 }, | ||
float8 : { type: "number", size: 8 }, | ||
photo : { type: "binary" } | ||
}); | ||
sync.sync(function (err) { | ||
if (err) { | ||
console.log("> Sync Error"); | ||
console.log(err); | ||
} else { | ||
console.log("> Sync Done"); | ||
} | ||
process.exit(0); | ||
}); | ||
}); | ||
@@ -70,0 +74,0 @@ |
exports.dialect = null; | ||
exports.table = "sql_ddl_sync_test_table"; | ||
exports.fakeDialect = { | ||
escapeId : function (id) { | ||
return "$$" + id + "$$"; | ||
exports.fakeDriver = { | ||
query: { | ||
escapeId : function (id) { | ||
return "$$" + id + "$$"; | ||
}, | ||
escapeVal : function (val) { | ||
return "^^" + val + "^^"; | ||
} | ||
}, | ||
customTypes: { | ||
json: { | ||
datastoreType: function (prop) { | ||
return 'JSON'; | ||
} | ||
} | ||
} | ||
@@ -12,7 +24,6 @@ }; | ||
return function (done) { | ||
switch (exports.dialect) { | ||
switch (exports.driver.dialect) { | ||
case "mysql": | ||
return exports.db.query("ALTER TABLE ?? DROP ??", [ exports.table, column ], done); | ||
case "postgresql": | ||
return exports.db.query("ALTER TABLE " + exports.table + " DROP " + column, done); | ||
return exports.driver.execQuery("ALTER TABLE ?? DROP ??", [ exports.table, column ], done); | ||
} | ||
@@ -25,9 +36,9 @@ return done(unknownProtocol()); | ||
return function (done) { | ||
switch (exports.dialect) { | ||
switch (exports.driver.dialect) { | ||
case "mysql": | ||
return exports.db.query("ALTER TABLE ?? ADD ?? INTEGER NOT NULL", [ exports.table, column ], done); | ||
return exports.driver.execQuery("ALTER TABLE ?? ADD ?? INTEGER NOT NULL", [ exports.table, column ], done); | ||
case "postgresql": | ||
return exports.db.query("ALTER TABLE " + exports.table + " ADD " + column + " INTEGER NOT NULL", done); | ||
return exports.driver.execQuery("ALTER TABLE " + exports.table + " ADD " + column + " INTEGER NOT NULL", done); | ||
case "sqlite": | ||
return exports.db.all("ALTER TABLE " + exports.table + " ADD " + column + " INTEGER", done); | ||
return exports.driver.execQuery("ALTER TABLE " + exports.table + " ADD " + column + " INTEGER", done); | ||
} | ||
@@ -40,9 +51,9 @@ return done(unknownProtocol()); | ||
return function (done) { | ||
switch (exports.dialect) { | ||
switch (exports.driver.dialect) { | ||
case "mysql": | ||
return exports.db.query("ALTER TABLE ?? MODIFY ?? INTEGER NOT NULL", [ exports.table, column ], done); | ||
return exports.driver.execQuery("ALTER TABLE ?? MODIFY ?? INTEGER NOT NULL", [ exports.table, column ], done); | ||
case "postgresql": | ||
return exports.db.query("ALTER TABLE " + exports.table + " ALTER " + column + " TYPE DOUBLE PRECISION", done); | ||
return exports.driver.execQuery("ALTER TABLE " + exports.table + " ALTER " + column + " TYPE DOUBLE PRECISION", done); | ||
case "sqlite": | ||
return exports.db.all("ALTER TABLE " + exports.table + " MODIFY " + column + " INTEGER NOT NULL", done); | ||
return exports.driver.execQuery("ALTER TABLE " + exports.table + " MODIFY " + column + " INTEGER NOT NULL", done); | ||
} | ||
@@ -55,9 +66,9 @@ return done(unknownProtocol()); | ||
return function (done) { | ||
switch (exports.dialect) { | ||
switch (exports.driver.dialect) { | ||
case "mysql": | ||
return exports.db.query("CREATE " + (unique ? "UNIQUE" : "") + " INDEX ?? ON ?? (??)", [ name, exports.table, column ], done); | ||
return exports.driver.execQuery("CREATE " + (unique ? "UNIQUE" : "") + " INDEX ?? ON ?? (??)", [ name, exports.table, column ], done); | ||
case "postgresql": | ||
return exports.db.query("CREATE " + (unique ? "UNIQUE" : "") + " INDEX " + exports.table + "_" + name + " ON " + exports.table + " (" + column + ")", done); | ||
return exports.driver.execQuery("CREATE " + (unique ? "UNIQUE" : "") + " INDEX " + exports.table + "_" + name + " ON " + exports.table + " (" + column + ")", done); | ||
case "sqlite": | ||
return exports.db.all("CREATE " + (unique ? "UNIQUE" : "") + " INDEX " + name + " ON " + exports.table + " (" + column + ")", done); | ||
return exports.driver.execQuery("CREATE " + (unique ? "UNIQUE" : "") + " INDEX " + name + " ON " + exports.table + " (" + column + ")", done); | ||
} | ||
@@ -70,9 +81,9 @@ return done(unknownProtocol()); | ||
return function (done) { | ||
switch (exports.dialect) { | ||
switch (exports.driver.dialect) { | ||
case "mysql": | ||
return exports.db.query("DROP INDEX ?? ON ??", [ name, exports.table ], done); | ||
return exports.driver.execQuery("DROP INDEX ?? ON ??", [ name, exports.table ], done); | ||
case "postgresql": | ||
return exports.db.query("DROP INDEX " + exports.table + "_" + name, done); | ||
return exports.driver.execQuery("DROP INDEX " + exports.table + "_" + name, done); | ||
case "sqlite": | ||
return exports.db.all("DROP INDEX " + name, done); | ||
return exports.driver.execQuery("DROP INDEX " + name, done); | ||
} | ||
@@ -83,4 +94,10 @@ return done(unknownProtocol()); | ||
exports.dropTable = function (name) { | ||
return function (done) { | ||
exports.driver.execQuery("DROP TABLE IF EXISTS ??", [exports.table], done); | ||
}; | ||
} | ||
function unknownProtocol() { | ||
return new Error("Unknown protocol - " + exports.dialect); | ||
return new Error("Unknown protocol - " + exports.driver.dialect); | ||
} |
@@ -5,6 +5,5 @@ var Sync = require("../../lib/Sync").Sync; | ||
var sync = new Sync({ | ||
dialect : common.dialect, | ||
db : common.db, | ||
driver : common.driver, | ||
debug : function (text) { | ||
// console.log("> %s", text); | ||
//console.log("> %s", text); | ||
} | ||
@@ -14,48 +13,27 @@ }); | ||
sync.defineCollection(common.table, { | ||
id : { type: "number", primary: true, serial: true }, | ||
name : { type: "text", required: true, defaultValue: 'John' }, | ||
age : { type: "number", rational: true }, | ||
male : { type: "boolean" }, | ||
dttm : { type: "date", time: true, index: true }, | ||
dt : { type: "date" }, | ||
int2 : { type: "number", size: 2, index: [ "idx1", "idx2" ] }, | ||
int4 : { type: "number", size: 4 }, | ||
int8 : { type: "number", size: 8, index: [ "idx2" ] }, | ||
float4 : { type: "number", rational: true, size: 4 }, | ||
float8 : { type: "number", rational: true, size: 8 }, | ||
enm : { type: "enum", values: [ 'dog', 'cat'], defaultValue: 'dog', required: true }, | ||
binry : { type: "binary" } | ||
id : { type: "serial", key: true, serial: true }, | ||
name : { type: "text", required: true }, | ||
age : { type: "integer" }, | ||
male : { type: "boolean" }, | ||
born : { type: "date", time: true }, | ||
born2 : { type: "date" }, | ||
int2 : { type: "integer", size: 2 }, | ||
int4 : { type: "integer", size: 4 }, | ||
int8 : { type: "integer", size: 8 }, | ||
float4 : { type: "number", size: 4 }, | ||
float8 : { type: "number", size: 8 }, | ||
photo : { type: "binary" } | ||
}); | ||
describe("Synching", function () { | ||
it("should create the table", function (done) { | ||
sync.sync(function (err, info) { | ||
should.not.exist(err); | ||
should.exist(info); | ||
info.should.have.property("changes"); | ||
// These will fail because autosync has been disabled pending data integrity concerns. | ||
return done(); | ||
}); | ||
}); | ||
describe("db", function () { | ||
before(common.dropTable()); | ||
it("should have no changes on second call", function (done) { | ||
sync.sync(function (err, info) { | ||
should.not.exist(err); | ||
should.exist(info); | ||
info.should.have.property("changes", 0); | ||
return done(); | ||
}); | ||
}); | ||
}); | ||
if (common.dialect != "sqlite") { | ||
describe("Dropping a column", function () { | ||
before(common.dropColumn('dt')); | ||
it("should recreate it on first call", function (done) { | ||
describe("Synching", function () { | ||
it("should create the table", function (done) { | ||
sync.sync(function (err, info) { | ||
should.not.exist(err); | ||
should.exist(info); | ||
info.should.have.property("changes", 1); | ||
info.should.have.property("changes"); | ||
@@ -77,10 +55,84 @@ return done(); | ||
describe("Dropping a column that has an index", function () { | ||
before(common.dropColumn('dttm')); | ||
if (common.dialect != "sqlite") { | ||
describe("Dropping a column", function () { | ||
before(common.dropColumn('born')); | ||
it("should recreate column and index on first call", function (done) { | ||
xit("should recreate it on first call", function (done) { | ||
sync.sync(function (err, info) { | ||
should.not.exist(err); | ||
should.exist(info); | ||
info.should.have.property("changes", 1); | ||
return done(); | ||
}); | ||
}); | ||
it("should have no changes on second call", function (done) { | ||
sync.sync(function (err, info) { | ||
should.not.exist(err); | ||
should.exist(info); | ||
info.should.have.property("changes", 0); | ||
return done(); | ||
}); | ||
}); | ||
}); | ||
xdescribe("Dropping a column that has an index", function () { | ||
before(common.dropColumn('born2')); | ||
it("should recreate column and index on first call", function (done) { | ||
sync.sync(function (err, info) { | ||
should.not.exist(err); | ||
should.exist(info); | ||
info.should.have.property("changes", 2); | ||
return done(); | ||
}); | ||
}); | ||
it("should have no changes on second call", function (done) { | ||
sync.sync(function (err, info) { | ||
should.not.exist(err); | ||
should.exist(info); | ||
info.should.have.property("changes", 0); | ||
return done(); | ||
}); | ||
}); | ||
}); | ||
xdescribe("Adding a column", function () { | ||
before(common.addColumn('unknown_col')); | ||
it("should drop column on first call", function (done) { | ||
sync.sync(function (err, info) { | ||
should.not.exist(err); | ||
should.exist(info); | ||
info.should.have.property("changes", 1); | ||
return done(); | ||
}); | ||
}); | ||
it("should have no changes on second call", function (done) { | ||
sync.sync(function (err, info) { | ||
should.not.exist(err); | ||
should.exist(info); | ||
info.should.have.property("changes", 0); | ||
return done(); | ||
}); | ||
}); | ||
}); | ||
} | ||
xdescribe("Changing a column", function () { | ||
before(common.changeColumn('int4')); | ||
it("should update column on first call", function (done) { | ||
sync.sync(function (err, info) { | ||
should.not.exist(err); | ||
should.exist(info); | ||
info.should.have.property("changes", 2); | ||
info.should.have.property("changes", 1); | ||
@@ -102,6 +154,6 @@ return done(); | ||
describe("Adding a column", function () { | ||
before(common.addColumn('unknown_col')); | ||
xdescribe("Adding an index", function () { | ||
before(common.addIndex('xpto', 'int4')); | ||
it("should drop column on first call", function (done) { | ||
it("should drop index on first call", function (done) { | ||
sync.sync(function (err, info) { | ||
@@ -126,102 +178,54 @@ should.not.exist(err); | ||
}); | ||
} | ||
describe("Changing a column", function () { | ||
before(common.changeColumn('int4')); | ||
xdescribe("Dropping an index", function () { | ||
before(common.dropIndex('idx2')); | ||
it("should update column on first call", function (done) { | ||
sync.sync(function (err, info) { | ||
should.not.exist(err); | ||
should.exist(info); | ||
info.should.have.property("changes", 1); | ||
it("should drop index on first call", function (done) { | ||
sync.sync(function (err, info) { | ||
should.not.exist(err); | ||
should.exist(info); | ||
info.should.have.property("changes", 1); | ||
return done(); | ||
return done(); | ||
}); | ||
}); | ||
}); | ||
it("should have no changes on second call", function (done) { | ||
sync.sync(function (err, info) { | ||
should.not.exist(err); | ||
should.exist(info); | ||
info.should.have.property("changes", 0); | ||
it("should have no changes on second call", function (done) { | ||
sync.sync(function (err, info) { | ||
should.not.exist(err); | ||
should.exist(info); | ||
info.should.have.property("changes", 0); | ||
return done(); | ||
return done(); | ||
}); | ||
}); | ||
}); | ||
}); | ||
describe("Adding an index", function () { | ||
before(common.addIndex('xpto', 'dt')); | ||
it("should drop index on first call", function (done) { | ||
sync.sync(function (err, info) { | ||
should.not.exist(err); | ||
should.exist(info); | ||
info.should.have.property("changes", 1); | ||
return done(); | ||
xdescribe("Changing index to unique index", function () { | ||
before(function (done) { | ||
common.dropIndex('float8_index')(function () { | ||
common.addIndex('float8_index', 'float8', true)(done); | ||
}); | ||
}); | ||
}); | ||
it("should have no changes on second call", function (done) { | ||
sync.sync(function (err, info) { | ||
should.not.exist(err); | ||
should.exist(info); | ||
info.should.have.property("changes", 0); | ||
it("should drop index and recreate it on first call", function (done) { | ||
sync.sync(function (err, info) { | ||
should.not.exist(err); | ||
should.exist(info); | ||
info.should.have.property("changes", 1); | ||
return done(); | ||
return done(); | ||
}); | ||
}); | ||
}); | ||
}); | ||
describe("Dropping an index", function () { | ||
before(common.dropIndex('idx2')); | ||
it("should have no changes on second call", function (done) { | ||
sync.sync(function (err, info) { | ||
should.not.exist(err); | ||
should.exist(info); | ||
info.should.have.property("changes", 0); | ||
it("should drop index on first call", function (done) { | ||
sync.sync(function (err, info) { | ||
should.not.exist(err); | ||
should.exist(info); | ||
info.should.have.property("changes", 1); | ||
return done(); | ||
return done(); | ||
}); | ||
}); | ||
}); | ||
it("should have no changes on second call", function (done) { | ||
sync.sync(function (err, info) { | ||
should.not.exist(err); | ||
should.exist(info); | ||
info.should.have.property("changes", 0); | ||
return done(); | ||
}); | ||
}); | ||
}); | ||
describe("Changing index to unique index", function () { | ||
before(function (done) { | ||
common.dropIndex('dttm_index')(function () { | ||
common.addIndex('dttm_index', 'dttm', true)(done); | ||
}); | ||
}); | ||
it("should drop index and recreate it on first call", function (done) { | ||
sync.sync(function (err, info) { | ||
should.not.exist(err); | ||
should.exist(info); | ||
info.should.have.property("changes", 1); | ||
return done(); | ||
}); | ||
}); | ||
it("should have no changes on second call", function (done) { | ||
sync.sync(function (err, info) { | ||
should.not.exist(err); | ||
should.exist(info); | ||
info.should.have.property("changes", 0); | ||
return done(); | ||
}); | ||
}); | ||
}); |
@@ -0,11 +1,11 @@ | ||
var should = require("should"); | ||
var common = require("../common"); | ||
var Dialect = require("../../lib/Dialects/mysql"); | ||
var driver = common.fakeDriver; | ||
var should = require("should"); | ||
describe("MySQL.getType", function () { | ||
it("should detect text", function (done) { | ||
Dialect.getType(null, null, { type: "text" }).value.should.equal("VARCHAR(255)"); | ||
Dialect.getType(null, null, { type: "text", size: 150 }).value.should.equal("VARCHAR(150)"); | ||
Dialect.getType(null, null, { type: "text", size: 1000 }).value.should.equal("VARCHAR(1000)"); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "text" }, driver).value.should.equal("VARCHAR(255)"); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "text", size: 150 }, driver).value.should.equal("VARCHAR(150)"); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "text", size: 1000 }, driver).value.should.equal("VARCHAR(1000)"); | ||
@@ -16,6 +16,7 @@ return done(); | ||
it("should detect numbers", function (done) { | ||
Dialect.getType(null, null, { type: "number" }).value.should.equal("INTEGER"); | ||
Dialect.getType(null, null, { type: "number", size: 4 }).value.should.equal("INTEGER"); | ||
Dialect.getType(null, null, { type: "number", size: 2 }).value.should.equal("SMALLINT"); | ||
Dialect.getType(null, null, { type: "number", size: 8 }).value.should.equal("BIGINT"); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "integer" }, driver).value.should.equal("INTEGER"); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "integer", size: 4 }, driver).value.should.equal("INTEGER"); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "integer", size: 2 }, driver).value.should.equal("SMALLINT"); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "integer", size: 8 }, driver).value.should.equal("BIGINT"); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "number", rational: false }, driver).value.should.equal("INTEGER"); | ||
@@ -26,5 +27,5 @@ return done(); | ||
it("should detect rational numbers", function (done) { | ||
Dialect.getType(null, null, { type: "number", rational: true }).value.should.equal("FLOAT"); | ||
Dialect.getType(null, null, { type: "number", rational: true, size: 4 }).value.should.equal("FLOAT"); | ||
Dialect.getType(null, null, { type: "number", rational: true, size: 8 }).value.should.equal("DOUBLE"); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "number"}, driver).value.should.equal("FLOAT"); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "number", size: 4 }, driver).value.should.equal("FLOAT"); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "number", size: 8 }, driver).value.should.equal("DOUBLE"); | ||
@@ -35,3 +36,3 @@ return done(); | ||
it("should detect booleans", function (done) { | ||
Dialect.getType(null, null, { type: "boolean" }).value.should.equal("TINYINT(1)"); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "boolean" }, driver).value.should.equal("TINYINT(1)"); | ||
@@ -42,3 +43,3 @@ return done(); | ||
it("should detect dates", function (done) { | ||
Dialect.getType(null, null, { type: "date" }).value.should.equal("DATE"); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "date" }, driver).value.should.equal("DATE"); | ||
@@ -49,3 +50,3 @@ return done(); | ||
it("should detect dates with times", function (done) { | ||
Dialect.getType(null, null, { type: "date", time: true }).value.should.equal("DATETIME"); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "date", time: true }, driver).value.should.equal("DATETIME"); | ||
@@ -56,3 +57,3 @@ return done(); | ||
it("should detect binary", function (done) { | ||
Dialect.getType(null, null, { type: "binary" }).value.should.equal("BLOB"); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "binary" }, driver).value.should.equal("BLOB"); | ||
@@ -63,3 +64,3 @@ return done(); | ||
it("should detect big binary", function (done) { | ||
Dialect.getType(null, null, { type: "binary", big: true }).value.should.equal("LONGBLOB"); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "binary", big: true }, driver).value.should.equal("LONGBLOB"); | ||
@@ -69,4 +70,10 @@ return done(); | ||
it("should detect custom types", function (done) { | ||
Dialect.getType(null, { mapsTo: 'abc', type: "json" }, driver).value.should.equal("JSON"); | ||
return done(); | ||
}); | ||
it("should detect required items", function (done) { | ||
Dialect.getType(null, null, { type: "boolean", required: true }).value.should.match(/NOT NULL/); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "boolean", required: true }, driver).value.should.match(/NOT NULL/); | ||
@@ -77,3 +84,3 @@ return done(); | ||
it("should detect default values", function (done) { | ||
Dialect.getType(null, null, { type: "number", defaultValue: 3 }).value.should.match(/DEFAULT 3/); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "number", defaultValue: 3 }, driver).value.should.match(/DEFAULT \^\^3\^\^/); | ||
@@ -84,6 +91,3 @@ return done(); | ||
it("should detect serial", function (done) { | ||
var column = Dialect.getType(null, null, { | ||
type : "number", | ||
serial : true | ||
}).value; | ||
var column = Dialect.getType(null, { mapsTo: 'abc', type: "serial" }).value; | ||
@@ -97,11 +101,1 @@ column.should.match(/INT/); | ||
}); | ||
describe("MySQL.escapeId", function () { | ||
it("should correctly escape identifiers", function (done) { | ||
Dialect.escapeId("my_id").should.equal("`my_id`"); | ||
Dialect.escapeId("my_`id").should.equal("`my_``id`"); | ||
Dialect.escapeId("my_id", "sub").should.equal("`my_id`.`sub`"); | ||
return done(); | ||
}); | ||
}); |
@@ -0,11 +1,11 @@ | ||
var should = require("should"); | ||
var common = require("../common"); | ||
var Dialect = require("../../lib/Dialects/postgresql"); | ||
var driver = common.fakeDriver; | ||
var should = require("should"); | ||
describe("PostgreSQL.getType", function () { | ||
it("should detect text", function (done) { | ||
Dialect.getType(null, null, { type: "text" }).value.should.equal("TEXT"); | ||
Dialect.getType(null, null, { type: "text", size: 150 }).value.should.equal("TEXT"); | ||
Dialect.getType(null, null, { type: "text", size: 1000 }).value.should.equal("TEXT"); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "text" }, driver).value.should.equal("TEXT"); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "text", size: 150 }, driver).value.should.equal("TEXT"); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "text", size: 1000 }, driver).value.should.equal("TEXT"); | ||
@@ -16,6 +16,7 @@ return done(); | ||
it("should detect numbers", function (done) { | ||
Dialect.getType(null, null, { type: "number" }).value.should.equal("INTEGER"); | ||
Dialect.getType(null, null, { type: "number", size: 4 }).value.should.equal("INTEGER"); | ||
Dialect.getType(null, null, { type: "number", size: 2 }).value.should.equal("SMALLINT"); | ||
Dialect.getType(null, null, { type: "number", size: 8 }).value.should.equal("BIGINT"); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "integer" }, driver).value.should.equal("INTEGER"); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "integer", size: 4 }, driver).value.should.equal("INTEGER"); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "integer", size: 2 }, driver).value.should.equal("SMALLINT"); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "integer", size: 8 }, driver).value.should.equal("BIGINT"); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "number", rational: false }, driver).value.should.equal("INTEGER"); | ||
@@ -26,5 +27,5 @@ return done(); | ||
it("should detect rational numbers", function (done) { | ||
Dialect.getType(null, null, { type: "number", rational: true }).value.should.equal("REAL"); | ||
Dialect.getType(null, null, { type: "number", rational: true, size: 4 }).value.should.equal("REAL"); | ||
Dialect.getType(null, null, { type: "number", rational: true, size: 8 }).value.should.equal("DOUBLE PRECISION"); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "number"}, driver).value.should.equal("REAL"); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "number", size: 4 }, driver).value.should.equal("REAL"); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "number", size: 8 }, driver).value.should.equal("DOUBLE PRECISION"); | ||
@@ -35,3 +36,3 @@ return done(); | ||
it("should detect booleans", function (done) { | ||
Dialect.getType(null, null, { type: "boolean" }).value.should.equal("BOOLEAN"); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "boolean" }, driver).value.should.equal("BOOLEAN"); | ||
@@ -42,3 +43,3 @@ return done(); | ||
it("should detect dates", function (done) { | ||
Dialect.getType(null, null, { type: "date" }).value.should.equal("DATE"); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "date" }, driver).value.should.equal("DATE"); | ||
@@ -49,3 +50,3 @@ return done(); | ||
it("should detect dates with times", function (done) { | ||
Dialect.getType(null, null, { type: "date", time: true }).value.should.equal("TIMESTAMP WITHOUT TIME ZONE"); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "date", time: true }, driver).value.should.equal("TIMESTAMP WITHOUT TIME ZONE"); | ||
@@ -56,3 +57,3 @@ return done(); | ||
it("should detect binary", function (done) { | ||
Dialect.getType(null, null, { type: "binary" }).value.should.equal("BYTEA"); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "binary" }, driver).value.should.equal("BYTEA"); | ||
@@ -62,4 +63,4 @@ return done(); | ||
it("should detect required items", function (done) { | ||
Dialect.getType(null, null, { type: "boolean", required: true }).value.should.match(/NOT NULL/); | ||
it("should detect custom types", function (done) { | ||
Dialect.getType(null, { mapsTo: 'abc', type: "json" }, driver).value.should.equal("JSON"); | ||
@@ -69,14 +70,11 @@ return done(); | ||
it("should detect default values", function (done) { | ||
Dialect.getType(null, null, { type: "number", defaultValue: 3 }).value.should.match(/DEFAULT 3/); | ||
it("should detect required items", function (done) { | ||
Dialect.getType(null, { mapsTo: 'abc', type: "boolean", required: true }, driver).value.should.match(/NOT NULL/); | ||
return done(); | ||
}); | ||
}); | ||
describe("PostgreSQL.escapeId", function () { | ||
it("should correctly escape identifiers", function (done) { | ||
Dialect.escapeId("my_id").should.equal('"my_id"'); | ||
Dialect.escapeId("my_\"id").should.equal('"my_""id"'); | ||
Dialect.escapeId("my_id", "sub").should.equal('"my_id"."sub"'); | ||
it("should detect default values", function (done) { | ||
Dialect.getType(null, { mapsTo: 'abc', type: "number", defaultValue: 3 }, driver).value.should.match(/DEFAULT \^\^3\^\^/); | ||
Dialect.getType(null, { mapsTo: 'abc', type: 'date', defaultValue: Date.now }, driver).value.should.equal('DATE DEFAULT now()'); | ||
@@ -83,0 +81,0 @@ return done(); |
@@ -0,8 +1,6 @@ | ||
var should = require("should"); | ||
var common = require("../common"); | ||
var SQL = require("../../lib/SQL"); | ||
var driver = common.fakeDriver; | ||
var should = require("should"); | ||
var Dialect = common.fakeDialect; | ||
describe("SQL.CREATE_TABLE", function () { | ||
@@ -13,4 +11,4 @@ it("should return a CREATE TABLE", function (done) { | ||
columns : [ "first_fake_column", "second_fake_column" ], | ||
primary : [ "my_primary_key" ] | ||
}, Dialect).should.equal("CREATE TABLE $$fake_table$$ (first_fake_column, second_fake_column, " + | ||
keys : [ "my_primary_key" ] | ||
}, driver).should.equal("CREATE TABLE $$fake_table$$ (first_fake_column, second_fake_column, " + | ||
"PRIMARY KEY ($$my_primary_key$$))"); | ||
@@ -27,3 +25,3 @@ | ||
columns : [ "first_fake_column", "second_fake_column" ] | ||
}, Dialect).should.equal("CREATE TABLE $$fake_table$$ (first_fake_column, second_fake_column)"); | ||
}, driver).should.equal("CREATE TABLE $$fake_table$$ (first_fake_column, second_fake_column)"); | ||
@@ -38,3 +36,3 @@ return done(); | ||
name : "fake_table" | ||
}, Dialect).should.equal("DROP TABLE $$fake_table$$"); | ||
}, driver).should.equal("DROP TABLE $$fake_table$$"); | ||
@@ -47,14 +45,12 @@ return done(); | ||
describe("SQL.ALTER_TABLE_ADD_COLUMN", function () { | ||
it("should return an ALTER TABLE", function (done) { | ||
it("should be correct", function (done) { | ||
SQL.ALTER_TABLE_ADD_COLUMN({ | ||
name : "fake_table", | ||
column : "my_fake_column" | ||
}, Dialect).should.equal("ALTER TABLE $$fake_table$$ ADD my_fake_column"); | ||
}, driver).should.equal("ALTER TABLE $$fake_table$$ ADD my_fake_column"); | ||
return done(); | ||
}); | ||
}); | ||
describe("SQL.ALTER_TABLE_ADD_COLUMN", function () { | ||
it("should return an ALTER TABLE", function (done) { | ||
it("should be correct when first is true", function (done) { | ||
SQL.ALTER_TABLE_ADD_COLUMN({ | ||
@@ -64,10 +60,8 @@ name : "fake_table", | ||
first : true | ||
}, Dialect).should.equal("ALTER TABLE $$fake_table$$ ADD my_fake_column FIRST"); | ||
}, driver).should.equal("ALTER TABLE $$fake_table$$ ADD my_fake_column FIRST"); | ||
return done(); | ||
}); | ||
}); | ||
describe("SQL.ALTER_TABLE_ADD_COLUMN", function () { | ||
it("should return an ALTER TABLE", function (done) { | ||
it("should be correct when after is specified", function (done) { | ||
SQL.ALTER_TABLE_ADD_COLUMN({ | ||
@@ -77,3 +71,3 @@ name : "fake_table", | ||
after : "other_column" | ||
}, Dialect).should.equal("ALTER TABLE $$fake_table$$ ADD my_fake_column AFTER $$other_column$$"); | ||
}, driver).should.equal("ALTER TABLE $$fake_table$$ ADD my_fake_column AFTER $$other_column$$"); | ||
@@ -84,2 +78,14 @@ return done(); | ||
describe("SQL.ALTER_TABLE_RENAME_COLUMN", function () { | ||
it("should be correct", function (done) { | ||
SQL.ALTER_TABLE_RENAME_COLUMN({ | ||
name : "fake_table", | ||
oldColName : "usersfullname", | ||
newColName : "name" | ||
}, driver).should.equal("ALTER TABLE $$fake_table$$ RENAME COLUMN $$usersfullname$$ TO $$name$$"); | ||
return done(); | ||
}); | ||
}); | ||
describe("SQL.ALTER_TABLE_MODIFY_COLUMN", function () { | ||
@@ -90,3 +96,3 @@ it("should return an ALTER TABLE", function (done) { | ||
column : "my_fake_column" | ||
}, Dialect).should.equal("ALTER TABLE $$fake_table$$ MODIFY my_fake_column"); | ||
}, driver).should.equal("ALTER TABLE $$fake_table$$ MODIFY my_fake_column"); | ||
@@ -102,3 +108,3 @@ return done(); | ||
column : "my_fake_column" | ||
}, Dialect).should.equal("ALTER TABLE $$fake_table$$ DROP $$my_fake_column$$"); | ||
}, driver).should.equal("ALTER TABLE $$fake_table$$ DROP $$my_fake_column$$"); | ||
@@ -115,3 +121,3 @@ return done(); | ||
columns : [ "my_fake_column" ] | ||
}, Dialect).should.equal("CREATE INDEX $$fake_index$$ ON $$fake_table$$ ($$my_fake_column$$)"); | ||
}, driver).should.equal("CREATE INDEX $$fake_index$$ ON $$fake_table$$ ($$my_fake_column$$)"); | ||
@@ -127,3 +133,3 @@ return done(); | ||
columns : [ "my_fake_column" ] | ||
}, Dialect).should.equal("CREATE UNIQUE INDEX $$fake_index$$ ON $$fake_table$$ ($$my_fake_column$$)"); | ||
}, driver).should.equal("CREATE UNIQUE INDEX $$fake_index$$ ON $$fake_table$$ ($$my_fake_column$$)"); | ||
@@ -139,3 +145,3 @@ return done(); | ||
collection : "fake_table" | ||
}, Dialect).should.equal("DROP INDEX $$fake_index$$ ON $$fake_table$$"); | ||
}, driver).should.equal("DROP INDEX $$fake_index$$ ON $$fake_table$$"); | ||
@@ -142,0 +148,0 @@ return done(); |
@@ -0,10 +1,10 @@ | ||
var should = require("should"); | ||
var common = require("../common"); | ||
var Dialect = require("../../lib/Dialects/sqlite"); | ||
var driver = common.fakeDriver; | ||
var should = require("should"); | ||
describe("SQLite.getType", function () { | ||
it("should detect text", function (done) { | ||
Dialect.getType(null, null, { type: "text" }).value.should.equal("TEXT"); | ||
Dialect.getType(null, null, { type: "text", size: 150 }).value.should.equal("TEXT"); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "text" }, driver).value.should.equal("TEXT"); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "text", size: 150 }, driver).value.should.equal("TEXT"); | ||
@@ -15,6 +15,7 @@ return done(); | ||
it("should detect numbers", function (done) { | ||
Dialect.getType(null, null, { type: "number" }).value.should.equal("INTEGER"); | ||
Dialect.getType(null, null, { type: "number", size: 4 }).value.should.equal("INTEGER"); | ||
Dialect.getType(null, null, { type: "number", size: 2 }).value.should.equal("INTEGER"); | ||
Dialect.getType(null, null, { type: "number", size: 8 }).value.should.equal("INTEGER"); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "integer" }, driver).value.should.equal("INTEGER"); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "integer", size: 4 }, driver).value.should.equal("INTEGER"); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "integer", size: 2 }, driver).value.should.equal("INTEGER"); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "integer", size: 8 }, driver).value.should.equal("INTEGER"); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "number", rational: false }, driver).value.should.equal("INTEGER"); | ||
@@ -25,5 +26,5 @@ return done(); | ||
it("should detect rational numbers", function (done) { | ||
Dialect.getType(null, null, { type: "number", rational: true }).value.should.equal("REAL"); | ||
Dialect.getType(null, null, { type: "number", rational: true, size: 4 }).value.should.equal("REAL"); | ||
Dialect.getType(null, null, { type: "number", rational: true, size: 8 }).value.should.equal("REAL"); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "number"}, driver).value.should.equal("REAL"); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "number", size: 4 }, driver).value.should.equal("REAL"); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "number", size: 8 }, driver).value.should.equal("REAL"); | ||
@@ -34,3 +35,3 @@ return done(); | ||
it("should detect booleans", function (done) { | ||
Dialect.getType(null, null, { type: "boolean" }).value.should.equal("INTEGER"); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "boolean" }, driver).value.should.equal("INTEGER UNSIGNED"); | ||
@@ -41,4 +42,4 @@ return done(); | ||
it("should detect dates", function (done) { | ||
Dialect.getType(null, null, { type: "date" }).value.should.equal("DATETIME"); | ||
Dialect.getType(null, null, { type: "date", time: true }).value.should.equal("DATETIME"); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "date" }, driver).value.should.equal("DATETIME"); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "date", time: true }, driver).value.should.equal("DATETIME"); | ||
@@ -49,4 +50,4 @@ return done(); | ||
it("should detect binary", function (done) { | ||
Dialect.getType(null, null, { type: "binary" }).value.should.equal("BLOB"); | ||
Dialect.getType(null, null, { type: "binary", big: true }).value.should.equal("BLOB"); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "binary" }, driver).value.should.equal("BLOB"); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "binary", big: true }, driver).value.should.equal("BLOB"); | ||
@@ -56,4 +57,10 @@ return done(); | ||
it("should detect custom types", function (done) { | ||
Dialect.getType(null, { mapsTo: 'abc', type: "json" }, driver).value.should.equal("JSON"); | ||
return done(); | ||
}); | ||
it("should detect required items", function (done) { | ||
Dialect.getType(null, null, { type: "boolean", required: true }).value.should.match(/NOT NULL/); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "boolean", required: true }, driver).value.should.match(/NOT NULL/); | ||
@@ -64,3 +71,3 @@ return done(); | ||
it("should detect default values", function (done) { | ||
Dialect.getType(null, null, { type: "number", defaultValue: 3 }).value.should.match(/DEFAULT 3/); | ||
Dialect.getType(null, { mapsTo: 'abc', type: "number", defaultValue: 3 }, driver).value.should.match(/DEFAULT \^\^3\^\^/); | ||
@@ -71,6 +78,3 @@ return done(); | ||
it("should detect serial", function (done) { | ||
var column = Dialect.getType(null, null, { | ||
type : "number", | ||
serial : true | ||
}).value; | ||
var column = Dialect.getType(null, { mapsTo: 'abc', type: "serial" }).value; | ||
@@ -83,11 +87,1 @@ column.should.match(/INT/); | ||
}); | ||
describe("SQLite.escapeId", function () { | ||
it("should correctly escape identifiers", function (done) { | ||
Dialect.escapeId("my_id").should.equal("`my_id`"); | ||
Dialect.escapeId("my_`id").should.equal("`my_``id`"); | ||
Dialect.escapeId("my_id", "sub").should.equal("`my_id`.`sub`"); | ||
return done(); | ||
}); | ||
}); |
var program = require("commander"); | ||
var Mocha = require("mocha"); | ||
var orm = require("orm"); | ||
var common = require("./common"); | ||
var url = require("url"); | ||
var common = require("./common"); | ||
program.version("0.1.0") | ||
@@ -23,38 +23,13 @@ .option("-u, --uri <uri>", "Database URI", String, null) | ||
switch (uri.protocol) { | ||
case "mysql:": | ||
common.dialect = "mysql"; | ||
orm.connect(uri, function (err, db) { | ||
if (err) throw err; | ||
common.db = require("mysql").createConnection(program.uri); | ||
common.db.connect(testDatabase); | ||
break; | ||
case "postgres:": | ||
case "postgresql:": | ||
case "pg:": | ||
common.dialect = "postgresql"; | ||
common.driver = db.driver; | ||
common.db = new (require("pg").Client)(uri); | ||
common.db.connect(testDatabase); | ||
break; | ||
case "sqlite:": | ||
case "sqlite3:": | ||
common.dialect = "sqlite"; | ||
testDatabase() | ||
}); | ||
common.db = new (require("sqlite3").Database)(uri.pathname); | ||
testDatabase(); | ||
// common.db.connect(testDatabase); | ||
break; | ||
default: | ||
process.stdout.write("Database protocol not supported.\n"); | ||
process.exit(2); | ||
} | ||
function testDatabase() { | ||
var mocha = new Mocha({ reporter : "spec" }); | ||
function testDatabase(err) { | ||
if (err) { | ||
throw err; | ||
} | ||
var mocha = new Mocha({ | ||
reporter : "spec" | ||
}); | ||
mocha.addFile(__dirname + "/integration/db.js"); | ||
@@ -61,0 +36,0 @@ mocha.run(function (failures) { |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
69058
21
2021
103
4
1