github.com/dolthub/go-mysql-server@v0.18.0/sql/expression/function/spatial/st_equals.go (about)

     1  // Copyright 2023 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  	"fmt"
    19  
    20  	"github.com/dolthub/go-mysql-server/sql"
    21  	"github.com/dolthub/go-mysql-server/sql/expression"
    22  	"github.com/dolthub/go-mysql-server/sql/types"
    23  )
    24  
    25  // STEquals is a function that returns the STEquals of a LineString
    26  type STEquals struct {
    27  	expression.BinaryExpressionStub
    28  }
    29  
    30  var _ sql.FunctionExpression = (*STEquals)(nil)
    31  
    32  // NewSTEquals creates a new STEquals expression.
    33  func NewSTEquals(g1, g2 sql.Expression) sql.Expression {
    34  	return &STEquals{
    35  		expression.BinaryExpressionStub{
    36  			LeftChild:  g1,
    37  			RightChild: g2,
    38  		},
    39  	}
    40  }
    41  
    42  // FunctionName implements sql.FunctionExpression
    43  func (s *STEquals) FunctionName() string {
    44  	return "st_equals"
    45  }
    46  
    47  // Description implements sql.FunctionExpression
    48  func (s *STEquals) Description() string {
    49  	return "returns 1 or 0 to indicate whether g1 is spatially equal to g2."
    50  }
    51  
    52  // Type implements the sql.Expression interface.
    53  func (s *STEquals) Type() sql.Type {
    54  	return types.Boolean
    55  }
    56  
    57  func (s *STEquals) String() string {
    58  	return fmt.Sprintf("ST_EQUALS(%s, %s)", s.LeftChild, s.RightChild)
    59  }
    60  
    61  // WithChildren implements the Expression interface.
    62  func (s *STEquals) WithChildren(children ...sql.Expression) (sql.Expression, error) {
    63  	if len(children) != 2 {
    64  		return nil, sql.ErrInvalidChildrenNumber.New(s, len(children), 2)
    65  	}
    66  	return NewSTEquals(children[0], children[1]), nil
    67  }
    68  
    69  // isEqual checks if the set of types.Points in g1 is spatially equal to g2
    70  // This is equivalent to checking if g1 within g2 and g2 within g1
    71  func isEqual(g1 types.GeometryValue, g2 types.GeometryValue) bool {
    72  	return isWithin(g1, g2) && isWithin(g2, g1)
    73  }
    74  
    75  // Eval implements the sql.Expression interface.
    76  func (s *STEquals) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) {
    77  	geom1, err := s.LeftChild.Eval(ctx, row)
    78  	if err != nil {
    79  		return nil, err
    80  	}
    81  	geom2, err := s.RightChild.Eval(ctx, row)
    82  	if err != nil {
    83  		return nil, err
    84  	}
    85  	g1, g2, err := validateGeomComp(geom1, geom2, s.FunctionName())
    86  	if err != nil {
    87  		return nil, err
    88  	}
    89  	if g1 == nil || g2 == nil {
    90  		return nil, nil
    91  	}
    92  
    93  	// TODO (james): remove this switch block when the other comparisons are implemented
    94  	switch geom1.(type) {
    95  	case types.LineString:
    96  		return nil, sql.ErrUnsupportedGISTypeForSpatialFunc.New("LineString", s.FunctionName())
    97  	case types.Polygon:
    98  		return nil, sql.ErrUnsupportedGISTypeForSpatialFunc.New("Polygon", s.FunctionName())
    99  	case types.MultiPoint:
   100  		return nil, sql.ErrUnsupportedGISTypeForSpatialFunc.New("MultiPoint", s.FunctionName())
   101  	case types.MultiLineString:
   102  		return nil, sql.ErrUnsupportedGISTypeForSpatialFunc.New("MultiLineString", s.FunctionName())
   103  	case types.MultiPolygon:
   104  		return nil, sql.ErrUnsupportedGISTypeForSpatialFunc.New("MultiPolygon", s.FunctionName())
   105  	case types.GeomColl:
   106  		return nil, sql.ErrUnsupportedGISTypeForSpatialFunc.New("GeomColl", s.FunctionName())
   107  	}
   108  
   109  	// TODO (james): remove this switch block when the other comparisons are implemented
   110  	switch geom2.(type) {
   111  	case types.LineString:
   112  		return nil, sql.ErrUnsupportedGISTypeForSpatialFunc.New("LineString", s.FunctionName())
   113  	case types.Polygon:
   114  		return nil, sql.ErrUnsupportedGISTypeForSpatialFunc.New("Polygon", s.FunctionName())
   115  	case types.MultiPoint:
   116  		return nil, sql.ErrUnsupportedGISTypeForSpatialFunc.New("MultiPoint", s.FunctionName())
   117  	case types.MultiLineString:
   118  		return nil, sql.ErrUnsupportedGISTypeForSpatialFunc.New("MultiLineString", s.FunctionName())
   119  	case types.MultiPolygon:
   120  		return nil, sql.ErrUnsupportedGISTypeForSpatialFunc.New("MultiPolygon", s.FunctionName())
   121  	case types.GeomColl:
   122  		return nil, sql.ErrUnsupportedGISTypeForSpatialFunc.New("GeomColl", s.FunctionName())
   123  	}
   124  
   125  	return isEqual(g1, g2), nil
   126  }