Browse Source

a lot of progress on items as well as get/find/create on project.

mian
Gisle Aune 2 years ago
parent
commit
a249110622
  1. 31
      api/common.go
  2. 129
      api/items.go
  3. 50
      api/projects.go
  4. 2
      api/scope.go
  5. 1
      cmd/stufflog3-server.go
  6. 22
      go.mod
  7. 7
      internal/database/database.go
  8. 23
      internal/database/mysql/database.go
  9. 38
      internal/database/mysql/items.go
  10. 491
      internal/database/mysql/mysqlcore/db.go
  11. 67
      internal/database/mysql/mysqlcore/item.sql.go
  12. 201
      internal/database/mysql/mysqlcore/project.sql.go
  13. 24
      internal/database/mysql/mysqlcore/scope.sql.go
  14. 2
      internal/database/mysql/mysqlcore/stats.sql.go
  15. 180
      internal/database/mysql/project.go
  16. 27
      internal/database/mysql/queries/item.sql
  17. 39
      internal/database/mysql/queries/project.sql
  18. 33
      internal/database/mysql/scopes.go
  19. 2
      internal/models/item.go
  20. 47
      internal/models/project.go
  21. 9
      internal/models/scope.go
  22. 20
      internal/models/status.go
  23. 2
      internal/slerrors/notfound.go
  24. 2
      sqlc.yaml

31
api/common.go

@ -20,12 +20,36 @@ func handler(key string, callback func(c *gin.Context) (interface{}, error)) gin
}
resJson := make(map[string]interface{}, 1)
if s := getScope(c); s != nil {
options := ScopeOptions{
StatusLabels: models.StatusLabels,
}
if s.Stats != nil {
options.Stats = make(map[int]models.Stat)
for _, stat := range s.Stats {
options.Stats[stat.ID] = stat
}
}
options.Members = make(map[string]string)
for _, member := range s.Members {
options.Members[member.ID] = member.Name
}
resJson["scopeInfo"] = options
}
resJson[key] = res
c.JSON(200, resJson)
}
}
type ScopeOptions struct {
StatusLabels map[models.Status]string `json:"statusLabels"`
Stats map[int]models.Stat `json:"stats,omitempty"`
Members map[string]string `json:"members,omitempty"`
}
func reqInt(c *gin.Context, key string) (int, error) {
v, err := strconv.Atoi(c.Param(key))
if err != nil {
@ -66,5 +90,10 @@ func scopeIDMiddleware(db database.Database) gin.HandlerFunc {
}
func getScope(c *gin.Context) *models.Scope {
return c.Request.Context().Value(&scopeIdContextKey).(*models.Scope)
scope := c.Request.Context().Value(&scopeIdContextKey)
if scope == nil {
return nil
}
return scope.(*models.Scope)
}

129
api/items.go

@ -12,23 +12,71 @@ import (
func Items(g *gin.RouterGroup, db database.Database) {
g.Use(scopeIDMiddleware(db))
g.GET("/:id", handler("item", func(c *gin.Context) (interface{}, error) {
id, err := reqInt(c, "id")
if err != nil {
return nil, err
g.GET("/", handler("items", func(c *gin.Context) (res interface{}, err error) {
mode := c.Query("mode")
var fromTime, toTime time.Time
var fromDate, toDate models.Date
if mode != "scheduled" {
if c.Query("to") == "" {
toTime = time.Now()
} else {
toTime, err = time.Parse(time.RFC3339Nano, c.Query("to"))
if err != nil {
return nil, slerrors.BadRequest("Invalid value for to")
}
}
if c.Query("from") == "" {
fromTime = time.Now().Add(-time.Hour * 24 * 30)
} else {
fromTime, err = time.Parse(time.RFC3339Nano, c.Query("from"))
if err != nil {
return nil, slerrors.BadRequest("Invalid value for from")
}
}
if toTime.After(toTime) {
return nil, slerrors.BadRequest("the flow of time itself is convoluted, but not so for the database")
}
} else {
if c.Query("to") == "" {
toDate, _ = models.ParseDate(time.Now().Add(time.Hour * 24 * 7).Format("2006-01-02"))
} else {
toDate, err = models.ParseDate(c.Query("to"))
if err != nil {
return nil, slerrors.BadRequest("Invalid value for to")
}
}
if c.Query("from") == "" {
fromDate, _ = models.ParseDate(time.Now().Format("2006-01-02"))
} else {
fromDate, err = models.ParseDate(c.Query("from"))
if err != nil {
return nil, slerrors.BadRequest("Invalid value for from")
}
}
}
item, err := db.Items(getScope(c).ID).Find(c.Request.Context(), id)
switch mode {
case "", "created":
return db.Items(getScope(c).ID).ListCreated(c.Request.Context(), fromTime, toTime)
case "acquired":
return db.Items(getScope(c).ID).ListAcquired(c.Request.Context(), fromTime, toTime)
case "loose":
return db.Items(getScope(c).ID).ListLoose(c.Request.Context(), fromTime, toTime)
case "scheduled":
return db.Items(getScope(c).ID).ListScheduled(c.Request.Context(), fromDate, toDate)
default:
return nil, slerrors.BadRequest("unknown mode")
}
}))
g.GET("/:id", handler("item", func(c *gin.Context) (interface{}, error) {
id, err := reqInt(c, "id")
if err != nil {
return nil, err
}
for _, member := range getScope(c).Members {
if member.ID == item.OwnerID {
item.Owner = &member
}
}
return item, nil
return db.Items(getScope(c).ID).Find(c.Request.Context(), id)
}))
g.POST("/", handler("item", func(c *gin.Context) (interface{}, error) {
@ -48,10 +96,6 @@ func Items(g *gin.RouterGroup, db database.Database) {
} else if getScope(c).HasMember(item.OwnerID) {
return nil, slerrors.Forbidden("Owner is not part of scope.")
}
if item.ProjectRequirementID != nil {
// TODO: Ensure project requirement exists in scope.
return nil, slerrors.Forbidden("TODO: check project requirement ID.")
}
for _, stat := range item.Stats {
if getScope(c).Stat(stat.ID) == nil {
return nil, slerrors.Forbidden("One or more stats are not part of scope.")
@ -61,12 +105,61 @@ func Items(g *gin.RouterGroup, db database.Database) {
}
}
item, err = db.Items(getScope(c).ID).Create(c.Request.Context(), *item)
return db.Items(getScope(c).ID).Create(c.Request.Context(), *item)
}))
g.PUT("/:id", handler("item", func(c *gin.Context) (interface{}, error) {
id, err := reqInt(c, "id")
if err != nil {
return nil, err
}
update := &models.ItemUpdate{}
err = c.BindJSON(update)
if err != nil {
return nil, slerrors.BadRequest("Invalid JSON input: " + err.Error())
}
item, err := db.Items(getScope(c).ID).Find(c.Request.Context(), id)
if err != nil {
return nil, err
}
if update.Name != nil && *update.Name == "" {
return nil, slerrors.BadRequest("Blank item name not allowed")
}
if update.OwnerID != nil || !getScope(c).HasMember(item.OwnerID) {
return nil, slerrors.Forbidden("New item is not part of scope.")
}
for _, stat := range update.Stats {
statRef := getScope(c).Stat(stat.ID)
if stat.Required != 0 && stat.Acquired != 0 && statRef == nil {
return nil, slerrors.Forbidden("One or more stats are not part of the scope.")
}
if !statRef.AllowsAmount(stat.Required) {
return nil, slerrors.Forbidden("One or more stats have a disallowed required amount.")
}
}
return db.Items(getScope(c).ID).Update(c.Request.Context(), *item, *update)
}))
g.DELETE("/:id", handler("item", func(c *gin.Context) (interface{}, error) {
id, err := reqInt(c, "id")
if err != nil {
return nil, err
}
item, err := db.Items(getScope(c).ID).Find(c.Request.Context(), id)
if err != nil {
return nil, err
}
item.Owner = getScope(c).Member(item.OwnerID)
return item, err
err = db.Items(getScope(c).ID).Delete(c.Request.Context(), *item)
if err != nil {
return nil, err
}
return item, nil
}))
}

50
api/projects.go

@ -0,0 +1,50 @@
package api
import (
"git.aiterp.net/stufflog3/stufflog3-api/internal/auth"
"git.aiterp.net/stufflog3/stufflog3-api/internal/database"
"git.aiterp.net/stufflog3/stufflog3-api/internal/models"
"git.aiterp.net/stufflog3/stufflog3-api/internal/slerrors"
"github.com/gin-gonic/gin"
"time"
)
func Projects(g *gin.RouterGroup, db database.Database) {
g.Use(scopeIDMiddleware(db))
g.GET("/", handler("projects", func(c *gin.Context) (interface{}, error) {
return db.Projects(getScope(c).ID).List(c.Request.Context())
}))
g.GET("/:id", handler("project", func(c *gin.Context) (interface{}, error) {
id, err := reqInt(c, "id")
if err != nil {
return nil, err
}
return db.Projects(getScope(c).ID).Find(c.Request.Context(), id)
}))
g.POST("/", handler("project", func(c *gin.Context) (interface{}, error) {
project := &models.Project{}
err := c.BindJSON(project)
if err != nil {
return nil, slerrors.BadRequest("Invalid JSON input: " + err.Error())
}
if !project.Status.Valid() {
return nil, slerrors.BadRequest("Unknown/unsupported project status")
}
if project.Name == "" {
return nil, slerrors.BadRequest("Project name cannot be blank")
}
if len(project.Requirements) > 0 {
return nil, slerrors.BadRequest("You cannot submit requirements this way")
}
project.OwnerID = auth.UserID(c)
project.CreatedTime = time.Now()
return db.Projects(getScope(c).ID).Create(c.Request.Context(), *project)
}))
}

2
api/scope.go

@ -3,6 +3,7 @@ package api
import (
"git.aiterp.net/stufflog3/stufflog3-api/internal/auth"
"git.aiterp.net/stufflog3/stufflog3-api/internal/database"
"git.aiterp.net/stufflog3/stufflog3-api/internal/models"
"git.aiterp.net/stufflog3/stufflog3-api/internal/slerrors"
"github.com/gin-gonic/gin"
)
@ -25,6 +26,7 @@ func Scopes(g *gin.RouterGroup, db database.Database) {
if !scope.HasMember(auth.UserID(c)) {
return nil, slerrors.NotFound("Scope")
}
scope.StatusLabels = models.StatusLabels
return scope, nil
}))

1
cmd/stufflog3-server.go

@ -35,6 +35,7 @@ func main() {
api.Scopes(server.Group("/api/scopes"), db)
api.Items(server.Group("/api/scope/:scope_id/items"), db)
api.Projects(server.Group("/api/scope/:scope_id/projects"), db)
exitSignal := make(chan os.Signal)
signal.Notify(exitSignal, os.Interrupt, os.Kill, syscall.SIGTERM)

22
go.mod

@ -8,24 +8,4 @@ require (
github.com/kyleconroy/sqlc v1.13.0
)
require (
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-playground/locales v0.13.0 // indirect
github.com/go-playground/universal-translator v0.17.0 // indirect
github.com/go-playground/validator/v10 v10.4.1 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/json-iterator/go v1.1.9 // indirect
github.com/kr/text v0.1.0 // indirect
github.com/leodido/go-urn v1.2.0 // indirect
github.com/mattn/go-isatty v0.0.12 // indirect
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 // indirect
github.com/stretchr/testify v1.7.0 // indirect
github.com/ugorji/go/codec v1.1.7 // indirect
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 // indirect
google.golang.org/protobuf v1.28.0 // indirect
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)
require golang.org/x/sync v0.0.0-20210220032951-036812b2e83c

7
internal/database/database.go

@ -10,7 +10,8 @@ type Database interface {
Scopes() ScopeRepository
Stats(scopeID int) StatRepository
Items(scopeID int) ItemRepository
ItemsMultiScope(scopeIDs []int) ItemRepository
Projects(scopeID int) ProjectRepository
ItemsMultiScope(scopeIDs []int) ItemMultiScopeRepository
}
type ScopeRepository interface {
@ -52,12 +53,12 @@ type ItemMultiScopeRepository interface {
type ProjectRepository interface {
Find(ctx context.Context, id int) (*models.Project, error)
List(ctx context.Context) ([]models.Project, error)
List(ctx context.Context) ([]models.ProjectEntry, error)
Create(ctx context.Context, project models.Project) (*models.Project, error)
Update(ctx context.Context, project models.Project) (*models.Project, error)
Delete(ctx context.Context, project models.ProjectEntry) error
AddRequirement(ctx context.Context, project models.ProjectEntry, requirement models.ProjectRequirement)
UpdateRequirement(ctx context.Context, project models.ProjectEntry, requirement models.ProjectRequirement, update models.ProjectRequirementUpdate)
DeleteRequirement(ctx context.Context, project models.ProjectEntry, requirement models.ProjectRequirement)
DeleteRequirement(ctx context.Context, project models.ProjectEntry, requirement models.ProjectRequirement, deleteItems bool)
}

23
internal/database/mysql/database.go

@ -1,9 +1,11 @@
package mysql
import (
"context"
"database/sql"
"fmt"
"git.aiterp.net/stufflog3/stufflog3-api/internal/database"
"git.aiterp.net/stufflog3/stufflog3-api/internal/database/mysql/mysqlcore"
"time"
_ "github.com/go-sql-driver/mysql"
@ -11,10 +13,11 @@ import (
type Database struct {
db *sql.DB
q *mysqlcore.Queries
}
func (d *Database) Scopes() database.ScopeRepository {
return &scopeRepository{db: d.db}
return &scopeRepository{db: d.db, q: d.q}
}
func (d *Database) Stats(scopeID int) database.StatRepository {
@ -23,10 +26,17 @@ func (d *Database) Stats(scopeID int) database.StatRepository {
}
func (d *Database) Items(scopeID int) database.ItemRepository {
return &itemRepository{db: d.db, scopeID: scopeID}
return &itemRepository{db: d.db, q: d.q, scopeID: scopeID}
}
func (d *Database) ItemsMultiScope(scopeIDs []int) database.ItemRepository {
func (d *Database) Projects(scopeID int) database.ProjectRepository {
return &projectRepository{
db: d.db, q: d.q, scopeID: scopeID,
items: &itemRepository{db: d.db, q: d.q, scopeID: scopeID},
}
}
func (d *Database) ItemsMultiScope(scopeIDs []int) database.ItemMultiScopeRepository {
//TODO implement me
panic("implement me")
}
@ -48,5 +58,10 @@ func Connect(host string, port int, username, password, database string) (*Datab
return nil, err
}
return &Database{db: db}, nil
q, err := mysqlcore.Prepare(context.Background(), db)
if err != nil {
return nil, err
}
return &Database{db: db, q: q}, nil
}

38
internal/database/mysql/items.go

@ -13,11 +13,12 @@ import (
type itemRepository struct {
db *sql.DB
q *mysqlcore.Queries
scopeID int
}
func (r *itemRepository) Find(ctx context.Context, id int) (*models.Item, error) {
res, err := mysqlcore.New(r.db).GetItem(ctx, id)
res, err := r.q.GetItem(ctx, id)
if err != nil {
if err == sql.ErrNoRows {
return nil, slerrors.NotFound("Item")
@ -30,7 +31,7 @@ func (r *itemRepository) Find(ctx context.Context, id int) (*models.Item, error)
item := r.resToItem(mysqlcore.ListItemsAcquiredBetweenRow(res))
stats, _ := mysqlcore.New(r.db).ListItemStatProgress(ctx, id)
stats, _ := r.q.ListItemStatProgress(ctx, id)
for _, stat := range stats {
item.Stats = append(item.Stats, models.StatProgressEntry{
StatEntry: models.StatEntry{
@ -47,7 +48,7 @@ func (r *itemRepository) Find(ctx context.Context, id int) (*models.Item, error)
}
func (r *itemRepository) ListCreated(ctx context.Context, from, to time.Time) ([]models.Item, error) {
rows, err := mysqlcore.New(r.db).ListItemsCreatedBetween(ctx, mysqlcore.ListItemsCreatedBetweenParams{
rows, err := r.q.ListItemsCreatedBetween(ctx, mysqlcore.ListItemsCreatedBetweenParams{
CreatedTime: from,
CreatedTime_2: to,
ScopeID: r.scopeID,
@ -70,7 +71,7 @@ func (r *itemRepository) ListCreated(ctx context.Context, from, to time.Time) ([
}
func (r *itemRepository) ListAcquired(ctx context.Context, from, to time.Time) ([]models.Item, error) {
rows, err := mysqlcore.New(r.db).ListItemsAcquiredBetween(ctx, mysqlcore.ListItemsAcquiredBetweenParams{
rows, err := r.q.ListItemsAcquiredBetween(ctx, mysqlcore.ListItemsAcquiredBetweenParams{
AcquiredTime: sql.NullTime{Valid: true, Time: from},
AcquiredTime_2: sql.NullTime{Valid: true, Time: to},
ScopeID: r.scopeID,
@ -93,7 +94,7 @@ func (r *itemRepository) ListAcquired(ctx context.Context, from, to time.Time) (
}
func (r *itemRepository) ListScheduled(ctx context.Context, from, to models.Date) ([]models.Item, error) {
rows, err := mysqlcore.New(r.db).ListItemsScheduledBetween(ctx, mysqlcore.ListItemsScheduledBetweenParams{
rows, err := r.q.ListItemsScheduledBetween(ctx, mysqlcore.ListItemsScheduledBetweenParams{
ScheduledDate: sqltypes.NullDate{Valid: true, Date: from},
ScheduledDate_2: sqltypes.NullDate{Valid: true, Date: to},
ScopeID: r.scopeID,
@ -116,7 +117,7 @@ func (r *itemRepository) ListScheduled(ctx context.Context, from, to models.Date
}
func (r *itemRepository) ListLoose(ctx context.Context, from, to time.Time) ([]models.Item, error) {
rows, err := mysqlcore.New(r.db).ListItemsLooseBetween(ctx, mysqlcore.ListItemsLooseBetweenParams{
rows, err := r.q.ListItemsLooseBetween(ctx, mysqlcore.ListItemsLooseBetweenParams{
CreatedTime: from,
CreatedTime_2: to,
ScopeID: r.scopeID,
@ -146,7 +147,14 @@ func (r *itemRepository) Create(ctx context.Context, item models.Item) (*models.
return nil, err
}
defer tx.Rollback()
q := mysqlcore.New(tx)
q := r.q.WithTx(tx)
if item.ProjectRequirementID != nil {
pr, err := q.GetProjectRequirement(ctx, *item.ProjectRequirementID)
if err != nil || pr.ScopeID != r.scopeID {
return nil, slerrors.NotFound("Project requirement")
}
}
prID, acqTime, schDate := r.generateNullables(item)
@ -212,7 +220,15 @@ func (r *itemRepository) Update(ctx context.Context, item models.Item, update mo
return nil, err
}
defer tx.Rollback()
q := mysqlcore.New(r.db)
q := r.q.WithTx(tx)
if update.ProjectRequirementID != nil {
pr, err := q.GetProjectRequirement(ctx, *update.ProjectRequirementID)
if err != nil || pr.ScopeID != r.scopeID {
return nil, slerrors.NotFound("Project requirement")
}
}
item.ApplyUpdate(update)
@ -266,7 +282,7 @@ func (r *itemRepository) Delete(ctx context.Context, item models.Item) error {
return err
}
defer tx.Rollback()
q := mysqlcore.New(r.db)
q := r.q.WithTx(tx)
err = q.DeleteItem(ctx, item.ID)
if err != nil {
@ -322,6 +338,10 @@ func (r *itemRepository) fillStats(ctx context.Context, items []models.Item) err
rows, err := r.db.QueryContext(ctx, query, ids...)
if err != nil {
if err == sql.ErrNoRows {
return nil
}
return err
}

491
internal/database/mysql/mysqlcore/db.go

@ -7,6 +7,7 @@ package mysqlcore
import (
"context"
"database/sql"
"fmt"
)
type DBTX interface {
@ -20,12 +21,498 @@ func New(db DBTX) *Queries {
return &Queries{db: db}
}
func Prepare(ctx context.Context, db DBTX) (*Queries, error) {
q := Queries{db: db}
var err error
if q.clearItemProjectRequirementStmt, err = db.PrepareContext(ctx, clearItemProjectRequirement); err != nil {
return nil, fmt.Errorf("error preparing query ClearItemProjectRequirement: %w", err)
}
if q.clearItemStatProgressStmt, err = db.PrepareContext(ctx, clearItemStatProgress); err != nil {
return nil, fmt.Errorf("error preparing query ClearItemStatProgress: %w", err)
}
if q.deleteAllScopeMembersStmt, err = db.PrepareContext(ctx, deleteAllScopeMembers); err != nil {
return nil, fmt.Errorf("error preparing query DeleteAllScopeMembers: %w", err)
}
if q.deleteItemStmt, err = db.PrepareContext(ctx, deleteItem); err != nil {
return nil, fmt.Errorf("error preparing query DeleteItem: %w", err)
}
if q.deleteItemForRequirementStmt, err = db.PrepareContext(ctx, deleteItemForRequirement); err != nil {
return nil, fmt.Errorf("error preparing query DeleteItemForRequirement: %w", err)
}
if q.deleteItemStatProgressStmt, err = db.PrepareContext(ctx, deleteItemStatProgress); err != nil {
return nil, fmt.Errorf("error preparing query DeleteItemStatProgress: %w", err)
}
if q.deleteProjectStmt, err = db.PrepareContext(ctx, deleteProject); err != nil {
return nil, fmt.Errorf("error preparing query DeleteProject: %w", err)
}
if q.deleteProjectRequirementStmt, err = db.PrepareContext(ctx, deleteProjectRequirement); err != nil {
return nil, fmt.Errorf("error preparing query DeleteProjectRequirement: %w", err)
}
if q.deleteScopeStmt, err = db.PrepareContext(ctx, deleteScope); err != nil {
return nil, fmt.Errorf("error preparing query DeleteScope: %w", err)
}
if q.deleteScopeMemberStmt, err = db.PrepareContext(ctx, deleteScopeMember); err != nil {
return nil, fmt.Errorf("error preparing query DeleteScopeMember: %w", err)
}
if q.getItemStmt, err = db.PrepareContext(ctx, getItem); err != nil {
return nil, fmt.Errorf("error preparing query GetItem: %w", err)
}
if q.getItemStatProgressBetweenStmt, err = db.PrepareContext(ctx, getItemStatProgressBetween); err != nil {
return nil, fmt.Errorf("error preparing query GetItemStatProgressBetween: %w", err)
}
if q.getProjectStmt, err = db.PrepareContext(ctx, getProject); err != nil {
return nil, fmt.Errorf("error preparing query GetProject: %w", err)
}
if q.getProjectRequirementStmt, err = db.PrepareContext(ctx, getProjectRequirement); err != nil {
return nil, fmt.Errorf("error preparing query GetProjectRequirement: %w", err)
}
if q.getScopeStmt, err = db.PrepareContext(ctx, getScope); err != nil {
return nil, fmt.Errorf("error preparing query GetScope: %w", err)
}
if q.getScopeDisplayNameStmt, err = db.PrepareContext(ctx, getScopeDisplayName); err != nil {
return nil, fmt.Errorf("error preparing query GetScopeDisplayName: %w", err)
}
if q.getScopeWithDisplayNameStmt, err = db.PrepareContext(ctx, getScopeWithDisplayName); err != nil {
return nil, fmt.Errorf("error preparing query GetScopeWithDisplayName: %w", err)
}
if q.insertItemStmt, err = db.PrepareContext(ctx, insertItem); err != nil {
return nil, fmt.Errorf("error preparing query InsertItem: %w", err)
}
if q.insertProjectStmt, err = db.PrepareContext(ctx, insertProject); err != nil {
return nil, fmt.Errorf("error preparing query InsertProject: %w", err)
}
if q.insertProjectRequirementStmt, err = db.PrepareContext(ctx, insertProjectRequirement); err != nil {
return nil, fmt.Errorf("error preparing query InsertProjectRequirement: %w", err)
}
if q.insertScopeStmt, err = db.PrepareContext(ctx, insertScope); err != nil {
return nil, fmt.Errorf("error preparing query InsertScope: %w", err)
}
if q.listItemStatProgressStmt, err = db.PrepareContext(ctx, listItemStatProgress); err != nil {
return nil, fmt.Errorf("error preparing query ListItemStatProgress: %w", err)
}
if q.listItemStatProgressMultiStmt, err = db.PrepareContext(ctx, listItemStatProgressMulti); err != nil {
return nil, fmt.Errorf("error preparing query ListItemStatProgressMulti: %w", err)
}
if q.listItemsAcquiredBetweenStmt, err = db.PrepareContext(ctx, listItemsAcquiredBetween); err != nil {
return nil, fmt.Errorf("error preparing query ListItemsAcquiredBetween: %w", err)
}
if q.listItemsByProjectStmt, err = db.PrepareContext(ctx, listItemsByProject); err != nil {
return nil, fmt.Errorf("error preparing query ListItemsByProject: %w", err)
}
if q.listItemsCreatedBetweenStmt, err = db.PrepareContext(ctx, listItemsCreatedBetween); err != nil {
return nil, fmt.Errorf("error preparing query ListItemsCreatedBetween: %w", err)
}
if q.listItemsCreatedBetweenNoScopeStmt, err = db.PrepareContext(ctx, listItemsCreatedBetweenNoScope); err != nil {
return nil, fmt.Errorf("error preparing query ListItemsCreatedBetweenNoScope: %w", err)
}
if q.listItemsLooseBetweenStmt, err = db.PrepareContext(ctx, listItemsLooseBetween); err != nil {
return nil, fmt.Errorf("error preparing query ListItemsLooseBetween: %w", err)
}
if q.listItemsLooseBetweenNoScopeStmt, err = db.PrepareContext(ctx, listItemsLooseBetweenNoScope); err != nil {
return nil, fmt.Errorf("error preparing query ListItemsLooseBetweenNoScope: %w", err)
}
if q.listItemsScheduledBetweenStmt, err = db.PrepareContext(ctx, listItemsScheduledBetween); err != nil {
return nil, fmt.Errorf("error preparing query ListItemsScheduledBetween: %w", err)
}
if q.listItemsScheduledBetweenNoScopeStmt, err = db.PrepareContext(ctx, listItemsScheduledBetweenNoScope); err != nil {
return nil, fmt.Errorf("error preparing query ListItemsScheduledBetweenNoScope: %w", err)
}
if q.listProjectEntriesStmt, err = db.PrepareContext(ctx, listProjectEntries); err != nil {
return nil, fmt.Errorf("error preparing query ListProjectEntries: %w", err)
}
if q.listProjectRequirementStatsStmt, err = db.PrepareContext(ctx, listProjectRequirementStats); err != nil {
return nil, fmt.Errorf("error preparing query ListProjectRequirementStats: %w", err)
}
if q.listProjectRequirementsByProjectIDStmt, err = db.PrepareContext(ctx, listProjectRequirementsByProjectID); err != nil {
return nil, fmt.Errorf("error preparing query ListProjectRequirementsByProjectID: %w", err)
}
if q.listScopeMembersStmt, err = db.PrepareContext(ctx, listScopeMembers); err != nil {
return nil, fmt.Errorf("error preparing query ListScopeMembers: %w", err)
}
if q.listScopesStmt, err = db.PrepareContext(ctx, listScopes); err != nil {
return nil, fmt.Errorf("error preparing query ListScopes: %w", err)
}
if q.listScopesByUserStmt, err = db.PrepareContext(ctx, listScopesByUser); err != nil {
return nil, fmt.Errorf("error preparing query ListScopesByUser: %w", err)
}
if q.listStatsStmt, err = db.PrepareContext(ctx, listStats); err != nil {
return nil, fmt.Errorf("error preparing query ListStats: %w", err)
}
if q.replaceItemStatProgressStmt, err = db.PrepareContext(ctx, replaceItemStatProgress); err != nil {
return nil, fmt.Errorf("error preparing query ReplaceItemStatProgress: %w", err)
}
if q.updateItemStmt, err = db.PrepareContext(ctx, updateItem); err != nil {
return nil, fmt.Errorf("error preparing query UpdateItem: %w", err)
}
if q.updateProjectStmt, err = db.PrepareContext(ctx, updateProject); err != nil {
return nil, fmt.Errorf("error preparing query UpdateProject: %w", err)
}
if q.updateProjectRequirementStmt, err = db.PrepareContext(ctx, updateProjectRequirement); err != nil {
return nil, fmt.Errorf("error preparing query UpdateProjectRequirement: %w", err)
}
if q.updateScopeStmt, err = db.PrepareContext(ctx, updateScope); err != nil {
return nil, fmt.Errorf("error preparing query UpdateScope: %w", err)
}
if q.updateScopeMemberStmt, err = db.PrepareContext(ctx, updateScopeMember); err != nil {
return nil, fmt.Errorf("error preparing query UpdateScopeMember: %w", err)
}
return &q, nil
}
func (q *Queries) Close() error {
var err error
if q.clearItemProjectRequirementStmt != nil {
if cerr := q.clearItemProjectRequirementStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing clearItemProjectRequirementStmt: %w", cerr)
}
}
if q.clearItemStatProgressStmt != nil {
if cerr := q.clearItemStatProgressStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing clearItemStatProgressStmt: %w", cerr)
}
}
if q.deleteAllScopeMembersStmt != nil {
if cerr := q.deleteAllScopeMembersStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing deleteAllScopeMembersStmt: %w", cerr)
}
}
if q.deleteItemStmt != nil {
if cerr := q.deleteItemStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing deleteItemStmt: %w", cerr)
}
}
if q.deleteItemForRequirementStmt != nil {
if cerr := q.deleteItemForRequirementStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing deleteItemForRequirementStmt: %w", cerr)
}
}
if q.deleteItemStatProgressStmt != nil {
if cerr := q.deleteItemStatProgressStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing deleteItemStatProgressStmt: %w", cerr)
}
}
if q.deleteProjectStmt != nil {
if cerr := q.deleteProjectStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing deleteProjectStmt: %w", cerr)
}
}
if q.deleteProjectRequirementStmt != nil {
if cerr := q.deleteProjectRequirementStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing deleteProjectRequirementStmt: %w", cerr)
}
}
if q.deleteScopeStmt != nil {
if cerr := q.deleteScopeStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing deleteScopeStmt: %w", cerr)
}
}
if q.deleteScopeMemberStmt != nil {
if cerr := q.deleteScopeMemberStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing deleteScopeMemberStmt: %w", cerr)
}
}
if q.getItemStmt != nil {
if cerr := q.getItemStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing getItemStmt: %w", cerr)
}
}
if q.getItemStatProgressBetweenStmt != nil {
if cerr := q.getItemStatProgressBetweenStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing getItemStatProgressBetweenStmt: %w", cerr)
}
}
if q.getProjectStmt != nil {
if cerr := q.getProjectStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing getProjectStmt: %w", cerr)
}
}
if q.getProjectRequirementStmt != nil {
if cerr := q.getProjectRequirementStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing getProjectRequirementStmt: %w", cerr)
}
}
if q.getScopeStmt != nil {
if cerr := q.getScopeStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing getScopeStmt: %w", cerr)
}
}
if q.getScopeDisplayNameStmt != nil {
if cerr := q.getScopeDisplayNameStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing getScopeDisplayNameStmt: %w", cerr)
}
}
if q.getScopeWithDisplayNameStmt != nil {
if cerr := q.getScopeWithDisplayNameStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing getScopeWithDisplayNameStmt: %w", cerr)
}
}
if q.insertItemStmt != nil {
if cerr := q.insertItemStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing insertItemStmt: %w", cerr)
}
}
if q.insertProjectStmt != nil {
if cerr := q.insertProjectStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing insertProjectStmt: %w", cerr)
}
}
if q.insertProjectRequirementStmt != nil {
if cerr := q.insertProjectRequirementStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing insertProjectRequirementStmt: %w", cerr)
}
}
if q.insertScopeStmt != nil {
if cerr := q.insertScopeStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing insertScopeStmt: %w", cerr)
}
}
if q.listItemStatProgressStmt != nil {
if cerr := q.listItemStatProgressStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing listItemStatProgressStmt: %w", cerr)
}
}
if q.listItemStatProgressMultiStmt != nil {
if cerr := q.listItemStatProgressMultiStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing listItemStatProgressMultiStmt: %w", cerr)
}
}
if q.listItemsAcquiredBetweenStmt != nil {
if cerr := q.listItemsAcquiredBetweenStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing listItemsAcquiredBetweenStmt: %w", cerr)
}
}
if q.listItemsByProjectStmt != nil {
if cerr := q.listItemsByProjectStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing listItemsByProjectStmt: %w", cerr)
}
}
if q.listItemsCreatedBetweenStmt != nil {
if cerr := q.listItemsCreatedBetweenStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing listItemsCreatedBetweenStmt: %w", cerr)
}
}
if q.listItemsCreatedBetweenNoScopeStmt != nil {
if cerr := q.listItemsCreatedBetweenNoScopeStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing listItemsCreatedBetweenNoScopeStmt: %w", cerr)
}
}
if q.listItemsLooseBetweenStmt != nil {
if cerr := q.listItemsLooseBetweenStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing listItemsLooseBetweenStmt: %w", cerr)
}
}
if q.listItemsLooseBetweenNoScopeStmt != nil {
if cerr := q.listItemsLooseBetweenNoScopeStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing listItemsLooseBetweenNoScopeStmt: %w", cerr)
}
}
if q.listItemsScheduledBetweenStmt != nil {
if cerr := q.listItemsScheduledBetweenStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing listItemsScheduledBetweenStmt: %w", cerr)
}
}
if q.listItemsScheduledBetweenNoScopeStmt != nil {
if cerr := q.listItemsScheduledBetweenNoScopeStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing listItemsScheduledBetweenNoScopeStmt: %w", cerr)
}
}
if q.listProjectEntriesStmt != nil {
if cerr := q.listProjectEntriesStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing listProjectEntriesStmt: %w", cerr)
}
}
if q.listProjectRequirementStatsStmt != nil {
if cerr := q.listProjectRequirementStatsStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing listProjectRequirementStatsStmt: %w", cerr)
}
}
if q.listProjectRequirementsByProjectIDStmt != nil {
if cerr := q.listProjectRequirementsByProjectIDStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing listProjectRequirementsByProjectIDStmt: %w", cerr)
}
}
if q.listScopeMembersStmt != nil {
if cerr := q.listScopeMembersStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing listScopeMembersStmt: %w", cerr)
}
}
if q.listScopesStmt != nil {
if cerr := q.listScopesStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing listScopesStmt: %w", cerr)
}
}
if q.listScopesByUserStmt != nil {
if cerr := q.listScopesByUserStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing listScopesByUserStmt: %w", cerr)
}
}
if q.listStatsStmt != nil {
if cerr := q.listStatsStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing listStatsStmt: %w", cerr)
}
}
if q.replaceItemStatProgressStmt != nil {
if cerr := q.replaceItemStatProgressStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing replaceItemStatProgressStmt: %w", cerr)
}
}
if q.updateItemStmt != nil {
if cerr := q.updateItemStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing updateItemStmt: %w", cerr)
}
}
if q.updateProjectStmt != nil {
if cerr := q.updateProjectStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing updateProjectStmt: %w", cerr)
}
}
if q.updateProjectRequirementStmt != nil {
if cerr := q.updateProjectRequirementStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing updateProjectRequirementStmt: %w", cerr)
}
}
if q.updateScopeStmt != nil {
if cerr := q.updateScopeStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing updateScopeStmt: %w", cerr)
}
}
if q.updateScopeMemberStmt != nil {
if cerr := q.updateScopeMemberStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing updateScopeMemberStmt: %w", cerr)
}
}
return err
}
func (q *Queries) exec(ctx context.Context, stmt *sql.Stmt, query string, args ...interface{}) (sql.Result, error) {
switch {
case stmt != nil && q.tx != nil:
return q.tx.StmtContext(ctx, stmt).ExecContext(ctx, args...)
case stmt != nil:
return stmt.ExecContext(ctx, args...)
default:
return q.db.ExecContext(ctx, query, args...)
}
}
func (q *Queries) query(ctx context.Context, stmt *sql.Stmt, query string, args ...interface{}) (*sql.Rows, error) {
switch {
case stmt != nil && q.tx != nil:
return q.tx.StmtContext(ctx, stmt).QueryContext(ctx, args...)
case stmt != nil:
return stmt.QueryContext(ctx, args...)
default:
return q.db.QueryContext(ctx, query, args...)
}
}
func (q *Queries) queryRow(ctx context.Context, stmt *sql.Stmt, query string, args ...interface{}) *sql.Row {
switch {
case stmt != nil && q.tx != nil:
return q.tx.StmtContext(ctx, stmt).QueryRowContext(ctx, args...)
case stmt != nil:
return stmt.QueryRowContext(ctx, args...)
default:
return q.db.QueryRowContext(ctx, query, args...)
}
}
type Queries struct {
db DBTX
db DBTX
tx *sql.Tx
clearItemProjectRequirementStmt *sql.Stmt
clearItemStatProgressStmt *sql.Stmt
deleteAllScopeMembersStmt *sql.Stmt
deleteItemStmt *sql.Stmt
deleteItemForRequirementStmt *sql.Stmt
deleteItemStatProgressStmt *sql.Stmt
deleteProjectStmt *sql.Stmt
deleteProjectRequirementStmt *sql.Stmt
deleteScopeStmt *sql.Stmt
deleteScopeMemberStmt *sql.Stmt
getItemStmt *sql.Stmt
getItemStatProgressBetweenStmt *sql.Stmt
getProjectStmt *sql.Stmt
getProjectRequirementStmt *sql.Stmt
getScopeStmt *sql.Stmt
getScopeDisplayNameStmt *sql.Stmt
getScopeWithDisplayNameStmt *sql.Stmt
insertItemStmt *sql.Stmt
insertProjectStmt *sql.Stmt
insertProjectRequirementStmt *sql.Stmt
insertScopeStmt *sql.Stmt
listItemStatProgressStmt *sql.Stmt
listItemStatProgressMultiStmt *sql.Stmt
listItemsAcquiredBetweenStmt *sql.Stmt
listItemsByProjectStmt *sql.Stmt
listItemsCreatedBetweenStmt *sql.Stmt
listItemsCreatedBetweenNoScopeStmt *sql.Stmt
listItemsLooseBetweenStmt *sql.Stmt
listItemsLooseBetweenNoScopeStmt *sql.Stmt
listItemsScheduledBetweenStmt *sql.Stmt
listItemsScheduledBetweenNoScopeStmt *sql.Stmt
listProjectEntriesStmt *sql.Stmt
listProjectRequirementStatsStmt *sql.Stmt
listProjectRequirementsByProjectIDStmt *sql.Stmt
listScopeMembersStmt *sql.Stmt
listScopesStmt *sql.Stmt
listScopesByUserStmt *sql.Stmt
listStatsStmt *sql.Stmt
replaceItemStatProgressStmt *sql.Stmt
updateItemStmt *sql.Stmt
updateProjectStmt *sql.Stmt
updateProjectRequirementStmt *sql.Stmt
updateScopeStmt *sql.Stmt
updateScopeMemberStmt *sql.Stmt
}
func (q *Queries) WithTx(tx *sql.Tx) *Queries {
return &Queries{
db: tx,
db: tx,
tx: tx,
clearItemProjectRequirementStmt: q.clearItemProjectRequirementStmt,
clearItemStatProgressStmt: q.clearItemStatProgressStmt,
deleteAllScopeMembersStmt: q.deleteAllScopeMembersStmt,
deleteItemStmt: q.deleteItemStmt,
deleteItemForRequirementStmt: q.deleteItemForRequirementStmt,
deleteItemStatProgressStmt: q.deleteItemStatProgressStmt,
deleteProjectStmt: q.deleteProjectStmt,
deleteProjectRequirementStmt: q.deleteProjectRequirementStmt,
deleteScopeStmt: q.deleteScopeStmt,
deleteScopeMemberStmt: q.deleteScopeMemberStmt,
getItemStmt: q.getItemStmt,
getItemStatProgressBetweenStmt: q.getItemStatProgressBetweenStmt,
getProjectStmt: q.getProjectStmt,
getProjectRequirementStmt: q.getProjectRequirementStmt,
getScopeStmt: q.getScopeStmt,
getScopeDisplayNameStmt: q.getScopeDisplayNameStmt,
getScopeWithDisplayNameStmt: q.getScopeWithDisplayNameStmt,
insertItemStmt: q.insertItemStmt,
insertProjectStmt: q.insertProjectStmt,
insertProjectRequirementStmt: q.insertProjectRequirementStmt,
insertScopeStmt: q.insertScopeStmt,
listItemStatProgressStmt: q.listItemStatProgressStmt,
listItemStatProgressMultiStmt: q.listItemStatProgressMultiStmt,
listItemsAcquiredBetweenStmt: q.listItemsAcquiredBetweenStmt,
listItemsByProjectStmt: q.listItemsByProjectStmt,
listItemsCreatedBetweenStmt: q.listItemsCreatedBetweenStmt,
listItemsCreatedBetweenNoScopeStmt: q.listItemsCreatedBetweenNoScopeStmt,
listItemsLooseBetweenStmt: q.listItemsLooseBetweenStmt,
listItemsLooseBetweenNoScopeStmt: q.listItemsLooseBetweenNoScopeStmt,
listItemsScheduledBetweenStmt: q.listItemsScheduledBetweenStmt,
listItemsScheduledBetweenNoScopeStmt: q.listItemsScheduledBetweenNoScopeStmt,
listProjectEntriesStmt: q.listProjectEntriesStmt,
listProjectRequirementStatsStmt: q.listProjectRequirementStatsStmt,
listProjectRequirementsByProjectIDStmt: q.listProjectRequirementsByProjectIDStmt,
listScopeMembersStmt: q.listScopeMembersStmt,
listScopesStmt: q.listScopesStmt,
listScopesByUserStmt: q.listScopesByUserStmt,
listStatsStmt: q.listStatsStmt,
replaceItemStatProgressStmt: q.replaceItemStatProgressStmt,
updateItemStmt: q.updateItemStmt,
updateProjectStmt: q.updateProjectStmt,
updateProjectRequirementStmt: q.updateProjectRequirementStmt,
updateScopeStmt: q.updateScopeStmt,
updateScopeMemberStmt: q.updateScopeMemberStmt,
}
}

67
internal/database/mysql/mysqlcore/item.sql.go

@ -13,12 +13,21 @@ import (
"git.aiterp.net/stufflog3/stufflog3-api/internal/sqltypes"
)
const clearItemProjectRequirement = `-- name: ClearItemProjectRequirement :exec
UPDATE item SET project_requirement_id = NULL WHERE project_requirement_id = ?
`
func (q *Queries) ClearItemProjectRequirement(ctx context.Context, projectRequirementID sql.NullInt32) error {
_, err := q.exec(ctx, q.clearItemProjectRequirementStmt, clearItemProjectRequirement, projectRequirementID)
return err
}
const clearItemStatProgress = `-- name: ClearItemStatProgress :exec
DELETE FROM item_stat_progress WHERE item_id = ?
`
func (q *Queries) ClearItemStatProgress(ctx context.Context, itemID int) error {
_, err := q.db.ExecContext(ctx, clearItemStatProgress, itemID)
_, err := q.exec(ctx, q.clearItemStatProgressStmt, clearItemStatProgress, itemID)
return err
}
@ -27,7 +36,16 @@ DELETE FROM item WHERE id = ?
`
func (q *Queries) DeleteItem(ctx context.Context, id int) error {
_, err := q.db.ExecContext(ctx, deleteItem, id)
_, err := q.exec(ctx, q.deleteItemStmt, deleteItem, id)
return err
}
const deleteItemForRequirement = `-- name: DeleteItemForRequirement :exec
DELETE FROM item WHERE project_requirement_id = ?
`
func (q *Queries) DeleteItemForRequirement(ctx context.Context, projectRequirementID sql.NullInt32) error {
_, err := q.exec(ctx, q.deleteItemForRequirementStmt, deleteItemForRequirement, projectRequirementID)
return err
}
@ -41,7 +59,7 @@ type DeleteItemStatProgressParams struct {
}
func (q *Queries) DeleteItemStatProgress(ctx context.Context, arg DeleteItemStatProgressParams) error {
_, err := q.db.ExecContext(ctx, deleteItemStatProgress, arg.ItemID, arg.StatID)
_, err := q.exec(ctx, q.deleteItemStatProgressStmt, deleteItemStatProgress, arg.ItemID, arg.StatID)
return err
}
@ -65,7 +83,7 @@ type GetItemRow struct {
}
func (q *Queries) GetItem(ctx context.Context, id int) (GetItemRow, error) {
row := q.db.QueryRowContext(ctx, getItem, id)
row := q.queryRow(ctx, q.getItemStmt, getItem, id)
var i GetItemRow
err := row.Scan(
&i.ID,
@ -107,7 +125,7 @@ type GetItemStatProgressBetweenRow struct {
}
func (q *Queries) GetItemStatProgressBetween(ctx context.Context, arg GetItemStatProgressBetweenParams) (GetItemStatProgressBetweenRow, error) {
row := q.db.QueryRowContext(ctx, getItemStatProgressBetween, arg.AcquiredTime, arg.AcquiredTime_2, arg.ScopeID)
row := q.queryRow(ctx, q.getItemStatProgressBetweenStmt, getItemStatProgressBetween, arg.AcquiredTime, arg.AcquiredTime_2, arg.ScopeID)
var i GetItemStatProgressBetweenRow
err := row.Scan(
&i.ID,
@ -136,7 +154,7 @@ type InsertItemParams struct {
}
func (q *Queries) InsertItem(ctx context.Context, arg InsertItemParams) (sql.Result, error) {
return q.db.ExecContext(ctx, insertItem,
return q.exec(ctx, q.insertItemStmt, insertItem,
arg.ScopeID,
arg.ProjectRequirementID,
arg.Name,
@ -163,7 +181,7 @@ type ListItemStatProgressRow struct {
}
func (q *Queries) ListItemStatProgress(ctx context.Context, itemID int) ([]ListItemStatProgressRow, error) {
rows, err := q.db.QueryContext(ctx, listItemStatProgress, itemID)
rows, err := q.query(ctx, q.listItemStatProgressStmt, listItemStatProgress, itemID)
if err != nil {
return nil, err
}
@ -218,7 +236,7 @@ type ListItemStatProgressMultiRow struct {
}
func (q *Queries) ListItemStatProgressMulti(ctx context.Context, arg ListItemStatProgressMultiParams) ([]ListItemStatProgressMultiRow, error) {
rows, err := q.db.QueryContext(ctx, listItemStatProgressMulti,
rows, err := q.query(ctx, q.listItemStatProgressMultiStmt, listItemStatProgressMulti,
arg.ItemID,
arg.ItemID_2,
arg.ItemID_3,
@ -260,8 +278,9 @@ const listItemsAcquiredBetween = `-- name: ListItemsAcquiredBetween :many
SELECT i.id, i.scope_id, i.project_requirement_id, i.name, i.description, i.created_time, i.created_user_id, i.acquired_time, i.scheduled_date, pr.project_id FROM item i
LEFT JOIN project_requirement pr ON pr.id = i.project_requirement_id
WHERE i.acquired_time >= ?
AND i.acquired_time < ?
AND i.acquired_time <= ?
AND i.scope_id = ?
ORDER BY acquired_time DESC, created_time DESC
`
type ListItemsAcquiredBetweenParams struct {
@ -284,7 +303,7 @@ type ListItemsAcquiredBetweenRow struct {
}
func (q *Queries) ListItemsAcquiredBetween(ctx context.Context, arg ListItemsAcquiredBetweenParams) ([]ListItemsAcquiredBetweenRow, error) {
rows, err := q.db.QueryContext(ctx, listItemsAcquiredBetween, arg.AcquiredTime, arg.AcquiredTime_2, arg.ScopeID)
rows, err := q.query(ctx, q.listItemsAcquiredBetweenStmt, listItemsAcquiredBetween, arg.AcquiredTime, arg.AcquiredTime_2, arg.ScopeID)
if err != nil {
return nil, err
}
@ -337,7 +356,7 @@ type ListItemsByProjectRow struct {
}
func (q *Queries) ListItemsByProject(ctx context.Context, projectID int) ([]ListItemsByProjectRow, error) {
rows, err := q.db.QueryContext(ctx, listItemsByProject, projectID)
rows, err := q.query(ctx, q.listItemsByProjectStmt, listItemsByProject, projectID)
if err != nil {
return nil, err
}
@ -374,8 +393,9 @@ const listItemsCreatedBetween = `-- name: ListItemsCreatedBetween :many
SELECT i.id, i.scope_id, i.project_requirement_id, i.name, i.description, i.created_time, i.created_user_id, i.acquired_time, i.scheduled_date, pr.project_id FROM item i
LEFT JOIN project_requirement pr ON pr.id = i.project_requirement_id
WHERE i.created_time >= ?
AND i.created_time < ?
AND i.created_time <= ?
AND i.scope_id = ?
ORDER BY created_time DESC
`
type ListItemsCreatedBetweenParams struct {
@ -398,7 +418,7 @@ type ListItemsCreatedBetweenRow struct {
}
func (q *Queries) ListItemsCreatedBetween(ctx context.Context, arg ListItemsCreatedBetweenParams) ([]ListItemsCreatedBetweenRow, error) {
rows, err := q.db.QueryContext(ctx, listItemsCreatedBetween, arg.CreatedTime, arg.CreatedTime_2, arg.ScopeID)
rows, err := q.query(ctx, q.listItemsCreatedBetweenStmt, listItemsCreatedBetween, arg.CreatedTime, arg.CreatedTime_2, arg.ScopeID)
if err != nil {
return nil, err
}
@ -457,7 +477,7 @@ type ListItemsCreatedBetweenNoScopeRow struct {
}
func (q *Queries) ListItemsCreatedBetweenNoScope(ctx context.Context, arg ListItemsCreatedBetweenNoScopeParams) ([]ListItemsCreatedBetweenNoScopeRow, error) {
rows, err := q.db.QueryContext(ctx, listItemsCreatedBetweenNoScope, arg.CreatedTime, arg.CreatedTime_2)
rows, err := q.query(ctx, q.listItemsCreatedBetweenNoScopeStmt, listItemsCreatedBetweenNoScope, arg.CreatedTime, arg.CreatedTime_2)
if err != nil {
return nil, err
}
@ -494,10 +514,12 @@ const listItemsLooseBetween = `-- name: ListItemsLooseBetween :many
SELECT i.id, i.scope_id, i.project_requirement_id, i.name, i.description, i.created_time, i.created_user_id, i.acquired_time, i.scheduled_date, pr.project_id FROM item i
LEFT JOIN project_requirement pr ON pr.id = i.project_requirement_id
WHERE i.created_time >= ?
AND i.created_time < ?
AND i.created_time <= ?
AND i.scope_id = ?
AND i.scheduled_date IS NULL
AND i.acquired_time IS NULL
AND i.project_requirement_id IS NULL
ORDER BY created_time DESC
`
type ListItemsLooseBetweenParams struct {
@ -520,7 +542,7 @@ type ListItemsLooseBetweenRow struct {
}
func (q *Queries) ListItemsLooseBetween(ctx context.Context, arg ListItemsLooseBetweenParams) ([]ListItemsLooseBetweenRow, error) {
rows, err := q.db.QueryContext(ctx, listItemsLooseBetween, arg.CreatedTime, arg.CreatedTime_2, arg.ScopeID)
rows, err := q.query(ctx, q.listItemsLooseBetweenStmt, listItemsLooseBetween, arg.CreatedTime, arg.CreatedTime_2, arg.ScopeID)
if err != nil {
return nil, err
}
@ -581,7 +603,7 @@ type ListItemsLooseBetweenNoScopeRow struct {
}
func (q *Queries) ListItemsLooseBetweenNoScope(ctx context.Context, arg ListItemsLooseBetweenNoScopeParams) ([]ListItemsLooseBetweenNoScopeRow, error) {
rows, err := q.db.QueryContext(ctx, listItemsLooseBetweenNoScope, arg.CreatedTime, arg.CreatedTime_2)
rows, err := q.query(ctx, q.listItemsLooseBetweenNoScopeStmt, listItemsLooseBetweenNoScope, arg.CreatedTime, arg.CreatedTime_2)
if err != nil {
return nil, err
}
@ -618,8 +640,9 @@ const listItemsScheduledBetween = `-- name: ListItemsScheduledBetween :many
SELECT i.id, i.scope_id, i.project_requirement_id, i.name, i.description, i.created_time, i.created_user_id, i.acquired_time, i.scheduled_date, pr.project_id FROM item i
LEFT JOIN project_requirement pr ON pr.id = i.project_requirement_id
WHERE i.scheduled_date >= ?
AND i.scheduled_date < ?
AND i.scheduled_date <= ?
AND i.scope_id = ?
ORDER BY scheduled_date, created_time
`
type ListItemsScheduledBetweenParams struct {
@ -642,7 +665,7 @@ type ListItemsScheduledBetweenRow struct {
}
func (q *Queries) ListItemsScheduledBetween(ctx context.Context, arg ListItemsScheduledBetweenParams) ([]ListItemsScheduledBetweenRow, error) {
rows, err := q.db.QueryContext(ctx, listItemsScheduledBetween, arg.ScheduledDate, arg.ScheduledDate_2, arg.ScopeID)
rows, err := q.query(ctx, q.listItemsScheduledBetweenStmt, listItemsScheduledBetween, arg.ScheduledDate, arg.ScheduledDate_2, arg.ScopeID)
if err != nil {
return nil, err
}
@ -701,7 +724,7 @@ type ListItemsScheduledBetweenNoScopeRow struct {
}
func (q *Queries) ListItemsScheduledBetweenNoScope(ctx context.Context, arg ListItemsScheduledBetweenNoScopeParams) ([]ListItemsScheduledBetweenNoScopeRow, error) {
rows, err := q.db.QueryContext(ctx, listItemsScheduledBetweenNoScope, arg.ScheduledDate, arg.ScheduledDate_2)
rows, err := q.query(ctx, q.listItemsScheduledBetweenNoScopeStmt, listItemsScheduledBetweenNoScope, arg.ScheduledDate, arg.ScheduledDate_2)
if err != nil {
return nil, err
}
@ -747,7 +770,7 @@ type ReplaceItemStatProgressParams struct {
}
func (q *Queries) ReplaceItemStatProgress(ctx context.Context, arg ReplaceItemStatProgressParams) error {
_, err := q.db.ExecContext(ctx, replaceItemStatProgress,
_, err := q.exec(ctx, q.replaceItemStatProgressStmt, replaceItemStatProgress,
arg.ItemID,
arg.StatID,
arg.Acquired,
@ -778,7 +801,7 @@ type UpdateItemParams struct {
}
func (q *Queries) UpdateItem(ctx context.Context, arg UpdateItemParams) error {
_, err := q.db.ExecContext(ctx, updateItem,
_, err := q.exec(ctx, q.updateItemStmt, updateItem,
arg.ProjectRequirementID,
arg.Name,
arg.Description,

201
internal/database/mysql/mysqlcore/project.sql.go

@ -7,14 +7,34 @@ package mysqlcore
import (
"context"
"database/sql"
"time"
)
const deleteProject = `-- name: DeleteProject :exec
DELETE FROM project WHERE id = ?
`
func (q *Queries) DeleteProject(ctx context.Context, id int) error {
_, err := q.exec(ctx, q.deleteProjectStmt, deleteProject, id)
return err
}
const deleteProjectRequirement = `-- name: DeleteProjectRequirement :exec
DELETE FROM project_requirement WHERE id = ?
`
func (q *Queries) DeleteProjectRequirement(ctx context.Context, id int) error {
_, err := q.exec(ctx, q.deleteProjectRequirementStmt, deleteProjectRequirement, id)
return err
}
const getProject = `-- name: GetProject :one
SELECT id, scope_id, author_id, name, status, description, created_time FROM project WHERE id = ?
`
func (q *Queries) GetProject(ctx context.Context, id int) (Project, error) {
row := q.db.QueryRowContext(ctx, getProject, id)
row := q.queryRow(ctx, q.getProjectStmt, getProject, id)
var i Project
err := row.Scan(
&i.ID,
@ -28,20 +48,88 @@ func (q *Queries) GetProject(ctx context.Context, id int) (Project, error) {
return i, err
}
const getProjectRequirement = `-- name: GetProjectRequirement :one
SELECT id, scope_id, project_id, name, status, description FROM project_requirement WHERE id = ?
`
func (q *Queries) GetProjectRequirement(ctx context.Context, id int) (ProjectRequirement, error) {
row := q.queryRow(ctx, q.getProjectRequirementStmt, getProjectRequirement, id)
var i ProjectRequirement
err := row.Scan(
&i.ID,
&i.ScopeID,
&i.ProjectID,
&i.Name,
&i.Status,
&i.Description,
)
return i, err
}
const insertProject = `-- name: InsertProject :execresult
INSERT INTO project (scope_id, author_id, name, status, description, created_time)
VALUES (?, ?, ?, ?, ?, ?)
`
type InsertProjectParams struct {
ScopeID int
AuthorID string
Name string
Status int
Description string
CreatedTime time.Time
}
func (q *Queries) InsertProject(ctx context.Context, arg InsertProjectParams) (sql.Result, error) {
return q.exec(ctx, q.insertProjectStmt, insertProject,
arg.ScopeID,
arg.AuthorID,
arg.Name,
arg.Status,
arg.Description,
arg.CreatedTime,
)
}
const insertProjectRequirement = `-- name: InsertProjectRequirement :execresult
INSERT INTO project_requirement (scope_id, project_id, name, status, description)
VALUES (?, ?, ?, ?, ?)
`
type InsertProjectRequirementParams struct {
ScopeID int
ProjectID int
Name string
Status int
Description string
}
func (q *Queries) InsertProjectRequirement(ctx context.Context, arg InsertProjectRequirementParams) (sql.Result, error) {
return q.exec(ctx, q.insertProjectRequirementStmt, insertProjectRequirement,
arg.ScopeID,
arg.ProjectID,
arg.Name,
arg.Status,
arg.Description,
)
}
const listProjectEntries = `-- name: ListProjectEntries :many
SELECT id, name, status FROM project
SELECT id, name, status, created_time, author_id FROM project
WHERE scope_id = ?
ORDER BY status, created_time
`
type ListProjectEntriesRow struct {
ID int
Name string
Status int
ID int
Name string
Status int
CreatedTime time.Time
AuthorID string
}
func (q *Queries) ListProjectEntries(ctx context.Context, scopeID int) ([]ListProjectEntriesRow, error) {
rows, err := q.db.QueryContext(ctx, listProjectEntries, scopeID)
rows, err := q.query(ctx, q.listProjectEntriesStmt, listProjectEntries, scopeID)
if err != nil {
return nil, err
}
@ -49,7 +137,54 @@ func (q *Queries) ListProjectEntries(ctx context.Context, scopeID int) ([]ListPr
items := []ListProjectEntriesRow{}
for rows.Next() {
var i ListProjectEntriesRow
if err := rows.Scan(&i.ID, &i.Name, &i.Status); err != nil {
if err := rows.Scan(
&i.ID,
&i.Name,
&i.Status,
&i.CreatedTime,
&i.AuthorID,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listProjectRequirementStats = `-- name: ListProjectRequirementStats :many
SELECT prs.required, s.id, s.name, s.weight FROM project_requirement_stat prs
RIGHT JOIN stat s ON s.id = prs.stat_id
WHERE project_requirement_id = ?
`
type ListProjectRequirementStatsRow struct {
Required sql.NullInt32
ID int
Name string
Weight float64
}
func (q *Queries) ListProjectRequirementStats(ctx context.Context, projectRequirementID int) ([]ListProjectRequirementStatsRow, error) {
rows, err := q.query(ctx, q.listProjectRequirementStatsStmt, listProjectRequirementStats, projectRequirementID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []ListProjectRequirementStatsRow{}
for rows.Next() {
var i ListProjectRequirementStatsRow
if err := rows.Scan(
&i.Required,
&i.ID,
&i.Name,
&i.Weight,
); err != nil {
return nil, err
}
items = append(items, i)
@ -68,7 +203,7 @@ SELECT id, scope_id, project_id, name, status, description FROM project_requirem
`
func (q *Queries) ListProjectRequirementsByProjectID(ctx context.Context, projectID int) ([]ProjectRequirement, error) {
rows, err := q.db.QueryContext(ctx, listProjectRequirementsByProjectID, projectID)
rows, err := q.query(ctx, q.listProjectRequirementsByProjectIDStmt, listProjectRequirementsByProjectID, projectID)
if err != nil {
return nil, err
}
@ -96,3 +231,53 @@ func (q *Queries) ListProjectRequirementsByProjectID(ctx context.Context, projec
}
return items, nil
}
const updateProject = `-- name: UpdateProject :exec
UPDATE project
SET name = ?,
status = ?,
description = ?
WHERE id = ?
`
type UpdateProjectParams struct {
Name string
Status int
Description string
ID int
}
func (q *Queries) UpdateProject(ctx context.Context, arg UpdateProjectParams) error {
_, err := q.exec(ctx, q.updateProjectStmt, updateProject,
arg.Name,
arg.Status,
arg.Description,
arg.ID,
)
return err
}
const updateProjectRequirement = `-- name: UpdateProjectRequirement :exec
UPDATE project_requirement
SET name = ?,
status = ?,
description = ?
WHERE id = ?
`
type UpdateProjectRequirementParams struct {
Name string
Status int
Description string
ID int
}
func (q *Queries) UpdateProjectRequirement(ctx context.Context, arg UpdateProjectRequirementParams) error {
_, err := q.exec(ctx, q.updateProjectRequirementStmt, updateProjectRequirement,
arg.Name,
arg.Status,
arg.Description,
arg.ID,
)
return err
}

24
internal/database/mysql/mysqlcore/scope.sql.go

@ -15,7 +15,7 @@ DELETE FROM scope_member WHERE scope_id=?
`
func (q *Queries) DeleteAllScopeMembers(ctx context.Context, scopeID int) error {
_, err := q.db.ExecContext(ctx, deleteAllScopeMembers, scopeID)
_, err := q.exec(ctx, q.deleteAllScopeMembersStmt, deleteAllScopeMembers, scopeID)
return err
}
@ -24,7 +24,7 @@ DELETE FROM scope WHERE id=?
`
func (q *Queries) DeleteScope(ctx context.Context, id int) error {
_, err := q.db.ExecContext(ctx, deleteScope, id)
_, err := q.exec(ctx, q.deleteScopeStmt, deleteScope, id)
return err
}
@ -38,7 +38,7 @@ type DeleteScopeMemberParams struct {
}
func (q *Queries) DeleteScopeMember(ctx context.Context, arg DeleteScopeMemberParams) error {
_, err := q.db.ExecContext(ctx, deleteScopeMember, arg.ScopeID, arg.UserID)
_, err := q.exec(ctx, q.deleteScopeMemberStmt, deleteScopeMember, arg.ScopeID, arg.UserID)
return err
}
@ -48,7 +48,7 @@ WHERE id = ?
`
func (q *Queries) GetScope(ctx context.Context, id int) (Scope, error) {
row := q.db.QueryRowContext(ctx, getScope, id)
row := q.queryRow(ctx, q.getScopeStmt, getScope, id)
var i Scope
err := row.Scan(&i.ID, &i.Name, &i.Abbreviation)
return i, err
@ -65,7 +65,7 @@ type GetScopeDisplayNameParams struct {
}
func (q *Queries) GetScopeDisplayName(ctx context.Context, arg GetScopeDisplayNameParams) (string, error) {
row := q.db.QueryRowContext(ctx, getScopeDisplayName, arg.UserID, arg.ScopeID)
row := q.queryRow(ctx, q.getScopeDisplayNameStmt, getScopeDisplayName, arg.UserID, arg.ScopeID)
var name string
err := row.Scan(&name)
return name, err
@ -90,7 +90,7 @@ type GetScopeWithDisplayNameRow struct {
}
func (q *Queries) GetScopeWithDisplayName(ctx context.Context, arg GetScopeWithDisplayNameParams) (GetScopeWithDisplayNameRow, error) {
row := q.db.QueryRowContext(ctx, getScopeWithDisplayName, arg.ID, arg.UserID)
row := q.queryRow(ctx, q.getScopeWithDisplayNameStmt, getScopeWithDisplayName, arg.ID, arg.UserID)
var i GetScopeWithDisplayNameRow
err := row.Scan(
&i.ID,
@ -113,7 +113,7 @@ type InsertScopeParams struct {
}
func (q *Queries) InsertScope(ctx context.Context, arg InsertScopeParams) (sql.Result, error) {
return q.db.ExecContext(ctx, insertScope, arg.ID, arg.Name, arg.Abbreviation)
return q.exec(ctx, q.insertScopeStmt, insertScope, arg.ID, arg.Name, arg.Abbreviation)
}
const listScopeMembers = `-- name: ListScopeMembers :many
@ -129,7 +129,7 @@ type ListScopeMembersRow struct {
}
func (q *Queries) ListScopeMembers(ctx context.Context, scopeID int) ([]ListScopeMembersRow, error) {
rows, err := q.db.QueryContext(ctx, listScopeMembers, scopeID)
rows, err := q.query(ctx, q.listScopeMembersStmt, listScopeMembers, scopeID)
if err != nil {
return nil, err
}
@ -157,7 +157,7 @@ ORDER BY name
`
func (q *Queries) ListScopes(ctx context.Context) ([]Scope, error) {
rows, err := q.db.QueryContext(ctx, listScopes)
rows, err := q.query(ctx, q.listScopesStmt, listScopes)
if err != nil {
return nil, err
}
@ -194,7 +194,7 @@ type ListScopesByUserRow struct {
}
func (q *Queries) ListScopesByUser(ctx context.Context, userID string) ([]ListScopesByUserRow, error) {
rows, err := q.db.QueryContext(ctx, listScopesByUser, userID)
rows, err := q.query(ctx, q.listScopesByUserStmt, listScopesByUser, userID)
if err != nil {
return nil, err
}
@ -232,7 +232,7 @@ type UpdateScopeParams struct {
}
func (q *Queries) UpdateScope(ctx context.Context, arg UpdateScopeParams) error {
_, err := q.db.ExecContext(ctx, updateScope, arg.Name, arg.Abbreviation, arg.ID)
_, err := q.exec(ctx, q.updateScopeStmt, updateScope, arg.Name, arg.Abbreviation, arg.ID)
return err
}
@ -249,7 +249,7 @@ type UpdateScopeMemberParams struct {
}
func (q *Queries) UpdateScopeMember(ctx context.Context, arg UpdateScopeMemberParams) error {
_, err := q.db.ExecContext(ctx, updateScopeMember,
_, err := q.exec(ctx, q.updateScopeMemberStmt, updateScopeMember,
arg.ScopeID,
arg.UserID,
arg.Name,

2
internal/database/mysql/mysqlcore/stats.sql.go

@ -25,7 +25,7 @@ type ListStatsRow struct {
}
func (q *Queries) ListStats(ctx context.Context, scopeID int) ([]ListStatsRow, error) {
rows, err := q.db.QueryContext(ctx, listStats, scopeID)
rows, err := q.query(ctx, q.listStatsStmt, listStats, scopeID)
if err != nil {
return nil, err
}

180
internal/database/mysql/project.go

@ -0,0 +1,180 @@
package mysql
import (
"context"
"database/sql"
"git.aiterp.net/stufflog3/stufflog3-api/internal/database/mysql/mysqlcore"
"git.aiterp.net/stufflog3/stufflog3-api/internal/models"
"git.aiterp.net/stufflog3/stufflog3-api/internal/slerrors"
"golang.org/x/sync/errgroup"
)
type projectRepository struct {
db *sql.DB
q *mysqlcore.Queries
items *itemRepository
scopeID int
}
func (r *projectRepository) Find(ctx context.Context, id int) (*models.Project, error) {
row, err := r.q.GetProject(ctx, id)
if err == sql.ErrNoRows || row.ScopeID != r.scopeID {
return nil, slerrors.NotFound("Project")
} else if err != nil {
return nil, err
}
project := models.Project{
ProjectEntry: models.ProjectEntry{
ID: row.ID,
OwnerID: row.AuthorID,
CreatedTime: row.CreatedTime,
Name: row.Name,
Status: models.Status(row.Status),
},
Description: row.Description,
Requirements: []models.ProjectRequirement{},
}
reqs, err := r.q.ListProjectRequirementsByProjectID(ctx, id)
if err != nil && err != sql.ErrNoRows {
return nil, err
}
itemRows, err := r.q.ListItemsByProject(ctx, id)
if err != nil && err != sql.ErrNoRows {
return nil, err
}
items := make([]models.Item, 0, len(itemRows))
for _, itemRow := range itemRows {
item := r.items.resToItem(mysqlcore.ListItemsAcquiredBetweenRow(itemRow))
items = append(items, item)
}
err = r.items.fillStats(ctx, items)
if err != nil {
return nil, err
}
eg, ctx := errgroup.WithContext(ctx)
for i := range reqs {
project.Requirements = append(project.Requirements, models.ProjectRequirement{
ID: reqs[i].ID,
Name: reqs[i].Name,
Description: reqs[i].Description,
Status: models.Status(reqs[i].Status),
Stats: []models.StatProgressEntry{},
Items: nil,
})
requirement := &project.Requirements[len(project.Requirements)-1]
for _, item := range items {
if *item.ProjectRequirementID == requirement.ID {
requirement.Items = append(requirement.Items, item)
}
}
eg.Go(func() error {
stats, err := r.q.ListProjectRequirementStats(ctx, requirement.ID)
if err != nil && err != sql.ErrNoRows {
return err
}
for _, statRow := range stats {
stat := models.StatProgressEntry{
StatEntry: models.StatEntry{
ID: statRow.ID,
Name: statRow.Name,
Weight: statRow.Weight,
},
Acquired: 0,
Required: int(statRow.Required.Int32),
}
for _, item := range requirement.Items {
for _, stat2 := range item.Stats {
if stat2.ID == stat.ID {
stat.Acquired += stat2.Acquired
}
}
}
requirement.Stats = append(requirement.Stats, stat)
}
return nil
})
}
err = eg.Wait()
if err != nil {
return nil, err
}
return &project, nil
}
func (r *projectRepository) List(ctx context.Context) ([]models.ProjectEntry, error) {
rows, err := r.q.ListProjectEntries(ctx, r.scopeID)
if err != nil && err != sql.ErrNoRows {
return nil, err
}
projects := make([]models.ProjectEntry, 0, len(rows))
for _, row := range rows {
projects = append(projects, models.ProjectEntry{
ID: row.ID,
OwnerID: row.AuthorID,
CreatedTime: row.CreatedTime,
Name: row.Name,
Status: models.Status(row.Status),
})
}
return projects, nil
}
func (r *projectRepository) Create(ctx context.Context, project models.Project) (*models.Project, error) {
res, err := r.q.InsertProject(ctx, mysqlcore.InsertProjectParams{
ScopeID: r.scopeID,
AuthorID: project.OwnerID,
Name: project.Name,
Status: int(project.Status),
Description: project.Description,
CreatedTime: project.CreatedTime,
})
if err != nil {
return nil, err
}
id, err := res.LastInsertId()
if err != nil {
return nil, err
}
return r.Find(ctx, int(id))
}
func (r *projectRepository) Update(ctx context.Context, project models.Project) (*models.Project, error) {
//TODO implement me
panic("implement me")
}
func (r *projectRepository) Delete(ctx context.Context, project models.ProjectEntry) error {
//TODO implement me
panic("implement me")
}
func (r *projectRepository) AddRequirement(ctx context.Context, project models.ProjectEntry, requirement models.ProjectRequirement) {
//TODO implement me
panic("implement me")
}
func (r *projectRepository) UpdateRequirement(ctx context.Context, project models.ProjectEntry, requirement models.ProjectRequirement, update models.ProjectRequirementUpdate) {
//TODO implement me
panic("implement me")
}
func (r *projectRepository) DeleteRequirement(ctx context.Context, project models.ProjectEntry, requirement models.ProjectRequirement, deleteItems bool) {
//TODO implement me
panic("implement me")
}

27
internal/database/mysql/queries/item.sql

@ -12,31 +12,36 @@ WHERE pr.project_id = ?;
SELECT i.*, pr.project_id FROM item i
LEFT JOIN project_requirement pr ON pr.id = i.project_requirement_id
WHERE i.acquired_time >= ?
AND i.acquired_time < ?
AND i.scope_id = ?;
AND i.acquired_time <= ?
AND i.scope_id = ?
ORDER BY acquired_time DESC, created_time DESC;
-- name: ListItemsScheduledBetween :many
SELECT i.*, pr.project_id FROM item i
LEFT JOIN project_requirement pr ON pr.id = i.project_requirement_id
WHERE i.scheduled_date >= ?
AND i.scheduled_date < ?
AND i.scope_id = ?;
AND i.scheduled_date <= ?
AND i.scope_id = ?
ORDER BY scheduled_date, created_time;
-- name: ListItemsCreatedBetween :many
SELECT i.*, pr.project_id FROM item i
LEFT JOIN project_requirement pr ON pr.id = i.project_requirement_id
WHERE i.created_time >= ?
AND i.created_time < ?
AND i.scope_id = ?;
AND i.created_time <= ?
AND i.scope_id = ?
ORDER BY created_time DESC;
-- name: ListItemsLooseBetween :many
SELECT i.*, pr.project_id FROM item i
LEFT JOIN project_requirement pr ON pr.id = i.project_requirement_id
WHERE i.created_time >= ?
AND i.created_time < ?
AND i.created_time <= ?
AND i.scope_id = ?
AND i.scheduled_date IS NULL
AND i.acquired_time IS NULL;
AND i.acquired_time IS NULL
AND i.project_requirement_id IS NULL
ORDER BY created_time DESC;
-- name: ListItemsScheduledBetweenNoScope :many
SELECT i.*, pr.project_id FROM item i
@ -94,6 +99,12 @@ WHERE id = ?;
-- name: DeleteItem :exec
DELETE FROM item WHERE id = ?;
-- name: DeleteItemForRequirement :exec
DELETE FROM item WHERE project_requirement_id = ?;
-- name: ClearItemProjectRequirement :exec
UPDATE item SET project_requirement_id = NULL WHERE project_requirement_id = ?;
-- name: ReplaceItemStatProgress :exec
REPLACE INTO item_stat_progress (item_id, stat_id, acquired, required)
VALUES (?, ?, ?, ?);

39
internal/database/mysql/queries/project.sql

@ -1,11 +1,48 @@
-- name: ListProjectEntries :many
SELECT id, name, status FROM project
SELECT id, name, status, created_time, author_id FROM project
WHERE scope_id = ?
ORDER BY status, created_time;
-- name: GetProject :one
SELECT * FROM project WHERE id = ?;
-- name: GetProjectRequirement :one
SELECT * FROM project_requirement WHERE id = ?;
-- name: ListProjectRequirementsByProjectID :many
SELECT * FROM project_requirement WHERE project_id = ?;
-- name: ListProjectRequirementStats :many
SELECT prs.required, s.id, s.name, s.weight FROM project_requirement_stat prs
RIGHT JOIN stat s ON s.id = prs.stat_id
WHERE project_requirement_id = ?;
-- name: InsertProject :execresult
INSERT INTO project (scope_id, author_id, name, status, description, created_time)
VALUES (?, ?, ?, ?, ?, ?);
-- name: UpdateProject :exec
UPDATE project
SET name = ?,
status = ?,
description = ?
WHERE id = ?;
-- name: DeleteProject :exec
DELETE FROM project WHERE id = ?;
-- name: InsertProjectRequirement :execresult
INSERT INTO project_requirement (scope_id, project_id, name, status, description)
VALUES (?, ?, ?, ?, ?);
-- name: UpdateProjectRequirement :exec
UPDATE project_requirement
SET name = ?,
status = ?,
description = ?
WHERE id = ?;
-- name: DeleteProjectRequirement :exec
DELETE FROM project_requirement WHERE id = ?;

33
internal/database/mysql/scopes.go

@ -4,21 +4,20 @@ import (
"context"
"database/sql"
"encoding/json"
"golang.org/x/sync/errgroup"
"sort"
"git.aiterp.net/stufflog3/stufflog3-api/internal/database/mysql/mysqlcore"
"git.aiterp.net/stufflog3/stufflog3-api/internal/models"
"git.aiterp.net/stufflog3/stufflog3-api/internal/slerrors"
"golang.org/x/sync/errgroup"
"sort"
)
type scopeRepository struct {
db *sql.DB
q *mysqlcore.Queries
}
func (r *scopeRepository) Find(ctx context.Context, id int, full bool) (*models.Scope, error) {
q := mysqlcore.New(r.db)
scope, err := q.GetScope(ctx, id)
scope, err := r.q.GetScope(ctx, id)
if err != nil {
if err == sql.ErrNoRows {
return nil, slerrors.NotFound("Scope")
@ -39,16 +38,18 @@ func (r *scopeRepository) Find(ctx context.Context, id int, full bool) (*models.
if full {
eg.Go(func() error {
projects, err := q.ListProjectEntries(ctx, id)
projects, err := r.q.ListProjectEntries(ctx, id)
if err != nil && err != sql.ErrNoRows {
return err
}
for _, project := range projects {
res.Projects = append(res.Projects, models.ProjectEntry{
ID: project.ID,
Name: project.Name,
Status: models.Status(project.Status),
ID: project.ID,
OwnerID: project.AuthorID,
CreatedTime: project.CreatedTime,
Name: project.Name,
Status: models.Status(project.Status),
})
}
@ -56,7 +57,7 @@ func (r *scopeRepository) Find(ctx context.Context, id int, full bool) (*models.
})
eg.Go(func() error {
stats, err := q.ListStats(ctx, id)
stats, err := r.q.ListStats(ctx, id)
if err != nil && err != sql.ErrNoRows {
return err
}
@ -87,7 +88,7 @@ func (r *scopeRepository) Find(ctx context.Context, id int, full bool) (*models.
}
eg.Go(func() error {
members, err := q.ListScopeMembers(ctx, id)
members, err := r.q.ListScopeMembers(ctx, id)
if err != nil && err != sql.ErrNoRows {
return err
}
@ -112,8 +113,7 @@ func (r *scopeRepository) Find(ctx context.Context, id int, full bool) (*models.
}
func (r *scopeRepository) List(ctx context.Context) ([]models.ScopeEntry, error) {
q := mysqlcore.New(r.db)
scopes, err := q.ListScopes(ctx)
scopes, err := r.q.ListScopes(ctx)
if err != nil {
return nil, err
}
@ -131,8 +131,7 @@ func (r *scopeRepository) List(ctx context.Context) ([]models.ScopeEntry, error)
}
func (r *scopeRepository) ListByUser(ctx context.Context, userID string) ([]models.ScopeEntry, error) {
q := mysqlcore.New(r.db)
scopes, err := q.ListScopesByUser(ctx, userID)
scopes, err := r.q.ListScopesByUser(ctx, userID)
if err != nil {
return nil, err
}
@ -156,7 +155,7 @@ func (r *scopeRepository) Create(ctx context.Context, scope models.ScopeEntry, o
}
defer tx.Rollback()
q := mysqlcore.New(tx)
q := r.q.WithTx(tx)
res, err := q.InsertScope(ctx, mysqlcore.InsertScopeParams(scope))
if err != nil {
return nil, err
@ -212,7 +211,7 @@ func (r *scopeRepository) Delete(ctx context.Context, scope models.Scope) error
}
defer tx.Rollback()
q := mysqlcore.New(tx)
q := r.q.WithTx(tx)
err = q.DeleteAllScopeMembers(ctx, scope.ID)
if err != nil {
return err

2
internal/models/item.go

@ -16,7 +16,6 @@ type Item struct {
ScheduledDate *Date `json:"scheduledDate"`
Stats []StatProgressEntry `json:"stats,omitempty"`
Owner *ScopeMember `json:"owner,omitempty"`
}
func (item *Item) ApplyUpdate(update ItemUpdate) {
@ -25,7 +24,6 @@ func (item *Item) ApplyUpdate(update ItemUpdate) {
}
if update.OwnerID != nil {
item.OwnerID = *update.OwnerID
item.Owner = nil
}
if update.Name != nil {
item.Name = *update.Name

47
internal/models/project.go

@ -1,9 +1,13 @@
package models
import "time"
type ProjectEntry struct {
ID int `json:"id"`
Name string `json:"name"`
Status Status `json:"status"`
ID int `json:"id"`
OwnerID string `json:"ownerId,omitempty"`
CreatedTime time.Time `json:"createdTime"`
Name string `json:"name"`
Status Status `json:"status"`
}
type ProjectRequirement struct {
@ -15,6 +19,39 @@ type ProjectRequirement struct {
Items []Item `json:"items,omitempty"`
}
func (requirement *ProjectRequirement) Update(update ProjectRequirementUpdate) {
if update.Name != nil {
requirement.Name = *update.Name
}
if update.Description != nil {
requirement.Description = *update.Description
}
if update.Status != nil {
requirement.Status = *update.Status
}
deleteList := make([]int, 0, len(update.Stats))
for i, stat := range update.Stats {
if stat.Acquired == 0 && stat.Required == 0 {
deleteList = append(deleteList, i-len(deleteList))
}
found := false
for j := range requirement.Stats {
if requirement.Stats[j].ID == stat.ID {
requirement.Stats[j].Required = stat.Required
requirement.Stats[j].Acquired = stat.Acquired
found = true
break
}
}
if !found {
requirement.Stats = append(requirement.Stats, stat)
}
}
}
type ProjectRequirementUpdate struct {
Name *string `json:"name"`
Description *string `json:"description"`
@ -24,6 +61,6 @@ type ProjectRequirementUpdate struct {
type Project struct {
ProjectEntry
Description string
Requirements []ProjectRequirement
Description string `json:"description"`
Requirements []ProjectRequirement `json:"requirements"`
}

9
internal/models/scope.go

@ -15,10 +15,11 @@ type ScopeMember struct {
type Scope struct {
ScopeEntry
DisplayName string `json:"displayName"`
Members []ScopeMember `json:"members,omitempty"`
Projects []ProjectEntry `json:"projects,omitempty"`
Stats []Stat `json:"stats,omitempty"`
DisplayName string `json:"displayName"`
Members []ScopeMember `json:"members,omitempty"`
Projects []ProjectEntry `json:"projects,omitempty"`
Stats []Stat `json:"stats,omitempty"`
StatusLabels map[Status]string `json:"statusLabels,omitempty"` // Not stored as part of scope, but may be in the future.
}
func (s *Scope) Member(id string) *ScopeMember {

20
internal/models/status.go

@ -2,14 +2,20 @@ package models
type Status int
func (s Status) Valid() bool {
return s >= 0 && s < maxStatus
}
const (
Blocked Status = 0
Available Status = 1
Background Status = 2
Active Status = 3
Completed Status = 4
Failed Status = 5
Dropped Status = 6
Blocked Status = iota
Available
Background
Active
Completed
Failed
Dropped
maxStatus
)
var StatusLabels = map[Status]string{

2
internal/slerrors/notfound.go

@ -5,7 +5,7 @@ type notFoundError struct {
}
func (err *notFoundError) Error() string {
return err.Subject + " not found"
return err.Subject + " not found or inaccessible"
}
func NotFound(subject string) error {

2
sqlc.yaml

@ -5,7 +5,7 @@ packages:
queries: "./internal/database/mysql/queries"
schema: "./scripts/goose-mysql"
engine: "mysql"
emit_prepared_queries: false
emit_prepared_queries: true
emit_interface: false
emit_exact_table_names: false
emit_empty_slices: true

Loading…
Cancel
Save