db: finish sql commands
All checks were successful
Build and test / Build (push) Successful in 2m23s

This commit is contained in:
Muyao CHEN
2024-10-19 17:08:05 +02:00
parent dac36db284
commit 3d616bff50
10 changed files with 493 additions and 44 deletions

View File

@ -0,0 +1,72 @@
-- name: InsertExpense :one
INSERT INTO "expense" (
created_at, updated_at, amount, currency, event_id, name, place
) VALUES ( $1, $2, $3, $4, $5, $6, $7 )
RETURNING *;
-- name: DeleteExpense :exec
DELETE FROM "expense" WHERE id = $1;
-- name: DeleteTransactionsOfExpenseID :exec
DELETE FROM "transaction" WHERE transaction.expense_id = $1;
-- name: UpdateExpenseByID :one
UPDATE "expense"
SET updated_at = $2, amount = $3, currency = $4, name = $5, place = $6
WHERE id = $1
RETURNING *;
-- name: ListExpensesByEventID :many
SELECT
ex.id, ex.created_at, ex.updated_at, ex.amount, ex.currency, ex.event_id,
ex.name, ex.place
FROM "expense" ex
JOIN "event" ev ON ev.id = ex.event_id
WHERE ev.id = $1;
-- name: ListExpensesByEventIDByUserID :many
SELECT
ex.id, ex.created_at, ex.updated_at, ex.amount, ex.currency, ex.event_id,
ex.name, ex.place
FROM "expense" ex
JOIN "event" ev ON ev.id = ex.event_id
WHERE ev.id = $1;
-- name: GetExpenseByID :one
WITH payer_transaction as (
SELECT pt.expense_id,
json_agg(json_build_object(
'payer_id', p.id,
'payer_first_name', p.first_name,
'payer_last_name', p.last_name,
'amount', pt.amount,
'currency', pt.currency
)) AS payments
FROM "transaction" pt
JOIN "user" p ON p.id = pt.user_id
WHERE pt.is_income = FALSE
GROUP BY pt.expense_id
), -- For each expense, aggregate payment info
recipient_transaction as (
SELECT rt.expense_id,
json_agg(json_build_object(
'recipient_id', p.id,
'recipient_first_name', p.first_name,
'recipient_last_name', p.last_name,
'amount', rt.amount,
'currency', rt.currency
)) AS benefits
FROM "transaction" rt
JOIN "user" p ON p.id = rt.user_id
WHERE rt.is_income = TRUE
GROUP BY rt.expense_id
) -- For each expense, aggregate benefits info
SELECT
ex.id, ex.created_at, ex.updated_at, ex.amount, ex.currency, ex.event_id,
ex.name, ex.place,
COALESCE(pt.payments, '[]') AS payments,
COALESCE(rt.benefits, '[]') AS benefits
FROM "expense" ex
LEFT JOIN "payer_transaction" pt ON pt.expense_id = ex.id
LEFT JOIN "recipient_transaction" rt ON rt.expense_id = ex.id
WHERE ex.id = $1;

View File

@ -0,0 +1,264 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.27.0
// source: expense.sql
package sqlc
import (
"context"
"database/sql"
"encoding/json"
"time"
)
const deleteExpense = `-- name: DeleteExpense :exec
DELETE FROM "expense" WHERE id = $1
`
func (q *Queries) DeleteExpense(ctx context.Context, id int32) error {
_, err := q.db.ExecContext(ctx, deleteExpense, id)
return err
}
const deleteTransactionsOfExpenseID = `-- name: DeleteTransactionsOfExpenseID :exec
DELETE FROM "transaction" WHERE transaction.expense_id = $1
`
func (q *Queries) DeleteTransactionsOfExpenseID(ctx context.Context, expenseID int32) error {
_, err := q.db.ExecContext(ctx, deleteTransactionsOfExpenseID, expenseID)
return err
}
const getExpenseByID = `-- name: GetExpenseByID :one
WITH payer_transaction as (
SELECT pt.expense_id,
json_agg(json_build_object(
'payer_id', p.id,
'payer_first_name', p.first_name,
'payer_last_name', p.last_name,
'amount', pt.amount,
'currency', pt.currency
)) AS payments
FROM "transaction" pt
JOIN "user" p ON p.id = pt.user_id
WHERE pt.is_income = FALSE
GROUP BY pt.expense_id
), -- For each expense, aggregate payment info
recipient_transaction as (
SELECT rt.expense_id,
json_agg(json_build_object(
'recipient_id', p.id,
'recipient_first_name', p.first_name,
'recipient_last_name', p.last_name,
'amount', rt.amount,
'currency', rt.currency
)) AS benefits
FROM "transaction" rt
JOIN "user" p ON p.id = rt.user_id
WHERE rt.is_income = TRUE
GROUP BY rt.expense_id
) -- For each expense, aggregate benefits info
SELECT
ex.id, ex.created_at, ex.updated_at, ex.amount, ex.currency, ex.event_id,
ex.name, ex.place,
COALESCE(pt.payments, '[]') AS payments,
COALESCE(rt.benefits, '[]') AS benefits
FROM "expense" ex
LEFT JOIN "payer_transaction" pt ON pt.expense_id = ex.id
LEFT JOIN "recipient_transaction" rt ON rt.expense_id = ex.id
WHERE ex.id = $1
`
type GetExpenseByIDRow struct {
ID int32
CreatedAt time.Time
UpdatedAt time.Time
Amount int32
Currency string
EventID int32
Name sql.NullString
Place sql.NullString
Payments json.RawMessage
Benefits json.RawMessage
}
func (q *Queries) GetExpenseByID(ctx context.Context, id int32) (GetExpenseByIDRow, error) {
row := q.db.QueryRowContext(ctx, getExpenseByID, id)
var i GetExpenseByIDRow
err := row.Scan(
&i.ID,
&i.CreatedAt,
&i.UpdatedAt,
&i.Amount,
&i.Currency,
&i.EventID,
&i.Name,
&i.Place,
&i.Payments,
&i.Benefits,
)
return i, err
}
const insertExpense = `-- name: InsertExpense :one
INSERT INTO "expense" (
created_at, updated_at, amount, currency, event_id, name, place
) VALUES ( $1, $2, $3, $4, $5, $6, $7 )
RETURNING id, created_at, updated_at, amount, currency, event_id, name, place
`
type InsertExpenseParams struct {
CreatedAt time.Time
UpdatedAt time.Time
Amount int32
Currency string
EventID int32
Name sql.NullString
Place sql.NullString
}
func (q *Queries) InsertExpense(ctx context.Context, arg InsertExpenseParams) (Expense, error) {
row := q.db.QueryRowContext(ctx, insertExpense,
arg.CreatedAt,
arg.UpdatedAt,
arg.Amount,
arg.Currency,
arg.EventID,
arg.Name,
arg.Place,
)
var i Expense
err := row.Scan(
&i.ID,
&i.CreatedAt,
&i.UpdatedAt,
&i.Amount,
&i.Currency,
&i.EventID,
&i.Name,
&i.Place,
)
return i, err
}
const listExpensesByEventID = `-- name: ListExpensesByEventID :many
SELECT
ex.id, ex.created_at, ex.updated_at, ex.amount, ex.currency, ex.event_id,
ex.name, ex.place
FROM "expense" ex
JOIN "event" ev ON ev.id = ex.event_id
WHERE ev.id = $1
`
func (q *Queries) ListExpensesByEventID(ctx context.Context, id int32) ([]Expense, error) {
rows, err := q.db.QueryContext(ctx, listExpensesByEventID, id)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Expense
for rows.Next() {
var i Expense
if err := rows.Scan(
&i.ID,
&i.CreatedAt,
&i.UpdatedAt,
&i.Amount,
&i.Currency,
&i.EventID,
&i.Name,
&i.Place,
); 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 listExpensesByEventIDByUserID = `-- name: ListExpensesByEventIDByUserID :many
SELECT
ex.id, ex.created_at, ex.updated_at, ex.amount, ex.currency, ex.event_id,
ex.name, ex.place
FROM "expense" ex
JOIN "event" ev ON ev.id = ex.event_id
WHERE ev.id = $1
`
func (q *Queries) ListExpensesByEventIDByUserID(ctx context.Context, id int32) ([]Expense, error) {
rows, err := q.db.QueryContext(ctx, listExpensesByEventIDByUserID, id)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Expense
for rows.Next() {
var i Expense
if err := rows.Scan(
&i.ID,
&i.CreatedAt,
&i.UpdatedAt,
&i.Amount,
&i.Currency,
&i.EventID,
&i.Name,
&i.Place,
); 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 updateExpenseByID = `-- name: UpdateExpenseByID :one
UPDATE "expense"
SET updated_at = $2, amount = $3, currency = $4, name = $5, place = $6
WHERE id = $1
RETURNING id, created_at, updated_at, amount, currency, event_id, name, place
`
type UpdateExpenseByIDParams struct {
ID int32
UpdatedAt time.Time
Amount int32
Currency string
Name sql.NullString
Place sql.NullString
}
func (q *Queries) UpdateExpenseByID(ctx context.Context, arg UpdateExpenseByIDParams) (Expense, error) {
row := q.db.QueryRowContext(ctx, updateExpenseByID,
arg.ID,
arg.UpdatedAt,
arg.Amount,
arg.Currency,
arg.Name,
arg.Place,
)
var i Expense
err := row.Scan(
&i.ID,
&i.CreatedAt,
&i.UpdatedAt,
&i.Amount,
&i.Currency,
&i.EventID,
&i.Name,
&i.Place,
)
return i, err
}

View File

@ -34,8 +34,8 @@ type Expense struct {
Amount int32
Currency string
EventID int32
Name sql.NullInt32
Place sql.NullInt32
Name sql.NullString
Place sql.NullString
}
type Participation struct {

View File

@ -0,0 +1,5 @@
-- name: InsertTransaction :exec
INSERT INTO "transaction" (
created_at, updated_at, amount, currency, expense_id, user_id, is_income
) VALUES ( $1, $2, $3, $4, $5, $6, $7 )
RETURNING *;

View File

@ -0,0 +1,41 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.27.0
// source: transaction.sql
package sqlc
import (
"context"
"time"
)
const insertTransaction = `-- name: InsertTransaction :exec
INSERT INTO "transaction" (
created_at, updated_at, amount, currency, expense_id, user_id, is_income
) VALUES ( $1, $2, $3, $4, $5, $6, $7 )
RETURNING id, expense_id, user_id, amount, currency, is_income, created_at, updated_at
`
type InsertTransactionParams struct {
CreatedAt time.Time
UpdatedAt time.Time
Amount int32
Currency string
ExpenseID int32
UserID int32
IsIncome bool
}
func (q *Queries) InsertTransaction(ctx context.Context, arg InsertTransactionParams) error {
_, err := q.db.ExecContext(ctx, insertTransaction,
arg.CreatedAt,
arg.UpdatedAt,
arg.Amount,
arg.Currency,
arg.ExpenseID,
arg.UserID,
arg.IsIncome,
)
return err
}

View File

@ -24,14 +24,38 @@ package model
import "time"
// {{{ Requrest
type ExpenseRequest struct {
Amount Money `json:"money" binding:"required,number"`
PayerIDs []int `json:"payer_ids" binding:"required"`
RecipientIDs []int `json:"recipient_ids" binding:"required"`
EventID int `json:"event_id" binding:"required"`
Detail ExpenseDetail `json:"detail"`
Amount Money `json:"money" binding:"required"`
Payments []Payment `json:"payments" binding:"required"`
Benefits []Benefit `json:"benefits" binding:"required"`
EventID int `json:"event_id" binding:"required"`
Detail ExpenseDetail `json:"detail"`
}
// }}}
// {{{ Response
type ExpensesListResponse struct {
ID int `json:"id"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
Amount Money `json:"money"`
EventID int `json:"event_id"`
Detail ExpenseDetail `json:"detail"`
}
type ExpenseGetResponse Expense
// }}}
// {{{ Retrieved
type ExpensesListRetrieved ExpensesListResponse
// }}}
// {{{ Entity
type ExpenseEntity struct {
@ -48,25 +72,40 @@ type ExpenseEntity struct {
Place string
}
// }}}
// {{{ Domain Models
type ExpenseDetail struct {
Name string `json:"name"`
Place string `json:"place"`
}
// }}}
type Expense struct {
ID int
CreatedAt time.Time
UpdatedAt time.Time
Amount Money
// Lazy aggregate using Transaction join
PayerIDs []int
// Lazy aggregate using Transaction join
RecipientIDs []int
EventID int
Detail ExpenseDetail
type Payment struct {
PayerID int `json:"payer_id" binding:"required,number"`
PayerFirstName string `json:"payer_first_name"`
PayerLastName string `json:"payer_last_name"`
Amount Money `json:"amount" binding:"required"`
}
type Benefit struct {
RecipientID int `json:"recipient_id" binding:"required,number"`
RecipientFirstName string `json:"recipient_first_name"`
RecipientLastName string `json:"recipient_last_name"`
Amount Money `json:"amount" binding:"required"`
}
type Expense struct {
ID int `json:"id"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
Amount Money `json:"money"`
EventID int `json:"event_id"`
Detail ExpenseDetail `json:"detail"`
Payments []Payment `json:"payments"`
Benefits []Benefit `json:"benefits"`
}
// }}}