Skip to content

Client-side LIKE filtering is case-insensitive; server ClickHouse LIKE is case-sensitive (Go + TS + server) #451

Description

@jfwoods

Problem

Both SDKs emulate the like/not_like filter operators client-side (for live-stream and other client-side filtering paths) using case-insensitive regexes, while the server compiles the same operator to ClickHouse's LIKE, which is case-sensitive, for historical queries. A LiveQuery that combines a historical backfill with a live stream can therefore apply two different match semantics to the same filter within a single query: the backfill (server-side LIKE) excludes rows the live stream (client-side, case-insensitive) would include — or, for not_like, the reverse.

Evidence

  • Go: clients/go/stream.go, compileLike compiles the SQL LIKE pattern to a regex with the (?i) case-insensitive flag; its doc comment explicitly says "matching the TS SDK."
  • TS: clients/ts/src/query-builder.ts:341-353 — both the like and not_like cases build new RegExp(pattern, "i"), the case-insensitive flag.
  • Server: internal/query/builder.go:365-366 — the like case compiles directly to ClickHouse col + " LIKE ?", which is case-sensitive by default in ClickHouse (there's no ILIKE here).
  • The client-side behavior is documented, not accidental: docs/src/content/docs/sdk/go/streaming.md:198-201 states client-side like/not_like matching is case-insensitive, and the Go implementation's own comment calls this deliberate TS parity.

Proposed fix

This is a design-alignment decision, not a straightforward bug fix — three options, each with different tradeoffs:

  1. Make both SDKs case-sensitive to match ClickHouse's LIKE. Removes the split, but is a breaking behavior change for any TS SDK user currently relying on case-insensitive client-side matching (the TS SDK is where this behavior originated).
  2. Switch the server to ILIKE for the like/not_like operators. Aligns the server with the SDKs' existing behavior, but changes historical-query semantics for any existing caller relying on ClickHouse's default case-sensitive LIKE.
  3. Keep the divergence and document it more prominently in both SDKs' reference/streaming pages, calling out specifically that a LiveQuery's backfill and live-stream portions can disagree on like/not_like matches.

No option is obviously correct without knowing whether any current caller depends on either semantic; this issue is to make the decision explicitly rather than let the split remain implicit.

Scope

  • clients/go/stream.go
  • clients/ts/src/query-builder.ts
  • internal/query/builder.go
  • docs/src/content/docs/sdk/go/streaming.md
  • docs/src/content/docs/sdk/streaming.md

Surfaced by an external Codex review of PR #434; verified pre-existing since the TS SDK (the Go SDK's case-insensitive behavior is an intentional match to the earlier TS behavior, not a new regression).

Activity

  1. coderabbitai commented on Aug 11, 2026

    @coderabbitai
    🔗 Related PRs

    #164 - refactor(ingest)!: insert-only pipeline; mutations via /v1/query [closed]
    #174 - refactor(table names): handle unsafe table names [closed]
    #313 - feat(docs): view-transition polish, branded search + 404, chrome pass [closed]


    🧪 Issue enrichment is currently in open beta.

    You can configure auto-planning by selecting labels in the issue_enrichment configuration.

    To disable automatic issue enrichment, add the following to your .coderabbit.yaml:

    issue_enrichment:
      auto_enrich:
        enabled: false

    💬 Have feedback or questions? Drop into our discord!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions