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.
 
 
 

215 lines
4.5 KiB

package mysqldriver
import (
"context"
"database/sql"
"git.aiterp.net/stufflog/server/internal/generate"
"git.aiterp.net/stufflog/server/internal/slerrors"
"git.aiterp.net/stufflog/server/models"
sq "github.com/Masterminds/squirrel"
"github.com/jmoiron/sqlx"
)
type itemRepository struct {
db *sqlx.DB
}
func (r *itemRepository) Find(ctx context.Context, id string) (*models.Item, error) {
item := models.Item{}
err := r.db.GetContext(ctx, &item, "SELECT * FROM item WHERE item_id=?", id)
if err != nil {
if err == sql.ErrNoRows {
return nil, slerrors.NotFound("Project")
}
return nil, err
}
err = r.db.SelectContext(ctx, &item.Tags, "SELECT tag FROM item_tag WHERE item_id=? ORDER BY tag", id)
if err != nil {
return nil, err
}
return &item, nil
}
func (r *itemRepository) List(ctx context.Context, filter models.ItemFilter) ([]*models.Item, error) {
q := sq.Select("item.*").From("item").OrderBy("name")
if len(filter.ItemIDs) > 0 {
q = q.Where(sq.Eq{"item_id": filter.ItemIDs})
}
if len(filter.Tags) > 0 {
q = q.LeftJoin("item_tag ON item_tag.item_id = item.item_id").
Where(sq.Eq{"item_tag.tag": filter.Tags}).
GroupBy("item.item_id")
}
query, args, err := q.ToSql()
if err != nil {
return nil, err
}
results := make([]*models.Item, 0, 16)
err = r.db.SelectContext(ctx, &results, query, args...)
if err != nil {
if err == sql.ErrNoRows {
return []*models.Item{}, nil
}
return nil, err
}
err = r.fillTags(ctx, results)
if err != nil {
return nil, err
}
return results, nil
}
func (r *itemRepository) Insert(ctx context.Context, item models.Item) (*models.Item, error) {
item.ID = generate.ItemID()
tx, err := r.db.BeginTxx(ctx, nil)
if err != nil {
return nil, err
}
_, err = tx.NamedExecContext(ctx, `
INSERT INTO item (item_id, name, description, image_url)
VALUES (:item_id, :name, :description, :image_url)
`, item)
if err != nil {
_ = tx.Rollback()
return nil, err
}
if len(item.Tags) > 0 {
q := sq.Insert("item_tag").Columns("item_id", "tag")
for _, tag := range item.Tags {
q = q.Values(item.ID, tag)
}
tagQuery, args, err := q.ToSql()
if err != nil {
_ = tx.Rollback()
return nil, err
}
_, err = r.db.ExecContext(ctx, tagQuery, args...)
if err != nil {
_ = tx.Rollback()
return nil, err
}
}
err = tx.Commit()
if err != nil {
return nil, err
}
return &item, nil
}
func (r *itemRepository) Save(ctx context.Context, item models.Item) error {
tx, err := r.db.BeginTxx(ctx, nil)
if err != nil {
return err
}
_, err = tx.NamedExecContext(ctx, `
UPDATE item
SET name=:name, description=:description, image_url=:image_url
WHERE item_id=:item_id
`, item)
if err != nil {
_ = tx.Rollback()
return err
}
_, err = r.db.ExecContext(ctx, "DELETE FROM item_tag WHERE item_id=?", item.ID)
if err != nil && err != sql.ErrNoRows {
_ = tx.Rollback()
return err
}
if len(item.Tags) > 0 {
q := sq.Insert("item_tag").Columns("item_id", "tag")
for _, tag := range item.Tags {
q = q.Values(item.ID, tag)
}
tagQuery, args, err := q.ToSql()
if err != nil {
_ = tx.Rollback()
return err
}
_, err = r.db.ExecContext(ctx, tagQuery, args...)
if err != nil {
_ = tx.Rollback()
return err
}
}
err = tx.Commit()
if err != nil {
return err
}
return nil
}
func (r *itemRepository) Delete(ctx context.Context, item models.Item) error {
_, err := r.db.ExecContext(ctx, "DELETE FROM item WHERE item_id=?", item.ID)
if err != nil {
return err
}
_, err = r.db.ExecContext(ctx, "DELETE FROM item_tag WHERE item_id=?", item.ID)
if err != nil {
return err
}
return err
}
func (r *itemRepository) GetTags(ctx context.Context) ([]string, error) {
tags := make([]string, 0, 16)
err := r.db.SelectContext(ctx, &tags, "SELECT DISTINCT(tag) FROM item_tag")
if err != nil {
return nil, err
}
return tags, nil
}
func (r *itemRepository) fillTags(ctx context.Context, items []*models.Item) error {
ids := make([]string, len(items))
idMap := make(map[string]int, len(items))
for i, item := range items {
ids[i] = item.ID
idMap[item.ID] = i
}
query, args, err := sq.Select("*").From("item_tag").Where(sq.Eq{"item_id": ids}).ToSql()
if err != nil {
return err
}
results := make([]struct {
ItemID string `db:"item_id"`
Tag string `db:"tag"`
}, 0, len(items)*4)
err = r.db.SelectContext(ctx, &results, query, args...)
if err != nil {
return err
}
for _, result := range results {
item := items[idMap[result.ItemID]]
item.Tags = append(item.Tags, result.Tag)
}
return nil
}