framed

package module
v0.0.3 Latest Latest
Warning

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

Go to latest
Published: Apr 17, 2025 License: MIT Imports: 13 Imported by: 0

README

Table


Push Status

Data manipulation library inspired from Pandas (Python) for golang

Download
go get -u github.com/OpenRunic/framed
Options

df := framed.New(

  // set max rows to import/load (default = -1)
  framed.WithMaxRows(100),

  // set column separater (default = ',')
  framed.WithSeparator(';'),

  // set column names for table (otherwise automatically generated from first row)
  framed.WithColumns([]string{"id", "col2", ... "colN"}),

  // set column definition
  framed.WithDefinitionType("id", framed.ToType(1)),

  // set column data type reader
  framed.WithTypeReader(func(idx int, value string) reflect.Type {
    return framed.ToType(bool)
  }),
)
Load data

Option callbacks can be used as above on table loaders below

// load table from file
table, err := framed.File("path_to_file.csv")

// load table from url
table, err := framed.URL("http_https_url...csv")

// load table from io.Reader
table, err := framed.Reader(io.Reader)

// load table from slice of string
table, err := framed.Lines([]string{"1....", "2...."})

// load table from slice of raw data
table, err := framed.Raw([][]string{{"1", "..."}, {"2", "..."}})
Actions Pipeline

Run set of pipeline actions to modify data in the table

// add column action
addAction := framed.AddColumn("name", "", func(s *framed.State, r *framed.Row) string {
  return fmt.Sprintf("%s %s", r.At(s.Index("last_name")), r.At(s.Index("first_name")))
})

// drop column action
dropAction := framed.DropColumn("last_name", "age")

// rename column action
renameAction := framed.RenameColumn("fname", "first_name")

// pick specific columns action
pickAction := framed.PickColumn("first_name", "last_name")

// omit specific columns action
omitAction := framed.PickColumn("id", "age")

// make specific changes to table or its options while in pipeline action
updateAction := framed.ChangeOptions(func(tbl *Table) (*Table, error) {
  return tbl, nil
})

// change column type action
changeColTypeAction := framed.ChangeColumnType("age", "", func(s *framed.State, r *framed.Row, a any) string {
  v := a.(int64)
  if v > 18 {
    return "adult"
  } else if v > 12 {
    return "teen"
  }

  return "kid"
})

// modify every table rows action
modifyAction := framed.ModifyRow(func(s *framed.State, r *framed.Row) *framed.Row {
  r.Set(0, framed.ColumnValue(r, 0, 0)+10) // add 10 to every row's column at index 0
  return r
})

// filter rows from table action
filterAction := framed.FilterRow(func(s *framed.State, r *framed.Row) bool {
  return r.Index > 9 // ignore first 10 rows
})

// execute actions to build new table from result
newTable, err := table.Execute(
  addAction,
  dropAction,
  renameAction,
  pickAction,
  omitAction,
  updateAction,
  changeColTypeAction,
  modifyAction,
  filterAction,
)
Table/Row utilities

// manually set columns for table
table.UseColumns([]string{"col1", "col2", ...., "colN"})

// add row to table
table.AddRow(&framed.Row{...})

// get first rows as new table
df := table.Chunk(0, 100)

// add line to table
err := table.InsertLine("a..,b..,..z")

// add slice of strings as line
err := table.InsertSlice([]string{"a..", "b...", "...", "...z"})

// add lines from reader to table
err := table.Read(io.Reader)

// get column definition
def := table.State.Definition("col1")

// get column definition by index
def := table.State.DefinitionAt(0)

// loop through chunks of tables with 100 rows each
for _, cTable := range table.Chunks(100) {
  ...
}

// get first 100 rows as []*framed.Row
rows := table.Slice(0, 100)

// get first row
table.First()

// get last row
table.Last()

// get length of rows
table.Length()

// get row at x index
row := table.At(x)

// get column at x index of row
colValue := row.At(0)

// set column value at x index of row
row.Set(0, "updated_value")

// patch column value at x index of row with type-safety
err := row.Patch(0, "updated_value")

// pick only selected columns from row
columns, err := row.Pick("col2", "col3")

// clone row with selected columns
newRow, err := row.CloneP("col2", "col3")
Other Utilities

// extract reflect.Type from any given value
framed.ToType(10)

// read typesafe column value from column as index 0
value := framed.ColumnValue[string](row, 0, "default_value")

Support

You can file an Issue.

Contribute

To contrib to this project, you can open a PR or an issue.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var BoolToStringValues = []string{"1", "false", "no", "n"}

BoolToStringValues contains slice of string values that can be auto-translated to boolean

View Source
var BoolTrueStringValues = []string{"1", "true", "yes", "y"}

BoolTrueStringValues contains slice of string value that can be auto-translated to true boolean

StringTranslatableKinds contains slice of reflect.Kind that can be translated to string

Functions

func ColumnValue

func ColumnValue[T any](row *Row, idx int, def T) T

ColumnValue will try to read the value of column as provided data type or else returns fallback value.

$0 : row instance from table
$1 : index of the column
$2 : fallback value of the type

val, err := ColumnValue[T any]($0, $1, $2)

func ColumnValueDecoder

func ColumnValueDecoder(def *Definition, value string) (any, error)

ColumnValueDecoder decodes the column value from string using column definition or with default methods

func ColumnValueEncoder

func ColumnValueEncoder(def *Definition, value any) (string, error)

ColumnValueEncoder encodes the column value to string using definition or with default methods

func ConvertValueType

func ConvertValueType(value string, tp reflect.Type) (any, error)

ConvertValueType converts string to provided type or throws error

func DetectValueType

func DetectValueType(name string, value string) reflect.Type

DetectValueType detects and returns reflect.Type of string value

func JoinAtChar

func JoinAtChar(ss []string, sep byte) string

JoinAtChar joins slice of string to string joined by provided separator and add quotes when needed

$0 : slice of String to join
$1 : joining to split the string

splits := JoinAtChar($0, $1)

func ParseInt

func ParseInt(s string, bitSize int) (int64, error)

ParseInt converts string to int as base10 with variable bit size

func ReaderToLines

func ReaderToLines(r io.Reader) iter.Seq[[]byte]

convert data from reader to iterable bytes

func SliceFilter

func SliceFilter[T any](src []T, cb func(T) bool) []T

SliceFilter filters slice values based on filter func

func SliceKeyMap

func SliceKeyMap[T any, L comparable, M any](src []T, cb func(T, int) (L, M)) map[L]M

SliceKeyMap convert slices of T to map of L[M]

func SliceMap

func SliceMap[T any, K any](src []T, cb func(T) K) []K

SliceMap converts slices of T to slices of K

func SliceOmit

func SliceOmit[T comparable](src []T, keys []T) []T

SlicePick omits slice values

func SlicePick

func SlicePick[T comparable](src []T, keys []T) []T

SlicePick picks slice values

func SplitAtChar

func SplitAtChar(s string, sep byte) []string

SplitAtChar splits string to slice separated by provided separator but respects quotes

$0 : string to split
$1 : separator to split the string

splits := SplitAtChar($0, $1)

func ToType

func ToType[T any](v T) reflect.Type

ToType reads the reflect.Type from provided value

func TryColumnValue

func TryColumnValue[T any](row *Row, idx int) (T, error)

TryColumnValue will try to read the value of column as provided data type or else create error message.

$0 : row instance from table
$1 : index of the column

val, err := TryColumnValue[T any]($0, $1)

Types

type ActionAddColumn

type ActionAddColumn[T any] struct {
	// contains filtered or unexported fields
}

func AddColumn

func AddColumn[T any](name string, sample T, cb AddColumnDataReader[T]) *ActionAddColumn[T]

AddColumn adds new column to every rows and resolves column value using callback and generates new table. Generic type of [T any] is applied.

$0 : Column Name
$1 : Sample Value of T
$2 : func(*framed.State, *framed.Row) T

newTable, err := table.Execute(
	...
	framed.AddColumn($0, $1, $2),
	...
)

func (ActionAddColumn[T]) ActionName

func (a ActionAddColumn[T]) ActionName() string

func (ActionAddColumn[T]) Execute

func (a ActionAddColumn[T]) Execute(src *Table) (*Table, error)

type ActionChangeColumnType

type ActionChangeColumnType[T any] struct {
	// contains filtered or unexported fields
}

func ChangeColumnType

func ChangeColumnType[T any](name string, sample T, cb ChangeColumnDataReader[T]) *ActionChangeColumnType[T]

ChangeColumnType updates columns on every rows and resolves column value using callback and generates new table. Generic type of [T any] is applied.

$0 : Column Name
$1 : Sample Value of T
$2 : func(*framed.State, *framed.Row, any) T

newTable, err := table.Execute(
	...
	framed.ChangeColumnType($0, $1, $2),
	...
)

func (ActionChangeColumnType[T]) ActionName

func (a ActionChangeColumnType[T]) ActionName() string

func (ActionChangeColumnType[T]) Execute

func (a ActionChangeColumnType[T]) Execute(src *Table) (*Table, error)

type ActionFilterRow

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

func FilterRow

func FilterRow(cb func(*State, *Row) bool) *ActionFilterRow

FilterRow iterates through all rows, filters the rows and build a new table.

newTable, err := table.Execute(
	...
	framed.FilterRow(func(*framed.State, *framed.Row) bool),
	...
)

func (ActionFilterRow) ActionName

func (a ActionFilterRow) ActionName() string

func (ActionFilterRow) Execute

func (a ActionFilterRow) Execute(src *Table) (*Table, error)

type ActionModifyRow

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

func ModifyRow

ModifyRow iterates through all rows to modify the row and generates the new table.

newTable, err := table.Execute(
	...
	framed.ModifyRow(func(*State, *Row) *Row),
	...
)

func (ActionModifyRow) ActionName

func (a ActionModifyRow) ActionName() string

func (ActionModifyRow) Execute

func (a ActionModifyRow) Execute(src *Table) (*Table, error)

type ActionRenameColumn

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

func RenameColumn

func RenameColumn(name string, newName string) *ActionRenameColumn

RenameColumn renames a column generates the new table.

$0 : Existing Column Name
$1 : New Column Name

newTable, err := table.Execute(
	...
	framed.RenameColumn($0, $1),
	...
)

func RenameColumns

func RenameColumns(pairs ...[]string) *ActionRenameColumn

RenameColumns renames multiple columns at once and generates the new table.

newTable, err := table.Execute(
	...
	framed.RenameColumns([]string{"EXISTING_COL_NAME", "NEW_COLUMN_NAME"}, ...),
	...
)

func (ActionRenameColumn) ActionName

func (a ActionRenameColumn) ActionName() string

func (ActionRenameColumn) Execute

func (a ActionRenameColumn) Execute(src *Table) (*Table, error)

type ActionSelection

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

func ColumnSelection

func ColumnSelection(name string, columns ...string) *ActionSelection

func ColumnSelectionCallback

func ColumnSelectionCallback(name string, callback func(*Table, []string) []string, columns ...string) *ActionSelection

func DropColumn

func DropColumn(columns ...string) *ActionSelection

DropColumn ignores the specified columns and generates the new table.

newTable, err := table.Execute(
	...
	framed.DropColumn("col1", "col2", ...),
	...
)

func PickColumn

func PickColumn(columns ...string) *ActionSelection

PickColumn plucks the specified columns and generates the new table.

newTable, err := table.Execute(
	...
	framed.PickColumn("col1", "col2", ...),
	...
)

func (ActionSelection) ActionName

func (a ActionSelection) ActionName() string

func (ActionSelection) Execute

func (a ActionSelection) Execute(src *Table) (*Table, error)

type ActionUpdate

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

func ChangeOptions

func ChangeOptions(cb func(*Table) (*Table, error)) *ActionUpdate

ChangeOptions provides access to current table in pipeline and allows to change options and definitions as required.

newTable, err := table.Execute(
	...
	framed.ChangeOptions(func(*Table) (*Table, error)),
	...
)

func (ActionUpdate) Execute

func (a ActionUpdate) Execute(src *Table) (*Table, error)

type AddColumnDataReader

type AddColumnDataReader[T any] = func(*State, *Row) T

type ChangeColumnDataReader

type ChangeColumnDataReader[T any] = func(*State, *Row, any) T

type Definition

type Definition struct {
	Label   string
	Type    reflect.Type
	Encoder func(any) (string, error)
	Decoder func(string) (any, error)
}

Definition defines details and encoder/decoder for values

func NewDefinition

func NewDefinition(tp reflect.Type) *Definition

NewDefinition creates new definition instance with reflect.Type

func (*Definition) Kind

func (d *Definition) Kind() reflect.Kind

Kind returns the reflect.Kind from stored reflect.Type

func (*Definition) WithDecoder

func (d *Definition) WithDecoder(cb func(string) (any, error)) *Definition

WithEncoder updates the decoder to use for data

func (*Definition) WithEncoder

func (d *Definition) WithEncoder(cb func(any) (string, error)) *Definition

WithEncoder updates the encoder to use for data

func (*Definition) WithLabel

func (d *Definition) WithLabel(val string) *Definition

WithLabel changes the label for current definition

type IndexCache

type IndexCache = map[string]int

columns index cache type

type ModifyTableDataReader

type ModifyTableDataReader = func(*State, *Row) *Row

type OptionCallback

type OptionCallback = func(*Options)

OptionCallback defines function signature for option builder

func WithColumns

func WithColumns(cols ...string) OptionCallback

func WithDefinition

func WithDefinition(name string, def *Definition) OptionCallback

func WithDefinitionType

func WithDefinitionType(name string, tp reflect.Type) OptionCallback

func WithIgnoreHeader

func WithIgnoreHeader(ih bool) OptionCallback

func WithMaxRows

func WithMaxRows(s int) OptionCallback

func WithSampleSize

func WithSampleSize(s int) OptionCallback

func WithSampling

func WithSampling(s int) OptionCallback

func WithSeparator

func WithSeparator(sep byte) OptionCallback

func WithTypeReader

func WithTypeReader(cb func(int, string) reflect.Type) OptionCallback

type Options

type Options struct {

	// sample rows count
	Sampling int

	// printable sample size
	SampleSize int

	// stop import at max defined count
	MaxRows int

	// ignore the header line
	IgnoreHeader bool

	// column separater character
	Separator byte

	// pre-defined columns for table
	Columns []string

	// pre-defined column definitions
	Definitions map[string]*Definition

	// helper to read column type
	TypeReader func(int, string) reflect.Type
}

Options defines settings for table data

func NewOptions

func NewOptions(ocbs ...OptionCallback) *Options

NewOptions creates option's instance using OptionCallback

func (*Options) Clone

func (o *Options) Clone() *Options

Clone duplicates the options as new instance

type PipelineAction

type PipelineAction interface {

	// ActionName returns the name of pipeline action
	ActionName() string

	// Execute executes the pipeline action
	Execute(*Table) (*Table, error)
}

PipelineAction defines an action interface to modify table rows and options as needed.

type Row

type Row struct {

	// index of row in table
	Index int

	// slice of column data
	Columns []any
}

Row holds columns of row in table

func (*Row) AddColumn

func (r *Row) AddColumn(value any) *Row

AddColumn appends new column value to row

func (*Row) AsSlice

func (r *Row) AsSlice(s *State) ([]string, error)

AsSlice encodes columns to slice of strings or throws error

func (*Row) At

func (r *Row) At(idx int) any

At gives access to column at x index

func (*Row) Clone

func (r *Row) Clone() *Row

Clone duplicates the row as-is

func (*Row) CloneP

func (r *Row) CloneP(s *State, names ...string) (*Row, error)

CloneP create duplicate row from selected columns

func (*Row) Patch

func (r *Row) Patch(def *Definition, idx int, value any) error

Patch attempts to update column value at x index and throws error on type fail

func (*Row) Pick

func (r *Row) Pick(s *State, names ...string) ([]any, error)

Pick selects provided columns from the row or throws error

func (*Row) Set

func (r *Row) Set(idx int, value any) *Row

Set updates column value at x index

func (*Row) WithIndex

func (r *Row) WithIndex(idx int) *Row

WithIndex updates the row index in table

type State

type State struct {

	// list of table columns
	Columns []string

	// indexes of detected columns
	Indexes IndexCache

	// resolved column definitions
	Definitions map[string]*Definition
}

current state of table

func (*State) Clone

func (s *State) Clone() *State

Clone duplicates state to new instance

func (*State) ColumnName

func (s *State) ColumnName(idx int) string

ColumnName retrieves the name of column from index

func (*State) DataType

func (s *State) DataType(name string) reflect.Type

DataType returns data type for single value

func (*State) DataTypes

func (s *State) DataTypes() map[string]reflect.Type

DataTypes returns the saved data types in definitions

func (*State) Definition

func (s *State) Definition(name string) *Definition

Definition retrieves the value definition

func (*State) DefinitionAt

func (s *State) DefinitionAt(idx int) *Definition

DefinitionAt retrieves the value definition via index

func (*State) HasColumn

func (s *State) HasColumn(name string) bool

HasColumn checks if column is available

func (*State) HasDefinition

func (s *State) HasDefinition(name string) bool

HasDefinition checks if definition is available

func (*State) Index

func (s *State) Index(name string) int

Index retrieves the index of column

func (*State) IsEmpty

func (s *State) IsEmpty() bool

IsEmpty checks if columns are available

type Table

type Table struct {

	// slice of table rows
	Rows []*Row

	// current state of table
	State *State

	// current resolved options for table
	Options *Options
	// contains filtered or unexported fields
}

func CherryPick

func CherryPick(src *Table, columns []string, rows []*Row) (*Table, error)

CherryPick selects the columns and assigns new rows for those columns to build new Table

func File

func File(path string, cbs ...OptionCallback) (*Table, error)

File opens file and creates table

func Lines

func Lines(lines []string, cbs ...OptionCallback) (*Table, error)

Lines imports slices of string to create table

func New

func New(ocbs ...OptionCallback) *Table

New creates new Table instance with OptionCallback

func Raw

func Raw(ss [][]string, cbs ...OptionCallback) (*Table, error)

Raw imports slices of raw data to create table

func Reader

func Reader(r io.Reader, cbs ...OptionCallback) (*Table, error)

Reader iterates through io.Reader and creates table

func URL

func URL(uri string, cbs ...OptionCallback) (*Table, error)

URL sends http request to url and creates table

func (*Table) AddRow

func (t *Table) AddRow(rows ...*Row)

func (*Table) AppendColumn

func (t *Table) AppendColumn(pos int, name string)

AppendColumn adds new column to table

func (*Table) AsColumn

func (t *Table) AsColumn(idx int, value string) (any, error)

AsColumn builds column info for provided value

func (*Table) At

func (t *Table) At(idx int) *Row

At retrieves row at x index

func (*Table) Chunk

func (t *Table) Chunk(start int, end int) *Table

Chunk build new table from provided slice indexes

func (*Table) Chunks

func (t *Table) Chunks(limit int) iter.Seq2[int, *Table]

Chunks split table into multiple chunk of tables from provided slice indexes

func (*Table) Clone

func (t *Table) Clone() *Table

Clone duplicates table as-is

func (*Table) CloneE

func (t *Table) CloneE() *Table

CloneE duplicates table as-is without rows

func (*Table) ColLength

func (t *Table) ColLength() int

ColLength returns number of columns

func (*Table) Execute

func (t *Table) Execute(actions ...PipelineAction) (*Table, error)

Execute is called by Table when pipeline actions are executed

func (*Table) ExecuteS

func (t *Table) ExecuteS(actions ...PipelineAction) error

ExecuteS runs pipeline actions and dereferences the resulting Table back to self

func (*Table) First

func (t *Table) First() *Row

First returns the first Row of table

func (*Table) Head

func (t *Table) Head(limit int) []*Row

Head returns the first n Row of table

func (*Table) Initialize

func (t *Table) Initialize() *Table

Initialize executes the options on table instance

func (*Table) Insert

func (t *Table) Insert(b []byte) error

Insert adds line of bytes as row

func (*Table) InsertGenBytes

func (t *Table) InsertGenBytes(it iter.Seq[[]byte]) error

InsertGenBytes iterates bytes from iterator

func (*Table) InsertLine

func (t *Table) InsertLine(line string) error

InsertLine adds string line as row

func (*Table) InsertLines

func (t *Table) InsertLines(lines []string) error

InsertLines iterates list of string lines

func (*Table) InsertSlice

func (t *Table) InsertSlice(values []string) error

InsertSlice adds slice of strings as row

func (*Table) InsertSlices

func (t *Table) InsertSlices(ss [][]string) error

InsertSlices iterates list of string slice

func (*Table) IsAtMaxLine

func (t *Table) IsAtMaxLine() bool

IsAtMaxLine checks rows are already at restricted max limit

func (*Table) IsEmpty

func (t *Table) IsEmpty() bool

IsEmpty verifies if table is empty

func (*Table) IsResolved

func (t *Table) IsResolved() bool

IsResolved checks table is resolved

func (*Table) Last

func (t *Table) Last() *Row

Last returns the last Row of table

func (*Table) Length

func (t *Table) Length() int

Length return number of total rows

func (*Table) MarkUnresolved

func (t *Table) MarkUnresolved() *Table

MarkUnresolved marks table as unresolved

func (*Table) RSlice

func (t *Table) RSlice(start int, end int) []*Row

RSlice retrieves slice of rows at given start and end but reverse

func (*Table) Read

func (t *Table) Read(r io.Reader) error

Read accepts io.Reader to loads data into table

func (*Table) ResolveDefinition

func (t *Table) ResolveDefinition(name string, tp reflect.Type) *Definition

ResolveDefinition stores the column Definition if it doesn't exist

func (*Table) ResolveTypes

func (t *Table) ResolveTypes(names []string, values []string) error

ResolveTypes resolves the data types from the column values

func (*Table) ResolveValueDefinition

func (t *Table) ResolveValueDefinition(idx int, name string, value string) *Definition

ResolveValueDefinition detects data type of column value and creates Definition

func (*Table) Save

func (t *Table) Save(path string) error

Save saves the table data to provided file path

func (*Table) SetColumns

func (t *Table) SetColumns(cols []string)

SetColumns updates the header columns for table

func (*Table) SetDefinition

func (t *Table) SetDefinition(name string, def *Definition) *Definition

SetDefinition assigns Definition for the column

func (*Table) SetIndexes

func (t *Table) SetIndexes(cache IndexCache)

SetIndexes updates the column indexes for table

func (*Table) SetOptions

func (t *Table) SetOptions(opts *Options) *Table

SetOptions overrides the Options of table

func (*Table) SetState

func (t *Table) SetState(s *State) *Table

SetState overrides the State of table

func (*Table) Slice

func (t *Table) Slice(start int, end int) []*Row

Slice retrieves slice of rows at given start and end

func (*Table) SliceToColumns

func (t *Table) SliceToColumns(values []string) ([]any, error)

SliceToColumns convert slice of values to column slices

func (*Table) String

func (t *Table) String() string

String generates printable stats about the table

func (*Table) Tail

func (t *Table) Tail(limit int) []*Row

Tail returns the last n Row of table

func (*Table) UseColumns

func (t *Table) UseColumns(values []string)

UseColumns updates header columns for table

func (*Table) Write

func (t *Table) Write(f io.Writer) error

Write writes table data to io.Writer

type TableError

type TableError struct {
	Row     int
	Col     int
	ColName string
	Reason  string
	Source  error
}

defines custom error with details about the table, row and column (if any)

func ColError

func ColError(idx int, idx2 int, col string, err error, reason string) *TableError

ColError will create an error instance with info about row and column index and name(if provided) along with the reason.

$0 : index of row
$1 : index of column
$2 : name of column
$3 : main originating error
$4 : reason of the error

err := ColError($0, $1, $2, $3, $4)

func NewError

func NewError(err error, reason string) TableError

NewError will create an error instance along with the reason.

$0 : main originating error
$1 : reason of the error

err := NewError($0, $1, $2, $3, $4)

func RowError

func RowError(idx int, err error, reason string) TableError

RowError will create an error instance with info about row along with the reason.

$0 : index of row
$1 : main originating error
$2 : reason of the error

err := RowError($0, $1, $2, $3, $4)

func (TableError) Error

func (e TableError) Error() string

Jump to

Keyboard shortcuts

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