Skip to content

Releases: rasuvaeff/clickhouse-toolkit

v1.12.0

Choose a tag to compare

@github-actions github-actions released this 17 Oct 01:03
86d3730
  • SelectQuery (#45): the statement builder around the WHERE the toolkit has
    always had. $qb->select(table)->final()->columns()->aggregate()->groupBy() ->orderBy()->limit()->build() returns a ParameterizedQuery {sql, params} —
    aggregates, GROUP BY, FINAL and a bound-parameter LIMIT/OFFSET without
    concatenating a skeleton around WhereClause::$sql, which is where
    identifier validation used to stop applying.
    • Projections come from closed sets with private constructors:
      Aggregate (count, sum, min, max, avg, uniqExact, and the
      conditional countIf/sumIf/uniqExactIf over a FilterInterface) and
      Scalar (toString). There is no raw-expression factory, so a projection
      cannot become an injection point; columns and aliases are
      identifier-validated at construction.
    • A conditional aggregate's condition renders through the same filter visitor
      as WHERE (allow-list, type map, bound parameters); a fully dropped
      condition throws instead of silently becoming the unconditional aggregate.
    • Mandatory filters apply exactly as in buildWhere().
    • LIMIT/OFFSET are emitted as {limit:UInt32}/{offset:UInt32} placeholders
      — constant statement text, one normalized_query_hash in the query log;
      name collisions are renamed through PlaceholderRemap.
    • ORDER BY accepts the allow-list plus everything the query itself projects
      or groups by (aggregate aliases included).
    • buildOrderBy() gained an optional array $alsoOrderable = [] parameter
      (behaviour unchanged when omitted); renderFilter() is a new internal
      helper. Existing buildSelect()/buildCount()/buildDistinct() are
      untouched. JOIN/subqueries stay a documented raw-SQL escape hatch.

v1.11.1

Choose a tag to compare

@github-actions github-actions released this 15 Oct 17:48
8797ebb
  • Allow rasuvaeff/context ^0.3, so the package installs next to context 0.3. No code changes: nothing used here changed in 0.3 (all additions).

v1.11.0

Choose a tag to compare

@github-actions github-actions released this 15 Oct 16:38
15bde47
  • Fixed: ContextClickHouseClient rounded the remaining budget up to whole
    seconds (1.2 s left became 2 s), and turned a configured
    max_execution_time => 0 (unlimited) into 1 second. The budget is now passed
    in fractional seconds; a looser or unlimited configured value is replaced
    by it (#41).
  • Fixed: a deadline passing between the check and reading the budget could
    produce max_execution_time = 0, i.e. unlimited; the budget is now read
    before the check.
  • Added: ContextClickHouseClient sets
    cancel_http_readonly_queries_on_client_close=1 unless the caller set it, so
    the server stops a read-only query when the HTTP client gives up (#42).

v1.10.1

Choose a tag to compare

@github-actions github-actions released this 11 Oct 10:36
40370f4
  • Allow rasuvaeff/context ^0.2 (^0.1 || ^0.2), so the package installs next to rasuvaeff/context-http 0.2. No code changes: the package does not use Context::onTerminate(), the only API change in context 0.2.

v1.10.0

Choose a tag to compare

@github-actions github-actions released this 10 Oct 18:32
edf9a9b
  • Added ContextClickHouseClient, which checks a rasuvaeff/context deadline
    around every operation and maps its remaining budget to ClickHouse's native
    max_execution_time setting.

v1.9.0

Choose a tag to compare

@github-actions github-actions released this 13 Sep 14:40
91203da

Fixed

  • Two ClickHouseRawFilters that reused a parameter name — under one AndX/OrX,
    or one in the mandatory filter and one in the user filter — merged by name, so
    the SQL kept both {name:Type} tokens while only the last value was bound; a
    raw name equal to a builder key (p0, …) or to the keyset boundary (ck0, …)
    lost the builder's value the same way. Parameters are now isolated at both
    merge points (ClickHouseSqlFilterVisitor composites and
    ClickHouseQueryBuilder::buildWhere()): the colliding name becomes name_0,
    name_1, … and its token is rewritten, whichever sibling comes second. A
    custom ClickHouseFilterVisitor keeps merging its own composites — only the
    builder-level merge is applied to it. The ck0/ck1 names are no longer
    reserved (#34).

v1.8.0

Choose a tag to compare

@github-actions github-actions released this 11 Sep 05:38
61a7a20
  • ClickHouseMigrationRunner::run() and status() now throw a
    ClickHouseMigrationException naming the path when $migrationsPath is not a
    directory, instead of treating it as an empty set of files. glob() returns an
    empty list for a mistyped path exactly as it does for an empty directory, so a
    wrong path — the one setting that cannot be verified locally, where it is
    correct by definition — made a deploy report success with no table created; the
    failure surfaced later, on the first query against a table that was never made.
    Behaviour change: a runner pointed at a directory that does not exist yet now
    fails instead of returning [] (#31).
  • clickhouse:migrations:migrate reports recorded migrations whose file is gone
    from disk. run() only walks the files, so it could not see them, and the two
    commands contradicted each other: status reported 1 missing where migrate
    reported an up-to-date schema. The command now reads the status once after
    applying, warns naming those records, and reflects them in the summary — while
    still exiting 0, since applying what is pending is its job and a deleted file
    is not a reason to fail a deploy. clickhouse:migrations:status remains the
    gate that exits 1 (#31).
  • ClickHouseDataReader::withFilter(), withSort(), withLimit() and
    withOffset() carry the TValue template argument over to the returned
    instance, and readOne() is annotated TValue|null. Psalm used to widen the
    reader back to its array|object bound behind any withX(), so every
    read()/readOne() after one lost its type and consumers had to re-annotate
    at each call site — an annotation that could not catch a mapper returning a
    different object type, both satisfying the bound. Docblocks only; no runtime
    or signature change (#32).

v1.7.0

Choose a tag to compare

@github-actions github-actions released this 10 Sep 17:46
1e03644
  • ClickHouseMigrationRunner accepts $migrationsTable: the bookkeeping table
    recording applied migrations is no longer hardcoded to _migrations. Adopting
    the runner where a table of that name already exists with a different schema
    used to fail inside the first read — before any migration file was read, so
    the repair could not itself ship as a migration — and two applications sharing
    one ClickHouse database collided on it. The name is interpolated into SQL, so
    it is validated as a plain identifier; a db-qualified form is refused. Existing
    installations keep _migrations (#29).

v1.6.0

Choose a tag to compare

@rasuvaeff rasuvaeff released this 01 Aug 22:43
87216d9
  • ClickHouseMigrationRunner accepts $placeholders: {{key}} tokens in a
    migration file are replaced before the file is hashed and executed, so a
    package can ship DDL whose table names the application configures instead of
    hard-coding them. An unresolved {{…}} throws a ClickHouseMigrationException
    naming the file and the token, rather than sending it to the server.
  • The checksum covers the resolved SQL, not the raw file. That is what makes
    the feature safe to adopt: a package switching its shipped DDL from a literal
    name to a placeholder is invisible to installations on the default value —
    their resolved text is byte-identical to what they applied. Changing a value
    after a migration has been applied is still reported as a divergence.
  • status() resolves placeholders identically to run(), so the two cannot
    disagree about whether a file has diverged.

v1.5.1

Choose a tag to compare

@rasuvaeff rasuvaeff released this 01 Aug 22:43
a0ae1b1
  • Reject trailing newlines in validated values: Identifier now anchors patterns
    with \z instead of $ (PCRE $ matches before a trailing \n, which let
    "<identifier>\n" slip through identifier/type validation).