From d9c7093b5c66ae7bb28c8f5f947c5116df7cd4f3 Mon Sep 17 00:00:00 2001 From: mohammad sharif ahrari Date: Wed, 22 Aug 2018 10:47:29 +0430 Subject: [PATCH 01/17] add withSum add withSum to framework . in the past people try to add withMax withMin withAvg withSum and ... together and implements withCount i think its should be separte because in withSum withAvg and... we should determine what column but in withCount we dont so i add withSum if you think its ok( i test it ) add withAvg and .... . im not pro to do that soory for my bad english --- .../Concerns/QueriesRelationships.php | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php b/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php index 5f2ec2dab7b9..8b551c03dd3e 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php +++ b/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php @@ -226,6 +226,63 @@ public function withCount($relations) return $this; } + /** + * Add subselect queries to sum the relations. + * + * @param mixed $relations + * @return $this + */ + public function withSum($relations,$column) + { + if (empty($relations)) { + return $this; + } + + if (is_null($this->query->columns)) { + $this->query->select([$this->query->from.'.*']); + } + + $relations = is_array($relations) ? $relations : [$relations]; + + foreach ($this->parseWithRelations($relations) as $name => $constraints) { + // First we will determine if the name has been aliased using an "as" clause on the name + // and if it has we will extract the actual relationship name and the desired name of + // the resulting column. This allows multiple counts on the same relationship name. + $segments = explode(' ', $name); + + unset($alias); + + if (count($segments) == 3 && Str::lower($segments[1]) == 'as') { + list($name, $alias) = [$segments[0], $segments[2]]; + } + + $relation = $this->getRelationWithoutConstraints($name); + + // Here we will get the relationship count query and prepare to add it to the main query + // as a sub-select. First, we'll get the "has" query and use that to get the relation + // count query. We will normalize the relation name then append _count as the name. + $query = $relation->getRelationExistenceSumQuery( + $relation->getRelated()->newQuery(), $this,$column + ); + + $query->callScope($constraints); + + $query = $query->mergeConstraintsFrom($relation->getQuery())->toBase(); + + if (count($query->columns) > 1) { + $query->columns = [$query->columns[0]]; + } + + // Finally we will add the proper result column alias to the query and run the subselect + // statement against the query builder. Then we will return the builder instance back + // to the developer for further constraint chaining that needs to take place on it. + $column = $alias ?? Str::snake($name.'_sum'); + + $this->selectSub($query, $column); + } + + return $this; + } /** * Add the "has" condition where clause to the query. From 39addfb6e20ad216b73a0d11273c3c606987d18d Mon Sep 17 00:00:00 2001 From: mohammad sharif ahrari Date: Wed, 22 Aug 2018 10:49:58 +0430 Subject: [PATCH 02/17] Update Relation.php --- .../Database/Eloquent/Relations/Relation.php | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/Relation.php b/src/Illuminate/Database/Eloquent/Relations/Relation.php index ae6ddbf4a5b2..ecdb53633620 100755 --- a/src/Illuminate/Database/Eloquent/Relations/Relation.php +++ b/src/Illuminate/Database/Eloquent/Relations/Relation.php @@ -194,7 +194,20 @@ public function getRelationExistenceCountQuery(Builder $query, Builder $parentQu $query, $parentQuery, new Expression('count(*)') )->setBindings([], 'select'); } - + /** + * Add the constraints for a relationship sum query. + * + * @param \Illuminate\Database\Eloquent\Builder $query + * @param \Illuminate\Database\Eloquent\Builder $parentQuery + * @param string $column for sum + * @return \Illuminate\Database\Eloquent\Builder + */ + public function getRelationExistenceSumQuery(Builder $query, Builder $parentQuery,$column) + { + return $this->getRelationExistenceQuery( + $query, $parentQuery, new Expression("sum(`{$column}`)") + )->setBindings([], 'select'); + } /** * Add the constraints for an internal relationship existence query. * From d28a4debfdf75cf9e8365707b688f9ae12a938f7 Mon Sep 17 00:00:00 2001 From: mohammad sharif ahrari Date: Wed, 22 Aug 2018 11:33:41 +0430 Subject: [PATCH 03/17] Update Relation.php --- src/Illuminate/Database/Eloquent/Relations/Relation.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/Relation.php b/src/Illuminate/Database/Eloquent/Relations/Relation.php index ecdb53633620..2cdbd8b5286e 100755 --- a/src/Illuminate/Database/Eloquent/Relations/Relation.php +++ b/src/Illuminate/Database/Eloquent/Relations/Relation.php @@ -202,7 +202,7 @@ public function getRelationExistenceCountQuery(Builder $query, Builder $parentQu * @param string $column for sum * @return \Illuminate\Database\Eloquent\Builder */ - public function getRelationExistenceSumQuery(Builder $query, Builder $parentQuery,$column) + public function getRelationExistenceSumQuery(Builder $query, Builder $parentQuery, $column) { return $this->getRelationExistenceQuery( $query, $parentQuery, new Expression("sum(`{$column}`)") From 8788ba8607d45b837dca4c9304bbbde54bb81c42 Mon Sep 17 00:00:00 2001 From: mohammad sharif ahrari Date: Wed, 22 Aug 2018 11:34:50 +0430 Subject: [PATCH 04/17] Update QueriesRelationships.php --- .../Database/Eloquent/Concerns/QueriesRelationships.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php b/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php index 8b551c03dd3e..531b661e60d0 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php +++ b/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php @@ -232,7 +232,7 @@ public function withCount($relations) * @param mixed $relations * @return $this */ - public function withSum($relations,$column) + public function withSum($relations, $column) { if (empty($relations)) { return $this; @@ -262,7 +262,7 @@ public function withSum($relations,$column) // as a sub-select. First, we'll get the "has" query and use that to get the relation // count query. We will normalize the relation name then append _count as the name. $query = $relation->getRelationExistenceSumQuery( - $relation->getRelated()->newQuery(), $this,$column + $relation->getRelated()->newQuery(), $this, $column ); $query->callScope($constraints); From c9f95ea861db875b964099789dbada659f7042c5 Mon Sep 17 00:00:00 2001 From: msharif ahrari Date: Wed, 22 Aug 2018 15:52:51 +0430 Subject: [PATCH 05/17] add tests add Tests for withSum --- .../Database/DatabaseEloquentBuilderTest.php | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/tests/Database/DatabaseEloquentBuilderTest.php b/tests/Database/DatabaseEloquentBuilderTest.php index d5d0c34f9606..2de790695e9a 100755 --- a/tests/Database/DatabaseEloquentBuilderTest.php +++ b/tests/Database/DatabaseEloquentBuilderTest.php @@ -768,6 +768,43 @@ public function testHasWithConstraintsAndHavingInSubqueryWithCount() $this->assertEquals(['baz', 'qux', 'quuux'], $builder->getBindings()); } + public function testWithSum() + { + $model = new EloquentBuilderTestModelParentStub; + + $builder = $model->withSum('foo','foo_id'); + + $this->assertEquals('select `eloquent_builder_test_model_parent_stubs`.*, (select sum(`foo_id`) from `eloquent_builder_test_model_close_related_stubs` where `eloquent_builder_test_model_parent_stubs`.`foo_id` = `eloquent_builder_test_model_close_related_stubs`.`id`) as `foo_sum` from `eloquent_builder_test_model_parent_stubs`', $builder->toSql()); + } + + public function testWithSumAndSelect() + { + $model = new EloquentBuilderTestModelParentStub; + + $builder = $model->select('id')->withSum('foo','foo_id'); + + $this->assertEquals('select `id`, (select sum(`foo_id`) from `eloquent_builder_test_model_close_related_stubs` where `eloquent_builder_test_model_parent_stubs`.`foo_id` = `eloquent_builder_test_model_close_related_stubs`.`id`) as `foo_sum` from `eloquent_builder_test_model_parent_stubs`', $builder->toSql()); + } + + public function testWithSumAndMergedWheres() + { + $model = new EloquentBuilderTestModelParentStub; + + $builder = $model->select('id')->withSum(['activeFoo' => function ($q) { + $q->where('bam', '>', 'qux'); + }],'foo_id'); + + $this->assertEquals('select `id`, (select sum(`foo_id`) from `eloquent_builder_test_model_close_related_stubs` where `eloquent_builder_test_model_parent_stubs`.`foo_id` = `eloquent_builder_test_model_close_related_stubs`.`id` and `bam` > ? and `active` = ?) as `active_foo_sum` from `eloquent_builder_test_model_parent_stubs`', $builder->toSql()); + $this->assertEquals(['qux', true], $builder->getBindings()); + } + public function testWithSumAndRename() + { + $model = new EloquentBuilderTestModelParentStub; + + $builder = $model->withSum('foo as foo_bar','foo_id'); + + $this->assertEquals('select `eloquent_builder_test_model_parent_stubs`.*, (select sum(`foo_id`) from `eloquent_builder_test_model_close_related_stubs` where `eloquent_builder_test_model_parent_stubs`.`foo_id` = `eloquent_builder_test_model_close_related_stubs`.`id`) as `foo_bar` from `eloquent_builder_test_model_parent_stubs`', $builder->toSql()); + } public function testHasNestedWithConstraints() { $model = new EloquentBuilderTestModelParentStub; From 37227f2707ca77c2af07ff86ae13bb37bc9ede6e Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Wed, 22 Aug 2018 13:11:42 +0100 Subject: [PATCH 06/17] Fixed phpdoc --- src/Illuminate/Database/Eloquent/Relations/Relation.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/Relation.php b/src/Illuminate/Database/Eloquent/Relations/Relation.php index 2cdbd8b5286e..68993451a16d 100755 --- a/src/Illuminate/Database/Eloquent/Relations/Relation.php +++ b/src/Illuminate/Database/Eloquent/Relations/Relation.php @@ -199,7 +199,7 @@ public function getRelationExistenceCountQuery(Builder $query, Builder $parentQu * * @param \Illuminate\Database\Eloquent\Builder $query * @param \Illuminate\Database\Eloquent\Builder $parentQuery - * @param string $column for sum + * @param string $column * @return \Illuminate\Database\Eloquent\Builder */ public function getRelationExistenceSumQuery(Builder $query, Builder $parentQuery, $column) @@ -215,7 +215,7 @@ public function getRelationExistenceSumQuery(Builder $query, Builder $parentQuer * * @param \Illuminate\Database\Eloquent\Builder $query * @param \Illuminate\Database\Eloquent\Builder $parentQuery - * @param array|mixed $columns + * @param array|mixed $columns * @return \Illuminate\Database\Eloquent\Builder */ public function getRelationExistenceQuery(Builder $query, Builder $parentQuery, $columns = ['*']) From 842884d126fa5a64291bb4eea598335c1b54e140 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Wed, 22 Aug 2018 13:12:29 +0100 Subject: [PATCH 07/17] Fixed phpdoc --- .../Database/Eloquent/Concerns/QueriesRelationships.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php b/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php index 531b661e60d0..d7a49a3d138a 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php +++ b/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php @@ -230,6 +230,7 @@ public function withCount($relations) * Add subselect queries to sum the relations. * * @param mixed $relations + * @param string $column * @return $this */ public function withSum($relations, $column) From a371c332d7fe44ed1a80ede74480f1314feefcfb Mon Sep 17 00:00:00 2001 From: msharif ahrari Date: Fri, 24 Aug 2018 12:02:07 +0430 Subject: [PATCH 08/17] add witheAggregate I change some methods and add withSum withCount withMin withMax withAvg that use witheAggregate that support all aggregate i add somet migrations and seed in test/migration and test against real database (i'm not sure its right way but i dont have better idea) hope its working . --- .../Concerns/QueriesRelationships.php | 103 +++++++++--------- .../Database/Eloquent/Relations/Relation.php | 5 +- .../DatabaseEloquentWithAggregateTest.php | 98 +++++++++++++++++ .../2018_08_24_051542_create_orders_table.php | 32 ++++++ ..._24_051645_create_product_orders_table.php | 34 ++++++ .../seeds/OrdersAndProductsSeed.php | 27 +++++ 6 files changed, 245 insertions(+), 54 deletions(-) create mode 100644 tests/Database/DatabaseEloquentWithAggregateTest.php create mode 100644 tests/Database/migrations/aggregates/migrations/2018_08_24_051542_create_orders_table.php create mode 100644 tests/Database/migrations/aggregates/migrations/2018_08_24_051645_create_product_orders_table.php create mode 100644 tests/Database/migrations/aggregates/seeds/OrdersAndProductsSeed.php diff --git a/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php b/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php index d7a49a3d138a..b61940569d36 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php +++ b/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php @@ -177,63 +177,62 @@ public function orWhereDoesntHave($relation, Closure $callback = null) */ public function withCount($relations) { - if (empty($relations)) { - return $this; - } - - if (is_null($this->query->columns)) { - $this->query->select([$this->query->from.'.*']); - } - - $relations = is_array($relations) ? $relations : func_get_args(); - - foreach ($this->parseWithRelations($relations) as $name => $constraints) { - // First we will determine if the name has been aliased using an "as" clause on the name - // and if it has we will extract the actual relationship name and the desired name of - // the resulting column. This allows multiple counts on the same relationship name. - $segments = explode(' ', $name); - - unset($alias); - - if (count($segments) == 3 && Str::lower($segments[1]) == 'as') { - list($name, $alias) = [$segments[0], $segments[2]]; - } - - $relation = $this->getRelationWithoutConstraints($name); - - // Here we will get the relationship count query and prepare to add it to the main query - // as a sub-select. First, we'll get the "has" query and use that to get the relation - // count query. We will normalize the relation name then append _count as the name. - $query = $relation->getRelationExistenceCountQuery( - $relation->getRelated()->newQuery(), $this - ); - - $query->callScope($constraints); - - $query = $query->mergeConstraintsFrom($relation->getQuery())->toBase(); - - if (count($query->columns) > 1) { - $query->columns = [$query->columns[0]]; - } - - // Finally we will add the proper result column alias to the query and run the subselect - // statement against the query builder. Then we will return the builder instance back - // to the developer for further constraint chaining that needs to take place on it. - $column = $alias ?? Str::snake($name.'_count'); - - $this->selectSub($query, $column); - } - - return $this; + return $this->witheAggregate($relations,'count','*'); } /** * Add subselect queries to sum the relations. * * @param mixed $relations - * @param string $column + * @param string $column * @return $this */ public function withSum($relations, $column) + { + return $this->witheAggregate($relations,'sum',$column); + } + /** + * Add subselect queries to avg the relations. + * + * @param mixed $relations + * @param string $column + * @return $this + */ + public function withAvg($relations,$column) + { + return $this->witheAggregate($relations,'avg',$column); + } + + /** + * Add subselect queries to max the relations. + * + * @param mixed $relations + * @param string $column + * @return $this + */ + public function withMax($relations,$column) + { + return $this->witheAggregate($relations,'max',$column); + } + /** + * Add subselect queries to min the relations. + * + * @param mixed $relations + * @param string $column + * @return $this + */ + public function withMin($relations,$column) + { + return $this->witheAggregate($relations,'min',$column); + } + /** + * Add subselect queries to aggregate the relations. + * + * @param mixed $relations + * @param string $aggregate + * @param string $column + * @return $this + */ + public function witheAggregate($relations, $aggregate, $column) { if (empty($relations)) { return $this; @@ -262,8 +261,8 @@ public function withSum($relations, $column) // Here we will get the relationship count query and prepare to add it to the main query // as a sub-select. First, we'll get the "has" query and use that to get the relation // count query. We will normalize the relation name then append _count as the name. - $query = $relation->getRelationExistenceSumQuery( - $relation->getRelated()->newQuery(), $this, $column + $query = $relation->getRelationExistenceAggregatesQuery( + $relation->getRelated()->newQuery(), $this, $aggregate, $column ); $query->callScope($constraints); @@ -277,7 +276,7 @@ public function withSum($relations, $column) // Finally we will add the proper result column alias to the query and run the subselect // statement against the query builder. Then we will return the builder instance back // to the developer for further constraint chaining that needs to take place on it. - $column = $alias ?? Str::snake($name.'_sum'); + $column = $alias ?? Str::snake($name.'_'.strtolower($aggregate)); $this->selectSub($query, $column); } diff --git a/src/Illuminate/Database/Eloquent/Relations/Relation.php b/src/Illuminate/Database/Eloquent/Relations/Relation.php index 68993451a16d..b86a580b557a 100755 --- a/src/Illuminate/Database/Eloquent/Relations/Relation.php +++ b/src/Illuminate/Database/Eloquent/Relations/Relation.php @@ -199,13 +199,14 @@ public function getRelationExistenceCountQuery(Builder $query, Builder $parentQu * * @param \Illuminate\Database\Eloquent\Builder $query * @param \Illuminate\Database\Eloquent\Builder $parentQuery + * @param string $aggregate * @param string $column * @return \Illuminate\Database\Eloquent\Builder */ - public function getRelationExistenceSumQuery(Builder $query, Builder $parentQuery, $column) + public function getRelationExistenceAggregatesQuery(Builder $query, Builder $parentQuery, $aggregate, $column) { return $this->getRelationExistenceQuery( - $query, $parentQuery, new Expression("sum(`{$column}`)") + $query, $parentQuery, new Expression($aggregate."({$column})") )->setBindings([], 'select'); } /** diff --git a/tests/Database/DatabaseEloquentWithAggregateTest.php b/tests/Database/DatabaseEloquentWithAggregateTest.php new file mode 100644 index 000000000000..f8bd4dd4dacd --- /dev/null +++ b/tests/Database/DatabaseEloquentWithAggregateTest.php @@ -0,0 +1,98 @@ +artisan('migrate'); + $this->artisan('db:seed'); + } + + public function testWithCount() + { + $actual = Orders::witheAggregate('products','count','*')->first(); + $expected = DB::select(DB::raw('select (select count(*) from "product_orders" where "orders"."id" = "product_orders"."order_id") as "products_count" from "orders"'))[0]; + $this->assertEquals($expected->products_count, $actual->products_count); + } + + public function testWithSum() + { + $actual = Orders::withSum('products','qty')->first(); + $expected = DB::select(DB::raw('select (select sum(qty) from "product_orders" where "orders"."id" = "product_orders"."order_id") as "products_sum" from "orders"'))[0]; // sum of qty products in order + $this->assertEquals($expected->products_sum, $actual->products_sum); + } + + public function testWithAvg() + { + $actual = Orders::withAvg('products','price')->first(); + $expected = DB::select(DB::raw('select (select avg(price) from "product_orders" where "orders"."id" = "product_orders"."order_id") as "products_avg" from "orders"'))[0]; // sum of qty products in order + $this->assertEquals($expected->products_avg, $actual->products_avg); + } + + public function testWithMinAndAlias() + { + $actual = Orders::withMin('products as min_price','price')->first(); + $expected = DB::select(DB::raw('select (select min(price) from "product_orders" where "orders"."id" = "product_orders"."order_id") as "min_price" from "orders"'))[0]; // sum of qty products in order + $this->assertEquals($expected->min_price, $actual->min_price); + } + + public function testWithMaxWithAliasWithWhere() + { + $actual = Orders::withMax(['products as higher_price'=>function($query){ + $query->where('qty','>',1); + }],'price')->first(); + $expected = DB::select(DB::raw('select (select max(price) from "product_orders" where "orders"."id" = "product_orders"."order_id" and "qty" > 1) as "higher_price" from "orders"'))[0]; + $this->assertEquals($expected->higher_price, $actual->higher_price); + } + + public function testWithSumPricesAndCountQtyWithAliases() + { + $actual = Orders::withSum('products as order_price','price')->withSum('products as order_products_count','qty')->withCount('products')->first(); + $expected = DB::select(DB::raw('select (select sum(price) from "product_orders" where "orders"."id" = "product_orders"."order_id") as "order_price", (select sum(qty) from "product_orders" where "orders"."id" = "product_orders"."order_id") as "order_products_count", (select count(*) from "product_orders" where "orders"."id" = "product_orders"."order_id") as "products_count" from "orders"'))[0]; + $this->assertEquals($expected->order_price,$actual->order_price); + $this->assertEquals($expected->products_count,$actual->products_count); + $this->assertEquals($expected->order_products_count,$actual->order_products_count); + } + + public function tearDown() + { + $this->artisan('migrate:reset'); + parent::tearDown(); + + } + +} + +class Orders extends Model +{ + + protected $fillable = [ + 'reference' + ]; + + public function products() + { + return $this->hasMany(ProductOrders::class,'order_id'); + } +} + +class ProductOrders extends Model +{ + protected $table = 'product_orders'; + protected $fillable = [ + 'name','qty','price', + ]; +} \ No newline at end of file diff --git a/tests/Database/migrations/aggregates/migrations/2018_08_24_051542_create_orders_table.php b/tests/Database/migrations/aggregates/migrations/2018_08_24_051542_create_orders_table.php new file mode 100644 index 000000000000..92e20f118d53 --- /dev/null +++ b/tests/Database/migrations/aggregates/migrations/2018_08_24_051542_create_orders_table.php @@ -0,0 +1,32 @@ +increments('id'); + $table->string('reference'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('tables'); + } +} diff --git a/tests/Database/migrations/aggregates/migrations/2018_08_24_051645_create_product_orders_table.php b/tests/Database/migrations/aggregates/migrations/2018_08_24_051645_create_product_orders_table.php new file mode 100644 index 000000000000..d4e88c2b1e31 --- /dev/null +++ b/tests/Database/migrations/aggregates/migrations/2018_08_24_051645_create_product_orders_table.php @@ -0,0 +1,34 @@ +increments('id'); + $table->string('name'); + $table->integer('order_id')->unsigned(); + $table->integer('qty'); + $table->integer('price'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('tables'); + } +} diff --git a/tests/Database/migrations/aggregates/seeds/OrdersAndProductsSeed.php b/tests/Database/migrations/aggregates/seeds/OrdersAndProductsSeed.php new file mode 100644 index 000000000000..c2a3831627c3 --- /dev/null +++ b/tests/Database/migrations/aggregates/seeds/OrdersAndProductsSeed.php @@ -0,0 +1,27 @@ +insert([ + 'reference' => '12345678', + ]); + + // products in orders + DB::table('product_orders')->insert([ + ['name' =>'imac','qty'=>'1','price'=>'1500','order_id'=>1], + ['name' =>'galaxy s9','qty'=>'2','price'=>'1000','order_id'=>1], + ['name' =>'apple watch','qty'=>'3','price'=>'1200','order_id'=>1], + ]); + + } +} From c6510f4e20690f5991133e69e06c96948b2e0ad7 Mon Sep 17 00:00:00 2001 From: msharif ahrari Date: Fri, 24 Aug 2018 12:22:06 +0430 Subject: [PATCH 09/17] style fixes --- .../Concerns/QueriesRelationships.php | 18 +++++----- .../Database/Eloquent/Relations/Relation.php | 1 + .../DatabaseEloquentWithAggregateTest.php | 34 ++++++++----------- .../seeds/OrdersAndProductsSeed.php | 9 ++--- 4 files changed, 29 insertions(+), 33 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php b/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php index b61940569d36..315f5c77fd35 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php +++ b/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php @@ -177,7 +177,7 @@ public function orWhereDoesntHave($relation, Closure $callback = null) */ public function withCount($relations) { - return $this->witheAggregate($relations,'count','*'); + return $this->withAggregate($relations, 'count', '*'); } /** * Add subselect queries to sum the relations. @@ -188,7 +188,7 @@ public function withCount($relations) */ public function withSum($relations, $column) { - return $this->witheAggregate($relations,'sum',$column); + return $this->withAggregate($relations, 'sum', $column); } /** * Add subselect queries to avg the relations. @@ -197,9 +197,9 @@ public function withSum($relations, $column) * @param string $column * @return $this */ - public function withAvg($relations,$column) + public function withAvg($relations, $column) { - return $this->witheAggregate($relations,'avg',$column); + return $this->withAggregate($relations, 'avg', $column); } /** @@ -209,9 +209,9 @@ public function withAvg($relations,$column) * @param string $column * @return $this */ - public function withMax($relations,$column) + public function withMax($relations, $column) { - return $this->witheAggregate($relations,'max',$column); + return $this->withAggregate($relations, 'max', $column); } /** * Add subselect queries to min the relations. @@ -220,9 +220,9 @@ public function withMax($relations,$column) * @param string $column * @return $this */ - public function withMin($relations,$column) + public function withMin($relations, $column) { - return $this->witheAggregate($relations,'min',$column); + return $this->withAggregate($relations, 'min', $column); } /** * Add subselect queries to aggregate the relations. @@ -232,7 +232,7 @@ public function withMin($relations,$column) * @param string $column * @return $this */ - public function witheAggregate($relations, $aggregate, $column) + public function withAggregate($relations, $aggregate, $column) { if (empty($relations)) { return $this; diff --git a/src/Illuminate/Database/Eloquent/Relations/Relation.php b/src/Illuminate/Database/Eloquent/Relations/Relation.php index b86a580b557a..62e5e625e803 100755 --- a/src/Illuminate/Database/Eloquent/Relations/Relation.php +++ b/src/Illuminate/Database/Eloquent/Relations/Relation.php @@ -209,6 +209,7 @@ public function getRelationExistenceAggregatesQuery(Builder $query, Builder $par $query, $parentQuery, new Expression($aggregate."({$column})") )->setBindings([], 'select'); } + /** * Add the constraints for an internal relationship existence query. * diff --git a/tests/Database/DatabaseEloquentWithAggregateTest.php b/tests/Database/DatabaseEloquentWithAggregateTest.php index f8bd4dd4dacd..354f9915ad16 100644 --- a/tests/Database/DatabaseEloquentWithAggregateTest.php +++ b/tests/Database/DatabaseEloquentWithAggregateTest.php @@ -1,16 +1,10 @@ first(); + $actual = Orders::withAggregate('products', 'count', '*')->first(); $expected = DB::select(DB::raw('select (select count(*) from "product_orders" where "orders"."id" = "product_orders"."order_id") as "products_count" from "orders"'))[0]; $this->assertEquals($expected->products_count, $actual->products_count); } public function testWithSum() { - $actual = Orders::withSum('products','qty')->first(); + $actual = Orders::withSum('products', 'qty')->first(); $expected = DB::select(DB::raw('select (select sum(qty) from "product_orders" where "orders"."id" = "product_orders"."order_id") as "products_sum" from "orders"'))[0]; // sum of qty products in order $this->assertEquals($expected->products_sum, $actual->products_sum); } public function testWithAvg() { - $actual = Orders::withAvg('products','price')->first(); + $actual = Orders::withAvg('products', 'price')->first(); $expected = DB::select(DB::raw('select (select avg(price) from "product_orders" where "orders"."id" = "product_orders"."order_id") as "products_avg" from "orders"'))[0]; // sum of qty products in order $this->assertEquals($expected->products_avg, $actual->products_avg); } public function testWithMinAndAlias() { - $actual = Orders::withMin('products as min_price','price')->first(); + $actual = Orders::withMin('products as min_price', 'price')->first(); $expected = DB::select(DB::raw('select (select min(price) from "product_orders" where "orders"."id" = "product_orders"."order_id") as "min_price" from "orders"'))[0]; // sum of qty products in order $this->assertEquals($expected->min_price, $actual->min_price); } @@ -52,19 +46,19 @@ public function testWithMinAndAlias() public function testWithMaxWithAliasWithWhere() { $actual = Orders::withMax(['products as higher_price'=>function($query){ - $query->where('qty','>',1); - }],'price')->first(); + $query->where('qty', '>', 1); + }], 'price')->first(); $expected = DB::select(DB::raw('select (select max(price) from "product_orders" where "orders"."id" = "product_orders"."order_id" and "qty" > 1) as "higher_price" from "orders"'))[0]; $this->assertEquals($expected->higher_price, $actual->higher_price); } public function testWithSumPricesAndCountQtyWithAliases() { - $actual = Orders::withSum('products as order_price','price')->withSum('products as order_products_count','qty')->withCount('products')->first(); + $actual = Orders::withSum('products as order_price', 'price')->withSum('products as order_products_count', 'qty')->withCount('products')->first(); $expected = DB::select(DB::raw('select (select sum(price) from "product_orders" where "orders"."id" = "product_orders"."order_id") as "order_price", (select sum(qty) from "product_orders" where "orders"."id" = "product_orders"."order_id") as "order_products_count", (select count(*) from "product_orders" where "orders"."id" = "product_orders"."order_id") as "products_count" from "orders"'))[0]; - $this->assertEquals($expected->order_price,$actual->order_price); - $this->assertEquals($expected->products_count,$actual->products_count); - $this->assertEquals($expected->order_products_count,$actual->order_products_count); + $this->assertEquals($expected->order_price, $actual->order_price); + $this->assertEquals($expected->products_count, $actual->products_count); + $this->assertEquals($expected->order_products_count, $actual->order_products_count); } public function tearDown() @@ -80,12 +74,12 @@ class Orders extends Model { protected $fillable = [ - 'reference' + 'reference', ]; public function products() { - return $this->hasMany(ProductOrders::class,'order_id'); + return $this->hasMany(ProductOrders::class, 'order_id'); } } @@ -93,6 +87,6 @@ class ProductOrders extends Model { protected $table = 'product_orders'; protected $fillable = [ - 'name','qty','price', + 'name', 'qty', 'price', ]; } \ No newline at end of file diff --git a/tests/Database/migrations/aggregates/seeds/OrdersAndProductsSeed.php b/tests/Database/migrations/aggregates/seeds/OrdersAndProductsSeed.php index c2a3831627c3..7bf4337616e0 100644 --- a/tests/Database/migrations/aggregates/seeds/OrdersAndProductsSeed.php +++ b/tests/Database/migrations/aggregates/seeds/OrdersAndProductsSeed.php @@ -1,7 +1,8 @@ insert([ - ['name' =>'imac','qty'=>'1','price'=>'1500','order_id'=>1], - ['name' =>'galaxy s9','qty'=>'2','price'=>'1000','order_id'=>1], - ['name' =>'apple watch','qty'=>'3','price'=>'1200','order_id'=>1], + ['name' =>'imac', 'qty'=>'1','price'=>'1500', 'order_id'=>1], + ['name' => 'galaxy s9', 'qty'=>'2', 'price'=>'1000', 'order_id'=>1], + ['name' => 'apple watch',' qty'=>'3', 'price'=>'1200', 'order_id'=>1], ]); } From 771a6b6ece22d5bf04925ab869b2ceb37259b453 Mon Sep 17 00:00:00 2001 From: msharif ahrari Date: Fri, 24 Aug 2018 20:35:42 +0430 Subject: [PATCH 10/17] fix tests --- .../2018_08_24_051542_create_orders_table.php | 32 -------------- ..._24_051645_create_product_orders_table.php | 34 --------------- .../seeds/OrdersAndProductsSeed.php | 28 ------------- .../Database/EloquentWithAggregateTest.php} | 42 +++++++++++++------ 4 files changed, 29 insertions(+), 107 deletions(-) delete mode 100644 tests/Database/migrations/aggregates/migrations/2018_08_24_051542_create_orders_table.php delete mode 100644 tests/Database/migrations/aggregates/migrations/2018_08_24_051645_create_product_orders_table.php delete mode 100644 tests/Database/migrations/aggregates/seeds/OrdersAndProductsSeed.php rename tests/{Database/DatabaseEloquentWithAggregateTest.php => Integration/Database/EloquentWithAggregateTest.php} (77%) diff --git a/tests/Database/migrations/aggregates/migrations/2018_08_24_051542_create_orders_table.php b/tests/Database/migrations/aggregates/migrations/2018_08_24_051542_create_orders_table.php deleted file mode 100644 index 92e20f118d53..000000000000 --- a/tests/Database/migrations/aggregates/migrations/2018_08_24_051542_create_orders_table.php +++ /dev/null @@ -1,32 +0,0 @@ -increments('id'); - $table->string('reference'); - $table->timestamps(); - }); - } - - /** - * Reverse the migrations. - * - * @return void - */ - public function down() - { - Schema::dropIfExists('tables'); - } -} diff --git a/tests/Database/migrations/aggregates/migrations/2018_08_24_051645_create_product_orders_table.php b/tests/Database/migrations/aggregates/migrations/2018_08_24_051645_create_product_orders_table.php deleted file mode 100644 index d4e88c2b1e31..000000000000 --- a/tests/Database/migrations/aggregates/migrations/2018_08_24_051645_create_product_orders_table.php +++ /dev/null @@ -1,34 +0,0 @@ -increments('id'); - $table->string('name'); - $table->integer('order_id')->unsigned(); - $table->integer('qty'); - $table->integer('price'); - }); - } - - /** - * Reverse the migrations. - * - * @return void - */ - public function down() - { - Schema::dropIfExists('tables'); - } -} diff --git a/tests/Database/migrations/aggregates/seeds/OrdersAndProductsSeed.php b/tests/Database/migrations/aggregates/seeds/OrdersAndProductsSeed.php deleted file mode 100644 index 7bf4337616e0..000000000000 --- a/tests/Database/migrations/aggregates/seeds/OrdersAndProductsSeed.php +++ /dev/null @@ -1,28 +0,0 @@ -insert([ - 'reference' => '12345678', - ]); - - // products in orders - DB::table('product_orders')->insert([ - ['name' =>'imac', 'qty'=>'1','price'=>'1500', 'order_id'=>1], - ['name' => 'galaxy s9', 'qty'=>'2', 'price'=>'1000', 'order_id'=>1], - ['name' => 'apple watch',' qty'=>'3', 'price'=>'1200', 'order_id'=>1], - ]); - - } -} diff --git a/tests/Database/DatabaseEloquentWithAggregateTest.php b/tests/Integration/Database/EloquentWithAggregateTest.php similarity index 77% rename from tests/Database/DatabaseEloquentWithAggregateTest.php rename to tests/Integration/Database/EloquentWithAggregateTest.php index 354f9915ad16..15e24c3193e9 100644 --- a/tests/Database/DatabaseEloquentWithAggregateTest.php +++ b/tests/Integration/Database/EloquentWithAggregateTest.php @@ -1,18 +1,42 @@ artisan('migrate'); - $this->artisan('db:seed'); + + Schema::create('orders', function ($table) { + $table->increments('id'); + $table->string('reference'); + $table->timestamps(); + }); + + Schema::create('product_orders', function ($table) { + $table->increments('id'); + $table->string('name'); + $table->integer('order_id')->unsigned(); + $table->integer('qty'); + $table->integer('price'); + }); + + DB::table('orders')->insert([ + 'reference' => '12345678', + ]); + + // products in orders + DB::table('product_orders')->insert([ + ['name' =>'imac','qty'=>'1','price'=>'1500','order_id'=>1], + ['name' =>'galaxy s9','qty'=>'2','price'=>'1000','order_id'=>1], + ['name' =>'apple watch','qty'=>'3','price'=>'1200','order_id'=>1], + ]); } public function testWithCount() @@ -60,14 +84,6 @@ public function testWithSumPricesAndCountQtyWithAliases() $this->assertEquals($expected->products_count, $actual->products_count); $this->assertEquals($expected->order_products_count, $actual->order_products_count); } - - public function tearDown() - { - $this->artisan('migrate:reset'); - parent::tearDown(); - - } - } class Orders extends Model From 228c64bec0e5a3d17bdf0ea0adb5b42b881082cd Mon Sep 17 00:00:00 2001 From: msharif ahrari Date: Fri, 24 Aug 2018 20:41:00 +0430 Subject: [PATCH 11/17] fix tests --- .../Database/DatabaseEloquentBuilderTest.php | 37 ------------------- 1 file changed, 37 deletions(-) diff --git a/tests/Database/DatabaseEloquentBuilderTest.php b/tests/Database/DatabaseEloquentBuilderTest.php index 2de790695e9a..d5d0c34f9606 100755 --- a/tests/Database/DatabaseEloquentBuilderTest.php +++ b/tests/Database/DatabaseEloquentBuilderTest.php @@ -768,43 +768,6 @@ public function testHasWithConstraintsAndHavingInSubqueryWithCount() $this->assertEquals(['baz', 'qux', 'quuux'], $builder->getBindings()); } - public function testWithSum() - { - $model = new EloquentBuilderTestModelParentStub; - - $builder = $model->withSum('foo','foo_id'); - - $this->assertEquals('select `eloquent_builder_test_model_parent_stubs`.*, (select sum(`foo_id`) from `eloquent_builder_test_model_close_related_stubs` where `eloquent_builder_test_model_parent_stubs`.`foo_id` = `eloquent_builder_test_model_close_related_stubs`.`id`) as `foo_sum` from `eloquent_builder_test_model_parent_stubs`', $builder->toSql()); - } - - public function testWithSumAndSelect() - { - $model = new EloquentBuilderTestModelParentStub; - - $builder = $model->select('id')->withSum('foo','foo_id'); - - $this->assertEquals('select `id`, (select sum(`foo_id`) from `eloquent_builder_test_model_close_related_stubs` where `eloquent_builder_test_model_parent_stubs`.`foo_id` = `eloquent_builder_test_model_close_related_stubs`.`id`) as `foo_sum` from `eloquent_builder_test_model_parent_stubs`', $builder->toSql()); - } - - public function testWithSumAndMergedWheres() - { - $model = new EloquentBuilderTestModelParentStub; - - $builder = $model->select('id')->withSum(['activeFoo' => function ($q) { - $q->where('bam', '>', 'qux'); - }],'foo_id'); - - $this->assertEquals('select `id`, (select sum(`foo_id`) from `eloquent_builder_test_model_close_related_stubs` where `eloquent_builder_test_model_parent_stubs`.`foo_id` = `eloquent_builder_test_model_close_related_stubs`.`id` and `bam` > ? and `active` = ?) as `active_foo_sum` from `eloquent_builder_test_model_parent_stubs`', $builder->toSql()); - $this->assertEquals(['qux', true], $builder->getBindings()); - } - public function testWithSumAndRename() - { - $model = new EloquentBuilderTestModelParentStub; - - $builder = $model->withSum('foo as foo_bar','foo_id'); - - $this->assertEquals('select `eloquent_builder_test_model_parent_stubs`.*, (select sum(`foo_id`) from `eloquent_builder_test_model_close_related_stubs` where `eloquent_builder_test_model_parent_stubs`.`foo_id` = `eloquent_builder_test_model_close_related_stubs`.`id`) as `foo_bar` from `eloquent_builder_test_model_parent_stubs`', $builder->toSql()); - } public function testHasNestedWithConstraints() { $model = new EloquentBuilderTestModelParentStub; From 9bc97e5e63a58d25893a33889db20b72fe6b96bd Mon Sep 17 00:00:00 2001 From: msharif ahrari Date: Fri, 24 Aug 2018 23:57:50 +0430 Subject: [PATCH 12/17] fix bug and tests --- .../Concerns/QueriesRelationships.php | 8 +++++-- .../Database/Eloquent/Relations/Relation.php | 13 ----------- .../Database/EloquentWithAggregateTest.php | 23 +++++++++---------- 3 files changed, 17 insertions(+), 27 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php b/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php index 315f5c77fd35..1d2d5e9fcfc2 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php +++ b/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php @@ -179,6 +179,7 @@ public function withCount($relations) { return $this->withAggregate($relations, 'count', '*'); } + /** * Add subselect queries to sum the relations. * @@ -190,6 +191,7 @@ public function withSum($relations, $column) { return $this->withAggregate($relations, 'sum', $column); } + /** * Add subselect queries to avg the relations. * @@ -213,6 +215,7 @@ public function withMax($relations, $column) { return $this->withAggregate($relations, 'max', $column); } + /** * Add subselect queries to min the relations. * @@ -224,6 +227,7 @@ public function withMin($relations, $column) { return $this->withAggregate($relations, 'min', $column); } + /** * Add subselect queries to aggregate the relations. * @@ -276,9 +280,9 @@ public function withAggregate($relations, $aggregate, $column) // Finally we will add the proper result column alias to the query and run the subselect // statement against the query builder. Then we will return the builder instance back // to the developer for further constraint chaining that needs to take place on it. - $column = $alias ?? Str::snake($name.'_'.strtolower($aggregate)); + $column_alias = $alias ?? Str::snake($name.'_'.strtolower($aggregate)); - $this->selectSub($query, $column); + $this->selectSub($query, $column_alias); } return $this; diff --git a/src/Illuminate/Database/Eloquent/Relations/Relation.php b/src/Illuminate/Database/Eloquent/Relations/Relation.php index 62e5e625e803..43bda3a8b91b 100755 --- a/src/Illuminate/Database/Eloquent/Relations/Relation.php +++ b/src/Illuminate/Database/Eloquent/Relations/Relation.php @@ -181,19 +181,6 @@ public function rawUpdate(array $attributes = []) return $this->query->withoutGlobalScopes()->update($attributes); } - /** - * Add the constraints for a relationship count query. - * - * @param \Illuminate\Database\Eloquent\Builder $query - * @param \Illuminate\Database\Eloquent\Builder $parentQuery - * @return \Illuminate\Database\Eloquent\Builder - */ - public function getRelationExistenceCountQuery(Builder $query, Builder $parentQuery) - { - return $this->getRelationExistenceQuery( - $query, $parentQuery, new Expression('count(*)') - )->setBindings([], 'select'); - } /** * Add the constraints for a relationship sum query. * diff --git a/tests/Integration/Database/EloquentWithAggregateTest.php b/tests/Integration/Database/EloquentWithAggregateTest.php index 15e24c3193e9..72f03690e9de 100644 --- a/tests/Integration/Database/EloquentWithAggregateTest.php +++ b/tests/Integration/Database/EloquentWithAggregateTest.php @@ -2,10 +2,9 @@ namespace Illuminate\Tests\Integration\Database; -use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Schema; - +use Illuminate\Database\Eloquent\Model; class EloquentWithAggregateTest extends DatabaseTestCase { @@ -33,43 +32,43 @@ public function setUp() // products in orders DB::table('product_orders')->insert([ - ['name' =>'imac','qty'=>'1','price'=>'1500','order_id'=>1], - ['name' =>'galaxy s9','qty'=>'2','price'=>'1000','order_id'=>1], - ['name' =>'apple watch','qty'=>'3','price'=>'1200','order_id'=>1], + ['name' =>'imac', 'qty'=>'1', 'price'=>'1500', 'order_id'=>1], + ['name' =>'galaxy s9', 'qty'=>'2', 'price'=>'1000', 'order_id'=>1], + ['name' =>'apple watch', 'qty'=>'3', 'price'=>'1200', 'order_id'=>1], ]); } public function testWithCount() { - $actual = Orders::withAggregate('products', 'count', '*')->first(); + $actual = Orders::withAggregate('products', 'count', '*')->first(); $expected = DB::select(DB::raw('select (select count(*) from "product_orders" where "orders"."id" = "product_orders"."order_id") as "products_count" from "orders"'))[0]; $this->assertEquals($expected->products_count, $actual->products_count); } public function testWithSum() { - $actual = Orders::withSum('products', 'qty')->first(); + $actual = Orders::withSum('products', 'qty')->first(); $expected = DB::select(DB::raw('select (select sum(qty) from "product_orders" where "orders"."id" = "product_orders"."order_id") as "products_sum" from "orders"'))[0]; // sum of qty products in order $this->assertEquals($expected->products_sum, $actual->products_sum); } public function testWithAvg() { - $actual = Orders::withAvg('products', 'price')->first(); + $actual = Orders::withAvg('products', 'price')->first(); $expected = DB::select(DB::raw('select (select avg(price) from "product_orders" where "orders"."id" = "product_orders"."order_id") as "products_avg" from "orders"'))[0]; // sum of qty products in order $this->assertEquals($expected->products_avg, $actual->products_avg); } public function testWithMinAndAlias() { - $actual = Orders::withMin('products as min_price', 'price')->first(); + $actual = Orders::withMin('products as min_price', 'price')->first(); $expected = DB::select(DB::raw('select (select min(price) from "product_orders" where "orders"."id" = "product_orders"."order_id") as "min_price" from "orders"'))[0]; // sum of qty products in order $this->assertEquals($expected->min_price, $actual->min_price); } public function testWithMaxWithAliasWithWhere() { - $actual = Orders::withMax(['products as higher_price'=>function($query){ + $actual = Orders::withMax(['products as higher_price'=>function($query){ $query->where('qty', '>', 1); }], 'price')->first(); $expected = DB::select(DB::raw('select (select max(price) from "product_orders" where "orders"."id" = "product_orders"."order_id" and "qty" > 1) as "higher_price" from "orders"'))[0]; @@ -78,7 +77,7 @@ public function testWithMaxWithAliasWithWhere() public function testWithSumPricesAndCountQtyWithAliases() { - $actual = Orders::withSum('products as order_price', 'price')->withSum('products as order_products_count', 'qty')->withCount('products')->first(); + $actual = Orders::withSum('products as order_price', 'price')->withSum('products as order_products_count', 'qty')->withCount('products')->first(); $expected = DB::select(DB::raw('select (select sum(price) from "product_orders" where "orders"."id" = "product_orders"."order_id") as "order_price", (select sum(qty) from "product_orders" where "orders"."id" = "product_orders"."order_id") as "order_products_count", (select count(*) from "product_orders" where "orders"."id" = "product_orders"."order_id") as "products_count" from "orders"'))[0]; $this->assertEquals($expected->order_price, $actual->order_price); $this->assertEquals($expected->products_count, $actual->products_count); @@ -88,7 +87,6 @@ public function testWithSumPricesAndCountQtyWithAliases() class Orders extends Model { - protected $fillable = [ 'reference', ]; @@ -97,6 +95,7 @@ public function products() { return $this->hasMany(ProductOrders::class, 'order_id'); } + } class ProductOrders extends Model From 407904a87991a68fef551f954896a48399506a4f Mon Sep 17 00:00:00 2001 From: msharif ahrari Date: Sat, 25 Aug 2018 00:03:35 +0430 Subject: [PATCH 13/17] fix tests --- .../Database/Eloquent/Relations/Relation.php | 14 ++++++++++++++ .../Database/EloquentWithAggregateTest.php | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/Relation.php b/src/Illuminate/Database/Eloquent/Relations/Relation.php index 43bda3a8b91b..d777f72f638b 100755 --- a/src/Illuminate/Database/Eloquent/Relations/Relation.php +++ b/src/Illuminate/Database/Eloquent/Relations/Relation.php @@ -181,6 +181,20 @@ public function rawUpdate(array $attributes = []) return $this->query->withoutGlobalScopes()->update($attributes); } + /** + * Add the constraints for a relationship count query. + * + * @param \Illuminate\Database\Eloquent\Builder $query + * @param \Illuminate\Database\Eloquent\Builder $parentQuery + * @return \Illuminate\Database\Eloquent\Builder + */ + public function getRelationExistenceCountQuery(Builder $query, Builder $parentQuery) + { + return $this->getRelationExistenceQuery( + $query, $parentQuery, new Expression('count(*)') + )->setBindings([], 'select'); + } + /** * Add the constraints for a relationship sum query. * diff --git a/tests/Integration/Database/EloquentWithAggregateTest.php b/tests/Integration/Database/EloquentWithAggregateTest.php index 72f03690e9de..6732b4378529 100644 --- a/tests/Integration/Database/EloquentWithAggregateTest.php +++ b/tests/Integration/Database/EloquentWithAggregateTest.php @@ -95,7 +95,7 @@ public function products() { return $this->hasMany(ProductOrders::class, 'order_id'); } - + } class ProductOrders extends Model From 5b0eb86ae7f5410c4aff2a275acbd3339170d6ce Mon Sep 17 00:00:00 2001 From: msharif ahrari Date: Sat, 25 Aug 2018 00:06:35 +0430 Subject: [PATCH 14/17] fix styles --- tests/Integration/Database/EloquentWithAggregateTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Integration/Database/EloquentWithAggregateTest.php b/tests/Integration/Database/EloquentWithAggregateTest.php index 6732b4378529..5509e6c6d518 100644 --- a/tests/Integration/Database/EloquentWithAggregateTest.php +++ b/tests/Integration/Database/EloquentWithAggregateTest.php @@ -68,7 +68,7 @@ public function testWithMinAndAlias() public function testWithMaxWithAliasWithWhere() { - $actual = Orders::withMax(['products as higher_price'=>function($query){ + $actual = Orders::withMax(['products as higher_price'=>function($query) { $query->where('qty', '>', 1); }], 'price')->first(); $expected = DB::select(DB::raw('select (select max(price) from "product_orders" where "orders"."id" = "product_orders"."order_id" and "qty" > 1) as "higher_price" from "orders"'))[0]; @@ -95,7 +95,6 @@ public function products() { return $this->hasMany(ProductOrders::class, 'order_id'); } - } class ProductOrders extends Model @@ -104,4 +103,5 @@ class ProductOrders extends Model protected $fillable = [ 'name', 'qty', 'price', ]; + } \ No newline at end of file From 4df89327a99f714909b6eecb063b73660522ecbe Mon Sep 17 00:00:00 2001 From: msharif ahrari Date: Sat, 25 Aug 2018 00:07:51 +0430 Subject: [PATCH 15/17] fix styles --- tests/Integration/Database/EloquentWithAggregateTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Integration/Database/EloquentWithAggregateTest.php b/tests/Integration/Database/EloquentWithAggregateTest.php index 5509e6c6d518..48e4a01d8f47 100644 --- a/tests/Integration/Database/EloquentWithAggregateTest.php +++ b/tests/Integration/Database/EloquentWithAggregateTest.php @@ -68,7 +68,7 @@ public function testWithMinAndAlias() public function testWithMaxWithAliasWithWhere() { - $actual = Orders::withMax(['products as higher_price'=>function($query) { + $actual = Orders::withMax(['products as higher_price'=>function ($query) { $query->where('qty', '>', 1); }], 'price')->first(); $expected = DB::select(DB::raw('select (select max(price) from "product_orders" where "orders"."id" = "product_orders"."order_id" and "qty" > 1) as "higher_price" from "orders"'))[0]; From 3204bc6a920c4f085b449b8a18fe506353cd7b7f Mon Sep 17 00:00:00 2001 From: mohammad sharif ahrari Date: Sat, 25 Aug 2018 00:10:58 +0430 Subject: [PATCH 16/17] fix styles --- tests/Integration/Database/EloquentWithAggregateTest.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/Integration/Database/EloquentWithAggregateTest.php b/tests/Integration/Database/EloquentWithAggregateTest.php index 48e4a01d8f47..40f94f7dd551 100644 --- a/tests/Integration/Database/EloquentWithAggregateTest.php +++ b/tests/Integration/Database/EloquentWithAggregateTest.php @@ -103,5 +103,4 @@ class ProductOrders extends Model protected $fillable = [ 'name', 'qty', 'price', ]; - -} \ No newline at end of file +} From ccd7ed88d8d05874d0665eea340451aa3ef33caf Mon Sep 17 00:00:00 2001 From: msharif ahrari Date: Sat, 25 Aug 2018 00:27:28 +0430 Subject: [PATCH 17/17] fix withCount method to prevent breaking changes --- .../Database/Eloquent/Concerns/QueriesRelationships.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php b/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php index 1d2d5e9fcfc2..6d261d6f4259 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php +++ b/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php @@ -177,6 +177,8 @@ public function orWhereDoesntHave($relation, Closure $callback = null) */ public function withCount($relations) { + $relations = is_array($relations) ? $relations : func_get_args(); + return $this->withAggregate($relations, 'count', '*'); }