feat: implement submission repository and service layer with caching support
All checks were successful
Build and Release / release (push) Successful in 1m32s
All checks were successful
Build and Release / release (push) Successful in 1m32s
This commit is contained in:
@@ -216,3 +216,13 @@ WHERE project_id = $1
|
|||||||
ORDER BY reviewed_at DESC, created_at DESC
|
ORDER BY reviewed_at DESC, created_at DESC
|
||||||
LIMIT 1;
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: GetLatestApprovedSubmission :one
|
||||||
|
SELECT
|
||||||
|
id, project_id, commit_id, user_id, created_at, status, reviewed_by, reviewed_at, review_note, content, is_deleted
|
||||||
|
FROM submissions
|
||||||
|
WHERE project_id = $1
|
||||||
|
AND status = 2
|
||||||
|
AND is_deleted = false
|
||||||
|
ORDER BY reviewed_at DESC, created_at DESC
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
|||||||
@@ -159,6 +159,50 @@ func (q *Queries) DeleteSubmission(ctx context.Context, id pgtype.UUID) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getLatestApprovedSubmission = `-- name: GetLatestApprovedSubmission :one
|
||||||
|
SELECT
|
||||||
|
id, project_id, commit_id, user_id, created_at, status, reviewed_by, reviewed_at, review_note, content, is_deleted
|
||||||
|
FROM submissions
|
||||||
|
WHERE project_id = $1
|
||||||
|
AND status = 2
|
||||||
|
AND is_deleted = false
|
||||||
|
ORDER BY reviewed_at DESC, created_at DESC
|
||||||
|
LIMIT 1
|
||||||
|
`
|
||||||
|
|
||||||
|
type GetLatestApprovedSubmissionRow struct {
|
||||||
|
ID pgtype.UUID `json:"id"`
|
||||||
|
ProjectID pgtype.UUID `json:"project_id"`
|
||||||
|
CommitID pgtype.UUID `json:"commit_id"`
|
||||||
|
UserID pgtype.UUID `json:"user_id"`
|
||||||
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
|
Status int16 `json:"status"`
|
||||||
|
ReviewedBy pgtype.UUID `json:"reviewed_by"`
|
||||||
|
ReviewedAt pgtype.Timestamptz `json:"reviewed_at"`
|
||||||
|
ReviewNote pgtype.Text `json:"review_note"`
|
||||||
|
Content pgtype.Text `json:"content"`
|
||||||
|
IsDeleted bool `json:"is_deleted"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) GetLatestApprovedSubmission(ctx context.Context, projectID pgtype.UUID) (GetLatestApprovedSubmissionRow, error) {
|
||||||
|
row := q.db.QueryRow(ctx, getLatestApprovedSubmission, projectID)
|
||||||
|
var i GetLatestApprovedSubmissionRow
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.ProjectID,
|
||||||
|
&i.CommitID,
|
||||||
|
&i.UserID,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.Status,
|
||||||
|
&i.ReviewedBy,
|
||||||
|
&i.ReviewedAt,
|
||||||
|
&i.ReviewNote,
|
||||||
|
&i.Content,
|
||||||
|
&i.IsDeleted,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
const getLatestApprovedSubmissionExcluding = `-- name: GetLatestApprovedSubmissionExcluding :one
|
const getLatestApprovedSubmissionExcluding = `-- name: GetLatestApprovedSubmissionExcluding :one
|
||||||
SELECT
|
SELECT
|
||||||
id, project_id, commit_id, user_id, created_at, status, reviewed_by, reviewed_at, review_note, content, is_deleted
|
id, project_id, commit_id, user_id, created_at, status, reviewed_by, reviewed_at, review_note, content, is_deleted
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ type SubmissionRepository interface {
|
|||||||
Update(ctx context.Context, params sqlc.UpdateSubmissionParams) (*models.SubmissionEntity, error)
|
Update(ctx context.Context, params sqlc.UpdateSubmissionParams) (*models.SubmissionEntity, error)
|
||||||
Delete(ctx context.Context, id pgtype.UUID) error
|
Delete(ctx context.Context, id pgtype.UUID) error
|
||||||
GetLatestApprovedSubmissionExcluding(ctx context.Context, projectID pgtype.UUID, id pgtype.UUID) (*models.SubmissionEntity, error)
|
GetLatestApprovedSubmissionExcluding(ctx context.Context, projectID pgtype.UUID, id pgtype.UUID) (*models.SubmissionEntity, error)
|
||||||
|
GetLatestApprovedSubmission(ctx context.Context, projectID pgtype.UUID) (*models.SubmissionEntity, error)
|
||||||
WithTx(tx pgx.Tx) SubmissionRepository
|
WithTx(tx pgx.Tx) SubmissionRepository
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -349,3 +350,25 @@ func (r *submissionRepository) GetLatestApprovedSubmissionExcluding(ctx context.
|
|||||||
}
|
}
|
||||||
return entity, nil
|
return entity, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *submissionRepository) GetLatestApprovedSubmission(ctx context.Context, projectID pgtype.UUID) (*models.SubmissionEntity, error) {
|
||||||
|
row, err := r.q.GetLatestApprovedSubmission(ctx, projectID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
entity := &models.SubmissionEntity{
|
||||||
|
ID: convert.UUIDToString(row.ID),
|
||||||
|
ProjectID: convert.UUIDToString(row.ProjectID),
|
||||||
|
CommitID: convert.UUIDToString(row.CommitID),
|
||||||
|
UserID: convert.UUIDToString(row.UserID),
|
||||||
|
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
||||||
|
Status: constants.ParseStatusType(row.Status),
|
||||||
|
ReviewedBy: convert.UUIDToStringPtr(row.ReviewedBy),
|
||||||
|
ReviewedAt: convert.TimeToPtr(row.ReviewedAt),
|
||||||
|
ReviewNote: convert.TextToPtr(row.ReviewNote),
|
||||||
|
Content: convert.TextToPtr(row.Content),
|
||||||
|
IsDeleted: row.IsDeleted,
|
||||||
|
}
|
||||||
|
return entity, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -421,12 +421,21 @@ func (s *submissionService) DeleteSubmission(ctx context.Context, userID string,
|
|||||||
|
|
||||||
submissionRepo := s.submissionRepo.WithTx(tx)
|
submissionRepo := s.submissionRepo.WithTx(tx)
|
||||||
|
|
||||||
|
isLatestApprovedDeleted := false
|
||||||
|
|
||||||
if submission.Status == constants.StatusTypeApproved {
|
if submission.Status == constants.StatusTypeApproved {
|
||||||
projectUUID, err := convert.StringToUUID(submission.ProjectID)
|
projectUUID, err := convert.StringToUUID(submission.ProjectID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid project ID")
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid project ID")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
latestApproved, err := s.submissionRepo.GetLatestApprovedSubmission(ctx, projectUUID)
|
||||||
|
if err != nil && !errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to check latest approved submission: "+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if err == nil && latestApproved != nil && latestApproved.ID == submission.ID {
|
||||||
|
isLatestApprovedDeleted = true
|
||||||
prevSubmission, err := s.submissionRepo.GetLatestApprovedSubmissionExcluding(ctx, projectUUID, submissionUUID)
|
prevSubmission, err := s.submissionRepo.GetLatestApprovedSubmissionExcluding(ctx, projectUUID, submissionUUID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, pgx.ErrNoRows) {
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
@@ -462,6 +471,7 @@ func (s *submissionService) DeleteSubmission(ctx context.Context, userID string,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err = submissionRepo.Delete(ctx, submissionUUID)
|
err = submissionRepo.Delete(ctx, submissionUUID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -473,7 +483,7 @@ func (s *submissionService) DeleteSubmission(ctx context.Context, userID string,
|
|||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to commit transaction: "+err.Error())
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to commit transaction: "+err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
if submission.Status == constants.StatusTypeApproved {
|
if isLatestApprovedDeleted {
|
||||||
go func() {
|
go func() {
|
||||||
bgCtx := context.Background()
|
bgCtx := context.Background()
|
||||||
_ = s.c.DelByPattern(bgCtx, "entity:search*")
|
_ = s.c.DelByPattern(bgCtx, "entity:search*")
|
||||||
|
|||||||
Reference in New Issue
Block a user