github.com/RevenueMonster/sqlike@v1.0.6/examples/spatial.go (about)

     1  package examples
     2  
     3  import (
     4  	"context"
     5  	"database/sql"
     6  	"testing"
     7  
     8  	"github.com/RevenueMonster/sqlike/sql/expr"
     9  	"github.com/RevenueMonster/sqlike/sqlike"
    10  	"github.com/RevenueMonster/sqlike/sqlike/actions"
    11  	"github.com/RevenueMonster/sqlike/sqlike/indexes"
    12  	"github.com/RevenueMonster/sqlike/sqlike/options"
    13  	"github.com/paulmach/orb"
    14  	"github.com/paulmach/orb/encoding/wkb"
    15  	"github.com/stretchr/testify/require"
    16  )
    17  
    18  // Spatial :
    19  type Spatial struct {
    20  	ID             int64 `sqlike:",primary_key,auto_increment"`
    21  	Point          orb.Point
    22  	PtrPoint       *orb.Point
    23  	Point4326      orb.Point `sqlike:"PointWithSRID,srid=4326"`
    24  	LineString     orb.LineString
    25  	LineString2    orb.LineString
    26  	LineString3    orb.LineString
    27  	PtrLineString  *orb.LineString
    28  	LineString4326 orb.LineString `sqlike:"LineStringWithSRID,srid=4326"`
    29  	// Polygon    orb.Polygon
    30  }
    31  
    32  // SpatialExamples :
    33  func SpatialExamples(ctx context.Context, t *testing.T, db *sqlike.Database) {
    34  	var (
    35  		sp    = Spatial{}
    36  		table = db.Table("spatial")
    37  		err   error
    38  	)
    39  
    40  	point := orb.Point{1, 5}
    41  
    42  	{
    43  		err = table.DropIfExists(ctx)
    44  		require.NoError(t, err)
    45  	}
    46  
    47  	// create spatial index
    48  	{
    49  		table.MustMigrate(ctx, Spatial{})
    50  		table.MustUnsafeMigrate(ctx, Spatial{})
    51  		iv := table.Indexes()
    52  		idx := indexes.Index{
    53  			Type:    indexes.Spatial,
    54  			Columns: indexes.Columns("Point"),
    55  		}
    56  		err = iv.CreateOne(ctx, idx)
    57  		require.NoError(t, err)
    58  		result, err := iv.List(ctx)
    59  		require.NoError(t, err)
    60  		require.True(t, len(result) > 0)
    61  		require.Equal(t, sqlike.Index{
    62  			Name:     idx.GetName(),
    63  			Type:     "SPATIAL",
    64  			IsUnique: false,
    65  		}, result[0])
    66  	}
    67  
    68  	// insert spatial record
    69  	{
    70  		sp.Point4326 = point
    71  		sp.Point = point
    72  		sp.LineString = []orb.Point{
    73  			{0, 0},
    74  			{1, 1},
    75  		}
    76  		sp.LineString2 = []orb.Point{
    77  			{0, 0},
    78  			{1, 1},
    79  			{2, 2},
    80  		}
    81  		sp.LineString3 = []orb.Point{
    82  			{0, 0},
    83  			{1, 1},
    84  			{2, 2},
    85  			{3, 3},
    86  			{4, 4},
    87  		}
    88  		sp.LineString4326 = []orb.Point{
    89  			{88, 0},
    90  			{1, 10},
    91  		}
    92  		// sp.Polygon = orb.Polygon{
    93  		// 	// (0 0,10 0,10 10,0 10,0 0)
    94  		// 	orb.Ring{
    95  		// 		orb.Point{0, 0},
    96  		// 		orb.Point{10, 0},
    97  		// 		orb.Point{10, 10},
    98  		// 		orb.Point{0, 10},
    99  		// 		orb.Point{0, 0},
   100  		// 	},
   101  		// 	// (5 5,7 5,7 7,5 7, 5 5)
   102  		// 	orb.Ring{
   103  		// 		orb.Point{5, 5},
   104  		// 		orb.Point{7, 5},
   105  		// 		orb.Point{7, 7},
   106  		// 		orb.Point{5, 7},
   107  		// 		orb.Point{5, 5},
   108  		// 	},
   109  		// }
   110  		sps := []Spatial{sp, sp, sp}
   111  		_, err = table.Insert(
   112  			ctx,
   113  			&sps,
   114  			options.Insert().SetDebug(true),
   115  		)
   116  		require.NoError(t, err)
   117  	}
   118  
   119  	// find spatial record
   120  	{
   121  		result := table.FindOne(
   122  			ctx,
   123  			actions.FindOne().
   124  				Select(
   125  					"ID",
   126  					"Point",
   127  					"PtrPoint",
   128  					"LineString",
   129  					"PtrLineString",
   130  				).
   131  				Where(
   132  					expr.Equal("ID", 1),
   133  				),
   134  			options.FindOne().SetDebug(true),
   135  		)
   136  
   137  		var (
   138  			c1 = new(sql.RawBytes)
   139  			c2 = orb.Point{}
   140  			c3 = orb.Point{}
   141  			c4 = orb.LineString{}
   142  			c5 *orb.LineString
   143  		)
   144  
   145  		cols := result.Columns()
   146  		require.ElementsMatch(t, []string{
   147  			"ID",
   148  			"Point",
   149  			"PtrPoint",
   150  			"LineString",
   151  			"PtrLineString",
   152  		}, cols)
   153  		err = result.Scan(c1, wkb.Scanner(&c2), wkb.Scanner(&c3), &c4, &c5)
   154  		require.NoError(t, err)
   155  
   156  		v1 := sql.RawBytes(`1`)
   157  		nilLineString := orb.LineString(nil)
   158  		require.Equal(t, &v1, c1)
   159  		require.Equal(t, &v1, c1)
   160  		require.Equal(t, orb.Point{}, c3)
   161  		require.Equal(t, orb.LineString{{0, 0}, {1, 1}}, c4)
   162  		require.Equal(t, &nilLineString, c5)
   163  	}
   164  
   165  	// find spatial record and verify the output
   166  	{
   167  		var o Spatial
   168  		result := table.FindOne(
   169  			ctx,
   170  			actions.FindOne().
   171  				Where(
   172  					expr.Equal("ID", 1),
   173  				),
   174  			options.FindOne().SetDebug(true),
   175  		)
   176  		err = result.Decode(&o)
   177  		require.NoError(t, err)
   178  
   179  		require.Equal(t, int64(1), o.ID)
   180  		require.Equal(t, point, o.Point)
   181  		require.Equal(t, orb.Point{5, 1}, o.Point4326)
   182  	}
   183  
   184  	// get distance between two point
   185  	{
   186  		origin := orb.Point{20, 10}
   187  		p1 := orb.Point{1, 3}
   188  		p2 := orb.Point{4, 18}
   189  		var o struct {
   190  			Dist1 float64
   191  			Dist2 float64
   192  			Text  string
   193  		}
   194  		/*
   195  			SELECT
   196  				ST_Distance(`Point`,ST_PointFromText("POINT(20 10)")) AS `dist`,
   197  				ST_Distance(ST_GeomFromText("POINT(1 3)",4326),ST_GeomFromText("POINT(4 18)",4326)),ST_AsText(`Point`)
   198  			FROM `sqlike`.`spatial`
   199  			WHERE (
   200  				`ID` = 1 AND
   201  				ST_Equals(ST_PointFromText("POINT(20 10)"),ST_PointFromText("POINT(20 10)"))
   202  			)
   203  			ORDER BY `dist` DESC LIMIT 1;
   204  		*/
   205  		err = table.FindOne(
   206  			ctx,
   207  			actions.FindOne().
   208  				Select(
   209  					expr.As(expr.ST_Distance(expr.Column("Point"), origin), "dist"),
   210  					expr.ST_Distance(
   211  						expr.ST_GeomFromText(p1, 4326),
   212  						expr.ST_GeomFromText(p2, 4326),
   213  					),
   214  					expr.ST_AsText(expr.Column("Point")),
   215  				).
   216  				Where(
   217  					expr.Equal("ID", 1),
   218  					expr.ST_Equals(origin, origin),
   219  					// expr.ST_Within(expr.Column("Point"), orb.Point{0, 0}),
   220  				).
   221  				OrderBy(
   222  					expr.Desc("dist"),
   223  				),
   224  			options.FindOne().SetDebug(true),
   225  		).Scan(&o.Dist1, &o.Dist2, &o.Text)
   226  		require.NoError(t, err)
   227  		require.Equal(t, float64(19.6468827043885), o.Dist1)
   228  		require.True(t, o.Dist2 > 0)
   229  		require.Equal(t, "POINT(1 5)", o.Text)
   230  	}
   231  }