Browse Source

[Go/echo] Update to pgx (#9134)

James Burns 1 year ago
parent
commit
eedd5e5c8a

+ 1 - 1
frameworks/Go/echo/echo.dockerfile

@@ -1,4 +1,4 @@
-FROM docker.io/golang:1.19
+FROM docker.io/golang:1.22
 
 ADD ./src /echo
 WORKDIR /echo

+ 6 - 2
frameworks/Go/echo/src/go.mod

@@ -1,13 +1,16 @@
 module echo/app
 
-go 1.19
+go 1.22
 
 require (
+	github.com/jackc/pgx/v5 v5.6.0
 	github.com/labstack/echo/v4 v4.9.0
-	github.com/lib/pq v1.10.7
 )
 
 require (
+	github.com/jackc/pgpassfile v1.0.0 // indirect
+	github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
+	github.com/jackc/puddle/v2 v2.2.1 // indirect
 	github.com/labstack/gommon v0.3.1 // indirect
 	github.com/mattn/go-colorable v0.1.13 // indirect
 	github.com/mattn/go-isatty v0.0.16 // indirect
@@ -15,6 +18,7 @@ require (
 	github.com/valyala/fasttemplate v1.2.1 // indirect
 	golang.org/x/crypto v0.21.0 // indirect
 	golang.org/x/net v0.23.0 // indirect
+	golang.org/x/sync v0.1.0 // indirect
 	golang.org/x/sys v0.18.0 // indirect
 	golang.org/x/text v0.14.0 // indirect
 )

+ 13 - 4
frameworks/Go/echo/src/go.sum

@@ -1,12 +1,18 @@
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
+github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
+github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
+github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
+github.com/jackc/pgx/v5 v5.6.0 h1:SWJzexBzPL5jb0GEsrPMLIsi/3jOo7RHlzTjcAeDrPY=
+github.com/jackc/pgx/v5 v5.6.0/go.mod h1:DNZ/vlrUnhWCoFGxHAG8U2ljioxukquj7utPDgtQdTw=
+github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
+github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
 github.com/labstack/echo/v4 v4.9.0 h1:wPOF1CE6gvt/kmbMR4dGzWvHMPT+sAEUJOwOTtvITVY=
 github.com/labstack/echo/v4 v4.9.0/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks=
 github.com/labstack/gommon v0.3.1 h1:OomWaJXm7xR6L1HmEtGyQf26TEn7V6X88mktX9kee9o=
 github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
-github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw=
-github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
 github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
 github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
 github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
@@ -16,8 +22,9 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
 github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
 github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
 github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4=
@@ -26,6 +33,8 @@ golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
 golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
 golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
 golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
+golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
+golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -36,5 +45,5 @@ golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
 golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

+ 23 - 28
frameworks/Go/echo/src/main.go

@@ -1,9 +1,11 @@
 package main
 
 import (
-	"database/sql"
+	"context"
 	"encoding/json"
 	"fmt"
+	"github.com/jackc/pgx/v5"
+	"github.com/jackc/pgx/v5/pgxpool"
 	"html/template"
 	"io"
 	"log"
@@ -13,7 +15,6 @@ import (
 	"strconv"
 
 	"github.com/labstack/echo/v4"
-	_ "github.com/lib/pq"
 )
 
 type (
@@ -79,10 +80,7 @@ const (
 
 var (
 	// Database
-	db                *sql.DB
-	worldSelectStmt   *sql.Stmt
-	worldUpdateStmt   *sql.Stmt
-	fortuneSelectStmt *sql.Stmt
+	db *pgxpool.Pool
 
 	// Template
 	Template = &StdTemplate{
@@ -120,8 +118,9 @@ func (h *handler) json() echo.HandlerFunc {
 // Test 2: Single database query
 func (h *handler) db() echo.HandlerFunc {
 	return func(c echo.Context) error {
+		ctx := c.Request().Context()
 		world := new(World)
-		if err := fetchRandomWorld(world); err != nil {
+		if err := fetchRandomWorld(ctx, world); err != nil {
 			return err
 		}
 
@@ -134,10 +133,11 @@ func (h *handler) db() echo.HandlerFunc {
 // Test 3: Multiple database queries
 func (h *handler) queries() echo.HandlerFunc {
 	return func(c echo.Context) error {
+		ctx := c.Request().Context()
 		n := getQueryCount(c.QueryParam("n"))
 		worlds := make([]World, n)
 		for i := 0; i < n; i++ {
-			if err := fetchRandomWorld(&worlds[i]); err != nil {
+			if err := fetchRandomWorld(ctx, &worlds[i]); err != nil {
 				return err
 			}
 		}
@@ -151,7 +151,8 @@ func (h *handler) queries() echo.HandlerFunc {
 // Test 4: Fortunes
 func (h *handler) fortunes() echo.HandlerFunc {
 	return func(c echo.Context) error {
-		rows, err := fortuneSelectStmt.Query()
+		ctx := c.Request().Context()
+		rows, err := db.Query(ctx, fortuneSelect)
 		if err != nil {
 			return fmt.Errorf("Error preparing statement: %v", err)
 		}
@@ -172,18 +173,19 @@ func (h *handler) fortunes() echo.HandlerFunc {
 // Test 5: Database updates
 func (h *handler) updates() echo.HandlerFunc {
 	return func(c echo.Context) error {
+		ctx := c.Request().Context()
 		n := getQueryCount(c.QueryParam("n"))
 		worlds := make([]World, n)
 		for i := 0; i < n; i++ {
 			// Fetch and modify
 			w := &worlds[i]
-			if err := fetchRandomWorld(&worlds[i]); err != nil {
+			if err := fetchRandomWorld(ctx, &worlds[i]); err != nil {
 				return err
 			}
 			w.RandomNumber = uint16(randomWorldNum())
 
 			// Update
-			if _, err := worldUpdateStmt.Exec(w.RandomNumber, w.ID); err != nil {
+			if _, err := db.Exec(ctx, worldUpdate, w.RandomNumber, w.ID); err != nil {
 				return fmt.Errorf("Error updating world row: %v", err)
 			}
 		}
@@ -221,9 +223,9 @@ func (h *handler) plaintext() echo.HandlerFunc {
 	}
 }
 
-func fetchRandomWorld(w *World) error {
+func fetchRandomWorld(ctx context.Context, w *World) error {
 	n := randomWorldNum()
-	return worldSelectStmt.QueryRow(n).Scan(&w.ID, &w.RandomNumber)
+	return db.QueryRow(ctx, worldSelect, n).Scan(&w.ID, &w.RandomNumber)
 }
 
 func randomWorldNum() int {
@@ -241,7 +243,7 @@ func getQueryCount(q string) int {
 	return n
 }
 
-func fetchFortunes(rows *sql.Rows) (Fortunes, error) {
+func fetchFortunes(rows pgx.Rows) (Fortunes, error) {
 	fortunes := make(Fortunes, 0)
 	for rows.Next() { // Fetch rows
 		f := new(Fortune)
@@ -267,24 +269,17 @@ func InitPostgres() {
 	host := "tfb-database"
 
 	var err error
-	db, err = sql.Open("postgres", fmt.Sprintf(connectionString, host))
-	if err != nil {
-		log.Fatalf("Error opening database: %v", err)
-	}
-	db.SetMaxIdleConns(maxConnections)
-	db.SetMaxOpenConns(maxConnections)
 
-	worldSelectStmt, err = db.Prepare(worldSelect)
+	dbCfg, err := pgxpool.ParseConfig(fmt.Sprintf(connectionString, host))
 	if err != nil {
-		log.Fatal(err)
+		log.Fatalf("Error reading database connection string: %v", err)
 	}
-	worldUpdateStmt, err = db.Prepare(worldUpdate)
-	if err != nil {
-		log.Fatal(err)
-	}
-	fortuneSelectStmt, err = db.Prepare(fortuneSelect)
+	dbCfg.MaxConns = maxConnections
+	dbCfg.MinConns = maxConnections
+
+	db, err = pgxpool.NewWithConfig(context.Background(), dbCfg)
 	if err != nil {
-		log.Fatal(err)
+		log.Fatalf("Error opening database: %v", err)
 	}
 }