Cookies management by TermsFeed Cookie Consent

Init the main function and the demo procedure

15/21

Demo procedure

Let’s start by initializing a test procedure that will perform a series of actions on the repository. After executing each function, we will check the results by writing them to the standard output or check if there was an error.

Create the app/demo.go file in the demo package we created at the beginning of the project and copy its contents.

The RunRepositoryDemo() function takes as arguments the context used in the repository methods and the repository itself. Note what type websiteRepository has. It is the website.Repository, which is our repository interface. This way, the RunRepositoryDemo() function can be used with any repository implementation, which is what we are going to do in the next steps. For now, this function does only one thing - it calls the Migrate() method to create our storage for Website objects.

The main() function

We already have the repository implementation and the first version of the demo procedure, so we can put everything together and run a test application.

  1. Create a new directory classic in the cmd package for the application that demonstrates the classic repository based on the database/sql package.
  2. Add a new file main.go to the classic directory. This is our executable file.
  3. Copy the contents of the cmd/classic/main.go to your newly created main.go.
  4. Run our test app with
    go run main.go
    If everything went well, the program should exit without error, and a new table called websites with columns: id, name, url, and rank should be created in the PostgreSQL database.

What does the main() function do?

Connect to PostgreSQL database

To connect to a PostgreSQL database using the pgx, it is necessary to register it as a database/sql driver. This is done by importing the driver package in line 11. By using a blank identifier, we import the package, even if it is not used by the current program. Once imported, it calls the internal init() function, which registers the driver in the database/sql interface under the name pgx.

The pgx has a database/sql compatible driver in the package github.com/jackc/pgx/v4/stdlib.

In lines 15-19, we use the registered driver. Using the sql.Open() function with the pgx as the first argument, we connect to the PostgreSQL database. The second argument is the dataSourceName consisting of the connection information. For PostgreSQL, we define the so-called connection URI here. In our case, we are connecting to the database named website located on localhost on port 5432 with username postgres and password mysecretpassword because this is what we set at the stage of running the Docker image. The result is the sql.DB object (and an error if it occurs) safe for concurrent use and maintaining its own pool of idle connections. A good practice is to close the DB connection at the end of the program with the Close() method.

Create a Website repository, context, and run the demo procedure

In line 21, we call a constructor of the PostgreSQLClassicRepository with the created sql.DB object as an argument. Then, we initialize a new Context object with a 10-second timeout using the context.WithTimeout() function. Its first argument is a parent Context which in our case is an empty fresh Context instance obtained from the Background() function.

Note that in addition to the context.Context object, as a result, we also get a cancel() function to release the resources associated with the context, so we do this at the end of the program as soon as all operations using the context have finished:

defer cancel()

In the last line of the main(), we call our demo procedure passing the created context and our classic database/sql repository as arguments.

app/demo.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
package app

import (
    "context"
    "fmt"
    "log"
    "postgresql-intro/website"
)

func RunRepositoryDemo(ctx context.Context, websiteRepository website.Repository) {
    fmt.Println("1. MIGRATE REPOSITORY")

    if err := websiteRepository.Migrate(ctx); err != nil {
        log.Fatal(err)
    }
}

cmd/classic/main.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package main

import (
    "context"
    "database/sql"
    "log"
    "postgresql-intro/app"
    "postgresql-intro/website"
    "time"

    _ "github.com/jackc/pgx/v4/stdlib"
)

func main() {
    db, err := sql.Open("pgx", "postgres://postgres:mysecretpassword@localhost:5432/website")
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()

    websiteRepository := website.NewPostgreSQLClassicRepository(db)

    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()

    app.RunRepositoryDemo(ctx, websiteRepository)
}
15/21