auth
auth/session_postgres.go
Wire up the postgres database for authd. Have authd use the AUTH_PG_DB environment variable to detect support for the postgres *Stores, and if postgres is supported, use it. If postgres isn't supported, fall back on the in-memory store. Also create-if-not-exists the test scopes, instead of panicking when the scope already exists.
| paddy@154 | 1 package auth |
| paddy@154 | 2 |
| paddy@154 | 3 import ( |
| paddy@154 | 4 "time" |
| paddy@154 | 5 |
| paddy@154 | 6 "code.secondbit.org/uuid.hg" |
| paddy@154 | 7 |
| paddy@154 | 8 "github.com/lib/pq" |
| paddy@154 | 9 "github.com/secondbit/pan" |
| paddy@154 | 10 ) |
| paddy@154 | 11 |
| paddy@154 | 12 func (s Session) GetSQLTableName() string { |
| paddy@154 | 13 return "sessions" |
| paddy@154 | 14 } |
| paddy@154 | 15 |
| paddy@154 | 16 func (p *postgres) createSessionSQL(session Session) *pan.Query { |
| paddy@154 | 17 fields, values := pan.GetFields(session) |
| paddy@154 | 18 query := pan.New(pan.POSTGRES, "INSERT INTO "+pan.GetTableName(session)) |
| paddy@154 | 19 query.Include("(" + pan.QueryList(fields) + ")") |
| paddy@154 | 20 query.Include("VALUES") |
| paddy@154 | 21 query.Include("("+pan.VariableList(len(values))+")", values...) |
| paddy@154 | 22 return query.FlushExpressions(" ") |
| paddy@154 | 23 } |
| paddy@154 | 24 |
| paddy@154 | 25 func (p *postgres) createSession(session Session) error { |
| paddy@154 | 26 query := p.createSessionSQL(session) |
| paddy@154 | 27 _, err := p.db.Exec(query.String(), query.Args...) |
| paddy@154 | 28 if e, ok := err.(*pq.Error); ok && e.Constraint == "sessions_pkey" { |
| paddy@154 | 29 err = ErrSessionAlreadyExists |
| paddy@154 | 30 } |
| paddy@154 | 31 return err |
| paddy@154 | 32 } |
| paddy@154 | 33 |
| paddy@154 | 34 func (p *postgres) getSessionSQL(id string) *pan.Query { |
| paddy@154 | 35 var session Session |
| paddy@154 | 36 fields, _ := pan.GetFields(session) |
| paddy@154 | 37 query := pan.New(pan.POSTGRES, "SELECT "+pan.QueryList(fields)+" FROM "+pan.GetTableName(session)) |
| paddy@154 | 38 query.IncludeWhere() |
| paddy@154 | 39 query.Include(pan.GetUnquotedColumn(session, "ID")+" = ?", id) |
| paddy@154 | 40 return query.FlushExpressions(" ") |
| paddy@154 | 41 } |
| paddy@154 | 42 |
| paddy@154 | 43 func (p *postgres) getSession(id string) (Session, error) { |
| paddy@154 | 44 query := p.getSessionSQL(id) |
| paddy@154 | 45 rows, err := p.db.Query(query.String(), query.Args...) |
| paddy@154 | 46 if err != nil { |
| paddy@154 | 47 return Session{}, err |
| paddy@154 | 48 } |
| paddy@154 | 49 var session Session |
| paddy@154 | 50 var found bool |
| paddy@154 | 51 for rows.Next() { |
| paddy@154 | 52 err := pan.Unmarshal(rows, &session) |
| paddy@154 | 53 if err != nil { |
| paddy@154 | 54 return session, err |
| paddy@154 | 55 } |
| paddy@154 | 56 found = true |
| paddy@154 | 57 } |
| paddy@154 | 58 if err = rows.Err(); err != nil { |
| paddy@154 | 59 return session, err |
| paddy@154 | 60 } |
| paddy@154 | 61 if !found { |
| paddy@154 | 62 return session, ErrSessionNotFound |
| paddy@154 | 63 } |
| paddy@154 | 64 return session, nil |
| paddy@154 | 65 } |
| paddy@154 | 66 |
| paddy@154 | 67 func (p *postgres) removeSessionSQL(id string) *pan.Query { |
| paddy@154 | 68 var session Session |
| paddy@154 | 69 query := pan.New(pan.POSTGRES, "DELETE FROM "+pan.GetTableName(session)) |
| paddy@154 | 70 query.IncludeWhere() |
| paddy@154 | 71 query.Include(pan.GetUnquotedColumn(session, "ID")+" = ?", id) |
| paddy@154 | 72 return query.FlushExpressions(" ") |
| paddy@154 | 73 } |
| paddy@154 | 74 |
| paddy@154 | 75 func (p *postgres) removeSession(id string) error { |
| paddy@154 | 76 query := p.removeSessionSQL(id) |
| paddy@154 | 77 res, err := p.db.Exec(query.String(), query.Args...) |
| paddy@154 | 78 if err != nil { |
| paddy@154 | 79 return err |
| paddy@154 | 80 } |
| paddy@154 | 81 rows, err := res.RowsAffected() |
| paddy@154 | 82 if err != nil { |
| paddy@154 | 83 return err |
| paddy@154 | 84 } |
| paddy@154 | 85 if rows < 1 { |
| paddy@154 | 86 return ErrSessionNotFound |
| paddy@154 | 87 } |
| paddy@154 | 88 return nil |
| paddy@154 | 89 } |
| paddy@154 | 90 |
| paddy@154 | 91 func (p *postgres) listSessionsSQL(profile uuid.ID, before time.Time, num int64) *pan.Query { |
| paddy@154 | 92 var session Session |
| paddy@154 | 93 fields, _ := pan.GetFields(session) |
| paddy@154 | 94 query := pan.New(pan.POSTGRES, "SELECT "+pan.QueryList(fields)+" FROM "+pan.GetTableName(session)) |
| paddy@154 | 95 query.IncludeWhere() |
| paddy@154 | 96 query.Include(pan.GetUnquotedColumn(session, "ProfileID")+" = ?", profile) |
| paddy@154 | 97 if !before.IsZero() { |
| paddy@154 | 98 query.Include(pan.GetUnquotedColumn(session, "Created")+" < ?", before) |
| paddy@154 | 99 } |
| paddy@154 | 100 query.FlushExpressions(" AND ") |
| paddy@154 | 101 if num > 0 { |
| paddy@154 | 102 query.IncludeLimit(num) |
| paddy@154 | 103 } |
| paddy@154 | 104 return query.FlushExpressions(" ") |
| paddy@154 | 105 } |
| paddy@154 | 106 |
| paddy@154 | 107 func (p *postgres) listSessions(profile uuid.ID, before time.Time, num int64) ([]Session, error) { |
| paddy@154 | 108 query := p.listSessionsSQL(profile, before, num) |
| paddy@154 | 109 rows, err := p.db.Query(query.String(), query.Args...) |
| paddy@154 | 110 if err != nil { |
| paddy@154 | 111 return []Session{}, err |
| paddy@154 | 112 } |
| paddy@154 | 113 var sessions []Session |
| paddy@154 | 114 for rows.Next() { |
| paddy@154 | 115 var session Session |
| paddy@154 | 116 err := pan.Unmarshal(rows, &session) |
| paddy@154 | 117 if err != nil { |
| paddy@154 | 118 return sessions, err |
| paddy@154 | 119 } |
| paddy@154 | 120 sessions = append(sessions, session) |
| paddy@154 | 121 } |
| paddy@154 | 122 if err = rows.Err(); err != nil { |
| paddy@154 | 123 return sessions, err |
| paddy@154 | 124 } |
| paddy@154 | 125 return sessions, nil |
| paddy@154 | 126 } |