diff --git a/src/Builders/FilterBuilder.php b/src/Builders/FilterBuilder.php index 5f47fa53..f3c159da 100644 --- a/src/Builders/FilterBuilder.php +++ b/src/Builders/FilterBuilder.php @@ -82,23 +82,26 @@ public function __construct(Model $model, $callback = null, $softDelete = false) * @see https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-range-query.html Range query * * Supported operators are =, >, <, >=, <=, <> - * @param string $field Field name - * @param mixed $value Scalar value or an array - * @return $this + * + * @param string|\Closure $field + * @param null $operator + * @param null $value + * @param string $boolean + * @return $this|FilterBuilder */ - public function where($field, $value) + public function where($field, $operator = null, $value = null, $boolean = 'must') { - $args = func_get_args(); - - if (count($args) === 3) { - [$field, $operator, $value] = $args; - } else { - $operator = '='; + if ($field instanceof \Closure) { + return $this->whereNested($field, $boolean); } + [$value, $operator] = $this->prepareValueAndOperator( + $value, $operator, func_num_args() === 2 + ); + switch ($operator) { case '=': - $this->wheres['must'][] = [ + $this->wheres[$boolean][] = [ 'term' => [ $field => $value, ], @@ -106,7 +109,7 @@ public function where($field, $value) break; case '>': - $this->wheres['must'][] = [ + $this->wheres[$boolean][] = [ 'range' => [ $field => [ 'gt' => $value, @@ -116,7 +119,7 @@ public function where($field, $value) break; case '<': - $this->wheres['must'][] = [ + $this->wheres[$boolean][] = [ 'range' => [ $field => [ 'lt' => $value, @@ -126,7 +129,7 @@ public function where($field, $value) break; case '>=': - $this->wheres['must'][] = [ + $this->wheres[$boolean][] = [ 'range' => [ $field => [ 'gte' => $value, @@ -136,7 +139,7 @@ public function where($field, $value) break; case '<=': - $this->wheres['must'][] = [ + $this->wheres[$boolean][] = [ 'range' => [ $field => [ 'lte' => $value, @@ -147,17 +150,83 @@ public function where($field, $value) case '!=': case '<>': - $this->wheres['must_not'][] = [ + $term = [ 'term' => [ $field => $value, ], ]; + $this->setNegativeCondition($term, $boolean); break; } return $this; } + /** + * @param $column + * @param null $operator + * @param null $value + * @return $this|\Illuminate\Database\Query\Builder + */ + public function orWhere($column, $operator = null, $value = null) + { + [$value, $operator] = $this->prepareValueAndOperator( + $value, $operator, func_num_args() === 2 + ); + + return $this->where($column, $operator, $value, 'should'); + } + + /** + * @param Closure $callback + * @param string $boolean + * @return $this + */ + public function whereNested(\Closure $callback, $boolean = 'must') + { + /** @var $filter FilterBuilder */ + call_user_func($callback, $filter = $this->model::search('*')); + + $payload = $filter->buildPayload(); + $this->wheres[$boolean][] = $payload[0]['body']['query']['bool']['filter']; + + return $this; + } + + /** + * Prepare the value and operator for a where clause. + * + * @param string $value + * @param string $operator + * @param bool $useDefault + * @return array + * + * @throws \InvalidArgumentException + */ + public function prepareValueAndOperator($value, $operator, $useDefault = false) + { + if ($useDefault) { + return [$operator, '=']; + } + + return [$value, $operator]; + } + + /** + * @param $condition + * @param string $boolean + */ + public function setNegativeCondition($condition, $boolean = 'must') + { + if ($boolean == 'should') { + $cond['bool']['must_not'][] = $condition; + + $this->wheres[$boolean][] = $cond; + } else { + $this->wheres['must_not'][] = $condition; + } + } + /** * Add a whereIn condition. * @@ -165,11 +234,12 @@ public function where($field, $value) * * @param string $field * @param array $value + * @param string $boolean * @return $this */ - public function whereIn($field, array $value) + public function whereIn($field, array $value, $boolean = 'must') { - $this->wheres['must'][] = [ + $this->wheres[$boolean][] = [ 'terms' => [ $field => $value, ], @@ -178,6 +248,16 @@ public function whereIn($field, array $value) return $this; } + /** + * @param $field + * @param array $value + * @return $this + */ + public function orWhereIn($field, array $value) + { + return $this->whereIn($field, $value, 'should'); + } + /** * Add a whereNotIn condition. * @@ -185,15 +265,29 @@ public function whereIn($field, array $value) * * @param string $field * @param array $value + * @param string $boolean * @return $this */ - public function whereNotIn($field, array $value) + public function whereNotIn($field, array $value, $boolean = 'must') { - $this->wheres['must_not'][] = [ + $term = [ 'terms' => [ $field => $value, ], ]; + $this->setNegativeCondition($term, $boolean); + + return $this; + } + + /** + * @param $field + * @param array $value + * @return $this + */ + public function orWhereNotIn($field, array $value) + { + return $this->whereNotIn($field, $value, 'should'); return $this; } @@ -205,11 +299,12 @@ public function whereNotIn($field, array $value) * * @param string $field * @param array $value + * @param string $boolean * @return $this */ - public function whereBetween($field, array $value) + public function whereBetween($field, array $value, $boolean = 'must') { - $this->wheres['must'][] = [ + $this->wheres[$boolean][] = [ 'range' => [ $field => [ 'gte' => $value[0], @@ -221,6 +316,16 @@ public function whereBetween($field, array $value) return $this; } + /** + * @param $field + * @param array $value + * @return $this + */ + public function orWhereBetween($field, array $value) + { + return $this->whereBetween($field, $value); + } + /** * Add a whereNotBetween condition. * @@ -228,11 +333,12 @@ public function whereBetween($field, array $value) * * @param string $field * @param array $value + * @param string $boolean * @return $this */ - public function whereNotBetween($field, array $value) + public function whereNotBetween($field, array $value, $boolean = 'must') { - $this->wheres['must_not'][] = [ + $term = [ 'range' => [ $field => [ 'gte' => $value[0], @@ -240,21 +346,32 @@ public function whereNotBetween($field, array $value) ], ], ]; + $this->setNegativeCondition($term, $boolean); return $this; } + /** + * @param $field + * @param array $value + */ + public function orWhereNotBetween($field, array $value) + { + return $this->whereNotBetween($field, $value, 'should'); + } + /** * Add a whereExists condition. * * @see https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-exists-query.html Exists query * * @param string $field + * @param string $boolean * @return $this */ - public function whereExists($field) + public function whereExists($field, $boolean = 'must') { - $this->wheres['must'][] = [ + $this->wheres[$boolean][] = [ 'exists' => [ 'field' => $field, ], @@ -263,35 +380,58 @@ public function whereExists($field) return $this; } + /** + * @param $field + * @return $this + */ + public function orWhereExists($field) + { + return $this->whereExists($field, 'should'); + } + /** * Add a whereNotExists condition. * * @see https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-exists-query.html Exists query * * @param string $field + * @param string $boolean * @return $this */ - public function whereNotExists($field) + public function whereNotExists($field, $boolean = 'must') { - $this->wheres['must_not'][] = [ + $term = [ 'exists' => [ 'field' => $field, ], ]; + $this->setNegativeCondition($term, $boolean); return $this; } + /** + * @see https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-exists-query.html Exists query + * + * @param string $field + * @return $this|FilterBuilder + */ + public function orWhereNotExists($field) + { + return $this->whereNotExists($field, 'should'); + } + /** * @see https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-query.html Match query * * @param string $field * @param string $value + * @param string $boolean * @return $this */ - public function whereMatch($field, $value) + public function whereMatch($field, $value, $boolean = 'must') { - $this->wheres['must'][] = [ + $this->wheres[$boolean][] = [ 'match' => [ $field => $value, ], @@ -300,24 +440,46 @@ public function whereMatch($field, $value) return $this; } + /** + * @param $field + * @param $value + * @return $this + */ + public function orWhereMatch($field, $value) + { + return $this->whereMatch($field, $value, 'should'); + } + /** * @see https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-query.html Match query * * @param string $field * @param string $value + * @param string $boolean * @return $this */ - public function whereNotMatch($field, $value) + public function whereNotMatch($field, $value, $boolean = 'must') { - $this->wheres['must_not'][] = [ + $term = [ 'match' => [ $field => $value, ], ]; + $this->setNegativeCondition($term, $boolean); return $this; } + /** + * @param $field + * @param $value + * @return $this + */ + public function orWhereNotMatch($field, $value) + { + return $this->whereNotMatch($field, $value, 'should'); + } + /** * Add a whereRegexp condition. * @@ -326,11 +488,12 @@ public function whereNotMatch($field, $value) * @param string $field * @param string $value * @param string $flags + * @param string $boolean * @return $this */ - public function whereRegexp($field, $value, $flags = 'ALL') + public function whereRegexp($field, $value, $flags = 'ALL', $boolean = 'must') { - $this->wheres['must'][] = [ + $this->wheres[$boolean][] = [ 'regexp' => [ $field => [ 'value' => $value, @@ -342,6 +505,11 @@ public function whereRegexp($field, $value, $flags = 'ALL') return $this; } + public function orWhereRegexp($field, $value, $flags = 'ALL') + { + return $this->whereRegexp($field, $value, $flags, 'should'); + } + /** * Add a whereGeoDistance condition. * @@ -350,11 +518,12 @@ public function whereRegexp($field, $value, $flags = 'ALL') * @param string $field * @param string|array $value * @param int|string $distance + * @param string $boolean * @return $this */ - public function whereGeoDistance($field, $value, $distance) + public function whereGeoDistance($field, $value, $distance, $boolean = 'must') { - $this->wheres['must'][] = [ + $this->wheres[$boolean][] = [ 'geo_distance' => [ 'distance' => $distance, $field => $value, @@ -364,6 +533,17 @@ public function whereGeoDistance($field, $value, $distance) return $this; } + /** + * @param $field + * @param $value + * @param $distance + * @return $this + */ + public function orWhereGeoDistance($field, $value, $distance) + { + return $this->whereGeoDistance($field, $value, $distance, 'should'); + } + /** * Add a whereGeoBoundingBox condition. * @@ -371,11 +551,12 @@ public function whereGeoDistance($field, $value, $distance) * * @param string $field * @param array $value + * @param string $boolean * @return $this */ - public function whereGeoBoundingBox($field, array $value) + public function whereGeoBoundingBox($field, array $value, $boolean = 'must') { - $this->wheres['must'][] = [ + $this->wheres[$boolean][] = [ 'geo_bounding_box' => [ $field => $value, ], @@ -384,6 +565,16 @@ public function whereGeoBoundingBox($field, array $value) return $this; } + /** + * @param $field + * @param $value + * @return $this + */ + public function orWhereGeoBoundingBox($field, $value) + { + return $this->whereGeoBoundingBox($field, $value, 'should'); + } + /** * Add a whereGeoPolygon condition. * @@ -391,11 +582,12 @@ public function whereGeoBoundingBox($field, array $value) * * @param string $field * @param array $points + * @param string $boolean * @return $this */ - public function whereGeoPolygon($field, array $points) + public function whereGeoPolygon($field, array $points, $boolean = 'must') { - $this->wheres['must'][] = [ + $this->wheres[$boolean][] = [ 'geo_polygon' => [ $field => [ 'points' => $points, @@ -406,6 +598,16 @@ public function whereGeoPolygon($field, array $points) return $this; } + /** + * @param $field + * @param array $points + * @return $this + */ + public function orWhereGeoPolygon($field, array $points) + { + return $this->whereGeoPolygon($field, $points, 'should'); + } + /** * Add a whereGeoShape condition. * @@ -414,11 +616,12 @@ public function whereGeoPolygon($field, array $points) * @param string $field * @param array $shape * @param string $relation + * @param string $boolean * @return $this */ - public function whereGeoShape($field, array $shape, $relation = 'INTERSECTS') + public function whereGeoShape($field, array $shape, $relation = 'INTERSECTS', $boolean = 'must') { - $this->wheres['must'][] = [ + $this->wheres[$boolean][] = [ 'geo_shape' => [ $field => [ 'shape' => $shape, @@ -430,6 +633,17 @@ public function whereGeoShape($field, array $shape, $relation = 'INTERSECTS') return $this; } + /** + * @param $field + * @param array $shape + * @param string $relation + * @return $this + */ + public function orWhereGeoShape($field, array $shape, $relation = 'INTERSECTS') + { + return $this->whereGeoShape($field, $shape, $relation, 'should'); + } + /** * Add a orderBy clause. *