Skip to content

Commit c2d82f5

Browse files
authored
Merge pull request #231 from felix-schott/202_ndgeojson
Add support for ndgeojson
2 parents 04fe2e0 + 51afc40 commit c2d82f5

File tree

5 files changed

+78
-5
lines changed

5 files changed

+78
-5
lines changed

cmd/gpq/command/convert.go

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ package command
1717
import (
1818
"net/url"
1919
"os"
20+
"path/filepath"
21+
"slices"
2022
"strings"
2123

2224
"github.com/planetlabs/gpq/internal/geojson"
@@ -63,19 +65,38 @@ func parseFormatType(format string) FormatType {
6365
return ft
6466
}
6567

68+
var geoParquetSuffixes = []string{
69+
".gpq", ".geoparquet",
70+
}
71+
72+
var parquetSuffixes = []string{
73+
".pq", ".parquet",
74+
}
75+
76+
var geoJsonSuffixes = []string{
77+
".geojson",
78+
".json",
79+
".ndjson",
80+
".ndgeojson",
81+
".geojsonl",
82+
}
83+
6684
func getFormatType(resource string) FormatType {
6785
if u, err := url.Parse(resource); err == nil {
6886
resource = u.Path
6987
}
70-
if strings.HasSuffix(resource, ".json") || strings.HasSuffix(resource, ".geojson") {
71-
return GeoJSONType
72-
}
73-
if strings.HasSuffix(resource, ".gpq") || strings.HasSuffix(resource, ".geoparquet") {
88+
89+
ext := filepath.Ext(resource)
90+
if slices.Contains(geoParquetSuffixes, ext) {
7491
return GeoParquetType
7592
}
76-
if strings.HasSuffix(resource, ".pq") || strings.HasSuffix(resource, ".parquet") {
93+
if slices.Contains(parquetSuffixes, ext) {
7794
return ParquetType
7895
}
96+
if slices.Contains(geoJsonSuffixes, ext) {
97+
return GeoJSONType
98+
}
99+
79100
return UnknownType
80101
}
81102

internal/geojson/featurereader.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ func (r *FeatureReader) Read() (*geo.Feature, error) {
6767

6868
delim, ok := keyToken.(json.Delim)
6969
if ok && delim == json.Delim('}') {
70+
if r.decoder.More() {
71+
r.collection = true
72+
}
7073
if feature == nil {
7174
return nil, errors.New("expected a FeatureCollection, a Feature, or a Geometry object")
7275
}

internal/geojson/featurereader_test.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,48 @@ func TestFeatureReaderSingleFeature(t *testing.T) {
9292
assert.Equal(t, map[string]any{"name": "test"}, feature.Properties)
9393
}
9494

95+
func TestFeatureReaderNewLineDelimited(t *testing.T) {
96+
file, openErr := os.Open("testdata/new-line-delimited.ndgeojson")
97+
require.NoError(t, openErr)
98+
99+
reader := geojson.NewFeatureReader(file)
100+
101+
features := []*geo.Feature{}
102+
for {
103+
feature, err := reader.Read()
104+
if err == io.EOF {
105+
break
106+
}
107+
require.NoError(t, err)
108+
features = append(features, feature)
109+
}
110+
require.Len(t, features, 5)
111+
112+
fiji := features[0]
113+
assert.NotNil(t, fiji.Geometry)
114+
assert.Equal(t, "Oceania", fiji.Properties["continent"])
115+
assert.Equal(t, float64(920938), fiji.Properties["pop_est"])
116+
117+
usa := features[4]
118+
assert.NotNil(t, usa.Geometry)
119+
assert.Equal(t, "North America", usa.Properties["continent"])
120+
assert.Equal(t, float64(326625791), usa.Properties["pop_est"])
121+
}
122+
123+
func TestFeatureReaderBadNewLineDelimited(t *testing.T) {
124+
file, openErr := os.Open("testdata/bad-new-line-delimited.ndgeojson")
125+
require.NoError(t, openErr)
126+
127+
reader := geojson.NewFeatureReader(file)
128+
129+
first, err := reader.Read()
130+
require.NoError(t, err)
131+
assert.Equal(t, "Oceania", first.Properties["continent"])
132+
133+
_, err = reader.Read()
134+
assert.ErrorContains(t, err, "unexpected end of JSON input")
135+
}
136+
95137
func TestFeatureReaderEmptyFeatureCollection(t *testing.T) {
96138
file, openErr := os.Open("testdata/empty-collection.geojson")
97139
require.NoError(t, openErr)

0 commit comments

Comments
 (0)