activerecord 1.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (311) hide show
  1. data/CHANGELOG +4928 -3
  2. data/README +45 -46
  3. data/RUNNING_UNIT_TESTS +8 -11
  4. data/Rakefile +247 -0
  5. data/install.rb +8 -38
  6. data/lib/active_record/aggregations.rb +64 -49
  7. data/lib/active_record/associations/association_collection.rb +217 -47
  8. data/lib/active_record/associations/association_proxy.rb +159 -0
  9. data/lib/active_record/associations/belongs_to_association.rb +56 -0
  10. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +50 -0
  11. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +155 -37
  12. data/lib/active_record/associations/has_many_association.rb +145 -75
  13. data/lib/active_record/associations/has_many_through_association.rb +283 -0
  14. data/lib/active_record/associations/has_one_association.rb +96 -0
  15. data/lib/active_record/associations.rb +1537 -304
  16. data/lib/active_record/attribute_methods.rb +328 -0
  17. data/lib/active_record/base.rb +2001 -588
  18. data/lib/active_record/calculations.rb +269 -0
  19. data/lib/active_record/callbacks.rb +169 -165
  20. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +308 -0
  21. data/lib/active_record/connection_adapters/abstract/database_statements.rb +171 -0
  22. data/lib/active_record/connection_adapters/abstract/query_cache.rb +87 -0
  23. data/lib/active_record/connection_adapters/abstract/quoting.rb +69 -0
  24. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +472 -0
  25. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +306 -0
  26. data/lib/active_record/connection_adapters/abstract_adapter.rb +125 -279
  27. data/lib/active_record/connection_adapters/mysql_adapter.rb +442 -77
  28. data/lib/active_record/connection_adapters/postgresql_adapter.rb +805 -135
  29. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +34 -0
  30. data/lib/active_record/connection_adapters/sqlite_adapter.rb +353 -69
  31. data/lib/active_record/fixtures.rb +946 -100
  32. data/lib/active_record/locking/optimistic.rb +144 -0
  33. data/lib/active_record/locking/pessimistic.rb +77 -0
  34. data/lib/active_record/migration.rb +417 -0
  35. data/lib/active_record/observer.rb +142 -32
  36. data/lib/active_record/query_cache.rb +23 -0
  37. data/lib/active_record/reflection.rb +163 -70
  38. data/lib/active_record/schema.rb +58 -0
  39. data/lib/active_record/schema_dumper.rb +171 -0
  40. data/lib/active_record/serialization.rb +98 -0
  41. data/lib/active_record/serializers/json_serializer.rb +71 -0
  42. data/lib/active_record/serializers/xml_serializer.rb +315 -0
  43. data/lib/active_record/timestamp.rb +41 -0
  44. data/lib/active_record/transactions.rb +87 -57
  45. data/lib/active_record/validations.rb +909 -122
  46. data/lib/active_record/vendor/db2.rb +362 -0
  47. data/lib/active_record/vendor/mysql.rb +126 -29
  48. data/lib/active_record/version.rb +9 -0
  49. data/lib/active_record.rb +35 -7
  50. data/lib/activerecord.rb +1 -0
  51. data/test/aaa_create_tables_test.rb +72 -0
  52. data/test/abstract_unit.rb +73 -5
  53. data/test/active_schema_test_mysql.rb +43 -0
  54. data/test/adapter_test.rb +105 -0
  55. data/test/adapter_test_sqlserver.rb +95 -0
  56. data/test/aggregations_test.rb +110 -16
  57. data/test/all.sh +2 -2
  58. data/test/ar_schema_test.rb +33 -0
  59. data/test/association_inheritance_reload.rb +14 -0
  60. data/test/associations/ar_joins_test.rb +0 -0
  61. data/test/associations/callbacks_test.rb +147 -0
  62. data/test/associations/cascaded_eager_loading_test.rb +110 -0
  63. data/test/associations/eager_singularization_test.rb +145 -0
  64. data/test/associations/eager_test.rb +442 -0
  65. data/test/associations/extension_test.rb +47 -0
  66. data/test/associations/inner_join_association_test.rb +88 -0
  67. data/test/associations/join_model_test.rb +553 -0
  68. data/test/associations_test.rb +1930 -267
  69. data/test/attribute_methods_test.rb +146 -0
  70. data/test/base_test.rb +1316 -84
  71. data/test/binary_test.rb +32 -0
  72. data/test/calculations_test.rb +251 -0
  73. data/test/callbacks_test.rb +400 -0
  74. data/test/class_inheritable_attributes_test.rb +3 -4
  75. data/test/column_alias_test.rb +17 -0
  76. data/test/connection_test_firebird.rb +8 -0
  77. data/test/connection_test_mysql.rb +30 -0
  78. data/test/connections/native_db2/connection.rb +25 -0
  79. data/test/connections/native_firebird/connection.rb +26 -0
  80. data/test/connections/native_frontbase/connection.rb +27 -0
  81. data/test/connections/native_mysql/connection.rb +21 -18
  82. data/test/connections/native_openbase/connection.rb +21 -0
  83. data/test/connections/native_oracle/connection.rb +27 -0
  84. data/test/connections/native_postgresql/connection.rb +17 -18
  85. data/test/connections/native_sqlite/connection.rb +17 -16
  86. data/test/connections/native_sqlite3/connection.rb +25 -0
  87. data/test/connections/native_sqlite3/in_memory_connection.rb +18 -0
  88. data/test/connections/native_sybase/connection.rb +23 -0
  89. data/test/copy_table_test_sqlite.rb +69 -0
  90. data/test/datatype_test_postgresql.rb +203 -0
  91. data/test/date_time_test.rb +37 -0
  92. data/test/default_test_firebird.rb +16 -0
  93. data/test/defaults_test.rb +67 -0
  94. data/test/deprecated_finder_test.rb +30 -0
  95. data/test/finder_test.rb +607 -32
  96. data/test/fixtures/accounts.yml +28 -0
  97. data/test/fixtures/all/developers.yml +0 -0
  98. data/test/fixtures/all/people.csv +0 -0
  99. data/test/fixtures/all/tasks.yml +0 -0
  100. data/test/fixtures/author.rb +107 -0
  101. data/test/fixtures/author_favorites.yml +4 -0
  102. data/test/fixtures/authors.yml +7 -0
  103. data/test/fixtures/bad_fixtures/attr_with_numeric_first_char +1 -0
  104. data/test/fixtures/bad_fixtures/attr_with_spaces +1 -0
  105. data/test/fixtures/bad_fixtures/blank_line +3 -0
  106. data/test/fixtures/bad_fixtures/duplicate_attributes +3 -0
  107. data/test/fixtures/bad_fixtures/missing_value +1 -0
  108. data/test/fixtures/binaries.yml +132 -0
  109. data/test/fixtures/binary.rb +2 -0
  110. data/test/fixtures/book.rb +4 -0
  111. data/test/fixtures/books.yml +7 -0
  112. data/test/fixtures/categories/special_categories.yml +9 -0
  113. data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -0
  114. data/test/fixtures/categories.yml +14 -0
  115. data/test/fixtures/categories_ordered.yml +7 -0
  116. data/test/fixtures/categories_posts.yml +23 -0
  117. data/test/fixtures/categorization.rb +5 -0
  118. data/test/fixtures/categorizations.yml +17 -0
  119. data/test/fixtures/category.rb +26 -0
  120. data/test/fixtures/citation.rb +6 -0
  121. data/test/fixtures/comment.rb +23 -0
  122. data/test/fixtures/comments.yml +59 -0
  123. data/test/fixtures/companies.yml +55 -0
  124. data/test/fixtures/company.rb +81 -4
  125. data/test/fixtures/company_in_module.rb +32 -6
  126. data/test/fixtures/computer.rb +4 -0
  127. data/test/fixtures/computers.yml +4 -0
  128. data/test/fixtures/contact.rb +16 -0
  129. data/test/fixtures/courses.yml +7 -0
  130. data/test/fixtures/customer.rb +28 -3
  131. data/test/fixtures/customers.yml +17 -0
  132. data/test/fixtures/db_definitions/db2.drop.sql +33 -0
  133. data/test/fixtures/db_definitions/db2.sql +235 -0
  134. data/test/fixtures/db_definitions/db22.drop.sql +2 -0
  135. data/test/fixtures/db_definitions/db22.sql +5 -0
  136. data/test/fixtures/db_definitions/firebird.drop.sql +65 -0
  137. data/test/fixtures/db_definitions/firebird.sql +310 -0
  138. data/test/fixtures/db_definitions/firebird2.drop.sql +2 -0
  139. data/test/fixtures/db_definitions/firebird2.sql +6 -0
  140. data/test/fixtures/db_definitions/frontbase.drop.sql +33 -0
  141. data/test/fixtures/db_definitions/frontbase.sql +273 -0
  142. data/test/fixtures/db_definitions/frontbase2.drop.sql +1 -0
  143. data/test/fixtures/db_definitions/frontbase2.sql +4 -0
  144. data/test/fixtures/db_definitions/openbase.drop.sql +2 -0
  145. data/test/fixtures/db_definitions/openbase.sql +318 -0
  146. data/test/fixtures/db_definitions/openbase2.drop.sql +2 -0
  147. data/test/fixtures/db_definitions/openbase2.sql +7 -0
  148. data/test/fixtures/db_definitions/oracle.drop.sql +67 -0
  149. data/test/fixtures/db_definitions/oracle.sql +330 -0
  150. data/test/fixtures/db_definitions/oracle2.drop.sql +2 -0
  151. data/test/fixtures/db_definitions/oracle2.sql +6 -0
  152. data/test/fixtures/db_definitions/postgresql.drop.sql +44 -0
  153. data/test/fixtures/db_definitions/postgresql.sql +217 -38
  154. data/test/fixtures/db_definitions/postgresql2.drop.sql +2 -0
  155. data/test/fixtures/db_definitions/postgresql2.sql +2 -2
  156. data/test/fixtures/db_definitions/schema.rb +354 -0
  157. data/test/fixtures/db_definitions/schema2.rb +11 -0
  158. data/test/fixtures/db_definitions/sqlite.drop.sql +33 -0
  159. data/test/fixtures/db_definitions/sqlite.sql +139 -5
  160. data/test/fixtures/db_definitions/sqlite2.drop.sql +2 -0
  161. data/test/fixtures/db_definitions/sqlite2.sql +1 -0
  162. data/test/fixtures/db_definitions/sybase.drop.sql +35 -0
  163. data/test/fixtures/db_definitions/sybase.sql +222 -0
  164. data/test/fixtures/db_definitions/sybase2.drop.sql +4 -0
  165. data/test/fixtures/db_definitions/sybase2.sql +5 -0
  166. data/test/fixtures/developer.rb +70 -6
  167. data/test/fixtures/developers.yml +21 -0
  168. data/test/fixtures/developers_projects/david_action_controller +2 -1
  169. data/test/fixtures/developers_projects/david_active_record +2 -1
  170. data/test/fixtures/developers_projects.yml +17 -0
  171. data/test/fixtures/edge.rb +5 -0
  172. data/test/fixtures/edges.yml +6 -0
  173. data/test/fixtures/entrants.yml +14 -0
  174. data/test/fixtures/example.log +1 -0
  175. data/test/fixtures/fk_test_has_fk.yml +3 -0
  176. data/test/fixtures/fk_test_has_pk.yml +2 -0
  177. data/test/fixtures/flowers.jpg +0 -0
  178. data/test/fixtures/funny_jokes.yml +10 -0
  179. data/test/fixtures/item.rb +7 -0
  180. data/test/fixtures/items.yml +4 -0
  181. data/test/fixtures/joke.rb +3 -0
  182. data/test/fixtures/keyboard.rb +3 -0
  183. data/test/fixtures/legacy_thing.rb +3 -0
  184. data/test/fixtures/legacy_things.yml +3 -0
  185. data/test/fixtures/matey.rb +4 -0
  186. data/test/fixtures/mateys.yml +4 -0
  187. data/test/fixtures/migrations/1_people_have_last_names.rb +9 -0
  188. data/test/fixtures/migrations/2_we_need_reminders.rb +12 -0
  189. data/test/fixtures/migrations/3_innocent_jointable.rb +12 -0
  190. data/test/fixtures/migrations_with_decimal/1_give_me_big_numbers.rb +15 -0
  191. data/test/fixtures/migrations_with_duplicate/1_people_have_last_names.rb +9 -0
  192. data/test/fixtures/migrations_with_duplicate/2_we_need_reminders.rb +12 -0
  193. data/test/fixtures/migrations_with_duplicate/3_foo.rb +7 -0
  194. data/test/fixtures/migrations_with_duplicate/3_innocent_jointable.rb +12 -0
  195. data/test/fixtures/migrations_with_missing_versions/1000_people_have_middle_names.rb +9 -0
  196. data/test/fixtures/migrations_with_missing_versions/1_people_have_last_names.rb +9 -0
  197. data/test/fixtures/migrations_with_missing_versions/3_we_need_reminders.rb +12 -0
  198. data/test/fixtures/migrations_with_missing_versions/4_innocent_jointable.rb +12 -0
  199. data/test/fixtures/minimalistic.rb +2 -0
  200. data/test/fixtures/minimalistics.yml +2 -0
  201. data/test/fixtures/mixed_case_monkey.rb +3 -0
  202. data/test/fixtures/mixed_case_monkeys.yml +6 -0
  203. data/test/fixtures/mixins.yml +29 -0
  204. data/test/fixtures/movies.yml +7 -0
  205. data/test/fixtures/naked/csv/accounts.csv +1 -0
  206. data/test/fixtures/naked/yml/accounts.yml +1 -0
  207. data/test/fixtures/naked/yml/companies.yml +1 -0
  208. data/test/fixtures/naked/yml/courses.yml +1 -0
  209. data/test/fixtures/order.rb +4 -0
  210. data/test/fixtures/parrot.rb +13 -0
  211. data/test/fixtures/parrots.yml +27 -0
  212. data/test/fixtures/parrots_pirates.yml +7 -0
  213. data/test/fixtures/people.yml +3 -0
  214. data/test/fixtures/person.rb +4 -0
  215. data/test/fixtures/pirate.rb +5 -0
  216. data/test/fixtures/pirates.yml +9 -0
  217. data/test/fixtures/post.rb +59 -0
  218. data/test/fixtures/posts.yml +48 -0
  219. data/test/fixtures/project.rb +27 -2
  220. data/test/fixtures/projects.yml +7 -0
  221. data/test/fixtures/reader.rb +4 -0
  222. data/test/fixtures/readers.yml +4 -0
  223. data/test/fixtures/reply.rb +18 -2
  224. data/test/fixtures/reserved_words/distinct.yml +5 -0
  225. data/test/fixtures/reserved_words/distincts_selects.yml +11 -0
  226. data/test/fixtures/reserved_words/group.yml +14 -0
  227. data/test/fixtures/reserved_words/select.yml +8 -0
  228. data/test/fixtures/reserved_words/values.yml +7 -0
  229. data/test/fixtures/ship.rb +3 -0
  230. data/test/fixtures/ships.yml +5 -0
  231. data/test/fixtures/subject.rb +4 -0
  232. data/test/fixtures/subscriber.rb +4 -3
  233. data/test/fixtures/tag.rb +7 -0
  234. data/test/fixtures/tagging.rb +10 -0
  235. data/test/fixtures/taggings.yml +25 -0
  236. data/test/fixtures/tags.yml +7 -0
  237. data/test/fixtures/task.rb +3 -0
  238. data/test/fixtures/tasks.yml +7 -0
  239. data/test/fixtures/topic.rb +20 -3
  240. data/test/fixtures/topics.yml +22 -0
  241. data/test/fixtures/treasure.rb +4 -0
  242. data/test/fixtures/treasures.yml +10 -0
  243. data/test/fixtures/vertex.rb +9 -0
  244. data/test/fixtures/vertices.yml +4 -0
  245. data/test/fixtures_test.rb +574 -8
  246. data/test/inheritance_test.rb +113 -27
  247. data/test/json_serialization_test.rb +180 -0
  248. data/test/lifecycle_test.rb +56 -29
  249. data/test/locking_test.rb +273 -0
  250. data/test/method_scoping_test.rb +416 -0
  251. data/test/migration_test.rb +933 -0
  252. data/test/migration_test_firebird.rb +124 -0
  253. data/test/mixin_test.rb +95 -0
  254. data/test/modules_test.rb +23 -10
  255. data/test/multiple_db_test.rb +17 -3
  256. data/test/pk_test.rb +59 -15
  257. data/test/query_cache_test.rb +104 -0
  258. data/test/readonly_test.rb +107 -0
  259. data/test/reflection_test.rb +124 -27
  260. data/test/reserved_word_test_mysql.rb +177 -0
  261. data/test/schema_authorization_test_postgresql.rb +75 -0
  262. data/test/schema_dumper_test.rb +131 -0
  263. data/test/schema_test_postgresql.rb +64 -0
  264. data/test/serialization_test.rb +47 -0
  265. data/test/synonym_test_oracle.rb +17 -0
  266. data/test/table_name_test_sqlserver.rb +23 -0
  267. data/test/threaded_connections_test.rb +48 -0
  268. data/test/transactions_test.rb +227 -29
  269. data/test/unconnected_test.rb +14 -6
  270. data/test/validations_test.rb +1293 -32
  271. data/test/xml_serialization_test.rb +202 -0
  272. metadata +347 -143
  273. data/dev-utils/eval_debugger.rb +0 -9
  274. data/examples/associations.rb +0 -87
  275. data/examples/shared_setup.rb +0 -15
  276. data/examples/validation.rb +0 -88
  277. data/lib/active_record/deprecated_associations.rb +0 -70
  278. data/lib/active_record/support/class_attribute_accessors.rb +0 -43
  279. data/lib/active_record/support/class_inheritable_attributes.rb +0 -37
  280. data/lib/active_record/support/clean_logger.rb +0 -10
  281. data/lib/active_record/support/inflector.rb +0 -70
  282. data/lib/active_record/vendor/simple.rb +0 -702
  283. data/lib/active_record/wrappers/yaml_wrapper.rb +0 -15
  284. data/lib/active_record/wrappings.rb +0 -59
  285. data/rakefile +0 -122
  286. data/test/deprecated_associations_test.rb +0 -336
  287. data/test/fixtures/accounts/signals37 +0 -3
  288. data/test/fixtures/accounts/unknown +0 -2
  289. data/test/fixtures/companies/first_client +0 -6
  290. data/test/fixtures/companies/first_firm +0 -4
  291. data/test/fixtures/companies/second_client +0 -6
  292. data/test/fixtures/courses/java +0 -2
  293. data/test/fixtures/courses/ruby +0 -2
  294. data/test/fixtures/customers/david +0 -6
  295. data/test/fixtures/db_definitions/mysql.sql +0 -96
  296. data/test/fixtures/db_definitions/mysql2.sql +0 -4
  297. data/test/fixtures/developers/david +0 -2
  298. data/test/fixtures/developers/jamis +0 -2
  299. data/test/fixtures/entrants/first +0 -3
  300. data/test/fixtures/entrants/second +0 -3
  301. data/test/fixtures/entrants/third +0 -3
  302. data/test/fixtures/fixture_database.sqlite +0 -0
  303. data/test/fixtures/fixture_database_2.sqlite +0 -0
  304. data/test/fixtures/movies/first +0 -2
  305. data/test/fixtures/movies/second +0 -2
  306. data/test/fixtures/projects/action_controller +0 -2
  307. data/test/fixtures/projects/active_record +0 -2
  308. data/test/fixtures/topics/first +0 -9
  309. data/test/fixtures/topics/second +0 -8
  310. data/test/inflector_test.rb +0 -104
  311. data/test/thread_safety_test.rb +0 -33
data/test/finder_test.rb CHANGED
@@ -1,42 +1,122 @@
1
1
  require 'abstract_unit'
2
+ require 'fixtures/author'
3
+ require 'fixtures/comment'
2
4
  require 'fixtures/company'
3
5
  require 'fixtures/topic'
6
+ require 'fixtures/reply'
7
+ require 'fixtures/entrant'
8
+ require 'fixtures/developer'
9
+ require 'fixtures/post'
4
10
 
5
11
  class FinderTest < Test::Unit::TestCase
6
- def setup
7
- @company_fixtures = create_fixtures("companies")
8
- @topic_fixtures = create_fixtures("topics")
9
- end
10
-
12
+ fixtures :companies, :topics, :entrants, :developers, :developers_projects, :posts, :comments, :accounts, :authors
13
+
11
14
  def test_find
12
- assert_equal(@topic_fixtures["first"]["title"], Topic.find(1).title)
15
+ assert_equal(topics(:first).title, Topic.find(1).title)
13
16
  end
14
-
17
+
18
+ # find should handle strings that come from URLs
19
+ # (example: Category.find(params[:id]))
20
+ def test_find_with_string
21
+ assert_equal(Topic.find(1).title,Topic.find("1").title)
22
+ end
23
+
24
+ def test_exists
25
+ assert Topic.exists?(1)
26
+ assert Topic.exists?("1")
27
+ assert Topic.exists?(:author_name => "David")
28
+ assert Topic.exists?(:author_name => "Mary", :approved => true)
29
+ assert Topic.exists?(["parent_id = ?", 1])
30
+ assert !Topic.exists?(45)
31
+ assert !Topic.exists?("foo")
32
+ assert_raise(NoMethodError) { Topic.exists?([1,2]) }
33
+ end
34
+
35
+ def test_find_by_array_of_one_id
36
+ assert_kind_of(Array, Topic.find([ 1 ]))
37
+ assert_equal(1, Topic.find([ 1 ]).length)
38
+ end
39
+
15
40
  def test_find_by_ids
16
- assert_equal(2, Topic.find(1, 2).length)
17
- assert_equal(@topic_fixtures["second"]["title"], Topic.find([ 2 ]).title)
41
+ assert_equal 2, Topic.find(1, 2).size
42
+ assert_equal topics(:second).title, Topic.find([2]).first.title
43
+ end
44
+
45
+ def test_find_by_ids_with_limit_and_offset
46
+ assert_equal 2, Entrant.find([1,3,2], :limit => 2).size
47
+ assert_equal 1, Entrant.find([1,3,2], :limit => 3, :offset => 2).size
48
+
49
+ # Also test an edge case: If you have 11 results, and you set a
50
+ # limit of 3 and offset of 9, then you should find that there
51
+ # will be only 2 results, regardless of the limit.
52
+ devs = Developer.find :all
53
+ last_devs = Developer.find devs.map(&:id), :limit => 3, :offset => 9
54
+ assert_equal 2, last_devs.size
55
+ end
56
+
57
+ def test_find_an_empty_array
58
+ assert_equal [], Topic.find([])
18
59
  end
19
60
 
20
61
  def test_find_by_ids_missing_one
21
- assert_raises(ActiveRecord::RecordNotFound) {
22
- Topic.find(1, 2, 45)
23
- }
62
+ assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, 2, 45) }
24
63
  end
25
-
64
+
65
+ def test_find_all_with_limit
66
+ entrants = Entrant.find(:all, :order => "id ASC", :limit => 2)
67
+
68
+ assert_equal(2, entrants.size)
69
+ assert_equal(entrants(:first).name, entrants.first.name)
70
+ end
71
+
72
+ def test_find_all_with_prepared_limit_and_offset
73
+ entrants = Entrant.find(:all, :order => "id ASC", :limit => 2, :offset => 1)
74
+
75
+ assert_equal(2, entrants.size)
76
+ assert_equal(entrants(:second).name, entrants.first.name)
77
+
78
+ entrants = Entrant.find(:all, :order => "id ASC", :limit => 2, :offset => 2)
79
+ assert_equal(1, entrants.size)
80
+ assert_equal(entrants(:third).name, entrants.first.name)
81
+ end
82
+
83
+ def test_find_all_with_limit_and_offset_and_multiple_orderings
84
+ developers = Developer.find(:all, :order => "salary ASC, id DESC", :limit => 3, :offset => 1)
85
+ assert_equal ["David", "fixture_10", "fixture_9"], developers.collect {|d| d.name}
86
+ end
87
+
88
+ def test_find_with_limit_and_condition
89
+ developers = Developer.find(:all, :order => "id DESC", :conditions => "salary = 100000", :limit => 3, :offset =>7)
90
+ assert_equal(1, developers.size)
91
+ assert_equal("fixture_3", developers.first.name)
92
+ end
93
+
26
94
  def test_find_with_entire_select_statement
27
95
  topics = Topic.find_by_sql "SELECT * FROM topics WHERE author_name = 'Mary'"
28
-
96
+
29
97
  assert_equal(1, topics.size)
30
- assert_equal(@topic_fixtures["second"]["title"], topics.first.title)
98
+ assert_equal(topics(:second).title, topics.first.title)
31
99
  end
32
-
100
+
101
+ def test_find_with_prepared_select_statement
102
+ topics = Topic.find_by_sql ["SELECT * FROM topics WHERE author_name = ?", "Mary"]
103
+
104
+ assert_equal(1, topics.size)
105
+ assert_equal(topics(:second).title, topics.first.title)
106
+ end
107
+
108
+ def test_find_by_sql_with_sti_on_joined_table
109
+ accounts = Account.find_by_sql("SELECT * FROM accounts INNER JOIN companies ON companies.id = accounts.firm_id")
110
+ assert_equal [Account], accounts.collect(&:class).uniq
111
+ end
112
+
33
113
  def test_find_first
34
- first = Topic.find_first "title = 'The First Topic'"
35
- assert_equal(@topic_fixtures["first"]["title"], first.title)
114
+ first = Topic.find(:first, :conditions => "title = 'The First Topic'")
115
+ assert_equal(topics(:first).title, first.title)
36
116
  end
37
-
117
+
38
118
  def test_find_first_failing
39
- first = Topic.find_first "title = 'The First Topic!'"
119
+ first = Topic.find(:first, :conditions => "title = 'The First Topic!'")
40
120
  assert_nil(first)
41
121
  end
42
122
 
@@ -44,24 +124,519 @@ class FinderTest < Test::Unit::TestCase
44
124
  assert_raises(ActiveRecord::RecordNotFound) {
45
125
  Topic.find(1).parent
46
126
  }
47
-
48
- Topic.find(2).parent
127
+
128
+ Topic.find(2).topic
49
129
  end
50
130
 
51
- def test_find_on_conditions
52
- assert Topic.find_on_conditions(1, "approved = 0")
53
- assert_raises(ActiveRecord::RecordNotFound) { Topic.find_on_conditions(1, "approved = 1") }
131
+ def test_find_only_some_columns
132
+ topic = Topic.find(1, :select => "author_name")
133
+ assert_raises(ActiveRecord::MissingAttributeError) {topic.title}
134
+ assert_equal "David", topic.author_name
135
+ assert !topic.attribute_present?("title")
136
+ #assert !topic.respond_to?("title")
137
+ assert topic.attribute_present?("author_name")
138
+ assert topic.respond_to?("author_name")
139
+ end
140
+
141
+ def test_find_on_blank_conditions
142
+ [nil, " ", [], {}].each do |blank|
143
+ assert_nothing_raised { Topic.find(:first, :conditions => blank) }
144
+ end
54
145
  end
55
146
 
147
+ def test_find_on_blank_bind_conditions
148
+ [ [""], ["",{}] ].each do |blank|
149
+ assert_nothing_raised { Topic.find(:first, :conditions => blank) }
150
+ end
151
+ end
152
+
153
+ def test_find_on_array_conditions
154
+ assert Topic.find(1, :conditions => ["approved = ?", false])
155
+ assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => ["approved = ?", true]) }
156
+ end
157
+
158
+ def test_find_on_hash_conditions
159
+ assert Topic.find(1, :conditions => { :approved => false })
160
+ assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { :approved => true }) }
161
+ end
162
+
163
+ def test_find_on_hash_conditions_with_explicit_table_name
164
+ assert Topic.find(1, :conditions => { 'topics.approved' => false })
165
+ assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { 'topics.approved' => true }) }
166
+ end
167
+
168
+ def test_find_on_association_proxy_conditions
169
+ assert_equal [1, 2, 3, 5, 6, 7, 8, 9, 10], Comment.find_all_by_post_id(authors(:david).posts).map(&:id).sort
170
+ end
171
+
172
+ def test_find_on_hash_conditions_with_range
173
+ assert_equal [1,2], Topic.find(:all, :conditions => { :id => 1..2 }).map(&:id).sort
174
+ assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { :id => 2..3 }) }
175
+ end
176
+
177
+ def test_find_on_hash_conditions_with_multiple_ranges
178
+ assert_equal [1,2,3], Comment.find(:all, :conditions => { :id => 1..3, :post_id => 1..2 }).map(&:id).sort
179
+ assert_equal [1], Comment.find(:all, :conditions => { :id => 1..1, :post_id => 1..10 }).map(&:id).sort
180
+ end
181
+
182
+ def test_find_on_multiple_hash_conditions
183
+ assert Topic.find(1, :conditions => { :author_name => "David", :title => "The First Topic", :replies_count => 1, :approved => false })
184
+ assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { :author_name => "David", :title => "The First Topic", :replies_count => 1, :approved => true }) }
185
+ assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { :author_name => "David", :title => "HHC", :replies_count => 1, :approved => false }) }
186
+ assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { :author_name => "David", :title => "The First Topic", :replies_count => 1, :approved => true }) }
187
+ end
188
+
189
+
56
190
  def test_condition_interpolation
57
- assert_kind_of Firm, Company.find_first(["name = '%s'", "37signals"])
58
- assert_nil Company.find_first(["name = '%s'", "37signals!"])
59
- assert_nil Company.find_first(["name = '%s'", "37signals!' OR 1=1"])
60
- assert_kind_of Time, Topic.find_first(["id = %d", 1]).written_on
191
+ assert_kind_of Firm, Company.find(:first, :conditions => ["name = '%s'", "37signals"])
192
+ assert_nil Company.find(:first, :conditions => ["name = '%s'", "37signals!"])
193
+ assert_nil Company.find(:first, :conditions => ["name = '%s'", "37signals!' OR 1=1"])
194
+ assert_kind_of Time, Topic.find(:first, :conditions => ["id = %d", 1]).written_on
195
+ end
196
+
197
+ def test_condition_array_interpolation
198
+ assert_kind_of Firm, Company.find(:first, :conditions => ["name = '%s'", "37signals"])
199
+ assert_nil Company.find(:first, :conditions => ["name = '%s'", "37signals!"])
200
+ assert_nil Company.find(:first, :conditions => ["name = '%s'", "37signals!' OR 1=1"])
201
+ assert_kind_of Time, Topic.find(:first, :conditions => ["id = %d", 1]).written_on
202
+ end
203
+
204
+ def test_condition_hash_interpolation
205
+ assert_kind_of Firm, Company.find(:first, :conditions => { :name => "37signals"})
206
+ assert_nil Company.find(:first, :conditions => { :name => "37signals!"})
207
+ assert_kind_of Time, Topic.find(:first, :conditions => {:id => 1}).written_on
208
+ end
209
+
210
+ def test_hash_condition_find_malformed
211
+ assert_raises(ActiveRecord::StatementInvalid) {
212
+ Company.find(:first, :conditions => { :id => 2, :dhh => true })
213
+ }
214
+ end
215
+
216
+ def test_hash_condition_find_with_escaped_characters
217
+ Company.create("name" => "Ain't noth'n like' \#stuff")
218
+ assert Company.find(:first, :conditions => { :name => "Ain't noth'n like' \#stuff" })
219
+ end
220
+
221
+ def test_hash_condition_find_with_array
222
+ p1, p2 = Post.find(:all, :limit => 2, :order => 'id asc')
223
+ assert_equal [p1, p2], Post.find(:all, :conditions => { :id => [p1, p2] }, :order => 'id asc')
224
+ assert_equal [p1, p2], Post.find(:all, :conditions => { :id => [p1, p2.id] }, :order => 'id asc')
225
+ end
226
+
227
+ def test_hash_condition_find_with_nil
228
+ topic = Topic.find(:first, :conditions => { :last_read => nil } )
229
+ assert_not_nil topic
230
+ assert_nil topic.last_read
231
+ end
232
+
233
+ def test_bind_variables
234
+ assert_kind_of Firm, Company.find(:first, :conditions => ["name = ?", "37signals"])
235
+ assert_nil Company.find(:first, :conditions => ["name = ?", "37signals!"])
236
+ assert_nil Company.find(:first, :conditions => ["name = ?", "37signals!' OR 1=1"])
237
+ assert_kind_of Time, Topic.find(:first, :conditions => ["id = ?", 1]).written_on
238
+ assert_raises(ActiveRecord::PreparedStatementInvalid) {
239
+ Company.find(:first, :conditions => ["id=? AND name = ?", 2])
240
+ }
241
+ assert_raises(ActiveRecord::PreparedStatementInvalid) {
242
+ Company.find(:first, :conditions => ["id=?", 2, 3, 4])
243
+ }
244
+ end
245
+
246
+ def test_bind_variables_with_quotes
247
+ Company.create("name" => "37signals' go'es agains")
248
+ assert Company.find(:first, :conditions => ["name = ?", "37signals' go'es agains"])
249
+ end
250
+
251
+ def test_named_bind_variables_with_quotes
252
+ Company.create("name" => "37signals' go'es agains")
253
+ assert Company.find(:first, :conditions => ["name = :name", {:name => "37signals' go'es agains"}])
254
+ end
255
+
256
+ def test_bind_arity
257
+ assert_nothing_raised { bind '' }
258
+ assert_raises(ActiveRecord::PreparedStatementInvalid) { bind '', 1 }
259
+
260
+ assert_raises(ActiveRecord::PreparedStatementInvalid) { bind '?' }
261
+ assert_nothing_raised { bind '?', 1 }
262
+ assert_raises(ActiveRecord::PreparedStatementInvalid) { bind '?', 1, 1 }
263
+ end
264
+
265
+ def test_named_bind_variables
266
+ assert_equal '1', bind(':a', :a => 1) # ' ruby-mode
267
+ assert_equal '1 1', bind(':a :a', :a => 1) # ' ruby-mode
268
+
269
+ assert_kind_of Firm, Company.find(:first, :conditions => ["name = :name", { :name => "37signals" }])
270
+ assert_nil Company.find(:first, :conditions => ["name = :name", { :name => "37signals!" }])
271
+ assert_nil Company.find(:first, :conditions => ["name = :name", { :name => "37signals!' OR 1=1" }])
272
+ assert_kind_of Time, Topic.find(:first, :conditions => ["id = :id", { :id => 1 }]).written_on
273
+ end
274
+
275
+ def test_bind_enumerable
276
+ quoted_abc = %(#{ActiveRecord::Base.connection.quote('a')},#{ActiveRecord::Base.connection.quote('b')},#{ActiveRecord::Base.connection.quote('c')})
277
+
278
+ assert_equal '1,2,3', bind('?', [1, 2, 3])
279
+ assert_equal quoted_abc, bind('?', %w(a b c))
280
+
281
+ assert_equal '1,2,3', bind(':a', :a => [1, 2, 3])
282
+ assert_equal quoted_abc, bind(':a', :a => %w(a b c)) # '
283
+
284
+ require 'set'
285
+ assert_equal '1,2,3', bind('?', Set.new([1, 2, 3]))
286
+ assert_equal quoted_abc, bind('?', Set.new(%w(a b c)))
287
+
288
+ assert_equal '1,2,3', bind(':a', :a => Set.new([1, 2, 3]))
289
+ assert_equal quoted_abc, bind(':a', :a => Set.new(%w(a b c))) # '
290
+ end
291
+
292
+ def test_bind_empty_enumerable
293
+ quoted_nil = ActiveRecord::Base.connection.quote(nil)
294
+ assert_equal quoted_nil, bind('?', [])
295
+ assert_equal " in (#{quoted_nil})", bind(' in (?)', [])
296
+ assert_equal "foo in (#{quoted_nil})", bind('foo in (?)', [])
297
+ end
298
+
299
+ def test_bind_string
300
+ assert_equal ActiveRecord::Base.connection.quote(''), bind('?', '')
301
+ end
302
+
303
+ def test_bind_record
304
+ o = Struct.new(:quoted_id).new(1)
305
+ assert_equal '1', bind('?', o)
306
+
307
+ os = [o] * 3
308
+ assert_equal '1,1,1', bind('?', os)
61
309
  end
62
310
 
63
311
  def test_string_sanitation
64
- assert_equal "something '' 1=1", ActiveRecord::Base.sanitize("something ' 1=1")
65
- assert_equal "something select table", ActiveRecord::Base.sanitize("something; select table")
312
+ assert_not_equal "#{ActiveRecord::Base.connection.quoted_string_prefix}'something ' 1=1'", ActiveRecord::Base.sanitize("something ' 1=1")
313
+ assert_equal "#{ActiveRecord::Base.connection.quoted_string_prefix}'something; select table'", ActiveRecord::Base.sanitize("something; select table")
314
+ end
315
+
316
+ def test_count
317
+ assert_equal(0, Entrant.count(:conditions => "id > 3"))
318
+ assert_equal(1, Entrant.count(:conditions => ["id > ?", 2]))
319
+ assert_equal(2, Entrant.count(:conditions => ["id > ?", 1]))
320
+ end
321
+
322
+ def test_count_by_sql
323
+ assert_equal(0, Entrant.count_by_sql("SELECT COUNT(*) FROM entrants WHERE id > 3"))
324
+ assert_equal(1, Entrant.count_by_sql(["SELECT COUNT(*) FROM entrants WHERE id > ?", 2]))
325
+ assert_equal(2, Entrant.count_by_sql(["SELECT COUNT(*) FROM entrants WHERE id > ?", 1]))
326
+ end
327
+
328
+ def test_find_by_one_attribute
329
+ assert_equal topics(:first), Topic.find_by_title("The First Topic")
330
+ assert_nil Topic.find_by_title("The First Topic!")
331
+ end
332
+
333
+ def test_find_by_one_attribute_caches_dynamic_finder
334
+ # ensure this test can run independently of order
335
+ class << Topic; self; end.send(:remove_method, :find_by_title) if Topic.respond_to?(:find_by_title)
336
+ assert !Topic.respond_to?(:find_by_title)
337
+ t = Topic.find_by_title("The First Topic")
338
+ assert Topic.respond_to?(:find_by_title)
339
+ end
340
+
341
+ def test_dynamic_finder_returns_same_results_after_caching
342
+ # ensure this test can run independently of order
343
+ class << Topic; self; end.send(:remove_method, :find_by_title) if Topic.respond_to?(:find_by_title)
344
+ t = Topic.find_by_title("The First Topic")
345
+ assert_equal t, Topic.find_by_title("The First Topic") # find_by_title has been cached
346
+ end
347
+
348
+ def test_find_by_one_attribute_with_order_option
349
+ assert_equal accounts(:signals37), Account.find_by_credit_limit(50, :order => 'id')
350
+ assert_equal accounts(:rails_core_account), Account.find_by_credit_limit(50, :order => 'id DESC')
66
351
  end
67
- end
352
+
353
+ def test_find_by_one_attribute_with_conditions
354
+ assert_equal accounts(:rails_core_account), Account.find_by_credit_limit(50, :conditions => ['firm_id = ?', 6])
355
+ end
356
+
357
+ def test_dynamic_finder_on_one_attribute_with_conditions_caches_method
358
+ # ensure this test can run independently of order
359
+ class << Account; self; end.send(:remove_method, :find_by_credit_limit) if Account.respond_to?(:find_by_credit_limit)
360
+ assert !Account.respond_to?(:find_by_credit_limit)
361
+ a = Account.find_by_credit_limit(50, :conditions => ['firm_id = ?', 6])
362
+ assert Account.respond_to?(:find_by_credit_limit)
363
+ end
364
+
365
+ def test_dynamic_finder_on_one_attribute_with_conditions_returns_same_results_after_caching
366
+ # ensure this test can run independently of order
367
+ class << Account; self; end.send(:remove_method, :find_by_credit_limit) if Account.respond_to?(:find_by_credit_limit)
368
+ a = Account.find_by_credit_limit(50, :conditions => ['firm_id = ?', 6])
369
+ assert_equal a, Account.find_by_credit_limit(50, :conditions => ['firm_id = ?', 6]) # find_by_credit_limit has been cached
370
+ end
371
+
372
+ def test_find_by_one_attribute_with_several_options
373
+ assert_equal accounts(:unknown), Account.find_by_credit_limit(50, :order => 'id DESC', :conditions => ['id != ?', 3])
374
+ end
375
+
376
+ def test_find_by_one_missing_attribute
377
+ assert_raises(NoMethodError) { Topic.find_by_undertitle("The First Topic!") }
378
+ end
379
+
380
+ def test_find_by_invalid_method_syntax
381
+ assert_raises(NoMethodError) { Topic.fail_to_find_by_title("The First Topic") }
382
+ assert_raises(NoMethodError) { Topic.find_by_title?("The First Topic") }
383
+ assert_raises(NoMethodError) { Topic.fail_to_find_or_create_by_title("Nonexistent Title") }
384
+ assert_raises(NoMethodError) { Topic.find_or_create_by_title?("Nonexistent Title") }
385
+ end
386
+
387
+ def test_find_by_two_attributes
388
+ assert_equal topics(:first), Topic.find_by_title_and_author_name("The First Topic", "David")
389
+ assert_nil Topic.find_by_title_and_author_name("The First Topic", "Mary")
390
+ end
391
+
392
+ def test_find_all_by_one_attribute
393
+ topics = Topic.find_all_by_content("Have a nice day")
394
+ assert_equal 2, topics.size
395
+ assert topics.include?(topics(:first))
396
+
397
+ assert_equal [], Topic.find_all_by_title("The First Topic!!")
398
+ end
399
+
400
+ def test_find_all_by_one_attribute_with_options
401
+ topics = Topic.find_all_by_content("Have a nice day", :order => "id DESC")
402
+ assert topics(:first), topics.last
403
+
404
+ topics = Topic.find_all_by_content("Have a nice day", :order => "id")
405
+ assert topics(:first), topics.first
406
+ end
407
+
408
+ def test_find_all_by_array_attribute
409
+ assert_equal 2, Topic.find_all_by_title(["The First Topic", "The Second Topic's of the day"]).size
410
+ end
411
+
412
+ def test_find_all_by_boolean_attribute
413
+ topics = Topic.find_all_by_approved(false)
414
+ assert_equal 1, topics.size
415
+ assert topics.include?(topics(:first))
416
+
417
+ topics = Topic.find_all_by_approved(true)
418
+ assert_equal 1, topics.size
419
+ assert topics.include?(topics(:second))
420
+ end
421
+
422
+ def test_find_by_nil_attribute
423
+ topic = Topic.find_by_last_read nil
424
+ assert_not_nil topic
425
+ assert_nil topic.last_read
426
+ end
427
+
428
+ def test_find_all_by_nil_attribute
429
+ topics = Topic.find_all_by_last_read nil
430
+ assert_equal 1, topics.size
431
+ assert_nil topics[0].last_read
432
+ end
433
+
434
+ def test_find_by_nil_and_not_nil_attributes
435
+ topic = Topic.find_by_last_read_and_author_name nil, "Mary"
436
+ assert_equal "Mary", topic.author_name
437
+ end
438
+
439
+ def test_find_all_by_nil_and_not_nil_attributes
440
+ topics = Topic.find_all_by_last_read_and_author_name nil, "Mary"
441
+ assert_equal 1, topics.size
442
+ assert_equal "Mary", topics[0].author_name
443
+ end
444
+
445
+ def test_find_or_create_from_one_attribute
446
+ number_of_companies = Company.count
447
+ sig38 = Company.find_or_create_by_name("38signals")
448
+ assert_equal number_of_companies + 1, Company.count
449
+ assert_equal sig38, Company.find_or_create_by_name("38signals")
450
+ assert !sig38.new_record?
451
+ end
452
+
453
+ def test_find_or_create_from_two_attributes
454
+ number_of_topics = Topic.count
455
+ another = Topic.find_or_create_by_title_and_author_name("Another topic","John")
456
+ assert_equal number_of_topics + 1, Topic.count
457
+ assert_equal another, Topic.find_or_create_by_title_and_author_name("Another topic", "John")
458
+ assert !another.new_record?
459
+ end
460
+
461
+ def test_find_or_create_from_one_attribute_and_hash
462
+ number_of_companies = Company.count
463
+ sig38 = Company.find_or_create_by_name({:name => "38signals", :firm_id => 17, :client_of => 23})
464
+ assert_equal number_of_companies + 1, Company.count
465
+ assert_equal sig38, Company.find_or_create_by_name({:name => "38signals", :firm_id => 17, :client_of => 23})
466
+ assert !sig38.new_record?
467
+ assert_equal "38signals", sig38.name
468
+ assert_equal 17, sig38.firm_id
469
+ assert_equal 23, sig38.client_of
470
+ end
471
+
472
+ def test_find_or_initialize_from_one_attribute
473
+ sig38 = Company.find_or_initialize_by_name("38signals")
474
+ assert_equal "38signals", sig38.name
475
+ assert sig38.new_record?
476
+ end
477
+
478
+ def test_find_or_initialize_from_one_attribute_should_set_attribute_even_when_protected
479
+ c = Company.find_or_initialize_by_name_and_rating("Fortune 1000", 1000)
480
+ assert_equal "Fortune 1000", c.name
481
+ assert_equal 1000, c.rating
482
+ assert c.valid?
483
+ assert c.new_record?
484
+ end
485
+
486
+ def test_find_or_create_from_one_attribute_should_set_attribute_even_when_protected
487
+ c = Company.find_or_create_by_name_and_rating("Fortune 1000", 1000)
488
+ assert_equal "Fortune 1000", c.name
489
+ assert_equal 1000, c.rating
490
+ assert c.valid?
491
+ assert !c.new_record?
492
+ end
493
+
494
+ def test_dynamic_find_or_initialize_from_one_attribute_caches_method
495
+ class << Company; self; end.send(:remove_method, :find_or_initialize_by_name) if Company.respond_to?(:find_or_initialize_by_name)
496
+ assert !Company.respond_to?(:find_or_initialize_by_name)
497
+ sig38 = Company.find_or_initialize_by_name("38signals")
498
+ assert Company.respond_to?(:find_or_initialize_by_name)
499
+ end
500
+
501
+ def test_find_or_initialize_from_two_attributes
502
+ another = Topic.find_or_initialize_by_title_and_author_name("Another topic","John")
503
+ assert_equal "Another topic", another.title
504
+ assert_equal "John", another.author_name
505
+ assert another.new_record?
506
+ end
507
+
508
+ def test_find_or_initialize_from_one_attribute_and_hash
509
+ sig38 = Company.find_or_initialize_by_name({:name => "38signals", :firm_id => 17, :client_of => 23})
510
+ assert_equal "38signals", sig38.name
511
+ assert_equal 17, sig38.firm_id
512
+ assert_equal 23, sig38.client_of
513
+ assert sig38.new_record?
514
+ end
515
+
516
+ def test_find_with_bad_sql
517
+ assert_raises(ActiveRecord::StatementInvalid) { Topic.find_by_sql "select 1 from badtable" }
518
+ end
519
+
520
+ def test_find_with_invalid_params
521
+ assert_raises(ArgumentError) { Topic.find :first, :join => "It should be `joins'" }
522
+ assert_raises(ArgumentError) { Topic.find :first, :conditions => '1 = 1', :join => "It should be `joins'" }
523
+ end
524
+
525
+ def test_dynamic_finder_with_invalid_params
526
+ assert_raises(ArgumentError) { Topic.find_by_title 'No Title', :join => "It should be `joins'" }
527
+ end
528
+
529
+ def test_find_all_with_limit
530
+ first_five_developers = Developer.find :all, :order => 'id ASC', :limit => 5
531
+ assert_equal 5, first_five_developers.length
532
+ assert_equal 'David', first_five_developers.first.name
533
+ assert_equal 'fixture_5', first_five_developers.last.name
534
+
535
+ no_developers = Developer.find :all, :order => 'id ASC', :limit => 0
536
+ assert_equal 0, no_developers.length
537
+ end
538
+
539
+ def test_find_all_with_limit_and_offset
540
+ first_three_developers = Developer.find :all, :order => 'id ASC', :limit => 3, :offset => 0
541
+ second_three_developers = Developer.find :all, :order => 'id ASC', :limit => 3, :offset => 3
542
+ last_two_developers = Developer.find :all, :order => 'id ASC', :limit => 2, :offset => 8
543
+
544
+ assert_equal 3, first_three_developers.length
545
+ assert_equal 3, second_three_developers.length
546
+ assert_equal 2, last_two_developers.length
547
+
548
+ assert_equal 'David', first_three_developers.first.name
549
+ assert_equal 'fixture_4', second_three_developers.first.name
550
+ assert_equal 'fixture_9', last_two_developers.first.name
551
+ end
552
+
553
+ def test_find_all_with_limit_and_offset_and_multiple_order_clauses
554
+ first_three_posts = Post.find :all, :order => 'author_id, id', :limit => 3, :offset => 0
555
+ second_three_posts = Post.find :all, :order => ' author_id,id ', :limit => 3, :offset => 3
556
+ last_posts = Post.find :all, :order => ' author_id, id ', :limit => 3, :offset => 6
557
+
558
+ assert_equal [[0,3],[1,1],[1,2]], first_three_posts.map { |p| [p.author_id, p.id] }
559
+ assert_equal [[1,4],[1,5],[1,6]], second_three_posts.map { |p| [p.author_id, p.id] }
560
+ assert_equal [[2,7]], last_posts.map { |p| [p.author_id, p.id] }
561
+ end
562
+
563
+ def test_find_all_with_join
564
+ developers_on_project_one = Developer.find(
565
+ :all,
566
+ :joins => 'LEFT JOIN developers_projects ON developers.id = developers_projects.developer_id',
567
+ :conditions => 'project_id=1'
568
+ )
569
+ assert_equal 3, developers_on_project_one.length
570
+ developer_names = developers_on_project_one.map { |d| d.name }
571
+ assert developer_names.include?('David')
572
+ assert developer_names.include?('Jamis')
573
+ end
574
+
575
+ def test_joins_dont_clobber_id
576
+ first = Firm.find(
577
+ :first,
578
+ :joins => 'INNER JOIN companies AS clients ON clients.firm_id = companies.id',
579
+ :conditions => 'companies.id = 1'
580
+ )
581
+ assert_equal 1, first.id
582
+ end
583
+
584
+ def test_find_by_id_with_conditions_with_or
585
+ assert_nothing_raised do
586
+ Post.find([1,2,3],
587
+ :conditions => "posts.id <= 3 OR posts.#{QUOTED_TYPE} = 'Post'")
588
+ end
589
+ end
590
+
591
+ # http://dev.rubyonrails.org/ticket/6778
592
+ def test_find_ignores_previously_inserted_record
593
+ post = Post.create!(:title => 'test', :body => 'it out')
594
+ assert_equal [], Post.find_all_by_id(nil)
595
+ end
596
+
597
+ def test_find_by_empty_ids
598
+ assert_equal [], Post.find([])
599
+ end
600
+
601
+ def test_find_by_empty_in_condition
602
+ assert_equal [], Post.find(:all, :conditions => ['id in (?)', []])
603
+ end
604
+
605
+ def test_find_by_records
606
+ p1, p2 = Post.find(:all, :limit => 2, :order => 'id asc')
607
+ assert_equal [p1, p2], Post.find(:all, :conditions => ['id in (?)', [p1, p2]], :order => 'id asc')
608
+ assert_equal [p1, p2], Post.find(:all, :conditions => ['id in (?)', [p1, p2.id]], :order => 'id asc')
609
+ end
610
+
611
+ def test_select_value
612
+ assert_equal "37signals", Company.connection.select_value("SELECT name FROM companies WHERE id = 1")
613
+ assert_nil Company.connection.select_value("SELECT name FROM companies WHERE id = -1")
614
+ # make sure we didn't break count...
615
+ assert_equal 0, Company.count_by_sql("SELECT COUNT(*) FROM companies WHERE name = 'Halliburton'")
616
+ assert_equal 1, Company.count_by_sql("SELECT COUNT(*) FROM companies WHERE name = '37signals'")
617
+ end
618
+
619
+ def test_select_values
620
+ assert_equal ["1","2","3","4","5","6","7","8","9"], Company.connection.select_values("SELECT id FROM companies ORDER BY id").map! { |i| i.to_s }
621
+ assert_equal ["37signals","Summit","Microsoft", "Flamboyant Software", "Ex Nihilo", "RailsCore", "Leetsoft", "Jadedpixel", "Odegy"], Company.connection.select_values("SELECT name FROM companies ORDER BY id")
622
+ end
623
+
624
+ def test_select_rows
625
+ assert_equal(
626
+ [["1", nil, nil, "37signals"],
627
+ ["2", "1", "2", "Summit"],
628
+ ["3", "1", "1", "Microsoft"]],
629
+ Company.connection.select_rows("SELECT id, firm_id, client_of, name FROM companies WHERE id IN (1,2,3) ORDER BY id").map! {|i| i.map! {|j| j.to_s unless j.nil?}})
630
+ assert_equal [["1", "37signals"], ["2", "Summit"], ["3", "Microsoft"]],
631
+ Company.connection.select_rows("SELECT id, name FROM companies WHERE id IN (1,2,3) ORDER BY id").map! {|i| i.map! {|j| j.to_s unless j.nil?}}
632
+ end
633
+
634
+ protected
635
+ def bind(statement, *vars)
636
+ if vars.first.is_a?(Hash)
637
+ ActiveRecord::Base.send(:replace_named_bind_variables, statement, vars.first)
638
+ else
639
+ ActiveRecord::Base.send(:replace_bind_variables, statement, vars)
640
+ end
641
+ end
642
+ end