diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..98e6ef6 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.db diff --git a/go.mod b/go.mod index cdfb3f0..0142ba2 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,5 @@ module timefu.li/backend go 1.24.2 + +require github.com/mattn/go-sqlite3 v1.14.28 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..42e5bac --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/mattn/go-sqlite3 v1.14.28 h1:ThEiQrnbtumT+QMknw63Befp/ce/nUPgBPMlRFEum7A= +github.com/mattn/go-sqlite3 v1.14.28/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= diff --git a/main.go b/main.go index b9146ad..88040d8 100644 --- a/main.go +++ b/main.go @@ -1,88 +1,18 @@ package main import ( - "encoding/json" "fmt" - "io" "log" "net/http" "os" "os/signal" - "reflect" - "strings" "syscall" "time" + + "timefu.li/backend/tubson" + "timefu.li/backend/tubsql" ) -type http_method uint8; const ( - GET http_method = iota - POST - PATCH - PUT - DELETE -) -func (method http_method) to_string() string { - switch method { - case GET: - return http.MethodGet - case POST: - return http.MethodPost - case PATCH: - return http.MethodPatch - case PUT: - return http.MethodPut - case DELETE: - return http.MethodDelete - } - - return "" -} - - -type http_status_code int; const ( - OK http_status_code = http.StatusOK - INTERNAL_SERVER_ERROR http_status_code = http.StatusInternalServerError - BAD_REQUEST http_status_code = http.StatusBadRequest -) - -type empty_request_body struct {} -/* T Representing any request body struct - S Representing any response body struct */ -func json_new_route[T any, S any](method http_method, route string, handle_func func(body T, raw_request *http.Request) (S, http_status_code)) { - http.HandleFunc(method.to_string() + " /" + route, func(response http.ResponseWriter, request *http.Request) { - request_body_bytes, err := io.ReadAll(request.Body) - if err != nil { - response.WriteHeader(int(INTERNAL_SERVER_ERROR)) - log.Panicln(err) - return - } - var decode_result T - if len(request_body_bytes) != 0 { - decoder := json.NewDecoder(strings.NewReader(string(request_body_bytes))) - decoder.DisallowUnknownFields() - err = decoder.Decode(&decode_result) - if err != nil { - response.WriteHeader(int(BAD_REQUEST)) - response.Write([]byte(err.Error())) - log.Println(err) - return - } - } - - body, status_code := handle_func(decode_result, request) - encode_result, err := json.Marshal(body) - if err != nil { - response.WriteHeader(int(INTERNAL_SERVER_ERROR)) - log.Panicln(err) - return - } - fmt.Println(reflect.VisibleFields(reflect.TypeOf(body))) - - response.WriteHeader(int(status_code)) - response.Write(encode_result) - }) - -} func main() { type foo_request_body struct { @@ -93,25 +23,29 @@ func main() { Field1 string Field2 int } - foo_route_handler := func(body foo_request_body, raw_request *http.Request) (foo_response_body, http_status_code) { + foo_route_handler := func(body foo_request_body, raw_request *http.Request) (foo_response_body, tubson.Http_status_code) { return foo_response_body { Field1: "hi there on foo!", Field2: body.Arg1 + body.Arg2, - }, OK + }, tubson.OK } - json_new_route(GET, "foo", foo_route_handler) + tubson.New_route(tubson.GET, "foo", foo_route_handler) type bar_response_body struct { Response int Message string } - bar_route_handler := func(body empty_request_body, raw_request *http.Request) (bar_response_body, http_status_code) { + bar_route_handler := func(body tubson.Empty_request_body, raw_request *http.Request) (bar_response_body, tubson.Http_status_code) { return bar_response_body { Response: 400, Message: "hi there on bar!", - }, INTERNAL_SERVER_ERROR + }, tubson.INTERNAL_SERVER_ERROR } - json_new_route(GET, "bar", bar_route_handler) + tubson.New_route(tubson.GET, "bar", bar_route_handler) + + db := tubsql.Connect_database() + tubsql.Test_commit(db) + db.Close() http_server := &http.Server{ Addr: ":8080", diff --git a/tubson/README.org b/tubson/README.org new file mode 100644 index 0000000..af6bdb1 --- /dev/null +++ b/tubson/README.org @@ -0,0 +1,3 @@ +* Tubson + +JSON Server and Handler diff --git a/tubson/tubson.go b/tubson/tubson.go new file mode 100644 index 0000000..1f02321 --- /dev/null +++ b/tubson/tubson.go @@ -0,0 +1,80 @@ +package tubson + +import ( + "encoding/json" + "fmt" + "io" + "log" + "net/http" + "reflect" + "strings" +) + +type Http_method uint8; const ( + GET Http_method = iota + POST + PATCH + PUT + DELETE +) +func (method Http_method) to_string() string { + switch method { + case GET: + return http.MethodGet + case POST: + return http.MethodPost + case PATCH: + return http.MethodPatch + case PUT: + return http.MethodPut + case DELETE: + return http.MethodDelete + } + + return "" +} + + +type Http_status_code int; const ( + OK Http_status_code = http.StatusOK + INTERNAL_SERVER_ERROR Http_status_code = http.StatusInternalServerError + BAD_REQUEST Http_status_code = http.StatusBadRequest +) + +type Empty_request_body struct {} +/* T Representing any request body struct + S Representing any response body struct */ +func New_route[T any, S any](method Http_method, route string, handle_func func(body T, raw_request *http.Request) (S, Http_status_code)) { + http.HandleFunc(method.to_string() + " /" + route, func(response http.ResponseWriter, request *http.Request) { + request_body_bytes, err := io.ReadAll(request.Body) + if err != nil { + response.WriteHeader(int(INTERNAL_SERVER_ERROR)) + log.Panicln(err) + return + } + var decode_result T + if len(request_body_bytes) != 0 { + decoder := json.NewDecoder(strings.NewReader(string(request_body_bytes))) + decoder.DisallowUnknownFields() + err = decoder.Decode(&decode_result) + if err != nil { + response.WriteHeader(int(BAD_REQUEST)) + response.Write([]byte(err.Error())) + log.Println(err) + return + } + } + + body, status_code := handle_func(decode_result, request) + encode_result, err := json.Marshal(body) + if err != nil { + response.WriteHeader(int(INTERNAL_SERVER_ERROR)) + log.Panicln(err) + return + } + fmt.Println(reflect.VisibleFields(reflect.TypeOf(body))) + + response.WriteHeader(int(status_code)) + response.Write(encode_result) + }) +} diff --git a/tubsql/README.org b/tubsql/README.org new file mode 100644 index 0000000..e8ace0c --- /dev/null +++ b/tubsql/README.org @@ -0,0 +1,3 @@ +* Tubsql + +SQL Handler diff --git a/tubsql/tubsql.go b/tubsql/tubsql.go new file mode 100644 index 0000000..2ff802d --- /dev/null +++ b/tubsql/tubsql.go @@ -0,0 +1,40 @@ +package tubsql + +import ( + "context" + "database/sql" + "log" + + _ "github.com/mattn/go-sqlite3" +) + +func Connect_database() *sql.DB { + db, err := sql.Open("sqlite3", "./test.db") + if err != nil { + log.Fatal(err) + } + + return db +} + +func Test_commit(db *sql.DB) { + tx, err := db.Begin() + if err != nil { + log.Fatal(err) + } + ctx := context.Background() + + _, err = tx.Exec("CREATE TABLE IF NOT EXISTS users ( name varchar(255), age int )") + _, err = tx.ExecContext( + ctx, + "INSERT INTO users (name, age) VALUES ($1, $2)", + "testing", + 42, + ) + + if err != nil { + tx.Rollback() + log.Fatal(err) + } + tx.Commit() +}