protected function formatWhere($type, $field, $statement = null)
    {
        if (is_array($field)) {
            foreach ($field as $_field => $_statement) {
                $this->formatWhere($type, $_field, $_statement);
            }

            return $this;
        }

        $isNested = false;

        // Closures represent nested where clauses.
        if ($field instanceof Closure) {
            // Create a new query.
            $nested = new static();

            // Fire the contents of the closure
            // on the newly created object
            $field($nested);

            // Compile the query
            $statement = $nested->getWhere();

            if (empty($statement)) {
                return $this;
            }

            // set the $field to $type so we can detect it later on
            $field = $type;

            // set the query as nested
            $isNested = true;
        }

        // Ensure the master $or clause
        $this->where || $this->where = ['$or' => []];

        // Because $or is the base for every query
        // $or queries can always be appended to the
        // main stack.
        if ($type === '$or') {
            if ($isNested) {
                $this->where['$or'][] = ['$and' => [$statement]];
            } else {
                $this->where['$or'][] = ['$and' => [[$field => $statement]]];
            }

            return $this;
        }

        // Retrieve the last $or clause or create a new one
        // when none available.
        $lastOrClause = array_pop($this->where['$or']) ?: ['$and' => []];

        // Retrieve the last $and clause from the $or clause
        // or create a new one when none available.
        $lastAndClause = array_pop($lastOrClause['$and']) ?: [];

        // Handle the result from nested where statements
        if ($isNested) {
            // Re-append the last $and clause
            empty($lastAndClause) || $lastOrClause['$and'][] = $lastAndClause;

            // The nested query has a base key (either $and or $or)
            // So following queries will always begin in a new clause
            $lastAndClause = $statement;
        } else {
            if (! isset($lastAndClause['$and'])) {
                if (! isset($lastAndClause[$field])) {
                    $lastAndClause[$field] = $statement;
                } elseif ($field === '$nor') {
                    $lastAndClause['$nor'] = array_merge($lastAndClause['$nor'], $statement);
                } else {
                    $lastAndClause = [
                        '$and' => [
                            $lastAndClause,
                            [$field => $statement],
                        ],
                    ];
                }
            } else {
                $lastSubAnd = array_pop($lastAndClause['$and']) ?: [];

                if (isset($lastSubAnd['$and']) || isset($lastSubAnd['$or']) || isset($lastSubAnd[$field])) {
                    empty($lastSubAnd) || $lastAndClause['$and'][] = $lastSubAnd;
                    $lastSubAnd = [];
                }

                $lastSubAnd[$field] = $statement;

                $lastAndClause['$and'][] = $lastSubAnd;
            }
        }

        // Re-append the last $and clause
        $lastOrClause['$and'][] = $lastAndClause;

        // Re-append the last $or clause
        $this->where['$or'][] = $lastOrClause;

        return $this;
    }