cartodb-rb-client-rails-322 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|