From 6d5ad5e470a5e33975a9a9d3e3c7a07aba407b2e Mon Sep 17 00:00:00 2001 From: yogesh Date: Thu, 16 Oct 2014 17:33:12 +0530 Subject: [PATCH 1/4] (cherry picked from commit a6d31e8) --- lib/mysql.js | 2 ++ test/mysql.test.js | 28 ++++++++++++++++++++++++---- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/lib/mysql.js b/lib/mysql.js index 4bd4b55..3325f6e 100644 --- a/lib/mysql.js +++ b/lib/mysql.js @@ -816,6 +816,7 @@ MySQL.prototype.alterTable = function (model, actualFields, actualIndexes, done, if (kind && type) { sql.push('ADD ' + kind + ' INDEX `' + propName + '` (`' + propName + '`) ' + type); } else { + (typeof i === 'object' && i.unique && i.unique === true) && (kind = "UNIQUE"); sql.push('ADD ' + kind + ' INDEX `' + propName + '` ' + type + ' (`' + propName + '`) '); } } @@ -945,6 +946,7 @@ MySQL.prototype.singleIndexSettingsSQL = function (model, prop) { if (kind && type) { return (kind + ' INDEX ' + columnName + ' (' + columnName + ') ' + type); } else { + (typeof i === 'object' && i.unique && i.unique === true) && (kind = "UNIQUE"); return (kind + ' INDEX ' + columnName + ' ' + type + ' (' + columnName + ') '); } }; diff --git a/test/mysql.test.js b/test/mysql.test.js index dfc2198..af1c3dc 100644 --- a/test/mysql.test.js +++ b/test/mysql.test.js @@ -1,6 +1,6 @@ var should = require('./init.js'); -var Post, PostWithStringId, db; +var Post, PostWithStringId, PostWithUniqueTitle, db; describe('mysql', function () { @@ -21,7 +21,12 @@ describe('mysql', function () { content: { type: String } }); - db.automigrate(['PostWithDefaultId', 'PostWithStringId'], function (err) { + PostWithUniqueTitle = db.define('PostWithUniqueTitle', { + title: { type: String, length: 255, index: {unique: true} }, + content: { type: String } + }); + + db.automigrate(['PostWithDefaultId', 'PostWithStringId', 'PostWithUniqueTitle'], function (err) { should.not.exist(err); done(err); }); @@ -30,7 +35,9 @@ describe('mysql', function () { beforeEach(function (done) { Post.destroyAll(function () { PostWithStringId.destroyAll(function () { - done(); + PostWithUniqueTitle.destroyAll(function () { + done(); + }); }); }); }); @@ -448,9 +455,22 @@ describe('mysql', function () { }); }); + it('should not allow duplicate titles', function (done) { + var data = {title: 'a', content: 'AAA'}; + PostWithUniqueTitle.create(data, function (err, post) { + should.not.exist(err); + PostWithUniqueTitle.create(data, function (err, post) { + should.exist(err); + done(); + }); + }); + }); + after(function (done) { Post.destroyAll(function () { - PostWithStringId.destroyAll(done); + PostWithStringId.destroyAll(function () { + PostWithUniqueTitle.destroyAll(done); + }); }); }); }); From b8589545fc682b2356497921ceb53f611a03a55a Mon Sep 17 00:00:00 2001 From: Ryan Graham Date: Mon, 29 Dec 2014 08:27:46 -0800 Subject: [PATCH 2/4] Fix bad CLA URL in CONTRIBUTING.md --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 630455d..01dbb54 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,7 +14,7 @@ Contributing to `loopback-connector-mysql` is easy. In a few simple steps: * Adhere to code style outlined in the [Google C++ Style Guide][] and [Google Javascript Style Guide][]. - * Sign the [Contributor License Agreement](https://cla.strongloop.com/strongloop/loopback-connector-mysql) + * Sign the [Contributor License Agreement](https://cla.strongloop.com/agreements/strongloop/loopback-connector-mysql) * Submit a pull request through Github. From 7fe8306db2d93c5dd6649f5641616bbfbfb579b9 Mon Sep 17 00:00:00 2001 From: Raymond Feng Date: Fri, 9 Jan 2015 09:02:36 -0800 Subject: [PATCH 3/4] Use mysql.escape/escapeId() --- lib/mysql.js | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/lib/mysql.js b/lib/mysql.js index 7e8e680..0864a2e 100644 --- a/lib/mysql.js +++ b/lib/mysql.js @@ -171,7 +171,7 @@ MySQL.prototype.query = function (sql, callback) { } if (self.settings.createDatabase) { // Call USE db ... - connection.query('USE `' + db + '`', function (err) { + connection.query('USE ' + client.escapeId(db), function (err) { if (err) { if (err && err.message.match(/(^|: )unknown database/i)) { var charset = self.settings.charset; @@ -179,7 +179,7 @@ MySQL.prototype.query = function (sql, callback) { var q = 'CREATE DATABASE ' + db + ' CHARACTER SET ' + charset + ' COLLATE ' + collation; connection.query(q, function (err) { if (!err) { - connection.query('USE `' + db + '`', function (err) { + connection.query('USE ' + client.escapeId(db), function (err) { runQuery(connection); }); } else { @@ -324,8 +324,7 @@ MySQL.prototype.toDatabase = function (prop, val, forCreate) { return this.client.escape(val); } if (prop.type === Number) { - val = Number(val); - return isNaN(val) ? 'NULL' : val; + return this.client.escape(val); } if (prop.type === Date) { if (!val) { @@ -400,7 +399,7 @@ MySQL.prototype.fromDatabase = function (model, data) { }; MySQL.prototype.escapeName = function (name) { - return '`' + name.replace(/\./g, '`.`') + '`'; + return this.client.escapeId(name); }; MySQL.prototype.getColumns = function (model, props) { @@ -771,7 +770,8 @@ MySQL.prototype.alterTable = function (model, actualFields, actualIndexes, done, if (found) { actualize(propName, found); } else { - sql.push('ADD COLUMN `' + propName + '` ' + self.propertySettingsSQL(model, propName)); + sql.push('ADD COLUMN ' + self.client.escapeId(propName) + ' ' + + self.propertySettingsSQL(model, propName)); } }); @@ -781,7 +781,7 @@ MySQL.prototype.alterTable = function (model, actualFields, actualIndexes, done, var notFound = !~propNames.indexOf(f.Field); if (m.properties[f.Field] && self.id(model, f.Field)) return; if (notFound || !m.properties[f.Field]) { - sql.push('DROP COLUMN `' + f.Field + '`'); + sql.push('DROP COLUMN ' + self.client.escapeId(f.Field)); } }); } @@ -790,7 +790,7 @@ MySQL.prototype.alterTable = function (model, actualFields, actualIndexes, done, aiNames.forEach(function (indexName) { if (indexName === 'PRIMARY' || (m.properties[indexName] && self.id(model, indexName))) return; if (indexNames.indexOf(indexName) === -1 && !m.properties[indexName] || m.properties[indexName] && !m.properties[indexName].index) { - sql.push('DROP INDEX `' + indexName + '`'); + sql.push('DROP INDEX ' + self.client.escapeId(indexName)); } else { // first: check single (only type and kind) if (m.properties[indexName] && !m.properties[indexName].index) { @@ -805,7 +805,7 @@ MySQL.prototype.alterTable = function (model, actualFields, actualIndexes, done, }); } if (!orderMatched) { - sql.push('DROP INDEX `' + indexName + '`'); + sql.push('DROP INDEX ' + self.client.escapeId(indexName)); delete ai[indexName]; } } @@ -819,6 +819,7 @@ MySQL.prototype.alterTable = function (model, actualFields, actualIndexes, done, } var found = ai[propName] && ai[propName].info; if (!found) { + var pName = self.client.escapeId(propName); var type = ''; var kind = ''; if (i.type) { @@ -828,10 +829,10 @@ MySQL.prototype.alterTable = function (model, actualFields, actualIndexes, done, // kind = i.kind; } if (kind && type) { - sql.push('ADD ' + kind + ' INDEX `' + propName + '` (`' + propName + '`) ' + type); + sql.push('ADD ' + kind + ' INDEX ' + pName + ' (' + pName + ') ' + type); } else { (typeof i === 'object' && i.unique && i.unique === true) && (kind = "UNIQUE"); - sql.push('ADD ' + kind + ' INDEX `' + propName + '` ' + type + ' (`' + propName + '`) '); + sql.push('ADD ' + kind + ' INDEX ' + pName + ' ' + type + ' (' + pName + ') '); } } }); @@ -841,6 +842,7 @@ MySQL.prototype.alterTable = function (model, actualFields, actualIndexes, done, var i = m.settings.indexes[indexName]; var found = ai[indexName] && ai[indexName].info; if (!found) { + var iName = self.client.escapeId(indexName); var type = ''; var kind = ''; if (i.type) { @@ -850,9 +852,9 @@ MySQL.prototype.alterTable = function (model, actualFields, actualIndexes, done, kind = i.kind; } if (kind && type) { - sql.push('ADD ' + kind + ' INDEX `' + indexName + '` (' + i.columns + ') ' + type); + sql.push('ADD ' + kind + ' INDEX ' + iName + ' (' + i.columns + ') ' + type); } else { - sql.push('ADD ' + kind + ' INDEX ' + type + ' `' + indexName + '` (' + i.columns + ')'); + sql.push('ADD ' + kind + ' INDEX ' + type + ' ' + iName + ' (' + i.columns + ')'); } } }); @@ -871,7 +873,8 @@ MySQL.prototype.alterTable = function (model, actualFields, actualIndexes, done, function actualize(propName, oldSettings) { var newSettings = m.properties[propName]; if (newSettings && changed(newSettings, oldSettings)) { - sql.push('CHANGE COLUMN `' + propName + '` `' + propName + '` ' + + var pName = self.client.escapeId(propName); + sql.push('CHANGE COLUMN ' + pName + ' ' + pName + ' ' + self.propertySettingsSQL(model, propName)); } } From ae989add21796aaf7af62d90edb335af17902ea4 Mon Sep 17 00:00:00 2001 From: Raymond Feng Date: Fri, 9 Jan 2015 09:21:14 -0800 Subject: [PATCH 4/4] v1.5.0 --- CHANGES.md | 10 ++++++++++ package.json | 4 ++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 29de763..0ea866a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,13 @@ +2015-01-09, Version 1.5.0 +========================= + + * Use mysql.escape/escapeId() (Raymond Feng) + + * Fix bad CLA URL in CONTRIBUTING.md (Ryan Graham) + + * (cherry picked from commit a6d31e8) (yogesh) + + 2014-12-05, Version 1.4.9 ========================= diff --git a/package.json b/package.json index 7fbf7dc..68688cc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "loopback-connector-mysql", - "version": "1.4.9", + "version": "1.5.0", "description": "MySQL connector for loopback-datasource-juggler", "main": "index.js", "scripts": { @@ -27,6 +27,6 @@ "url": "https://github.com/strongloop/loopback-connector-mysql/blob/master/LICENSE" }, "optionalDependencies": { - "sl-blip": "http://blip.strongloop.com/loopback-connector-mysql@1.4.9" + "sl-blip": "http://blip.strongloop.com/loopback-connector-mysql@1.5.0" } }