sqlutil

package
v0.77.1 Latest Latest
Warning

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

Go to latest
Published: Oct 5, 2020 License: Apache-2.0 Imports: 4 Imported by: 0

Documentation

Overview

Package sqlutil provides helpers for scanning database/sql responses into a data.Frame.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func FrameFromRows

func FrameFromRows(rows *sql.Rows, rowLimit int64, converters ...StringConverter) (*data.Frame, map[int]StringConverter, error)

FrameFromRows returns a new Frame populated with the data from rows. The field types will be nullable ([]*T) if the SQL column is nullable or if the nullable property is unknown. Otherwise, the field types will be non-nullable ([]T) types.

The number of rows scanned is limited to rowLimit. If maxRows is reached, then a data.Notice with a warning severity will be attached to the frame. If rowLimit is less than 0, there is no limit.

Fields will be named to match name of the SQL columns.

All the types must be supported by the Frame or a StringConverter will be created and the resulting FieldType type will be FieldTypeNullableString ([]*string).

The StringConverter's ConversionFunc will be applied to matching rows if it is not nil. Additionally, if the StringConverter's Replacer is not nil, the replacement will be performed. A map of Field/Column index to the corresponding StringConverter is returned so what conversions were done can be inspected.

Example
package main

import (
	"database/sql"

	"github.com/grafana/grafana-plugin-sdk-go/data/sqlutil"
)

func main() {
	aQuery := "SELECT * FROM GoodData"
	db, err := sql.Open("fancySql", "fancysql://user:pass@localhost:1433")
	if err != nil {
		// return err
	}

	defer db.Close()

	rows, err := db.Query(aQuery)
	if err != nil {
		// return err
	}
	if rows.Err() != nil {
		// return err
	}
	defer rows.Close()

	frame, mappings, err := sqlutil.FrameFromRows(rows, 1000)
	if err != nil {
		// return err
	}
	_, _ = frame, mappings
}
Output:

func Replace

func Replace(frame *data.Frame, fieldIdx int, replacer *StringFieldReplacer) error

Replace will replace a *string Vector of the specified Field's index using the StringFieldReplacer.

Example
package main

import (
	"fmt"
	"strconv"

	"github.com/grafana/grafana-plugin-sdk-go/data"
	"github.com/grafana/grafana-plugin-sdk-go/data/sqlutil"
)

func main() {
	i := 0
	getString := func() *string {
		i++
		s := strconv.Itoa(i)
		return &s
	}

	frame := data.NewFrame("Before",
		data.NewField("string", nil, []*string{getString(), getString()}))

	st, _ := frame.StringTable(-1, -1)
	fmt.Println(st)

	intReplacer := &sqlutil.StringFieldReplacer{
		OutputFieldType: data.FieldTypeNullableInt64,
		ReplaceFunc: func(in *string) (interface{}, error) {
			if in == nil {
				return nil, nil
			}
			v, err := strconv.ParseInt(*in, 10, 64)
			if err != nil {
				return nil, err
			}
			return &v, nil
		},
	}

	err := sqlutil.Replace(frame, 0, intReplacer)
	if err != nil {
		// return err
	}

	frame.Name = "After"
	st, _ = frame.StringTable(-1, -1)
	fmt.Println(st) // After
}
Output:

Name: Before
Dimensions: 1 Fields by 2 Rows
+-----------------+
| Name: string    |
| Labels:         |
| Type: []*string |
+-----------------+
| 1               |
| 2               |
+-----------------+

Name: After
Dimensions: 1 Fields by 2 Rows
+----------------+
| Name: string   |
| Labels:        |
| Type: []*int64 |
+----------------+
| 1              |
| 2              |
+----------------+

Types

type StringConverter

type StringConverter struct {
	// Name is an optional property that can be used to identify a converter
	Name          string
	InputScanKind reflect.Kind // reflect.Type might better or worse option?
	InputTypeName string

	// Conversion func may be nil to do no additional operations on the string conversion.
	ConversionFunc func(in *string) (*string, error)

	// If the Replacer is not nil, the replacement will be performed.
	Replacer *StringFieldReplacer
}

StringConverter can be used to store types not supported by a Frame into a *string. When scanning, if a SQL's row's InputScanType's Kind and InputScanKind match that returned by the sql response, then the conversion func will be run on the row.

Example
package main

import (
	"reflect"
	"strconv"

	"github.com/grafana/grafana-plugin-sdk-go/data"
	"github.com/grafana/grafana-plugin-sdk-go/data/sqlutil"
)

func main() {
	_ = sqlutil.StringConverter{
		Name:          "BIGINT to *int64",
		InputScanKind: reflect.Struct,
		InputTypeName: "BIGINT",
		Replacer: &sqlutil.StringFieldReplacer{
			OutputFieldType: data.FieldTypeNullableInt64,
			ReplaceFunc: func(in *string) (interface{}, error) {
				if in == nil {
					return nil, nil
				}
				v, err := strconv.ParseInt(*in, 10, 64)
				if err != nil {
					return nil, err
				}
				return &v, nil
			},
		},
	}
}
Output:

type StringFieldReplacer

type StringFieldReplacer struct {
	OutputFieldType data.FieldType
	ReplaceFunc     func(in *string) (interface{}, error)
}

StringFieldReplacer is used to replace a *string Field in a Frame. The type returned by the ReplaceFunc must match the type of elements of VectorType. Both properties must be non-nil.

Jump to

Keyboard shortcuts

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