ActiveRecordWriteTest.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. <?php
  2. include 'helpers/config.php';
  3. use ActiveRecord\DateTime;
  4. class DirtyAuthor extends ActiveRecord\Model
  5. {
  6. static $table = 'authors';
  7. static $before_save = 'before_save';
  8. public function before_save()
  9. {
  10. $this->name = 'i saved';
  11. }
  12. };
  13. class AuthorWithoutSequence extends ActiveRecord\Model
  14. {
  15. static $table = 'authors';
  16. static $sequence = 'invalid_seq';
  17. }
  18. class AuthorExplicitSequence extends ActiveRecord\Model
  19. {
  20. static $sequence = 'blah_seq';
  21. }
  22. class ActiveRecordWriteTest extends DatabaseTest
  23. {
  24. private function make_new_book_and($save=true)
  25. {
  26. $book = new Book();
  27. $book->name = 'rivers cuomo';
  28. $book->special = 1;
  29. if ($save)
  30. $book->save();
  31. return $book;
  32. }
  33. public function test_save()
  34. {
  35. $venue = new Venue(array('name' => 'Tito'));
  36. $venue->save();
  37. }
  38. public function test_insert()
  39. {
  40. $author = new Author(array('name' => 'Blah Blah'));
  41. $author->save();
  42. $this->assert_not_null(Author::find($author->id));
  43. }
  44. /**
  45. * @expectedException ActiveRecord\DatabaseException
  46. */
  47. public function test_insert_with_no_sequence_defined()
  48. {
  49. if (!$this->conn->supports_sequences())
  50. throw new ActiveRecord\DatabaseException('');
  51. AuthorWithoutSequence::create(array('name' => 'Bob!'));
  52. }
  53. public function test_insert_should_quote_keys()
  54. {
  55. $author = new Author(array('name' => 'Blah Blah'));
  56. $author->save();
  57. $this->assert_true(strpos($author->connection()->last_query,$author->connection()->quote_name('updated_at')) !== false);
  58. }
  59. public function test_save_auto_increment_id()
  60. {
  61. $venue = new Venue(array('name' => 'Bob'));
  62. $venue->save();
  63. $this->assert_true($venue->id > 0);
  64. }
  65. public function test_sequence_was_set()
  66. {
  67. if ($this->conn->supports_sequences())
  68. $this->assert_equals($this->conn->get_sequence_name('authors','author_id'),Author::table()->sequence);
  69. else
  70. $this->assert_null(Author::table()->sequence);
  71. }
  72. public function test_sequence_was_explicitly_set()
  73. {
  74. if ($this->conn->supports_sequences())
  75. $this->assert_equals(AuthorExplicitSequence::$sequence,AuthorExplicitSequence::table()->sequence);
  76. else
  77. $this->assert_null(Author::table()->sequence);
  78. }
  79. public function test_delete()
  80. {
  81. $author = Author::find(1);
  82. $author->delete();
  83. $this->assert_false(Author::exists(1));
  84. }
  85. public function test_delete_by_find_all()
  86. {
  87. $books = Book::all();
  88. foreach ($books as $model)
  89. $model->delete();
  90. $res = Book::all();
  91. $this->assert_equals(0,count($res));
  92. }
  93. public function test_update()
  94. {
  95. $book = Book::find(1);
  96. $new_name = 'new name';
  97. $book->name = $new_name;
  98. $book->save();
  99. $this->assert_same($new_name, $book->name);
  100. $this->assert_same($new_name, $book->name, Book::find(1)->name);
  101. }
  102. public function test_update_should_quote_keys()
  103. {
  104. $book = Book::find(1);
  105. $book->name = 'new name';
  106. $book->save();
  107. $this->assert_true(strpos($book->connection()->last_query,$book->connection()->quote_name('name')) !== false);
  108. }
  109. public function test_update_attributes()
  110. {
  111. $book = Book::find(1);
  112. $new_name = 'How to lose friends and alienate people'; // jax i'm worried about you
  113. $attrs = array('name' => $new_name);
  114. $book->update_attributes($attrs);
  115. $this->assert_same($new_name, $book->name);
  116. $this->assert_same($new_name, $book->name, Book::find(1)->name);
  117. }
  118. /**
  119. * @expectedException ActiveRecord\UndefinedPropertyException
  120. */
  121. public function test_update_attributes_undefined_property()
  122. {
  123. $book = Book::find(1);
  124. $book->update_attributes(array('name' => 'new name', 'invalid_attribute' => true , 'another_invalid_attribute' => 'blah'));
  125. }
  126. public function test_update_attribute()
  127. {
  128. $book = Book::find(1);
  129. $new_name = 'some stupid self-help book';
  130. $book->update_attribute('name', $new_name);
  131. $this->assert_same($new_name, $book->name);
  132. $this->assert_same($new_name, $book->name, Book::find(1)->name);
  133. }
  134. /**
  135. * @expectedException ActiveRecord\UndefinedPropertyException
  136. */
  137. public function test_update_attribute_undefined_property()
  138. {
  139. $book = Book::find(1);
  140. $book->update_attribute('invalid_attribute', true);
  141. }
  142. public function test_save_null_value()
  143. {
  144. $book = Book::first();
  145. $book->name = null;
  146. $book->save();
  147. $this->assert_same(null,Book::find($book->id)->name);
  148. }
  149. public function test_save_blank_value()
  150. {
  151. // oracle doesn't do blanks. probably an option to enable?
  152. if ($this->conn instanceof ActiveRecord\OciAdapter)
  153. return;
  154. $book = Book::find(1);
  155. $book->name = '';
  156. $book->save();
  157. $this->assert_same('',Book::find(1)->name);
  158. }
  159. public function test_dirty_attributes()
  160. {
  161. $book = $this->make_new_book_and(false);
  162. $this->assert_equals(array('name','special'),array_keys($book->dirty_attributes()));
  163. }
  164. public function test_dirty_attributes_cleared_after_saving()
  165. {
  166. $book = $this->make_new_book_and();
  167. $this->assert_true(strpos($book->table()->last_sql,'name') !== false);
  168. $this->assert_true(strpos($book->table()->last_sql,'special') !== false);
  169. $this->assert_equals(null,$book->dirty_attributes());
  170. }
  171. public function test_dirty_attributes_cleared_after_inserting()
  172. {
  173. $book = $this->make_new_book_and();
  174. $this->assert_equals(null,$book->dirty_attributes());
  175. }
  176. public function test_no_dirty_attributes_but_still_insert_record()
  177. {
  178. $book = new Book;
  179. $this->assert_equals(null,$book->dirty_attributes());
  180. $book->save();
  181. $this->assert_equals(null,$book->dirty_attributes());
  182. $this->assert_not_null($book->id);
  183. }
  184. public function test_dirty_attributes_cleared_after_updating()
  185. {
  186. $book = Book::first();
  187. $book->name = 'rivers cuomo';
  188. $book->save();
  189. $this->assert_equals(null,$book->dirty_attributes());
  190. }
  191. public function test_dirty_attributes_after_reloading()
  192. {
  193. $book = Book::first();
  194. $book->name = 'rivers cuomo';
  195. $book->reload();
  196. $this->assert_equals(null,$book->dirty_attributes());
  197. }
  198. public function test_dirty_attributes_with_mass_assignment()
  199. {
  200. $book = Book::first();
  201. $book->set_attributes(array('name' => 'rivers cuomo'));
  202. $this->assert_equals(array('name'), array_keys($book->dirty_attributes()));
  203. }
  204. public function test_timestamps_set_before_save()
  205. {
  206. $author = new Author;
  207. $author->save();
  208. $this->assert_not_null($author->created_at, $author->updated_at);
  209. $author->reload();
  210. $this->assert_not_null($author->created_at, $author->updated_at);
  211. }
  212. public function test_timestamps_updated_at_only_set_before_update()
  213. {
  214. $author = new Author();
  215. $author->save();
  216. $created_at = $author->created_at;
  217. $updated_at = $author->updated_at;
  218. sleep(1);
  219. $author->name = 'test';
  220. $author->save();
  221. $this->assert_not_null($author->updated_at);
  222. $this->assert_same($created_at, $author->created_at);
  223. $this->assert_not_equals($updated_at, $author->updated_at);
  224. }
  225. public function test_create()
  226. {
  227. $author = Author::create(array('name' => 'Blah Blah'));
  228. $this->assert_not_null(Author::find($author->id));
  229. }
  230. public function test_create_should_set_created_at()
  231. {
  232. $author = Author::create(array('name' => 'Blah Blah'));
  233. $this->assert_not_null($author->created_at);
  234. }
  235. /**
  236. * @expectedException ActiveRecord\ActiveRecordException
  237. */
  238. public function test_update_with_no_primary_key_defined()
  239. {
  240. Author::table()->pk = array();
  241. $author = Author::first();
  242. $author->name = 'blahhhhhhhhhh';
  243. $author->save();
  244. }
  245. /**
  246. * @expectedException ActiveRecord\ActiveRecordException
  247. */
  248. public function test_delete_with_no_primary_key_defined()
  249. {
  250. Author::table()->pk = array();
  251. $author = author::first();
  252. $author->delete();
  253. }
  254. public function test_inserting_with_explicit_pk()
  255. {
  256. $author = Author::create(array('author_id' => 9999, 'name' => 'blah'));
  257. $this->assert_equals(9999,$author->author_id);
  258. }
  259. /**
  260. * @expectedException ActiveRecord\ReadOnlyException
  261. */
  262. public function test_readonly()
  263. {
  264. $author = Author::first(array('readonly' => true));
  265. $author->save();
  266. }
  267. public function test_modified_attributes_in_before_handlers_get_saved()
  268. {
  269. $author = DirtyAuthor::first();
  270. $author->encrypted_password = 'coco';
  271. $author->save();
  272. $this->assert_equals('i saved',DirtyAuthor::find($author->id)->name);
  273. }
  274. public function test_is_dirty()
  275. {
  276. $author = Author::first();
  277. $this->assert_equals(false,$author->is_dirty());
  278. $author->name = 'coco';
  279. $this->assert_equals(true,$author->is_dirty());
  280. }
  281. public function test_set_date_flags_dirty()
  282. {
  283. $author = Author::create(array('some_date' => new DateTime()));
  284. $author = Author::find($author->id);
  285. $author->some_date->setDate(2010,1,1);
  286. $this->assert_has_keys('some_date', $author->dirty_attributes());
  287. }
  288. public function test_set_date_flags_dirty_with_php_datetime()
  289. {
  290. $author = Author::create(array('some_date' => new \DateTime()));
  291. $author = Author::find($author->id);
  292. $author->some_date->setDate(2010,1,1);
  293. $this->assert_has_keys('some_date', $author->dirty_attributes());
  294. }
  295. public function test_delete_all_with_conditions_as_string()
  296. {
  297. $num_affected = Author::delete_all(array('conditions' => 'parent_author_id = 2'));
  298. $this->assert_equals(2, $num_affected);
  299. }
  300. public function test_delete_all_with_conditions_as_hash()
  301. {
  302. $num_affected = Author::delete_all(array('conditions' => array('parent_author_id' => 2)));
  303. $this->assert_equals(2, $num_affected);
  304. }
  305. public function test_delete_all_with_conditions_as_array()
  306. {
  307. $num_affected = Author::delete_all(array('conditions' => array('parent_author_id = ?', 2)));
  308. $this->assert_equals(2, $num_affected);
  309. }
  310. public function test_delete_all_with_limit_and_order()
  311. {
  312. if (!$this->conn->accepts_limit_and_order_for_update_and_delete())
  313. $this->mark_test_skipped('Only MySQL & Sqlite accept limit/order with UPDATE clause');
  314. $num_affected = Author::delete_all(array('conditions' => array('parent_author_id = ?', 2), 'limit' => 1, 'order' => 'name asc'));
  315. $this->assert_equals(1, $num_affected);
  316. $this->assert_true(strpos(Author::table()->last_sql, 'ORDER BY name asc LIMIT 1') !== false);
  317. }
  318. public function test_update_all_with_set_as_string()
  319. {
  320. $num_affected = Author::update_all(array('set' => 'parent_author_id = 2'));
  321. $this->assert_equals(2, $num_affected);
  322. $this->assert_equals(4, Author::count_by_parent_author_id(2));
  323. }
  324. public function test_update_all_with_set_as_hash()
  325. {
  326. $num_affected = Author::update_all(array('set' => array('parent_author_id' => 2)));
  327. $this->assert_equals(2, $num_affected);
  328. }
  329. /**
  330. * TODO: not implemented
  331. public function test_update_all_with_set_as_array()
  332. {
  333. $num_affected = Author::update_all(array('set' => array('parent_author_id = ?', 2)));
  334. $this->assert_equals(2, $num_affected);
  335. }
  336. */
  337. public function test_update_all_with_conditions_as_string()
  338. {
  339. $num_affected = Author::update_all(array('set' => 'parent_author_id = 2', 'conditions' => 'name = "Tito"'));
  340. $this->assert_equals(1, $num_affected);
  341. }
  342. public function test_update_all_with_conditions_as_hash()
  343. {
  344. $num_affected = Author::update_all(array('set' => 'parent_author_id = 2', 'conditions' => array('name' => "Tito")));
  345. $this->assert_equals(1, $num_affected);
  346. }
  347. public function test_update_all_with_conditions_as_array()
  348. {
  349. $num_affected = Author::update_all(array('set' => 'parent_author_id = 2', 'conditions' => array('name = ?', "Tito")));
  350. $this->assert_equals(1, $num_affected);
  351. }
  352. public function test_update_all_with_limit_and_order()
  353. {
  354. if (!$this->conn->accepts_limit_and_order_for_update_and_delete())
  355. $this->mark_test_skipped('Only MySQL & Sqlite accept limit/order with UPDATE clause');
  356. $num_affected = Author::update_all(array('set' => 'parent_author_id = 2', 'limit' => 1, 'order' => 'name asc'));
  357. $this->assert_equals(1, $num_affected);
  358. $this->assert_true(strpos(Author::table()->last_sql, 'ORDER BY name asc LIMIT 1') !== false);
  359. }
  360. };