From 522fe2746ac146f9942e54324129288def2e1b3a Mon Sep 17 00:00:00 2001 From: markus Date: Mon, 14 Dec 2020 20:06:10 +0100 Subject: [PATCH] fix: add or update devices, sensors and measured values 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. --- pkg/repository/db/db.go | 3 + pkg/repository/db/postgres.go | 184 ++++++++++++++++- .../db/postgres/insertOrUpdateDevice.sql | 14 ++ .../db/postgres/insertOrUpdateHumidity.sql | 16 ++ .../db/postgres/insertOrUpdatePressure.sql | 16 ++ .../db/postgres/insertOrUpdateSensor.sql | 31 +++ .../db/postgres/insertOrUpdateTemperature.sql | 16 ++ pkg/repository/db/postgres/selectHumidity.sql | 2 +- pkg/repository/db/postgres/selectPressure.sql | 2 +- .../db/postgres/selectTemperature.sql | 2 +- pkg/repository/db/sqlite.go | 182 +++++++++++++++++ .../db/sqlite3/insertOrUpdateDevice.sql | 14 ++ .../db/sqlite3/insertOrUpdateHumidity.sql | 16 ++ .../db/sqlite3/insertOrUpdatePressure.sql | 16 ++ .../db/sqlite3/insertOrUpdateSensor.sql | 31 +++ .../db/sqlite3/insertOrUpdateTemperature.sql | 16 ++ pkg/repository/db/sqlite3/selectHumidity.sql | 2 +- pkg/repository/db/sqlite3/selectPressure.sql | 2 +- .../db/sqlite3/selectTemperature.sql | 2 +- pkg/repository/repository.go | 30 +++ pkg/repository/repository_test.go | 192 +++++++++++++++++- 21 files changed, 775 insertions(+), 14 deletions(-) create mode 100644 pkg/repository/db/postgres/insertOrUpdateDevice.sql create mode 100644 pkg/repository/db/postgres/insertOrUpdateHumidity.sql create mode 100644 pkg/repository/db/postgres/insertOrUpdatePressure.sql create mode 100644 pkg/repository/db/postgres/insertOrUpdateSensor.sql create mode 100644 pkg/repository/db/postgres/insertOrUpdateTemperature.sql create mode 100644 pkg/repository/db/sqlite3/insertOrUpdateDevice.sql create mode 100644 pkg/repository/db/sqlite3/insertOrUpdateHumidity.sql create mode 100644 pkg/repository/db/sqlite3/insertOrUpdatePressure.sql create mode 100644 pkg/repository/db/sqlite3/insertOrUpdateSensor.sql create mode 100644 pkg/repository/db/sqlite3/insertOrUpdateTemperature.sql diff --git a/pkg/repository/db/db.go b/pkg/repository/db/db.go index c793750..0920e58 100644 --- a/pkg/repository/db/db.go +++ b/pkg/repository/db/db.go @@ -20,8 +20,11 @@ type Database interface { DeleteDevices(ctx context.Context, deviceIDs ...string) error DeleteSensors(ctx context.Context, sensorIDs ...string) error InsertDevices(ctx context.Context, devices ...*types.Device) error + InsertOrUpdateDevices(ctx context.Context, devices ...*types.Device) error InsertMeasuredValues(ctx context.Context, measuredValues ...*types.MeasuredValue) error + InsertOrUpdateMeasuredValues(ctx context.Context, measuredValues ...*types.MeasuredValue) error InsertSensors(ctx context.Context, sensors ...*types.Sensor) error + InsertOrUpdateSensors(ctx context.Context, sensors ...*types.Sensor) error Scheme(ctx context.Context) error SelectDevice(ctx context.Context, deviceID string) (*types.Device, error) SelectDevices(ctx context.Context) ([]*types.Device, error) diff --git a/pkg/repository/db/postgres.go b/pkg/repository/db/postgres.go index 49424bd..97ee594 100644 --- a/pkg/repository/db/postgres.go +++ b/pkg/repository/db/postgres.go @@ -85,17 +85,26 @@ func (postgres *Postgres) DeleteSensors(ctx context.Context, sensorIDs ...string // InsertDevices into the database func (postgres *Postgres) InsertDevices(ctx context.Context, devices ...*types.Device) error { + tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: false}) + if err != nil { + return fmt.Errorf("Failed to begin new transaction: %v", err) + } + + err = postgres.insertDevices(tx, devices...) + if err != nil { + return err + } + + return tx.Commit() +} + +func (postgres *Postgres) insertDevices(tx *sql.Tx, devices ...*types.Device) error { queryFile := "insertDevice.sql" query, present := postgres.queries[queryFile] if !present { return fmt.Errorf("Postgres-Backend: File %v not found", queryFile) } - 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) @@ -121,7 +130,7 @@ func (postgres *Postgres) InsertDevices(ctx context.Context, devices ...*types.D } } - return tx.Commit() + return nil } // InsertMeasuredValues into the database @@ -201,6 +210,167 @@ func (postgres *Postgres) InsertMeasuredValues(ctx context.Context, measuredValu return tx.Commit() } +func (postgres *Postgres) InsertOrUpdateDevices(ctx context.Context, devices ...*types.Device) error { + queryFile := "insertOrUpdateDevice.sql" + query, present := postgres.queries[queryFile] + if !present { + return fmt.Errorf("Postgres-Backend: File %v not found", queryFile) + } + + tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: false}) + if err != nil { + return fmt.Errorf("Failed to begin new transaction: %v", err) + } + + for _, device := range devices { + + if device.CreationDate.Equal(time.Time{}) { + device.CreationDate = time.Now() + } + + _, err = tx.Exec( + query, + &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() +} + +// InsertOrUpdateMeasuredValues into the database +func (postgres *Postgres) 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 := postgres.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 := postgres.queries[queryFile] + if !present { + return fmt.Errorf("Postgres-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 { + + if measuredValue.CreationDate.Equal(time.Time{}) { + measuredValue.CreationDate = time.Now() + } + + _, 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() +} + +// InsertOrUpdateSensors into the database +func (postgres *Postgres) InsertOrUpdateSensors(ctx context.Context, sensors ...*types.Sensor) error { + queryFile := "insertOrUpdateSensor.sql" + query, present := postgres.queries[queryFile] + if !present { + return fmt.Errorf("Postgres-Backend: File %v not found", queryFile) + } + + 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 _, sensor := range sensors { + + if sensor.CreationDate.Equal(time.Time{}) { + sensor.CreationDate = time.Now() + } + + _, 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 (postgres *Postgres) InsertSensors(ctx context.Context, sensors ...*types.Sensor) error { queryFile := "insertSensor.sql" @@ -438,8 +608,8 @@ func (postgres *Postgres) selectMeasuredValue(tx *sql.Tx, query string, args ... err := rows.Scan( &measuredValue.ID, &measuredValue.Value, - &measuredValue.SensorID, &measuredValue.Date, + &measuredValue.SensorID, &measuredValue.CreationDate, &measuredValue.UpdateDate, ) diff --git a/pkg/repository/db/postgres/insertOrUpdateDevice.sql b/pkg/repository/db/postgres/insertOrUpdateDevice.sql new file mode 100644 index 0000000..ddeda57 --- /dev/null +++ b/pkg/repository/db/postgres/insertOrUpdateDevice.sql @@ -0,0 +1,14 @@ +INSERT INTO devices ( + device_id, + device_name, + device_location, + creation_date, + update_date +) +VALUES ($1, $2, $3, $4, $5) +ON CONFLICT (device_id) +DO + UPDATE SET + device_name = EXCLUDED.device_name, + device_location = EXCLUDED.device_location, + update_date = NOW(); \ No newline at end of file diff --git a/pkg/repository/db/postgres/insertOrUpdateHumidity.sql b/pkg/repository/db/postgres/insertOrUpdateHumidity.sql new file mode 100644 index 0000000..4cfd294 --- /dev/null +++ b/pkg/repository/db/postgres/insertOrUpdateHumidity.sql @@ -0,0 +1,16 @@ +INSERT INTO humidities ( + id, + value, + date, + sensor_id, + creation_date, + update_date +) +VALUES ($1, $2, $3, $4, $5, $6) +ON CONFLICT (id) +DO + UPDATE SET + value = EXCLUDED.value, + date = EXCLUDED.date, + sensor_id = EXCLUDED.sensor_id, + update_date = NOW(); \ No newline at end of file diff --git a/pkg/repository/db/postgres/insertOrUpdatePressure.sql b/pkg/repository/db/postgres/insertOrUpdatePressure.sql new file mode 100644 index 0000000..c22a280 --- /dev/null +++ b/pkg/repository/db/postgres/insertOrUpdatePressure.sql @@ -0,0 +1,16 @@ +INSERT INTO pressures ( + id, + value, + date, + sensor_id, + creation_date, + update_date +) +VALUES ($1, $2, $3, $4, $5, $6) +ON CONFLICT (id) +DO + UPDATE SET + value = EXCLUDED.value, + date = EXCLUDED.date, + sensor_id = EXCLUDED.sensor_id, + update_date = NOW(); \ No newline at end of file diff --git a/pkg/repository/db/postgres/insertOrUpdateSensor.sql b/pkg/repository/db/postgres/insertOrUpdateSensor.sql new file mode 100644 index 0000000..0b743bc --- /dev/null +++ b/pkg/repository/db/postgres/insertOrUpdateSensor.sql @@ -0,0 +1,31 @@ +INSERT INTO sensors ( + sensor_id, + sensor_name, + sensor_location, + wire_id, + i2c_bus, + i2c_address, + gpio_number, + sensor_model, + sensor_enabled, + tick_duration, + device_id, + creation_date, + update_date +) +VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) +ON CONFLICT (sensor_id) +DO + UPDATE SET + sensor_name = EXCLUDED.sensor_name, + sensor_location = EXCLUDED.sensor_location, + wire_id = EXCLUDED.wire_id, + i2c_bus = EXCLUDED.i2c_bus, + i2c_address = EXCLUDED.i2c_address, + gpio_number = EXCLUDED.gpio_number, + sensor_model = EXCLUDED.sensor_model, + sensor_enabled = EXCLUDED.sensor_enabled, + tick_duration = EXCLUDED.tick_duration, + device_id = EXCLUDED.device_id, + creation_date = EXCLUDED.creation_date, + update_date = NOW(); diff --git a/pkg/repository/db/postgres/insertOrUpdateTemperature.sql b/pkg/repository/db/postgres/insertOrUpdateTemperature.sql new file mode 100644 index 0000000..42b7f17 --- /dev/null +++ b/pkg/repository/db/postgres/insertOrUpdateTemperature.sql @@ -0,0 +1,16 @@ +INSERT INTO temperatures ( + id, + value, + date, + sensor_id, + creation_date, + update_date +) +VALUES ($1, $2, $3, $4, $5, $6) +ON CONFLICT (id) +DO + UPDATE SET + value = EXCLUDED.value, + date = EXCLUDED.date, + sensor_id = EXCLUDED.sensor_id, + update_date = NOW(); \ No newline at end of file diff --git a/pkg/repository/db/postgres/selectHumidity.sql b/pkg/repository/db/postgres/selectHumidity.sql index 78ebc28..7e8fa06 100644 --- a/pkg/repository/db/postgres/selectHumidity.sql +++ b/pkg/repository/db/postgres/selectHumidity.sql @@ -8,4 +8,4 @@ SELECT FROM humidities WHERE - humidity_id = $1 \ No newline at end of file + id = $1 \ No newline at end of file diff --git a/pkg/repository/db/postgres/selectPressure.sql b/pkg/repository/db/postgres/selectPressure.sql index 08f8a71..fc295c2 100644 --- a/pkg/repository/db/postgres/selectPressure.sql +++ b/pkg/repository/db/postgres/selectPressure.sql @@ -8,4 +8,4 @@ SELECT FROM pressures WHERE - pressure_id = $1 \ No newline at end of file + id = $1 \ No newline at end of file diff --git a/pkg/repository/db/postgres/selectTemperature.sql b/pkg/repository/db/postgres/selectTemperature.sql index 51ab33a..5696656 100644 --- a/pkg/repository/db/postgres/selectTemperature.sql +++ b/pkg/repository/db/postgres/selectTemperature.sql @@ -8,4 +8,4 @@ SELECT FROM temperatures WHERE - temperature_id = $1 \ No newline at end of file + id = $1 \ No newline at end of file diff --git a/pkg/repository/db/sqlite.go b/pkg/repository/db/sqlite.go index d2bf8d5..6a12239 100644 --- a/pkg/repository/db/sqlite.go +++ b/pkg/repository/db/sqlite.go @@ -82,6 +82,42 @@ func (sqlite *SQLite) DeleteSensors(ctx context.Context, sensorIDs ...string) er 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" @@ -184,6 +220,152 @@ func (sqlite *SQLite) InsertMeasuredValues(ctx context.Context, measuredValues . 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" diff --git a/pkg/repository/db/sqlite3/insertOrUpdateDevice.sql b/pkg/repository/db/sqlite3/insertOrUpdateDevice.sql new file mode 100644 index 0000000..1886add --- /dev/null +++ b/pkg/repository/db/sqlite3/insertOrUpdateDevice.sql @@ -0,0 +1,14 @@ +INSERT INTO devices ( + device_id, + device_name, + device_location, + creation_date, + update_date +) +VALUES ($1, $2, $3, $4, $5) +ON CONFLICT (device_id) +DO + UPDATE SET + device_name = EXCLUDED.device_name, + device_location = EXCLUDED.device_location, + update_date = date('now'); \ No newline at end of file diff --git a/pkg/repository/db/sqlite3/insertOrUpdateHumidity.sql b/pkg/repository/db/sqlite3/insertOrUpdateHumidity.sql new file mode 100644 index 0000000..91a6aad --- /dev/null +++ b/pkg/repository/db/sqlite3/insertOrUpdateHumidity.sql @@ -0,0 +1,16 @@ +INSERT INTO humidities ( + id, + value, + date, + sensor_id, + creation_date, + update_date +) +VALUES ($1, $2, $3, $4, $5, $6) +ON CONFLICT (id) +DO + UPDATE SET + value = EXCLUDED.value, + date = EXCLUDED.date, + sensor_id = EXCLUDED.sensor_id, + update_date = date('now'); \ No newline at end of file diff --git a/pkg/repository/db/sqlite3/insertOrUpdatePressure.sql b/pkg/repository/db/sqlite3/insertOrUpdatePressure.sql new file mode 100644 index 0000000..430f8aa --- /dev/null +++ b/pkg/repository/db/sqlite3/insertOrUpdatePressure.sql @@ -0,0 +1,16 @@ +INSERT INTO pressures ( + id, + value, + date, + sensor_id, + creation_date, + update_date +) +VALUES ($1, $2, $3, $4, $5, $6) +ON CONFLICT (id) +DO + UPDATE SET + value = EXCLUDED.value, + date = EXCLUDED.date, + sensor_id = EXCLUDED.sensor_id, + update_date = date('now'); \ No newline at end of file diff --git a/pkg/repository/db/sqlite3/insertOrUpdateSensor.sql b/pkg/repository/db/sqlite3/insertOrUpdateSensor.sql new file mode 100644 index 0000000..2e87609 --- /dev/null +++ b/pkg/repository/db/sqlite3/insertOrUpdateSensor.sql @@ -0,0 +1,31 @@ +INSERT INTO sensors ( + sensor_id, + sensor_name, + sensor_location, + wire_id, + i2c_bus, + i2c_address, + gpio_number, + sensor_model, + sensor_enabled, + tick_duration, + device_id, + creation_date, + update_date +) +VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) +ON CONFLICT (sensor_id) +DO + UPDATE SET + sensor_name = EXCLUDED.sensor_name, + sensor_location = EXCLUDED.sensor_location, + wire_id = EXCLUDED.wire_id, + i2c_bus = EXCLUDED.i2c_bus, + i2c_address = EXCLUDED.i2c_address, + gpio_number = EXCLUDED.gpio_number, + sensor_model = EXCLUDED.sensor_model, + sensor_enabled = EXCLUDED.sensor_enabled, + tick_duration = EXCLUDED.tick_duration, + device_id = EXCLUDED.device_id, + creation_date = EXCLUDED.creation_date, + update_date = date('now'); diff --git a/pkg/repository/db/sqlite3/insertOrUpdateTemperature.sql b/pkg/repository/db/sqlite3/insertOrUpdateTemperature.sql new file mode 100644 index 0000000..cf1e4d6 --- /dev/null +++ b/pkg/repository/db/sqlite3/insertOrUpdateTemperature.sql @@ -0,0 +1,16 @@ +INSERT INTO temperatures ( + id, + value, + date, + sensor_id, + creation_date, + update_date +) +VALUES ($1, $2, $3, $4, $5, $6) +ON CONFLICT (id) +DO + UPDATE SET + value = EXCLUDED.value, + date = EXCLUDED.date, + sensor_id = EXCLUDED.sensor_id, + update_date = date('now'); \ No newline at end of file diff --git a/pkg/repository/db/sqlite3/selectHumidity.sql b/pkg/repository/db/sqlite3/selectHumidity.sql index 78ebc28..7e8fa06 100644 --- a/pkg/repository/db/sqlite3/selectHumidity.sql +++ b/pkg/repository/db/sqlite3/selectHumidity.sql @@ -8,4 +8,4 @@ SELECT FROM humidities WHERE - humidity_id = $1 \ No newline at end of file + id = $1 \ No newline at end of file diff --git a/pkg/repository/db/sqlite3/selectPressure.sql b/pkg/repository/db/sqlite3/selectPressure.sql index 08f8a71..fc295c2 100644 --- a/pkg/repository/db/sqlite3/selectPressure.sql +++ b/pkg/repository/db/sqlite3/selectPressure.sql @@ -8,4 +8,4 @@ SELECT FROM pressures WHERE - pressure_id = $1 \ No newline at end of file + id = $1 \ No newline at end of file diff --git a/pkg/repository/db/sqlite3/selectTemperature.sql b/pkg/repository/db/sqlite3/selectTemperature.sql index 51ab33a..5696656 100644 --- a/pkg/repository/db/sqlite3/selectTemperature.sql +++ b/pkg/repository/db/sqlite3/selectTemperature.sql @@ -8,4 +8,4 @@ SELECT FROM temperatures WHERE - temperature_id = $1 \ No newline at end of file + id = $1 \ No newline at end of file diff --git a/pkg/repository/repository.go b/pkg/repository/repository.go index 64cbc0c..3227050 100644 --- a/pkg/repository/repository.go +++ b/pkg/repository/repository.go @@ -27,6 +27,21 @@ func (repo *Repository) AddMeasuredValues(measuredValues ...*types.MeasuredValue return repo.database.InsertMeasuredValues(context.Background(), measuredValues...) } +// AddOrUpdateDevices to the repository +func (repo *Repository) AddOrUpdateDevices(devices ...*types.Device) error { + return repo.database.InsertOrUpdateDevices(context.Background(), devices...) +} + +// AddOrUpdateMeasuredValues to the repository +func (repo *Repository) AddOrUpdateMeasuredValues(measuredValues ...*types.MeasuredValue) error { + return repo.database.InsertOrUpdateMeasuredValues(context.Background(), measuredValues...) +} + +// AddOrUpdateSensors to the repository +func (repo *Repository) AddOrUpdateSensors(sensors ...*types.Sensor) error { + return repo.database.InsertOrUpdateSensors(context.Background(), sensors...) +} + // AddSensors to the repository func (repo *Repository) AddSensors(sensors ...*types.Sensor) error { return repo.database.InsertSensors(context.Background(), sensors...) @@ -91,6 +106,16 @@ func (repo *Repository) GetDevices() ([]*types.Device, error) { return repo.database.SelectDevices(context.Background()) } +// GetHumidity returns a humidity value by id +func (repo *Repository) GetHumidity(humidityID string) (*types.MeasuredValue, error) { + return repo.database.SelectHumidity(context.Background(), humidityID) +} + +// GetPressure returns a pressure value by id +func (repo *Repository) GetPressure(pressureID string) (*types.MeasuredValue, error) { + return repo.database.SelectPressure(context.Background(), pressureID) +} + // GetSensor returns a sensor by his id. If no sensor has been found, the // function returns nil. func (repo *Repository) GetSensor(sensorID string) (*types.Sensor, error) { @@ -141,6 +166,11 @@ func (repo *Repository) GetSensorsByDeviceID(deviceID string) ([]*types.Sensor, return cachedSensors, nil } +// GetTemperature returns a temperature value by id +func (repo *Repository) GetTemperature(pressureID string) (*types.MeasuredValue, error) { + return repo.database.SelectTemperature(context.Background(), pressureID) +} + // RemoveDevices removes devices by their ids from the repository. Additional // all sensors and measured values, which are in relation with the device // respectively the sensors will also be deleted. diff --git a/pkg/repository/repository_test.go b/pkg/repository/repository_test.go index ee3b89e..560b631 100644 --- a/pkg/repository/repository_test.go +++ b/pkg/repository/repository_test.go @@ -135,7 +135,47 @@ func testBackend(t *testing.T, repo *repository.Repository) { device, err = repo.GetDevice(expectedDevice.ID) require.NoError(err) - // require.JSONEq(jsonEncoder(expectedDevice), jsonEncoder(device)) + require.NotEmpty(device) + require.Equal(expectedDevice.ID, device.ID) + require.Equal(expectedDevice.Name, device.Name) + require.Equal(expectedDevice.Location, device.Location) + + // Test: AddOrUpdateDevices + location = "MySweetLocation" + expectedDevice = &types.Device{ + ID: "9d8c59a5-7927-4a7c-ad48-dbf5405ffd68", + Name: "MySweetDevice", + Location: &location, + CreationDate: *timeNow(require), + } + err = repo.AddOrUpdateDevices(expectedDevice) + require.NoError(err) + + // time.Sleep(time.Minute * 10) + + device, err = repo.GetDevice(expectedDevice.ID) + require.NoError(err) + require.NotEmpty(device) + require.Equal(expectedDevice.ID, device.ID) + require.Equal(expectedDevice.Name, device.Name) + require.Equal(expectedDevice.Location, device.Location) + + location = "MyUglyLocation" + expectedDevice = &types.Device{ + ID: "9d8c59a5-7927-4a7c-ad48-dbf5405ffd68", + Name: "MyUglyDevice", + Location: &location, + CreationDate: *timeNow(require), + } + err = repo.AddOrUpdateDevices(expectedDevice) + require.NoError(err) + + device, err = repo.GetDevice(expectedDevice.ID) + require.NoError(err) + require.NotEmpty(device) + require.Equal(expectedDevice.ID, device.ID) + require.Equal(expectedDevice.Name, device.Name) + require.Equal(expectedDevice.Location, device.Location) var ( wireID = "50473fdc-f6ef-4227-b3c4-484d8e9c1323" @@ -293,6 +333,65 @@ func testBackend(t *testing.T, repo *repository.Repository) { require.NotNil(sensor) // require.JSONEq(jsonEncoder(expectedSensor), jsonEncoder(sensor)) + // Test: AddOrUpdateSensors + expectedSensor = &types.Sensor{ + ID: "9bba0e0a-e996-4242-966f-db21bab6752f", + Name: "b4ac3d0f-cef6-4e93-bd7b-e821ae5ab593", + Location: "HelloWorld", + I2CBus: nil, + I2CAddress: nil, + Model: "SDS011", + Enabled: true, + TickDuration: "6h", + DeviceID: "39b8f150-8abf-4539-9f16-7f68cedb1649", + CreationDate: *timeNow(require), + } + + err = repo.AddOrUpdateSensors(expectedSensor) + require.NoError(err) + + sensor, err = repo.GetSensor(expectedSensor.ID) + require.NoError(err) + require.NotEmpty(sensor) + require.Equal(expectedSensor.ID, sensor.ID) + require.Equal(expectedSensor.Name, sensor.Name) + require.Equal(expectedSensor.Location, sensor.Location) + require.Equal(expectedSensor.I2CBus, sensor.I2CBus) + require.Equal(expectedSensor.I2CAddress, sensor.I2CAddress) + require.Equal(expectedSensor.Model, sensor.Model) + require.Equal(expectedSensor.Enabled, sensor.Enabled) + require.Equal(expectedSensor.TickDuration, sensor.TickDuration) + require.Equal(expectedSensor.DeviceID, sensor.DeviceID) + + expectedSensor = &types.Sensor{ + ID: "9bba0e0a-e996-4242-966f-db21bab6752f", + Name: "MySweetSensor", + Location: "MySweetLocation", + I2CBus: nil, + I2CAddress: nil, + Model: "Jap", + Enabled: false, + TickDuration: "8h", + DeviceID: "39b8f150-8abf-4539-9f16-7f68cedb1649", + CreationDate: *timeNow(require), + } + + err = repo.AddOrUpdateSensors(expectedSensor) + require.NoError(err) + + sensor, err = repo.GetSensor(expectedSensor.ID) + require.NoError(err) + require.NotEmpty(sensor) + require.Equal(expectedSensor.ID, sensor.ID) + require.Equal(expectedSensor.Name, sensor.Name) + require.Equal(expectedSensor.Location, sensor.Location) + require.Equal(expectedSensor.I2CBus, sensor.I2CBus) + require.Equal(expectedSensor.I2CAddress, sensor.I2CAddress) + require.Equal(expectedSensor.Model, sensor.Model) + require.Equal(expectedSensor.Enabled, sensor.Enabled) + require.Equal(expectedSensor.TickDuration, sensor.TickDuration) + require.Equal(expectedSensor.DeviceID, sensor.DeviceID) + var ( expectedMeasuredValues = []*types.MeasuredValue{ { @@ -328,6 +427,97 @@ func testBackend(t *testing.T, repo *repository.Repository) { // Test: AddMeasuredValues err = repo.AddMeasuredValues(expectedMeasuredValues...) require.NoError(err) + + for i := range expectedMeasuredValues { + + var ( + err error + measuredValue *types.MeasuredValue + ) + + switch expectedMeasuredValues[i].ValueType { + case types.Humidity: + measuredValue, err = repo.GetHumidity(expectedMeasuredValues[i].ID) + require.NoError(err) + require.NotNil(measuredValue) + case types.Pressure: + measuredValue, err = repo.GetPressure(expectedMeasuredValues[i].ID) + require.NoError(err) + require.NotNil(measuredValue) + case types.Temperature: + measuredValue, err = repo.GetTemperature(expectedMeasuredValues[i].ID) + require.NoError(err) + require.NotNil(measuredValue) + } + + require.Equal(expectedMeasuredValues[i].ID, measuredValue.ID) + require.Equal(expectedMeasuredValues[i].Value, measuredValue.Value) + require.Equal(expectedMeasuredValues[i].ValueType, measuredValue.ValueType) + require.Equal(expectedMeasuredValues[i].SensorID, measuredValue.SensorID) + } + + // Test: AddOrUpdateMeasuredValues + expectedMeasuredValues = []*types.MeasuredValue{ + { + ID: "2e5a297a-3da0-46ae-89d2-0fcab0f1d5f7", + Value: 35, + ValueType: types.Humidity, + Date: *timeNow(require), + SensorID: "8c74397f-8e60-4c9d-960d-3197747cef9a", + CreationDate: *timeNow(require), + UpdateDate: timeNow(require), + }, + { + ID: "d69f1b62-0c6c-4058-b42c-4a2821bd220c", + Value: 37, + ValueType: types.Pressure, + Date: *timeNow(require), + SensorID: "8c74397f-8e60-4c9d-960d-3197747cef9a", + CreationDate: *timeNow(require), + UpdateDate: timeNow(require), + }, + { + ID: "ea945ae0-412b-4561-a191-1f8f1f909fa4", + Value: 35.4, + ValueType: types.Temperature, + Date: *timeNow(require), + SensorID: "8c74397f-8e60-4c9d-960d-3197747cef9a", + CreationDate: *timeNow(require), + UpdateDate: timeNow(require), + }, + } + + err = repo.AddOrUpdateMeasuredValues(expectedMeasuredValues...) + require.NoError(err) + + for i := range expectedMeasuredValues { + + var ( + err error + measuredValue *types.MeasuredValue + ) + + switch expectedMeasuredValues[i].ValueType { + case types.Humidity: + measuredValue, err = repo.GetHumidity(expectedMeasuredValues[i].ID) + require.NoError(err) + require.NotNil(measuredValue) + case types.Pressure: + measuredValue, err = repo.GetPressure(expectedMeasuredValues[i].ID) + require.NoError(err) + require.NotNil(measuredValue) + case types.Temperature: + measuredValue, err = repo.GetTemperature(expectedMeasuredValues[i].ID) + require.NoError(err) + require.NotNil(measuredValue) + } + + require.Equal(expectedMeasuredValues[i].ID, measuredValue.ID) + require.Equal(expectedMeasuredValues[i].Value, measuredValue.Value) + require.Equal(expectedMeasuredValues[i].ValueType, measuredValue.ValueType) + require.Equal(expectedMeasuredValues[i].SensorID, measuredValue.SensorID) + } + } func jsonEncoder(v interface{}) string {