Skip to content

Commit e77c16d

Browse files
committed
Fix withAggregate
1 parent f86f52e commit e77c16d

File tree

3 files changed

+265
-177
lines changed

3 files changed

+265
-177
lines changed

src/Eloquent/Builder.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ public function withAggregate($relations, $column, $function = null)
319319
$segments = explode(' ', $name);
320320

321321
$name = $segments[0];
322-
$alias = (count($segments) === 3 && Str::lower($segments[1]) === 'as' ? $segments[2] : Str::snake($name) . '_count');
322+
$alias = (count($segments) === 3 && Str::lower($segments[1]) === 'as' ? $segments[2] : Str::snake($name) . '_' . $function);
323323

324324
$relation = $this->getRelationWithoutConstraints($name);
325325

@@ -335,6 +335,7 @@ public function withAggregate($relations, $column, $function = null)
335335
throw new InvalidArgumentException(sprintf('Invalid aggregate function "%s"', $function));
336336
}
337337
} else {
338+
// @todo support "exists"
338339
$this->withAggregate[$alias] = [
339340
'relation' => $relation,
340341
'function' => $function,
Lines changed: 263 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
<?php
2+
3+
namespace MongoDB\Laravel\Tests\Eloquent;
4+
5+
use Illuminate\Database\Eloquent\Builder;
6+
use Illuminate\Support\Facades\DB;
7+
use MongoDB\Laravel\Eloquent\Model;
8+
use MongoDB\Laravel\Tests\TestCase;
9+
10+
use function count;
11+
12+
class EloquentWithAggregateTest extends TestCase
13+
{
14+
protected function tearDown(): void
15+
{
16+
EloquentWithCountModel1::truncate();
17+
EloquentWithCountModel2::truncate();
18+
EloquentWithCountModel3::truncate();
19+
EloquentWithCountModel4::truncate();
20+
21+
parent::tearDown();
22+
}
23+
24+
public function testWithAggregate()
25+
{
26+
EloquentWithCountModel1::create(['id' => 1]);
27+
$one = EloquentWithCountModel1::create(['id' => 2]);
28+
$one->twos()->create(['value' => 4]);
29+
$one->twos()->create(['value' => 6]);
30+
31+
$results = EloquentWithCountModel1::withCount('twos')->where('id', 2);
32+
$this->assertSame([
33+
['id' => 2, 'twos_count' => 2],
34+
], $results->get()->toArray());
35+
36+
$results = EloquentWithCountModel1::withMax('twos', 'value')->where('id', 2);
37+
$this->assertSame([
38+
['id' => 2, 'twos_max' => 6],
39+
], $results->get()->toArray());
40+
41+
$results = EloquentWithCountModel1::withMin('twos', 'value')->where('id', 2);
42+
$this->assertSame([
43+
['id' => 2, 'twos_min' => 4],
44+
], $results->get()->toArray());
45+
46+
$results = EloquentWithCountModel1::withAvg('twos', 'value')->where('id', 2);
47+
$this->assertSame([
48+
['id' => 2, 'twos_avg' => 5.0],
49+
], $results->get()->toArray());
50+
}
51+
52+
public function testWithAggregateFiltered()
53+
{
54+
EloquentWithCountModel1::create(['id' => 1]);
55+
$one = EloquentWithCountModel1::create(['id' => 2]);
56+
$one->twos()->create(['value' => 4]);
57+
$one->twos()->create(['value' => 6]);
58+
$one->twos()->create(['value' => 8]);
59+
$filter = static function (Builder $query) {
60+
$query->where('value', '<=', 6);
61+
};
62+
63+
$results = EloquentWithCountModel1::withCount(['twos' => $filter])->where('id', 2);
64+
$this->assertSame([
65+
['id' => 2, 'twos_count' => 2],
66+
], $results->get()->toArray());
67+
68+
$results = EloquentWithCountModel1::withMax(['twos' => $filter], 'value')->where('id', 2);
69+
$this->assertSame([
70+
['id' => 2, 'twos_max' => 6],
71+
], $results->get()->toArray());
72+
73+
$results = EloquentWithCountModel1::withMin(['twos' => $filter], 'value')->where('id', 2);
74+
$this->assertSame([
75+
['id' => 2, 'twos_min' => 4],
76+
], $results->get()->toArray());
77+
78+
$results = EloquentWithCountModel1::withAvg(['twos' => $filter], 'value')->where('id', 2);
79+
$this->assertSame([
80+
['id' => 2, 'twos_avg' => 5.0],
81+
], $results->get()->toArray());
82+
}
83+
84+
public function testWithAggregateMultipleResults()
85+
{
86+
$connection = DB::connection('mongodb');
87+
$ones = [
88+
EloquentWithCountModel1::create(['id' => 1]),
89+
EloquentWithCountModel1::create(['id' => 2]),
90+
EloquentWithCountModel1::create(['id' => 3]),
91+
EloquentWithCountModel1::create(['id' => 4]),
92+
];
93+
94+
$ones[0]->twos()->create(['value' => 1]);
95+
$ones[0]->twos()->create(['value' => 2]);
96+
$ones[0]->twos()->create(['value' => 3]);
97+
$ones[0]->twos()->create(['value' => 1]);
98+
$ones[2]->twos()->create(['value' => 1]);
99+
$ones[2]->twos()->create(['value' => 2]);
100+
101+
$connection->enableQueryLog();
102+
103+
// Count
104+
$results = EloquentWithCountModel1::withCount([
105+
'twos' => function ($query) {
106+
$query->where('value', '>=', 2);
107+
},
108+
]);
109+
110+
$this->assertSame([
111+
['id' => 1, 'twos_count' => 2],
112+
['id' => 2, 'twos_count' => 0],
113+
['id' => 3, 'twos_count' => 1],
114+
['id' => 4, 'twos_count' => 0],
115+
], $results->get()->toArray());
116+
117+
$this->assertSame(2, count($connection->getQueryLog()));
118+
$connection->flushQueryLog();
119+
120+
// Max
121+
$results = EloquentWithCountModel1::withMax([
122+
'twos' => function ($query) {
123+
$query->where('value', '>=', 2);
124+
},
125+
], 'value');
126+
127+
$this->assertSame([
128+
['id' => 1, 'twos_max' => 3],
129+
['id' => 2, 'twos_max' => null],
130+
['id' => 3, 'twos_max' => 2],
131+
['id' => 4, 'twos_max' => null],
132+
], $results->get()->toArray());
133+
134+
$this->assertSame(2, count($connection->getQueryLog()));
135+
$connection->flushQueryLog();
136+
137+
// Min
138+
$results = EloquentWithCountModel1::withMin([
139+
'twos' => function ($query) {
140+
$query->where('value', '>=', 2);
141+
},
142+
], 'value');
143+
144+
$this->assertSame([
145+
['id' => 1, 'twos_min' => 2],
146+
['id' => 2, 'twos_min' => null],
147+
['id' => 3, 'twos_min' => 2],
148+
['id' => 4, 'twos_min' => null],
149+
], $results->get()->toArray());
150+
151+
$this->assertSame(2, count($connection->getQueryLog()));
152+
$connection->flushQueryLog();
153+
154+
// Avg
155+
$results = EloquentWithCountModel1::withAvg([
156+
'twos' => function ($query) {
157+
$query->where('value', '>=', 2);
158+
},
159+
], 'value');
160+
161+
$this->assertSame([
162+
['id' => 1, 'twos_avg' => 2.5],
163+
['id' => 2, 'twos_avg' => null],
164+
['id' => 3, 'twos_avg' => 2.0],
165+
['id' => 4, 'twos_avg' => null],
166+
], $results->get()->toArray());
167+
168+
$this->assertSame(2, count($connection->getQueryLog()));
169+
$connection->flushQueryLog();
170+
}
171+
172+
public function testGlobalScopes()
173+
{
174+
$one = EloquentWithCountModel1::create();
175+
$one->fours()->create();
176+
177+
$result = EloquentWithCountModel1::withCount('fours')->first();
178+
$this->assertSame(0, $result->fours_count);
179+
180+
$result = EloquentWithCountModel1::withCount('allFours')->first();
181+
$this->assertSame(1, $result->all_fours_count);
182+
}
183+
}
184+
185+
class EloquentWithCountModel1 extends Model
186+
{
187+
protected $connection = 'mongodb';
188+
public $table = 'one';
189+
public $timestamps = false;
190+
protected $guarded = [];
191+
192+
public function twos()
193+
{
194+
return $this->hasMany(EloquentWithCountModel2::class, 'one_id');
195+
}
196+
197+
public function fours()
198+
{
199+
return $this->hasMany(EloquentWithCountModel4::class, 'one_id');
200+
}
201+
202+
public function allFours()
203+
{
204+
return $this->fours()->withoutGlobalScopes();
205+
}
206+
}
207+
208+
class EloquentWithCountModel2 extends Model
209+
{
210+
protected $connection = 'mongodb';
211+
public $table = 'two';
212+
public $timestamps = false;
213+
protected $guarded = [];
214+
protected $withCount = ['threes'];
215+
216+
protected static function boot()
217+
{
218+
parent::boot();
219+
220+
static::addGlobalScope('app', function ($builder) {
221+
$builder->latest();
222+
});
223+
}
224+
225+
public function threes()
226+
{
227+
return $this->hasMany(EloquentWithCountModel3::class, 'two_id');
228+
}
229+
}
230+
231+
class EloquentWithCountModel3 extends Model
232+
{
233+
protected $connection = 'mongodb';
234+
public $table = 'three';
235+
public $timestamps = false;
236+
protected $guarded = [];
237+
238+
protected static function boot()
239+
{
240+
parent::boot();
241+
242+
static::addGlobalScope('app', function ($builder) {
243+
$builder->where('id', '>', 0);
244+
});
245+
}
246+
}
247+
248+
class EloquentWithCountModel4 extends Model
249+
{
250+
protected $connection = 'mongodb';
251+
public $table = 'four';
252+
public $timestamps = false;
253+
protected $guarded = [];
254+
255+
protected static function boot()
256+
{
257+
parent::boot();
258+
259+
static::addGlobalScope('app', function ($builder) {
260+
$builder->where('id', '>', 1);
261+
});
262+
}
263+
}

0 commit comments

Comments
 (0)