1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Doctrine\Tests\DBAL\Query\Expression; |
4
|
|
|
|
5
|
|
|
use Doctrine\DBAL\Connection; |
6
|
|
|
use Doctrine\DBAL\Query\Expression\CompositeExpression; |
7
|
|
|
use Doctrine\DBAL\Query\Expression\ExpressionBuilder; |
8
|
|
|
use Doctrine\Tests\DbalTestCase; |
9
|
|
|
|
10
|
|
|
/** |
11
|
|
|
* @group DBAL-12 |
12
|
|
|
*/ |
13
|
|
|
class ExpressionBuilderTest extends DbalTestCase |
14
|
|
|
{ |
15
|
|
|
/** @var ExpressionBuilder */ |
16
|
|
|
protected $expr; |
17
|
|
|
|
18
|
|
|
protected function setUp() : void |
19
|
|
|
{ |
20
|
|
|
$conn = $this->createMock(Connection::class); |
21
|
|
|
|
22
|
|
|
$this->expr = new ExpressionBuilder($conn); |
23
|
|
|
|
24
|
|
|
$conn->expects($this->any()) |
25
|
|
|
->method('getExpressionBuilder') |
26
|
|
|
->will($this->returnValue($this->expr)); |
27
|
|
|
} |
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* @param string[]|CompositeExpression[] $parts |
31
|
|
|
* |
32
|
|
|
* @dataProvider provideDataForAnd |
33
|
|
|
*/ |
34
|
|
|
public function testAnd(array $parts, string $expected) : void |
35
|
|
|
{ |
36
|
|
|
$composite = $this->expr->and(...$parts); |
37
|
|
|
|
38
|
|
|
self::assertEquals($expected, (string) $composite); |
39
|
|
|
} |
40
|
|
|
|
41
|
|
|
/** |
42
|
|
|
* @param string[]|CompositeExpression[] $parts |
43
|
|
|
* |
44
|
|
|
* @dataProvider provideDataForAnd |
45
|
|
|
*/ |
46
|
|
|
public function testAndX(array $parts, string $expected) : void |
47
|
|
|
{ |
48
|
|
|
$composite = $this->expr->andX(); |
|
|
|
|
49
|
|
|
|
50
|
|
|
foreach ($parts as $part) { |
51
|
|
|
$composite->add($part); |
52
|
|
|
} |
53
|
|
|
|
54
|
|
|
self::assertEquals($expected, (string) $composite); |
55
|
|
|
} |
56
|
|
|
|
57
|
|
|
/** |
58
|
|
|
* @return mixed[][] |
59
|
|
|
*/ |
60
|
|
|
public static function provideDataForAnd() : iterable |
61
|
|
|
{ |
62
|
|
|
return [ |
63
|
|
|
[ |
64
|
|
|
['u.user = 1'], |
65
|
|
|
'u.user = 1', |
66
|
|
|
], |
67
|
|
|
[ |
68
|
|
|
['u.user = 1', 'u.group_id = 1'], |
69
|
|
|
'(u.user = 1) AND (u.group_id = 1)', |
70
|
|
|
], |
71
|
|
|
[ |
72
|
|
|
['u.user = 1'], |
73
|
|
|
'u.user = 1', |
74
|
|
|
], |
75
|
|
|
[ |
76
|
|
|
['u.group_id = 1', 'u.group_id = 2'], |
77
|
|
|
'(u.group_id = 1) AND (u.group_id = 2)', |
78
|
|
|
], |
79
|
|
|
[ |
80
|
|
|
[ |
81
|
|
|
'u.user = 1', |
82
|
|
|
new CompositeExpression( |
83
|
|
|
CompositeExpression::TYPE_OR, |
84
|
|
|
['u.group_id = 1', 'u.group_id = 2'] |
85
|
|
|
), |
86
|
|
|
], |
87
|
|
|
'(u.user = 1) AND ((u.group_id = 1) OR (u.group_id = 2))', |
88
|
|
|
], |
89
|
|
|
[ |
90
|
|
|
[ |
91
|
|
|
'u.group_id = 1', |
92
|
|
|
new CompositeExpression( |
93
|
|
|
CompositeExpression::TYPE_AND, |
94
|
|
|
['u.user = 1', 'u.group_id = 2'] |
95
|
|
|
), |
96
|
|
|
], |
97
|
|
|
'(u.group_id = 1) AND ((u.user = 1) AND (u.group_id = 2))', |
98
|
|
|
], |
99
|
|
|
]; |
100
|
|
|
} |
101
|
|
|
|
102
|
|
|
/** |
103
|
|
|
* @param string[]|CompositeExpression[] $parts |
104
|
|
|
* |
105
|
|
|
* @dataProvider provideDataForOr |
106
|
|
|
*/ |
107
|
|
|
public function testOr(array $parts, string $expected) : void |
108
|
|
|
{ |
109
|
|
|
$composite = $this->expr->or(...$parts); |
110
|
|
|
|
111
|
|
|
self::assertEquals($expected, (string) $composite); |
112
|
|
|
} |
113
|
|
|
|
114
|
|
|
/** |
115
|
|
|
* @param string[]|CompositeExpression[] $parts |
116
|
|
|
* |
117
|
|
|
* @dataProvider provideDataForOr |
118
|
|
|
*/ |
119
|
|
|
public function testOrX(array $parts, string $expected) : void |
120
|
|
|
{ |
121
|
|
|
$composite = $this->expr->orX(); |
|
|
|
|
122
|
|
|
|
123
|
|
|
foreach ($parts as $part) { |
124
|
|
|
$composite->add($part); |
125
|
|
|
} |
126
|
|
|
|
127
|
|
|
self::assertEquals($expected, (string) $composite); |
128
|
|
|
} |
129
|
|
|
|
130
|
|
|
/** |
131
|
|
|
* @return mixed[][] |
132
|
|
|
*/ |
133
|
|
|
public static function provideDataForOr() : iterable |
134
|
|
|
{ |
135
|
|
|
return [ |
136
|
|
|
[ |
137
|
|
|
['u.user = 1'], |
138
|
|
|
'u.user = 1', |
139
|
|
|
], |
140
|
|
|
[ |
141
|
|
|
['u.user = 1', 'u.group_id = 1'], |
142
|
|
|
'(u.user = 1) OR (u.group_id = 1)', |
143
|
|
|
], |
144
|
|
|
[ |
145
|
|
|
['u.user = 1'], |
146
|
|
|
'u.user = 1', |
147
|
|
|
], |
148
|
|
|
[ |
149
|
|
|
['u.group_id = 1', 'u.group_id = 2'], |
150
|
|
|
'(u.group_id = 1) OR (u.group_id = 2)', |
151
|
|
|
], |
152
|
|
|
[ |
153
|
|
|
[ |
154
|
|
|
'u.user = 1', |
155
|
|
|
new CompositeExpression( |
156
|
|
|
CompositeExpression::TYPE_OR, |
157
|
|
|
['u.group_id = 1', 'u.group_id = 2'] |
158
|
|
|
), |
159
|
|
|
], |
160
|
|
|
'(u.user = 1) OR ((u.group_id = 1) OR (u.group_id = 2))', |
161
|
|
|
], |
162
|
|
|
[ |
163
|
|
|
[ |
164
|
|
|
'u.group_id = 1', |
165
|
|
|
new CompositeExpression( |
166
|
|
|
CompositeExpression::TYPE_AND, |
167
|
|
|
['u.user = 1', 'u.group_id = 2'] |
168
|
|
|
), |
169
|
|
|
], |
170
|
|
|
'(u.group_id = 1) OR ((u.user = 1) AND (u.group_id = 2))', |
171
|
|
|
], |
172
|
|
|
]; |
173
|
|
|
} |
174
|
|
|
|
175
|
|
|
/** |
176
|
|
|
* @dataProvider provideDataForComparison |
177
|
|
|
*/ |
178
|
|
|
public function testComparison(string $leftExpr, string $operator, string $rightExpr, string $expected) : void |
179
|
|
|
{ |
180
|
|
|
$part = $this->expr->comparison($leftExpr, $operator, $rightExpr); |
181
|
|
|
|
182
|
|
|
self::assertEquals($expected, (string) $part); |
183
|
|
|
} |
184
|
|
|
|
185
|
|
|
/** |
186
|
|
|
* @return mixed[][] |
187
|
|
|
*/ |
188
|
|
|
public static function provideDataForComparison() : iterable |
189
|
|
|
{ |
190
|
|
|
return [ |
191
|
|
|
['u.user_id', ExpressionBuilder::EQ, '1', 'u.user_id = 1'], |
192
|
|
|
['u.user_id', ExpressionBuilder::NEQ, '1', 'u.user_id <> 1'], |
193
|
|
|
['u.salary', ExpressionBuilder::LT, '10000', 'u.salary < 10000'], |
194
|
|
|
['u.salary', ExpressionBuilder::LTE, '10000', 'u.salary <= 10000'], |
195
|
|
|
['u.salary', ExpressionBuilder::GT, '10000', 'u.salary > 10000'], |
196
|
|
|
['u.salary', ExpressionBuilder::GTE, '10000', 'u.salary >= 10000'], |
197
|
|
|
]; |
198
|
|
|
} |
199
|
|
|
|
200
|
|
|
public function testEq() : void |
201
|
|
|
{ |
202
|
|
|
self::assertEquals('u.user_id = 1', $this->expr->eq('u.user_id', '1')); |
203
|
|
|
} |
204
|
|
|
|
205
|
|
|
public function testNeq() : void |
206
|
|
|
{ |
207
|
|
|
self::assertEquals('u.user_id <> 1', $this->expr->neq('u.user_id', '1')); |
208
|
|
|
} |
209
|
|
|
|
210
|
|
|
public function testLt() : void |
211
|
|
|
{ |
212
|
|
|
self::assertEquals('u.salary < 10000', $this->expr->lt('u.salary', '10000')); |
213
|
|
|
} |
214
|
|
|
|
215
|
|
|
public function testLte() : void |
216
|
|
|
{ |
217
|
|
|
self::assertEquals('u.salary <= 10000', $this->expr->lte('u.salary', '10000')); |
218
|
|
|
} |
219
|
|
|
|
220
|
|
|
public function testGt() : void |
221
|
|
|
{ |
222
|
|
|
self::assertEquals('u.salary > 10000', $this->expr->gt('u.salary', '10000')); |
223
|
|
|
} |
224
|
|
|
|
225
|
|
|
public function testGte() : void |
226
|
|
|
{ |
227
|
|
|
self::assertEquals('u.salary >= 10000', $this->expr->gte('u.salary', '10000')); |
228
|
|
|
} |
229
|
|
|
|
230
|
|
|
public function testIsNull() : void |
231
|
|
|
{ |
232
|
|
|
self::assertEquals('u.deleted IS NULL', $this->expr->isNull('u.deleted')); |
233
|
|
|
} |
234
|
|
|
|
235
|
|
|
public function testIsNotNull() : void |
236
|
|
|
{ |
237
|
|
|
self::assertEquals('u.updated IS NOT NULL', $this->expr->isNotNull('u.updated')); |
238
|
|
|
} |
239
|
|
|
|
240
|
|
|
public function testIn() : void |
241
|
|
|
{ |
242
|
|
|
self::assertEquals('u.groups IN (1, 3, 4, 7)', $this->expr->in('u.groups', [1, 3, 4, 7])); |
243
|
|
|
} |
244
|
|
|
|
245
|
|
|
public function testInWithPlaceholder() : void |
246
|
|
|
{ |
247
|
|
|
self::assertEquals('u.groups IN (?)', $this->expr->in('u.groups', '?')); |
248
|
|
|
} |
249
|
|
|
|
250
|
|
|
public function testNotIn() : void |
251
|
|
|
{ |
252
|
|
|
self::assertEquals('u.groups NOT IN (1, 3, 4, 7)', $this->expr->notIn('u.groups', [1, 3, 4, 7])); |
253
|
|
|
} |
254
|
|
|
|
255
|
|
|
public function testNotInWithPlaceholder() : void |
256
|
|
|
{ |
257
|
|
|
self::assertEquals('u.groups NOT IN (:values)', $this->expr->notIn('u.groups', ':values')); |
258
|
|
|
} |
259
|
|
|
|
260
|
|
|
public function testLikeWithoutEscape() : void |
261
|
|
|
{ |
262
|
|
|
self::assertEquals("a.song LIKE 'a virgin'", $this->expr->like('a.song', "'a virgin'")); |
263
|
|
|
} |
264
|
|
|
|
265
|
|
|
public function testLikeWithEscape() : void |
266
|
|
|
{ |
267
|
|
|
self::assertEquals( |
268
|
|
|
"a.song LIKE 'a virgin' ESCAPE '💩'", |
269
|
|
|
$this->expr->like('a.song', "'a virgin'", "'💩'") |
270
|
|
|
); |
271
|
|
|
} |
272
|
|
|
|
273
|
|
|
public function testNotLikeWithoutEscape() : void |
274
|
|
|
{ |
275
|
|
|
self::assertEquals( |
276
|
|
|
"s.last_words NOT LIKE 'this'", |
277
|
|
|
$this->expr->notLike('s.last_words', "'this'") |
278
|
|
|
); |
279
|
|
|
} |
280
|
|
|
|
281
|
|
|
public function testNotLikeWithEscape() : void |
282
|
|
|
{ |
283
|
|
|
self::assertEquals( |
284
|
|
|
"p.description NOT LIKE '20💩%' ESCAPE '💩'", |
285
|
|
|
$this->expr->notLike('p.description', "'20💩%'", "'💩'") |
286
|
|
|
); |
287
|
|
|
} |
288
|
|
|
} |
289
|
|
|
|
This function has been deprecated. The supplier of the function has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.