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 }