github.com/dolthub/go-mysql-server@v0.18.0/sql/expression/function/spatial/geojson_test.go (about) 1 // Copyright 2020-2021 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package spatial 16 17 import ( 18 "testing" 19 20 "github.com/stretchr/testify/require" 21 22 "github.com/dolthub/go-mysql-server/sql" 23 "github.com/dolthub/go-mysql-server/sql/expression" 24 "github.com/dolthub/go-mysql-server/sql/types" 25 ) 26 27 func TestAsGeoJSON(t *testing.T) { 28 t.Run("convert point to geojson", func(t *testing.T) { 29 require := require.New(t) 30 f, err := NewAsGeoJSON(expression.NewLiteral(types.Point{X: 1, Y: 2}, types.PointType{})) 31 require.NoError(err) 32 33 v, err := f.Eval(sql.NewEmptyContext(), nil) 34 require.NoError(err) 35 require.Equal(types.JSONDocument{Val: map[string]interface{}{"coordinates": [2]float64{1, 2}, "type": "Point"}}, v) 36 }) 37 t.Run("convert linestring to geojson", func(t *testing.T) { 38 require := require.New(t) 39 f, err := NewAsGeoJSON(expression.NewLiteral(types.LineString{Points: []types.Point{{X: 1, Y: 2}, {X: 3, Y: 4}}}, types.LineStringType{})) 40 require.NoError(err) 41 42 v, err := f.Eval(sql.NewEmptyContext(), nil) 43 require.NoError(err) 44 require.Equal(types.JSONDocument{Val: map[string]interface{}{"coordinates": [][2]float64{{1, 2}, {3, 4}}, "type": "LineString"}}, v) 45 }) 46 t.Run("convert polygon to geojson", func(t *testing.T) { 47 require := require.New(t) 48 f, err := NewAsGeoJSON(expression.NewLiteral(types.Polygon{Lines: []types.LineString{{Points: []types.Point{{X: 0, Y: 0}, {X: 1, Y: 0}, {X: 1, Y: 1}, {X: 0, Y: 0}}}}}, types.PolygonType{})) 49 require.NoError(err) 50 51 v, err := f.Eval(sql.NewEmptyContext(), nil) 52 require.NoError(err) 53 require.Equal(types.JSONDocument{Val: map[string]interface{}{"coordinates": [][][2]float64{{{0, 0}, {1, 0}, {1, 1}, {0, 0}}}, "type": "Polygon"}}, v) 54 }) 55 t.Run("convert multipoint to geojson", func(t *testing.T) { 56 require := require.New(t) 57 f, err := NewAsGeoJSON(expression.NewLiteral(types.MultiPoint{Points: []types.Point{{X: 1, Y: 2}, {X: 3, Y: 4}}}, types.MultiPointType{})) 58 require.NoError(err) 59 60 v, err := f.Eval(sql.NewEmptyContext(), nil) 61 require.NoError(err) 62 require.Equal(types.JSONDocument{Val: map[string]interface{}{"coordinates": [][2]float64{{1, 2}, {3, 4}}, "type": "MultiPoint"}}, v) 63 }) 64 t.Run("convert multilinestring to geojson", func(t *testing.T) { 65 require := require.New(t) 66 f, err := NewAsGeoJSON(expression.NewLiteral(types.MultiLineString{Lines: []types.LineString{{Points: []types.Point{{X: 1, Y: 2}, {X: 3, Y: 4}}}}}, types.MultiLineStringType{})) 67 require.NoError(err) 68 69 v, err := f.Eval(sql.NewEmptyContext(), nil) 70 require.NoError(err) 71 require.Equal(types.JSONDocument{Val: map[string]interface{}{"coordinates": [][][2]float64{{{1, 2}, {3, 4}}}, "type": "MultiLineString"}}, v) 72 }) 73 t.Run("convert multipolygon to geojson", func(t *testing.T) { 74 require := require.New(t) 75 line := types.LineString{Points: []types.Point{{X: 0, Y: 0}, {X: 1, Y: 2}, {X: 3, Y: 4}, {X: 0, Y: 0}}} 76 poly := types.Polygon{Lines: []types.LineString{line}} 77 f, err := NewAsGeoJSON(expression.NewLiteral(types.MultiPolygon{Polygons: []types.Polygon{poly}}, types.MultiPolygonType{})) 78 require.NoError(err) 79 80 v, err := f.Eval(sql.NewEmptyContext(), nil) 81 require.NoError(err) 82 require.Equal(types.JSONDocument{Val: map[string]interface{}{"coordinates": [][][][2]float64{{{{0, 0}, {1, 2}, {3, 4}, {0, 0}}}}, "type": "MultiPolygon"}}, v) 83 }) 84 t.Run("convert empty geometrycollection to geojson", func(t *testing.T) { 85 require := require.New(t) 86 g := types.GeomColl{} 87 f, err := NewAsGeoJSON(expression.NewLiteral(g, types.GeomCollType{})) 88 require.NoError(err) 89 90 v, err := f.Eval(sql.NewEmptyContext(), nil) 91 require.NoError(err) 92 93 require.Equal(types.JSONDocument{Val: map[string]interface{}{"geometries": []interface{}{}, "type": "GeometryCollection"}}, v) 94 }) 95 t.Run("convert geometrycollection to geojson", func(t *testing.T) { 96 require := require.New(t) 97 point := types.Point{X: 1, Y: 2} 98 line := types.LineString{Points: []types.Point{{X: 1, Y: 2}, {X: 3, Y: 4}}} 99 poly := types.Polygon{Lines: []types.LineString{{Points: []types.Point{{X: 0, Y: 0}, {X: 1, Y: 1}, {X: 1, Y: 0}, {X: 0, Y: 0}}}}} 100 mpoint := types.MultiPoint{Points: []types.Point{point, point}} 101 mline := types.MultiLineString{Lines: []types.LineString{line, line}} 102 mpoly := types.MultiPolygon{Polygons: []types.Polygon{poly, poly}} 103 gColl := types.GeomColl{} 104 g := types.GeomColl{Geoms: []types.GeometryValue{point, line, poly, mpoint, mline, mpoly, gColl}} 105 f, err := NewAsGeoJSON(expression.NewLiteral(g, types.GeomCollType{})) 106 require.NoError(err) 107 108 v, err := f.Eval(sql.NewEmptyContext(), nil) 109 require.NoError(err) 110 111 pointjson := map[string]interface{}{"coordinates": [2]float64{1, 2}, "type": "Point"} 112 linejson := map[string]interface{}{"coordinates": [][2]float64{{1, 2}, {3, 4}}, "type": "LineString"} 113 polyjson := map[string]interface{}{"coordinates": [][][2]float64{{{0, 0}, {1, 1}, {1, 0}, {0, 0}}}, "type": "Polygon"} 114 mpointjson := map[string]interface{}{"coordinates": [][2]float64{{1, 2}, {1, 2}}, "type": "MultiPoint"} 115 mlinejson := map[string]interface{}{"coordinates": [][][2]float64{{{1, 2}, {3, 4}}, {{1, 2}, {3, 4}}}, "type": "MultiLineString"} 116 mpolyjson := map[string]interface{}{"coordinates": [][][][2]float64{{{{0, 0}, {1, 1}, {1, 0}, {0, 0}}}, {{{0, 0}, {1, 1}, {1, 0}, {0, 0}}}}, "type": "MultiPolygon"} 117 mgeomjson := map[string]interface{}{"geometries": []interface{}{}, "type": "GeometryCollection"} 118 119 require.Equal(types.JSONDocument{Val: map[string]interface{}{"geometries": []interface{}{pointjson, linejson, polyjson, mpointjson, mlinejson, mpolyjson, mgeomjson}, "type": "GeometryCollection"}}, v) 120 }) 121 t.Run("convert point with floats to geojson", func(t *testing.T) { 122 require := require.New(t) 123 f, err := NewAsGeoJSON(expression.NewLiteral(types.Point{X: 123.45, Y: 5.6789}, types.PointType{})) 124 require.NoError(err) 125 126 v, err := f.Eval(sql.NewEmptyContext(), nil) 127 require.NoError(err) 128 require.Equal(types.JSONDocument{Val: map[string]interface{}{"coordinates": [2]float64{123.45, 5.6789}, "type": "Point"}}, v) 129 }) 130 t.Run("convert point with low precision", func(t *testing.T) { 131 require := require.New(t) 132 f, err := NewAsGeoJSON( 133 expression.NewLiteral(types.Point{X: 0.123456789, Y: 0.987654321}, types.PointType{}), 134 expression.NewLiteral(3, types.Int64), 135 ) 136 require.NoError(err) 137 138 v, err := f.Eval(sql.NewEmptyContext(), nil) 139 require.NoError(err) 140 require.Equal(types.JSONDocument{Val: map[string]interface{}{"coordinates": [2]float64{0.123, 0.988}, "type": "Point"}}, v) 141 }) 142 t.Run("convert point with high precision", func(t *testing.T) { 143 require := require.New(t) 144 f, err := NewAsGeoJSON( 145 expression.NewLiteral(types.Point{X: 0.123456789, Y: 0.987654321}, types.PointType{}), 146 expression.NewLiteral(20, types.Int64), 147 ) 148 require.NoError(err) 149 150 v, err := f.Eval(sql.NewEmptyContext(), nil) 151 require.NoError(err) 152 require.Equal(types.JSONDocument{Val: map[string]interface{}{"coordinates": [2]float64{0.123456789, 0.987654321}, "type": "Point"}}, v) 153 }) 154 t.Run("convert point with bounding box", func(t *testing.T) { 155 require := require.New(t) 156 f, err := NewAsGeoJSON( 157 expression.NewLiteral(types.Point{X: 123.45678, Y: 456.789}, types.PointType{}), 158 expression.NewLiteral(2, types.Int64), 159 expression.NewLiteral(1, types.Int64), 160 ) 161 require.NoError(err) 162 163 v, err := f.Eval(sql.NewEmptyContext(), nil) 164 require.NoError(err) 165 require.Equal(types.JSONDocument{Val: map[string]interface{}{"coordinates": [2]float64{123.46, 456.79}, "type": "Point", "bbox": [4]float64{123.46, 456.79, 123.46, 456.79}}}, v) 166 }) 167 t.Run("convert linestring with bounding box", func(t *testing.T) { 168 require := require.New(t) 169 f, err := NewAsGeoJSON( 170 expression.NewLiteral(types.LineString{Points: []types.Point{{X: 100, Y: 2}, {X: 1, Y: 200}}}, types.LineStringType{}), 171 expression.NewLiteral(2, types.Int64), 172 expression.NewLiteral(1, types.Int64), 173 ) 174 require.NoError(err) 175 176 v, err := f.Eval(sql.NewEmptyContext(), nil) 177 require.NoError(err) 178 require.Equal(types.JSONDocument{Val: map[string]interface{}{"coordinates": [][2]float64{{100, 2}, {1, 200}}, "type": "LineString", "bbox": [4]float64{1, 2, 100, 200}}}, v) 179 }) 180 t.Run("convert polygon with bounding box", func(t *testing.T) { 181 require := require.New(t) 182 f, err := NewAsGeoJSON( 183 expression.NewLiteral(types.Polygon{Lines: []types.LineString{{Points: []types.Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 1, Y: 1}, {X: 0, Y: 0}}}}}, types.PolygonType{}), 184 expression.NewLiteral(2, types.Int64), 185 expression.NewLiteral(1, types.Int64), 186 ) 187 require.NoError(err) 188 189 v, err := f.Eval(sql.NewEmptyContext(), nil) 190 require.NoError(err) 191 require.Equal(types.JSONDocument{Val: map[string]interface{}{"coordinates": [][][2]float64{{{0, 0}, {0, 1}, {1, 1}, {0, 0}}}, "type": "Polygon", "bbox": [4]float64{0, 0, 1, 1}}}, v) 192 }) 193 t.Run("convert multipoint with bounding box", func(t *testing.T) { 194 require := require.New(t) 195 f, err := NewAsGeoJSON( 196 expression.NewLiteral(types.MultiPoint{Points: []types.Point{{X: 100, Y: 2}, {X: 1, Y: 200}}}, types.MultiPointType{}), 197 expression.NewLiteral(2, types.Int64), 198 expression.NewLiteral(1, types.Int64), 199 ) 200 require.NoError(err) 201 202 v, err := f.Eval(sql.NewEmptyContext(), nil) 203 require.NoError(err) 204 require.Equal(types.JSONDocument{Val: map[string]interface{}{"coordinates": [][2]float64{{100, 2}, {1, 200}}, "type": "MultiPoint", "bbox": [4]float64{1, 2, 100, 200}}}, v) 205 }) 206 t.Run("convert multilinestring with bounding box", func(t *testing.T) { 207 require := require.New(t) 208 f, err := NewAsGeoJSON( 209 expression.NewLiteral(types.MultiLineString{Lines: []types.LineString{{Points: []types.Point{{X: 1, Y: 2}, {X: 3, Y: 4}}}}}, types.MultiLineStringType{}), 210 expression.NewLiteral(2, types.Int64), 211 expression.NewLiteral(1, types.Int64), 212 ) 213 require.NoError(err) 214 215 v, err := f.Eval(sql.NewEmptyContext(), nil) 216 require.NoError(err) 217 require.Equal(types.JSONDocument{Val: map[string]interface{}{"coordinates": [][][2]float64{{{1, 2}, {3, 4}}}, "type": "MultiLineString", "bbox": [4]float64{1, 2, 3, 4}}}, v) 218 }) 219 t.Run("convert multipolygon with bounding box", func(t *testing.T) { 220 require := require.New(t) 221 line := types.LineString{Points: []types.Point{{X: 0, Y: 0}, {X: 1, Y: 2}, {X: 3, Y: 4}, {X: 0, Y: 0}}} 222 poly := types.Polygon{Lines: []types.LineString{line}} 223 f, err := NewAsGeoJSON( 224 expression.NewLiteral(types.MultiPolygon{Polygons: []types.Polygon{poly}}, types.MultiPolygonType{}), 225 expression.NewLiteral(2, types.Int64), 226 expression.NewLiteral(1, types.Int64), 227 ) 228 require.NoError(err) 229 230 v, err := f.Eval(sql.NewEmptyContext(), nil) 231 require.NoError(err) 232 require.Equal(types.JSONDocument{Val: map[string]interface{}{"coordinates": [][][][2]float64{{{{0, 0}, {1, 2}, {3, 4}, {0, 0}}}}, "type": "MultiPolygon", "bbox": [4]float64{0, 0, 3, 4}}}, v) 233 }) 234 t.Run("convert empty geometrycollection to geojson with bounding box", func(t *testing.T) { 235 require := require.New(t) 236 g := types.GeomColl{} 237 f, err := NewAsGeoJSON( 238 expression.NewLiteral(g, types.GeomCollType{}), 239 expression.NewLiteral(2, types.Int64), 240 expression.NewLiteral(1, types.Int64), 241 ) 242 require.NoError(err) 243 244 v, err := f.Eval(sql.NewEmptyContext(), nil) 245 require.NoError(err) 246 247 require.Equal(types.JSONDocument{Val: map[string]interface{}{"geometries": []interface{}{}, "type": "GeometryCollection"}}, v) 248 }) 249 t.Run("convert geometrycollection to geojson with bounding box", func(t *testing.T) { 250 require := require.New(t) 251 point := types.Point{X: 1, Y: 2} 252 line := types.LineString{Points: []types.Point{{X: 1, Y: 2}, {X: 3, Y: 4}}} 253 poly := types.Polygon{Lines: []types.LineString{{Points: []types.Point{{X: 0, Y: 0}, {X: 1, Y: 1}, {X: 1, Y: 0}, {X: 0, Y: 0}}}}} 254 mpoint := types.MultiPoint{Points: []types.Point{point, point}} 255 mline := types.MultiLineString{Lines: []types.LineString{line, line}} 256 mpoly := types.MultiPolygon{Polygons: []types.Polygon{poly, poly}} 257 gColl := types.GeomColl{} 258 g := types.GeomColl{Geoms: []types.GeometryValue{point, line, poly, mpoint, mline, mpoly, gColl}} 259 f, err := NewAsGeoJSON( 260 expression.NewLiteral(g, types.GeomCollType{}), 261 expression.NewLiteral(2, types.Int64), 262 expression.NewLiteral(1, types.Int64)) 263 require.NoError(err) 264 265 v, err := f.Eval(sql.NewEmptyContext(), nil) 266 require.NoError(err) 267 268 pointjson := map[string]interface{}{"coordinates": [2]float64{1, 2}, "type": "Point"} 269 linejson := map[string]interface{}{"coordinates": [][2]float64{{1, 2}, {3, 4}}, "type": "LineString"} 270 polyjson := map[string]interface{}{"coordinates": [][][2]float64{{{0, 0}, {1, 1}, {1, 0}, {0, 0}}}, "type": "Polygon"} 271 mpointjson := map[string]interface{}{"coordinates": [][2]float64{{1, 2}, {1, 2}}, "type": "MultiPoint"} 272 mlinejson := map[string]interface{}{"coordinates": [][][2]float64{{{1, 2}, {3, 4}}, {{1, 2}, {3, 4}}}, "type": "MultiLineString"} 273 mpolyjson := map[string]interface{}{"coordinates": [][][][2]float64{{{{0, 0}, {1, 1}, {1, 0}, {0, 0}}}, {{{0, 0}, {1, 1}, {1, 0}, {0, 0}}}}, "type": "MultiPolygon"} 274 mgeomjson := map[string]interface{}{"geometries": []interface{}{}, "type": "GeometryCollection"} 275 276 require.Equal(types.JSONDocument{Val: map[string]interface{}{"bbox": [4]float64{0, 0, 3, 4}, "geometries": []interface{}{pointjson, linejson, polyjson, mpointjson, mlinejson, mpolyjson, mgeomjson}, "type": "GeometryCollection"}}, v) 277 }) 278 t.Run("convert point with srid 0 and flag 2", func(t *testing.T) { 279 require := require.New(t) 280 f, err := NewAsGeoJSON( 281 expression.NewLiteral(types.Point{X: 1, Y: 2}, types.PointType{}), 282 expression.NewLiteral(1, types.Int64), 283 expression.NewLiteral(2, types.Int64), 284 ) 285 require.NoError(err) 286 287 v, err := f.Eval(sql.NewEmptyContext(), nil) 288 require.NoError(err) 289 obj := map[string]interface{}{ 290 "coordinates": [2]float64{1, 2}, 291 "type": "Point", 292 } 293 require.Equal(types.JSONDocument{Val: obj}, v) 294 }) 295 t.Run("convert point with srid 4326 and flag 2", func(t *testing.T) { 296 require := require.New(t) 297 f, err := NewAsGeoJSON( 298 expression.NewLiteral(types.Point{SRID: 4326, X: 1, Y: 2}, types.PointType{}), 299 expression.NewLiteral(1, types.Int64), 300 expression.NewLiteral(2, types.Int64), 301 ) 302 require.NoError(err) 303 304 v, err := f.Eval(sql.NewEmptyContext(), nil) 305 require.NoError(err) 306 obj := map[string]interface{}{ 307 "crs": map[string]interface{}{ 308 "type": "name", 309 "properties": map[string]interface{}{ 310 "name": "EPSG:4326", 311 }, 312 }, 313 "coordinates": [2]float64{1, 2}, 314 "type": "Point", 315 } 316 require.Equal(types.JSONDocument{Val: obj}, v) 317 }) 318 t.Run("convert point with srid 4326 and flag 4", func(t *testing.T) { 319 require := require.New(t) 320 f, err := NewAsGeoJSON( 321 expression.NewLiteral(types.Point{SRID: 4326, X: 1, Y: 2}, types.PointType{}), 322 expression.NewLiteral(1, types.Int64), 323 expression.NewLiteral(4, types.Int64), 324 ) 325 require.NoError(err) 326 327 v, err := f.Eval(sql.NewEmptyContext(), nil) 328 require.NoError(err) 329 obj := map[string]interface{}{ 330 "crs": map[string]interface{}{ 331 "type": "name", 332 "properties": map[string]interface{}{ 333 "name": "urn:ogc:def:crs:EPSG::4326", 334 }, 335 }, 336 "coordinates": [2]float64{1, 2}, 337 "type": "Point", 338 } 339 require.Equal(types.JSONDocument{Val: obj}, v) 340 }) 341 t.Run("convert null is null", func(t *testing.T) { 342 require := require.New(t) 343 f, err := NewAsGeoJSON( 344 expression.NewLiteral(nil, types.Null), 345 expression.NewLiteral(2, types.Int64), 346 expression.NewLiteral(1, types.Int64), 347 ) 348 require.NoError(err) 349 350 v, err := f.Eval(sql.NewEmptyContext(), nil) 351 require.NoError(err) 352 require.Equal(nil, v) 353 }) 354 t.Run("convert null precision is null", func(t *testing.T) { 355 require := require.New(t) 356 f, err := NewAsGeoJSON( 357 expression.NewLiteral(types.Point{X: 1, Y: 2}, types.PointType{}), 358 expression.NewLiteral(nil, types.Null), 359 expression.NewLiteral(1, types.Int64), 360 ) 361 require.NoError(err) 362 363 v, err := f.Eval(sql.NewEmptyContext(), nil) 364 require.NoError(err) 365 require.Equal(nil, v) 366 }) 367 t.Run("convert null flag is null", func(t *testing.T) { 368 require := require.New(t) 369 f, err := NewAsGeoJSON( 370 expression.NewLiteral(types.Point{X: 1, Y: 2}, types.PointType{}), 371 expression.NewLiteral(2, types.Int64), 372 expression.NewLiteral(nil, types.Null), 373 ) 374 require.NoError(err) 375 376 v, err := f.Eval(sql.NewEmptyContext(), nil) 377 require.NoError(err) 378 require.Equal(nil, v) 379 }) 380 } 381 382 func TestGeomFromGeoJSON(t *testing.T) { 383 t.Run("convert point from geojson", func(t *testing.T) { 384 require := require.New(t) 385 f, err := NewGeomFromGeoJSON(expression.NewLiteral(`{"type":"Point", "coordinates":[1,2]}`, types.Blob)) 386 require.NoError(err) 387 388 v, err := f.Eval(sql.NewEmptyContext(), nil) 389 require.NoError(err) 390 require.Equal(types.Point{SRID: 4326, X: 1, Y: 2}, v) 391 }) 392 t.Run("convert linestring from geojson", func(t *testing.T) { 393 require := require.New(t) 394 f, err := NewGeomFromGeoJSON(expression.NewLiteral(`{"type":"LineString", "coordinates":[[1,2],[3,4]]}`, types.Blob)) 395 require.NoError(err) 396 397 v, err := f.Eval(sql.NewEmptyContext(), nil) 398 require.NoError(err) 399 require.Equal(types.LineString{SRID: 4326, Points: []types.Point{{4326, 1, 2}, {4326, 3, 4}}}, v) 400 }) 401 t.Run("convert polygon from geojson", func(t *testing.T) { 402 require := require.New(t) 403 f, err := NewGeomFromGeoJSON(expression.NewLiteral(`{"type":"Polygon", "coordinates":[[[0,0],[1,1],[0,1],[0,0]]]}`, types.Blob)) 404 require.NoError(err) 405 406 v, err := f.Eval(sql.NewEmptyContext(), nil) 407 require.NoError(err) 408 require.Equal(types.Polygon{SRID: 4326, Lines: []types.LineString{{4326, []types.Point{{4326, 0, 0}, {4326, 1, 1}, {4326, 0, 1}, {4326, 0, 0}}}}}, v) 409 }) 410 t.Run("convert multipoint from geojson", func(t *testing.T) { 411 require := require.New(t) 412 f, err := NewGeomFromGeoJSON(expression.NewLiteral(`{"type":"MultiPoint", "coordinates":[[1,2],[3,4]]}`, types.Blob)) 413 require.NoError(err) 414 415 v, err := f.Eval(sql.NewEmptyContext(), nil) 416 require.NoError(err) 417 require.Equal(types.MultiPoint{SRID: 4326, Points: []types.Point{{4326, 1, 2}, {4326, 3, 4}}}, v) 418 }) 419 t.Run("convert multilinestring from geojson", func(t *testing.T) { 420 require := require.New(t) 421 f, err := NewGeomFromGeoJSON(expression.NewLiteral(`{"type":"MultiLineString", "coordinates":[[[0,0],[1,1],[0,1],[0,0]]]}`, types.Blob)) 422 require.NoError(err) 423 424 v, err := f.Eval(sql.NewEmptyContext(), nil) 425 require.NoError(err) 426 require.Equal(types.MultiLineString{SRID: 4326, Lines: []types.LineString{{4326, []types.Point{{4326, 0, 0}, {4326, 1, 1}, {4326, 0, 1}, {4326, 0, 0}}}}}, v) 427 }) 428 t.Run("convert mutlipolygon from geojson", func(t *testing.T) { 429 require := require.New(t) 430 f, err := NewGeomFromGeoJSON(expression.NewLiteral(`{"type":"MultiPolygon", "coordinates":[[[[0,0],[1,1],[0,1],[0,0]]]]}`, types.Blob)) 431 require.NoError(err) 432 433 v, err := f.Eval(sql.NewEmptyContext(), nil) 434 require.NoError(err) 435 require.Equal(types.MultiPolygon{SRID: 4326, Polygons: []types.Polygon{{SRID: 4326, Lines: []types.LineString{{SRID: 4326, Points: []types.Point{{SRID: 4326, X: 0, Y: 0}, {SRID: 4326, X: 1, Y: 1}, {SRID: 4326, X: 0, Y: 1}, {SRID: 4326, X: 0, Y: 0}}}}}}}, v) 436 }) 437 t.Run("convert empty geometrycollection from geojson", func(t *testing.T) { 438 require := require.New(t) 439 f, err := NewGeomFromGeoJSON(expression.NewLiteral(`{"type":"GeometryCollection", "geometries":[]}`, types.Blob)) 440 require.NoError(err) 441 442 v, err := f.Eval(sql.NewEmptyContext(), nil) 443 require.NoError(err) 444 require.Equal(types.GeomColl{SRID: 4326, Geoms: []types.GeometryValue{}}, v) 445 }) 446 t.Run("convert geometrycollection to geojson", func(t *testing.T) { 447 require := require.New(t) 448 449 s := `{"type":"GeometryCollection", "geometries":[` + 450 `{"type":"Point", "coordinates":[1,2]},` + 451 `{"type":"LineString", "coordinates":[[1,2],[3,4]]},` + 452 `{"type":"Polygon", "coordinates":[[[0,0],[1,1],[1,0],[0,0]]]},` + 453 `{"type":"MultiPoint", "coordinates":[[1,2],[1,2]]},` + 454 `{"type":"MultiLineString", "coordinates":[[[1,2],[3,4]],[[1,2],[3,4]]]},` + 455 `{"type":"MultiPolygon", "coordinates":[[[[0,0],[1,1],[1,0],[0,0]]],[[[0,0],[1,1],[1,0],[0,0]]]]},` + 456 `{"type":"GeometryCollection", "geometries":[]}` + 457 `]}` 458 f, err := NewGeomFromGeoJSON(expression.NewLiteral(s, types.Blob)) 459 require.NoError(err) 460 461 v, err := f.Eval(sql.NewEmptyContext(), nil) 462 require.NoError(err) 463 464 point := types.Point{SRID: 4326, X: 1, Y: 2} 465 line := types.LineString{SRID: 4326, Points: []types.Point{{SRID: 4326, X: 1, Y: 2}, {SRID: 4326, X: 3, Y: 4}}} 466 poly := types.Polygon{SRID: 4326, Lines: []types.LineString{{SRID: 4326, Points: []types.Point{{SRID: 4326, X: 0, Y: 0}, {SRID: 4326, X: 1, Y: 1}, {SRID: 4326, X: 1, Y: 0}, {SRID: 4326, X: 0, Y: 0}}}}} 467 mpoint := types.MultiPoint{SRID: 4326, Points: []types.Point{point, point}} 468 mline := types.MultiLineString{SRID: 4326, Lines: []types.LineString{line, line}} 469 mpoly := types.MultiPolygon{SRID: 4326, Polygons: []types.Polygon{poly, poly}} 470 gColl := types.GeomColl{SRID: 4326, Geoms: []types.GeometryValue{}} 471 g := types.GeomColl{SRID: 4326, Geoms: []types.GeometryValue{point, line, poly, mpoint, mline, mpoly, gColl}} 472 require.Equal(g, v) 473 }) 474 t.Run("convert feature point from geojson", func(t *testing.T) { 475 require := require.New(t) 476 f, err := NewGeomFromGeoJSON(expression.NewLiteral(`{"type":"Feature","geometry":{"type":"Point", "coordinates":[1,2]},"properties":{}}`, types.Blob)) 477 require.NoError(err) 478 479 v, err := f.Eval(sql.NewEmptyContext(), nil) 480 require.NoError(err) 481 require.Equal(types.Point{SRID: 4326, X: 1, Y: 2}, v) 482 }) 483 t.Run("convert feature no props from geojson", func(t *testing.T) { 484 require := require.New(t) 485 f, err := NewGeomFromGeoJSON(expression.NewLiteral(`{"type":"Feature","geometry":{"type":"Point", "coordinates":[1,2]}}`, types.Blob)) 486 require.NoError(err) 487 488 _, err = f.Eval(sql.NewEmptyContext(), nil) 489 require.Error(err) 490 }) 491 t.Run("convert feature no geometry from geojson", func(t *testing.T) { 492 require := require.New(t) 493 f, err := NewGeomFromGeoJSON(expression.NewLiteral(`{"type":"Feature","properties":{}}`, types.Blob)) 494 require.NoError(err) 495 496 _, err = f.Eval(sql.NewEmptyContext(), nil) 497 require.Error(err) 498 }) 499 t.Run("convert feature collection of points from geojson", func(t *testing.T) { 500 require := require.New(t) 501 f, err := NewGeomFromGeoJSON(expression.NewLiteral(`{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Point", "coordinates":[1,2]},"properties":{}}],"properties":{}}`, types.Blob)) 502 require.NoError(err) 503 504 v, err := f.Eval(sql.NewEmptyContext(), nil) 505 require.NoError(err) 506 507 point := types.Point{SRID: 4326, X: 1, Y: 2} 508 g := types.GeomColl{SRID: 4326, Geoms: []types.GeometryValue{point}} 509 require.Equal(g, v) 510 }) 511 t.Run("reject dimensions greater than 2 with flag 1", func(t *testing.T) { 512 require := require.New(t) 513 f, err := NewGeomFromGeoJSON( 514 expression.NewLiteral(`{"type":"Polygon", "coordinates":[[[0,0],[1,1],[0,1],[0,0,0]]]}`, types.Blob), 515 expression.NewLiteral(1, types.Int32), 516 ) 517 require.NoError(err) 518 519 _, err = f.Eval(sql.NewEmptyContext(), nil) 520 require.Error(err) 521 }) 522 t.Run("accept dimensions greater than 2 with flag 2", func(t *testing.T) { 523 require := require.New(t) 524 f, err := NewGeomFromGeoJSON( 525 expression.NewLiteral(`{"type":"Polygon", "coordinates":[[[0,0],[1,1],[0,1],[0,0,0]]]}`, types.Blob), 526 expression.NewLiteral(2, types.Int32), 527 ) 528 require.NoError(err) 529 530 v, err := f.Eval(sql.NewEmptyContext(), nil) 531 require.Equal(types.Polygon{SRID: 4326, Lines: []types.LineString{{4326, []types.Point{{4326, 0, 0}, {4326, 1, 1}, {4326, 0, 1}, {4326, 0, 0}}}}}, v) 532 }) 533 t.Run("srid 0 swaps x and y", func(t *testing.T) { 534 require := require.New(t) 535 f, err := NewGeomFromGeoJSON( 536 expression.NewLiteral(`{"type":"Point", "coordinates":[1,2]}`, types.Blob), 537 expression.NewLiteral(1, types.Int32), 538 expression.NewLiteral(0, types.Int32), 539 ) 540 require.NoError(err) 541 542 v, err := f.Eval(sql.NewEmptyContext(), nil) 543 require.Equal(types.Point{0, 1, 2}, v) 544 }) 545 t.Run("srid 0 swaps x and y", func(t *testing.T) { 546 require := require.New(t) 547 f, err := NewGeomFromGeoJSON( 548 expression.NewLiteral(`{"type":"LineString", "coordinates":[[1,2],[3,4]]}`, types.Blob), 549 expression.NewLiteral(1, types.Int32), 550 expression.NewLiteral(0, types.Int32), 551 ) 552 require.NoError(err) 553 554 v, err := f.Eval(sql.NewEmptyContext(), nil) 555 require.Equal(types.LineString{SRID: 0, Points: []types.Point{{0, 1, 2}, {0, 3, 4}}}, v) 556 }) 557 t.Run("srid 0 swaps x and y", func(t *testing.T) { 558 require := require.New(t) 559 f, err := NewGeomFromGeoJSON( 560 expression.NewLiteral(`{"type":"Polygon", "coordinates":[[[0,0],[1,1],[0,1],[0,0]]]}`, types.Blob), 561 expression.NewLiteral(1, types.Int32), 562 expression.NewLiteral(0, types.Int32), 563 ) 564 require.NoError(err) 565 566 v, err := f.Eval(sql.NewEmptyContext(), nil) 567 require.Equal(types.Polygon{SRID: 0, Lines: []types.LineString{{0, []types.Point{{0, 0, 0}, {0, 1, 1}, {0, 0, 1}, {0, 0, 0}}}}}, v) 568 }) 569 t.Run("check return type", func(t *testing.T) { 570 require := require.New(t) 571 f, err := NewAsGeoJSON(expression.NewLiteral(types.Point{X: 1, Y: 2}, types.PointType{})) 572 require.NoError(err) 573 574 v, err := f.Eval(sql.NewEmptyContext(), nil) 575 require.NoError(err) 576 typ := f.Type() 577 578 _, _, err = typ.Convert(v) 579 require.NoError(err) 580 }) 581 }