cartodb-rb-client-rails-322 0.4.3
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/.rvmrc +1 -0
- data/.travis.yml +15 -0
- data/Gemfile +15 -0
- data/LICENSE +28 -0
- data/README.markdown +365 -0
- data/Rakefile +10 -0
- data/cartodb-rb-client.gemspec +34 -0
- data/lib/cartodb-rb-client.rb +18 -0
- data/lib/cartodb-rb-client/cartodb.rb +6 -0
- data/lib/cartodb-rb-client/cartodb/client.rb +4 -0
- data/lib/cartodb-rb-client/cartodb/client/authorization.rb +92 -0
- data/lib/cartodb-rb-client/cartodb/client/cache.rb +14 -0
- data/lib/cartodb-rb-client/cartodb/client/connection.rb +4 -0
- data/lib/cartodb-rb-client/cartodb/client/connection/base.rb +44 -0
- data/lib/cartodb-rb-client/cartodb/client/connection/cartodb.rb +280 -0
- data/lib/cartodb-rb-client/cartodb/client/connection/postgres.rb +255 -0
- data/lib/cartodb-rb-client/cartodb/client/error.rb +68 -0
- data/lib/cartodb-rb-client/cartodb/client/utils.rb +20 -0
- data/lib/cartodb-rb-client/cartodb/helpers.rb +1 -0
- data/lib/cartodb-rb-client/cartodb/helpers/sql_helper.rb +36 -0
- data/lib/cartodb-rb-client/cartodb/init.rb +30 -0
- data/lib/cartodb-rb-client/cartodb/libs.rb +2 -0
- data/lib/cartodb-rb-client/cartodb/libs/object.rb +15 -0
- data/lib/cartodb-rb-client/cartodb/libs/string.rb +116 -0
- data/lib/cartodb-rb-client/cartodb/model.rb +11 -0
- data/lib/cartodb-rb-client/cartodb/model/base.rb +20 -0
- data/lib/cartodb-rb-client/cartodb/model/constants.rb +30 -0
- data/lib/cartodb-rb-client/cartodb/model/defaults.rb +15 -0
- data/lib/cartodb-rb-client/cartodb/model/geo.rb +101 -0
- data/lib/cartodb-rb-client/cartodb/model/getters.rb +75 -0
- data/lib/cartodb-rb-client/cartodb/model/persistence.rb +69 -0
- data/lib/cartodb-rb-client/cartodb/model/query.rb +66 -0
- data/lib/cartodb-rb-client/cartodb/model/schema.rb +121 -0
- data/lib/cartodb-rb-client/cartodb/model/scope.rb +163 -0
- data/lib/cartodb-rb-client/cartodb/model/setters.rb +37 -0
- data/lib/cartodb-rb-client/cartodb/types.rb +2 -0
- data/lib/cartodb-rb-client/cartodb/types/metadata.rb +97 -0
- data/lib/cartodb-rb-client/cartodb/types/pg_result.rb +17 -0
- data/lib/cartodb-rb-client/install_utils.rb +19 -0
- data/lib/cartodb-rb-client/version.rb +7 -0
- data/run_tests.sh +6 -0
- data/spec/client_spec.rb +357 -0
- data/spec/fixtures/cassettes/CartoDB_client/should_add_and_remove_colums_in_a_previously_created_table.yml +635 -0
- data/spec/fixtures/cassettes/CartoDB_client/should_allow_reserved_words_in_columns_names.yml +284 -0
- data/spec/fixtures/cassettes/CartoDB_client/should_change_a_previously_created_column.yml +362 -0
- data/spec/fixtures/cassettes/CartoDB_client/should_create_a_table_and_get_its_table_definition.yml +1634 -0
- data/spec/fixtures/cassettes/CartoDB_client/should_create_a_table_forcing_the_schema_and_get_its_table_definition.yml +298 -0
- data/spec/fixtures/cassettes/CartoDB_client/should_create_a_table_from_a_csv_file.yml +2947 -0
- data/spec/fixtures/cassettes/CartoDB_client/should_create_a_table_with_MULTILINESTRING_type_geometry.yml +299 -0
- data/spec/fixtures/cassettes/CartoDB_client/should_create_a_table_with_MULTIPOLYGON_type_geometry.yml +298 -0
- data/spec/fixtures/cassettes/CartoDB_client/should_create_a_table_with_POINT_type_geometry.yml +580 -0
- data/spec/fixtures/cassettes/CartoDB_client/should_delete_a_table_s_row.yml +410 -0
- data/spec/fixtures/cassettes/CartoDB_client/should_drop_a_table.yml +380 -0
- data/spec/fixtures/cassettes/CartoDB_client/should_escape_properly_input_data_in_insert_queries.yml +295 -0
- data/spec/fixtures/cassettes/CartoDB_client/should_execute_a_select_query_and_return_results.yml +987 -0
- data/spec/fixtures/cassettes/CartoDB_client/should_get_a_table_by_its_name.yml +298 -0
- data/spec/fixtures/cassettes/CartoDB_client/should_import_any_kind_of_data_file.yml +6951 -0
- data/spec/fixtures/cassettes/CartoDB_client/should_insert_a_row_in_a_table.yml +357 -0
- data/spec/fixtures/cassettes/CartoDB_client/should_paginate_records.yml +3642 -0
- data/spec/fixtures/cassettes/CartoDB_client/should_rename_an_existing_table.yml +299 -0
- data/spec/fixtures/cassettes/CartoDB_client/should_return_errors_on_invalid_queries.yml +132 -0
- data/spec/fixtures/cassettes/CartoDB_client/should_return_nil_when_requesting_a_table_which_does_not_exists.yml +218 -0
- data/spec/fixtures/cassettes/CartoDB_client/should_return_user_s_table_list.yml +244 -0
- data/spec/fixtures/cassettes/CartoDB_client/should_update_a_row_in_a_table.yml +347 -0
- data/spec/fixtures/cassettes/CartoDB_model_data_methods/should_destroy_a_previously_created_record.yml +1920 -0
- data/spec/fixtures/cassettes/CartoDB_model_data_methods/should_initialize_attributes_of_the_model_without_persisting_them.yml +963 -0
- data/spec/fixtures/cassettes/CartoDB_model_data_methods/should_persist_into_cartodb_using_the_save_method.yml +1946 -0
- data/spec/fixtures/cassettes/CartoDB_model_data_methods/should_persist_into_cartodb_using_the_static_create_method.yml +1796 -0
- data/spec/fixtures/cassettes/CartoDB_model_data_methods/should_save_polygons_in_different_formats.yml +1801 -0
- data/spec/fixtures/cassettes/CartoDB_model_data_methods/should_update_an_existing_record.yml +2856 -0
- data/spec/fixtures/cassettes/CartoDB_model_metadata_methods/should_add_more_columns_if_the_table_previously_exists.yml +1509 -0
- data/spec/fixtures/cassettes/CartoDB_model_metadata_methods/should_contain_an_array_of_columns.yml +2007 -0
- data/spec/fixtures/cassettes/CartoDB_model_metadata_methods/should_create_a_table_with_custom_name_if_specified.yml +357 -0
- data/spec/fixtures/cassettes/CartoDB_model_metadata_methods/should_create_model_with_custom_data_types_columns.yml +565 -0
- data/spec/fixtures/cassettes/CartoDB_model_metadata_methods/should_create_model_with_polygon_type_geometry_columns.yml +493 -0
- data/spec/fixtures/cassettes/CartoDB_model_metadata_methods/should_create_the_table_in_cartodb_if_it_doesn_t_exists.yml +1048 -0
- data/spec/fixtures/cassettes/CartoDB_model_metadata_methods/should_have_a_valid_CartoDB_Client_instance_as_a_connection_object.yml +971 -0
- data/spec/fixtures/cassettes/CartoDB_model_metadata_methods/should_have_a_valid_table_name.yml +970 -0
- data/spec/fixtures/cassettes/CartoDB_model_metadata_methods/should_return_only_data_columns.yml +1096 -0
- data/spec/fixtures/cassettes/CartoDB_model_scopes/should_allow_to_select_the_specified_fiels.yml +25828 -0
- data/spec/fixtures/cassettes/CartoDB_model_scopes/should_count_all_records.yml +22401 -0
- data/spec/fixtures/cassettes/CartoDB_model_scopes/should_find_a_record_by_its_id.yml +21852 -0
- data/spec/fixtures/cassettes/CartoDB_model_scopes/should_order_results.yml +23701 -0
- data/spec/fixtures/cassettes/CartoDB_model_scopes/should_paginate_results.yml +35644 -0
- data/spec/fixtures/cassettes/CartoDB_model_scopes/should_return_all_records_paginated.yml +23699 -0
- data/spec/fixtures/cassettes/CartoDB_model_scopes/should_search_records_by_certain_filters.yml +7080 -0
- data/spec/fixtures/cassettes/cartodb_spec_models.yml +3409 -0
- data/spec/fixtures/cassettes/clean_tables.yml +224 -0
- data/spec/model/data_spec.rb +157 -0
- data/spec/model/metadata_spec.rb +124 -0
- data/spec/model/scopes_spec.rb +171 -0
- data/spec/model_specs_helper.rb +2 -0
- data/spec/spec_helper.rb +54 -0
- data/spec/support/cartodb_config.yml +11 -0
- data/spec/support/cartodb_config.yml.sample +16 -0
- data/spec/support/cartodb_factories.rb +33 -0
- data/spec/support/cartodb_helpers.rb +14 -0
- data/spec/support/cartodb_models.rb +29 -0
- data/spec/support/data/110m-glaciated-areas.zip +0 -0
- data/spec/support/data/CartoDB_csv_export.zip +0 -0
- data/spec/support/data/CartoDB_shp_export.zip +0 -0
- data/spec/support/data/rmnp.kml +51 -0
- data/spec/support/data/states.kml.zip +0 -0
- data/spec/support/database.yml +5 -0
- data/spec/support/shp/cereal.dbf +0 -0
- data/spec/support/shp/cereal.shp +0 -0
- data/spec/support/shp/cereal.shx +0 -0
- data/spec/support/shp/cereal.zip +0 -0
- data/spec/support/shp/parcelas.dbf +0 -0
- data/spec/support/shp/parcelas.shp +0 -0
- data/spec/support/shp/parcelas.shx +0 -0
- data/spec/support/shp/parcelas.zip +0 -0
- data/spec/support/shp/zonas.dbf +0 -0
- data/spec/support/shp/zonas.shp +0 -0
- data/spec/support/shp/zonas.shx +0 -0
- data/spec/support/shp/zonas.zip +0 -0
- data/spec/support/whs_features.csv +315 -0
- data/spec/support/whs_features.csv.zip +0 -0
- data/spec/support/whs_features_temp.csv +315 -0
- metadata +400 -0
@@ -0,0 +1,255 @@
|
|
1
|
+
module CartoDB
|
2
|
+
module Client
|
3
|
+
module Connection
|
4
|
+
class PostgreSQL
|
5
|
+
include CartoDB::Helpers::SqlHelper
|
6
|
+
|
7
|
+
DATA_TYPES_TRANSLATION_TABLE = {
|
8
|
+
'int4' => 'number',
|
9
|
+
'numeric' => 'number',
|
10
|
+
'text' => 'string',
|
11
|
+
'varchar' => 'string',
|
12
|
+
'date' => 'date',
|
13
|
+
'timestamp' => 'date',
|
14
|
+
'bool' => 'boolean',
|
15
|
+
'geometry' => 'geometry'
|
16
|
+
}
|
17
|
+
|
18
|
+
def initialize(connection_settings)
|
19
|
+
@pg = connect_to_postgres(connection_settings)
|
20
|
+
end
|
21
|
+
|
22
|
+
def connect_to_postgres(settings)
|
23
|
+
pg_connection = PGconn.open(
|
24
|
+
:host => settings['host'],
|
25
|
+
:port => settings['port'],
|
26
|
+
:user => settings['user'],
|
27
|
+
:password => settings['password'],
|
28
|
+
:dbname => settings['database']
|
29
|
+
)
|
30
|
+
pg_connection.set_notice_processor{|message| nil}
|
31
|
+
pg_connection
|
32
|
+
end
|
33
|
+
private :connect_to_postgres
|
34
|
+
|
35
|
+
def create_table(table_name = nil, schema_or_file = nil, the_geom_type = 'Point')
|
36
|
+
schema = schema_or_file if schema_or_file && schema_or_file.is_a?(Array)
|
37
|
+
file = schema_or_file if schema_or_file && schema_or_file.is_a?(File)
|
38
|
+
|
39
|
+
params = {:name => table_name}
|
40
|
+
params[:file] = file if file
|
41
|
+
|
42
|
+
table_name = table_name.sanitize
|
43
|
+
|
44
|
+
if schema.nil? || schema.empty?
|
45
|
+
schema = []
|
46
|
+
schema << {:name => 'name', :type => 'text'} if schema.select{|c| c[:name].eql?('name')}.empty?
|
47
|
+
schema << {:name => 'description', :type => 'text'} if schema.select{|c| c[:name].eql?('description')}.empty?
|
48
|
+
create_the_geom = "SELECT AddGeometryColumn('public', '#{table_name}', 'the_geom', 4326, 'POINT', 2)"
|
49
|
+
end
|
50
|
+
|
51
|
+
schema << {:name => 'cartodb_id', :type => 'serial', :extra => 'NOT NULL'} if schema.select{|c| c[:name].eql?('cartodb_id')}.empty?
|
52
|
+
schema << {:name => 'created_at', :type => 'timestamp', :extra => 'without time zone DEFAULT current_timestamp::timestamp without time zone'} if schema.select{|c| c[:name].eql?('created_at')}.empty?
|
53
|
+
schema << {:name => 'updated_at', :type => 'timestamp', :extra => 'without time zone DEFAULT current_timestamp::timestamp without time zone'} if schema.select{|c| c[:name].eql?('updated_at')}.empty?
|
54
|
+
if schema.any? && schema.select{|c| c[:name].downcase.match(/geo/)}.any?
|
55
|
+
the_geom_field = schema.select{|c| c[:name].downcase.match(/geo/)}.first
|
56
|
+
create_the_geom = "SELECT AddGeometryColumn('public', '#{table_name}', 'the_geom', 4326, '#{the_geom_field[:geometry_type].upcase}', 2)"
|
57
|
+
schema.reject!{|c| c[:name].downcase.match(/geo/)}
|
58
|
+
end
|
59
|
+
|
60
|
+
@pg.query(<<-SQL
|
61
|
+
CREATE TABLE #{table_name}
|
62
|
+
(
|
63
|
+
#{schema.map{|s| "#{s[:name]} #{s[:type]} #{s[:extra]}"}.join(', ')}
|
64
|
+
)
|
65
|
+
WITH (
|
66
|
+
OIDS=FALSE
|
67
|
+
);
|
68
|
+
ALTER TABLE #{table_name} OWNER TO #{@pg.user};
|
69
|
+
SQL
|
70
|
+
)
|
71
|
+
|
72
|
+
@pg.query(create_the_geom) if create_the_geom
|
73
|
+
|
74
|
+
table table_name
|
75
|
+
end
|
76
|
+
|
77
|
+
def add_column(table_name, column_name, column_type)
|
78
|
+
@pg.query(<<-SQL
|
79
|
+
ALTER TABLE #{table_name} ADD COLUMN #{column_name} #{column_type};
|
80
|
+
SQL
|
81
|
+
)
|
82
|
+
end
|
83
|
+
|
84
|
+
def drop_column(table_name, column_name)
|
85
|
+
@pg.query(<<-SQL
|
86
|
+
ALTER TABLE #{table_name} DROP COLUMN #{column_name};
|
87
|
+
SQL
|
88
|
+
)
|
89
|
+
end
|
90
|
+
|
91
|
+
def change_column(table_name, old_column_name, new_column_name, column_type)
|
92
|
+
add_column table_name, new_column_name, column_type
|
93
|
+
@pg.query(<<-SQL
|
94
|
+
UPDATE #{table_name} SET #{new_column_name}=cast(#{old_column_name} as #{column_type})
|
95
|
+
SQL
|
96
|
+
)
|
97
|
+
drop_column table_name, old_column_name
|
98
|
+
end
|
99
|
+
|
100
|
+
def tables
|
101
|
+
pg_result = @pg.query(<<-SQL
|
102
|
+
SELECT columns.table_name, columns.column_name, columns.udt_name as data_type
|
103
|
+
FROM information_schema.tables tables
|
104
|
+
INNER JOIN information_schema.columns columns ON columns.table_name = tables.table_name
|
105
|
+
WHERE tables.table_schema = 'public' AND tables.table_name not IN ('spatial_ref_sys', 'geometry_columns', 'geography_columns')
|
106
|
+
SQL
|
107
|
+
)
|
108
|
+
|
109
|
+
result = CartoDB::Types::Metadata.new
|
110
|
+
tables = {}
|
111
|
+
pg_result.each do |column|
|
112
|
+
tables[column['table_name']] = CartoDB::Types::Metadata.from_hash({:name => column['table_name'], :schema => []}) unless tables[column['table_name']]
|
113
|
+
tables[column['table_name']].schema << %W(#{column['column_name']} #{CartoDB::Client::Connection::PostgreSQL::DATA_TYPES_TRANSLATION_TABLE[column['data_type']]})
|
114
|
+
end
|
115
|
+
|
116
|
+
result.total_entries = tables.to_a.length
|
117
|
+
result.tables = tables.to_a.map(&:last)
|
118
|
+
result
|
119
|
+
end
|
120
|
+
|
121
|
+
def table(table_name)
|
122
|
+
pg_result = @pg.query(<<-SQL
|
123
|
+
SELECT columns.table_name, columns.column_name, columns.udt_name as data_type, geo_cols.type as geometry_type
|
124
|
+
FROM information_schema.tables tables
|
125
|
+
INNER JOIN information_schema.columns columns ON columns.table_name = tables.table_name
|
126
|
+
LEFT OUTER JOIN public.geometry_columns geo_cols ON geo_cols.f_table_schema = columns.table_schema AND geo_cols.f_table_name = columns.table_name AND geo_cols.f_geometry_column = columns.column_name
|
127
|
+
WHERE tables.table_schema = 'public' AND tables.table_name not IN ('spatial_ref_sys', 'geometry_columns', 'geography_columns') AND tables.table_name ilike '#{table_name}'
|
128
|
+
SQL
|
129
|
+
)
|
130
|
+
|
131
|
+
if pg_result.to_a.empty?
|
132
|
+
non_existing_table = @pg.query(<<-SQL
|
133
|
+
SELECT tables.table_name
|
134
|
+
FROM information_schema.tables tables
|
135
|
+
WHERE tables.table_schema = 'public' AND tables.table_name not IN ('spatial_ref_sys', 'geometry_columns', 'geography_columns') AND tables.table_name ilike '#{table_name}'
|
136
|
+
SQL
|
137
|
+
)
|
138
|
+
raise CartoDB::Client::Error.new if non_existing_table.to_a.empty?
|
139
|
+
end
|
140
|
+
|
141
|
+
table_result = nil
|
142
|
+
pg_result.each do |column|
|
143
|
+
table_result = CartoDB::Types::Metadata.from_hash({:name => column['table_name'], :schema => []}) unless table_result
|
144
|
+
table_result.schema << %W(#{column['column_name']} #{CartoDB::Client::Connection::PostgreSQL::DATA_TYPES_TRANSLATION_TABLE[column['data_type']]})
|
145
|
+
table_result.schema.last << CartoDB::Client::Connection::PostgreSQL::DATA_TYPES_TRANSLATION_TABLE[column['data_type']] if column['geometry_type']
|
146
|
+
table_result.schema.last << column['geometry_type'].downcase if column['geometry_type']
|
147
|
+
end
|
148
|
+
table_result
|
149
|
+
end
|
150
|
+
|
151
|
+
def drop_table(table_name)
|
152
|
+
@pg.query(<<-SQL
|
153
|
+
DROP TABLE #{table_name}
|
154
|
+
SQL
|
155
|
+
)
|
156
|
+
end
|
157
|
+
|
158
|
+
def row(table_name, row_id)
|
159
|
+
results = query(<<-SQL
|
160
|
+
SELECT #{table_name}.cartodb_id as id, #{table_name}.*
|
161
|
+
FROM #{table_name}
|
162
|
+
WHERE cartodb_id = #{row_id};
|
163
|
+
SQL
|
164
|
+
)
|
165
|
+
|
166
|
+
results.rows.first
|
167
|
+
end
|
168
|
+
|
169
|
+
def insert_row(table_name, row)
|
170
|
+
row = prepare_data(row)
|
171
|
+
|
172
|
+
results = query(<<-SQL
|
173
|
+
INSERT INTO #{table_name}
|
174
|
+
(#{row.keys.join(',')})
|
175
|
+
VALUES (#{row.values.join(',')});
|
176
|
+
|
177
|
+
SELECT #{table_name}.cartodb_id as id, #{table_name}.*
|
178
|
+
FROM #{table_name}
|
179
|
+
WHERE cartodb_id = currval('public.#{table_name}_cartodb_id_seq');
|
180
|
+
SQL
|
181
|
+
)
|
182
|
+
|
183
|
+
results.rows.first
|
184
|
+
end
|
185
|
+
|
186
|
+
def update_row(table_name, row_id, row)
|
187
|
+
row = prepare_data(row)
|
188
|
+
|
189
|
+
results = query(<<-SQL
|
190
|
+
UPDATE #{table_name}
|
191
|
+
SET (#{row.keys.join(',')})
|
192
|
+
= (#{row.values.join(',')})
|
193
|
+
WHERE cartodb_id = #{row_id};
|
194
|
+
SELECT #{table_name}.cartodb_id as id, #{table_name}.*
|
195
|
+
FROM #{table_name}
|
196
|
+
WHERE cartodb_id = currval('public.#{table_name}_cartodb_id_seq');
|
197
|
+
SQL
|
198
|
+
)
|
199
|
+
|
200
|
+
results.rows.first
|
201
|
+
end
|
202
|
+
|
203
|
+
def delete_row(table_name, row_id)
|
204
|
+
@pg.query(<<-SQL
|
205
|
+
DELETE FROM #{table_name}
|
206
|
+
WHERE cartodb_id = #{row_id}
|
207
|
+
SQL
|
208
|
+
)
|
209
|
+
end
|
210
|
+
|
211
|
+
def records(table_name, options = {})
|
212
|
+
sql = <<-SQL
|
213
|
+
SELECT #{table_name}.cartodb_id AS id, #{table_name}.*
|
214
|
+
FROM #{table_name}
|
215
|
+
SQL
|
216
|
+
|
217
|
+
results = query(sql, options)
|
218
|
+
|
219
|
+
results[:name] = table_name
|
220
|
+
results
|
221
|
+
end
|
222
|
+
|
223
|
+
def query(sql, options = {})
|
224
|
+
sql = sql.strip if sql
|
225
|
+
|
226
|
+
if sql.include?('*')
|
227
|
+
table_name = sql.match(/select(.*)\s((\w+\.)?\*)(.*)from\s+(\w*)[^;]*;?/im)[5]
|
228
|
+
schema = table(table_name).schema if table_name
|
229
|
+
|
230
|
+
sql.gsub!(/^select(.*)\s((\w+\.)?\*)(.*)from/im) do |matches|
|
231
|
+
%Q{SELECT #{$1.strip} #{schema.map{|c| "#{$3}#{c[0]}"}.join(', ')} #{$4.strip} FROM}
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
crono = Time.now
|
236
|
+
begin
|
237
|
+
result = @pg.query(<<-SQL
|
238
|
+
#{sql}
|
239
|
+
SQL
|
240
|
+
)
|
241
|
+
rescue PGError => e
|
242
|
+
raise CartoDB::Client::Error.new(nil, nil, nil, e.message)
|
243
|
+
end
|
244
|
+
|
245
|
+
CartoDB::Types::Metadata.from_hash({
|
246
|
+
:time => Time.now - crono,
|
247
|
+
:total_rows => result.cmd_tuples,
|
248
|
+
:rows => result.map{|row| CartoDB::Types::Metadata.from_hash(row)}
|
249
|
+
})
|
250
|
+
end
|
251
|
+
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module CartoDB
|
2
|
+
module Client
|
3
|
+
class Error < Exception
|
4
|
+
attr_accessor :status_code
|
5
|
+
|
6
|
+
HTTP_MESSAGES = {
|
7
|
+
401 => 'Unauthorized request',
|
8
|
+
404 => 'Not found',
|
9
|
+
500 => 'Server error'
|
10
|
+
}
|
11
|
+
|
12
|
+
def initialize(uri = nil, method = nil, http_response = nil, error_message = nil)
|
13
|
+
@uri = uri
|
14
|
+
@method = method
|
15
|
+
@error_messages = ['undefined CartoDB error']
|
16
|
+
@status_code = 400
|
17
|
+
@error_messages = [uri] if method == nil && http_response == nil && error_message == nil
|
18
|
+
@error_messages = [error_message] if error_message
|
19
|
+
|
20
|
+
if http_response
|
21
|
+
@status_code = http_response.code
|
22
|
+
@error_messages = custom_error(http_response) || standard_error
|
23
|
+
@body = http_response.body
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_s
|
29
|
+
message = <<-EOF
|
30
|
+
#{http_error_message_header}
|
31
|
+
#{format_error_messages}
|
32
|
+
#{@body}
|
33
|
+
EOF
|
34
|
+
message.strip
|
35
|
+
end
|
36
|
+
|
37
|
+
def http_error_message_header
|
38
|
+
if @method && @uri
|
39
|
+
%{There were errors running the #{@method.to_s.upcase} request "#{@uri}":}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
private :http_error_message_header
|
43
|
+
|
44
|
+
def custom_error(http_response)
|
45
|
+
json = Utils.parse_json(http_response)
|
46
|
+
json[:error] if json
|
47
|
+
end
|
48
|
+
|
49
|
+
def standard_error
|
50
|
+
"#{status_code} - #{HTTP_MESSAGES[status_code.to_i]}"
|
51
|
+
end
|
52
|
+
private :standard_error
|
53
|
+
|
54
|
+
def format_error_messages
|
55
|
+
return '' unless @error_messages
|
56
|
+
if @error_messages.is_a?(String)
|
57
|
+
@error_messages
|
58
|
+
elsif @error_messages.is_a?(Array) && @error_messages.count == 1
|
59
|
+
@error_messages.first
|
60
|
+
else
|
61
|
+
@error_messages.map{|e| "- #{e}"}.join("\n")
|
62
|
+
end
|
63
|
+
end
|
64
|
+
private :format_error_messages
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module CartoDB
|
2
|
+
module Client
|
3
|
+
module Utils
|
4
|
+
|
5
|
+
def self.parse_json(response)
|
6
|
+
json = nil
|
7
|
+
|
8
|
+
unless response.nil? || response.body.nil? || response.body.strip == ''
|
9
|
+
begin
|
10
|
+
json = ::JSON.parse(response.body, :object_class => CartoDB::Types::Metadata, :symbolize_names => true)
|
11
|
+
rescue JSON::ParserError => e
|
12
|
+
json = CartoDB::Types::Metadata.new
|
13
|
+
end
|
14
|
+
end
|
15
|
+
json
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'cartodb-rb-client/cartodb/helpers/sql_helper'
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module CartoDB
|
2
|
+
module Helpers
|
3
|
+
module SqlHelper
|
4
|
+
require 'time'
|
5
|
+
|
6
|
+
def prepare_data(hash)
|
7
|
+
hash.each do |key, value|
|
8
|
+
hash[key] = format_value(key, value)
|
9
|
+
end
|
10
|
+
hash
|
11
|
+
end
|
12
|
+
|
13
|
+
def format_value(key, value)
|
14
|
+
case value
|
15
|
+
when ::String
|
16
|
+
#value = value.gsub(/\\/, '\&\&').gsub(/'/, "''")
|
17
|
+
if key.match(/geo/)
|
18
|
+
"#{value}"
|
19
|
+
else
|
20
|
+
"'#{value.gsub(/\\/, '\&\&').gsub(/'/, "''")}'"
|
21
|
+
end
|
22
|
+
when ::Date, ::DateTime, ::Time
|
23
|
+
"'#{value.to_time.utc}'"
|
24
|
+
when RGeo::Feature::Geometry
|
25
|
+
"'#{RGeo::WKRep::WKBGenerator.new(:type_format => :ewkb, :emit_ewkb_srid => true, :hex_format => true).generate(value)}'"
|
26
|
+
when NilClass
|
27
|
+
'NULL'
|
28
|
+
else
|
29
|
+
value
|
30
|
+
end
|
31
|
+
end
|
32
|
+
private :format_value
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module CartoDB
|
2
|
+
class Init
|
3
|
+
|
4
|
+
class << self
|
5
|
+
|
6
|
+
def start(cartodb_settings = nil)
|
7
|
+
if cartodb_settings.blank?
|
8
|
+
config_path = Rails.root.join('config/cartodb_config.yml')
|
9
|
+
cartodb_settings = YAML.load_file(config_path)[Rails.env.to_s] if File.exists?(config_path)
|
10
|
+
end
|
11
|
+
|
12
|
+
return if cartodb_settings.blank?
|
13
|
+
|
14
|
+
if CartoDB.const_defined?('Settings')
|
15
|
+
CartoDB::Settings.merge!(cartodb_settings)
|
16
|
+
else
|
17
|
+
CartoDB.const_set('Settings', cartodb_settings)
|
18
|
+
end
|
19
|
+
|
20
|
+
CartoDB.const_set('Connection', CartoDB::Client::Connection::Base.new) unless CartoDB.const_defined?('Connection')
|
21
|
+
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
|
@@ -0,0 +1,116 @@
|
|
1
|
+
# coding: UTF-8
|
2
|
+
|
3
|
+
class String
|
4
|
+
def self.random(length=10)
|
5
|
+
('a'..'z').sort_by {rand}[0,length].join
|
6
|
+
end
|
7
|
+
|
8
|
+
def normalize
|
9
|
+
str = self.downcase
|
10
|
+
return '' if str.blank?
|
11
|
+
n = str.force_encoding("UTF-8")
|
12
|
+
n.gsub!(/[àáâãäåāă]/, 'a')
|
13
|
+
n.gsub!(/æ/, 'ae')
|
14
|
+
n.gsub!(/[ďđ]/, 'd')
|
15
|
+
n.gsub!(/[çćčĉċ]/, 'c')
|
16
|
+
n.gsub!(/[èéêëēęěĕė]/, 'e')
|
17
|
+
n.gsub!(/ƒ/, 'f')
|
18
|
+
n.gsub!(/[ĝğġģ]/, 'g')
|
19
|
+
n.gsub!(/[ĥħ]/, 'h')
|
20
|
+
n.gsub!(/[ììíîïīĩĭ]/, 'i')
|
21
|
+
n.gsub!(/[įıijĵ]/, 'j')
|
22
|
+
n.gsub!(/[ķĸ]/, 'k')
|
23
|
+
n.gsub!(/[łľĺļŀ]/, 'l')
|
24
|
+
n.gsub!(/[ñńňņʼnŋ]/, 'n')
|
25
|
+
n.gsub!(/[òóôõöøōőŏŏ]/, 'o')
|
26
|
+
n.gsub!(/œ/, 'oe')
|
27
|
+
n.gsub!(/ą/, 'q')
|
28
|
+
n.gsub!(/[ŕřŗ]/, 'r')
|
29
|
+
n.gsub!(/[śšşŝș]/, 's')
|
30
|
+
n.gsub!(/[ťţŧț]/, 't')
|
31
|
+
n.gsub!(/[ùúûüūůűŭũų]/, 'u')
|
32
|
+
n.gsub!(/ŵ/, 'w')
|
33
|
+
n.gsub!(/[ýÿŷ]/, 'y')
|
34
|
+
n.gsub!(/[žżź]/, 'z')
|
35
|
+
n.gsub!(/[ÀÁÂÃÄÅĀĂ]/i, 'A')
|
36
|
+
n.gsub!(/Æ/i, 'AE')
|
37
|
+
n.gsub!(/[ĎĐ]/i, 'D')
|
38
|
+
n.gsub!(/[ÇĆČĈĊ]/i, 'C')
|
39
|
+
n.gsub!(/[ÈÉÊËĒĘĚĔĖ]/i, 'E')
|
40
|
+
n.gsub!(/Ƒ/i, 'F')
|
41
|
+
n.gsub!(/[ĜĞĠĢ]/i, 'G')
|
42
|
+
n.gsub!(/[ĤĦ]/i, 'H')
|
43
|
+
n.gsub!(/[ÌÌÍÎÏĪĨĬ]/i, 'I')
|
44
|
+
n.gsub!(/[IJĴ]/i, 'J')
|
45
|
+
n.gsub!(/[Ķĸ]/i, 'J')
|
46
|
+
n.gsub!(/[ŁĽĹĻĿ]/i, 'L')
|
47
|
+
n.gsub!(/[ÑŃŇŅʼnŊ]/i, 'M')
|
48
|
+
n.gsub!(/[ÒÓÔÕÖØŌŐŎŎ]/i, 'N')
|
49
|
+
n.gsub!(/Œ/i, 'OE')
|
50
|
+
n.gsub!(/Ą/i, 'Q')
|
51
|
+
n.gsub!(/[ŔŘŖ]/i, 'R')
|
52
|
+
n.gsub!(/[ŚŠŞŜȘ]/i, 'S')
|
53
|
+
n.gsub!(/[ŤŢŦȚ]/i, 'T')
|
54
|
+
n.gsub!(/[ÙÚÛÜŪŮŰŬŨŲ]/i, 'U')
|
55
|
+
n.gsub!(/Ŵ/i, 'W')
|
56
|
+
n.gsub!(/[ÝŸŶ]/i, 'Y')
|
57
|
+
n.gsub!(/[ŽŻŹ]/i, 'Z')
|
58
|
+
n
|
59
|
+
end
|
60
|
+
|
61
|
+
def sanitize
|
62
|
+
return if self.blank?
|
63
|
+
self.gsub(/<[^>]+>/m,'').normalize.downcase.gsub(/&.+?;/,'-').
|
64
|
+
gsub(/[^a-z0-9 _-]/,'-').strip.gsub(/\s+/,'-').gsub(/-+/,'-').
|
65
|
+
gsub(/-/,' ').strip.gsub(/ /,'-').gsub(/-/,'_')
|
66
|
+
end
|
67
|
+
|
68
|
+
def strip_tags
|
69
|
+
self.gsub(/<[^>]+>/m,'').strip
|
70
|
+
end
|
71
|
+
|
72
|
+
def convert_to_db_type
|
73
|
+
if CartoDB::TYPES.keys.include?(self.downcase)
|
74
|
+
if self.downcase == "number"
|
75
|
+
"double precision"
|
76
|
+
else
|
77
|
+
CartoDB::TYPES[self.downcase].first
|
78
|
+
end
|
79
|
+
else
|
80
|
+
self.downcase
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# {"integer"=>:number, "real"=>:number, "varchar"=>:string, "text"=>:string, "timestamp"=>:date, "boolean"=>:boolean}
|
85
|
+
def convert_to_cartodb_type
|
86
|
+
inverse_types = CartoDB::TYPES.invert.inject({}){ |h, e| e.first.each{ |k| h[k] = e.last }; h}
|
87
|
+
if inverse_types.keys.include?(self.downcase)
|
88
|
+
inverse_types[self.downcase]
|
89
|
+
else
|
90
|
+
inverse_types.keys.select{ |t| !t.is_a?(String) }.each do |re|
|
91
|
+
if self.downcase.match(re)
|
92
|
+
return inverse_types[re]
|
93
|
+
end
|
94
|
+
end
|
95
|
+
self.downcase
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def sanitize_sql
|
100
|
+
self.gsub(/\\/, '\&\&').gsub(/'/, "''")
|
101
|
+
end
|
102
|
+
|
103
|
+
def host
|
104
|
+
self.split('/')[2]
|
105
|
+
end
|
106
|
+
|
107
|
+
def sanitize_column_name
|
108
|
+
temporal_name = self.sanitize
|
109
|
+
if temporal_name !~ /^[a-zA-Z_]/ || CartoDB::POSTGRESQL_RESERVED_WORDS.include?(self.upcase)
|
110
|
+
return '_' + temporal_name
|
111
|
+
else
|
112
|
+
temporal_name
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|