Compare commits

..

2 commits

Author SHA1 Message Date
22ddacde2e basic temple+air testing setup 2024-01-12 15:48:31 -08:00
da14c059c1 ran gofmt 2024-01-11 20:07:47 -08:00
12 changed files with 458 additions and 212 deletions

46
.air.toml Normal file
View file

@ -0,0 +1,46 @@
root = "."
testdata_dir = "testdata"
tmp_dir = "tmp"
[build]
args_bin = []
bin = "./tmp/main"
cmd = "templ generate && go build -o ./tmp/main ."
delay = 1000
exclude_dir = ["assets", "tmp", "vendor", "testdata"]
exclude_file = []
exclude_regex = ["_test.go", ".*_templ.go"]
exclude_unchanged = false
follow_symlink = false
full_bin = ""
include_dir = []
include_ext = ["go", "tpl", "tmpl", "templ", "html"]
include_file = []
kill_delay = "0s"
log = "build-errors.log"
poll = false
poll_interval = 0
post_cmd = []
pre_cmd = []
rerun = false
rerun_delay = 500
send_interrupt = false
stop_on_error = false
[color]
app = ""
build = "yellow"
main = "magenta"
runner = "green"
watcher = "cyan"
[log]
main_only = false
time = false
[misc]
clean_on_exit = false
[screen]
clear_on_rebuild = false
keep_scroll = true

96
api.go
View file

@ -1,75 +1,75 @@
package main package main
import ( import (
"net/http" "encoding/json"
"encoding/json" "net/http"
//"context" //"context"
"fmt" "fmt"
"github.com/go-chi/chi/v5" "github.com/ggicci/httpin"
"github.com/ggicci/httpin" "github.com/go-chi/chi/v5"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
) )
const DEFAULT_RESULT_COUNT = 50; const DEFAULT_RESULT_COUNT = 50
type GetTransactionPaginationInput struct { type GetTransactionPaginationInput struct {
ResultCount int `in:"query=result_count"` ResultCount int `in:"query=result_count"`
PageNum int `in:"query=page_num"` PageNum int `in:"query=page_num"`
} }
func apiRouter() http.Handler { func apiRouter() http.Handler {
r := chi.NewRouter() r := chi.NewRouter()
//r.Use(ApiLoginRequired) //r.Use(ApiLoginRequired)
r.With( r.With(
httpin.NewInput(GetTransactionPaginationInput{}), httpin.NewInput(GetTransactionPaginationInput{}),
).Get("/get_transactions", getTransactions) ).Get("/get_transactions", getTransactions)
r.Post("/new_transaction", newTransaction) r.Post("/new_transaction", newTransaction)
return r return r
} }
func getTransactions(w http.ResponseWriter, req *http.Request) { func getTransactions(w http.ResponseWriter, req *http.Request) {
input := req.Context().Value(httpin.Input).(*GetTransactionPaginationInput) input := req.Context().Value(httpin.Input).(*GetTransactionPaginationInput)
if input.ResultCount == 0 { if input.ResultCount == 0 {
input.ResultCount = DEFAULT_RESULT_COUNT input.ResultCount = DEFAULT_RESULT_COUNT
} }
transactions := []Transaction{} transactions := []Transaction{}
err := db_get_transactions(&transactions, input) err := db_get_transactions(&transactions, input)
if err != nil { if err != nil {
log.Fatal(). log.Fatal().
Err(err). Err(err).
Msg("Fatal error in getTransactions from db_get_transactions") Msg("Fatal error in getTransactions from db_get_transactions")
} }
for _, trns := range transactions { for _, trns := range transactions {
//bytes, err := json.Marshal(trns) //bytes, err := json.Marshal(trns)
bytes, err := json.MarshalIndent(trns, "", "\t") bytes, err := json.MarshalIndent(trns, "", "\t")
if err != nil { if err != nil {
log.Fatal(). log.Fatal().
Err(err). Err(err).
Msg("Could not marshal json") Msg("Could not marshal json")
} }
fmt.Fprintf(w, string(bytes)) fmt.Fprintf(w, string(bytes))
} }
} }
func newTransaction(w http.ResponseWriter, req *http.Request) { func newTransaction(w http.ResponseWriter, req *http.Request) {
decoder := json.NewDecoder(req.Body) decoder := json.NewDecoder(req.Body)
var t Transaction var t Transaction
err := decoder.Decode(&t) err := decoder.Decode(&t)
if err != nil { if err != nil {
log.Fatal(). log.Fatal().
Err(err). Err(err).
Msg("Could not decode incoming post data") Msg("Could not decode incoming post data")
} }
//fmt.Fprintf(w, "New transaction created for Account: %d, with an Amount of: %s", //fmt.Fprintf(w, "New transaction created for Account: %d, with an Amount of: %s",
// t.Account, t.Amount) // t.Account, t.Amount)
db_new_transaction(t) db_new_transaction(t)
} }

86
db.go
View file

@ -1,58 +1,58 @@
package main package main
import ( import (
"fmt" "fmt"
_ "github.com/lib/pq" "github.com/jmoiron/sqlx"
_ "github.com/mattn/go-sqlite3" _ "github.com/lib/pq"
"github.com/jmoiron/sqlx" _ "github.com/mattn/go-sqlite3"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
) )
func db_get_transactions(transactions *[]Transaction,r *GetTransactionPaginationInput) (error) { func db_get_transactions(transactions *[]Transaction, r *GetTransactionPaginationInput) error {
db, err := sqlx.Connect(DB_TYPE, DB_CONNECTION_STRING) db, err := sqlx.Connect(DB_TYPE, DB_CONNECTION_STRING)
if err != nil { if err != nil {
log.Fatal(). log.Fatal().
Err(err). Err(err).
Msg("Fatal error in db_get_transactions\nCannot connect to server") Msg("Fatal error in db_get_transactions\nCannot connect to server")
} }
defer db.Close() defer db.Close()
err = db.Select(transactions, err = db.Select(transactions,
"SELECT trns_id, trns_amount, trns_description, " + "SELECT trns_id, trns_amount, trns_description, "+
"trns_account, trns_bucket, trns_date " + "trns_account, trns_bucket, trns_date "+
fmt.Sprintf("FROM %stransactions ORDER BY trns_id DESC ", DB_SCHEMA) + fmt.Sprintf("FROM %stransactions ORDER BY trns_id DESC ", DB_SCHEMA)+
fmt.Sprintf("LIMIT %d OFFSET %d", fmt.Sprintf("LIMIT %d OFFSET %d",
r.ResultCount, r.PageNum * r.ResultCount )) r.ResultCount, r.PageNum*r.ResultCount))
if err != nil { if err != nil {
return err return err
} }
return nil return nil
} }
func db_new_transaction(transaction Transaction) (error) { func db_new_transaction(transaction Transaction) error {
db, err := sqlx.Connect(DB_TYPE, DB_CONNECTION_STRING) db, err := sqlx.Connect(DB_TYPE, DB_CONNECTION_STRING)
if err != nil { if err != nil {
log.Info() log.Info()
log.Fatal(). log.Fatal().
Err(err). Err(err).
Msg("Fatal error in db_get_transactions\nCannot connect to server") Msg("Fatal error in db_get_transactions\nCannot connect to server")
} }
defer db.Close() defer db.Close()
log.Debug().Msgf("%#v", transaction) log.Debug().Msgf("%#v", transaction)
_, err = db.NamedExec( _, err = db.NamedExec(
fmt.Sprintf("INSERT INTO %stransactions", DB_SCHEMA) + fmt.Sprintf("INSERT INTO %stransactions", DB_SCHEMA)+
"(trns_amount, trns_description, trns_account, trns_bucket, trns_date)" + "(trns_amount, trns_description, trns_account, trns_bucket, trns_date)"+
"VALUES (:trns_amount, :trns_description, :trns_account, :trns_bucket, :trns_date)", "VALUES (:trns_amount, :trns_description, :trns_account, :trns_bucket, :trns_date)",
transaction) transaction)
if err != nil { if err != nil {
log.Fatal(). log.Fatal().
Err(err). Err(err).
Msg("Could not exec insert db query") Msg("Could not exec insert db query")
} }
return nil return nil
} }

View file

@ -1,5 +1,41 @@
{ {
"nodes": { "nodes": {
"flake-utils": {
"locked": {
"lastModified": 1667395993,
"narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"gitignore": {
"inputs": {
"nixpkgs": [
"templ",
"nixpkgs"
]
},
"locked": {
"lastModified": 1694102001,
"narHash": "sha256-vky6VPK1n1od6vXbqzOXnekrQpTL4hbPAwUhT5J9c9E=",
"owner": "hercules-ci",
"repo": "gitignore.nix",
"rev": "9e21c80adf67ebcb077d75bd5e7d724d21eeafd6",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "gitignore.nix",
"type": "github"
}
},
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1702830618, "lastModified": 1702830618,
@ -16,9 +52,68 @@
"type": "github" "type": "github"
} }
}, },
"nixpkgs_2": {
"locked": {
"lastModified": 1694422566,
"narHash": "sha256-lHJ+A9esOz9vln/3CJG23FV6Wd2OoOFbDeEs4cMGMqc=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "3a2786eea085f040a66ecde1bc3ddc7099f6dbeb",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": { "root": {
"inputs": { "inputs": {
"nixpkgs": "nixpkgs" "nixpkgs": "nixpkgs",
"templ": "templ"
}
},
"templ": {
"inputs": {
"gitignore": "gitignore",
"nixpkgs": "nixpkgs_2",
"xc": "xc"
},
"locked": {
"lastModified": 1704923336,
"narHash": "sha256-aS/k5kkf8kShS5hoyHjnGCZrDnJxawstO/hzTcBPziY=",
"owner": "a-h",
"repo": "templ",
"rev": "914bc73f8030166c9f8bd46af62f5f9bb2c3b089",
"type": "github"
},
"original": {
"owner": "a-h",
"repo": "templ",
"type": "github"
}
},
"xc": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": [
"templ",
"nixpkgs"
]
},
"locked": {
"lastModified": 1703164129,
"narHash": "sha256-kCcCqqwvjN07H8FPG4tXsRVRcMqT8dUNt9pwW1kKAe8=",
"owner": "joerdav",
"repo": "xc",
"rev": "0655cccfcf036556aeaddfb8f45dc7e8dd1b3680",
"type": "github"
},
"original": {
"owner": "joerdav",
"repo": "xc",
"type": "github"
} }
} }
}, },

View file

@ -2,9 +2,12 @@
description = "Recount's server/backend, written in Go"; description = "Recount's server/backend, written in Go";
# Nixpkgs / NixOS version to use. # Nixpkgs / NixOS version to use.
inputs.nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
templ.url = "github:a-h/templ";
};
outputs = { self, nixpkgs }: outputs = { self, nixpkgs, templ }:
let let
# Generate a user-friendly version number. # Generate a user-friendly version number.
version = builtins.substring 0 8 self.lastModifiedDate; version = builtins.substring 0 8 self.lastModifiedDate;
@ -18,12 +21,13 @@
# Nixpkgs instantiated for supported system types. # Nixpkgs instantiated for supported system types.
nixpkgsFor = forAllSystems (system: import nixpkgs { inherit system; }); nixpkgsFor = forAllSystems (system: import nixpkgs { inherit system; });
templ_function = system: templ.packages.${system}.templ;
in in
{ {
# Provide some binary packages for selected system types. # Provide some binary packages for selected system types.
packages = forAllSystems (system: packages = forAllSystems (system:
let let
inherit system;
pkgs = nixpkgsFor.${system}; pkgs = nixpkgsFor.${system};
in in
{ {
@ -33,6 +37,9 @@
default = pkgs.buildGoModule { default = pkgs.buildGoModule {
pname = "recount-server"; pname = "recount-server";
inherit version; inherit version;
preBuild = ''
${templ_function system}/bin/templ generate
'';
# In 'nix develop', we don't need a copy of the source tree # In 'nix develop', we don't need a copy of the source tree
# in the Nix store. # in the Nix store.
src = ./.; src = ./.;
@ -61,10 +68,22 @@
devShells = forAllSystems (system: devShells = forAllSystems (system:
let pkgs = nixpkgsFor.${system}; let
inherit system;
pkgs = nixpkgsFor.${system};
in { in {
default = pkgs.mkShell { default = pkgs.mkShell {
buildInputs = with pkgs; [ go gopls gotools go-tools ]; shellHook = ''
alias gotest='templ generate;go run . -d'
'';
buildInputs = with pkgs; [
air # live go app reloading
go
gopls
gotools
go-tools
(templ_function system)
];
}; };
}); });
}; };

5
go.mod
View file

@ -12,8 +12,9 @@ require (
) )
require ( require (
github.com/a-h/templ v0.2.513 // indirect
github.com/ggicci/owl v0.4.0 // indirect github.com/ggicci/owl v0.4.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
golang.org/x/sys v0.12.0 // indirect golang.org/x/sys v0.14.0 // indirect
) )

6
go.sum
View file

@ -1,3 +1,5 @@
github.com/a-h/templ v0.2.513 h1:ZmwGAOx4NYllnHy+FTpusc4+c5msoMpPIYX0Oy3dNqw=
github.com/a-h/templ v0.2.513/go.mod h1:9gZxTLtRzM3gQxO8jr09Na0v8/jfliS97S9W5SScanM=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -24,6 +26,8 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg= github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg=
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@ -38,5 +42,7 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

110
main.go
View file

@ -2,6 +2,7 @@ package main
import ( import (
"nickiel.net/recount_server/tests" "nickiel.net/recount_server/tests"
"nickiel.net/recount_server/web"
"database/sql" "database/sql"
"net/http" "net/http"
@ -25,80 +26,79 @@ var DB_CONNECTION_STRING string = "user=rcntuser password=Devel@pmentPa$$w0rd ho
// "json:"json_code_name,omitempty"" (omit empty) // "json:"json_code_name,omitempty"" (omit empty)
// if you use `json:"-"` it doesn't encode it // if you use `json:"-"` it doesn't encode it
type Transaction struct { type Transaction struct {
Id int `db:"trns_id" json:"Id"` Id int `db:"trns_id" json:"Id"`
Amount string `db:"trns_amount" json:"Amount"` Amount string `db:"trns_amount" json:"Amount"`
Description sql.NullString `db:"trns_description" json:"Description"` Description sql.NullString `db:"trns_description" json:"Description"`
Account int `db:"trns_account" json:"Account"` Account int `db:"trns_account" json:"Account"`
Bucket sql.NullInt64 `db:"trns_bucket" json:"Bucket"` Bucket sql.NullInt64 `db:"trns_bucket" json:"Bucket"`
Date time.Time `db:"trns_date" json:"TransactionDate"` Date time.Time `db:"trns_date" json:"TransactionDate"`
} }
func hello(w http.ResponseWriter, req *http.Request) { func hello(w http.ResponseWriter, req *http.Request) {
fmt.Fprintf(w, "hello\n") fmt.Fprintf(w, "hello\n")
} }
func headers(w http.ResponseWriter, req *http.Request) { func headers(w http.ResponseWriter, req *http.Request) {
for name, headers := range req.Header { for name, headers := range req.Header {
for _, h := range headers { for _, h := range headers {
fmt.Fprintf(w, "%v: %v\n", name, h) fmt.Fprintf(w, "%v: %v\n", name, h)
} }
} }
} }
func main() { func main() {
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
zerolog.SetGlobalLevel(zerolog.InfoLevel) zerolog.SetGlobalLevel(zerolog.InfoLevel)
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}) log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
var debugFlag = flag.Bool("d", false, "whether to enable debug mode") var debugFlag = flag.Bool("d", false, "whether to enable debug mode")
var traceFlag = flag.Bool("t", false, "whether to trace logging") var traceFlag = flag.Bool("t", false, "whether to trace logging")
flag.Parse() flag.Parse()
if *traceFlag { if *traceFlag {
zerolog.SetGlobalLevel(zerolog.TraceLevel) zerolog.SetGlobalLevel(zerolog.TraceLevel)
log.Debug().Msg("Enabling trace level debugging") log.Debug().Msg("Enabling trace level debugging")
} }
if *debugFlag { if *debugFlag {
if !*traceFlag { if !*traceFlag {
zerolog.SetGlobalLevel(zerolog.DebugLevel) zerolog.SetGlobalLevel(zerolog.DebugLevel)
} }
log.Debug().Msg("Is debugging") log.Debug().Msg("Is debugging")
DB_TYPE = "sqlite3" DB_TYPE = "sqlite3"
DB_SCHEMA = "" DB_SCHEMA = ""
DB_CONNECTION_STRING = "test.db" DB_CONNECTION_STRING = "test.db"
debug_mode.Init_testdb(DB_TYPE, DB_CONNECTION_STRING) debug_mode.Init_testdb(DB_TYPE, DB_CONNECTION_STRING)
} }
debug_mode.SetLogLevel(zerolog.GlobalLevel())
debug_mode.SetLogLevel(zerolog.GlobalLevel()) log.Info().Msg("starting server")
log.Info().Msg("starting server") r := chi.NewRouter()
r := chi.NewRouter() // A good base middleware stack
r.Use(middleware.RequestID)
r.Use(middleware.RealIP)
r.Use(middleware.Recoverer)
r.Use(middleware.Logger)
// A good base middleware stack // Set a timeout value on the request context (ctx), that will signal
r.Use(middleware.RequestID) // through ctx.Done() that the request has timed out and further
r.Use(middleware.RealIP) // processing should be stopped.
r.Use(middleware.Recoverer) //r.Use(middleware.Timeout(60 * time.Second))
r.Use(middleware.Logger)
// Set a timeout value on the request context (ctx), that will signal r.Get("/headers", headers)
// through ctx.Done() that the request has timed out and further r.Mount("/", web.WebRouter())
// processing should be stopped. r.Mount("/api", apiRouter())
//r.Use(middleware.Timeout(60 * time.Second))
r.Get("/", hello) err := http.ListenAndServe(":8090", r)
r.Get("/headers", headers) if err != nil {
r.Mount("/api", apiRouter()) log.Fatal().
Err(err).
Msg("Could not open server connection")
}
err := http.ListenAndServe(":8090", r) //fmt.Println("Hello World")
if err != nil {
log.Fatal().
Err(err).
Msg("Could not open server connection")
}
//fmt.Println("Hello World")
} }

View file

@ -1,9 +1,9 @@
package debug_mode package debug_mode
import ( import (
"os"
"encoding/json"
"database/sql" "database/sql"
"encoding/json"
"os"
"time" "time"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
@ -13,50 +13,50 @@ import (
) )
type Transaction struct { type Transaction struct {
Id int `db:"trns_id" json:"Id"` Id int `db:"trns_id" json:"Id"`
Amount string `db:"trns_amount" json:"Amount"` Amount string `db:"trns_amount" json:"Amount"`
Description sql.NullString `db:"trns_description" json:"Description"` Description sql.NullString `db:"trns_description" json:"Description"`
Account int `db:"trns_account" json:"Account"` Account int `db:"trns_account" json:"Account"`
Bucket sql.NullInt64 `db:"trns_bucket" json:"Bucket"` Bucket sql.NullInt64 `db:"trns_bucket" json:"Bucket"`
Date time.Time `db:"trns_date" json:"TransactionDate"` Date time.Time `db:"trns_date" json:"TransactionDate"`
} }
func SetLogLevel(level zerolog.Level) { func SetLogLevel(level zerolog.Level) {
zerolog.SetGlobalLevel(level) zerolog.SetGlobalLevel(level)
} }
func Init_testdb(DB_TYPE string, DB_CONNECTION_STRING string) { func Init_testdb(DB_TYPE string, DB_CONNECTION_STRING string) {
cwd, err := os.Getwd() cwd, err := os.Getwd()
if err != nil { if err != nil {
log.Fatal().Err(err).Msg("Could not get current working directory") log.Fatal().Err(err).Msg("Could not get current working directory")
} else { } else {
log.Trace().Msgf("Currect working directory is: %s", cwd) log.Trace().Msgf("Currect working directory is: %s", cwd)
} }
_, err = os.Stat(cwd + DB_CONNECTION_STRING) _, err = os.Stat(cwd + DB_CONNECTION_STRING)
if err != nil { if err != nil {
log.Debug().Msg("Found existing test.db file. Attempting to delete") log.Debug().Msg("Found existing test.db file. Attempting to delete")
err = os.Remove(DB_CONNECTION_STRING) err = os.Remove(DB_CONNECTION_STRING)
if err != nil { if err != nil {
log.Fatal().Err(err).Msg("Failed to delete testing db") log.Fatal().Err(err).Msg("Failed to delete testing db")
} else { } else {
log.Debug().Msg("Deleted test.db file successfully") log.Debug().Msg("Deleted test.db file successfully")
} }
} else { } else {
log.Debug().Msg("No existing test.db file found") log.Debug().Msg("No existing test.db file found")
} }
db, err := sqlx.Connect(DB_TYPE, DB_CONNECTION_STRING) db, err := sqlx.Connect(DB_TYPE, DB_CONNECTION_STRING)
if err != nil { if err != nil {
log.Fatal(). log.Fatal().
Err(err). Err(err).
Msg("Couldn't open test db") Msg("Couldn't open test db")
} }
defer db.Close() defer db.Close()
init_sql := ` init_sql := `
CREATE TABLE accounts ( CREATE TABLE accounts (
acnt_id Integer PRIMARY KEY, acnt_id Integer PRIMARY KEY,
acnt_dsply_name varchar(50) NOT NULL, acnt_dsply_name varchar(50) NOT NULL,
@ -116,18 +116,18 @@ INSERT INTO transactions (trns_amount, trns_description, trns_account, trns_buck
("50.00", "Money", 1, 1, "2023-11-10"); ("50.00", "Money", 1, 1, "2023-11-10");
` `
tx := db.MustBegin() tx := db.MustBegin()
tx.MustExec(init_sql) tx.MustExec(init_sql)
err = tx.Commit() err = tx.Commit()
if err != nil { if err != nil {
log.Fatal(). log.Fatal().
Err(err). Err(err).
Msg("Could not commit transaction") Msg("Could not commit transaction")
} }
jsonExample := `{ jsonExample := `{
"Id": 3, "Id": 3,
"Amount": "100", "Amount": "100",
"Description": { "Description": {
@ -142,20 +142,18 @@ INSERT INTO transactions (trns_amount, trns_description, trns_account, trns_buck
"TransactionDate": "2023-11-11T00:00:00Z" "TransactionDate": "2023-11-11T00:00:00Z"
}` }`
var trns Transaction = Transaction{} var trns Transaction = Transaction{}
err = json.Unmarshal([]byte(jsonExample), &trns) err = json.Unmarshal([]byte(jsonExample), &trns)
if err != nil { if err != nil {
log.Fatal().Err(err).Msg("could not unmarshal") log.Fatal().Err(err).Msg("could not unmarshal")
} }
_, err = db.NamedExec("INSERT INTO transactions" + _, err = db.NamedExec("INSERT INTO transactions"+
"(trns_amount, trns_description, trns_account, trns_bucket, trns_date)" + "(trns_amount, trns_description, trns_account, trns_bucket, trns_date)"+
"VALUES (:trns_amount, :trns_description, :trns_account, :trns_bucket, :trns_date)", "VALUES (:trns_amount, :trns_description, :trns_account, :trns_bucket, :trns_date)",
trns) trns)
log.Debug().Msg("Test database initialized")
log.Debug().Msg("Test database initialized")
} }

6
web/index.templ Normal file
View file

@ -0,0 +1,6 @@
package web
templ hello(name string) {
<div>Hello { name } </div>
<h1>SUPRISE!!!</h1>
}

48
web/index_templ.go Normal file
View file

@ -0,0 +1,48 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.2.529
package web
//lint:file-ignore SA4006 This context is only used if a nested component is present.
import "github.com/a-h/templ"
import "context"
import "io"
import "bytes"
func hello(name string) templ.Component {
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
if !templ_7745c5c3_IsBuffer {
templ_7745c5c3_Buffer = templ.GetBuffer()
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
if templ_7745c5c3_Var1 == nil {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div>Hello ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var2 string
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(name)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/index.templ`, Line: 3, Col: 21}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div><h1>SUPRISE!!!</h1>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if !templ_7745c5c3_IsBuffer {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
}
return templ_7745c5c3_Err
})
}

27
web/router.go Normal file
View file

@ -0,0 +1,27 @@
package web
import (
"net/http"
"context"
"github.com/go-chi/chi/v5"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
)
func SetLogLevel(level zerolog.Level) {
zerolog.SetGlobalLevel(level)
}
func WebRouter() http.Handler {
r := chi.NewRouter()
r.Get("/", getIndex)
return r
}
func getIndex(w http.ResponseWriter, req *http.Request) {
log.Debug().Msg("Got index")
component := hello("Nick")
component.Render(context.Background(), w)
}