stufflog graphql server
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

169 lines
3.8 KiB

package mysqldriver
import (
"context"
"database/sql"
"errors"
"fmt"
"git.aiterp.net/stufflog/server/internal/xlerrors"
"git.aiterp.net/stufflog/server/models"
sq "github.com/Masterminds/squirrel"
"github.com/jmoiron/sqlx"
"time"
)
var counterKindIssueID = "NextIssueID"
type issueRepository struct {
db *sqlx.DB
}
func (r *issueRepository) Find(ctx context.Context, id string) (*models.Issue, error) {
issue := models.Issue{}
err := r.db.GetContext(ctx, &issue, "SELECT * FROM issue WHERE issue_id=?", id)
if err != nil {
if err == sql.ErrNoRows {
return nil, xlerrors.NotFound("Issue")
}
return nil, err
}
return &issue, nil
}
func (r *issueRepository) List(ctx context.Context, filter models.IssueFilter) ([]*models.Issue, error) {
q := sq.Select("*").From("issue").OrderBy("updated_time DESC")
if len(filter.IssueIDs) > 0 {
q = q.Where(sq.Eq{"issue_id": filter.IssueIDs})
}
if len(filter.ProjectIDs) > 0 {
q = q.Where(sq.Eq{"project_id": filter.ProjectIDs})
}
if len(filter.OwnerIDs) > 0 {
q = q.Where(sq.Eq{"owner_id": filter.OwnerIDs})
}
if len(filter.AssigneeIDs) > 0 {
q = q.Where(sq.Eq{"assignee_id": filter.AssigneeIDs})
}
if filter.Search != nil && *filter.Search != "" {
q = q.Where("MATCH (name, title, description) AGAINST (?)", *filter.Search)
}
if filter.MinStage != nil {
q = q.Where(sq.GtOrEq{"status_stage": *filter.MinStage})
}
if filter.MaxStage != nil {
q = q.Where(sq.LtOrEq{"status_stage": *filter.MaxStage})
}
if filter.Limit != nil && *filter.Limit > 0 {
q = q.Limit(uint64(*filter.Limit))
}
query, args, err := q.ToSql()
if err != nil {
return nil, err
}
results := make([]*models.Issue, 0, 16)
err = r.db.SelectContext(ctx, &results, query, args...)
if err != nil {
if err == sql.ErrNoRows {
return []*models.Issue{}, nil
}
return nil, err
}
return results, nil
}
func (r *issueRepository) Insert(ctx context.Context, issue models.Issue) (*models.Issue, error) {
if issue.ProjectID == "" {
return nil, errors.New("missing project id")
}
if issue.CreatedTime.IsZero() {
issue.CreatedTime = time.Now().Truncate(time.Second)
issue.UpdatedTime = issue.CreatedTime
}
tx, err := r.db.BeginTxx(ctx, nil)
if err != nil {
return nil, err
}
nextID, err := incCounter(ctx, tx, counterKindIssueID, issue.ProjectID)
if err != nil {
_ = tx.Rollback()
return nil, err
}
issue.ID = fmt.Sprintf("%s-%d", issue.ProjectID, nextID)
_, err = tx.NamedExecContext(ctx, `
INSERT INTO issue (
issue_id, project_id, owner_id, assignee_id,
status_stage, status_name, created_time,
updated_time, due_time, name, title, description
) VALUES (
:issue_id, :project_id, :owner_id, :assignee_id,
:status_stage, :status_name, :created_time,
:updated_time, :due_time, :name, :title, :description
)
`, issue)
if err != nil {
_ = tx.Rollback()
return nil, err
}
err = tx.Commit()
if err != nil {
_ = tx.Rollback()
return nil, err
}
return &issue, nil
}
func (r *issueRepository) Save(ctx context.Context, issue models.Issue) error {
_, err := r.db.NamedExecContext(ctx, `
UPDATE issue
SET assignee_id=:assignee_id,
status_stage=:status_stage,
status_name=:status_name,
created_time=:created_time,
updated_time=:updated_time,
due_time=:due_time,
name=:name,
title=:title,
description=:description
WHERE issue_id=:issue_id
`, issue)
if err != nil {
return err
}
return nil
}
func (r *issueRepository) Delete(ctx context.Context, issue models.Issue) error {
tx, err := r.db.BeginTxx(ctx, nil)
if err != nil {
return err
}
_, err = tx.ExecContext(ctx, "DELETE FROM issue WHERE issue_id=?", issue.ID)
if err != nil {
_ = tx.Rollback()
return err
}
// TODO: delete from issue_*
err = tx.Commit()
if err != nil {
_ = tx.Rollback()
return err
}
return nil
}