initial database connection and migration
This commit is contained in:
parent
f589322cfe
commit
2c7fab0a38
1
db/.gitignore
vendored
Normal file
1
db/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
_data/
|
13
db/compose.yml
Normal file
13
db/compose.yml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
version: "3"
|
||||||
|
|
||||||
|
services:
|
||||||
|
|
||||||
|
postgres:
|
||||||
|
image: postgres:11
|
||||||
|
ports:
|
||||||
|
- 5432:5432
|
||||||
|
environment:
|
||||||
|
POSTGRES_PASSWORD: postgres
|
||||||
|
volumes:
|
||||||
|
- ./_data:/var/lib/postgresql/data
|
70
db/init.sh
Executable file
70
db/init.sh
Executable file
@ -0,0 +1,70 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# @author : annika
|
||||||
|
# @file : init
|
||||||
|
# @created : Tuesday Jan 11, 2022 15:35:20 CET
|
||||||
|
# @description : Initialize the database
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
if [ -z $PSQL ]; then
|
||||||
|
PSQL="psql"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z $PGHOST ]; then
|
||||||
|
export PGHOST="localhost"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z $PGPORT ]; then
|
||||||
|
export PGPORT="5432"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z $PGDATABASE ]; then
|
||||||
|
export PGDATABASE="alice"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z $PGUSER ]; then
|
||||||
|
export PGUSER="postgres"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z $PGPASSWORD ]; then
|
||||||
|
export PGPASSWORD="postgres"
|
||||||
|
fi
|
||||||
|
|
||||||
|
## Commandline opts:
|
||||||
|
OPT_USAGE=0
|
||||||
|
OPT_TESTING=0
|
||||||
|
OPT_CLEAR=0
|
||||||
|
|
||||||
|
while [ $# -gt 0 ]; do
|
||||||
|
case "$1" in
|
||||||
|
-h) OPT_USAGE=1 ;;
|
||||||
|
-t) OPT_TESTING=1 ;;
|
||||||
|
-c) OPT_CLEAR=1 ;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ $OPT_USAGE -eq 1 ]; then
|
||||||
|
echo "Options:"
|
||||||
|
echo " -h Show this helpful text"
|
||||||
|
echo " -c Drop and create the database"
|
||||||
|
echo " -t Make a test database"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $OPT_TESTING -eq 1 ]; then
|
||||||
|
echo "++ using test database"
|
||||||
|
NAME="${PGDATABASE}_test"
|
||||||
|
export PGDATABASE=$NAME
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $OPT_CLEAR -eq 1 ]; then
|
||||||
|
echo "++ clearing database"
|
||||||
|
$PSQL template1 -c "DROP DATABASE $PGDATABASE"
|
||||||
|
$PSQL template1 -c "CREATE DATABASE $PGDATABASE"
|
||||||
|
fi
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -10,11 +10,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// ErrNotInitialized will be returned if the
|
|
||||||
// database pool is accessed before initializing using
|
|
||||||
// Connect.
|
|
||||||
ErrNotInitialized = errors.New("store not initialized, pool not ready")
|
|
||||||
|
|
||||||
// ErrMaxConnsUnconfigured will be returned, if the
|
// ErrMaxConnsUnconfigured will be returned, if the
|
||||||
// the maximum connections are zero.
|
// the maximum connections are zero.
|
||||||
ErrMaxConnsUnconfigured = errors.New("MaxConns not configured")
|
ErrMaxConnsUnconfigured = errors.New("MaxConns not configured")
|
||||||
|
46
pkg/store/backends/postgres/connection_test.go
Normal file
46
pkg/store/backends/postgres/connection_test.go
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
package postgres
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/v4/pgxpool"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ConnectTest uses defaults for the connection
|
||||||
|
// environment variable is not set.
|
||||||
|
func ConnectTest() *pgxpool.Pool {
|
||||||
|
ctx := context.Background()
|
||||||
|
url := os.Getenv("ALICE_TEST_DB_URL")
|
||||||
|
if url == "" {
|
||||||
|
url = "postgres://postgres:postgres@localhost:5432/alice_test"
|
||||||
|
}
|
||||||
|
p, err := Connect(ctx, &ConnectOpts{
|
||||||
|
URL: url,
|
||||||
|
MinConns: 2,
|
||||||
|
MaxConns: 16})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
m := NewManager(p)
|
||||||
|
err = m.Initialize(ctx)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInitialize(t *testing.T) {
|
||||||
|
p := ConnectTest()
|
||||||
|
m := NewManager(p)
|
||||||
|
s := m.Status(context.Background())
|
||||||
|
if s.Error != nil {
|
||||||
|
t.Error(s.Error)
|
||||||
|
}
|
||||||
|
if s.Migrated == false {
|
||||||
|
t.Error("schema is not migrated, current:", s.SchemaVersion)
|
||||||
|
}
|
||||||
|
}
|
102
pkg/store/backends/postgres/manager.go
Normal file
102
pkg/store/backends/postgres/manager.go
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
package postgres
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
_ "embed" // embed schema
|
||||||
|
"log"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/v4/pgxpool"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Include the schema through embedding
|
||||||
|
//go:embed schema.sql
|
||||||
|
var schema string
|
||||||
|
|
||||||
|
// CurrentSchemaVersion is the current version of the schema
|
||||||
|
const CurrentSchemaVersion = 1
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrNotInitialized is returned when the database
|
||||||
|
// schema is not migrated yet
|
||||||
|
)
|
||||||
|
|
||||||
|
// Status is the database / store status
|
||||||
|
type Status struct {
|
||||||
|
Migrated bool `json:"migrated"`
|
||||||
|
SchemaVersion int `json:"schema_version"`
|
||||||
|
SchemaAppliedAt time.Time `json:"schema_applied_at"`
|
||||||
|
Error error `json:"error"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log writes the status into the log
|
||||||
|
func (s *Status) Log() {
|
||||||
|
log.Println(
|
||||||
|
"Database migrated:", s.Migrated)
|
||||||
|
log.Println(
|
||||||
|
"Schema version:", s.SchemaVersion,
|
||||||
|
"applied at:", s.SchemaAppliedAt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Manager supervises the database. It can migrate the
|
||||||
|
// schema and retrieve a status.
|
||||||
|
type Manager struct {
|
||||||
|
pool *pgxpool.Pool
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewManager creates a new database manager
|
||||||
|
func NewManager(pool *pgxpool.Pool) *Manager {
|
||||||
|
return &Manager{
|
||||||
|
pool: pool,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the background jobs for database management
|
||||||
|
func (m *Manager) Start(ctx context.Context) {
|
||||||
|
m.Status(ctx).Log()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Status retrieves the current schema version
|
||||||
|
// and checks if migrated. In case an error occures,
|
||||||
|
// it will be included in the result.
|
||||||
|
func (m *Manager) Status(ctx context.Context) *Status {
|
||||||
|
status := &Status{}
|
||||||
|
qry := `
|
||||||
|
SELECT version, applied_at FROM __meta__
|
||||||
|
ORDER BY version DESC
|
||||||
|
LIMIT 1
|
||||||
|
`
|
||||||
|
err := m.pool.QueryRow(ctx, qry).Scan(
|
||||||
|
&status.SchemaVersion,
|
||||||
|
&status.SchemaAppliedAt,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
status.Error = err
|
||||||
|
return status
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is the database migrated?
|
||||||
|
status.Migrated = CurrentSchemaVersion == status.SchemaVersion
|
||||||
|
|
||||||
|
return status
|
||||||
|
}
|
||||||
|
|
||||||
|
// Migrate applies the database intialisation script if required.
|
||||||
|
func (m *Manager) Migrate(ctx context.Context) error {
|
||||||
|
s := m.Status(ctx)
|
||||||
|
if s.Migrated {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return m.Initialize(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize will apply the database schema. This will clear the
|
||||||
|
// database. However for now we treat the state as disposable.
|
||||||
|
func (m *Manager) Initialize(ctx context.Context) error {
|
||||||
|
_, err := m.pool.Exec(ctx, schema)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
33
pkg/store/backends/postgres/neighbors_backend.go
Normal file
33
pkg/store/backends/postgres/neighbors_backend.go
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package postgres
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/alice-lg/alice-lg/pkg/api"
|
||||||
|
"github.com/jackc/pgx/v4/pgxpool"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NeighborsBackend implements a neighbors store
|
||||||
|
// using a postgres database
|
||||||
|
type NeighborsBackend struct {
|
||||||
|
pool *pgxpool.Pool
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewNeighborsBackend initializes the backend
|
||||||
|
// with a pool.
|
||||||
|
func NewNeighborsBackend(pool *pgxpool.Pool) *NeighborsBackend {
|
||||||
|
b := &NeighborsBackend{
|
||||||
|
pool: pool,
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNeighbors updates the current neighbors of
|
||||||
|
// a route server identified by sourceID
|
||||||
|
func (b *NeighborsBackend) SetNeighbors(
|
||||||
|
ctx context.Context,
|
||||||
|
sourceID string,
|
||||||
|
neighbors api.Neighbors,
|
||||||
|
) error {
|
||||||
|
return nil
|
||||||
|
}
|
@ -5,9 +5,14 @@
|
|||||||
-- ----------------------
|
-- ----------------------
|
||||||
--
|
--
|
||||||
-- %% Author: annika
|
-- %% Author: annika
|
||||||
-- %% Description: Create alice-lg db schema.
|
-- %% Description: Apply alice-lg db schema.
|
||||||
--
|
--
|
||||||
|
|
||||||
|
-- Clear state
|
||||||
|
DROP TABLE IF EXISTS routes;
|
||||||
|
DROP TABLE IF EXISTS neighbors;
|
||||||
|
DROP TABLE IF EXISTS __meta__;
|
||||||
|
|
||||||
-- Neighbors
|
-- Neighbors
|
||||||
CREATE TABLE neighbors (
|
CREATE TABLE neighbors (
|
||||||
id VARCHAR(255) NOT NULL PRIMARY KEY,
|
id VARCHAR(255) NOT NULL PRIMARY KEY,
|
||||||
@ -19,7 +24,7 @@ CREATE TABLE neighbors (
|
|||||||
neighbor jsonb NOT NULL,
|
neighbor jsonb NOT NULL,
|
||||||
|
|
||||||
-- Timestamps
|
-- Timestamps
|
||||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE INDEX idx_neighbors_rs_id
|
CREATE INDEX idx_neighbors_rs_id
|
||||||
@ -39,7 +44,7 @@ CREATE TABLE routes (
|
|||||||
route jsonb NOT NULL,
|
route jsonb NOT NULL,
|
||||||
|
|
||||||
-- Timestamps
|
-- Timestamps
|
||||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE INDEX idx_routes_network ON routes ( network );
|
CREATE INDEX idx_routes_network ON routes ( network );
|
||||||
|
Loading…
x
Reference in New Issue
Block a user