Skip to content

Commit

Permalink
Merge pull request #2189 from CartoDB/2182-geometry_types_frontend
Browse files Browse the repository at this point in the history
geometry types fetched form SQL api frontend side
  • Loading branch information
javisantana committed Feb 16, 2015
2 parents 50677b6 + 6887903 commit c464237
Show file tree
Hide file tree
Showing 10 changed files with 206 additions and 301 deletions.
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* [content guessing] Prioritize ip over country guessing [#2089](https://github.com/CartoDB/cartodb/issues/2089)
* Added new import error code (6667) for detecting and reporting statement timeouts.
* Fixes creation of a visualization from a table [#2145](https://github.com/CartoDB/cartodb/issues/2145)
* Changes the way geometry types are loaded client side (performance), see PR [#2189](https://github.com/CartoDB/cartodb/pull/218)
* Added PlatformLimits service. For now, only includes an importer maximum file size limit.

3.8.0 (2015-01-30)
Expand Down
2 changes: 1 addition & 1 deletion lib/assets/javascripts/cartodb/models/carto.js
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,7 @@ function normalizeQuartiles(quartiles) {
var normalized = [];
for(var i = 0; i < quartiles.length; ++i) {
var q = quartiles[i];
if(q > Math.abs(maxNumber)) {
if(q > Math.abs(maxNumber) && String(q).indexOf('.') === -1) {
q = q + ".01";
}
normalized.push(q);
Expand Down
4 changes: 3 additions & 1 deletion lib/assets/javascripts/cartodb/models/cartodb_layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ cdb.admin.CartoDBLayer = cdb.geo.CartoDBLayer.extend({
},

isTableLoaded: function() {
return this.table.get('id') && this.table.get('schema');
return this.table.get('id') && this.table.get('privacy');
},

getLayerDef: function() {
Expand Down Expand Up @@ -339,6 +339,8 @@ cdb.admin.CartoDBLayer = cdb.geo.CartoDBLayer.extend({
var sql = this.get('query');
if (sql) {
this.applySQLView(sql, { add_to_history: false });
} else {
this.table.data().fetch();
}
},

Expand Down
138 changes: 0 additions & 138 deletions lib/assets/javascripts/cartodb/models/sqlview.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,35 +25,6 @@ cdb.admin.SQLViewData = cdb.admin.CartoDBTableData.extend({
}
},

/**
* we need to override sync to avoid the sql request to be sent by GET.
* For security reasons, we need them to be send as a PUT request.
* @method sync
* @param method {'save' || 'read' || 'delete' || 'create'}
* @param model {Object}
* @param options {Object}
*/
sync: function(method, model, options) {
if(!options) { options = {}; }
options.data = this._createUrlOptions(function(d) {
return d !== 'sql';
});

if (cdb.admin.CartoDBTableMetadata.alterTableData(this.options.get('sql'))) {
options.data += "&q=" + encodeURIComponent(this.options.get('sql'));
options.type = 'POST';
} else {
// when a geometry can be lazy fetched, don't fetch it
var fetchGeometry = 'cartodb_id' in this.query_schema;
options.data += "&q=" + encodeURIComponent(this.wrappedSQL(this.query_schema, [], !fetchGeometry));

if (options.data.length > 2048) {
options.type = 'POST';
}
}

return Backbone.sync.call(this, method, this, options);
},

_parseSQL: function(sql) {
sql = sql.replace(/([^\\]){x}/g, '$10').replace(/\\{x}/g, '{x}')
Expand Down Expand Up @@ -101,115 +72,6 @@ cdb.admin.SQLViewData = cdb.admin.CartoDBTableData.extend({
return this.options.get('sql');
},

/**
* with the data from the rows fetch create an schema
* if the schema from original table is passed the method
* set the column types according to it
* return an empty list if no data was fetch
*/
schemaFromData: function(originalTableSchema) {
// build schema in format [ [field, type] , ...]
return cdb.admin.CartoDBTableMetadata.sortSchema(_(this.query_schema).map(function(v, k) {
return [k, v];
}));
},

geometryTypeFromGeoJSON: function(geojson) {
try {
var geo = JSON.parse(geojson);
return geo.type
} catch(e) {
}
},

geometryTypeFromWKT: function(wkt) {
if(!wkt) return null;
var types = cdb.admin.WKT.types;
wkt = wkt.toUpperCase();
for(var i = 0; i < types.length; ++i) {
var t = types[i];
if (wkt.indexOf(t) !== -1) {
return t;
}
}
},

geometryTypeFromWKB: function(wkb) {
if(!wkb) return null;

var typeMap = {
'0001': 'Point',
'0002': 'LineString',
'0003': 'Polygon',
'0004': 'MultiPoint',
'0005': 'MultiLineString',
'0006': 'MultiPolygon'
};

var bigendian = wkb[0] === '0' && wkb[1] === '0';
var type = wkb.substring(2, 6);
if(!bigendian) {
// swap '0100' => '0001'
type = type[2] + type[3] + type[0] + type[1];
}
return typeMap[type];

},


//
// guesses from the first row the geometry types involved
// returns an empty array where there is no rows
// return postgist types, like st_GEOTYPE
//
getGeometryTypes: function() {
var row = null;
var i = this.size();
while (i-- && !(row && row.get('the_geom'))) {
row = this.at(i);
}
if(!row) return [];
var geom = row.get('the_geom') || row.get('the_geom_webmercator');
var geoType = this.geometryTypeFromWKB(geom) || this.geometryTypeFromWKT(geom);
if(geoType) {
return ['ST_' + geoType[0].toUpperCase() + geoType.substring(1).toLowerCase()];
}
return [];
},

// fixes schema. Special geometry columns (the_geom) are fetch as geojson
// so the returned type is string. Fix it
_schemaFromQueryFields: function(fields) {
if ('the_geom' in fields) {
fields['the_geom'].type = 'geometry';
}
if ('the_geom_webmercator' in fields) {
fields['the_geom_webmercator'].type = 'geometry';
}
return cdb.admin.CartoDBTableData.prototype._schemaFromQueryFields.call(this, fields);
},

fetch: function(opts) {
var MAX_GET_LENGTH = 1024;
var self = this;
this.trigger('loading', opts);
// if the query changes the database just send it
if (cdb.admin.CartoDBTableMetadata.alterTableData(this.options.get('sql'))) {
self.elder('fetch', opts);
return;
}

// use get to fetch the schema, probably cached
var sql = this.options.get('sql') || '';
this._sqlQuery(_.template('select * from (<%= sql %>) __wrapped limit 0')(this.options.attributes), function(data) {
// get schema
self.query_schema = self._schemaFromQueryFields(data.fields);
self.elder('fetch', opts);
}, function (err) {
self.trigger('error', self, err);
}, sql.length > MAX_GET_LENGTH ? "POST" : "GET");
},

url: function() {
return this.sqlApiUrl();
},
Expand Down
35 changes: 18 additions & 17 deletions lib/assets/javascripts/cartodb/models/table.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,15 @@
this._data.bind('error', function(e, resp) {
this.notice('error loading rows, check your SQL query', 'error', 5000);
}, this);

this._data.bind('reset', function() {
var view = this._data;
this.set({
schema: view.schemaFromData(this.get('schema')),
geometry_types: view.getGeometryTypes()
});
}, this);

this.retrigger('change', this._data, 'data:changed');
this.retrigger('saved', this._data, 'data:saved');

Expand All @@ -121,10 +130,10 @@
if(resp.name) {
resp.id = resp.name;
}
if (this.isInSQLView()) {
delete resp.schema;
delete resp.geometry_types;
}
// do not drop geometry_types. It's calculated from sql query
// but in some places the cached value from backend is enough
//delete resp.geometry_types;
delete resp.schema;
return resp;
},

Expand Down Expand Up @@ -300,7 +309,7 @@
success: function() {
self.notice(self._TEXTS.columnAdded, 'info');
self.trigger('columnAdd', columnName);
self.fetch();
self.data().fetch();
callback && callback();
},
error: function(e, resp) {
Expand All @@ -319,7 +328,7 @@
success: function() {
self.trigger('columnDelete', columnName);
self.notice(self._TEXTS.columnDeleted, 'info');
self.fetch();
self.data().fetch();
},
error: function(e, resp) {
self.error('error deleting column', resp);
Expand All @@ -343,7 +352,7 @@
success: function() {
self.notice('Column has been renamed', 'info');
self.trigger('columnRename', newName, oldName);
self.fetch();
self.data().fetch();
},
error: function(e, resp) {
cdb.log.error("can't rename column");
Expand Down Expand Up @@ -403,7 +412,7 @@
success: function() {
self.notice('Column type has been changed', 'info');
self.trigger('typeChanged', newType); // to make it testable
self.fetch();
self.data().fetch();
},
error: function(e, resp) {
self.trigger('typeChangeFailed', newType, e); // to make it testable
Expand Down Expand Up @@ -471,7 +480,6 @@
this.bindData();

if(view) {
this._data.unlinkFromSchema();
view.bind('reset', function() {
if(!view.modify_rows) {
this.set({
Expand Down Expand Up @@ -502,19 +510,12 @@
this.dataModel = this.sqlView;
view.table = this;
} else {
this._data.linkToSchema();
this.dataModel = this._data;
// get the original schema
self.set({
'schema': self.get('original_schema')
});///*, { silent: true });
this.fetch({
success: function() {
if(options.force_data_fetch) {
self.data().fetch();
}
}
});
self.data().fetch();
}
this.trigger('change:dataSource', this.dataModel, this);
},
Expand Down
Loading

0 comments on commit c464237

Please sign in to comment.