Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Restore lost code #199

Merged
merged 2 commits into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 56 additions & 55 deletions datastore/datastore/storagebackend/postgresql/getextents.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,79 +5,80 @@ import (
"datastore/common"
"datastore/datastore"
"fmt"
"time"

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

// createExtQueryVals creates from request values used for querying extensions.
//
// Values to be used for query placeholders are appended to phVals.
//
// Returns:
// - time filter used in a 'WHERE ... AND ...' clause
// - filter for reflectable metadata fields of type int64 ... ditto
// - filter for reflectable metadata fields of type string ... ditto
func createExtQueryVals(request *datastore.GetExtentsRequest, phVals *[]interface{}) (
string, string, string) {
// 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)

loTime, hiTime := common.GetValidTimeRange()
timeFilter := fmt.Sprintf(`
((obstime_instant >= to_timestamp(%d)) AND (obstime_instant <= to_timestamp(%d)))
`, loTime.Unix(), hiTime.Unix())
var start, end time.Time

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

int64MdataFilter := getInt64MdataFilter(request.GetFilter(), phVals)
stringMdataFilter := getStringMdataFilter(request.GetFilter(), phVals)
loTime, hiTime := common.GetValidTimeRange()
if start.Before(loTime) {
start = loTime
}
if end.After(hiTime) {
end = hiTime
}

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

// GetExtents ... (see documentation in StorageBackend interface)
func (sbe *PostgreSQL) GetExtents(request *datastore.GetExtentsRequest) (
*datastore.GetExtentsResponse, codes.Code, string) {
// 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

// get values needed for query
phVals := []interface{}{} // placeholder values
timeFilter, int64MdataFilter, stringMdataFilter := createExtQueryVals(request, &phVals)
err := row.Scan(&xmin, &ymin, &xmax, &ymax)
if err != nil {
return nil, fmt.Errorf("row.Scan() failed: %v", err)
}

query := fmt.Sprintf(`
SELECT temp_min, temp_max,
ST_XMin(spat_ext), ST_YMin(spat_ext), ST_XMax(spat_ext), ST_YMax(spat_ext)
FROM (
SELECT min(obstime_instant) AS temp_min, max(obstime_instant) AS temp_max,
ST_Extent(point::geometry) AS spat_ext
FROM observation
JOIN time_series ON observation.ts_id = time_series.id
JOIN geo_point ON observation.geo_point_id = geo_point.id
WHERE %s AND %s AND %s
) t
`, timeFilter, int64MdataFilter, stringMdataFilter)
return &datastore.BoundingBox{
Left: xmin,
Bottom: ymin,
Right: xmax,
Top: ymax,
}, nil
}

row := sbe.Db.QueryRow(query, phVals...)
// GetExtents ... (see documentation in StorageBackend interface)
func (sbe *PostgreSQL) GetExtents(_ *datastore.GetExtentsRequest) (
*datastore.GetExtentsResponse, codes.Code, string,
) {
var err error

var (
start, end sql.NullTime
xmin, ymin, xmax, ymax float64
)
temporalExtent, err := getTemporalExtent(sbe.Db)
if err != nil {
return nil, codes.Internal, fmt.Sprintf("getTemporalExtent() failed: %v", err)
}

err := row.Scan(&start, &end, &xmin, &ymin, &xmax, &ymax)
if !start.Valid { // indicates no matching rows found!
return nil, codes.NotFound, "no matching data to compute extensions for"
} else if err != nil {
return nil, codes.Internal, fmt.Sprintf("row.Scan() failed: %v", err)
spatialExtent, err := getSpatialExtent(sbe.Db)
if err != nil {
return nil, codes.Internal, fmt.Sprintf("getSpatialExtent() failed: %v", err)
}

return &datastore.GetExtentsResponse{
TemporalExtent: &datastore.TimeInterval{
Start: timestamppb.New(start.Time),
End: timestamppb.New(end.Time),
},
SpatialExtent: &datastore.BoundingBox{
Left: xmin,
Bottom: ymin,
Right: xmax,
Top: ymax,
},
TemporalExtent: temporalExtent,
SpatialExtent: spatialExtent,
}, codes.OK, ""
}
10 changes: 2 additions & 8 deletions protobuf/datastore.proto
Original file line number Diff line number Diff line change
Expand Up @@ -305,15 +305,9 @@ message GetTSAGResponse {
//---------------------------------------------------------------------------

message GetExtentsRequest {
// --- BEGIN filter for reflectable metadata of type int64 or string -------------------------

// general filter
// - map keys must correspond exactly with string field names in TSMetadata or ObsMetadata
// - if map key F is specified (where F is for example 'platform'), only observations that match
// at least one of these values for F may be returned
map<string, Strings> filter = 1;
// No parameters

// --- END filter for reflectable metadata of type int64 or string -------------------------
// --- END string metadata (handleable with reflection) -------------------------
Teddy-1000 marked this conversation as resolved.
Show resolved Hide resolved
}

message GetExtentsResponse {
Expand Down