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  }