Skip to content
This repository was archived by the owner on Aug 22, 2023. It is now read-only.

Commit e3c73df

Browse files
committed
PHPORM-47 Improve Builder::whereBetween to support CarbonPeriod and reject invalid array
1 parent 8562a4b commit e3c73df

File tree

2 files changed

+203
-5
lines changed

2 files changed

+203
-5
lines changed

src/Query/Builder.php

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Jenssegers\Mongodb\Query;
44

5+
use Carbon\CarbonPeriod;
56
use Closure;
67
use DateTimeInterface;
78
use Illuminate\Database\Query\Builder as BaseBuilder;
@@ -559,6 +560,15 @@ public function whereBetween($column, iterable $values, $boolean = 'and', $not =
559560
{
560561
$type = 'between';
561562

563+
if (is_array($values)) {
564+
if (!array_is_list($values)) {
565+
throw new \InvalidArgumentException('Between array must a list with 2 elements: [min, max]');
566+
}
567+
if (count($values) !== 2) {
568+
throw new \InvalidArgumentException('Between array must have 2 elements: [min, max]');
569+
}
570+
}
571+
562572
$this->wheres[] = compact('column', 'type', 'boolean', 'values', 'not');
563573

564574
return $this;
@@ -995,11 +1005,18 @@ protected function compileWheres(): array
9951005
}
9961006
}
9971007
} elseif (isset($where['values'])) {
998-
array_walk_recursive($where['values'], function (&$item, $key) {
999-
if ($item instanceof DateTimeInterface) {
1000-
$item = new UTCDateTime($item);
1001-
}
1002-
});
1008+
if (is_array($where['values'])) {
1009+
array_walk_recursive($where['values'], function (&$item, $key) {
1010+
if ($item instanceof DateTimeInterface) {
1011+
$item = new UTCDateTime($item);
1012+
}
1013+
});
1014+
} elseif ($where['values'] instanceof CarbonPeriod) {
1015+
$where['values'] = [
1016+
new UTCDateTime($where['values']->getStartDate()),
1017+
new UTCDateTime($where['values']->getEndDate()),
1018+
];
1019+
}
10031020
}
10041021

10051022
// The next item in a "chain" of wheres devices the boolean of the

tests/Query/BuilderTest.php

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,174 @@ function (Builder $builder) {
124124
->orderBy('score', ['$meta' => 'textScore']),
125125
];
126126

127+
/** @see DatabaseQueryBuilderTest::testWhereBetweens() */
128+
yield 'whereBetween array of numbers' => [
129+
['find' => [
130+
['id' => ['$gte' => 1, '$lte' => 2]],
131+
['typeMap' => ['root' => 'array', 'document' => 'array']]],
132+
],
133+
fn (Builder $builder) => $builder->whereBetween('id', [1, 2]),
134+
];
135+
136+
/*
137+
yield 'whereBetween excessive nested array of numbers' => [
138+
['find' => [
139+
['id' => ['$gte' => 1, '$lte' => 2]],
140+
['typeMap' => ['root' => 'array', 'document' => 'array']]],
141+
],
142+
fn (Builder $builder) => $builder->whereBetween('id', [[1, 2, 3]]),
143+
];
144+
145+
yield 'whereBetween nested array of numbers' => [
146+
['find' => [
147+
['id' => ['$gte' => 1, '$lte' => 2]],
148+
['typeMap' => ['root' => 'array', 'document' => 'array']]],
149+
],
150+
fn (Builder $builder) => $builder->whereBetween('id', [[1], [2, 3]]),
151+
];
152+
*/
153+
154+
yield 'whereNotBetween array of numbers' => [
155+
['find' => [
156+
['$or' => [['id' => ['$lte' => 1]], ['id' => ['$gte' => 2]]]],
157+
['typeMap' => ['root' => 'array', 'document' => 'array']]],
158+
],
159+
fn (Builder $builder) => $builder->whereNotBetween('id', [1, 2]),
160+
];
161+
162+
$period = now()->toPeriod(now()->addDay());
163+
yield 'whereBetween CarbonPeriod' => [
164+
['find' => [
165+
['created_at' => ['$gte' => new UTCDateTime($period->start), '$lte' => new UTCDateTime($period->end)]],
166+
[]
167+
]],
168+
fn (Builder $builder) => $builder->whereBetween('created_at', $period),
169+
];
170+
171+
$period = now()->toPeriod(now()->addMonth());
172+
yield 'custom long carbon period date' => [
173+
['find' => [
174+
['created_at' => ['$gte' => new UTCDateTime($period->start), '$lte' => new UTCDateTime($period->end)]],
175+
[]
176+
]],
177+
fn (Builder $builder) => $builder->whereBetween('created_at', $period),
178+
];
179+
180+
yield 'whereBetween collection' => [
181+
['find' => [
182+
['id' => ['$gte' => 1, '$lte' => 2]],
183+
[]
184+
]],
185+
fn (Builder $builder) => $builder->whereBetween('id', collect([1, 2])),
186+
];
187+
188+
/** @see DatabaseQueryBuilderTest::testOrWhereBetween() */
189+
yield 'whereBetween array numbers' => [
190+
['find' => [
191+
['$or' => [['id' => 1], ['id' => ['$gte' => 3, '$lte' => 5]]]],
192+
[]
193+
]],
194+
fn (Builder $builder) => $builder
195+
->where('id', '=', 1)
196+
->orWhereBetween('id', [3, 5]),
197+
];
198+
199+
/*
200+
yield 'whereBetween excessive nested array numbers' => [
201+
['find' => [
202+
['$or' => [['id' => 1], ['id' => ['$gte' => 3, '$lte' => 4]]]],
203+
[]
204+
]],
205+
fn (Builder $builder) => $builder
206+
->where('id', '=', 1)
207+
->orWhereBetween('id', [[3, 4, 5]]),
208+
];
209+
210+
yield 'orWhereBetween nested array numbers' => [
211+
['find' => [
212+
['$or' => [['id' => 1], ['id' => ['$gte' => 3, '$lte' => 5]]]],
213+
[]
214+
]],
215+
fn (Builder $builder) => $builder
216+
->where('id', '=', 1)
217+
->orWhereBetween('id', [[3, 5]]),
218+
];
219+
220+
yield 'orWhereBetween nested excessive array numbers' => [
221+
['find' => [
222+
['$or' => [['id' => 1], ['id' => ['$gte' => 4, '$lte' => 6]]]],
223+
[]
224+
]],
225+
fn (Builder $builder) => $builder
226+
->where('id', '=', 1)
227+
->orWhereBetween('id', [[4], [6, 8]]),
228+
];
229+
*/
230+
231+
yield 'orWhereBetween collection' => [
232+
['find' => [
233+
['$or' => [['id' => 1], ['id' => ['$gte' => 3, '$lte' => 4]]]],
234+
[]
235+
]],
236+
fn (Builder $builder) => $builder
237+
->where('id', '=', 1)
238+
->orWhereBetween('id', collect([3, 4])),
239+
];
240+
241+
/** @see DatabaseQueryBuilderTest::testOrWhereNotBetween() */
242+
yield 'orWhereNotBetween array of numbers' => [
243+
['find' => [
244+
['$or' => [['id' => 1], ['$or' => [['id' => ['$lte' => 3]], ['id' => ['$gte' => 5]]]]]],
245+
[]
246+
]],
247+
fn (Builder $builder) => $builder
248+
->where('id', '=', 1)
249+
->orWhereNotBetween('id', [3, 5]),
250+
];
251+
252+
/*
253+
yield 'orWhereNotBetween excessive array of numbers' => [
254+
['find' => [
255+
['$or' => [['id' => 1], ['$or' => [['id' => ['$lte' => 3]], ['id' => ['$gte' => 4]]]]]],
256+
[]
257+
]],
258+
fn (Builder $builder) => $builder
259+
->where('id', '=', 1)
260+
->orWhereNotBetween('id', [[3, 4, 5]]),
261+
];
262+
263+
yield 'orWhereNotBetween nested array of numbers' => [
264+
['find' => [
265+
['$or' => [['id' => 1], ['$or' => [['id' => ['$lte' => 3]], ['id' => ['$gte' => 5]]]]]],
266+
[]
267+
]],
268+
fn (Builder $builder) => $builder
269+
->where('id', '=', 1)
270+
->orWhereNotBetween('id', [[3, 5]]),
271+
];
272+
*/
273+
274+
yield 'orWhereNotBetween excessive nested array of numbers' => [
275+
['find' => [
276+
['$or' => [['id' => 1], ['$or' => [['id' => ['$lte' => [4]]], ['id' => ['$gte' => [6, 8]]]]]]],
277+
//['$or' => [['id' => 1], ['$or' => [['id' => ['$lte' => 4]], ['id' => ['$gte' => 6]]]]]],
278+
[]
279+
]],
280+
fn (Builder $builder) => $builder
281+
->where('id', '=', 1)
282+
->orWhereNotBetween('id', [[4], [6, 8]]),
283+
];
284+
285+
yield 'orWhereNotBetween collection' => [
286+
['find' => [
287+
['$or' => [['id' => 1], ['$or' => [['id' => ['$lte' => 3]], ['id' => ['$gte' => 4]]]]]],
288+
[]
289+
]],
290+
fn (Builder $builder) => $builder
291+
->where('id', '=', 1)
292+
->orWhereNotBetween('id', collect([3, 4])),
293+
];
294+
127295
yield 'distinct' => [
128296
['distinct' => ['foo', [], []]],
129297
fn (Builder $builder) => $builder->distinct('foo'),
@@ -154,6 +322,19 @@ public static function provideExceptions(): iterable
154322
'Order direction must be "asc" or "desc"',
155323
fn (Builder $builder) => $builder->orderBy('_id', 'dasc'),
156324
];
325+
326+
/** @see DatabaseQueryBuilderTest::testWhereBetweens */
327+
yield [
328+
\InvalidArgumentException::class,
329+
'Between array must have 2 elements: [min, max]',
330+
fn (Builder $builder) => $builder->whereBetween('id', [1, 2, 3]),
331+
];
332+
333+
yield [
334+
\InvalidArgumentException::class,
335+
'Between array must a list with 2 elements: [min, max]',
336+
fn (Builder $builder) => $builder->whereBetween('id', ['min' => 1, 'max' => 2]),
337+
];
157338
}
158339

159340
private static function getBuilder(): Builder

0 commit comments

Comments
 (0)