Compare commits

...

3 Commits

Author SHA1 Message Date
Muyao CHEN
dde4eb337c repo: add some sql for events
All checks were successful
Build and test / Build (push) Successful in 2m29s
2024-10-18 21:15:27 +02:00
Muyao CHEN
39eaae46d8 db: add migrations 2024-10-18 19:36:31 +02:00
Muyao CHEN
86832cf1f9 test: add wrong params test cases for session create 2024-10-17 22:12:31 +02:00
14 changed files with 363 additions and 2 deletions

View File

@ -421,7 +421,7 @@ The following basic use cases are to be implemented at the first time.
- [X] A user signs up
- [X] A user logs in
- [] A user lists their events (pagination)
- [X] A user lists their events (pagination)
- [] A user sees the detail of an event (description, members, amount)
- [] A user sees the expenses of an event (total amount, personal expenses, pagination)
- [] A user sees the detail of an expense: (time, amount, payers, recipients)
@ -430,7 +430,7 @@ The following basic use cases are to be implemented at the first time.
- [] A user deletes an expense (may handle some extra access control)
- [] A user restore a deleted expense
- [] A user can pay the debt to other members
- [X] A user creates an event
- [X] A user creates an event (and participate to it)
- [] A user updates the event info
- [] A user invites another user by sending a mail with a token.
- [] A user joins an event by accepting an invitation
@ -449,3 +449,40 @@ work on other aspects. For example:
- ex. Trip journal...
Stop dreaming... Just do the simple stuff first!
### 2024/10/18
I spent some time to figure out this one! But I don't actually need it for now.
So I just keep it here:
```SQL
SELECT
e.id,
e.name,
e.description,
e.created_at,
json_build_object(
'id', o.id,
'first_name', o.first_name,
'last_name', o.last_name
) AS owner,
json_agg(
json_build_object(
'id', u.id,
'first_name', u.first_name,
'last_name', u.last_name
)
) AS users -- Aggregation for users in the event
FROM "event" e
JOIN "participation" p ON p.event_id = e.id -- participation linked with the event
JOIN "user" u ON u.id = p.user_id -- and the query user
JOIN "user" o ON o.id = e.owner_id -- get the owner info
WHERE e.id IN (
SELECT pt.event_id FROM participation pt WHERE pt.user_id = $1
-- consider the events participated by user_id
)
GROUP BY
e.id, e.name, e.description, e.created_at,
o.id, o.first_name, o.last_name;
```

View File

@ -85,6 +85,14 @@ func TestSessionCreate(t *testing.T) {
Email: "unregistered@error.com",
Password: "strong password",
}, usecase.UserNotExist},
{"wrong email", createParams{
Email: "error.com",
Password: "strong password",
}, UserParamsErr},
{"no passwrd", createParams{
Email: "no@error.com",
Password: "",
}, UserParamsErr},
}
token.Init("secret", 1*time.Second)

View File

@ -0,0 +1,58 @@
-- name: InsertEvent :one
INSERT INTO "event" (
name, description, total_amount, default_currency, owner_id, created_at, updated_at
) VALUES ( $1, $2, $3, $4, $5, $6, $7 )
RETURNING *;
-- name: ListEventsByUserID :many
SELECT
e.id,
e.name,
e.description,
e.created_at,
json_build_object(
'id', o.id,
'first_name', o.first_name,
'last_name', o.last_name
) AS owner
FROM "event" e
JOIN "participation" p ON p.event_id = e.id -- participation linked with the event
JOIN "user" o ON o.id = e.owner_id -- get the owner info
WHERE e.id IN (
SELECT pt.event_id FROM participation pt WHERE pt.user_id = $1 -- consider the events participated by user_id
)
GROUP BY
e.id, e.name, e.description, e.created_at,
o.id, o.first_name, o.last_name;
-- name: GetEventByID :one
SELECT
e.id,
e.name,
e.description,
e.total_amount,
e.default_currency,
e.created_at,
e.updated_at,
json_build_object(
'id', o.id,
'first_name', o.first_name,
'last_name', o.last_name
) AS owner,
json_agg(
json_build_object(
'id', u.id,
'first_name', u.first_name,
'last_name', u.last_name
)
) AS users -- Aggregation for users in the event
FROM "event" e
JOIN "participation" p ON p.event_id = e.id -- participation linked with the event
JOIN "user" u ON u.id = p.user_id -- and the query user
JOIN "user" o ON o.id = e.owner_id -- get the owner info
WHERE e.id = $1
GROUP BY
e.id, e.name, e.description, e.created_at, e.updated_at,
e.total_amount, e.default_currency,
o.id, o.first_name, o.last_name;

View File

@ -0,0 +1,174 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.27.0
// source: event.sql
package sqlc
import (
"context"
"database/sql"
"encoding/json"
"time"
)
const getEventByID = `-- name: GetEventByID :one
SELECT
e.id,
e.name,
e.description,
e.total_amount,
e.default_currency,
e.created_at,
e.updated_at,
json_build_object(
'id', o.id,
'first_name', o.first_name,
'last_name', o.last_name
) AS owner,
json_agg(
json_build_object(
'id', u.id,
'first_name', u.first_name,
'last_name', u.last_name
)
) AS users -- Aggregation for users in the event
FROM "event" e
JOIN "participation" p ON p.event_id = e.id -- participation linked with the event
JOIN "user" u ON u.id = p.user_id -- and the query user
JOIN "user" o ON o.id = e.owner_id -- get the owner info
WHERE e.id = $1
GROUP BY
e.id, e.name, e.description, e.created_at, e.updated_at,
e.total_amount, e.default_currency,
o.id, o.first_name, o.last_name
`
type GetEventByIDRow struct {
ID int32
Name string
Description sql.NullString
TotalAmount sql.NullInt32
DefaultCurrency string
CreatedAt time.Time
UpdatedAt time.Time
Owner json.RawMessage
Users json.RawMessage
}
func (q *Queries) GetEventByID(ctx context.Context, id int32) (GetEventByIDRow, error) {
row := q.db.QueryRowContext(ctx, getEventByID, id)
var i GetEventByIDRow
err := row.Scan(
&i.ID,
&i.Name,
&i.Description,
&i.TotalAmount,
&i.DefaultCurrency,
&i.CreatedAt,
&i.UpdatedAt,
&i.Owner,
&i.Users,
)
return i, err
}
const insertEvent = `-- name: InsertEvent :one
INSERT INTO "event" (
name, description, total_amount, default_currency, owner_id, created_at, updated_at
) VALUES ( $1, $2, $3, $4, $5, $6, $7 )
RETURNING id, name, description, default_currency, owner_id, created_at, updated_at, total_amount
`
type InsertEventParams struct {
Name string
Description sql.NullString
TotalAmount sql.NullInt32
DefaultCurrency string
OwnerID int32
CreatedAt time.Time
UpdatedAt time.Time
}
func (q *Queries) InsertEvent(ctx context.Context, arg InsertEventParams) (Event, error) {
row := q.db.QueryRowContext(ctx, insertEvent,
arg.Name,
arg.Description,
arg.TotalAmount,
arg.DefaultCurrency,
arg.OwnerID,
arg.CreatedAt,
arg.UpdatedAt,
)
var i Event
err := row.Scan(
&i.ID,
&i.Name,
&i.Description,
&i.DefaultCurrency,
&i.OwnerID,
&i.CreatedAt,
&i.UpdatedAt,
&i.TotalAmount,
)
return i, err
}
const listEventsByUserID = `-- name: ListEventsByUserID :many
SELECT
e.id,
e.name,
e.description,
e.created_at,
json_build_object(
'id', o.id,
'first_name', o.first_name,
'last_name', o.last_name
) AS owner
FROM "event" e
JOIN "participation" p ON p.event_id = e.id -- participation linked with the event
JOIN "user" o ON o.id = e.owner_id -- get the owner info
WHERE e.id IN (
SELECT pt.event_id FROM participation pt WHERE pt.user_id = $1 -- consider the events participated by user_id
)
GROUP BY
e.id, e.name, e.description, e.created_at,
o.id, o.first_name, o.last_name
`
type ListEventsByUserIDRow struct {
ID int32
Name string
Description sql.NullString
CreatedAt time.Time
Owner json.RawMessage
}
func (q *Queries) ListEventsByUserID(ctx context.Context, userID int32) ([]ListEventsByUserIDRow, error) {
rows, err := q.db.QueryContext(ctx, listEventsByUserID, userID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []ListEventsByUserIDRow
for rows.Next() {
var i ListEventsByUserIDRow
if err := rows.Scan(
&i.ID,
&i.Name,
&i.Description,
&i.CreatedAt,
&i.Owner,
); 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
}

View File

@ -0,0 +1,5 @@
-- name: InsertParticipation :one
INSERT INTO participation (
user_id, event_id, invited_by_user_id, created_at, updated_at
) VALUES ($1, $2, $3, $4, $5)
RETURNING *;

View File

@ -0,0 +1,47 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.27.0
// source: participation.sql
package sqlc
import (
"context"
"database/sql"
"time"
)
const insertParticipation = `-- name: InsertParticipation :one
INSERT INTO participation (
user_id, event_id, invited_by_user_id, created_at, updated_at
) VALUES ($1, $2, $3, $4, $5)
RETURNING id, user_id, event_id, invited_by_user_id, created_at, updated_at
`
type InsertParticipationParams struct {
UserID int32
EventID int32
InvitedByUserID sql.NullInt32
CreatedAt time.Time
UpdatedAt time.Time
}
func (q *Queries) InsertParticipation(ctx context.Context, arg InsertParticipationParams) (Participation, error) {
row := q.db.QueryRowContext(ctx, insertParticipation,
arg.UserID,
arg.EventID,
arg.InvitedByUserID,
arg.CreatedAt,
arg.UpdatedAt,
)
var i Participation
err := row.Scan(
&i.ID,
&i.UserID,
&i.EventID,
&i.InvitedByUserID,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}

View File

@ -0,0 +1 @@
DROP TABLE "event"

View File

@ -0,0 +1,10 @@
CREATE TABLE "event" (
"id" serial NOT NULL,
PRIMARY KEY ("id"),
"name" character varying(255) NOT NULL,
"description" character varying(10000) NULL,
"default_currency" character varying(255) NOT NULL,
"owner_id" integer NOT NULL,
"created_at" date NOT NULL,
"updated_at" date NOT NULL
);

View File

@ -0,0 +1 @@
DROP TABLE participation;

View File

@ -0,0 +1,16 @@
CREATE TABLE "participation" (
"id" serial NOT NULL,
PRIMARY KEY ("id"),
"user_id" integer NOT NULL,
"event_id" integer NOT NULL,
"invited_by_user_id" integer NULL,
"created_at" date NOT NULL,
"updated_at" date NOT NULL
);
ALTER TABLE "participation"
ADD FOREIGN KEY ("event_id") REFERENCES "event" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "participation"
ADD FOREIGN KEY ("user_id") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE;

View File

@ -0,0 +1,2 @@
ALTER TABLE "event"
ADD "total_amount" integer NULL;

View File

@ -0,0 +1,2 @@
ALTER TABLE "participation"
ADD CONSTRAINT unique_user_event UNIQUE ("user_id", "event_id");