first commit

This commit is contained in:
2020-12-31 17:49:54 +01:00
commit 2240985aa1
120 changed files with 11574 additions and 0 deletions
+28
View File
@@ -0,0 +1,28 @@
package database
import (
"context"
"errors"
"github.com/gissleh/stufflog/database/postgres"
"github.com/gissleh/stufflog/models"
)
var ErrUnsupportedDriver = errors.New("usupported driver")
type Database interface {
Goals() models.GoalRepository
Groups() models.GroupRepository
Items() models.ItemRepository
Logs() models.LogRepository
Projects() models.ProjectRepository
Tasks() models.TaskRepository
}
func Open(ctx context.Context, driver string, connect string) (Database, error) {
switch driver {
case "postgres":
return postgres.Setup(ctx, connect)
default:
return nil, ErrUnsupportedDriver
}
}
+51
View File
@@ -0,0 +1,51 @@
package postgres
import (
"context"
"github.com/gissleh/stufflog/models"
"github.com/jmoiron/sqlx"
_ "github.com/lib/pq"
)
type Database struct {
db *sqlx.DB
}
func (d *Database) Goals() models.GoalRepository {
return &goalRepository{db: d.db}
}
func (d *Database) Groups() models.GroupRepository {
return &groupRepository{db: d.db}
}
func (d *Database) Items() models.ItemRepository {
return &itemRepository{db: d.db}
}
func (d *Database) Logs() models.LogRepository {
return &logRepository{db: d.db}
}
func (d *Database) Projects() models.ProjectRepository {
return &projectRepository{db: d.db}
}
func (d *Database) Tasks() models.TaskRepository {
return &taskRepository{db: d.db}
}
func Setup(ctx context.Context, connect string) (*Database, error) {
db, err := sqlx.ConnectContext(ctx, "postgres", connect)
if err != nil {
return nil, err
}
err = db.PingContext(ctx)
if err != nil {
return nil, err
}
return &Database{db: db}, nil
}
+115
View File
@@ -0,0 +1,115 @@
package postgres
import (
"context"
"database/sql"
"github.com/Masterminds/squirrel"
"github.com/gissleh/stufflog/internal/slerrors"
"github.com/gissleh/stufflog/models"
"github.com/jmoiron/sqlx"
)
type goalRepository struct {
db *sqlx.DB
}
func (r *goalRepository) Find(ctx context.Context, id string) (*models.Goal, error) {
res := models.Goal{}
err := r.db.GetContext(ctx, &res, "SELECT * FROM goal WHERE goal_id=$1", id)
if err != nil {
if err == sql.ErrNoRows {
return nil, slerrors.NotFound("Goal")
}
return nil, err
}
return &res, nil
}
func (r *goalRepository) List(ctx context.Context, filter models.GoalFilter) ([]*models.Goal, error) {
sq := squirrel.Select("*").From("goal").PlaceholderFormat(squirrel.Dollar)
sq = sq.Where(squirrel.Eq{"user_id": filter.UserID})
if len(filter.IDs) > 0 {
sq = sq.Where(squirrel.Eq{"goal_id": filter.IDs})
}
if filter.MinTime != nil {
sq = sq.Where(squirrel.GtOrEq{
"end_time": *filter.MinTime,
})
}
if filter.MaxTime != nil {
sq = sq.Where(squirrel.LtOrEq{
"start_time": *filter.MaxTime,
})
}
if filter.IncludesTime != nil {
sq = sq.Where(squirrel.LtOrEq{
"start_time": *filter.IncludesTime,
}).Where(squirrel.GtOrEq{
"end_time": *filter.IncludesTime,
})
}
sq = sq.OrderBy("start_time", "end_time", "name")
query, args, err := sq.ToSql()
if err != nil {
return nil, err
}
res := make([]*models.Goal, 0, 8)
err = r.db.SelectContext(ctx, &res, query, args...)
if err != nil {
if err == sql.ErrNoRows {
return res, nil
}
return nil, err
}
return res, nil
}
func (r *goalRepository) Insert(ctx context.Context, goal models.Goal) error {
_, err := r.db.NamedExecContext(ctx, `
INSERT INTO goal (
goal_id, user_id, group_id, amount, start_time, end_time, name, description
) VALUES (
:goal_id, :user_id, :group_id, :amount, :start_time, :end_time, :name, :description
)
`, &goal)
if err != nil {
return err
}
return nil
}
func (r *goalRepository) Update(ctx context.Context, goal models.Goal) error {
_, err := r.db.NamedExecContext(ctx, `
UPDATE goal SET
amount=:amount,
start_time=:start_time,
end_time=:end_time,
name=:name,
description=:description
WHERE goal_id=:goal_id
`, &goal)
if err != nil {
return err
}
return nil
}
func (r *goalRepository) Delete(ctx context.Context, goal models.Goal) error {
_, err := r.db.ExecContext(ctx, `DELETE FROM goal WHERE goal_id=$1`, goal.ID)
if err != nil {
if err == sql.ErrNoRows {
return slerrors.NotFound("Goal")
}
return err
}
return nil
}
+96
View File
@@ -0,0 +1,96 @@
package postgres
import (
"context"
"database/sql"
"github.com/Masterminds/squirrel"
"github.com/gissleh/stufflog/internal/slerrors"
"github.com/gissleh/stufflog/models"
"github.com/jmoiron/sqlx"
)
type groupRepository struct {
db *sqlx.DB
}
func (r *groupRepository) Find(ctx context.Context, id string) (*models.Group, error) {
res := models.Group{}
err := r.db.GetContext(ctx, &res, "SELECT * FROM \"group\" WHERE group_id=$1", id)
if err != nil {
if err == sql.ErrNoRows {
return nil, slerrors.NotFound("Group")
}
return nil, err
}
return &res, nil
}
func (r *groupRepository) List(ctx context.Context, filter models.GroupFilter) ([]*models.Group, error) {
sq := squirrel.Select("*").From("\"group\"").PlaceholderFormat(squirrel.Dollar)
sq = sq.Where(squirrel.Eq{"user_id": filter.UserID})
if len(filter.IDs) > 0 {
sq = sq.Where(squirrel.Eq{"group_id": filter.IDs})
}
sq = sq.OrderBy("name")
query, args, err := sq.ToSql()
if err != nil {
return nil, err
}
res := make([]*models.Group, 0, 8)
err = r.db.SelectContext(ctx, &res, query, args...)
if err != nil {
if err == sql.ErrNoRows {
return []*models.Group{}, nil
}
return nil, err
}
return res, nil
}
func (r *groupRepository) Insert(ctx context.Context, group models.Group) error {
_, err := r.db.NamedExecContext(ctx, `
INSERT INTO "group" (
group_id, user_id, name, icon, description
) VALUES (
:group_id, :user_id, :name, :icon, :description
)
`, &group)
if err != nil {
return err
}
return nil
}
func (r *groupRepository) Update(ctx context.Context, group models.Group) error {
_, err := r.db.NamedExecContext(ctx, `
UPDATE "group" SET
name=:name,
icon=:icon,
description=:description
WHERE group_id=:group_id
`, &group)
if err != nil {
return err
}
return nil
}
func (r *groupRepository) Delete(ctx context.Context, group models.Group) error {
_, err := r.db.ExecContext(ctx, `DELETE FROM "group" WHERE group_id=$1`, group.ID)
if err != nil {
if err == sql.ErrNoRows {
return slerrors.NotFound("Group")
}
return err
}
return nil
}
+100
View File
@@ -0,0 +1,100 @@
package postgres
import (
"context"
"database/sql"
"github.com/Masterminds/squirrel"
"github.com/gissleh/stufflog/internal/slerrors"
"github.com/gissleh/stufflog/models"
"github.com/jmoiron/sqlx"
)
type itemRepository struct {
db *sqlx.DB
}
func (r *itemRepository) Find(ctx context.Context, id string) (*models.Item, error) {
res := models.Item{}
err := r.db.GetContext(ctx, &res, "SELECT item.*, g.icon FROM item INNER JOIN \"group\" AS g ON item.group_id = g.group_id WHERE item_id=$1", id)
if err != nil {
if err == sql.ErrNoRows {
return nil, slerrors.NotFound("Item")
}
return nil, err
}
return &res, nil
}
func (r *itemRepository) List(ctx context.Context, filter models.ItemFilter) ([]*models.Item, error) {
sq := squirrel.Select("item.*", "g.icon").From("item").PlaceholderFormat(squirrel.Dollar)
sq = sq.Where(squirrel.Eq{"item.user_id": filter.UserID})
if len(filter.IDs) > 0 {
sq = sq.Where(squirrel.Eq{"item.item_id": filter.IDs})
}
if len(filter.GroupIDs) > 0 {
sq = sq.Where(squirrel.Eq{"item.group_id": filter.GroupIDs})
}
sq = sq.InnerJoin("\"group\" AS g ON item.group_id = g.group_id")
sq = sq.OrderBy("item.group_weight", "item.name")
query, args, err := sq.ToSql()
if err != nil {
return nil, err
}
res := make([]*models.Item, 0, 8)
err = r.db.SelectContext(ctx, &res, query, args...)
if err != nil {
if err == sql.ErrNoRows {
return res, nil
}
return nil, err
}
return res, nil
}
func (r *itemRepository) Insert(ctx context.Context, item models.Item) error {
_, err := r.db.NamedExecContext(ctx, `
INSERT INTO item (
item_id, user_id, group_id, group_weight, name, description
) VALUES (
:item_id, :user_id, :group_id, :group_weight, :name, :description
)
`, &item)
if err != nil {
return err
}
return nil
}
func (r *itemRepository) Update(ctx context.Context, item models.Item) error {
_, err := r.db.NamedExecContext(ctx, `
UPDATE item SET
group_weight = :group_weight,
name = :name,
description = :description
WHERE item_id=:item_id
`, &item)
if err != nil {
return err
}
return nil
}
func (r *itemRepository) Delete(ctx context.Context, item models.Item) error {
_, err := r.db.ExecContext(ctx, `DELETE FROM item WHERE item_id=$1`, item.ID)
if err != nil {
if err == sql.ErrNoRows {
return slerrors.NotFound("Item")
}
return err
}
return nil
}
+108
View File
@@ -0,0 +1,108 @@
package postgres
import (
"context"
"database/sql"
"github.com/Masterminds/squirrel"
"github.com/gissleh/stufflog/internal/slerrors"
"github.com/gissleh/stufflog/models"
"github.com/jmoiron/sqlx"
)
type logRepository struct {
db *sqlx.DB
}
func (r *logRepository) Find(ctx context.Context, id string) (*models.Log, error) {
res := models.Log{}
err := r.db.GetContext(ctx, &res, "SELECT * FROM log WHERE log_id=$1", id)
if err != nil {
if err == sql.ErrNoRows {
return nil, slerrors.NotFound("Log")
}
return nil, err
}
return &res, nil
}
func (r *logRepository) List(ctx context.Context, filter models.LogFilter) ([]*models.Log, error) {
sq := squirrel.Select("log.*").From("log").PlaceholderFormat(squirrel.Dollar)
sq = sq.Where(squirrel.Eq{"user_id": filter.UserID})
if len(filter.IDs) > 0 {
sq = sq.Where(squirrel.Eq{"task_id": filter.IDs})
}
if len(filter.ItemIDs) > 0 {
sq = sq.Where(squirrel.Eq{"item_id": filter.ItemIDs})
}
if filter.MinTime != nil {
sq = sq.Where(squirrel.GtOrEq{
"logged_time": *filter.MinTime,
})
}
if filter.MaxTime != nil {
sq = sq.Where(squirrel.LtOrEq{
"logged_time": *filter.MaxTime,
})
}
sq = sq.OrderBy("logged_time")
query, args, err := sq.ToSql()
if err != nil {
return nil, err
}
res := make([]*models.Log, 0, 8)
err = r.db.SelectContext(ctx, &res, query, args...)
if err != nil {
if err == sql.ErrNoRows {
return res, nil
}
return nil, err
}
return res, nil
}
func (r *logRepository) Insert(ctx context.Context, log models.Log) error {
_, err := r.db.NamedExecContext(ctx, `
INSERT INTO log (
log_id, user_id, task_id, item_id, logged_time, description
) VALUES (
:log_id, :user_id, :task_id, :item_id, :logged_time, :description
)
`, &log)
if err != nil {
return err
}
return nil
}
func (r *logRepository) Update(ctx context.Context, log models.Log) error {
_, err := r.db.NamedExecContext(ctx, `
UPDATE log SET
logged_time=:logged_time,
description=:description
WHERE log_id=:log_id
`, &log)
if err != nil {
return err
}
return nil
}
func (r *logRepository) Delete(ctx context.Context, log models.Log) error {
_, err := r.db.ExecContext(ctx, `DELETE FROM log WHERE log_id=$1`, log.ID)
if err != nil {
if err == sql.ErrNoRows {
return slerrors.NotFound("Log")
}
return err
}
return nil
}
+104
View File
@@ -0,0 +1,104 @@
package postgres
import (
"context"
"database/sql"
"github.com/Masterminds/squirrel"
"github.com/gissleh/stufflog/internal/slerrors"
"github.com/gissleh/stufflog/models"
"github.com/jmoiron/sqlx"
)
type projectRepository struct {
db *sqlx.DB
}
func (r *projectRepository) Find(ctx context.Context, id string) (*models.Project, error) {
res := models.Project{}
err := r.db.GetContext(ctx, &res, "SELECT * FROM project WHERE project_id=$1", id)
if err != nil {
if err == sql.ErrNoRows {
return nil, slerrors.NotFound("Log")
}
return nil, err
}
return &res, nil
}
func (r *projectRepository) List(ctx context.Context, filter models.ProjectFilter) ([]*models.Project, error) {
sq := squirrel.Select("*").From("project").PlaceholderFormat(squirrel.Dollar)
sq = sq.Where(squirrel.Eq{"user_id": filter.UserID})
if filter.IDs != nil {
sq = sq.Where(squirrel.Eq{"project_id": filter.IDs})
}
if filter.Active != nil {
sq = sq.Where(squirrel.Eq{"active": *filter.Active})
}
if filter.Expiring {
sq = sq.Where("end_time IS NOT NULL")
}
sq = sq.OrderBy("created_time DESC")
query, args, err := sq.ToSql()
if err != nil {
return nil, err
}
res := make([]*models.Project, 0, 8)
err = r.db.SelectContext(ctx, &res, query, args...)
if err != nil {
if err == sql.ErrNoRows {
return res, nil
}
return nil, err
}
return res, nil
}
func (r *projectRepository) Insert(ctx context.Context, project models.Project) error {
_, err := r.db.NamedExecContext(ctx, `
INSERT INTO project(
project_id, user_id, name, description, icon, active, created_time, end_time
) VALUES (
:project_id, :user_id, :name, :description, :icon, :active, :created_time, :end_time
)
`, &project)
if err != nil {
return err
}
return nil
}
func (r *projectRepository) Update(ctx context.Context, project models.Project) error {
_, err := r.db.NamedExecContext(ctx, `
UPDATE project SET
name = :name,
description = :description,
icon = :icon,
active = :active,
end_time = :end_time
WHERE project_id=:project_id
`, &project)
if err != nil {
return err
}
return nil
}
func (r *projectRepository) Delete(ctx context.Context, project models.Project) error {
_, err := r.db.ExecContext(ctx, `DELETE FROM project WHERE project_id=$1`, project.ID)
if err != nil {
if err == sql.ErrNoRows {
return slerrors.NotFound("Project")
}
return err
}
return nil
}
+109
View File
@@ -0,0 +1,109 @@
package postgres
import (
"context"
"database/sql"
"github.com/Masterminds/squirrel"
"github.com/gissleh/stufflog/internal/slerrors"
"github.com/gissleh/stufflog/models"
"github.com/jmoiron/sqlx"
)
type taskRepository struct {
db *sqlx.DB
}
func (r *taskRepository) Find(ctx context.Context, id string) (*models.Task, error) {
res := models.Task{}
err := r.db.GetContext(ctx, &res, "SELECT task.*, p.icon FROM task INNER JOIN project AS p ON task.project_id = p.project_id WHERE task_id=$1", id)
if err != nil {
if err == sql.ErrNoRows {
return nil, slerrors.NotFound("Task")
}
return nil, err
}
return &res, nil
}
func (r *taskRepository) List(ctx context.Context, filter models.TaskFilter) ([]*models.Task, error) {
sq := squirrel.Select("task.*", "p.icon").From("task").PlaceholderFormat(squirrel.Dollar)
sq = sq.Where(squirrel.Eq{"task.user_id": filter.UserID})
if filter.Active != nil {
sq = sq.Where(squirrel.Eq{"task.active": *filter.Active})
}
if filter.IDs != nil {
sq = sq.Where(squirrel.Eq{"task.task_id": filter.IDs})
}
if filter.ItemIDs != nil {
sq = sq.Where(squirrel.Eq{"task.item_id": filter.ItemIDs})
}
if filter.ProjectIDs != nil {
sq = sq.Where(squirrel.Eq{"task.project_id": filter.ProjectIDs})
}
sq = sq.InnerJoin("project AS p ON task.project_id = p.project_id")
sq = sq.OrderBy("created_time")
query, args, err := sq.ToSql()
if err != nil {
return nil, err
}
res := make([]*models.Task, 0, 8)
err = r.db.SelectContext(ctx, &res, query, args...)
if err != nil {
if err == sql.ErrNoRows {
return res, nil
}
return nil, err
}
return res, nil
}
func (r *taskRepository) Insert(ctx context.Context, task models.Task) error {
_, err := r.db.NamedExecContext(ctx, `
INSERT INTO task (
task_id, user_id, item_id, project_id, item_amount, name, description, active, created_time, end_time
) VALUES (
:task_id, :user_id, :item_id, :project_id, :item_amount, :name, :description, :active, :created_time, :end_time
)
`, &task)
if err != nil {
return err
}
return nil
}
func (r *taskRepository) Update(ctx context.Context, task models.Task) error {
_, err := r.db.NamedExecContext(ctx, `
UPDATE task SET
item_id = :item_id,
item_amount = :item_amount,
name = :name,
description = :description,
active = :active,
end_time = :end_time
WHERE task_id=:task_id
`, &task)
if err != nil {
return err
}
return nil
}
func (r *taskRepository) Delete(ctx context.Context, task models.Task) error {
_, err := r.db.ExecContext(ctx, `DELETE FROM task WHERE task_id=$1`, task.ID)
if err != nil {
if err == sql.ErrNoRows {
return slerrors.NotFound("Task")
}
return err
}
return nil
}