magiccol

package module
v1.2.0 Latest Latest
Warning

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

Go to latest
Published: Jan 20, 2023 License: MIT Imports: 5 Imported by: 3

README

magiccol

Test Go Report Card Coverage Status godoc

Dinamyc columns for database/sql. Magiccol allows to scan rows for a sql query, without known which columns it returns and create a map[string]any

But Why?

In some cases is not possible to create a struct or variable to scan a value from a database query, then you can scan it into any but this lead to incorrect scanned values, for example MYSQL by default scan DATETIME into a []uint8 magiccol ensures that a DATETIME value will be scanned into a mysql.NullTime. This behaviour can be changed according to any sql/db driver.

Example

package main

import (
    "database/sql"
    "fmt"
    "log"
    "reflect"

    "github.com/go-sql-driver/mysql"
    "github.com/licaonfee/magiccol"
)

func main() {
    db, err := sql.Open("mysql", "user:password@tcp(localhost:3306)/employees?charset=utf8mb4")
    if err != nil {
        log.Fatal(err)
    }
    r, err := db.Query("select * from employees limit 10;")
    if err != nil {
        log.Fatal(err)
    }
    m := magiccol.DefaultMapper()
    //Use mysql native Time type see
    //https://github.com/go-sql-driver/mysql#timetime-support
    custom := reflect.TypeOf(mysql.NullTime{})
    match := []magiccol.Matcher{
        magiccol.DatabaseTypeAs("DATE", custom),
        magiccol.DatabaseTypeAs("DATETIME", custom),
        magiccol.DatabaseTypeAs("TIMESTAMP", custom),
    }
    m.Match(match)

    sc, err := magiccol.NewScanner(magiccol.Options{Rows:r, Mapper: m})
    if err != nil {
        log.Fatal(err)
    }
    var value map[string]any
    for sc.Scan() {
        value = sc.Value()
        fmt.Printf("%v\n", value)
    }
    if sc.Err() != nil {
        log.Fatal(sc.Err())
    }
}

Documentation

Overview

Package magiccol allows to scan sql rows into an arbitrary map

Index

Constants

This section is empty.

Variables

View Source
var ErrInvalidDataType = errors.New("data type not valid for column")

ErrInvalidDataType columnd declared with a type incompatible with the actual value

View Source
var ErrNilRows = errors.New("nil *sql.Rows as argument")

ErrNilRows a nil Rows interface is provided

Functions

This section is empty.

Types

type ColumnType added in v0.2.0

type ColumnType interface {
	Name() string
	DatabaseTypeName() string
	ScanType() reflect.Type
	Nullable() (nullable bool, ok bool)
	DecimalSize() (precision int64, scale int64, ok bool)
	Length() (length int64, ok bool)
}

ColumnType is identical as defined in sql.ColumnType struct

type Mapper

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

Mapper translate sql types to golang types

func DefaultMapper

func DefaultMapper() *Mapper

DefaultMapper provides a mapping for most common sql types type list reference used is: http://jakewheat.github.io/sql-overview/sql-2011-foundation-grammar.html#predefined-type

func (*Mapper) Get

func (l *Mapper) Get(col ColumnType) reflect.Type

Get do a map lookup if type is not found return a ScanType itself

func (*Mapper) Match added in v0.2.0

func (l *Mapper) Match(m ...Matcher)

Match method allow to set custom types as scanneable types if m is nil then is a no-op

type Matcher added in v0.2.0

type Matcher func(ColumnType) (reflect.Type, bool)

Matcher return a type and true if column definition match on a negative match reflect.Type should be null but is not mandatory

func ColumnNameAs added in v0.2.0

func ColumnNameAs(columnName string, t reflect.Type) Matcher

ColumnNameAs match a column name

func DatabaseTypeAs added in v0.2.0

func DatabaseTypeAs(databaseTypeName string, t reflect.Type) Matcher

DatabaseTypeAs match a column type

type Options

type Options struct {
	// Rows must be a valid sql.Rows object
	Rows Rows
	// Mapper can be nil, if so DefaultMapper is used
	Mapper *Mapper
}

Options for Scanner

type Rows added in v0.1.2

type Rows interface {
	ColumnTypes() ([]*sql.ColumnType, error)
	Columns() ([]string, error)
	Next() bool
	Err() error
	Scan(...any) error
}

Rows allow to mock sql.Rows object

type Scanner

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

Scanner read data from an sql.Rows object into a map

func NewScanner

func NewScanner(o Options) (*Scanner, error)

NewScanner create a new Scanner object, return an error if a nil Rows interface is provided or any error is returned by its

func (*Scanner) Err

func (s *Scanner) Err() error

Err return last error in Scanner

func (*Scanner) Scan

func (s *Scanner) Scan() bool

Scan return true if there are rows in queue and false if there is no more rows or an error occurred. To distinguish between error or no more rows Err() method should be consulted

func (*Scanner) SetMap

func (s *Scanner) SetMap(value map[string]any)

SetMap read values from current row and load it in a given map[string]any this allow to set default values, or reutilize same map in multiple iterations SetMap does not clear map object and any preexistent key will be preserved

func (*Scanner) Value

func (s *Scanner) Value() map[string]any

Value returns a new map object with all values from current row successives calls to Value without call Scan returns always same values in a new allocated map. Call Value() before Scan return all values as Zero

Jump to

Keyboard shortcuts

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