From 112b74ee7a6dfd371011f9e8ff5e5a46e72a6410 Mon Sep 17 00:00:00 2001 From: Dmitry Rashupkin Date: Tue, 23 Jun 2026 12:59:49 +0300 Subject: [PATCH] Save --- CHANGELOG.md | 2 +- README.md | 4 +- composer.json | 2 +- docs/known_issues.md | 2 +- src/Builder.php | 103 ++++++++++++++++++++++------------------ tests.bootstrap.sh | 2 +- tests/docker/Dockerfile | 2 +- 7 files changed, 63 insertions(+), 54 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index da029d8..6f9863b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -120,4 +120,4 @@ ## 1.4.0 [2020-12-11] ### Features -1. [#1](https://github.com/glushkovds/phpclickhouse-laravel/pull/1): Ability to retry requests while received not 200 response, maybe due network connectivity problems. +1. [#1](https://github.com/drashupkin/phpclickhouse-laravel/pull/1): Ability to retry requests while received not 200 response, maybe due network connectivity problems. diff --git a/README.md b/README.md index 67c6001..b46301c 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -![Tests](https://github.com/glushkovds/phpclickhouse-laravel/actions/workflows/test.yml/badge.svg) +![Tests](https://github.com/drashupkin/phpclickhouse-laravel/actions/workflows/test.yml/badge.svg) # phpClickHouse-laravel @@ -24,7 +24,7 @@ More: https://github.com/smi2/phpClickHouse#features **1.** Install via composer ```sh -$ composer require glushkovds/phpclickhouse-laravel +$ composer require drashupkin/phpclickhouse-laravel ``` **2.** Add new connection into your config/database.php: diff --git a/composer.json b/composer.json index 0afe247..2a53317 100644 --- a/composer.json +++ b/composer.json @@ -1,5 +1,5 @@ { - "name": "glushkovds/phpclickhouse-laravel", + "name": "drashupkin/phpclickhouse-laravel", "description": "Adapter of the most popular library https://github.com/smi2/phpClickHouse to Laravel", "keywords": [ "php", diff --git a/docs/known_issues.md b/docs/known_issues.md index eb4d514..b79b181 100644 --- a/docs/known_issues.md +++ b/docs/known_issues.md @@ -1,6 +1,6 @@ ## Parameter numbering with whereIn -The problem is described here: https://github.com/glushkovds/phpclickhouse-laravel/pull/34 +The problem is described here: https://github.com/drashupkin/phpclickhouse-laravel/pull/34 The reason for the problem is that for the `DB::table('my-table')` construction the builder used was not from this library `\PhpClickHouseLaravel\Builder`, diff --git a/src/Builder.php b/src/Builder.php index 35b09c3..20de343 100644 --- a/src/Builder.php +++ b/src/Builder.php @@ -15,7 +15,6 @@ use Tinderbox\ClickhouseBuilder\Query\Expression; class Builder extends BaseBuilder { - use WithClient; use BuilderMethodsFromLaravel; @@ -69,6 +68,58 @@ class Builder extends BaseBuilder return round((microtime(true) - $start) * 1000, 2); } + /** + * 🔑 Переопределяем select() для авто-обёртки агрегатных функций в Expression + * Это предотвращает экранирование `` функций типа count(), uniq(), avg() + */ + public function select(...$columns): self + { + // Если передан массив первым аргументом (совместимость со старым вызовом) + if (isset($columns[0]) && is_array($columns[0])) { + $columns = $columns[0]; + } + + if (is_array($columns)) { + $columns = array_map(function ($col) { + if (is_string($col) && preg_match('/\(|\s+as\s+|\b(count|uniq|avg|sum|min|max|toStartOfDay)\b/i', $col)) { + return new Expression($col); + } + return $col; + }, $columns); + } + + return parent::select(...(is_array($columns) ? $columns : [$columns])); + } + + /** + * Добавляет сырое SQL-выражение в SELECT без автоматического экранирования ``. + * Необходимо для агрегатных функций: count(), avg(), uniq(), toStartOfDay() и т.д. + */ + public function selectRaw(string $expression, array $bindings = []): self + { + return $this->select(new Expression($expression)); + } + + /** + * Получает первую строку результата как ассоциативный массив или null. + * Аналог Eloquent::first() + */ + public function first(): ?array + { + $rows = $this->limit(1)->getRows(); + return $rows[0] ?? null; + } + + /** + * Получает значение одного поля из первой строки. + * Аналог Eloquent::value() + */ + public function value(string $column) + { + $row = $this->select([new Expression($column)])->first(); + return $row ? reset($row) : null; + } + /** * @return Statement */ @@ -85,7 +136,6 @@ class Builder extends BaseBuilder $this->resolveConnection()->logQuery($query, $bindings, $this->getElapsedTime($start)); } - return $statement; } @@ -121,36 +171,9 @@ class Builder extends BaseBuilder public function setSourcesTable(string $table): self { $this->tableSources = $table; - return $this; } - /** - * Добавляет сырое SQL-выражение в SELECT без автоматического экранирования ``. - * Необходимо для агрегатных функций: count(), avg(), uniq(), toStartOfDay() и т.д. - */ -public function selectRaw(string $expression, array $bindings = []): self -{ - // Expression сообщает Grammar'у: "не трогай эту строку кавычками" - return $this->select(new Expression($expression)); -} - /** - * Получает первую строку результата как ассоциативный массив или null. - * Аналог Eloquent::first() - */ - public function first(): ?array - { - $rows = $this->limit(1)->getRows(); - return $rows[0] ?? null; - } - /** - * Получает значение одного поля из первой строки. - * Аналог Eloquent::value() - */ - public function value(string $column) - { - $row = $this->select([$column])->first(); - return $row[$column] ?? null; - } + /** * Note! This is a heavy operation not designed for frequent use. * @return Statement @@ -190,7 +213,6 @@ public function selectRaw(string $expression, array $bindings = []): self { $builder = $this->getCountQuery(); $result = $builder->getRows(); - return (int) $result[0]['count'] ?? 0; } @@ -209,16 +231,9 @@ public function selectRaw(string $expression, array $bindings = []): self public function paginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null) { $page = $page ?: Paginator::resolveCurrentPage($pageName); - $count = (clone $this)->count(); - - $perPage = ($perPage instanceof Closure - ? $perPage($count) - : $perPage - ) ?: 15; - - $results = $this->limit($perPage, $perPage * ($page - 1)) - ->getRows(); + $perPage = ($perPage instanceof Closure ? $perPage($count) : $perPage) ?: 15; + $results = $this->limit($perPage, $perPage * ($page - 1))->getRows(); return new LengthAwarePaginator( $results, @@ -244,14 +259,8 @@ public function selectRaw(string $expression, array $bindings = []): self public function simplePaginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null) { $page = $page ?: Paginator::resolveCurrentPage($pageName); - $perPage = $perPage ?: 15; - - // Next we will set the limit and offset for this query so that when we get the - // results we get the proper section of results. Then, we'll create the full - // paginator instances for these results with the given page and per page. - $results = $this->limit($perPage + 1, ($page - 1) * $perPage) - ->getRows(); + $results = $this->limit($perPage + 1, ($page - 1) * $perPage)->getRows(); return new Paginator( $results, diff --git a/tests.bootstrap.sh b/tests.bootstrap.sh index d61c11a..2e52feb 100755 --- a/tests.bootstrap.sh +++ b/tests.bootstrap.sh @@ -1,7 +1,7 @@ #!/bin/bash # Installing current library files to empty laravel app -cp -r /src/* vendor/glushkovds/phpclickhouse-laravel +cp -r /src/* vendor/drashupkin/phpclickhouse-laravel # Preparing Phpunit cp /src/phpunit.xml phpunit.xml diff --git a/tests/docker/Dockerfile b/tests/docker/Dockerfile index 53a1c5a..386ce7b 100644 --- a/tests/docker/Dockerfile +++ b/tests/docker/Dockerfile @@ -1,5 +1,5 @@ FROM bitnami/laravel RUN cd / && composer create-project laravel/laravel app -RUN composer require glushkovds/phpclickhouse-laravel +RUN composer require drashupkin/phpclickhouse-laravel WORKDIR "/app"