// +build ignore 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 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 }