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

Commit 14e3deaf by Mike Ringrose

Adding GEOMETRY for Postgres.

1 parent c38aa5f7
......@@ -26,6 +26,8 @@ addons:
before_script:
- "mysql -e 'create database sequelize_test;'"
- "psql -c 'create database sequelize_test;' -U postgres"
- "psql -c 'create database sequelize_test;' -U postgres"
- "psql -c 'create extension postgis;' -U postgres"
script:
- "make test"
......
......@@ -2,6 +2,7 @@
var util = require('util')
, _ = require('lodash')
, Wkt = require('wellknown')
, warnings = {};
/**
......@@ -594,6 +595,26 @@ var helpers = {
SCALE: [DECIMAL]
};
var GEOMETRY = function(type, srid) {
var options = _.isPlainObject(type) ? type : {
type: type,
srid: srid
};
if (!(this instanceof GEOMETRY)) return new GEOMETRY(options);
this.options = options;
this.type = options.type;
this.srid = options.srid;
};
util.inherits(GEOMETRY, ABSTRACT);
GEOMETRY.prototype.key = GEOMETRY.key = 'GEOMETRY';
GEOMETRY.prototype.parse = function(value) {
return Wkt.parse(value);
};
Object.keys(helpers).forEach(function (helper) {
helpers[helper].forEach(function (DataType) {
if (!DataType[helper]) {
......@@ -640,5 +661,6 @@ module.exports = {
RANGE: RANGE,
REAL: REAL,
DOUBLE: DOUBLE,
'DOUBLE PRECISION': DOUBLE
'DOUBLE PRECISION': DOUBLE,
GEOMETRY: GEOMETRY
};
......@@ -996,7 +996,10 @@ var QueryGenerator = {
attr[0] = self.handleSequelizeMethod(attr[0]);
addTable = false;
} else {
if (attr[0].indexOf('(') === -1 && attr[0].indexOf(')') === -1) {
if (mainModel && mainModel._isGeometryAttribute(attr[1])) {
attr[0] = this.geometrySelect(attr[0]);
}
else if (attr[0].indexOf('(') === -1 && attr[0].indexOf(')') === -1) {
attr[0] = self.quoteIdentifier(attr[0]);
}
}
......@@ -2143,6 +2146,10 @@ var QueryGenerator = {
booleanValue: function(value) {
return value;
},
geometrySelect: function(column) {
return this.quoteIdentifiers(column);
}
};
......
......@@ -2,7 +2,9 @@
var BaseTypes = require('../../data-types')
, util = require('util')
, _ = require('lodash');
, _ = require('lodash')
, wkx = require('wkx')
, wkt = require('wellknown');
BaseTypes.ABSTRACT.prototype.dialectTypes = 'http://www.postgresql.org/docs/9.4/static/datatype.html';
......@@ -153,6 +155,33 @@ BaseTypes.BLOB.prototype.toSql = function() {
return 'BYTEA';
};
var GEOMETRY = function() {
if (!(this instanceof GEOMETRY)) return new GEOMETRY();
BaseTypes.GEOMETRY.apply(this, arguments);
};
util.inherits(GEOMETRY, BaseTypes.GEOMETRY);
GEOMETRY.prototype.toSql = function() {
var result = this.key;
if (this.type){
result += '(' + this.type;
if (this.srid){
result += ',' + this.srid;
}
result += ')';
}
return result;
};
GEOMETRY.prototype.parse = function(value) {
var b = new Buffer(value, 'hex');
return wkt.parse(wkx.Geometry.parse(b).toWkt());
};
module.exports = {
STRING: STRING,
CHAR: CHAR,
......@@ -162,7 +191,8 @@ module.exports = {
BIGINT: BIGINT,
REAL: REAL,
'DOUBLE PRECISION': DOUBLE,
FLOAT: FLOAT
FLOAT: FLOAT,
GEOMETRY: GEOMETRY
};
_.forIn(module.exports, function (DataType, key) {
......@@ -172,4 +202,4 @@ _.forIn(module.exports, function (DataType, key) {
return new DataType(oldType.options);
};
}
});
\ No newline at end of file
});
......@@ -95,7 +95,7 @@ var QueryGenerator = {
},
showTablesQuery: function() {
return "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public';";
return "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_type LIKE '%TABLE' AND table_name != 'spatial_ref_sys';";
},
describeTableQuery: function(tableName, schema) {
......@@ -897,6 +897,13 @@ var QueryGenerator = {
return 'ARRAY[' + value.map(function (v) {
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 SqlString.escape(value, false, this.options.timezone, this.dialect, field);
......
......@@ -28,6 +28,10 @@ parseDialectSpecificFields = {
this.lib.types.arrayParser.create(value, function (v) {
return range.parse(v, options.dataType.type);
}).parse() : range.parse(value, options.dataType);
},
geometry: function (value, options) {
if (value === null) return null;
return options.dataType.parse(value);
}
};
......
......@@ -360,6 +360,13 @@ Instance.prototype.set = function(key, value, options) {
value = (value === 1) ? true : (value === 0) ? false : value;
}
}
if (this.Model._hasGeometryAttributes && this.Model._isGeometryAttribute(key) && value !== null && value !== undefined && !value._isSequelizeMethod) {
if(_.isString(value)){
value = this.dialect.DatatTypes.GEOMETRY.parse(value);
}
}
if (!options.raw && ((primitives.indexOf(typeof value) === -1 && value !== null) || value !== originalValue)) {
this._previousDataValues[key] = originalValue;
this.changed(key, true);
......@@ -978,7 +985,7 @@ Instance.prototype.decrement = function(fields, options) {
*/
Instance.prototype.equals = function(other) {
var result = true;
if (!other || !other.dataValues) {
return false;
}
......
......@@ -736,6 +736,7 @@ Model.prototype.refreshAttributes = function() {
this._hstoreAttributes = [];
this._rangeAttributes = [];
this._jsonAttributes = [];
this._geometryAttributes = [];
this._virtualAttributes = [];
this._defaultValues = {};
this.Instance.prototype.validators = {};
......@@ -767,6 +768,8 @@ Model.prototype.refreshAttributes = function() {
self._jsonAttributes.push(name);
} else if (definition.type instanceof DataTypes.VIRTUAL) {
self._virtualAttributes.push(name);
} else if (definition.type instanceof DataTypes.GEOMETRY) {
self._geometryAttributes.push(name);
}
if (definition.hasOwnProperty('defaultValue')) {
......@@ -825,6 +828,11 @@ Model.prototype.refreshAttributes = function() {
return self._virtualAttributes.indexOf(key) !== -1;
});
this._hasGeometryAttributes = !!this._geometryAttributes.length;
this._isGeometryAttribute = Utils._.memoize(function(key) {
return self._geometryAttributes.indexOf(key) !== -1;
});
this._hasDefaultValues = !Utils._.isEmpty(this._defaultValues);
this.attributes = this.rawAttributes;
......
......@@ -43,7 +43,9 @@
"node-uuid": "~1.4.1",
"shimmer": "1.0.0",
"toposort-class": "~0.3.0",
"validator": "^3.34.0"
"validator": "^3.34.0",
"wellknown": "^0.3.1",
"wkx": "0.0.7"
},
"devDependencies": {
"chai": "^2.1.2",
......
......@@ -31,7 +31,8 @@ if (dialect.match(/^postgres/)) {
course_period: DataTypes.RANGE(DataTypes.DATE),
acceptable_marks: { type: DataTypes.RANGE(DataTypes.DECIMAL), defaultValue: [0.65, 1] },
available_amount: DataTypes.RANGE,
holidays: DataTypes.ARRAY(DataTypes.RANGE(DataTypes.DATE))
holidays: DataTypes.ARRAY(DataTypes.RANGE(DataTypes.DATE)),
location: DataTypes.GEOMETRY()
});
return this.User.sync({ force: true });
});
......@@ -875,6 +876,35 @@ if (dialect.match(/^postgres/)) {
});
});
it('should save geometry correctly', function() {
var point = { type: 'Point', coordinates: [39.807222,-76.984722] };
return this.User.create({ username: 'user', email: ['foo@bar.com'], location: point}).then(function(newUser) {
expect(newUser.location).to.deep.eql(point);
});
});
it('should update geometry correctly', function() {
var User = this.User;
var point1 = { type: 'Point', coordinates: [39.807222,-76.984722] }
, point2 = { type: 'Point', coordinates: [39.828333,-77.232222] };
return User.create({ username: 'user', email: ['foo@bar.com'], location: point1}).then(function(oldUser) {
return User.update({ location: point2 }, { where: { username: oldUser.username }, returning: true }).spread(function(count, updatedUsers) {
expect(updatedUsers[0].location).to.deep.eql(point2);
});
});
});
it('should read geometry correctly', function() {
var User = this.User;
var point = { type: 'Point', coordinates: [39.807222,-76.984722] };
return User.create({ username: 'user', email: ['foo@bar.com'], location: point}).then(function(user) {
return User.find({ where: { username: user.username }});
}).then(function(user) {
expect(user.location).to.deep.eql(point);
});
});
describe('[POSTGRES] Unquoted identifiers', function() {
it('can insert and select', function() {
var self = this;
......
......@@ -666,5 +666,32 @@ suite(Support.getTestDialectTeaser('SQL'), function() {
}
});
}
suite('GEOMETRY', function () {
testsql('GEOMETRY', DataTypes.GEOMETRY, {
default: 'GEOMETRY',
postgres: 'GEOMETRY'
});
testsql('GEOMETRY(\'POINT\')', DataTypes.GEOMETRY('POINT'), {
default: 'GEOMETRY(POINT)',
postgres: 'GEOMETRY(POINT)'
});
testsql('GEOMETRY(\'LINESTRING\')', DataTypes.GEOMETRY('LINESTRING'), {
default: 'GEOMETRY(LINESTRING)',
postgres: 'GEOMETRY(LINESTRING)',
});
testsql('GEOMETRY(\'POLYGON\')', DataTypes.GEOMETRY('POLYGON'), {
default: 'GEOMETRY(POLYGON)',
postgres: 'GEOMETRY(POLYGON)'
});
testsql('GEOMETRY(\'POINT\',4326)', DataTypes.GEOMETRY('POINT', 4326), {
default: 'GEOMETRY(POINT,4326)',
postgres: 'GEOMETRY(POINT,4326)'
});
});
});
});
\ No newline at end of file
});
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!