Browse Source

item repository and api progress.

mian
Gisle Aune 2 years ago
parent
commit
b2624dc4ab
  1. 39
      api/common.go
  2. 72
      api/items.go
  3. 2
      api/scope.go
  4. 1
      cmd/stufflog3-server.go
  5. 30
      internal/database/database.go
  6. 4
      internal/database/mysql/database.go
  7. 354
      internal/database/mysql/items.go
  8. 191
      internal/database/mysql/mysqlcore/db.go
  9. 791
      internal/database/mysql/mysqlcore/item.sql.go
  10. 84
      internal/database/mysql/mysqlcore/models.go
  11. 61
      internal/database/mysql/mysqlcore/project.sql.go
  12. 78
      internal/database/mysql/mysqlcore/scope.sql.go
  13. 12
      internal/database/mysql/mysqlcore/stats.sql.go
  14. 105
      internal/database/mysql/queries/item.sql
  15. 6
      internal/database/mysql/queries/project.sql
  16. 98
      internal/database/mysql/scopes.go
  17. 46
      internal/models/common.go
  18. 92
      internal/models/item.go
  19. 14
      internal/models/project.go
  20. 26
      internal/models/scope.go
  21. 17
      internal/models/stat.go
  22. 46
      internal/sqltypes/nulldate.go
  23. 10
      sqlc.yaml

39
api/common.go

@ -1,8 +1,13 @@
package api
import (
"context"
"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"
"net/http"
"strconv"
)
@ -29,3 +34,37 @@ func reqInt(c *gin.Context, key string) (int, error) {
return v, nil
}
var scopeIdContextKey = struct{ stuff string }{stuff: "Things"}
func scopeIDMiddleware(db database.Database) gin.HandlerFunc {
return func(c *gin.Context) {
scopeID, err := strconv.Atoi(c.Param("scope_id"))
if err != nil {
c.AbortWithStatusJSON(http.StatusUnauthorized, slerrors.ErrorResponse{
Code: http.StatusBadRequest,
Message: "Invalid scope ID in path!",
})
return
}
scope, err := db.Scopes().Find(c.Request.Context(), scopeID, c.Request.Method != "GET")
if err != nil || !scope.HasMember(auth.UserID(c)) {
c.AbortWithStatusJSON(http.StatusUnauthorized, slerrors.ErrorResponse{
Code: http.StatusNotFound,
Message: "Scope not found or you don't have permission to it!",
})
return
}
c.Request = c.Request.WithContext(
context.WithValue(c.Request.Context(), &scopeIdContextKey, scope),
)
}
}
func getScope(c *gin.Context) *models.Scope {
return c.Request.Context().Value(&scopeIdContextKey).(*models.Scope)
}

72
api/items.go

@ -0,0 +1,72 @@
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 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
}
item, err := db.Items(getScope(c).ID).Find(c.Request.Context(), id)
if err != nil {
return nil, err
}
for _, member := range getScope(c).Members {
if member.ID == item.OwnerID {
item.Owner = &member
}
}
return item, nil
}))
g.POST("/", handler("item", func(c *gin.Context) (interface{}, error) {
item := &models.Item{}
err := c.BindJSON(item)
if err != nil {
return nil, slerrors.BadRequest("Invalid JSON input: " + err.Error())
}
item.CreatedTime = time.Now()
if item.Name == "" {
return nil, slerrors.BadRequest("Blank item name not allowed")
}
if item.OwnerID == "" {
item.OwnerID = auth.UserID(c)
} 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.")
}
if stat.Acquired == 0 && stat.Required == 0 {
return nil, slerrors.BadRequest("0/0 stats are not allowed when creating items.")
}
}
item, err = db.Items(getScope(c).ID).Create(c.Request.Context(), *item)
if err != nil {
return nil, err
}
item.Owner = getScope(c).Member(item.OwnerID)
return item, err
}))
}

2
api/scope.go

@ -18,7 +18,7 @@ func Scopes(g *gin.RouterGroup, db database.Database) {
return nil, err
}
scope, err := db.Scopes().Find(c.Request.Context(), id)
scope, err := db.Scopes().Find(c.Request.Context(), id, true)
if err != nil {
return nil, err
}

1
cmd/stufflog3-server.go

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

30
internal/database/database.go

@ -10,10 +10,11 @@ type Database interface {
Scopes() ScopeRepository
Stats(scopeID int) StatRepository
Items(scopeID int) ItemRepository
ItemsMultiScope(scopeIDs []int) ItemRepository
}
type ScopeRepository interface {
Find(ctx context.Context, id int) (*models.Scope, error)
Find(ctx context.Context, id int, full bool) (*models.Scope, error)
List(ctx context.Context) ([]models.ScopeEntry, error)
ListByUser(ctx context.Context, userID string) ([]models.ScopeEntry, error)
Create(ctx context.Context, scope models.ScopeEntry, owner models.ScopeMember) (*models.Scope, error)
@ -33,7 +34,30 @@ type StatRepository interface {
type ItemRepository interface {
Find(ctx context.Context, id int) (*models.Item, error)
List(ctx context.Context) ([]models.Item, error)
ListCreated(ctx context.Context, from, to time.Time) ([]models.Item, error)
ListAcquired(ctx context.Context, from, to time.Time) ([]models.Item, error)
Create(ctx context.Context, stat models.Stat) (*models.Item, error)
ListScheduled(ctx context.Context, from, to models.Date) ([]models.Item, error)
ListLoose(ctx context.Context, from, to time.Time) ([]models.Item, error)
Create(ctx context.Context, item models.Item) (*models.Item, error)
Update(ctx context.Context, item models.Item, update models.ItemUpdate) (*models.Item, error)
Delete(ctx context.Context, item models.Item) error
}
type ItemMultiScopeRepository interface {
ListCreated(ctx context.Context, from, to time.Time) ([]models.Item, error)
ListAcquired(ctx context.Context, from, to time.Time) ([]models.Item, error)
ListScheduled(ctx context.Context, from, to models.Date) ([]models.Item, error)
ListLoose(ctx context.Context, from, to time.Time) ([]models.Item, error)
}
type ProjectRepository interface {
Find(ctx context.Context, id int) (*models.Project, error)
List(ctx context.Context) ([]models.Project, 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)
}

4
internal/database/mysql/database.go

@ -23,6 +23,10 @@ func (d *Database) Stats(scopeID int) database.StatRepository {
}
func (d *Database) Items(scopeID int) database.ItemRepository {
return &itemRepository{db: d.db, scopeID: scopeID}
}
func (d *Database) ItemsMultiScope(scopeIDs []int) database.ItemRepository {
//TODO implement me
panic("implement me")
}

354
internal/database/mysql/items.go

@ -0,0 +1,354 @@
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"
"git.aiterp.net/stufflog3/stufflog3-api/internal/sqltypes"
"strings"
"time"
)
type itemRepository struct {
db *sql.DB
scopeID int
}
func (r *itemRepository) Find(ctx context.Context, id int) (*models.Item, error) {
res, err := mysqlcore.New(r.db).GetItem(ctx, id)
if err != nil {
if err == sql.ErrNoRows {
return nil, slerrors.NotFound("Item")
}
return nil, err
}
if res.ScopeID != r.scopeID {
return nil, slerrors.NotFound("Item")
}
item := r.resToItem(mysqlcore.ListItemsAcquiredBetweenRow(res))
stats, _ := mysqlcore.New(r.db).ListItemStatProgress(ctx, id)
for _, stat := range stats {
item.Stats = append(item.Stats, models.StatProgressEntry{
StatEntry: models.StatEntry{
ID: int(stat.ID.Int32),
Name: stat.Name.String,
Weight: stat.Weight,
},
Acquired: stat.Acquired,
Required: stat.Required,
})
}
return &item, nil
}
func (r *itemRepository) ListCreated(ctx context.Context, from, to time.Time) ([]models.Item, error) {
rows, err := mysqlcore.New(r.db).ListItemsCreatedBetween(ctx, mysqlcore.ListItemsCreatedBetweenParams{
CreatedTime: from,
CreatedTime_2: to,
ScopeID: r.scopeID,
})
if err != nil {
return nil, err
}
items := make([]models.Item, 0, len(rows))
for _, row := range rows {
items = append(items, r.resToItem(mysqlcore.ListItemsAcquiredBetweenRow(row)))
}
err = r.fillStats(ctx, items)
if err != nil {
return nil, err
}
return items, nil
}
func (r *itemRepository) ListAcquired(ctx context.Context, from, to time.Time) ([]models.Item, error) {
rows, err := mysqlcore.New(r.db).ListItemsAcquiredBetween(ctx, mysqlcore.ListItemsAcquiredBetweenParams{
AcquiredTime: sql.NullTime{Valid: true, Time: from},
AcquiredTime_2: sql.NullTime{Valid: true, Time: to},
ScopeID: r.scopeID,
})
if err != nil {
return nil, err
}
items := make([]models.Item, 0, len(rows))
for _, row := range rows {
items = append(items, r.resToItem(row))
}
err = r.fillStats(ctx, items)
if err != nil {
return nil, err
}
return items, nil
}
func (r *itemRepository) ListScheduled(ctx context.Context, from, to models.Date) ([]models.Item, error) {
rows, err := mysqlcore.New(r.db).ListItemsScheduledBetween(ctx, mysqlcore.ListItemsScheduledBetweenParams{
ScheduledDate: sqltypes.NullDate{Valid: true, Date: from},
ScheduledDate_2: sqltypes.NullDate{Valid: true, Date: to},
ScopeID: r.scopeID,
})
if err != nil {
return nil, err
}
items := make([]models.Item, 0, len(rows))
for _, row := range rows {
items = append(items, r.resToItem(mysqlcore.ListItemsAcquiredBetweenRow(row)))
}
err = r.fillStats(ctx, items)
if err != nil {
return nil, err
}
return items, nil
}
func (r *itemRepository) ListLoose(ctx context.Context, from, to time.Time) ([]models.Item, error) {
rows, err := mysqlcore.New(r.db).ListItemsLooseBetween(ctx, mysqlcore.ListItemsLooseBetweenParams{
CreatedTime: from,
CreatedTime_2: to,
ScopeID: r.scopeID,
})
if err != nil {
return nil, err
}
items := make([]models.Item, 0, len(rows))
for _, row := range rows {
items = append(items, r.resToItem(mysqlcore.ListItemsAcquiredBetweenRow(row)))
}
err = r.fillStats(ctx, items)
if err != nil {
return nil, err
}
return items, nil
}
func (r *itemRepository) Create(ctx context.Context, item models.Item) (*models.Item, error) {
item.Stats = append(item.Stats[:0:0], item.Stats...)
tx, err := r.db.BeginTx(ctx, nil)
if err != nil {
return nil, err
}
defer tx.Rollback()
q := mysqlcore.New(tx)
prID, acqTime, schDate := r.generateNullables(item)
res, err := q.InsertItem(ctx, mysqlcore.InsertItemParams{
ScopeID: r.scopeID,
ProjectRequirementID: prID,
Name: item.Name,
Description: item.Description,
CreatedTime: time.Now(),
CreatedUserID: item.OwnerID,
AcquiredTime: acqTime,
ScheduledDate: schDate,
})
if err != nil {
return nil, err
}
id, err := res.LastInsertId()
if err != nil {
return nil, err
}
for _, stat := range item.Stats {
err = q.ReplaceItemStatProgress(ctx, mysqlcore.ReplaceItemStatProgressParams{
ItemID: int(id),
StatID: stat.ID,
Acquired: stat.Acquired,
Required: stat.Required,
})
if err != nil {
return nil, err
}
}
err = tx.Commit()
if err != nil {
return nil, err
}
return r.Find(ctx, int(id))
}
func (r *itemRepository) generateNullables(item models.Item) (prID sql.NullInt32, acqTime sql.NullTime, schDate sqltypes.NullDate) {
if item.ProjectRequirementID != nil {
prID.Valid = true
prID.Int32 = int32(*item.ProjectRequirementID)
}
if item.AcquiredTime != nil {
acqTime.Valid = true
acqTime.Time = *item.AcquiredTime
}
if item.ScheduledDate != nil {
schDate.Valid = true
schDate.Date = *item.ScheduledDate
}
return
}
func (r *itemRepository) Update(ctx context.Context, item models.Item, update models.ItemUpdate) (*models.Item, error) {
tx, err := r.db.BeginTx(ctx, nil)
if err != nil {
return nil, err
}
defer tx.Rollback()
q := mysqlcore.New(r.db)
item.ApplyUpdate(update)
prID, acqTime, schDate := r.generateNullables(item)
err = q.UpdateItem(ctx, mysqlcore.UpdateItemParams{
ID: item.ID,
ProjectRequirementID: prID,
Name: item.Name,
Description: item.Description,
AcquiredTime: acqTime,
ScheduledDate: schDate,
CreatedUserID: item.OwnerID,
})
if err != nil {
return nil, err
}
for _, stat := range update.Stats {
if stat.Acquired == 0 && stat.Required == 0 {
err = q.DeleteItemStatProgress(ctx, mysqlcore.DeleteItemStatProgressParams{
ItemID: item.ID,
StatID: stat.ID,
})
} else {
err = q.ReplaceItemStatProgress(ctx, mysqlcore.ReplaceItemStatProgressParams{
ItemID: item.ID,
StatID: stat.ID,
Acquired: stat.Acquired,
Required: stat.Required,
})
}
if err != nil {
return nil, err
}
}
err = tx.Commit()
if err != nil {
return nil, err
}
return r.Find(ctx, item.ID)
}
func (r *itemRepository) Delete(ctx context.Context, item models.Item) error {
tx, err := r.db.BeginTx(ctx, nil)
if err != nil {
return err
}
defer tx.Rollback()
q := mysqlcore.New(r.db)
err = q.DeleteItem(ctx, item.ID)
if err != nil {
return err
}
err = q.ClearItemStatProgress(ctx, item.ID)
if err != nil {
return err
}
return tx.Commit()
}
func (r *itemRepository) resToItem(res mysqlcore.ListItemsAcquiredBetweenRow) models.Item {
item := models.Item{
ID: res.ID,
ScopeID: res.ScopeID,
OwnerID: res.CreatedUserID,
Name: res.Name,
Description: res.Description,
CreatedTime: res.CreatedTime.UTC(),
}
if res.ProjectRequirementID.Valid {
projectRequirementID := int(res.ProjectRequirementID.Int32)
projectID := int(res.ProjectID.Int32)
item.ProjectRequirementID = &projectRequirementID
item.ProjectID = &projectID
}
if res.ScheduledDate.Valid {
item.ScheduledDate = &res.ScheduledDate.Date
}
if res.AcquiredTime.Valid {
item.AcquiredTime = &res.AcquiredTime.Time
}
return item
}
func (r *itemRepository) fillStats(ctx context.Context, items []models.Item) error {
if len(items) == 0 {
return nil
}
ids := make([]interface{}, 0, len(items))
for _, item := range items {
ids = append(ids, item.ID)
}
query := `
SELECT isp.item_id, isp.required, isp.acquired, s.id, s.name, s.weight FROM item_stat_progress isp
LEFT JOIN stat s ON s.id = isp.stat_id
WHERE item_id IN (?` + strings.Repeat(",?", len(ids)-1) + `);
`
rows, err := r.db.QueryContext(ctx, query, ids...)
if err != nil {
return err
}
for rows.Next() {
var itemID, required, acquired, statID int
var statName string
var statWeight float64
err = rows.Scan(&itemID, &required, &acquired, &statID, &statName, &statWeight)
if err != nil {
return err
}
for i := range items {
if items[i].ID == itemID {
items[i].Stats = append(items[i].Stats, models.StatProgressEntry{
StatEntry: models.StatEntry{
ID: statID,
Name: statName,
Weight: statWeight,
},
Acquired: acquired,
Required: required,
})
}
}
}
return nil
}

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

@ -7,7 +7,6 @@ package mysqlcore
import (
"context"
"database/sql"
"fmt"
)
type DBTX interface {
@ -21,198 +20,12 @@ 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.deleteAllScopeMembersStmt, err = db.PrepareContext(ctx, deleteAllScopeMembers); err != nil {
return nil, fmt.Errorf("error preparing query DeleteAllScopeMembers: %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.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.insertScopeStmt, err = db.PrepareContext(ctx, insertScope); err != nil {
return nil, fmt.Errorf("error preparing query InsertScope: %w", err)
}
if q.listProjectEntriesStmt, err = db.PrepareContext(ctx, listProjectEntries); err != nil {
return nil, fmt.Errorf("error preparing query ListProjectEntries: %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.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.deleteAllScopeMembersStmt != nil {
if cerr := q.deleteAllScopeMembersStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing deleteAllScopeMembersStmt: %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.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.insertScopeStmt != nil {
if cerr := q.insertScopeStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing insertScopeStmt: %w", cerr)
}
}
if q.listProjectEntriesStmt != nil {
if cerr := q.listProjectEntriesStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing listProjectEntriesStmt: %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.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
tx *sql.Tx
deleteAllScopeMembersStmt *sql.Stmt
deleteScopeStmt *sql.Stmt
deleteScopeMemberStmt *sql.Stmt
getScopeStmt *sql.Stmt
getScopeDisplayNameStmt *sql.Stmt
getScopeWithDisplayNameStmt *sql.Stmt
insertScopeStmt *sql.Stmt
listProjectEntriesStmt *sql.Stmt
listScopeMembersStmt *sql.Stmt
listScopesStmt *sql.Stmt
listScopesByUserStmt *sql.Stmt
listStatsStmt *sql.Stmt
updateScopeStmt *sql.Stmt
updateScopeMemberStmt *sql.Stmt
db DBTX
}
func (q *Queries) WithTx(tx *sql.Tx) *Queries {
return &Queries{
db: tx,
tx: tx,
deleteAllScopeMembersStmt: q.deleteAllScopeMembersStmt,
deleteScopeStmt: q.deleteScopeStmt,
deleteScopeMemberStmt: q.deleteScopeMemberStmt,
getScopeStmt: q.getScopeStmt,
getScopeDisplayNameStmt: q.getScopeDisplayNameStmt,
getScopeWithDisplayNameStmt: q.getScopeWithDisplayNameStmt,
insertScopeStmt: q.insertScopeStmt,
listProjectEntriesStmt: q.listProjectEntriesStmt,
listScopeMembersStmt: q.listScopeMembersStmt,
listScopesStmt: q.listScopesStmt,
listScopesByUserStmt: q.listScopesByUserStmt,
listStatsStmt: q.listStatsStmt,
updateScopeStmt: q.updateScopeStmt,
updateScopeMemberStmt: q.updateScopeMemberStmt,
db: tx,
}
}

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

@ -0,0 +1,791 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.13.0
// source: item.sql
package mysqlcore
import (
"context"
"database/sql"
"time"
"git.aiterp.net/stufflog3/stufflog3-api/internal/sqltypes"
)
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)
return err
}
const deleteItem = `-- name: DeleteItem :exec
DELETE FROM item WHERE id = ?
`
func (q *Queries) DeleteItem(ctx context.Context, id int) error {
_, err := q.db.ExecContext(ctx, deleteItem, id)
return err
}
const deleteItemStatProgress = `-- name: DeleteItemStatProgress :exec
DELETE FROM item_stat_progress WHERE item_id = ? AND stat_id = ?
`
type DeleteItemStatProgressParams struct {
ItemID int
StatID int
}
func (q *Queries) DeleteItemStatProgress(ctx context.Context, arg DeleteItemStatProgressParams) error {
_, err := q.db.ExecContext(ctx, deleteItemStatProgress, arg.ItemID, arg.StatID)
return err
}
const getItem = `-- name: GetItem :one
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.id = ?
`
type GetItemRow struct {
ID int
ScopeID int
ProjectRequirementID sql.NullInt32
Name string
Description string
CreatedTime time.Time
CreatedUserID string
AcquiredTime sql.NullTime
ScheduledDate sqltypes.NullDate
ProjectID sql.NullInt32
}
func (q *Queries) GetItem(ctx context.Context, id int) (GetItemRow, error) {
row := q.db.QueryRowContext(ctx, getItem, id)
var i GetItemRow
err := row.Scan(
&i.ID,
&i.ScopeID,
&i.ProjectRequirementID,
&i.Name,
&i.Description,
&i.CreatedTime,
&i.CreatedUserID,
&i.AcquiredTime,
&i.ScheduledDate,
&i.ProjectID,
)
return i, err
}
const getItemStatProgressBetween = `-- name: GetItemStatProgressBetween :one
SELECT s.id, s.name, s.weight, SUM(isp.acquired), SUM(isp.required) FROM item i
LEFT JOIN item_stat_progress isp on i.id = isp.item_id
LEFT JOIN stat s on isp.stat_id = s.id
WHERE i.acquired_time >= ?
AND i.acquired_time < ?
AND i.scope_id = ?
GROUP BY stat_id
`
type GetItemStatProgressBetweenParams struct {
AcquiredTime sql.NullTime
AcquiredTime_2 sql.NullTime
ScopeID int
}
type GetItemStatProgressBetweenRow struct {
ID sql.NullInt32
Name sql.NullString
Weight float64
Sum interface{}
Sum_2 interface{}
}
func (q *Queries) GetItemStatProgressBetween(ctx context.Context, arg GetItemStatProgressBetweenParams) (GetItemStatProgressBetweenRow, error) {
row := q.db.QueryRowContext(ctx, getItemStatProgressBetween, arg.AcquiredTime, arg.AcquiredTime_2, arg.ScopeID)
var i GetItemStatProgressBetweenRow
err := row.Scan(
&i.ID,
&i.Name,
&i.Weight,
&i.Sum,
&i.Sum_2,
)
return i, err
}
const insertItem = `-- name: InsertItem :execresult
INSERT INTO item (scope_id, project_requirement_id, name, description, created_time, created_user_id, acquired_time, scheduled_date)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
`
type InsertItemParams struct {
ScopeID int
ProjectRequirementID sql.NullInt32
Name string
Description string
CreatedTime time.Time
CreatedUserID string
AcquiredTime sql.NullTime
ScheduledDate sqltypes.NullDate
}
func (q *Queries) InsertItem(ctx context.Context, arg InsertItemParams) (sql.Result, error) {
return q.db.ExecContext(ctx, insertItem,
arg.ScopeID,
arg.ProjectRequirementID,
arg.Name,
arg.Description,
arg.CreatedTime,
arg.CreatedUserID,
arg.AcquiredTime,
arg.ScheduledDate,
)
}
const listItemStatProgress = `-- name: ListItemStatProgress :many
SELECT isp.required, isp.acquired, s.id, s.name, s.weight FROM item_stat_progress isp
LEFT JOIN stat s ON s.id = isp.stat_id
WHERE item_id = ?
`
type ListItemStatProgressRow struct {
Required int
Acquired int
ID sql.NullInt32
Name sql.NullString
Weight float64
}
func (q *Queries) ListItemStatProgress(ctx context.Context, itemID int) ([]ListItemStatProgressRow, error) {
rows, err := q.db.QueryContext(ctx, listItemStatProgress, itemID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []ListItemStatProgressRow{}
for rows.Next() {
var i ListItemStatProgressRow
if err := rows.Scan(
&i.Required,
&i.Acquired,
&i.ID,
&i.Name,
&i.Weight,
); 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 listItemStatProgressMulti = `-- name: ListItemStatProgressMulti :many
SELECT isp.item_id, isp.required, isp.acquired, s.id, s.name, s.weight FROM item_stat_progress isp
LEFT JOIN stat s ON s.id = isp.stat_id
WHERE item_id IN (?, ?, ?, ?, ?, ?, ?, ?)
`
type ListItemStatProgressMultiParams struct {
ItemID int
ItemID_2 int
ItemID_3 int
ItemID_4 int
ItemID_5 int
ItemID_6 int
ItemID_7 int
ItemID_8 int
}
type ListItemStatProgressMultiRow struct {
ItemID int
Required int
Acquired int
ID sql.NullInt32
Name sql.NullString
Weight float64
}
func (q *Queries) ListItemStatProgressMulti(ctx context.Context, arg ListItemStatProgressMultiParams) ([]ListItemStatProgressMultiRow, error) {
rows, err := q.db.QueryContext(ctx, listItemStatProgressMulti,
arg.ItemID,
arg.ItemID_2,
arg.ItemID_3,
arg.ItemID_4,
arg.ItemID_5,
arg.ItemID_6,
arg.ItemID_7,
arg.ItemID_8,
)
if err != nil {
return nil, err
}
defer rows.Close()
items := []ListItemStatProgressMultiRow{}
for rows.Next() {
var i ListItemStatProgressMultiRow
if err := rows.Scan(
&i.ItemID,
&i.Required,
&i.Acquired,
&i.ID,
&i.Name,
&i.Weight,
); 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 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.scope_id = ?
`
type ListItemsAcquiredBetweenParams struct {
AcquiredTime sql.NullTime
AcquiredTime_2 sql.NullTime
ScopeID int
}
type ListItemsAcquiredBetweenRow struct {
ID int
ScopeID int
ProjectRequirementID sql.NullInt32
Name string
Description string
CreatedTime time.Time
CreatedUserID string
AcquiredTime sql.NullTime
ScheduledDate sqltypes.NullDate
ProjectID sql.NullInt32
}
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)
if err != nil {
return nil, err
}
defer rows.Close()
items := []ListItemsAcquiredBetweenRow{}
for rows.Next() {
var i ListItemsAcquiredBetweenRow
if err := rows.Scan(
&i.ID,
&i.ScopeID,
&i.ProjectRequirementID,
&i.Name,
&i.Description,
&i.CreatedTime,
&i.CreatedUserID,
&i.AcquiredTime,
&i.ScheduledDate,
&i.ProjectID,
); 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 listItemsByProject = `-- name: ListItemsByProject :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 pr.project_id = ?
`
type ListItemsByProjectRow struct {
ID int
ScopeID int
ProjectRequirementID sql.NullInt32
Name string
Description string
CreatedTime time.Time
CreatedUserID string
AcquiredTime sql.NullTime
ScheduledDate sqltypes.NullDate
ProjectID sql.NullInt32
}
func (q *Queries) ListItemsByProject(ctx context.Context, projectID int) ([]ListItemsByProjectRow, error) {
rows, err := q.db.QueryContext(ctx, listItemsByProject, projectID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []ListItemsByProjectRow{}
for rows.Next() {
var i ListItemsByProjectRow
if err := rows.Scan(
&i.ID,
&i.ScopeID,
&i.ProjectRequirementID,
&i.Name,
&i.Description,
&i.CreatedTime,
&i.CreatedUserID,
&i.AcquiredTime,
&i.ScheduledDate,
&i.ProjectID,
); 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 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.scope_id = ?
`
type ListItemsCreatedBetweenParams struct {
CreatedTime time.Time
CreatedTime_2 time.Time
ScopeID int
}
type ListItemsCreatedBetweenRow struct {
ID int
ScopeID int
ProjectRequirementID sql.NullInt32
Name string
Description string
CreatedTime time.Time
CreatedUserID string
AcquiredTime sql.NullTime
ScheduledDate sqltypes.NullDate
ProjectID sql.NullInt32
}
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)
if err != nil {
return nil, err
}
defer rows.Close()
items := []ListItemsCreatedBetweenRow{}
for rows.Next() {
var i ListItemsCreatedBetweenRow
if err := rows.Scan(
&i.ID,
&i.ScopeID,
&i.ProjectRequirementID,
&i.Name,
&i.Description,
&i.CreatedTime,
&i.CreatedUserID,
&i.AcquiredTime,
&i.ScheduledDate,
&i.ProjectID,
); 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 listItemsCreatedBetweenNoScope = `-- name: ListItemsCreatedBetweenNoScope :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 < ?
`
type ListItemsCreatedBetweenNoScopeParams struct {
CreatedTime time.Time
CreatedTime_2 time.Time
}
type ListItemsCreatedBetweenNoScopeRow struct {
ID int
ScopeID int
ProjectRequirementID sql.NullInt32
Name string
Description string
CreatedTime time.Time
CreatedUserID string
AcquiredTime sql.NullTime
ScheduledDate sqltypes.NullDate
ProjectID sql.NullInt32
}
func (q *Queries) ListItemsCreatedBetweenNoScope(ctx context.Context, arg ListItemsCreatedBetweenNoScopeParams) ([]ListItemsCreatedBetweenNoScopeRow, error) {
rows, err := q.db.QueryContext(ctx, listItemsCreatedBetweenNoScope, arg.CreatedTime, arg.CreatedTime_2)
if err != nil {
return nil, err
}
defer rows.Close()
items := []ListItemsCreatedBetweenNoScopeRow{}
for rows.Next() {
var i ListItemsCreatedBetweenNoScopeRow
if err := rows.Scan(
&i.ID,
&i.ScopeID,
&i.ProjectRequirementID,
&i.Name,
&i.Description,
&i.CreatedTime,
&i.CreatedUserID,
&i.AcquiredTime,
&i.ScheduledDate,
&i.ProjectID,
); 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 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.scope_id = ?
AND i.scheduled_date IS NULL
AND i.acquired_time IS NULL
`
type ListItemsLooseBetweenParams struct {
CreatedTime time.Time
CreatedTime_2 time.Time
ScopeID int
}
type ListItemsLooseBetweenRow struct {
ID int
ScopeID int
ProjectRequirementID sql.NullInt32
Name string
Description string
CreatedTime time.Time
CreatedUserID string
AcquiredTime sql.NullTime
ScheduledDate sqltypes.NullDate
ProjectID sql.NullInt32
}
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)
if err != nil {
return nil, err
}
defer rows.Close()
items := []ListItemsLooseBetweenRow{}
for rows.Next() {
var i ListItemsLooseBetweenRow
if err := rows.Scan(
&i.ID,
&i.ScopeID,
&i.ProjectRequirementID,
&i.Name,
&i.Description,
&i.CreatedTime,
&i.CreatedUserID,
&i.AcquiredTime,
&i.ScheduledDate,
&i.ProjectID,
); 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 listItemsLooseBetweenNoScope = `-- name: ListItemsLooseBetweenNoScope :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.scheduled_date IS NULL
AND i.acquired_time IS NULL
`
type ListItemsLooseBetweenNoScopeParams struct {
CreatedTime time.Time
CreatedTime_2 time.Time
}
type ListItemsLooseBetweenNoScopeRow struct {
ID int
ScopeID int
ProjectRequirementID sql.NullInt32
Name string
Description string
CreatedTime time.Time
CreatedUserID string
AcquiredTime sql.NullTime
ScheduledDate sqltypes.NullDate
ProjectID sql.NullInt32
}
func (q *Queries) ListItemsLooseBetweenNoScope(ctx context.Context, arg ListItemsLooseBetweenNoScopeParams) ([]ListItemsLooseBetweenNoScopeRow, error) {
rows, err := q.db.QueryContext(ctx, listItemsLooseBetweenNoScope, arg.CreatedTime, arg.CreatedTime_2)
if err != nil {
return nil, err
}
defer rows.Close()
items := []ListItemsLooseBetweenNoScopeRow{}
for rows.Next() {
var i ListItemsLooseBetweenNoScopeRow
if err := rows.Scan(
&i.ID,
&i.ScopeID,
&i.ProjectRequirementID,
&i.Name,
&i.Description,
&i.CreatedTime,
&i.CreatedUserID,
&i.AcquiredTime,
&i.ScheduledDate,
&i.ProjectID,
); 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 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.scope_id = ?
`
type ListItemsScheduledBetweenParams struct {
ScheduledDate sqltypes.NullDate
ScheduledDate_2 sqltypes.NullDate
ScopeID int
}
type ListItemsScheduledBetweenRow struct {
ID int
ScopeID int
ProjectRequirementID sql.NullInt32
Name string
Description string
CreatedTime time.Time
CreatedUserID string
AcquiredTime sql.NullTime
ScheduledDate sqltypes.NullDate
ProjectID sql.NullInt32
}
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)
if err != nil {
return nil, err
}
defer rows.Close()
items := []ListItemsScheduledBetweenRow{}
for rows.Next() {
var i ListItemsScheduledBetweenRow
if err := rows.Scan(
&i.ID,
&i.ScopeID,
&i.ProjectRequirementID,
&i.Name,
&i.Description,
&i.CreatedTime,
&i.CreatedUserID,
&i.AcquiredTime,
&i.ScheduledDate,
&i.ProjectID,
); 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 listItemsScheduledBetweenNoScope = `-- name: ListItemsScheduledBetweenNoScope :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 < ?
`
type ListItemsScheduledBetweenNoScopeParams struct {
ScheduledDate sqltypes.NullDate
ScheduledDate_2 sqltypes.NullDate
}
type ListItemsScheduledBetweenNoScopeRow struct {
ID int
ScopeID int
ProjectRequirementID sql.NullInt32
Name string
Description string
CreatedTime time.Time
CreatedUserID string
AcquiredTime sql.NullTime
ScheduledDate sqltypes.NullDate
ProjectID sql.NullInt32
}
func (q *Queries) ListItemsScheduledBetweenNoScope(ctx context.Context, arg ListItemsScheduledBetweenNoScopeParams) ([]ListItemsScheduledBetweenNoScopeRow, error) {
rows, err := q.db.QueryContext(ctx, listItemsScheduledBetweenNoScope, arg.ScheduledDate, arg.ScheduledDate_2)
if err != nil {
return nil, err
}
defer rows.Close()
items := []ListItemsScheduledBetweenNoScopeRow{}
for rows.Next() {
var i ListItemsScheduledBetweenNoScopeRow
if err := rows.Scan(
&i.ID,
&i.ScopeID,
&i.ProjectRequirementID,
&i.Name,
&i.Description,
&i.CreatedTime,
&i.CreatedUserID,
&i.AcquiredTime,
&i.ScheduledDate,
&i.ProjectID,
); 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 replaceItemStatProgress = `-- name: ReplaceItemStatProgress :exec
REPLACE INTO item_stat_progress (item_id, stat_id, acquired, required)
VALUES (?, ?, ?, ?)
`
type ReplaceItemStatProgressParams struct {
ItemID int
StatID int
Acquired int
Required int
}
func (q *Queries) ReplaceItemStatProgress(ctx context.Context, arg ReplaceItemStatProgressParams) error {
_, err := q.db.ExecContext(ctx, replaceItemStatProgress,
arg.ItemID,
arg.StatID,
arg.Acquired,
arg.Required,
)
return err
}
const updateItem = `-- name: UpdateItem :exec
UPDATE item
SET project_requirement_id = ?,
name = ?,
description = ?,
acquired_time = ?,
scheduled_date = ?,
created_user_id = ?
WHERE id = ?
`
type UpdateItemParams struct {
ProjectRequirementID sql.NullInt32
Name string
Description string
AcquiredTime sql.NullTime
ScheduledDate sqltypes.NullDate
CreatedUserID string
ID int
}
func (q *Queries) UpdateItem(ctx context.Context, arg UpdateItemParams) error {
_, err := q.db.ExecContext(ctx, updateItem,
arg.ProjectRequirementID,
arg.Name,
arg.Description,
arg.AcquiredTime,
arg.ScheduledDate,
arg.CreatedUserID,
arg.ID,
)
return err
}

84
internal/database/mysql/mysqlcore/models.go

@ -12,67 +12,67 @@ import (
)
type Item struct {
ID int `json:"id"`
ScopeID int `json:"scope_id"`
ProjectRequirementID sql.NullInt32 `json:"project_requirement_id"`
Name string `json:"name"`
Description string `json:"description"`
CreatedTime time.Time `json:"created_time"`
CreatedUserID string `json:"created_user_id"`
AcquiredTime sql.NullTime `json:"acquired_time"`
ScheduledDate sql.NullTime `json:"scheduled_date"`
ID int
ScopeID int
ProjectRequirementID sql.NullInt32
Name string
Description string
CreatedTime time.Time
CreatedUserID string
AcquiredTime sql.NullTime
ScheduledDate sqltypes.NullDate
}
type ItemStatProgress struct {
ItemID int `json:"item_id"`
StatID int `json:"stat_id"`
Acquired int `json:"acquired"`
Required int `json:"required"`
ItemID int
StatID int
Acquired int
Required int
}
type Project struct {
ID int `json:"id"`
ScopeID int `json:"scope_id"`
AuthorID string `json:"author_id"`
Name string `json:"name"`
Status int `json:"status"`
Description string `json:"description"`
CreatedTime time.Time `json:"created_time"`
ID int
ScopeID int
AuthorID string
Name string
Status int
Description string
CreatedTime time.Time
}
type ProjectRequirement struct {
ID int `json:"id"`
ScopeID int `json:"scope_id"`
ProjectID int `json:"project_id"`
Name string `json:"name"`
Status int `json:"status"`
Description string `json:"description"`
ID int
ScopeID int
ProjectID int
Name string
Status int
Description string
}
type ProjectRequirementStat struct {
ProjectRequirementID int `json:"project_requirement_id"`
StatID int `json:"stat_id"`
Required int `json:"required"`
ProjectRequirementID int
StatID int
Required int
}
type Scope struct {
ID int `json:"id"`
Name string `json:"name"`
Abbreviation string `json:"abbreviation"`
ID int
Name string
Abbreviation string
}
type ScopeMember struct {
ScopeID int `json:"scope_id"`
UserID string `json:"user_id"`
Name string `json:"name"`
Owner bool `json:"owner"`
ScopeID int
UserID string
Name string
Owner bool
}
type Stat struct {
ID int `json:"id"`
ScopeID int `json:"scope_id"`
Name string `json:"name"`
Description string `json:"description"`
Weight float64 `json:"weight"`
AllowedAmounts sqltypes.NullRawMessage `json:"allowed_amounts"`
ID int
ScopeID int
Name string
Description string
Weight float64
AllowedAmounts sqltypes.NullRawMessage
}

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

@ -9,6 +9,25 @@ import (
"context"
)
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)
var i Project
err := row.Scan(
&i.ID,
&i.ScopeID,
&i.AuthorID,
&i.Name,
&i.Status,
&i.Description,
&i.CreatedTime,
)
return i, err
}
const listProjectEntries = `-- name: ListProjectEntries :many
SELECT id, name, status FROM project
WHERE scope_id = ?
@ -16,13 +35,13 @@ ORDER BY status, created_time
`
type ListProjectEntriesRow struct {
ID int `json:"id"`
Name string `json:"name"`
Status int `json:"status"`
ID int
Name string
Status int
}
func (q *Queries) ListProjectEntries(ctx context.Context, scopeID int) ([]ListProjectEntriesRow, error) {
rows, err := q.query(ctx, q.listProjectEntriesStmt, listProjectEntries, scopeID)
rows, err := q.db.QueryContext(ctx, listProjectEntries, scopeID)
if err != nil {
return nil, err
}
@ -43,3 +62,37 @@ func (q *Queries) ListProjectEntries(ctx context.Context, scopeID int) ([]ListPr
}
return items, nil
}
const listProjectRequirementsByProjectID = `-- name: ListProjectRequirementsByProjectID :many
SELECT id, scope_id, project_id, name, status, description FROM project_requirement WHERE project_id = ?
`
func (q *Queries) ListProjectRequirementsByProjectID(ctx context.Context, projectID int) ([]ProjectRequirement, error) {
rows, err := q.db.QueryContext(ctx, listProjectRequirementsByProjectID, projectID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []ProjectRequirement{}
for rows.Next() {
var i ProjectRequirement
if err := rows.Scan(
&i.ID,
&i.ScopeID,
&i.ProjectID,
&i.Name,
&i.Status,
&i.Description,
); 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
}

78
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.exec(ctx, q.deleteAllScopeMembersStmt, deleteAllScopeMembers, scopeID)
_, err := q.db.ExecContext(ctx, 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.exec(ctx, q.deleteScopeStmt, deleteScope, id)
_, err := q.db.ExecContext(ctx, deleteScope, id)
return err
}
@ -33,12 +33,12 @@ DELETE FROM scope_member WHERE scope_id=? AND user_id=?
`
type DeleteScopeMemberParams struct {
ScopeID int `json:"scope_id"`
UserID string `json:"user_id"`
ScopeID int
UserID string
}
func (q *Queries) DeleteScopeMember(ctx context.Context, arg DeleteScopeMemberParams) error {
_, err := q.exec(ctx, q.deleteScopeMemberStmt, deleteScopeMember, arg.ScopeID, arg.UserID)
_, err := q.db.ExecContext(ctx, 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.queryRow(ctx, q.getScopeStmt, getScope, id)
row := q.db.QueryRowContext(ctx, getScope, id)
var i Scope
err := row.Scan(&i.ID, &i.Name, &i.Abbreviation)
return i, err
@ -60,12 +60,12 @@ WHERE user_id = ? AND scope_id = ?
`
type GetScopeDisplayNameParams struct {
UserID string `json:"user_id"`
ScopeID int `json:"scope_id"`
UserID string
ScopeID int
}
func (q *Queries) GetScopeDisplayName(ctx context.Context, arg GetScopeDisplayNameParams) (string, error) {
row := q.queryRow(ctx, q.getScopeDisplayNameStmt, getScopeDisplayName, arg.UserID, arg.ScopeID)
row := q.db.QueryRowContext(ctx, getScopeDisplayName, arg.UserID, arg.ScopeID)
var name string
err := row.Scan(&name)
return name, err
@ -78,19 +78,19 @@ WHERE id = ? AND sm.user_id = ?
`
type GetScopeWithDisplayNameParams struct {
ID int `json:"id"`
UserID string `json:"user_id"`
ID int
UserID string
}
type GetScopeWithDisplayNameRow struct {
ID int `json:"id"`
Name string `json:"name"`
Abbreviation string `json:"abbreviation"`
DisplayName sql.NullString `json:"display_name"`
ID int
Name string
Abbreviation string
DisplayName sql.NullString
}
func (q *Queries) GetScopeWithDisplayName(ctx context.Context, arg GetScopeWithDisplayNameParams) (GetScopeWithDisplayNameRow, error) {
row := q.queryRow(ctx, q.getScopeWithDisplayNameStmt, getScopeWithDisplayName, arg.ID, arg.UserID)
row := q.db.QueryRowContext(ctx, getScopeWithDisplayName, arg.ID, arg.UserID)
var i GetScopeWithDisplayNameRow
err := row.Scan(
&i.ID,
@ -107,13 +107,13 @@ VALUES (?, ?, ?)
`
type InsertScopeParams struct {
ID int `json:"id"`
Name string `json:"name"`
Abbreviation string `json:"abbreviation"`
ID int
Name string
Abbreviation string
}
func (q *Queries) InsertScope(ctx context.Context, arg InsertScopeParams) (sql.Result, error) {
return q.exec(ctx, q.insertScopeStmt, insertScope, arg.ID, arg.Name, arg.Abbreviation)
return q.db.ExecContext(ctx, insertScope, arg.ID, arg.Name, arg.Abbreviation)
}
const listScopeMembers = `-- name: ListScopeMembers :many
@ -123,13 +123,13 @@ ORDER BY name
`
type ListScopeMembersRow struct {
UserID string `json:"user_id"`
Name string `json:"name"`
Owner bool `json:"owner"`
UserID string
Name string
Owner bool
}
func (q *Queries) ListScopeMembers(ctx context.Context, scopeID int) ([]ListScopeMembersRow, error) {
rows, err := q.query(ctx, q.listScopeMembersStmt, listScopeMembers, scopeID)
rows, err := q.db.QueryContext(ctx, 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.query(ctx, q.listScopesStmt, listScopes)
rows, err := q.db.QueryContext(ctx, listScopes)
if err != nil {
return nil, err
}
@ -187,14 +187,14 @@ ORDER BY s.name
`
type ListScopesByUserRow struct {
ID int `json:"id"`
Name string `json:"name"`
Abbreviation string `json:"abbreviation"`
DisplayName sql.NullString `json:"display_name"`
ID int
Name string
Abbreviation string
DisplayName sql.NullString
}
func (q *Queries) ListScopesByUser(ctx context.Context, userID string) ([]ListScopesByUserRow, error) {
rows, err := q.query(ctx, q.listScopesByUserStmt, listScopesByUser, userID)
rows, err := q.db.QueryContext(ctx, listScopesByUser, userID)
if err != nil {
return nil, err
}
@ -226,13 +226,13 @@ UPDATE scope SET name = ?, abbreviation = ? WHERE id = ?
`
type UpdateScopeParams struct {
Name string `json:"name"`
Abbreviation string `json:"abbreviation"`
ID int `json:"id"`
Name string
Abbreviation string
ID int
}
func (q *Queries) UpdateScope(ctx context.Context, arg UpdateScopeParams) error {
_, err := q.exec(ctx, q.updateScopeStmt, updateScope, arg.Name, arg.Abbreviation, arg.ID)
_, err := q.db.ExecContext(ctx, updateScope, arg.Name, arg.Abbreviation, arg.ID)
return err
}
@ -242,14 +242,14 @@ VALUES (?, ?, ?, ?)
`
type UpdateScopeMemberParams struct {
ScopeID int `json:"scope_id"`
UserID string `json:"user_id"`
Name string `json:"name"`
Owner bool `json:"owner"`
ScopeID int
UserID string
Name string
Owner bool
}
func (q *Queries) UpdateScopeMember(ctx context.Context, arg UpdateScopeMemberParams) error {
_, err := q.exec(ctx, q.updateScopeMemberStmt, updateScopeMember,
_, err := q.db.ExecContext(ctx, updateScopeMember,
arg.ScopeID,
arg.UserID,
arg.Name,

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

@ -17,15 +17,15 @@ WHERE scope_id = ?
`
type ListStatsRow struct {
ID int `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
Weight float64 `json:"weight"`
AllowedAmounts sqltypes.NullRawMessage `json:"allowed_amounts"`
ID int
Name string
Description string
Weight float64
AllowedAmounts sqltypes.NullRawMessage
}
func (q *Queries) ListStats(ctx context.Context, scopeID int) ([]ListStatsRow, error) {
rows, err := q.query(ctx, q.listStatsStmt, listStats, scopeID)
rows, err := q.db.QueryContext(ctx, listStats, scopeID)
if err != nil {
return nil, err
}

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

@ -0,0 +1,105 @@
-- name: GetItem :one
SELECT i.*, pr.project_id FROM item i
LEFT JOIN project_requirement pr ON pr.id = i.project_requirement_id
WHERE i.id = ?;
-- name: ListItemsByProject :many
SELECT i.*, pr.project_id FROM item i
LEFT JOIN project_requirement pr ON pr.id = i.project_requirement_id
WHERE pr.project_id = ?;
-- name: ListItemsAcquiredBetween :many
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 = ?;
-- 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 = ?;
-- 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 = ?;
-- 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.scope_id = ?
AND i.scheduled_date IS NULL
AND i.acquired_time IS NULL;
-- name: ListItemsScheduledBetweenNoScope :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 < ?;
-- name: ListItemsCreatedBetweenNoScope :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 < ?;
-- name: ListItemsLooseBetweenNoScope :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.scheduled_date IS NULL
AND i.acquired_time IS NULL;
-- name: GetItemStatProgressBetween :one
SELECT s.id, s.name, s.weight, SUM(isp.acquired), SUM(isp.required) FROM item i
LEFT JOIN item_stat_progress isp on i.id = isp.item_id
LEFT JOIN stat s on isp.stat_id = s.id
WHERE i.acquired_time >= ?
AND i.acquired_time < ?
AND i.scope_id = ?
GROUP BY stat_id;
-- name: ListItemStatProgress :many
SELECT isp.required, isp.acquired, s.id, s.name, s.weight FROM item_stat_progress isp
LEFT JOIN stat s ON s.id = isp.stat_id
WHERE item_id = ?;
-- name: ListItemStatProgressMulti :many
SELECT isp.item_id, isp.required, isp.acquired, s.id, s.name, s.weight FROM item_stat_progress isp
LEFT JOIN stat s ON s.id = isp.stat_id
WHERE item_id IN (?, ?, ?, ?, ?, ?, ?, ?);
-- name: InsertItem :execresult
INSERT INTO item (scope_id, project_requirement_id, name, description, created_time, created_user_id, acquired_time, scheduled_date)
VALUES (?, ?, ?, ?, ?, ?, ?, ?);
-- name: UpdateItem :exec
UPDATE item
SET project_requirement_id = ?,
name = ?,
description = ?,
acquired_time = ?,
scheduled_date = ?,
created_user_id = ?
WHERE id = ?;
-- name: DeleteItem :exec
DELETE FROM item WHERE id = ?;
-- name: ReplaceItemStatProgress :exec
REPLACE INTO item_stat_progress (item_id, stat_id, acquired, required)
VALUES (?, ?, ?, ?);
-- name: DeleteItemStatProgress :exec
DELETE FROM item_stat_progress WHERE item_id = ? AND stat_id = ?;
-- name: ClearItemStatProgress :exec
DELETE FROM item_stat_progress WHERE item_id = ?;

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

@ -3,3 +3,9 @@ SELECT id, name, status FROM project
WHERE scope_id = ?
ORDER BY status, created_time;
-- name: GetProject :one
SELECT * FROM project WHERE id = ?;
-- name: ListProjectRequirementsByProjectID :many
SELECT * FROM project_requirement WHERE project_id = ?;

98
internal/database/mysql/scopes.go

@ -16,7 +16,7 @@ type scopeRepository struct {
db *sql.DB
}
func (r *scopeRepository) Find(ctx context.Context, id int) (*models.Scope, error) {
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)
if err != nil {
@ -37,64 +37,66 @@ func (r *scopeRepository) Find(ctx context.Context, id int) (*models.Scope, erro
eg, ctx := errgroup.WithContext(ctx)
eg.Go(func() error {
members, err := q.ListScopeMembers(ctx, id)
if err != nil && err != sql.ErrNoRows {
return err
}
if full {
eg.Go(func() error {
projects, err := q.ListProjectEntries(ctx, id)
if err != nil && err != sql.ErrNoRows {
return err
}
for _, member := range members {
res.Members = append(res.Members, models.ScopeMember{
ID: member.UserID,
Name: member.Name,
Owner: member.Owner,
})
}
for _, project := range projects {
res.Projects = append(res.Projects, models.ProjectEntry{
ID: project.ID,
Name: project.Name,
Status: models.Status(project.Status),
})
}
return nil
})
return nil
})
eg.Go(func() error {
projects, err := q.ListProjectEntries(ctx, id)
if err != nil && err != sql.ErrNoRows {
return err
}
eg.Go(func() error {
stats, err := q.ListStats(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),
})
}
for _, stat := range stats {
var amounts map[string]int
if stat.AllowedAmounts.Valid {
amounts = make(map[string]int)
err := json.Unmarshal(stat.AllowedAmounts.RawMessage, &amounts)
if err != nil {
return err
}
}
return nil
})
res.Stats = append(res.Stats, models.Stat{
StatEntry: models.StatEntry{
ID: stat.ID,
Name: stat.Name,
Weight: stat.Weight,
},
Description: stat.Description,
AllowedAmounts: amounts,
})
}
return nil
})
}
eg.Go(func() error {
stats, err := q.ListStats(ctx, id)
members, err := q.ListScopeMembers(ctx, id)
if err != nil && err != sql.ErrNoRows {
return err
}
for _, stat := range stats {
var amounts map[string]int
if stat.AllowedAmounts.Valid {
amounts = make(map[string]int)
err := json.Unmarshal(stat.AllowedAmounts.RawMessage, &amounts)
if err != nil {
return err
}
}
res.Stats = append(res.Stats, models.Stat{
StatEntry: models.StatEntry{
ID: stat.ID,
Name: stat.Name,
Weight: stat.Weight,
},
Description: stat.Description,
AllowedAmounts: amounts,
for _, member := range members {
res.Members = append(res.Members, models.ScopeMember{
ID: member.UserID,
Name: member.Name,
Owner: member.Owner,
})
}

46
internal/models/common.go

@ -0,0 +1,46 @@
package models
import (
"encoding/json"
"fmt"
"time"
)
type Date [3]int
func ParseDate(s string) (Date, error) {
date, err := time.ParseInLocation("2006-01-02", s, time.UTC)
if err != nil {
return [3]int{}, err
}
y, m, d := date.Date()
return Date{y, int(m), d}, nil
}
func (d *Date) UnmarshalJSON(b []byte) error {
var str string
err := json.Unmarshal(b, &str)
if err != nil {
return err
}
*d, err = ParseDate(str)
if err != nil {
return err
}
return nil
}
func (d Date) String() string {
return fmt.Sprintf("%04d-%02d-%02d", d[0], d[1], d[2])
}
func (d Date) MarshalJSON() ([]byte, error) {
return []byte("\"" + d.String() + "\""), nil
}
func (d Date) ToTime() time.Time {
return time.Date(d[0], time.Month(d[1]), d[2], 0, 0, 0, 0, time.UTC)
}

92
internal/models/item.go

@ -3,15 +3,85 @@ package models
import "time"
type Item struct {
ID int
ProjectRequirementID *int
OwnerID string
Name string
Description string
OwnerName string
CreatedTime time.Time
AcquiredTime *time.Time
ScheduledDate *time.Time
Stats []StatProgressEntry
ID int `json:"id"`
ScopeID int `json:"scopeId"`
OwnerID string `json:"-"`
ProjectID *int `json:"projectId,omitempty"`
ProjectRequirementID *int `json:"projectRequirementId,omitempty"`
Name string `json:"name"`
Description string `json:"description"`
CreatedTime time.Time `json:"createdTime"`
AcquiredTime *time.Time `json:"acquiredTime"`
ScheduledDate *Date `json:"scheduledDate"`
Stats []StatProgressEntry `json:"stats,omitempty"`
Owner *ScopeMember `json:"owner,omitempty"`
}
func (item *Item) ApplyUpdate(update ItemUpdate) {
if update.ProjectRequirementID != nil {
item.ProjectRequirementID = update.ProjectRequirementID
}
if update.OwnerID != nil {
item.OwnerID = *update.OwnerID
item.Owner = nil
}
if update.Name != nil {
item.Name = *update.Name
}
if update.Description != nil {
item.Description = *update.Description
}
if update.AcquiredTime != nil {
item.AcquiredTime = update.AcquiredTime
}
if update.ScheduledDate != nil {
item.ScheduledDate = update.ScheduledDate
}
if update.ClearScheduledDate {
item.ScheduledDate = nil
}
if update.ClearProjectRequirementID {
item.ProjectRequirementID = nil
}
if update.ClearAcquiredTime {
item.AcquiredTime = nil
}
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 item.Stats {
if item.Stats[j].ID == stat.ID {
item.Stats[j].Required = stat.Required
item.Stats[j].Acquired = stat.Acquired
found = true
break
}
}
if !found {
item.Stats = append(item.Stats, stat)
}
}
}
type ItemUpdate struct {
ProjectRequirementID *int `json:"projectRequirementId"`
OwnerID *string `json:"ownerId"`
Name *string `json:"name"`
Description *string `json:"description"`
AcquiredTime *time.Time `json:"acquiredTime"`
ScheduledDate *Date `json:"scheduledDate"`
Stats []StatProgressEntry `json:"stats"`
ClearProjectRequirementID bool `json:"clearProjectRequirementId"`
ClearAcquiredTime bool `json:"clearAcquiredTime"`
ClearScheduledDate bool `json:"clearScheduledDate"`
}

14
internal/models/project.go

@ -11,5 +11,19 @@ type ProjectRequirement struct {
Name string `json:"name"`
Description string `json:"description"`
Status Status `json:"status"`
Stats []StatProgressEntry `json:"stats,omitempty"`
Items []Item `json:"items,omitempty"`
}
type ProjectRequirementUpdate struct {
Name *string `json:"name"`
Description *string `json:"description"`
Status *Status `json:"status"`
Stats []StatProgressEntry `json:"stats"`
}
type Project struct {
ProjectEntry
Description string
Requirements []ProjectRequirement
}

26
internal/models/scope.go

@ -16,9 +16,19 @@ type Scope struct {
ScopeEntry
DisplayName string `json:"displayName"`
Members []ScopeMember `json:"members"`
Projects []ProjectEntry `json:"projects"`
Stats []Stat `json:"stats"`
Members []ScopeMember `json:"members,omitempty"`
Projects []ProjectEntry `json:"projects,omitempty"`
Stats []Stat `json:"stats,omitempty"`
}
func (s *Scope) Member(id string) *ScopeMember {
for _, user := range s.Members {
if user.ID == id {
return &user
}
}
return nil
}
func (s *Scope) HasMember(id string) bool {
@ -30,3 +40,13 @@ func (s *Scope) HasMember(id string) bool {
return false
}
func (s *Scope) Stat(id int) *Stat {
for _, stat := range s.Stats {
if stat.ID == id {
return &stat
}
}
return nil
}

17
internal/models/stat.go

@ -19,3 +19,20 @@ type Stat struct {
Description string `json:"description"`
AllowedAmounts map[string]int `json:"allowedAmounts"`
}
func (stat *Stat) AllowsAmount(amount int) bool {
if stat == nil {
return false
}
if stat.AllowedAmounts == nil || len(stat.AllowedAmounts) == 0 {
return true
}
for _, v := range stat.AllowedAmounts {
if v == amount {
return true
}
}
return false
}

46
internal/sqltypes/nulldate.go

@ -0,0 +1,46 @@
package sqltypes
import (
"database/sql/driver"
"errors"
"git.aiterp.net/stufflog3/stufflog3-api/internal/models"
"time"
)
type NullDate struct {
Date models.Date
Valid bool
}
func (n *NullDate) Scan(value interface{}) error {
if value == nil {
n.Valid = false
return nil
}
switch value := value.(type) {
case string:
date, err := models.ParseDate(value)
if err != nil {
return err
}
n.Date = date
n.Valid = true
case time.Time:
n.Date = models.Date{value.Year(), int(value.Month()), value.Day()}
n.Valid = true
default:
return errors.New("invalid type")
}
return nil
}
func (n NullDate) Value() (driver.Value, error) {
if !n.Valid {
return nil, nil
}
return n.Date.String(), nil
}

10
sqlc.yaml

@ -5,17 +5,23 @@ packages:
queries: "./internal/database/mysql/queries"
schema: "./scripts/goose-mysql"
engine: "mysql"
emit_prepared_queries: true
emit_prepared_queries: false
emit_interface: false
emit_exact_table_names: false
emit_empty_slices: true
emit_json_tags: true
emit_json_tags: false
overrides:
- go_type: "git.aiterp.net/stufflog3/stufflog3-api/internal/sqltypes.NullRawMessage"
db_type: "json"
nullable: true
- go_type: "git.aiterp.net/stufflog3/stufflog3-api/internal/sqltypes.NullDate"
db_type: "date"
nullable: true
- go_type: "float64"
db_type: "float"
- go_type: "float64"
db_type: "float"
nullable: true
- go_type: "int"
db_type: "int"
Loading…
Cancel
Save