不要怂,就是干,撸起袖子干!

Commit 75b2503a by Jan Aagaard Meier

Merge pull request #4089 from mikeringrose/master

MySQL Geometry Support
2 parents e1de2e37 df13127d
......@@ -991,18 +991,18 @@ var QueryGenerator = {
return self.handleSequelizeMethod(attr);
}
if (mainModel && mainModel._isGeometryAttribute(attr)) {
return self.geometrySelect(attr);
}
if (Array.isArray(attr) && attr.length === 2) {
if (attr[0]._isSequelizeMethod) {
attr[0] = self.handleSequelizeMethod(attr[0]);
addTable = false;
} else {
if (mainModel && mainModel._isGeometryAttribute(attr[1])) {
attr[0] = this.geometrySelect(attr[0]);
}
else if (attr[0].indexOf('(') === -1 && attr[0].indexOf(')') === -1) {
} else if (attr[0].indexOf('(') === -1 && attr[0].indexOf(')') === -1) {
attr[0] = self.quoteIdentifier(attr[0]);
}
}
attr = [attr[0], self.quoteIdentifier(attr[1])].join(' AS ');
} else {
attr = attr.indexOf(Utils.TICK_CHAR) < 0 && attr.indexOf('"') < 0 ? self.quoteIdentifiers(attr) : attr;
......
......@@ -16,8 +16,28 @@ UUID.prototype.toSql = function() {
return 'CHAR(36) BINARY';
};
var SUPPORTED_GEOMETRY_TYPES = ['POINT', 'LINESTRING', 'POLYGON'];
var GEOMETRY = function() {
if (!(this instanceof GEOMETRY)) return new GEOMETRY();
BaseTypes.GEOMETRY.apply(this, arguments);
if (_.isEmpty(this.type)) {
this.sqlType = this.key;
} else if (_.includes(SUPPORTED_GEOMETRY_TYPES, this.type)) {
this.sqlType = this.type;
} else {
throw new Error('Supported geometry types are: ' + SUPPORTED_GEOMETRY_TYPES.join(', '));
}
};
util.inherits(GEOMETRY, BaseTypes.GEOMETRY);
GEOMETRY.prototype.toSql = function() {
return this.sqlType;
};
module.exports = {
UUID: UUID
UUID: UUID,
GEOMETRY: GEOMETRY
};
_.forIn(module.exports, function (DataType, key) {
......
......@@ -32,7 +32,8 @@ MysqlDialect.prototype.supports = _.merge(_.cloneDeep(Abstract.prototype.support
using: 1,
},
indexViaAlter: true,
NUMERIC: true
NUMERIC: true,
GEOMETRY: true
});
MysqlDialect.prototype.Query = Query;
......
'use strict';
var Utils = require('../../utils')
, DataTypes = require('../../data-types');
, DataTypes = require('../../data-types')
, SqlString = require('../../sql-string')
, Wkt = require('wellknown');
var QueryGenerator = {
dialect: 'mysql',
......@@ -349,6 +351,17 @@ var QueryGenerator = {
if (identifier === '*') return identifier;
return Utils.addTicks(identifier, '`');
},
escape: function(value, field) {
if (value && value._isSequelizeMethod) {
return this.handleSequelizeMethod(value);
} else if (value && field && field.type instanceof DataTypes.GEOMETRY) {
return 'GeomFromText(\'' + Wkt.stringify(value) + '\')';
} else {
return SqlString.escape(value, false, this.options.timezone, this.dialect, field);
}
},
/**
* Generates an SQL query that returns all foreign keys of a table.
*
......@@ -370,6 +383,10 @@ var QueryGenerator = {
*/
dropForeignKeyQuery: function(tableName, foreignKey) {
return 'ALTER TABLE ' + this.quoteTable(tableName) + ' DROP FOREIGN KEY ' + this.quoteIdentifier(foreignKey) + ';';
},
geometrySelect: function(column) {
return 'AsText(' + this.quoteIdentifiers(column) + ') AS ' + column;
}
};
......
......@@ -43,6 +43,7 @@ PostgresDialect.prototype.supports = _.merge(_.cloneDeep(Abstract.prototype.supp
},
NUMERIC: true,
ARRAY: true,
GEOMETRY: true,
JSON: true,
JSONB: true,
deferrableConstraints: true
......
......@@ -898,12 +898,7 @@ var QueryGenerator = {
return SqlString.escape(JSON.stringify(v), false, this.options.timezone, this.dialect, field);
}, this).join(',') + ']::' + jsonType.key + '[]';
} else if (value && field && field.type instanceof DataTypes.GEOMETRY) {
var s = "ST_GeomFromGeoJSON('" + JSON.stringify(value) + "'";
if (field.type.srid) {
s += + ", " + field.type.srid;
}
s += ")";
return s;
return "ST_GeomFromGeoJSON('" + JSON.stringify(value) + "')";
}
return SqlString.escape(value, false, this.options.timezone, this.dialect, field);
......@@ -944,6 +939,10 @@ var QueryGenerator = {
}
return AbstractQueryGenerator.setAutocommitQuery.call(this, value, options);
},
geometrySelect: function(column) {
return this.quoteIdentifiers(column);
}
};
......
......@@ -362,7 +362,7 @@ Instance.prototype.set = function(key, value, options) { // testhint options:non
}
if (this.Model._hasGeometryAttributes && this.Model._isGeometryAttribute(key) && _.isString(value)) {
value = this.dialect.DatatTypes.GEOMETRY.parse(value);
value = this.Model.attributes[key].type.parse(value);
}
if (!options.raw && ((primitives.indexOf(typeof value) === -1 && value !== null) || value !== originalValue)) {
......
'use strict';
/* jshint -W030 */
/* jshint -W110 */
var chai = require('chai')
, expect = chai.expect
, Support = require(__dirname + '/../support')
, DataTypes = require(__dirname + '/../../../lib/data-types');
var current = Support.sequelize;
describe(Support.getTestDialectTeaser('Model'), function() {
if (current.dialect.supports.GEOMETRY) {
describe('GEOMETRY', function() {
beforeEach(function() {
return Support.prepareTransactionTest(this.sequelize).bind(this).then(function(sequelize) {
this.User = this.sequelize.define('User', {
username: DataTypes.STRING,
geometry: DataTypes.GEOMETRY
});
return this.User.sync({ force: true });
});
});
it('should create a geometry object', function() {
var User = this.User;
var point = { type: 'Point', coordinates: [39.807222,-76.984722]};
return User.create({username: 'username', geometry: point }).then(function(newUser) {
expect(newUser).not.to.be.null;
expect(newUser.geometry).to.be.deep.eql(point);
});
});
it('should update a geometry object', function() {
var User = this.User;
var point1 = { type: 'Point', coordinates: [39.807222,-76.984722]}
, point2 = { type: 'Point', coordinates: [49.807222,-86.984722]};
var props = {username: 'username', geometry: point1};
return User.create(props).then(function(user) {
return User.update({geometry: point2}, {where: {username: props.username}});
}).then(function(count) {
return User.findOne({where: {username: props.username}});
}).then(function(user) {
expect(user.geometry).to.be.deep.eql(point2);
});
});
});
describe('GEOMETRY(POINT)', function() {
beforeEach(function() {
return Support.prepareTransactionTest(this.sequelize).bind(this).then(function(sequelize) {
this.User = this.sequelize.define('User', {
username: DataTypes.STRING,
geometry: DataTypes.GEOMETRY('POINT')
});
return this.User.sync({ force: true });
});
});
it('should create a geometry object', function() {
var User = this.User;
var point = { type: 'Point', coordinates: [39.807222,-76.984722]};
return User.create({username: 'username', geometry: point }).then(function(newUser) {
expect(newUser).not.to.be.null;
expect(newUser.geometry).to.be.deep.eql(point);
});
});
it('should update a geometry object', function() {
var User = this.User;
var point1 = { type: 'Point', coordinates: [39.807222,-76.984722]}
, point2 = { type: 'Point', coordinates: [49.807222,-86.984722]};
var props = {username: 'username', geometry: point1};
return User.create(props).then(function(user) {
return User.update({geometry: point2}, {where: {username: props.username}});
}).then(function(count) {
return User.findOne({where: {username: props.username}});
}).then(function(user) {
expect(user.geometry).to.be.deep.eql(point2);
});
});
});
describe('GEOMETRY(LINESTRING)', function() {
beforeEach(function() {
return Support.prepareTransactionTest(this.sequelize).bind(this).then(function(sequelize) {
this.User = this.sequelize.define('User', {
username: DataTypes.STRING,
geometry: DataTypes.GEOMETRY('LINESTRING')
});
return this.User.sync({ force: true });
});
});
it('should create a geometry object', function() {
var User = this.User;
var point = { type: 'LineString', 'coordinates': [ [100.0, 0.0], [101.0, 1.0] ] };
return User.create({username: 'username', geometry: point }).then(function(newUser) {
expect(newUser).not.to.be.null;
expect(newUser.geometry).to.be.deep.eql(point);
});
});
it('should update a geometry object', function() {
var User = this.User;
var point1 = { type: 'LineString', coordinates: [ [100.0, 0.0], [101.0, 1.0] ] }
, point2 = { type: 'LineString', coordinates: [ [101.0, 0.0], [102.0, 1.0] ] };
var props = {username: 'username', geometry: point1};
return User.create(props).then(function(user) {
return User.update({geometry: point2}, {where: {username: props.username}});
}).then(function(count) {
return User.findOne({where: {username: props.username}});
}).then(function(user) {
expect(user.geometry).to.be.deep.eql(point2);
});
});
});
describe('GEOMETRY(POLYGON)', function() {
beforeEach(function() {
return Support.prepareTransactionTest(this.sequelize).bind(this).then(function(sequelize) {
this.User = this.sequelize.define('User', {
username: DataTypes.STRING,
geometry: DataTypes.GEOMETRY('POLYGON')
});
return this.User.sync({ force: true });
});
});
it('should create a geometry object', function() {
var User = this.User;
var point = { type: 'Polygon', coordinates: [
[ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0],
[100.0, 1.0], [100.0, 0.0] ]
]};
return User.create({username: 'username', geometry: point }).then(function(newUser) {
expect(newUser).not.to.be.null;
expect(newUser.geometry).to.be.deep.eql(point);
});
});
it('should update a geometry object', function() {
var User = this.User;
var polygon1 = { type: 'Polygon', coordinates: [
[ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0],
[100.0, 1.0], [100.0, 0.0] ]
]}
, polygon2 = { type: 'Polygon', coordinates: [
[ [100.0, 0.0], [102.0, 0.0], [102.0, 1.0],
[100.0, 1.0], [100.0, 0.0] ]
]};
var props = {username: 'username', geometry: polygon1};
return User.create(props).then(function(user) {
return User.update({geometry: polygon2}, {where: {username: props.username}});
}).then(function(count) {
return User.findOne({where: {username: props.username}});
}).then(function(user) {
expect(user.geometry).to.be.deep.eql(polygon2);
});
});
});
}
});
......@@ -667,26 +667,30 @@ suite(Support.getTestDialectTeaser('SQL'), function() {
});
}
if (current.dialect.supports.ARRAY) {
if (current.dialect.supports.GEOMETRY) {
suite('GEOMETRY', function () {
testsql('GEOMETRY', DataTypes.GEOMETRY, {
postgres: 'GEOMETRY'
default: 'GEOMETRY'
});
testsql('GEOMETRY(\'POINT\')', DataTypes.GEOMETRY('POINT'), {
postgres: 'GEOMETRY(POINT)'
postgres: 'GEOMETRY(POINT)',
mysql: 'POINT'
});
testsql('GEOMETRY(\'LINESTRING\')', DataTypes.GEOMETRY('LINESTRING'), {
postgres: 'GEOMETRY(LINESTRING)',
mysql: 'LINESTRING'
});
testsql('GEOMETRY(\'POLYGON\')', DataTypes.GEOMETRY('POLYGON'), {
postgres: 'GEOMETRY(POLYGON)'
postgres: 'GEOMETRY(POLYGON)',
mysql: 'POLYGON'
});
testsql('GEOMETRY(\'POINT\',4326)', DataTypes.GEOMETRY('POINT', 4326), {
postgres: 'GEOMETRY(POINT,4326)'
postgres: 'GEOMETRY(POINT,4326)',
mysql: 'POINT'
});
});
}
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!