activerecord 2.3.18 → 3.2.22

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.

Files changed (454) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1014 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +222 -0
  5. data/examples/performance.rb +100 -126
  6. data/examples/simple.rb +14 -0
  7. data/lib/active_record/aggregations.rb +93 -99
  8. data/lib/active_record/associations/alias_tracker.rb +76 -0
  9. data/lib/active_record/associations/association.rb +247 -0
  10. data/lib/active_record/associations/association_scope.rb +134 -0
  11. data/lib/active_record/associations/belongs_to_association.rb +54 -61
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +17 -59
  13. data/lib/active_record/associations/builder/association.rb +55 -0
  14. data/lib/active_record/associations/builder/belongs_to.rb +88 -0
  15. data/lib/active_record/associations/builder/collection_association.rb +75 -0
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +57 -0
  17. data/lib/active_record/associations/builder/has_many.rb +71 -0
  18. data/lib/active_record/associations/builder/has_one.rb +62 -0
  19. data/lib/active_record/associations/builder/singular_association.rb +32 -0
  20. data/lib/active_record/associations/collection_association.rb +580 -0
  21. data/lib/active_record/associations/collection_proxy.rb +133 -0
  22. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +39 -119
  23. data/lib/active_record/associations/has_many_association.rb +60 -79
  24. data/lib/active_record/associations/has_many_through_association.rb +127 -206
  25. data/lib/active_record/associations/has_one_association.rb +55 -114
  26. data/lib/active_record/associations/has_one_through_association.rb +25 -26
  27. data/lib/active_record/associations/join_dependency/join_association.rb +159 -0
  28. data/lib/active_record/associations/join_dependency/join_base.rb +24 -0
  29. data/lib/active_record/associations/join_dependency/join_part.rb +78 -0
  30. data/lib/active_record/associations/join_dependency.rb +214 -0
  31. data/lib/active_record/associations/join_helper.rb +55 -0
  32. data/lib/active_record/associations/preloader/association.rb +125 -0
  33. data/lib/active_record/associations/preloader/belongs_to.rb +17 -0
  34. data/lib/active_record/associations/preloader/collection_association.rb +24 -0
  35. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +60 -0
  36. data/lib/active_record/associations/preloader/has_many.rb +17 -0
  37. data/lib/active_record/associations/preloader/has_many_through.rb +15 -0
  38. data/lib/active_record/associations/preloader/has_one.rb +23 -0
  39. data/lib/active_record/associations/preloader/has_one_through.rb +9 -0
  40. data/lib/active_record/associations/preloader/singular_association.rb +21 -0
  41. data/lib/active_record/associations/preloader/through_association.rb +67 -0
  42. data/lib/active_record/associations/preloader.rb +181 -0
  43. data/lib/active_record/associations/singular_association.rb +64 -0
  44. data/lib/active_record/associations/through_association.rb +87 -0
  45. data/lib/active_record/associations.rb +693 -1337
  46. data/lib/active_record/attribute_assignment.rb +221 -0
  47. data/lib/active_record/attribute_methods/before_type_cast.rb +31 -0
  48. data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +32 -0
  49. data/lib/active_record/attribute_methods/dirty.rb +111 -0
  50. data/lib/active_record/attribute_methods/primary_key.rb +114 -0
  51. data/lib/active_record/attribute_methods/query.rb +39 -0
  52. data/lib/active_record/attribute_methods/read.rb +136 -0
  53. data/lib/active_record/attribute_methods/serialization.rb +120 -0
  54. data/lib/active_record/attribute_methods/time_zone_conversion.rb +65 -0
  55. data/lib/active_record/attribute_methods/write.rb +70 -0
  56. data/lib/active_record/attribute_methods.rb +211 -339
  57. data/lib/active_record/autosave_association.rb +179 -149
  58. data/lib/active_record/base.rb +401 -2907
  59. data/lib/active_record/callbacks.rb +91 -176
  60. data/lib/active_record/coders/yaml_column.rb +41 -0
  61. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +236 -119
  62. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +110 -58
  63. data/lib/active_record/connection_adapters/abstract/database_limits.rb +12 -11
  64. data/lib/active_record/connection_adapters/abstract/database_statements.rb +175 -74
  65. data/lib/active_record/connection_adapters/abstract/query_cache.rb +31 -35
  66. data/lib/active_record/connection_adapters/abstract/quoting.rb +71 -21
  67. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +81 -311
  68. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +194 -78
  69. data/lib/active_record/connection_adapters/abstract_adapter.rb +130 -83
  70. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +676 -0
  71. data/lib/active_record/connection_adapters/column.rb +296 -0
  72. data/lib/active_record/connection_adapters/mysql2_adapter.rb +280 -0
  73. data/lib/active_record/connection_adapters/mysql_adapter.rb +272 -493
  74. data/lib/active_record/connection_adapters/postgresql_adapter.rb +650 -405
  75. data/lib/active_record/connection_adapters/schema_cache.rb +69 -0
  76. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +30 -9
  77. data/lib/active_record/connection_adapters/sqlite_adapter.rb +276 -147
  78. data/lib/active_record/connection_adapters/statement_pool.rb +40 -0
  79. data/lib/active_record/counter_cache.rb +123 -0
  80. data/lib/active_record/dynamic_finder_match.rb +41 -14
  81. data/lib/active_record/dynamic_matchers.rb +84 -0
  82. data/lib/active_record/dynamic_scope_match.rb +13 -15
  83. data/lib/active_record/errors.rb +195 -0
  84. data/lib/active_record/explain.rb +86 -0
  85. data/lib/active_record/explain_subscriber.rb +25 -0
  86. data/lib/active_record/fixtures/file.rb +65 -0
  87. data/lib/active_record/fixtures.rb +695 -770
  88. data/lib/active_record/identity_map.rb +162 -0
  89. data/lib/active_record/inheritance.rb +174 -0
  90. data/lib/active_record/integration.rb +60 -0
  91. data/lib/active_record/locale/en.yml +9 -27
  92. data/lib/active_record/locking/optimistic.rb +76 -73
  93. data/lib/active_record/locking/pessimistic.rb +32 -10
  94. data/lib/active_record/log_subscriber.rb +72 -0
  95. data/lib/active_record/migration/command_recorder.rb +105 -0
  96. data/lib/active_record/migration.rb +415 -205
  97. data/lib/active_record/model_schema.rb +368 -0
  98. data/lib/active_record/nested_attributes.rb +153 -63
  99. data/lib/active_record/observer.rb +27 -103
  100. data/lib/active_record/persistence.rb +376 -0
  101. data/lib/active_record/query_cache.rb +49 -8
  102. data/lib/active_record/querying.rb +58 -0
  103. data/lib/active_record/railtie.rb +131 -0
  104. data/lib/active_record/railties/console_sandbox.rb +6 -0
  105. data/lib/active_record/railties/controller_runtime.rb +49 -0
  106. data/lib/active_record/railties/databases.rake +659 -0
  107. data/lib/active_record/railties/jdbcmysql_error.rb +16 -0
  108. data/lib/active_record/readonly_attributes.rb +26 -0
  109. data/lib/active_record/reflection.rb +269 -120
  110. data/lib/active_record/relation/batches.rb +90 -0
  111. data/lib/active_record/relation/calculations.rb +372 -0
  112. data/lib/active_record/relation/delegation.rb +49 -0
  113. data/lib/active_record/relation/finder_methods.rb +402 -0
  114. data/lib/active_record/relation/predicate_builder.rb +63 -0
  115. data/lib/active_record/relation/query_methods.rb +417 -0
  116. data/lib/active_record/relation/spawn_methods.rb +180 -0
  117. data/lib/active_record/relation.rb +537 -0
  118. data/lib/active_record/result.rb +40 -0
  119. data/lib/active_record/sanitization.rb +194 -0
  120. data/lib/active_record/schema.rb +9 -6
  121. data/lib/active_record/schema_dumper.rb +55 -32
  122. data/lib/active_record/scoping/default.rb +142 -0
  123. data/lib/active_record/scoping/named.rb +200 -0
  124. data/lib/active_record/scoping.rb +152 -0
  125. data/lib/active_record/serialization.rb +8 -91
  126. data/lib/active_record/serializers/xml_serializer.rb +43 -197
  127. data/lib/active_record/session_store.rb +129 -103
  128. data/lib/active_record/store.rb +52 -0
  129. data/lib/active_record/test_case.rb +30 -23
  130. data/lib/active_record/timestamp.rb +95 -52
  131. data/lib/active_record/transactions.rb +212 -66
  132. data/lib/active_record/translation.rb +22 -0
  133. data/lib/active_record/validations/associated.rb +43 -0
  134. data/lib/active_record/validations/uniqueness.rb +180 -0
  135. data/lib/active_record/validations.rb +43 -1106
  136. data/lib/active_record/version.rb +5 -4
  137. data/lib/active_record.rb +121 -48
  138. data/lib/rails/generators/active_record/migration/migration_generator.rb +25 -0
  139. data/lib/rails/generators/active_record/migration/templates/migration.rb +34 -0
  140. data/lib/rails/generators/active_record/migration.rb +15 -0
  141. data/lib/rails/generators/active_record/model/model_generator.rb +47 -0
  142. data/lib/rails/generators/active_record/model/templates/migration.rb +15 -0
  143. data/lib/rails/generators/active_record/model/templates/model.rb +12 -0
  144. data/lib/rails/generators/active_record/model/templates/module.rb +7 -0
  145. data/lib/rails/generators/active_record/observer/observer_generator.rb +15 -0
  146. data/lib/rails/generators/active_record/observer/templates/observer.rb +4 -0
  147. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +25 -0
  148. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +12 -0
  149. data/lib/rails/generators/active_record.rb +25 -0
  150. metadata +187 -363
  151. data/CHANGELOG +0 -5904
  152. data/README +0 -351
  153. data/RUNNING_UNIT_TESTS +0 -36
  154. data/Rakefile +0 -268
  155. data/install.rb +0 -30
  156. data/lib/active_record/association_preload.rb +0 -406
  157. data/lib/active_record/associations/association_collection.rb +0 -533
  158. data/lib/active_record/associations/association_proxy.rb +0 -288
  159. data/lib/active_record/batches.rb +0 -85
  160. data/lib/active_record/calculations.rb +0 -321
  161. data/lib/active_record/dirty.rb +0 -183
  162. data/lib/active_record/named_scope.rb +0 -197
  163. data/lib/active_record/serializers/json_serializer.rb +0 -91
  164. data/lib/activerecord.rb +0 -2
  165. data/test/assets/example.log +0 -1
  166. data/test/assets/flowers.jpg +0 -0
  167. data/test/cases/aaa_create_tables_test.rb +0 -24
  168. data/test/cases/active_schema_test_mysql.rb +0 -122
  169. data/test/cases/active_schema_test_postgresql.rb +0 -24
  170. data/test/cases/adapter_test.rb +0 -144
  171. data/test/cases/aggregations_test.rb +0 -167
  172. data/test/cases/ar_schema_test.rb +0 -32
  173. data/test/cases/associations/belongs_to_associations_test.rb +0 -438
  174. data/test/cases/associations/callbacks_test.rb +0 -161
  175. data/test/cases/associations/cascaded_eager_loading_test.rb +0 -131
  176. data/test/cases/associations/eager_load_includes_full_sti_class_test.rb +0 -36
  177. data/test/cases/associations/eager_load_nested_include_test.rb +0 -131
  178. data/test/cases/associations/eager_load_nested_polymorphic_include.rb +0 -19
  179. data/test/cases/associations/eager_singularization_test.rb +0 -145
  180. data/test/cases/associations/eager_test.rb +0 -852
  181. data/test/cases/associations/extension_test.rb +0 -62
  182. data/test/cases/associations/habtm_join_table_test.rb +0 -56
  183. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +0 -827
  184. data/test/cases/associations/has_many_associations_test.rb +0 -1273
  185. data/test/cases/associations/has_many_through_associations_test.rb +0 -360
  186. data/test/cases/associations/has_one_associations_test.rb +0 -330
  187. data/test/cases/associations/has_one_through_associations_test.rb +0 -209
  188. data/test/cases/associations/inner_join_association_test.rb +0 -93
  189. data/test/cases/associations/inverse_associations_test.rb +0 -566
  190. data/test/cases/associations/join_model_test.rb +0 -712
  191. data/test/cases/associations_test.rb +0 -282
  192. data/test/cases/attribute_methods_test.rb +0 -305
  193. data/test/cases/autosave_association_test.rb +0 -1218
  194. data/test/cases/base_test.rb +0 -2166
  195. data/test/cases/batches_test.rb +0 -81
  196. data/test/cases/binary_test.rb +0 -30
  197. data/test/cases/calculations_test.rb +0 -360
  198. data/test/cases/callbacks_observers_test.rb +0 -38
  199. data/test/cases/callbacks_test.rb +0 -438
  200. data/test/cases/class_inheritable_attributes_test.rb +0 -32
  201. data/test/cases/column_alias_test.rb +0 -17
  202. data/test/cases/column_definition_test.rb +0 -70
  203. data/test/cases/connection_pool_test.rb +0 -25
  204. data/test/cases/connection_test_firebird.rb +0 -8
  205. data/test/cases/connection_test_mysql.rb +0 -65
  206. data/test/cases/copy_table_test_sqlite.rb +0 -80
  207. data/test/cases/counter_cache_test.rb +0 -84
  208. data/test/cases/database_statements_test.rb +0 -12
  209. data/test/cases/datatype_test_postgresql.rb +0 -204
  210. data/test/cases/date_time_test.rb +0 -37
  211. data/test/cases/default_test_firebird.rb +0 -16
  212. data/test/cases/defaults_test.rb +0 -111
  213. data/test/cases/deprecated_finder_test.rb +0 -30
  214. data/test/cases/dirty_test.rb +0 -316
  215. data/test/cases/finder_respond_to_test.rb +0 -76
  216. data/test/cases/finder_test.rb +0 -1098
  217. data/test/cases/fixtures_test.rb +0 -661
  218. data/test/cases/helper.rb +0 -68
  219. data/test/cases/i18n_test.rb +0 -46
  220. data/test/cases/inheritance_test.rb +0 -262
  221. data/test/cases/invalid_date_test.rb +0 -24
  222. data/test/cases/json_serialization_test.rb +0 -219
  223. data/test/cases/lifecycle_test.rb +0 -193
  224. data/test/cases/locking_test.rb +0 -350
  225. data/test/cases/method_scoping_test.rb +0 -704
  226. data/test/cases/migration_test.rb +0 -1649
  227. data/test/cases/migration_test_firebird.rb +0 -124
  228. data/test/cases/mixin_test.rb +0 -96
  229. data/test/cases/modules_test.rb +0 -109
  230. data/test/cases/multiple_db_test.rb +0 -85
  231. data/test/cases/named_scope_test.rb +0 -372
  232. data/test/cases/nested_attributes_test.rb +0 -840
  233. data/test/cases/pk_test.rb +0 -119
  234. data/test/cases/pooled_connections_test.rb +0 -103
  235. data/test/cases/query_cache_test.rb +0 -129
  236. data/test/cases/readonly_test.rb +0 -107
  237. data/test/cases/reflection_test.rb +0 -234
  238. data/test/cases/reload_models_test.rb +0 -22
  239. data/test/cases/repair_helper.rb +0 -50
  240. data/test/cases/reserved_word_test_mysql.rb +0 -176
  241. data/test/cases/sanitize_test.rb +0 -25
  242. data/test/cases/schema_authorization_test_postgresql.rb +0 -75
  243. data/test/cases/schema_dumper_test.rb +0 -211
  244. data/test/cases/schema_test_postgresql.rb +0 -178
  245. data/test/cases/serialization_test.rb +0 -47
  246. data/test/cases/sp_test_mysql.rb +0 -16
  247. data/test/cases/synonym_test_oracle.rb +0 -17
  248. data/test/cases/timestamp_test.rb +0 -75
  249. data/test/cases/transactions_test.rb +0 -543
  250. data/test/cases/unconnected_test.rb +0 -32
  251. data/test/cases/validations_i18n_test.rb +0 -925
  252. data/test/cases/validations_test.rb +0 -1684
  253. data/test/cases/xml_serialization_test.rb +0 -240
  254. data/test/cases/yaml_serialization_test.rb +0 -11
  255. data/test/config.rb +0 -5
  256. data/test/connections/jdbc_jdbcderby/connection.rb +0 -18
  257. data/test/connections/jdbc_jdbch2/connection.rb +0 -18
  258. data/test/connections/jdbc_jdbchsqldb/connection.rb +0 -18
  259. data/test/connections/jdbc_jdbcmysql/connection.rb +0 -26
  260. data/test/connections/jdbc_jdbcpostgresql/connection.rb +0 -26
  261. data/test/connections/jdbc_jdbcsqlite3/connection.rb +0 -25
  262. data/test/connections/native_db2/connection.rb +0 -25
  263. data/test/connections/native_firebird/connection.rb +0 -26
  264. data/test/connections/native_frontbase/connection.rb +0 -27
  265. data/test/connections/native_mysql/connection.rb +0 -25
  266. data/test/connections/native_openbase/connection.rb +0 -21
  267. data/test/connections/native_oracle/connection.rb +0 -27
  268. data/test/connections/native_postgresql/connection.rb +0 -21
  269. data/test/connections/native_sqlite/connection.rb +0 -25
  270. data/test/connections/native_sqlite3/connection.rb +0 -25
  271. data/test/connections/native_sqlite3/in_memory_connection.rb +0 -18
  272. data/test/connections/native_sybase/connection.rb +0 -23
  273. data/test/fixtures/accounts.yml +0 -29
  274. data/test/fixtures/all/developers.yml +0 -0
  275. data/test/fixtures/all/people.csv +0 -0
  276. data/test/fixtures/all/tasks.yml +0 -0
  277. data/test/fixtures/author_addresses.yml +0 -5
  278. data/test/fixtures/author_favorites.yml +0 -4
  279. data/test/fixtures/authors.yml +0 -9
  280. data/test/fixtures/binaries.yml +0 -132
  281. data/test/fixtures/books.yml +0 -7
  282. data/test/fixtures/categories/special_categories.yml +0 -9
  283. data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +0 -4
  284. data/test/fixtures/categories.yml +0 -14
  285. data/test/fixtures/categories_ordered.yml +0 -7
  286. data/test/fixtures/categories_posts.yml +0 -23
  287. data/test/fixtures/categorizations.yml +0 -17
  288. data/test/fixtures/clubs.yml +0 -6
  289. data/test/fixtures/comments.yml +0 -59
  290. data/test/fixtures/companies.yml +0 -56
  291. data/test/fixtures/computers.yml +0 -4
  292. data/test/fixtures/courses.yml +0 -7
  293. data/test/fixtures/customers.yml +0 -26
  294. data/test/fixtures/developers.yml +0 -21
  295. data/test/fixtures/developers_projects.yml +0 -17
  296. data/test/fixtures/edges.yml +0 -6
  297. data/test/fixtures/entrants.yml +0 -14
  298. data/test/fixtures/faces.yml +0 -11
  299. data/test/fixtures/fk_test_has_fk.yml +0 -3
  300. data/test/fixtures/fk_test_has_pk.yml +0 -2
  301. data/test/fixtures/funny_jokes.yml +0 -10
  302. data/test/fixtures/interests.yml +0 -33
  303. data/test/fixtures/items.yml +0 -4
  304. data/test/fixtures/jobs.yml +0 -7
  305. data/test/fixtures/legacy_things.yml +0 -3
  306. data/test/fixtures/mateys.yml +0 -4
  307. data/test/fixtures/member_types.yml +0 -6
  308. data/test/fixtures/members.yml +0 -6
  309. data/test/fixtures/memberships.yml +0 -20
  310. data/test/fixtures/men.yml +0 -5
  311. data/test/fixtures/minimalistics.yml +0 -2
  312. data/test/fixtures/mixed_case_monkeys.yml +0 -6
  313. data/test/fixtures/mixins.yml +0 -29
  314. data/test/fixtures/movies.yml +0 -7
  315. data/test/fixtures/naked/csv/accounts.csv +0 -1
  316. data/test/fixtures/naked/yml/accounts.yml +0 -1
  317. data/test/fixtures/naked/yml/companies.yml +0 -1
  318. data/test/fixtures/naked/yml/courses.yml +0 -1
  319. data/test/fixtures/organizations.yml +0 -5
  320. data/test/fixtures/owners.yml +0 -7
  321. data/test/fixtures/parrots.yml +0 -27
  322. data/test/fixtures/parrots_pirates.yml +0 -7
  323. data/test/fixtures/people.yml +0 -15
  324. data/test/fixtures/pets.yml +0 -14
  325. data/test/fixtures/pirates.yml +0 -9
  326. data/test/fixtures/polymorphic_designs.yml +0 -19
  327. data/test/fixtures/polymorphic_prices.yml +0 -19
  328. data/test/fixtures/posts.yml +0 -52
  329. data/test/fixtures/price_estimates.yml +0 -7
  330. data/test/fixtures/projects.yml +0 -7
  331. data/test/fixtures/readers.yml +0 -9
  332. data/test/fixtures/references.yml +0 -17
  333. data/test/fixtures/reserved_words/distinct.yml +0 -5
  334. data/test/fixtures/reserved_words/distincts_selects.yml +0 -11
  335. data/test/fixtures/reserved_words/group.yml +0 -14
  336. data/test/fixtures/reserved_words/select.yml +0 -8
  337. data/test/fixtures/reserved_words/values.yml +0 -7
  338. data/test/fixtures/ships.yml +0 -5
  339. data/test/fixtures/sponsors.yml +0 -9
  340. data/test/fixtures/subscribers.yml +0 -7
  341. data/test/fixtures/subscriptions.yml +0 -12
  342. data/test/fixtures/taggings.yml +0 -28
  343. data/test/fixtures/tags.yml +0 -7
  344. data/test/fixtures/tasks.yml +0 -7
  345. data/test/fixtures/tees.yml +0 -4
  346. data/test/fixtures/ties.yml +0 -4
  347. data/test/fixtures/topics.yml +0 -42
  348. data/test/fixtures/toys.yml +0 -4
  349. data/test/fixtures/treasures.yml +0 -10
  350. data/test/fixtures/vertices.yml +0 -4
  351. data/test/fixtures/warehouse-things.yml +0 -3
  352. data/test/fixtures/zines.yml +0 -5
  353. data/test/migrations/broken/100_migration_that_raises_exception.rb +0 -10
  354. data/test/migrations/decimal/1_give_me_big_numbers.rb +0 -15
  355. data/test/migrations/duplicate/1_people_have_last_names.rb +0 -9
  356. data/test/migrations/duplicate/2_we_need_reminders.rb +0 -12
  357. data/test/migrations/duplicate/3_foo.rb +0 -7
  358. data/test/migrations/duplicate/3_innocent_jointable.rb +0 -12
  359. data/test/migrations/duplicate_names/20080507052938_chunky.rb +0 -7
  360. data/test/migrations/duplicate_names/20080507053028_chunky.rb +0 -7
  361. data/test/migrations/interleaved/pass_1/3_innocent_jointable.rb +0 -12
  362. data/test/migrations/interleaved/pass_2/1_people_have_last_names.rb +0 -9
  363. data/test/migrations/interleaved/pass_2/3_innocent_jointable.rb +0 -12
  364. data/test/migrations/interleaved/pass_3/1_people_have_last_names.rb +0 -9
  365. data/test/migrations/interleaved/pass_3/2_i_raise_on_down.rb +0 -8
  366. data/test/migrations/interleaved/pass_3/3_innocent_jointable.rb +0 -12
  367. data/test/migrations/missing/1000_people_have_middle_names.rb +0 -9
  368. data/test/migrations/missing/1_people_have_last_names.rb +0 -9
  369. data/test/migrations/missing/3_we_need_reminders.rb +0 -12
  370. data/test/migrations/missing/4_innocent_jointable.rb +0 -12
  371. data/test/migrations/valid/1_people_have_last_names.rb +0 -9
  372. data/test/migrations/valid/2_we_need_reminders.rb +0 -12
  373. data/test/migrations/valid/3_innocent_jointable.rb +0 -12
  374. data/test/models/author.rb +0 -151
  375. data/test/models/auto_id.rb +0 -4
  376. data/test/models/binary.rb +0 -2
  377. data/test/models/bird.rb +0 -9
  378. data/test/models/book.rb +0 -4
  379. data/test/models/categorization.rb +0 -5
  380. data/test/models/category.rb +0 -34
  381. data/test/models/citation.rb +0 -6
  382. data/test/models/club.rb +0 -13
  383. data/test/models/column_name.rb +0 -3
  384. data/test/models/comment.rb +0 -29
  385. data/test/models/company.rb +0 -173
  386. data/test/models/company_in_module.rb +0 -78
  387. data/test/models/computer.rb +0 -3
  388. data/test/models/contact.rb +0 -16
  389. data/test/models/contract.rb +0 -5
  390. data/test/models/course.rb +0 -3
  391. data/test/models/customer.rb +0 -73
  392. data/test/models/default.rb +0 -2
  393. data/test/models/developer.rb +0 -101
  394. data/test/models/edge.rb +0 -5
  395. data/test/models/entrant.rb +0 -3
  396. data/test/models/essay.rb +0 -3
  397. data/test/models/event.rb +0 -3
  398. data/test/models/event_author.rb +0 -8
  399. data/test/models/face.rb +0 -7
  400. data/test/models/guid.rb +0 -2
  401. data/test/models/interest.rb +0 -5
  402. data/test/models/invoice.rb +0 -4
  403. data/test/models/item.rb +0 -7
  404. data/test/models/job.rb +0 -5
  405. data/test/models/joke.rb +0 -3
  406. data/test/models/keyboard.rb +0 -3
  407. data/test/models/legacy_thing.rb +0 -3
  408. data/test/models/line_item.rb +0 -3
  409. data/test/models/man.rb +0 -9
  410. data/test/models/matey.rb +0 -4
  411. data/test/models/member.rb +0 -12
  412. data/test/models/member_detail.rb +0 -5
  413. data/test/models/member_type.rb +0 -3
  414. data/test/models/membership.rb +0 -9
  415. data/test/models/minimalistic.rb +0 -2
  416. data/test/models/mixed_case_monkey.rb +0 -3
  417. data/test/models/movie.rb +0 -5
  418. data/test/models/order.rb +0 -4
  419. data/test/models/organization.rb +0 -6
  420. data/test/models/owner.rb +0 -5
  421. data/test/models/parrot.rb +0 -22
  422. data/test/models/person.rb +0 -16
  423. data/test/models/pet.rb +0 -5
  424. data/test/models/pirate.rb +0 -80
  425. data/test/models/polymorphic_design.rb +0 -3
  426. data/test/models/polymorphic_price.rb +0 -3
  427. data/test/models/post.rb +0 -102
  428. data/test/models/price_estimate.rb +0 -3
  429. data/test/models/project.rb +0 -30
  430. data/test/models/reader.rb +0 -4
  431. data/test/models/reference.rb +0 -4
  432. data/test/models/reply.rb +0 -46
  433. data/test/models/ship.rb +0 -19
  434. data/test/models/ship_part.rb +0 -7
  435. data/test/models/sponsor.rb +0 -4
  436. data/test/models/subject.rb +0 -4
  437. data/test/models/subscriber.rb +0 -8
  438. data/test/models/subscription.rb +0 -4
  439. data/test/models/tag.rb +0 -7
  440. data/test/models/tagging.rb +0 -10
  441. data/test/models/task.rb +0 -3
  442. data/test/models/tee.rb +0 -4
  443. data/test/models/tie.rb +0 -4
  444. data/test/models/topic.rb +0 -80
  445. data/test/models/toy.rb +0 -6
  446. data/test/models/treasure.rb +0 -8
  447. data/test/models/vertex.rb +0 -9
  448. data/test/models/warehouse_thing.rb +0 -5
  449. data/test/models/zine.rb +0 -3
  450. data/test/schema/mysql_specific_schema.rb +0 -31
  451. data/test/schema/postgresql_specific_schema.rb +0 -114
  452. data/test/schema/schema.rb +0 -550
  453. data/test/schema/schema2.rb +0 -6
  454. data/test/schema/sqlite_specific_schema.rb +0 -25
@@ -0,0 +1,402 @@
1
+ require 'active_support/core_ext/object/blank'
2
+ require 'active_support/core_ext/hash/indifferent_access'
3
+
4
+ module ActiveRecord
5
+ module FinderMethods
6
+ # Find operates with four different retrieval approaches:
7
+ #
8
+ # * Find by id - This can either be a specific id (1), a list of ids (1, 5, 6), or an array of ids ([5, 6, 10]).
9
+ # If no record can be found for all of the listed ids, then RecordNotFound will be raised.
10
+ # * Find first - This will return the first record matched by the options used. These options can either be specific
11
+ # conditions or merely an order. If no record can be matched, +nil+ is returned. Use
12
+ # <tt>Model.find(:first, *args)</tt> or its shortcut <tt>Model.first(*args)</tt>.
13
+ # * Find last - This will return the last record matched by the options used. These options can either be specific
14
+ # conditions or merely an order. If no record can be matched, +nil+ is returned. Use
15
+ # <tt>Model.find(:last, *args)</tt> or its shortcut <tt>Model.last(*args)</tt>.
16
+ # * Find all - This will return all the records matched by the options used.
17
+ # If no records are found, an empty array is returned. Use
18
+ # <tt>Model.find(:all, *args)</tt> or its shortcut <tt>Model.all(*args)</tt>.
19
+ #
20
+ # All approaches accept an options hash as their last parameter.
21
+ #
22
+ # ==== Options
23
+ #
24
+ # * <tt>:conditions</tt> - An SQL fragment like "administrator = 1", <tt>["user_name = ?", username]</tt>,
25
+ # or <tt>["user_name = :user_name", { :user_name => user_name }]</tt>. See conditions in the intro.
26
+ # * <tt>:order</tt> - An SQL fragment like "created_at DESC, name".
27
+ # * <tt>:group</tt> - An attribute name by which the result should be grouped. Uses the <tt>GROUP BY</tt> SQL-clause.
28
+ # * <tt>:having</tt> - Combined with +:group+ this can be used to filter the records that a
29
+ # <tt>GROUP BY</tt> returns. Uses the <tt>HAVING</tt> SQL-clause.
30
+ # * <tt>:limit</tt> - An integer determining the limit on the number of rows that should be returned.
31
+ # * <tt>:offset</tt> - An integer determining the offset from where the rows should be fetched. So at 5,
32
+ # it would skip rows 0 through 4.
33
+ # * <tt>:joins</tt> - Either an SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id" (rarely needed),
34
+ # named associations in the same form used for the <tt>:include</tt> option, which will perform an
35
+ # <tt>INNER JOIN</tt> on the associated table(s),
36
+ # or an array containing a mixture of both strings and named associations.
37
+ # If the value is a string, then the records will be returned read-only since they will
38
+ # have attributes that do not correspond to the table's columns.
39
+ # Pass <tt>:readonly => false</tt> to override.
40
+ # * <tt>:include</tt> - Names associations that should be loaded alongside. The symbols named refer
41
+ # to already defined associations. See eager loading under Associations.
42
+ # * <tt>:select</tt> - By default, this is "*" as in "SELECT * FROM", but can be changed if you,
43
+ # for example, want to do a join but not include the joined columns. Takes a string with the SELECT SQL fragment (e.g. "id, name").
44
+ # * <tt>:from</tt> - By default, this is the table name of the class, but can be changed
45
+ # to an alternate table name (or even the name of a database view).
46
+ # * <tt>:readonly</tt> - Mark the returned records read-only so they cannot be saved or updated.
47
+ # * <tt>:lock</tt> - An SQL fragment like "FOR UPDATE" or "LOCK IN SHARE MODE".
48
+ # <tt>:lock => true</tt> gives connection's default exclusive lock, usually "FOR UPDATE".
49
+ #
50
+ # ==== Examples
51
+ #
52
+ # # find by id
53
+ # Person.find(1) # returns the object for ID = 1
54
+ # Person.find(1, 2, 6) # returns an array for objects with IDs in (1, 2, 6)
55
+ # Person.find([7, 17]) # returns an array for objects with IDs in (7, 17)
56
+ # Person.find([1]) # returns an array for the object with ID = 1
57
+ # Person.where("administrator = 1").order("created_on DESC").find(1)
58
+ #
59
+ # Note that returned records may not be in the same order as the ids you
60
+ # provide since database rows are unordered. Give an explicit <tt>:order</tt>
61
+ # to ensure the results are sorted.
62
+ #
63
+ # ==== Examples
64
+ #
65
+ # # find first
66
+ # Person.first # returns the first object fetched by SELECT * FROM people
67
+ # Person.where(["user_name = ?", user_name]).first
68
+ # Person.where(["user_name = :u", { :u => user_name }]).first
69
+ # Person.order("created_on DESC").offset(5).first
70
+ #
71
+ # # find last
72
+ # Person.last # returns the last object fetched by SELECT * FROM people
73
+ # Person.where(["user_name = ?", user_name]).last
74
+ # Person.order("created_on DESC").offset(5).last
75
+ #
76
+ # # find all
77
+ # Person.all # returns an array of objects for all the rows fetched by SELECT * FROM people
78
+ # Person.where(["category IN (?)", categories]).limit(50).all
79
+ # Person.where({ :friends => ["Bob", "Steve", "Fred"] }).all
80
+ # Person.offset(10).limit(10).all
81
+ # Person.includes([:account, :friends]).all
82
+ # Person.group("category").all
83
+ #
84
+ # Example for find with a lock: Imagine two concurrent transactions:
85
+ # each will read <tt>person.visits == 2</tt>, add 1 to it, and save, resulting
86
+ # in two saves of <tt>person.visits = 3</tt>. By locking the row, the second
87
+ # transaction has to wait until the first is finished; we get the
88
+ # expected <tt>person.visits == 4</tt>.
89
+ #
90
+ # Person.transaction do
91
+ # person = Person.lock(true).find(1)
92
+ # person.visits += 1
93
+ # person.save!
94
+ # end
95
+ def find(*args)
96
+ return to_a.find { |*block_args| yield(*block_args) } if block_given?
97
+
98
+ options = args.extract_options!
99
+
100
+ if options.present?
101
+ apply_finder_options(options).find(*args)
102
+ else
103
+ case args.first
104
+ when :first, :last, :all
105
+ send(args.first)
106
+ else
107
+ find_with_ids(*args)
108
+ end
109
+ end
110
+ end
111
+
112
+ # A convenience wrapper for <tt>find(:first, *args)</tt>. You can pass in all the
113
+ # same arguments to this method as you can to <tt>find(:first)</tt>.
114
+ def first(*args)
115
+ if args.any?
116
+ if args.first.kind_of?(Integer) || (loaded? && !args.first.kind_of?(Hash))
117
+ limit(*args).to_a
118
+ else
119
+ apply_finder_options(args.first).first
120
+ end
121
+ else
122
+ find_first
123
+ end
124
+ end
125
+
126
+ # Same as +first+ but raises <tt>ActiveRecord::RecordNotFound</tt> if no record
127
+ # is found. Note that <tt>first!</tt> accepts no arguments.
128
+ def first!
129
+ first or raise RecordNotFound
130
+ end
131
+
132
+ # A convenience wrapper for <tt>find(:last, *args)</tt>. You can pass in all the
133
+ # same arguments to this method as you can to <tt>find(:last)</tt>.
134
+ def last(*args)
135
+ if args.any?
136
+ if args.first.kind_of?(Integer) || (loaded? && !args.first.kind_of?(Hash))
137
+ if order_values.empty? && primary_key
138
+ order("#{quoted_table_name}.#{quoted_primary_key} DESC").limit(*args).reverse
139
+ else
140
+ to_a.last(*args)
141
+ end
142
+ else
143
+ apply_finder_options(args.first).last
144
+ end
145
+ else
146
+ find_last
147
+ end
148
+ end
149
+
150
+ # Same as +last+ but raises <tt>ActiveRecord::RecordNotFound</tt> if no record
151
+ # is found. Note that <tt>last!</tt> accepts no arguments.
152
+ def last!
153
+ last or raise RecordNotFound
154
+ end
155
+
156
+ # A convenience wrapper for <tt>find(:all, *args)</tt>. You can pass in all the
157
+ # same arguments to this method as you can to <tt>find(:all)</tt>.
158
+ def all(*args)
159
+ args.any? ? apply_finder_options(args.first).to_a : to_a
160
+ end
161
+
162
+ # Returns true if a record exists in the table that matches the +id+ or
163
+ # conditions given, or false otherwise. The argument can take five forms:
164
+ #
165
+ # * Integer - Finds the record with this primary key.
166
+ # * String - Finds the record with a primary key corresponding to this
167
+ # string (such as <tt>'5'</tt>).
168
+ # * Array - Finds the record that matches these +find+-style conditions
169
+ # (such as <tt>['color = ?', 'red']</tt>).
170
+ # * Hash - Finds the record that matches these +find+-style conditions
171
+ # (such as <tt>{:color => 'red'}</tt>).
172
+ # * No args - Returns false if the table is empty, true otherwise.
173
+ #
174
+ # For more information about specifying conditions as a Hash or Array,
175
+ # see the Conditions section in the introduction to ActiveRecord::Base.
176
+ #
177
+ # Note: You can't pass in a condition as a string (like <tt>name =
178
+ # 'Jamie'</tt>), since it would be sanitized and then queried against
179
+ # the primary key column, like <tt>id = 'name = \'Jamie\''</tt>.
180
+ #
181
+ # ==== Examples
182
+ # Person.exists?(5)
183
+ # Person.exists?('5')
184
+ # Person.exists?(:name => "David")
185
+ # Person.exists?(['name LIKE ?', "%#{query}%"])
186
+ # Person.exists?
187
+ def exists?(id = false)
188
+ id = id.id if ActiveRecord::Base === id
189
+ return false if id.nil?
190
+
191
+ join_dependency = construct_join_dependency_for_association_find
192
+ relation = construct_relation_for_association_find(join_dependency)
193
+ relation = relation.except(:select, :order).select("1 AS one").limit(1)
194
+
195
+ case id
196
+ when Array, Hash
197
+ relation = relation.where(id)
198
+ else
199
+ relation = relation.where(table[primary_key].eq(id)) if id
200
+ end
201
+
202
+ connection.select_value(relation, "#{name} Exists") ? true : false
203
+ rescue ThrowResult
204
+ false
205
+ end
206
+
207
+ protected
208
+
209
+ def find_with_associations
210
+ join_dependency = construct_join_dependency_for_association_find
211
+ relation = construct_relation_for_association_find(join_dependency)
212
+ rows = connection.select_all(relation, 'SQL', relation.bind_values.dup)
213
+ join_dependency.instantiate(rows)
214
+ rescue ThrowResult
215
+ []
216
+ end
217
+
218
+ def construct_join_dependency_for_association_find
219
+ including = (@eager_load_values + @includes_values).uniq
220
+ ActiveRecord::Associations::JoinDependency.new(@klass, including, [])
221
+ end
222
+
223
+ def construct_relation_for_association_calculations
224
+ including = (@eager_load_values + @includes_values).uniq
225
+ join_dependency = ActiveRecord::Associations::JoinDependency.new(@klass, including, arel.froms.first)
226
+ relation = except(:includes, :eager_load, :preload)
227
+ apply_join_dependency(relation, join_dependency)
228
+ end
229
+
230
+ def construct_relation_for_association_find(join_dependency)
231
+ relation = except(:includes, :eager_load, :preload, :select).select(join_dependency.columns)
232
+ apply_join_dependency(relation, join_dependency)
233
+ end
234
+
235
+ def apply_join_dependency(relation, join_dependency)
236
+ join_dependency.join_associations.each do |association|
237
+ relation = association.join_relation(relation)
238
+ end
239
+
240
+ limitable_reflections = using_limitable_reflections?(join_dependency.reflections)
241
+
242
+ if !limitable_reflections && relation.limit_value
243
+ limited_id_condition = construct_limited_ids_condition(relation.except(:select))
244
+ relation = relation.where(limited_id_condition)
245
+ end
246
+
247
+ relation = relation.except(:limit, :offset) unless limitable_reflections
248
+
249
+ relation
250
+ end
251
+
252
+ def construct_limited_ids_condition(relation)
253
+ orders = relation.order_values.map { |val| val.presence }.compact
254
+ values = @klass.connection.distinct("#{@klass.connection.quote_table_name table_name}.#{primary_key}", orders)
255
+
256
+ relation = relation.dup.select(values)
257
+ relation.uniq_value = nil
258
+
259
+ id_rows = @klass.connection.select_all(relation.arel, 'SQL', relation.bind_values)
260
+ ids_array = id_rows.map {|row| row[primary_key]}
261
+
262
+ ids_array.empty? ? raise(ThrowResult) : table[primary_key].in(ids_array)
263
+ end
264
+
265
+ def find_by_attributes(match, attributes, *args)
266
+ conditions = Hash[attributes.map {|a| [a, args[attributes.index(a)]]}]
267
+ result = where(conditions).send(match.finder)
268
+
269
+ if match.bang? && result.nil?
270
+ raise RecordNotFound, "Couldn't find #{@klass.name} with #{conditions.to_a.collect {|p| p.join(' = ')}.join(', ')}"
271
+ else
272
+ yield(result) if block_given?
273
+ result
274
+ end
275
+ end
276
+
277
+ def find_or_instantiator_by_attributes(match, attributes, *args)
278
+ options = args.size > 1 && args.last(2).all?{ |a| a.is_a?(Hash) } ? args.extract_options! : {}
279
+ protected_attributes_for_create, unprotected_attributes_for_create = {}, {}
280
+ args.each_with_index do |arg, i|
281
+ if arg.is_a?(Hash)
282
+ protected_attributes_for_create = args[i].with_indifferent_access
283
+ else
284
+ unprotected_attributes_for_create[attributes[i]] = args[i]
285
+ end
286
+ end
287
+
288
+ conditions = (protected_attributes_for_create.merge(unprotected_attributes_for_create)).slice(*attributes).symbolize_keys
289
+
290
+ record = where(conditions).first
291
+
292
+ unless record
293
+ record = @klass.new(protected_attributes_for_create, options) do |r|
294
+ r.assign_attributes(unprotected_attributes_for_create, :without_protection => true)
295
+ end
296
+ yield(record) if block_given?
297
+ record.send(match.save_method) if match.save_record?
298
+ end
299
+
300
+ record
301
+ end
302
+
303
+ def find_with_ids(*ids)
304
+ return to_a.find { |*block_args| yield(*block_args) } if block_given?
305
+
306
+ expects_array = ids.first.kind_of?(Array)
307
+ return ids.first if expects_array && ids.first.empty?
308
+
309
+ ids = ids.flatten.compact.uniq
310
+
311
+ case ids.size
312
+ when 0
313
+ raise RecordNotFound, "Couldn't find #{@klass.name} without an ID"
314
+ when 1
315
+ result = find_one(ids.first)
316
+ expects_array ? [ result ] : result
317
+ else
318
+ find_some(ids)
319
+ end
320
+ end
321
+
322
+ def find_one(id)
323
+ id = id.id if ActiveRecord::Base === id
324
+
325
+ if IdentityMap.enabled? && where_values.blank? &&
326
+ limit_value.blank? && order_values.blank? &&
327
+ includes_values.blank? && preload_values.blank? &&
328
+ readonly_value.nil? && joins_values.blank? &&
329
+ !@klass.locking_enabled? &&
330
+ record = IdentityMap.get(@klass, id)
331
+ return record
332
+ end
333
+
334
+ column = columns_hash[primary_key]
335
+
336
+ substitute = connection.substitute_at(column, @bind_values.length)
337
+ relation = where(table[primary_key].eq(substitute))
338
+ relation.bind_values = [[column, id]]
339
+ record = relation.first
340
+
341
+ unless record
342
+ conditions = arel.where_sql
343
+ conditions = " [#{conditions}]" if conditions
344
+ raise RecordNotFound, "Couldn't find #{@klass.name} with #{primary_key}=#{id}#{conditions}"
345
+ end
346
+
347
+ record
348
+ end
349
+
350
+ def find_some(ids)
351
+ result = where(table[primary_key].in(ids)).all
352
+
353
+ expected_size =
354
+ if @limit_value && ids.size > @limit_value
355
+ @limit_value
356
+ else
357
+ ids.size
358
+ end
359
+
360
+ # 11 ids with limit 3, offset 9 should give 2 results.
361
+ if @offset_value && (ids.size - @offset_value < expected_size)
362
+ expected_size = ids.size - @offset_value
363
+ end
364
+
365
+ if result.size == expected_size
366
+ result
367
+ else
368
+ conditions = arel.where_sql
369
+ conditions = " [#{conditions}]" if conditions
370
+
371
+ error = "Couldn't find all #{@klass.name.pluralize} with IDs "
372
+ error << "(#{ids.join(", ")})#{conditions} (found #{result.size} results, but was looking for #{expected_size})"
373
+ raise RecordNotFound, error
374
+ end
375
+ end
376
+
377
+ def find_first
378
+ if loaded?
379
+ @records.first
380
+ else
381
+ @first ||= limit(1).to_a[0]
382
+ end
383
+ end
384
+
385
+ def find_last
386
+ if loaded?
387
+ @records.last
388
+ else
389
+ @last ||=
390
+ if offset_value || limit_value
391
+ to_a.last
392
+ else
393
+ reverse_order.limit(1).to_a[0]
394
+ end
395
+ end
396
+ end
397
+
398
+ def using_limitable_reflections?(reflections)
399
+ reflections.none? { |r| r.collection? }
400
+ end
401
+ end
402
+ end
@@ -0,0 +1,63 @@
1
+ module ActiveRecord
2
+ class PredicateBuilder # :nodoc:
3
+ def self.build_from_hash(engine, attributes, default_table, allow_table_name = true)
4
+ predicates = attributes.map do |column, value|
5
+ table = default_table
6
+
7
+ if allow_table_name && value.is_a?(Hash)
8
+ table = Arel::Table.new(column, engine)
9
+
10
+ if value.empty?
11
+ '1 = 2'
12
+ else
13
+ build_from_hash(engine, value, table, false)
14
+ end
15
+ else
16
+ column = column.to_s
17
+
18
+ if allow_table_name && column.include?('.')
19
+ table_name, column = column.split('.', 2)
20
+ table = Arel::Table.new(table_name, engine)
21
+ end
22
+
23
+ attribute = table[column]
24
+
25
+ case value
26
+ when ActiveRecord::Relation
27
+ value = value.select(value.klass.arel_table[value.klass.primary_key]) if value.select_values.empty?
28
+ attribute.in(value.arel.ast)
29
+ when Array, ActiveRecord::Associations::CollectionProxy
30
+ values = value.to_a.map {|x| x.is_a?(ActiveRecord::Base) ? x.id : x}
31
+ ranges, values = values.partition {|v| v.is_a?(Range) || v.is_a?(Arel::Relation)}
32
+
33
+ array_predicates = ranges.map {|range| attribute.in(range)}
34
+
35
+ if values.include?(nil)
36
+ values = values.compact
37
+ if values.empty?
38
+ array_predicates << attribute.eq(nil)
39
+ else
40
+ array_predicates << attribute.in(values.compact).or(attribute.eq(nil))
41
+ end
42
+ else
43
+ array_predicates << attribute.in(values)
44
+ end
45
+
46
+ array_predicates.inject {|composite, predicate| composite.or(predicate)}
47
+ when Range, Arel::Relation
48
+ attribute.in(value)
49
+ when ActiveRecord::Base
50
+ attribute.eq(value.id)
51
+ when Class
52
+ # FIXME: I think we need to deprecate this behavior
53
+ attribute.eq(value.name)
54
+ else
55
+ attribute.eq(value)
56
+ end
57
+ end
58
+ end
59
+
60
+ predicates.flatten
61
+ end
62
+ end
63
+ end