Should complete DL-1, adds functions for getting latest values of all tags

This commit is contained in:
Patrick McDonagh
2017-10-05 17:25:59 -05:00
parent 3f20496dfa
commit 932de9cd0d
7 changed files with 157 additions and 41 deletions

1
app.go
View File

@@ -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")

View File

@@ -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)
}

View File

@@ -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)

View File

@@ -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)

View File

@@ -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
}

View File

@@ -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)
}

View File

@@ -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()