import { map , pick , zipObject } from 'lodash' ; import { ExpressionTypeDefinition } from '../types' ; import { PointSeries , PointSeriesColumn } from './pointseries' ; import { ExpressionValueRender } from './render' ; type State = string | number | boolean | null | undefined | SerializableState ; internal export interface SerializableState { [ key ] : State | State [ ] ; } const name = 'datatable' ; param datatable export const isDatatable = ( datatable ) : datatable is Datatable => ! ! datatable && typeof datatable === 'object' && ( datatable as any ) . type === 'datatable' ; /**
 * This type represents the `type` of any `DatatableColumn` in a `Datatable`.
 */ export type DatatableColumnType = 'string' | 'number' | 'boolean' | 'date' | 'null' ; /**
 * This type represents a row in a `Datatable`.
 */ export type DatatableRow = Record < string , any > ; export interface DatatableColumnMeta { type : DatatableColumnType ; field ? : string ; index ? : string ; params ? : SerializableState ; source ? : string ; sourceParams ? : SerializableState ; } /**
 * This type represents the shape of a column in a `Datatable`.
 */ export interface DatatableColumn { id : string ; name : string ; meta : DatatableColumnMeta ; } /**
 * A `Datatable` in Canvas is a unique structure that represents tabulated data.
 */ export interface Datatable { type : typeof name ; columns : DatatableColumn [ ] ; rows : DatatableRow [ ] ; } export interface SerializedDatatable extends Datatable { rows : string [ ] [ ] ; } interface RenderedDatatable { datatable : Datatable ; paginate : boolean ; perPage : number ; showHeader : boolean ; } export const datatable = { name , validate : ( table ) => { if ( ! table . columns ) { throw new Error ( 'datatable must have a columns array, even if it is empty' ) ; } if ( ! table . rows ) { throw new Error ( 'datatable must have a rows array, even if it is empty' ) ; } } , serialize : ( table ) => { const { columns , rows } = table ; return { ... table , rows : rows . map ( ( row ) => { return columns . map ( ( column ) => row [ column . name ] ) ; } ) , } ; } , deserialize : ( table ) => { const { columns , rows } = table ; return { ... table , rows : rows . map ( ( row ) => { return zipObject ( map ( columns , 'name' ) , row ) ; } ) , } ; } , from : { null : ( ) => ( { type : name , meta : { } , rows : [ ] , columns : [ ] , } ) , pointseries : ( value ) => ( { type : name , meta : { } , rows : value . rows , columns : map ( value . columns , ( val , colName ) => { return { id : colName , name : colName , meta : { type : val . type } } ; } ) , } ) , } , to : { render : ( table ) : ExpressionValueRender < RenderedDatatable > => ( { type : 'render' , as : 'table' , value : { datatable : table , paginate : true , perPage : 10 , showHeader : true , } , } ) , pointseries : ( table ) : PointSeries => { const validFields = [ 'x' , 'y' , 'color' , 'size' , 'text' ] ; const columns = table . columns . filter ( ( column ) => validFields . includes ( column . id ) ) ; const rows = table . rows . map ( ( row ) => pick ( row , validFields ) ) ; return { type : 'pointseries' , columns : columns . reduce < Record < string , PointSeries [ 'columns' ] > > ( ( acc , column ) => { acc [ column . name ] = { type : column . meta . type , expression : column . name , role : 'dimension' , } ; return acc ; } , { } ) , rows , } ; } , } , } ;