Skip to content
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
50 changes: 50 additions & 0 deletions asset.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package stac

import (
"encoding/json"
"fmt"

"github.com/mitchellh/mapstructure"
)

type Asset struct {
Type string `json:"type,omitempty"`
Href string `json:"href"`
Title string `json:"title,omitempty"`
Description string `json:"description,omitempty"`
Created string `json:"created,omitempty"`
Roles []string `json:"roles,omitempty"`
Extensions []AssetExtension `json:"-"`
}

var _ json.Marshaler = (*Asset)(nil)

type AssetExtension interface {
Apply(*Asset)
URI() string
}

func (asset Asset) MarshalJSON() ([]byte, error) {
assetMap := map[string]any{}
decoder, decoderErr := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
TagName: "json",
Result: &assetMap,
})
if decoderErr != nil {
return nil, decoderErr
}

decodeErr := decoder.Decode(asset)
if decodeErr != nil {
return nil, decodeErr
}

for _, extension := range asset.Extensions {
extension.Apply(&asset)
if decodeErr := decoder.Decode(extension); decodeErr != nil {
return nil, fmt.Errorf("trouble encoding JSON for %s asset: %w", extension.URI(), decodeErr)
}
}

return json.Marshal(assetMap)
}
57 changes: 57 additions & 0 deletions asset_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package stac_test

import (
"encoding/json"
"testing"

"github.com/planetlabs/go-stac"
"github.com/planetlabs/go-stac/extensions/pl"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestAssetMarshal(t *testing.T) {
asset := &stac.Asset{
Title: "An Image",
Href: "https://example.com/image.tif",
Type: "image/tiff",
Roles: []string{"data", "reflectance"},
}

data, err := json.Marshal(asset)
require.Nil(t, err)

expected := `{
"title": "An Image",
"href": "https://example.com/image.tif",
"type": "image/tiff",
"roles": ["data", "reflectance"]
}`

assert.JSONEq(t, expected, string(data))
}

func TestAssetExtendedMarshal(t *testing.T) {
asset := &stac.Asset{
Href: "https://example.com/image.tif",
Type: "image/tiff",
Extensions: []stac.AssetExtension{
&pl.Asset{
AssetType: "ortho_analytic_4b_sr",
BundleType: "analytic_sr_udm2",
},
},
}

data, err := json.Marshal(asset)
require.Nil(t, err)

expected := `{
"href": "https://example.com/image.tif",
"type": "image/tiff",
"pl:asset_type": "ortho_analytic_4b_sr",
"pl:bundle_type": "analytic_sr_udm2"
}`

assert.JSONEq(t, expected, string(data))
}
38 changes: 38 additions & 0 deletions catalog.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package stac

import (
"encoding/json"

"github.com/mitchellh/mapstructure"
)

type Catalog struct {
Version string `json:"stac_version"`
Id string `json:"id"`
Title string `json:"title,omitempty"`
Description string `json:"description"`
Links []*Link `json:"links"`
ConformsTo []string `json:"conformsTo,omitempty"`
}

var _ json.Marshaler = (*Catalog)(nil)

func (catalog Catalog) MarshalJSON() ([]byte, error) {
collectionMap := map[string]any{
"type": "Catalog",
}
decoder, decoderErr := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
TagName: "json",
Result: &collectionMap,
})
if decoderErr != nil {
return nil, decoderErr
}

decodeErr := decoder.Decode(catalog)
if decodeErr != nil {
return nil, decodeErr
}

return json.Marshal(collectionMap)
}
40 changes: 40 additions & 0 deletions catalog_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package stac_test

import (
"encoding/json"
"testing"

"github.com/planetlabs/go-stac"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestCatalogMarshal(t *testing.T) {
catalog := &stac.Catalog{
Version: "1.0.0",
Id: "catalog-id",
Description: "Test Catalog",
Links: []*stac.Link{
{Href: "https://example.com/stac/catalog", Rel: "self", Type: "application/json"},
},
}

data, err := json.Marshal(catalog)
require.Nil(t, err)

expected := `{
"type": "Catalog",
"id": "catalog-id",
"description": "Test Catalog",
"links": [
{
"href": "https://example.com/stac/catalog",
"rel": "self",
"type": "application/json"
}
],
"stac_version": "1.0.0"
}`

assert.JSONEq(t, expected, string(data))
}
68 changes: 68 additions & 0 deletions collection.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package stac

import (
"encoding/json"

"github.com/mitchellh/mapstructure"
)

type Collection struct {
Version string `json:"stac_version"`
Id string `json:"id"`
Title string `json:"title,omitempty"`
Description string `json:"description"`
Keywords []string `json:"keywords,omitempty"`
License string `json:"license"`
Providers []*Provider `json:"providers,omitempty"`
Extent *Extent `json:"extent"`
Summaries map[string]any `json:"summaries,omitempty"`
Links []*Link `json:"links"`
Assets map[string]*Asset `json:"assets,omitempty"`
}

type Provider struct {
Name string `json:"name"`
Description string `json:"description,omitempty"`
Roles []string `json:"roles,omitempty"`
Url string `json:"url,omitempty"`
}

type Extent struct {
Spatial *SpatialExtent `json:"spatial,omitempty"`
Temporal *TemporalExtent `json:"temporal,omitempty"`
}

type SpatialExtent struct {
Bbox [][]float64 `json:"bbox"`
}

type TemporalExtent struct {
Interval [][]any `json:"interval"`
}

var _ json.Marshaler = (*Collection)(nil)

func (collection Collection) MarshalJSON() ([]byte, error) {
collectionMap := map[string]any{
"type": "Collection",
}
decoder, decoderErr := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
TagName: "json",
Result: &collectionMap,
})
if decoderErr != nil {
return nil, decoderErr
}

decodeErr := decoder.Decode(collection)
if decodeErr != nil {
return nil, decodeErr
}

return json.Marshal(collectionMap)
}

type CollectionsList struct {
Collections []*Collection `json:"collections"`
Links []*Link `json:"links"`
}
54 changes: 54 additions & 0 deletions collection_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package stac_test

import (
"encoding/json"
"testing"

"github.com/planetlabs/go-stac"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestCollectionMarshal(t *testing.T) {
collection := &stac.Collection{
Version: "1.0.0",
Id: "collection-id",
Description: "Test Collection",
License: "various",
Links: []*stac.Link{
{Href: "https://example.com/stac/collections/collection-id", Rel: "self", Type: "application/json"},
},
Extent: &stac.Extent{
Spatial: &stac.SpatialExtent{
Bbox: [][]float64{{-180, -90, 180, 90}},
},
},
}

data, err := json.Marshal(collection)
require.Nil(t, err)

expected := `{
"type": "Collection",
"id": "collection-id",
"description": "Test Collection",
"extent": {
"spatial": {
"bbox": [
[-180, -90, 180, 90]
]
}
},
"license": "various",
"links": [
{
"href": "https://example.com/stac/collections/collection-id",
"rel": "self",
"type": "application/json"
}
],
"stac_version": "1.0.0"
}`

assert.JSONEq(t, expected, string(data))
}
39 changes: 39 additions & 0 deletions extensions/pl/pl.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package pl

import "github.com/planetlabs/go-stac"

const extensionUri = "https://planetlabs.github.io/stac-extension/v1.0.0-beta.1/schema.json"

type Asset struct {
AssetType string `json:"pl:asset_type,omitempty"`
BundleType string `json:"pl:bundle_type,omitempty"`
}

var _ stac.AssetExtension = (*Asset)(nil)

func (*Asset) URI() string {
return extensionUri
}

func (*Asset) Apply(*stac.Asset) {}

type Item struct {
ItemType string `json:"pl:item_type,omitempty"`
PixelResolution float64 `json:"pl:pixel_resolution,omitempty"`
PublishingStage string `json:"pl:publishing_stage,omitempty"`
QualityCategory string `json:"pl:quality_category,omitempty"`
StripId string `json:"pl:strip_id,omitempty"`
BlackFill *float64 `json:"pl:black_fill,omitempty"`
ClearPercent *float64 `json:"pl:clear_percent,omitempty"`
GridCell *int `json:"pl:grid_cell,omitempty"`
GroundControl *bool `json:"pl:ground_control,omitempty"`
GroundControlRatio *float64 `json:"pl:ground_control_ratio,omitempty"`
}

var _ stac.ItemExtension = (*Item)(nil)

func (*Item) URI() string {
return extensionUri
}

func (*Item) Apply(*stac.Item) {}
Loading