activerecord 2.3.18 → 3.0.0.beta

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 (378) hide show
  1. data/CHANGELOG +105 -34
  2. data/examples/performance.rb +3 -39
  3. data/examples/simple.rb +14 -0
  4. data/lib/active_record.rb +81 -47
  5. data/lib/active_record/aggregations.rb +1 -3
  6. data/lib/active_record/association_preload.rb +39 -54
  7. data/lib/active_record/associations.rb +262 -419
  8. data/lib/active_record/associations/association_collection.rb +85 -100
  9. data/lib/active_record/associations/association_proxy.rb +20 -18
  10. data/lib/active_record/associations/belongs_to_association.rb +8 -8
  11. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +13 -35
  12. data/lib/active_record/associations/has_many_association.rb +11 -19
  13. data/lib/active_record/associations/has_many_through_association.rb +30 -183
  14. data/lib/active_record/associations/has_one_association.rb +10 -10
  15. data/lib/active_record/associations/has_one_through_association.rb +13 -11
  16. data/lib/active_record/associations/through_association_scope.rb +153 -0
  17. data/lib/active_record/attribute_methods.rb +17 -370
  18. data/lib/active_record/attribute_methods/before_type_cast.rb +33 -0
  19. data/lib/active_record/attribute_methods/dirty.rb +87 -0
  20. data/lib/active_record/attribute_methods/primary_key.rb +44 -0
  21. data/lib/active_record/attribute_methods/query.rb +37 -0
  22. data/lib/active_record/attribute_methods/read.rb +116 -0
  23. data/lib/active_record/attribute_methods/time_zone_conversion.rb +60 -0
  24. data/lib/active_record/attribute_methods/write.rb +37 -0
  25. data/lib/active_record/autosave_association.rb +20 -41
  26. data/lib/active_record/base.rb +357 -1180
  27. data/lib/active_record/batches.rb +10 -16
  28. data/lib/active_record/callbacks.rb +66 -126
  29. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +17 -13
  30. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +5 -25
  31. data/lib/active_record/connection_adapters/abstract/database_statements.rb +4 -43
  32. data/lib/active_record/connection_adapters/abstract/query_cache.rb +3 -2
  33. data/lib/active_record/connection_adapters/abstract/quoting.rb +15 -4
  34. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +1 -1
  35. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +18 -72
  36. data/lib/active_record/connection_adapters/abstract_adapter.rb +16 -49
  37. data/lib/active_record/connection_adapters/mysql_adapter.rb +15 -27
  38. data/lib/active_record/connection_adapters/postgresql_adapter.rb +84 -46
  39. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +9 -3
  40. data/lib/active_record/connection_adapters/sqlite_adapter.rb +34 -65
  41. data/lib/active_record/fixtures.rb +21 -25
  42. data/lib/active_record/locale/en.yml +9 -27
  43. data/lib/active_record/locking/optimistic.rb +16 -48
  44. data/lib/active_record/migration.rb +59 -46
  45. data/lib/active_record/named_scope.rb +85 -92
  46. data/lib/active_record/nested_attributes.rb +18 -24
  47. data/lib/active_record/observer.rb +18 -94
  48. data/lib/active_record/railtie.rb +83 -0
  49. data/lib/active_record/railties/controller_runtime.rb +38 -0
  50. data/lib/active_record/railties/databases.rake +477 -0
  51. data/lib/active_record/railties/subscriber.rb +27 -0
  52. data/lib/active_record/reflection.rb +2 -15
  53. data/lib/active_record/relation.rb +339 -0
  54. data/lib/active_record/relation/calculations.rb +259 -0
  55. data/lib/active_record/relation/finder_methods.rb +315 -0
  56. data/lib/active_record/relation/predicate_builder.rb +46 -0
  57. data/lib/active_record/relation/query_methods.rb +218 -0
  58. data/lib/active_record/relation/spawn_methods.rb +102 -0
  59. data/lib/active_record/schema_dumper.rb +10 -6
  60. data/lib/active_record/serialization.rb +31 -74
  61. data/lib/active_record/serializers/xml_serializer.rb +33 -121
  62. data/lib/active_record/session_store.rb +1 -9
  63. data/lib/active_record/test_case.rb +1 -3
  64. data/lib/active_record/timestamp.rb +7 -5
  65. data/lib/active_record/transactions.rb +9 -9
  66. data/lib/active_record/validations.rb +51 -1100
  67. data/lib/active_record/validations/associated.rb +47 -0
  68. data/lib/active_record/validations/uniqueness.rb +181 -0
  69. data/lib/active_record/version.rb +3 -3
  70. data/lib/generators/active_record.rb +30 -0
  71. data/lib/generators/active_record/migration/migration_generator.rb +25 -0
  72. data/lib/generators/active_record/migration/templates/migration.rb +11 -0
  73. data/lib/generators/active_record/model/model_generator.rb +33 -0
  74. data/lib/generators/active_record/model/templates/migration.rb +16 -0
  75. data/lib/generators/active_record/model/templates/model.rb +5 -0
  76. data/lib/generators/active_record/observer/observer_generator.rb +15 -0
  77. data/lib/generators/active_record/observer/templates/observer.rb +2 -0
  78. data/lib/generators/active_record/session_migration/session_migration_generator.rb +24 -0
  79. data/lib/generators/active_record/session_migration/templates/migration.rb +16 -0
  80. metadata +67 -325
  81. data/RUNNING_UNIT_TESTS +0 -36
  82. data/Rakefile +0 -268
  83. data/install.rb +0 -30
  84. data/lib/active_record/calculations.rb +0 -321
  85. data/lib/active_record/connection_adapters/abstract/database_limits.rb +0 -57
  86. data/lib/active_record/dirty.rb +0 -183
  87. data/lib/active_record/serializers/json_serializer.rb +0 -91
  88. data/lib/activerecord.rb +0 -2
  89. data/test/assets/example.log +0 -1
  90. data/test/assets/flowers.jpg +0 -0
  91. data/test/cases/aaa_create_tables_test.rb +0 -24
  92. data/test/cases/active_schema_test_mysql.rb +0 -122
  93. data/test/cases/active_schema_test_postgresql.rb +0 -24
  94. data/test/cases/adapter_test.rb +0 -144
  95. data/test/cases/aggregations_test.rb +0 -167
  96. data/test/cases/ar_schema_test.rb +0 -32
  97. data/test/cases/associations/belongs_to_associations_test.rb +0 -438
  98. data/test/cases/associations/callbacks_test.rb +0 -161
  99. data/test/cases/associations/cascaded_eager_loading_test.rb +0 -131
  100. data/test/cases/associations/eager_load_includes_full_sti_class_test.rb +0 -36
  101. data/test/cases/associations/eager_load_nested_include_test.rb +0 -131
  102. data/test/cases/associations/eager_load_nested_polymorphic_include.rb +0 -19
  103. data/test/cases/associations/eager_singularization_test.rb +0 -145
  104. data/test/cases/associations/eager_test.rb +0 -852
  105. data/test/cases/associations/extension_test.rb +0 -62
  106. data/test/cases/associations/habtm_join_table_test.rb +0 -56
  107. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +0 -827
  108. data/test/cases/associations/has_many_associations_test.rb +0 -1273
  109. data/test/cases/associations/has_many_through_associations_test.rb +0 -360
  110. data/test/cases/associations/has_one_associations_test.rb +0 -330
  111. data/test/cases/associations/has_one_through_associations_test.rb +0 -209
  112. data/test/cases/associations/inner_join_association_test.rb +0 -93
  113. data/test/cases/associations/inverse_associations_test.rb +0 -566
  114. data/test/cases/associations/join_model_test.rb +0 -712
  115. data/test/cases/associations_test.rb +0 -282
  116. data/test/cases/attribute_methods_test.rb +0 -305
  117. data/test/cases/autosave_association_test.rb +0 -1218
  118. data/test/cases/base_test.rb +0 -2166
  119. data/test/cases/batches_test.rb +0 -81
  120. data/test/cases/binary_test.rb +0 -30
  121. data/test/cases/calculations_test.rb +0 -360
  122. data/test/cases/callbacks_observers_test.rb +0 -38
  123. data/test/cases/callbacks_test.rb +0 -438
  124. data/test/cases/class_inheritable_attributes_test.rb +0 -32
  125. data/test/cases/column_alias_test.rb +0 -17
  126. data/test/cases/column_definition_test.rb +0 -70
  127. data/test/cases/connection_pool_test.rb +0 -25
  128. data/test/cases/connection_test_firebird.rb +0 -8
  129. data/test/cases/connection_test_mysql.rb +0 -65
  130. data/test/cases/copy_table_test_sqlite.rb +0 -80
  131. data/test/cases/counter_cache_test.rb +0 -84
  132. data/test/cases/database_statements_test.rb +0 -12
  133. data/test/cases/datatype_test_postgresql.rb +0 -204
  134. data/test/cases/date_time_test.rb +0 -37
  135. data/test/cases/default_test_firebird.rb +0 -16
  136. data/test/cases/defaults_test.rb +0 -111
  137. data/test/cases/deprecated_finder_test.rb +0 -30
  138. data/test/cases/dirty_test.rb +0 -316
  139. data/test/cases/finder_respond_to_test.rb +0 -76
  140. data/test/cases/finder_test.rb +0 -1098
  141. data/test/cases/fixtures_test.rb +0 -661
  142. data/test/cases/helper.rb +0 -68
  143. data/test/cases/i18n_test.rb +0 -46
  144. data/test/cases/inheritance_test.rb +0 -262
  145. data/test/cases/invalid_date_test.rb +0 -24
  146. data/test/cases/json_serialization_test.rb +0 -219
  147. data/test/cases/lifecycle_test.rb +0 -193
  148. data/test/cases/locking_test.rb +0 -350
  149. data/test/cases/method_scoping_test.rb +0 -704
  150. data/test/cases/migration_test.rb +0 -1649
  151. data/test/cases/migration_test_firebird.rb +0 -124
  152. data/test/cases/mixin_test.rb +0 -96
  153. data/test/cases/modules_test.rb +0 -109
  154. data/test/cases/multiple_db_test.rb +0 -85
  155. data/test/cases/named_scope_test.rb +0 -372
  156. data/test/cases/nested_attributes_test.rb +0 -840
  157. data/test/cases/pk_test.rb +0 -119
  158. data/test/cases/pooled_connections_test.rb +0 -103
  159. data/test/cases/query_cache_test.rb +0 -129
  160. data/test/cases/readonly_test.rb +0 -107
  161. data/test/cases/reflection_test.rb +0 -234
  162. data/test/cases/reload_models_test.rb +0 -22
  163. data/test/cases/repair_helper.rb +0 -50
  164. data/test/cases/reserved_word_test_mysql.rb +0 -176
  165. data/test/cases/sanitize_test.rb +0 -25
  166. data/test/cases/schema_authorization_test_postgresql.rb +0 -75
  167. data/test/cases/schema_dumper_test.rb +0 -211
  168. data/test/cases/schema_test_postgresql.rb +0 -178
  169. data/test/cases/serialization_test.rb +0 -47
  170. data/test/cases/sp_test_mysql.rb +0 -16
  171. data/test/cases/synonym_test_oracle.rb +0 -17
  172. data/test/cases/timestamp_test.rb +0 -75
  173. data/test/cases/transactions_test.rb +0 -543
  174. data/test/cases/unconnected_test.rb +0 -32
  175. data/test/cases/validations_i18n_test.rb +0 -925
  176. data/test/cases/validations_test.rb +0 -1684
  177. data/test/cases/xml_serialization_test.rb +0 -240
  178. data/test/cases/yaml_serialization_test.rb +0 -11
  179. data/test/config.rb +0 -5
  180. data/test/connections/jdbc_jdbcderby/connection.rb +0 -18
  181. data/test/connections/jdbc_jdbch2/connection.rb +0 -18
  182. data/test/connections/jdbc_jdbchsqldb/connection.rb +0 -18
  183. data/test/connections/jdbc_jdbcmysql/connection.rb +0 -26
  184. data/test/connections/jdbc_jdbcpostgresql/connection.rb +0 -26
  185. data/test/connections/jdbc_jdbcsqlite3/connection.rb +0 -25
  186. data/test/connections/native_db2/connection.rb +0 -25
  187. data/test/connections/native_firebird/connection.rb +0 -26
  188. data/test/connections/native_frontbase/connection.rb +0 -27
  189. data/test/connections/native_mysql/connection.rb +0 -25
  190. data/test/connections/native_openbase/connection.rb +0 -21
  191. data/test/connections/native_oracle/connection.rb +0 -27
  192. data/test/connections/native_postgresql/connection.rb +0 -21
  193. data/test/connections/native_sqlite/connection.rb +0 -25
  194. data/test/connections/native_sqlite3/connection.rb +0 -25
  195. data/test/connections/native_sqlite3/in_memory_connection.rb +0 -18
  196. data/test/connections/native_sybase/connection.rb +0 -23
  197. data/test/fixtures/accounts.yml +0 -29
  198. data/test/fixtures/all/developers.yml +0 -0
  199. data/test/fixtures/all/people.csv +0 -0
  200. data/test/fixtures/all/tasks.yml +0 -0
  201. data/test/fixtures/author_addresses.yml +0 -5
  202. data/test/fixtures/author_favorites.yml +0 -4
  203. data/test/fixtures/authors.yml +0 -9
  204. data/test/fixtures/binaries.yml +0 -132
  205. data/test/fixtures/books.yml +0 -7
  206. data/test/fixtures/categories.yml +0 -14
  207. data/test/fixtures/categories/special_categories.yml +0 -9
  208. data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +0 -4
  209. data/test/fixtures/categories_ordered.yml +0 -7
  210. data/test/fixtures/categories_posts.yml +0 -23
  211. data/test/fixtures/categorizations.yml +0 -17
  212. data/test/fixtures/clubs.yml +0 -6
  213. data/test/fixtures/comments.yml +0 -59
  214. data/test/fixtures/companies.yml +0 -56
  215. data/test/fixtures/computers.yml +0 -4
  216. data/test/fixtures/courses.yml +0 -7
  217. data/test/fixtures/customers.yml +0 -26
  218. data/test/fixtures/developers.yml +0 -21
  219. data/test/fixtures/developers_projects.yml +0 -17
  220. data/test/fixtures/edges.yml +0 -6
  221. data/test/fixtures/entrants.yml +0 -14
  222. data/test/fixtures/faces.yml +0 -11
  223. data/test/fixtures/fk_test_has_fk.yml +0 -3
  224. data/test/fixtures/fk_test_has_pk.yml +0 -2
  225. data/test/fixtures/funny_jokes.yml +0 -10
  226. data/test/fixtures/interests.yml +0 -33
  227. data/test/fixtures/items.yml +0 -4
  228. data/test/fixtures/jobs.yml +0 -7
  229. data/test/fixtures/legacy_things.yml +0 -3
  230. data/test/fixtures/mateys.yml +0 -4
  231. data/test/fixtures/member_types.yml +0 -6
  232. data/test/fixtures/members.yml +0 -6
  233. data/test/fixtures/memberships.yml +0 -20
  234. data/test/fixtures/men.yml +0 -5
  235. data/test/fixtures/minimalistics.yml +0 -2
  236. data/test/fixtures/mixed_case_monkeys.yml +0 -6
  237. data/test/fixtures/mixins.yml +0 -29
  238. data/test/fixtures/movies.yml +0 -7
  239. data/test/fixtures/naked/csv/accounts.csv +0 -1
  240. data/test/fixtures/naked/yml/accounts.yml +0 -1
  241. data/test/fixtures/naked/yml/companies.yml +0 -1
  242. data/test/fixtures/naked/yml/courses.yml +0 -1
  243. data/test/fixtures/organizations.yml +0 -5
  244. data/test/fixtures/owners.yml +0 -7
  245. data/test/fixtures/parrots.yml +0 -27
  246. data/test/fixtures/parrots_pirates.yml +0 -7
  247. data/test/fixtures/people.yml +0 -15
  248. data/test/fixtures/pets.yml +0 -14
  249. data/test/fixtures/pirates.yml +0 -9
  250. data/test/fixtures/polymorphic_designs.yml +0 -19
  251. data/test/fixtures/polymorphic_prices.yml +0 -19
  252. data/test/fixtures/posts.yml +0 -52
  253. data/test/fixtures/price_estimates.yml +0 -7
  254. data/test/fixtures/projects.yml +0 -7
  255. data/test/fixtures/readers.yml +0 -9
  256. data/test/fixtures/references.yml +0 -17
  257. data/test/fixtures/reserved_words/distinct.yml +0 -5
  258. data/test/fixtures/reserved_words/distincts_selects.yml +0 -11
  259. data/test/fixtures/reserved_words/group.yml +0 -14
  260. data/test/fixtures/reserved_words/select.yml +0 -8
  261. data/test/fixtures/reserved_words/values.yml +0 -7
  262. data/test/fixtures/ships.yml +0 -5
  263. data/test/fixtures/sponsors.yml +0 -9
  264. data/test/fixtures/subscribers.yml +0 -7
  265. data/test/fixtures/subscriptions.yml +0 -12
  266. data/test/fixtures/taggings.yml +0 -28
  267. data/test/fixtures/tags.yml +0 -7
  268. data/test/fixtures/tasks.yml +0 -7
  269. data/test/fixtures/tees.yml +0 -4
  270. data/test/fixtures/ties.yml +0 -4
  271. data/test/fixtures/topics.yml +0 -42
  272. data/test/fixtures/toys.yml +0 -4
  273. data/test/fixtures/treasures.yml +0 -10
  274. data/test/fixtures/vertices.yml +0 -4
  275. data/test/fixtures/warehouse-things.yml +0 -3
  276. data/test/fixtures/zines.yml +0 -5
  277. data/test/migrations/broken/100_migration_that_raises_exception.rb +0 -10
  278. data/test/migrations/decimal/1_give_me_big_numbers.rb +0 -15
  279. data/test/migrations/duplicate/1_people_have_last_names.rb +0 -9
  280. data/test/migrations/duplicate/2_we_need_reminders.rb +0 -12
  281. data/test/migrations/duplicate/3_foo.rb +0 -7
  282. data/test/migrations/duplicate/3_innocent_jointable.rb +0 -12
  283. data/test/migrations/duplicate_names/20080507052938_chunky.rb +0 -7
  284. data/test/migrations/duplicate_names/20080507053028_chunky.rb +0 -7
  285. data/test/migrations/interleaved/pass_1/3_innocent_jointable.rb +0 -12
  286. data/test/migrations/interleaved/pass_2/1_people_have_last_names.rb +0 -9
  287. data/test/migrations/interleaved/pass_2/3_innocent_jointable.rb +0 -12
  288. data/test/migrations/interleaved/pass_3/1_people_have_last_names.rb +0 -9
  289. data/test/migrations/interleaved/pass_3/2_i_raise_on_down.rb +0 -8
  290. data/test/migrations/interleaved/pass_3/3_innocent_jointable.rb +0 -12
  291. data/test/migrations/missing/1000_people_have_middle_names.rb +0 -9
  292. data/test/migrations/missing/1_people_have_last_names.rb +0 -9
  293. data/test/migrations/missing/3_we_need_reminders.rb +0 -12
  294. data/test/migrations/missing/4_innocent_jointable.rb +0 -12
  295. data/test/migrations/valid/1_people_have_last_names.rb +0 -9
  296. data/test/migrations/valid/2_we_need_reminders.rb +0 -12
  297. data/test/migrations/valid/3_innocent_jointable.rb +0 -12
  298. data/test/models/author.rb +0 -151
  299. data/test/models/auto_id.rb +0 -4
  300. data/test/models/binary.rb +0 -2
  301. data/test/models/bird.rb +0 -9
  302. data/test/models/book.rb +0 -4
  303. data/test/models/categorization.rb +0 -5
  304. data/test/models/category.rb +0 -34
  305. data/test/models/citation.rb +0 -6
  306. data/test/models/club.rb +0 -13
  307. data/test/models/column_name.rb +0 -3
  308. data/test/models/comment.rb +0 -29
  309. data/test/models/company.rb +0 -173
  310. data/test/models/company_in_module.rb +0 -78
  311. data/test/models/computer.rb +0 -3
  312. data/test/models/contact.rb +0 -16
  313. data/test/models/contract.rb +0 -5
  314. data/test/models/course.rb +0 -3
  315. data/test/models/customer.rb +0 -73
  316. data/test/models/default.rb +0 -2
  317. data/test/models/developer.rb +0 -101
  318. data/test/models/edge.rb +0 -5
  319. data/test/models/entrant.rb +0 -3
  320. data/test/models/essay.rb +0 -3
  321. data/test/models/event.rb +0 -3
  322. data/test/models/event_author.rb +0 -8
  323. data/test/models/face.rb +0 -7
  324. data/test/models/guid.rb +0 -2
  325. data/test/models/interest.rb +0 -5
  326. data/test/models/invoice.rb +0 -4
  327. data/test/models/item.rb +0 -7
  328. data/test/models/job.rb +0 -5
  329. data/test/models/joke.rb +0 -3
  330. data/test/models/keyboard.rb +0 -3
  331. data/test/models/legacy_thing.rb +0 -3
  332. data/test/models/line_item.rb +0 -3
  333. data/test/models/man.rb +0 -9
  334. data/test/models/matey.rb +0 -4
  335. data/test/models/member.rb +0 -12
  336. data/test/models/member_detail.rb +0 -5
  337. data/test/models/member_type.rb +0 -3
  338. data/test/models/membership.rb +0 -9
  339. data/test/models/minimalistic.rb +0 -2
  340. data/test/models/mixed_case_monkey.rb +0 -3
  341. data/test/models/movie.rb +0 -5
  342. data/test/models/order.rb +0 -4
  343. data/test/models/organization.rb +0 -6
  344. data/test/models/owner.rb +0 -5
  345. data/test/models/parrot.rb +0 -22
  346. data/test/models/person.rb +0 -16
  347. data/test/models/pet.rb +0 -5
  348. data/test/models/pirate.rb +0 -80
  349. data/test/models/polymorphic_design.rb +0 -3
  350. data/test/models/polymorphic_price.rb +0 -3
  351. data/test/models/post.rb +0 -102
  352. data/test/models/price_estimate.rb +0 -3
  353. data/test/models/project.rb +0 -30
  354. data/test/models/reader.rb +0 -4
  355. data/test/models/reference.rb +0 -4
  356. data/test/models/reply.rb +0 -46
  357. data/test/models/ship.rb +0 -19
  358. data/test/models/ship_part.rb +0 -7
  359. data/test/models/sponsor.rb +0 -4
  360. data/test/models/subject.rb +0 -4
  361. data/test/models/subscriber.rb +0 -8
  362. data/test/models/subscription.rb +0 -4
  363. data/test/models/tag.rb +0 -7
  364. data/test/models/tagging.rb +0 -10
  365. data/test/models/task.rb +0 -3
  366. data/test/models/tee.rb +0 -4
  367. data/test/models/tie.rb +0 -4
  368. data/test/models/topic.rb +0 -80
  369. data/test/models/toy.rb +0 -6
  370. data/test/models/treasure.rb +0 -8
  371. data/test/models/vertex.rb +0 -9
  372. data/test/models/warehouse_thing.rb +0 -5
  373. data/test/models/zine.rb +0 -3
  374. data/test/schema/mysql_specific_schema.rb +0 -31
  375. data/test/schema/postgresql_specific_schema.rb +0 -114
  376. data/test/schema/schema.rb +0 -550
  377. data/test/schema/schema2.rb +0 -6
  378. data/test/schema/sqlite_specific_schema.rb +0 -25
@@ -0,0 +1,102 @@
1
+ module ActiveRecord
2
+ module SpawnMethods
3
+ def spawn
4
+ clone.reset
5
+ end
6
+
7
+ def merge(r)
8
+ merged_relation = spawn
9
+ return merged_relation unless r
10
+
11
+ merged_relation = merged_relation.eager_load(r.eager_load_values).preload(r.preload_values).includes(r.includes_values)
12
+
13
+ merged_relation.readonly_value = r.readonly_value unless r.readonly_value.nil?
14
+ merged_relation.limit_value = r.limit_value if r.limit_value.present?
15
+ merged_relation.lock_value = r.lock_value unless merged_relation.lock_value
16
+ merged_relation.offset_value = r.offset_value if r.offset_value.present?
17
+
18
+ merged_relation = merged_relation.
19
+ joins(r.joins_values).
20
+ group(r.group_values).
21
+ select(r.select_values).
22
+ from(r.from_value).
23
+ having(r.having_values)
24
+
25
+ merged_relation.order_values = r.order_values if r.order_values.present?
26
+
27
+ merged_relation.create_with_value = @create_with_value
28
+
29
+ if @create_with_value && r.create_with_value
30
+ merged_relation.create_with_value = @create_with_value.merge(r.create_with_value)
31
+ else
32
+ merged_relation.create_with_value = r.create_with_value || @create_with_value
33
+ end
34
+
35
+ merged_wheres = @where_values
36
+
37
+ r.where_values.each do |w|
38
+ if w.is_a?(Arel::Predicates::Equality)
39
+ merged_wheres = merged_wheres.reject {|p| p.is_a?(Arel::Predicates::Equality) && p.operand1.name == w.operand1.name }
40
+ end
41
+
42
+ merged_wheres += [w]
43
+ end
44
+
45
+ merged_relation.where_values = merged_wheres
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,
83
+ :order, :select, :readonly, :group, :having, :from, :lock ]
84
+
85
+ def apply_finder_options(options)
86
+ relation = spawn
87
+ return relation unless options
88
+
89
+ options.assert_valid_keys(VALID_FIND_OPTIONS)
90
+
91
+ [:joins, :select, :group, :having, :order, :limit, :offset, :from, :lock, :readonly].each do |finder|
92
+ relation = relation.send(finder, options[finder]) if options.has_key?(finder)
93
+ end
94
+
95
+ relation = relation.where(options[:conditions]) if options.has_key?(:conditions)
96
+ relation = relation.includes(options[:include]) if options.has_key?(:include)
97
+
98
+ relation
99
+ end
100
+
101
+ end
102
+ end
@@ -1,5 +1,5 @@
1
1
  require 'stringio'
2
- require 'bigdecimal'
2
+ require 'active_support/core_ext/big_decimal'
3
3
 
4
4
  module ActiveRecord
5
5
  # This class is used to dump the database schema for some connection to some
@@ -102,8 +102,15 @@ HEADER
102
102
  next if column.name == pk
103
103
  spec = {}
104
104
  spec[:name] = column.name.inspect
105
- spec[:type] = column.type.to_s
106
- spec[:limit] = column.limit.inspect if column.limit != @types[column.type][:limit] && column.type != :decimal
105
+
106
+ # AR has an optimisation which handles zero-scale decimals as integers. This
107
+ # code ensures that the dumper still dumps the column as a decimal.
108
+ spec[:type] = if column.type == :integer && [/^numeric/, /^decimal/].any? { |e| e.match(column.sql_type) }
109
+ 'decimal'
110
+ else
111
+ column.type.to_s
112
+ end
113
+ spec[:limit] = column.limit.inspect if column.limit != @types[column.type][:limit] && spec[:type] != 'decimal'
107
114
  spec[:precision] = column.precision.inspect if !column.precision.nil?
108
115
  spec[:scale] = column.scale.inspect if !column.scale.nil?
109
116
  spec[:null] = 'false' if !column.null
@@ -171,9 +178,6 @@ HEADER
171
178
  statment_parts << (':name => ' + index.name.inspect)
172
179
  statment_parts << ':unique => true' if index.unique
173
180
 
174
- index_lengths = index.lengths.compact if index.lengths.is_a?(Array)
175
- statment_parts << (':length => ' + Hash[*index.columns.zip(index.lengths).flatten].inspect) if index_lengths.present?
176
-
177
181
  ' ' + statment_parts.join(', ')
178
182
  end
179
183
 
@@ -1,101 +1,58 @@
1
- require 'active_support/json'
2
-
3
1
  module ActiveRecord #:nodoc:
4
2
  module Serialization
5
- class Serializer #:nodoc:
6
- attr_reader :options
7
-
8
- def initialize(record, options = nil)
9
- @record = record
10
- @options = options ? options.dup : {}
11
- end
3
+ extend ActiveSupport::Concern
4
+ include ActiveModel::Serializers::JSON
12
5
 
13
- # To replicate the behavior in ActiveRecord#attributes,
14
- # <tt>:except</tt> takes precedence over <tt>:only</tt>. If <tt>:only</tt> is not set
15
- # for a N level model but is set for the N+1 level models,
16
- # then because <tt>:except</tt> is set to a default value, the second
17
- # level model can have both <tt>:except</tt> and <tt>:only</tt> set. So if
18
- # <tt>:only</tt> is set, always delete <tt>:except</tt>.
19
- def serializable_attribute_names
20
- attribute_names = @record.attribute_names
6
+ def serializable_hash(options = nil)
7
+ options ||= {}
21
8
 
22
- if options[:only]
23
- options.delete(:except)
24
- attribute_names = attribute_names & Array(options[:only]).collect { |n| n.to_s }
25
- else
26
- options[:except] = Array(options[:except]) | Array(@record.class.inheritance_column)
27
- attribute_names = attribute_names - options[:except].collect { |n| n.to_s }
28
- end
9
+ options[:except] = Array.wrap(options[:except]).map { |n| n.to_s }
10
+ options[:except] |= Array.wrap(self.class.inheritance_column)
29
11
 
30
- attribute_names
31
- end
12
+ hash = super(options)
32
13
 
33
- def serializable_method_names
34
- Array(options[:methods]).inject([]) do |method_attributes, name|
35
- method_attributes << name if @record.respond_to?(name.to_s)
36
- method_attributes
37
- end
14
+ serializable_add_includes(options) do |association, records, opts|
15
+ hash[association] = records.is_a?(Enumerable) ?
16
+ records.map { |r| r.serializable_hash(opts) } :
17
+ records.serializable_hash(opts)
38
18
  end
39
19
 
40
- def serializable_names
41
- serializable_attribute_names + serializable_method_names
42
- end
20
+ hash
21
+ end
43
22
 
23
+ private
44
24
  # Add associations specified via the <tt>:includes</tt> option.
45
25
  # Expects a block that takes as arguments:
46
26
  # +association+ - name of the association
47
27
  # +records+ - the association record(s) to be serialized
48
28
  # +opts+ - options for the association records
49
- def add_includes(&block)
50
- if include_associations = options.delete(:include)
51
- base_only_or_except = { :except => options[:except],
52
- :only => options[:only] }
29
+ def serializable_add_includes(options = {})
30
+ return unless include_associations = options.delete(:include)
53
31
 
54
- include_has_options = include_associations.is_a?(Hash)
55
- associations = include_has_options ? include_associations.keys : Array(include_associations)
32
+ base_only_or_except = { :except => options[:except],
33
+ :only => options[:only] }
56
34
 
57
- for association in associations
58
- records = case @record.class.reflect_on_association(association).macro
59
- when :has_many, :has_and_belongs_to_many
60
- @record.send(association).to_a
61
- when :has_one, :belongs_to
62
- @record.send(association)
63
- end
35
+ include_has_options = include_associations.is_a?(Hash)
36
+ associations = include_has_options ? include_associations.keys : Array.wrap(include_associations)
64
37
 
65
- unless records.nil?
66
- association_options = include_has_options ? include_associations[association] : base_only_or_except
67
- opts = options.merge(association_options)
68
- yield(association, records, opts)
69
- end
38
+ for association in associations
39
+ records = case self.class.reflect_on_association(association).macro
40
+ when :has_many, :has_and_belongs_to_many
41
+ send(association).to_a
42
+ when :has_one, :belongs_to
43
+ send(association)
70
44
  end
71
45
 
72
- options[:include] = include_associations
73
- end
74
- end
75
-
76
- def serializable_record
77
- {}.tap do |serializable_record|
78
- serializable_names.each { |name| serializable_record[name] = @record.send(name) }
79
- add_includes do |association, records, opts|
80
- if records.is_a?(Enumerable)
81
- serializable_record[association] = records.collect { |r| self.class.new(r, opts).serializable_record }
82
- else
83
- serializable_record[association] = self.class.new(records, opts).serializable_record
84
- end
46
+ unless records.nil?
47
+ association_options = include_has_options ? include_associations[association] : base_only_or_except
48
+ opts = options.merge(association_options)
49
+ yield(association, records, opts)
85
50
  end
86
51
  end
87
- end
88
52
 
89
- def serialize
90
- # overwrite to implement
53
+ options[:include] = include_associations
91
54
  end
92
-
93
- def to_s(&block)
94
- serialize(&block)
95
- end
96
- end
97
55
  end
98
56
  end
99
57
 
100
58
  require 'active_record/serializers/xml_serializer'
101
- require 'active_record/serializers/json_serializer'
@@ -1,5 +1,9 @@
1
+ require 'active_support/core_ext/hash/conversions'
2
+
1
3
  module ActiveRecord #:nodoc:
2
4
  module Serialization
5
+ include ActiveModel::Serializers::Xml
6
+
3
7
  # Builds an XML document to represent the model. Some configuration is
4
8
  # available through +options+. However more complicated cases should
5
9
  # override ActiveRecord::Base#to_xml.
@@ -69,6 +73,21 @@ module ActiveRecord #:nodoc:
69
73
  # </account>
70
74
  # </firm>
71
75
  #
76
+ # Additionally, the record being serialized will be passed to a Proc's second
77
+ # parameter. This allows for ad hoc additions to the resultant document that
78
+ # incorporate the context of the record being serialized. And by leveraging the
79
+ # closure created by a Proc, to_xml can be used to add elements that normally fall
80
+ # outside of the scope of the model -- for example, generating and appending URLs
81
+ # associated with models.
82
+ #
83
+ # proc = Proc.new { |options, record| options[:builder].tag!('name-reverse', record.name.reverse) }
84
+ # firm.to_xml :procs => [ proc ]
85
+ #
86
+ # <firm>
87
+ # # ... normal attributes as shown above ...
88
+ # <name-reverse>slangis73</name-reverse>
89
+ # </firm>
90
+ #
72
91
  # To include deeper levels of associations pass a hash like this:
73
92
  #
74
93
  # firm.to_xml :include => {:account => {}, :clients => {:include => :address}}
@@ -152,82 +171,27 @@ module ActiveRecord #:nodoc:
152
171
  # end
153
172
  # end
154
173
  def to_xml(options = {}, &block)
155
- serializer = XmlSerializer.new(self, options)
156
- block_given? ? serializer.to_s(&block) : serializer.to_s
157
- end
158
-
159
- def from_xml(xml)
160
- self.attributes = Hash.from_xml(xml).values.first
161
- self
174
+ XmlSerializer.new(self, options).serialize(&block)
162
175
  end
163
176
  end
164
177
 
165
- class XmlSerializer < ActiveRecord::Serialization::Serializer #:nodoc:
166
- def builder
167
- @builder ||= begin
168
- options[:indent] ||= 2
169
- builder = options[:builder] ||= Builder::XmlMarkup.new(:indent => options[:indent])
170
-
171
- unless options[:skip_instruct]
172
- builder.instruct!
173
- options[:skip_instruct] = true
174
- end
175
-
176
- builder
177
- end
178
- end
179
-
180
- def root
181
- root = (options[:root] || @record.class.model_name.singular).to_s
182
- reformat_name(root)
183
- end
184
-
185
- def dasherize?
186
- !options.has_key?(:dasherize) || options[:dasherize]
187
- end
188
-
189
- def camelize?
190
- options.has_key?(:camelize) && options[:camelize]
191
- end
192
-
193
- def reformat_name(name)
194
- name = name.camelize if camelize?
195
- dasherize? ? name.dasherize : name
178
+ class XmlSerializer < ActiveModel::Serializers::Xml::Serializer #:nodoc:
179
+ def initialize(*args)
180
+ super
181
+ options[:except] |= Array.wrap(@serializable.class.inheritance_column)
196
182
  end
197
183
 
198
184
  def serializable_attributes
199
- serializable_attribute_names.collect { |name| Attribute.new(name, @record) }
185
+ serializable_attribute_names.collect { |name| Attribute.new(name, @serializable) }
200
186
  end
201
187
 
202
188
  def serializable_method_attributes
203
189
  Array(options[:methods]).inject([]) do |method_attributes, name|
204
- method_attributes << MethodAttribute.new(name.to_s, @record) if @record.respond_to?(name.to_s)
190
+ method_attributes << MethodAttribute.new(name.to_s, @serializable) if @serializable.respond_to?(name.to_s)
205
191
  method_attributes
206
192
  end
207
193
  end
208
194
 
209
- def add_attributes
210
- (serializable_attributes + serializable_method_attributes).each do |attribute|
211
- add_tag(attribute)
212
- end
213
- end
214
-
215
- def add_procs
216
- if procs = options.delete(:procs)
217
- [ *procs ].each do |proc|
218
- proc.call(options)
219
- end
220
- end
221
- end
222
-
223
- def add_tag(attribute)
224
- builder.tag!(
225
- reformat_name(attribute.name),
226
- attribute.value.to_s,
227
- attribute.decorations(!options[:skip_types])
228
- )
229
- end
230
-
231
195
  def add_associations(association, records, opts)
232
196
  if records.is_a?(Enumerable)
233
197
  tag = reformat_name(association.to_s)
@@ -251,7 +215,7 @@ module ActiveRecord #:nodoc:
251
215
  end
252
216
  end
253
217
  else
254
- if record = @record.send(association)
218
+ if record = @serializable.send(association)
255
219
  record.to_xml(opts.merge(:root => association))
256
220
  end
257
221
  end
@@ -270,61 +234,19 @@ module ActiveRecord #:nodoc:
270
234
  builder.tag!(*args) do
271
235
  add_attributes
272
236
  procs = options.delete(:procs)
273
- add_includes { |association, records, opts| add_associations(association, records, opts) }
237
+ @serializable.send(:serializable_add_includes, options) { |association, records, opts|
238
+ add_associations(association, records, opts)
239
+ }
274
240
  options[:procs] = procs
275
241
  add_procs
276
242
  yield builder if block_given?
277
243
  end
278
244
  end
279
245
 
280
- class Attribute #:nodoc:
281
- attr_reader :name, :value, :type
282
-
283
- def initialize(name, record)
284
- @name, @record = name, record
285
-
286
- @type = compute_type
287
- @value = compute_value
288
- end
289
-
290
- # There is a significant speed improvement if the value
291
- # does not need to be escaped, as <tt>tag!</tt> escapes all values
292
- # to ensure that valid XML is generated. For known binary
293
- # values, it is at least an order of magnitude faster to
294
- # Base64 encode binary values and directly put them in the
295
- # output XML than to pass the original value or the Base64
296
- # encoded value to the <tt>tag!</tt> method. It definitely makes
297
- # no sense to Base64 encode the value and then give it to
298
- # <tt>tag!</tt>, since that just adds additional overhead.
299
- def needs_encoding?
300
- ![ :binary, :date, :datetime, :boolean, :float, :integer ].include?(type)
301
- end
302
-
303
- def decorations(include_types = true)
304
- decorations = {}
305
-
306
- if type == :binary
307
- decorations[:encoding] = 'base64'
308
- end
309
-
310
- if include_types && type != :string
311
- decorations[:type] = type
312
- end
313
-
314
- if value.nil?
315
- decorations[:nil] = true
316
- end
317
-
318
- decorations
319
- end
320
-
246
+ class Attribute < ActiveModel::Serializers::Xml::Serializer::Attribute #:nodoc:
321
247
  protected
322
248
  def compute_type
323
- type = if @record.class.serialized_attributes.has_key?(name)
324
- :yaml
325
- else
326
- @record.class.columns_hash[name].try(:type)
327
- end
249
+ type = @serializable.class.serialized_attributes.has_key?(name) ? :yaml : @serializable.class.columns_hash[name].type
328
250
 
329
251
  case type
330
252
  when :text
@@ -335,22 +257,12 @@ module ActiveRecord #:nodoc:
335
257
  type
336
258
  end
337
259
  end
338
-
339
- def compute_value
340
- value = @record.send(name)
341
-
342
- if formatter = Hash::XML_FORMATTING[type.to_s]
343
- value ? formatter.call(value) : nil
344
- else
345
- value
346
- end
347
- end
348
260
  end
349
261
 
350
262
  class MethodAttribute < Attribute #:nodoc:
351
263
  protected
352
264
  def compute_type
353
- Hash::XML_TYPE_NAMES[@record.send(name).class.name] || :string
265
+ Hash::XML_TYPE_NAMES[@serializable.send(name).class.name] || :string
354
266
  end
355
267
  end
356
268
  end