markus
522fe2746a
Add additional functions to the repository to add or update devices, sensors or measured values. Furthermore the test has been adapt to the new functions.
926 lines
22 KiB
Go
926 lines
22 KiB
Go
package db
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"fmt"
|
|
|
|
"git.cryptic.systems/volker.raschek/flucky/pkg/types"
|
|
"git.cryptic.systems/volker.raschek/go-logger"
|
|
)
|
|
|
|
// SQLite implementation
|
|
type SQLite struct {
|
|
dbo *sql.DB
|
|
flogger logger.Logger
|
|
queries map[string]string
|
|
}
|
|
|
|
// 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 (sqlite *SQLite) Close() error {
|
|
return sqlite.dbo.Close()
|
|
}
|
|
|
|
// DeleteDevices from the database
|
|
func (sqlite *SQLite) DeleteDevices(ctx context.Context, deviceIDs ...string) error {
|
|
queryFile := "deleteDevice.sql"
|
|
query, present := sqlite.queries[queryFile]
|
|
if !present {
|
|
return fmt.Errorf("SQLite-Backend: File %v not found", queryFile)
|
|
}
|
|
|
|
tx, err := sqlite.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 _, deviceID := range deviceIDs {
|
|
_, err = stmt.Exec(deviceID)
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return err
|
|
}
|
|
}
|
|
|
|
return tx.Commit()
|
|
}
|
|
|
|
// DeleteSensors from the database
|
|
func (sqlite *SQLite) DeleteSensors(ctx context.Context, sensorIDs ...string) error {
|
|
queryFile := "deleteSensor.sql"
|
|
query, present := sqlite.queries[queryFile]
|
|
if !present {
|
|
return fmt.Errorf("SQLite-Backend: File %v not found", queryFile)
|
|
}
|
|
|
|
tx, err := sqlite.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()
|
|
}
|
|
|
|
func (sqlite *SQLite) ExistDevice(ctx context.Context, deviceID string) (bool, error) {
|
|
queryFile := "existDevice.sql"
|
|
query, present := sqlite.queries[queryFile]
|
|
if !present {
|
|
return false, fmt.Errorf("SQLite-Backend: File %v not found", queryFile)
|
|
}
|
|
|
|
tx, err := sqlite.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: false})
|
|
if err != nil {
|
|
return false, fmt.Errorf("Failed to begin new transaction: %v", err)
|
|
}
|
|
|
|
stmt, err := tx.Prepare(query)
|
|
if err != nil {
|
|
return false, fmt.Errorf("Failed to prepare statement: %v", err)
|
|
}
|
|
defer stmt.Close()
|
|
|
|
rows, err := stmt.Query()
|
|
if err != nil {
|
|
return false, fmt.Errorf("Failed to query statement: %v", err)
|
|
}
|
|
defer rows.Close()
|
|
|
|
var t bool
|
|
for rows.Next() {
|
|
rows.Scan(&t)
|
|
}
|
|
|
|
return t, nil
|
|
}
|
|
|
|
func (sqlite *SQLite) ExistDevices(ctx context.Context, deviceIDs ...string) (map[string]bool, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
// InsertDevices into the database
|
|
func (sqlite *SQLite) InsertDevices(ctx context.Context, devices ...*types.Device) error {
|
|
queryFile := "insertDevice.sql"
|
|
query, present := sqlite.queries[queryFile]
|
|
if !present {
|
|
return fmt.Errorf("SQLite-Backend: File %v not found", queryFile)
|
|
}
|
|
|
|
tx, err := sqlite.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 {
|
|
_, err = stmt.Exec(&device.ID, &device.Name, &device.Location, &device.CreationDate, &device.UpdateDate)
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return fmt.Errorf("Failed to execute statement: %v", err)
|
|
}
|
|
}
|
|
|
|
return tx.Commit()
|
|
}
|
|
|
|
// InsertMeasuredValues into the database
|
|
func (sqlite *SQLite) InsertMeasuredValues(ctx context.Context, measuredValues ...*types.MeasuredValue) error {
|
|
splittedMeasuredValues := make(map[types.MeasuredValueType][]*types.MeasuredValue, 0)
|
|
|
|
for _, measuredValue := range measuredValues {
|
|
if _, ok := splittedMeasuredValues[measuredValue.ValueType]; !ok {
|
|
splittedMeasuredValues[measuredValue.ValueType] = make([]*types.MeasuredValue, 0)
|
|
}
|
|
splittedMeasuredValues[measuredValue.ValueType] = append(splittedMeasuredValues[measuredValue.ValueType], measuredValue)
|
|
}
|
|
|
|
tx, err := sqlite.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: false})
|
|
if err != nil {
|
|
return fmt.Errorf("Failed to begin new transaction: %v", err)
|
|
}
|
|
|
|
// General insert function
|
|
insert := func(tx *sql.Tx, queryFile string, measuredValues []*types.MeasuredValue) error {
|
|
query, present := sqlite.queries[queryFile]
|
|
if !present {
|
|
return fmt.Errorf("SQLite-Backend: File %v not found", queryFile)
|
|
}
|
|
|
|
stmt, err := tx.Prepare(query)
|
|
if err != nil {
|
|
return fmt.Errorf("Failed to prepare statement: %v", err)
|
|
}
|
|
defer stmt.Close()
|
|
|
|
for _, measuredValue := range measuredValues {
|
|
_, err := stmt.Exec(
|
|
&measuredValue.ID,
|
|
&measuredValue.Value,
|
|
&measuredValue.Date,
|
|
&measuredValue.SensorID,
|
|
&measuredValue.CreationDate,
|
|
&measuredValue.UpdateDate,
|
|
)
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("Failed to execute statement: %v", err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
for measuredValueType, measuredValues := range splittedMeasuredValues {
|
|
var queryFile string
|
|
|
|
switch measuredValueType {
|
|
case types.Humidity:
|
|
queryFile = "insertHumidity.sql"
|
|
case types.Pressure:
|
|
queryFile = "insertPressure.sql"
|
|
case types.Temperature:
|
|
queryFile = "insertTemperature.sql"
|
|
default:
|
|
tx.Rollback()
|
|
return fmt.Errorf("Measured value type %v not supported", measuredValueType)
|
|
}
|
|
|
|
err := insert(tx, queryFile, measuredValues)
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return err
|
|
}
|
|
}
|
|
|
|
return tx.Commit()
|
|
}
|
|
|
|
// InsertOrUpdateMeasuredValues into the database
|
|
func (sqlite *SQLite) InsertOrUpdateMeasuredValues(ctx context.Context, measuredValues ...*types.MeasuredValue) error {
|
|
splittedMeasuredValues := make(map[types.MeasuredValueType][]*types.MeasuredValue, 0)
|
|
|
|
for _, measuredValue := range measuredValues {
|
|
if _, ok := splittedMeasuredValues[measuredValue.ValueType]; !ok {
|
|
splittedMeasuredValues[measuredValue.ValueType] = make([]*types.MeasuredValue, 0)
|
|
}
|
|
splittedMeasuredValues[measuredValue.ValueType] = append(splittedMeasuredValues[measuredValue.ValueType], measuredValue)
|
|
}
|
|
|
|
tx, err := sqlite.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: false})
|
|
if err != nil {
|
|
return fmt.Errorf("Failed to begin new transaction: %v", err)
|
|
}
|
|
|
|
// General insert function
|
|
insert := func(tx *sql.Tx, queryFile string, measuredValues []*types.MeasuredValue) error {
|
|
query, present := sqlite.queries[queryFile]
|
|
if !present {
|
|
return fmt.Errorf("SQLite-Backend: File %v not found", queryFile)
|
|
}
|
|
|
|
stmt, err := tx.Prepare(query)
|
|
if err != nil {
|
|
return fmt.Errorf("Failed to prepare statement: %v", err)
|
|
}
|
|
defer stmt.Close()
|
|
|
|
for _, measuredValue := range measuredValues {
|
|
_, err := stmt.Exec(
|
|
&measuredValue.ID,
|
|
&measuredValue.Value,
|
|
&measuredValue.Date,
|
|
&measuredValue.SensorID,
|
|
&measuredValue.CreationDate,
|
|
&measuredValue.UpdateDate,
|
|
)
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("Failed to execute statement: %v", err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
for measuredValueType, measuredValues := range splittedMeasuredValues {
|
|
var queryFile string
|
|
|
|
switch measuredValueType {
|
|
case types.Humidity:
|
|
queryFile = "insertOrUpdateHumidity.sql"
|
|
case types.Pressure:
|
|
queryFile = "insertOrUpdatePressure.sql"
|
|
case types.Temperature:
|
|
queryFile = "insertOrUpdateTemperature.sql"
|
|
default:
|
|
tx.Rollback()
|
|
return fmt.Errorf("Measured value type %v not supported", measuredValueType)
|
|
}
|
|
|
|
err := insert(tx, queryFile, measuredValues)
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return err
|
|
}
|
|
}
|
|
|
|
return tx.Commit()
|
|
}
|
|
|
|
// InsertOrUpdateDevices into the database
|
|
func (sqlite *SQLite) InsertOrUpdateDevices(ctx context.Context, devices ...*types.Device) error {
|
|
queryFile := "insertOrUpdateDevice.sql"
|
|
query, present := sqlite.queries[queryFile]
|
|
if !present {
|
|
return fmt.Errorf("SQLite-Backend: File %v not found", queryFile)
|
|
}
|
|
|
|
tx, err := sqlite.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 {
|
|
_, err = stmt.Exec(&device.ID, &device.Name, &device.Location, &device.CreationDate, &device.UpdateDate)
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return fmt.Errorf("Failed to execute statement: %v", err)
|
|
}
|
|
}
|
|
|
|
return tx.Commit()
|
|
}
|
|
|
|
// InsertOrUpdateSensors into the database
|
|
func (sqlite *SQLite) InsertOrUpdateSensors(ctx context.Context, sensors ...*types.Sensor) error {
|
|
queryFile := "insertOrUpdateSensor.sql"
|
|
query, present := sqlite.queries[queryFile]
|
|
if !present {
|
|
return fmt.Errorf("SQLite-Backend: File %v not found", queryFile)
|
|
}
|
|
|
|
tx, err := sqlite.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 _, sensor := range sensors {
|
|
_, 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,
|
|
)
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return fmt.Errorf("Failed to execute statement: %v", err)
|
|
}
|
|
}
|
|
|
|
return tx.Commit()
|
|
}
|
|
|
|
// InsertSensors into the database
|
|
func (sqlite *SQLite) InsertSensors(ctx context.Context, sensors ...*types.Sensor) error {
|
|
queryFile := "insertSensor.sql"
|
|
query, present := sqlite.queries[queryFile]
|
|
if !present {
|
|
return fmt.Errorf("SQLite-Backend: File %v not found", queryFile)
|
|
}
|
|
|
|
tx, err := sqlite.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 _, sensor := range sensors {
|
|
_, 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,
|
|
)
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return fmt.Errorf("Failed to execute statement: %v", err)
|
|
}
|
|
}
|
|
|
|
return tx.Commit()
|
|
}
|
|
|
|
// Scheme creates all required tables if not exist
|
|
func (sqlite *SQLite) Scheme(ctx context.Context) error {
|
|
for _, query := range []string{
|
|
sqlite.queries["createTableDevices.sql"],
|
|
sqlite.queries["createTableSensors.sql"],
|
|
sqlite.queries["createTableHumidities.sql"],
|
|
sqlite.queries["createTablePressures.sql"],
|
|
sqlite.queries["createTableTemperatures.sql"],
|
|
} {
|
|
_, err := sqlite.dbo.ExecContext(ctx, query)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// SelectDevice from database
|
|
func (sqlite *SQLite) SelectDevice(ctx context.Context, id string) (*types.Device, error) {
|
|
queryFile := "selectDevice.sql"
|
|
query, present := sqlite.queries[queryFile]
|
|
if !present {
|
|
return nil, fmt.Errorf("SQLite-Backend: File %v not found", queryFile)
|
|
}
|
|
|
|
tx, err := sqlite.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: true})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Failed to begin new transaction: %v", err)
|
|
}
|
|
|
|
devices, err := sqlite.selectDevices(tx, query, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
err = tx.Commit()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if len(devices) == 0 {
|
|
return nil, nil
|
|
}
|
|
|
|
return devices[0], nil
|
|
}
|
|
|
|
// SelectDevices from the database
|
|
func (sqlite *SQLite) SelectDevices(ctx context.Context) ([]*types.Device, error) {
|
|
queryFile := "selectDevices.sql"
|
|
query, present := sqlite.queries[queryFile]
|
|
if !present {
|
|
return nil, fmt.Errorf("SQLite-Backend: File %v not found", queryFile)
|
|
}
|
|
|
|
tx, err := sqlite.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: true})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Failed to begin new transaction: %v", err)
|
|
}
|
|
|
|
devices, err := sqlite.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 (sqlite *SQLite) selectDevices(tx *sql.Tx, query string, args ...interface{}) ([]*types.Device, error) {
|
|
stmt, err := tx.Prepare(query)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Failed to prepare statement: %v", err)
|
|
}
|
|
defer stmt.Close()
|
|
|
|
rows, err := stmt.Query(args...)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Failed to query statement: %v", err)
|
|
}
|
|
defer rows.Close()
|
|
|
|
devices := make([]*types.Device, 0)
|
|
for rows.Next() {
|
|
device := new(types.Device)
|
|
err = rows.Scan(
|
|
&device.ID,
|
|
&device.Name,
|
|
&device.Location,
|
|
&device.CreationDate,
|
|
&device.UpdateDate,
|
|
)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Failed to scan row: %v", err)
|
|
}
|
|
devices = append(devices, device)
|
|
}
|
|
|
|
return devices, nil
|
|
}
|
|
|
|
// SelectHumidity returns humidity from the database
|
|
func (sqlite *SQLite) SelectHumidity(ctx context.Context, id string) (*types.MeasuredValue, error) {
|
|
queryFile := "selectHumidity.sql"
|
|
query, present := sqlite.queries[queryFile]
|
|
if !present {
|
|
return nil, fmt.Errorf("SQLite-Backend: File %v not found", queryFile)
|
|
}
|
|
|
|
tx, err := sqlite.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: true})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
measuredValues, err := sqlite.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 {
|
|
measuredValue.ValueType = types.Humidity
|
|
}
|
|
|
|
return measuredValues[0], nil
|
|
}
|
|
|
|
// SelectHumidities returns humidities from the database
|
|
func (sqlite *SQLite) SelectHumidities(ctx context.Context) ([]*types.MeasuredValue, error) {
|
|
queryFile := "selectHumidities.sql"
|
|
query, present := sqlite.queries[queryFile]
|
|
if !present {
|
|
return nil, fmt.Errorf("SQLite-Backend: File %v not found", queryFile)
|
|
}
|
|
|
|
tx, err := sqlite.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: true})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
measuredValues, err := sqlite.selectMeasuredValue(tx, query)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
err = tx.Commit()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for _, measuredValue := range measuredValues {
|
|
measuredValue.ValueType = types.Humidity
|
|
}
|
|
|
|
return measuredValues, nil
|
|
}
|
|
|
|
func (sqlite *SQLite) selectMeasuredValue(tx *sql.Tx, query string, args ...interface{}) ([]*types.MeasuredValue, error) {
|
|
stmt, err := tx.Prepare(query)
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return nil, err
|
|
}
|
|
defer stmt.Close()
|
|
|
|
rows, err := stmt.Query(args...)
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
|
|
measuredValues := make([]*types.MeasuredValue, 0)
|
|
for rows.Next() {
|
|
measuredValue := new(types.MeasuredValue)
|
|
err := rows.Scan(
|
|
&measuredValue.ID,
|
|
&measuredValue.Value,
|
|
&measuredValue.Date,
|
|
&measuredValue.SensorID,
|
|
&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 (sqlite *SQLite) SelectPressure(ctx context.Context, id string) (*types.MeasuredValue, error) {
|
|
queryFile := "selectPressure.sql"
|
|
query, present := sqlite.queries[queryFile]
|
|
if !present {
|
|
return nil, fmt.Errorf("SQLite-Backend: File %v not found", queryFile)
|
|
}
|
|
|
|
tx, err := sqlite.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: true})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
measuredValues, err := sqlite.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 {
|
|
measuredValue.ValueType = types.Pressure
|
|
}
|
|
|
|
return measuredValues[0], nil
|
|
}
|
|
|
|
// SelectPressures returns pressure from the database
|
|
func (sqlite *SQLite) SelectPressures(ctx context.Context) ([]*types.MeasuredValue, error) {
|
|
queryFile := "selectPressures.sql"
|
|
query, present := sqlite.queries[queryFile]
|
|
if !present {
|
|
return nil, fmt.Errorf("SQLite-Backend: File %v not found", queryFile)
|
|
}
|
|
|
|
tx, err := sqlite.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: true})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
measuredValues, err := sqlite.selectMeasuredValue(tx, query)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
err = tx.Commit()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for _, measuredValue := range measuredValues {
|
|
measuredValue.ValueType = types.Pressure
|
|
}
|
|
|
|
return measuredValues, nil
|
|
}
|
|
|
|
// SelectSensor from database
|
|
func (sqlite *SQLite) SelectSensor(ctx context.Context, id string) (*types.Sensor, error) {
|
|
queryFile := "selectSensor.sql"
|
|
query, present := sqlite.queries[queryFile]
|
|
if !present {
|
|
return nil, fmt.Errorf("SQLite-Backend: File %v not found", queryFile)
|
|
}
|
|
|
|
tx, err := sqlite.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: true})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Failed to begin new transaction: %v", err)
|
|
}
|
|
|
|
sensors, err := sqlite.selectSensors(tx, query, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
err = tx.Commit()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Failed to commit transaction: %v", err)
|
|
}
|
|
|
|
if len(sensors) == 0 {
|
|
return nil, nil
|
|
}
|
|
|
|
return sensors[0], nil
|
|
}
|
|
|
|
// SelectSensors from the database
|
|
func (sqlite *SQLite) SelectSensors(ctx context.Context) ([]*types.Sensor, error) {
|
|
queryFile := "selectSensors.sql"
|
|
query, present := sqlite.queries[queryFile]
|
|
if !present {
|
|
return nil, fmt.Errorf("SQLite-Backend: File %v not found", queryFile)
|
|
}
|
|
|
|
tx, err := sqlite.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: true})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Failed to begin new transaction: %v", err)
|
|
}
|
|
|
|
sensors, err := sqlite.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 (sqlite *SQLite) selectSensors(tx *sql.Tx, query string, args ...interface{}) ([]*types.Sensor, error) {
|
|
stmt, err := tx.Prepare(query)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Failed to prepare statement: %v", err)
|
|
}
|
|
defer stmt.Close()
|
|
|
|
rows, err := stmt.Query(args...)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Failed to query statement: %v", err)
|
|
}
|
|
defer rows.Close()
|
|
|
|
sensors := make([]*types.Sensor, 0)
|
|
for rows.Next() {
|
|
sensor := new(types.Sensor)
|
|
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,
|
|
)
|
|
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Failed to scan row: %v", err)
|
|
}
|
|
sensors = append(sensors, sensor)
|
|
}
|
|
|
|
return sensors, nil
|
|
}
|
|
|
|
// SelectTemperature returns temperatures from the database
|
|
func (sqlite *SQLite) SelectTemperature(ctx context.Context, id string) (*types.MeasuredValue, error) {
|
|
queryFile := "selectTemperature.sql"
|
|
query, present := sqlite.queries[queryFile]
|
|
if !present {
|
|
return nil, fmt.Errorf("SQLite-Backend: File %v not found", queryFile)
|
|
}
|
|
|
|
tx, err := sqlite.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: true})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
measuredValues, err := sqlite.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 {
|
|
measuredValue.ValueType = types.Temperature
|
|
}
|
|
|
|
return measuredValues[0], nil
|
|
}
|
|
|
|
// SelectTemperatures returns temperatures from the database
|
|
func (sqlite *SQLite) SelectTemperatures(ctx context.Context) ([]*types.MeasuredValue, error) {
|
|
queryFile := "selectTemperatures.sql"
|
|
query, present := sqlite.queries[queryFile]
|
|
if !present {
|
|
return nil, fmt.Errorf("SQLite-Backend: File %v not found", queryFile)
|
|
}
|
|
|
|
tx, err := sqlite.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: true})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
measuredValues, err := sqlite.selectMeasuredValue(tx, query)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
err = tx.Commit()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for _, measuredValue := range measuredValues {
|
|
measuredValue.ValueType = types.Temperature
|
|
}
|
|
|
|
return measuredValues, nil
|
|
}
|
|
|
|
// UpdateDevices updates a device in the database
|
|
func (sqlite *SQLite) UpdateDevices(ctx context.Context, devices ...*types.Device) error {
|
|
queryFile := "updateDevice.sql"
|
|
query, present := sqlite.queries[queryFile]
|
|
if !present {
|
|
return fmt.Errorf("SQLite-Backend: File %v not found", queryFile)
|
|
}
|
|
|
|
tx, err := sqlite.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 {
|
|
_, err := stmt.Exec(
|
|
&device.Name,
|
|
&device.Location,
|
|
&device.CreationDate,
|
|
&device.UpdateDate,
|
|
&device.ID,
|
|
)
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return err
|
|
}
|
|
}
|
|
|
|
return tx.Commit()
|
|
}
|
|
|
|
// UpdateSensors updates a sensor in the database
|
|
func (sqlite *SQLite) UpdateSensors(ctx context.Context, sensors ...*types.Sensor) error {
|
|
queryFile := "updateSensor.sql"
|
|
query, present := sqlite.queries[queryFile]
|
|
if !present {
|
|
return fmt.Errorf("SQLite-Backend: File %v not found", queryFile)
|
|
}
|
|
|
|
tx, err := sqlite.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 {
|
|
_, 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()
|
|
}
|