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

Remove filtering parameters from GetExtents. #179

Merged
merged 1 commit into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
109 changes: 52 additions & 57 deletions datastore/datastore/storagebackend/postgresql/getextents.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,85 +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 extentions.
//
// Values to be used for query placeholders are appended to phVals.
//
// Upon success the function returns two values:
// - time filter used in a 'WHERE ... AND ...' clause
// - string metadata ... ditto
// - nil,
// otherwise (..., ..., error).
func createExtQueryVals(request *datastore.GetExtentsRequest, phVals *[]interface{}) (
string, string, error) {
// 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)
}

loTime, hiTime := common.GetValidTimeRange()
timeFilter := fmt.Sprintf(`
((obstime_instant >= to_timestamp(%d)) AND (obstime_instant <= to_timestamp(%d)))
`, loTime.Unix(), hiTime.Unix())
if start.Before(loTime) {
start = loTime
}
if end.After(hiTime) {
end = hiTime
}

stringMdataFilter, err := getStringMdataFilter(request.GetFilter(), phVals)
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 "", "", fmt.Errorf("getStringMdataFilter() failed: %v", err)
return nil, fmt.Errorf("row.Scan() failed: %v", err)
}

return timeFilter, stringMdataFilter, nil
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) (
func (sbe *PostgreSQL) GetExtents(_ *datastore.GetExtentsRequest) (
*datastore.GetExtentsResponse, codes.Code, string) {

// get values needed for query
phVals := []interface{}{} // placeholder values
timeFilter, stringMdataFilter, err := createExtQueryVals(request, &phVals)
var err error

temporalExtent, err := getTemporalExtent(sbe.Db)
if err != nil {
return nil, codes.Internal, fmt.Sprintf("createQueryVals() failed: %v", err)
return nil, codes.Internal, fmt.Sprintf("getTemporalExtent() 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
) t
`, timeFilter, stringMdataFilter)

row := sbe.Db.QueryRow(query, phVals...)

var (
start, end sql.NullTime
xmin, ymin, xmax, ymax float64
)

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, ""
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DROP INDEX CONCURRENTLY observation_obstim_instant;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
CREATE INDEX CONCURRENTLY observation_obstime_instant ON observation (obstime_instant);
8 changes: 1 addition & 7 deletions protobuf/datastore.proto
Original file line number Diff line number Diff line change
Expand Up @@ -257,13 +257,7 @@ message GetTSAGResponse {
//---------------------------------------------------------------------------

message GetExtentsRequest {
// --- BEGIN string metadata (handleable with reflection) -------------------------

// 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 string metadata (handleable with reflection) -------------------------
}
Expand Down