structql

package module
v0.5.2 Latest Latest
Warning

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

Go to latest
Published: Sep 14, 2024 License: Apache-2.0 Imports: 15 Imported by: 3

README

structql (SQL for GoLang data structures)

GoReportCard GoDoc

This library is compatible with Go 1.17+

Please refer to CHANGELOG.md if you encounter breaking changes.

Motivation

The primary aim of this library is to facilitate access to structured data through SQL queries. It is specifically tailored to transform Golang data structures using SQL syntax. The initial release of this library focuses on implementing the foundational features of SQL, laying the groundwork for more advanced functionalities in future updates

Introduction

Go struct transformation with SQL
  • Basic Query

SQL := "SELECT ID, Name FROM `/` WHERE Status = 2"
query, err := structql.NewQuery(SQL, reflect.TypeOf(&Vendor{}), nil)
if err != nil {
    log.Fatal(err)
}	
result, err := query.Select(vendors)
if err != nil {
    log.Fatal(err)
}
  • Nested Query
SQL := "SELECT ProductID,Revenue FROM `/Products[Active=1]/Performance` WHERE Revenue > 100.0 "
query, err := structql.NewQuery(SQL, reflect.TypeOf(&Vendor{}), nil)
if err != nil {
    log.Fatal(err)
}	
result, err := query.Select(vendors)
if err != nil {
    log.Fatal(err)
}
Querying data with database/sql

DSN Data Source Name

The structql driver accepts the following DSN

  • 'structql://[localhost|cloudProvider$bucket]/[baseURI|folderPath][{options}]'

    Where queryString can optionally configure the following option:

    • key: access key id
    • secret: access key secret

Usage

database/sql
package mypkg

import (
  "context"
  "database/sql"
  _ "github.com/viant/structql/sql"
  "log"
)

func Example() {
  db, err := sql.Open("structql", "structql:///opt/local/testdata/")
  if err != nil {
    log.Fatal(err)
  }
  type Foo struct {
    ID   int
    Name string
  }
  _, err = db.Exec("REGISTER TYPE Foo AS ?", &Foo{})
  if err != nil {
    log.Fatal(err)
  }

  rows, err := db.QueryContext(context.Background(), "SELECT id,name FROM Foo WHERE id IN(?, ?)", 1, 3)
  if err != nil {
    log.Fatal(err)
  }
  var foos []*Foo
  for rows.Next() {
    var foo Foo
    err = rows.Scan(&foo.ID, &foo.Name)
    if err != nil {
      log.Fatal(err)
    }
    foos = append(foos, &foo)
  }
}




### Go struct transformation with SQL

```go

package myPkg

import (
	"github.com/viant/structql"
	"log"
	"reflect"
	"time"
)

type (
	Vendor struct {
		ID       int
		Name     string
		Revenue  float64
		Status int
		Products []*Product
	}

	Product struct {
		ID          int
		Name        string
		Status      int
		Performance []*Performance
	}

	Performance struct {
		ProductID int
		Date      time.Time
		Quantity  float64
		Revenue   float64
	}
)


func ExampleQuery_Select() {
	var vendors = []*Vendor{
		{
			ID:   1,
			Name: "Vendor 1",
			Products: []*Product{
				{
					ID:     1,
					Status: 1,
					Name:   "Product 1",
					Performance: []*Performance{
						{
							ProductID: 1,
							Revenue:   13050,
							Quantity:  124,
						},
					},
				},
			},
		},
		{
			ID:   2,
			Name: "Vendor 2",
			Products: []*Product{
				{
					ID:     2,
					Name:   "Product 2",
					Status: 1,
					Performance: []*Performance{
						{
							ProductID: 2,
							Revenue:   16050,
							Quantity:  110,
						},
					},
				},
				{
					ID:     7,
					Name:   "Product 7",
					Status: 0,
					Performance: []*Performance{
						{
							ProductID: 7,
							Revenue:   160,
							Quantity:  10,
						},
					},
				},
			},
		},
		{
			ID:   3,
			Name: "Vendor 3",
			Products: []*Product{
				{
					ID:     3,
					Name:   "Product 3",
					Status: 1,
					Performance: []*Performance{
						{
							ProductID: 3,
							Revenue:   11750,
							Quantity:  143,
						},
					},
				},
				{
					ID:     4,
					Name:   "Product 4",
					Status: 1,
					Performance: []*Performance{
						{
							ProductID: 4,
							Revenue:   11,
							Quantity:  1,
						},
					},
				},
			},
		},
	}
	SQL := "SELECT ProductID,Revenue FROM `/Products[Active=1]/Performance` WHERE Revenue > 100.0 "
	type Query1Output struct {
		ProductID int
		Revenue   float64
	}
	query, err := structql.NewQuery(SQL, reflect.TypeOf(vendors), reflect.TypeOf(Query1Output{}))
	if err != nil {
		log.Fatal(err)
	}
	result, err := query.Select(vendors)
	if err != nil {
		log.Fatal(err)
	}
	
}

Contributing to structql

structql is an open source project and contributors are welcome!

See TODO list

Credits and Acknowledgements

Library Author: Adrian Witas

Documentation

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func IsStructTypeQuery added in v0.3.0

func IsStructTypeQuery(query string, source reflect.Type, values ...interface{}) (bool, error)

IsStructQuery returns true if dest result in struct

Types

type Context

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

func NewContext

func NewContext(mapper *Mapper, appender *xunsafe.Appender, aggregate bool) *Context

func (*Context) Next

func (c *Context) Next(source interface{}) interface{}

type Mapper

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

Mapper represents struct mapper

func NewMapper

func NewMapper(source reflect.Type, dest reflect.Type, sel *query.Select) (*Mapper, error)

NewMapper creates a mapper

func (*Mapper) Map

func (m *Mapper) Map(walker *Walker, source interface{}, appender *xunsafe.Appender) error

Map maps source to appender

func (*Mapper) MapStruct

func (m *Mapper) MapStruct(srcItemPtr unsafe.Pointer, destItemPtr unsafe.Pointer) error

MapStruct maps struct

type Node

type Node struct {
	IsLeaf bool
	// contains filtered or unexported fields
}

Node represents a node

func NewNode

func NewNode(ownerType reflect.Type, sel *node.Selector, values *node.Values) (*Node, error)

NewNode creates a node

func (*Node) Leaf

func (n *Node) Leaf() *Node

Leaf returns leaf node

func (*Node) LeafOwnerType

func (n *Node) LeafOwnerType() reflect.Type

LeafOwnerType returns leaf type

func (*Node) LeafType

func (n *Node) LeafType() reflect.Type

LeafType returns leaf type

func (*Node) Type

func (n *Node) Type() reflect.Type

Type returns node Type

func (*Node) When

func (n *Node) When(value interface{}) bool

When applied expr or returns true if not defined

type NodeVisitor

type NodeVisitor func(node *Node, value interface{}) error

NodeVisitor represents a node visitor (struct or leaf node)

type Query

type Query struct {
	Limit int

	CompType reflect.Type
	Binding  *node.Binding
	// contains filtered or unexported fields
}

Query represents a selector

func NewQuery

func NewQuery(query string, source, dest reflect.Type, values ...interface{}) (*Query, error)

NewQuery returns a selector

func (*Query) First

func (s *Query) First(source interface{}) (interface{}, error)

First returns the first selection result

func (*Query) Select

func (s *Query) Select(source interface{}) (interface{}, error)

Select returns selection result

Example
package main

import (
	"fmt"
	"github.com/viant/structql"
	"log"
	"reflect"
	"time"
)

type (
	Vendor struct {
		ID       int
		Name     string
		Revenue  float64
		Products []*Product
	}

	Product struct {
		ID          int
		Name        string
		Status      int
		Performance []*Performance
	}

	Performance struct {
		ProductID int
		Date      time.Time
		Quantity  float64
		Revenue   float64
	}
)

func main() {
	var vendors = []*Vendor{
		{
			ID:   1,
			Name: "Vendor 1",
			Products: []*Product{
				{
					ID:     1,
					Status: 1,
					Name:   "Product 1",
					Performance: []*Performance{
						{
							ProductID: 1,
							Revenue:   13050,
							Quantity:  124,
						},
					},
				},
			},
		},
		{
			ID:   2,
			Name: "Vendor 2",
			Products: []*Product{
				{
					ID:     2,
					Name:   "Product 2",
					Status: 1,
					Performance: []*Performance{
						{
							ProductID: 2,
							Revenue:   16050,
							Quantity:  110,
						},
					},
				},
				{
					ID:     7,
					Name:   "Product 7",
					Status: 0,
					Performance: []*Performance{
						{
							ProductID: 7,
							Revenue:   160,
							Quantity:  10,
						},
					},
				},
			},
		},
		{
			ID:   3,
			Name: "Vendor 3",
			Products: []*Product{
				{
					ID:     3,
					Name:   "Product 3",
					Status: 1,
					Performance: []*Performance{
						{
							ProductID: 3,
							Revenue:   11750,
							Quantity:  143,
						},
					},
				},
				{
					ID:     4,
					Name:   "Product 4",
					Status: 1,
					Performance: []*Performance{
						{
							ProductID: 4,
							Revenue:   11,
							Quantity:  1,
						},
					},
				},
			},
		},
	}
	SQL := "SELECT ProductID,Revenue FROM `/Products[Active=1]/Performance` WHERE Revenue > 100.0 "
	type Query1Output struct {
		ProductID int
		Revenue   float64
	}
	query, err := structql.NewQuery(SQL, reflect.TypeOf(vendors), reflect.TypeOf(Query1Output{}))
	if err != nil {
		log.Fatal(err)
	}
	result, err := query.Select(vendors)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%v\n", result)
}
Output:

func (*Query) StructType added in v0.2.2

func (s *Query) StructType() reflect.Type

StructType returns dest struct type

func (*Query) Type

func (s *Query) Type() reflect.Type

Type returns dest slice type

type Visitor

type Visitor func(value interface{}) error

Visitor represents a visitor

type Walker

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

Walker represents struct walker

func NewWalker

func NewWalker(root *Node) *Walker

NewWalker creates a struct walker

func (*Walker) Count

func (w *Walker) Count(value interface{}) int

Count counts leaf node

func (*Walker) Traverse

func (w *Walker) Traverse(aNode *Node, value interface{}, visitor interface{}) error

Traverse walks the node

Directories

Path Synopsis
in

Jump to

Keyboard shortcuts

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