datamapper 0.2.5 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +5 -1
- data/FAQ +96 -0
- data/QUICKLINKS +12 -0
- data/README +57 -155
- data/environment.rb +61 -43
- data/example.rb +30 -12
- data/lib/data_mapper.rb +6 -1
- data/lib/data_mapper/adapters/abstract_adapter.rb +0 -57
- data/lib/data_mapper/adapters/data_object_adapter.rb +203 -97
- data/lib/data_mapper/adapters/mysql_adapter.rb +4 -0
- data/lib/data_mapper/adapters/postgresql_adapter.rb +7 -1
- data/lib/data_mapper/adapters/sql/coersion.rb +3 -2
- data/lib/data_mapper/adapters/sql/commands/load_command.rb +29 -10
- data/lib/data_mapper/adapters/sql/mappings/associations_set.rb +4 -0
- data/lib/data_mapper/adapters/sql/mappings/column.rb +13 -9
- data/lib/data_mapper/adapters/sql/mappings/conditions.rb +172 -0
- data/lib/data_mapper/adapters/sql/mappings/table.rb +43 -17
- data/lib/data_mapper/adapters/sqlite3_adapter.rb +9 -2
- data/lib/data_mapper/associations.rb +75 -3
- data/lib/data_mapper/associations/belongs_to_association.rb +70 -36
- data/lib/data_mapper/associations/has_and_belongs_to_many_association.rb +195 -86
- data/lib/data_mapper/associations/has_many_association.rb +168 -61
- data/lib/data_mapper/associations/has_n_association.rb +23 -3
- data/lib/data_mapper/attributes.rb +73 -0
- data/lib/data_mapper/auto_migrations.rb +2 -6
- data/lib/data_mapper/base.rb +5 -9
- data/lib/data_mapper/database.rb +4 -3
- data/lib/data_mapper/embedded_value.rb +66 -30
- data/lib/data_mapper/identity_map.rb +1 -3
- data/lib/data_mapper/is/tree.rb +121 -0
- data/lib/data_mapper/migration.rb +155 -0
- data/lib/data_mapper/persistence.rb +532 -218
- data/lib/data_mapper/property.rb +306 -0
- data/lib/data_mapper/query.rb +164 -0
- data/lib/data_mapper/support/blank.rb +2 -2
- data/lib/data_mapper/support/connection_pool.rb +5 -6
- data/lib/data_mapper/support/enumerable.rb +3 -3
- data/lib/data_mapper/support/errors.rb +10 -1
- data/lib/data_mapper/support/inflector.rb +174 -238
- data/lib/data_mapper/support/object.rb +54 -0
- data/lib/data_mapper/support/serialization.rb +19 -1
- data/lib/data_mapper/support/string.rb +7 -16
- data/lib/data_mapper/support/symbol.rb +3 -15
- data/lib/data_mapper/support/typed_set.rb +68 -0
- data/lib/data_mapper/types/base.rb +44 -0
- data/lib/data_mapper/types/string.rb +34 -0
- data/lib/data_mapper/validations/number_validator.rb +40 -0
- data/lib/data_mapper/validations/string_validator.rb +20 -0
- data/lib/data_mapper/validations/validator.rb +13 -0
- data/performance.rb +26 -1
- data/profile_data_mapper.rb +1 -1
- data/rakefile.rb +42 -2
- data/spec/acts_as_tree_spec.rb +11 -3
- data/spec/adapters/data_object_adapter_spec.rb +31 -0
- data/spec/associations/belongs_to_association_spec.rb +98 -0
- data/spec/associations/has_and_belongs_to_many_association_spec.rb +377 -0
- data/spec/associations/has_many_association_spec.rb +337 -0
- data/spec/attributes_spec.rb +23 -1
- data/spec/auto_migrations_spec.rb +86 -29
- data/spec/callbacks_spec.rb +107 -0
- data/spec/column_spec.rb +5 -2
- data/spec/count_command_spec.rb +33 -1
- data/spec/database_spec.rb +18 -0
- data/spec/dependency_spec.rb +4 -2
- data/spec/embedded_value_spec.rb +8 -8
- data/spec/fixtures/people.yaml +1 -1
- data/spec/fixtures/projects.yaml +10 -1
- data/spec/fixtures/tasks.yaml +6 -0
- data/spec/fixtures/tasks_tasks.yaml +2 -0
- data/spec/fixtures/tomatoes.yaml +1 -0
- data/spec/is_a_tree_spec.rb +149 -0
- data/spec/load_command_spec.rb +71 -9
- data/spec/magic_columns_spec.rb +17 -2
- data/spec/migration_spec.rb +267 -0
- data/spec/models/animal.rb +1 -1
- data/spec/models/candidate.rb +8 -0
- data/spec/models/career.rb +1 -1
- data/spec/models/chain.rb +8 -0
- data/spec/models/comment.rb +1 -1
- data/spec/models/exhibit.rb +1 -1
- data/spec/models/fence.rb +7 -0
- data/spec/models/fruit.rb +2 -2
- data/spec/models/job.rb +8 -0
- data/spec/models/person.rb +2 -3
- data/spec/models/post.rb +1 -1
- data/spec/models/project.rb +21 -1
- data/spec/models/section.rb +1 -1
- data/spec/models/serializer.rb +1 -1
- data/spec/models/task.rb +9 -0
- data/spec/models/tomato.rb +27 -0
- data/spec/models/user.rb +8 -2
- data/spec/models/zoo.rb +2 -7
- data/spec/paranoia_spec.rb +1 -1
- data/spec/{base_spec.rb → persistence_spec.rb} +207 -18
- data/spec/postgres_spec.rb +48 -6
- data/spec/property_spec.rb +90 -9
- data/spec/query_spec.rb +71 -5
- data/spec/save_command_spec.rb +11 -0
- data/spec/spec_helper.rb +14 -11
- data/spec/support/blank_spec.rb +8 -0
- data/spec/support/inflector_spec.rb +41 -0
- data/spec/support/object_spec.rb +9 -0
- data/spec/{serialization_spec.rb → support/serialization_spec.rb} +1 -1
- data/spec/support/silence_spec.rb +15 -0
- data/spec/{support_spec.rb → support/string_spec.rb} +3 -3
- data/spec/support/struct_spec.rb +12 -0
- data/spec/support/typed_set_spec.rb +66 -0
- data/spec/table_spec.rb +3 -3
- data/spec/types/string.rb +81 -0
- data/spec/validates_uniqueness_of_spec.rb +17 -0
- data/spec/validations/number_validator.rb +59 -0
- data/spec/validations/string_validator.rb +14 -0
- metadata +59 -17
- data/do_performance.rb +0 -153
- data/lib/data_mapper/support/active_record_impersonation.rb +0 -103
- data/lib/data_mapper/support/weak_hash.rb +0 -46
- data/spec/active_record_impersonation_spec.rb +0 -129
- data/spec/associations_spec.rb +0 -232
- data/spec/conditions_spec.rb +0 -49
- data/spec/has_many_association_spec.rb +0 -173
- data/spec/models/animals_exhibit.rb +0 -8
@@ -17,6 +17,9 @@ module DataMapper
|
|
17
17
|
TRUE_ALIASES << "T".freeze << "\004\bT".freeze
|
18
18
|
FALSE_ALIASES << "F".freeze << "\004\bF".freeze
|
19
19
|
|
20
|
+
def empty_insert_sql
|
21
|
+
"() VALUES ()"
|
22
|
+
end
|
20
23
|
|
21
24
|
def create_connection
|
22
25
|
|
@@ -28,6 +31,7 @@ module DataMapper
|
|
28
31
|
builder['password', :password]
|
29
32
|
builder['dbname', :database]
|
30
33
|
builder['socket', :socket]
|
34
|
+
builder['port', :port]
|
31
35
|
|
32
36
|
logger.debug { connection_string.strip }
|
33
37
|
|
@@ -37,6 +37,7 @@ module DataMapper
|
|
37
37
|
builder['password', :password]
|
38
38
|
builder['dbname', :database]
|
39
39
|
builder['socket', :socket]
|
40
|
+
builder['port', :port]
|
40
41
|
conn = DataObject::Postgres::Connection.new(connection_string.strip)
|
41
42
|
conn.logger = self.logger
|
42
43
|
conn.open
|
@@ -239,8 +240,13 @@ module DataMapper
|
|
239
240
|
end
|
240
241
|
end
|
241
242
|
|
243
|
+
# size is still required, as length in postgres behaves slightly differently
|
242
244
|
def size
|
243
|
-
|
245
|
+
case self.type
|
246
|
+
#strings in postgres can be unlimited length
|
247
|
+
when :string then return (@options.has_key?(:length) || @options.has_key?(:size) ? @size : nil)
|
248
|
+
else nil
|
249
|
+
end
|
244
250
|
end
|
245
251
|
end # class Column
|
246
252
|
end # module Mappings
|
@@ -23,11 +23,12 @@ module DataMapper
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def type_cast_boolean(raw_value)
|
26
|
+
return nil if raw_value.nil? || (raw_value.respond_to?(:empty?) && raw_value.empty?)
|
26
27
|
case raw_value
|
27
28
|
when TrueClass, FalseClass then raw_value
|
28
29
|
when *self::class::TRUE_ALIASES then true
|
29
30
|
when *self::class::FALSE_ALIASES then false
|
30
|
-
else "Can't type-cast #{raw_value.inspect} to a boolean"
|
31
|
+
else raise CoersionError.new("Can't type-cast #{raw_value.inspect} to a boolean")
|
31
32
|
end
|
32
33
|
end
|
33
34
|
|
@@ -45,7 +46,7 @@ module DataMapper
|
|
45
46
|
|
46
47
|
def type_cast_class(raw_value)
|
47
48
|
return nil if raw_value.blank?
|
48
|
-
|
49
|
+
Object::recursive_const_get(raw_value)
|
49
50
|
end
|
50
51
|
|
51
52
|
def type_cast_integer(raw_value)
|
@@ -56,10 +56,14 @@ module DataMapper
|
|
56
56
|
# setting both the original_value, and the
|
57
57
|
# instance-variable through method chaining to avoid
|
58
58
|
# lots of extra short-lived local variables.
|
59
|
-
|
60
|
-
column.
|
61
|
-
|
62
|
-
|
59
|
+
begin
|
60
|
+
type_casted_values[column.name] = instance.instance_variable_set(
|
61
|
+
column.instance_variable_name,
|
62
|
+
column.type_cast_value(values[index])
|
63
|
+
)
|
64
|
+
rescue => e
|
65
|
+
raise MaterializationError.new("Failed to materialize column #{column.name.inspect} with value #{values[index].inspect}\n#{e.display}")
|
66
|
+
end
|
63
67
|
end
|
64
68
|
|
65
69
|
instance.original_values = type_casted_values
|
@@ -71,7 +75,11 @@ module DataMapper
|
|
71
75
|
return instance
|
72
76
|
|
73
77
|
rescue => e
|
74
|
-
|
78
|
+
if e.is_a?(MaterializationError)
|
79
|
+
raise e
|
80
|
+
else
|
81
|
+
raise MaterializationError.new("Failed to materialize row: #{values.inspect}\n#{e.display}")
|
82
|
+
end
|
75
83
|
end
|
76
84
|
|
77
85
|
def loaded_set
|
@@ -84,7 +92,7 @@ module DataMapper
|
|
84
92
|
instance = @database_context.identity_map.get(@klass, instance_id)
|
85
93
|
|
86
94
|
if instance.nil? || @reload
|
87
|
-
instance = instance_type.
|
95
|
+
instance = instance_type.allocate() if instance.nil?
|
88
96
|
instance.instance_variable_set(:@__key, instance_id)
|
89
97
|
instance.instance_variable_set(:@new_record, false)
|
90
98
|
@database_context.identity_map.set(instance)
|
@@ -358,7 +366,11 @@ module DataMapper
|
|
358
366
|
else raise "CAN HAS CRASH? #{clause.inspect}"
|
359
367
|
end
|
360
368
|
rescue => e
|
361
|
-
|
369
|
+
if e.is_a?(ConditionsError)
|
370
|
+
raise e
|
371
|
+
else
|
372
|
+
raise ConditionsError.new(clause, value, e)
|
373
|
+
end
|
362
374
|
end
|
363
375
|
|
364
376
|
private
|
@@ -368,10 +380,12 @@ module DataMapper
|
|
368
380
|
qualify_columns = qualify_columns?
|
369
381
|
@columns_for_select = []
|
370
382
|
|
371
|
-
|
383
|
+
i = 0
|
384
|
+
columns.each do |column|
|
372
385
|
class_for_loader = column.table.klass
|
373
386
|
@loaders[class_for_loader].add_column(column, i) if class_for_loader
|
374
387
|
@columns_for_select << column.to_sql(qualify_columns)
|
388
|
+
i += 1
|
375
389
|
end
|
376
390
|
|
377
391
|
@columns_for_select
|
@@ -482,8 +496,13 @@ module DataMapper
|
|
482
496
|
|
483
497
|
case x = conditions_hash.delete(:conditions)
|
484
498
|
when Array then
|
485
|
-
|
486
|
-
|
499
|
+
# DO NOT mutate incoming Array values!!!
|
500
|
+
# Otherwise the mutated version may impact all the
|
501
|
+
# way up to the options passed to the finders,
|
502
|
+
# and have unintended side-effects.
|
503
|
+
array_copy = x.dup
|
504
|
+
clause = array_copy.shift
|
505
|
+
expression_to_sql(clause, array_copy, collection)
|
487
506
|
when Hash then
|
488
507
|
x.each_pair do |key,value|
|
489
508
|
expression_to_sql(key, value, collection)
|
@@ -7,7 +7,7 @@ module DataMapper
|
|
7
7
|
# Ordinal, Length/Size, Nullability are just a few.
|
8
8
|
class Column
|
9
9
|
attr_reader :type, :name, :ordinal, :size, :default, :check
|
10
|
-
attr_writer :lazy, :index
|
10
|
+
attr_writer :lazy, :index, :unique
|
11
11
|
attr_accessor :table, :options
|
12
12
|
|
13
13
|
def initialize(adapter, table, name, type, ordinal, options = {})
|
@@ -15,13 +15,17 @@ module DataMapper
|
|
15
15
|
@table = table
|
16
16
|
@name, self.type, @options = name.to_sym, type, options
|
17
17
|
@ordinal = ordinal
|
18
|
-
|
18
|
+
parse_options!
|
19
|
+
end
|
20
|
+
|
21
|
+
def parse_options!
|
19
22
|
@key = @options[:key] == true || @options[:serial] == true
|
20
23
|
@nullable = @options.has_key?(:nullable) ? @options[:nullable] : !@key
|
21
24
|
@lazy = @options.has_key?(:lazy) ? @options[:lazy] : (@type == :text && !@key)
|
22
25
|
@serial = @options[:serial] == true
|
23
26
|
@default = @options[:default]
|
24
|
-
|
27
|
+
|
28
|
+
@unique = if @options[:index] == :unique then @options.delete(:index); true else false end
|
25
29
|
@index = @options[:index]
|
26
30
|
@check = @options[:check] # only for postgresql
|
27
31
|
|
@@ -36,8 +40,11 @@ module DataMapper
|
|
36
40
|
else nil
|
37
41
|
end
|
38
42
|
end
|
43
|
+
@size = @size.last if @size.is_a?(Range)
|
39
44
|
end
|
40
45
|
|
46
|
+
def defaulted?() instance_variables.include?("@default") end
|
47
|
+
|
41
48
|
def type=(value)
|
42
49
|
self.flush_sql_caches!
|
43
50
|
@type = value
|
@@ -167,7 +174,7 @@ module DataMapper
|
|
167
174
|
def rename!(new_name)
|
168
175
|
old_name = name # Store the old_name
|
169
176
|
|
170
|
-
new_column = @table.add_column(new_name, self.type, self.options)
|
177
|
+
new_column = @table.add_column(new_name, self.type, self.options.merge(:ordinal => self.ordinal))
|
171
178
|
|
172
179
|
# Create the new column
|
173
180
|
new_column.create!
|
@@ -181,11 +188,8 @@ module DataMapper
|
|
181
188
|
command.execute_non_query
|
182
189
|
end
|
183
190
|
|
184
|
-
|
185
|
-
|
186
|
-
# Drop the old column
|
187
|
-
new_column.drop!
|
188
|
-
true
|
191
|
+
self.drop!
|
192
|
+
new_column
|
189
193
|
end
|
190
194
|
|
191
195
|
def to_long_form
|
@@ -0,0 +1,172 @@
|
|
1
|
+
module DataMapper
|
2
|
+
module Adapters
|
3
|
+
module Sql
|
4
|
+
module Mappings
|
5
|
+
|
6
|
+
class Conditions
|
7
|
+
def initialize(table, adapter, qualify_columns=false, options={})
|
8
|
+
@table = table
|
9
|
+
@qualify_columns = qualify_columns
|
10
|
+
|
11
|
+
# BEGIN: Partion out the options hash into general options,
|
12
|
+
# and conditions.
|
13
|
+
standard_find_options = adapter.class::FIND_OPTIONS
|
14
|
+
conditions_hash = {}
|
15
|
+
|
16
|
+
options.each do |key,value|
|
17
|
+
unless standard_find_options.include?(key) && key != :conditions
|
18
|
+
conditions_hash[key] = value
|
19
|
+
end
|
20
|
+
end
|
21
|
+
# END
|
22
|
+
|
23
|
+
@conditions = parse_conditions(conditions_hash)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Generate a statement after 'WHERE' based on the initialization
|
27
|
+
# arguments.
|
28
|
+
def to_params_sql
|
29
|
+
parameters = []
|
30
|
+
sql = ""
|
31
|
+
|
32
|
+
unless @conditions.empty?
|
33
|
+
sql << ' WHERE ('
|
34
|
+
|
35
|
+
last_index = @conditions.size
|
36
|
+
current_index = 0
|
37
|
+
|
38
|
+
@conditions.each do |condition|
|
39
|
+
case condition
|
40
|
+
when String then sql << condition
|
41
|
+
when Array then
|
42
|
+
sql << condition.shift
|
43
|
+
parameters += condition
|
44
|
+
else
|
45
|
+
raise "Unable to parse condition: #{condition.inspect}" if condition
|
46
|
+
end
|
47
|
+
|
48
|
+
if (current_index += 1) == last_index
|
49
|
+
sql << ')'
|
50
|
+
else
|
51
|
+
sql << ') AND ('
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
parameters.unshift(sql)
|
57
|
+
end
|
58
|
+
|
59
|
+
def parse_conditions(conditions_hash)
|
60
|
+
collection = []
|
61
|
+
|
62
|
+
case x = conditions_hash.delete(:conditions)
|
63
|
+
when Array then
|
64
|
+
# DO NOT mutate incoming Array values!!!
|
65
|
+
# Otherwise the mutated version may impact all the
|
66
|
+
# way up to the options passed to the finders,
|
67
|
+
# and have unintended side-effects.
|
68
|
+
array_copy = x.dup
|
69
|
+
clause = array_copy.shift
|
70
|
+
expression_to_sql(clause, array_copy, collection)
|
71
|
+
when Hash then
|
72
|
+
x.each_pair do |key,value|
|
73
|
+
expression_to_sql(key, value, collection)
|
74
|
+
end
|
75
|
+
else
|
76
|
+
raise "Unable to parse conditions: #{x.inspect}" if x
|
77
|
+
end
|
78
|
+
|
79
|
+
if @table.paranoid?
|
80
|
+
conditions_hash[@table.paranoid_column.name] = nil
|
81
|
+
end
|
82
|
+
|
83
|
+
conditions_hash.each_pair do |key,value|
|
84
|
+
expression_to_sql(key, value, collection)
|
85
|
+
end
|
86
|
+
|
87
|
+
collection
|
88
|
+
end
|
89
|
+
|
90
|
+
# expression_to_sql takes a set of arguments, and turns them into a an
|
91
|
+
# Array of generated SQL, followed by optional Values to interpolate as SQL-Parameters.
|
92
|
+
#
|
93
|
+
# Parameters:
|
94
|
+
# +clause+ The name of the column as a Symbol, a raw-SQL String, a Mappings::Column
|
95
|
+
# instance, or a Symbol::Operator.
|
96
|
+
# +value+ The Value for the condition.
|
97
|
+
# +collector+ An Array representing all conditions that is appended to by expression_to_sql
|
98
|
+
#
|
99
|
+
# Returns: Undefined Output. The work performed is added to the +collector+ argument.
|
100
|
+
# Example:
|
101
|
+
# conditions = []
|
102
|
+
# expression_to_sql(:name, 'Bob', conditions)
|
103
|
+
# => +undefined return value+
|
104
|
+
# conditions.inspect
|
105
|
+
# => ["name = ?", 'Bob']
|
106
|
+
def expression_to_sql(clause, value, collector)
|
107
|
+
case clause
|
108
|
+
when Symbol::Operator then
|
109
|
+
operator = case clause.type
|
110
|
+
when :gt then '>'
|
111
|
+
when :gte then '>='
|
112
|
+
when :lt then '<'
|
113
|
+
when :lte then '<='
|
114
|
+
when :not then inequality_operator(value)
|
115
|
+
when :eql then equality_operator(value)
|
116
|
+
when :like then equality_operator(value, 'LIKE')
|
117
|
+
when :in then equality_operator(value)
|
118
|
+
else raise ArgumentError.new('Operator type not supported')
|
119
|
+
end
|
120
|
+
#Table[column name] is column.to_sql(true/false based on associations or not)
|
121
|
+
collector << ["#{@table[clause].to_sql(@qualify_columns)} #{operator} ?", value]
|
122
|
+
when Symbol then
|
123
|
+
collector << ["#{@table[clause].to_sql(@qualify_columns)} #{equality_operator(value)} ?", value]
|
124
|
+
when String then
|
125
|
+
collector << [clause, *value]
|
126
|
+
when Mappings::Column then
|
127
|
+
collector << ["#{clause.to_sql(@qualify_columns)} #{equality_operator(value)} ?", value]
|
128
|
+
else raise "CAN HAS CRASH? #{clause.inspect}"
|
129
|
+
end
|
130
|
+
rescue => e
|
131
|
+
raise ConditionsError.new(clause, value, e)
|
132
|
+
end
|
133
|
+
|
134
|
+
def equality_operator(value, default = '=')
|
135
|
+
case value
|
136
|
+
when NilClass then 'IS'
|
137
|
+
when Array then 'IN'
|
138
|
+
else default
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def inequality_operator(value, default = '<>')
|
143
|
+
case value
|
144
|
+
when NilClass then 'IS NOT'
|
145
|
+
when Array then 'NOT IN'
|
146
|
+
else default
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
class ConditionsError < StandardError
|
151
|
+
|
152
|
+
attr_reader :inner_error
|
153
|
+
|
154
|
+
def initialize(clause, value, inner_error)
|
155
|
+
@clause, @value, @inner_error = clause, value, inner_error
|
156
|
+
end
|
157
|
+
|
158
|
+
def message
|
159
|
+
"Conditions (:clause => #{@clause.inspect}, :value => #{@value.inspect}) failed: #{@inner_error}"
|
160
|
+
end
|
161
|
+
|
162
|
+
def backtrace
|
163
|
+
@inner_error.backtrace
|
164
|
+
end
|
165
|
+
|
166
|
+
end
|
167
|
+
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/column'
|
2
|
+
require File.dirname(__FILE__) + '/conditions'
|
2
3
|
require File.dirname(__FILE__) + '/associations_set'
|
3
4
|
|
4
5
|
module DataMapper
|
@@ -45,6 +46,10 @@ module DataMapper
|
|
45
46
|
@schema || @schema = @adapter.schema
|
46
47
|
end
|
47
48
|
|
49
|
+
def conditions(args)
|
50
|
+
Conditions.new(self, @adapter, @associations.empty?, args)
|
51
|
+
end
|
52
|
+
|
48
53
|
def paranoid?
|
49
54
|
@paranoid
|
50
55
|
end
|
@@ -73,6 +78,12 @@ module DataMapper
|
|
73
78
|
@associations
|
74
79
|
end
|
75
80
|
|
81
|
+
def activate_associations!(force = false)
|
82
|
+
@associations.each do |association|
|
83
|
+
association.activate! force
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
76
87
|
def reflect_columns
|
77
88
|
@adapter.reflect_columns(self)
|
78
89
|
end
|
@@ -85,6 +96,11 @@ module DataMapper
|
|
85
96
|
|
86
97
|
self.columns
|
87
98
|
end
|
99
|
+
|
100
|
+
def mapped_column_exists?(column_name)
|
101
|
+
@columns.each {|column| return true if column.name == column_name}
|
102
|
+
false
|
103
|
+
end
|
88
104
|
|
89
105
|
def exists?
|
90
106
|
@adapter.connection do |db|
|
@@ -136,19 +152,22 @@ module DataMapper
|
|
136
152
|
|
137
153
|
def truncate!
|
138
154
|
@adapter.connection do |db|
|
139
|
-
result = db.create_command(
|
155
|
+
result = db.create_command(to_truncate_sql).execute_non_query
|
140
156
|
database.identity_map.clear!(name)
|
141
157
|
result.to_i > 0
|
142
158
|
end
|
143
159
|
end
|
144
160
|
|
145
|
-
def count(
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
161
|
+
def count(args={})
|
162
|
+
sql = "SELECT COUNT(*) AS row_count FROM #{to_sql}"
|
163
|
+
parameters = []
|
164
|
+
|
165
|
+
paramsql, *parameters = conditions(args).to_params_sql
|
166
|
+
sql << paramsql #gotta shift it in
|
167
|
+
|
168
|
+
@adapter.connection do |db|
|
150
169
|
command = db.create_command(sql)
|
151
|
-
command.execute_reader do |reader|
|
170
|
+
command.execute_reader(*parameters) do |reader|
|
152
171
|
if reader.has_rows?
|
153
172
|
reader.current_row.first.to_i
|
154
173
|
else
|
@@ -175,13 +194,17 @@ module DataMapper
|
|
175
194
|
end
|
176
195
|
end
|
177
196
|
|
178
|
-
def key
|
197
|
+
def key
|
179
198
|
@key || begin
|
180
199
|
@key = @columns.find { |column| column.key? }
|
181
200
|
|
182
201
|
if @key.nil?
|
183
|
-
@
|
184
|
-
|
202
|
+
unless @klass.nil?
|
203
|
+
@klass.send(:property, :id, :integer, :serial => true, :ordinal => -1)
|
204
|
+
@key = self[:id]
|
205
|
+
else
|
206
|
+
@key = add_column(:id, :integer, :serial => true, :ordinal => -1)
|
207
|
+
end
|
185
208
|
end
|
186
209
|
|
187
210
|
@key
|
@@ -269,13 +292,13 @@ module DataMapper
|
|
269
292
|
@custom_name = value
|
270
293
|
self.name
|
271
294
|
end
|
272
|
-
|
295
|
+
|
273
296
|
def default_foreign_key
|
274
|
-
@default_foreign_key
|
297
|
+
@default_foreign_key ||= Inflector.foreign_key(@klass_or_name, key.name).freeze
|
275
298
|
end
|
276
299
|
|
277
300
|
def to_sql
|
278
|
-
@to_sql
|
301
|
+
@to_sql ||= quote_table.freeze
|
279
302
|
end
|
280
303
|
|
281
304
|
def to_s
|
@@ -343,6 +366,10 @@ module DataMapper
|
|
343
366
|
queries
|
344
367
|
end
|
345
368
|
|
369
|
+
def to_truncate_sql
|
370
|
+
"TRUNCATE TABLE #{to_sql}"
|
371
|
+
end
|
372
|
+
|
346
373
|
def to_drop_sql
|
347
374
|
@to_drop_sql || @to_drop_sql = "DROP TABLE #{to_sql}"
|
348
375
|
end
|
@@ -399,6 +426,7 @@ module DataMapper
|
|
399
426
|
@to_drop_sql = nil
|
400
427
|
@to_sql = nil
|
401
428
|
@name = nil
|
429
|
+
@columns_hash.clear
|
402
430
|
|
403
431
|
if flush_columns
|
404
432
|
@columns.each do |column|
|
@@ -411,9 +439,7 @@ module DataMapper
|
|
411
439
|
|
412
440
|
def activate!
|
413
441
|
@activated = true
|
414
|
-
|
415
|
-
association.activate!
|
416
|
-
end
|
442
|
+
activate_associations!
|
417
443
|
end
|
418
444
|
|
419
445
|
def activated?
|
@@ -430,4 +456,4 @@ module DataMapper
|
|
430
456
|
end
|
431
457
|
end
|
432
458
|
end
|
433
|
-
end
|
459
|
+
end
|