package mysqldriver import ( "context" "database/sql" "errors" "fmt" "git.aiterp.net/stufflog/server/internal/slerrors" "git.aiterp.net/stufflog/server/models" sq "github.com/Masterminds/squirrel" "github.com/jmoiron/sqlx" ) type issueItemRepository struct { db *sqlx.DB } func (r *issueItemRepository) Find(ctx context.Context, id string) (*models.IssueItem, error) { issueItem := models.IssueItem{} err := r.db.GetContext(ctx, &issueItem, "SELECT * FROM issue_item WHERE issue_item_id=?", id) if err != nil { if err == sql.ErrNoRows { return nil, slerrors.NotFound("Issue item") } return nil, err } return &issueItem, nil } func (r *issueItemRepository) List(ctx context.Context, filter models.IssueItemFilter) ([]*models.IssueItem, error) { q := sq.Select("issue_item.*").From("issue_item").GroupBy("issue_item.issue_item_id") if len(filter.IssueItemIDs) > 0 { q = q.Where(sq.Eq{"issue_item_id": filter.IssueIDs}) } if len(filter.IssueIDs) > 0 { q = q.Where(sq.Eq{"issue_id": filter.IssueIDs}) } if len(filter.IssueAssignees) > 0 || len(filter.IssueOwners) > 0 || filter.IssueMinStage != nil || filter.IssueMaxStage != nil { q = q.Join("issue ON issue.issue_id = issue_item.issue_id") } if len(filter.IssueAssignees) > 0 { q = q.Where(sq.Eq{"issue.assignee_id": filter.IssueAssignees}) } if len(filter.IssueOwners) > 0 { q = q.Where(sq.Eq{"issue.owner_id": filter.IssueOwners}) } if filter.IssueMinStage != nil && filter.IssueMaxStage != nil && *filter.IssueMinStage == *filter.IssueMaxStage { q = q.Where(sq.Eq{"issue.status_stage": *filter.IssueMinStage}) } else { if filter.IssueMinStage != nil { q = q.Where(sq.GtOrEq{"issue.status_stage": *filter.IssueMinStage}) } if filter.IssueMaxStage != nil { q = q.Where(sq.LtOrEq{"issue.status_stage": *filter.IssueMaxStage}) } } if len(filter.ItemIDs) > 0 { q = q.Where(sq.Eq{"item_id": filter.IssueIDs}) } if len(filter.ItemTags) > 0 { q = q.Join("item_tag ON item_tag.item_id = issue_item.item_id").Where( sq.Eq{"item_tag.tag": filter.ItemTags}, ) } if filter.Acquired != nil { q = q.Where(sq.Eq{"acquired": *filter.Acquired}) } query, args, err := q.ToSql() if err != nil { return nil, err } results := make([]*models.IssueItem, 0, 16) err = r.db.SelectContext(ctx, &results, query, args...) if err != nil { if err == sql.ErrNoRows { return []*models.IssueItem{}, nil } return nil, err } return results, nil } func (r *issueItemRepository) Insert(ctx context.Context, item models.IssueItem) (*models.IssueItem, error) { if item.IssueID == "" { return nil, errors.New("missing issue id") } tx, err := r.db.BeginTxx(ctx, nil) if err != nil { return nil, err } nextID, err := incCounter(ctx, tx, counterKindIssueSubID, item.IssueID) if err != nil { _ = tx.Rollback() return nil, err } item.ID = fmt.Sprintf("%s-%d", item.IssueID, nextID) _, err = tx.NamedExecContext(ctx, ` INSERT INTO issue_item ( issue_item_id, issue_id, item_id, quantity, acquired ) VALUES ( :issue_item_id, :issue_id, :item_id, :quantity, :acquired ); `, item) if err != nil { _ = tx.Rollback() return nil, err } err = tx.Commit() if err != nil { _ = tx.Rollback() return nil, err } return &item, nil } func (r *issueItemRepository) Save(ctx context.Context, item models.IssueItem) error { _, err := r.db.NamedExecContext(ctx, ` UPDATE issue_item SET acquired=:acquired, quantity=:quantity WHERE issue_item_id=:issue_item_id `, item) return err } func (r *issueItemRepository) Delete(ctx context.Context, item models.IssueItem) error { _, err := r.db.ExecContext(ctx, "DELETE FROM issue_item WHERE issue_item_id=? LIMIT 1;", item.ID) return err }