Hello!

Today we will look at how we can use golang to connect to the Postgres database and execute queries. To work with the database we will use github.com/jackc/pgx.

Let’s start with initializing the module and installing the driver for the database.

go mod init
go get github.com/jackc/pgx/v4

After that pgx will be available for use in code.

For the database, I am using docker, but it can be another type of installation. To do this, create a file docker-compose.yml with content:

version: '3'

services:
  Postgres:
    image: Postgres
    tty: true
    restart: always
    ports:
      - "5432:5432"
    environment:
      - POSTGRES_PASSWORD=postgres

And execute the command docker-compose up -d. Docker-compose and docker must be installed. The database is ready to work, and now we can start writing code.

Let’s start with the connection to the database. First, we create a configuration cfg which will have the address, port, user, password, and database to which we connect. Since my database works locally, I specify localhost as the host. When the configuration is ready, call pgx.Connect (cfg) to create a connection. After finishing work with the database connection it is necessary to close therefore we will add defer conn.Close() and we check for errors. Also to check that the database is responding we will run conn.Ping(context.Background())

package main

import (
    "context"
    "fmt"
    "log"
    "os"

    "github.com/jackc/pgx"
)

func main() {
    cfg := pgx.ConnConfig{
        Host:     "localhost",
        Port:     5432,
        User:     "postgres",
        Password: "postgres",
        Database: "postgres",
    }
    conn, err := pgx.Connect(cfg)
    if err != nil {
        fmt.Fprintf(os.Stderr, "Unable to connect to database: %v\n", err)
        log.Fatalf("Connect to database failed: %v\n", err)
    }
    defer conn.Close()

    err = conn.Ping(context.Background())
    if err != nil {
        log.Fatalf("Ping Failed: %v\n", err)
    }
}

We can start making inquiries. To begin, create a new table and write data to it. The Exec method is used to call requests that do not return anything.

    _, err = conn.Exec(`
        CREATE TABLE IF NOT EXISTS users(
            id SERIAL PRIMARY KEY,
            name TEXT,
            email TEXT UNIQUE NOT NULL
        );
    `)
    if err != nil {
        log.Fatalln(err)
    }

    name := "TestUser1"
    email := "testuser@gmail.com"
    _, err = conn.Exec(`
        INSERT INTO users(name, email)
        VALUES ($1, $2);
    `, name, email)
    if err != nil {
        log.Fatalln(err)
    }

The data has been created and we can try to read it. If one record is returned from the database, you can use the QueryRow method, if many, then Query. Also, in order to read the data you need the structure, we will have the structure name User which will have the same parameters as the fields in the table.

type User struct {
	Id    int
	Name  string
	Email string
}

And the request itself to get the data

	user := User{}
	err = conn.QueryRow("SELECT * FROM users WHERE name=$1;", name).Scan(&user.Id, &user.Name, &user.Email)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(user)

Pgx can also be used as a driver for the built-in sql package