diff --git a/.gitignore b/.gitignore index f66f36f..bd0122e 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ # Output of the go coverage tool, specifically when used with LiteIDE *.out +coverage.html # Dependency directories (remove the comment below to include it) # vendor/ diff --git a/Makefile b/Makefile index 14b79e3..ff03289 100644 --- a/Makefile +++ b/Makefile @@ -24,4 +24,13 @@ dropdb: sqlc: sqlc generate -.PHONY: postgres migratenew createdb dropdb migrateup migratedown sqlc \ No newline at end of file +sqlcinit: + sqlc init + +test: + go test -v -coverage -short -count=1 ./... + +coverage: + go test -coverprofile=coverage.out ./... && go tool cover -html=coverage.out + +.PHONY: postgres migratenew createdb dropdb migrateup migratedown sqlc sqlcinit test \ No newline at end of file diff --git a/db/query/customer.sql b/db/query/customer.sql new file mode 100644 index 0000000..42aa923 --- /dev/null +++ b/db/query/customer.sql @@ -0,0 +1,51 @@ +-- name: GetCustomer :one +SELECT * FROM customers +WHERE "ID" = $1 LIMIT 1; + +-- name: CreateCutomer :one +INSERT INTO customers ( + username, + passwordhash, + firstname, + lastname, + birthday, + email, + phone, + city, + zip, + street, + country, + creator, + changer +) VALUES ( + $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13 +) RETURNING *; + +-- name: ListCustomers :many +SELECT * FROM customers +ORDER BY username +LIMIT $1 +OFFSET $2; + +-- name: UpdateCustomer :one +UPDATE customers +SET + username = COALESCE(sqlc.narg(username), username), + passwordhash = COALESCE(sqlc.narg(passwordhash), passwordhash), + firstname = COALESCE(sqlc.narg(firstname), firstname), + lastname = COALESCE(sqlc.narg(lastname), lastname), + birthday = COALESCE(sqlc.narg(birthday), birthday), + email = COALESCE(sqlc.narg(email), email), + phone = COALESCE(sqlc.narg(phone), phone), + city = COALESCE(sqlc.narg(city), city), + zip = COALESCE(sqlc.narg(zip), zip), + street = COALESCE(sqlc.narg(street), street), + country = COALESCE(sqlc.narg(country), country), + changer = $2, + changed = now() +WHERE "ID" = $1 +RETURNING *; + +-- name: DeleteCustomer :exec +DELETE FROM customers +WHERE "ID" = $1; \ No newline at end of file diff --git a/db/sqlc/customer.sql.go b/db/sqlc/customer.sql.go new file mode 100644 index 0000000..268d211 --- /dev/null +++ b/db/sqlc/customer.sql.go @@ -0,0 +1,271 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.21.0 +// source: customer.sql + +package db + +import ( + "context" + "database/sql" + "time" +) + +const createCutomer = `-- name: CreateCutomer :one +INSERT INTO customers ( + username, + passwordhash, + firstname, + lastname, + birthday, + email, + phone, + city, + zip, + street, + country, + creator, + changer +) VALUES ( + $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13 +) RETURNING "ID", username, passwordhash, firstname, lastname, birthday, "privacyAccepted", "privacyAcceptedDate", email, phone, city, zip, street, country, token, "tokenValid", "tokenExpiration", creator, created, changer, changed +` + +type CreateCutomerParams struct { + Username string `json:"username"` + Passwordhash string `json:"passwordhash"` + Firstname string `json:"firstname"` + Lastname string `json:"lastname"` + Birthday time.Time `json:"birthday"` + Email string `json:"email"` + Phone sql.NullString `json:"phone"` + City string `json:"city"` + Zip string `json:"zip"` + Street string `json:"street"` + Country string `json:"country"` + Creator string `json:"creator"` + Changer string `json:"changer"` +} + +func (q *Queries) CreateCutomer(ctx context.Context, arg CreateCutomerParams) (Customer, error) { + row := q.db.QueryRowContext(ctx, createCutomer, + arg.Username, + arg.Passwordhash, + arg.Firstname, + arg.Lastname, + arg.Birthday, + arg.Email, + arg.Phone, + arg.City, + arg.Zip, + arg.Street, + arg.Country, + arg.Creator, + arg.Changer, + ) + var i Customer + err := row.Scan( + &i.ID, + &i.Username, + &i.Passwordhash, + &i.Firstname, + &i.Lastname, + &i.Birthday, + &i.PrivacyAccepted, + &i.PrivacyAcceptedDate, + &i.Email, + &i.Phone, + &i.City, + &i.Zip, + &i.Street, + &i.Country, + &i.Token, + &i.TokenValid, + &i.TokenExpiration, + &i.Creator, + &i.Created, + &i.Changer, + &i.Changed, + ) + return i, err +} + +const deleteCustomer = `-- name: DeleteCustomer :exec +DELETE FROM customers +WHERE "ID" = $1 +` + +func (q *Queries) DeleteCustomer(ctx context.Context, id int64) error { + _, err := q.db.ExecContext(ctx, deleteCustomer, id) + return err +} + +const getCustomer = `-- name: GetCustomer :one +SELECT "ID", username, passwordhash, firstname, lastname, birthday, "privacyAccepted", "privacyAcceptedDate", email, phone, city, zip, street, country, token, "tokenValid", "tokenExpiration", creator, created, changer, changed FROM customers +WHERE "ID" = $1 LIMIT 1 +` + +func (q *Queries) GetCustomer(ctx context.Context, id int64) (Customer, error) { + row := q.db.QueryRowContext(ctx, getCustomer, id) + var i Customer + err := row.Scan( + &i.ID, + &i.Username, + &i.Passwordhash, + &i.Firstname, + &i.Lastname, + &i.Birthday, + &i.PrivacyAccepted, + &i.PrivacyAcceptedDate, + &i.Email, + &i.Phone, + &i.City, + &i.Zip, + &i.Street, + &i.Country, + &i.Token, + &i.TokenValid, + &i.TokenExpiration, + &i.Creator, + &i.Created, + &i.Changer, + &i.Changed, + ) + return i, err +} + +const listCustomers = `-- name: ListCustomers :many +SELECT "ID", username, passwordhash, firstname, lastname, birthday, "privacyAccepted", "privacyAcceptedDate", email, phone, city, zip, street, country, token, "tokenValid", "tokenExpiration", creator, created, changer, changed FROM customers +ORDER BY username +LIMIT $1 +OFFSET $2 +` + +type ListCustomersParams struct { + Limit int32 `json:"limit"` + Offset int32 `json:"offset"` +} + +func (q *Queries) ListCustomers(ctx context.Context, arg ListCustomersParams) ([]Customer, error) { + rows, err := q.db.QueryContext(ctx, listCustomers, arg.Limit, arg.Offset) + if err != nil { + return nil, err + } + defer rows.Close() + items := []Customer{} + for rows.Next() { + var i Customer + if err := rows.Scan( + &i.ID, + &i.Username, + &i.Passwordhash, + &i.Firstname, + &i.Lastname, + &i.Birthday, + &i.PrivacyAccepted, + &i.PrivacyAcceptedDate, + &i.Email, + &i.Phone, + &i.City, + &i.Zip, + &i.Street, + &i.Country, + &i.Token, + &i.TokenValid, + &i.TokenExpiration, + &i.Creator, + &i.Created, + &i.Changer, + &i.Changed, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const updateCustomer = `-- name: UpdateCustomer :one +UPDATE customers +SET + username = COALESCE($3, username), + passwordhash = COALESCE($4, passwordhash), + firstname = COALESCE($5, firstname), + lastname = COALESCE($6, lastname), + birthday = COALESCE($7, birthday), + email = COALESCE($8, email), + phone = COALESCE($9, phone), + city = COALESCE($10, city), + zip = COALESCE($11, zip), + street = COALESCE($12, street), + country = COALESCE($13, country), + changer = $2, + changed = now() +WHERE "ID" = $1 +RETURNING "ID", username, passwordhash, firstname, lastname, birthday, "privacyAccepted", "privacyAcceptedDate", email, phone, city, zip, street, country, token, "tokenValid", "tokenExpiration", creator, created, changer, changed +` + +type UpdateCustomerParams struct { + ID int64 `json:"ID"` + Changer string `json:"changer"` + Username sql.NullString `json:"username"` + Passwordhash sql.NullString `json:"passwordhash"` + Firstname sql.NullString `json:"firstname"` + Lastname sql.NullString `json:"lastname"` + Birthday sql.NullTime `json:"birthday"` + Email sql.NullString `json:"email"` + Phone sql.NullString `json:"phone"` + City sql.NullString `json:"city"` + Zip sql.NullString `json:"zip"` + Street sql.NullString `json:"street"` + Country sql.NullString `json:"country"` +} + +func (q *Queries) UpdateCustomer(ctx context.Context, arg UpdateCustomerParams) (Customer, error) { + row := q.db.QueryRowContext(ctx, updateCustomer, + arg.ID, + arg.Changer, + arg.Username, + arg.Passwordhash, + arg.Firstname, + arg.Lastname, + arg.Birthday, + arg.Email, + arg.Phone, + arg.City, + arg.Zip, + arg.Street, + arg.Country, + ) + var i Customer + err := row.Scan( + &i.ID, + &i.Username, + &i.Passwordhash, + &i.Firstname, + &i.Lastname, + &i.Birthday, + &i.PrivacyAccepted, + &i.PrivacyAcceptedDate, + &i.Email, + &i.Phone, + &i.City, + &i.Zip, + &i.Street, + &i.Country, + &i.Token, + &i.TokenValid, + &i.TokenExpiration, + &i.Creator, + &i.Created, + &i.Changer, + &i.Changed, + ) + return i, err +} diff --git a/db/sqlc/customer_test.go b/db/sqlc/customer_test.go new file mode 100644 index 0000000..81464c2 --- /dev/null +++ b/db/sqlc/customer_test.go @@ -0,0 +1,52 @@ +package db + +import ( + "context" + "database/sql" + "testing" + "time" + + "github.com/stretchr/testify/require" +) + +func TestCreateCustomer(t *testing.T) { + arg := CreateCutomerParams{ + Username: "whoami123", + Passwordhash: "abcdefghijklmnopqrstuvwxyz123456789", + Firstname: "John", + Lastname: "Doe", + Birthday: time.Date(1990, 1, 1, 0, 0, 0, 0, time.UTC), + Email: "john.doe@example.com", + Phone: sql.NullString{ + Valid: true, + String: "0123456789", + }, + City: "New York", + Zip: "12345", + Street: "Main Street 1", + Country: "United States", + Creator: "user", + } + + account, err := testQueries.CreateCutomer(context.Background(), arg) + require.NoError(t, err) + require.NotEmpty(t, account) + + require.Equal(t, arg.Username, account.Username) + require.Equal(t, arg.Passwordhash, account.Passwordhash) + require.Equal(t, arg.Firstname, account.Firstname) + require.Equal(t, arg.Lastname, account.Lastname) + require.Equal(t, arg.Birthday, account.Birthday) + require.Equal(t, arg.Email, account.Email) + require.Equal(t, arg.Phone, account.Phone) + require.Equal(t, arg.City, account.City) + require.Equal(t, arg.Zip, account.Zip) + require.Equal(t, arg.Street, account.Street) + require.Equal(t, arg.Country, account.Country) + require.Equal(t, arg.Creator, account.Creator) + + require.NotZero(t, account.ID) + require.NotZero(t, account.Created) + + _ = testQueries.DeleteCustomer(context.Background(), account.ID) +} diff --git a/db/sqlc/db.go b/db/sqlc/db.go new file mode 100644 index 0000000..46fda54 --- /dev/null +++ b/db/sqlc/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.21.0 + +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...interface{}) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...interface{}) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/db/sqlc/main_test.go b/db/sqlc/main_test.go new file mode 100644 index 0000000..3cd255c --- /dev/null +++ b/db/sqlc/main_test.go @@ -0,0 +1,28 @@ +package db + +import ( + "database/sql" + "log" + "os" + "testing" + + _ "github.com/lib/pq" +) + +var testQueries *Queries + +const ( + dbDriver = "postgres" + dbSource = "postgresql://root:secret@localhost:5432/df?sslmode=disable" +) + +func TestMain(m *testing.M) { + conn, err := sql.Open(dbDriver, dbSource) + if err != nil { + log.Fatalf("could not connect to DB: %s", err) + } + + testQueries = New(conn) + + os.Exit(m.Run()) +} diff --git a/db/sqlc/models.go b/db/sqlc/models.go new file mode 100644 index 0000000..28e885d --- /dev/null +++ b/db/sqlc/models.go @@ -0,0 +1,128 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.21.0 + +package db + +import ( + "database/sql" + "time" +) + +type Customer struct { + ID int64 `json:"ID"` + Username string `json:"username"` + Passwordhash string `json:"passwordhash"` + Firstname string `json:"firstname"` + Lastname string `json:"lastname"` + Birthday time.Time `json:"birthday"` + PrivacyAccepted bool `json:"privacyAccepted"` + PrivacyAcceptedDate sql.NullTime `json:"privacyAcceptedDate"` + Email string `json:"email"` + Phone sql.NullString `json:"phone"` + City string `json:"city"` + Zip string `json:"zip"` + Street string `json:"street"` + Country string `json:"country"` + Token sql.NullString `json:"token"` + TokenValid sql.NullBool `json:"tokenValid"` + TokenExpiration time.Time `json:"tokenExpiration"` + Creator string `json:"creator"` + Created time.Time `json:"created"` + Changer string `json:"changer"` + Changed time.Time `json:"changed"` +} + +type Document struct { + ID int64 `json:"ID"` + PersonID sql.NullInt64 `json:"personID"` + Name string `json:"name"` + Type string `json:"type"` + Path string `json:"path"` + Url string `json:"url"` + Valid bool `json:"valid"` + ValidDate sql.NullTime `json:"validDate"` + ValidatedBy sql.NullString `json:"validatedBy"` +} + +type Mail struct { + ID int64 `json:"ID"` + From string `json:"from"` + To string `json:"to"` + Cc sql.NullString `json:"cc"` + Timestamp time.Time `json:"timestamp"` + Subject string `json:"subject"` + Body string `json:"body"` + Attachments sql.NullInt32 `json:"attachments"` +} + +type Payment struct { + ID int64 `json:"ID"` + CustomerID int64 `json:"customerID"` + PaymentCategory string `json:"paymentCategory"` + Bankname sql.NullString `json:"bankname"` + IBAN sql.NullString `json:"IBAN"` + BIC sql.NullString `json:"BIC"` + PaypalAccount sql.NullString `json:"paypalAccount"` + PaypalID sql.NullString `json:"paypalID"` + PaymentSystem sql.NullString `json:"paymentSystem"` + Type string `json:"type"` + Creator string `json:"creator"` + Created time.Time `json:"created"` + Changer string `json:"changer"` + Changed time.Time `json:"changed"` +} + +type Person struct { + ID int64 `json:"ID"` + CustomerID sql.NullInt64 `json:"customerID"` + Firstname string `json:"firstname"` + Lastname string `json:"lastname"` + Birthday time.Time `json:"birthday"` + City string `json:"city"` + Zip string `json:"zip"` + Street string `json:"street"` + Country string `json:"country"` + Creator string `json:"creator"` + Created time.Time `json:"created"` + Changer string `json:"changer"` + Changed time.Time `json:"changed"` +} + +type Provider struct { + ID int64 `json:"ID"` + Name string `json:"name"` + Description string `json:"description"` + Category string `json:"category"` + Email string `json:"email"` + Creator string `json:"creator"` + Created time.Time `json:"created"` + Changer string `json:"changer"` + Changed time.Time `json:"changed"` +} + +type Return struct { + ID int64 `json:"ID"` + PersonID int64 `json:"personID"` + ProviderID int64 `json:"providerID"` + Name string `json:"name"` + Description string `json:"description"` + Category string `json:"category"` + Email string `json:"email"` + Status string `json:"status"` + Creator string `json:"creator"` + Created time.Time `json:"created"` + Changer string `json:"changer"` + Changed time.Time `json:"changed"` +} + +type ReturnsLog struct { + ID int64 `json:"ID"` + ReturnsID sql.NullInt64 `json:"returnsID"` + MailID sql.NullInt64 `json:"mailID"` + Status sql.NullString `json:"status"` + Creator string `json:"creator"` + Created time.Time `json:"created"` + Changer string `json:"changer"` + Changed time.Time `json:"changed"` +} diff --git a/go.mod b/go.mod index 4e3b254..8db1657 100644 --- a/go.mod +++ b/go.mod @@ -3,3 +3,14 @@ module github.com/itsscb/df go 1.21 toolchain go1.21.1 + +require ( + github.com/lib/pq v1.10.9 + github.com/stretchr/testify v1.8.4 +) + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum index e69de29..f3c7ba2 100644 --- a/go.sum +++ b/go.sum @@ -0,0 +1,12 @@ +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/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/sqlc.yaml b/sqlc.yaml new file mode 100644 index 0000000..37f62fe --- /dev/null +++ b/sqlc.yaml @@ -0,0 +1,19 @@ +version: "2" +sql: + - schema: "db/migration" + queries: "db/query" + engine: "postgresql" + gen: + go: + package: "db" + out: "db/sqlc" + sql_package: "lib/pq" + emit_json_tags: true + emit_interface: false + emit_empty_slices: true + emit_exact_table_names: false + overrides: + - db_type: "timestamptz" + go_type: "time.Time" + - db_type: "uuid" + go_type: "github.com/google/uuid.UUID"