package main import ( "context" "errors" "fmt" "log" "log/slog" "net/http" "time" "github.com/gin-gonic/gin" "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgxpool" ) /* Variables */ var connPool *pgxpool.Pool func Config() (*pgxpool.Config) { const defaultMaxConns = int32(4) const defaultMinConns = int32(0) const defaultMaxConnLifetime = time.Hour const defaultMaxConnIdleTime = time.Minute * 30 const defaultHealthCheckPeriod = time.Minute const defaultConnectTimeout = time.Second * 5 // Your own Database URL const DATABASE_URL string = "postgres://tooloftheweek:b4lKAuHRz3Xho6WUQq4YUGnfiAQs5zNg@10.0.100.172:5432/tooloftheweek" dbConfig, err := pgxpool.ParseConfig(DATABASE_URL) if err!=nil { log.Fatal("Failed to create a config, error: ", err) } dbConfig.MaxConns = defaultMaxConns dbConfig.MinConns = defaultMinConns dbConfig.MaxConnLifetime = defaultMaxConnLifetime dbConfig.MaxConnIdleTime = defaultMaxConnIdleTime dbConfig.HealthCheckPeriod = defaultHealthCheckPeriod dbConfig.ConnConfig.ConnectTimeout = defaultConnectTimeout dbConfig.BeforeAcquire = func(ctx context.Context, c *pgx.Conn) bool { slog.Info("Before acquiring the connection pool to the database") return true } dbConfig.AfterRelease = func(c *pgx.Conn) bool { slog.Info("After releasing the connection pool to the database") return true } dbConfig.BeforeClose = func(c *pgx.Conn) { slog.Info("Closed the connection pool to the database") } return dbConfig } /* Structs */ type tool struct { Name string Description string Url string Week_to_post int } /* Database Functions*/ func database_connection(url string) (*pgx.Conn, error) { var err error conn, err := pgx.Connect(context.Background(), url) if err != nil { slog.Error("Could not connect to database") } return conn, err } func insertTool(conn *pgx.Conn, new_tool tool) error { _, err := conn.Exec(context.Background(), "INSERT INTO tool_tb(name,description) VALUES($1,$2)", new_tool.Name, new_tool.Description) if err != nil { slog.Error("Could not insert new tool into database") if err.Error() == `ERROR: duplicate key value violates unique constraint "tool_tb_name_key" (SQLSTATE 23505)` { slog.Error("Tool already in database.") } else { fmt.Println(err) } return err } return nil } func currentTool() (tool,error) { var currenttool tool var currentweek int //Calculate current week currenttime := int(time.Now().Unix()) + 259200 currentweek = currenttime/604800 fmt.Println(currentweek) //Select current tool from database rows, err := connPool.Query(context.Background(), "SELECT id,name,description,url,week_to_post FROM tool_tb WHERE week_to_post=$1", currentweek) if err != nil { slog.Error("Could not query tools_tb") } for rows.Next(){ var id int var name string var description string var url string var week_to_post int //var currenttoolinloop tool rows.Scan(&id, &name, &description, &url, &week_to_post) if name == "" { return currenttool, errors.New("Could not find tool for current week. Please update tool list.") } slog.Info("Found tool: " + name) currenttool.Name = name currenttool.Description = description currenttool.Url = url currenttool.Week_to_post = week_to_post } return currenttool, nil } func getTools() ([]tool,error) { var err error var tools []tool rows, err := connPool.Query(context.Background(), "SELECT id,name,description,url,week_to_post FROM tool_tb") if err != nil { slog.Error("Could not query tool_tb") return nil, err } for rows.Next(){ var id int var name string var description string var url string var week_to_post int var currenttoolinloop tool err := rows.Scan(&id, &name, &description, &url, &week_to_post) if err != nil { slog.Error("Could not scan query") return nil, err } currenttoolinloop.Name = name currenttoolinloop.Description = description currenttoolinloop.Url = url currenttoolinloop.Week_to_post = week_to_post tools = append(tools, currenttoolinloop) } return tools, nil } /* Gin Functions */ func getToolsHandler(c *gin.Context) { //var tools []tool tools, err := getTools() if err != nil { fmt.Println(err) } fmt.Println(tools) c.IndentedJSON(http.StatusOK, tools) } func currentToolHandler(c *gin.Context) { var currenttool tool //var tools []tool currenttool, err := currentTool() if err != nil { fmt.Println(err) } fmt.Println(currenttool) c.IndentedJSON(http.StatusOK, currenttool) } func insertToolHandler(c *gin.Context) { var newTool tool c.IndentedJSON(http.StatusCreated, newTool) } func updateToolHandler(c *gin.Context) { var updatedTool tool c.IndentedJSON(http.StatusOK, updatedTool) } func deleteToolHandler(c *gin.Context) { var removedTool tool c.IndentedJSON(http.StatusOK, removedTool) } func main() { var err error connPool, err = pgxpool.NewWithConfig(context.Background(), Config()) if err != nil { log.Fatal("Error acquiring connection from database.") } conn, err := connPool.Acquire(context.Background()) if err!=nil { log.Fatal("Error while acquiring connection from the database pool!!") } defer conn.Release() err = conn.Ping(context.Background()) if err != nil { log.Fatal("Could not ping database.") } slog.Info("Connection to database successful.") _, err = conn.Exec(context.Background(), "CREATE TABLE IF NOT EXISTS tool_tb (id SERIAL, name TEXT UNIQUE, url TEXT, description TEXT, time_created TIMESTAMP, week_to_post INT)") if err != nil { slog.Error("Could not create tool table.") } router := gin.Default() router.GET("/api/v0/tools", getToolsHandler) router.GET("/api/v0/tooloftheweek", currentToolHandler) router.POST("/api/v0/inserttool", insertToolHandler) router.POST("/api/v0/updatetool", updateToolHandler) router.POST("/api/v0/deletetool", deleteToolHandler) router.Run("0.0.0.0:8080") }