datamapper 0.2.3 → 0.2.4

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/example.rb +5 -5
  2. data/lib/data_mapper/adapters/abstract_adapter.rb +2 -2
  3. data/lib/data_mapper/adapters/data_object_adapter.rb +141 -147
  4. data/lib/data_mapper/adapters/mysql_adapter.rb +14 -1
  5. data/lib/data_mapper/adapters/postgresql_adapter.rb +123 -18
  6. data/lib/data_mapper/adapters/sql/coersion.rb +21 -9
  7. data/lib/data_mapper/adapters/sql/commands/load_command.rb +36 -19
  8. data/lib/data_mapper/adapters/sql/mappings/column.rb +111 -17
  9. data/lib/data_mapper/adapters/sql/mappings/schema.rb +27 -0
  10. data/lib/data_mapper/adapters/sql/mappings/table.rb +256 -29
  11. data/lib/data_mapper/adapters/sqlite3_adapter.rb +93 -8
  12. data/lib/data_mapper/associations/belongs_to_association.rb +53 -54
  13. data/lib/data_mapper/associations/has_and_belongs_to_many_association.rb +157 -25
  14. data/lib/data_mapper/associations/has_many_association.rb +45 -15
  15. data/lib/data_mapper/associations/has_n_association.rb +79 -20
  16. data/lib/data_mapper/associations/has_one_association.rb +2 -2
  17. data/lib/data_mapper/associations/reference.rb +1 -1
  18. data/lib/data_mapper/auto_migrations.rb +40 -0
  19. data/lib/data_mapper/base.rb +201 -98
  20. data/lib/data_mapper/context.rb +16 -10
  21. data/lib/data_mapper/database.rb +22 -11
  22. data/lib/data_mapper/dependency_queue.rb +28 -0
  23. data/lib/data_mapper/embedded_value.rb +61 -17
  24. data/lib/data_mapper/property.rb +4 -0
  25. data/lib/data_mapper/support/active_record_impersonation.rb +13 -5
  26. data/lib/data_mapper/support/errors.rb +5 -0
  27. data/lib/data_mapper/support/serialization.rb +8 -4
  28. data/lib/data_mapper/validatable_extensions/errors.rb +12 -0
  29. data/lib/data_mapper/validatable_extensions/macros.rb +7 -0
  30. data/lib/data_mapper/validatable_extensions/validatable_instance_methods.rb +62 -0
  31. data/lib/data_mapper/validatable_extensions/validation_base.rb +18 -0
  32. data/lib/data_mapper/validatable_extensions/validations/formats/email.rb +43 -0
  33. data/lib/data_mapper/validatable_extensions/validations/validates_acceptance_of.rb +7 -0
  34. data/lib/data_mapper/validatable_extensions/validations/validates_confirmation_of.rb +7 -0
  35. data/lib/data_mapper/validatable_extensions/validations/validates_each.rb +7 -0
  36. data/lib/data_mapper/validatable_extensions/validations/validates_format_of.rb +28 -0
  37. data/lib/data_mapper/validatable_extensions/validations/validates_length_of.rb +15 -0
  38. data/lib/data_mapper/validatable_extensions/validations/validates_numericality_of.rb +7 -0
  39. data/lib/data_mapper/validatable_extensions/validations/validates_presence_of.rb +7 -0
  40. data/lib/data_mapper/validatable_extensions/validations/validates_true_for.rb +7 -0
  41. data/lib/data_mapper/validatable_extensions/validations/validates_uniqueness_of.rb +33 -0
  42. data/lib/data_mapper/validations.rb +20 -0
  43. data/lib/data_mapper.rb +39 -34
  44. data/performance.rb +24 -18
  45. data/plugins/dataobjects/do_rb +0 -0
  46. data/rakefile.rb +12 -2
  47. data/spec/active_record_impersonation_spec.rb +133 -0
  48. data/spec/acts_as_tree_spec.rb +25 -9
  49. data/spec/associations_spec.rb +124 -4
  50. data/spec/attributes_spec.rb +13 -0
  51. data/spec/auto_migrations_spec.rb +44 -0
  52. data/spec/base_spec.rb +189 -1
  53. data/spec/column_spec.rb +85 -7
  54. data/spec/conditions_spec.rb +2 -2
  55. data/spec/dependency_spec.rb +25 -0
  56. data/spec/embedded_value_spec.rb +123 -3
  57. data/spec/fixtures/animals.yaml +1 -0
  58. data/spec/fixtures/careers.yaml +5 -0
  59. data/spec/fixtures/comments.yaml +1 -0
  60. data/spec/fixtures/people.yaml +14 -9
  61. data/spec/fixtures/projects.yaml +4 -0
  62. data/spec/fixtures/sections.yaml +5 -0
  63. data/spec/fixtures/serializers.yaml +6 -0
  64. data/spec/fixtures/users.yaml +1 -0
  65. data/spec/load_command_spec.rb +5 -4
  66. data/spec/mock_adapter.rb +2 -2
  67. data/spec/models/animal.rb +2 -1
  68. data/spec/models/animals_exhibit.rb +2 -2
  69. data/spec/models/career.rb +6 -0
  70. data/spec/models/comment.rb +4 -0
  71. data/spec/models/exhibit.rb +4 -0
  72. data/spec/models/person.rb +3 -13
  73. data/spec/models/project.rb +1 -1
  74. data/spec/models/serializer.rb +3 -0
  75. data/spec/models/user.rb +4 -0
  76. data/spec/models/zoo.rb +8 -1
  77. data/spec/natural_key_spec.rb +36 -0
  78. data/spec/paranoia_spec.rb +36 -0
  79. data/spec/property_spec.rb +70 -0
  80. data/spec/schema_spec.rb +10 -2
  81. data/spec/serialization_spec.rb +6 -3
  82. data/spec/serialize_spec.rb +19 -0
  83. data/spec/single_table_inheritance_spec.rb +7 -1
  84. data/spec/spec_helper.rb +26 -8
  85. data/spec/table_spec.rb +33 -0
  86. data/spec/validates_confirmation_of_spec.rb +20 -4
  87. data/spec/validates_format_of_spec.rb +22 -8
  88. data/spec/validates_length_of_spec.rb +26 -13
  89. data/spec/validates_uniqueness_of_spec.rb +18 -5
  90. data/spec/validations_spec.rb +55 -10
  91. data/tasks/fixtures.rb +13 -7
  92. metadata +189 -153
  93. data/lib/data_mapper/validations/confirmation_validator.rb +0 -53
  94. data/lib/data_mapper/validations/contextual_validations.rb +0 -50
  95. data/lib/data_mapper/validations/format_validator.rb +0 -85
  96. data/lib/data_mapper/validations/formats/email.rb +0 -78
  97. data/lib/data_mapper/validations/generic_validator.rb +0 -22
  98. data/lib/data_mapper/validations/length_validator.rb +0 -76
  99. data/lib/data_mapper/validations/required_field_validator.rb +0 -41
  100. data/lib/data_mapper/validations/unique_validator.rb +0 -56
  101. data/lib/data_mapper/validations/validation_errors.rb +0 -37
  102. data/lib/data_mapper/validations/validation_helper.rb +0 -77
  103. data/plugins/dataobjects/REVISION +0 -1
  104. data/plugins/dataobjects/Rakefile +0 -9
  105. data/plugins/dataobjects/do.rb +0 -348
  106. data/plugins/dataobjects/do_mysql.rb +0 -212
  107. data/plugins/dataobjects/do_postgres.rb +0 -196
  108. data/plugins/dataobjects/do_sqlite3.rb +0 -157
  109. data/plugins/dataobjects/spec/do_spec.rb +0 -150
  110. data/plugins/dataobjects/spec/spec_helper.rb +0 -81
  111. data/plugins/dataobjects/swig_mysql/extconf.rb +0 -45
  112. data/plugins/dataobjects/swig_mysql/mysql_c.c +0 -16602
  113. data/plugins/dataobjects/swig_mysql/mysql_c.i +0 -67
  114. data/plugins/dataobjects/swig_mysql/mysql_supp.i +0 -46
  115. data/plugins/dataobjects/swig_postgres/extconf.rb +0 -29
  116. data/plugins/dataobjects/swig_postgres/postgres_c.c +0 -8185
  117. data/plugins/dataobjects/swig_postgres/postgres_c.i +0 -73
  118. data/plugins/dataobjects/swig_sqlite/extconf.rb +0 -9
  119. data/plugins/dataobjects/swig_sqlite/sqlite3_c.c +0 -4725
  120. data/plugins/dataobjects/swig_sqlite/sqlite_c.i +0 -168
  121. data/tasks/drivers.rb +0 -20
data/example.rb CHANGED
@@ -37,7 +37,7 @@ DataMapper::Database.setup({
37
37
  :username => 'root'
38
38
  })
39
39
 
40
- class Animal < DataMapper::Base
40
+ class Animal < DataMapper::Base #:nodoc:
41
41
  set_table_name 'animals' # Just as an example. Same inflector as Rails,
42
42
  # so this really isn't necessary.
43
43
 
@@ -47,17 +47,17 @@ class Animal < DataMapper::Base
47
47
  has_and_belongs_to_many :exhibits
48
48
  end
49
49
 
50
- class Exhibit < DataMapper::Base
50
+ class Exhibit < DataMapper::Base #:nodoc:
51
51
  property :name, :string
52
52
  belongs_to :zoo
53
53
  end
54
54
 
55
- class Zoo < DataMapper::Base
55
+ class Zoo < DataMapper::Base #:nodoc:
56
56
  property :name, :string
57
57
  has_many :exhibits
58
58
  end
59
59
 
60
- class Person < DataMapper::Base
60
+ class Person < DataMapper::Base #:nodoc:
61
61
 
62
62
  property :name, :string
63
63
  property :age, :integer
@@ -127,4 +127,4 @@ end
127
127
  # DataMapper find_by_sql equivilent
128
128
  database.query("SELECT * FROM zoos")
129
129
 
130
- end
130
+ end
@@ -21,11 +21,11 @@ module DataMapper
21
21
  raise NotImplementedError.new
22
22
  end
23
23
 
24
- def save(session, instance)
24
+ def save(database_context, instance)
25
25
  raise NotImplementedError.new
26
26
  end
27
27
 
28
- def load(session, klass, options)
28
+ def load(database_context, klass, options)
29
29
  raise NotImplementedError.new
30
30
  end
31
31
 
@@ -49,13 +49,26 @@ module DataMapper
49
49
 
50
50
  def initialize(configuration)
51
51
  super
52
- @connection_pool = Support::ConnectionPool.new(4) { create_connection }
52
+ @connection_pool = Support::ConnectionPool.new { create_connection }
53
+ end
54
+
55
+ def activated?
56
+ @activated
57
+ end
58
+
59
+ def activate!
60
+ @activated = true
61
+ schema.activate!
53
62
  end
54
63
 
55
64
  def create_connection
56
65
  raise NotImplementedError.new
57
66
  end
58
67
 
68
+ def batch_insertable?
69
+ true
70
+ end
71
+
59
72
  # Yields an available connection. Flushes the connection-pool and reconnects
60
73
  # if the connection returns an error.
61
74
  def connection
@@ -95,32 +108,34 @@ module DataMapper
95
108
  raise NotImplementedError.new
96
109
  end
97
110
 
98
- def query(*args)
99
- connection do |db|
111
+ def query(*args)
112
+ db = create_connection
100
113
 
101
- command = db.create_command(args.shift)
102
- logger.debug { command.text }
103
-
104
- command.execute_reader(*args) do |reader|
105
- fields = reader.fields.map { |field| Inflector.underscore(field).to_sym }
106
-
107
- results = []
108
-
109
- if fields.size > 1
110
- struct = Struct.new(*fields)
111
-
112
- reader.each do
113
- results << struct.new(*reader.current_row)
114
- end
115
- else
116
- reader.each do
117
- results << reader.item(0)
118
- end
119
- end
114
+ command = db.create_command(args.shift)
115
+
116
+ reader = command.execute_reader(*args)
117
+ fields = reader.fields.map { |field| Inflector.underscore(field).to_sym }
118
+ results = []
120
119
 
121
- results
120
+ if fields.size > 1
121
+ struct = Struct.new(*fields)
122
+
123
+ reader.each do
124
+ results << struct.new(*reader.current_row)
125
+ end
126
+ else
127
+ reader.each do
128
+ results << reader.item(0)
122
129
  end
123
130
  end
131
+
132
+ return results
133
+ rescue => e
134
+ logger.error { e }
135
+ raise e
136
+ ensure
137
+ reader.close if reader
138
+ db.close
124
139
  end
125
140
 
126
141
  def handle_error(error)
@@ -128,153 +143,68 @@ module DataMapper
128
143
  end
129
144
 
130
145
  def schema
131
- @schema || ( @schema = Mappings::Schema.new(self, @configuration.database) )
146
+ @schema || ( @schema = self.class::Mappings::Schema.new(self, @configuration.database) )
132
147
  end
133
148
 
134
- def table_exists?(name)
149
+ def column_exists_for_table?(table_name, column_name)
135
150
  connection do |db|
136
- table = self.table(name)
137
- command = db.create_command(table.to_exists_sql)
138
- command.execute_reader(table.name, table.schema.name) do |reader|
139
- reader.has_rows?
151
+ table = self.table(table_name)
152
+ command = db.create_command(table.to_column_exists_sql)
153
+ command.execute_reader(table.name, column_name, table.schema.name) do |reader|
154
+ reader.any? { reader.item(1) == column_name.to_s }
140
155
  end
141
156
  end
142
157
  end
143
-
144
- def truncate(session, name)
145
- connection do |db|
146
- result = db.create_command("TRUNCATE TABLE #{table(name).to_sql}").execute_non_query
147
- session.identity_map.clear!(name)
148
- result.to_i > 0
149
- end
150
- end
151
-
152
- def drop(session, name)
153
- table = self.table(name)
154
-
155
- if table.exists?
156
- connection do |db|
157
- result = db.create_command("DROP TABLE #{table.to_sql}").execute_non_query
158
- session.identity_map.clear!(name)
159
- true
160
- end
161
- else
162
- false
163
- end
164
- end
165
-
166
- def create_table(name)
167
- table = self.table(name)
168
-
169
- if table.exists?
170
- false
171
- else
172
- connection do |db|
173
- db.create_command(table.to_create_table_sql).execute_non_query
174
- true
175
- end
176
- end
177
- end
178
-
179
- def delete(session, instance)
158
+
159
+ def delete(database_context, instance)
180
160
  table = self.table(instance)
181
161
 
182
162
  if instance.is_a?(Class)
183
- connection do |db|
184
- db.create_command("DELETE FROM #{table.to_sql}").execute_non_query
185
- end
186
- session.identity_map.clear!(instance)
163
+ table.delete_all!
187
164
  else
188
165
  callback(instance, :before_destroy)
189
166
 
190
- if connection do |db|
191
- command = db.create_command("DELETE FROM #{table.to_sql} WHERE #{table.key.to_sql} = ?")
192
- command.execute_non_query(instance.key).to_i > 0
193
- end # connection do...end # if continued below:
194
- instance.instance_variable_set(:@new_record, true)
195
- instance.session = session
196
- instance.original_values.clear
197
- session.identity_map.delete(instance)
198
- callback(instance, :after_destroy)
199
- end
167
+ if table.paranoid?
168
+ instance.instance_variable_set(table.paranoid_column.instance_variable_name, Time::now)
169
+ instance.save
170
+ else
171
+ if connection do |db|
172
+ command = db.create_command("DELETE FROM #{table.to_sql} WHERE #{table.key.to_sql} = ?")
173
+ command.execute_non_query(instance.key).to_i > 0
174
+ end # connection do...end # if continued below:
175
+ instance.instance_variable_set(:@new_record, true)
176
+ instance.database_context = database_context
177
+ instance.original_values.clear
178
+ database_context.identity_map.delete(instance)
179
+ callback(instance, :after_destroy)
180
+ end
181
+ end
200
182
  end
201
183
  end
202
184
 
203
- def save(session, instance)
185
+ def save(database_context, instance, validate = true)
204
186
  case instance
205
- when Class, Mappings::Table then create_table(instance)
187
+ when Class then table(instance).create!
188
+ when Mappings::Table then instance.create!
206
189
  when DataMapper::Base then
207
- return false unless instance.dirty? && instance.valid?
190
+ return false unless instance.new_record? || instance.dirty?
208
191
 
209
- callback(instance, :before_save)
192
+ event = instance.new_record? ? :create : :update
210
193
 
211
- # INSERT
212
- result = if instance.new_record?
213
- callback(instance, :before_create)
214
-
215
- table = self.table(instance)
216
- attributes = instance.dirty_attributes
217
-
218
- unless attributes.empty?
219
- if table.multi_class?
220
- instance.instance_variable_set(
221
- table[:type].instance_variable_name,
222
- attributes[:type] = instance.class.name
223
- )
224
- end
225
-
226
- keys = []
227
- values = []
228
- attributes.each_pair do |key, value|
229
- keys << table[key].to_sql
230
- values << value
231
- end
194
+ return false if validate && !instance.validate_recursively(event, Set.new)
232
195
 
233
- # Formatting is a bit off here, but it looks nicer in the log this way.
234
- insert_id = connection do |db|
235
- db.create_command("INSERT INTO #{table.to_sql} (#{keys.join(', ')}) VALUES ?")\
236
- .execute_non_query(values).last_insert_row
237
- end
238
- instance.instance_variable_set(:@new_record, false)
239
- instance.key = insert_id if table.key.serial? && !attributes.include?(table.key.name)
240
- session.identity_map.set(instance)
241
- callback(instance, :after_create)
242
- end
243
- # UPDATE
244
- else
245
- callback(instance, :before_update)
246
-
247
- table = self.table(instance)
248
- attributes = instance.dirty_attributes
249
- parameters = []
250
-
251
- unless attributes.empty?
252
- sql = "UPDATE " << table.to_sql << " SET "
253
-
254
- sql << attributes.map do |key, value|
255
- parameters << value
256
- "#{table[key].to_sql} = ?"
257
- end.join(', ')
258
-
259
- sql << " WHERE #{table.key.to_sql} = ?"
260
- parameters << instance.key
261
-
262
- connection do |db|
263
- db.create_command(sql).execute_non_query(*parameters).to_i > 0 \
264
- && callback(instance, :after_update)
265
- end
266
- end
267
- end
196
+ callback(instance, :before_save)
197
+ result = send(event, database_context, instance)
268
198
 
199
+ instance.database_context = database_context
269
200
  instance.attributes.each_pair do |name, value|
270
201
  instance.original_values[name] = value
271
202
  end
272
203
 
273
204
  instance.loaded_associations.each do |association|
274
- association.save if association.respond_to?(:save)
205
+ association.save_without_validation(database_context) if association.dirty?
275
206
  end
276
207
 
277
- instance.session = session
278
208
  callback(instance, :after_save)
279
209
  result
280
210
  end
@@ -283,12 +213,74 @@ module DataMapper
283
213
  raise error
284
214
  end
285
215
 
286
- def load(session, klass, options)
287
- self.class::Commands::LoadCommand.new(self, session, klass, options).call
216
+ def save_without_validation(database_context, instance)
217
+ save(database_context, instance, false)
218
+ end
219
+
220
+ def update(database_context, instance)
221
+ callback(instance, :before_update)
222
+
223
+ table = self.table(instance)
224
+ attributes = instance.dirty_attributes
225
+ parameters = []
226
+
227
+ unless attributes.empty?
228
+ sql = "UPDATE " << table.to_sql << " SET "
229
+
230
+ sql << attributes.map do |key, value|
231
+ parameters << value
232
+ "#{table[key].to_sql} = ?"
233
+ end.join(', ')
234
+
235
+ sql << " WHERE #{table.key.to_sql} = ?"
236
+ parameters << instance.key
237
+
238
+ connection do |db|
239
+ db.create_command(sql).execute_non_query(*parameters).to_i > 0 \
240
+ && callback(instance, :after_update)
241
+ end
242
+ else
243
+ true
244
+ end
245
+ end
246
+
247
+ def create(database_context, instance)
248
+ callback(instance, :before_create)
249
+
250
+ table = self.table(instance)
251
+ attributes = instance.dirty_attributes
252
+
253
+ if table.multi_class?
254
+ instance.instance_variable_set(
255
+ table[:type].instance_variable_name,
256
+ attributes[:type] = instance.class.name
257
+ )
258
+ end
259
+
260
+ keys = []
261
+ values = []
262
+ attributes.each_pair do |key, value|
263
+ keys << table[key].to_sql
264
+ values << value
265
+ end
266
+
267
+ sql = if keys.size > 0
268
+ "INSERT INTO #{table.to_sql} (#{keys.join(', ')}) VALUES ?"
269
+ else
270
+ "INSERT INTO #{table.to_sql}"
271
+ end
272
+
273
+ insert_id = connection do |db|
274
+ db.create_command(sql).execute_non_query(values).last_insert_row
275
+ end
276
+ instance.instance_variable_set(:@new_record, false)
277
+ instance.key = insert_id if table.key.serial? && !attributes.include?(table.key.name)
278
+ database_context.identity_map.set(instance)
279
+ callback(instance, :after_create)
288
280
  end
289
281
 
290
- def count(klass_or_instance, options)
291
- query("SELECT COUNT(*) AS row_count FROM " + table(klass_or_instance).to_sql).first.to_i
282
+ def load(database_context, klass, options)
283
+ self.class::Commands::LoadCommand.new(self, database_context, klass, options).call
292
284
  end
293
285
 
294
286
  def table(instance)
@@ -340,7 +332,9 @@ module DataMapper
340
332
  :decimal => 'decimal'.freeze,
341
333
  :float => 'float'.freeze,
342
334
  :datetime => 'datetime'.freeze,
343
- :date => 'date'.freeze
335
+ :date => 'date'.freeze,
336
+ :boolean => 'boolean'.freeze,
337
+ :object => 'text'.freeze
344
338
  }
345
339
 
346
340
  include Sql
@@ -4,7 +4,7 @@ begin
4
4
  rescue LoadError
5
5
  STDERR.puts <<-EOS
6
6
  You must install the DataObjects::Mysql driver.
7
- rake dm:install:mysql
7
+ gem install do_mysql
8
8
  EOS
9
9
  exit
10
10
  end
@@ -34,6 +34,10 @@ module DataMapper
34
34
  return conn
35
35
  end
36
36
 
37
+ def database_column_name
38
+ "TABLE_SCHEMA"
39
+ end
40
+
37
41
  module Mappings
38
42
 
39
43
  def to_create_table_sql
@@ -42,6 +46,15 @@ module DataMapper
42
46
  end
43
47
  end
44
48
 
49
+ class Schema
50
+
51
+ def database_tables
52
+ get_database_tables(@adapter.schema.name)
53
+ end
54
+
55
+ end
56
+
57
+
45
58
  end # module Mappings
46
59
  end # class MysqlAdapter
47
60
 
@@ -3,8 +3,8 @@ begin
3
3
  require 'do_postgres'
4
4
  rescue LoadError
5
5
  STDERR.puts <<-EOS
6
- You must install the DataObjects::PostgreSQL driver.
7
- rake dm:install:postgresql
6
+ You must install the DataObjects::Postgres driver.
7
+ gem install do_postgres
8
8
  EOS
9
9
  exit
10
10
  end
@@ -27,16 +27,29 @@ module DataMapper
27
27
  end
28
28
 
29
29
  def create_connection
30
- conn = DataObject::Postgres::Connection.new("dbname=#{@configuration.database}")
30
+ connection_string = ""
31
+ builder = lambda do |k,v|
32
+ connection_string << "#{k}=#{@configuration.send(v)} " unless
33
+ @configuration.send(v).blank?
34
+ end
35
+ builder['host', :host]
36
+ builder['user', :username]
37
+ builder['password', :password]
38
+ builder['dbname', :database]
39
+ builder['socket', :socket]
40
+ conn = DataObject::Postgres::Connection.new(connection_string.strip)
31
41
  conn.logger = self.logger
32
42
  conn.open
33
- return conn
34
-
43
+
35
44
  unless schema_search_path.empty?
36
45
  execute("SET search_path TO #{schema_search_path}")
37
46
  end
38
-
39
- return connection
47
+
48
+ return conn
49
+ end
50
+
51
+ def database_column_name
52
+ "TABLE_CATALOG"
40
53
  end
41
54
 
42
55
  TABLE_QUOTING_CHARACTER = '"'.freeze
@@ -72,15 +85,47 @@ module DataMapper
72
85
  return sql
73
86
  end
74
87
 
75
- def to_exists_sql
76
- @to_exists_sql || @to_exists_sql = <<-EOS.compress_lines
77
- SELECT TABLE_NAME
78
- FROM INFORMATION_SCHEMA.TABLES
79
- WHERE TABLE_NAME = ?
80
- AND TABLE_CATALOG = ?
81
- EOS
88
+ # The logic of this comes from AR; it was modified for smarter typecasting
89
+ def unquote_default(default)
90
+ # Boolean types
91
+ return true if default =~ /true/i
92
+ return false if default =~ /false/i
93
+
94
+ # Char/String/Bytea type values
95
+ return $1 if default =~ /^'(.*)'::(bpchar|text|character varying|bytea)$/
96
+
97
+ # Numeric values
98
+ return value.to_f if default =~ /^-?[0-9]+(\.[0-9]*)/
99
+ return value.to_i if default =~ /^-?[0-9]+/
100
+
101
+ # Fixed dates / times
102
+ return Date.parse($1) if default =~ /^'(.+)'::date/
103
+ return DateTime.parse($1) if default =~ /^'(.+)'::timestamp/
104
+
105
+ # Anything else is blank, some user type, or some function
106
+ # and we can't know the value of that, so return nil.
107
+ return nil
82
108
  end
83
109
 
110
+ # def to_exists_sql
111
+ # @to_exists_sql || @to_exists_sql = <<-EOS.compress_lines
112
+ # SELECT TABLE_NAME
113
+ # FROM INFORMATION_SCHEMA.TABLES
114
+ # WHERE TABLE_NAME = ?
115
+ # AND TABLE_CATALOG = ?
116
+ # EOS
117
+ # end
118
+ #
119
+ # def to_column_exists_sql
120
+ # @to_column_exists_sql || @to_column_exists_sql = <<-EOS.compress_lines
121
+ # SELECT TABLE_NAME, COLUMN_NAME
122
+ # FROM INFORMATION_SCHEMA.COLUMNS
123
+ # WHERE TABLE_NAME = ?
124
+ # AND COLUMN_NAME = ?
125
+ # AND TABLE_CATALOG = ?
126
+ # EOS
127
+ # end
128
+
84
129
  private
85
130
 
86
131
  def quote_table(table_suffix = nil)
@@ -91,17 +136,81 @@ module DataMapper
91
136
  end
92
137
  end # class Table
93
138
 
139
+ class Schema
140
+
141
+ def database_tables
142
+ get_database_tables("public")
143
+ end
144
+
145
+ end
146
+
94
147
  class Column
95
148
  def serial_declaration
96
149
  "SERIAL"
97
150
  end
98
151
 
152
+ def to_alter_sql
153
+ "ALTER TABLE " << table.to_sql << " ALTER COLUMN " << to_alter_form
154
+ end
155
+
156
+ def alter!
157
+ result = super
158
+ reset_alter_state!
159
+ result
160
+ end
161
+
162
+ def reset_alter_state!
163
+ @type_changed = false
164
+ @default_changed = false
165
+ end
166
+
167
+ def default=(value)
168
+ @default_changed = true
169
+ super
170
+ end
171
+
172
+ def type=(value)
173
+ @type_changed = true
174
+ super
175
+ end
176
+
177
+ def to_alter_form
178
+ sql = to_sql.dup
179
+
180
+ changes = 0
181
+
182
+ if @type_changed
183
+ changes += 1
184
+ sql << " TYPE " << type_declaration
185
+ case self.type
186
+ when :integer then sql << " USING #{to_sql}::integer"
187
+ when :datetime then
188
+ sql << " USING timestamp with time zone"
189
+ end
190
+ end
191
+
192
+ if @default_changed
193
+ sql << ", " if changes += 1 > 1
194
+
195
+ if default.blank? || default_declaration.blank?
196
+ sql << " DROP DEFAULT"
197
+ else
198
+ sql << " " << default_declaration
199
+ end
200
+ end
201
+
202
+ sql
203
+ end
204
+
99
205
  def to_long_form
100
206
  @to_long_form || begin
101
207
  @to_long_form = "#{to_sql}"
102
208
 
103
209
  if serial? && !serial_declaration.blank?
104
210
  @to_long_form << " #{serial_declaration}"
211
+ if key? && !primary_key_declaration.blank?
212
+ @to_long_form << " #{primary_key_declaration}"
213
+ end
105
214
  else
106
215
  @to_long_form << " #{type_declaration}"
107
216
 
@@ -109,10 +218,6 @@ module DataMapper
109
218
  @to_long_form << " #{not_null_declaration}"
110
219
  end
111
220
 
112
- if key? && !primary_key_declaration.blank?
113
- @to_long_form << " #{primary_key_declaration}"
114
- end
115
-
116
221
  if default && !default_declaration.blank?
117
222
  @to_long_form << " #{default_declaration}"
118
223
  end