forked from vmware-archive/atc
/
base_resource_type.go
95 lines (81 loc) · 2.51 KB
/
base_resource_type.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
package dbng
import (
"database/sql"
"errors"
sq "github.com/Masterminds/squirrel"
"github.com/lib/pq"
)
var ErrBaseResourceTypeAlreadyExists = errors.New("base-resource-type-already-exists")
// BaseResourceType represents a resource type provided by workers.
//
// It is created via worker registration. All creates are upserts.
//
// It is removed by gc.BaseResourceTypeCollector, once there are no references
// to it from worker_base_resource_types.
type BaseResourceType struct {
Name string // The name of the type, e.g. 'git'.
}
// UsedBaseResourceType is created whenever a ResourceConfig is used, either
// for a build, a resource in the pipeline, or a resource type in the pipeline.
//
// So long as the UsedBaseResourceType's ID is referenced by a ResourceConfig
// that is in use, this guarantees that the BaseResourceType will not be
// removed. That is to say that its "Use" is vicarious.
type UsedBaseResourceType struct {
ID int // The ID of the BaseResourceType.
Name string
}
// FindOrCreate looks for an existing BaseResourceType and creates it if it
// doesn't exist. It returns a UsedBaseResourceType.
//
// Note that if the BaseResourceType already existed, there's a chance that it
// will be garbage-collected before the referencing ResourceConfig can be
// created and used.
//
// This method can return ErrBaseResourceTypeAlreadyExists if two concurrent
// FindOrCreates clashed. The caller should retry from the start of the
// transaction.
func (brt BaseResourceType) FindOrCreate(tx Tx) (*UsedBaseResourceType, error) {
ubrt, found, err := brt.Find(tx)
if err != nil {
return nil, err
}
if found {
return ubrt, nil
}
return brt.create(tx)
}
func (brt BaseResourceType) Find(tx Tx) (*UsedBaseResourceType, bool, error) {
var id int
err := psql.Select("id").From("base_resource_types").Where(sq.Eq{
"name": brt.Name,
}).RunWith(tx).QueryRow().Scan(&id)
if err != nil {
if err == sql.ErrNoRows {
return nil, false, nil
}
return nil, false, err
}
return &UsedBaseResourceType{ID: id, Name: brt.Name}, true, nil
}
func (brt BaseResourceType) create(tx Tx) (*UsedBaseResourceType, error) {
var id int
err := psql.Insert("base_resource_types").
Columns(
"name",
).
Values(
brt.Name,
).
Suffix("RETURNING id").
RunWith(tx).
QueryRow().
Scan(&id)
if err != nil {
if pqErr, ok := err.(*pq.Error); ok && pqErr.Code.Name() == "unique_violation" {
return nil, ErrBaseResourceTypeAlreadyExists
}
return nil, err
}
return &UsedBaseResourceType{ID: id, Name: brt.Name}, nil
}