Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

geometry types frontend [do not merge] #2189

Merged
merged 17 commits into from
Feb 16, 2015
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
17 changes: 11 additions & 6 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);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excuse my backbone.js ignorance: my understanding is that this is binding a piece of code to the reset event of the CartoDBTableMetadata model and it will be called upon fetching data from the server. Am I right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, every time we fetch data from sql api we will update schema and geometry types in CartoDBTableMetadata

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

Expand All @@ -121,10 +130,8 @@
if(resp.name) {
resp.id = resp.name;
}
if (this.isInSQLView()) {
delete resp.schema;
delete resp.geometry_types;
}
delete resp.geometry_types;
delete resp.schema;
return resp;
},

Expand Down Expand Up @@ -471,7 +478,6 @@
this.bindData();

if(view) {
this._data.unlinkFromSchema();
view.bind('reset', function() {
if(!view.modify_rows) {
this.set({
Expand Down Expand Up @@ -502,7 +508,6 @@
this.dataModel = this.sqlView;
view.table = this;
} else {
this._data.linkToSchema();
this.dataModel = this._data;
// get the original schema
self.set({
Expand Down
Loading