Skip to content

Commit

Permalink
Merge pull request #71 from EURODEO/get_extents_issue_63
Browse files Browse the repository at this point in the history
Added GetExtents method
  • Loading branch information
jo-asplin-met-no authored Nov 22, 2023
2 parents 9dd1546 + 921c6b6 commit 0d01f00
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 1 deletion.
18 changes: 18 additions & 0 deletions datastore/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,24 @@ $ grpcurl -d '{"standard_names": ["wind_speed", "air_temperature"], "interval":
...
```

### Get the temporal- and spatial extent of all observations currently in the storage

```text
$ grpcurl -plaintext -proto protobuf/datastore.proto 127.0.0.1:50050 datastore.Datastore.GetExtents
{
"timeExtent": {
"start": "2022-12-31T00:00:00Z",
"end": "2022-12-31T23:50:00Z"
},
"geoExtent": {
"left": -68.2758333,
"bottom": 12.13,
"right": 7.1493220605216,
"top": 55.399166666667
}
}
```

## Testing the datastore service with a Python client

### Compiling the protobuf file
Expand Down
20 changes: 20 additions & 0 deletions datastore/dsimpl/getextents.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package dsimpl

import (
"context"
"fmt"

"datastore/datastore"
)

func (svcInfo *ServiceInfo) GetExtents(
ctx context.Context, request *datastore.GetExtentsRequest) (
*datastore.GetExtentsResponse, error) {

response, err := svcInfo.Sbe.GetExtents(request)
if err != nil {
return nil, fmt.Errorf("svcInfo.Sbe.GetExtents() failed: %v", err)
}

return response, nil
}
22 changes: 21 additions & 1 deletion datastore/protobuf/datastore.proto
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ option go_package = "./datastore";
service Datastore {
rpc PutObservations(PutObsRequest) returns (PutObsResponse);
rpc GetObservations(GetObsRequest) returns (GetObsResponse);
rpc GetExtents(GetExtentsRequest) returns (GetExtentsResponse);
}

//---------------------------------------------------------------------------
Expand All @@ -35,6 +36,13 @@ message Polygon { // horizontal area; three or more points
repeated Point points = 1;
}

message BoundingBox {
double left = 1;
double bottom = 2;
double right = 3;
double top = 4;
}

message TimeInterval {
google.protobuf.Timestamp start = 1;
google.protobuf.Timestamp end = 2;
Expand Down Expand Up @@ -127,9 +135,21 @@ message GetObsRequest {
// TODO: add search filters for other metadata
}


message GetObsResponse {
int32 status = 1;
string error = 2; // any error description (empty on success)
repeated Metadata2 observations = 3;
}

//---------------------------------------------------------------------------

message GetExtentsRequest {
// currently no args
}

message GetExtentsResponse {
int32 status = 1;
string error = 2; // any error description (empty on success)
TimeInterval temporal_extent = 3;
BoundingBox spatial_extent = 4;
}
74 changes: 74 additions & 0 deletions datastore/storagebackend/postgresql/getextents.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package postgresql

import (
"database/sql"
"datastore/datastore"
"fmt"
"time"

_ "github.com/lib/pq"
"google.golang.org/protobuf/types/known/timestamppb"
)

// getTemporalExtent gets the current temporal extent of all observations in the storage.
func getTemporalExtent(db *sql.DB) (*datastore.TimeInterval, error) {
query := "SELECT min(obstime_instant), max(obstime_instant) FROM observation"
row := db.QueryRow(query)

var start, end time.Time

err := row.Scan(&start, &end)
if err != nil {
return nil, fmt.Errorf("row.Scan() failed: %v", err)
}

return &datastore.TimeInterval{
Start: timestamppb.New(start),
End: timestamppb.New(end),
}, nil
}

// getSpatialExtent gets the current horizontally spatial extent of all observations in the storage.
func getSpatialExtent(db *sql.DB) (*datastore.BoundingBox, error) {
query := `
SELECT ST_XMin(ext), ST_YMin(ext), ST_XMax(ext), ST_YMax(ext)
FROM (SELECT ST_Extent(point::geometry) AS ext FROM geo_point) t
`
row := db.QueryRow(query)

var xmin, ymin, xmax, ymax float64

err := row.Scan(&xmin, &ymin, &xmax, &ymax)
if err != nil {
return nil, fmt.Errorf("row.Scan() failed: %v", err)
}

return &datastore.BoundingBox{
Left: xmin,
Bottom: ymin,
Right: xmax,
Top: ymax,
}, nil
}

// GetExtents ... (see documentation in StorageBackend interface)
func (sbe *PostgreSQL) GetExtents(request *datastore.GetExtentsRequest) (
*datastore.GetExtentsResponse, error) {

var err error

temporalExtent, err := getTemporalExtent(sbe.Db)
if err != nil {
return nil, fmt.Errorf("getTemporalExtent() failed: %v", err)
}

spatialExtent, err := getSpatialExtent(sbe.Db)
if err != nil {
return nil, fmt.Errorf("getSpatialExtent() failed: %v", err)
}

return &datastore.GetExtentsResponse{
TemporalExtent: temporalExtent,
SpatialExtent: spatialExtent,
}, nil
}
4 changes: 4 additions & 0 deletions datastore/storagebackend/storagebackend.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,8 @@ type StorageBackend interface {
// GetObservations retrieves observations from the storage.
// Returns nil upon success, otherwise error.
GetObservations(*datastore.GetObsRequest) (*datastore.GetObsResponse, error)

// GetExtents gets the time- and geo extents of all currently stored observations.
// Returns nil upon success, otherwise error.
GetExtents(*datastore.GetExtentsRequest) (*datastore.GetExtentsResponse, error)
}

0 comments on commit 0d01f00

Please sign in to comment.