square-activerecord 3.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. data/CHANGELOG +6140 -0
  2. data/README.rdoc +222 -0
  3. data/examples/associations.png +0 -0
  4. data/examples/performance.rb +179 -0
  5. data/examples/simple.rb +14 -0
  6. data/lib/active_record.rb +124 -0
  7. data/lib/active_record/aggregations.rb +277 -0
  8. data/lib/active_record/association_preload.rb +430 -0
  9. data/lib/active_record/associations.rb +2307 -0
  10. data/lib/active_record/associations/association_collection.rb +572 -0
  11. data/lib/active_record/associations/association_proxy.rb +299 -0
  12. data/lib/active_record/associations/belongs_to_association.rb +91 -0
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +82 -0
  14. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +143 -0
  15. data/lib/active_record/associations/has_many_association.rb +128 -0
  16. data/lib/active_record/associations/has_many_through_association.rb +115 -0
  17. data/lib/active_record/associations/has_one_association.rb +143 -0
  18. data/lib/active_record/associations/has_one_through_association.rb +40 -0
  19. data/lib/active_record/associations/through_association_scope.rb +154 -0
  20. data/lib/active_record/attribute_methods.rb +60 -0
  21. data/lib/active_record/attribute_methods/before_type_cast.rb +30 -0
  22. data/lib/active_record/attribute_methods/dirty.rb +95 -0
  23. data/lib/active_record/attribute_methods/primary_key.rb +56 -0
  24. data/lib/active_record/attribute_methods/query.rb +39 -0
  25. data/lib/active_record/attribute_methods/read.rb +145 -0
  26. data/lib/active_record/attribute_methods/time_zone_conversion.rb +64 -0
  27. data/lib/active_record/attribute_methods/write.rb +43 -0
  28. data/lib/active_record/autosave_association.rb +369 -0
  29. data/lib/active_record/base.rb +1904 -0
  30. data/lib/active_record/callbacks.rb +284 -0
  31. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +364 -0
  32. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +113 -0
  33. data/lib/active_record/connection_adapters/abstract/database_limits.rb +57 -0
  34. data/lib/active_record/connection_adapters/abstract/database_statements.rb +333 -0
  35. data/lib/active_record/connection_adapters/abstract/query_cache.rb +81 -0
  36. data/lib/active_record/connection_adapters/abstract/quoting.rb +73 -0
  37. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +739 -0
  38. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +539 -0
  39. data/lib/active_record/connection_adapters/abstract_adapter.rb +217 -0
  40. data/lib/active_record/connection_adapters/mysql_adapter.rb +657 -0
  41. data/lib/active_record/connection_adapters/postgresql_adapter.rb +1031 -0
  42. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -0
  43. data/lib/active_record/connection_adapters/sqlite_adapter.rb +401 -0
  44. data/lib/active_record/counter_cache.rb +115 -0
  45. data/lib/active_record/dynamic_finder_match.rb +56 -0
  46. data/lib/active_record/dynamic_scope_match.rb +23 -0
  47. data/lib/active_record/errors.rb +172 -0
  48. data/lib/active_record/fixtures.rb +1006 -0
  49. data/lib/active_record/locale/en.yml +40 -0
  50. data/lib/active_record/locking/optimistic.rb +172 -0
  51. data/lib/active_record/locking/pessimistic.rb +55 -0
  52. data/lib/active_record/log_subscriber.rb +48 -0
  53. data/lib/active_record/migration.rb +617 -0
  54. data/lib/active_record/named_scope.rb +138 -0
  55. data/lib/active_record/nested_attributes.rb +419 -0
  56. data/lib/active_record/observer.rb +125 -0
  57. data/lib/active_record/persistence.rb +290 -0
  58. data/lib/active_record/query_cache.rb +36 -0
  59. data/lib/active_record/railtie.rb +91 -0
  60. data/lib/active_record/railties/controller_runtime.rb +38 -0
  61. data/lib/active_record/railties/databases.rake +512 -0
  62. data/lib/active_record/reflection.rb +411 -0
  63. data/lib/active_record/relation.rb +394 -0
  64. data/lib/active_record/relation/batches.rb +89 -0
  65. data/lib/active_record/relation/calculations.rb +295 -0
  66. data/lib/active_record/relation/finder_methods.rb +363 -0
  67. data/lib/active_record/relation/predicate_builder.rb +48 -0
  68. data/lib/active_record/relation/query_methods.rb +303 -0
  69. data/lib/active_record/relation/spawn_methods.rb +132 -0
  70. data/lib/active_record/schema.rb +59 -0
  71. data/lib/active_record/schema_dumper.rb +195 -0
  72. data/lib/active_record/serialization.rb +60 -0
  73. data/lib/active_record/serializers/xml_serializer.rb +244 -0
  74. data/lib/active_record/session_store.rb +340 -0
  75. data/lib/active_record/test_case.rb +67 -0
  76. data/lib/active_record/timestamp.rb +88 -0
  77. data/lib/active_record/transactions.rb +359 -0
  78. data/lib/active_record/validations.rb +84 -0
  79. data/lib/active_record/validations/associated.rb +48 -0
  80. data/lib/active_record/validations/uniqueness.rb +190 -0
  81. data/lib/active_record/version.rb +10 -0
  82. data/lib/rails/generators/active_record.rb +19 -0
  83. data/lib/rails/generators/active_record/migration.rb +15 -0
  84. data/lib/rails/generators/active_record/migration/migration_generator.rb +25 -0
  85. data/lib/rails/generators/active_record/migration/templates/migration.rb +17 -0
  86. data/lib/rails/generators/active_record/model/model_generator.rb +38 -0
  87. data/lib/rails/generators/active_record/model/templates/migration.rb +16 -0
  88. data/lib/rails/generators/active_record/model/templates/model.rb +5 -0
  89. data/lib/rails/generators/active_record/model/templates/module.rb +5 -0
  90. data/lib/rails/generators/active_record/observer/observer_generator.rb +15 -0
  91. data/lib/rails/generators/active_record/observer/templates/observer.rb +2 -0
  92. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +24 -0
  93. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +16 -0
  94. metadata +223 -0
@@ -0,0 +1,113 @@
1
+ module ActiveRecord
2
+ class Base
3
+ class ConnectionSpecification #:nodoc:
4
+ attr_reader :config, :adapter_method
5
+ def initialize (config, adapter_method)
6
+ @config, @adapter_method = config, adapter_method
7
+ end
8
+ end
9
+
10
+ ##
11
+ # :singleton-method:
12
+ # The connection handler
13
+ class_attribute :connection_handler, :instance_writer => false
14
+ self.connection_handler = ConnectionAdapters::ConnectionHandler.new
15
+
16
+ # Returns the connection currently associated with the class. This can
17
+ # also be used to "borrow" the connection to do database work that isn't
18
+ # easily done without going straight to SQL.
19
+ def connection
20
+ self.class.connection
21
+ end
22
+
23
+ # Establishes the connection to the database. Accepts a hash as input where
24
+ # the <tt>:adapter</tt> key must be specified with the name of a database adapter (in lower-case)
25
+ # example for regular databases (MySQL, Postgresql, etc):
26
+ #
27
+ # ActiveRecord::Base.establish_connection(
28
+ # :adapter => "mysql",
29
+ # :host => "localhost",
30
+ # :username => "myuser",
31
+ # :password => "mypass",
32
+ # :database => "somedatabase"
33
+ # )
34
+ #
35
+ # Example for SQLite database:
36
+ #
37
+ # ActiveRecord::Base.establish_connection(
38
+ # :adapter => "sqlite",
39
+ # :database => "path/to/dbfile"
40
+ # )
41
+ #
42
+ # Also accepts keys as strings (for parsing from YAML for example):
43
+ #
44
+ # ActiveRecord::Base.establish_connection(
45
+ # "adapter" => "sqlite",
46
+ # "database" => "path/to/dbfile"
47
+ # )
48
+ #
49
+ # The exceptions AdapterNotSpecified, AdapterNotFound and ArgumentError
50
+ # may be returned on an error.
51
+ def self.establish_connection(spec = nil)
52
+ case spec
53
+ when nil
54
+ raise AdapterNotSpecified unless defined?(Rails.env)
55
+ establish_connection(Rails.env)
56
+ when ConnectionSpecification
57
+ self.connection_handler.establish_connection(name, spec)
58
+ when Symbol, String
59
+ if configuration = configurations[spec.to_s]
60
+ establish_connection(configuration)
61
+ else
62
+ raise AdapterNotSpecified, "#{spec} database is not configured"
63
+ end
64
+ else
65
+ spec = spec.symbolize_keys
66
+ unless spec.key?(:adapter) then raise AdapterNotSpecified, "database configuration does not specify adapter" end
67
+
68
+ begin
69
+ require "active_record/connection_adapters/#{spec[:adapter]}_adapter"
70
+ rescue LoadError => e
71
+ raise "Please install the #{spec[:adapter]} adapter: `gem install activerecord-#{spec[:adapter]}-adapter` (#{e})"
72
+ end
73
+
74
+ adapter_method = "#{spec[:adapter]}_connection"
75
+ if !respond_to?(adapter_method)
76
+ raise AdapterNotFound, "database configuration specifies nonexistent #{spec[:adapter]} adapter"
77
+ end
78
+
79
+ remove_connection
80
+ establish_connection(ConnectionSpecification.new(spec, adapter_method))
81
+ end
82
+ end
83
+
84
+ class << self
85
+ # Returns the connection currently associated with the class. This can
86
+ # also be used to "borrow" the connection to do database work unrelated
87
+ # to any of the specific Active Records.
88
+ def connection
89
+ retrieve_connection
90
+ end
91
+
92
+ def connection_pool
93
+ connection_handler.retrieve_connection_pool(self)
94
+ end
95
+
96
+ def retrieve_connection
97
+ connection_handler.retrieve_connection(self)
98
+ end
99
+
100
+ # Returns true if Active Record is connected.
101
+ def connected?
102
+ connection_handler.connected?(self)
103
+ end
104
+
105
+ def remove_connection(klass = self)
106
+ connection_handler.remove_connection(klass)
107
+ end
108
+
109
+ delegate :clear_active_connections!, :clear_reloadable_connections!,
110
+ :clear_all_connections!,:verify_active_connections!, :to => :connection_handler
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,57 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters # :nodoc:
3
+ module DatabaseLimits
4
+
5
+ # the maximum length of a table alias
6
+ def table_alias_length
7
+ 255
8
+ end
9
+
10
+ # the maximum length of a column name
11
+ def column_name_length
12
+ 64
13
+ end
14
+
15
+ # the maximum length of a table name
16
+ def table_name_length
17
+ 64
18
+ end
19
+
20
+ # the maximum length of an index name
21
+ def index_name_length
22
+ 64
23
+ end
24
+
25
+ # the maximum number of columns per table
26
+ def columns_per_table
27
+ 1024
28
+ end
29
+
30
+ # the maximum number of indexes per table
31
+ def indexes_per_table
32
+ 16
33
+ end
34
+
35
+ # the maximum number of columns in a multicolumn index
36
+ def columns_per_multicolumn_index
37
+ 16
38
+ end
39
+
40
+ # the maximum number of elements in an IN (x,y,z) clause
41
+ def in_clause_length
42
+ 65535
43
+ end
44
+
45
+ # the maximum length of an SQL query
46
+ def sql_query_length
47
+ 1048575
48
+ end
49
+
50
+ # maximum number of joins in a single query
51
+ def joins_per_query
52
+ 256
53
+ end
54
+
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,333 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters # :nodoc:
3
+ module DatabaseStatements
4
+ # Returns an array of record hashes with the column names as keys and
5
+ # column values as values.
6
+ def select_all(sql, name = nil)
7
+ select(sql, name)
8
+ end
9
+
10
+ # Returns a record hash with the column names as keys and column values
11
+ # as values.
12
+ def select_one(sql, name = nil)
13
+ result = select_all(sql, name)
14
+ result.first if result
15
+ end
16
+
17
+ # Returns a single value from a record
18
+ def select_value(sql, name = nil)
19
+ if result = select_one(sql, name)
20
+ result.values.first
21
+ end
22
+ end
23
+
24
+ # Returns an array of the values of the first column in a select:
25
+ # select_values("SELECT id FROM companies LIMIT 3") => [1,2,3]
26
+ def select_values(sql, name = nil)
27
+ result = select_rows(sql, name)
28
+ result.map { |v| v[0] }
29
+ end
30
+
31
+ # Returns an array of arrays containing the field values.
32
+ # Order is the same as that returned by +columns+.
33
+ def select_rows(sql, name = nil)
34
+ end
35
+ undef_method :select_rows
36
+
37
+ # Executes the SQL statement in the context of this connection.
38
+ def execute(sql, name = nil, skip_logging = false)
39
+ end
40
+ undef_method :execute
41
+
42
+ # Returns the last auto-generated ID from the affected table.
43
+ def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
44
+ insert_sql(sql, name, pk, id_value, sequence_name)
45
+ end
46
+
47
+ # Executes the update statement and returns the number of rows affected.
48
+ def update(sql, name = nil)
49
+ update_sql(sql, name)
50
+ end
51
+
52
+ # Executes the delete statement and returns the number of rows affected.
53
+ def delete(sql, name = nil)
54
+ delete_sql(sql, name)
55
+ end
56
+
57
+ # Checks whether there is currently no transaction active. This is done
58
+ # by querying the database driver, and does not use the transaction
59
+ # house-keeping information recorded by #increment_open_transactions and
60
+ # friends.
61
+ #
62
+ # Returns true if there is no transaction active, false if there is a
63
+ # transaction active, and nil if this information is unknown.
64
+ #
65
+ # Not all adapters supports transaction state introspection. Currently,
66
+ # only the PostgreSQL adapter supports this.
67
+ def outside_transaction?
68
+ nil
69
+ end
70
+
71
+ # Runs the given block in a database transaction, and returns the result
72
+ # of the block.
73
+ #
74
+ # == Nested transactions support
75
+ #
76
+ # Most databases don't support true nested transactions. At the time of
77
+ # writing, the only database that supports true nested transactions that
78
+ # we're aware of, is MS-SQL.
79
+ #
80
+ # In order to get around this problem, #transaction will emulate the effect
81
+ # of nested transactions, by using savepoints:
82
+ # http://dev.mysql.com/doc/refman/5.0/en/savepoints.html
83
+ # Savepoints are supported by MySQL and PostgreSQL, but not SQLite3.
84
+ #
85
+ # It is safe to call this method if a database transaction is already open,
86
+ # i.e. if #transaction is called within another #transaction block. In case
87
+ # of a nested call, #transaction will behave as follows:
88
+ #
89
+ # - The block will be run without doing anything. All database statements
90
+ # that happen within the block are effectively appended to the already
91
+ # open database transaction.
92
+ # - However, if +:requires_new+ is set, the block will be wrapped in a
93
+ # database savepoint acting as a sub-transaction.
94
+ #
95
+ # === Caveats
96
+ #
97
+ # MySQL doesn't support DDL transactions. If you perform a DDL operation,
98
+ # then any created savepoints will be automatically released. For example,
99
+ # if you've created a savepoint, then you execute a CREATE TABLE statement,
100
+ # then the savepoint that was created will be automatically released.
101
+ #
102
+ # This means that, on MySQL, you shouldn't execute DDL operations inside
103
+ # a #transaction call that you know might create a savepoint. Otherwise,
104
+ # #transaction will raise exceptions when it tries to release the
105
+ # already-automatically-released savepoints:
106
+ #
107
+ # Model.connection.transaction do # BEGIN
108
+ # Model.connection.transaction(:requires_new => true) do # CREATE SAVEPOINT active_record_1
109
+ # Model.connection.create_table(...)
110
+ # # active_record_1 now automatically released
111
+ # end # RELEASE SAVEPOINT active_record_1 <--- BOOM! database error!
112
+ # end
113
+ def transaction(options = {})
114
+ options.assert_valid_keys :requires_new, :joinable
115
+
116
+ last_transaction_joinable = defined?(@transaction_joinable) ? @transaction_joinable : nil
117
+ if options.has_key?(:joinable)
118
+ @transaction_joinable = options[:joinable]
119
+ else
120
+ @transaction_joinable = true
121
+ end
122
+ requires_new = options[:requires_new] || !last_transaction_joinable
123
+
124
+ transaction_open = false
125
+ @_current_transaction_records ||= []
126
+
127
+ begin
128
+ if block_given?
129
+ if requires_new || open_transactions == 0
130
+ if open_transactions == 0
131
+ begin_db_transaction
132
+ elsif requires_new
133
+ create_savepoint
134
+ end
135
+ increment_open_transactions
136
+ transaction_open = true
137
+ @_current_transaction_records.push([])
138
+ end
139
+ yield
140
+ end
141
+ rescue Exception => database_transaction_rollback
142
+ if transaction_open && !outside_transaction?
143
+ transaction_open = false
144
+ decrement_open_transactions
145
+ if open_transactions == 0
146
+ rollback_db_transaction
147
+ rollback_transaction_records(true)
148
+ else
149
+ rollback_to_savepoint
150
+ rollback_transaction_records(false)
151
+ end
152
+ end
153
+ raise unless database_transaction_rollback.is_a?(ActiveRecord::Rollback)
154
+ end
155
+ ensure
156
+ @transaction_joinable = last_transaction_joinable
157
+
158
+ if outside_transaction?
159
+ @open_transactions = 0
160
+ elsif transaction_open
161
+ decrement_open_transactions
162
+ begin
163
+ if open_transactions == 0
164
+ commit_db_transaction
165
+ commit_transaction_records
166
+ else
167
+ release_savepoint
168
+ save_point_records = @_current_transaction_records.pop
169
+ unless save_point_records.blank?
170
+ @_current_transaction_records.push([]) if @_current_transaction_records.empty?
171
+ @_current_transaction_records.last.concat(save_point_records)
172
+ end
173
+ end
174
+ rescue Exception => database_transaction_rollback
175
+ if open_transactions == 0
176
+ rollback_db_transaction
177
+ rollback_transaction_records(true)
178
+ else
179
+ rollback_to_savepoint
180
+ rollback_transaction_records(false)
181
+ end
182
+ raise
183
+ end
184
+ end
185
+ end
186
+
187
+ # Register a record with the current transaction so that its after_commit and after_rollback callbacks
188
+ # can be called.
189
+ def add_transaction_record(record)
190
+ last_batch = @_current_transaction_records.last
191
+ last_batch << record if last_batch
192
+ end
193
+
194
+ # Begins the transaction (and turns off auto-committing).
195
+ def begin_db_transaction() end
196
+
197
+ # Commits the transaction (and turns on auto-committing).
198
+ def commit_db_transaction() end
199
+
200
+ # Rolls back the transaction (and turns on auto-committing). Must be
201
+ # done if the transaction block raises an exception or returns false.
202
+ def rollback_db_transaction() end
203
+
204
+ # Appends +LIMIT+ and +OFFSET+ options to an SQL statement, or some SQL
205
+ # fragment that has the same semantics as LIMIT and OFFSET.
206
+ #
207
+ # +options+ must be a Hash which contains a +:limit+ option
208
+ # and an +:offset+ option.
209
+ #
210
+ # This method *modifies* the +sql+ parameter.
211
+ #
212
+ # ===== Examples
213
+ # add_limit_offset!('SELECT * FROM suppliers', {:limit => 10, :offset => 50})
214
+ # generates
215
+ # SELECT * FROM suppliers LIMIT 10 OFFSET 50
216
+
217
+ def add_limit_offset!(sql, options)
218
+ if limit = options[:limit]
219
+ sql << " LIMIT #{sanitize_limit(limit)}"
220
+ end
221
+ if offset = options[:offset]
222
+ sql << " OFFSET #{offset.to_i}"
223
+ end
224
+ sql
225
+ end
226
+
227
+ def default_sequence_name(table, column)
228
+ nil
229
+ end
230
+
231
+ # Set the sequence to the max value of the table's column.
232
+ def reset_sequence!(table, column, sequence = nil)
233
+ # Do nothing by default. Implement for PostgreSQL, Oracle, ...
234
+ end
235
+
236
+ # Inserts the given fixture into the table. Overridden in adapters that require
237
+ # something beyond a simple insert (eg. Oracle).
238
+ def insert_fixture(fixture, table_name)
239
+ execute "INSERT INTO #{quote_table_name(table_name)} (#{fixture.key_list}) VALUES (#{fixture.value_list})", 'Fixture Insert'
240
+ end
241
+
242
+ def empty_insert_statement_value
243
+ "VALUES(DEFAULT)"
244
+ end
245
+
246
+ def case_sensitive_equality_operator
247
+ "="
248
+ end
249
+
250
+ def limited_update_conditions(where_sql, quoted_table_name, quoted_primary_key)
251
+ "WHERE #{quoted_primary_key} IN (SELECT #{quoted_primary_key} FROM #{quoted_table_name} #{where_sql})"
252
+ end
253
+
254
+ # Sanitizes the given LIMIT parameter in order to prevent SQL injection.
255
+ #
256
+ # The +limit+ may be anything that can evaluate to a string via #to_s. It
257
+ # should look like an integer, or a comma-delimited list of integers, or
258
+ # an Arel SQL literal.
259
+ #
260
+ # Returns Integer and Arel::Nodes::SqlLiteral limits as is.
261
+ # Returns the sanitized limit parameter, either as an integer, or as a
262
+ # string which contains a comma-delimited list of integers.
263
+ def sanitize_limit(limit)
264
+ if limit.is_a?(Integer) || limit.is_a?(Arel::Nodes::SqlLiteral)
265
+ limit
266
+ elsif limit.to_s =~ /,/
267
+ Arel.sql limit.to_s.split(',').map{ |i| Integer(i) }.join(',')
268
+ else
269
+ Integer(limit)
270
+ end
271
+ end
272
+
273
+ protected
274
+ # Returns an array of record hashes with the column names as keys and
275
+ # column values as values.
276
+ def select(sql, name = nil)
277
+ end
278
+ undef_method :select
279
+
280
+ # Returns the last auto-generated ID from the affected table.
281
+ def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
282
+ execute(sql, name)
283
+ id_value
284
+ end
285
+
286
+ # Executes the update statement and returns the number of rows affected.
287
+ def update_sql(sql, name = nil)
288
+ execute(sql, name)
289
+ end
290
+
291
+ # Executes the delete statement and returns the number of rows affected.
292
+ def delete_sql(sql, name = nil)
293
+ update_sql(sql, name)
294
+ end
295
+
296
+ # Send a rollback message to all records after they have been rolled back. If rollback
297
+ # is false, only rollback records since the last save point.
298
+ def rollback_transaction_records(rollback) #:nodoc
299
+ if rollback
300
+ records = @_current_transaction_records.flatten
301
+ @_current_transaction_records.clear
302
+ else
303
+ records = @_current_transaction_records.pop
304
+ end
305
+
306
+ unless records.blank?
307
+ records.uniq.each do |record|
308
+ begin
309
+ record.rolledback!(rollback)
310
+ rescue Exception => e
311
+ record.logger.error(e) if record.respond_to?(:logger) && record.logger
312
+ end
313
+ end
314
+ end
315
+ end
316
+
317
+ # Send a commit message to all records after they have been committed.
318
+ def commit_transaction_records #:nodoc
319
+ records = @_current_transaction_records.flatten
320
+ @_current_transaction_records.clear
321
+ unless records.blank?
322
+ records.uniq.each do |record|
323
+ begin
324
+ record.committed!
325
+ rescue Exception => e
326
+ record.logger.error(e) if record.respond_to?(:logger) && record.logger
327
+ end
328
+ end
329
+ end
330
+ end
331
+ end
332
+ end
333
+ end