query

package
v0.9.2 Latest Latest
Warning

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

Go to latest
Published: Jul 15, 2026 License: MIT Imports: 7 Imported by: 0

Documentation

Overview

Package query is the segmentation backbone: filter events by their properties and break them down (group by) a property. Every report (funnel, retention, trends) gets filtering + breakdown by composing these over the event slice before the deterministic compute — the thing that makes analytics powerful.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Apply

func Apply(events []event.Event, filters []Filter) []event.Event

Apply returns the events matching ALL filters — and enforces the one default scope of the whole query layer: events stamped env=development are EXCLUDED unless the filters explicitly reference "env". Localhost traffic polluting production funnels is the classic silent report-corruptor; asking for dev data stays one filter away (env eq development). Living inside Apply means every surface (HTTP API, MCP, dashboard) inherits the same rule — the agreement test depends on that.

func ApplyMode added in v0.9.1

func ApplyMode(evs []event.Event, filters []Filter, anyMode bool) []event.Event

ApplyMode is Apply with an any/all switch: all = every filter must match (the default AND), any = at least one must (the OR mode of the dashboard's filter builder). Dev-traffic exclusion applies in both modes, before the user filters.

func FirstUnknownProp added in v0.9.1

func FirstUnknownProp(events []event.Event, filters []Filter) (string, []string)

FirstUnknownProp returns the first filter property that uses a POSITIVE operator (eq/contains/gt/lt/in/set/regex — ones that can only match when the property exists) yet appears on NO event, plus a sorted list of the properties that DO exist. This is how a filtered report tells a typo ("plann=pro" → no such property) apart from a genuine empty result, instead of silently returning 0 as if it were the honest answer. Negative operators (neq/notin/notset/notcontains) are skipped: a missing property legitimately satisfies them. Returns ("", nil) when every positive filter is known.

func ScopeUsers added in v0.9.1

func ScopeUsers(events []event.Event, filters []Filter, anyMode bool) []event.Event

ScopeUsers keeps every event of any user who has at least one event matching the filters — user-level scoping (vs Apply's event-level). Funnels use this so a filter on a user attribute (plan, device) that isn't present on every step event scopes the POPULATION, not the events, and later steps aren't dropped. Empty filters = unchanged.

func StampFirstTouch added in v0.9.1

func StampFirstTouch(events []event.Event, prop string) []event.Event

StampFirstTouch returns a copy of events where every event of a user carries that user's FIRST-TOUCH value of `prop` (from their earliest event that has it). This lets a funnel/report breakdown segment by an acquisition/user attribute (referrer, device, country) even though the conversion events don't carry it — otherwise the breakdown collapses everyone into "(none)". Referrer values are reduced to their host.

func Validate added in v0.2.0

func Validate(filters []Filter) error

Validate rejects malformed filters up front. An unrecognized op would otherwise match NOTHING and every report would return zeros that look like a real answer — the exact silent-wrong-number failure this engine exists to prevent.

Types

type Filter

type Filter struct {
	Property string `json:"property"`
	Op       Op     `json:"op"`
	Value    any    `json:"value"`
}

Filter is a single predicate over an event property. Filters combine with AND.

type Group

type Group struct {
	Value  string        `json:"value"`
	Events []event.Event `json:"-"`
	Count  int           `json:"count"`
}

Group is one breakdown bucket: a property value and its events.

func Breakdown

func Breakdown(events []event.Event, property string) []Group

Breakdown groups events by a property value, sorted by count descending. Events missing the property fall into "(none)".

type Op

type Op string

Op is a filter comparison.

const (
	Eq          Op = "eq"
	Neq         Op = "neq"
	Contains    Op = "contains"
	Gt          Op = "gt"
	Lt          Op = "lt"
	In          Op = "in"     // value is one of a list — expresses OR over one property (source in [hn, twitter])
	NotIn       Op = "notin"  // value is none of a list (or the property is missing)
	Set         Op = "set"    // the property exists on the event (value ignored)
	NotSet      Op = "notset" // the property is missing (value ignored)
	Regex       Op = "regex"  // value is a Go regexp matched against the stringified property
	NotContains Op = "ncontains"
)

Jump to

Keyboard shortcuts

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