query

package
v0.1.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 16, 2026 License: AGPL-3.0 Imports: 12 Imported by: 0

Documentation

Overview

Package query owns the analytics read path. HTTP and MCP adapters call this package instead of constructing ClickHouse SQL settings themselves, so tenant isolation and query limits stay in one place.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrEmptySQL is returned before ClickHouse is touched when the request
	// body doesn't carry a query.
	ErrEmptySQL = errors.New("sql is required")

	// ErrRowLimitExceeded is used by the web playground sink to stop rendering
	// before a huge result set is buffered in memory.
	ErrRowLimitExceeded = errors.New("row limit exceeded")

	// ErrSettingsNotAllowed is returned when user SQL carries its own SETTINGS
	// clause. The readonly user runs with readonly=2 so the app can attach
	// per-request settings (additional_table_filters, resource limits); that
	// same mode lets a user-supplied SETTINGS clause OVERRIDE those settings,
	// including the tenant-isolation filter. We reject such queries rather than
	// let a query silently widen its own scope. Query settings are the server's
	// to control, not the caller's.
	ErrSettingsNotAllowed = errors.New("SETTINGS clause is not allowed in queries")
)

Functions

This section is empty.

Types

type Column

type Column struct {
	Name        string `json:"name"`
	Type        string `json:"type"`
	Description string `json:"description,omitempty"`
}

Column describes one query output or schema column. Description is only populated on the schema surface (curated, keyed by column name); query result columns leave it empty and omitempty keeps it off the wire there.

type Executor

type Executor struct {
	MaxExecutionTime int
	MaxMemoryUsage   uint64
	MaxResultRows    uint64
	// contains filtered or unexported fields
}

Executor runs user SQL through the readonly ClickHouse pool with project filters and bounded resource settings.

func NewExecutor

func NewExecutor(db Querier, database string) *Executor

NewExecutor builds an executor over the readonly ClickHouse pool. database is usually "analytics". The public allowlist exposes only the curated events/persons/sessions surface; filterNames holds the hidden physical tables those views read so tenant isolation still anchors to real storage.

func (*Executor) Collect

func (e *Executor) Collect(ctx context.Context, projectID, sqlText string, maxRows int) (Result, error)

Collect runs a query and buffers up to maxRows rows for the web playground.

func (*Executor) StreamJSON

func (e *Executor) StreamJSON(ctx context.Context, projectID, sqlText string, w io.Writer) (Stats, error)

StreamJSON writes the API response envelope incrementally:

{"columns":[...],"rows":[...],"stats":{...}}

Rows are emitted as arrays in column order. The caller must set status and Content-Type before calling if it wants headers written early.

func (*Executor) Tables

func (e *Executor) Tables() []Table

Tables returns a defensive copy of the queryable table allowlist.

type Querier

type Querier interface {
	QueryContext(ctx context.Context, query string, args ...any) (*sql.Rows, error)
}

Querier is the subset of *sql.DB the executor needs. Tests use it to assert the original request context reaches the ClickHouse driver call.

type Result

type Result struct {
	Columns []Column
	Rows    [][]any
	Stats   Stats
}

Result is the bounded in-memory shape used by the web playground. The API route streams instead.

type Schema

type Schema struct {
	Tables []SchemaTable `json:"tables"`
}

Schema is the public catalog exposed by /api/v1/.../schema and MCP. It is derived from the executor's table allowlist and enriched with curated descriptions so an agent (or human) can build effective queries without guessing what each table and column means.

type SchemaProvider

type SchemaProvider struct {
	// contains filtered or unexported fields
}

SchemaProvider reads ClickHouse metadata for the allowlisted query tables.

func NewSchemaProvider

func NewSchemaProvider(db Querier, exec *Executor) *SchemaProvider

func (*SchemaProvider) Schema

func (p *SchemaProvider) Schema(ctx context.Context) (Schema, error)

type SchemaTable

type SchemaTable struct {
	Name        string   `json:"name"`
	Description string   `json:"description,omitempty"`
	Columns     []Column `json:"columns"`
}

type Stats

type Stats struct {
	Rows      int64 `json:"rows"`
	ElapsedMS int64 `json:"elapsed_ms"`
}

Stats carries minimal execution metadata. It is intentionally small and transport-neutral so MCP can reuse it later.

type Table

type Table struct {
	Name          string
	QualifiedName string
}

Table is an allowlisted analytics object. Name is what users see in the schema response; QualifiedName is the safely quoted table/view for metadata reads.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL