170 lines
4.0 KiB
Go
170 lines
4.0 KiB
Go
package repository
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"errors"
|
|
"time"
|
|
|
|
"github.com/jackc/pgerrcode"
|
|
"github.com/jackc/pgx/v5/pgconn"
|
|
)
|
|
|
|
type ProjectData struct {
|
|
UUID string
|
|
Name string
|
|
Slug string
|
|
Description string
|
|
CreatedBy string
|
|
CreatedAt time.Time
|
|
ClosedAt sql.NullTime
|
|
Blocked bool
|
|
UpdatedAt time.Time
|
|
UpdatedBy string
|
|
}
|
|
|
|
// CreateProject adds a new projects to the database
|
|
func CreateProject(ctx context.Context, db *sql.DB, data *ProjectData) error {
|
|
tx, err := StartTransaction(ctx, db)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer tx.Rollback()
|
|
queryProject := `
|
|
INSERT INTO projects
|
|
(uuid, name, slug, description, owner_user_id, billing_account_id, created_by, created_at, updated_by, updated_at)
|
|
VALUES
|
|
($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
|
|
`
|
|
|
|
if _, err := tx.ExecContext(ctx, queryProject,
|
|
data.UUID, data.Name, data.Slug, data.Description, data.CreatedBy,
|
|
data.CreatedBy, data.CreatedBy, data.CreatedAt, data.CreatedBy, data.CreatedAt); err != nil {
|
|
var pgErr *pgconn.PgError
|
|
if errors.As(err, &pgErr) {
|
|
switch pgErr.Code {
|
|
case pgerrcode.UniqueViolation:
|
|
return ErrAlreadyExists
|
|
case pgerrcode.CheckViolation:
|
|
return ErrCheckNotPassed
|
|
}
|
|
return err
|
|
}
|
|
return err
|
|
}
|
|
|
|
// When a project is created, we need to insert the default owner project membership
|
|
queryMembership := `
|
|
INSERT INTO project_membership
|
|
(project_uuid, user_uuid, role, status, invited_by, joined_at)
|
|
VALUES
|
|
($1, $2, $3, $4, $5, $6);
|
|
`
|
|
if _, err := tx.ExecContext(ctx, queryMembership,
|
|
data.UUID, data.CreatedBy, "owner", "active", data.CreatedBy, data.CreatedAt,
|
|
); err != nil {
|
|
var pgErr *pgconn.PgError
|
|
if errors.As(err, &pgErr) {
|
|
switch pgErr.Code {
|
|
case pgerrcode.UniqueViolation:
|
|
return ErrAlreadyExists
|
|
case pgerrcode.CheckViolation:
|
|
return ErrCheckNotPassed
|
|
}
|
|
return err
|
|
}
|
|
return err
|
|
}
|
|
|
|
if err := tx.Commit(); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GetProjectByID returns a project from the database
|
|
func GetProjectByID(ctx context.Context, db *sql.DB, projectID string) (*ProjectData, error) {
|
|
data := &ProjectData{}
|
|
query := `
|
|
SELECT uuid, name, slug, description, owner_user_id, closed_at, created_at
|
|
FROM projects
|
|
WHERE uuid=$1`
|
|
|
|
if err := db.QueryRowContext(ctx, query, projectID).Scan(
|
|
&data.UUID,
|
|
&data.Name,
|
|
&data.Slug,
|
|
&data.Description,
|
|
&data.CreatedBy,
|
|
&data.ClosedAt,
|
|
&data.CreatedAt,
|
|
); err != nil {
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
return nil, ErrNotFound
|
|
}
|
|
return nil, err
|
|
}
|
|
return data, nil
|
|
}
|
|
|
|
// UpdateProject change editable project data
|
|
func UpdateProject(ctx context.Context, db *sql.DB, data *ProjectData) error {
|
|
query := `
|
|
UPDATE projects
|
|
SET
|
|
name = $2,
|
|
description = $3,
|
|
updated_at = $4,
|
|
updated_by = $5
|
|
WHERE uuid = $1;`
|
|
if _, err := db.Query(query, data.UUID, data.Name, data.Description, data.UpdatedAt, data.UpdatedBy); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ListProjects get all projects that are available for the user from the database
|
|
func ListProjects(ctx context.Context, db *sql.DB, userID string) ([]*ProjectData, error) {
|
|
query := `
|
|
SELECT p.uuid, p.name
|
|
FROM projects p
|
|
JOIN project_membership pm ON pm.project_uuid = p.uuid
|
|
WHERE pm.user_uuid = $1`
|
|
rows, err := db.QueryContext(ctx, query, userID)
|
|
if err != nil {
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
return nil, ErrNotFound
|
|
}
|
|
return nil, err
|
|
}
|
|
result := []*ProjectData{}
|
|
|
|
for rows.Next() {
|
|
pd := &ProjectData{}
|
|
err := rows.Scan(&pd.UUID, &pd.Name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
result = append(result, pd)
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
// GetProjectOwner should return an owner if a project
|
|
func GetProjectOwner(ctx context.Context, db *sql.DB, projectID string) (userID string, err error) {
|
|
query := `
|
|
SELECT user_uuid
|
|
FROM project_membership
|
|
WHERE project_uuid = $1 AND role = 'owner'`
|
|
|
|
if err := db.QueryRowContext(ctx, query, projectID).Scan(
|
|
&userID,
|
|
); err != nil {
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
return "", ErrNotFound
|
|
}
|
|
return "", err
|
|
}
|
|
return
|
|
}
|