2020-05-21 15:40:24 +00:00
|
|
|
package db
|
2019-10-11 10:36:00 +00:00
|
|
|
|
|
|
|
import (
|
2019-12-07 15:53:49 +00:00
|
|
|
"context"
|
2020-05-03 12:04:08 +00:00
|
|
|
"database/sql"
|
2019-12-07 15:53:49 +00:00
|
|
|
"fmt"
|
2020-06-01 20:36:57 +00:00
|
|
|
"time"
|
2019-10-11 10:36:00 +00:00
|
|
|
|
2020-06-10 19:13:05 +00:00
|
|
|
"git.cryptic.systems/volker.raschek/flucky/pkg/types"
|
|
|
|
"git.cryptic.systems/volker.raschek/go-logger"
|
2019-10-11 10:36:00 +00:00
|
|
|
)
|
|
|
|
|
2020-05-03 12:04:08 +00:00
|
|
|
// Postgres implementation
|
|
|
|
type Postgres struct {
|
|
|
|
dbo *sql.DB
|
|
|
|
flogger logger.Logger
|
2020-06-01 20:36:57 +00:00
|
|
|
queries map[string]string
|
2020-05-03 12:04:08 +00:00
|
|
|
}
|
|
|
|
|
2020-06-27 19:12:00 +00:00
|
|
|
// Close closes the database and prevents new queries from starting. Close then
|
|
|
|
// waits for all queries that have started processing on the server to finish.
|
|
|
|
func (postgres *Postgres) Close() error {
|
|
|
|
return postgres.dbo.Close()
|
|
|
|
}
|
|
|
|
|
2020-05-21 15:40:24 +00:00
|
|
|
// DeleteDevices from the database
|
|
|
|
func (postgres *Postgres) DeleteDevices(ctx context.Context, deviceIDs ...string) error {
|
2020-06-01 20:36:57 +00:00
|
|
|
queryFile := "deleteDevice.sql"
|
|
|
|
query, present := postgres.queries[queryFile]
|
|
|
|
if !present {
|
2020-10-07 21:38:27 +00:00
|
|
|
return fmt.Errorf("Postgres-Backend: File %v not found", queryFile)
|
2020-05-03 12:04:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: false})
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Failed to begin new transaction: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
stmt, err := tx.Prepare(query)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Failed to prepare statement: %v", err)
|
|
|
|
}
|
|
|
|
defer stmt.Close()
|
|
|
|
|
2020-05-21 15:40:24 +00:00
|
|
|
for _, deviceID := range deviceIDs {
|
|
|
|
_, err = stmt.Exec(deviceID)
|
|
|
|
if err != nil {
|
|
|
|
tx.Rollback()
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return tx.Commit()
|
|
|
|
}
|
|
|
|
|
|
|
|
// DeleteSensors from the database
|
|
|
|
func (postgres *Postgres) DeleteSensors(ctx context.Context, sensorIDs ...string) error {
|
2020-06-01 20:36:57 +00:00
|
|
|
queryFile := "deleteSensor.sql"
|
|
|
|
query, present := postgres.queries[queryFile]
|
|
|
|
if !present {
|
2020-10-07 21:38:27 +00:00
|
|
|
return fmt.Errorf("Postgres-Backend: File %v not found", queryFile)
|
2020-05-21 15:40:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: false})
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Failed to begin new transaction: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
stmt, err := tx.Prepare(query)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Failed to prepare statement: %v", err)
|
|
|
|
}
|
|
|
|
defer stmt.Close()
|
|
|
|
|
|
|
|
for _, sensorID := range sensorIDs {
|
|
|
|
_, err = stmt.Exec(sensorID)
|
|
|
|
if err != nil {
|
|
|
|
tx.Rollback()
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return tx.Commit()
|
|
|
|
}
|
|
|
|
|
|
|
|
// InsertDevices into the database
|
|
|
|
func (postgres *Postgres) InsertDevices(ctx context.Context, devices ...*types.Device) error {
|
2020-06-01 20:36:57 +00:00
|
|
|
queryFile := "insertDevice.sql"
|
|
|
|
query, present := postgres.queries[queryFile]
|
|
|
|
if !present {
|
2020-10-07 21:38:27 +00:00
|
|
|
return fmt.Errorf("Postgres-Backend: File %v not found", queryFile)
|
2020-05-21 15:40:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: false})
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Failed to begin new transaction: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
stmt, err := tx.Prepare(query)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Failed to prepare statement: %v", err)
|
|
|
|
}
|
|
|
|
defer stmt.Close()
|
|
|
|
|
|
|
|
for _, device := range devices {
|
2020-10-07 21:38:27 +00:00
|
|
|
|
|
|
|
if device.CreationDate.Equal(time.Time{}) {
|
|
|
|
device.CreationDate = time.Now()
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err = stmt.Exec(
|
|
|
|
&device.ID,
|
|
|
|
&device.Name,
|
|
|
|
&device.Location,
|
|
|
|
&device.CreationDate,
|
|
|
|
&device.UpdateDate,
|
|
|
|
)
|
2020-05-21 15:40:24 +00:00
|
|
|
if err != nil {
|
|
|
|
tx.Rollback()
|
|
|
|
return fmt.Errorf("Failed to execute statement: %v", err)
|
|
|
|
}
|
2020-05-03 12:04:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return tx.Commit()
|
|
|
|
}
|
|
|
|
|
|
|
|
// InsertMeasuredValues into the database
|
2020-05-21 15:40:24 +00:00
|
|
|
func (postgres *Postgres) InsertMeasuredValues(ctx context.Context, measuredValues ...*types.MeasuredValue) error {
|
2020-09-21 17:36:42 +00:00
|
|
|
splittedMeasuredValues := make(map[types.MeasuredValueType][]*types.MeasuredValue, 0)
|
2019-10-11 10:36:00 +00:00
|
|
|
|
|
|
|
for _, measuredValue := range measuredValues {
|
2020-05-03 12:04:08 +00:00
|
|
|
if _, ok := splittedMeasuredValues[measuredValue.ValueType]; !ok {
|
|
|
|
splittedMeasuredValues[measuredValue.ValueType] = make([]*types.MeasuredValue, 0)
|
|
|
|
}
|
|
|
|
splittedMeasuredValues[measuredValue.ValueType] = append(splittedMeasuredValues[measuredValue.ValueType], measuredValue)
|
|
|
|
}
|
|
|
|
|
|
|
|
tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: false})
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Failed to begin new transaction: %v", err)
|
|
|
|
}
|
2019-12-07 17:57:41 +00:00
|
|
|
|
2020-05-03 12:04:08 +00:00
|
|
|
// General insert function
|
2020-06-01 20:36:57 +00:00
|
|
|
insert := func(tx *sql.Tx, queryFile string, measuredValues []*types.MeasuredValue) error {
|
|
|
|
query, present := postgres.queries[queryFile]
|
|
|
|
if !present {
|
2020-10-07 21:38:27 +00:00
|
|
|
return fmt.Errorf("Postgres-Backend: File %v not found", queryFile)
|
2019-10-11 10:36:00 +00:00
|
|
|
}
|
|
|
|
|
2020-05-03 12:04:08 +00:00
|
|
|
stmt, err := tx.Prepare(query)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Failed to prepare statement: %v", err)
|
2019-10-11 10:36:00 +00:00
|
|
|
}
|
2020-05-03 12:04:08 +00:00
|
|
|
defer stmt.Close()
|
2019-10-11 10:36:00 +00:00
|
|
|
|
2020-05-03 12:04:08 +00:00
|
|
|
for _, measuredValue := range measuredValues {
|
2020-10-07 21:38:27 +00:00
|
|
|
|
|
|
|
if measuredValue.CreationDate.Equal(time.Time{}) {
|
|
|
|
measuredValue.CreationDate = time.Now()
|
|
|
|
}
|
|
|
|
|
2020-06-01 20:36:57 +00:00
|
|
|
_, err := stmt.Exec(
|
|
|
|
&measuredValue.ID,
|
|
|
|
&measuredValue.Value,
|
|
|
|
&measuredValue.Date,
|
|
|
|
&measuredValue.SensorID,
|
|
|
|
&measuredValue.CreationDate,
|
|
|
|
&measuredValue.UpdateDate,
|
|
|
|
)
|
|
|
|
|
2020-05-03 12:04:08 +00:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Failed to execute statement: %v", err)
|
|
|
|
}
|
2019-10-11 10:36:00 +00:00
|
|
|
}
|
2020-05-03 12:04:08 +00:00
|
|
|
|
|
|
|
return nil
|
2019-10-11 10:36:00 +00:00
|
|
|
}
|
|
|
|
|
2020-05-03 12:04:08 +00:00
|
|
|
for measuredValueType, measuredValues := range splittedMeasuredValues {
|
2020-06-01 20:36:57 +00:00
|
|
|
var queryFile string
|
2020-05-03 12:04:08 +00:00
|
|
|
|
|
|
|
switch measuredValueType {
|
2020-09-21 17:36:42 +00:00
|
|
|
case types.Humidity:
|
2020-06-01 20:36:57 +00:00
|
|
|
queryFile = "insertHumidity.sql"
|
2020-09-21 17:36:42 +00:00
|
|
|
case types.Pressure:
|
2020-06-01 20:36:57 +00:00
|
|
|
queryFile = "insertPressure.sql"
|
2020-09-21 17:36:42 +00:00
|
|
|
case types.Temperature:
|
2020-06-01 20:36:57 +00:00
|
|
|
queryFile = "insertTemperature.sql"
|
2020-05-03 12:04:08 +00:00
|
|
|
default:
|
|
|
|
tx.Rollback()
|
|
|
|
return fmt.Errorf("Measured value type %v not supported", measuredValueType)
|
2019-10-11 10:36:00 +00:00
|
|
|
}
|
2020-05-03 12:04:08 +00:00
|
|
|
|
2020-06-01 20:36:57 +00:00
|
|
|
err := insert(tx, queryFile, measuredValues)
|
2020-05-03 12:04:08 +00:00
|
|
|
if err != nil {
|
|
|
|
tx.Rollback()
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return tx.Commit()
|
|
|
|
}
|
|
|
|
|
2020-05-21 15:40:24 +00:00
|
|
|
// InsertSensors into the database
|
|
|
|
func (postgres *Postgres) InsertSensors(ctx context.Context, sensors ...*types.Sensor) error {
|
2020-06-01 20:36:57 +00:00
|
|
|
queryFile := "insertSensor.sql"
|
|
|
|
query, present := postgres.queries[queryFile]
|
|
|
|
if !present {
|
2020-10-07 21:38:27 +00:00
|
|
|
return fmt.Errorf("Postgres-Backend: File %v not found", queryFile)
|
2020-05-03 12:04:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: false})
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Failed to begin new transaction: %v", err)
|
2019-10-11 10:36:00 +00:00
|
|
|
}
|
|
|
|
|
2020-05-03 12:04:08 +00:00
|
|
|
stmt, err := tx.Prepare(query)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Failed to prepare statement: %v", err)
|
|
|
|
}
|
|
|
|
defer stmt.Close()
|
2019-10-11 10:36:00 +00:00
|
|
|
|
2020-05-21 15:40:24 +00:00
|
|
|
for _, sensor := range sensors {
|
2020-10-07 21:38:27 +00:00
|
|
|
|
|
|
|
if sensor.CreationDate.Equal(time.Time{}) {
|
|
|
|
sensor.CreationDate = time.Now()
|
|
|
|
}
|
|
|
|
|
2020-06-01 20:36:57 +00:00
|
|
|
_, err = stmt.Exec(
|
|
|
|
&sensor.ID,
|
|
|
|
&sensor.Name,
|
|
|
|
&sensor.Location,
|
|
|
|
&sensor.WireID,
|
|
|
|
&sensor.I2CBus,
|
|
|
|
&sensor.I2CAddress,
|
|
|
|
&sensor.GPIONumber,
|
|
|
|
&sensor.Model,
|
|
|
|
&sensor.Enabled,
|
|
|
|
&sensor.TickDuration,
|
|
|
|
&sensor.DeviceID,
|
|
|
|
&sensor.CreationDate,
|
|
|
|
&sensor.UpdateDate,
|
|
|
|
)
|
2020-05-21 15:40:24 +00:00
|
|
|
if err != nil {
|
|
|
|
tx.Rollback()
|
|
|
|
return fmt.Errorf("Failed to execute statement: %v", err)
|
|
|
|
}
|
2020-05-03 12:04:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return tx.Commit()
|
2019-10-11 10:36:00 +00:00
|
|
|
}
|
|
|
|
|
2020-06-01 20:36:57 +00:00
|
|
|
// Scheme creates all required tables if not exist
|
|
|
|
func (postgres *Postgres) Scheme(ctx context.Context) error {
|
|
|
|
for _, query := range []string{
|
|
|
|
postgres.queries["createTableDevices.sql"],
|
|
|
|
postgres.queries["createTableSensors.sql"],
|
2020-06-27 19:12:00 +00:00
|
|
|
postgres.queries["createTableHumidities.sql"],
|
2020-06-01 20:36:57 +00:00
|
|
|
postgres.queries["createTablePressures.sql"],
|
|
|
|
postgres.queries["createTableTemperatures.sql"],
|
|
|
|
} {
|
|
|
|
_, err := postgres.dbo.ExecContext(ctx, query)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-05-21 15:40:24 +00:00
|
|
|
// SelectDevice from database
|
|
|
|
func (postgres *Postgres) SelectDevice(ctx context.Context, id string) (*types.Device, error) {
|
2020-06-01 20:36:57 +00:00
|
|
|
queryFile := "selectDevice.sql"
|
|
|
|
query, present := postgres.queries[queryFile]
|
|
|
|
if !present {
|
2020-10-07 21:38:27 +00:00
|
|
|
return nil, fmt.Errorf("Postgres-Backend: File %v not found", queryFile)
|
2020-05-17 11:00:51 +00:00
|
|
|
}
|
|
|
|
|
2020-05-21 15:40:24 +00:00
|
|
|
tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: true})
|
2020-05-17 11:00:51 +00:00
|
|
|
if err != nil {
|
2020-05-21 15:40:24 +00:00
|
|
|
return nil, fmt.Errorf("Failed to begin new transaction: %v", err)
|
2020-05-17 11:00:51 +00:00
|
|
|
}
|
|
|
|
|
2020-06-01 20:36:57 +00:00
|
|
|
devices, err := postgres.selectDevices(tx, query, id)
|
2020-05-17 11:00:51 +00:00
|
|
|
if err != nil {
|
2020-06-01 20:36:57 +00:00
|
|
|
return nil, err
|
2020-05-17 11:00:51 +00:00
|
|
|
}
|
2020-05-21 15:40:24 +00:00
|
|
|
|
2020-06-01 20:36:57 +00:00
|
|
|
err = tx.Commit()
|
2020-05-21 15:40:24 +00:00
|
|
|
if err != nil {
|
2020-06-01 20:36:57 +00:00
|
|
|
return nil, err
|
2020-05-21 15:40:24 +00:00
|
|
|
}
|
|
|
|
|
2020-06-01 20:36:57 +00:00
|
|
|
if len(devices) == 0 {
|
|
|
|
return nil, nil
|
2020-05-17 11:00:51 +00:00
|
|
|
}
|
|
|
|
|
2020-06-01 20:36:57 +00:00
|
|
|
return devices[0], nil
|
2020-05-17 11:00:51 +00:00
|
|
|
}
|
|
|
|
|
2020-05-21 15:40:24 +00:00
|
|
|
// SelectDevices from the database
|
|
|
|
func (postgres *Postgres) SelectDevices(ctx context.Context) ([]*types.Device, error) {
|
2020-06-01 20:36:57 +00:00
|
|
|
queryFile := "selectDevices.sql"
|
|
|
|
query, present := postgres.queries[queryFile]
|
|
|
|
if !present {
|
2020-10-07 21:38:27 +00:00
|
|
|
return nil, fmt.Errorf("Postgres-Backend: File %v not found", queryFile)
|
2020-05-17 11:00:51 +00:00
|
|
|
}
|
|
|
|
|
2020-05-21 15:40:24 +00:00
|
|
|
tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: true})
|
2020-05-17 11:00:51 +00:00
|
|
|
if err != nil {
|
2020-05-21 15:40:24 +00:00
|
|
|
return nil, fmt.Errorf("Failed to begin new transaction: %v", err)
|
2020-05-17 11:00:51 +00:00
|
|
|
}
|
|
|
|
|
2020-06-01 20:36:57 +00:00
|
|
|
devices, err := postgres.selectDevices(tx, query)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = tx.Commit()
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("Failed to commit transaction: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return devices, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (postgres *Postgres) selectDevices(tx *sql.Tx, query string, args ...interface{}) ([]*types.Device, error) {
|
2020-05-17 11:00:51 +00:00
|
|
|
stmt, err := tx.Prepare(query)
|
|
|
|
if err != nil {
|
2020-05-21 15:40:24 +00:00
|
|
|
return nil, fmt.Errorf("Failed to prepare statement: %v", err)
|
2020-05-17 11:00:51 +00:00
|
|
|
}
|
|
|
|
defer stmt.Close()
|
|
|
|
|
2020-06-01 20:36:57 +00:00
|
|
|
rows, err := stmt.Query(args...)
|
2020-05-17 11:00:51 +00:00
|
|
|
if err != nil {
|
2020-05-21 15:40:24 +00:00
|
|
|
return nil, fmt.Errorf("Failed to query statement: %v", err)
|
2020-05-17 11:00:51 +00:00
|
|
|
}
|
|
|
|
|
2020-05-21 15:40:24 +00:00
|
|
|
devices := make([]*types.Device, 0)
|
|
|
|
for rows.Next() {
|
|
|
|
device := new(types.Device)
|
2020-06-01 20:36:57 +00:00
|
|
|
err = rows.Scan(
|
|
|
|
&device.ID,
|
|
|
|
&device.Name,
|
|
|
|
&device.Location,
|
|
|
|
&device.CreationDate,
|
|
|
|
&device.UpdateDate,
|
|
|
|
)
|
2020-05-21 15:40:24 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("Failed to scan row: %v", err)
|
|
|
|
}
|
|
|
|
devices = append(devices, device)
|
|
|
|
}
|
|
|
|
|
2020-06-01 20:36:57 +00:00
|
|
|
return devices, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// SelectHumidity returns humidity from the database
|
|
|
|
func (postgres *Postgres) SelectHumidity(ctx context.Context, id string) (*types.MeasuredValue, error) {
|
|
|
|
queryFile := "selectHumidity.sql"
|
|
|
|
query, present := postgres.queries[queryFile]
|
|
|
|
if !present {
|
2020-10-07 21:38:27 +00:00
|
|
|
return nil, fmt.Errorf("Postgres-Backend: File %v not found", queryFile)
|
2020-06-01 20:36:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: true})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
measuredValues, err := postgres.selectMeasuredValue(tx, query, id)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-05-21 15:40:24 +00:00
|
|
|
err = tx.Commit()
|
|
|
|
if err != nil {
|
2020-06-01 20:36:57 +00:00
|
|
|
return nil, err
|
2020-05-21 15:40:24 +00:00
|
|
|
}
|
|
|
|
|
2020-06-01 20:36:57 +00:00
|
|
|
if measuredValues == nil {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, measuredValue := range measuredValues {
|
2020-09-21 17:36:42 +00:00
|
|
|
measuredValue.ValueType = types.Humidity
|
2020-06-01 20:36:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return measuredValues[0], nil
|
2020-05-17 11:00:51 +00:00
|
|
|
}
|
|
|
|
|
2020-06-01 20:36:57 +00:00
|
|
|
// SelectHumidities returns humidities from the database
|
|
|
|
func (postgres *Postgres) SelectHumidities(ctx context.Context) ([]*types.MeasuredValue, error) {
|
|
|
|
queryFile := "selectHumidities.sql"
|
|
|
|
query, present := postgres.queries[queryFile]
|
|
|
|
if !present {
|
2020-10-07 21:38:27 +00:00
|
|
|
return nil, fmt.Errorf("Postgres-Backend: File %v not found", queryFile)
|
2020-05-03 12:04:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: true})
|
|
|
|
if err != nil {
|
2020-06-01 20:36:57 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-11-06 22:06:53 +00:00
|
|
|
measuredValues, err := postgres.selectMeasuredValue(tx, query)
|
2020-06-01 20:36:57 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = tx.Commit()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, measuredValue := range measuredValues {
|
2020-09-21 17:36:42 +00:00
|
|
|
measuredValue.ValueType = types.Humidity
|
2019-12-07 15:53:49 +00:00
|
|
|
}
|
2020-05-03 12:04:08 +00:00
|
|
|
|
2020-06-01 20:36:57 +00:00
|
|
|
return measuredValues, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (postgres *Postgres) selectMeasuredValue(tx *sql.Tx, query string, args ...interface{}) ([]*types.MeasuredValue, error) {
|
2020-05-03 12:04:08 +00:00
|
|
|
stmt, err := tx.Prepare(query)
|
|
|
|
if err != nil {
|
2020-06-01 20:36:57 +00:00
|
|
|
tx.Rollback()
|
|
|
|
return nil, err
|
2020-05-03 12:04:08 +00:00
|
|
|
}
|
|
|
|
defer stmt.Close()
|
|
|
|
|
2020-06-01 20:36:57 +00:00
|
|
|
rows, err := stmt.Query(args...)
|
|
|
|
if err != nil {
|
|
|
|
tx.Rollback()
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
measuredValues := make([]*types.MeasuredValue, 0)
|
|
|
|
for rows.Next() {
|
|
|
|
measuredValue := new(types.MeasuredValue)
|
|
|
|
err := rows.Scan(
|
|
|
|
&measuredValue.ID,
|
|
|
|
&measuredValue.Value,
|
|
|
|
&measuredValue.SensorID,
|
|
|
|
&measuredValue.Date,
|
|
|
|
&measuredValue.CreationDate,
|
|
|
|
&measuredValue.UpdateDate,
|
|
|
|
)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
tx.Rollback()
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
measuredValues = append(measuredValues, measuredValue)
|
|
|
|
}
|
|
|
|
|
|
|
|
return measuredValues, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// SelectPressure returns pressure from the database
|
|
|
|
func (postgres *Postgres) SelectPressure(ctx context.Context, id string) (*types.MeasuredValue, error) {
|
|
|
|
queryFile := "selectPressure.sql"
|
|
|
|
query, present := postgres.queries[queryFile]
|
|
|
|
if !present {
|
2020-10-07 21:38:27 +00:00
|
|
|
return nil, fmt.Errorf("Postgres-Backend: File %v not found", queryFile)
|
2020-06-01 20:36:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: true})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
measuredValues, err := postgres.selectMeasuredValue(tx, query, id)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = tx.Commit()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if measuredValues == nil {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, measuredValue := range measuredValues {
|
2020-09-21 17:36:42 +00:00
|
|
|
measuredValue.ValueType = types.Pressure
|
2020-06-01 20:36:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return measuredValues[0], nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// SelectPressures returns pressure from the database
|
|
|
|
func (postgres *Postgres) SelectPressures(ctx context.Context) ([]*types.MeasuredValue, error) {
|
|
|
|
queryFile := "selectPressures.sql"
|
|
|
|
query, present := postgres.queries[queryFile]
|
|
|
|
if !present {
|
2020-10-07 21:38:27 +00:00
|
|
|
return nil, fmt.Errorf("Postgres-Backend: File %v not found", queryFile)
|
2020-06-01 20:36:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: true})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-11-06 22:06:53 +00:00
|
|
|
measuredValues, err := postgres.selectMeasuredValue(tx, query)
|
2020-06-01 20:36:57 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = tx.Commit()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, measuredValue := range measuredValues {
|
2020-09-21 17:36:42 +00:00
|
|
|
measuredValue.ValueType = types.Pressure
|
2020-06-01 20:36:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return measuredValues, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// SelectSensor from database
|
|
|
|
func (postgres *Postgres) SelectSensor(ctx context.Context, id string) (*types.Sensor, error) {
|
|
|
|
queryFile := "selectSensor.sql"
|
|
|
|
query, present := postgres.queries[queryFile]
|
|
|
|
if !present {
|
2020-10-07 21:38:27 +00:00
|
|
|
return nil, fmt.Errorf("Postgres-Backend: File %v not found", queryFile)
|
2020-06-01 20:36:57 +00:00
|
|
|
}
|
2020-05-03 12:04:08 +00:00
|
|
|
|
2020-06-01 20:36:57 +00:00
|
|
|
tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: true})
|
2020-05-03 12:04:08 +00:00
|
|
|
if err != nil {
|
2020-06-01 20:36:57 +00:00
|
|
|
return nil, fmt.Errorf("Failed to begin new transaction: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
sensors, err := postgres.selectSensors(tx, query, id)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2020-05-03 12:04:08 +00:00
|
|
|
}
|
|
|
|
|
2020-05-21 15:40:24 +00:00
|
|
|
err = tx.Commit()
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("Failed to commit transaction: %v", err)
|
|
|
|
}
|
|
|
|
|
2020-06-01 20:36:57 +00:00
|
|
|
if len(sensors) == 0 {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return sensors[0], nil
|
2019-12-07 15:53:49 +00:00
|
|
|
}
|
|
|
|
|
2020-05-21 15:40:24 +00:00
|
|
|
// SelectSensors from the database
|
|
|
|
func (postgres *Postgres) SelectSensors(ctx context.Context) ([]*types.Sensor, error) {
|
2020-06-01 20:36:57 +00:00
|
|
|
queryFile := "selectSensors.sql"
|
|
|
|
query, present := postgres.queries[queryFile]
|
|
|
|
if !present {
|
2020-10-07 21:38:27 +00:00
|
|
|
return nil, fmt.Errorf("Postgres-Backend: File %v not found", queryFile)
|
2020-05-03 12:04:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: true})
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("Failed to begin new transaction: %v", err)
|
2019-10-11 10:36:00 +00:00
|
|
|
}
|
2020-05-03 12:04:08 +00:00
|
|
|
|
2020-06-01 20:36:57 +00:00
|
|
|
sensors, err := postgres.selectSensors(tx, query)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = tx.Commit()
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("Failed to commit transaction: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return sensors, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (postgres *Postgres) selectSensors(tx *sql.Tx, query string, args ...interface{}) ([]*types.Sensor, error) {
|
2020-05-03 12:04:08 +00:00
|
|
|
stmt, err := tx.Prepare(query)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("Failed to prepare statement: %v", err)
|
|
|
|
}
|
|
|
|
defer stmt.Close()
|
|
|
|
|
2020-06-01 20:36:57 +00:00
|
|
|
rows, err := stmt.Query(args...)
|
2020-05-03 12:04:08 +00:00
|
|
|
if err != nil {
|
2020-05-21 15:40:24 +00:00
|
|
|
return nil, fmt.Errorf("Failed to query statement: %v", err)
|
2020-05-03 12:04:08 +00:00
|
|
|
}
|
|
|
|
|
2020-05-21 15:40:24 +00:00
|
|
|
sensors := make([]*types.Sensor, 0)
|
|
|
|
for rows.Next() {
|
|
|
|
sensor := new(types.Sensor)
|
2020-06-01 20:36:57 +00:00
|
|
|
err = rows.Scan(
|
|
|
|
&sensor.ID,
|
|
|
|
&sensor.Name,
|
|
|
|
&sensor.Location,
|
|
|
|
&sensor.WireID,
|
|
|
|
&sensor.I2CBus,
|
|
|
|
&sensor.I2CAddress,
|
|
|
|
&sensor.GPIONumber,
|
|
|
|
&sensor.Model,
|
|
|
|
&sensor.Enabled,
|
|
|
|
&sensor.TickDuration,
|
|
|
|
&sensor.DeviceID,
|
|
|
|
&sensor.CreationDate,
|
|
|
|
&sensor.UpdateDate,
|
|
|
|
)
|
|
|
|
|
2020-05-21 15:40:24 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("Failed to scan row: %v", err)
|
|
|
|
}
|
|
|
|
sensors = append(sensors, sensor)
|
|
|
|
}
|
2019-12-07 15:53:49 +00:00
|
|
|
|
2020-06-01 20:36:57 +00:00
|
|
|
return sensors, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// SelectTemperature returns temperatures from the database
|
|
|
|
func (postgres *Postgres) SelectTemperature(ctx context.Context, id string) (*types.MeasuredValue, error) {
|
|
|
|
queryFile := "selectTemperature.sql"
|
|
|
|
query, present := postgres.queries[queryFile]
|
|
|
|
if !present {
|
2020-10-07 21:38:27 +00:00
|
|
|
return nil, fmt.Errorf("Postgres-Backend: File %v not found", queryFile)
|
2020-06-01 20:36:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: true})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
measuredValues, err := postgres.selectMeasuredValue(tx, query, id)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-05-21 15:40:24 +00:00
|
|
|
err = tx.Commit()
|
2020-05-03 12:04:08 +00:00
|
|
|
if err != nil {
|
2020-06-01 20:36:57 +00:00
|
|
|
return nil, err
|
2020-05-03 12:04:08 +00:00
|
|
|
}
|
|
|
|
|
2020-06-01 20:36:57 +00:00
|
|
|
if measuredValues == nil {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, measuredValue := range measuredValues {
|
2020-09-21 17:36:42 +00:00
|
|
|
measuredValue.ValueType = types.Temperature
|
2020-06-01 20:36:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return measuredValues[0], nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// SelectTemperatures returns temperatures from the database
|
|
|
|
func (postgres *Postgres) SelectTemperatures(ctx context.Context) ([]*types.MeasuredValue, error) {
|
|
|
|
queryFile := "selectTemperatures.sql"
|
|
|
|
query, present := postgres.queries[queryFile]
|
|
|
|
if !present {
|
2020-10-07 21:38:27 +00:00
|
|
|
return nil, fmt.Errorf("Postgres-Backend: File %v not found", queryFile)
|
2020-06-01 20:36:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: true})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-11-06 22:06:53 +00:00
|
|
|
measuredValues, err := postgres.selectMeasuredValue(tx, query)
|
2020-06-01 20:36:57 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = tx.Commit()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, measuredValue := range measuredValues {
|
2020-09-21 17:36:42 +00:00
|
|
|
measuredValue.ValueType = types.Temperature
|
2020-06-01 20:36:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return measuredValues, nil
|
2020-05-21 15:40:24 +00:00
|
|
|
}
|
2020-01-18 13:40:47 +00:00
|
|
|
|
2020-05-21 15:40:24 +00:00
|
|
|
// UpdateDevices updates a device in the database
|
|
|
|
func (postgres *Postgres) UpdateDevices(ctx context.Context, devices ...*types.Device) error {
|
2020-06-01 20:36:57 +00:00
|
|
|
queryFile := "updateDevice.sql"
|
|
|
|
query, present := postgres.queries[queryFile]
|
|
|
|
if !present {
|
2020-10-07 21:38:27 +00:00
|
|
|
return fmt.Errorf("Postgres-Backend: File %v not found", queryFile)
|
2020-06-01 20:36:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: false})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
stmt, err := tx.Prepare(query)
|
|
|
|
if err != nil {
|
|
|
|
tx.Rollback()
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer stmt.Close()
|
|
|
|
|
|
|
|
for _, device := range devices {
|
|
|
|
now := time.Now()
|
|
|
|
device.UpdateDate = &now
|
|
|
|
|
|
|
|
_, err := stmt.Exec(
|
|
|
|
&device.Name,
|
|
|
|
&device.Location,
|
|
|
|
&device.CreationDate,
|
|
|
|
&device.UpdateDate,
|
|
|
|
&device.ID,
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
tx.Rollback()
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return tx.Commit()
|
2020-05-21 15:40:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// UpdateSensors updates a sensor in the database
|
2020-06-01 20:36:57 +00:00
|
|
|
func (postgres *Postgres) UpdateSensors(ctx context.Context, sensors ...*types.Sensor) error {
|
|
|
|
queryFile := "updateSensor.sql"
|
|
|
|
query, present := postgres.queries[queryFile]
|
|
|
|
if !present {
|
2020-10-07 21:38:27 +00:00
|
|
|
return fmt.Errorf("Postgres-Backend: File %v not found", queryFile)
|
2020-06-01 20:36:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: false})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
stmt, err := tx.Prepare(query)
|
|
|
|
if err != nil {
|
|
|
|
tx.Rollback()
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer stmt.Close()
|
|
|
|
|
|
|
|
for _, sensor := range sensors {
|
|
|
|
now := time.Now()
|
|
|
|
sensor.UpdateDate = &now
|
|
|
|
_, err := stmt.Exec(
|
|
|
|
&sensor.Name,
|
|
|
|
&sensor.Location,
|
|
|
|
&sensor.WireID,
|
|
|
|
&sensor.I2CBus,
|
|
|
|
&sensor.I2CAddress,
|
|
|
|
&sensor.GPIONumber,
|
|
|
|
&sensor.Model,
|
|
|
|
&sensor.Enabled,
|
|
|
|
&sensor.TickDuration,
|
|
|
|
&sensor.DeviceID,
|
|
|
|
&sensor.CreationDate,
|
|
|
|
&sensor.UpdateDate,
|
|
|
|
&sensor.ID,
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
tx.Rollback()
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return tx.Commit()
|
2019-12-07 15:53:49 +00:00
|
|
|
}
|