Skip to content

Commit

Permalink
Complete example with revised structure.
Browse files Browse the repository at this point in the history
  • Loading branch information
giuliocn authored Sep 19, 2024
1 parent 117f4c9 commit efee7a3
Showing 1 changed file with 91 additions and 98 deletions.
189 changes: 91 additions & 98 deletions examples/batch/batch.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,114 +4,112 @@ import (
"context"
"errors"
"fmt"
"net/http"
"strings"

pgx "github.com/jackc/pgx/v5"
pgconn "github.com/jackc/pgx/v5/pgconn"
pgxpool "github.com/jackc/pgx/v5/pgxpool"
)

type PgxPoolInterface interface {
Begin(context.Context) (pgx.Tx, error)
Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error)
SendBatch(context.Context, *pgx.Batch) pgx.BatchResults
Close()
}

type ExampleBatch struct {
batch *pgx.Batch
br pgx.BatchResults
db PgxPoolInterface
output strings.Builder
type exampleBatch struct {
batch *pgx.Batch // batch pointer
results pgx.BatchResults // query results
db PgxPoolInterface // database connection
}

func (ex *ExampleBatch) insertRow(fields ...string) (err error) {
for i, value := range fields {
fields[i] = "$$" + value + "$$"
}
sql := `INSERT INTO metadata (title, authors, subject, description)
VALUES
(` + strings.Join(fields[:4], ", ") + ");"
_, err = ex.db.Exec(context.Background(), sql)
return err
type metadata struct {
title string
authors string
subject string
description string
}

func (ex *ExampleBatch) databaseSetup() (err error) {
// Create a new table 'metadata'
sql := `
CREATE TABLE IF NOT EXISTS metadata (
func NewExample(db PgxPoolInterface) (example exampleBatch, err error) {

example = exampleBatch{
db: db, // database
batch: &pgx.Batch{}, // batch struct address
}

sql := `CREATE TABLE IF NOT EXISTS metadata (
id BIGINT PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
title TEXT NOT NULL,
authors TEXT NOT NULL,
subject TEXT NOT NULL,
description TEXT NOT NULL);
DELETE FROM metadata ;
INSERT INTO metadata (title, authors, subject, description)
VALUES
($$A Journey Through the Alps$$, $$John Doe, Jane Smith$$, $$Hiking, Nature, Travel$$, $$Explore the breathtaking beauty of the Alps on a scenic hiking adventure. Discover hidden trails, alpine lakes, and charming mountain villages.$$),
($$The Art of Baking: A Beginner's Guide$$, $$Emily Baker$$, $$Cooking, Baking, Food$$, $$Learn the fundamentals of baking and create delicious treats from scratch. Master techniques like kneading dough, frosting cakes, and piping cookies.$$),
($$The History of Ancient Rome$$, $$David Johnson$$, $$History, Ancient Rome, Civilization$$, $$Delve into the fascinating history of the Roman Empire. Explore its rise to power, its cultural achievements, and its eventual decline.$$);
`
_, err = ex.db.Exec(context.Background(), sql)
return err
}

func (ex *ExampleBatch) printResults(w http.ResponseWriter, req *http.Request) {
DELETE FROM metadata ;`
_, err = example.db.Exec(context.Background(), sql) // Execute sql

var temp strings.Builder

// Iterate over a batch of queued queries
for _, query := range ex.batch.QueuedQueries {

// Read results from the current query
rows, _ := ex.br.Query()

// Print SQL field of the current query
temp.WriteString(fmt.Sprintf("%v \n", query.SQL))
return example, err
}

// Iterate over the selected records
//
for rows.Next() {
err := rows.Err()
if err != nil {
return
}

values, err := rows.Values()
if err != nil {
return
}

// Convert values to a string
temp.WriteString(fmt.Sprintf("%v \n", values))
func (ex *exampleBatch) BulkInsertMetadata(data []metadata) error {
query := `INSERT INTO metadata (title, authors, subject, description)
VALUES
(@title, @authors, @subject, @description)
`
batch := &pgx.Batch{}
for _, m := range data {
args := pgx.NamedArgs{
"title": m.title,
"authors": m.authors,
"subject": m.subject,
"description": m.description,
}
batch.Queue(query, args)
}

if ex.output.Len() == 0 {
ex.output = temp
results := ex.db.SendBatch(context.Background(), batch)
defer results.Close()

for index := range data {
_, err := results.Exec()
if err != nil {
return fmt.Errorf("unable to insert row %d: %w", index, err)
}
}
fmt.Fprint(w, ex.output.String())

return results.Close()
}

func (ex *ExampleBatch) requestBatch() (err error) {
func (ex *exampleBatch) SendCustomBatch(queries []string) (err error) {

// Add SQL queries to the queue for a custom batch
for _, query := range queries {
ex.batch.Queue(query)
}

// Efficiently transmits queued queries as a single transaction.
// After the queries are run, a BatchResults object is returned.
//
ex.br = ex.db.SendBatch(context.Background(), ex.batch)
if ex.br == nil {
ex.results = ex.db.SendBatch(context.Background(), ex.batch)
if ex.results == nil {
return errors.New("SendBatch returns a NIL object")
}

return err
}

func (ex *ExampleBatch) Close() (err error) {
func (ex *exampleBatch) TestCustomResults() (err error) {

for index := range ex.batch.QueuedQueries {
_, err := ex.results.Exec()
if err != nil {
return fmt.Errorf("unable to run query %d: %w", index, err)
}
}

return ex.results.Close()
}

func (ex *exampleBatch) Close() (err error) {

// Close batch results object
ex.br.Close()
ex.results.Close()

// Close connection to database
ex.db.Close()
Expand All @@ -122,41 +120,36 @@ func (ex *ExampleBatch) Close() (err error) {
func main() {

// @NOTE: the real connection is not required for tests
db, err := pgxpool.New(context.Background(), "postgres://postgres:password@localhost/batch")
if err != nil {
panic(err)
}
db, _ := pgxpool.New(context.Background(), "postgres://postgres:password@localhost/batch")

// Setup the database
var example = ExampleBatch{
db: db,
batch: &pgx.Batch{},
}
if err = example.databaseSetup(); err != nil {
// Create a new instance of example struct
example, err := NewExample(db)
if err != nil {
panic(err)
}
defer example.Close()

// Add an example to database table
example.insertRow(
"The Adventures of Captain Pickle",
"Timothy T. Turtle",
"Adventure, Fantasy",
"Join Captain Pickle...",
)

// Add SQL queries to the queue for a batch operation
example.batch.Queue("SELECT title FROM metadata")
example.batch.Queue("SELECT authors FROM metadata")
example.batch.Queue("SELECT subject, description FROM metadata")

// Send the batch request to database
if err = example.requestBatch(); err != nil {
panic(err)
// Insert multiple rows into the database
example.BulkInsertMetadata([]metadata{
{`A Journey Through the Alps`, `John Doe, Jane Smith`, `Hiking, Nature, Travel`, `Explore the breathtaking beauty of the Alps on a scenic hiking adventure. Discover hidden trails, alpine lakes, and charming mountain villages.`},
{`The Art of Baking: A Beginner's Guide`, `Emily Baker`, `Cooking, Baking, Food`, `Learn the fundamentals of baking and create delicious treats from scratch. Master techniques like kneading dough, frosting cakes, and piping cookies.`},
{`The History of Ancient Rome`, `David Johnson`, `History, Ancient Rome, Civilization`, `Delve into the fascinating history of the Roman Empire. Explore its rise to power, its cultural achievements, and its eventual decline.`},
})

// Send a custom batch operation to database
example.SendCustomBatch([]string{
"SELECT title FROM metadata",
"SELECT authors FROM metadata",
"SELECT subject, description FROM metadata",
})

// Print batch results
for _, query := range example.batch.QueuedQueries {
fmt.Println(query.SQL)
rows, _ := example.results.Query()
for rows.Next() {
values, _ := rows.Values()
fmt.Println(values)
}
}

// Print batch result to ...
http.HandleFunc("/", example.printResults)
_ = http.ListenAndServe(":8080", nil)

}

0 comments on commit efee7a3

Please sign in to comment.