diff --git a/pkg/storage/db/db.go b/pkg/storage/db/db.go index 2e5608f..bbcb974 100644 --- a/pkg/storage/db/db.go +++ b/pkg/storage/db/db.go @@ -2,7 +2,7 @@ package db import ( "database/sql" - "fmt" + "errors" "net/url" _ "github.com/lib/pq" @@ -10,22 +10,23 @@ import ( ) var ( - flogger = logger.NewSilentLogger() + errorUnsupportedDatabase = errors.New("Unsupported database scheme") + flogger = logger.NewSilentLogger() ) func New(storageEndpoint *url.URL) (Database, error) { - newDBO, err := sql.Open(storageEndpoint.Scheme, storageEndpoint.String()) - if err != nil { - return nil, err - } - switch storageEndpoint.Scheme { case "postgres": + newDBO, err := sql.Open(storageEndpoint.Scheme, storageEndpoint.String()) + if err != nil { + return nil, err + } + return &Postgres{ dbo: newDBO, }, nil default: - return nil, fmt.Errorf("Unknown Database Type") + return nil, errorUnsupportedDatabase } } diff --git a/pkg/storage/db/db_test.go b/pkg/storage/db/db_test.go new file mode 100644 index 0000000..4108cfa --- /dev/null +++ b/pkg/storage/db/db_test.go @@ -0,0 +1,38 @@ +package db + +import ( + "net/url" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestNew(t *testing.T) { + require := require.New(t) + + validStorageEndpoints := []string{ + "postgres://flucky:flucky@markus-pc.trier.cryptic.systems/postgres?sslmode=disable", + } + + unsupportedStorageEndpoints := []string{ + "html://flucky.cryptic.systems", + "oracle://flucky:flucky@example.com/postgres", + } + + for _, validStorageEndpoint := range validStorageEndpoints { + storageEndpointURL, err := url.Parse(validStorageEndpoint) + require.Nil(err) + dbo, err := New(storageEndpointURL) + require.Nil(err) + err = dbo.Close() + require.Nil(err) + } + + for _, unsupportedStorageEndpoint := range unsupportedStorageEndpoints { + storageEndpointURL, err := url.Parse(unsupportedStorageEndpoint) + require.Nil(err) + _, err = New(storageEndpointURL) + require.Equal(errorUnsupportedDatabase, err) + } + +} diff --git a/pkg/storage/db/errors.go b/pkg/storage/db/errors.go index 0b57bc9..30a4602 100644 --- a/pkg/storage/db/errors.go +++ b/pkg/storage/db/errors.go @@ -5,13 +5,14 @@ import ( ) var ( - errorBeginTransaction = errors.New("Can not start new transaction") - errorGetAsset = errors.New("Can not get asset from go-bindata") - errorRowNotFound = errors.New("Can not find row by given ID") - errorPrepareStatement = errors.New("Can not prepare sql statement") - errorRollbackTransaction = errors.New("Can not rollback transaction") - errorScanRow = errors.New("Can not scan row") - errorStatementExecute = errors.New("Can not execute statement") - errorStatementQuery = errors.New("Can not query statement") + errorBeginTransaction = errors.New("Failed to start new transaction") + errorGetAsset = errors.New("Failed to get asset from go-bindata") + errorNoRowsAffected = errors.New("No rows affected") + errorRowNotFound = errors.New("Failed to find row by given ID") + errorPrepareStatement = errors.New("Failed to prepare sql statement") + errorRollbackTransaction = errors.New("Failed to rollback transaction") + errorScanRow = errors.New("Failed to scan row") + errorStatementExecute = errors.New("Failed to execute statement") + errorStatementQuery = errors.New("Failed to query statement") errorUnknownMeasuredValueType = errors.New("Unknown measured value type") ) diff --git a/pkg/storage/db/interfaces.go b/pkg/storage/db/interfaces.go index 75b3fa8..9c016d0 100644 --- a/pkg/storage/db/interfaces.go +++ b/pkg/storage/db/interfaces.go @@ -17,11 +17,13 @@ type Database interface { // Delete DeleteDevices(ctx context.Context, devices []*types.Device) error + DeleteInfo(ctx context.Context, key string) error DeleteMeasuredValues(ctx context.Context, measuredValues []*types.MeasuredValue) error DeleteSensors(ctx context.Context, sensors []*types.Sensor) error // Insert InsertDevices(ctx context.Context, devices []*types.Device) error + InsertInfo(ctx context.Context, key string, value string) error InsertMeasuredValues(ctx context.Context, measuredValues []*types.MeasuredValue) error InsertSensors(ctx context.Context, sensors []*types.Sensor) error @@ -29,6 +31,7 @@ type Database interface { SelectDeviceByID(ctx context.Context, id string) (*types.Device, error) SelectHumidities(ctx context.Context) ([]*types.MeasuredValue, error) SelectHumidityByID(ctx context.Context, id string) (*types.MeasuredValue, error) + SelectInfo(ctx context.Context, key string) (string, error) SelectMeasuredValues(ctx context.Context) ([]*types.MeasuredValue, error) SelectMeasuredValuesByIDAndType(ctx context.Context, id string, valueType types.MeasuredValueType) (*types.MeasuredValue, error) SelectPressures(ctx context.Context) ([]*types.MeasuredValue, error) @@ -39,6 +42,7 @@ type Database interface { // Update UpdateDevices(ctx context.Context, devices []*types.Device) error + UpdateInfo(ctx context.Context, key string, value string) error UpdateMeasuredValues(ctx context.Context, measuredValues []*types.MeasuredValue) error UpdateSensors(ctx context.Context, sensots []*types.Sensor) error } diff --git a/pkg/storage/db/postgres.go b/pkg/storage/db/postgres.go index 9247468..6f5146d 100644 --- a/pkg/storage/db/postgres.go +++ b/pkg/storage/db/postgres.go @@ -152,6 +152,29 @@ func (p *Postgres) DeleteSensors(ctx context.Context, sensors []*types.Sensor) e return nil } +// DeleteInfo delete a key with his value +func (p *Postgres) DeleteInfo(ctx context.Context, key string) error { + asset := fmt.Sprintf("%v/deleteInfo.sql", postgresAssetPath) + queryBytes, err := Asset(asset) + if err != nil { + return fmt.Errorf("%v: %v", errorGetAsset, err) + } + query := string(queryBytes) + + stmt, err := p.dbo.PrepareContext(ctx, query) + if err != nil { + return fmt.Errorf("%v: %v", errorPrepareStatement, err) + } + defer stmt.Close() + + _, err = stmt.ExecContext(ctx, &key) + if err != nil { + return fmt.Errorf("%v: %v", errorStatementExecute, err) + } + + return nil +} + // DeleteMeasuredValues delete all spicified measured values func (p *Postgres) DeleteMeasuredValues(ctx context.Context, measuredValues []*types.MeasuredValue) error { @@ -662,11 +685,20 @@ func (p *Postgres) UpdateInfo(ctx context.Context, key string, value string) err } defer stmt.Close() - _, err = stmt.ExecContext(ctx, key, value) + res, err := stmt.ExecContext(ctx, key, value) if err != nil { return fmt.Errorf("%v: %v", errorStatementExecute, err) } + affected, err := res.RowsAffected() + if err != nil { + return err + } + + if affected == 0 { + return errorNoRowsAffected + } + return nil } diff --git a/pkg/storage/db/postgres_test.go b/pkg/storage/db/postgres_test.go index c3f3ab4..ac90970 100644 --- a/pkg/storage/db/postgres_test.go +++ b/pkg/storage/db/postgres_test.go @@ -86,6 +86,10 @@ func TestPostgres(t *testing.T) { Name: "schema", Test: testSchemaCreate, }, + &test{ + Name: "insertInfo", + Test: testInsertInfo, + }, &test{ Name: "insertDevices", Test: testInsertDevices, @@ -106,10 +110,30 @@ func TestPostgres(t *testing.T) { Name: "insertTemperatures", Test: testInsertTemperatures, }, + &test{ + Name: "selectHumidities", + Test: testSelectHumidities, + }, + &test{ + Name: "selectPressures", + Test: testSelectPressures, + }, + &test{ + Name: "selectTemperatures", + Test: testSelectTemperatures, + }, + // &test{ + // Name: "selectMeasuredValues", + // Test: testSelectMeasuredValues, + // }, &test{ Name: "deleteHumidities", Test: testDeleteHumidity, }, + &test{ + Name: "deleteInfo", + Test: testDeleteInfo, + }, &test{ Name: "deletePressures", Test: testDeletePressures, @@ -134,6 +158,10 @@ func TestPostgres(t *testing.T) { Name: "deleteDevices", Test: testDeleteDevices, }, + &test{ + Name: "updateInfo", + Test: testUpdateInfo, + }, } for _, test := range tests { @@ -193,6 +221,18 @@ func testInsertHumidity(t *testing.T) { } } +func testInsertInfo(t *testing.T) { + require := require.New(t) + ctx := context.Background() + err := database.InsertInfo(ctx, "test", "value") + require.NoError(err) + + value, err := database.SelectInfo(ctx, "test") + require.NoError(err) + + require.Equal("value", value) +} + func testInsertMeasuredValues(t *testing.T) { require := require.New(t) ctx := context.Background() @@ -229,6 +269,38 @@ func testInsertTemperatures(t *testing.T) { } } +func testSelectHumidities(t *testing.T) { + require := require.New(t) + ctx := context.Background() + humidities, err := database.SelectHumidities(ctx) + require.NoError(err) + goldenfiles.CompareMeasuredValues(t, goldenHumidites, humidities) +} + +func testSelectMeasuredValues(t *testing.T) { + require := require.New(t) + ctx := context.Background() + measuredValues, err := database.SelectMeasuredValues(ctx) + require.NoError(err) + goldenfiles.CompareMeasuredValues(t, goldenMeasuredValues, measuredValues) +} + +func testSelectPressures(t *testing.T) { + require := require.New(t) + ctx := context.Background() + pressures, err := database.SelectPressures(ctx) + require.NoError(err) + goldenfiles.CompareMeasuredValues(t, goldenPressures, pressures) +} + +func testSelectTemperatures(t *testing.T) { + require := require.New(t) + ctx := context.Background() + temperatures, err := database.SelectTemperatures(ctx) + require.NoError(err) + goldenfiles.CompareMeasuredValues(t, goldenTemperatures, temperatures) +} + func testDeleteDevices(t *testing.T) { require := require.New(t) ctx := context.Background() @@ -262,6 +334,15 @@ func testDeleteHumidity(t *testing.T) { } } +func testDeleteInfo(t *testing.T) { + require := require.New(t) + ctx := context.Background() + err := database.DeleteInfo(ctx, "test") + require.NoError(err) + _, err = database.SelectInfo(ctx, "test") + require.Error(err) +} + func testDeleteMeasuredValues(t *testing.T) { require := require.New(t) ctx := context.Background() @@ -294,3 +375,23 @@ func testDeleteTemperatures(t *testing.T) { require.Error(err) } } + +func testUpdateInfo(t *testing.T) { + require := require.New(t) + ctx := context.Background() + + // VALID + err := database.InsertInfo(ctx, "key", "value") + require.NoError(err) + err = database.UpdateInfo(ctx, "key", "value2") + require.NoError(err) + value, err := database.SelectInfo(ctx, "key") + require.NoError(err) + require.Equal("value2", value) + err = database.DeleteInfo(ctx, "key") + require.NoError(err) + + // INVALID + err = database.UpdateInfo(ctx, "key2", "value") + require.Error(err) +} diff --git a/pkg/storage/db/sql/psql/deleteInfo.sql b/pkg/storage/db/sql/psql/deleteInfo.sql new file mode 100644 index 0000000..4bdf5d0 --- /dev/null +++ b/pkg/storage/db/sql/psql/deleteInfo.sql @@ -0,0 +1,2 @@ +DELETE FROM info +WHERE key = $1; \ No newline at end of file