feat(datasets): periods (start_date/end_date), dg_id column, date filters; rename observation dates
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -71,20 +71,28 @@ type DatasetFilter struct {
|
||||
FileType *FileType
|
||||
Automated *bool
|
||||
Status *string
|
||||
// DatasetGroupID restricts the listing to one dataset group.
|
||||
DatasetGroupID *uuid.UUID
|
||||
// StartDateFrom / StartDateTo and EndDateFrom / EndDateTo are inclusive
|
||||
// YYYY-MM-DD bounds on the dataset's period columns.
|
||||
StartDateFrom *string
|
||||
StartDateTo *string
|
||||
EndDateFrom *string
|
||||
EndDateTo *string
|
||||
}
|
||||
|
||||
// Observation is a single unpivoted value from a dataset's attribute table,
|
||||
// keyed by KATO code and date (optionally a date..DateTo period). Exactly one
|
||||
// of Value / ValueText is typically set (numeric vs non-numeric cell); both
|
||||
// keyed by KATO code and date (optionally a StartDate..EndDate period). Exactly
|
||||
// one of Value / ValueText is typically set (numeric vs non-numeric cell); both
|
||||
// may be nil for an empty cell.
|
||||
type Observation struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
DatasetID uuid.UUID `json:"dataset_id"`
|
||||
KatoCode string `json:"kato_code"`
|
||||
Date string `json:"date"`
|
||||
// DateTo is the period's end date. Nil for a point-in-time observation
|
||||
StartDate string `json:"start_date"`
|
||||
// EndDate is the period's end date. Nil for a point-in-time observation
|
||||
// (pre-existing behavior).
|
||||
DateTo *string `json:"date_to,omitempty"`
|
||||
EndDate *string `json:"end_date,omitempty"`
|
||||
Value *float64 `json:"value"`
|
||||
ValueText *string `json:"value_text"`
|
||||
}
|
||||
@@ -185,21 +193,29 @@ type AttributeColumn struct {
|
||||
}
|
||||
|
||||
// YearColumn maps an attribute column to the date (or date period) it
|
||||
// represents, e.g. {"column": "F_2023", "date": "2023-01-01"} for a single
|
||||
// point in time, or {"column": "F_2020_2023", "date": "2020-01-01", "date_to":
|
||||
// "2023-12-31"} for a period. DateTo is optional; when nil the mapping is a
|
||||
// single point in time, preserving the original (pre-period) behavior.
|
||||
// represents, e.g. {"column": "F_2023", "start_date": "2023-01-01"} for a
|
||||
// single point in time, or {"column": "F_2020_2023", "start_date":
|
||||
// "2020-01-01", "end_date": "2023-12-31"} for a period. EndDate is optional;
|
||||
// when nil the mapping is a single point in time, preserving the original
|
||||
// (pre-period) behavior.
|
||||
type YearColumn struct {
|
||||
Column string `json:"column"`
|
||||
Date string `json:"date"`
|
||||
DateTo *string `json:"date_to,omitempty"`
|
||||
Column string `json:"column"`
|
||||
StartDate string `json:"start_date"`
|
||||
EndDate *string `json:"end_date,omitempty"`
|
||||
}
|
||||
|
||||
// DatasetSummary is the lightweight view of a dataset used in list responses.
|
||||
// It omits the heavy geometry/attribute/JSONB fields.
|
||||
type DatasetSummary struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
CategoryID uuid.UUID `json:"category_id"`
|
||||
ID uuid.UUID `json:"id"`
|
||||
CategoryID uuid.UUID `json:"category_id"`
|
||||
// DatasetGroupID links the dataset to its dataset group ("одноимённые"
|
||||
// datasets versioned by period). Nullable.
|
||||
DatasetGroupID *uuid.UUID `json:"dg_id"`
|
||||
// StartDate / EndDate is the period the dataset describes (YYYY-MM-DD).
|
||||
// Both nullable; EndDate drives the "freshest in group" rule.
|
||||
StartDate *string `json:"start_date"`
|
||||
EndDate *string `json:"end_date"`
|
||||
Name string `json:"name"`
|
||||
Description *string `json:"description"`
|
||||
Unit *string `json:"unit"`
|
||||
@@ -212,13 +228,20 @@ type DatasetSummary struct {
|
||||
|
||||
// Dataset is a geo file stored in the object store and grouped under a category.
|
||||
type Dataset struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
CategoryID uuid.UUID `json:"category_id"`
|
||||
Name string `json:"name"`
|
||||
Description *string `json:"description"`
|
||||
Unit *string `json:"unit"`
|
||||
Filename string `json:"filename"`
|
||||
StorageKey string `json:"storage_key"`
|
||||
ID uuid.UUID `json:"id"`
|
||||
CategoryID uuid.UUID `json:"category_id"`
|
||||
// DatasetGroupID links the dataset to its dataset group ("одноимённые"
|
||||
// datasets versioned by period). Nullable.
|
||||
DatasetGroupID *uuid.UUID `json:"dg_id"`
|
||||
// StartDate / EndDate is the period the dataset describes (YYYY-MM-DD).
|
||||
// Both nullable; EndDate drives the "freshest in group" rule.
|
||||
StartDate *string `json:"start_date"`
|
||||
EndDate *string `json:"end_date"`
|
||||
Name string `json:"name"`
|
||||
Description *string `json:"description"`
|
||||
Unit *string `json:"unit"`
|
||||
Filename string `json:"filename"`
|
||||
StorageKey string `json:"storage_key"`
|
||||
// CogStorageKey points to the Cloud-Optimized GeoTIFF for rasters. Nullable.
|
||||
CogStorageKey *string `json:"cog_storage_key"`
|
||||
FileType FileType `json:"file_type"`
|
||||
@@ -262,3 +285,37 @@ type Dataset struct {
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// DatasetFields is the set of editable metadata columns written by
|
||||
// UpdateFields. Nil pointers clear the corresponding nullable column.
|
||||
type DatasetFields struct {
|
||||
CategoryID uuid.UUID
|
||||
Name string
|
||||
Description *string
|
||||
Unit *string
|
||||
DatasetGroupID *uuid.UUID
|
||||
StartDate *string
|
||||
EndDate *string
|
||||
}
|
||||
|
||||
// ValidateDatePeriod checks that start/end (YYYY-MM-DD, either may be nil)
|
||||
// parse and that end is not before start. Returns an ErrValidation-wrapped
|
||||
// error naming the offending field.
|
||||
func ValidateDatePeriod(start, end *string) error {
|
||||
var from, to time.Time
|
||||
var err error
|
||||
if start != nil {
|
||||
if from, err = time.Parse("2006-01-02", *start); err != nil {
|
||||
return fmt.Errorf("%w: start_date %q is not YYYY-MM-DD", ErrValidation, *start)
|
||||
}
|
||||
}
|
||||
if end != nil {
|
||||
if to, err = time.Parse("2006-01-02", *end); err != nil {
|
||||
return fmt.Errorf("%w: end_date %q is not YYYY-MM-DD", ErrValidation, *end)
|
||||
}
|
||||
}
|
||||
if start != nil && end != nil && to.Before(from) {
|
||||
return fmt.Errorf("%w: end_date %q is before start_date %q", ErrValidation, *end, *start)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user