Documentation
¶
Overview ¶
Package jsonstat is a Go-native library for the JSON-stat 2.0 format.
jsonstat-go is a complete round-trip alternative to the JavaScript JSON-stat Toolkit + Utilities Suite, targeting backend and cloud-native use cases (Go microservices, statistical agencies, open-data platforms). It is the first JSON-stat library written in Go and intentionally drops the legacy parts of the JS Toolkit: there is no toTable and no Slice. The non-deprecated tabular methods are Dataset.Unflatten (callback-based, faithful port of the JS Toolkit method of the same name) and Dataset.Transform (options-based, faithful port of the JS Toolkit method of the same name); the single subsetting method is Dataset.Dice.
JSON-stat in one paragraph ¶
A JSON-stat dataset is a multi-dimensional cube. Cells sit at the intersection of dimensions; the flat [Dataset.value] array lists cells in row-major order ("what does not change, first"). The last dimension in [Dataset.id] changes fastest. See the package examples for the stride math that converts between flat indices and dimension coordinates.
Three surfaces, one model ¶
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).
The companion subpackage github.com/jsonstat/go/jsonstathttp adds an net/http handler that serves a Dataset with query-string subsetting and content negotiation (JSON-stat, CSV-stat, JSON, CSV).
Decode a document ¶
jsonstat.Decode(r io.Reader) (*Dataset, error) jsonstat.Fetch(ctx context.Context, url string, opts ...FetchOption) (*Dataset, error)
Decode accepts both the dense ("value": [1, 2, null, ...]) and sparse ("value": {"0": 1, "2": 3}) value forms, and all three status forms (array, single string, object). The runtime representation normalises them so callers never branch on the wire format.
Traverse ¶
ds.Dimension(id string) (*Dimension, error) ds.DimensionByRole(role Role) (*Dimension, error) ds.CellByFlat(i int) (Cell, error) // flat row-major index ds.CellByCoord(coords ...int) (Cell, error) // one category index per dim ds.CellByLabel(map[string]string) (Cell, error) // map[dimID]catID ds.Cells() iter.Seq2[Cell, error] // lazy, Go 1.23 range-over-func ds.Walk(func(Cell) error) // callback iteration
Transform and subset ¶
ds.Unflatten(fn UnflattenFunc) ([]any, error) // raw cell stream (faithful JS port) ds.Transform(opts ...TransformOption) (any, error) // array / arrobj / objarr / object (faithful JS port) ds.Dice(jsonstat.Filter, opts ...DiceOption) (*Dataset, error) // no Slice
Idiomatic Go, not a port ¶
The JS Toolkit uses polymorphic methods (null returns, overloaded argument shapes, boolean flags). jsonstat-go uses typed returns plus an error, the functional-options pattern for configuration, context.Context for cancellation, log/slog for structured logging, and iter.Seq2 for lazy iteration. It depends only on the Go standard library at runtime.
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 real version from VCS via -ldflags (see Version). See FormatVersion for the JSON-stat wire-format version implemented here.
Index ¶
- Constants
- Variables
- func CoordinatesCategoryKey(prefix string, catIndex int) string
- func Encode(w *bytes.Buffer, doc *Document) error
- func EncodeBytes(doc *Document) ([]byte, error)
- func FormatValidationReport(errs []ValidationError) string
- func MarshalCollection(c *Collection) ([]byte, error)
- func MarshalDataset(ds *Dataset) ([]byte, error)
- func MarshalDimension(dim *Dimension) ([]byte, error)
- func MarshalDocument(doc *Document) ([]byte, error)
- func VersionInfo() map[string]string
- type Builder
- func (b *Builder) Build() (*Dataset, error)
- func (b *Builder) DenseValuesWithMissing(vals []float64, missing []bool) *Builder
- func (b *Builder) Dim(id, label string) *DimBuilder
- func (b *Builder) Extension(key string, value any) *Builder
- func (b *Builder) Href(s string) *Builder
- func (b *Builder) Label(s string) *Builder
- func (b *Builder) Note(s string) *Builder
- func (b *Builder) Source(s string) *Builder
- func (b *Builder) SparseValues(m map[int]float64) *Builder
- func (b *Builder) StatusArray(arr []string) *Builder
- func (b *Builder) StatusMap(m map[int]string) *Builder
- func (b *Builder) UniformStatus(s string) *Builder
- func (b *Builder) Updated(s string) *Builder
- func (b *Builder) Values(vals []float64) *Builder
- type Category
- type Cell
- type Collection
- type Content
- type Coordinates
- type DataTable
- type DataTableCol
- type DataTableRow
- type Datapoint
- type Dataset
- func (d *Dataset) CellByCoord(coords ...int) (Cell, error)
- func (d *Dataset) CellByFlat(i int) (Cell, error)
- func (d *Dataset) CellByLabel(m map[string]string) (Cell, error)
- func (d *Dataset) Cells() iter.Seq2[Cell, error]
- func (d *Dataset) CellsSlice() ([]Cell, error)
- func (d *Dataset) Dice(f Filter, opts ...DiceOption) (*Dataset, error)
- func (d *Dataset) DimCount() int
- func (d *Dataset) Dimension(id string) (*Dimension, error)
- func (d *Dataset) DimensionByIndex(i int) (*Dimension, error)
- func (d *Dataset) DimensionByRole(role Role) (*Dimension, error)
- func (d *Dataset) DimensionIDs() []string
- func (d *Dataset) DimensionPosition(id string) (int, error)
- func (d *Dataset) DimensionsByRole(role Role) []*Dimension
- func (d *Dataset) HasRole(role Role) bool
- func (d *Dataset) MarshalJSON() ([]byte, error)
- func (d *Dataset) N() int
- func (d *Dataset) Roles() []Role
- func (d *Dataset) SizeSlice() []int
- func (d *Dataset) StatusFormat() string
- func (d *Dataset) Strides() []int
- func (d *Dataset) Transform(opts ...TransformOption) (any, error)
- func (d *Dataset) Unflatten(fn UnflattenFunc) ([]any, error)
- func (d *Dataset) ValueFormat() string
- func (d *Dataset) Walk(fn func(Cell) error) error
- type DiceOption
- type DimBuilder
- type Dimension
- func (d *Dimension) CategoryByID(id string) (*Category, error)
- func (d *Dimension) CategoryIDs() []string
- func (d *Dimension) CategoryIndex(id string) (int, error)
- func (d *Dimension) CategoryLabels() []string
- func (d *Dimension) ChildrenOf(parentID string) ([]string, bool)
- func (d *Dimension) HasHierarchy() bool
- func (d *Dimension) MarshalJSON() ([]byte, error)
- type Document
- type FetchOption
- type Field
- type Filter
- type Item
- type Link
- type Role
- type TableDimCategories
- type TableDimMeta
- type TableMeta
- type TableWithMeta
- type TransformOption
- func WithBy(dimID string) TransformOption
- func WithComma(b bool) TransformOption
- func WithContent(ct Content) TransformOption
- func WithDrop(dimIDs ...string) TransformOption
- func WithField(f Field) TransformOption
- func WithMeta(b bool) TransformOption
- func WithPrefix(s string) TransformOption
- func WithStatus(b bool) TransformOption
- func WithStatusLabel(s string) TransformOption
- func WithTransformType(t TransformType) TransformOption
- func WithValueLabel(s string) TransformOption
- type TransformType
- type UnflattenFunc
- type Unit
- type ValidationCode
- type ValidationError
- type ValueError
Constants ¶
const ( ClassDataset = "dataset" ClassCollection = "collection" ClassDimension = "dimension" // ClassBundle is the legacy pre-2.0 container. It is not a valid 2.0 // class but is recognised by [Decode] for backwards compatibility. ClassBundle = "bundle" )
ClassDataset, ClassCollection, ClassDimension are the JSON-stat 2.0 response class values. The pre-2.0 bundle has no class value; documents without a class are treated as ClassDataset by tolerant decoders (see Decode).
const ( PositionStart = "start" PositionEnd = "end" )
PositionStart and PositionEnd are the two legal values for Unit.Position.
const FormatVersion = "2.0"
FormatVersion is the JSON-stat format version implemented by this library.
jsonstat-go targets JSON-stat 2.0, matching the rest of the modern ecosystem (toolkit, php, io, validator, wasm). Pre-2.0 bundle documents are tolerated on decode (see Decode) but never produced on encode.
Variables ¶
var ErrBuildIncomplete = errors.New("jsonstat: incomplete cube definition")
ErrBuildIncomplete is returned by Builder.Build when the cube is missing required pieces (dimensions, categories, or values).
var ErrCategoryNotFound = errors.New("jsonstat: category not found")
ErrCategoryNotFound is returned when a requested category ID is not present in a dimension.
var ErrCellMissing = errors.New("jsonstat: cell has no value")
CellMissing reports that the requested cell has no value (a JSON null in a dense value array, or an absent key in a sparse value object). It is not an error: callers should use Cell.Missing to test rather than errors.Is, but the sentinel is exported so that error-returning helpers can wrap it.
var ErrCoordLenMismatch = errors.New("jsonstat: coordinate length mismatch")
ErrCoordLenMismatch is returned when a coordinate vector length does not match the dataset's dimension count.
var ErrDatasetNotFound = errors.New("jsonstat: dataset not found")
ErrDatasetNotFound is returned when a requested dataset is not present in the document (for example, doc.Dataset(99) on a single-dataset document).
var ErrDimensionNotFound = errors.New("jsonstat: dimension not found")
ErrDimensionNotFound is returned when a requested dimension ID is not declared in the dataset.
var ErrEmptyDocument = errors.New("jsonstat: empty document")
ErrEmptyDocument is returned by decode when the input is empty or only whitespace.
var ErrHTTPFailure = errors.New("jsonstat: HTTP request failed")
ErrHTTPFailure is returned by Fetch when the server returns a non-2xx status code. The wrapping ValueError carries the status code in the Flat field.
var ErrIndexOutOfRange = errors.New("jsonstat: index out of range")
ErrIndexOutOfRange is returned when a numeric index (dataset index, category index, or cell coordinate) is out of range.
var ErrInvalidSize = errors.New("jsonstat: invalid size")
ErrInvalidSize is returned by decode/validate when the size array is inconsistent (negative entries, length mismatch with id, etc.).
var ErrItemNotFound = errors.New("jsonstat: item not found")
ErrItemNotFound is returned when a collection item lookup fails.
var ErrMissingRequired = errors.New("jsonstat: missing required property")
ErrMissingRequired is returned by validate when a JSON-stat 2.0 required property is absent.
var ErrResponseTooLarge = errors.New("jsonstat: response too large")
ErrResponseTooLarge is returned by Fetch when the response body exceeds the limit set by WithMaxBytes.
var ErrSparseValueLength = errors.New("jsonstat: sparse value key out of range")
ErrSparseValueLength is returned by validate when a sparse value object contains a key ≥ the dataset's total cell count.
var ErrStatusShape = errors.New("jsonstat: invalid status shape")
ErrStatusShape is returned by decode when the "status" property is neither a string, an array, nor an object.
var ErrUnknownClass = errors.New("jsonstat: unknown response class")
ErrUnknownClass is returned by decode when the document's "class" is not one of the JSON-stat 2.0 response classes.
var ErrUnsupportedVersion = errors.New("jsonstat: unsupported version")
ErrUnsupportedVersion is returned by decode when the document's "version" is below 2.0 and the document does not appear to be a tolerated pre-2.0 bundle. Pre-2.0 bundles are accepted (see Decode) but never re-emitted by Encode.
var ErrValueShape = errors.New("jsonstat: invalid value shape")
ErrValueShape is returned by decode when the "value" property is neither an array nor an object, or by traverse when the resolved flat index is out of range for the value store.
var Version = "0.1.1"
Version is the semantic version of the jsonstat-go library.
It is a var rather than a const so that release builds can inject the real version from VCS at link time, for example:
go build -ldflags '-X github.com/jsonstat/go.Version=v0.1.1' ./cmd/jsonstat
or, equivalently, via git:
go build -ldflags "-X github.com/jsonstat/go.Version=$(git describe --tags --always --dirty)" ./cmd/jsonstat
When no -ldflags override is supplied, the default below is used. The CLI's Makefile `install-cli` target injects the version automatically when a git working tree is present; see the "Status" section of API.md.
Note that Go modules do not expose build/debug.ReadBuildInfo() version metadata for the main module itself (only for dependencies), so a compile-time value is required for runtime introspection of the library version.
Functions ¶
func CoordinatesCategoryKey ¶
CoordinatesCategoryKey returns the string key under which a category's coordinates would be stored in the source JSON-stat object. Exported as a small helper for tests that build synthetic fixtures programmatically.
func Encode ¶
Encode serialises doc to its JSON-stat 2.0 wire form and writes it to w. The output is compact (no extraneous whitespace) and uses canonical JSON-stat property ordering.
Encode supports single-dataset, single-collection, and single-dimension documents. Pre-2.0 bundles are rejected: marshal each entry of Document.Bundle individually instead.
func EncodeBytes ¶
EncodeBytes is like Encode but returns the marshalled bytes.
func FormatValidationReport ¶
func FormatValidationReport(errs []ValidationError) string
FormatValidationReport renders a slice of validation errors as a human-readable, path-sorted multi-line string. Useful for CLI tools and test failure output.
func MarshalCollection ¶
func MarshalCollection(c *Collection) ([]byte, error)
MarshalCollection returns the JSON-stat wire form of a collection.
func MarshalDataset ¶
MarshalDataset returns the JSON-stat wire form of a single dataset.
func MarshalDimension ¶
MarshalDimension returns the JSON-stat wire form of a standalone dimension response (class "dimension").
func MarshalDocument ¶
MarshalDocument marshals a Document to its JSON-stat wire form. It is the functional inverse of DecodeBytes.
func VersionInfo ¶
VersionInfo returns build metadata about the library and the JSON-stat format version it implements. It is intended for diagnostics, /version endpoints, and CLI banners.
Types ¶
type Builder ¶
type Builder struct {
// contains filtered or unexported fields
}
Builder is a fluent constructor for Dataset instances. It is the Go-native authoring counterpart of Decode: instead of parsing JSON-stat bytes, a caller assembles a cube dimension by dimension from Go data, then calls Builder.Build to materialise a ready-to-use Dataset.
The intended usage reads top-to-bottom:
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()
The values slice is interpreted in JSON-stat row-major order — the last declared dimension varies fastest — exactly as if it had been decoded from a dense "value" array. Use Builder.SparseValues for a sparse (object) value form; the resulting Dataset encodes back to the same form.
func NewBuilder ¶
func NewBuilder() *Builder
NewBuilder returns an empty Builder ready for Dim/Cat/Values/Status calls.
func (*Builder) Build ¶
Build materialises the configured cube into a Dataset. It validates that at least one dimension is declared, that every dimension has at least one category, that the value array (when dense) has the expected length, and that sparse value keys fit within the cube. On success the returned Dataset is fully reindexed and ready for traversal, transform, or encode.
The Builder is not mutated by Build and may be reused to build further cubes (each call produces a fresh Dataset).
func (*Builder) DenseValuesWithMissing ¶
DenseValuesWithMissing is like Builder.Values but accepts a parallel "missing" slice whose true entries mark absent observations (encoded as JSON null in dense form).
func (*Builder) Dim ¶
func (b *Builder) Dim(id, label string) *DimBuilder
Dim begins a new dimension declaration. Subsequent DimBuilder.Cat calls add categories; DimBuilder.End closes the dimension and returns the parent Builder.
func (*Builder) SparseValues ¶
SparseValues sets the dataset's value as a sparse JSON-stat object: only the supplied flat-index/value pairs are present, every other cell is considered missing. The resulting Dataset encodes back to the sparse form.
func (*Builder) StatusArray ¶
StatusArray sets a per-cell status in array form: one entry per cell in row-major order. Entries that are the empty string encode as missing in the resulting object form (see Builder.StatusMap).
func (*Builder) StatusMap ¶
StatusMap sets a per-flat-index status in object form: only the supplied flat-index/status pairs are present; every other cell has no status.
func (*Builder) UniformStatus ¶
UniformStatus sets a single status string that applies to every cell. This is the most compact status form and overrides any earlier status call.
func (*Builder) Updated ¶
Updated sets the dataset's last-updated timestamp. Stored verbatim; callers are responsible for ISO 8601 formatting.
func (*Builder) Values ¶
Values sets the dataset's value array as a dense JSON-stat array. The slice must have length equal to the product of every dimension's category count, in row-major order (last declared dimension varies fastest). Every cell is treated as present; to mark specific cells as missing (JSON null), use Builder.DenseValuesWithMissing.
type Category ¶
type Category struct {
// ID is the category's identifier string. It is unique within its
// dimension.
ID string
// Index is the 0-based position of this category within its dimension's
// category list. This corresponds to the value found in the dimension's
// category.index object (when present) and is used directly in the
// row-major flat-index calculation.
Index int
// Label is the human-readable name of this category (e.g. "Spain"). May
// be empty when the source document omitted category.label.
Label string
// Unit is the unit metadata for this category. Only metric-role
// categories typically carry a Unit; for other categories it is nil.
Unit *Unit
// Coordinates is the optional geographic coordinate pair attached to a
// category in a geo-role dimension. It has length 2: [longitude,
// latitude]. nil when not present.
Coordinates []float64
}
Category is one possible value of a Dimension. For example, in a "geo" dimension with size 2, the two categories might be "ES" and "FR".
Category identity is the Category.ID string (e.g. "ES"); Category.Index is its 0-based position in the dimension's category order, which together with the dataset strides pinpoints the cell positions holding its values.
type Cell ¶
type Cell struct {
// Value is the observation's numeric value. Always 0 when Missing is
// true.
Value float64
// Status is the observation-level status code. May be empty even when
// the value is present.
Status string
// Missing reports whether the cell has no value (JSON null in a dense
// array, or absent key in a sparse object).
Missing bool
// Flat is the row-major flat index of the cell within the dataset's
// value array. Always ≥ 0.
Flat int
// Coords is the per-dimension category index of the cell, in
// [Dataset.ID] order.
Coords []int
}
Cell is a single value-status pair read out of a dataset cube. It is the return type of the cell-access methods on Dataset.
A cell may be missing: dense value arrays encode missing observations as JSON null, and sparse value objects omit them. Missing cells have Value set to the zero float64 (0) and Missing set to true; callers should test Missing before reading Value.
type Collection ¶
type Collection struct {
// Label is the collection's human-readable title.
Label string
// Href is the collection's canonical URL.
Href string
// Updated is the collection's last-updated timestamp in ISO 8601 format.
Updated string
// Source is the collection's source attribution text.
Source string
// Note is the collection-level notes.
Note []string
// Link holds the collection's links. Items appear here with rel "item".
Link []Link
// Extension collects provider-specific extra fields.
Extension map[string]any
// Items is the parsed item list, in declaration order.
Items []Item
}
Collection is the in-memory representation of a JSON-stat collection response (class "collection"). A collection is an ordered list of Item values, each of which may embed or link to a dataset, dimension, or another collection.
func (*Collection) Datasets ¶
func (c *Collection) Datasets() []*Dataset
Datasets returns every embedded dataset in the collection, in declaration order. Items that only link (without embedding) are skipped.
func (*Collection) ItemByID ¶
func (c *Collection) ItemByID(id string) (*Item, error)
ItemByID returns the first item whose Item.ID matches id, or ErrItemNotFound when absent. ID equality is exact-string.
func (*Collection) ItemByIndex ¶
func (c *Collection) ItemByIndex(i int) (*Item, error)
ItemByIndex returns the i-th item, or ErrItemNotFound when out of range.
func (*Collection) ItemsByClass ¶
func (c *Collection) ItemsByClass(class string) []*Item
ItemsByClass returns the items whose embedded class matches the given JSON-stat class string (e.g. ClassDataset).
func (*Collection) MarshalJSON ¶
func (c *Collection) MarshalJSON() ([]byte, error)
MarshalJSON makes *Collection satisfy json.Marshaler.
type Content ¶
type Content string
Content controls whether categories are identified by label or by ID in the Transform output. Mirrors the JS Toolkit's opts.content.
type Coordinates ¶
Coordinates is the dimension-ID → category-ID map exposed to the UnflattenFunc callback for the current cell. It is freshly allocated per cell so the callback may retain references safely. Category IDs are always strings (e.g. the "year" dimension exposes {"year": "2012"}, not 2012).
type DataTable ¶
type DataTable struct {
Cols []DataTableCol `json:"cols"`
Rows []DataTableRow `json:"rows"`
}
DataTable is the Google DataTable {cols, rows} shape produced by Transform with the TransformObject type. See https://developers.google.com/chart/interactive/docs/reference#DataTable.
type DataTableCol ¶
type DataTableCol struct {
ID string `json:"id,omitempty"`
Type string `json:"type"`
Label string `json:"label,omitempty"`
}
DataTableCol is one column descriptor in a DataTable.
type DataTableRow ¶
DataTableRow is one row of a DataTable. Cells carry the value in `v` and an optional `f` (formatted) — here only `v` is populated, matching the JS Toolkit's behaviour.
type Datapoint ¶
Datapoint is the value/status pair exposed to the UnflattenFunc callback for the current cell. When the cell carries no status, Status is the empty string (matching the JS Toolkit, which exposes null but uses "" here to stay Go-friendly). When the cell is missing (JSON null in a dense value array, or absent key in a sparse object), Value is 0 and Missing is true.
type Dataset ¶
type Dataset struct {
// Class is always [ClassDataset] for a Dataset. Present so that a
// *Dataset satisfies the shared [Response] contract.
Class string
// Version is the JSON-stat version declared on the source document, or
// [FormatVersion] for documents built with the [Builder].
Version string
// Label is the dataset's human-readable title.
Label string
// Href is the dataset's canonical URL, if declared.
Href string
// Source is the dataset's source attribution text.
Source string
// Updated is the dataset's last-updated timestamp in ISO 8601 format.
// Stored as the raw string to avoid timezone pitfalls; callers that need
// a time.Time should parse it themselves.
Updated string
// ID is the ordered list of dimension IDs that define the cube's axes.
// The order matters: it determines row-major flat-index math.
ID []string
// Size is the number of categories per dimension, in the same order as
// ID.
Size []int
// Role maps declared roles (time, geo, metric) to the dimension IDs that
// carry them. May be empty.
Role map[Role][]string
// Dimensions holds each dimension by ID. Order is preserved from ID.
Dimensions map[string]*Dimension
// Note is the dataset-level notes array. Empty when absent.
Note []string
// Link is the dataset's related-resource links.
Link []Link
// Extension collects provider-specific extra fields attached to the
// dataset itself. Anything that does not map onto a typed field ends up
// here.
Extension map[string]any
// contains filtered or unexported fields
}
Dataset is the in-memory representation of a JSON-stat dataset response (class "dataset"). It is the primary type of this package: every read, traverse, subset, transform, and serve operation is a function over a *Dataset.
Dataset normalises the polymorphic parts of the wire format:
- The "value" property can be a dense JSON array (with nulls) or a sparse JSON object; both are represented as a [valueStore] with a uniform float64 slice and a "missing" set.
- The "status" property can be a string, an array, or an object; it is represented as a [statusStore] that resolves the effective status per cell.
On encode, Dataset re-emits the same form it was decoded from (or the form chosen by the Builder), preserving round-trip fidelity on canonical input.
func (*Dataset) CellByCoord ¶
CellByCoord returns the Cell at the coordinates described by one category index per dimension, in Dataset.ID order. The number of coordinates must match Dataset.DimCount, and each must be in range for its dimension.
In the JS Toolkit this corresponds to `Dataset.Data([0,0,0])` with an array of integer category indices.
func (*Dataset) CellByFlat ¶
CellByFlat returns the Cell at the given flat row-major index. The index must satisfy 0 ≤ i < Dataset.N. Out-of-range indices return a ValueError wrapping ErrIndexOutOfRange.
In the JS Toolkit this corresponds to `Dataset.Data(i)` with a single integer argument.
func (*Dataset) CellByLabel ¶
CellByLabel resolves a cell from a map of dimension ID → category ID. The map must contain exactly one entry per dimension (use the empty string as a category ID for single-category dimensions when the source omitted the category.index). Unknown dimension or category IDs return the corresponding sentinel wrapped in a ValueError.
In the JS Toolkit this corresponds to `Dataset.Data({TIME:2020, GEO:"ES"})`.
func (*Dataset) Cells ¶
Cells returns a lazy iterator over every cell of the cube, in row-major order. It is the Go 1.23 range-over-func counterpart of the JS Toolkit's `Dataset.Data()` (called with no arguments).
Usage:
for cell, err := range ds.Cells() {
if err != nil { return err }
_ = cell
}
The iterator yields exactly Dataset.N cells before stopping. Missing cells (JSON null in a dense array, or absent keys in a sparse object) are yielded with Cell.Missing set to true; they are not errors. The error return is reserved for malformed datasets whose strides cannot be computed — which, by the time a Dataset has been decoded or built, should not occur.
The yielded Cell.Coords slice is freshly allocated per yield; callers may retain references to past cells without copying. The iterator does not allocate any large per-cell slice.
func (*Dataset) CellsSlice ¶
CellsSlice materialises the full cube as a slice of cells. It is the non-iterator fallback for callers on older Go or for code that needs random post-iteration access. Equivalent to collecting Dataset.Cells.
func (*Dataset) Dice ¶
func (d *Dataset) Dice(f Filter, opts ...DiceOption) (*Dataset, error)
Dice subsets the cube, keeping (or, with WithDropFilter, removing) the categories named by f. It is the single subsetting operation in jsonstat-go: there is no Slice. Dice never removes dimensions from the cube — only categories. A dimension not mentioned in f is left untouched.
Dice returns a new Dataset whose dimensions carry the retained categories in their original order, whose Size reflects the new category counts, and whose value/status stores are reindexed to match. The receiver is not mutated.
An empty filter (or nil) returns a deep clone of the dataset. A filter that removes every category of some dimension produces a dataset with N()==0.
func (*Dataset) Dimension ¶
Dimension returns the dimension with the given ID, or ErrDimensionNotFound when no such dimension exists.
func (*Dataset) DimensionByIndex ¶
DimensionByIndex returns the dimension at position i in Dataset.ID. Returns ErrIndexOutOfRange when i is out of range.
func (*Dataset) DimensionByRole ¶
DimensionByRole returns the first dimension assigned the given role, or ErrDimensionNotFound when no dimension carries that role. For the (rare) case of multiple dimensions sharing a role, use Dataset.DimensionsByRole.
func (*Dataset) DimensionIDs ¶
DimensionIDs returns a defensive copy of Dataset.ID.
func (*Dataset) DimensionPosition ¶
DimensionPosition returns the index in Dataset.ID of the given dimension ID, or ErrDimensionNotFound when absent.
func (*Dataset) DimensionsByRole ¶
DimensionsByRole returns every dimension assigned the given role, in the order they appear in Dataset.ID.
func (*Dataset) MarshalJSON ¶
MarshalJSON makes *Dataset satisfy json.Marshaler so it can be embedded in other JSON structures or marshalled directly.
func (*Dataset) N ¶
N returns the total number of cells in the cube (the product of Size), including missing ones. This is the Go counterpart of the JS Toolkit's `n` property. Returns 0 if the dataset has no dimensions or any dimension has size 0.
func (*Dataset) SizeSlice ¶
SizeSlice returns a defensive copy of Dataset.Size.
func (*Dataset) StatusFormat ¶
StatusFormat reports which wire form the dataset's status store would emit on encode.
func (*Dataset) Strides ¶
Strides returns the cached strides for this dataset. The returned slice is a defensive copy; callers may mutate it. Returns nil before [reindex] is called (which Decode and Builder do automatically).
func (*Dataset) Transform ¶
func (d *Dataset) Transform(opts ...TransformOption) (any, error)
Transform converts the dataset to tabular form. It is the Go counterpart of the JS Toolkit's `Dataset.Transform(opts)`, built on top of Dataset.Unflatten and using the same options vocabulary. It returns one of:
- `[][]any` for TransformArray (header row + data rows)
- `[]map[string]any` for TransformArrObj (one object per cell)
- `map[string][]any` for TransformObjArr (columnar)
- `*DataTable` for TransformObject (Google DataTable)
When WithMeta is true the array/objarr shapes are wrapped in *TableWithMeta carrying the dataset metadata block, matching the JS Toolkit's `{meta, data}` shape. The object type never emits metadata.
An empty (nil) dataset returns (nil, nil).
func (*Dataset) Unflatten ¶
func (d *Dataset) Unflatten(fn UnflattenFunc) ([]any, error)
Unflatten walks every cell of the cube, invoking fn for each, and returns the slice of non-nil results. It is the Go counterpart of the JS Toolkit's `Dataset.Unflatten(cb)`.
fn returns any → appended to the result; nil → cell dropped.
An empty (nil) dataset or a nil callback returns (nil, nil).
Usage (mirrors the JS example that returns {coordinates, datapoint}):
out, err := ds.Unflatten(func(coords jsonstat.Coordinates, dp jsonstat.Datapoint, n int, row []any) any {
return map[string]any{"coordinates": coords, "datapoint": dp}
})
func (*Dataset) ValueFormat ¶
ValueFormat reports which wire form the dataset's value store would emit on encode. See [valueStore].
func (*Dataset) Walk ¶
Walk calls fn for every cell in the cube in row-major order, stopping at the first non-nil error returned by fn. It is the Go counterpart of the JS Toolkit's `Dataset.Unflatten(cb)`.
Walk allocates one Cell per cell of the cube (reused via the same path as Dataset.Cells); fn receives a value copy so it may retain cells safely.
type DiceOption ¶
type DiceOption func(*diceConfig)
DiceOption configures a Dataset.Dice operation.
func WithClone ¶
func WithClone(b bool) DiceOption
WithClone controls whether Dice returns a deep copy of the receiver or is permitted to mutate it in place. The default is true (clone); passing false is an opt-in optimisation for callers that will not use the receiver again.
func WithDropFilter ¶
func WithDropFilter(b bool) DiceOption
WithDropFilter inverts the meaning of the Filter passed to Dataset.Dice: listed categories are removed rather than retained. Dimensions absent from the filter are still left untouched.
type DimBuilder ¶
type DimBuilder struct {
// contains filtered or unexported fields
}
DimBuilder accumulates categories (and optional role/label) for a single dimension. It is returned by Builder.Dim and closed by DimBuilder.End, which returns control to the parent Builder.
func (*DimBuilder) Cat ¶
func (d *DimBuilder) Cat(id, label string) *DimBuilder
Cat appends a category to the current dimension. An empty label is allowed (the category will render under its ID).
func (*DimBuilder) CatWith ¶
func (d *DimBuilder) CatWith(c catSpec) *DimBuilder
CatWith attaches a builder-configured category (with optional unit or coordinates) to the current dimension. It is the entry point for the richer per-category metadata the simple DimBuilder.Cat does not expose.
func (*DimBuilder) Coordinates ¶
func (d *DimBuilder) Coordinates(lon, lat float64) *DimBuilder
Coordinates attaches a [lon, lat] pair to the most recently added category. Meaningful only for geo-role dimensions.
func (*DimBuilder) End ¶
func (d *DimBuilder) End() *Builder
End closes the current dimension and returns the parent Builder.
func (*DimBuilder) Role ¶
func (d *DimBuilder) Role(r Role) *DimBuilder
Role declares the JSON-stat role carried by this dimension (time, geo, or metric). Multiple dimensions may share a role.
func (*DimBuilder) Unit ¶
func (d *DimBuilder) Unit(u *Unit) *DimBuilder
Unit attaches a Unit to the most recently added category of this dimension. Metric dimensions typically carry a unit on each category.
type Dimension ¶
type Dimension struct {
// ID is the dimension's identifier, matching one entry of [Dataset.ID].
ID string
// Label is the human-readable name of the dimension (e.g. "Geography").
Label string
// Role is the special role assigned to this dimension by the dataset's
// "role" object, or [RoleUnknown] (the empty string) when no role is set.
Role Role
// Size is the number of categories in this dimension. It equals
// [Dataset.Size][i] for the dimension's position i in [Dataset.ID].
Size int
// Categories lists this dimension's categories in index order. The slice
// has length Size.
Categories []Category
// Child captures the category.child hierarchy: parent category ID → list
// of child category IDs. nil when the dimension has no hierarchy. See
// https://json-stat.org/format/#child.
Child map[string][]string
// Href is the URL of the standalone "dimension" response for this
// dimension, if the source document provided one.
Href string
// Link is the list of related resources for this dimension (e.g.
// "alternate" geographic breakdowns). Empty when absent.
Link []Link
// Note is the dimension-level notes. Empty when absent.
Note []string
// Extension collects provider-specific extra fields attached to this
// dimension.
Extension map[string]any
// contains filtered or unexported fields
}
Dimension describes one axis of a dataset's cube. JSON-stat stores dimensions under the dataset's "dimension" object keyed by dimension ID; the order in the dataset's "id" array defines the cube's axis order and determines stride math.
jsonstat-go attaches a few precomputed conveniences to Dimension (Size, Categories, and the lookup maps) so that traversal methods do not have to re-walk the JSON-stat structure on every call.
func (*Dimension) CategoryByID ¶
CategoryByID returns the category with the given ID, or ErrCategoryNotFound if no such category exists in this dimension.
func (*Dimension) CategoryIDs ¶
CategoryIDs returns the ID of every category in index order.
func (*Dimension) CategoryIndex ¶
CategoryIndex returns the 0-based position of the category with the given ID within this dimension, or ErrCategoryNotFound if it is absent.
func (*Dimension) CategoryLabels ¶
CategoryLabels returns the human-readable label of every category in index order. Categories without a label are represented by their ID. This is the Go counterpart of the JS Toolkit's `Dimension(id, true)` boolean flag.
func (*Dimension) ChildrenOf ¶
ChildrenOf returns the child category IDs of the given parent category ID, or false if the parent has no children (or the dimension has no hierarchy). The returned slice is a defensive copy; callers may mutate it freely.
func (*Dimension) HasHierarchy ¶
HasHierarchy reports whether the dimension declares a category.child hierarchy.
func (*Dimension) MarshalJSON ¶
MarshalJSON makes *Dimension satisfy json.Marshaler for the standalone dimension response class.
type Document ¶
type Document struct {
// Class is the JSON-stat response class declared on the document. It is
// one of [ClassDataset], [ClassCollection], [ClassDimension], or
// [ClassBundle] (the legacy pre-2.0 marker, synthesised by Decode).
Class string
// Version is the JSON-stat version declared on the document.
Version string
// Label is the document-level label, if any.
Label string
// Href is the document-level canonical URL, if any.
Href string
// Note is the document-level notes array.
Note []string
// Link is the document-level related-resource links.
Link []Link
// Extension collects provider-specific extra fields attached to the
// document itself.
Extension map[string]any
// Dataset holds the parsed dataset when Class == [ClassDataset]. It is
// nil otherwise.
Dataset *Dataset
// Collection holds the parsed collection when Class == [ClassCollection].
Collection *Collection
// Dimension holds the parsed standalone dimension when Class ==
// [ClassDimension]. It is nil otherwise.
Dimension *Dimension
// Bundle holds the parsed datasets when the document is a pre-2.0 bundle
// (a JSON object whose values are datasets, with no "class" property).
// Keyed by dataset id. nil for 2.0 documents.
Bundle map[string]*Dataset
// IsBundle reports whether the document was decoded as a pre-2.0 bundle.
IsBundle bool
}
Document is the top-level parsed value of a JSON-stat response. Depending on the source document's "class", exactly one of the fields below is populated:
- class "dataset": Document.Dataset holds the single dataset. (Some 2.0 documents omit "class" entirely; Decode treats these as datasets when they have the required dataset properties.)
- class "collection": Document.Collection holds the collection.
- class "dimension": Document.Dimension holds the standalone dimension.
The pre-2.0 bundle container is also accepted: Document.Bundle is a map of datasets keyed by id, and Document.IsBundle reports this case. Bundles are decoded for backward compatibility but never re-emitted by Encode.
func Decode ¶
Decode parses a JSON-stat 2.0 document from r and returns the corresponding Document. Decode accepts all three 2.0 response classes (dataset, collection, dimension) and tolerates the pre-2.0 bundle container: when the input has no "class" property but its top-level values look like datasets, Document.IsBundle is set and Document.Bundle is populated.
Decode normalises the polymorphic parts of the format:
- dense (array) and sparse (object) "value" forms are both supported and exposed uniformly via the traversal methods.
- the three "status" forms (string, array, object) are supported.
The document's structural shape is checked; semantic checks (size/value length agreement, role references, etc.) are performed by Validate.
func DecodeBytes ¶
DecodeBytes is like Decode but accepts a byte slice.
func Fetch ¶
Fetch loads a JSON-stat document from url via HTTP and decodes it. It is the context-aware counterpart of Decode for remote sources. The supplied context.Context governs the entire request lifecycle, including connection setup and body reads; cancelling it aborts the call.
By default Fetch uses a fresh http.Client with a 30-second timeout. A shared client (connection pooling, custom transport, mTLS, etc.) can be supplied via WithHTTPClient.
fetchCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
doc, err := jsonstat.Fetch(fetchCtx, url,
jsonstat.WithUserAgent("my-app/1.0"),
jsonstat.WithMaxBytes(50*1024*1024), // 50 MiB guard
)
func (*Document) Datasets ¶
Datasets returns every dataset in the document, regardless of class:
- dataset: a one-element slice holding Document.Dataset.
- collection: a slice holding each embedded dataset.
- bundle: a slice holding each bundled dataset, in id-key order.
- otherwise: nil.
func (*Document) IsCollection ¶
IsCollection reports whether the document is a collection response.
func (*Document) IsDimension ¶
IsDimension reports whether the document is a standalone dimension response.
func (*Document) MarshalJSON ¶
MarshalJSON makes *Document satisfy json.Marshaler, dispatching on the populated response-class field.
func (*Document) SingleDataset ¶
SingleDataset is a convenience for the common case of a single-dataset document. It returns Document.Dataset when present, or ErrDatasetNotFound otherwise.
type FetchOption ¶
type FetchOption func(*fetchConfig)
FetchOption configures a Fetch call.
func WithBody ¶
func WithBody(r io.Reader) FetchOption
WithBody supplies a request body for non-GET methods. It is the caller's responsibility to also set an appropriate Content-Type via WithHeader.
func WithHTTPClient ¶
func WithHTTPClient(c *http.Client) FetchOption
WithHTTPClient supplies the http.Client used by Fetch. When not set, Fetch uses a per-call client with a 30-second timeout (overridable via the request context.Context).
func WithHeader ¶
func WithHeader(key, value string) FetchOption
WithHeader sets or overrides a single request header on the outgoing GET. Calling it multiple times with different keys accumulates; calling it twice with the same key replaces the value. "Host" cannot be set this way.
func WithMaxBytes ¶
func WithMaxBytes(n int64) FetchOption
WithMaxBytes caps the number of bytes Fetch will read from the response body. A response whose body exceeds the cap is aborted with ErrResponseTooLarge. A value of 0 (the default) means unlimited.
func WithMethod ¶
func WithMethod(m string) FetchOption
WithMethod overrides the HTTP method used by Fetch. The default is GET. When set to "POST", WithBody should be supplied as well.
func WithUserAgent ¶
func WithUserAgent(ua string) FetchOption
WithUserAgent sets the User-Agent header on the outgoing request. This is a shortcut for WithHeader("User-Agent", …) but also records the value for use when no headers are otherwise set.
type Field ¶
type Field string
Field controls whether the dimension, value and status column keys are IDs or labels. Mirrors the JS Toolkit's opts.field. The default is FieldID, except for the "array" type whose default is FieldLabel (matching JS).
type Filter ¶
Filter selects the categories of a Dataset to keep (or, when WithDropFilter is set, to exclude) during a Dataset.Dice operation. The map is keyed by dimension ID; each value is the list of category IDs in that dimension to retain (or drop).
A dimension absent from the map is left untouched (all of its categories are kept). Category IDs that do not exist in their dimension cause Dice to return ErrCategoryNotFound. Duplicate IDs and ordering are ignored: the resulting dimension always preserves the original category order of the source.
type Item ¶
type Item struct {
// Href is the URL of the item, when it is referenced rather than
// embedded.
Href string
// Type is the MIME type of the item at Href.
Type string
// Label is the human-readable item title.
Label string
// Class is the embedded item's class (e.g. "dataset"), when the item is
// embedded rather than only linked.
Class string
// ID is the optional item identifier inside the collection. Some
// providers add an "id" extension to disambiguate items.
ID string
// Extension collects provider-specific extra fields attached to the
// item's link entry.
Extension map[string]any
// EmbeddedDataset is non-nil when the item embeds a full dataset.
EmbeddedDataset *Dataset
// EmbeddedDimension is non-nil when the item embeds a standalone
// dimension.
EmbeddedDimension *Dimension
}
Item is one entry in a JSON-stat collection. JSON-stat's collection class uses a "link" array with rel "item" to enumerate its contents; each item may embed a full dataset, dimension, or another collection, or merely link to one via Href.
func (*Item) IsEmbedded ¶
IsEmbedded reports whether the item carries an embedded response rather than only a link.
type Link ¶
type Link struct {
// Href is the target URL of the link.
Href string `json:"href,omitempty"`
// Type is the MIME type of the resource at Href. For example
// "application/json-stat".
Type string `json:"type,omitempty"`
// Rel is the IANA link relation type. Common values in JSON-stat include
// "self", "item", "alternate", "version", and "note".
Rel string `json:"rel,omitempty"`
// Label is a human-readable description of the link target.
Label string `json:"label,omitempty"`
// Extension carries provider-specific extra fields. JSON-stat allows
// arbitrary keys inside link objects beyond href/type/rel/label; they are
// collected here.
Extension map[string]any `json:"-"`
}
Link represents a single entry in a JSON-stat "link" array. Links describe related resources via the IANA link relation type ("rel") and a target URL ("href"). They are used at every level of a JSON-stat document: the document itself, individual datasets, dimensions, and categories.
The collection response class uses links with rel "item" to enumerate its contents; the dimension response class uses links with rel "self" and "related" (e.g. alternate geographic breakdowns).
type Role ¶
type Role string
Role names a special meaning assigned to a dimension via the dataset's "role" object. JSON-stat 2.0 defines exactly three roles: time, geo, and metric. See https://json-stat.org/format/#role.
const ( // RoleTime identifies a dimension whose categories are points or periods // in time (e.g. "2020", "2021-Q1"). RoleTime Role = "time" // RoleGeo identifies a spatial dimension whose categories are places // (e.g. country codes, NUTS regions). RoleGeo Role = "geo" // RoleMetric identifies a dimension whose categories name the quantity // being measured (e.g. "POP", "GDP"). Metric categories typically carry // [Unit] metadata via [Category.Unit]. RoleMetric Role = "metric" )
type TableDimCategories ¶
TableDimCategories holds the parallel category ID/label arrays.
type TableDimMeta ¶
type TableDimMeta struct {
Label string `json:"label"`
Role string `json:"role,omitempty"`
Categories TableDimCategories `json:"categories"`
}
TableDimMeta is the per-dimension metadata attached under TableMeta.
type TableMeta ¶
type TableMeta struct {
Type string `json:"type"`
Label string `json:"label,omitempty"`
Source string `json:"source,omitempty"`
Updated string `json:"updated,omitempty"`
ID []string `json:"id"`
Status bool `json:"status"`
By string `json:"by,omitempty"`
Drop []string `json:"drop,omitempty"`
Prefix string `json:"prefix,omitempty"`
Comma bool `json:"comma"`
Dimensions map[string]TableDimMeta `json:"dimensions,omitempty"`
}
TableMeta is the metadata block attached by WithMeta. Only the fields the JS Toolkit includes are populated; provider-specific extension is left to callers via the Dataset.Extension map (not auto-copied here).
type TableWithMeta ¶
TableWithMeta wraps a Transform result with the dataset metadata block, emitted when WithMeta is true. It mirrors the JS Toolkit's {meta, data} shape exactly so that JSON serialisation is byte-compatible.
type TransformOption ¶
type TransformOption func(*transformConfig)
TransformOption configures Dataset.Transform. The functional-options pattern keeps the call sites self-documenting.
func WithBy ¶
func WithBy(dimID string) TransformOption
WithBy pivots the value column on the given dimension (one output column per category of that dimension). Only supported by the arrobj and objarr types (silently ignored for the array and object types, matching JS). When `by` names a non-existent dimension, it is ignored.
func WithComma ¶
func WithComma(b bool) TransformOption
WithComma formats numbers as strings with a comma decimal mark. Default false. Not available with the object type.
func WithContent ¶
func WithContent(ct Content) TransformOption
WithContent controls whether categories are identified by label or by ID. Default ContentLabel.
func WithDrop ¶
func WithDrop(dimIDs ...string) TransformOption
WithDrop excludes the listed dimension IDs from the output. Invalid dimension IDs and multi-category dimensions are ignored (single-category dimensions are the only ones droppable, matching the JS rule).
func WithField ¶
func WithField(f Field) TransformOption
WithField controls whether dimension, value and status keys are IDs or labels. Default FieldID (the array type overrides this to FieldLabel).
func WithMeta ¶
func WithMeta(b bool) TransformOption
WithMeta attaches dataset metadata to the output, wrapping it as *TableWithMeta. Default false. Not available with the object type.
func WithPrefix ¶
func WithPrefix(s string) TransformOption
WithPrefix sets a prefix prepended to the pivoted category columns when WithBy is in effect. Default "".
func WithStatus ¶
func WithStatus(b bool) TransformOption
WithStatus includes the status column in the output. Default false. Ignored when WithBy is also set (matching JS behaviour).
func WithStatusLabel ¶
func WithStatusLabel(s string) TransformOption
WithStatusLabel sets the label of the status column. Default "Status". Only relevant when WithStatus is true.
func WithTransformType ¶
func WithTransformType(t TransformType) TransformOption
WithTransformType sets the output shape. Default TransformArray.
func WithValueLabel ¶
func WithValueLabel(s string) TransformOption
WithValueLabel sets the label of the value column. Default "Value".
type TransformType ¶
type TransformType string
TransformType selects the output shape of Dataset.Transform. It mirrors the JS Toolkit's opts.type string values.
const ( // TransformArray is the default type: an array of arrays whose first // element is a header row. Mirrors JS type "array". TransformArray TransformType = "array" // TransformArrObj produces an array of per-cell objects keyed by dimension // ID, "value" and "status". Mirrors JS type "arrobj". Supports the `by` // (pivot) and `meta` options. TransformArrObj TransformType = "arrobj" // TransformObjArr produces a columnar object: each property is a parallel // array. Mirrors JS type "objarr". Supports the `by` (pivot) and `meta` // options. TransformObjArr TransformType = "objarr" // TransformObject produces a Google DataTable {cols, rows}. Mirrors JS // type "object". Infers column type ("number" or "string") from the first // value. TransformObject TransformType = "object" )
type UnflattenFunc ¶
type UnflattenFunc func(coords Coordinates, dp Datapoint, n int, row []any) any
UnflattenFunc mirrors the JS Toolkit's Unflatten callback. It is invoked once per cell in row-major order. The arguments are:
- coords: the Coordinates of the cell (dimension ID → category ID).
- dp: the cell's value/status pair (Datapoint).
- n: the 0-based cell counter (the flat row-major index).
- row: the accumulator slice being built; the value returned by the callback is appended to it after the callback returns.
Returning nil skips the cell (it is not appended), matching the JS Toolkit's treatment of a callback that returns undefined.
type Unit ¶
type Unit struct {
// Decimals is the recommended number of decimal places to display. It is
// required by the spec whenever a unit object is present, but jsonstat-go
// does not enforce that on the type itself — that is a validation rule,
// see [Validate].
Decimals int `json:"decimals,omitempty"`
// Label is a human-readable unit label (e.g. "persons", "euros"). It is
// typically appended after the value.
Label string `json:"label,omitempty"`
// Symbol is a unit symbol (e.g. "$", "%", "€"). When both Label and
// Symbol are present, JSON-stat providers conventionally use Symbol for
// compact display and Label for accessibility.
Symbol string `json:"symbol,omitempty"`
// Position governs where the symbol is placed relative to the value.
// "end" (the default) renders "5%"; "start" renders "$5".
Position string `json:"position,omitempty"`
}
Unit describes the unit of measure attached to a metric category. It is the Go representation of the "unit" object inside dimension.<id>.category.unit.<catid>. See https://json-stat.org/format/#unit.
JSON-stat requires decimals whenever unit is present. The other fields are optional.
type ValidationCode ¶
type ValidationCode string
ValidationCode is a stable identifier for a single class of validation problem. Codes are kebab-case strings, kept short so they fit on one line of structured-log output. Callers may switch on them to drive user-facing messages or selective ignoring.
const ( // CodeMissingClass: the document has no "class" property and is not a // tolerated pre-2.0 bundle. CodeMissingClass ValidationCode = "missing-class" // CodeUnknownClass: the document's "class" is not one of dataset, // collection, or dimension. CodeUnknownClass ValidationCode = "unknown-class" // CodeMissingRequired: a JSON-stat 2.0 required property is absent. CodeMissingRequired ValidationCode = "missing-required" // CodeIDSizeMismatch: len(id) != len(size). CodeIDSizeMismatch ValidationCode = "id-size-mismatch" // CodeDimMissing: a dimension named in id is absent from dimension. CodeDimMissing ValidationCode = "dim-missing" // CodeDimExtra: the dimension object has a key not present in id. CodeDimExtra ValidationCode = "dim-extra" // CodeCategorySizeMismatch: a dimension's category count != its size. CodeCategorySizeMismatch ValidationCode = "category-size-mismatch" // CodeInvalidSize: size contains a negative element or is otherwise // malformed. CodeInvalidSize ValidationCode = "invalid-size" // CodeValueLengthMismatch: dense value array length != prod(size). CodeValueLengthMismatch ValidationCode = "value-length-mismatch" // CodeSparseValueKeyOutOfRange: a sparse value object has a key ≥ prod(size). CodeSparseValueKeyOutOfRange ValidationCode = "sparse-value-key-out-of-range" // CodeStatusLengthMismatch: status array length != prod(size). CodeStatusLengthMismatch ValidationCode = "status-length-mismatch" // CodeRoleReferencesUnknownDim: role names a dimension not in id. CodeRoleReferencesUnknownDim ValidationCode = "role-unknown-dim" // CodeDuplicateCategoryID: a dimension has two categories with the same ID. CodeDuplicateCategoryID ValidationCode = "duplicate-category-id" // CodeDuplicateDimID: id contains the same dimension ID twice. CodeDuplicateDimID ValidationCode = "duplicate-dim-id" )
Stable validation codes. The set is intentionally small: each identifies a single invariant, regardless of which tier (structural or semantic) it belongs to. Tests and downstream tooling can rely on these strings not changing across releases.
type ValidationError ¶
type ValidationError struct {
// Code is the stable identifier (see the Code* constants).
Code ValidationCode
// Path locates the problem using dotted-path notation, e.g.
// "dimension.geo.category.index" or "value[3]". The empty string means
// "the document as a whole".
Path string
// Message is a human-readable description.
Message string
// Err is the underlying sentinel error (one of the Err* package-level
// values), suitable for errors.Is.
Err error
}
ValidationError describes a single validation problem on a Document or Dataset. A slice of ValidationError is returned by Validate; the slice is empty when the input is valid.
func Validate ¶
func Validate(doc *Document) []ValidationError
Validate runs the structural and semantic tiers over doc and returns every problem found, in path order. An empty (nil) slice means the document is valid. Problems are never silently dropped: a single missing property can produce several cascading errors, and Validate surfaces all of them so callers can show a complete report.
Validate never panics. A nil document yields a single CodeMissingClass error.
func ValidateDataset ¶
func ValidateDataset(ds *Dataset, prefix string) []ValidationError
ValidateDataset runs the structural and semantic tiers over a single Dataset. The optional prefix is prepended to every reported Path so bundle/collection members can be distinguished.
func (*ValidationError) Error ¶
func (v *ValidationError) Error() string
Error implements error. Validation errors are usually collected into a slice, but a single ValidationError is itself a valid error so it can be returned from one-shot helpers.
func (*ValidationError) HasSeverity ¶
func (v *ValidationError) HasSeverity() string
HasSeverity reports whether the validation error is fatal (a dataset with any fatal error cannot be safely traversed or encoded). The current rule treats every code as fatal except CodeDimExtra, which is a permissive warning about extra keys in the dimension object.
func (*ValidationError) Unwrap ¶
func (v *ValidationError) Unwrap() error
Unwrap exposes the wrapped sentinel for errors.Is / errors.As.
type ValueError ¶
type ValueError struct {
// Op is the operation that failed (e.g. "Decode", "Dataset.Dimension").
Op string
// Dim is the dimension ID involved, if any.
Dim string
// Cat is the category ID involved, if any.
Cat string
// Flat is the flat row-major cell index involved, if any. -1 means
// "not applicable".
Flat int
// Err is the wrapped sentinel or underlying error.
Err error
}
ValueError carries context about where in the cube an error occurred. It is the structured wrapping type used by Decode, Validate, and the traversal methods. Callers can use errors.As to recover the structured context.
func (*ValueError) Unwrap ¶
func (v *ValueError) Unwrap() error
Unwrap allows errors.Is / errors.As to reach the wrapped sentinel.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
jsonstat
command
Command jsonstat is a thin command-line shell over the github.com/jsonstat/go library.
|
Command jsonstat is a thin command-line shell over the github.com/jsonstat/go library. |
|
examples
|
|
|
basic-read
command
Command basic-read shows the simplest end-to-end client flow:
|
Command basic-read shows the simplest end-to-end client flow: |
|
build-cube
command
Command build-cube constructs a small 3-dimensional JSON-stat dataset programmatically with the Builder, then writes the canonical JSON-stat wire form to stdout.
|
Command build-cube constructs a small 3-dimensional JSON-stat dataset programmatically with the Builder, then writes the canonical JSON-stat wire form to stdout. |
|
serve-http
command
Command serve-http builds a small cube in-memory and serves it over HTTP via the jsonstathttp handler.
|
Command serve-http builds a small cube in-memory and serves it over HTTP via the jsonstathttp handler. |
|
internal
|
|
|
stride
Package stride implements the row-major ("what does not change, first") index math used by JSON-stat cubes.
|
Package stride implements the row-major ("what does not change, first") index math used by JSON-stat cubes. |
|
Package 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.
|
Package 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. |