Jump to content

Connect SuperML | Leeroopedia MCP: Equip your AI agents with best practices, code verification, and debugging knowledge. Powered by Leeroo — building Organizational Superintelligence. Contact us at founders@leeroo.com.

Implementation:Helicone Helicone Filters

From Leeroopedia
Knowledge Sources
Domains Filtering, SQL Generation, ClickHouse, PostgreSQL
Last Updated 2026-02-14 06:32 GMT

Overview

The central filter-to-SQL compiler that translates FilterNode trees into parameterized SQL WHERE and HAVING clauses for both PostgreSQL and ClickHouse databases.

Description

This file is the core query filter engine for Helicone. It defines two sets of key-to-column mappings (whereKeyMappings for WHERE clauses, havingKeyMappings for HAVING clauses) that translate abstract filter tree nodes into concrete SQL column references for every supported database table. The recursive buildFilter function walks the FilterNode tree, calling buildFilterBranch for AND/OR combinators and buildFilterLeaf for leaf nodes that produce actual SQL conditions.

The file handles numerous special cases including: JSONB property containment with gin-contains operator, ClickHouse map column lookups for properties and scores, cached request detection via UUID comparison, cost precision multiplication, session tag subqueries through a tags table, null/empty value handling, and full-text search with vector-contains. It provides both ClickHouse ({val_N : Type}) and PostgreSQL ($N) parameter placeholder formats and exports convenience functions that automatically inject organization ID filters for authenticated queries.

Usage

Use buildFilterClickHouse or buildFilterPostgres as the primary entry points for compiling filter trees into SQL. For authenticated queries, use the buildFilterWithAuth* family of functions which automatically wrap the filter with an organization ID constraint.

Code Reference

Source Location

Signature

// Core filter building
export function buildFilter(args: BuildFilterArgs): { filter: string; argsAcc: any[] };
export function buildFilterLeaf(filter: FilterLeaf, argsAcc: any[], keyMappings: KeyMappings,
  argPlaceHolder: (arg_index: number, arg: any) => string): { filters: string[]; argsAcc: any[] };
export function buildFilterBranch(args: ...): { filter: string; argsAcc: any[] };

// Database-specific builders
export function buildFilterClickHouse(args: ExternalBuildFilterArgs): { filter: string; argsAcc: any[] };
export function buildFilterPostgres(args: ExternalBuildFilterArgs): { filter: string; argsAcc: any[] };

// Authenticated filter builders
export async function buildFilterWithAuth(args: ExternalBuildFilterArgs & { org_id: string },
  database?: "postgres" | "clickhouse", getOrgIdFilter?: ...): Promise<{ filter: string; argsAcc: any[] }>;
export async function buildFilterWithAuthClickHouse(args: ...): Promise<{ filter: string; argsAcc: any[] }>;
export async function buildFilterWithAuthClickHousePropResponse(args: ...): Promise<...>;
export async function buildFilterWithAuthClickHouseProperties(args: ...): Promise<...>;
export async function buildFilterWithAuthClickHouseCacheMetrics(args: ...): Promise<...>;
export async function buildFilterWithAuthClickHouseRateLimits(args: ...): Promise<...>;
export async function buildFilterWithAuthClickHouseOrganizationProperties(args: ...): Promise<...>;

// Utilities
export function clickhouseParam(index: number, parameter: any): string;
export class FilterNotImplemented extends Error { ... }

Import

import {
  buildFilterClickHouse,
  buildFilterPostgres,
  buildFilterWithAuthClickHouse,
  clickhouseParam,
} from "@helicone-package/filters/filters";

Architecture

Filter Compilation Pipeline

FilterNode (tree)
    |
    v
buildFilter() -- dispatches based on node type
    |
    +-- "all" -> returns "true"
    |
    +-- FilterBranch (has "left") -> buildFilterBranch()
    |       |
    |       +-- Recursively builds left and right subtrees
    |       +-- Joins with AND/OR operator
    |
    +-- FilterLeaf -> buildFilterLeaf()
            |
            +-- Looks up KeyMapper for the table
            +-- Extracts column, operator, value
            +-- Handles special cases (properties, scores, cached, etc.)
            +-- Returns parameterized SQL clause

Key Mapping System

The KeyMappings type maps each table key to a KeyMapper function:

type KeyMapper<T> = (
  filter: T,
  placeValueSafely: (val: string | number) => string | number
) => {
  column?: string;
  operator: AllOperators;
  value: string | number;
};

Most tables use easyKeyMappings, a helper that creates a simple column name mapping. Complex tables like request_response_rmt use custom mapper functions to handle special cases.

Special Case Handling

Properties (JSONB/Map)

// PostgreSQL: JSONB containment for equals, arrow operator for other ops
"properties" -> {
  equals: `properties @> jsonb_build_object(key, value)`
  other:  `properties ->> key OPERATOR value`
}

// ClickHouse: Map column access
"request_response_rmt.properties" -> `request_response_rmt.properties[key] OPERATOR value`

Scores (Map)

// ClickHouse: Checks existence before comparison
"scores" -> `has(scores, key) AND scores[key] OPERATOR value`

Cached Request Detection

// cached=true  -> cache_reference_id != '00000000-0000-0000-0000-000000000000'
// cached=false -> cache_reference_id =  '00000000-0000-0000-0000-000000000000'

Cost Precision

// Costs are stored as integers with COST_PRECISION_MULTIPLIER
"cost" -> Math.floor(value * COST_PRECISION_MULTIPLIER)

Session Tags

// Session tags use a subquery through the tags table
"session_tag" -> `properties['Helicone-Session-Id'] IN (
  SELECT entity_id FROM tags WHERE tag OPERATOR value AND entity_type = 'session'
)`

Operator to SQL Mapping

Operator SQL Notes
equals = Special handling for "null" and "__empty__"
not-equals != Special handling for "null" (IS NOT NULL)
like LIKE Case-sensitive pattern match
ilike ILIKE Case-insensitive pattern match
gte >=
gt >
lt <
lte <=
contains ILIKE Wraps value with % wildcards
not-contains NOT ILIKE Wraps value with % wildcards
gin-contains @> PostgreSQL JSONB containment
vector-contains @@ Full-text search with plainto_tsquery
has HAS ClickHouse map key existence

I/O Contract

Inputs (buildFilterClickHouse / buildFilterPostgres)

Name Type Required Description
filter FilterNode Yes The filter tree to compile into SQL
argsAcc any[] Yes Accumulator array for parameterized values
having boolean No If true, use HAVING key mappings instead of WHERE mappings

Outputs

Name Type Description
filter string Parameterized SQL condition string (e.g., status = {val_0 : Int32} AND model ILIKE {val_1 : String})
argsAcc any[] Array of parameter values to bind

Parameter Placeholder Formats

// ClickHouse format
clickhouseParam(0, 200)     // -> "{val_0 : Int32}"
clickhouseParam(1, "gpt-4") // -> "{val_1 : String}"
clickhouseParam(2, true)    // -> "{val_2 : UInt8}"
clickhouseParam(3, new Date()) // -> "{val_3 : DateTime}"

// PostgreSQL format
postgresParam(0, any)       // -> "$1"
postgresParam(1, any)       // -> "$2"

Usage Examples

import { buildFilterClickHouse, buildFilterWithAuthClickHouse } from "@helicone-package/filters/filters";

// Basic filter compilation
const { filter, argsAcc } = buildFilterClickHouse({
  filter: {
    left: { request_response_rmt: { status: { equals: 200 } } },
    operator: "and",
    right: { request_response_rmt: { model: { like: "gpt-4" } } },
  },
  argsAcc: [],
});
// filter: "(request_response_rmt.status = {val_0 : Int32} AND request_response_rmt.model LIKE {val_1 : String})"
// argsAcc: [200, "gpt-4"]

// Authenticated filter (adds org_id constraint)
const result = await buildFilterWithAuthClickHouse({
  filter: { request_response_rmt: { status: { equals: 200 } } },
  argsAcc: [],
  org_id: "org-123",
});
// Automatically wraps with: organization_id = 'org-123' AND status = 200

Related Pages

Page Connections

Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment