Skip to content

Commit feee548

Browse files
Use QueriesJsonColumns trait in entry query builder (#488)
* Use `QueriesJsonColumns` trait in entry query builder * Rename tests * Fix styling * Handle cast where `Collection::find()` result is null * simplify conditional --------- Co-authored-by: duncanmcclean <[email protected]>
1 parent 7c404f2 commit feee548

File tree

2 files changed

+29
-88
lines changed

2 files changed

+29
-88
lines changed

src/Entries/EntryQueryBuilder.php

Lines changed: 27 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,25 @@
22

33
namespace Statamic\Eloquent\Entries;
44

5+
use Illuminate\Support\Collection as IlluminateCollection;
56
use Illuminate\Support\Str;
67
use Statamic\Contracts\Entries\QueryBuilder;
78
use Statamic\Eloquent\Entries\Entry as EloquentEntry;
9+
use Statamic\Eloquent\QueriesJsonColumns;
810
use Statamic\Entries\EntryCollection;
911
use Statamic\Facades\Blink;
1012
use Statamic\Facades\Collection;
1113
use Statamic\Facades\Entry;
1214
use Statamic\Facades\Taxonomy;
15+
use Statamic\Fields\Field;
1316
use Statamic\Query\EloquentQueryBuilder;
1417
use Statamic\Stache\Query\QueriesEntryStatus;
1518
use Statamic\Stache\Query\QueriesTaxonomizedEntries;
1619

1720
class EntryQueryBuilder extends EloquentQueryBuilder implements QueryBuilder
1821
{
1922
use QueriesEntryStatus,
23+
QueriesJsonColumns,
2024
QueriesTaxonomizedEntries;
2125

2226
private $selectedQueryColumns;
@@ -28,92 +32,6 @@ class EntryQueryBuilder extends EloquentQueryBuilder implements QueryBuilder
2832
'date', 'collection', 'created_at', 'updated_at', 'order', 'blueprint',
2933
];
3034

31-
public function orderBy($column, $direction = 'asc')
32-
{
33-
$actualColumn = $this->column($column);
34-
35-
if (Str::contains($actualColumn, 'data->')) {
36-
$wheres = collect($this->builder->getQuery()->wheres);
37-
38-
if ($wheres->where('column', 'collection')->count() == 1) {
39-
$collectionWhere = $wheres->firstWhere('column', 'collection');
40-
if (isset($collectionWhere['values']) && count($collectionWhere['values']) == 1) {
41-
$collectionWhere['value'] = $collectionWhere['values'][0];
42-
}
43-
44-
if (isset($collectionWhere['value'])) {
45-
if ($collection = Collection::find($collectionWhere['value'])) {
46-
$blueprintField = $collection->entryBlueprints()
47-
->flatMap(function ($blueprint) {
48-
return $blueprint->fields()
49-
->all()
50-
->filter(function ($field) {
51-
return in_array($field->type(), ['float', 'integer', 'date']);
52-
});
53-
})
54-
->filter()
55-
->get($column);
56-
57-
if ($blueprintField) {
58-
$castType = '';
59-
$fieldType = $blueprintField->type();
60-
61-
$grammar = $this->builder->getConnection()->getQueryGrammar();
62-
$actualColumn = $grammar->wrap($actualColumn);
63-
64-
if (in_array($fieldType, ['float'])) {
65-
$castType = 'float';
66-
} elseif (in_array($fieldType, ['integer'])) {
67-
$castType = 'float'; // bit sneaky but mysql doesnt support casting as integer, it wants unsigned
68-
} elseif (in_array($fieldType, ['date'])) {
69-
// Take time into account when enabled
70-
if ($blueprintField->get('time_enabled')) {
71-
$castType = 'datetime';
72-
} else {
73-
$castType = 'date';
74-
}
75-
76-
// take range into account
77-
if ($blueprintField->get('mode') == 'range') {
78-
$actualColumnStartDate = $grammar->wrap($this->column($column).'->start');
79-
$actualColumnEndDate = $grammar->wrap($this->column($column).'->end');
80-
if (str_contains(get_class($grammar), 'SQLiteGrammar')) {
81-
$this->builder
82-
->orderByRaw("datetime({$actualColumnStartDate}) {$direction}")
83-
->orderByRaw("datetime({$actualColumnEndDate}) {$direction}");
84-
} else {
85-
$this->builder
86-
->orderByRaw("cast({$actualColumnStartDate} as {$castType}) {$direction}")
87-
->orderByRaw("cast({$actualColumnEndDate} as {$castType}) {$direction}");
88-
}
89-
90-
return $this;
91-
}
92-
93-
// sqlite casts dates to year, which is pretty unhelpful
94-
if (str_contains(get_class($grammar), 'SQLiteGrammar')) {
95-
$this->builder->orderByRaw("datetime({$actualColumn}) {$direction}");
96-
97-
return $this;
98-
}
99-
}
100-
101-
if ($castType) {
102-
$this->builder->orderByRaw("cast({$actualColumn} as {$castType}) {$direction}");
103-
104-
return $this;
105-
}
106-
}
107-
}
108-
}
109-
}
110-
}
111-
112-
parent::orderBy($column, $direction);
113-
114-
return $this;
115-
}
116-
11735
protected function transform($items, $columns = [])
11836
{
11937
$items = EntryCollection::make($items)->map(function ($model) use ($columns) {
@@ -292,4 +210,27 @@ private function getKeysForTaxonomyWhereIn($where)
292210
->pluck('id');
293211
});
294212
}
213+
214+
protected function getJsonCasts(): IlluminateCollection
215+
{
216+
$wheres = collect($this->builder->getQuery()->wheres);
217+
$collectionWhere = $wheres->firstWhere('column', 'collection');
218+
219+
if (
220+
! $collectionWhere
221+
|| ! isset($collectionWhere['value'])
222+
|| ! ($collection = Collection::find($collectionWhere['value']))
223+
) {
224+
return [];
225+
}
226+
227+
return $collection->entryBlueprints()
228+
->flatMap(function ($blueprint) {
229+
return $blueprint->fields()
230+
->all()
231+
->filter(fn ($field) => in_array($field->type(), ['float', 'integer', 'date']))
232+
->map(fn (Field $field) => $this->toCast($field));
233+
})
234+
->filter();
235+
}
295236
}

tests/Data/Entries/EntryQueryBuilderTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -764,7 +764,7 @@ public function entries_can_be_ordered_by_an_integer_json_field()
764764
}
765765

766766
#[Test]
767-
public function entries_can_be_ordered_by_an_float_json_field()
767+
public function entries_can_be_ordered_by_a_float_json_field()
768768
{
769769
$blueprint = Blueprint::makeFromFields(['float' => ['type' => 'float']]);
770770
Blueprint::shouldReceive('in')->with('collections/posts')->andReturn(collect(['posts' => $blueprint]));
@@ -781,7 +781,7 @@ public function entries_can_be_ordered_by_an_float_json_field()
781781
}
782782

783783
#[Test]
784-
public function entries_can_be_ordered_by_an_date_json_field()
784+
public function entries_can_be_ordered_by_a_date_json_field()
785785
{
786786
$blueprint = Blueprint::makeFromFields(['date_field' => ['type' => 'date', 'time_enabled' => true]]);
787787
Blueprint::shouldReceive('in')->with('collections/posts')->andReturn(collect(['posts' => $blueprint]));

0 commit comments

Comments
 (0)