ExpressionTypeCastingIntegrationTest.php 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. <?php
  2. /**
  3. * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  4. * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  5. *
  6. * Licensed under The Open Group Test Suite License
  7. * Redistributions of files must retain the above copyright notice.
  8. *
  9. * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  10. * @link http://cakephp.org CakePHP(tm) Project
  11. * @since 3.3.0
  12. * @license http://www.opensource.org/licenses/mit-license.php MIT License
  13. */
  14. namespace Cake\Test\TestCase\Database;
  15. use Cake\Database\Driver;
  16. use Cake\Database\Driver\Sqlserver;
  17. use Cake\Database\Expression\FunctionExpression;
  18. use Cake\Database\Type;
  19. use Cake\Database\Type\BinaryType;
  20. use Cake\Database\Type\ExpressionTypeInterface;
  21. use Cake\Datasource\ConnectionManager;
  22. use Cake\TestSuite\TestCase;
  23. /**
  24. * Value object for testing mappings.
  25. */
  26. class UuidValue
  27. {
  28. public $value;
  29. public function __construct($value)
  30. {
  31. $this->value = $value;
  32. }
  33. }
  34. /**
  35. * Custom type class that maps between value objects, and SQL expressions.
  36. */
  37. class OrderedUuidType extends Type implements ExpressionTypeInterface
  38. {
  39. public function toPHP($value, Driver $d)
  40. {
  41. return new UuidValue($value);
  42. }
  43. public function toExpression($value)
  44. {
  45. if ($value instanceof UuidValue) {
  46. $value = $value->value;
  47. }
  48. $substr = function ($start, $length = null) use ($value) {
  49. return new FunctionExpression(
  50. 'SUBSTR',
  51. $length === null ? [$value, $start] : [$value, $start, $length],
  52. ['string', 'integer', 'integer']
  53. );
  54. };
  55. return new FunctionExpression(
  56. 'CONCAT',
  57. [$substr(15, 4), $substr(10, 4), $substr(1, 8), $substr(20, 4), $substr(25)]
  58. );
  59. }
  60. }
  61. /**
  62. * Tests for Expression objects casting values to other expressions
  63. * using the type classes
  64. *
  65. */
  66. class ExpressionTypeCastingIntegrationTest extends TestCase
  67. {
  68. public $fixtures = ['core.ordered_uuid_items'];
  69. public function setUp()
  70. {
  71. parent::setUp();
  72. $this->connection = ConnectionManager::get('test');
  73. $this->skipIf($this->connection->driver() instanceof Sqlserver, 'This tests uses functions specific to other drivers');
  74. Type::map('ordered_uuid', OrderedUuidType::class);
  75. }
  76. protected function _insert()
  77. {
  78. $query = $this->connection->newQuery();
  79. $values = $query
  80. ->insert(['id', 'published', 'name'], ['id' => 'ordered_uuid'])
  81. ->into('ordered_uuid_items')
  82. ->clause('values');
  83. $values
  84. ->values([
  85. ['id' => '481fc6d0-b920-43e0-a40d-6d1740cf8569', 'published' => 0, 'name' => 'Item 1'],
  86. ['id' => '48298a29-81c0-4c26-a7fb-413140cf8569', 'published' => 0, 'name' => 'Item 2'],
  87. ['id' => '482b7756-8da0-419a-b21f-27da40cf8569', 'published' => 0, 'name' => 'Item 3'],
  88. ]);
  89. $query->execute();
  90. }
  91. /**
  92. * Tests inserting a value that is to be converted to an expression
  93. * automatically
  94. *
  95. * @return void
  96. */
  97. public function testInsert()
  98. {
  99. $this->_insert();
  100. $query = $this->connection->newQuery()
  101. ->select('id')
  102. ->from('ordered_uuid_items')
  103. ->order('id')
  104. ->defaultTypes(['id' => 'ordered_uuid']);
  105. $query->selectTypeMap($query->typeMap());
  106. $results = $query->execute()->fetchAll('assoc');
  107. $this->assertEquals(new UuidValue('419a8da0482b7756b21f27da40cf8569'), $results[0]['id']);
  108. $this->assertEquals(new UuidValue('43e0b920481fc6d0a40d6d1740cf8569'), $results[1]['id']);
  109. $this->assertEquals(new UuidValue('4c2681c048298a29a7fb413140cf8569'), $results[2]['id']);
  110. }
  111. /**
  112. * Test selecting with a custom expression type using conditions
  113. *
  114. * @return void
  115. */
  116. public function testSelectWithConditions()
  117. {
  118. $this->_insert();
  119. $result = $this->connection->newQuery()
  120. ->select('id')
  121. ->from('ordered_uuid_items')
  122. ->where(['id' => '48298a29-81c0-4c26-a7fb-413140cf8569'], ['id' => 'ordered_uuid'])
  123. ->execute()
  124. ->fetchAll('assoc');
  125. $this->assertCount(1, $result);
  126. $this->assertEquals('4c2681c048298a29a7fb413140cf8569', $result[0]['id']);
  127. }
  128. /**
  129. * Tests Select using value object in conditions
  130. *
  131. * @return void
  132. */
  133. public function testSelectWithConditionsValueObject()
  134. {
  135. $this->_insert();
  136. $result = $this->connection->newQuery()
  137. ->select('id')
  138. ->from('ordered_uuid_items')
  139. ->where(['id' => new UuidValue('48298a29-81c0-4c26-a7fb-413140cf8569')], ['id' => 'ordered_uuid'])
  140. ->execute()
  141. ->fetchAll('assoc');
  142. $this->assertCount(1, $result);
  143. $this->assertEquals('4c2681c048298a29a7fb413140cf8569', $result[0]['id']);
  144. }
  145. /**
  146. * Tests using the expression type in with an IN condition
  147. *
  148. * @var string
  149. */
  150. public function testSelectWithInCondition()
  151. {
  152. $this->_insert();
  153. $result = $this->connection->newQuery()
  154. ->select('id')
  155. ->from('ordered_uuid_items')
  156. ->where(
  157. ['id' => ['48298a29-81c0-4c26-a7fb-413140cf8569', '482b7756-8da0-419a-b21f-27da40cf8569']],
  158. ['id' => 'ordered_uuid[]']
  159. )
  160. ->order('id')
  161. ->execute()
  162. ->fetchAll('assoc');
  163. $this->assertCount(2, $result);
  164. $this->assertEquals('419a8da0482b7756b21f27da40cf8569', $result[0]['id']);
  165. $this->assertEquals('419a8da0482b7756b21f27da40cf8569', $result[0]['id']);
  166. }
  167. /**
  168. * Tests using an expression type in a between condition
  169. *
  170. * @return void
  171. */
  172. public function testSelectWithBetween()
  173. {
  174. $this->_insert();
  175. $result = $this->connection->newQuery()
  176. ->select('id')
  177. ->from('ordered_uuid_items')
  178. ->where(function ($exp) {
  179. return $exp->between(
  180. 'id',
  181. '482b7756-8da0-419a-b21f-27da40cf8569',
  182. '48298a29-81c0-4c26-a7fb-413140cf8569',
  183. 'ordered_uuid'
  184. );
  185. })
  186. ->execute()
  187. ->fetchAll('assoc');
  188. $this->assertCount(3, $result);
  189. }
  190. /**
  191. * Tests using an expression type inside a function expression
  192. *
  193. * @return void
  194. */
  195. public function testSelectWithFunction()
  196. {
  197. $this->_insert();
  198. $result = $this->connection->newQuery()
  199. ->select('id')
  200. ->from('ordered_uuid_items')
  201. ->where(function ($exp, $q) {
  202. return $exp->eq(
  203. 'id',
  204. $q->func()->concat(['48298a29-81c0-4c26-a7fb', '-413140cf8569'], []),
  205. 'ordered_uuid'
  206. );
  207. })
  208. ->execute()
  209. ->fetchAll('assoc');
  210. $this->assertCount(1, $result);
  211. $this->assertEquals('4c2681c048298a29a7fb413140cf8569', $result[0]['id']);
  212. }
  213. }