private function arrayWhere(string $grouper, array $where, &$tokens, callable $wrapper)
    {
        $joiner = ($grouper == Compiler::TOKEN_AND ? 'AND' : 'OR');

        foreach ($where as $key => $value) {
            $token = strtoupper($key);

            //Grouping identifier (@OR, @AND), MongoDB like style
            if ($token == Compiler::TOKEN_AND || $token == Compiler::TOKEN_OR) {
                $tokens[] = [$joiner, '('];

                foreach ($value as $nested) {
                    if (count($nested) == 1) {
                        $this->arrayWhere($token, $nested, $tokens, $wrapper);
                        continue;
                    }

                    $tokens[] = [$token == Compiler::TOKEN_AND ? 'AND' : 'OR', '('];
                    $this->arrayWhere(Compiler::TOKEN_AND, $nested, $tokens, $wrapper);
                    $tokens[] = ['', ')'];
                }

                $tokens[] = ['', ')'];

                continue;
            }

            //AND|OR [name] = [value]
            if (!is_array($value)) {
                $tokens[] = [$joiner, [$key, '=', $wrapper($value)]];
                continue;
            }

            if (count($value) > 1) {
                //Multiple values to be joined by AND condition (x = 1, x != 5)
                $tokens[] = [$joiner, '('];
                $this->builtConditions('AND', $key, $value, $tokens, $wrapper);
                $tokens[] = ['', ')'];
            } else {
                $this->builtConditions($joiner, $key, $value, $tokens, $wrapper);
            }
        }

        return;
    }