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

Commit 778ec124 by EdwardGonzalez

geography and tests

1 parent 2efa123a
......@@ -10,6 +10,7 @@
- [ADDED] Add `IF EXIST` to postgres alter enum [#4464](https://github.com/sequelize/sequelize/pull/4464)
- [FIXED] Postgres destroy with `where` fails on JSONB data [#5092](https://github.com/sequelize/sequelize/issues/5092)
- [FIXED] hasMany.separate with foreign keys having `field`
- [ADDED] Geography support for postgres
# 3.17.3
- [FIXED] Regression with array values from security fix in 3.17.2
......
......@@ -840,6 +840,31 @@ GEOMETRY.prototype.$stringify = function (value) {
return 'GeomFromText(\'' + Wkt.stringify(value) + '\')';
};
/**
* A geography datatype represents two dimensional spacial objects in an elliptic coord system.
* @property GEOGRAPHY
*/
var GEOGRAPHY = ABSTRACT.inherits(function(type, srid) {
var options = _.isPlainObject(type) ? type : {
type: type,
srid: srid
};
if (!(this instanceof GEOGRAPHY)) return new GEOGRAPHY(options);
this.options = options;
this.type = options.type;
this.srid = options.srid;
});
GEOGRAPHY.prototype.key = GEOGRAPHY.key = 'GEOGRAPHY';
GEOGRAPHY.prototype.escape = false;
GEOGRAPHY.prototype.$stringify = function (value) {
return 'GeomFromText(\'' + Wkt.stringify(value) + '\')';
};
Object.keys(helpers).forEach(function (helper) {
helpers[helper].forEach(function (DataType) {
if (!DataType[helper]) {
......@@ -887,7 +912,8 @@ var dataTypes = {
REAL: REAL,
DOUBLE: DOUBLE,
'DOUBLE PRECISION': DOUBLE,
GEOMETRY: GEOMETRY
GEOMETRY: GEOMETRY,
GEOGRAPHY: GEOGRAPHY
};
_.each(dataTypes, function (dataType) {
......
......@@ -140,7 +140,7 @@ ConnectionManager.prototype.connect = function(config) {
// oids for hstore and geometry are dynamic - so select them at connection time
if (dataTypes.HSTORE.types.postgres.oids.length === 0) {
query += 'SELECT typname, oid, typarray FROM pg_type WHERE typtype = \'b\' AND typname IN (\'hstore\', \'geometry\')';
query += 'SELECT typname, oid, typarray FROM pg_type WHERE typtype = \'b\' AND typname IN (\'hstore\', \'geometry\', \'geography\')';
}
return new Promise(function (resolve, reject) {
......@@ -152,6 +152,8 @@ ConnectionManager.prototype.connect = function(config) {
type = dataTypes.postgres.GEOMETRY;
} else if (row.typname === 'hstore') {
type = dataTypes.postgres.HSTORE;
} else if (row.typname === 'geography'){
type = dataTypes.postgres.GEOGRAPHY;
}
type.types.postgres.oids.push(row.oid);
......
......@@ -269,6 +269,38 @@ module.exports = function (BaseTypes) {
return 'ST_GeomFromGeoJSON(\'' + JSON.stringify(value) + '\')';
};
var GEOGRAPHY = BaseTypes.GEOGRAPHY.inherits();
GEOGRAPHY.prototype.toSql = function() {
var result = 'GEOGRAPHY';
if (this.type){
result += '(' + this.type;
if (this.srid){
result += ',' + this.srid;
}
result += ')';
}
return result;
};
BaseTypes.GEOGRAPHY.types.postgres = {
oids: [],
array_oids: []
};
GEOGRAPHY.parse = GEOGRAPHY.prototype.parse = function(value) {
var b = new Buffer(value, 'hex');
return wkx.Geometry.parse(b).toGeoJSON();
};
GEOGRAPHY.prototype.$stringify = function (value) {
return 'ST_GeomFromGeoJSON(\'' + JSON.stringify(value) + '\')';
};
var hstore;
var HSTORE = BaseTypes.HSTORE.inherits(function () {
if (!(this instanceof HSTORE)) return new HSTORE();
......@@ -373,6 +405,7 @@ module.exports = function (BaseTypes) {
'DOUBLE PRECISION': DOUBLE,
FLOAT: FLOAT,
GEOMETRY: GEOMETRY,
GEOGRAPHY: GEOGRAPHY,
HSTORE: HSTORE,
RANGE: RANGE
};
......
......@@ -42,6 +42,7 @@ PostgresDialect.prototype.supports = _.merge(_.cloneDeep(Abstract.prototype.supp
NUMERIC: true,
ARRAY: true,
GEOMETRY: true,
GEOGRAPHY: true,
JSON: true,
JSONB: true,
deferrableConstraints: true,
......
'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.GEOGRAPHY) {
describe('GEOGRAPHY', function() {
beforeEach(function() {
return Support.prepareTransactionTest(this.sequelize).bind(this).then(function(sequelize) {
this.User = this.sequelize.define('User', {
username: DataTypes.STRING,
geography: DataTypes.GEOGRAPHY
});
return this.User.sync({ force: true });
});
});
it('works with aliases fields', function () {
var Pub = this.sequelize.define('Pub', {
location: {field: 'coordinates', type: DataTypes.GEOGRAPHY}
})
, point = {type: 'Point', coordinates: [39.807222, -76.984722]};
return Pub.sync({ force: true }).then(function () {
return Pub.create({location: point});
}).then(function (pub) {
expect(pub).not.to.be.null;
expect(pub.location).to.be.deep.eql(point);
});
});
it('should create a geography object', function() {
var User = this.User;
var point = { type: 'Point', coordinates: [39.807222,-76.984722]};
return User.create({username: 'username', geography: point }).then(function(newUser) {
expect(newUser).not.to.be.null;
expect(newUser.geography).to.be.deep.eql(point);
});
});
it('should update a geography 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', geography: point1};
return User.create(props).then(function(user) {
return User.update({geography: point2}, {where: {username: props.username}});
}).then(function(count) {
return User.findOne({where: {username: props.username}});
}).then(function(user) {
expect(user.geography).to.be.deep.eql(point2);
});
});
});
describe('GEOGRAPHY(POINT)', function() {
beforeEach(function() {
return Support.prepareTransactionTest(this.sequelize).bind(this).then(function(sequelize) {
this.User = this.sequelize.define('User', {
username: DataTypes.STRING,
geography: DataTypes.GEOGRAPHY('POINT')
});
return this.User.sync({ force: true });
});
});
it('should create a geography object', function() {
var User = this.User;
var point = { type: 'Point', coordinates: [39.807222,-76.984722]};
return User.create({username: 'username', geography: point }).then(function(newUser) {
expect(newUser).not.to.be.null;
expect(newUser.geography).to.be.deep.eql(point);
});
});
it('should update a geography 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', geography: point1};
return User.create(props).then(function(user) {
return User.update({geography: point2}, {where: {username: props.username}});
}).then(function(count) {
return User.findOne({where: {username: props.username}});
}).then(function(user) {
expect(user.geography).to.be.deep.eql(point2);
});
});
});
describe('GEOGRAPHY(LINESTRING)', function() {
beforeEach(function() {
return Support.prepareTransactionTest(this.sequelize).bind(this).then(function(sequelize) {
this.User = this.sequelize.define('User', {
username: DataTypes.STRING,
geography: DataTypes.GEOGRAPHY('LINESTRING')
});
return this.User.sync({ force: true });
});
});
it('should create a geography object', function() {
var User = this.User;
var point = { type: 'LineString', 'coordinates': [ [100.0, 0.0], [101.0, 1.0] ] };
return User.create({username: 'username', geography: point }).then(function(newUser) {
expect(newUser).not.to.be.null;
expect(newUser.geography).to.be.deep.eql(point);
});
});
it('should update a geography 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', geography: point1};
return User.create(props).then(function(user) {
return User.update({geography: point2}, {where: {username: props.username}});
}).then(function(count) {
return User.findOne({where: {username: props.username}});
}).then(function(user) {
expect(user.geography).to.be.deep.eql(point2);
});
});
});
describe('GEOGRAPHY(POLYGON)', function() {
beforeEach(function() {
return Support.prepareTransactionTest(this.sequelize).bind(this).then(function(sequelize) {
this.User = this.sequelize.define('User', {
username: DataTypes.STRING,
geography: DataTypes.GEOGRAPHY('POLYGON')
});
return this.User.sync({ force: true });
});
});
it('should create a geography 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', geography: point }).then(function(newUser) {
expect(newUser).not.to.be.null;
expect(newUser.geography).to.be.deep.eql(point);
});
});
it('should update a geography 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', geography: polygon1};
return User.create(props).then(function(user) {
return User.update({geography: polygon2}, {where: {username: props.username}});
}).then(function(count) {
return User.findOne({where: {username: props.username}});
}).then(function(user) {
expect(user.geography).to.be.deep.eql(polygon2);
});
});
});
}
});
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!