From 932de9cd0d57fbc8cd559103e2156e974471f9a4 Mon Sep 17 00:00:00 2001 From: Patrick McDonagh Date: Thu, 5 Oct 2017 17:25:59 -0500 Subject: [PATCH] Should complete DL-1, adds functions for getting latest values of all tags --- app.go | 1 + handler_tagvalue.go | 11 +++++ main.go | 2 + model_tag.go | 114 ++++++++++++++++++++++++++++--------------- model_tagvalue.go | 64 +++++++++++++++++++++++- test_test.go | 2 + testtagvalue_test.go | 4 ++ 7 files changed, 157 insertions(+), 41 deletions(-) diff --git a/app.go b/app.go index 3e70303..fde8fbe 100644 --- a/app.go +++ b/app.go @@ -98,6 +98,7 @@ func (a *App) initializeRoutes() { a.Router.HandleFunc("/api/v1/tag/{id:[0-9]+}", a.deleteTag).Methods("DELETE") a.Router.HandleFunc("/api/v1/tagValues", a.getTagValues).Methods("GET") + a.Router.HandleFunc("/api/v1/tagValues/latest", a.getLatestTagValues).Methods("GET") a.Router.HandleFunc("/api/v1/tagValue", a.createTagValue).Methods("POST") a.Router.HandleFunc("/api/v1/tagValue/{id:[0-9]+}", a.getTagValue).Methods("GET") a.Router.HandleFunc("/api/v1/tagValue/{id:[0-9]+}", a.updateTagValue).Methods("PUT") diff --git a/handler_tagvalue.go b/handler_tagvalue.go index 9f57b81..03cf752 100644 --- a/handler_tagvalue.go +++ b/handler_tagvalue.go @@ -109,3 +109,14 @@ func (a *App) deleteTagValue(w http.ResponseWriter, r *http.Request) { respondWithJSON(w, http.StatusOK, map[string]string{"result": "success"}) } + +func (a *App) getLatestTagValues(w http.ResponseWriter, r *http.Request) { + + latesTagValues, err := getLatestTagValues(a.DB) + if err != nil { + respondWithError(w, http.StatusInternalServerError, err.Error()) + return + } + + respondWithJSON(w, http.StatusOK, latesTagValues) +} diff --git a/main.go b/main.go index 1c2dd1f..ed41047 100644 --- a/main.go +++ b/main.go @@ -26,6 +26,8 @@ func main() { ensureFileTableExists(a.DB) ensureTagClassTableExists(a.DB) ensureTagTableExists(a.DB) + ensureTagValueTableExists(a.DB) + ensureLatestTagValueTableExists(a.DB) seedDeviceTypeData(a.DB) seedDataTypeData(a.DB) diff --git a/model_tag.go b/model_tag.go index c0a6a0e..2b284b6 100644 --- a/model_tag.go +++ b/model_tag.go @@ -2,6 +2,7 @@ package main import ( "database/sql" + "fmt" "log" "time" ) @@ -53,15 +54,31 @@ const tagTableCreationQuery = `CREATE TABLE IF NOT EXISTS tags ( CONSTRAINT fk_datatype FOREIGN KEY (dataTypeId) REFERENCES dataTypes(id) );` +const latestTagValueCreationQuery = `CREATE TABLE IF NOT EXISTS latestValues ( + id int(10) unsigned NOT NULL AUTO_INCREMENT, + tagId int(10) unsigned, + val varchar(64), + createdAt datetime, + updatedAt datetime, + PRIMARY KEY (id), + CONSTRAINT fk_tagId FOREIGN KEY (tagId) REFERENCES tags(id) ON DELETE CASCADE + );` + func ensureTagTableExists(db *sql.DB) { if _, err := db.Exec(tagTableCreationQuery); err != nil { log.Fatal(err) } } +func ensureLatestTagValueTableExists(db *sql.DB) { + if _, err := db.Exec(latestTagValueCreationQuery); err != nil { + log.Fatal(err) + } +} + // getTag : used during GET command func (t *Tag) getTag(db *sql.DB) error { - sqlQuery := `SELECT + sqlQuery := `SELECT tags.name, tags.tagName, tags.tagClassId, @@ -79,7 +96,7 @@ func (t *Tag) getTag(db *sql.DB) error { deviceTypes.createdAt, deviceTypes.updatedAt, devices.address, - devices.createdAt, + devices.createdAt, devices.updatedAt, tags.description, tags.dataTypeId, @@ -94,13 +111,13 @@ func (t *Tag) getTag(db *sql.DB) error { tags.units, tags.maxExpected, tags.minExpected, - tags.createdAt, - tags.updatedAt - FROM tags + tags.createdAt, + tags.updatedAt + FROM tags JOIN tagClasses ON tags.tagClassId = tagClasses.id JOIN devices ON tags.deviceId = devices.id JOIN deviceTypes ON devices.deviceTypeId = deviceTypes.id - JOIN dataTypes ON tags.dataTypeId = dataTypes.id + JOIN dataTypes ON tags.dataTypeId = dataTypes.id WHERE tags.id=?` return db.QueryRow(sqlQuery, t.ID).Scan( &t.Name, @@ -142,19 +159,19 @@ func (t *Tag) getTag(db *sql.DB) error { // updateTag : used during PUT command func (t *Tag) updateTag(db *sql.DB) error { sqlQuery := `UPDATE tags SET - name=?, - tagName=?, - tagClassId=?, - deviceId=?, - description=?, - dataTypeId=?, - changeThreshold=?, - guaranteeSec=?, - mapFunction=?, - units=?, - minExpected=?, - maxExpected=?, - updatedAt=? + name=?, + tagName=?, + tagClassId=?, + deviceId=?, + description=?, + dataTypeId=?, + changeThreshold=?, + guaranteeSec=?, + mapFunction=?, + units=?, + minExpected=?, + maxExpected=?, + updatedAt=? WHERE id=?` updStmt, updErr := db.Prepare(sqlQuery) if updErr != nil { @@ -176,36 +193,53 @@ func (t *Tag) deleteTag(db *sql.DB) error { // createTag : used during PUSH command func (t *Tag) createTag(db *sql.DB) error { - sqlQuery := `INSERT INTO tags ( - name, - tagName, - tagClassId, - deviceId, - description, - dataTypeId, - changeThreshold, - guaranteeSec, - mapFunction, - units, - minExpected, - maxExpected, + tagSQLQuery := `INSERT INTO tags ( + name, + tagName, + tagClassId, + deviceId, + description, + dataTypeId, + changeThreshold, + guaranteeSec, + mapFunction, + units, + minExpected, + maxExpected, createdAt, updatedAt) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` - stmtIns, insErr := db.Prepare(sqlQuery) + + valSQLQuery := `INSERT INTO latestValues (tagId, val, createdAt, updatedAt) VALUES (?, ?, ?, ?)` + + stmtIns, insErr := db.Prepare(tagSQLQuery) if insErr != nil { panic(insErr.Error()) // proper error handling instead of panic in your app } defer stmtIns.Close() // Close the statement when we leave main() / the program terminates - _, err := stmtIns.Exec(t.Name, t.TagName, t.TagClassID, t.DeviceID, + stmtInsVal, insValErr := db.Prepare(valSQLQuery) + if insValErr != nil { + panic(insValErr.Error()) // proper error handling instead of panic in your app + } + defer stmtInsVal.Close() // Close the statement when we leave main() / the program terminates + + res, err := stmtIns.Exec(t.Name, t.TagName, t.TagClassID, t.DeviceID, t.Description, t.DataTypeID, t.ChangeThreshold, t.GuaranteeSec, t.MapFunction, t.Units, t.MinExpected, t.MaxExpected, time.Now(), time.Now()) + + lastID, idErr := res.LastInsertId() + if idErr == nil { + _, valErr := stmtInsVal.Exec(lastID, "0.0", time.Now(), time.Now()) + return valErr + } + fmt.Printf("\n%s -- %d\n", "Invalid last inserted id", lastID) + return err } // getTags : used during GET command for all func getTags(db *sql.DB, start, count int) (Tags, error) { - sqlQuery := `SELECT + sqlQuery := `SELECT tags.ID, tags.name, tags.tagName, @@ -224,7 +258,7 @@ func getTags(db *sql.DB, start, count int) (Tags, error) { deviceTypes.createdAt, deviceTypes.updatedAt, devices.address, - devices.createdAt, + devices.createdAt, devices.updatedAt, tags.description, tags.dataTypeId, @@ -239,13 +273,13 @@ func getTags(db *sql.DB, start, count int) (Tags, error) { tags.units, tags.maxExpected, tags.minExpected, - tags.createdAt, - tags.updatedAt - FROM tags + tags.createdAt, + tags.updatedAt + FROM tags JOIN tagClasses ON tags.tagClassId = tagClasses.id JOIN devices ON tags.deviceId = devices.id JOIN deviceTypes ON devices.deviceTypeId = deviceTypes.id - JOIN dataTypes ON tags.dataTypeId = dataTypes.id + JOIN dataTypes ON tags.dataTypeId = dataTypes.id LIMIT ? OFFSET ?;` getStmt, prepErr := db.Prepare(sqlQuery) diff --git a/model_tagvalue.go b/model_tagvalue.go index 7b425bb..6ffc3c3 100644 --- a/model_tagvalue.go +++ b/model_tagvalue.go @@ -18,9 +18,25 @@ type TagValue struct { UpdatedAt time.Time `json:"updatedAt"` } +// LatestTagValue : latest tag value struct +type LatestTagValue struct { + ID int `json:"id"` + TagID int `json:"tagId"` + Val string `json:"val"` + TagName string `json:"tagName"` + Units string `json:"units"` + DataType string `json:"dataType"` + MaxExpected float32 `json:"maxExpected"` + MinExpected float32 `json:"minExpected"` + UpdatedAt time.Time `json:"updatedAt"` +} + // TagValues : a list of TagValue items type TagValues []TagValue +// LatestTagValues : a list of LatestTagValue items +type LatestTagValues []LatestTagValue + const tagValueTableCreationQuery = `CREATE TABLE IF NOT EXISTS tagValues ( id int(10) unsigned NOT NULL AUTO_INCREMENT, tagId int(10) unsigned, @@ -28,7 +44,7 @@ const tagValueTableCreationQuery = `CREATE TABLE IF NOT EXISTS tagValues ( createdAt datetime, updatedAt datetime, PRIMARY KEY (id), - CONSTRAINT fk_tag FOREIGN KEY (tagId) REFERENCES tags(id) + CONSTRAINT fk_tag FOREIGN KEY (tagId) REFERENCES tags(id) ON DELETE CASCADE )` func ensureTagValueTableExists(db *sql.DB) { @@ -80,6 +96,18 @@ func (t *TagValue) createTagValue(db *sql.DB) error { defer stmtIns.Close() // Close the statement when we leave main() / the program terminates _, err := stmtIns.Exec(t.TagID, t.Val, time.Now(), time.Now()) + + if err == nil { + valStmtUpd, valStmtErr := db.Prepare("UPDATE latestValues SET val=?, updatedAt=? WHERE tagId=?") + if valStmtErr != nil { + panic(valStmtErr.Error()) // proper error handling instead of panic in your app + } + defer valStmtUpd.Close() // Close the statement when we leave main() / the program terminates + + _, updErr := valStmtUpd.Exec(t.Val, time.Now(), t.TagID) + return updErr + } + return err } @@ -118,3 +146,37 @@ func getTagValues(db *sql.DB, start, count int) (TagValues, error) { return tagValues, nil } + +// getLatestTagValues : used to get all latest tag values +func getLatestTagValues(db *sql.DB) (LatestTagValues, error) { + tagValues := LatestTagValues{} + sqlQuery := `SELECT latestValues.id, + latestValues.tagId, + latestValues.val, + tags.name, + tags.units, + tags.minExpected, + tags.maxExpected, + dataTypes.dataType, + latestValues.updatedAt + FROM latestValues + JOIN tags on latestValues.tagId = tags.id + JOIN dataTypes ON tags.dataTypeId = dataTypes.id` + + rows, err := db.Query(sqlQuery) + if err != nil { + return nil, err + } + defer rows.Close() + + for rows.Next() { + var tag LatestTagValue + if err := rows.Scan(&tag.ID, &tag.TagID, &tag.Val, &tag.TagName, &tag.Units, &tag.MinExpected, &tag.MaxExpected, &tag.DataType, &tag.UpdatedAt); err != nil { + return nil, err + } + tagValues = append(tagValues, tag) + + } + return tagValues, nil + +} diff --git a/test_test.go b/test_test.go index 5933854..b8f4941 100644 --- a/test_test.go +++ b/test_test.go @@ -31,6 +31,7 @@ func TestMain(m *testing.M) { ensureTagClassTableExists(a.DB) ensureTagTableExists(a.DB) ensureTagValueTableExists(a.DB) + ensureLatestTagValueTableExists(a.DB) code := m.Run() @@ -42,6 +43,7 @@ func TestMain(m *testing.M) { clearTagClassTable() clearTagTable() clearTagValueTable() + clearLatestTagValueTable() os.Exit(code) } diff --git a/testtagvalue_test.go b/testtagvalue_test.go index f79ad55..2dc95e8 100644 --- a/testtagvalue_test.go +++ b/testtagvalue_test.go @@ -13,6 +13,10 @@ func clearTagValueTable() { a.DB.Exec("DELETE FROM tagValues") a.DB.Exec("ALTER TABLE tagValues AUTO_INCREMENT = 1") } +func clearLatestTagValueTable() { + a.DB.Exec("DELETE FROM latestValues") + a.DB.Exec("ALTER TABLE latestValues AUTO_INCREMENT = 1") +} func TestEmptyTagValueTable(t *testing.T) { clearTagValueTable()