311 lines
8.2 KiB
Go
311 lines
8.2 KiB
Go
package models
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"fmt"
|
|
"screenmark/screenmark/.gen/haystack/haystack/model"
|
|
. "screenmark/screenmark/.gen/haystack/haystack/table"
|
|
|
|
. "github.com/go-jet/jet/v2/postgres"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
type ListModel struct {
|
|
dbPool *sql.DB
|
|
}
|
|
|
|
type ListWithItems struct {
|
|
model.Lists
|
|
|
|
Schema struct {
|
|
model.Schemas
|
|
|
|
SchemaItems []model.SchemaItems
|
|
}
|
|
}
|
|
|
|
type ImageWithSchema struct {
|
|
model.ImageLists
|
|
|
|
Items []model.ImageSchemaItems
|
|
}
|
|
|
|
type IDValue struct {
|
|
ID string `json:"id"`
|
|
Value string `json:"value"`
|
|
}
|
|
|
|
// ========================================
|
|
// SELECT for lists
|
|
// ========================================
|
|
|
|
func (m ListModel) List(ctx context.Context, userId uuid.UUID) ([]ListWithItems, error) {
|
|
getListsWithItems := SELECT(
|
|
Lists.AllColumns,
|
|
Schemas.AllColumns,
|
|
SchemaItems.AllColumns,
|
|
).
|
|
FROM(
|
|
Lists.
|
|
INNER_JOIN(Schemas, Schemas.ListID.EQ(Lists.ID)).
|
|
INNER_JOIN(SchemaItems, SchemaItems.SchemaID.EQ(Schemas.ID)),
|
|
).
|
|
WHERE(Lists.UserID.EQ(UUID(userId)))
|
|
|
|
lists := []ListWithItems{}
|
|
err := getListsWithItems.QueryContext(ctx, m.dbPool, &lists)
|
|
|
|
return lists, err
|
|
}
|
|
|
|
func (m ListModel) ListItems(ctx context.Context, listID uuid.UUID) ([]ImageWithSchema, error) {
|
|
getListItems := SELECT(
|
|
ImageLists.AllColumns,
|
|
ImageSchemaItems.AllColumns,
|
|
).
|
|
FROM(
|
|
ImageLists.
|
|
INNER_JOIN(ImageSchemaItems, ImageSchemaItems.ImageID.EQ(ImageLists.ImageID)),
|
|
).
|
|
WHERE(ImageLists.ListID.EQ(UUID(listID)))
|
|
|
|
listItems := make([]ImageWithSchema, 0)
|
|
err := getListItems.QueryContext(ctx, m.dbPool, &listItems)
|
|
|
|
return listItems, err
|
|
}
|
|
|
|
// ========================================
|
|
// SELECT for specific items
|
|
// ========================================
|
|
|
|
func (m ListModel) GetProcessing(ctx context.Context, processingListID uuid.UUID) (model.ProcessingLists, error) {
|
|
getProcessingListStmt := ProcessingLists.
|
|
SELECT(ProcessingLists.AllColumns).
|
|
WHERE(ProcessingLists.ID.EQ(UUID(processingListID)))
|
|
|
|
list := model.ProcessingLists{}
|
|
err := getProcessingListStmt.QueryContext(ctx, m.dbPool, &list)
|
|
|
|
return list, err
|
|
}
|
|
|
|
func (m ListModel) GetToProcess(ctx context.Context, listID uuid.UUID) (model.ProcessingLists, error) {
|
|
getToProcessStmt := ProcessingLists.
|
|
SELECT(ProcessingLists.AllColumns).
|
|
WHERE(ProcessingLists.ID.EQ(UUID(listID)))
|
|
|
|
stack := []model.ProcessingLists{}
|
|
err := getToProcessStmt.QueryContext(ctx, m.dbPool, &stack)
|
|
|
|
if len(stack) != 1 {
|
|
return model.ProcessingLists{}, fmt.Errorf("Expected 1, got %d\n", len(stack))
|
|
}
|
|
|
|
return stack[0], err
|
|
}
|
|
|
|
// ========================================
|
|
// UPDATE
|
|
// ========================================
|
|
|
|
func (m ListModel) StartProcessing(ctx context.Context, processingListID uuid.UUID) error {
|
|
startProcessingStmt := ProcessingLists.
|
|
UPDATE(ProcessingLists.Status).
|
|
SET(model.Progress_InProgress).
|
|
WHERE(ProcessingLists.ID.EQ(UUID(processingListID)))
|
|
|
|
_, err := startProcessingStmt.ExecContext(ctx, m.dbPool)
|
|
return err
|
|
}
|
|
|
|
func (m ListModel) EndProcessing(ctx context.Context, processingListID uuid.UUID) error {
|
|
startProcessingStmt := ProcessingLists.
|
|
UPDATE(ProcessingLists.Status).
|
|
SET(model.Progress_Complete).
|
|
WHERE(ProcessingLists.ID.EQ(UUID(processingListID)))
|
|
|
|
_, err := startProcessingStmt.ExecContext(ctx, m.dbPool)
|
|
return err
|
|
}
|
|
|
|
// ========================================
|
|
// INSERT methods
|
|
// ========================================
|
|
|
|
func (m ListModel) Save(ctx context.Context, userId uuid.UUID, name string, description string, schemaItems []model.SchemaItems) (ListWithItems, error) {
|
|
tx, err := m.dbPool.BeginTx(ctx, nil)
|
|
|
|
stmt := Lists.INSERT(Lists.UserID, Lists.Name, Lists.Description).
|
|
VALUES(userId, name, description).
|
|
RETURNING(Lists.ID, Lists.Name, Lists.Description)
|
|
|
|
newList := model.Lists{}
|
|
err = stmt.QueryContext(ctx, tx, &newList)
|
|
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return ListWithItems{}, fmt.Errorf("Could not save new list. %s", err)
|
|
}
|
|
|
|
insertSchemaStmt := Schemas.INSERT(Schemas.ListID).
|
|
VALUES(newList.ID).
|
|
RETURNING(Schemas.ID)
|
|
|
|
newSchema := model.Schemas{}
|
|
err = insertSchemaStmt.QueryContext(ctx, tx, &newSchema)
|
|
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return ListWithItems{}, fmt.Errorf("Could not save new schema. %s", err)
|
|
}
|
|
|
|
// This is very interesting...
|
|
for i := range schemaItems {
|
|
schemaItems[i].SchemaID = newSchema.ID
|
|
}
|
|
|
|
insertSchemaItemsStmt := SchemaItems.INSERT(SchemaItems.Item, SchemaItems.Value, SchemaItems.Description, SchemaItems.SchemaID).
|
|
MODELS(schemaItems)
|
|
_, err = insertSchemaItemsStmt.ExecContext(ctx, tx)
|
|
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return ListWithItems{}, fmt.Errorf("Could not save schema items. %s", err)
|
|
}
|
|
|
|
err = tx.Commit()
|
|
if err != nil {
|
|
return ListWithItems{}, fmt.Errorf("Could not commit transaction. %s", err)
|
|
}
|
|
|
|
getListAndItems := SELECT(Lists.AllColumns, Schemas.AllColumns, SchemaItems.AllColumns).
|
|
FROM(
|
|
Lists.
|
|
INNER_JOIN(Schemas, Schemas.ListID.EQ(Lists.ID)).
|
|
INNER_JOIN(SchemaItems, SchemaItems.SchemaID.EQ(Schemas.ID)),
|
|
).
|
|
WHERE(Lists.ID.EQ(UUID(newList.ID)))
|
|
|
|
listWithItems := ListWithItems{}
|
|
err = getListAndItems.QueryContext(ctx, m.dbPool, &listWithItems)
|
|
|
|
return listWithItems, err
|
|
}
|
|
|
|
func (m ListModel) SaveInto(ctx context.Context, listId uuid.UUID, imageId uuid.UUID, schemaValues []IDValue) error {
|
|
imageSchemaItems := make([]model.ImageSchemaItems, len(schemaValues))
|
|
|
|
for i, v := range schemaValues {
|
|
parsedId, err := uuid.Parse(v.ID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
imageSchemaItems[i].SchemaItemID = parsedId
|
|
imageSchemaItems[i].ImageID = imageId
|
|
imageSchemaItems[i].Value = &v.Value
|
|
}
|
|
|
|
tx, err := m.dbPool.BeginTx(ctx, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
stmt := ImageLists.INSERT(ImageLists.ListID, ImageLists.ImageID).
|
|
VALUES(listId, imageId)
|
|
|
|
_, err = stmt.ExecContext(ctx, tx)
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return fmt.Errorf("Could not insert new list. %s", err)
|
|
}
|
|
|
|
insertSchemaItemsStmt := ImageSchemaItems.
|
|
INSERT(ImageSchemaItems.Value, ImageSchemaItems.SchemaItemID, ImageSchemaItems.ImageID).
|
|
MODELS(imageSchemaItems)
|
|
|
|
_, err = insertSchemaItemsStmt.ExecContext(ctx, tx)
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return fmt.Errorf("Could not insert schema items. %s", err)
|
|
}
|
|
|
|
err = tx.Commit()
|
|
return err
|
|
}
|
|
|
|
func (m ListModel) SaveProcessing(ctx context.Context, userID uuid.UUID, title string, fields string) error {
|
|
insertListToProcess := ProcessingLists.
|
|
INSERT(ProcessingLists.UserID, ProcessingLists.Title, ProcessingLists.Fields).
|
|
VALUES(userID, title, fields)
|
|
|
|
_, err := insertListToProcess.ExecContext(ctx, m.dbPool)
|
|
|
|
return err
|
|
}
|
|
|
|
// ========================================
|
|
// DELETE methods
|
|
// ========================================
|
|
|
|
func (m ListModel) Delete(ctx context.Context, listID uuid.UUID, userID uuid.UUID) error {
|
|
// First verify the list belongs to the user
|
|
checkOwnershipStmt := Lists.
|
|
SELECT(Lists.ID).
|
|
WHERE(Lists.ID.EQ(UUID(listID)).AND(Lists.UserID.EQ(UUID(userID))))
|
|
|
|
var existingList model.Lists
|
|
err := checkOwnershipStmt.QueryContext(ctx, m.dbPool, &existingList)
|
|
if err != nil {
|
|
return fmt.Errorf("could not verify list ownership: %w", err)
|
|
}
|
|
|
|
// Start a transaction to ensure all deletions happen atomically
|
|
tx, err := m.dbPool.BeginTx(ctx, nil)
|
|
if err != nil {
|
|
return fmt.Errorf("could not start transaction: %w", err)
|
|
}
|
|
defer tx.Rollback()
|
|
|
|
// Delete in reverse order of dependencies:
|
|
// 1. Delete schema items first
|
|
deleteSchemaItemsStmt := SchemaItems.DELETE().
|
|
WHERE(SchemaItems.SchemaID.IN(
|
|
Schemas.SELECT(Schemas.ID).
|
|
WHERE(Schemas.ListID.EQ(UUID(listID))),
|
|
))
|
|
_, err = deleteSchemaItemsStmt.ExecContext(ctx, tx)
|
|
if err != nil {
|
|
return fmt.Errorf("could not delete schema items: %w", err)
|
|
}
|
|
|
|
// 2. Delete schemas
|
|
deleteSchemasStmt := Schemas.DELETE().WHERE(Schemas.ListID.EQ(UUID(listID)))
|
|
_, err = deleteSchemasStmt.ExecContext(ctx, tx)
|
|
if err != nil {
|
|
return fmt.Errorf("could not delete schemas: %w", err)
|
|
}
|
|
|
|
// 3. Delete the list itself
|
|
deleteListStmt := Lists.DELETE().WHERE(Lists.ID.EQ(UUID(listID)))
|
|
_, err = deleteListStmt.ExecContext(ctx, tx)
|
|
if err != nil {
|
|
return fmt.Errorf("could not delete list: %w", err)
|
|
}
|
|
|
|
// Commit the transaction
|
|
err = tx.Commit()
|
|
if err != nil {
|
|
return fmt.Errorf("could not commit transaction: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func NewListModel(db *sql.DB) ListModel {
|
|
return ListModel{dbPool: db}
|
|
}
|