TupleComparisonTest.php 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
  5. * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  6. *
  7. * Licensed under The MIT License
  8. * For full copyright and license information, please see the LICENSE.txt
  9. * Redistributions of files must retain the above copyright notice.
  10. *
  11. * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  12. * @link https://cakephp.org CakePHP(tm) Project
  13. * @since 3.0.0
  14. * @license https://opensource.org/licenses/mit-license.php MIT License
  15. */
  16. namespace Cake\Test\TestCase\Database\Expression;
  17. use Cake\Database\Expression\QueryExpression;
  18. use Cake\Database\Expression\TupleComparison;
  19. use Cake\Database\ValueBinder;
  20. use Cake\TestSuite\TestCase;
  21. use InvalidArgumentException;
  22. /**
  23. * Tests TupleComparison class
  24. */
  25. class TupleComparisonTest extends TestCase
  26. {
  27. /**
  28. * Tests generating a function with no arguments
  29. */
  30. public function testsSimpleTuple(): void
  31. {
  32. $f = new TupleComparison(['field1', 'field2'], [1, 2], ['integer', 'integer'], '=');
  33. $binder = new ValueBinder();
  34. $this->assertSame('(field1, field2) = (:tuple0, :tuple1)', $f->sql($binder));
  35. $this->assertSame(1, $binder->bindings()[':tuple0']['value']);
  36. $this->assertSame(2, $binder->bindings()[':tuple1']['value']);
  37. $this->assertSame('integer', $binder->bindings()[':tuple0']['type']);
  38. $this->assertSame('integer', $binder->bindings()[':tuple1']['type']);
  39. }
  40. /**
  41. * Tests generating tuples in the fields side containing expressions
  42. */
  43. public function testTupleWithExpressionFields(): void
  44. {
  45. $field1 = new QueryExpression(['a' => 1]);
  46. $f = new TupleComparison([$field1, 'field2'], [4, 5], ['integer', 'integer'], '>');
  47. $binder = new ValueBinder();
  48. $this->assertSame('(a = :c0, field2) > (:tuple1, :tuple2)', $f->sql($binder));
  49. $this->assertSame(1, $binder->bindings()[':c0']['value']);
  50. $this->assertSame(4, $binder->bindings()[':tuple1']['value']);
  51. $this->assertSame(5, $binder->bindings()[':tuple2']['value']);
  52. }
  53. /**
  54. * Tests generating tuples in the values side containing expressions
  55. */
  56. public function testTupleWithExpressionValues(): void
  57. {
  58. $value1 = new QueryExpression(['a' => 1]);
  59. $f = new TupleComparison(['field1', 'field2'], [$value1, 2], ['integer', 'integer'], '=');
  60. $binder = new ValueBinder();
  61. $this->assertSame('(field1, field2) = (a = :c0, :tuple1)', $f->sql($binder));
  62. $this->assertSame(1, $binder->bindings()[':c0']['value']);
  63. $this->assertSame(2, $binder->bindings()[':tuple1']['value']);
  64. }
  65. /**
  66. * Tests generating tuples using the IN conjunction
  67. */
  68. public function testTupleWithInComparison(): void
  69. {
  70. $f = new TupleComparison(
  71. ['field1', 'field2'],
  72. [[1, 2], [3, 4]],
  73. ['integer', 'integer'],
  74. 'IN'
  75. );
  76. $binder = new ValueBinder();
  77. $this->assertSame('(field1, field2) IN ((:tuple0,:tuple1), (:tuple2,:tuple3))', $f->sql($binder));
  78. $this->assertSame(1, $binder->bindings()[':tuple0']['value']);
  79. $this->assertSame(2, $binder->bindings()[':tuple1']['value']);
  80. $this->assertSame(3, $binder->bindings()[':tuple2']['value']);
  81. $this->assertSame(4, $binder->bindings()[':tuple3']['value']);
  82. }
  83. /**
  84. * Tests traversing
  85. */
  86. public function testTraverse(): void
  87. {
  88. $value1 = new QueryExpression(['a' => 1]);
  89. $field2 = new QueryExpression(['b' => 2]);
  90. $f = new TupleComparison(['field1', $field2], [$value1, 2], ['integer', 'integer'], '=');
  91. $binder = new ValueBinder();
  92. $expressions = [];
  93. $collector = function ($e) use (&$expressions): void {
  94. $expressions[] = $e;
  95. };
  96. $f->traverse($collector);
  97. $this->assertCount(4, $expressions);
  98. $this->assertSame($field2, $expressions[0]);
  99. $this->assertSame($value1, $expressions[2]);
  100. $f = new TupleComparison(
  101. ['field1', $field2],
  102. [[1, 2], [3, $value1]],
  103. ['integer', 'integer'],
  104. 'IN'
  105. );
  106. $expressions = [];
  107. $f->traverse($collector);
  108. $this->assertCount(4, $expressions);
  109. $this->assertSame($field2, $expressions[0]);
  110. $this->assertSame($value1, $expressions[2]);
  111. }
  112. /**
  113. * Tests that a single ExpressionInterface can be used as the value for
  114. * comparison
  115. */
  116. public function testValueAsSingleExpression(): void
  117. {
  118. $value = new QueryExpression('SELECT 1, 1');
  119. $f = new TupleComparison(['field1', 'field2'], $value);
  120. $binder = new ValueBinder();
  121. $this->assertSame('(field1, field2) = (SELECT 1, 1)', $f->sql($binder));
  122. }
  123. /**
  124. * Tests that a single ExpressionInterface can be used as the field for
  125. * comparison
  126. */
  127. public function testFieldAsSingleExpression(): void
  128. {
  129. $value = [1, 1];
  130. $f = new TupleComparison(new QueryExpression('a, b'), $value);
  131. $binder = new ValueBinder();
  132. $this->assertSame('(a, b) = (:tuple0, :tuple1)', $f->sql($binder));
  133. }
  134. public function testMultiTupleComparisonRequiresMultiTupleValue(): void
  135. {
  136. $this->expectException(InvalidArgumentException::class);
  137. $this->expectExceptionMessage('Multi-tuple comparisons require a multi-tuple value, single-tuple given.');
  138. new TupleComparison(
  139. ['field1', 'field2'],
  140. [1, 1],
  141. ['integer', 'integer'],
  142. 'IN'
  143. );
  144. }
  145. public function testSingleTupleComparisonRequiresSingleTupleValue(): void
  146. {
  147. $this->expectException(InvalidArgumentException::class);
  148. $this->expectExceptionMessage('Single-tuple comparisons require a single-tuple value, multi-tuple given.');
  149. new TupleComparison(
  150. ['field1', 'field2'],
  151. [[1, 1], [2, 2]],
  152. ['integer', 'integer'],
  153. '='
  154. );
  155. }
  156. }