activerecord 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- data/CHANGELOG +6023 -0
- data/README.rdoc +222 -0
- data/examples/associations.png +0 -0
- data/examples/performance.rb +162 -0
- data/examples/simple.rb +14 -0
- data/lib/active_record.rb +124 -0
- data/lib/active_record/aggregations.rb +277 -0
- data/lib/active_record/association_preload.rb +403 -0
- data/lib/active_record/associations.rb +2254 -0
- data/lib/active_record/associations/association_collection.rb +562 -0
- data/lib/active_record/associations/association_proxy.rb +295 -0
- data/lib/active_record/associations/belongs_to_association.rb +91 -0
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +78 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +137 -0
- data/lib/active_record/associations/has_many_association.rb +128 -0
- data/lib/active_record/associations/has_many_through_association.rb +116 -0
- data/lib/active_record/associations/has_one_association.rb +143 -0
- data/lib/active_record/associations/has_one_through_association.rb +40 -0
- data/lib/active_record/associations/through_association_scope.rb +154 -0
- data/lib/active_record/attribute_methods.rb +60 -0
- data/lib/active_record/attribute_methods/before_type_cast.rb +33 -0
- data/lib/active_record/attribute_methods/dirty.rb +95 -0
- data/lib/active_record/attribute_methods/primary_key.rb +50 -0
- data/lib/active_record/attribute_methods/query.rb +39 -0
- data/lib/active_record/attribute_methods/read.rb +116 -0
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +61 -0
- data/lib/active_record/attribute_methods/write.rb +37 -0
- data/lib/active_record/autosave_association.rb +369 -0
- data/lib/active_record/base.rb +1867 -0
- data/lib/active_record/callbacks.rb +288 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +365 -0
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +113 -0
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +57 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +329 -0
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +81 -0
- data/lib/active_record/connection_adapters/abstract/quoting.rb +72 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +739 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +543 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +212 -0
- data/lib/active_record/connection_adapters/mysql_adapter.rb +643 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +1030 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +53 -0
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +401 -0
- data/lib/active_record/counter_cache.rb +115 -0
- data/lib/active_record/dynamic_finder_match.rb +53 -0
- data/lib/active_record/dynamic_scope_match.rb +32 -0
- data/lib/active_record/errors.rb +172 -0
- data/lib/active_record/fixtures.rb +1008 -0
- data/lib/active_record/locale/en.yml +40 -0
- data/lib/active_record/locking/optimistic.rb +172 -0
- data/lib/active_record/locking/pessimistic.rb +55 -0
- data/lib/active_record/log_subscriber.rb +48 -0
- data/lib/active_record/migration.rb +617 -0
- data/lib/active_record/named_scope.rb +138 -0
- data/lib/active_record/nested_attributes.rb +417 -0
- data/lib/active_record/observer.rb +140 -0
- data/lib/active_record/persistence.rb +291 -0
- data/lib/active_record/query_cache.rb +36 -0
- data/lib/active_record/railtie.rb +91 -0
- data/lib/active_record/railties/controller_runtime.rb +38 -0
- data/lib/active_record/railties/databases.rake +512 -0
- data/lib/active_record/reflection.rb +403 -0
- data/lib/active_record/relation.rb +393 -0
- data/lib/active_record/relation/batches.rb +89 -0
- data/lib/active_record/relation/calculations.rb +286 -0
- data/lib/active_record/relation/finder_methods.rb +355 -0
- data/lib/active_record/relation/predicate_builder.rb +41 -0
- data/lib/active_record/relation/query_methods.rb +261 -0
- data/lib/active_record/relation/spawn_methods.rb +112 -0
- data/lib/active_record/schema.rb +59 -0
- data/lib/active_record/schema_dumper.rb +195 -0
- data/lib/active_record/serialization.rb +60 -0
- data/lib/active_record/serializers/xml_serializer.rb +244 -0
- data/lib/active_record/session_store.rb +340 -0
- data/lib/active_record/test_case.rb +67 -0
- data/lib/active_record/timestamp.rb +88 -0
- data/lib/active_record/transactions.rb +356 -0
- data/lib/active_record/validations.rb +84 -0
- data/lib/active_record/validations/associated.rb +48 -0
- data/lib/active_record/validations/uniqueness.rb +185 -0
- data/lib/active_record/version.rb +9 -0
- data/lib/rails/generators/active_record.rb +27 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +25 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb +17 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +38 -0
- data/lib/rails/generators/active_record/model/templates/migration.rb +16 -0
- data/lib/rails/generators/active_record/model/templates/model.rb +5 -0
- data/lib/rails/generators/active_record/model/templates/module.rb +5 -0
- data/lib/rails/generators/active_record/observer/observer_generator.rb +15 -0
- data/lib/rails/generators/active_record/observer/templates/observer.rb +2 -0
- data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +24 -0
- data/lib/rails/generators/active_record/session_migration/templates/migration.rb +16 -0
- metadata +224 -0
@@ -0,0 +1,41 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
class PredicateBuilder
|
3
|
+
|
4
|
+
def initialize(engine)
|
5
|
+
@engine = engine
|
6
|
+
end
|
7
|
+
|
8
|
+
def build_from_hash(attributes, default_table)
|
9
|
+
predicates = attributes.map do |column, value|
|
10
|
+
table = default_table
|
11
|
+
|
12
|
+
if value.is_a?(Hash)
|
13
|
+
table = Arel::Table.new(column, :engine => @engine)
|
14
|
+
build_from_hash(value, table)
|
15
|
+
else
|
16
|
+
column = column.to_s
|
17
|
+
|
18
|
+
if column.include?('.')
|
19
|
+
table_name, column = column.split('.', 2)
|
20
|
+
table = Arel::Table.new(table_name, :engine => @engine)
|
21
|
+
end
|
22
|
+
|
23
|
+
attribute = table[column] || Arel::Attribute.new(table, column)
|
24
|
+
|
25
|
+
case value
|
26
|
+
when Array, ActiveRecord::Associations::AssociationCollection, ActiveRecord::Relation
|
27
|
+
values = value.to_a
|
28
|
+
attribute.in(values)
|
29
|
+
when Range, Arel::Relation
|
30
|
+
attribute.in(value)
|
31
|
+
else
|
32
|
+
attribute.eq(value)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
predicates.flatten
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,261 @@
|
|
1
|
+
require 'active_support/core_ext/array/wrap'
|
2
|
+
require 'active_support/core_ext/object/blank'
|
3
|
+
|
4
|
+
module ActiveRecord
|
5
|
+
module QueryMethods
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
attr_accessor :includes_values, :eager_load_values, :preload_values,
|
9
|
+
:select_values, :group_values, :order_values, :joins_values, :where_values, :having_values,
|
10
|
+
:limit_value, :offset_value, :lock_value, :readonly_value, :create_with_value, :from_value
|
11
|
+
|
12
|
+
def includes(*args)
|
13
|
+
args.reject! { |a| a.blank? }
|
14
|
+
clone.tap {|r| r.includes_values = (r.includes_values + args).flatten.uniq if args.present? }
|
15
|
+
end
|
16
|
+
|
17
|
+
def eager_load(*args)
|
18
|
+
clone.tap {|r| r.eager_load_values += args if args.present? }
|
19
|
+
end
|
20
|
+
|
21
|
+
def preload(*args)
|
22
|
+
clone.tap {|r| r.preload_values += args if args.present? }
|
23
|
+
end
|
24
|
+
|
25
|
+
def select(*args)
|
26
|
+
if block_given?
|
27
|
+
to_a.select {|*block_args| yield(*block_args) }
|
28
|
+
else
|
29
|
+
clone.tap {|r| r.select_values += args if args.present? }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def group(*args)
|
34
|
+
clone.tap {|r| r.group_values += args.flatten if args.present? }
|
35
|
+
end
|
36
|
+
|
37
|
+
def order(*args)
|
38
|
+
clone.tap {|r| r.order_values += args if args.present? }
|
39
|
+
end
|
40
|
+
|
41
|
+
def reorder(*args)
|
42
|
+
clone.tap {|r| r.order_values = args if args.present? }
|
43
|
+
end
|
44
|
+
|
45
|
+
def joins(*args)
|
46
|
+
args.flatten!
|
47
|
+
clone.tap {|r| r.joins_values += args if args.present? }
|
48
|
+
end
|
49
|
+
|
50
|
+
def where(opts, *rest)
|
51
|
+
value = build_where(opts, rest)
|
52
|
+
copy = clone
|
53
|
+
copy.where_values += Array.wrap(value) if value
|
54
|
+
copy
|
55
|
+
end
|
56
|
+
|
57
|
+
def having(*args)
|
58
|
+
value = build_where(*args)
|
59
|
+
clone.tap {|r| r.having_values += Array.wrap(value) if value.present? }
|
60
|
+
end
|
61
|
+
|
62
|
+
def limit(value = true)
|
63
|
+
copy = clone
|
64
|
+
copy.limit_value = value
|
65
|
+
copy
|
66
|
+
end
|
67
|
+
|
68
|
+
def offset(value = true)
|
69
|
+
clone.tap {|r| r.offset_value = value }
|
70
|
+
end
|
71
|
+
|
72
|
+
def lock(locks = true)
|
73
|
+
case locks
|
74
|
+
when String, TrueClass, NilClass
|
75
|
+
clone.tap {|r| r.lock_value = locks || true }
|
76
|
+
else
|
77
|
+
clone.tap {|r| r.lock_value = false }
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def readonly(value = true)
|
82
|
+
clone.tap {|r| r.readonly_value = value }
|
83
|
+
end
|
84
|
+
|
85
|
+
def create_with(value = true)
|
86
|
+
clone.tap {|r| r.create_with_value = value }
|
87
|
+
end
|
88
|
+
|
89
|
+
def from(value = true)
|
90
|
+
clone.tap {|r| r.from_value = value }
|
91
|
+
end
|
92
|
+
|
93
|
+
def extending(*modules, &block)
|
94
|
+
modules << Module.new(&block) if block_given?
|
95
|
+
clone.tap {|r| r.send(:apply_modules, *modules) }
|
96
|
+
end
|
97
|
+
|
98
|
+
def reverse_order
|
99
|
+
order_clause = arel.order_clauses.join(', ')
|
100
|
+
relation = except(:order)
|
101
|
+
|
102
|
+
order = order_clause.blank? ?
|
103
|
+
"#{@klass.table_name}.#{@klass.primary_key} DESC" :
|
104
|
+
reverse_sql_order(order_clause)
|
105
|
+
|
106
|
+
relation.order Arel::SqlLiteral.new order
|
107
|
+
end
|
108
|
+
|
109
|
+
def arel
|
110
|
+
@arel ||= build_arel
|
111
|
+
end
|
112
|
+
|
113
|
+
def custom_join_sql(*joins)
|
114
|
+
arel = table
|
115
|
+
joins.each do |join|
|
116
|
+
next if join.blank?
|
117
|
+
|
118
|
+
@implicit_readonly = true
|
119
|
+
|
120
|
+
case join
|
121
|
+
when Hash, Array, Symbol
|
122
|
+
if array_of_strings?(join)
|
123
|
+
join_string = join.join(' ')
|
124
|
+
arel = arel.join(Arel::SqlLiteral.new(join_string))
|
125
|
+
end
|
126
|
+
when String
|
127
|
+
arel = arel.join(Arel::SqlLiteral.new(join))
|
128
|
+
else
|
129
|
+
arel = arel.join(join)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
arel.joins(arel)
|
133
|
+
end
|
134
|
+
|
135
|
+
def build_arel
|
136
|
+
arel = table
|
137
|
+
|
138
|
+
arel = build_joins(arel, @joins_values) unless @joins_values.empty?
|
139
|
+
|
140
|
+
(@where_values - ['']).uniq.each do |where|
|
141
|
+
case where
|
142
|
+
when Arel::SqlLiteral
|
143
|
+
arel = arel.where(where)
|
144
|
+
else
|
145
|
+
sql = where.is_a?(String) ? where : where.to_sql
|
146
|
+
arel = arel.where(Arel::SqlLiteral.new("(#{sql})"))
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
arel = arel.having(*@having_values.uniq.select{|h| h.present?}) unless @having_values.empty?
|
151
|
+
|
152
|
+
arel = arel.take(@limit_value) if @limit_value
|
153
|
+
arel = arel.skip(@offset_value) if @offset_value
|
154
|
+
|
155
|
+
arel = arel.group(*@group_values.uniq.select{|g| g.present?}) unless @group_values.empty?
|
156
|
+
|
157
|
+
arel = arel.order(*@order_values.uniq.select{|o| o.present?}) unless @order_values.empty?
|
158
|
+
|
159
|
+
arel = build_select(arel, @select_values.uniq)
|
160
|
+
|
161
|
+
arel = arel.from(@from_value) if @from_value
|
162
|
+
arel = arel.lock(@lock_value) if @lock_value
|
163
|
+
|
164
|
+
arel
|
165
|
+
end
|
166
|
+
|
167
|
+
def build_where(opts, other = [])
|
168
|
+
case opts
|
169
|
+
when String, Array
|
170
|
+
@klass.send(:sanitize_sql, other.empty? ? opts : ([opts] + other))
|
171
|
+
when Hash
|
172
|
+
attributes = @klass.send(:expand_hash_conditions_for_aggregates, opts)
|
173
|
+
PredicateBuilder.new(table.engine).build_from_hash(attributes, table)
|
174
|
+
else
|
175
|
+
opts
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
private
|
180
|
+
|
181
|
+
def build_joins(relation, joins)
|
182
|
+
joined_associations = []
|
183
|
+
association_joins = []
|
184
|
+
|
185
|
+
joins = @joins_values.map {|j| j.respond_to?(:strip) ? j.strip : j}.uniq
|
186
|
+
|
187
|
+
joins.each do |join|
|
188
|
+
association_joins << join if [Hash, Array, Symbol].include?(join.class) && !array_of_strings?(join)
|
189
|
+
end
|
190
|
+
|
191
|
+
stashed_association_joins = joins.grep(ActiveRecord::Associations::ClassMethods::JoinDependency::JoinAssociation)
|
192
|
+
|
193
|
+
non_association_joins = (joins - association_joins - stashed_association_joins)
|
194
|
+
custom_joins = custom_join_sql(*non_association_joins)
|
195
|
+
|
196
|
+
join_dependency = ActiveRecord::Associations::ClassMethods::JoinDependency.new(@klass, association_joins, custom_joins)
|
197
|
+
|
198
|
+
join_dependency.graft(*stashed_association_joins)
|
199
|
+
|
200
|
+
@implicit_readonly = true unless association_joins.empty? && stashed_association_joins.empty?
|
201
|
+
|
202
|
+
to_join = []
|
203
|
+
|
204
|
+
join_dependency.join_associations.each do |association|
|
205
|
+
if (association_relation = association.relation).is_a?(Array)
|
206
|
+
to_join << [association_relation.first, association.join_class, association.association_join.first]
|
207
|
+
to_join << [association_relation.last, association.join_class, association.association_join.last]
|
208
|
+
else
|
209
|
+
to_join << [association_relation, association.join_class, association.association_join]
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
to_join.each do |tj|
|
214
|
+
unless joined_associations.detect {|ja| ja[0] == tj[0] && ja[1] == tj[1] && ja[2] == tj[2] }
|
215
|
+
joined_associations << tj
|
216
|
+
relation = relation.join(tj[0], tj[1]).on(*tj[2])
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
relation.join(custom_joins)
|
221
|
+
end
|
222
|
+
|
223
|
+
def build_select(arel, selects)
|
224
|
+
unless selects.empty?
|
225
|
+
@implicit_readonly = false
|
226
|
+
# TODO: fix this ugly hack, we should refactor the callers to get an ARel compatible array.
|
227
|
+
# Before this change we were passing to ARel the last element only, and ARel is capable of handling an array
|
228
|
+
if selects.all? {|s| s.is_a?(String) || !s.is_a?(Arel::Expression) } && !(selects.last =~ /^COUNT\(/)
|
229
|
+
arel.project(*selects)
|
230
|
+
else
|
231
|
+
arel.project(selects.last)
|
232
|
+
end
|
233
|
+
else
|
234
|
+
arel.project(Arel::SqlLiteral.new(@klass.quoted_table_name + '.*'))
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
def apply_modules(modules)
|
239
|
+
values = Array.wrap(modules)
|
240
|
+
@extensions += values if values.present?
|
241
|
+
values.each {|extension| extend(extension) }
|
242
|
+
end
|
243
|
+
|
244
|
+
def reverse_sql_order(order_query)
|
245
|
+
order_query.to_s.split(/,/).each { |s|
|
246
|
+
if s.match(/\s(asc|ASC)$/)
|
247
|
+
s.gsub!(/\s(asc|ASC)$/, ' DESC')
|
248
|
+
elsif s.match(/\s(desc|DESC)$/)
|
249
|
+
s.gsub!(/\s(desc|DESC)$/, ' ASC')
|
250
|
+
else
|
251
|
+
s.concat(' DESC')
|
252
|
+
end
|
253
|
+
}.join(',')
|
254
|
+
end
|
255
|
+
|
256
|
+
def array_of_strings?(o)
|
257
|
+
o.is_a?(Array) && o.all?{|obj| obj.is_a?(String)}
|
258
|
+
end
|
259
|
+
|
260
|
+
end
|
261
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'active_support/core_ext/object/blank'
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module SpawnMethods
|
5
|
+
def merge(r)
|
6
|
+
merged_relation = clone
|
7
|
+
return merged_relation unless r
|
8
|
+
|
9
|
+
((Relation::ASSOCIATION_METHODS + Relation::MULTI_VALUE_METHODS) - [:joins, :where]).each do |method|
|
10
|
+
value = r.send(:"#{method}_values")
|
11
|
+
unless value.empty?
|
12
|
+
if method == :includes
|
13
|
+
merged_relation = merged_relation.includes(value)
|
14
|
+
else
|
15
|
+
merged_relation.send(:"#{method}_values=", value)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
merged_relation = merged_relation.joins(r.joins_values)
|
21
|
+
|
22
|
+
merged_wheres = @where_values
|
23
|
+
|
24
|
+
r.where_values.each do |w|
|
25
|
+
if w.respond_to?(:operator) && w.operator == :==
|
26
|
+
merged_wheres = merged_wheres.reject { |p|
|
27
|
+
p.respond_to?(:operator) && p.operator == :== && p.operand1.name == w.operand1.name
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
merged_wheres += [w]
|
32
|
+
end
|
33
|
+
|
34
|
+
merged_relation.where_values = merged_wheres
|
35
|
+
|
36
|
+
Relation::SINGLE_VALUE_METHODS.reject {|m| m == :lock}.each do |method|
|
37
|
+
unless (value = r.send(:"#{method}_value")).nil?
|
38
|
+
merged_relation.send(:"#{method}_value=", value)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
merged_relation.lock_value = r.lock_value unless merged_relation.lock_value
|
43
|
+
|
44
|
+
# Apply scope extension modules
|
45
|
+
merged_relation.send :apply_modules, r.extensions
|
46
|
+
|
47
|
+
merged_relation
|
48
|
+
end
|
49
|
+
|
50
|
+
alias :& :merge
|
51
|
+
|
52
|
+
def except(*skips)
|
53
|
+
result = self.class.new(@klass, table)
|
54
|
+
|
55
|
+
(Relation::ASSOCIATION_METHODS + Relation::MULTI_VALUE_METHODS).each do |method|
|
56
|
+
result.send(:"#{method}_values=", send(:"#{method}_values")) unless skips.include?(method)
|
57
|
+
end
|
58
|
+
|
59
|
+
Relation::SINGLE_VALUE_METHODS.each do |method|
|
60
|
+
result.send(:"#{method}_value=", send(:"#{method}_value")) unless skips.include?(method)
|
61
|
+
end
|
62
|
+
|
63
|
+
result
|
64
|
+
end
|
65
|
+
|
66
|
+
def only(*onlies)
|
67
|
+
result = self.class.new(@klass, table)
|
68
|
+
|
69
|
+
onlies.each do |only|
|
70
|
+
if (Relation::ASSOCIATION_METHODS + Relation::MULTI_VALUE_METHODS).include?(only)
|
71
|
+
result.send(:"#{only}_values=", send(:"#{only}_values"))
|
72
|
+
elsif Relation::SINGLE_VALUE_METHODS.include?(only)
|
73
|
+
result.send(:"#{only}_value=", send(:"#{only}_value"))
|
74
|
+
else
|
75
|
+
raise "Invalid argument : #{only}"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
result
|
80
|
+
end
|
81
|
+
|
82
|
+
VALID_FIND_OPTIONS = [ :conditions, :include, :joins, :limit, :offset, :extend,
|
83
|
+
:order, :select, :readonly, :group, :having, :from, :lock ]
|
84
|
+
|
85
|
+
def apply_finder_options(options)
|
86
|
+
relation = clone
|
87
|
+
return relation unless options
|
88
|
+
|
89
|
+
options.assert_valid_keys(VALID_FIND_OPTIONS)
|
90
|
+
|
91
|
+
[:joins, :select, :group, :having, :limit, :offset, :from, :lock].each do |finder|
|
92
|
+
if value = options[finder]
|
93
|
+
relation = relation.send(finder, value)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
relation = relation.readonly(options[:readonly]) if options.key? :readonly
|
98
|
+
|
99
|
+
# Give precedence to newly-applied orders and groups to play nicely with with_scope
|
100
|
+
[:group, :order].each do |finder|
|
101
|
+
relation.send("#{finder}_values=", Array.wrap(options[finder]) + relation.send("#{finder}_values")) if options.has_key?(finder)
|
102
|
+
end
|
103
|
+
|
104
|
+
relation = relation.where(options[:conditions]) if options.has_key?(:conditions)
|
105
|
+
relation = relation.includes(options[:include]) if options.has_key?(:include)
|
106
|
+
relation = relation.extending(options[:extend]) if options.has_key?(:extend)
|
107
|
+
|
108
|
+
relation
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'active_support/core_ext/object/blank'
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
# = Active Record Schema
|
5
|
+
#
|
6
|
+
# Allows programmers to programmatically define a schema in a portable
|
7
|
+
# DSL. This means you can define tables, indexes, etc. without using SQL
|
8
|
+
# directly, so your applications can more easily support multiple
|
9
|
+
# databases.
|
10
|
+
#
|
11
|
+
# Usage:
|
12
|
+
#
|
13
|
+
# ActiveRecord::Schema.define do
|
14
|
+
# create_table :authors do |t|
|
15
|
+
# t.string :name, :null => false
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# add_index :authors, :name, :unique
|
19
|
+
#
|
20
|
+
# create_table :posts do |t|
|
21
|
+
# t.integer :author_id, :null => false
|
22
|
+
# t.string :subject
|
23
|
+
# t.text :body
|
24
|
+
# t.boolean :private, :default => false
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# add_index :posts, :author_id
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# ActiveRecord::Schema is only supported by database adapters that also
|
31
|
+
# support migrations, the two features being very similar.
|
32
|
+
class Schema < Migration
|
33
|
+
private_class_method :new
|
34
|
+
|
35
|
+
def self.migrations_path
|
36
|
+
ActiveRecord::Migrator.migrations_path
|
37
|
+
end
|
38
|
+
|
39
|
+
# Eval the given block. All methods available to the current connection
|
40
|
+
# adapter are available within the block, so you can easily use the
|
41
|
+
# database definition DSL to build up your schema (+create_table+,
|
42
|
+
# +add_index+, etc.).
|
43
|
+
#
|
44
|
+
# The +info+ hash is optional, and if given is used to define metadata
|
45
|
+
# about the current schema (currently, only the schema's version):
|
46
|
+
#
|
47
|
+
# ActiveRecord::Schema.define(:version => 20380119000001) do
|
48
|
+
# ...
|
49
|
+
# end
|
50
|
+
def self.define(info={}, &block)
|
51
|
+
instance_eval(&block)
|
52
|
+
|
53
|
+
unless info[:version].blank?
|
54
|
+
initialize_schema_migrations_table
|
55
|
+
assume_migrated_upto_version(info[:version], migrations_path)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|