181 lines
3.6 KiB
Go
181 lines
3.6 KiB
Go
|
package database
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"database/sql"
|
||
|
"log"
|
||
|
|
||
|
"git.xeserv.us/xena/route/internal/database/dmigrations"
|
||
|
"github.com/Xe/uuid"
|
||
|
"github.com/brandur/simplebox"
|
||
|
"github.com/gchaincl/dotsql"
|
||
|
_ "github.com/lib/pq"
|
||
|
"golang.org/x/net/context"
|
||
|
)
|
||
|
|
||
|
type Scanner interface {
|
||
|
Scan(...interface{}) error
|
||
|
}
|
||
|
|
||
|
type PostgresStorage struct {
|
||
|
ds *dotsql.DotSql
|
||
|
db *sql.DB
|
||
|
sb *simplebox.SimpleBox
|
||
|
|
||
|
//cs *postgresCertificateStorage
|
||
|
rs *postgresRouteStorage
|
||
|
//ts *postgresTokenStorage
|
||
|
}
|
||
|
|
||
|
type postgresCertificateStorage struct {
|
||
|
*PostgresStorage
|
||
|
}
|
||
|
|
||
|
type postgresRouteStorage struct {
|
||
|
*PostgresStorage
|
||
|
}
|
||
|
|
||
|
type postgresTokenStorage struct {
|
||
|
*PostgresStorage
|
||
|
}
|
||
|
|
||
|
// NewPostgresStorage creates a new Storage instance backed by postgres at the
|
||
|
// given URL.
|
||
|
func NewPostgresStorage(url string, key *[32]byte) (Storage, error) {
|
||
|
db, err := sql.Open("postgres", url)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
data, err := dmigrations.Asset("postgres.sql")
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
buf := bytes.NewBuffer(data)
|
||
|
|
||
|
ds, err := dotsql.Load(buf)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
for k := range ds.QueryMap() {
|
||
|
log.Printf("preparing %s", k)
|
||
|
stmt, err := ds.Prepare(db, k)
|
||
|
if err != nil {
|
||
|
db.Close()
|
||
|
return nil, err
|
||
|
}
|
||
|
defer stmt.Close()
|
||
|
}
|
||
|
|
||
|
p := &PostgresStorage{
|
||
|
db: db,
|
||
|
ds: ds,
|
||
|
sb: simplebox.NewFromSecretKey(key),
|
||
|
}
|
||
|
|
||
|
//p.cs = &postgresCertificateStorage{p}
|
||
|
p.rs = &postgresRouteStorage{p}
|
||
|
//p.ts = &postgresTokenStorage{p}
|
||
|
|
||
|
return p, nil
|
||
|
}
|
||
|
|
||
|
// Certs gets the certificate storage interface.
|
||
|
func (p *PostgresStorage) Certs() Certs { return nil }
|
||
|
|
||
|
// Routes gets the route storage interface.
|
||
|
func (p *PostgresStorage) Routes() Routes { return p.rs }
|
||
|
|
||
|
// Tokens gets the token storage interface.
|
||
|
func (p *PostgresStorage) Tokens() Tokens { return nil }
|
||
|
|
||
|
// Close cleans up resources for this Storage.
|
||
|
func (p *PostgresStorage) Close() error { return p.db.Close() }
|
||
|
|
||
|
// interface compliance
|
||
|
var (
|
||
|
_ Storage = &PostgresStorage{}
|
||
|
//_ Certs = &postgresCertificateStorage{}
|
||
|
_ Routes = &postgresRouteStorage{}
|
||
|
//_ Tokens = &postgresTokenStorage{}
|
||
|
)
|
||
|
|
||
|
func (p *postgresRouteStorage) getRouteInner(ctx context.Context, arg string, kind string) (Route, error) {
|
||
|
r, err := p.ds.QueryRow(p.db, kind, arg)
|
||
|
if err != nil {
|
||
|
return Route{}, err
|
||
|
}
|
||
|
|
||
|
rt := Route{}
|
||
|
|
||
|
err = (&rt).Scan(r)
|
||
|
if err != nil {
|
||
|
return Route{}, err
|
||
|
}
|
||
|
|
||
|
return rt, nil
|
||
|
}
|
||
|
|
||
|
func (p *postgresRouteStorage) Get(ctx context.Context, id string) (Route, error) {
|
||
|
return p.getRouteInner(ctx, id, "find-one-route-by-id")
|
||
|
}
|
||
|
|
||
|
func (p *postgresRouteStorage) GetHost(ctx context.Context, host string) (Route, error) {
|
||
|
return p.getRouteInner(ctx, host, "find-one-route-by-host")
|
||
|
}
|
||
|
|
||
|
func (p *postgresRouteStorage) GetAll(ctx context.Context, user string) ([]Route, error) {
|
||
|
var result []Route
|
||
|
|
||
|
rows, err := p.ds.Query(p.db, "find-all-routes-for-user", user)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
defer rows.Close()
|
||
|
for rows.Next() {
|
||
|
rt := &Route{}
|
||
|
|
||
|
if err := rt.Scan(rows); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
result = append(result, *rt)
|
||
|
}
|
||
|
|
||
|
if err := rows.Err(); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
return result, nil
|
||
|
}
|
||
|
|
||
|
func (p *postgresRouteStorage) Put(ctx context.Context, r Route) (Route, error) {
|
||
|
if r.ID == "" {
|
||
|
r.ID = uuid.New()
|
||
|
}
|
||
|
|
||
|
_, err := p.ds.Exec(p.db, "insert-route", r.ID, r.Hostname)
|
||
|
if err != nil {
|
||
|
return Route{}, err
|
||
|
}
|
||
|
|
||
|
return p.Get(ctx, r.ID)
|
||
|
}
|
||
|
|
||
|
func (p *postgresRouteStorage) Delete(ctx context.Context, r Route) (Route, error) {
|
||
|
rt, err := p.Get(ctx, r.ID)
|
||
|
if err != nil {
|
||
|
return Route{}, err
|
||
|
}
|
||
|
|
||
|
_, err = p.ds.Exec(p.db, "delete-one-route", rt.ID, rt.Hostname)
|
||
|
if err != nil {
|
||
|
return Route{}, err
|
||
|
}
|
||
|
|
||
|
return rt, nil
|
||
|
}
|