| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -655,7 +655,7 @@ public function orWhere($column, $operator = null, $value = null) | |||
| 655 | 655 | } | |
| 656 | 656 | ||
| 657 | 657 | /** | |
| 658 | - * Add a relationship count condition to the query. | ||
| 658 | + * Add a relationship count/exists condition to the query. | ||
| 659 | 659 | * | |
| 660 | 660 | * @param string $relation | |
| 661 | 661 | * @param string $operator | |
@@ -672,7 +672,12 @@ public function has($relation, $operator = '>=', $count = 1, $boolean = 'and', C | |||
| 672 | 672 | ||
| 673 | 673 | $relation = $this->getHasRelationQuery($relation); | |
| 674 | 674 | ||
| 675 | - $query = $relation->getRelationCountQuery($relation->getRelated()->newQuery(), $this); | ||
| 675 | + // If we only need to check for the existence of the relation, then we can | ||
| 676 | + // optimize the subquery to only run a "where exists" clause instead of | ||
| 677 | + // the full "count" clause. This will make the query run much faster. | ||
| 678 | + $queryType = $this->shouldRunExistsQuery($operator, $count) ? 'getRelationQuery' : 'getRelationCountQuery'; | ||
| 679 | + | ||
| 680 | + $query = $relation->$queryType($relation->getRelated()->newQuery(), $this); | ||
| 676 | 681 | ||
| 677 | 682 | if ($callback) { | |
| 678 | 683 | call_user_func($callback, $query); | |
@@ -684,7 +689,7 @@ public function has($relation, $operator = '>=', $count = 1, $boolean = 'and', C | |||
| 684 | 689 | } | |
| 685 | 690 | ||
| 686 | 691 | /** | |
| 687 | - * Add nested relationship count conditions to the query. | ||
| 692 | + * Add nested relationship count/exists conditions to the query. | ||
| 688 | 693 | * | |
| 689 | 694 | * @param string $relations | |
| 690 | 695 | * @param string $operator | |
@@ -712,7 +717,7 @@ protected function hasNested($relations, $operator = '>=', $count = 1, $boolean | |||
| 712 | 717 | } | |
| 713 | 718 | ||
| 714 | 719 | /** | |
| 715 | - * Add a relationship count condition to the query. | ||
| 720 | + * Add a relationship count/exists condition to the query. | ||
| 716 | 721 | * | |
| 717 | 722 | * @param string $relation | |
| 718 | 723 | * @param string $boolean | |
@@ -725,7 +730,7 @@ public function doesntHave($relation, $boolean = 'and', Closure $callback = null | |||
| 725 | 730 | } | |
| 726 | 731 | ||
| 727 | 732 | /** | |
| 728 | - * Add a relationship count condition to the query with where clauses. | ||
| 733 | + * Add a relationship count/exists condition to the query with where clauses. | ||
| 729 | 734 | * | |
| 730 | 735 | * @param string $relation | |
| 731 | 736 | * @param \Closure $callback | |
@@ -739,7 +744,7 @@ public function whereHas($relation, Closure $callback, $operator = '>=', $count | |||
| 739 | 744 | } | |
| 740 | 745 | ||
| 741 | 746 | /** | |
| 742 | - * Add a relationship count condition to the query with where clauses. | ||
| 747 | + * Add a relationship count/exists condition to the query with where clauses. | ||
| 743 | 748 | * | |
| 744 | 749 | * @param string $relation | |
| 745 | 750 | * @param \Closure|null $callback | |
@@ -751,7 +756,7 @@ public function whereDoesntHave($relation, Closure $callback = null) | |||
| 751 | 756 | } | |
| 752 | 757 | ||
| 753 | 758 | /** | |
| 754 | - * Add a relationship count condition to the query with an "or". | ||
| 759 | + * Add a relationship count/exists condition to the query with an "or". | ||
| 755 | 760 | * | |
| 756 | 761 | * @param string $relation | |
| 757 | 762 | * @param string $operator | |
@@ -764,7 +769,7 @@ public function orHas($relation, $operator = '>=', $count = 1) | |||
| 764 | 769 | } | |
| 765 | 770 | ||
| 766 | 771 | /** | |
| 767 | - * Add a relationship count condition to the query with where clauses and an "or". | ||
| 772 | + * Add a relationship count/exists condition to the query with where clauses and an "or". | ||
| 768 | 773 | * | |
| 769 | 774 | * @param string $relation | |
| 770 | 775 | * @param \Closure $callback | |
@@ -791,11 +796,45 @@ protected function addHasWhere(Builder $hasQuery, Relation $relation, $operator, | |||
| 791 | 796 | { | |
| 792 | 797 | $this->mergeModelDefinedRelationWheresToHasQuery($hasQuery, $relation); | |
| 793 | 798 | ||
| 799 | + if($this->shouldRunExistsQuery($operator, $count)) { | ||
| 800 | + $not = ($operator === '<' && $count === 1); | ||
| 801 | + | ||
| 802 | + return $this->whereExistsQuery($hasQuery->toBase(), $boolean, $not); | ||
| 803 | + } | ||
| 804 | + | ||
| 805 | + return $this->whereCountQuery($hasQuery->toBase(), $operator, $count, $boolean); | ||
| 806 | + } | ||
| 807 | + | ||
| 808 | + /** | ||
| 809 | + * Check if we can run an "exists" query to optimize performance. | ||
| 810 | + * | ||
| 811 | + * @param string $operator | ||
| 812 | + * @param int $count | ||
| 813 | + * @return bool | ||
| 814 | + */ | ||
| 815 | + protected function shouldRunExistsQuery($operator, $count) | ||
| 816 | + { | ||
| 817 | + return ($operator === '>=' && $count === 1) || ($operator === '<' && $count === 1); | ||
| 818 | + } | ||
| 819 | + | ||
| 820 | + /** | ||
| 821 | + * Add a sub query count clause to the query. | ||
| 822 | + * | ||
| 823 | + * @param \Illuminate\Database\Query\Builder $query | ||
| 824 | + * @param string $operator | ||
| 825 | + * @param int $count | ||
| 826 | + * @param string $boolean | ||
| 827 | + * @return $this | ||
| 828 | + */ | ||
| 829 | + protected function whereCountQuery(QueryBuilder $query, $operator = '>=', $count = 1, $boolean = 'and') | ||
| 830 | + { | ||
| 794 | 831 | if (is_numeric($count)) { | |
| 795 | 832 | $count = new Expression($count); | |
| 796 | 833 | } | |
| 797 | 834 | ||
| 798 | - return $this->where(new Expression('('.$hasQuery->toSql().')'), $operator, $count, $boolean); | ||
| 835 | + $this->query->addBinding($query->getBindings(), 'where'); | ||
| 836 | + | ||
| 837 | + return $this->where(new Expression('('.$query->toSql().')'), $operator, $count, $boolean); | ||
| 799 | 838 | } | |
| 800 | 839 | ||
| 801 | 840 | /** | |
@@ -815,8 +854,6 @@ protected function mergeModelDefinedRelationWheresToHasQuery(Builder $hasQuery, | |||
| 815 | 854 | $hasQuery->mergeWheres( | |
| 816 | 855 | $relationQuery->wheres, $relationQuery->getBindings() | |
| 817 | 856 | ); | |
| 818 | - | ||
| 819 | - $this->query->addBinding($hasQuery->getBindings(), 'where'); | ||
| 820 | 857 | } | |
| 821 | 858 | ||
| 822 | 859 | /** | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -77,35 +77,37 @@ public function addConstraints() | |||
| 77 | 77 | } | |
| 78 | 78 | ||
| 79 | 79 | /** | |
| 80 | - * Add the constraints for a relationship count query. | ||
| 80 | + * Add the constraints for a relationship query. | ||
| 81 | 81 | * | |
| 82 | 82 | * @param \Illuminate\Database\Eloquent\Builder $query | |
| 83 | 83 | * @param \Illuminate\Database\Eloquent\Builder $parent | |
| 84 | + * @param array|mixed $columns | ||
| 84 | 85 | * @return \Illuminate\Database\Eloquent\Builder | |
| 85 | 86 | */ | |
| 86 | - public function getRelationCountQuery(Builder $query, Builder $parent) | ||
| 87 | + public function getRelationQuery(Builder $query, Builder $parent, $columns = ['*']) | ||
| 87 | 88 | { | |
| 88 | 89 | if ($parent->getQuery()->from == $query->getQuery()->from) { | |
| 89 | - return $this->getRelationCountQueryForSelfRelation($query, $parent); | ||
| 90 | + return $this->getRelationQueryForSelfRelation($query, $parent, $columns); | ||
| 90 | 91 | } | |
| 91 | 92 | ||
| 92 | - $query->select(new Expression('count(*)')); | ||
| 93 | + $query->select($columns); | ||
| 93 | 94 | ||
| 94 | 95 | $otherKey = $this->wrap($query->getModel()->getTable().'.'.$this->otherKey); | |
| 95 | 96 | ||
| 96 | 97 | return $query->where($this->getQualifiedForeignKey(), '=', new Expression($otherKey)); | |
| 97 | 98 | } | |
| 98 | 99 | ||
| 99 | 100 | /** | |
| 100 | - * Add the constraints for a relationship count query on the same table. | ||
| 101 | + * Add the constraints for a relationship query on the same table. | ||
| 101 | 102 | * | |
| 102 | 103 | * @param \Illuminate\Database\Eloquent\Builder $query | |
| 103 | 104 | * @param \Illuminate\Database\Eloquent\Builder $parent | |
| 105 | + * @param array|mixed $columns | ||
| 104 | 106 | * @return \Illuminate\Database\Eloquent\Builder | |
| 105 | 107 | */ | |
| 106 | - public function getRelationCountQueryForSelfRelation(Builder $query, Builder $parent) | ||
| 108 | + public function getRelationQueryForSelfRelation(Builder $query, Builder $parent, $columns = ['*']) | ||
| 107 | 109 | { | |
| 108 | - $query->select(new Expression('count(*)')); | ||
| 110 | + $query->select($columns); | ||
| 109 | 111 | ||
| 110 | 112 | $query->from($query->getModel()->getTable().' as '.$hash = $this->getRelationCountHash()); | |
| 111 | 113 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -299,33 +299,35 @@ public function addConstraints() | |||
| 299 | 299 | } | |
| 300 | 300 | ||
| 301 | 301 | /** | |
| 302 | - * Add the constraints for a relationship count query. | ||
| 302 | + * Add the constraints for a relationship query. | ||
| 303 | 303 | * | |
| 304 | 304 | * @param \Illuminate\Database\Eloquent\Builder $query | |
| 305 | 305 | * @param \Illuminate\Database\Eloquent\Builder $parent | |
| 306 | + * @param array|mixed $columns | ||
| 306 | 307 | * @return \Illuminate\Database\Eloquent\Builder | |
| 307 | 308 | */ | |
| 308 | - public function getRelationCountQuery(Builder $query, Builder $parent) | ||
| 309 | + public function getRelationQuery(Builder $query, Builder $parent, $columns = ['*']) | ||
| 309 | 310 | { | |
| 310 | 311 | if ($parent->getQuery()->from == $query->getQuery()->from) { | |
| 311 | - return $this->getRelationCountQueryForSelfJoin($query, $parent); | ||
| 312 | + return $this->getRelationQueryForSelfJoin($query, $parent, $columns); | ||
| 312 | 313 | } | |
| 313 | 314 | ||
| 314 | 315 | $this->setJoin($query); | |
| 315 | 316 | ||
| 316 | - return parent::getRelationCountQuery($query, $parent); | ||
| 317 | + return parent::getRelationQuery($query, $parent, $columns); | ||
| 317 | 318 | } | |
| 318 | 319 | ||
| 319 | 320 | /** | |
| 320 | - * Add the constraints for a relationship count query on the same table. | ||
| 321 | + * Add the constraints for a relationship query on the same table. | ||
| 321 | 322 | * | |
| 322 | 323 | * @param \Illuminate\Database\Eloquent\Builder $query | |
| 323 | 324 | * @param \Illuminate\Database\Eloquent\Builder $parent | |
| 325 | + * @param array|mixed $columns | ||
| 324 | 326 | * @return \Illuminate\Database\Eloquent\Builder | |
| 325 | 327 | */ | |
| 326 | - public function getRelationCountQueryForSelfJoin(Builder $query, Builder $parent) | ||
| 328 | + public function getRelationQueryForSelfJoin(Builder $query, Builder $parent, $columns = ['*']) | ||
| 327 | 329 | { | |
| 328 | - $query->select(new Expression('count(*)')); | ||
| 330 | + $query->select($columns); | ||
| 329 | 331 | ||
| 330 | 332 | $query->from($this->table.' as '.$hash = $this->getRelationCountHash()); | |
| 331 | 333 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -79,19 +79,20 @@ public function addConstraints() | |||
| 79 | 79 | } | |
| 80 | 80 | ||
| 81 | 81 | /** | |
| 82 | - * Add the constraints for a relationship count query. | ||
| 82 | + * Add the constraints for a relationship query. | ||
| 83 | 83 | * | |
| 84 | 84 | * @param \Illuminate\Database\Eloquent\Builder $query | |
| 85 | 85 | * @param \Illuminate\Database\Eloquent\Builder $parent | |
| 86 | + * @param array|mixed $columns | ||
| 86 | 87 | * @return \Illuminate\Database\Eloquent\Builder | |
| 87 | 88 | */ | |
| 88 | - public function getRelationCountQuery(Builder $query, Builder $parent) | ||
| 89 | + public function getRelationQuery(Builder $query, Builder $parent, $columns = '*') | ||
| 89 | 90 | { | |
| 90 | 91 | $parentTable = $this->parent->getTable(); | |
| 91 | 92 | ||
| 92 | 93 | $this->setJoin($query); | |
| 93 | 94 | ||
| 94 | - $query->select(new Expression('count(*)')); | ||
| 95 | + $query->select($columns); | ||
| 95 | 96 | ||
| 96 | 97 | $key = $this->wrap($parentTable.'.'.$this->firstKey); | |
| 97 | 98 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -55,31 +55,33 @@ public function addConstraints() | |||
| 55 | 55 | } | |
| 56 | 56 | ||
| 57 | 57 | /** | |
| 58 | - * Add the constraints for a relationship count query. | ||
| 58 | + * Add the constraints for a relationship query. | ||
| 59 | 59 | * | |
| 60 | 60 | * @param \Illuminate\Database\Eloquent\Builder $query | |
| 61 | 61 | * @param \Illuminate\Database\Eloquent\Builder $parent | |
| 62 | + * @param array|mixed $columns | ||
| 62 | 63 | * @return \Illuminate\Database\Eloquent\Builder | |
| 63 | 64 | */ | |
| 64 | - public function getRelationCountQuery(Builder $query, Builder $parent) | ||
| 65 | + public function getRelationQuery(Builder $query, Builder $parent, $columns = ['*']) | ||
| 65 | 66 | { | |
| 66 | 67 | if ($parent->getQuery()->from == $query->getQuery()->from) { | |
| 67 | - return $this->getRelationCountQueryForSelfRelation($query, $parent); | ||
| 68 | + return $this->getRelationQueryForSelfRelation($query, $parent, $columns); | ||
| 68 | 69 | } | |
| 69 | 70 | ||
| 70 | - return parent::getRelationCountQuery($query, $parent); | ||
| 71 | + return parent::getRelationQuery($query, $parent, $columns); | ||
| 71 | 72 | } | |
| 72 | 73 | ||
| 73 | 74 | /** | |
| 74 | - * Add the constraints for a relationship count query on the same table. | ||
| 75 | + * Add the constraints for a relationship query on the same table. | ||
| 75 | 76 | * | |
| 76 | 77 | * @param \Illuminate\Database\Eloquent\Builder $query | |
| 77 | 78 | * @param \Illuminate\Database\Eloquent\Builder $parent | |
| 79 | + * @param array|mixed $columns | ||
| 78 | 80 | * @return \Illuminate\Database\Eloquent\Builder | |
| 79 | 81 | */ | |
| 80 | - public function getRelationCountQueryForSelfRelation(Builder $query, Builder $parent) | ||
| 82 | + public function getRelationQueryForSelfRelation(Builder $query, Builder $parent, $columns = ['*']) | ||
| 81 | 83 | { | |
| 82 | - $query->select(new Expression('count(*)')); | ||
| 84 | + $query->select($columns); | ||
| 83 | 85 | ||
| 84 | 86 | $query->from($query->getModel()->getTable().' as '.$hash = $this->getRelationCountHash()); | |
| 85 | 87 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -55,15 +55,16 @@ public function addConstraints() | |||
| 55 | 55 | } | |
| 56 | 56 | ||
| 57 | 57 | /** | |
| 58 | - * Get the relationship count query. | ||
| 58 | + * Get the relationship query. | ||
| 59 | 59 | * | |
| 60 | 60 | * @param \Illuminate\Database\Eloquent\Builder $query | |
| 61 | 61 | * @param \Illuminate\Database\Eloquent\Builder $parent | |
| 62 | + * @param array|mixed $columns | ||
| 62 | 63 | * @return \Illuminate\Database\Eloquent\Builder | |
| 63 | 64 | */ | |
| 64 | - public function getRelationCountQuery(Builder $query, Builder $parent) | ||
| 65 | + public function getRelationQuery(Builder $query, Builder $parent, $columns = ['*']) | ||
| 65 | 66 | { | |
| 66 | - $query = parent::getRelationCountQuery($query, $parent); | ||
| 67 | + $query = parent::getRelationQuery($query, $parent, $columns); | ||
| 67 | 68 | ||
| 68 | 69 | return $query->where($this->morphType, $this->morphClass); | |
| 69 | 70 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2,6 +2,7 @@ | |||
| 2 | 2 | ||
| 3 | 3 | namespace Illuminate\Database\Eloquent\Relations; | |
| 4 | 4 | ||
| 5 | + use Illuminate\Database\Query\Expression; | ||
| 5 | 6 | use Illuminate\Support\Arr; | |
| 6 | 7 | use Illuminate\Database\Eloquent\Model; | |
| 7 | 8 | use Illuminate\Database\Eloquent\Builder; | |
@@ -72,11 +73,12 @@ protected function setWhere() | |||
| 72 | 73 | * | |
| 73 | 74 | * @param \Illuminate\Database\Eloquent\Builder $query | |
| 74 | 75 | * @param \Illuminate\Database\Eloquent\Builder $parent | |
| 76 | + * @param array|mixed $columns | ||
| 75 | 77 | * @return \Illuminate\Database\Eloquent\Builder | |
| 76 | 78 | */ | |
| 77 | - public function getRelationCountQuery(Builder $query, Builder $parent) | ||
| 79 | + public function getRelationQuery(Builder $query, Builder $parent, $columns = ['*']) | ||
| 78 | 80 | { | |
| 79 | - $query = parent::getRelationCountQuery($query, $parent); | ||
| 81 | + $query = parent::getRelationQuery($query, $parent, $columns); | ||
| 80 | 82 | ||
| 81 | 83 | return $query->where($this->table.'.'.$this->morphType, $this->morphClass); | |
| 82 | 84 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -145,7 +145,20 @@ public function rawUpdate(array $attributes = []) | |||
| 145 | 145 | */ | |
| 146 | 146 | public function getRelationCountQuery(Builder $query, Builder $parent) | |
| 147 | 147 | { | |
| 148 | - $query->select(new Expression('count(*)')); | ||
| 148 | + return $this->getRelationQuery($query, $parent, new Expression('count(*)')); | ||
| 149 | + } | ||
| 150 | + | ||
| 151 | + /** | ||
| 152 | + * Add the constraints for a relationship count query. | ||
| 153 | + * | ||
| 154 | + * @param \Illuminate\Database\Eloquent\Builder $query | ||
| 155 | + * @param \Illuminate\Database\Eloquent\Builder $parent | ||
| 156 | + * @param array|mixed $columns | ||
| 157 | + * @return \Illuminate\Database\Eloquent\Builder | ||
| 158 | + */ | ||
| 159 | + public function getRelationQuery(Builder $query, Builder $parent, $columns = ['*']) | ||
| 160 | + { | ||
| 161 | + $query->select($columns); | ||
| 149 | 162 | ||
| 150 | 163 | $key = $this->wrap($this->getQualifiedParentKeyName()); | |
| 151 | 164 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -708,20 +708,14 @@ protected function whereSub($column, $operator, Closure $callback, $boolean) | |||
| 708 | 708 | */ | |
| 709 | 709 | public function whereExists(Closure $callback, $boolean = 'and', $not = false) | |
| 710 | 710 | { | |
| 711 | - $type = $not ? 'NotExists' : 'Exists'; | ||
| 712 | - | ||
| 713 | 711 | $query = $this->newQuery(); | |
| 714 | 712 | ||
| 715 | 713 | // Similar to the sub-select clause, we will create a new query instance so | |
| 716 | 714 | // the developer may cleanly specify the entire exists query and we will | |
| 717 | 715 | // compile the whole thing in the grammar and insert it into the SQL. | |
| 718 | 716 | call_user_func($callback, $query); | |
| 719 | 717 | ||
| 720 | - $this->wheres[] = compact('type', 'operator', 'query', 'boolean'); | ||
| 721 | - | ||
| 722 | - $this->addBinding($query->getBindings(), 'where'); | ||
| 723 | - | ||
| 724 | - return $this; | ||
| 718 | + return $this->whereExistsQuery($query, $boolean, $not); | ||
| 725 | 719 | } | |
| 726 | 720 | ||
| 727 | 721 | /** | |
@@ -748,6 +742,25 @@ public function whereNotExists(Closure $callback, $boolean = 'and') | |||
| 748 | 742 | return $this->whereExists($callback, $boolean, true); | |
| 749 | 743 | } | |
| 750 | 744 | ||
| 745 | + /** | ||
| 746 | + * Add an exists clause to the query. | ||
| 747 | + * | ||
| 748 | + * @param \Illuminate\Database\Query\Builder $query | ||
| 749 | + * @param string $boolean | ||
| 750 | + * @param bool $not | ||
| 751 | + * @return $this | ||
| 752 | + */ | ||
| 753 | + public function whereExistsQuery(Builder $query, $boolean = 'and', $not = false) | ||
| 754 | + { | ||
| 755 | + $type = $not ? 'NotExists' : 'Exists'; | ||
| 756 | + | ||
| 757 | + $this->wheres[] = compact('type', 'operator', 'query', 'boolean'); | ||
| 758 | + | ||
| 759 | + $this->addBinding($query->getBindings(), 'where'); | ||
| 760 | + | ||
| 761 | + return $this; | ||
| 762 | + } | ||
| 763 | + | ||
| 751 | 764 | /** | |
| 752 | 765 | * Add a where not exists clause to the query. | |
| 753 | 766 | * | |
| Back | FazBrowse Home | New Git URL |
0 commit comments