-
Notifications
You must be signed in to change notification settings - Fork 1
/
database.go
129 lines (101 loc) · 3.83 KB
/
database.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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package common
import (
"bytes"
"context"
"fmt"
"html/template"
"strconv"
"strings"
"github.com/Masterminds/sprig/v3"
"github.com/marema31/kamino/datasource"
"github.com/Sirupsen/logrus"
)
// ToSkipDatabase run the query (likely a SELECT COUNT) on the datasource
// return true if the query return a non-zero value in the only column of the only row.
func ToSkipDatabase(ctx context.Context, log *logrus.Entry, ds datasource.Datasourcer, admin bool, nodb bool, queries []SkipQuery) (bool, error) {
var needskip int
if len(queries) == 0 {
return false, nil
}
db, err := ds.OpenDatabase(log, admin, nodb)
if err != nil {
return false, err
}
defer ds.CloseDatabase(log, admin, nodb) //nolint: errcheck
for _, query := range queries {
err = db.QueryRowContext(ctx, query.query).Scan(&needskip)
if err != nil {
log.Errorf("Query of skip phase failed : %v", err)
return false, err
}
log.Debugf("Skip query: %s (%d ~ %d)", query.query, needskip, query.compareValue)
// If the query returned a 0 result we shoud do it, do not test other queries (AND) to allow test table exists and table contains something
if needskip == query.compareValue {
if !query.inverted {
log.Debugf("Skip query not skipped: %s", query.query)
return false, nil
}
} else {
if query.inverted {
log.Debugf("Skip query not skipped: %s", query.query)
return false, nil
}
}
}
return true, nil
}
// ParseQueries parse the queries templates from step configuration file.
func ParseQueries(log *logrus.Entry, queriesTmpl []string) ([]TemplateSkipQuery, error) {
var err error
tqueries := make([]TemplateSkipQuery, 0, len(queriesTmpl))
if len(queriesTmpl) == 0 {
log.Warning("No SQL queries provided")
}
for _, queryTmpl := range queriesTmpl {
cmpValue := 0
inverted := false
if queryTmpl == "" {
log.Error("No SQL query provided")
return nil, fmt.Errorf("the step cannot have an empty query to be executed: %w", ErrMissingParameter)
}
if strings.HasPrefix(queryTmpl, "!") {
inverted = true
queryTmpl = strings.TrimPrefix(queryTmpl, "!")
}
if strings.HasPrefix(queryTmpl, "=") {
endValue := strings.Index(queryTmpl, ":")
if endValue == -1 {
log.Errorf("Query %s has comparison but value has no terminator", queryTmpl)
return nil, fmt.Errorf("the step cannot have an incorrectly formatted query to be executed: %w", ErrWrongParameterValue)
}
cmpValue, err = strconv.Atoi(queryTmpl[1:endValue])
if err != nil {
log.Errorf("Query %s has comparison but incorrect value has been provided", queryTmpl)
return nil, fmt.Errorf("the step cannot have an incorrectly formatted query to be executed: %w", ErrWrongParameterValue)
}
queryTmpl = strings.TrimPrefix(queryTmpl, queryTmpl[0:endValue+1])
}
tquery, err := template.New("query").Funcs(sprig.FuncMap()).Parse(queryTmpl)
if err != nil {
log.Errorf("Parsing the SQL query template failed: %v", err)
return nil, fmt.Errorf("error parsing the query of step: %w", err)
}
tqueries = append(tqueries, TemplateSkipQuery{tquery: tquery, compareValue: cmpValue, inverted: inverted, text: queryTmpl})
}
return tqueries, nil
}
//RenderQueries render the templated query with parameter corresponding to the datasource.
func RenderQueries(log *logrus.Entry, tqueries []TemplateSkipQuery, tmplValues datasource.TmplValues) ([]SkipQuery, error) {
renderedQuery := bytes.NewBuffer(make([]byte, 0, 4096))
queries := make([]SkipQuery, 0, len(tqueries))
for _, tquery := range tqueries {
err := tquery.tquery.Execute(renderedQuery, tmplValues)
if err != nil {
log.Errorf("Rendering the '%s' query template failed :%v ", tquery.text, err)
return nil, err
}
queries = append(queries, SkipQuery{query: renderedQuery.String(), compareValue: tquery.compareValue, inverted: tquery.inverted})
renderedQuery.Reset()
}
return queries, nil
}