https://github.com/olbrichattila/gogenerator
Generator iterator in golang
https://github.com/olbrichattila/gogenerator
generator iterator iterator-library
Last synced: about 1 year ago
JSON representation
Generator iterator in golang
- Host: GitHub
- URL: https://github.com/olbrichattila/gogenerator
- Owner: olbrichattila
- Created: 2024-07-20T18:53:18.000Z (almost 2 years ago)
- Default Branch: main
- Last Pushed: 2024-07-20T21:33:03.000Z (almost 2 years ago)
- Last Synced: 2025-02-08T02:44:37.919Z (over 1 year ago)
- Topics: generator, iterator, iterator-library
- Language: Go
- Homepage:
- Size: 8.79 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Golang generator
> The code provides a mechanism to create a generator in Go that can be used to process elements via callbacks, suitable for handling tasks such as processing large files or databases. If you are familiar with PHP Generator, it is possible to achieve similar result.
`Note: The next version of golang plans to release a similar iterator with yield`
## Functions
- SetInitFunc(InitFunc)
- SetDeferFunc(DeferFunc)
- Next() <-chan interface{}
- GetLastError() error
### SetInitFunc(InitFunc)
> This is a function which is called first and can return any number of arguments and an error: Signature:
```func(...interface{}) ([]interface{}, error)```
### SetDeferFunc(DeferFunc)
> This function is called when the process ended or the init function or callback function returned an error: Signature:
```func(...interface{}) error```
### Next() <-chan interface{}
> This is the iterator, in the for loop it returns a channel with ```interface{}```. Examle:
```
for res := range generator.Next() {
fmt.Println(res)
}
```
### GetLastError() error
> Check at the end of the process if any error occurred
Examples:
- simple list:
```
package main
import (
"fmt"
"github.com/olbrichattila/gogenerator"
)
func main() {
generator := gogenerator.New(callback)
for res := range generator.Next() {
fmt.Println(res)
}
}
func callback(i int, p ...interface{}) (interface{}, error) {
if i > 10 {
return nil, nil
}
return fmt.Sprintf("hello %d", i), nil
}
```
- Simple list with init func
```
package main
import (
"fmt"
"github.com/olbrichattila/gogenerator"
)
func main() {
generator := gogenerator.New(callback)
for res := range generator.Next() {
fmt.Println(res)
}
}
func callback(i int, p ...interface{}) (interface{}, error) {
if i > 10 {
return nil, nil
}
return fmt.Sprintf("hello %d", i), nil
}
```
- Error handling from when it comes from init func
```
package main
import (
"fmt"
"github.com/olbrichattila/gogenerator"
)
func main() {
generator := gogenerator.New(callback)
generator.SetInitFunc(initFunc)
for res := range generator.Next() {
fmt.Println(res)
}
if generator.GetLastError() != nil {
fmt.Println(generator.GetLastError())
}
}
func initFunc(...interface{}) ([]interface{}, error) {
return nil, fmt.Errorf("error from init func")
}
func callback(i int, p ...interface{}) (interface{}, error) {
if i > 10 {
return nil, nil
}
return fmt.Sprintf("hello %d", i), nil
}
```
- Error handling when it comes from callback
```
package main
import (
"fmt"
"github.com/olbrichattila/gogenerator"
)
func main() {
generator := gogenerator.New(callback)
generator.SetInitFunc(initFunc)
for res := range generator.Next() {
fmt.Println(res)
}
if generator.GetLastError() != nil {
fmt.Println(generator.GetLastError())
}
}
func initFunc(...interface{}) ([]interface{}, error) {
return nil, nil
}
func callback(i int, p ...interface{}) (interface{}, error) {
return "param", fmt.Errorf("error from callback")
}
```
- Full example with database read:
```
package main
import (
"database/sql"
"fmt"
"github.com/olbrichattila/gogenerator"
// This blank import is necessary to have the driver
_ "github.com/mattn/go-sqlite3"
)
type vehicle struct {
make string
model string
}
func main() {
sql := "select make, model from vehicles"
generator := gogenerator.New(callback, sql)
generator.SetInitFunc(initFunc)
generator.SetDeferFunc(deferFunc)
for res := range generator.Next() {
fmt.Println(res)
}
if generator.GetLastError() != nil {
fmt.Println(generator.GetLastError())
}
}
func initFunc(params ...interface{}) ([]interface{}, error) {
if len(params) != 1 {
return nil, fmt.Errorf("init function requires 1 parameter which is the sql string")
}
db, err := sql.Open("sqlite3", "./data/database.sqlite")
if err != nil {
return nil, err
}
stmt, err := db.Prepare(params[0].(string))
if err != nil {
return nil, err
}
rows, err := stmt.Query()
if err != nil {
return nil, err
}
return []interface{}{db, stmt, rows}, nil
}
func deferFunc(params ...interface{}) error {
if len(params) != 3 {
return fmt.Errorf("two parameter required in defer func")
}
stmt, ok := params[1].(*sql.Stmt)
if !ok {
return fmt.Errorf("parameter 2 is not *sql.Stmt")
}
defer stmt.Close()
db, ok := params[0].(*sql.DB)
if !ok {
return fmt.Errorf("parameter 1 is not *sql.DB")
}
defer db.Close()
return nil
}
func callback(i int, params ...interface{}) (interface{}, error) {
if len(params) != 3 {
return nil, fmt.Errorf("two parameter required in callback")
}
rows, ok := params[2].(*sql.Rows)
if !ok {
return nil, fmt.Errorf("parameter 2 is not *sql.Rows")
}
hasNextRow := rows.Next()
if !hasNextRow {
return nil, nil
}
var vehicle vehicle
rows.Scan(&vehicle.make, &vehicle.model)
return vehicle, nil
}
```