scopes

Paddy 2015-12-13

2:a64a25ae2db1 Go to Latest

scopes/scope_postgres.go

Port over Postgres storage and tests. Do the minimum possible port of the code from auth to get Postgres working and make the tests run and pass again. This leaves a bug where the ErrScopeAlreadyExists type, when populatd from Postgres, contains the entire error string returned from the database, instead of parsing the ID itself out. Which is a thing we should do and add a test for.

History
paddy@2 1 package scopes
paddy@2 2
paddy@2 3 import (
paddy@2 4 "code.secondbit.org/scopes.hg/types"
paddy@2 5 "golang.org/x/net/context"
paddy@2 6
paddy@2 7 "github.com/lib/pq"
paddy@2 8 "github.com/secondbit/pan"
paddy@2 9 )
paddy@2 10
paddy@2 11 func (p *postgres) createScopesSQL(scopes []scopeTypes.Scope) *pan.Query {
paddy@2 12 fields, _ := pan.GetFields(scopes[0])
paddy@2 13 query := pan.New(pan.POSTGRES, "INSERT INTO "+pan.GetTableName(scopes[0]))
paddy@2 14 query.Include("(" + pan.QueryList(fields) + ")")
paddy@2 15 query.Include("VALUES")
paddy@2 16 query.FlushExpressions(" ")
paddy@2 17 for _, scope := range scopes {
paddy@2 18 _, values := pan.GetFields(scope)
paddy@2 19 query.Include("("+pan.VariableList(len(values))+")", values...)
paddy@2 20 }
paddy@2 21 return query.FlushExpressions(", ")
paddy@2 22 }
paddy@2 23
paddy@2 24 func (p *postgres) CreateScopes(scopes []scopeTypes.Scope, ctx context.Context) error {
paddy@2 25 if len(scopes) < 1 {
paddy@2 26 return nil
paddy@2 27 }
paddy@2 28 query := p.createScopesSQL(scopes)
paddy@2 29 _, err := p.db.Exec(query.String(), query.Args...)
paddy@2 30 if e, ok := err.(*pq.Error); ok && e.Constraint == "scopes_pkey" {
paddy@2 31 // BUG(paddy): we need to parse e.Detail to pull out the duplicate Scope ID
paddy@2 32 err = ErrScopeAlreadyExists(e.Detail)
paddy@2 33 }
paddy@2 34 return err
paddy@2 35 }
paddy@2 36
paddy@2 37 func (p *postgres) getScopesSQL(ids []string) *pan.Query {
paddy@2 38 var scope scopeTypes.Scope
paddy@2 39 intids := make([]interface{}, len(ids))
paddy@2 40 for pos, id := range ids {
paddy@2 41 intids[pos] = id
paddy@2 42 }
paddy@2 43 fields, _ := pan.GetFields(scope)
paddy@2 44 query := pan.New(pan.POSTGRES, "SELECT "+pan.QueryList(fields)+" FROM "+pan.GetTableName(scope))
paddy@2 45 query.IncludeWhere()
paddy@2 46 query.Include(pan.GetUnquotedColumn(scope, "ID") + " IN")
paddy@2 47 query.Include("("+pan.VariableList(len(ids))+")", intids...)
paddy@2 48 return query.FlushExpressions(" ")
paddy@2 49 }
paddy@2 50
paddy@2 51 func (p *postgres) GetScopes(ids []string, ctx context.Context) (map[string]scopeTypes.Scope, error) {
paddy@2 52 query := p.getScopesSQL(ids)
paddy@2 53 rows, err := p.db.Query(query.String(), query.Args...)
paddy@2 54 if err != nil {
paddy@2 55 return map[string]scopeTypes.Scope{}, err
paddy@2 56 }
paddy@2 57 scopes := map[string]scopeTypes.Scope{}
paddy@2 58 for rows.Next() {
paddy@2 59 var scope scopeTypes.Scope
paddy@2 60 err := pan.Unmarshal(rows, &scope)
paddy@2 61 if err != nil {
paddy@2 62 return scopes, err
paddy@2 63 }
paddy@2 64 scopes[scope.ID] = scope
paddy@2 65 }
paddy@2 66 if err = rows.Err(); err != nil {
paddy@2 67 return scopes, err
paddy@2 68 }
paddy@2 69 return scopes, nil
paddy@2 70 }
paddy@2 71
paddy@2 72 func (p *postgres) updateScopeSQL(change scopeTypes.ScopeChange) *pan.Query {
paddy@2 73 var scope scopeTypes.Scope
paddy@2 74 query := pan.New(pan.POSTGRES, "UPDATE "+pan.GetTableName(scope)+" SET ")
paddy@2 75 query.IncludeIfNotNil(pan.GetUnquotedColumn(scope, "Name")+" = ?", change.Name)
paddy@2 76 query.IncludeIfNotNil(pan.GetUnquotedColumn(scope, "Description")+" = ?", change.Description)
paddy@2 77 query.FlushExpressions(", ")
paddy@2 78 query.IncludeWhere()
paddy@2 79 query.Include(pan.GetUnquotedColumn(scope, "ID")+" = ?", change.ScopeID)
paddy@2 80 return query.FlushExpressions(" ")
paddy@2 81 }
paddy@2 82
paddy@2 83 func (p *postgres) UpdateScope(change scopeTypes.ScopeChange, ctx context.Context) error {
paddy@2 84 if change.Empty() {
paddy@2 85 return nil
paddy@2 86 }
paddy@2 87 query := p.updateScopeSQL(change)
paddy@2 88 res, err := p.db.Exec(query.String(), query.Args...)
paddy@2 89 if err != nil {
paddy@2 90 return err
paddy@2 91 }
paddy@2 92 rows, err := res.RowsAffected()
paddy@2 93 if err != nil {
paddy@2 94 return err
paddy@2 95 }
paddy@2 96 if rows < 1 {
paddy@2 97 return ErrScopeNotFound
paddy@2 98 }
paddy@2 99 return err
paddy@2 100 }
paddy@2 101
paddy@2 102 func (p *postgres) removeScopesSQL(ids []string) *pan.Query {
paddy@2 103 var scope scopeTypes.Scope
paddy@2 104 intids := make([]interface{}, len(ids))
paddy@2 105 for pos, id := range ids {
paddy@2 106 intids[pos] = id
paddy@2 107 }
paddy@2 108 query := pan.New(pan.POSTGRES, "DELETE FROM "+pan.GetTableName(scope))
paddy@2 109 query.IncludeWhere()
paddy@2 110 query.Include(pan.GetUnquotedColumn(scope, "ID") + " IN")
paddy@2 111 query.Include("("+pan.VariableList(len(ids))+")", intids...)
paddy@2 112 return query.FlushExpressions(" ")
paddy@2 113 }
paddy@2 114
paddy@2 115 func (p *postgres) RemoveScopes(ids []string, ctx context.Context) error {
paddy@2 116 query := p.removeScopesSQL(ids)
paddy@2 117 res, err := p.db.Exec(query.String(), query.Args...)
paddy@2 118 if err != nil {
paddy@2 119 return err
paddy@2 120 }
paddy@2 121 rows, err := res.RowsAffected()
paddy@2 122 if err != nil {
paddy@2 123 return err
paddy@2 124 }
paddy@2 125 if rows < 1 {
paddy@2 126 return ErrScopeNotFound
paddy@2 127 }
paddy@2 128 return nil
paddy@2 129 }
paddy@2 130
paddy@2 131 func (p *postgres) listScopesSQL() *pan.Query {
paddy@2 132 var scope scopeTypes.Scope
paddy@2 133 fields, _ := pan.GetFields(scope)
paddy@2 134 query := pan.New(pan.POSTGRES, "SELECT "+pan.QueryList(fields)+" FROM "+pan.GetTableName(scope))
paddy@2 135 return query.FlushExpressions(" ")
paddy@2 136 }
paddy@2 137
paddy@2 138 func (p *postgres) ListScopes(ctx context.Context) ([]scopeTypes.Scope, error) {
paddy@2 139 query := p.listScopesSQL()
paddy@2 140 rows, err := p.db.Query(query.String(), query.Args...)
paddy@2 141 if err != nil {
paddy@2 142 return []scopeTypes.Scope{}, err
paddy@2 143 }
paddy@2 144 var scopes []scopeTypes.Scope
paddy@2 145 for rows.Next() {
paddy@2 146 var scope scopeTypes.Scope
paddy@2 147 err = pan.Unmarshal(rows, &scope)
paddy@2 148 if err != nil {
paddy@2 149 return scopes, err
paddy@2 150 }
paddy@2 151 scopes = append(scopes, scope)
paddy@2 152 }
paddy@2 153 if err = rows.Err(); err != nil {
paddy@2 154 return scopes, err
paddy@2 155 }
paddy@2 156 return scopes, nil
paddy@2 157 }