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.
- data/example.rb +5 -5
- data/lib/data_mapper/adapters/abstract_adapter.rb +2 -2
- data/lib/data_mapper/adapters/data_object_adapter.rb +141 -147
- data/lib/data_mapper/adapters/mysql_adapter.rb +14 -1
- data/lib/data_mapper/adapters/postgresql_adapter.rb +123 -18
- data/lib/data_mapper/adapters/sql/coersion.rb +21 -9
- data/lib/data_mapper/adapters/sql/commands/load_command.rb +36 -19
- data/lib/data_mapper/adapters/sql/mappings/column.rb +111 -17
- data/lib/data_mapper/adapters/sql/mappings/schema.rb +27 -0
- data/lib/data_mapper/adapters/sql/mappings/table.rb +256 -29
- data/lib/data_mapper/adapters/sqlite3_adapter.rb +93 -8
- data/lib/data_mapper/associations/belongs_to_association.rb +53 -54
- data/lib/data_mapper/associations/has_and_belongs_to_many_association.rb +157 -25
- data/lib/data_mapper/associations/has_many_association.rb +45 -15
- data/lib/data_mapper/associations/has_n_association.rb +79 -20
- data/lib/data_mapper/associations/has_one_association.rb +2 -2
- data/lib/data_mapper/associations/reference.rb +1 -1
- data/lib/data_mapper/auto_migrations.rb +40 -0
- data/lib/data_mapper/base.rb +201 -98
- data/lib/data_mapper/context.rb +16 -10
- data/lib/data_mapper/database.rb +22 -11
- data/lib/data_mapper/dependency_queue.rb +28 -0
- data/lib/data_mapper/embedded_value.rb +61 -17
- data/lib/data_mapper/property.rb +4 -0
- data/lib/data_mapper/support/active_record_impersonation.rb +13 -5
- data/lib/data_mapper/support/errors.rb +5 -0
- data/lib/data_mapper/support/serialization.rb +8 -4
- data/lib/data_mapper/validatable_extensions/errors.rb +12 -0
- data/lib/data_mapper/validatable_extensions/macros.rb +7 -0
- data/lib/data_mapper/validatable_extensions/validatable_instance_methods.rb +62 -0
- data/lib/data_mapper/validatable_extensions/validation_base.rb +18 -0
- data/lib/data_mapper/validatable_extensions/validations/formats/email.rb +43 -0
- data/lib/data_mapper/validatable_extensions/validations/validates_acceptance_of.rb +7 -0
- data/lib/data_mapper/validatable_extensions/validations/validates_confirmation_of.rb +7 -0
- data/lib/data_mapper/validatable_extensions/validations/validates_each.rb +7 -0
- data/lib/data_mapper/validatable_extensions/validations/validates_format_of.rb +28 -0
- data/lib/data_mapper/validatable_extensions/validations/validates_length_of.rb +15 -0
- data/lib/data_mapper/validatable_extensions/validations/validates_numericality_of.rb +7 -0
- data/lib/data_mapper/validatable_extensions/validations/validates_presence_of.rb +7 -0
- data/lib/data_mapper/validatable_extensions/validations/validates_true_for.rb +7 -0
- data/lib/data_mapper/validatable_extensions/validations/validates_uniqueness_of.rb +33 -0
- data/lib/data_mapper/validations.rb +20 -0
- data/lib/data_mapper.rb +39 -34
- data/performance.rb +24 -18
- data/plugins/dataobjects/do_rb +0 -0
- data/rakefile.rb +12 -2
- data/spec/active_record_impersonation_spec.rb +133 -0
- data/spec/acts_as_tree_spec.rb +25 -9
- data/spec/associations_spec.rb +124 -4
- data/spec/attributes_spec.rb +13 -0
- data/spec/auto_migrations_spec.rb +44 -0
- data/spec/base_spec.rb +189 -1
- data/spec/column_spec.rb +85 -7
- data/spec/conditions_spec.rb +2 -2
- data/spec/dependency_spec.rb +25 -0
- data/spec/embedded_value_spec.rb +123 -3
- data/spec/fixtures/animals.yaml +1 -0
- data/spec/fixtures/careers.yaml +5 -0
- data/spec/fixtures/comments.yaml +1 -0
- data/spec/fixtures/people.yaml +14 -9
- data/spec/fixtures/projects.yaml +4 -0
- data/spec/fixtures/sections.yaml +5 -0
- data/spec/fixtures/serializers.yaml +6 -0
- data/spec/fixtures/users.yaml +1 -0
- data/spec/load_command_spec.rb +5 -4
- data/spec/mock_adapter.rb +2 -2
- data/spec/models/animal.rb +2 -1
- data/spec/models/animals_exhibit.rb +2 -2
- data/spec/models/career.rb +6 -0
- data/spec/models/comment.rb +4 -0
- data/spec/models/exhibit.rb +4 -0
- data/spec/models/person.rb +3 -13
- data/spec/models/project.rb +1 -1
- data/spec/models/serializer.rb +3 -0
- data/spec/models/user.rb +4 -0
- data/spec/models/zoo.rb +8 -1
- data/spec/natural_key_spec.rb +36 -0
- data/spec/paranoia_spec.rb +36 -0
- data/spec/property_spec.rb +70 -0
- data/spec/schema_spec.rb +10 -2
- data/spec/serialization_spec.rb +6 -3
- data/spec/serialize_spec.rb +19 -0
- data/spec/single_table_inheritance_spec.rb +7 -1
- data/spec/spec_helper.rb +26 -8
- data/spec/table_spec.rb +33 -0
- data/spec/validates_confirmation_of_spec.rb +20 -4
- data/spec/validates_format_of_spec.rb +22 -8
- data/spec/validates_length_of_spec.rb +26 -13
- data/spec/validates_uniqueness_of_spec.rb +18 -5
- data/spec/validations_spec.rb +55 -10
- data/tasks/fixtures.rb +13 -7
- metadata +189 -153
- data/lib/data_mapper/validations/confirmation_validator.rb +0 -53
- data/lib/data_mapper/validations/contextual_validations.rb +0 -50
- data/lib/data_mapper/validations/format_validator.rb +0 -85
- data/lib/data_mapper/validations/formats/email.rb +0 -78
- data/lib/data_mapper/validations/generic_validator.rb +0 -22
- data/lib/data_mapper/validations/length_validator.rb +0 -76
- data/lib/data_mapper/validations/required_field_validator.rb +0 -41
- data/lib/data_mapper/validations/unique_validator.rb +0 -56
- data/lib/data_mapper/validations/validation_errors.rb +0 -37
- data/lib/data_mapper/validations/validation_helper.rb +0 -77
- data/plugins/dataobjects/REVISION +0 -1
- data/plugins/dataobjects/Rakefile +0 -9
- data/plugins/dataobjects/do.rb +0 -348
- data/plugins/dataobjects/do_mysql.rb +0 -212
- data/plugins/dataobjects/do_postgres.rb +0 -196
- data/plugins/dataobjects/do_sqlite3.rb +0 -157
- data/plugins/dataobjects/spec/do_spec.rb +0 -150
- data/plugins/dataobjects/spec/spec_helper.rb +0 -81
- data/plugins/dataobjects/swig_mysql/extconf.rb +0 -45
- data/plugins/dataobjects/swig_mysql/mysql_c.c +0 -16602
- data/plugins/dataobjects/swig_mysql/mysql_c.i +0 -67
- data/plugins/dataobjects/swig_mysql/mysql_supp.i +0 -46
- data/plugins/dataobjects/swig_postgres/extconf.rb +0 -29
- data/plugins/dataobjects/swig_postgres/postgres_c.c +0 -8185
- data/plugins/dataobjects/swig_postgres/postgres_c.i +0 -73
- data/plugins/dataobjects/swig_sqlite/extconf.rb +0 -9
- data/plugins/dataobjects/swig_sqlite/sqlite3_c.c +0 -4725
- data/plugins/dataobjects/swig_sqlite/sqlite_c.i +0 -168
- 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(
|
24
|
+
def save(database_context, instance)
|
25
25
|
raise NotImplementedError.new
|
26
26
|
end
|
27
27
|
|
28
|
-
def load(
|
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
|
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
|
-
|
111
|
+
def query(*args)
|
112
|
+
db = create_connection
|
100
113
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
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
|
-
|
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
|
149
|
+
def column_exists_for_table?(table_name, column_name)
|
135
150
|
connection do |db|
|
136
|
-
table = self.table(
|
137
|
-
command = db.create_command(table.
|
138
|
-
command.execute_reader(table.name, table.schema.name) do |reader|
|
139
|
-
reader.
|
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
|
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
|
-
|
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
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
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(
|
185
|
+
def save(database_context, instance, validate = true)
|
204
186
|
case instance
|
205
|
-
when Class
|
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.
|
190
|
+
return false unless instance.new_record? || instance.dirty?
|
208
191
|
|
209
|
-
|
192
|
+
event = instance.new_record? ? :create : :update
|
210
193
|
|
211
|
-
|
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
|
-
|
234
|
-
|
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.
|
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
|
287
|
-
|
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
|
291
|
-
|
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
|
-
|
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::
|
7
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
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
|