jsonic

package
v0.30.38 Latest Latest
Warning

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

Go to latest
Published: Sep 7, 2026 License: Apache-2.0 Imports: 8 Imported by: 0

Documentation

Index

Constants

View Source
const MaxNestingDepth = 10000

MaxNestingDepth bounds how deeply the tokeniser will recurse through nested objects and arrays. Beyond this, Tokenise returns an error rather than recursing further (D-003): unbounded recursion on attacker-shaped nesting produces a `fatal error: stack overflow`, which is not a panic and cannot be caught by recover(), so it would kill the process. The limit matches the standard library's json decoder ceiling (10000), keeping jsonic self- protecting independent of who fills the document column.

Variables

This section is empty.

Functions

func AllIndices

func AllIndices(n int) []int

AllIndices returns a slice [0, 1, 2, ..., n-1].

func Avg

func Avg[T Numeric](col []T) float64

Avg returns the arithmetic mean of a numeric column.

func CoercePredicateValue

func CoercePredicateValue(val interface{}, ft FieldType) (interface{}, error)

CoercePredicateValue converts an interface{} value (typically from OQL parsing) into the appropriate Go type for the given FieldType. This is used when building FieldPredicates from parsed OQL WHERE expressions.

func Count

func Count[T any](col []T) int

Count returns the number of elements in a slice. Trivial, but provided for API consistency with other aggregate functions.

func DistinctString

func DistinctString(col []string) []string

DistinctString returns the unique values in a string column, preserving first-occurrence order.

func FilterIndices

func FilterIndices[T Numeric](col []T, op func(T) bool) []int

FilterIndices returns the indices of elements that satisfy the predicate. The returned slice is allocated once at ~25% of the column length (a reasonable estimate for selective filters).

func FilterIndicesBool

func FilterIndicesBool(col []bool, op func(bool) bool) []int

FilterIndicesBool returns the indices of bool elements that satisfy the predicate.

func FilterIndicesString

func FilterIndicesString(col []string, op func(string) bool) []int

FilterIndicesString returns the indices of string elements that satisfy the predicate.

func Gather

func Gather[T any](col []T, indices []int) []T

Gather collects elements at the given indices into a new slice.

func GroupCount

func GroupCount(groupCol []string) map[string]int

GroupCount counts elements per group key.

func GroupCountIndices

func GroupCountIndices(groupCol []string, indices []int) map[string]int

GroupCountIndices counts elements per group key using an index subset.

func GroupSum

func GroupSum[T Numeric](groupCol []string, valCol []T) map[string]T

GroupSum groups a numeric column by a string column and returns the sum per group.

func GroupSumIndices

func GroupSumIndices[T Numeric](groupCol []string, valCol []T, indices []int) map[string]T

GroupSumIndices groups by string column using an index subset.

func Max

func Max[T Numeric](col []T) T

Max returns the maximum value in a numeric column.

func Min

func Min[T Numeric](col []T) T

Min returns the minimum value in a numeric column.

func PutTokeniser

func PutTokeniser(t *Tokeniser)

PutTokeniser returns a tokeniser to the pool for reuse. The input reference is cleared to avoid retaining large byte slices.

func SkipValue

func SkipValue(tokens []Token, i int) int

SkipValue advances past a single JSON value (including nested objects and arrays) starting at token index i. Returns the index of the next token after the skipped value.

func SortIndicesBy

func SortIndicesBy[T Numeric](col []T, indices []int, desc bool)

SortIndicesBy sorts a set of row indices by the values in a numeric column. When desc is true, sorts in descending order.

func SortIndicesByString

func SortIndicesByString(col []string, indices []int, desc bool)

SortIndicesByString sorts row indices by string column values.

func Sum

func Sum[T Numeric](col []T) T

Sum returns the sum of all values in a numeric column.

Types

type Atom

type Atom uint64

Atom is a uint64-packed representation of a field name for O(1) key matching during JSON token walking. Names up to 8 bytes are packed directly (one byte per position); longer names use FNV-1a hashing.

func MakeAtom

func MakeAtom(s string) Atom

MakeAtom converts a string to an Atom. For names <= 8 bytes, the packing is bijective (no collisions possible). For names > 8 bytes, FNV-1a is used and the caller should use AtomRegistry to detect hash collisions.

func MakeAtomBytes

func MakeAtomBytes(b []byte) Atom

MakeAtomBytes converts a byte slice to an Atom without allocation.

func (Atom) MatchBytes

func (a Atom) MatchBytes(b []byte) bool

MatchBytes reports whether a byte slice matches this Atom. For short names (<= 8 bytes), this is a single integer comparison. For hashed names, it compares the hash value.

type AtomRegistry

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

AtomRegistry manages a set of field names and their Atom representations. It detects hash collisions for names longer than 8 bytes (where FNV-1a is used). For names <= 8 bytes, packing is bijective and collision-free.

The registry is safe for concurrent reads after initial registration. Registration itself is mutex-protected.

func NewAtomRegistry

func NewAtomRegistry() *AtomRegistry

NewAtomRegistry creates a new empty registry.

func (*AtomRegistry) FullName

func (r *AtomRegistry) FullName(a Atom) (string, bool)

FullName returns the registered name for an atom. Returns ("", false) if the atom was not registered.

func (*AtomRegistry) Lookup

func (r *AtomRegistry) Lookup(name string) (Atom, bool)

Lookup returns the Atom for a previously registered name. Returns (0, false) if the name was not registered.

func (*AtomRegistry) MustRegister

func (r *AtomRegistry) MustRegister(name string) Atom

MustRegister is like Register but panics on collision.

func (*AtomRegistry) NeedsFullVerify

func (r *AtomRegistry) NeedsFullVerify(a Atom) bool

NeedsFullVerify reports whether an atom match requires full string comparison (true for FNV-1a hashed names > 8 bytes).

func (*AtomRegistry) Register

func (r *AtomRegistry) Register(name string) (Atom, error)

Register adds a field name to the registry and returns its Atom. If the name collides with an existing (different) name, Register returns an error. This should be called at query planning time, not in the hot path.

func (*AtomRegistry) VerifyMatch

func (r *AtomRegistry) VerifyMatch(a Atom, keyBytes []byte) bool

VerifyMatch checks whether a byte slice from the JSON input truly matches an atom. For short names (<= 8 bytes), atom comparison is sufficient. For hashed names, it compares the full string.

type ColumnStore

type ColumnStore struct {
	Strings map[Atom][]string
	Ints    map[Atom][]int64
	Floats  map[Atom][]float64
	Bools   map[Atom][]bool
	Rows    int
}

ColumnStore holds typed columnar data indexed by Atom. Each column is a contiguous slice of a single type, enabling tight loops that the CPU can pipeline. Row N across all columns corresponds to the same entity.

func ExtractRows

func ExtractRows(blobs [][]byte, fields []FieldSpec, registry *AtomRegistry, copyStrings bool) *ColumnStore

ExtractRows tokenises and extracts fields from multiple JSON blobs into a single ColumnStore. This is the primary entry point for batch processing.

func NewColumnStore

func NewColumnStore(capacity int) *ColumnStore

NewColumnStore creates a new column store. The capacity hint is used to pre-allocate column slices (not required for correctness).

func (*ColumnStore) IncrementRows

func (cs *ColumnStore) IncrementRows()

IncrementRows increments the row counter. Called after extracting fields from one JSON object.

func (*ColumnStore) String

func (cs *ColumnStore) String() string

func (*ColumnStore) ToMaps

func (cs *ColumnStore) ToMaps(nameMap map[Atom]string) []map[string]interface{}

ToMaps converts the columnar data back to the traditional []map[string]interface{} representation. This is the compatibility bridge for executor code that hasn't been migrated to columnar input.

The nameMap maps Atom -> field name string for the output maps.

type FieldExtractor

type FieldExtractor struct {
	Fields      []FieldSpec
	Registry    *AtomRegistry // optional, for collision verification
	CopyStrings bool          // if true, copy strings from input (safe for pooled buffers)
	// contains filtered or unexported fields
}

FieldExtractor walks a tokenised JSON object and populates a ColumnStore with only the specified fields. Unrecognised fields are skipped without allocation.

The copyStrings parameter controls whether string values are copied from the input buffer. When true (production use), strings are heap- allocated and safe to use after the input buffer is recycled. When false (benchmark use), zero-copy unsafeString is used.

func NewFieldExtractor

func NewFieldExtractor(fields []FieldSpec, registry *AtomRegistry, copyStrings bool) *FieldExtractor

NewFieldExtractor creates a new extractor for the given fields. If registry is non-nil, hashed atom matches (names > 8 bytes) are verified against the full string to detect collisions.

func (*FieldExtractor) Extract

func (fe *FieldExtractor) Extract(tok *Tokeniser, cs *ColumnStore)

Extract walks the tokens from a single JSON object and appends extracted field values to the appropriate columns in the store. After calling Extract for each row, call cs.IncrementRows().

The method expects the token stream to start with TokObjStart. Nested objects and arrays are skipped correctly but not extracted.

type FieldPredicate

type FieldPredicate struct {
	Name string      // JSON key name
	Atom Atom        // pre-computed atom for fast key matching
	Type FieldType   // expected value type of the field
	Op   PredicateOp // comparison operator
	Val  interface{} // comparison target: string, float64, int64, bool, or []interface{} for IN
}

FieldPredicate describes a filter condition on a single JSON field. The Value is stored as the native Go type that will be compared against the tokenised JSON value.

func MakeFieldPredicate

func MakeFieldPredicate(name string, typ FieldType, op PredicateOp, val interface{}) FieldPredicate

MakeFieldPredicate creates a predicate, computing the Atom from the name.

func (*FieldPredicate) EvalTokenValue

func (fp *FieldPredicate) EvalTokenValue(tokens []Token, input []byte, tokenIdx int) (bool, bool)

EvalTokenValue evaluates a predicate against a raw token from the JSON input. Returns (matched, fieldWasSeen). If the token type doesn't match the predicate's expected type, returns (false, true) — the field was seen but the type mismatch means no match.

type FieldSpec

type FieldSpec struct {
	Name string    // JSON key name
	Atom Atom      // pre-computed atom for fast matching
	Type FieldType // expected value type
}

FieldSpec describes a field to extract from a JSON object.

func MakeFieldSpec

func MakeFieldSpec(name string, typ FieldType) FieldSpec

MakeFieldSpec creates a FieldSpec, computing the Atom from the name.

type FieldType

type FieldType uint8

FieldType identifies the expected type of a field for extraction.

const (
	FieldString FieldType = iota
	FieldInt
	FieldFloat
	FieldBool
)

type FilterFieldEntry

type FilterFieldEntry struct {
	Atom Atom
	Name string
}

FilterFieldEntry pairs an Atom with its output field name.

func MakeFilterFieldEntries

func MakeFilterFieldEntries(names []string) []FilterFieldEntry

MakeFilterFieldEntries builds a slice of FilterFieldEntry from names.

type FilterResult

type FilterResult struct {
	Passed bool                   // true if all predicates matched
	Data   map[string]interface{} // extracted fields (only populated if Passed)
}

FilterResult holds the outcome of a filtered extraction pass.

func FilterExtractFromTokens

func FilterExtractFromTokens(
	tok *Tokeniser,
	outputFields []FilterFieldEntry,
	preds *PredicateSet,
) FilterResult

FilterExtractFromTokens walks a tokenised JSON object, extracts the requested fields, and evaluates the predicate set in a single pass.

The walk extracts both predicate fields and output fields as they are encountered (JSON key order is arbitrary). At the end of the object, all predicates are evaluated. If any predicate field was not found in the object, the predicate is treated as not matching (closed-world).

This avoids allocating the output map entirely for rows that fail the predicate — the main performance win of B4.

Parameters:

  • tok: tokeniser with a completed Tokenise() call
  • outputFields: the SELECT fields to extract (FilterFieldEntry-style)
  • preds: predicate set to evaluate (may be nil for no filtering)

Returns a FilterResult. If preds is nil, Passed is always true.

type Numeric

type Numeric interface {
	~int64 | ~float64
}

Numeric is a type constraint for numeric column operations.

type PredicateOp

type PredicateOp uint8

PredicateOp identifies a comparison operator for field predicates.

const (
	OpEq   PredicateOp = iota // =
	OpNeq                     // !=
	OpLt                      // <
	OpLte                     // <=
	OpGt                      // >
	OpGte                     // >=
	OpIn                      // IN (value list)
	OpLike                    // LIKE (string pattern)
)

func (PredicateOp) String

func (op PredicateOp) String() string

String returns the operator symbol.

type PredicateSet

type PredicateSet struct {
	Predicates []FieldPredicate
	// contains filtered or unexported fields
}

PredicateSet is an AND-combined set of field predicates. All must match for a row to pass. This represents the subset of WHERE clauses that can be evaluated during tokenisation.

func NewPredicateSet

func NewPredicateSet(preds []FieldPredicate) *PredicateSet

NewPredicateSet creates a predicate set from the given predicates.

func (*PredicateSet) Len

func (ps *PredicateSet) Len() int

Len returns the number of predicates.

func (*PredicateSet) LookupAtom

func (ps *PredicateSet) LookupAtom(a Atom) int

LookupAtom returns the predicate index for a given atom, or -1 if the atom doesn't correspond to any predicate field.

type Token

type Token struct {
	Type  TokenType
	Start uint32 // byte offset of token content start
	End   uint32 // byte offset past last byte of token content
}

Token represents a single JSON token as a (type, start, end) triple referencing byte offsets in the original input. No copies are made.

type TokenType

type TokenType uint8

TokenType identifies the kind of JSON token.

const (
	TokString   TokenType = iota // Quoted string (Start/End exclude quotes)
	TokNumber                    // Numeric literal
	TokTrue                      // true
	TokFalse                     // false
	TokNull                      // null
	TokObjStart                  // {
	TokObjEnd                    // }
	TokArrStart                  // [
	TokArrEnd                    // ]
	TokColon                     // :
	TokComma                     // ,
)

type Tokeniser

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

Tokeniser is a zero-allocation JSON tokeniser that produces a flat array of tokens referencing the original input byte slice.

func GetTokeniser

func GetTokeniser() *Tokeniser

GetTokeniser returns a tokeniser from the pool, or allocates a new one.

func (*Tokeniser) Input

func (t *Tokeniser) Input() []byte

Input returns the input byte slice from the last Tokenise call.

func (*Tokeniser) TokenBytes

func (t *Tokeniser) TokenBytes(tok Token) []byte

TokenBytes returns the raw bytes of a token from the input.

func (*Tokeniser) TokenCount

func (t *Tokeniser) TokenCount() int

TokenCount returns the number of tokens produced.

func (*Tokeniser) TokenString

func (t *Tokeniser) TokenString(tok Token) string

TokenString extracts the string content of a TokString token from the input. This is a zero-copy operation using unsafeString; the returned string is only valid while the input byte slice is alive.

func (*Tokeniser) Tokenise

func (t *Tokeniser) Tokenise(input []byte) error

Tokenise parses the input bytes into tokens. The input must be valid JSON. The tokeniser references the input slice directly; the caller must keep the input alive while tokens are in use.

func (*Tokeniser) Tokens

func (t *Tokeniser) Tokens() []Token

Tokens returns the token slice produced by the last Tokenise call.

Jump to

Keyboard shortcuts

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