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,11 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
require 'active_support/core_ext/string'
|
3
|
+
require 'cartodb-rb-client/cartodb/model/constants'
|
4
|
+
require 'cartodb-rb-client/cartodb/model/geo'
|
5
|
+
require 'cartodb-rb-client/cartodb/model/getters'
|
6
|
+
require 'cartodb-rb-client/cartodb/model/setters'
|
7
|
+
require 'cartodb-rb-client/cartodb/model/schema'
|
8
|
+
require 'cartodb-rb-client/cartodb/model/persistence'
|
9
|
+
require 'cartodb-rb-client/cartodb/model/query'
|
10
|
+
require 'cartodb-rb-client/cartodb/model/base'
|
11
|
+
require 'cartodb-rb-client/cartodb/model/scope'
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module CartoDB
|
2
|
+
module Model
|
3
|
+
class Base
|
4
|
+
include CartoDB::Model::Getters
|
5
|
+
include CartoDB::Model::Setters
|
6
|
+
include CartoDB::Model::Geo
|
7
|
+
include CartoDB::Model::Schema
|
8
|
+
include CartoDB::Model::Persistence
|
9
|
+
include CartoDB::Model::Query
|
10
|
+
include RGeo::Feature
|
11
|
+
|
12
|
+
def initialize(attributes = {})
|
13
|
+
self.class.cartodb_table = nil
|
14
|
+
self.class.send(:set_geometry_type) unless self.class.send(:geometry_type).present?
|
15
|
+
self.attributes = attributes
|
16
|
+
self.class.send(:update_cartodb_schema) unless schema_synchronized?
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module CartoDB
|
2
|
+
module Model
|
3
|
+
module Constants
|
4
|
+
include RGeo::Feature
|
5
|
+
|
6
|
+
CARTODB_TYPES = {
|
7
|
+
String => 'text',
|
8
|
+
Integer => 'numeric',
|
9
|
+
Numeric => 'numeric',
|
10
|
+
Date => 'date',
|
11
|
+
DateTime => 'date',
|
12
|
+
TrueClass => 'boolean',
|
13
|
+
FalseClass => 'boolean',
|
14
|
+
Point => 'geometry'
|
15
|
+
}.freeze
|
16
|
+
|
17
|
+
INVALID_COLUMNS = [
|
18
|
+
:cartodb_id,
|
19
|
+
:id
|
20
|
+
].freeze
|
21
|
+
|
22
|
+
GEOMETRY_COLUMN = 'the_geom'.freeze
|
23
|
+
|
24
|
+
RGEO_FACTORY = ::RGeo::Geographic.simple_mercator_factory(:srid => 4326)
|
25
|
+
|
26
|
+
DEFAULT_ROWS_PER_PAGE = 10.freeze
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
module CartoDB
|
2
|
+
module Model
|
3
|
+
module Geo
|
4
|
+
include CartoDB::Model::Constants
|
5
|
+
|
6
|
+
def self.included(base)
|
7
|
+
base.extend(ClassMethods)
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
include CartoDB::Model::Constants
|
12
|
+
|
13
|
+
def setup_geometry_column(geometry_column)
|
14
|
+
return if geometry_column[:geometry_type].nil?
|
15
|
+
|
16
|
+
geometry_name = geometry_column[:name].to_sym
|
17
|
+
|
18
|
+
case geometry_column[:geometry_type].upcase
|
19
|
+
when 'POINT'
|
20
|
+
self.send :define_method, :the_geom do
|
21
|
+
self.attributes[geometry_name]
|
22
|
+
end
|
23
|
+
|
24
|
+
self.send :define_method, :the_geom= do |the_geom|
|
25
|
+
self.attributes[geometry_name] = the_geom
|
26
|
+
end
|
27
|
+
|
28
|
+
setup_point_geometry
|
29
|
+
when 'MULTIPOLYGON'
|
30
|
+
self.send :define_method, :the_geom do
|
31
|
+
self.attributes[geometry_name]
|
32
|
+
end
|
33
|
+
|
34
|
+
self.send :define_method, :the_geom= do |the_geom|
|
35
|
+
self.attributes[geometry_name] = convert_to_polygon(the_geom)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
private :setup_geometry_column
|
40
|
+
|
41
|
+
def setup_point_geometry
|
42
|
+
self.send :define_method, :latitude do
|
43
|
+
self.the_geom ? self.the_geom.y : nil
|
44
|
+
end
|
45
|
+
|
46
|
+
self.send :define_method, :longitude do
|
47
|
+
self.the_geom ? self.the_geom.x : nil
|
48
|
+
end
|
49
|
+
|
50
|
+
self.send :define_method, :latitude= do |latitude|
|
51
|
+
@latitude = latitude
|
52
|
+
if @latitude && @longitude
|
53
|
+
self.the_geom = RGEO_FACTORY.point(@longitude, @latitude)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
self.send :define_method, :longitude= do |longitude|
|
57
|
+
@longitude = longitude
|
58
|
+
if @latitude && @longitude
|
59
|
+
self.the_geom = RGEO_FACTORY.point(@longitude, @latitude)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
private :setup_point_geometry
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
def prepare_geo_attributes(attributes)
|
69
|
+
return if attributes.nil?
|
70
|
+
|
71
|
+
case self.class.geometry_type
|
72
|
+
when 'point'
|
73
|
+
longitude = attributes.delete(:longitude)
|
74
|
+
latitude = attributes.delete(:latitude)
|
75
|
+
|
76
|
+
attributes[:the_geom] = convert_to_point(latitude, longitude) if latitude && longitude
|
77
|
+
when /polygon/
|
78
|
+
attributes[:the_geom] = convert_to_polygon(attributes[:the_geom])
|
79
|
+
end
|
80
|
+
|
81
|
+
attributes
|
82
|
+
end
|
83
|
+
private :prepare_geo_attributes
|
84
|
+
|
85
|
+
def convert_to_point(latitude, longitude)
|
86
|
+
RGEO_FACTORY.point(longitude, latitude)
|
87
|
+
end
|
88
|
+
|
89
|
+
def convert_to_polygon(the_geom)
|
90
|
+
case the_geom
|
91
|
+
when String
|
92
|
+
RGeo::GeoJSON.decode(the_geom, :json_parser => :json, :geo_factory => RGeo::Geographic.spherical_factory(:srid => 4326))
|
93
|
+
when Hash
|
94
|
+
RGeo::GeoJSON.decode(::JSON.generate(the_geom), :json_parser => :json, :geo_factory => RGeo::Geographic.spherical_factory(:srid => 4326))
|
95
|
+
end
|
96
|
+
end
|
97
|
+
private :convert_to_polygon
|
98
|
+
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module CartoDB
|
2
|
+
module Model
|
3
|
+
module Getters
|
4
|
+
attr_reader :table, :attributes
|
5
|
+
|
6
|
+
def self.included(base)
|
7
|
+
base.extend(ClassMethods)
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
|
12
|
+
def connection
|
13
|
+
CartoDB::Connection
|
14
|
+
end
|
15
|
+
|
16
|
+
def table_name
|
17
|
+
@table_name ||= self.name.tableize
|
18
|
+
end
|
19
|
+
|
20
|
+
def cartodb_table
|
21
|
+
@cartodb_table = begin
|
22
|
+
connection.table table_name
|
23
|
+
rescue CartoDB::Client::Error
|
24
|
+
nil
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def columns
|
29
|
+
update_cartodb_schema unless schema_synchronized?
|
30
|
+
@columns
|
31
|
+
end
|
32
|
+
|
33
|
+
def data_columns
|
34
|
+
columns.reject{|c| %w(cartodb_id created_at updated_at).include?(c[:name])}.compact
|
35
|
+
end
|
36
|
+
|
37
|
+
def geometry_type
|
38
|
+
@geometry_type
|
39
|
+
end
|
40
|
+
|
41
|
+
def model_columns
|
42
|
+
@model_columns || []
|
43
|
+
end
|
44
|
+
private :model_columns
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
def connection
|
49
|
+
self.class.connection
|
50
|
+
end
|
51
|
+
|
52
|
+
def table_name
|
53
|
+
self.class.table_name
|
54
|
+
end
|
55
|
+
|
56
|
+
def cartodb_table
|
57
|
+
self.class.cartodb_table
|
58
|
+
end
|
59
|
+
|
60
|
+
def columns
|
61
|
+
self.class.columns
|
62
|
+
end
|
63
|
+
|
64
|
+
def attributes
|
65
|
+
@attributes ||= {}
|
66
|
+
end
|
67
|
+
|
68
|
+
def column_names
|
69
|
+
columns.map{|column| column[:name]}
|
70
|
+
end
|
71
|
+
private :column_names
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module CartoDB
|
2
|
+
module Model
|
3
|
+
module Persistence
|
4
|
+
include CartoDB::Model::Constants
|
5
|
+
|
6
|
+
def self.included(base)
|
7
|
+
base.extend(ClassMethods)
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
|
12
|
+
def create(attributes = {})
|
13
|
+
model = self.new attributes
|
14
|
+
model.save
|
15
|
+
model
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
def save
|
21
|
+
if new_record?
|
22
|
+
create_row
|
23
|
+
else
|
24
|
+
update_row
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def destroy
|
29
|
+
unless new_record?
|
30
|
+
delete_row
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def new_record?
|
35
|
+
cartodb_id.nil? || cartodb_id <= 0
|
36
|
+
end
|
37
|
+
|
38
|
+
def create_row
|
39
|
+
inserted_record = connection.insert_row table_name, attributes_for_insert
|
40
|
+
self.cartodb_id = inserted_record.id
|
41
|
+
end
|
42
|
+
private :create_row
|
43
|
+
|
44
|
+
def update_row
|
45
|
+
connection.update_row table_name, cartodb_id, attributes_for_update
|
46
|
+
end
|
47
|
+
private :update_row
|
48
|
+
|
49
|
+
def delete_row
|
50
|
+
connection.delete_row table_name, cartodb_id
|
51
|
+
end
|
52
|
+
private :delete_row
|
53
|
+
|
54
|
+
def attributes_for_insert
|
55
|
+
# only the columns defined in the model are allowed to be inserted
|
56
|
+
row = attributes.symbolize_keys.reject{|key,value| INVALID_COLUMNS.include?(key) || !column_names.include?(key.to_s) }
|
57
|
+
row
|
58
|
+
end
|
59
|
+
private :attributes_for_insert
|
60
|
+
|
61
|
+
def attributes_for_update
|
62
|
+
row = attributes.reject{|key,value| !column_names.include?(key.to_s) }
|
63
|
+
row
|
64
|
+
end
|
65
|
+
private :attributes_for_update
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module CartoDB
|
2
|
+
module Model
|
3
|
+
module Query
|
4
|
+
|
5
|
+
def self.included(base)
|
6
|
+
base.extend(ClassMethods)
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
|
11
|
+
def select(*fields)
|
12
|
+
scope = Scope.new(self)
|
13
|
+
scope.select(fields)
|
14
|
+
end
|
15
|
+
|
16
|
+
def all
|
17
|
+
scope = Scope.new(self)
|
18
|
+
scope.all
|
19
|
+
end
|
20
|
+
|
21
|
+
def where(attributes = nil, *rest)
|
22
|
+
scope = Scope.new(self)
|
23
|
+
scope.where(attributes, rest)
|
24
|
+
end
|
25
|
+
|
26
|
+
def find(id)
|
27
|
+
where(id)
|
28
|
+
end
|
29
|
+
|
30
|
+
def count
|
31
|
+
begin
|
32
|
+
results = connection.query "SELECT COUNT(CARTODB_ID) FROM #{table_name}"
|
33
|
+
results.rows.first[:count].try(:to_i)
|
34
|
+
rescue Exception => e
|
35
|
+
0
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def page(page_number)
|
40
|
+
scope = Scope.new(self)
|
41
|
+
scope.page(page_number)
|
42
|
+
end
|
43
|
+
|
44
|
+
def per_page(ammount)
|
45
|
+
scope = Scope.new(self)
|
46
|
+
scope.page(page_number)
|
47
|
+
end
|
48
|
+
|
49
|
+
def order(order_clause)
|
50
|
+
scope = Scope.new(self)
|
51
|
+
scope.order(order_clause)
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
def count
|
57
|
+
self.class.count
|
58
|
+
end
|
59
|
+
|
60
|
+
def count=(ammount)
|
61
|
+
self.class.count= ammount
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
module CartoDB
|
2
|
+
module Model
|
3
|
+
module Schema
|
4
|
+
|
5
|
+
def self.included(base)
|
6
|
+
base.extend(ClassMethods)
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
include CartoDB::Model::Constants
|
11
|
+
|
12
|
+
def schema_synchronized?
|
13
|
+
cartodb_table && @columns_synchronized
|
14
|
+
end
|
15
|
+
|
16
|
+
def cartodb_table_exists?
|
17
|
+
begin
|
18
|
+
cartodb_table && cartodb_table.name.eql?(table_name)
|
19
|
+
rescue CartoDB::Client::Error => e
|
20
|
+
e.status_code != 404
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def field(name, options = {:type => String})
|
25
|
+
return if name == 'the_geom'
|
26
|
+
|
27
|
+
@columns_synchronized = false
|
28
|
+
@model_columns ||= []
|
29
|
+
column = {
|
30
|
+
:name => name.to_s,
|
31
|
+
:type => CARTODB_TYPES[options[:type]] || options[:type]
|
32
|
+
}
|
33
|
+
return if model_columns.include?(column)
|
34
|
+
|
35
|
+
model_columns << column
|
36
|
+
update_cartodb_schema
|
37
|
+
end
|
38
|
+
private :field
|
39
|
+
|
40
|
+
def set_geometry_type(geometry_type = Point)
|
41
|
+
self.geometry_type = case geometry_type
|
42
|
+
when Class, Module
|
43
|
+
geometry_type.name.split('::').last.downcase
|
44
|
+
else
|
45
|
+
geometry_type.to_s.downcase
|
46
|
+
end
|
47
|
+
end
|
48
|
+
private :set_geometry_type
|
49
|
+
|
50
|
+
def update_cartodb_schema
|
51
|
+
table = nil
|
52
|
+
if cartodb_table_exists?
|
53
|
+
table = cartodb_table
|
54
|
+
else
|
55
|
+
table = connection.create_table table_name, geometry_type
|
56
|
+
end
|
57
|
+
|
58
|
+
read_metadata table
|
59
|
+
create_missing_columns
|
60
|
+
create_column_accessors
|
61
|
+
@columns_synchronized = true
|
62
|
+
end
|
63
|
+
private :update_cartodb_schema
|
64
|
+
|
65
|
+
def read_metadata(table)
|
66
|
+
extract_columns table
|
67
|
+
end
|
68
|
+
private :read_metadata
|
69
|
+
|
70
|
+
def extract_columns(table)
|
71
|
+
@columns = table.schema.map{|c| c[0].eql?('the_geom') ? {:name => c[0], :type => c[1], :geometry_type => c[3]} : {:name => c[0], :type => c[1]}}
|
72
|
+
end
|
73
|
+
private :extract_columns
|
74
|
+
|
75
|
+
def create_missing_columns
|
76
|
+
table_column_names = @columns.map{|c| c[:name]}
|
77
|
+
missing_columns = model_columns.reject{|c| table_column_names.include?(c[:name])}
|
78
|
+
return unless missing_columns && missing_columns.any?
|
79
|
+
|
80
|
+
missing_columns.each do |column|
|
81
|
+
connection.add_column table_name, column[:name], column[:type]
|
82
|
+
end
|
83
|
+
|
84
|
+
self.cartodb_table = nil
|
85
|
+
read_metadata self.cartodb_table
|
86
|
+
end
|
87
|
+
private :create_missing_columns
|
88
|
+
|
89
|
+
def create_column_accessors
|
90
|
+
@columns.each do |c|
|
91
|
+
column_name = c[:name]
|
92
|
+
column_type = c[:type]
|
93
|
+
|
94
|
+
if column_name.eql?(GEOMETRY_COLUMN) || column_type.eql?('geometry')
|
95
|
+
setup_geometry_column(c)
|
96
|
+
else
|
97
|
+
self.send :define_method, column_name do
|
98
|
+
self.attributes[column_name.to_sym]
|
99
|
+
end
|
100
|
+
|
101
|
+
self.send :define_method, "#{column_name}=" do |value|
|
102
|
+
self.attributes[column_name.to_sym] = value
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
private :create_column_accessors
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
def schema_synchronized?
|
112
|
+
self.class.schema_synchronized? && cartodb_table_exists?
|
113
|
+
end
|
114
|
+
|
115
|
+
def cartodb_table_exists?
|
116
|
+
self.class.cartodb_table_exists?
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|