Skip to content

Latest commit

 

History

History
929 lines (712 loc) · 43.8 KB

File metadata and controls

929 lines (712 loc) · 43.8 KB

jsonstat-go API Reference

This document is a systematic reference for every exported identifier in the jsonstat-go module (module github.com/jsonstat/go). It is generated from the package godoc and kept in sync with the source; when in doubt, run go doc for the authoritative wording.

Notation: signatures are written as in Go. A trailing // → introduces the concrete Go type returned by the function. Click any symbol to jump to its definition.

Contents


Status

The current release is v0.1.1. The compiled-in Version reads "0.1.1" and is overridable at link time; release builds inject the exact tag from VCS via -ldflags (see Version and Makefile):

make install-cli                           # uses `git describe --tags --always --dirty`
make install-cli VERSION=v0.1.1            # explicit override
go build -ldflags '-X github.com/jsonstat/go.Version=v0.1.1' ./cmd/jsonstat

jsonstat-go targets JSON-stat 2.0 (FormatVersion), matching the modern ecosystem (toolkit, php, io, validator, wasm). Pre-2.0 bundle documents are tolerated on decode (see Decode) but never produced on encode.


Package jsonstat

import "github.com/jsonstat/go"

A JSON-stat dataset is a multi-dimensional cube. Cells sit at the intersection of dimensions; the flat value array lists cells in row-major order ("what does not change, first"). The last dimension in id changes fastest.

Every operation in jsonstat-go is a function over the same in-memory model:

  • Client: decode → traverse → subset (Dice) → transform (Unflatten, Transform) → encode.
  • Authoring: build cubes programmatically with the fluent Builder.
  • Validate: structural + semantic tiers, pure Go (see Validate).

Idiomatic Go, not a port: typed returns + error, functional-options for configuration, context.Context for cancellation, log/slog for structured logging, and iter.Seq2 for lazy iteration. Runtime dependency is the Go standard library only.

Constants

Response classes

Constant Value Meaning
ClassDataset "dataset" A dataset response.
ClassCollection "collection" A collection response.
ClassDimension "dimension" A standalone dimension response.
ClassBundle "bundle" Legacy pre-2.0 container; not a valid 2.0 class but recognised by Decode for backwards compatibility.

Documents without a class are treated as ClassDataset by tolerant decoders.

Unit symbol position

Constant Value Meaning
PositionStart "start" Symbol precedes the value (e.g. $5).
PositionEnd "end" Symbol follows the value (e.g. 5%; the default).

Format version

const FormatVersion = "2.0"   // version.go

See version.go.

Variables — sentinel errors

All errors are typed sentinels safe to use with errors.Is and errors.As. They are typically wrapped inside a ValueError by Decode, Validate, and the traversal methods.

Sentinel Meaning
ErrBuildIncomplete Builder.Build — missing dimensions, categories, or values.
ErrCategoryNotFound A requested category ID is not present in a dimension.
ErrCellMissing Requested cell has no value (JSON null / absent key). Not an error in the usual sense — callers should test Cell.Missing; the sentinel exists so helpers can wrap it.
ErrCoordLenMismatch A coordinate vector length ≠ dataset dimension count.
ErrDatasetNotFound A requested dataset is not present in the document.
ErrDimensionNotFound A requested dimension ID is not declared.
ErrEmptyDocument Input was empty or whitespace only.
ErrHTTPFailure Fetch — server returned non-2xx. The wrapping ValueError carries the status code in Flat.
ErrIndexOutOfRange A numeric index (dataset index, category index, cell coordinate) is out of range.
ErrInvalidSize The size array is inconsistent (negative entries, length mismatch with id, etc.).
ErrItemNotFound A collection item lookup failed.
ErrMissingRequired A JSON-stat 2.0 required property is absent.
ErrResponseTooLarge Fetch — response body exceeded the limit set by WithMaxBytes.
ErrSparseValueLength A sparse value object contains a key ≥ the dataset's total cell count.
ErrStatusShape The status property is neither a string, an array, nor an object.
ErrUnknownClass The document's class is not one of the JSON-stat 2.0 response classes.
ErrUnsupportedVersion The document's version is below 2.0 and the document does not look like a tolerated pre-2.0 bundle.
ErrValueShape The value property is neither an array nor an object, or the resolved flat index is out of range.

Functions

func Decode(r io.Reader) (*Document, error)

Parses a JSON-stat 2.0 document from r. Accepts all three 2.0 response classes (dataset, collection, dimension) and tolerates the pre-2.0 bundle container. Normalises dense/sparse value and all three status forms. Structural shape is checked; semantic checks live in Validate.

func DecodeBytes(b []byte) (*Document, error)

Like Decode but accepts a byte slice.

Fetch

func Fetch(ctx context.Context, url string, opts ...FetchOption) (*Document, error)

Context-aware counterpart of Decode for remote HTTP sources. Default client has a 30-second timeout; supply WithHTTPClient for pooling / mTLS / custom transports.

doc, err := jsonstat.Fetch(ctx, url,
    jsonstat.WithUserAgent("my-app/1.0"),
    jsonstat.WithMaxBytes(50*1024*1024), // 50 MiB guard
)

Encoding / marshalling

Function Returns Notes
Encode(w *bytes.Buffer, doc *Document) error error Compact wire form, canonical JSON-stat property ordering. Supports single-dataset / collection / dimension. Pre-2.0 bundles are rejected.
EncodeBytes(doc *Document) ([]byte, error) []byte Like Encode but returns bytes.
MarshalDocument(doc *Document) ([]byte, error) []byte Functional inverse of DecodeBytes.
MarshalDataset(ds *Dataset) ([]byte, error) []byte JSON-stat wire form of a single dataset.
MarshalCollection(c *Collection) ([]byte, error) []byte JSON-stat wire form of a collection.
MarshalDimension(dim *Dimension) ([]byte, error) []byte JSON-stat wire form of a standalone dimension-class response.

Each type also satisfies json.Marshaler directly ((*Dataset).MarshalJSON, etc.), so it can be embedded in other JSON structures.

Validation

Validate
func Validate(doc *Document) []ValidationError

Runs structural + semantic tiers over doc and returns every problem found, in path order. An empty/nil slice means valid. Never panics; a nil document yields a single CodeMissingClass error. Problems are never silently dropped: a single missing property may cascade into several errors, all of which are surfaced.

ValidateDataset
func ValidateDataset(ds *Dataset, prefix string) []ValidationError

Same as Validate but for a single dataset. The prefix is prepended to every reported Path so bundle/collection members can be distinguished.

FormatValidationReport
func FormatValidationReport(errs []ValidationError) string

Renders a slice of validation errors as a path-sorted multi-line string. Useful for CLI output and test failure messages.

Version helpers

var Version = "0.1.1"                           // version.go — overridable via -ldflags
func VersionInfo() map[string]string            // → {"library","version","jsonstat","go","spec","license"}

VersionInfo is intended for diagnostics, /version endpoints, and CLI banners.

Misc helper

func CoordinatesCategoryKey(prefix string, catIndex int) string

Returns the string key under which a category's coordinates would be stored in the source JSON-stat object. Exported as a helper for tests that build synthetic fixtures programmatically.

Types

Type Cell

A single value-status pair read out of a cube. Return type of the cell-access methods on Dataset.

Field Type Meaning
Value float64 Numeric observation. Always 0 when Missing is true.
Status string Observation-level status code. May be empty.
Missing bool Cell has no value (JSON null in dense form, or absent key in sparse).
Flat int Row-major flat index. Always ≥ 0.
Coords []int Per-dimension category index, in Dataset.ID order.
func (c Cell) HasValue() bool   // reports whether the cell carries a numeric observation

Missing cells: Value is the zero float64 and Missing is true; callers should test Missing before reading Value.

One possible value of a Dimension.

Field Type Meaning
ID string Identifier, unique within its dimension.
Index int 0-based position — used directly in flat-index math.
Label string Human-readable name (may be empty).
Unit *Unit Unit metadata (typically only on metric-role categories).
Coordinates []float64 [longitude, latitude] pair for geo-role categories; nil when absent.

One axis of a dataset's cube.

Field Type Meaning
ID string Identifier matching one entry of Dataset.ID.
Label string Human-readable name.
Role Role Special role, or empty when unset.
Size int Number of categories. Equals Dataset.Size[i].
Categories []Category Categories in index order.
Child map[string][]string Category hierarchy: parent ID → child IDs. nil if none. See spec.
Href string URL of the standalone dimension response, if any.
Link []Link Related-resource links (e.g. alternate geo breakdowns).
Note []string Dimension-level notes.
Extension map[string]any Provider-specific extra fields.
Method Signature Notes
CategoryByID (id string) (*Category, error) Returns the category or ErrCategoryNotFound.
CategoryIndex (id string) (int, error) 0-based position or ErrCategoryNotFound.
CategoryIDs () []string IDs of every category in index order.
CategoryLabels () []string Labels in index order; unlabelled categories render under their ID. Go counterpart of JS Dimension(id, true).
HasHierarchy () bool Reports category.child presence.
ChildrenOf (parentID string) ([]string, bool) Child IDs (defensive copy) or false.

Type Dataset

The primary type of the package: every read, traverse, subset, transform, and serve operation is a function over a *Dataset. Normalises the polymorphic parts of the wire format (value dense/sparse, status string/array/object).

Field Type Meaning
Class string Always ClassDataset.
Version string JSON-stat version declared on source, or FormatVersion for Builder-built datasets.
Label, Href, Source, Updated string Standard metadata. Updated stored as raw string to avoid tz pitfalls.
ID []string Ordered dimension IDs; order determines stride math.
Size []int Category count per dimension, parallel to ID.
Role map[Role][]string Declared roles → dimension IDs. May be empty.
Dimensions map[string]*Dimension Dimensions keyed by ID.
Note []string Dataset-level notes.
Link []Link Related-resource links.
Extension map[string]any Provider-specific extra fields.
Dataset — geometry & introspection
Method Signature Notes
N () int Total cell count (product of Size). Counterpart of JS n. Returns 0 if no dimensions or any size is 0.
DimCount () int Number of dimensions.
Dimension (id string) (*Dimension, error) Or ErrDimensionNotFound.
DimensionByIndex (i int) (*Dimension, error) Or ErrIndexOutOfRange.
DimensionByRole (role Role) (*Dimension, error) First dimension with that role, or ErrDimensionNotFound.
DimensionsByRole (role Role) []*Dimension All dimensions with that role, in ID order.
DimensionPosition (id string) (int, error) Index in ID.
DimensionIDs () []string Defensive copy of ID.
SizeSlice () []int Defensive copy of Size.
Roles () []Role Declared roles.
HasRole (role Role) bool Reports role presence.
Strides () []int Cached strides (defensive copy). nil before reindex.
ValueFormat () string Which value wire form would be emitted on encode.
StatusFormat () string Which status wire form would be emitted on encode.
Dataset — cell access
Method Signature Notes
CellByFlat (i int) (Cell, error) Cell at flat row-major index. Counterpart of JS Dataset.Data(i).
CellByCoord (coords ...int) (Cell, error) Cell at one category index per dim, in ID order. Counterpart of JS Dataset.Data([0,0,0]).
CellByLabel (m map[string]string) (Cell, error) Cell at dim-ID → cat-ID. Counterpart of JS Dataset.Data({TIME:2020, GEO:"ES"}).
Cells () iter.Seq2[Cell, error] Lazy Go 1.23 range-over-func; yields exactly N cells. Counterpart of JS Dataset.Data().
CellsSlice () ([]Cell, error) Materialises the full cube as a slice.
Walk (fn func(Cell) error) error Callback iteration; stops at first non-nil error.
Dataset — subset & transform
Method Signature Notes
Dice (f Filter, opts ...DiceOption) (*Dataset, error) The single subsetting operation (no Slice). Returns a fresh reindexed dataset.
Unflatten (fn UnflattenFunc) ([]any, error) Faithful JS port; callback-driven raw cell stream.
Transform (opts ...TransformOption) (any, error) Faithful JS port; options-driven tabular output (array / arrobj / objarr / object).
Dataset — encode
func (d *Dataset) MarshalJSON() ([]byte, error)

Satisfies json.Marshaler so the dataset can be embedded or marshalled directly.

The top-level parsed value of a JSON-stat response. Exactly one of the class-specific fields is populated, depending on Class:

Field Type Populated when
Class string Always — one of the Class* constants.
Version string Always.
Label, Href, Note, Link, Extension various Document-level metadata.
Dataset *Dataset Class == ClassDataset (also when class is omitted but required dataset properties are present).
Collection *Collection Class == ClassCollection.
Dimension *Dimension Class == ClassDimension.
Bundle map[string]*Dataset Pre-2.0 bundle (no class, top-level values look like datasets). Keyed by dataset id.
IsBundle bool Document was decoded as a pre-2.0 bundle.
Method Signature Notes
IsDataset () bool
IsCollection () bool
IsDimension () bool
Datasets () []*Dataset Every dataset regardless of class: single dataset → one-element slice; collection → embedded datasets; bundle → bundled datasets in id-key order.
SingleDataset () (*Dataset, error) Convenience: returns Dataset or ErrDatasetNotFound.
MarshalJSON () ([]byte, error) Dispatches on the populated response-class field.

In-memory representation of a JSON-stat collection response: an ordered list of Item values, each of which may embed or link to a dataset, dimension, or another collection.

Field Type Meaning
Label, Href, Updated, Source string Standard metadata.
Note []string Collection-level notes.
Link []Link Links; items appear here with rel "item".
Extension map[string]any Provider-specific extra fields.
Items []Item Parsed item list, in declaration order.
Method Signature Notes
ItemByIndex (i int) (*Item, error) i-th item or ErrItemNotFound.
ItemByID (id string) (*Item, error) First item whose Item.ID matches; exact-string equality.
ItemsByClass (class string) []*Item Items whose embedded class matches (e.g. ClassDataset).
Datasets () []*Dataset Every embedded dataset; link-only items are skipped.
MarshalJSON () ([]byte, error)

Type Item

One entry in a JSON-stat collection. Items may embed a full dataset/dimension or merely link via Href.

Field Type Meaning
Href string URL when referenced rather than embedded.
Type string MIME type at Href.
Label string Human-readable title.
Class string Embedded item's class (e.g. "dataset").
ID string Optional item identifier inside the collection.
Extension map[string]any Provider-specific extra fields.
EmbeddedDataset *Dataset Non-nil when the item embeds a full dataset.
EmbeddedDimension *Dimension Non-nil when the item embeds a standalone dimension.
func (i *Item) IsEmbedded() bool   // reports an embedded response rather than only a link

Type Link

A single entry in a JSON-stat link array. Used at every level: document, dataset, dimension, category.

Field Type Meaning
Href string Target URL.
Type string MIME type of the resource at Href (e.g. application/json-stat).
Rel string IANA link relation type (self, item, alternate, version, note).
Label string Human-readable description.
Extension map[string]any Arbitrary extra keys beyond href/type/rel/label.

See spec.

Type Role

type Role string

Names a special meaning assigned to a dimension via the dataset's role object. JSON-stat 2.0 defines exactly three:

Constant Value Meaning
RoleTime "time" Points or periods in time (e.g. "2020", "2021-Q1").
RoleGeo "geo" Spatial dimension (country codes, NUTS regions).
RoleMetric "metric" Names the quantity being measured (e.g. "POP", "GDP"). Metric categories typically carry a Unit.

See spec.

Type Unit

Unit of measure attached to a metric category.

Field Type Meaning
Decimals int Recommended display decimal places (required by spec when unit is present; enforced by Validate, not the type).
Label string Human-readable unit label (persons, euros).
Symbol string Unit symbol ($, %, ).
Position string PositionStart or PositionEnd (default).

See spec.

Type Filter

type Filter map[string][]string

Selects the categories to keep (or, with WithDropFilter, exclude) during a Dice operation. Keyed by dimension ID; each value is the list of category IDs to retain (or drop). A dimension absent from the map is left untouched. Unknown category IDs cause ErrCategoryNotFound. Duplicate IDs and ordering are ignored: the result always preserves the original category order of the source.

Type Builder

Fluent constructor for Dataset instances — the Go-native authoring counterpart of Decode.

ds, err := jsonstat.NewBuilder().
    Label("Population by sex and year").
    Dim("sex", "Sex").Cat("F", "Female").Cat("M", "Male").End().
    Dim("year", "Year").Cat("2020", "").Cat("2021", "").End().
    Values([]float64{100, 110, 200, 210}). // [F2020, F2021, M2020, M2021]
    Build()

Values are interpreted in JSON-stat row-major order (last declared dimension varies fastest). Use SparseValues for sparse input; the resulting dataset encodes back to the sparse form.

Builder — top-level setters
Method Signature Notes
NewBuilder () *Builder Returns an empty builder.
Label (s string) *Builder Dataset title.
Source (s string) *Builder Source attribution.
Updated (s string) *Builder Last-updated timestamp (stored verbatim; callers format ISO 8601).
Href (s string) *Builder Canonical URL.
Note (s string) *Builder Appends a free-text note.
Extension (key string, value any) *Builder Provider-specific extension field.
Builder — dimension declarations
Method Signature Notes
Dim (id, label string) *DimBuilder Begins a new dimension; subsequent Cat calls add categories.
DimBuilder.End () *Builder Closes the dimension, returns the parent Builder.
DimBuilder.Cat (id, label string) *DimBuilder Appends a category (empty label allowed).
DimBuilder.CatWith (c catSpec) *DimBuilder Richer per-category metadata entry point (unit, coordinates).
DimBuilder.Role (r Role) *DimBuilder Declares the role (time/geo/metric); multiple dims may share a role.
DimBuilder.Unit (u *Unit) *DimBuilder Attaches a Unit to the most recently added category.
DimBuilder.Coordinates (lon, lat float64) *DimBuilder Attaches a [lon, lat] pair to the most recently added category (geo dims).
Builder — values & status
Method Signature Notes
Values (vals []float64) *Builder Dense value array; length must equal product of category counts. Every cell present.
DenseValuesWithMissing (vals []float64, missing []bool) *Builder Like Values but a parallel missing slice marks absent observations (JSON null).
SparseValues (m map[int]float64) *Builder Sparse object form; only supplied flat-index/value pairs are present. Encodes back to sparse.
UniformStatus (s string) *Builder Single status string for every cell. Most compact form; overrides earlier status calls.
StatusArray (arr []string) *Builder Per-cell status in array form (row-major). Empty string = no status.
StatusMap (m map[int]string) *Builder Per-flat-index status in object form.
Build () (*Dataset, error) Materialises the cube. Validates: ≥1 dim, every dim ≥1 category, dense value length, sparse keys in range. Returns a fully reindexed dataset. The builder is not mutated and may be reused.

Value/status pair exposed to the UnflattenFunc callback for the current cell. When the cell has no status, Status is "" (Go-friendly counterpart of the JS null). When missing, Value is 0 and Missing is true.

type Coordinates map[string]string

Dimension-ID → category-ID map exposed to the UnflattenFunc callback for the current cell. Freshly allocated per cell so the callback may retain references safely. Category IDs are always strings (e.g. {"year": "2012"}, not 2012).

type UnflattenFunc func(coords Coordinates, dp Datapoint, n int, row []any) any

Mirrors the JS Toolkit's Unflatten callback. Invoked once per cell in row-major order.

Argument Meaning
coords Coordinates of the cell (dim ID → cat ID).
dp Cell's value/status pair (Datapoint).
n 0-based cell counter (flat row-major index).
row Accumulator slice being built; the returned value is appended after the callback returns.

Returning nil skips the cell (matching the JS Toolkit's treatment of a callback that returns undefined).

out, err := ds.Unflatten(func(coords jsonstat.Coordinates, dp jsonstat.Datapoint, n int, row []any) any {
    return map[string]any{"coordinates": coords, "datapoint": dp}
})
type TransformType string

Selects the output shape of Transform. Mirrors JS opts.type.

Constant Value Output Go type Notes
TransformArray "array" [][]any Default. Header row + data rows.
TransformArrObj "arrobj" []map[string]any One object per cell. Supports by (pivot) and meta.
TransformObjArr "objarr" map[string][]any Columnar. Supports by and meta.
TransformObject "object" *DataTable Google DataTable {cols, rows}. Infers column type from first value.

When WithMeta is true, the array/objarr shapes are wrapped in *TableWithMeta carrying the metadata block, matching the JS {meta, data} shape. The object type never emits metadata.

Type Content

type Content string

Controls whether categories are identified by label or by ID in Transform output.

Constant Value Meaning
ContentLabel "label" (Default) human-readable label.
ContentID "id" Category ID.

Type Field

type Field string

Controls whether dimension/value/status column keys are IDs or labels. Default FieldID; the array type overrides this to FieldLabel.

Constant Value Meaning
FieldID "id" Key columns by IDs.
FieldLabel "label" Key columns by labels.

Type DataTable and friends

Produced by Transform with the TransformObject type. Mirrors the Google DataTable shape.

type DataTable     struct { Cols []DataTableCol; Rows []DataTableRow }
type DataTableCol  struct { ID, Type, Label string }
type DataTableRow  struct { C map[string]any }   // cells carry value in "v"; "f" not populated

Type TableMeta and friends

Emitted when WithMeta is true.

type TableWithMeta      struct { Meta TableMeta; Data any }
type TableMeta          struct { Type, Label, Source, Updated, By, Prefix string; ID []string; Status, Comma bool; Drop []string; Dimensions map[string]TableDimMeta }
type TableDimMeta       struct { Label, Role string; Categories TableDimCategories }
type TableDimCategories struct { ID, Label []string }

Carries context about where in the cube an error occurred. The structured wrapping type used by Decode, Validate, and the traversal methods. Recover with errors.As.

Field Type Meaning
Op string Operation that failed (e.g. "Decode", "Dataset.Dimension").
Dim string Dimension ID involved, if any.
Cat string Category ID involved, if any.
Flat int Flat row-major cell index involved. -1 = not applicable.
Err error Wrapped sentinel / underlying error.
func (v *ValueError) Error() string
func (v *ValueError) Unwrap() error
type ValidationCode string

Stable kebab-case identifier for a single class of validation problem. The set is intentionally small; each identifies a single invariant regardless of tier. Tests and downstream tooling can rely on these strings not changing across releases.

Code Constant Meaning
missing-class CodeMissingClass No class property and not a tolerated pre-2.0 bundle.
unknown-class CodeUnknownClass class not one of dataset/collection/dimension.
missing-required CodeMissingRequired A JSON-stat 2.0 required property is absent.
id-size-mismatch CodeIDSizeMismatch len(id) != len(size).
dim-missing CodeDimMissing A dimension named in id is absent from dimension.
dim-extra CodeDimExtra dimension has a key not present in id (the only permissive warning).
category-size-mismatch CodeCategorySizeMismatch A dimension's category count ≠ its size.
invalid-size CodeInvalidSize size has a negative element or is malformed.
value-length-mismatch CodeValueLengthMismatch Dense value length ≠ prod(size).
sparse-value-key-out-of-range CodeSparseValueKeyOutOfRange Sparse value key ≥ prod(size).
status-length-mismatch CodeStatusLengthMismatch status array length ≠ prod(size).
role-unknown-dim CodeRoleReferencesUnknownDim role names a dimension not in id.
duplicate-category-id CodeDuplicateCategoryID A dimension has two categories with the same ID.
duplicate-dim-id CodeDuplicateDimID id contains the same dimension ID twice.

Describes a single validation problem. Returned by Validate / ValidateDataset as a slice (empty when valid).

Field Type Meaning
Code ValidationCode Stable identifier.
Path string Dotted-path location (dimension.geo.category.index, value[3]); empty = whole document.
Message string Human-readable description.
Err error Underlying sentinel (one of the Err* values).
func (v *ValidationError) Error() string
func (v *ValidationError) Unwrap() error
func (v *ValidationError) HasSeverity() string   // "fatal" except for CodeDimExtra (permissive warning)

Functional-option families

Transform options (TransformOption)

Option Effect
WithTransformType Sets the output shape. Default TransformArray.
WithStatus Includes the status column. Default false. Ignored when WithBy is also set.
WithContent Label vs ID for categories. Default ContentLabel.
WithField ID vs label for dimension/value/status keys. Default FieldID (array type overrides to FieldLabel).
WithValueLabel Label of the value column. Default "Value".
WithStatusLabel Label of the status column. Default "Status". Only relevant when WithStatus is true.
WithMeta Attaches dataset metadata, wrapping as *TableWithMeta. Default false. Not available with the object type.
WithBy Pivots the value column on a dimension (one output column per category). arrobj/objarr only; silently ignored for array/object. Non-existent dims are ignored.
WithPrefix Prefix prepended to pivoted category columns. Default "".
WithDrop Excludes dimension IDs from output. Only single-category dims are droppable; invalid/multi-category IDs are ignored.
WithComma Formats numbers with a comma decimal mark. Default false. Not available with the object type.

Dice options (DiceOption)

Option Effect
WithDropFilter Inverts Filter: listed categories are removed rather than retained. Dims absent from the filter are still untouched.
WithClone Controls deep copy vs in-place mutation. Default true (clone); false is an opt-in optimisation for callers that will not reuse the receiver.

Fetch options (FetchOption)

Option Effect
WithHTTPClient Supplies the http.Client. Default: per-call client with 30s timeout.
WithHeader Sets/overrides a single request header. Multiple calls with different keys accumulate; same key replaces. Host cannot be set this way.
WithUserAgent Sets the User-Agent header. Default jsonstat-go/+Version.
WithMaxBytes Caps response body bytes; exceeded → ErrResponseTooLarge. 0 = unlimited.
WithMethod Overrides HTTP method. Default GET. With POST, supply WithBody.
WithBody Supplies a request body for non-GET methods. Caller sets Content-Type via WithHeader.

Package jsonstathttp

import "github.com/jsonstat/go/jsonstathttp"

Serves a JSON-stat Dataset over net/http with query-string subsetting, content negotiation, conditional GET (ETag / If-None-Match), and slog access logging. Go counterpart of the server-side helpers shipped with the JS JSON-stat Toolkit. A single constructor returns an http.Handler ready to mount on any ServeMux. All heavy lifting is delegated to the core jsonstat package.

Constructor

func NewHandler(ds *jsonstat.Dataset, opts ...HandlerOption) http.Handler

The dataset is concurrency-safe: the handler never mutates it (Dice returns a fresh Dataset).

h := jsonstathttp.NewHandler(ds, jsonstathttp.WithLogger(log))
http.ListenAndServe(":8080", h)

Query parsing

func ParseQuery(q urlQuery) (jsonstat.Filter, error)

Extracts a subsetting Filter from a request's query string. Returns (nil, nil) when no subsetting parameters are present (the handler then serves the full dataset). Invalid filters return a non-nil error wrapping ErrInvalidQuery (safe to surface as HTTP 400).

Handler options (HandlerOption)

Option Effect
WithLogger slog.Logger for access logging. Default slog.Default.
WithETagPrefix Prefix prepended to the ETag value. Default "jsonstat". Useful when serving multiple datasets on one origin.
WithIndentJSON Pretty-prints (2-space) JSON for json-stat and plain-JSON representations. Default compact. Debug aid — roughly doubles response size.
WithStatusColumn Includes the status column in CSV/CSV-stat output. Default omits status (matching the JS Toolkit default).
WithDefaultRepresentation Changes the representation served when no Accept / ?format= signal is present. Default RepJSONStat.
WithoutETag Disables ETag emission and If-None-Match handling. For tests asserting on bodies.
type Representation int

Carries the response Content-Type and a discriminator the handler switches on to pick the encoder.

Representation constants

Constant Content-Type Notes
RepJSONStat application/json-stat Default.
RepJSON application/json Plain JSON view.
RepCSVStat text/csv-stat CSV-stat flavour.
RepCSV text/csv Plain CSV.
func (r Representation) ContentType() string   // HTTP Content-Type (no parameters)
func (r Representation) IsCSV() bool           // one of the CSV flavours (shared encoder)
func (r Representation) String() string        // human-readable label for logging

Content negotiation honours Accept q-values and the ?format= query override (json-stat, json, csv-stat, csv).


Package internal/stride

import "github.com/jsonstat/go/internal/stride"   // internal — reached via Dataset methods

Implements the row-major ("what does not change, first") index math. The cell at coordinates (c₀, c₁, …, cₙ₋₁) — where cᵢ is the category index of dimension i — is stored at:

flat(c₀, c₁, …, cₙ₋₁) = Σᵢ cᵢ · strideᵢ

where strideᵢ = ∏ⱼ sizeⱼ for j > i. The last dimension changes fastest. See Row-major order and the canonical JSON-stat sample.

This package is internal; callers reach it through the methods on Dataset. All public-facing APIs accept dimension IDs and category indices, never raw strides.

Functions

Function Signature Notes
ValidateSize (size []int) error Non-empty and every element non-negative. Zero-size allowed (denotes empty dimension → total 0).
Total (size []int) (int, error) Product of all sizes.
Strides (size []int) ([]int, error) Per-dimension stride; last is always 1. E.g. [1, 36, 12] → [432, 12, 1].
Flat (size, coords []int) (int, error) Coordinates → flat position.
Coords (size []int, flat int) ([]int, error) Inverse of Flat.
Inc (size, coords []int) (next []int, carry bool, err error) Advances a coordinate vector by one cell in-place; carry true when wrapped back to all-zero.
AllCoords (size []int) ([][]int, error) Full enumeration in row-major order (tests/small cubes).

Stride sentinels

Sentinel Meaning
ErrEmptySize size slice is empty.
ErrNegativeSize Some element of size is negative.
ErrCoordLenMismatch Coordinate count ≠ dimension count.
ErrCoordOutOfRange Coordinate negative or ≥ corresponding size.
ErrIndexOutOfRange Flat index negative or ≥ total.

CLI (cmd/jsonstat)

go install ./cmd/jsonstat            # from a module checkout
make install-cli                     # injects the VCS version via -ldflags

The CLI is a thin shell over the jsonstat and jsonstathttp packages. Subcommands:

Subcommand Purpose
decode <file> Decode a JSON-stat document and print a summary of its structure.
validate <file> Run Validate and print a FormatValidationReport.
convert <in> <out> -f <format> Convert between formats (csv, csv-stat, json). Optional -status flag.
slice <file> -f <filter> Subset a dataset via Dice and print the result.
serve <file> [addr] Serve a dataset over HTTP via jsonstathttp.NewHandler.
version Print jsonstat <Version> (JSON-stat <FormatVersion>).

See cmd/jsonstat/main.go for flag details.


Worked examples

The repository ships three runnable examples under examples/:

Example Demonstrates
examples/basic-read End-to-end client flow: Decode → traverse → DiceTransform.
examples/build-cube Build a 3-dimensional cube with the Builder (per-category units, object-form status), MarshalDataset, round-trip decode.
examples/serve-http Build a toy dataset in-memory and serve it over HTTP with jsonstathttp.NewHandler.

License

Apache-2.0. See LICENSE.