Detects if it's a child where or a parent where, runs the child clauses and where statements, if there are any
results, adds a WHERE at the start if it's a parent, then adds the selected operator (and or or ) between each
clause.

{@inheritDoc}
5199
@Override
    public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body) throws TemplateException, IOException {
        StringWriter stringWriter = new StringWriter();
        WhereContext whereContext = new WhereContext(env.getCustomAttribute("whereTag"));
        env.setCustomAttribute("whereTag", whereContext);
        body.render(stringWriter);
        if (params.size() != 0 && !((Map.Entry)params.entrySet().toArray()[0]).getKey().equals("type"))
        {
            String message = "This directive only takes 'type' with a value of either 'AND' or 'OR'.";
            errors.add(message);
            throw new TemplateModelException(message);
        }
        Object typeParam = params.get("type");
        if (typeParam instanceof TemplateScalarModel)
        {
            TemplateScalarModel typeScalar = (TemplateScalarModel) typeParam;
            if (StringUtils.isNotBlank(typeScalar.getAsString()))
                whereContext.setConnector(typeScalar.getAsString().toUpperCase());
        }
        if (!Arrays.asList("AND", "OR").contains(whereContext.getConnector()))
        {
            String message = "This directive only takes 'type' with a value of either 'AND' or 'OR'.";
            errors.add(message);
            throw new TemplateModelException(message);
        }

        String outputBody = StringUtils.join(whereContext.getFreemarkerWhereClauses(), " " + whereContext.getConnector() + " ");
        if (whereContext.getFreemarkerWhereClauses().size() > 1 && whereContext.getParent() != null && !whereContext.getParent().getConnector().equals(whereContext.getConnector()))
            outputBody = "(" + outputBody + ")";
        if (StringUtils.isNotBlank(outputBody)) {
            if (whereContext.getParent() == null)
                env.getOut().write(" WHERE ");
            if (whereContext.getParent() != null)
                whereContext.getParent().addWhereBody(outputBody);
            else
                env.getOut().write(outputBody);
        }
        env.setCustomAttribute("whereTag", whereContext.getParent());
    }
1284054
public function orWhereRaw($field, $operator = null, $value = null)
    {
        return $this->where($field, $operator, $value, 'or', true);
    }
898711
public function find($criteria=null)
	{
		if($this->_parent===null) // root element
		{
			$query=new CJoinQuery($this,$criteria);
			$this->_finder->baseLimited=($criteria->offset>=0 || $criteria->limit>=0);
			$this->buildQuery($query);
			$this->_finder->baseLimited=false;
			$this->runQuery($query);
		}
		elseif(!$this->_joined && !empty($this->_parent->records)) // not joined before
		{
			$query=new CJoinQuery($this->_parent);
			$this->_joined=true;
			$query->join($this);
			$this->buildQuery($query);
			$this->_parent->runQuery($query);
		}

		foreach($this->children as $child) // find recursively
			$child->find();

		foreach($this->stats as $stat)
			$stat->query();
	}
948288
public function addWhere(array $where): void
    {
        if (empty($where)) {
            return;
        }

        $firstClause = true;
        $this->statement .= ' WHERE ';
        foreach ($where as $clause) {
            if ($firstClause === false) {
                $this->statement .= ' ' . $clause['concatenator'] . ' ';
            }
            switch ($clause['operator']) {
                case 'IN':
                    $this->addWhereIn($clause['key'], $clause['value'], false);
                    break;
                case 'NOT IN':
                    $this->addWhereIn($clause['key'], $clause['value'], true);
                    break;
                case 'BETWEEN':
                    $this->addWhereBetween($clause['key'], $clause['value']['min'], $clause['value']['max']);
                    break;
                case 'NULL':
                    $this->addWhereNull($clause['key'], false);
                    break;
                case 'NOT NULL':
                    $this->addWhereNull($clause['key'], true);
                    break;
                default:
                    $this->addSimpleWhere($clause['key'], $clause['operator'], $clause['value']);
                    break;
            }

            $firstClause = false;
        }
    }
681057
private function addCondition(Andx $andExpr, QueryBuilder $pivot, $searchType, $searchField, $searchValue, $i)
    {
        switch ($searchType) {
            case 'like':
                $andExpr->add($pivot->expr()->like($searchField, '?'.$i));
                $pivot->setParameter($i, '%'.$searchValue.'%');
                break;
            case 'notLike':
                $andExpr->add($pivot->expr()->notLike($searchField, '?'.$i));
                $pivot->setParameter($i, '%'.$searchValue.'%');
                break;
            case 'eq':
                $andExpr->add($pivot->expr()->eq($searchField, '?'.$i));
                $pivot->setParameter($i, $searchValue);
                break;
            case 'neq':
                $andExpr->add($pivot->expr()->neq($searchField, '?'.$i));
                $pivot->setParameter($i, $searchValue);
                break;
            case 'lt':
                $andExpr->add($pivot->expr()->lt($searchField, '?'.$i));
                $pivot->setParameter($i, $searchValue);
                break;
            case 'lte':
                $andExpr->add($pivot->expr()->lte($searchField, '?'.$i));
                $pivot->setParameter($i, $searchValue);
                break;
            case 'gt':
                $andExpr->add($pivot->expr()->gt($searchField, '?'.$i));
                $pivot->setParameter($i, $searchValue);
                break;
            case 'gte':
                $andExpr->add($pivot->expr()->gte($searchField, '?'.$i));
                $pivot->setParameter($i, $searchValue);
                break;
            case 'in':
                $andExpr->add($pivot->expr()->in($searchField, '?'.$i));
                $pivot->setParameter($i, explode(',', $searchValue));
                break;
            case 'notIn':
                $andExpr->add($pivot->expr()->notIn($searchField, '?'.$i));
                $pivot->setParameter($i, explode(',', $searchValue));
                break;
            case 'isNull':
                $andExpr->add($pivot->expr()->isNull($searchField));
                break;
            case 'isNotNull':
                $andExpr->add($pivot->expr()->isNotNull($searchField));
                break;
        }

        return $andExpr;
    }
1263201
public function has($relation, $operator = '>=', $count = 1, $boolean = 'and', $callback = null)
    {
        $entity = $this->mapper->newInstance();

        $relation = $this->getHasRelationQuery($relation, $entity);

        $query = $relation->getRelationCountQuery($relation->getRelatedMapper()->getQuery(), $this);

        if ($callback) {
            call_user_func($callback, $query);
        }

        return $this->addHasWhere($query, $relation, $operator, $count, $boolean);
    }
647179
function _filter (node, expr, resultSet) {
        var
            selectedNodes,
            conditions,
            type,
            idx,
            condition;
        if (expr.and) {
            conditions = expr.and;
            type = 0;
        } else if (expr.or) {
            conditions = expr.or;
            type = 1;
        }
        for (idx = 0; idx < conditions.length; ++idx) {
            condition = conditions[idx];
            if (condition.and || condition.or) {
                selectedNodes = [];
                _filter(node, condition, selectedNodes);
            } else {
                selectedNodes = _select(node, condition);
            }
            if (0 === type && selectedNodes.length === 0) {
                return;
            }
            if (1 === type && selectedNodes.length !== 0) {
                resultSet.push(node);
                return;
            }
        }
        if (0 === type) {
            resultSet.push(node);
        }
    }
529167
protected function groupWhereSliceForScope(QueryBuilder $query, $whereSlice)
    {
        $whereBooleans = collect($whereSlice)->pluck('boolean');

        // Here we'll check if the given subset of where clauses contains any "or"
        // booleans and in this case create a nested where expression. That way
        // we don't add any unnecessary nesting thus keeping the query clean.
        if ($whereBooleans->contains('or')) {
            $query->wheres[] = $this->createNestedWhere(
                $whereSlice, $whereBooleans->first()
            );
        } else {
            $query->wheres = array_merge($query->wheres, $whereSlice);
        }
    }
210036
protected function addCondition($value, string $operator, bool $isColumn = false): WhereStatement
    {
        if ($isColumn && is_string($value)) {
            $value = function (Expression $expr) use ($value) {
                $expr->column($value);
            };
        }
        $this->sql->addWhereCondition($this->column, $value, $operator, $this->separator);
        return $this->statement;
    }
1318517
public function having(string $key, string $operator, $value): SelectQueryBuilder
    {
        $this->addHaving($key, $operator, $value, 'AND');
        return $this;
    }
904606
public function set( $where, $andOr=null )
    {
        if( $where instanceof Where ) {
            if( $where->countCriteria() > 1 ) {
                $where->parenthesis();
            }
            $where->setParent( $this );
            return $this->where( '', false, $where, $andOr );
        }
        return $this->where( '', false, Sql::raw($where), $andOr );
    }
1205730
public function where($key, $value = true, $operator = '=')
    {
        return $this->addCondition($key, $value, $operator, 'where');
    }
836211
protected function matchParentType(
        /*# string */ $childType,
        array $typesToCheck,
        array &$result
    )/*# : bool */ {
        foreach ($typesToCheck as $type) {
            if ($this->isAType($childType) &&
                is_a($childType, $type, true)
            ) {
                $result[$type] = true;
            }
        }
    }
404823
public function where($column, $operator = null, $value = null, $boolean = 'and')
	{
        // First we check whether the operator is 'IN' so that we call whereIn() on it
        // as a helping hand and centralization strategy, whereIn knows what to do with the IN operator.
        if (mb_strtolower($operator) == 'in')
        {
            return $this->whereIn($column, $value, $boolean);
        }

        // If the column is an array, we will assume it is an array of key-value pairs
		// and can add them each as a where clause. We will maintain the boolean we
		// received when the method was called and pass it into the nested where.
		if (is_array($column))
		{
			return $this->whereNested(function(IlluminateQueryBuilder $query) use ($column)
			{
				foreach ($column as $key => $value)
				{
					$query->where($key, '=', $value);
				}
			}, $boolean);
		}

		if (func_num_args() == 2)
		{
			list($value, $operator) = array($operator, '=');
		}
		elseif ($this->invalidOperatorAndValue($operator, $value))
		{
			throw new \InvalidArgumentException("Value must be provided.");
		}

		// If the columns is actually a Closure instance, we will assume the developer
		// wants to begin a nested where statement which is wrapped in parenthesis.
		// We'll add that Closure to the query then return back out immediately.
		if ($column instanceof Closure)
		{
			return $this->whereNested($column, $boolean);
		}

		// If the given operator is not found in the list of valid operators we will
		// assume that the developer is just short-cutting the '=' operators and
		// we will set the operators to '=' and set the values appropriately.
		if ( ! in_array(mb_strtolower($operator), $this->operators, true))
		{
			list($value, $operator) = array($operator, '=');
		}

		// If the value is a Closure, it means the developer is performing an entire
		// sub-select within the query and we will need to compile the sub-select
		// within the where clause to get the appropriate query record results.
		if ($value instanceof Closure)
		{
			return $this->whereSub($column, $operator, $value, $boolean);
		}

		// If the value is "null", we will just assume the developer wants to add a
		// where null clause to the query. So, we will allow a short-cut here to
		// that method for convenience so the developer doesn't have to check.
		if (is_null($value))
		{
			return $this->whereNull($column, $boolean, $operator != '=');
		}

		// Now that we are working with just a simple query we can put the elements
		// in our array and add the query binding to our array of bindings that
		// will be bound to each SQL statements when it is finally executed.
		$type = 'Basic';

        $property = $column;

        // When the column is an id we need to treat it as a graph db id and transform it
        // into the form of id(n) and the typecast the value into int.
        if ($column == 'id')
        {
            $column = 'id('. $this->modelAsNode() .')';
            $value = intval($value);
        }
        // When it's been already passed in the form of NodeLabel.id we'll have to
        // re-format it into id(NodeLabel)
        elseif (preg_match('/^.*\.id$/', $column))
        {
            $parts = explode('.', $column);
            $column = sprintf('%s(%s)', $parts[1], $parts[0]);
            $value = intval($value);
        }
        // Also if the $column is already a form of id(n) we'd have to type-cast the value into int.
        elseif (preg_match('/^id\(.*\)$/', $column)) $value = intval($value);

        $binding = $this->prepareBindingColumn($column);

        $this->wheres[] = compact('type', 'binding', 'column', 'operator', 'value', 'boolean');

        $property = $this->wrap($binding);

        if ( ! $value instanceof Expression)
        {
			$this->addBinding([$property => $value], 'where');
		}

		return $this;
	}
730687
public function where($column, $operator = null, $value = null, $boolean = 'and')
    {
        // If the column is an array, we will assume it is an array of key-value pairs
        // and can add them each as a where clause. We will maintain the boolean we
        // received when the method was called and pass it into the nested where.
        if (is_array($column)) {
            return $this->addArrayOfWheres($column, $boolean);
        }

        // Here we will make some assumptions about the operator. If only 2 values are
        // passed to the method, we will assume that the operator is an equals sign
        // and keep going. Otherwise, we'll require the operator to be passed in.
        list($value, $operator) = $this->prepareValueAndOperator(
            $value,
            $operator,
            func_num_args() == 2
        );

        // If the columns is actually a Closure instance, we will assume the developer
        // wants to begin a nested where statement which is wrapped in parenthesis.
        // We'll add that Closure to the query then return back out immediately.
        if ($column instanceof Closure) {
            return $this->whereNested($column, $boolean);
        }

        // If the given operator is not found in the list of valid operators we will
        // assume that the developer is just short-cutting the '=' operators and
        // we will set the operators to '=' and set the values appropriately.
        if (! in_array(strtolower($operator), $this->operators, true) &&
            ! in_array(strtolower($operator), $this->grammar->getOperators(), true)) {
            list($value, $operator) = [$operator, '='];
        }

        // If the value is a Closure, it means the developer is performing an entire
        // sub-select within the query and we will need to compile the sub-select
        // within the where clause to get the appropriate query record results.
        if ($value instanceof Closure) {
            return $this->whereSub($column, $operator, $value, $boolean);
        }

        // If the value is "null", we will just assume the developer wants to add a
        // where null clause to the query. So, we will allow a short-cut here to
        // that method for convenience so the developer doesn't have to check.
        if (is_null($value)) {
            return $this->whereNull($column, $boolean, $operator != '=');
        }

        // Now that we are working with just a simple query we can put the elements
        // in our array and add the query binding to our array of bindings that
        // will be bound to each SQL statements when it is finally executed.
        $type = 'Basic';

        if (mb_strpos($column, '->') !== false && is_bool($value)) {
            $value = new Expression($value ? 'true' : 'false');
        }

        $this->wheres[] = compact('type', 'column', 'operator', 'value', 'boolean');

        if (! $value instanceof Expression) {
            $this->addBinding($value, 'where');
        }

        return $this;
    }
853795
public function where($key, $operator = null, $value = null): IQueryBuilderHandler
    {
        // If two params are given then assume operator is =
        if (\func_num_args() === 2) {
            $value = $operator;
            $operator = '=';
        }

        if (\is_bool($value) === true) {
            $value = (int)$value;
        }

        return $this->whereHandler($key, $operator, $value);
    }
303358
private static function filterAndOr($operation, QueryBuilder $queryBuilder)
    {
        $children = $operation['children'];

        if (empty($children)) {
            return;
        }

        $whereOperation = strtolower($operation['operation']) . 'Where';

        foreach ($children as $child) {
            $queryBuilder->{$whereOperation}(static::calculateSubFilter($child, $queryBuilder));
        }
    }