2024-12-20 00:52:27 +00:00
package database
2024-12-20 13:28:54 +00:00
import (
"database/sql"
"errors"
2024-12-25 15:40:56 +00:00
"os"
"strings"
2024-12-22 19:58:57 +00:00
_ "github.com/jackc/pgx/v5/stdlib"
2024-12-20 13:28:54 +00:00
)
2024-12-20 00:52:27 +00:00
type DB struct {
Host string
User string
Password string
Name string
Port string
}
2024-12-20 13:28:54 +00:00
var (
database DB
)
2024-12-20 00:52:27 +00:00
2024-12-25 15:40:56 +00:00
const (
SqlFile = "./database/bookholder.sql"
)
2024-12-20 13:28:54 +00:00
func SetEnv ( env map [ string ] string ) * DB {
2024-12-20 00:52:27 +00:00
var db DB
db . Host = env [ "DB_HOST" ]
db . User = env [ "DB_USER" ]
db . Password = env [ "DB_PASSWORD" ]
db . Name = env [ "DB_NAME" ]
db . Port = env [ "DB_PORT" ]
database = db
2024-12-20 13:28:54 +00:00
checkDatabase ( )
return & db
}
func New ( ) ( * sql . DB , error ) {
2024-12-22 19:58:57 +00:00
conn , err := sql . Open ( "pgx" , connect ( ) )
2024-12-20 13:28:54 +00:00
if err != nil {
return nil , err
}
return conn , nil
}
func connect ( ) string {
2024-12-25 15:40:56 +00:00
return "postgres://" + database . User + ":" + database . Password + "@" + database . Host + ":" + database . Port + "/" + database . Name + "?sslmode=disable"
2024-12-22 19:58:57 +00:00
//return "user=" + database.User + " password=" + database.Password + " host=" + database.Host + " dbname=" + database.Name + " sslmode=disable"
2024-12-20 13:28:54 +00:00
}
func checkDatabase ( ) {
2024-12-22 19:58:57 +00:00
conn , err := sql . Open ( "pgx" , "postgres://" + database . User + ":" + database . Password + "@" + database . Host + ":" + database . Port + "/postgres?sslmode=disable" )
2024-12-20 13:28:54 +00:00
if err != nil {
panic ( err )
}
defer conn . Close ( )
err = conn . QueryRow ( "SELECT datname FROM pg_database WHERE datname = $1" , database . Name ) . Scan ( & database . Name )
if err != nil {
if err == sql . ErrNoRows {
createDatabase ( )
} else {
panic ( err )
}
}
2024-12-20 00:52:27 +00:00
}
2024-12-20 13:28:54 +00:00
func createDatabase ( ) {
2024-12-22 19:58:57 +00:00
conn , err := sql . Open ( "pgx" , "postgres://" + database . User + ":" + database . Password + "@" + database . Host + ":" + database . Port + "/postgres?sslmode=disable" )
2024-12-20 13:28:54 +00:00
if err != nil {
panic ( err )
}
defer conn . Close ( )
_ , err = conn . Exec ( "CREATE DATABASE " + database . Name )
if err != nil {
panic ( err )
}
2024-12-25 15:40:56 +00:00
createTables ( )
2024-12-20 13:28:54 +00:00
}
func checkTables ( ) {
2024-12-20 00:52:27 +00:00
}
func createTables ( ) {
2024-12-25 15:40:56 +00:00
sqlFile , err := os . ReadFile ( SqlFile )
if err != nil {
panic ( err )
}
sqlStatements := strings . Split ( string ( sqlFile ) , ";" )
conn , err := sql . Open ( "pgx" , connect ( ) )
if err != nil {
panic ( err )
}
defer conn . Close ( )
for _ , statement := range sqlStatements {
_ , err := conn . Exec ( statement )
if err != nil {
panic ( err )
}
}
2024-12-20 00:52:27 +00:00
}
func updateTables ( ) {
}
2024-12-20 13:28:54 +00:00
func existAccount ( database * sql . DB , id int ) ( bool , error ) {
err := database . QueryRow ( "SELECT id FROM accounts WHERE id = $1" , id ) . Scan ( & id )
if err != nil {
if err != sql . ErrNoRows {
return false , err
}
return false , nil
}
return true , nil
}
2024-12-20 00:52:27 +00:00
2024-12-20 13:28:54 +00:00
func NewAccount ( database * sql . DB , account Account ) error {
2024-12-26 15:08:43 +00:00
2024-12-20 13:28:54 +00:00
exists , err := existAccount ( database , int ( account . ID ) )
if err != nil {
return err
}
if exists {
return errors . New ( "account already exists" )
}
2024-12-26 15:08:43 +00:00
_ , err = database . Exec ( "INSERT INTO accounts (id, name, kind) VALUES ($1, $2, $3)" , int ( account . ID ) , string ( account . Name ) , account . Kind )
2024-12-20 13:28:54 +00:00
if err != nil {
return err
}
2024-12-26 15:08:43 +00:00
2024-12-20 13:28:54 +00:00
return nil
2024-12-20 00:52:27 +00:00
}
2024-12-20 13:28:54 +00:00
func UpdateAccount ( database * sql . DB , account Account ) error {
2024-12-25 22:54:14 +00:00
exists , err := existAccount ( database , int ( account . ID ) )
if err != nil {
return err
}
if ! exists {
return errors . New ( "account does not exist" )
}
_ , err = database . Exec ( "UPDATE accounts SET name = $1, kind = $2 WHERE id = $3" , account . Name , account . Kind , account . ID )
2024-12-20 13:28:54 +00:00
if err != nil {
return err
}
2024-12-20 00:52:27 +00:00
2024-12-26 15:08:43 +00:00
return nil
2024-12-20 00:52:27 +00:00
}
2024-12-20 13:28:54 +00:00
func DeleteAccount ( database * sql . DB , id int ) error {
2024-12-25 22:54:14 +00:00
exists , err := existAccount ( database , id )
if err != nil {
return err
}
if ! exists {
return errors . New ( "account does not exist" )
}
_ , err = database . Exec ( "DELETE FROM accounts WHERE id = $1" , id )
2024-12-20 13:28:54 +00:00
if err != nil {
return err
}
return nil
2024-12-20 00:52:27 +00:00
}
2024-12-20 13:28:54 +00:00
func GetAccount ( database * sql . DB , id int ) ( Account , error ) {
var account Account
err := database . QueryRow ( "SELECT * FROM accounts WHERE id = $1" , id ) . Scan ( & account . ID , & account . Name , & account . Kind )
if err != nil {
2024-12-26 15:08:43 +00:00
if err == sql . ErrNoRows {
return account , errors . New ( "account does not exist" )
}
2024-12-20 13:28:54 +00:00
return account , err
}
return account , nil
2024-12-20 00:52:27 +00:00
}
2024-12-25 22:54:14 +00:00
func existTransaction ( database * sql . DB , id int ) ( bool , error ) {
err := database . QueryRow ( "SELECT id FROM transactions WHERE id = $1" , id ) . Scan ( & id )
if err != nil {
if err != sql . ErrNoRows {
return false , err
}
return false , nil
}
return true , nil
}
2024-12-20 13:28:54 +00:00
func NewTransaction ( database * sql . DB , transaction Transaction ) error {
2024-12-26 15:08:43 +00:00
if transaction . OffsetAccount == transaction . Account {
return errors . New ( "offset account and account cannot be the same" )
}
if transaction . Amount == 0 {
return errors . New ( "amount cannot be 0" )
}
if transaction . Date . IsZero ( ) {
return errors . New ( "date is required" )
}
_ , err := database . Exec ( "INSERT INTO transactions (amount, debit, offset_account, account, date, description) VALUES ($1, $2, $3, $4, $5, $6)" , transaction . Amount , transaction . Debit , transaction . OffsetAccount , transaction . Account , transaction . Date , transaction . Description )
2024-12-20 13:28:54 +00:00
if err != nil {
return err
}
return nil
2024-12-20 00:52:27 +00:00
}
2024-12-20 13:28:54 +00:00
func UpdateTransaction ( database * sql . DB , transaction Transaction ) error {
2024-12-25 22:54:14 +00:00
exists , err := existTransaction ( database , int ( transaction . ID ) )
if err != nil {
return err
}
if ! exists {
return errors . New ( "transaction already exists" )
}
2024-12-26 15:08:43 +00:00
_ , err = database . Exec ( "UPDATE transactions SET amount = $1, debit = $2, offset_account = $3, account = $4, date = $5, description = $6 WHERE id = $7" , transaction . Amount , transaction . Debit , transaction . OffsetAccount , transaction . Account , transaction . Date , transaction . Description , transaction . ID )
2024-12-20 13:28:54 +00:00
if err != nil {
return err
}
return nil
2024-12-20 00:52:27 +00:00
}
2024-12-20 13:28:54 +00:00
func DeleteTransaction ( database * sql . DB , id int ) error {
2024-12-25 22:54:14 +00:00
exists , err := existTransaction ( database , id )
if err != nil {
return err
}
if ! exists {
return errors . New ( "transaction already exists" )
}
_ , err = database . Exec ( "DELETE FROM transactions WHERE id = $1" , id )
2024-12-20 13:28:54 +00:00
if err != nil {
return err
}
return nil
2024-12-20 00:52:27 +00:00
}
2024-12-20 13:28:54 +00:00
func GetTransaction ( database * sql . DB , id int ) ( Transaction , error ) {
var transaction Transaction
2024-12-26 15:08:43 +00:00
err := database . QueryRow ( "SELECT id, amount, debit, offset_account, account, date, description FROM transactions WHERE id = $1" , id ) . Scan ( & transaction . ID , & transaction . Amount , & transaction . Debit , & transaction . OffsetAccount , & transaction . Account , & transaction . Date , & transaction . Description )
2024-12-20 13:28:54 +00:00
if err != nil {
return transaction , err
}
return transaction , nil
}
func GetTransactions ( database * sql . DB , account int , year int , month int ) ( [ ] Transaction , error ) {
var transactions [ ] Transaction
var row * sql . Rows
var err error
if year == 0 {
return nil , errors . New ( "year is required" )
}
if month == 0 {
2024-12-26 15:08:43 +00:00
row , err = database . Query ( "SELECT id, amount, debit, offset_account, account, date, description FROM transactions WHERE (account = $1 OR offset_account = $1) AND EXTRACT(YEAR FROM date) = $2" , account , year )
2024-12-20 13:28:54 +00:00
} else {
2024-12-26 15:08:43 +00:00
row , err = database . Query ( "SELECT id, amount, debit, offset_account, account, date, description FROM transactions WHERE (account = $1 OR offset_account = $1) AND EXTRACT(YEAR FROM date) = $2 AND EXTRACT(MONTH FROM date) = $3" , account , year , month )
2024-12-20 13:28:54 +00:00
}
if err != nil {
return nil , err
}
defer row . Close ( )
for row . Next ( ) {
var transaction Transaction
2024-12-25 15:40:56 +00:00
err := row . Scan ( & transaction . ID , & transaction . Amount , & transaction . Debit , & transaction . OffsetAccount , & transaction . Account , & transaction . Date , & transaction . Description )
2024-12-20 13:28:54 +00:00
if err != nil {
return nil , err
}
transactions = append ( transactions , transaction )
}
return transactions , nil
2024-12-20 00:52:27 +00:00
}
2024-12-20 13:28:54 +00:00
func NewUser ( database * sql . DB , user User ) error {
_ , err := database . Exec ( "INSERT INTO users (name, password) VALUES ($1, $2)" , user . Name , user . Password )
if err != nil {
return err
}
return nil
2024-12-20 00:52:27 +00:00
}
2024-12-20 13:28:54 +00:00
func UpdateUser ( database * sql . DB , user User ) error {
_ , err := database . Exec ( "UPDATE users SET name = $1, password = $2 WHERE id = $3" , user . Name , user . Password , user . ID )
if err != nil {
return err
}
return nil
2024-12-20 00:52:27 +00:00
}
2024-12-26 15:08:43 +00:00
func DeleteUser ( database * sql . DB , id string ) error {
2024-12-20 13:28:54 +00:00
_ , err := database . Exec ( "DELETE FROM users WHERE id = $1" , id )
if err != nil {
return err
}
return nil
}
2024-12-20 00:52:27 +00:00
2024-12-26 15:08:43 +00:00
func GetUser ( database * sql . DB , id string ) ( User , error ) {
2024-12-20 13:28:54 +00:00
var user User
err := database . QueryRow ( "SELECT * FROM users WHERE id = $1" , id ) . Scan ( & user . ID , & user . Name , & user . Password )
if err != nil {
return user , err
}
return user , nil
2024-12-20 00:52:27 +00:00
}
2024-12-20 14:19:33 +00:00
func GetUserByName ( database * sql . DB , name string ) ( User , error ) {
var user User
err := database . QueryRow ( "SELECT * FROM users WHERE name = $1" , name ) . Scan ( & user . ID , & user . Name , & user . Password )
if err != nil {
return user , err
}
return user , nil
}
2024-12-26 15:08:43 +00:00
func AuthenticateUser ( database * sql . DB , name string , password string ) ( User , error ) {
2024-12-20 13:28:54 +00:00
var user User
err := database . QueryRow ( "SELECT * FROM users WHERE name = $1 AND password = $2" , name , password ) . Scan ( & user . ID , & user . Name , & user . Password )
if err != nil {
return user , err
}
return user , nil
2024-12-20 00:52:27 +00:00
}