PageRenderTime 50ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/backbone.cartodb.js

https://github.com/jplusplus/camcuts
JavaScript | 210 lines | 155 code | 24 blank | 31 comment | 26 complexity | 8640d7336208912cb6ca052db3d8165a MD5 | raw file
Possible License(s): BSD-3-Clause
  1. /**
  2. *
  3. * backbone cartodb adapter
  4. *
  5. * this is a small library that allows to use Backbone with models
  6. * to work with data stored in CartoDB (a geospatial database on
  7. * the cloud, see more info at http://cartodb.com).
  8. *
  9. * it does NOT overrride Backbone.sync
  10. *
  11. */
  12. Backbone.CartoDB = function(options, query, cache) {
  13. options = _.defaults(options, {
  14. USE_PROXY: false,
  15. user: ''
  16. });
  17. function _SQL(sql) {
  18. this.sql = sql;
  19. }
  20. function SQL(sql) {
  21. return new _SQL(sql);
  22. }
  23. // SQL("{0} is {1}").format("CartoDB", "epic!");
  24. _SQL.prototype.format = function() {
  25. var str = this.sql,
  26. len = arguments.length+1;
  27. var safe, arg;
  28. for (i=0; i < len; arg = arguments[i++]) {
  29. safe = typeof arg === 'object' ? JSON.stringify(arg) : arg;
  30. str = str.replace(RegExp('\\{'+(i-1)+'\\}', 'g'), safe);
  31. }
  32. return str;
  33. };
  34. var resource_path= options.user + '.cartodb.com/api/v2/sql';
  35. var resource_url = 'https://' + resource_path;
  36. /**
  37. * fetch sql from the server
  38. *
  39. * this function should be changed if you're working on node
  40. *
  41. */
  42. query = query || function(sql, callback, proxy) {
  43. var url = resource_url;
  44. var crossDomain = true;
  45. if(proxy) {
  46. url = 'api/v0/proxy/' + resource_url;
  47. crossDomain = false;
  48. }
  49. if(sql.length > 1500) {
  50. $.ajax({
  51. url: url,
  52. crossDomain: crossDomain,
  53. type: 'POST',
  54. dataType: 'json',
  55. data: 'q=' + encodeURIComponent(sql),
  56. success: callback,
  57. error: function(){
  58. if(proxy) {
  59. callback();
  60. } else {
  61. //try fallback
  62. if(USE_PROXY) {
  63. query(sql, callback, true);
  64. }
  65. }
  66. }
  67. });
  68. } else {
  69. // TODO: add timeout
  70. $.getJSON(resource_url + '?q=' + encodeURIComponent(sql) + '&callback=?')
  71. .success(callback)
  72. .fail(function(){
  73. callback();
  74. }).complete(function() {
  75. });
  76. }
  77. };
  78. var dummy_cache = {
  79. setItem: function(key, value) { },
  80. getItem: function(key) { return null; },
  81. removeItem: function(key) { }
  82. };
  83. cache = cache && dummy_cache;
  84. var CartoDBModel = Backbone.Model.extend({
  85. _create_sql: function() {
  86. var where = SQL(" where {0} = '{1}'").format(
  87. this.columns[this.what],
  88. this.get(this.what).replace("'", "''")
  89. );
  90. var select = this._sql_select();
  91. var sql = 'select ' + select.join(',') + ' from ' + this.table + where;
  92. return sql;
  93. },
  94. _sql_select: function() {
  95. var select = [];
  96. for(var k in this.columns) {
  97. var w = this.columns[k];
  98. if(w.indexOf('ST_') !== -1 || w === "the_geom") {
  99. select.push(SQL('ST_AsGeoJSON({1}) as {0}').format(k,w));
  100. } else {
  101. select.push(SQL('{1} as {0}').format(k, w));
  102. }
  103. }
  104. return select;
  105. },
  106. _parse_columns: function(row) {
  107. var parsed = {};
  108. for(var k in row) {
  109. var v = row[k];
  110. var c = this.columns[k];
  111. if (c.indexOf('ST_') !== -1 || c === "the_geom") {
  112. parsed[k] = JSON.parse(v);
  113. } else {
  114. parsed[k] = row[k];
  115. }
  116. }
  117. return parsed;
  118. },
  119. fetch: function() {
  120. var self = this;
  121. query(this._create_sql(), function(data) {
  122. self.set(self._parse_columns(data.rows[0]));
  123. });
  124. }
  125. });
  126. /**
  127. * cartodb collection created from a sql composed using 'columns' and
  128. * 'table' attributes defined in a child class
  129. *
  130. * var C = CartoDBCollection.extend({
  131. * table: 'table',
  132. * columns: ['c1', 'c2']
  133. * });
  134. * var c = new C();
  135. * c.fetch();
  136. */
  137. var CartoDBCollection = Backbone.Collection.extend({
  138. _create_sql: function() {
  139. var tables = this.table;
  140. if(!_.isArray(this.table)) {
  141. tables = [this.table];
  142. }
  143. tables = tables.join(',');
  144. var select = CartoDBModel.prototype._sql_select.call(this);
  145. var sql = 'select ' + select.join(',') + ' from ' + this.table;
  146. if (this.where) {
  147. sql += " WHERE " + this.where;
  148. }
  149. return sql;
  150. },
  151. fetch: function() {
  152. var self = this;
  153. var sql = this.sql || this._create_sql();
  154. if(typeof(sql) === "function") {
  155. sql = sql.call(this);
  156. }
  157. var item = this.cache ? cache.getItem(sql): false;
  158. if(!item) {
  159. query(sql, function(data) {
  160. if(this.cache) {
  161. try {
  162. cache.setItem(sql, JSON.stringify(data.rows));
  163. } catch(e) {}
  164. }
  165. var rows;
  166. if(!self.sql) {
  167. rows = _.map(data.rows, function(r) {
  168. return CartoDBModel.prototype._parse_columns.call(self, r);
  169. });
  170. } else {
  171. rows = data.rows;
  172. }
  173. self.reset(rows);
  174. });
  175. } else {
  176. self.reset(JSON.parse(item));
  177. }
  178. }
  179. });
  180. return {
  181. query: query,
  182. CartoDBCollection: CartoDBCollection,
  183. CartoDBModel: CartoDBModel,
  184. SQL: SQL
  185. };
  186. };