Skip to content

Commit b2b580d

Browse files
committed
Support for STAC 1.1
1 parent 95993f9 commit b2b580d

22 files changed

+430
-19
lines changed

asset.go

+11
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ type Asset struct {
1313
Description string `json:"description,omitempty"`
1414
Created string `json:"created,omitempty"`
1515
Roles []string `json:"roles,omitempty"`
16+
Bands []*Band `json:"bands,omitempty"`
1617
Extensions []Extension `json:"-"`
1718
}
1819

@@ -47,6 +48,16 @@ func EncodeAssets(assets map[string]*Asset) (map[string]any, []string, error) {
4748
return nil, nil, err
4849
}
4950
}
51+
52+
bandMaps, uris, err := EncodeBands(asset.Bands)
53+
if err != nil {
54+
return nil, nil, err
55+
}
56+
if len(bandMaps) > 0 {
57+
extensionUris = append(extensionUris, uris...)
58+
assetMap["bands"] = bandMaps
59+
}
60+
5061
assetsMap[key] = assetMap
5162
}
5263
return assetsMap, extensionUris, nil

asset_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55
"testing"
66

77
"github.com/planetlabs/go-stac"
8-
"github.com/planetlabs/go-stac/extensions/pl"
8+
"github.com/planetlabs/go-stac/extensions/pl/v1"
99
"github.com/stretchr/testify/assert"
1010
"github.com/stretchr/testify/require"
1111
)

band.go

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package stac
2+
3+
import (
4+
"regexp"
5+
6+
"github.com/go-viper/mapstructure/v2"
7+
)
8+
9+
var bandExtensions = newExtensionRegistry()
10+
11+
func RegisterBandExtension(pattern *regexp.Regexp, provider ExtensionProvider) {
12+
bandExtensions.register(pattern, provider)
13+
}
14+
15+
func GetBandExtension(uri string) Extension {
16+
return bandExtensions.get(uri)
17+
}
18+
19+
type Band struct {
20+
Name string `json:"name,omitempty"`
21+
Description string `json:"description,omitempty"`
22+
NoData any `json:"nodata,omitempty"`
23+
DataType string `json:"data_type,omitempty"`
24+
Statistics *Statistics `json:"statistics,omitempty"`
25+
Unit string `json:"unit,omitempty"`
26+
Extensions []Extension `json:"-"`
27+
}
28+
29+
type Statistics struct {
30+
Mean *float64 `json:"mean,omitempty"`
31+
Minimum *float64 `json:"minimum,omitempty"`
32+
Maximum *float64 `json:"maximum,omitempty"`
33+
Stdev *float64 `json:"stdev,omitempty"`
34+
ValidPercent *float64 `json:"valid_percent,omitempty"`
35+
Count *int `json:"count,omitempty"`
36+
}
37+
38+
func encodeBand(band *Band) (map[string]any, []string, error) {
39+
extensionUris := []string{}
40+
bandMap := map[string]any{}
41+
decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
42+
TagName: "json",
43+
Result: &bandMap,
44+
})
45+
if err != nil {
46+
return nil, nil, err
47+
}
48+
if err := decoder.Decode(band); err != nil {
49+
return nil, nil, err
50+
}
51+
for _, extension := range band.Extensions {
52+
extensionUris = append(extensionUris, extension.URI())
53+
if err := extension.Encode(bandMap); err != nil {
54+
return nil, nil, err
55+
}
56+
}
57+
return bandMap, extensionUris, nil
58+
}
59+
60+
func EncodeBands(bands []*Band) ([]map[string]any, []string, error) {
61+
extensionUris := []string{}
62+
bandMaps := make([]map[string]any, len(bands))
63+
for i, band := range bands {
64+
bandMap, uris, err := encodeBand(band)
65+
if err != nil {
66+
return nil, nil, err
67+
}
68+
bandMaps[i] = bandMap
69+
extensionUris = append(extensionUris, uris...)
70+
}
71+
return bandMaps, extensionUris, nil
72+
}

catalog.go

+4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package stac
22

33
import (
44
"encoding/json"
5+
"errors"
56
"fmt"
67
"regexp"
78

@@ -116,6 +117,9 @@ func (catalog *Catalog) UnmarshalJSON(data []byte) error {
116117
continue
117118
}
118119
if err := extension.Decode(catalogMap); err != nil {
120+
if errors.Is(err, ErrExtensionDoesNotApply) {
121+
continue
122+
}
119123
return fmt.Errorf("decoding error for %s: %w", uri, err)
120124
}
121125
catalog.Extensions = append(catalog.Extensions, extension)

collection.go

+4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package stac
22

33
import (
44
"encoding/json"
5+
"errors"
56
"fmt"
67
"regexp"
78

@@ -140,6 +141,9 @@ func (collection *Collection) UnmarshalJSON(data []byte) error {
140141
continue
141142
}
142143
if err := extension.Decode(collectionMap); err != nil {
144+
if errors.Is(err, ErrExtensionDoesNotApply) {
145+
continue
146+
}
143147
return fmt.Errorf("decoding error for %s: %w", uri, err)
144148
}
145149
collection.Extensions = append(collection.Extensions, extension)

extension.go

+63-5
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66
"regexp"
77
"slices"
8+
"strings"
89
"sync"
910

1011
"github.com/go-viper/mapstructure/v2"
@@ -153,7 +154,19 @@ func EncodeExtendedMap(extension Extension, data map[string]any) error {
153154
return encoder.Decode(extension)
154155
}
155156

156-
func DecodeExtendedMap(extension Extension, data map[string]any) error {
157+
func DecodeExtendedMap(extension Extension, data map[string]any, prefix string) error {
158+
if prefix != "" {
159+
applies := false
160+
for k := range data {
161+
if strings.HasPrefix(k, prefix+":") {
162+
applies = true
163+
break
164+
}
165+
}
166+
if !applies {
167+
return ErrExtensionDoesNotApply
168+
}
169+
}
157170
decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
158171
TagName: "json",
159172
Result: extension,
@@ -208,15 +221,16 @@ func decodeExtendedAssets(data map[string]any, assets map[string]*Asset, extensi
208221
}
209222

210223
for key, asset := range assets {
224+
assetMap, ok := assetsMap[key].(map[string]any)
225+
if !ok {
226+
return fmt.Errorf("unexpected type for %q asset: %T", key, assetsMap[key])
227+
}
228+
211229
for _, uri := range extensionUris {
212230
extension := GetAssetExtension(uri)
213231
if extension == nil {
214232
continue
215233
}
216-
assetMap, ok := assetsMap[key].(map[string]any)
217-
if !ok {
218-
return fmt.Errorf("unexpected type for %q asset: %t", key, assetsMap[key])
219-
}
220234
if err := extension.Decode(assetMap); err != nil {
221235
if errors.Is(err, ErrExtensionDoesNotApply) {
222236
continue
@@ -225,8 +239,52 @@ func decodeExtendedAssets(data map[string]any, assets map[string]*Asset, extensi
225239
}
226240
asset.Extensions = append(asset.Extensions, extension)
227241
}
242+
243+
if err := decodeExtendedBands(assetMap, asset.Bands, extensionUris); err != nil {
244+
return err
245+
}
246+
}
247+
248+
return nil
249+
}
250+
251+
func decodeExtendedBands(assetData map[string]any, bands []*Band, extensionUris []string) error {
252+
bandsValue, ok := assetData["bands"]
253+
if !ok {
254+
return nil
228255
}
229256

257+
bandsSlice, ok := bandsValue.([]any)
258+
if !ok {
259+
return fmt.Errorf("unexpected type for bands: %T", bandsValue)
260+
}
261+
262+
if len(bandsSlice) != len(bands) {
263+
return fmt.Errorf("band length mismatch: got %d but expected %d", len(bandsSlice), len(bands))
264+
}
265+
266+
for i, band := range bands {
267+
for _, uri := range extensionUris {
268+
extension := GetBandExtension(uri)
269+
if extension == nil {
270+
continue
271+
}
272+
273+
bandMap, ok := bandsSlice[i].(map[string]any)
274+
if !ok {
275+
return fmt.Errorf("unexpected type for band %d: %T", i, bandsSlice[i])
276+
}
277+
278+
if err := extension.Decode(bandMap); err != nil {
279+
if errors.Is(err, ErrExtensionDoesNotApply) {
280+
continue
281+
}
282+
return fmt.Errorf("decoding error for %s: %w", uri, err)
283+
}
284+
285+
band.Extensions = append(band.Extensions, extension)
286+
}
287+
}
230288
return nil
231289
}
232290

extensions/auth/auth.go extensions/auth/v1/auth.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
const (
1212
extensionUri = "https://stac-extensions.github.io/authentication/v1.1.0/schema.json"
1313
extensionPattern = `https://stac-extensions.github.io/authentication/v1\..*/schema.json`
14+
prefix = "auth"
1415
schemesKey = "auth:schemes"
1516
refsKey = "auth:refs"
1617
)
@@ -159,7 +160,7 @@ func (e *Asset) Decode(assetMap map[string]any) error {
159160
if _, ok := assetMap[refsKey]; !ok {
160161
return stac.ErrExtensionDoesNotApply
161162
}
162-
return stac.DecodeExtendedMap(e, assetMap)
163+
return stac.DecodeExtendedMap(e, assetMap, prefix)
163164
}
164165

165166
type Link struct {
@@ -180,5 +181,5 @@ func (e *Link) Decode(linkMap map[string]any) error {
180181
if _, ok := linkMap[refsKey]; !ok {
181182
return stac.ErrExtensionDoesNotApply
182183
}
183-
return stac.DecodeExtendedMap(e, linkMap)
184+
return stac.DecodeExtendedMap(e, linkMap, prefix)
184185
}

extensions/auth/auth_test.go extensions/auth/v1/auth_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55
"testing"
66

77
"github.com/planetlabs/go-stac"
8-
"github.com/planetlabs/go-stac/extensions/auth"
8+
"github.com/planetlabs/go-stac/extensions/auth/v1"
99
"github.com/stretchr/testify/assert"
1010
"github.com/stretchr/testify/require"
1111
)

extensions/eo/eo.go extensions/eo/v1/eo.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
const (
1010
extensionUri = "https://stac-extensions.github.io/eo/v1.1.0/schema.json"
1111
extensionPattern = `https://stac-extensions.github.io/eo/v1\..*/schema.json`
12+
prefix = "eo"
1213
)
1314

1415
func init() {
@@ -76,7 +77,7 @@ func (e *Asset) Encode(assetMap map[string]any) error {
7677
}
7778

7879
func (e *Asset) Decode(assetMap map[string]any) error {
79-
if err := stac.DecodeExtendedMap(e, assetMap); err != nil {
80+
if err := stac.DecodeExtendedMap(e, assetMap, prefix); err != nil {
8081
return err
8182
}
8283
if len(e.Bands) == 0 {

extensions/eo/eo_test.go extensions/eo/v1/eo_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55
"testing"
66

77
"github.com/planetlabs/go-stac"
8-
"github.com/planetlabs/go-stac/extensions/eo"
8+
"github.com/planetlabs/go-stac/extensions/eo/v1"
99
"github.com/stretchr/testify/assert"
1010
"github.com/stretchr/testify/require"
1111
)
File renamed without changes.

extensions/itemassets/itemassets_test.go extensions/itemassets/v1/itemassets_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import (
55
"testing"
66

77
"github.com/planetlabs/go-stac"
8-
"github.com/planetlabs/go-stac/extensions/itemassets"
9-
"github.com/planetlabs/go-stac/extensions/raster"
8+
"github.com/planetlabs/go-stac/extensions/itemassets/v1"
9+
"github.com/planetlabs/go-stac/extensions/raster/v1"
1010
"github.com/stretchr/testify/assert"
1111
"github.com/stretchr/testify/require"
1212
)

extensions/pl/pl.go extensions/pl/v1/pl.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
const (
1010
extensionUri = "https://planetlabs.github.io/stac-extension/v1.0.0-beta.3/schema.json"
1111
extensionPattern = `https://planetlabs.github.io/stac-extension/v1\..*/schema.json`
12+
prefix = "pl"
1213
)
1314

1415
func init() {
@@ -42,7 +43,7 @@ func (e *Asset) Encode(assetMap map[string]any) error {
4243
}
4344

4445
func (e *Asset) Decode(assetMap map[string]any) error {
45-
return stac.DecodeExtendedMap(e, assetMap)
46+
return stac.DecodeExtendedMap(e, assetMap, prefix)
4647
}
4748

4849
type Item struct {

extensions/pl/pl_test.go extensions/pl/v1/pl_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55
"testing"
66

77
"github.com/planetlabs/go-stac"
8-
"github.com/planetlabs/go-stac/extensions/pl"
8+
"github.com/planetlabs/go-stac/extensions/pl/v1"
99
"github.com/stretchr/testify/assert"
1010
"github.com/stretchr/testify/require"
1111
)

extensions/raster/raster.go extensions/raster/v1/raster.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
const (
1010
extensionUri = "https://stac-extensions.github.io/raster/v1.1.0/schema.json"
1111
extensionPattern = `https://stac-extensions.github.io/raster/v1\..*/schema.json`
12+
prefix = "raster"
1213
)
1314

1415
func init() {
@@ -63,5 +64,5 @@ func (e *Asset) Encode(assetMap map[string]any) error {
6364
}
6465

6566
func (e *Asset) Decode(assetMap map[string]any) error {
66-
return stac.DecodeExtendedMap(e, assetMap)
67+
return stac.DecodeExtendedMap(e, assetMap, prefix)
6768
}

extensions/raster/raster_test.go extensions/raster/v1/raster_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55
"testing"
66

77
"github.com/planetlabs/go-stac"
8-
"github.com/planetlabs/go-stac/extensions/raster"
8+
"github.com/planetlabs/go-stac/extensions/raster/v1"
99
"github.com/stretchr/testify/assert"
1010
"github.com/stretchr/testify/require"
1111
)

0 commit comments

Comments
 (0)