JoinQLTest.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. <?php
  2. namespace Test\Michel\SqlMapper;
  3. use PDO;
  4. use Michel\SqlMapper\QL\JoinQL;
  5. use Michel\UniTester\TestCase;
  6. class JoinQLTest extends TestCase
  7. {
  8. private PDO $connection;
  9. protected function setUp(): void
  10. {
  11. $this->connection = new PDO(
  12. 'sqlite::memory:',
  13. null,
  14. null,
  15. [PDO::ATTR_EMULATE_PREPARES => false]
  16. );
  17. $this->setUpDatabaseSchema();
  18. }
  19. protected function tearDown(): void
  20. {
  21. }
  22. protected function execute(): void
  23. {
  24. $this->testRealRelations();
  25. $this->testSelect();
  26. $this->testAddSelect();
  27. $this->testWhere();
  28. $this->testOrderBy();
  29. $this->testLeftJoin();
  30. $this->testInnerJoin();
  31. $this->testWithLimit();
  32. $this->testWithParams();
  33. $this->testPaginationWithOffsetAndLimit();
  34. }
  35. public function testSelect(): void
  36. {
  37. $joinQl = new JoinQL($this->connection);
  38. $joinQl->select('table', 'alias', ['column', 'column2' => 'alias__column']);
  39. $this->assertEquals('SELECT alias.column AS alias__column, alias.column2 AS alias__alias__column FROM table AS alias', $joinQl->getQuery());
  40. }
  41. public function testAddSelect(): void
  42. {
  43. $joinQl = new JoinQL($this->connection);
  44. $joinQl->select('table', 'alias', ['column']);
  45. $joinQl->addSelect('alias', ['column']);
  46. $this->assertEquals('SELECT alias.column AS alias__column, alias.column AS alias__column FROM table AS alias', $joinQl->getQuery());
  47. }
  48. public function testWhere(): void
  49. {
  50. $joinQl = new JoinQL($this->connection);
  51. $joinQl->select('table', 'alias', ['column']);
  52. $joinQl->where('alias.column = value');
  53. $this->assertEquals('SELECT alias.column AS alias__column FROM table AS alias WHERE alias.column = value', $joinQl->getQuery());
  54. }
  55. public function testOrderBy(): void
  56. {
  57. $joinQl = new JoinQL($this->connection);
  58. $joinQl->select('table', 'alias', ['column']);
  59. $joinQl->orderBy('column');
  60. $this->assertEquals('SELECT alias.column AS alias__column FROM table AS alias ORDER BY column ASC', $joinQl->getQuery());
  61. }
  62. public function testLeftJoin(): void
  63. {
  64. $joinQl = new JoinQL($this->connection);
  65. $joinQl->select('table', 'alias', ['column']);
  66. $joinQl->leftJoin('table', 'table2', 'alias2', ['column = column'], false, 'relation');
  67. $this->assertEquals('SELECT alias.column AS alias__column FROM table AS alias LEFT JOIN table2 alias2 ON column = column', $joinQl->getQuery());
  68. }
  69. public function testInnerJoin(): void
  70. {
  71. $joinQl = new JoinQL($this->connection);
  72. $joinQl->select('table', 'alias', ['column']);
  73. $joinQl->innerJoin('table', 'table2', 'alias2', ['column = column'], false, 'relation');
  74. $this->assertEquals('SELECT alias.column AS alias__column FROM table AS alias INNER JOIN table2 alias2 ON column = column', $joinQl->getQuery());
  75. }
  76. private function testRealRelations(): void
  77. {
  78. $joinQl = new JoinQL($this->connection, 'id', 5);
  79. $joinQl
  80. ->select('user', 'u', ['id', 'firstname' => 'firstname', 'lastname', 'email' => 'email_address', 'password', 'is_active', 'created_at'])
  81. ->addSelect('p', ['id', 'title', 'user_id', 'content', 'created_at'])
  82. ->addSelect('t', ['id', 'name' => 'tag_name', 'post_id'])
  83. ->addSelect('c', ['id', 'body', 'post_id'])
  84. ->leftJoin('user', 'post', 'p', ['u.id = p.user_id'], true, 'posts', 'user_id')
  85. ->leftJoin('post', 'tag', 't', ['p.id = t.post_id'], true, 'tags', 'post_id')
  86. ->leftJoin('post', 'comment', 'c', ['p.id = c.post_id'], true, 'comments', 'post_id');
  87. foreach ($joinQl->getResult() as $row) {
  88. $this->testRowOneToMany($row);
  89. }
  90. $row = $joinQl->getOneOrNullResult();
  91. $this->testRowOneToMany($row);
  92. foreach ($joinQl->getResultIterator() as $row) {
  93. $this->testRowOneToMany($row);
  94. }
  95. $row = $joinQl->getOneOrNullResult();
  96. $this->testRowOneToMany($row);
  97. $joinQl = new JoinQL($this->connection);
  98. $joinQl
  99. ->select('post', 'p', ['id', 'title', 'user_id', 'content', 'created_at'])
  100. ->addSelect('u', ['id', 'firstname' , 'lastname', 'email' , 'password', 'is_active', 'created_at'])
  101. ->addSelect('t', ['id', 'name', 'post_id'])
  102. ->addSelect('c', ['id', 'body', 'post_id'])
  103. ->leftJoin('post', 'user', 'u', ['u.id = p.user_id'], false, 'user', 'user_id')
  104. ->leftJoin('post', 'tag', 't', ['p.id = t.post_id'], true, 'tags', 'post_id')
  105. ->leftJoin('post', 'comment', 'c', ['p.id = c.post_id'], true, 'comments', 'post_id')
  106. ->orderBy('p.id', 'desc')
  107. ->setMaxResults(3);
  108. $data = $joinQl->getResult();
  109. $this->assertEquals( 3 , count($data));
  110. foreach ($data as $row) {
  111. $this->assertTrue(array_key_exists('user', $row));
  112. $this->assertTrue(array_key_exists('comments', $row));
  113. $this->assertTrue(array_key_exists('tags', $row));
  114. }
  115. $count = $joinQl->count();
  116. $this->assertEquals( 10 , $count);
  117. }
  118. private function testWithLimit()
  119. {
  120. $joinQl = new JoinQL($this->connection);
  121. $joinQl
  122. ->select('post', 'p', ['id', 'title', 'user_id', 'content', 'created_at'])
  123. ->setMaxResults(1000000);
  124. $data = $joinQl->getResult();
  125. $this->assertEquals( 10 , count($data));
  126. $count = $joinQl->count();
  127. $this->assertEquals( 10 , $count);
  128. }
  129. public function testWithParams(): void {
  130. $joinQl = new JoinQL($this->connection);
  131. $joinQl
  132. ->select('post', 'p', ['id', 'title', 'user_id', 'content', 'created_at'])
  133. ->where('id > :id')
  134. ->setParam('id', 5)
  135. ->setMaxResults(1000000);
  136. $data = $joinQl->getResult();
  137. $this->assertEquals( 5 , count($data));
  138. $this->assertEquals( 5 , $joinQl->count());
  139. }
  140. public function testPaginationWithOffsetAndLimit(): void
  141. {
  142. $joinQl = new JoinQL($this->connection);
  143. // Page 1 : OFFSET 0 LIMIT 2
  144. $page1 = $joinQl
  145. ->select('post', 'p', ['id', 'title'])
  146. ->setFirstResult(0)
  147. ->setMaxResults(2)
  148. ->getResult();
  149. $this->assertEquals(2, count($page1));
  150. $this->assertEquals(1, $page1[0]['id']);
  151. $this->assertEquals(2, $page1[1]['id']);
  152. // Page 2 : OFFSET 2 LIMIT 2
  153. $joinQl = new JoinQL($this->connection);
  154. $page2 = $joinQl
  155. ->select('post', 'p', ['id', 'title'])
  156. ->setFirstResult(2)
  157. ->setMaxResults(2)
  158. ->getResult();
  159. $this->assertEquals(2, count($page2));
  160. $this->assertEquals(3, $page2[0]['id']);
  161. $this->assertEquals(4, $page2[1]['id']);
  162. // Vérifier que le count() ignore la pagination
  163. $total = $joinQl->count();
  164. $this->assertEquals(10, $total);
  165. }
  166. private function testRowOneToMany($row)
  167. {
  168. $this->assertTrue(is_array($row));
  169. $this->assertTrue(array_key_exists('id', $row));
  170. $this->assertTrue(array_key_exists('firstname', $row));
  171. $this->assertTrue(array_key_exists('lastname', $row));
  172. $this->assertTrue(array_key_exists('email_address', $row));
  173. $this->assertTrue(array_key_exists('password', $row));
  174. $this->assertTrue(array_key_exists('is_active', $row));
  175. $this->assertTrue(array_key_exists('posts', $row));
  176. $this->assertTrue(array_key_exists('tags', $row['posts'][0]));
  177. $this->assertTrue(array_key_exists('comments', $row['posts'][0]));
  178. $this->assertTrue(array_key_exists('tag_name', $row['posts'][0]['tags'][0]));
  179. $this->assertEquals(2, count($row['posts']));
  180. }
  181. protected function setUpDatabaseSchema(): void
  182. {
  183. $this->connection->exec('CREATE TABLE user (
  184. id INTEGER PRIMARY KEY,
  185. firstname VARCHAR(255),
  186. lastname VARCHAR(255),
  187. email VARCHAR(255),
  188. password VARCHAR(255),
  189. is_active BOOLEAN,
  190. created_at DATETIME DEFAULT CURRENT_TIMESTAMP
  191. );');
  192. $this->connection->exec('CREATE TABLE post (
  193. id INTEGER PRIMARY KEY,
  194. user_id INTEGER,
  195. title VARCHAR(255),
  196. content VARCHAR(255),
  197. created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
  198. FOREIGN KEY (user_id) REFERENCES user (id)
  199. );');
  200. $this->connection->exec('CREATE TABLE tag (
  201. id INTEGER PRIMARY KEY,
  202. post_id INTEGER,
  203. name VARCHAR(255)
  204. )');
  205. $this->connection->exec('CREATE TABLE comment (
  206. id INTEGER PRIMARY KEY,
  207. post_id INTEGER,
  208. body VARCHAR(255)
  209. )');
  210. for ($i = 0; $i < 5; $i++) {
  211. $user = [
  212. 'firstname' => 'John' . $i,
  213. 'lastname' => 'Doe' . $i,
  214. 'email' => $i . 'bqQpB@example.com',
  215. 'password' => 'password123',
  216. 'is_active' => true,
  217. ];
  218. $this->connection->exec("INSERT INTO user (firstname, lastname, email, password, is_active) VALUES (
  219. '{$user['firstname']}',
  220. '{$user['lastname']}',
  221. '{$user['email']}',
  222. '{$user['password']}',
  223. '{$user['is_active']}'
  224. )");
  225. }
  226. for ($i = 0; $i < 5; $i++) {
  227. $id = uniqid('post_', true);
  228. $post = [
  229. 'user_id' => $i + 1,
  230. 'title' => 'Post ' . $id,
  231. 'content' => 'Content ' . $id,
  232. ];
  233. $this->connection->exec("INSERT INTO post (user_id, title, content) VALUES (
  234. '{$post['user_id']}',
  235. '{$post['title']}',
  236. '{$post['content']}'
  237. )");
  238. $id = uniqid('post_', true);
  239. $post = [
  240. 'user_id' => $i + 1,
  241. 'title' => 'Post ' . $id,
  242. 'content' => 'Content ' . $id,
  243. ];
  244. $this->connection->exec("INSERT INTO post (user_id, title, content) VALUES (
  245. '{$post['user_id']}',
  246. '{$post['title']}',
  247. '{$post['content']}'
  248. )");
  249. }
  250. for ($i = 0; $i < 10; $i++) {
  251. $id = uniqid('tag_', true);
  252. $tag = [
  253. 'post_id' => $i + 1,
  254. 'name' => 'Tag ' . $id,
  255. ];
  256. $this->connection->exec("INSERT INTO tag (post_id, name) VALUES (
  257. '{$tag['post_id']}',
  258. '{$tag['name']}'
  259. )");
  260. $id = uniqid('tag_', true);
  261. $tag = [
  262. 'post_id' => $i + 1,
  263. 'name' => 'Tag ' . $id,
  264. ];
  265. $this->connection->exec("INSERT INTO tag (post_id, name) VALUES (
  266. '{$tag['post_id']}',
  267. '{$tag['name']}'
  268. )");
  269. }
  270. for ($i = 0; $i < 10; $i++) {
  271. $id = uniqid('comment_', true);
  272. $comment = [
  273. 'post_id' => $i + 1,
  274. 'body' => 'Comment ' . $id,
  275. ];
  276. $this->connection->exec("INSERT INTO comment (post_id, body) VALUES (
  277. '{$comment['post_id']}',
  278. '{$comment['body']}'
  279. )");
  280. }
  281. }
  282. }