tessera 0.2.2
tessera: ^0.2.2 copied to clipboard
Analyze, group and aggregate tabular data: a pivot-table engine with expandable row/column hierarchies. Pure Dart; tessera_flutter adds the widgets.
0.2.2 #
ExportTable: a plain table — not a cube — for the new table exporters:ExportColumns (header, sourcename,type,numberFormat,width;showsTimedecides date vs. date-time by the type) and rows of values.ExportTable.ofFacts(facts, columns:, rows:, filter:, useLabels:)reads a fact table lazily (e.g. the facts behind a cell, or those passing the cube's filter);withColumnadjusts one column.TableExportThemeis the format-neutral look (header fill and font, data font, borders) thattessera_xlsx'sXlsxTableExporterandtessera_ods'sOdsTableExportertake.CsvTableExporter: anExportTableas CSV — header row, numbers plainly with the options' decimal mark, days asyyyy-MM-dd, points in time as ISO 8601 — so a fact table survives a CSV round trip with its types.CsvExportOptions.fieldquotes one field (what both CSV exporters use).JsonFactExporter:records,export,exportLinesandwriteLinestakerows:andfilter:likeExportTable.ofFacts.Schema.structureKey: a canonical key for the structure of a source (the JSON list of its column names, in order), so that applications can remember schema edits or layouts per structure and apply them to the next file of the same shape. Built from names only on purpose: inferred types vary with the sampled rows.TesseraSnapshot.mimeType(application/vnd.tessera.snapshot) andTesseraSnapshot.fileExtension(tsnp): the official media type and extension of snapshots, so that servers, file dialogs and file associations all declare the same value. Documented indocs/snapshot.md.
0.2.1 #
JsonDataSource(a JSON array of objects, parsed whole) andJsonlDataSource(JSON Lines, streamed with a row estimate), withJsonOptions: nested objects flattened into dotted columns (or kept as JSON text), arrays as JSON text,columnsto name the columns,scanAllRowsto union every record's keys. Values keep their JSON types; strings go through the schema's parsers like CSV cells.JsonFactExporter: aFactTableas records — one object per fact with a field per column (columnsto pick,useLabelsfor label keys) — as a JSON array (export, optionally indented) or JSON Lines (exportLines,writeLinesstreams row by row;recordsis lazy). Integers stay integers, dates become ISO text, soJsonlDataSourcereads the table back with its types.- The default date formats also recognize the full ISO 8601 forms JSON
producers write:
yyyy-MM-ddTHH:mm:ss.SSS, with or without a trailingZ. JsonCubeExporter: a layout as records — one object per grid row, the row dimensions as fields named after their titles, one field per column entry and aggregate named from the labels — as a JSON array (export, optionally indented) or JSON Lines (exportLines,writeLines);recordsgives the objects.JsonExportOptions: group labels repeated (default) or once per group, the path separator, the indent.- Chart series:
ChartData(categories × series of doubles) andScatterData((x, y) points in series) for feeding any chart library.fromLayoutreads a layout's cells as displayed (ChartEntriesselects the entries: visible leaves by default, one level, given paths, or all),fromFactsbuilds a one- or two-dimensional cube for the purpose,fromCelldrills into the facts behind one cell by another dimension,ScatterData.ofFactsplots individual facts (two measures, optional series dimension, row set and limit). Categories carry the raw dimension value (DateTime,int,double…) andperiodStartcomposes nested date parts for a time axis;withoutEmpty(),transposed().Coordinate.toFilter()andcellFilter(layout, cell)give the filter behind a cell. - Continuous integration: a GitHub Actions workflow
(
.github/workflows/ci.ymlat the repository root) runs the analyzer, the format check and every package's tests on each push and pull request, with LibreOffice, poppler, qpdf, ghostscript, librsvg and Noto Sans installed so the exporter round-trip tests run rather than skip.
0.2.0 #
The expression language and everything built on it. One breaking change.
Breaking #
Measureis sealed:Measure('total')still constructs aColumnMeasure, butMeasure.columnmoved toColumnMeasure; every measure hasid,label,explicitLabel,labelForandcolumns.DimensiongainedsourceColumns.AxisSidenow lives in the engine (tessera_flutterre-exports it, so no import change there).
Expression language #
Expression(parse,check,validate,compile),ExpressionScope(row or cell scope over aFactTableorSchema),ExpressionError(kind, source range, arguments),ExprType,FunctionRegistry/ExpressionFunction(built-in functions plus application ones), theExprsyntax tree withtoSource. SQL/Excel-flavoured syntax (and,or,not,=,<>,in,between,is empty,if(),#2024-01-31#dates,[quoted names]), static typing, SQL three-valued null handling, day arithmetic on dates, compiled to closures over the typed column arrays.TesseraStrings.expressionErrorgives the message in every locale.- Plug points:
ExpressionFilter;Measure.expression(ExpressionMeasure, materialized once per fact table);ExpressionDimension;Aggregate.expression(ExpressionAggregate, a cell formula oversum(x),avg(x),count,count(x),min,max,stdev,stdevp,var,varpanddistinct(x), wherexis a column or any row expression —sum(qty * price) / sum(qty)), and theDerivedAggregatebase for aggregates computed from other aggregates' results.
Aggregates #
- Statistical:
Aggregate.stdDev/stdDevPopulation/variance/variancePopulation(Excel's STDEV.S / STDEV.P / VAR.S / VAR.P), one Welford accumulator merged with Chan's formula so parents are exact and large means do not cancel. - Layout-relative ("Show Values As"):
Aggregate.percentOf(TotalOf.row/column/grand/parentRow/parentColumn),differenceFromandpercentDifferenceFrom(BaseItem.previous/next/value(v)along anAxisSide),runningTotal,rank; theLayoutAggregatebase withLayoutCellContextfor custom ones;ValueDisplaynames the ready-made choices for pickers. Computed when a cell is read; sorting by one sorts by its base.CubeCell.aggregatealso accepts the dependencies of a derived aggregate. AggregateKindcovers the new kinds; every label is localized.
Filters #
- Structured filters
CompareFilter,RangeFilter,TextFilter,EmptyFilterover a column, equal by value likeValueFilter,AndFilter,OrFilterandNotFilternow are.FactFilter.toExpressionSource()on every filter (nullwhere it cannot be expressed);FactFilter.compilebinds a filter to a table once per scan.
Saving and transport #
CubeJson: JSON encoding and decoding ofCubeConfig(a bundle ofCubeSpec, bothExpansionStates and theSchema;CubeConfig.of(cube),toCube(facts)) and of every part on its own.JsonAdapterfor custom aggregates, dimensions and filters;functionsfor decoded expressions;FormatExceptionon malformed input,UnsupportedErrorfor members without a JSON form.TesseraSnapshot: aFactTable(and optionally aCubeConfig) as oneUint8List— JSON header, raw little-endian column arrays — thatdecodeloads back in a copy after validating every section. The format is specified indocs/snapshot.mdfor other writers. 2 M rows: 106 MB, ~40 ms to encode, ~60 ms to decode.
Strings #
- New members for the filter editor, the aggregate picker's formula and label fields, "show values as", the statistical and layout-relative aggregate labels, and expression errors, in all fourteen locales. The count-of-facts function is "Count of records" in the picker (it said "rows" in most locales, which clashed with the cube's rows).
0.1.1 #
- README: the status note no longer says the package is unpublished.
0.1.0 #
- Initial release: data sources (CSV, lists), schema inference, the fact
table importer, cubes with expandable row/column hierarchies, built-in
aggregates,
AxisGeometryfor renderers, andTesseraStringswith fourteen built-in languages. Cube.expandRowLevel/collapseRowLevel/expandColumnLevel/collapseColumnLevelopen or close every group of one level (keeping deeper expansions),rowsAddedByExpandingLevel/columnsAddedByExpandingLevelcount the effect beforehand;ExpansionState.collapseLevel. StringssortAscending,sortDescending,expandAll,collapseAll,inheritSort,totalsAtEnd,totalsAtStart,totalsHidden,subtotalsAbove,subtotalsBelow,subtotalsLeft,subtotalsRight,subtotalsHidden.CubeAxis.subtotalPosition(SubtotalPosition.top/bottom/hidden): where an expanded group's own row goes;AxisLayout.entryForresolves groups without a row;HeaderArea.path.CubeGrid: aCubeLayoutas a rectangular grid of typed cells with merged areas, the wayCubeViewshows it — what exporters render from.CubeExportTheme/ExportFont/NumberFormat: the format-neutral look of an exported document (fills, border, fonts per role, number format;brand(primary:),gradient,mix), shared by every exporter.Oklch(perceptual colour, to/from ARGB, gamut clipping) andHueLevels: nesting levels coloured by hue alone at one lightness, headers the same hue with more chroma, golden-angle steps so adding a level keeps the others' colours.CubeExportTheme.hueLevels,rowHeaderFills/columnHeaderFillsper level,levelBasis(combined/row),fillOf/fontOffor exporters;GridCell.rowLevel/columnLevel.GridMetrics: pixel geometry of aCubeGrid(content-sized column widths from an estimate or aTextMeasurer, row heights from the fonts, offsets) for renderers that lay cells out themselves;GridPaginationcuts it into pages with repeated header rows and columns;NumberFormat.format(value, strings).CsvCubeExporter(CsvExportOptions: delimiter, quote, line ending, decimal separator, BOM, group labels at the origin or repeated).FactTable.withLabelsrelabels columns without a re-import (data is shared).AxisDimension.sortis nullable:nullinherits the ordering of the level above (CubeAxis.sortAtresolves it), so an aggregate sort on the first level orders every level.