· 5 years ago · Aug 18, 2020, 10:42 AM
1package main
2
3import (
4 "database/sql"
5 "encoding/json"
6 "fmt"
7 "log"
8 "net/http"
9 "strconv"
10
11 "github.com/cridenour/go-postgis"
12 "github.com/gorilla/mux"
13 _ "github.com/lib/pq"
14)
15
16const WGS84_SRID = 4326
17
18var (
19 db *sql.DB
20)
21
22type poi struct {
23 Name string `json:"name"`
24 Lat float64 `json:"lat"`
25 Long float64 `json:"long"`
26}
27
28func initDb() {
29 var err error
30
31 psqlInfo := "database=pqgotest user=freedom sslmode=disable"
32 db, err = sql.Open("postgres", psqlInfo)
33 if err != nil {
34 log.Fatal(err)
35 }
36 err = db.Ping()
37 if err != nil {
38 log.Fatal(err)
39 }
40
41 // Ensure we have PostGIS on the table
42 _, err = db.Exec("CREATE EXTENSION IF NOT EXISTS postgis")
43 if err != nil {
44 log.Fatal(err)
45 }
46
47 createQuery := fmt.Sprintf(`
48CREATE TABLE IF NOT EXISTS points (
49id SERIAL PRIMARY KEY,
50geom GEOMETRY(Point, %v),
51name VARCHAR(128)
52)`, WGS84_SRID)
53
54 _, err = db.Query(createQuery)
55 if err != nil {
56 log.Fatal(err)
57 }
58
59}
60
61func homePageEndpoint(w http.ResponseWriter, r *http.Request) {
62 fmt.Fprintf(w, "Freedom for all!")
63}
64
65func addPointEndpoint(w http.ResponseWriter, r *http.Request) {
66 vars := mux.Vars(r)
67
68 lat, _ := strconv.ParseFloat(vars["lat"], 64)
69 long, _ := strconv.ParseFloat(vars["long"], 64)
70 addPoint(vars["name"], lat, long)
71 fmt.Fprintf(w, "successfully")
72
73}
74
75func nearbyPointsEndpoint(w http.ResponseWriter, r *http.Request) {
76 vars := mux.Vars(r)
77
78 lat, _ := strconv.ParseFloat(vars["lat"], 64)
79 long, _ := strconv.ParseFloat(vars["long"], 64)
80 radius, _ := strconv.ParseFloat(vars["radius"], 64)
81
82 points := nearbyPoints(lat, long, float32(radius))
83 response, err := json.Marshal(points)
84 if err != nil {
85 fmt.Fprintf(w, "Cant serialize response")
86 return
87 }
88 fmt.Fprintf(w, string(response))
89}
90
91func addPoint(name string, lat float64, long float64) {
92 point := postgis.PointS{WGS84_SRID, lat, long}
93
94 _, err := db.Query("INSERT INTO points(geom, name) VALUES (GeomFromEWKB($1), $2);", point, name)
95 if err != nil {
96 log.Fatal(err)
97 }
98}
99
100func nearbyPoints(lat float64, long float64, radius float32) []poi {
101 var points []poi
102
103 targetPoint := postgis.PointS{WGS84_SRID, lat, long}
104 rows, err := db.Query(`
105SELECT id, geom, name --// , ST_Distance(geom, $1) AS distance
106FROM points
107WHERE ST_DWithin(geom::geography, GeomFromEWKB($1)::geography, $2);
108`, targetPoint, radius)
109
110 if err != nil {
111 log.Fatal(err)
112 }
113 defer rows.Close()
114
115 for rows.Next() {
116 var id int64
117 var newPoint postgis.PointS
118 var name string
119
120 if err := rows.Scan(&id, &newPoint, &name); err != nil {
121 log.Fatal(err)
122 }
123
124 points = append(points, poi{Name: name, Lat: newPoint.X, Long: newPoint.Y})
125 }
126 return points
127
128}
129
130func main() {
131 // Enable line numbers in logging
132 log.SetFlags(log.LstdFlags | log.Lshortfile)
133
134 log.Println("Started")
135
136 initDb()
137
138 r := mux.NewRouter()
139 r.HandleFunc("/", homePageEndpoint)
140 r.HandleFunc("/add/{name}/{lat}/{long}", addPointEndpoint)
141 r.HandleFunc("/nearby/{radius}/{lat}/{long}", nearbyPointsEndpoint)
142 http.ListenAndServe(":9797", r)
143}
144