-
Notifications
You must be signed in to change notification settings - Fork 0
/
db.go
152 lines (128 loc) · 4.94 KB
/
db.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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// database functions
package main
import (
"database/sql"
"log"
"strconv"
"strings"
"time"
// blank import required for DB package
_ "github.com/go-sql-driver/mysql"
"github.com/google/uuid"
"github.com/x1um1n/checkerr"
)
// DB is the global DB handler
var DB *sql.DB
// InitDB creates the DB handler and a test connection to confirm it works
func InitDB() {
log.Printf("Connecting to the %s database on %s", K.String("dbschema"), K.String("dbhost"))
connstr := K.String("dbuser") + ":" + K.String("dbpasswd") + "@tcp(" + K.String("dbhost") + ":" + K.String("dbport") + ")/" + K.String("dbschema")
var err error
DB, err = sql.Open("mysql", connstr)
checkerr.CheckFatal(err, "Error creating database object")
for i := 0; i < K.Int("dbretries"); i++ {
err = DB.Ping()
if err == nil {
log.Println("Database connection established")
break
} //get out of the loop
if i < K.Int("dbretries") {
checkerr.Check(err, "Error connecting to database... retrying in 5s")
time.Sleep(5 * time.Second)
} else {
checkerr.CheckFatal(err, "Error connecting to database :(")
}
}
}
// getSurvey retrieves a specified survey from the db and returns
func getSurvey(sid string) (s Survey, e error) {
log.Println("Getting survey " + sid)
qry, e := DB.Prepare("SELECT * FROM surveys WHERE survey_id = '" + sid + "'")
defer qry.Close()
if !checkerr.Check(e, "Error preparing SELECT from surveys") {
row := qry.QueryRow()
switch e = row.Scan(&s.SurveyID, &s.PathID, &s.Date, &s.User, &s.Detail, &s.ImageIDs); e {
case sql.ErrNoRows:
checkerr.Check(e, "No survey found for "+sid)
case nil:
s.Images = getImages(s.ImageIDs)
default:
checkerr.Check(e, "Error reading survey data for "+sid)
}
}
return
}
// putSurvey writes a survey struct to the DB
// if a survey record already exists with the supplied ID, it will be overwritten
func putSurvey(s Survey) (e error) {
_, err := getSurvey(s.SurveyID)
if err == sql.ErrNoRows {
log.Println("Inserting new survey for path " + s.PathID)
stmt, es := DB.Prepare("INSERT INTO surveys (`survey_id`,`path_id`,`survey_date`,`survey_submitted_by`,`survey_detail`,`image_ids`) VALUES (UUID(),?,?,?,?,?)")
checkerr.Check(es, "Error preparing INSERT")
defer stmt.Close()
s.ImageIDs = makeImageCSL(s.Images)
_, err = stmt.Exec(s.PathID, s.Date, s.User, s.Detail, s.ImageIDs)
checkerr.Check(err, "Error inserting survey:", s.PathID, s.Date, s.User, s.Detail, s.ImageIDs)
} else {
log.Println("Updating survey " + s.SurveyID)
if s.ImageIDs == "" {
s.ImageIDs = makeImageCSL(s.Images)
}
stmt, es := DB.Prepare("UPDATE surveys SET `path_id` = '" + s.PathID + "',`survey_date` = '" + s.Date + "',`survey_submitted_by` = '" + s.User + "',`survey_detail` = '" + s.Detail + "',`image_ids` = '" + s.ImageIDs + "'")
checkerr.Check(es, "Error preparing UPDATE")
defer stmt.Close()
_, err = stmt.Exec()
checkerr.Check(err, "Error updating survey:", s.PathID, s.Date, s.User, s.Detail, s.ImageIDs)
}
return
}
// delSurvey deletes a survey record from the DB and purges any associated images
func delSurvey(sid string) (e error) {
log.Println("Finding survey to delete: " + sid)
_, e = getSurvey(sid)
if !checkerr.Check(e, "Survey not found in database") {
stmt, e := DB.Prepare("DELETE FROM surveys WHERE `survey_id` = ?")
checkerr.Check(e, "Error preparing DELETE")
defer stmt.Close()
_, e = stmt.Exec(sid)
if !checkerr.Check(e, "Error deleting survey: ", sid) {
log.Printf("Survey %s successfully deleted\n", sid)
//fixme: purge images
}
}
return
}
// getImages takes a CSL of imageIDs and returns a slice containing details of the relevant images
func getImages(imageIDs string) (ims []Image) {
img := strings.Split(imageIDs, ",")
for _, im := range img {
qry, e := DB.Prepare("SELECT * FROM images WHERE image_id = '" + im + "'")
checkerr.Check(e, "Error preparing SELECT from images")
defer qry.Close()
var i Image
row := qry.QueryRow()
switch e = row.Scan(&i.ImageID, &i.Filename, &i.S3Path, &i.Location.Latitude, &i.Location.Longitude); e {
case sql.ErrNoRows:
log.Println("No images found for imageID " + im)
case nil:
ims = append(ims, i)
default:
checkerr.Check(e, "Error reading image data for "+im)
}
}
return
}
// putImage inserts an image record corresponding to an uploaded file
func putImage(im Image) (id string, e error) {
log.Println("Inserting new image for path " + im.S3Path)
stmt, e := DB.Prepare("INSERT INTO images (`image_id`,`filename`,`s3-location`,`image_latitude`,`image_longitude`) VALUES (?,?,?,?,?)")
checkerr.Check(e, "Error preparing INSERT")
defer stmt.Close()
id = uuid.New().String()
_, e = stmt.Exec(id, im.Filename, im.S3Path, im.Location.Latitude, im.Location.Longitude)
if checkerr.Check(e, "Error inserting image record:", id, im.Filename, im.S3Path, strconv.FormatFloat(im.Location.Latitude, 'E', -1, 64), strconv.FormatFloat(im.Location.Longitude, 'E', -1, 64)) {
id = "" //blank out the id if the insert fails
}
return
}