creating stacks using a user request
This commit is contained in:
22
backend/.gen/haystack/haystack/model/processing_lists.go
Normal file
22
backend/.gen/haystack/haystack/model/processing_lists.go
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
//
|
||||||
|
// Code generated by go-jet DO NOT EDIT.
|
||||||
|
//
|
||||||
|
// WARNING: Changes to this file may cause incorrect behavior
|
||||||
|
// and will be lost if the code is regenerated
|
||||||
|
//
|
||||||
|
|
||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ProcessingLists struct {
|
||||||
|
ID uuid.UUID `sql:"primary_key"`
|
||||||
|
UserID uuid.UUID
|
||||||
|
Title string
|
||||||
|
Fields string
|
||||||
|
Status Progress
|
||||||
|
CreatedAt *time.Time
|
||||||
|
}
|
@ -20,10 +20,11 @@ type imageTable struct {
|
|||||||
ID postgres.ColumnString
|
ID postgres.ColumnString
|
||||||
ImageName postgres.ColumnString
|
ImageName postgres.ColumnString
|
||||||
Description postgres.ColumnString
|
Description postgres.ColumnString
|
||||||
Image postgres.ColumnString
|
Image postgres.ColumnBytea
|
||||||
|
|
||||||
AllColumns postgres.ColumnList
|
AllColumns postgres.ColumnList
|
||||||
MutableColumns postgres.ColumnList
|
MutableColumns postgres.ColumnList
|
||||||
|
DefaultColumns postgres.ColumnList
|
||||||
}
|
}
|
||||||
|
|
||||||
type ImageTable struct {
|
type ImageTable struct {
|
||||||
@ -64,9 +65,10 @@ func newImageTableImpl(schemaName, tableName, alias string) imageTable {
|
|||||||
IDColumn = postgres.StringColumn("id")
|
IDColumn = postgres.StringColumn("id")
|
||||||
ImageNameColumn = postgres.StringColumn("image_name")
|
ImageNameColumn = postgres.StringColumn("image_name")
|
||||||
DescriptionColumn = postgres.StringColumn("description")
|
DescriptionColumn = postgres.StringColumn("description")
|
||||||
ImageColumn = postgres.StringColumn("image")
|
ImageColumn = postgres.ByteaColumn("image")
|
||||||
allColumns = postgres.ColumnList{IDColumn, ImageNameColumn, DescriptionColumn, ImageColumn}
|
allColumns = postgres.ColumnList{IDColumn, ImageNameColumn, DescriptionColumn, ImageColumn}
|
||||||
mutableColumns = postgres.ColumnList{ImageNameColumn, DescriptionColumn, ImageColumn}
|
mutableColumns = postgres.ColumnList{ImageNameColumn, DescriptionColumn, ImageColumn}
|
||||||
|
defaultColumns = postgres.ColumnList{IDColumn}
|
||||||
)
|
)
|
||||||
|
|
||||||
return imageTable{
|
return imageTable{
|
||||||
@ -80,5 +82,6 @@ func newImageTableImpl(schemaName, tableName, alias string) imageTable {
|
|||||||
|
|
||||||
AllColumns: allColumns,
|
AllColumns: allColumns,
|
||||||
MutableColumns: mutableColumns,
|
MutableColumns: mutableColumns,
|
||||||
|
DefaultColumns: defaultColumns,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ type imageListsTable struct {
|
|||||||
|
|
||||||
AllColumns postgres.ColumnList
|
AllColumns postgres.ColumnList
|
||||||
MutableColumns postgres.ColumnList
|
MutableColumns postgres.ColumnList
|
||||||
|
DefaultColumns postgres.ColumnList
|
||||||
}
|
}
|
||||||
|
|
||||||
type ImageListsTable struct {
|
type ImageListsTable struct {
|
||||||
@ -65,6 +66,7 @@ func newImageListsTableImpl(schemaName, tableName, alias string) imageListsTable
|
|||||||
ListIDColumn = postgres.StringColumn("list_id")
|
ListIDColumn = postgres.StringColumn("list_id")
|
||||||
allColumns = postgres.ColumnList{IDColumn, ImageIDColumn, ListIDColumn}
|
allColumns = postgres.ColumnList{IDColumn, ImageIDColumn, ListIDColumn}
|
||||||
mutableColumns = postgres.ColumnList{ImageIDColumn, ListIDColumn}
|
mutableColumns = postgres.ColumnList{ImageIDColumn, ListIDColumn}
|
||||||
|
defaultColumns = postgres.ColumnList{IDColumn}
|
||||||
)
|
)
|
||||||
|
|
||||||
return imageListsTable{
|
return imageListsTable{
|
||||||
@ -77,5 +79,6 @@ func newImageListsTableImpl(schemaName, tableName, alias string) imageListsTable
|
|||||||
|
|
||||||
AllColumns: allColumns,
|
AllColumns: allColumns,
|
||||||
MutableColumns: mutableColumns,
|
MutableColumns: mutableColumns,
|
||||||
|
DefaultColumns: defaultColumns,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ type imageSchemaItemsTable struct {
|
|||||||
|
|
||||||
AllColumns postgres.ColumnList
|
AllColumns postgres.ColumnList
|
||||||
MutableColumns postgres.ColumnList
|
MutableColumns postgres.ColumnList
|
||||||
|
DefaultColumns postgres.ColumnList
|
||||||
}
|
}
|
||||||
|
|
||||||
type ImageSchemaItemsTable struct {
|
type ImageSchemaItemsTable struct {
|
||||||
@ -67,6 +68,7 @@ func newImageSchemaItemsTableImpl(schemaName, tableName, alias string) imageSche
|
|||||||
ImageIDColumn = postgres.StringColumn("image_id")
|
ImageIDColumn = postgres.StringColumn("image_id")
|
||||||
allColumns = postgres.ColumnList{IDColumn, ValueColumn, SchemaItemIDColumn, ImageIDColumn}
|
allColumns = postgres.ColumnList{IDColumn, ValueColumn, SchemaItemIDColumn, ImageIDColumn}
|
||||||
mutableColumns = postgres.ColumnList{ValueColumn, SchemaItemIDColumn, ImageIDColumn}
|
mutableColumns = postgres.ColumnList{ValueColumn, SchemaItemIDColumn, ImageIDColumn}
|
||||||
|
defaultColumns = postgres.ColumnList{IDColumn}
|
||||||
)
|
)
|
||||||
|
|
||||||
return imageSchemaItemsTable{
|
return imageSchemaItemsTable{
|
||||||
@ -80,5 +82,6 @@ func newImageSchemaItemsTableImpl(schemaName, tableName, alias string) imageSche
|
|||||||
|
|
||||||
AllColumns: allColumns,
|
AllColumns: allColumns,
|
||||||
MutableColumns: mutableColumns,
|
MutableColumns: mutableColumns,
|
||||||
|
DefaultColumns: defaultColumns,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ type listsTable struct {
|
|||||||
|
|
||||||
AllColumns postgres.ColumnList
|
AllColumns postgres.ColumnList
|
||||||
MutableColumns postgres.ColumnList
|
MutableColumns postgres.ColumnList
|
||||||
|
DefaultColumns postgres.ColumnList
|
||||||
}
|
}
|
||||||
|
|
||||||
type ListsTable struct {
|
type ListsTable struct {
|
||||||
@ -69,6 +70,7 @@ func newListsTableImpl(schemaName, tableName, alias string) listsTable {
|
|||||||
CreatedAtColumn = postgres.TimestampzColumn("created_at")
|
CreatedAtColumn = postgres.TimestampzColumn("created_at")
|
||||||
allColumns = postgres.ColumnList{IDColumn, UserIDColumn, NameColumn, DescriptionColumn, CreatedAtColumn}
|
allColumns = postgres.ColumnList{IDColumn, UserIDColumn, NameColumn, DescriptionColumn, CreatedAtColumn}
|
||||||
mutableColumns = postgres.ColumnList{UserIDColumn, NameColumn, DescriptionColumn, CreatedAtColumn}
|
mutableColumns = postgres.ColumnList{UserIDColumn, NameColumn, DescriptionColumn, CreatedAtColumn}
|
||||||
|
defaultColumns = postgres.ColumnList{IDColumn, CreatedAtColumn}
|
||||||
)
|
)
|
||||||
|
|
||||||
return listsTable{
|
return listsTable{
|
||||||
@ -83,5 +85,6 @@ func newListsTableImpl(schemaName, tableName, alias string) listsTable {
|
|||||||
|
|
||||||
AllColumns: allColumns,
|
AllColumns: allColumns,
|
||||||
MutableColumns: mutableColumns,
|
MutableColumns: mutableColumns,
|
||||||
|
DefaultColumns: defaultColumns,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ type logsTable struct {
|
|||||||
|
|
||||||
AllColumns postgres.ColumnList
|
AllColumns postgres.ColumnList
|
||||||
MutableColumns postgres.ColumnList
|
MutableColumns postgres.ColumnList
|
||||||
|
DefaultColumns postgres.ColumnList
|
||||||
}
|
}
|
||||||
|
|
||||||
type LogsTable struct {
|
type LogsTable struct {
|
||||||
@ -65,6 +66,7 @@ func newLogsTableImpl(schemaName, tableName, alias string) logsTable {
|
|||||||
CreatedAtColumn = postgres.TimestampzColumn("created_at")
|
CreatedAtColumn = postgres.TimestampzColumn("created_at")
|
||||||
allColumns = postgres.ColumnList{LogColumn, ImageIDColumn, CreatedAtColumn}
|
allColumns = postgres.ColumnList{LogColumn, ImageIDColumn, CreatedAtColumn}
|
||||||
mutableColumns = postgres.ColumnList{LogColumn, ImageIDColumn, CreatedAtColumn}
|
mutableColumns = postgres.ColumnList{LogColumn, ImageIDColumn, CreatedAtColumn}
|
||||||
|
defaultColumns = postgres.ColumnList{CreatedAtColumn}
|
||||||
)
|
)
|
||||||
|
|
||||||
return logsTable{
|
return logsTable{
|
||||||
@ -77,5 +79,6 @@ func newLogsTableImpl(schemaName, tableName, alias string) logsTable {
|
|||||||
|
|
||||||
AllColumns: allColumns,
|
AllColumns: allColumns,
|
||||||
MutableColumns: mutableColumns,
|
MutableColumns: mutableColumns,
|
||||||
|
DefaultColumns: defaultColumns,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
93
backend/.gen/haystack/haystack/table/processing_lists.go
Normal file
93
backend/.gen/haystack/haystack/table/processing_lists.go
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
//
|
||||||
|
// Code generated by go-jet DO NOT EDIT.
|
||||||
|
//
|
||||||
|
// WARNING: Changes to this file may cause incorrect behavior
|
||||||
|
// and will be lost if the code is regenerated
|
||||||
|
//
|
||||||
|
|
||||||
|
package table
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/go-jet/jet/v2/postgres"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ProcessingLists = newProcessingListsTable("haystack", "processing_lists", "")
|
||||||
|
|
||||||
|
type processingListsTable struct {
|
||||||
|
postgres.Table
|
||||||
|
|
||||||
|
// Columns
|
||||||
|
ID postgres.ColumnString
|
||||||
|
UserID postgres.ColumnString
|
||||||
|
Title postgres.ColumnString
|
||||||
|
Fields postgres.ColumnString
|
||||||
|
Status postgres.ColumnString
|
||||||
|
CreatedAt postgres.ColumnTimestampz
|
||||||
|
|
||||||
|
AllColumns postgres.ColumnList
|
||||||
|
MutableColumns postgres.ColumnList
|
||||||
|
DefaultColumns postgres.ColumnList
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProcessingListsTable struct {
|
||||||
|
processingListsTable
|
||||||
|
|
||||||
|
EXCLUDED processingListsTable
|
||||||
|
}
|
||||||
|
|
||||||
|
// AS creates new ProcessingListsTable with assigned alias
|
||||||
|
func (a ProcessingListsTable) AS(alias string) *ProcessingListsTable {
|
||||||
|
return newProcessingListsTable(a.SchemaName(), a.TableName(), alias)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Schema creates new ProcessingListsTable with assigned schema name
|
||||||
|
func (a ProcessingListsTable) FromSchema(schemaName string) *ProcessingListsTable {
|
||||||
|
return newProcessingListsTable(schemaName, a.TableName(), a.Alias())
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithPrefix creates new ProcessingListsTable with assigned table prefix
|
||||||
|
func (a ProcessingListsTable) WithPrefix(prefix string) *ProcessingListsTable {
|
||||||
|
return newProcessingListsTable(a.SchemaName(), prefix+a.TableName(), a.TableName())
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithSuffix creates new ProcessingListsTable with assigned table suffix
|
||||||
|
func (a ProcessingListsTable) WithSuffix(suffix string) *ProcessingListsTable {
|
||||||
|
return newProcessingListsTable(a.SchemaName(), a.TableName()+suffix, a.TableName())
|
||||||
|
}
|
||||||
|
|
||||||
|
func newProcessingListsTable(schemaName, tableName, alias string) *ProcessingListsTable {
|
||||||
|
return &ProcessingListsTable{
|
||||||
|
processingListsTable: newProcessingListsTableImpl(schemaName, tableName, alias),
|
||||||
|
EXCLUDED: newProcessingListsTableImpl("", "excluded", ""),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newProcessingListsTableImpl(schemaName, tableName, alias string) processingListsTable {
|
||||||
|
var (
|
||||||
|
IDColumn = postgres.StringColumn("id")
|
||||||
|
UserIDColumn = postgres.StringColumn("user_id")
|
||||||
|
TitleColumn = postgres.StringColumn("title")
|
||||||
|
FieldsColumn = postgres.StringColumn("fields")
|
||||||
|
StatusColumn = postgres.StringColumn("status")
|
||||||
|
CreatedAtColumn = postgres.TimestampzColumn("created_at")
|
||||||
|
allColumns = postgres.ColumnList{IDColumn, UserIDColumn, TitleColumn, FieldsColumn, StatusColumn, CreatedAtColumn}
|
||||||
|
mutableColumns = postgres.ColumnList{UserIDColumn, TitleColumn, FieldsColumn, StatusColumn, CreatedAtColumn}
|
||||||
|
defaultColumns = postgres.ColumnList{IDColumn, StatusColumn, CreatedAtColumn}
|
||||||
|
)
|
||||||
|
|
||||||
|
return processingListsTable{
|
||||||
|
Table: postgres.NewTable(schemaName, tableName, alias, allColumns...),
|
||||||
|
|
||||||
|
//Columns
|
||||||
|
ID: IDColumn,
|
||||||
|
UserID: UserIDColumn,
|
||||||
|
Title: TitleColumn,
|
||||||
|
Fields: FieldsColumn,
|
||||||
|
Status: StatusColumn,
|
||||||
|
CreatedAt: CreatedAtColumn,
|
||||||
|
|
||||||
|
AllColumns: allColumns,
|
||||||
|
MutableColumns: mutableColumns,
|
||||||
|
DefaultColumns: defaultColumns,
|
||||||
|
}
|
||||||
|
}
|
@ -25,6 +25,7 @@ type schemaItemsTable struct {
|
|||||||
|
|
||||||
AllColumns postgres.ColumnList
|
AllColumns postgres.ColumnList
|
||||||
MutableColumns postgres.ColumnList
|
MutableColumns postgres.ColumnList
|
||||||
|
DefaultColumns postgres.ColumnList
|
||||||
}
|
}
|
||||||
|
|
||||||
type SchemaItemsTable struct {
|
type SchemaItemsTable struct {
|
||||||
@ -69,6 +70,7 @@ func newSchemaItemsTableImpl(schemaName, tableName, alias string) schemaItemsTab
|
|||||||
SchemaIDColumn = postgres.StringColumn("schema_id")
|
SchemaIDColumn = postgres.StringColumn("schema_id")
|
||||||
allColumns = postgres.ColumnList{IDColumn, ItemColumn, ValueColumn, DescriptionColumn, SchemaIDColumn}
|
allColumns = postgres.ColumnList{IDColumn, ItemColumn, ValueColumn, DescriptionColumn, SchemaIDColumn}
|
||||||
mutableColumns = postgres.ColumnList{ItemColumn, ValueColumn, DescriptionColumn, SchemaIDColumn}
|
mutableColumns = postgres.ColumnList{ItemColumn, ValueColumn, DescriptionColumn, SchemaIDColumn}
|
||||||
|
defaultColumns = postgres.ColumnList{IDColumn}
|
||||||
)
|
)
|
||||||
|
|
||||||
return schemaItemsTable{
|
return schemaItemsTable{
|
||||||
@ -83,5 +85,6 @@ func newSchemaItemsTableImpl(schemaName, tableName, alias string) schemaItemsTab
|
|||||||
|
|
||||||
AllColumns: allColumns,
|
AllColumns: allColumns,
|
||||||
MutableColumns: mutableColumns,
|
MutableColumns: mutableColumns,
|
||||||
|
DefaultColumns: defaultColumns,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ type schemasTable struct {
|
|||||||
|
|
||||||
AllColumns postgres.ColumnList
|
AllColumns postgres.ColumnList
|
||||||
MutableColumns postgres.ColumnList
|
MutableColumns postgres.ColumnList
|
||||||
|
DefaultColumns postgres.ColumnList
|
||||||
}
|
}
|
||||||
|
|
||||||
type SchemasTable struct {
|
type SchemasTable struct {
|
||||||
@ -63,6 +64,7 @@ func newSchemasTableImpl(schemaName, tableName, alias string) schemasTable {
|
|||||||
ListIDColumn = postgres.StringColumn("list_id")
|
ListIDColumn = postgres.StringColumn("list_id")
|
||||||
allColumns = postgres.ColumnList{IDColumn, ListIDColumn}
|
allColumns = postgres.ColumnList{IDColumn, ListIDColumn}
|
||||||
mutableColumns = postgres.ColumnList{ListIDColumn}
|
mutableColumns = postgres.ColumnList{ListIDColumn}
|
||||||
|
defaultColumns = postgres.ColumnList{IDColumn}
|
||||||
)
|
)
|
||||||
|
|
||||||
return schemasTable{
|
return schemasTable{
|
||||||
@ -74,5 +76,6 @@ func newSchemasTableImpl(schemaName, tableName, alias string) schemasTable {
|
|||||||
|
|
||||||
AllColumns: allColumns,
|
AllColumns: allColumns,
|
||||||
MutableColumns: mutableColumns,
|
MutableColumns: mutableColumns,
|
||||||
|
DefaultColumns: defaultColumns,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ func UseSchema(schema string) {
|
|||||||
ImageSchemaItems = ImageSchemaItems.FromSchema(schema)
|
ImageSchemaItems = ImageSchemaItems.FromSchema(schema)
|
||||||
Lists = Lists.FromSchema(schema)
|
Lists = Lists.FromSchema(schema)
|
||||||
Logs = Logs.FromSchema(schema)
|
Logs = Logs.FromSchema(schema)
|
||||||
|
ProcessingLists = ProcessingLists.FromSchema(schema)
|
||||||
SchemaItems = SchemaItems.FromSchema(schema)
|
SchemaItems = SchemaItems.FromSchema(schema)
|
||||||
Schemas = Schemas.FromSchema(schema)
|
Schemas = Schemas.FromSchema(schema)
|
||||||
UserImages = UserImages.FromSchema(schema)
|
UserImages = UserImages.FromSchema(schema)
|
||||||
|
@ -24,6 +24,7 @@ type userImagesTable struct {
|
|||||||
|
|
||||||
AllColumns postgres.ColumnList
|
AllColumns postgres.ColumnList
|
||||||
MutableColumns postgres.ColumnList
|
MutableColumns postgres.ColumnList
|
||||||
|
DefaultColumns postgres.ColumnList
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserImagesTable struct {
|
type UserImagesTable struct {
|
||||||
@ -67,6 +68,7 @@ func newUserImagesTableImpl(schemaName, tableName, alias string) userImagesTable
|
|||||||
CreatedAtColumn = postgres.TimestampzColumn("created_at")
|
CreatedAtColumn = postgres.TimestampzColumn("created_at")
|
||||||
allColumns = postgres.ColumnList{IDColumn, ImageIDColumn, UserIDColumn, CreatedAtColumn}
|
allColumns = postgres.ColumnList{IDColumn, ImageIDColumn, UserIDColumn, CreatedAtColumn}
|
||||||
mutableColumns = postgres.ColumnList{ImageIDColumn, UserIDColumn, CreatedAtColumn}
|
mutableColumns = postgres.ColumnList{ImageIDColumn, UserIDColumn, CreatedAtColumn}
|
||||||
|
defaultColumns = postgres.ColumnList{IDColumn, CreatedAtColumn}
|
||||||
)
|
)
|
||||||
|
|
||||||
return userImagesTable{
|
return userImagesTable{
|
||||||
@ -80,5 +82,6 @@ func newUserImagesTableImpl(schemaName, tableName, alias string) userImagesTable
|
|||||||
|
|
||||||
AllColumns: allColumns,
|
AllColumns: allColumns,
|
||||||
MutableColumns: mutableColumns,
|
MutableColumns: mutableColumns,
|
||||||
|
DefaultColumns: defaultColumns,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ type userImagesToProcessTable struct {
|
|||||||
|
|
||||||
AllColumns postgres.ColumnList
|
AllColumns postgres.ColumnList
|
||||||
MutableColumns postgres.ColumnList
|
MutableColumns postgres.ColumnList
|
||||||
|
DefaultColumns postgres.ColumnList
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserImagesToProcessTable struct {
|
type UserImagesToProcessTable struct {
|
||||||
@ -67,6 +68,7 @@ func newUserImagesToProcessTableImpl(schemaName, tableName, alias string) userIm
|
|||||||
UserIDColumn = postgres.StringColumn("user_id")
|
UserIDColumn = postgres.StringColumn("user_id")
|
||||||
allColumns = postgres.ColumnList{IDColumn, StatusColumn, ImageIDColumn, UserIDColumn}
|
allColumns = postgres.ColumnList{IDColumn, StatusColumn, ImageIDColumn, UserIDColumn}
|
||||||
mutableColumns = postgres.ColumnList{StatusColumn, ImageIDColumn, UserIDColumn}
|
mutableColumns = postgres.ColumnList{StatusColumn, ImageIDColumn, UserIDColumn}
|
||||||
|
defaultColumns = postgres.ColumnList{IDColumn, StatusColumn}
|
||||||
)
|
)
|
||||||
|
|
||||||
return userImagesToProcessTable{
|
return userImagesToProcessTable{
|
||||||
@ -80,5 +82,6 @@ func newUserImagesToProcessTableImpl(schemaName, tableName, alias string) userIm
|
|||||||
|
|
||||||
AllColumns: allColumns,
|
AllColumns: allColumns,
|
||||||
MutableColumns: mutableColumns,
|
MutableColumns: mutableColumns,
|
||||||
|
DefaultColumns: defaultColumns,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ type usersTable struct {
|
|||||||
|
|
||||||
AllColumns postgres.ColumnList
|
AllColumns postgres.ColumnList
|
||||||
MutableColumns postgres.ColumnList
|
MutableColumns postgres.ColumnList
|
||||||
|
DefaultColumns postgres.ColumnList
|
||||||
}
|
}
|
||||||
|
|
||||||
type UsersTable struct {
|
type UsersTable struct {
|
||||||
@ -63,6 +64,7 @@ func newUsersTableImpl(schemaName, tableName, alias string) usersTable {
|
|||||||
EmailColumn = postgres.StringColumn("email")
|
EmailColumn = postgres.StringColumn("email")
|
||||||
allColumns = postgres.ColumnList{IDColumn, EmailColumn}
|
allColumns = postgres.ColumnList{IDColumn, EmailColumn}
|
||||||
mutableColumns = postgres.ColumnList{EmailColumn}
|
mutableColumns = postgres.ColumnList{EmailColumn}
|
||||||
|
defaultColumns = postgres.ColumnList{IDColumn}
|
||||||
)
|
)
|
||||||
|
|
||||||
return usersTable{
|
return usersTable{
|
||||||
@ -74,5 +76,6 @@ func newUsersTableImpl(schemaName, tableName, alias string) usersTable {
|
|||||||
|
|
||||||
AllColumns: allColumns,
|
AllColumns: allColumns,
|
||||||
MutableColumns: mutableColumns,
|
MutableColumns: mutableColumns,
|
||||||
|
DefaultColumns: defaultColumns,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -187,6 +187,15 @@ func (chat *Chat) AddSystem(prompt string) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (chat *Chat) AddUser(msg string) {
|
||||||
|
chat.Messages = append(chat.Messages, ChatUserMessage{
|
||||||
|
Role: User,
|
||||||
|
MessageContent: SingleMessage{
|
||||||
|
Content: msg,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func (chat *Chat) AddImage(imageName string, image []byte, query *string) error {
|
func (chat *Chat) AddImage(imageName string, image []byte, query *string) error {
|
||||||
extension := filepath.Ext(imageName)
|
extension := filepath.Ext(imageName)
|
||||||
if len(extension) == 0 {
|
if len(extension) == 0 {
|
||||||
|
@ -270,3 +270,38 @@ func (client *AgentClient) RunAgent(userId uuid.UUID, imageId uuid.UUID, imageNa
|
|||||||
|
|
||||||
return client.ToolLoop(toolHandlerInfo, &request)
|
return client.ToolLoop(toolHandlerInfo, &request)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (client *AgentClient) RunAgentAlone(userID uuid.UUID, userReq string) error {
|
||||||
|
var tools any
|
||||||
|
err := json.Unmarshal([]byte(client.Options.JsonTools), &tools)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
toolChoice := "auto"
|
||||||
|
seed := 42
|
||||||
|
|
||||||
|
request := AgentRequestBody{
|
||||||
|
Tools: &tools,
|
||||||
|
ToolChoice: &toolChoice,
|
||||||
|
Model: "google/gemini-2.5-flash",
|
||||||
|
RandomSeed: &seed,
|
||||||
|
Temperature: 0.3,
|
||||||
|
EndToolCall: client.Options.EndToolCall,
|
||||||
|
ResponseFormat: ResponseFormat{
|
||||||
|
Type: "text",
|
||||||
|
},
|
||||||
|
Chat: &Chat{
|
||||||
|
Messages: make([]ChatMessage, 0),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
request.Chat.AddSystem(client.Options.SystemPrompt)
|
||||||
|
request.Chat.AddUser(userReq)
|
||||||
|
|
||||||
|
toolHandlerInfo := ToolHandlerInfo{
|
||||||
|
UserId: userID,
|
||||||
|
}
|
||||||
|
|
||||||
|
return client.ToolLoop(toolHandlerInfo, &request)
|
||||||
|
}
|
||||||
|
140
backend/agents/create_list_agent.go
Normal file
140
backend/agents/create_list_agent.go
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
package agents
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"screenmark/screenmark/.gen/haystack/haystack/model"
|
||||||
|
"screenmark/screenmark/agents/client"
|
||||||
|
"screenmark/screenmark/models"
|
||||||
|
|
||||||
|
"github.com/charmbracelet/log"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
const createListAgentPrompt = `
|
||||||
|
You are an agent who's job is to produce a reasonable output for an unstructured input.
|
||||||
|
|
||||||
|
Your job is to create lists for the user, the user will give you a title and some fields they want
|
||||||
|
as part of the list. Your job is to take these fields, adjust their names so they have good names,
|
||||||
|
and add a good description for each one.
|
||||||
|
|
||||||
|
You can add fields if you think they make a lot of sense.
|
||||||
|
You can remove fields if they are not correct, but be sure before you do this.
|
||||||
|
`
|
||||||
|
|
||||||
|
const listJsonSchema = `
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"title": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "the title of the list"
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "the description of the list"
|
||||||
|
},
|
||||||
|
"fields": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The name of the field."
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "A description of the field."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"name",
|
||||||
|
"description"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"description": "An array of field objects."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"fields"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
type createNewListArguments struct {
|
||||||
|
Title string `json:"title"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
|
||||||
|
Fields []struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
} `json:"fields"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateListAgent struct {
|
||||||
|
client client.AgentClient
|
||||||
|
|
||||||
|
listModel models.ListModel
|
||||||
|
}
|
||||||
|
|
||||||
|
func (agent *CreateListAgent) CreateList(log *log.Logger, userID uuid.UUID, userReq string) error {
|
||||||
|
request := client.AgentRequestBody{
|
||||||
|
Model: "google/gemini-2.5-flash",
|
||||||
|
Temperature: 0.3,
|
||||||
|
ResponseFormat: client.ResponseFormat{
|
||||||
|
Type: "json_object",
|
||||||
|
JsonSchema: listJsonSchema,
|
||||||
|
},
|
||||||
|
Chat: &client.Chat{
|
||||||
|
Messages: make([]client.ChatMessage, 0),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
request.Chat.AddSystem(agent.client.Options.SystemPrompt)
|
||||||
|
request.Chat.AddUser(userReq)
|
||||||
|
|
||||||
|
resp, err := agent.client.Request(&request)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("request: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
structuredOutput := resp.Choices[0].Message.Content
|
||||||
|
|
||||||
|
var createListArgs createNewListArguments
|
||||||
|
err = json.Unmarshal([]byte(structuredOutput), &createListArgs)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
schemaItems := make([]model.SchemaItems, 0)
|
||||||
|
for _, field := range createListArgs.Fields {
|
||||||
|
schemaItems = append(schemaItems, model.SchemaItems{
|
||||||
|
Item: field.Name,
|
||||||
|
Description: field.Description,
|
||||||
|
|
||||||
|
Value: "string", // keep it simple for now.
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
agent.listModel.Save(ctx, userID, createListArgs.Title, createListArgs.Description, schemaItems)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCreateListAgent(log *log.Logger, listModel models.ListModel) CreateListAgent {
|
||||||
|
client := client.CreateAgentClient(client.CreateAgentClientOptions{
|
||||||
|
SystemPrompt: createListAgentPrompt,
|
||||||
|
Log: log,
|
||||||
|
})
|
||||||
|
|
||||||
|
agent := CreateListAgent{
|
||||||
|
client,
|
||||||
|
listModel,
|
||||||
|
}
|
||||||
|
|
||||||
|
return agent
|
||||||
|
}
|
@ -186,10 +186,6 @@ func NewListAgent(log *log.Logger, listModel models.ListModel) client.AgentClien
|
|||||||
return "Thought", nil
|
return "Thought", nil
|
||||||
})
|
})
|
||||||
|
|
||||||
agentClient.ToolHandler.AddTool("listLists", func(info client.ToolHandlerInfo, args string, call client.ToolCall) (any, error) {
|
|
||||||
return listModel.List(context.Background(), info.UserId)
|
|
||||||
})
|
|
||||||
|
|
||||||
agentClient.ToolHandler.AddTool("createList", func(info client.ToolHandlerInfo, _args string, call client.ToolCall) (any, error) {
|
agentClient.ToolHandler.AddTool("createList", func(info client.ToolHandlerInfo, _args string, call client.ToolCall) (any, error) {
|
||||||
args := createListArguments{}
|
args := createListArguments{}
|
||||||
err := json.Unmarshal([]byte(_args), &args)
|
err := json.Unmarshal([]byte(_args), &args)
|
||||||
@ -210,6 +206,10 @@ func NewListAgent(log *log.Logger, listModel models.ListModel) client.AgentClien
|
|||||||
return savedList, nil
|
return savedList, nil
|
||||||
})
|
})
|
||||||
|
|
||||||
|
agentClient.ToolHandler.AddTool("listLists", func(info client.ToolHandlerInfo, args string, call client.ToolCall) (any, error) {
|
||||||
|
return listModel.List(context.Background(), info.UserId)
|
||||||
|
})
|
||||||
|
|
||||||
agentClient.ToolHandler.AddTool("addToList", func(info client.ToolHandlerInfo, _args string, call client.ToolCall) (any, error) {
|
agentClient.ToolHandler.AddTool("addToList", func(info client.ToolHandlerInfo, _args string, call client.ToolCall) (any, error) {
|
||||||
args := addToListArguments{}
|
args := addToListArguments{}
|
||||||
err := json.Unmarshal([]byte(_args), &args)
|
err := json.Unmarshal([]byte(_args), &args)
|
||||||
|
@ -140,6 +140,57 @@ func ListenProcessingImageStatus(db *sql.DB, images models.ImageModel, notifier
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ListenNewStackEvents(db *sql.DB) {
|
||||||
|
listener := pq.NewListener(os.Getenv("DB_CONNECTION"), time.Second, time.Second, func(event pq.ListenerEventType, err error) {
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
defer listener.Close()
|
||||||
|
|
||||||
|
stackModel := models.NewListModel(db)
|
||||||
|
|
||||||
|
newStacksLogger := createLogger("New Stacks 🤖", os.Stdout)
|
||||||
|
newStacksLogger.SetLevel(log.DebugLevel)
|
||||||
|
|
||||||
|
err := listener.Listen("new_stack")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for parameters := range listener.Notify {
|
||||||
|
stackID := uuid.MustParse(parameters.Extra)
|
||||||
|
|
||||||
|
newStacksLogger.Debug("Starting processing stack", "StackID", stackID)
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
stack, err := stackModel.GetProcessing(ctx, stackID)
|
||||||
|
if err != nil {
|
||||||
|
newStacksLogger.Error("failed to get processing", "error", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := stackModel.StartProcessing(ctx, stackID); err != nil {
|
||||||
|
newStacksLogger.Error("failed to start processing", "error", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
listAgent := agents.NewCreateListAgent(newStacksLogger, stackModel)
|
||||||
|
userListRequest := fmt.Sprintf("title=%s,fields=%s", stack.Title, stack.Fields)
|
||||||
|
|
||||||
|
err = listAgent.CreateList(newStacksLogger, stack.UserID, userListRequest)
|
||||||
|
if err != nil {
|
||||||
|
newStacksLogger.Error("running agent", "err", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
newStacksLogger.Debug("Finished processing stack", "StackID", stackID)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TODO: We have channels open every a user sends an image.
|
* TODO: We have channels open every a user sends an image.
|
||||||
* We never close these channels.
|
* We never close these channels.
|
||||||
|
@ -57,6 +57,7 @@ func main() {
|
|||||||
|
|
||||||
go ListenNewImageEvents(db, ¬ifier)
|
go ListenNewImageEvents(db, ¬ifier)
|
||||||
go ListenProcessingImageStatus(db, imageModel, ¬ifier)
|
go ListenProcessingImageStatus(db, imageModel, ¬ifier)
|
||||||
|
go ListenNewStackEvents(db)
|
||||||
|
|
||||||
r := chi.NewRouter()
|
r := chi.NewRouter()
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/charmbracelet/log"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -15,7 +16,7 @@ func CorsMiddleware(next http.Handler) http.Handler {
|
|||||||
w.Header().Add("Access-Control-Allow-Headers", "*")
|
w.Header().Add("Access-Control-Allow-Headers", "*")
|
||||||
|
|
||||||
// Access-Control-Allow-Methods is often needed for preflight OPTIONS requests
|
// Access-Control-Allow-Methods is often needed for preflight OPTIONS requests
|
||||||
w.Header().Add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
|
w.Header().Add("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS")
|
||||||
|
|
||||||
// The client makes an OPTIONS preflight request before a complex request.
|
// The client makes an OPTIONS preflight request before a complex request.
|
||||||
// We must handle this and respond with the appropriate headers.
|
// We must handle this and respond with the appropriate headers.
|
||||||
@ -30,15 +31,19 @@ func CorsMiddleware(next http.Handler) http.Handler {
|
|||||||
|
|
||||||
const USER_ID = "UserID"
|
const USER_ID = "UserID"
|
||||||
|
|
||||||
func GetUserID(ctx context.Context) (uuid.UUID, error) {
|
func GetUserID(ctx context.Context, logger *log.Logger, w http.ResponseWriter) (uuid.UUID, error) {
|
||||||
userId := ctx.Value(USER_ID)
|
userId := ctx.Value(USER_ID)
|
||||||
|
|
||||||
if userId == nil {
|
if userId == nil {
|
||||||
|
w.WriteHeader(http.StatusUnauthorized)
|
||||||
|
logger.Warn("UserID not present in request")
|
||||||
return uuid.Nil, errors.New("context does not contain a user id")
|
return uuid.Nil, errors.New("context does not contain a user id")
|
||||||
}
|
}
|
||||||
|
|
||||||
userIdUuid, ok := userId.(uuid.UUID)
|
userIdUuid, ok := userId.(uuid.UUID)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
w.WriteHeader(http.StatusUnauthorized)
|
||||||
|
logger.Warn("UserID not of correct type")
|
||||||
return uuid.Nil, fmt.Errorf("context user id is not of type uuid, got: %t", userId)
|
return uuid.Nil, fmt.Errorf("context user id is not of type uuid, got: %t", userId)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,3 +92,25 @@ func GetUserIdFromUrl(next http.Handler) http.Handler {
|
|||||||
next.ServeHTTP(w, newR)
|
next.ServeHTTP(w, newR)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetPathParamID(logger *log.Logger, param string, w http.ResponseWriter, r *http.Request) (uuid.UUID, error) {
|
||||||
|
pathParam := r.PathValue(param)
|
||||||
|
if len(pathParam) == 0 {
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
|
||||||
|
err := fmt.Errorf("%s was not present", param)
|
||||||
|
logger.Warn(err)
|
||||||
|
return uuid.Nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
uuidParam, err := uuid.Parse(pathParam)
|
||||||
|
if len(pathParam) == 0 {
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
|
||||||
|
err := fmt.Errorf("could not parse param: %w", err)
|
||||||
|
logger.Warn(err)
|
||||||
|
return uuid.Nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return uuidParam, nil
|
||||||
|
}
|
||||||
|
@ -26,6 +26,90 @@ type ListWithItems struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// INSERT methods
|
||||||
|
// ========================================
|
||||||
|
|
||||||
func (m ListModel) Save(ctx context.Context, userId uuid.UUID, name string, description string, schemaItems []model.SchemaItems) (ListWithItems, error) {
|
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)
|
tx, err := m.dbPool.BeginTx(ctx, nil)
|
||||||
|
|
||||||
@ -86,53 +170,6 @@ func (m ListModel) Save(ctx context.Context, userId uuid.UUID, name string, desc
|
|||||||
return listWithItems, err
|
return listWithItems, err
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
type ImageWithSchema struct {
|
|
||||||
model.ImageLists
|
|
||||||
|
|
||||||
Items []model.ImageSchemaItems
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
type IDValue struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
Value string `json:"value"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m ListModel) SaveInto(ctx context.Context, listId uuid.UUID, imageId uuid.UUID, schemaValues []IDValue) error {
|
func (m ListModel) SaveInto(ctx context.Context, listId uuid.UUID, imageId uuid.UUID, schemaValues []IDValue) error {
|
||||||
imageSchemaItems := make([]model.ImageSchemaItems, len(schemaValues))
|
imageSchemaItems := make([]model.ImageSchemaItems, len(schemaValues))
|
||||||
|
|
||||||
@ -175,6 +212,16 @@ func (m ListModel) SaveInto(ctx context.Context, listId uuid.UUID, imageId uuid.
|
|||||||
return err
|
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
|
||||||
|
}
|
||||||
|
|
||||||
func NewListModel(db *sql.DB) ListModel {
|
func NewListModel(db *sql.DB) ListModel {
|
||||||
return ListModel{dbPool: db}
|
return ListModel{dbPool: db}
|
||||||
}
|
}
|
||||||
|
@ -52,6 +52,18 @@ CREATE TABLE haystack.lists (
|
|||||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT now()
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT now()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE TABLE haystack.processing_lists (
|
||||||
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
user_id UUID NOT NULL REFERENCES haystack.users (id),
|
||||||
|
|
||||||
|
title TEXT NOT NULL,
|
||||||
|
fields TEXT NOT NULL,
|
||||||
|
|
||||||
|
status haystack.progress NOT NULL DEFAULT 'not-started',
|
||||||
|
|
||||||
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT now()
|
||||||
|
);
|
||||||
|
|
||||||
CREATE TABLE haystack.image_lists (
|
CREATE TABLE haystack.image_lists (
|
||||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
|
||||||
@ -104,6 +116,14 @@ PERFORM pg_notify('new_processing_image_status', NEW.id::text || NEW.status::tex
|
|||||||
END
|
END
|
||||||
$$ LANGUAGE plpgsql;
|
$$ LANGUAGE plpgsql;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION notify_new_stacks()
|
||||||
|
RETURNS TRIGGER AS $$
|
||||||
|
BEGIN
|
||||||
|
PERFORM pg_notify('new_stack', NEW.id::text);
|
||||||
|
RETURN NEW;
|
||||||
|
END
|
||||||
|
$$ LANGUAGE plpgsql;
|
||||||
|
|
||||||
/* -----| Triggers |----- */
|
/* -----| Triggers |----- */
|
||||||
|
|
||||||
CREATE OR REPLACE TRIGGER on_new_image AFTER INSERT
|
CREATE OR REPLACE TRIGGER on_new_image AFTER INSERT
|
||||||
@ -117,4 +137,9 @@ ON haystack.user_images_to_process
|
|||||||
FOR EACH ROW
|
FOR EACH ROW
|
||||||
EXECUTE PROCEDURE notify_new_processing_image_status();
|
EXECUTE PROCEDURE notify_new_processing_image_status();
|
||||||
|
|
||||||
|
CREATE OR REPLACE TRIGGER on_new_image AFTER INSERT
|
||||||
|
ON haystack.processing_lists
|
||||||
|
FOR EACH ROW
|
||||||
|
EXECUTE PROCEDURE notify_new_stacks();
|
||||||
|
|
||||||
/* -----| Test Data |----- */
|
/* -----| Test Data |----- */
|
||||||
|
@ -3,6 +3,7 @@ package stacks
|
|||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"screenmark/screenmark/middleware"
|
"screenmark/screenmark/middleware"
|
||||||
@ -10,7 +11,6 @@ import (
|
|||||||
|
|
||||||
"github.com/charmbracelet/log"
|
"github.com/charmbracelet/log"
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
"github.com/google/uuid"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func writeJsonOrError[K any](logger *log.Logger, object K, w http.ResponseWriter) {
|
func writeJsonOrError[K any](logger *log.Logger, object K, w http.ResponseWriter) {
|
||||||
@ -30,26 +30,36 @@ type StackHandler struct {
|
|||||||
stackModel models.ListModel
|
stackModel models.ListModel
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *StackHandler) withUserID(
|
func withValidatedPost[K any](
|
||||||
fn func(userID uuid.UUID, w http.ResponseWriter, r *http.Request),
|
fn func(request K, w http.ResponseWriter, r *http.Request),
|
||||||
) func(w http.ResponseWriter, r *http.Request) {
|
) func(w http.ResponseWriter, r *http.Request) {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := r.Context()
|
request := new(K)
|
||||||
|
|
||||||
userID, err := middleware.GetUserID(ctx)
|
body, err := io.ReadAll(r.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logger.Warn("could not get users in get all stacks", "err", err)
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
w.WriteHeader(http.StatusUnauthorized)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fn(userID, w, r)
|
err = json.Unmarshal(body, request)
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fn(*request, w, r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *StackHandler) getAllStacks(userID uuid.UUID, w http.ResponseWriter, r *http.Request) {
|
func (h *StackHandler) getAllStacks(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
|
|
||||||
|
userID, err := middleware.GetUserID(ctx, h.logger, w)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
lists, err := h.stackModel.List(ctx, userID)
|
lists, err := h.stackModel.List(ctx, userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logger.Warn("could not get stacks", "err", err)
|
h.logger.Warn("could not get stacks", "err", err)
|
||||||
@ -60,26 +70,21 @@ func (h *StackHandler) getAllStacks(userID uuid.UUID, w http.ResponseWriter, r *
|
|||||||
writeJsonOrError(h.logger, lists, w)
|
writeJsonOrError(h.logger, lists, w)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *StackHandler) getStackItems(userID uuid.UUID, w http.ResponseWriter, r *http.Request) {
|
func (h *StackHandler) getStackItems(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
|
_, err := middleware.GetUserID(ctx, h.logger, w)
|
||||||
listID := r.PathValue("listID")
|
if err != nil {
|
||||||
if len(listID) == 0 {
|
|
||||||
h.logger.Warn("listID is not present in path")
|
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
uuidListID, err := uuid.Parse(listID)
|
listID, err := middleware.GetPathParamID(h.logger, "listID", w, r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logger.Warn("could not parse list id uuid", "err", err)
|
|
||||||
w.WriteHeader(http.StatusUnauthorized)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: must check for permission here.
|
// TODO: must check for permission here.
|
||||||
|
|
||||||
lists, err := h.stackModel.ListItems(ctx, uuidListID)
|
lists, err := h.stackModel.ListItems(ctx, listID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logger.Warn("could not get list items", "err", err)
|
h.logger.Warn("could not get list items", "err", err)
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
@ -89,6 +94,38 @@ func (h *StackHandler) getStackItems(userID uuid.UUID, w http.ResponseWriter, r
|
|||||||
writeJsonOrError(h.logger, lists, w)
|
writeJsonOrError(h.logger, lists, w)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type EditStack struct {
|
||||||
|
Hello string `json:"hello"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *StackHandler) editStack(req EditStack, w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.WriteHeader(http.StatusNotImplemented)
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateStackBody struct {
|
||||||
|
Title string `json:"title"`
|
||||||
|
|
||||||
|
// We want a regular string because AI will take care of creating these for us.
|
||||||
|
Fields string `json:"fields"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *StackHandler) createStack(body CreateStackBody, w http.ResponseWriter, r *http.Request) {
|
||||||
|
ctx := r.Context()
|
||||||
|
userID, err := middleware.GetUserID(ctx, h.logger, w)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = h.stackModel.SaveProcessing(ctx, userID, body.Title, body.Fields)
|
||||||
|
if err != nil {
|
||||||
|
h.logger.Warn("could not save processing", "err", err)
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
func (h *StackHandler) CreateRoutes(r chi.Router) {
|
func (h *StackHandler) CreateRoutes(r chi.Router) {
|
||||||
h.logger.Info("Mounting stack router")
|
h.logger.Info("Mounting stack router")
|
||||||
|
|
||||||
@ -96,8 +133,12 @@ func (h *StackHandler) CreateRoutes(r chi.Router) {
|
|||||||
r.Use(middleware.ProtectedRoute)
|
r.Use(middleware.ProtectedRoute)
|
||||||
r.Use(middleware.SetJson)
|
r.Use(middleware.SetJson)
|
||||||
|
|
||||||
r.Get("/", h.withUserID(h.getAllStacks))
|
r.Get("/", h.getAllStacks)
|
||||||
r.Get("/{listID}", h.withUserID(h.getStackItems))
|
r.Get("/{listID}", h.getStackItems)
|
||||||
|
|
||||||
|
r.Post("/", withValidatedPost(h.createStack))
|
||||||
|
|
||||||
|
r.Patch("/{listID}", withValidatedPost(h.editStack))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user