2022-10-02 22:01:59 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
"database/sql"
|
|
|
|
"log"
|
|
|
|
"os"
|
|
|
|
"fmt"
|
|
|
|
"strconv"
|
|
|
|
_ "github.com/mattn/go-sqlite3"
|
|
|
|
)
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
database_path, ok := os.LookupEnv("DB_PATH")
|
|
|
|
if !ok {
|
|
|
|
log.Fatal("Environment variable $DB_PATH must point to sqlite3 database with text indices.")
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
|
|
|
|
port := 3000
|
|
|
|
port_str, ok := os.LookupEnv("PORT")
|
|
|
|
if ok {
|
|
|
|
port_num, err := strconv.Atoi(port_str)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
if (port_num < 1) || (port_num > 65535) {
|
|
|
|
log.Fatal("Environment variale $PORT must be a number between 1 and 65535.")
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
port = port_num
|
|
|
|
}
|
|
|
|
|
|
|
|
db, err := sql.Open("sqlite3", database_path)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
|
|
|
|
r := gin.Default()
|
|
|
|
|
|
|
|
api := r.Group("/api")
|
|
|
|
|
|
|
|
api.GET("/ping", func(c *gin.Context) {
|
|
|
|
c.JSON(200, gin.H{
|
|
|
|
"message": "pong",
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2022-10-03 21:40:57 +00:00
|
|
|
api.OPTIONS("/search", func(c *gin.Context) {
|
|
|
|
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
|
|
|
|
c.Writer.Header().Set("Access-Control-Allow-Headers", "Accept-Encoding, Authorization, accept, origin, Cache-Control, X-Requested-With")
|
|
|
|
c.Writer.Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS")
|
|
|
|
|
|
|
|
c.AbortWithStatus(204)
|
|
|
|
})
|
|
|
|
|
2022-10-02 22:01:59 +00:00
|
|
|
api.GET("/search", func(c *gin.Context) {
|
2022-10-03 21:40:57 +00:00
|
|
|
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
|
|
|
|
c.Writer.Header().Set("Access-Control-Allow-Headers", "Accept-Encoding, Authorization, accept, origin, Cache-Control, X-Requested-With")
|
|
|
|
c.Writer.Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS")
|
|
|
|
|
2022-10-02 22:01:59 +00:00
|
|
|
query := c.Query("q")
|
|
|
|
|
2022-10-30 22:44:31 +00:00
|
|
|
stm, err := db.Prepare("SELECT note_id, title, top_level_title, is_done, is_todo FROM note_search(?)")
|
2022-10-02 22:01:59 +00:00
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
c.JSON(500, gin.H{
|
|
|
|
"success": false,
|
|
|
|
"message": "Error preparing note-search query",
|
|
|
|
})
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
results := make([]map[string]string, 0)
|
|
|
|
|
2022-10-30 22:44:31 +00:00
|
|
|
rows, err := stm.Query(query)
|
2022-10-02 22:01:59 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
c.JSON(500, gin.H{
|
|
|
|
"success": false,
|
|
|
|
"message": "Error querying note DB",
|
|
|
|
})
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
for rows.Next() {
|
|
|
|
var note_id string
|
|
|
|
var note_title string
|
2022-10-18 21:13:21 +00:00
|
|
|
var note_top_level_title string
|
|
|
|
var note_is_done string
|
|
|
|
var note_is_todo string
|
|
|
|
|
|
|
|
err = rows.Scan(
|
|
|
|
¬e_id,
|
|
|
|
¬e_title,
|
|
|
|
¬e_top_level_title,
|
|
|
|
¬e_is_done,
|
|
|
|
¬e_is_todo,
|
|
|
|
)
|
2022-10-02 22:01:59 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
c.JSON(500, gin.H{
|
|
|
|
"success": false,
|
|
|
|
"message": "Error reading note DB results",
|
|
|
|
})
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
item := make(map[string]string)
|
|
|
|
item["id"] = note_id
|
|
|
|
item["title"] = note_title
|
2022-10-18 21:13:21 +00:00
|
|
|
item["top_level_title"] = note_top_level_title
|
|
|
|
item["is_done"] = note_is_done
|
|
|
|
item["is_todo"] = note_is_todo
|
2022-10-02 22:01:59 +00:00
|
|
|
results = append(results, item)
|
|
|
|
}
|
|
|
|
|
|
|
|
c.JSON(200, gin.H{
|
|
|
|
"results": gin.H{
|
|
|
|
"notes": results,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
r.Run(fmt.Sprintf(":%v", port))
|
|
|
|
}
|