package main import ( "database/sql" "log" "time" _ "github.com/lib/pq" ) type Session struct { Id string UserId int64 Created time.Time } type User struct { Id int64 Name string Password []byte } type Store interface { GetSession(id string) (*Session, bool) NewSession(userId int64) *Session GetUser(name string) (*User, bool) DeleteSession(id string) ChangePassword(userId int64, hash []byte) } type PgStore struct { *sql.DB sessionCache map[string]*Session } func NewPgStore(database string) *PgStore { db, err := sql.Open("postgres", database) if err != nil { log.Panic(err) } return &PgStore{db, make(map[string]*Session)} } func (store *PgStore) GetSession(id string) (*Session, bool) { s, ok := store.sessionCache[id] if ok { return s, true } s = new(Session) row := store.QueryRow( "SELECT id, user_id, created_at FROM sessions WHERE id = $1", id, ) if err := row.Scan(&s.Id, &s.UserId, &s.Created); err != nil { return nil, false } store.sessionCache[s.Id] = s return s, true } func (store *PgStore) NewSession(userId int64) *Session { s := &Session{UserId: userId} store.QueryRow( "INSERT INTO sessions(user_id) VALUES ($1) RETURNING id, created_at", userId, ).Scan(&s.Id, &s.Created) store.sessionCache[s.Id] = s return s } func (store *PgStore) DeleteSession(id string) { store.Exec("DELETE FROM sessions WHERE id = $1", id) delete(store.sessionCache, id) } func (store *PgStore) ChangePassword(userId int64, hash []byte) { store.Exec("UPDATE users SET password=$1 WHERE id=$2", hash, userId) } func (store *PgStore) GetUser(name string) (*User, bool) { u := &User{Name: name} row := store.QueryRow( "SELECT id, password FROM users WHERE name = $1", name, ) if err := row.Scan(&u.Id, &u.Password); err != nil { return nil, false } return u, true }