Changeset 4078
- Timestamp:
- 03/28/06 03:06:40 (3 years ago)
- Files:
-
- trunk/activerecord/lib/active_record/associations.rb (modified) (4 diffs)
- trunk/activerecord/lib/active_record/base.rb (modified) (20 diffs)
- trunk/activerecord/lib/active_record/calculations.rb (modified) (2 diffs)
- trunk/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb (modified) (6 diffs)
- trunk/activerecord/lib/active_record/connection_adapters/oracle_adapter.rb (modified) (2 diffs)
- trunk/activerecord/lib/active_record/locking.rb (modified) (1 diff)
- trunk/activerecord/lib/active_record/validations.rb (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/activerecord/lib/active_record/associations.rb
r4069 r4078 10 10 11 11 module ActiveRecord 12 class HasManyThroughAssociationNotFoundError < ActiveRecordError 12 class HasManyThroughAssociationNotFoundError < ActiveRecordError #:nodoc: 13 13 def initialize(reflection) 14 14 @reflection = reflection … … 20 20 end 21 21 22 class HasManyThroughAssociationPolymorphicError < ActiveRecordError 22 class HasManyThroughAssociationPolymorphicError < ActiveRecordError #:nodoc: 23 23 def initialize(owner_class_name, reflection, source_reflection) 24 24 @owner_class_name = owner_class_name … … 32 32 end 33 33 34 class HasManyThroughSourceAssociationNotFoundError < ActiveRecordError 34 class HasManyThroughSourceAssociationNotFoundError < ActiveRecordError #:nodoc: 35 35 def initialize(reflection) 36 36 @reflection = reflection … … 45 45 end 46 46 47 class EagerLoadPolymorphicError < ActiveRecordError 47 class EagerLoadPolymorphicError < ActiveRecordError #:nodoc: 48 48 def initialize(reflection) 49 49 @reflection = reflection trunk/activerecord/lib/active_record/base.rb
r4076 r4078 254 254 end 255 255 256 def self.reset_subclasses 256 def self.reset_subclasses #:nodoc: 257 257 nonreloadables = [] 258 258 subclasses.each do |klass| … … 562 562 end 563 563 564 def reset_table_name 564 def reset_table_name #:nodoc: 565 565 name = "#{table_name_prefix}#{undecorated_table_name(base_class.name)}#{table_name_suffix}" 566 566 set_table_name(name) … … 574 574 end 575 575 576 def reset_primary_key 576 def reset_primary_key #:nodoc: 577 577 key = 'id' 578 578 case primary_key_prefix_type … … 593 593 # Lazy-set the sequence name to the connection's default. This method 594 594 # is only ever called once since set_sequence_name overrides it. 595 def sequence_name 595 def sequence_name #:nodoc: 596 596 reset_sequence_name 597 597 end 598 598 599 def reset_sequence_name 599 def reset_sequence_name #:nodoc: 600 600 default = connection.default_sequence_name(table_name, primary_key) 601 601 set_sequence_name(default) … … 705 705 end 706 706 707 # Returns an array of column names as strings. 707 708 def column_names 708 709 @column_names ||= columns.map { |column| column.name } … … 718 719 # and true as the value. This makes it possible to do O(1) lookups in respond_to? to check if a given method for attribute 719 720 # is available. 720 def column_methods_hash 721 def column_methods_hash #:nodoc: 721 722 @dynamic_methods_hash ||= column_names.inject(Hash.new(false)) do |methods, attr| 722 723 attr_name = attr.to_s … … 730 731 731 732 # Contains the names of the generated reader methods. 732 def read_methods 733 def read_methods #:nodoc: 733 734 @read_methods ||= Set.new 734 735 end … … 1191 1192 1192 1193 protected 1193 def subclasses 1194 def subclasses #:nodoc: 1194 1195 @@subclasses[self] ||= [] 1195 1196 @@subclasses[self] + extra = @@subclasses[self].inject([]) {|list, subclass| list + subclass.subclasses } … … 1197 1198 1198 1199 # Test whether the given method and optional key are scoped. 1199 def scoped?(method, key = nil) 1200 def scoped?(method, key = nil) #:nodoc: 1200 1201 if current_scoped_methods && (scope = current_scoped_methods[method]) 1201 1202 !key || scope.has_key?(key) … … 1204 1205 1205 1206 # Retrieve the scope for the given method and optional key. 1206 def scope(method, key = nil) 1207 def scope(method, key = nil) #:nodoc: 1207 1208 if current_scoped_methods && (scope = current_scoped_methods[method]) 1208 1209 key ? scope[key] : scope … … 1226 1227 end 1227 1228 1228 def current_scoped_methods 1229 def current_scoped_methods #:nodoc: 1229 1230 scoped_methods.last 1230 1231 end … … 1255 1256 1256 1257 # Returns the name of the class descending directly from ActiveRecord in the inheritance hierarchy. 1257 def class_name_of_active_record_descendant(klass) 1258 def class_name_of_active_record_descendant(klass) #:nodoc: 1258 1259 klass.base_class.name 1259 1260 end … … 1277 1278 alias_method :sanitize_conditions, :sanitize_sql 1278 1279 1279 def replace_bind_variables(statement, values) 1280 def replace_bind_variables(statement, values) #:nodoc: 1280 1281 raise_if_bind_arity_mismatch(statement, statement.count('?'), values.size) 1281 1282 bound = values.dup … … 1283 1284 end 1284 1285 1285 def replace_named_bind_variables(statement, bind_vars) 1286 def replace_named_bind_variables(statement, bind_vars) #:nodoc: 1286 1287 statement.gsub(/:(\w+)/) do 1287 1288 match = $1.to_sym … … 1294 1295 end 1295 1296 1296 def quote_bound_value(value) 1297 def quote_bound_value(value) #:nodoc: 1297 1298 if (value.respond_to?(:map) && !value.is_a?(String)) 1298 1299 value.map { |v| connection.quote(v) }.join(',') … … 1302 1303 end 1303 1304 1304 def raise_if_bind_arity_mismatch(statement, expected, provided) 1305 def raise_if_bind_arity_mismatch(statement, expected, provided) #:nodoc: 1305 1306 unless expected == provided 1306 1307 raise PreparedStatementInvalid, "wrong number of bind variables (#{provided} for #{expected}) in: #{statement}" … … 1308 1309 end 1309 1310 1310 def extract_options_from_args!(args) 1311 def extract_options_from_args!(args) #:nodoc: 1311 1312 args.last.is_a?(Hash) ? args.pop : {} 1312 1313 end … … 1315 1316 :order, :select, :readonly, :group, :from ] 1316 1317 1317 def validate_find_options(options) 1318 def validate_find_options(options) #:nodoc: 1318 1319 options.assert_valid_keys(VALID_FIND_OPTIONS) 1319 1320 end 1320 1321 1321 def set_readonly_option!(options) 1322 def set_readonly_option!(options) #:nodoc: 1322 1323 # Inherit :readonly from finder scope if set. Otherwise, 1323 1324 # if :joins is not blank then :readonly defaults to true. … … 1331 1332 end 1332 1333 1333 def encode_quoted_value(value) 1334 def encode_quoted_value(value) #:nodoc: 1334 1335 quoted_value = connection.quote(value) 1335 1336 quoted_value = "'#{quoted_value[1..-2].gsub(/\'/, "\\\\'")}'" if quoted_value.include?("\\\'") # (for ruby mode) " … … 1605 1606 end 1606 1607 1608 # Records loaded through joins with piggy-back attributes will be marked as read only as they cannot be saved and return true to this query. 1607 1609 def readonly? 1608 1610 @readonly == true 1609 1611 end 1610 1612 1611 def readonly! 1613 def readonly! #:nodoc: 1612 1614 @readonly = true 1613 1615 end trunk/activerecord/lib/active_record/calculations.rb
r4069 r4078 1 1 module ActiveRecord 2 module Calculations 2 module Calculations #:nodoc: 3 3 CALCULATIONS_OPTIONS = [:conditions, :joins, :order, :select, :group, :having, :distinct] 4 4 def self.included(base) … … 144 144 145 145 protected 146 def construct_calculation_sql(aggregate, aggregate_alias, options)147 scope = scope(:find)148 sql = ["SELECT #{aggregate} AS #{aggregate_alias}"]149 sql << ", #{options[:group_field]} AS #{options[:group_alias]}" if options[:group]150 sql << " FROM #{table_name} "151 add_joins!(sql, options, scope)152 add_conditions!(sql, options[:conditions], scope)153 sql << " GROUP BY #{options[:group_field]}" if options[:group]154 sql << " HAVING #{options[:having]}" if options[:group] && options[:having]155 sql << " ORDER BY #{options[:order]}" if options[:order]156 sql.join157 end158 159 def execute_simple_calculation(operation, column_name, column, aggregate, aggregate_alias, options)160 value = connection.select_value(construct_calculation_sql(aggregate, aggregate_alias, options))161 type_cast_calculated_value(value, column, operation)162 end163 164 def execute_grouped_calculation(operation, column_name, column, aggregate, aggregate_alias, options)165 group_attr = options[:group].to_s166 association = reflect_on_association(group_attr.to_sym)167 associated = association && association.macro == :belongs_to # only count belongs_to associations168 group_field = (associated ? "#{options[:group]}_id" : options[:group]).to_s169 group_alias = column_alias_for(group_field)170 group_column = column_for group_field171 sql = construct_calculation_sql(aggregate, aggregate_alias, options.merge(:group_field => group_field, :group_alias => group_alias))172 calculated_data = connection.select_all(sql)173 174 if association175 key_ids = calculated_data.collect { |row| row[group_alias] }176 key_records = association.klass.base_class.find(key_ids)177 key_records = key_records.inject({}) { |hsh, r| hsh.merge(r.id => r) }178 end179 180 calculated_data.inject(OrderedHash.new) do |all, row|181 key = associated ? key_records[row[group_alias].to_i] : type_cast_calculated_value(row[group_alias], group_column)182 value = row[aggregate_alias]183 all << [key, type_cast_calculated_value(value, column, operation)]184 end185 end146 def construct_calculation_sql(aggregate, aggregate_alias, options) #:nodoc: 147 scope = scope(:find) 148 sql = ["SELECT #{aggregate} AS #{aggregate_alias}"] 149 sql << ", #{options[:group_field]} AS #{options[:group_alias]}" if options[:group] 150 sql << " FROM #{table_name} " 151 add_joins!(sql, options, scope) 152 add_conditions!(sql, options[:conditions], scope) 153 sql << " GROUP BY #{options[:group_field]}" if options[:group] 154 sql << " HAVING #{options[:having]}" if options[:group] && options[:having] 155 sql << " ORDER BY #{options[:order]}" if options[:order] 156 sql.join 157 end 158 159 def execute_simple_calculation(operation, column_name, column, aggregate, aggregate_alias, options) #:nodoc: 160 value = connection.select_value(construct_calculation_sql(aggregate, aggregate_alias, options)) 161 type_cast_calculated_value(value, column, operation) 162 end 163 164 def execute_grouped_calculation(operation, column_name, column, aggregate, aggregate_alias, options) #:nodoc: 165 group_attr = options[:group].to_s 166 association = reflect_on_association(group_attr.to_sym) 167 associated = association && association.macro == :belongs_to # only count belongs_to associations 168 group_field = (associated ? "#{options[:group]}_id" : options[:group]).to_s 169 group_alias = column_alias_for(group_field) 170 group_column = column_for group_field 171 sql = construct_calculation_sql(aggregate, aggregate_alias, options.merge(:group_field => group_field, :group_alias => group_alias)) 172 calculated_data = connection.select_all(sql) 173 174 if association 175 key_ids = calculated_data.collect { |row| row[group_alias] } 176 key_records = association.klass.base_class.find(key_ids) 177 key_records = key_records.inject({}) { |hsh, r| hsh.merge(r.id => r) } 178 end 179 180 calculated_data.inject(OrderedHash.new) do |all, row| 181 key = associated ? key_records[row[group_alias].to_i] : type_cast_calculated_value(row[group_alias], group_column) 182 value = row[aggregate_alias] 183 all << [key, type_cast_calculated_value(value, column, operation)] 184 end 185 end 186 186 187 187 private 188 def validate_calculation_options(operation, options = {})189 if operation.to_s == 'count'190 options.assert_valid_keys(CALCULATIONS_OPTIONS + [:include])191 else192 options.assert_valid_keys(CALCULATIONS_OPTIONS)193 end194 end195 196 def select_aggregate(operation, column_name, options)197 "#{operation}(#{'DISTINCT ' if options[:distinct]}#{column_name})"198 end199 200 # converts a given key to the value that the database adapter returns as201 #202 # users.id #=> users_id203 # sum(id) #=> sum_id204 # count(distinct users.id) #=> count_distinct_users_id205 # count(*) #=> count_all206 def column_alias_for(*keys)207 keys.join(' ').downcase.gsub(/\*/, 'all').gsub(/\W+/, ' ').strip.gsub(/ +/, '_')208 end209 210 def column_for(field)211 field_name = field.to_s.split('.').last212 columns.detect { |c| c.name.to_s == field_name }213 end214 215 def type_cast_calculated_value(value, column, operation = nil)216 operation = operation.to_s.downcase217 case operation218 when 'count' then value.to_i219 when 'avg' then value.to_f220 else column ? column.type_cast(value) : value221 end222 end188 def validate_calculation_options(operation, options = {}) 189 if operation.to_s == 'count' 190 options.assert_valid_keys(CALCULATIONS_OPTIONS + [:include]) 191 else 192 options.assert_valid_keys(CALCULATIONS_OPTIONS) 193 end 194 end 195 196 def select_aggregate(operation, column_name, options) 197 "#{operation}(#{'DISTINCT ' if options[:distinct]}#{column_name})" 198 end 199 200 # converts a given key to the value that the database adapter returns as 201 # 202 # users.id #=> users_id 203 # sum(id) #=> sum_id 204 # count(distinct users.id) #=> count_distinct_users_id 205 # count(*) #=> count_all 206 def column_alias_for(*keys) 207 keys.join(' ').downcase.gsub(/\*/, 'all').gsub(/\W+/, ' ').strip.gsub(/ +/, '_') 208 end 209 210 def column_for(field) 211 field_name = field.to_s.split('.').last 212 columns.detect { |c| c.name.to_s == field_name } 213 end 214 215 def type_cast_calculated_value(value, column, operation = nil) 216 operation = operation.to_s.downcase 217 case operation 218 when 'count' then value.to_i 219 when 'avg' then value.to_f 220 else column ? column.type_cast(value) : value 221 end 222 end 223 223 end 224 224 end trunk/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb
r3862 r4078 39 39 40 40 # set concurrency support flag (not thread safe, like most of the methods in this file) 41 def allow_concurrency=(threaded) 41 def allow_concurrency=(threaded) #:nodoc: 42 42 logger.debug "allow_concurrency=#{threaded}" if logger 43 43 return if @@allow_concurrency == threaded … … 52 52 end 53 53 54 def active_connection_name 54 def active_connection_name #:nodoc: 55 55 @active_connection_name ||= 56 56 if active_connections[name] || @@defined_connections[name] … … 63 63 end 64 64 65 def clear_active_connection_name 65 def clear_active_connection_name #:nodoc: 66 66 @active_connection_name = nil 67 67 subclasses.each { |klass| klass.clear_active_connection_name } … … 89 89 90 90 # Verify active connections. 91 def verify_active_connections! 91 def verify_active_connections! #:nodoc: 92 92 if @@allow_concurrency 93 93 remove_stale_cached_threads!(@@active_connections) do |name, conn| … … 245 245 246 246 # Set the connection for the class. 247 def self.connection=(spec) 247 def self.connection=(spec) #:nodoc: 248 248 if spec.kind_of?(ActiveRecord::ConnectionAdapters::AbstractAdapter) 249 249 active_connections[name] = spec … … 258 258 259 259 # connection state logging 260 def self.log_connections 260 def self.log_connections #:nodoc: 261 261 if logger 262 262 logger.info "Defined connections: #{@@defined_connections.inspect}" trunk/activerecord/lib/active_record/connection_adapters/oracle_adapter.rb
r4055 r4078 45 45 # This is preferable to inserting the hard-coded value here, because the insert method 46 46 # needs to know the id value explicitly. 47 alias :attributes_with_quotes_pre_oracle :attributes_with_quotes #:nodoc: 47 def attributes_with_quotes_pre_oracle #:nodoc: 48 attributes_with_quotes 49 end 50 51 48 52 def attributes_with_quotes(creating = true) #:nodoc: 49 53 aq = attributes_with_quotes_pre_oracle creating … … 543 547 end 544 548 545 class OraObject 549 class OraObject #:nodoc: 546 550 attr_reader :schema, :name 547 551 def initialize(info) trunk/activerecord/lib/active_record/locking.rb
r3822 r4078 61 61 62 62 class << self 63 def set_locking_column( value=nil, &block)63 def set_locking_column(value = nil, &block) 64 64 define_attr_method :locking_column, value, &block 65 65 end 66 66 67 def locking_column 67 def locking_column #:nodoc: 68 68 reset_locking_column 69 69 end 70 70 71 def reset_locking_column 71 def reset_locking_column #:nodoc: 72 72 default = 'lock_version' 73 73 set_locking_column(default) trunk/activerecord/lib/active_record/validations.rb
r4074 r4078 7 7 # puts invalid.record.errors 8 8 # end 9 class RecordInvalid < ActiveRecordError 9 class RecordInvalid < ActiveRecordError #:nodoc: 10 10 attr_reader :record 11 11 def initialize(record)