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.
Files changed (121) hide show
  1. data/.gitignore +5 -0
  2. data/.rvmrc +1 -0
  3. data/.travis.yml +15 -0
  4. data/Gemfile +15 -0
  5. data/LICENSE +28 -0
  6. data/README.markdown +365 -0
  7. data/Rakefile +10 -0
  8. data/cartodb-rb-client.gemspec +34 -0
  9. data/lib/cartodb-rb-client.rb +18 -0
  10. data/lib/cartodb-rb-client/cartodb.rb +6 -0
  11. data/lib/cartodb-rb-client/cartodb/client.rb +4 -0
  12. data/lib/cartodb-rb-client/cartodb/client/authorization.rb +92 -0
  13. data/lib/cartodb-rb-client/cartodb/client/cache.rb +14 -0
  14. data/lib/cartodb-rb-client/cartodb/client/connection.rb +4 -0
  15. data/lib/cartodb-rb-client/cartodb/client/connection/base.rb +44 -0
  16. data/lib/cartodb-rb-client/cartodb/client/connection/cartodb.rb +280 -0
  17. data/lib/cartodb-rb-client/cartodb/client/connection/postgres.rb +255 -0
  18. data/lib/cartodb-rb-client/cartodb/client/error.rb +68 -0
  19. data/lib/cartodb-rb-client/cartodb/client/utils.rb +20 -0
  20. data/lib/cartodb-rb-client/cartodb/helpers.rb +1 -0
  21. data/lib/cartodb-rb-client/cartodb/helpers/sql_helper.rb +36 -0
  22. data/lib/cartodb-rb-client/cartodb/init.rb +30 -0
  23. data/lib/cartodb-rb-client/cartodb/libs.rb +2 -0
  24. data/lib/cartodb-rb-client/cartodb/libs/object.rb +15 -0
  25. data/lib/cartodb-rb-client/cartodb/libs/string.rb +116 -0
  26. data/lib/cartodb-rb-client/cartodb/model.rb +11 -0
  27. data/lib/cartodb-rb-client/cartodb/model/base.rb +20 -0
  28. data/lib/cartodb-rb-client/cartodb/model/constants.rb +30 -0
  29. data/lib/cartodb-rb-client/cartodb/model/defaults.rb +15 -0
  30. data/lib/cartodb-rb-client/cartodb/model/geo.rb +101 -0
  31. data/lib/cartodb-rb-client/cartodb/model/getters.rb +75 -0
  32. data/lib/cartodb-rb-client/cartodb/model/persistence.rb +69 -0
  33. data/lib/cartodb-rb-client/cartodb/model/query.rb +66 -0
  34. data/lib/cartodb-rb-client/cartodb/model/schema.rb +121 -0
  35. data/lib/cartodb-rb-client/cartodb/model/scope.rb +163 -0
  36. data/lib/cartodb-rb-client/cartodb/model/setters.rb +37 -0
  37. data/lib/cartodb-rb-client/cartodb/types.rb +2 -0
  38. data/lib/cartodb-rb-client/cartodb/types/metadata.rb +97 -0
  39. data/lib/cartodb-rb-client/cartodb/types/pg_result.rb +17 -0
  40. data/lib/cartodb-rb-client/install_utils.rb +19 -0
  41. data/lib/cartodb-rb-client/version.rb +7 -0
  42. data/run_tests.sh +6 -0
  43. data/spec/client_spec.rb +357 -0
  44. data/spec/fixtures/cassettes/CartoDB_client/should_add_and_remove_colums_in_a_previously_created_table.yml +635 -0
  45. data/spec/fixtures/cassettes/CartoDB_client/should_allow_reserved_words_in_columns_names.yml +284 -0
  46. data/spec/fixtures/cassettes/CartoDB_client/should_change_a_previously_created_column.yml +362 -0
  47. data/spec/fixtures/cassettes/CartoDB_client/should_create_a_table_and_get_its_table_definition.yml +1634 -0
  48. data/spec/fixtures/cassettes/CartoDB_client/should_create_a_table_forcing_the_schema_and_get_its_table_definition.yml +298 -0
  49. data/spec/fixtures/cassettes/CartoDB_client/should_create_a_table_from_a_csv_file.yml +2947 -0
  50. data/spec/fixtures/cassettes/CartoDB_client/should_create_a_table_with_MULTILINESTRING_type_geometry.yml +299 -0
  51. data/spec/fixtures/cassettes/CartoDB_client/should_create_a_table_with_MULTIPOLYGON_type_geometry.yml +298 -0
  52. data/spec/fixtures/cassettes/CartoDB_client/should_create_a_table_with_POINT_type_geometry.yml +580 -0
  53. data/spec/fixtures/cassettes/CartoDB_client/should_delete_a_table_s_row.yml +410 -0
  54. data/spec/fixtures/cassettes/CartoDB_client/should_drop_a_table.yml +380 -0
  55. data/spec/fixtures/cassettes/CartoDB_client/should_escape_properly_input_data_in_insert_queries.yml +295 -0
  56. data/spec/fixtures/cassettes/CartoDB_client/should_execute_a_select_query_and_return_results.yml +987 -0
  57. data/spec/fixtures/cassettes/CartoDB_client/should_get_a_table_by_its_name.yml +298 -0
  58. data/spec/fixtures/cassettes/CartoDB_client/should_import_any_kind_of_data_file.yml +6951 -0
  59. data/spec/fixtures/cassettes/CartoDB_client/should_insert_a_row_in_a_table.yml +357 -0
  60. data/spec/fixtures/cassettes/CartoDB_client/should_paginate_records.yml +3642 -0
  61. data/spec/fixtures/cassettes/CartoDB_client/should_rename_an_existing_table.yml +299 -0
  62. data/spec/fixtures/cassettes/CartoDB_client/should_return_errors_on_invalid_queries.yml +132 -0
  63. data/spec/fixtures/cassettes/CartoDB_client/should_return_nil_when_requesting_a_table_which_does_not_exists.yml +218 -0
  64. data/spec/fixtures/cassettes/CartoDB_client/should_return_user_s_table_list.yml +244 -0
  65. data/spec/fixtures/cassettes/CartoDB_client/should_update_a_row_in_a_table.yml +347 -0
  66. data/spec/fixtures/cassettes/CartoDB_model_data_methods/should_destroy_a_previously_created_record.yml +1920 -0
  67. data/spec/fixtures/cassettes/CartoDB_model_data_methods/should_initialize_attributes_of_the_model_without_persisting_them.yml +963 -0
  68. data/spec/fixtures/cassettes/CartoDB_model_data_methods/should_persist_into_cartodb_using_the_save_method.yml +1946 -0
  69. data/spec/fixtures/cassettes/CartoDB_model_data_methods/should_persist_into_cartodb_using_the_static_create_method.yml +1796 -0
  70. data/spec/fixtures/cassettes/CartoDB_model_data_methods/should_save_polygons_in_different_formats.yml +1801 -0
  71. data/spec/fixtures/cassettes/CartoDB_model_data_methods/should_update_an_existing_record.yml +2856 -0
  72. data/spec/fixtures/cassettes/CartoDB_model_metadata_methods/should_add_more_columns_if_the_table_previously_exists.yml +1509 -0
  73. data/spec/fixtures/cassettes/CartoDB_model_metadata_methods/should_contain_an_array_of_columns.yml +2007 -0
  74. data/spec/fixtures/cassettes/CartoDB_model_metadata_methods/should_create_a_table_with_custom_name_if_specified.yml +357 -0
  75. data/spec/fixtures/cassettes/CartoDB_model_metadata_methods/should_create_model_with_custom_data_types_columns.yml +565 -0
  76. data/spec/fixtures/cassettes/CartoDB_model_metadata_methods/should_create_model_with_polygon_type_geometry_columns.yml +493 -0
  77. data/spec/fixtures/cassettes/CartoDB_model_metadata_methods/should_create_the_table_in_cartodb_if_it_doesn_t_exists.yml +1048 -0
  78. data/spec/fixtures/cassettes/CartoDB_model_metadata_methods/should_have_a_valid_CartoDB_Client_instance_as_a_connection_object.yml +971 -0
  79. data/spec/fixtures/cassettes/CartoDB_model_metadata_methods/should_have_a_valid_table_name.yml +970 -0
  80. data/spec/fixtures/cassettes/CartoDB_model_metadata_methods/should_return_only_data_columns.yml +1096 -0
  81. data/spec/fixtures/cassettes/CartoDB_model_scopes/should_allow_to_select_the_specified_fiels.yml +25828 -0
  82. data/spec/fixtures/cassettes/CartoDB_model_scopes/should_count_all_records.yml +22401 -0
  83. data/spec/fixtures/cassettes/CartoDB_model_scopes/should_find_a_record_by_its_id.yml +21852 -0
  84. data/spec/fixtures/cassettes/CartoDB_model_scopes/should_order_results.yml +23701 -0
  85. data/spec/fixtures/cassettes/CartoDB_model_scopes/should_paginate_results.yml +35644 -0
  86. data/spec/fixtures/cassettes/CartoDB_model_scopes/should_return_all_records_paginated.yml +23699 -0
  87. data/spec/fixtures/cassettes/CartoDB_model_scopes/should_search_records_by_certain_filters.yml +7080 -0
  88. data/spec/fixtures/cassettes/cartodb_spec_models.yml +3409 -0
  89. data/spec/fixtures/cassettes/clean_tables.yml +224 -0
  90. data/spec/model/data_spec.rb +157 -0
  91. data/spec/model/metadata_spec.rb +124 -0
  92. data/spec/model/scopes_spec.rb +171 -0
  93. data/spec/model_specs_helper.rb +2 -0
  94. data/spec/spec_helper.rb +54 -0
  95. data/spec/support/cartodb_config.yml +11 -0
  96. data/spec/support/cartodb_config.yml.sample +16 -0
  97. data/spec/support/cartodb_factories.rb +33 -0
  98. data/spec/support/cartodb_helpers.rb +14 -0
  99. data/spec/support/cartodb_models.rb +29 -0
  100. data/spec/support/data/110m-glaciated-areas.zip +0 -0
  101. data/spec/support/data/CartoDB_csv_export.zip +0 -0
  102. data/spec/support/data/CartoDB_shp_export.zip +0 -0
  103. data/spec/support/data/rmnp.kml +51 -0
  104. data/spec/support/data/states.kml.zip +0 -0
  105. data/spec/support/database.yml +5 -0
  106. data/spec/support/shp/cereal.dbf +0 -0
  107. data/spec/support/shp/cereal.shp +0 -0
  108. data/spec/support/shp/cereal.shx +0 -0
  109. data/spec/support/shp/cereal.zip +0 -0
  110. data/spec/support/shp/parcelas.dbf +0 -0
  111. data/spec/support/shp/parcelas.shp +0 -0
  112. data/spec/support/shp/parcelas.shx +0 -0
  113. data/spec/support/shp/parcelas.zip +0 -0
  114. data/spec/support/shp/zonas.dbf +0 -0
  115. data/spec/support/shp/zonas.shp +0 -0
  116. data/spec/support/shp/zonas.shx +0 -0
  117. data/spec/support/shp/zonas.zip +0 -0
  118. data/spec/support/whs_features.csv +315 -0
  119. data/spec/support/whs_features.csv.zip +0 -0
  120. data/spec/support/whs_features_temp.csv +315 -0
  121. 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,15 @@
1
+ module CartoDB
2
+ module Model
3
+ module Defaults
4
+
5
+ def self.included(base)
6
+ base.extend(ClassMethods)
7
+ end
8
+
9
+ module ClassMethods
10
+
11
+ end
12
+
13
+ end
14
+ end
15
+ 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