feat(contacts): events can now have organizers
This commit is contained in:
@ -19,4 +19,5 @@ type Events struct {
|
|||||||
StartDateTime *time.Time
|
StartDateTime *time.Time
|
||||||
EndDateTime *time.Time
|
EndDateTime *time.Time
|
||||||
LocationID *uuid.UUID
|
LocationID *uuid.UUID
|
||||||
|
OrganizerID *uuid.UUID
|
||||||
}
|
}
|
||||||
|
18
backend/.gen/haystack/haystack/model/image_contacts.go
Normal file
18
backend/.gen/haystack/haystack/model/image_contacts.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
//
|
||||||
|
// 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"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ImageContacts struct {
|
||||||
|
ID uuid.UUID `sql:"primary_key"`
|
||||||
|
ImageID uuid.UUID
|
||||||
|
ContactID uuid.UUID
|
||||||
|
}
|
@ -23,6 +23,7 @@ type eventsTable struct {
|
|||||||
StartDateTime postgres.ColumnTimestamp
|
StartDateTime postgres.ColumnTimestamp
|
||||||
EndDateTime postgres.ColumnTimestamp
|
EndDateTime postgres.ColumnTimestamp
|
||||||
LocationID postgres.ColumnString
|
LocationID postgres.ColumnString
|
||||||
|
OrganizerID postgres.ColumnString
|
||||||
|
|
||||||
AllColumns postgres.ColumnList
|
AllColumns postgres.ColumnList
|
||||||
MutableColumns postgres.ColumnList
|
MutableColumns postgres.ColumnList
|
||||||
@ -69,8 +70,9 @@ func newEventsTableImpl(schemaName, tableName, alias string) eventsTable {
|
|||||||
StartDateTimeColumn = postgres.TimestampColumn("start_date_time")
|
StartDateTimeColumn = postgres.TimestampColumn("start_date_time")
|
||||||
EndDateTimeColumn = postgres.TimestampColumn("end_date_time")
|
EndDateTimeColumn = postgres.TimestampColumn("end_date_time")
|
||||||
LocationIDColumn = postgres.StringColumn("location_id")
|
LocationIDColumn = postgres.StringColumn("location_id")
|
||||||
allColumns = postgres.ColumnList{IDColumn, NameColumn, DescriptionColumn, StartDateTimeColumn, EndDateTimeColumn, LocationIDColumn}
|
OrganizerIDColumn = postgres.StringColumn("organizer_id")
|
||||||
mutableColumns = postgres.ColumnList{NameColumn, DescriptionColumn, StartDateTimeColumn, EndDateTimeColumn, LocationIDColumn}
|
allColumns = postgres.ColumnList{IDColumn, NameColumn, DescriptionColumn, StartDateTimeColumn, EndDateTimeColumn, LocationIDColumn, OrganizerIDColumn}
|
||||||
|
mutableColumns = postgres.ColumnList{NameColumn, DescriptionColumn, StartDateTimeColumn, EndDateTimeColumn, LocationIDColumn, OrganizerIDColumn}
|
||||||
)
|
)
|
||||||
|
|
||||||
return eventsTable{
|
return eventsTable{
|
||||||
@ -83,6 +85,7 @@ func newEventsTableImpl(schemaName, tableName, alias string) eventsTable {
|
|||||||
StartDateTime: StartDateTimeColumn,
|
StartDateTime: StartDateTimeColumn,
|
||||||
EndDateTime: EndDateTimeColumn,
|
EndDateTime: EndDateTimeColumn,
|
||||||
LocationID: LocationIDColumn,
|
LocationID: LocationIDColumn,
|
||||||
|
OrganizerID: OrganizerIDColumn,
|
||||||
|
|
||||||
AllColumns: allColumns,
|
AllColumns: allColumns,
|
||||||
MutableColumns: mutableColumns,
|
MutableColumns: mutableColumns,
|
||||||
|
81
backend/.gen/haystack/haystack/table/image_contacts.go
Normal file
81
backend/.gen/haystack/haystack/table/image_contacts.go
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
//
|
||||||
|
// 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 ImageContacts = newImageContactsTable("haystack", "image_contacts", "")
|
||||||
|
|
||||||
|
type imageContactsTable struct {
|
||||||
|
postgres.Table
|
||||||
|
|
||||||
|
// Columns
|
||||||
|
ID postgres.ColumnString
|
||||||
|
ImageID postgres.ColumnString
|
||||||
|
ContactID postgres.ColumnString
|
||||||
|
|
||||||
|
AllColumns postgres.ColumnList
|
||||||
|
MutableColumns postgres.ColumnList
|
||||||
|
}
|
||||||
|
|
||||||
|
type ImageContactsTable struct {
|
||||||
|
imageContactsTable
|
||||||
|
|
||||||
|
EXCLUDED imageContactsTable
|
||||||
|
}
|
||||||
|
|
||||||
|
// AS creates new ImageContactsTable with assigned alias
|
||||||
|
func (a ImageContactsTable) AS(alias string) *ImageContactsTable {
|
||||||
|
return newImageContactsTable(a.SchemaName(), a.TableName(), alias)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Schema creates new ImageContactsTable with assigned schema name
|
||||||
|
func (a ImageContactsTable) FromSchema(schemaName string) *ImageContactsTable {
|
||||||
|
return newImageContactsTable(schemaName, a.TableName(), a.Alias())
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithPrefix creates new ImageContactsTable with assigned table prefix
|
||||||
|
func (a ImageContactsTable) WithPrefix(prefix string) *ImageContactsTable {
|
||||||
|
return newImageContactsTable(a.SchemaName(), prefix+a.TableName(), a.TableName())
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithSuffix creates new ImageContactsTable with assigned table suffix
|
||||||
|
func (a ImageContactsTable) WithSuffix(suffix string) *ImageContactsTable {
|
||||||
|
return newImageContactsTable(a.SchemaName(), a.TableName()+suffix, a.TableName())
|
||||||
|
}
|
||||||
|
|
||||||
|
func newImageContactsTable(schemaName, tableName, alias string) *ImageContactsTable {
|
||||||
|
return &ImageContactsTable{
|
||||||
|
imageContactsTable: newImageContactsTableImpl(schemaName, tableName, alias),
|
||||||
|
EXCLUDED: newImageContactsTableImpl("", "excluded", ""),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newImageContactsTableImpl(schemaName, tableName, alias string) imageContactsTable {
|
||||||
|
var (
|
||||||
|
IDColumn = postgres.StringColumn("id")
|
||||||
|
ImageIDColumn = postgres.StringColumn("image_id")
|
||||||
|
ContactIDColumn = postgres.StringColumn("contact_id")
|
||||||
|
allColumns = postgres.ColumnList{IDColumn, ImageIDColumn, ContactIDColumn}
|
||||||
|
mutableColumns = postgres.ColumnList{ImageIDColumn, ContactIDColumn}
|
||||||
|
)
|
||||||
|
|
||||||
|
return imageContactsTable{
|
||||||
|
Table: postgres.NewTable(schemaName, tableName, alias, allColumns...),
|
||||||
|
|
||||||
|
//Columns
|
||||||
|
ID: IDColumn,
|
||||||
|
ImageID: ImageIDColumn,
|
||||||
|
ContactID: ContactIDColumn,
|
||||||
|
|
||||||
|
AllColumns: allColumns,
|
||||||
|
MutableColumns: mutableColumns,
|
||||||
|
}
|
||||||
|
}
|
@ -13,6 +13,7 @@ func UseSchema(schema string) {
|
|||||||
Contacts = Contacts.FromSchema(schema)
|
Contacts = Contacts.FromSchema(schema)
|
||||||
Events = Events.FromSchema(schema)
|
Events = Events.FromSchema(schema)
|
||||||
Image = Image.FromSchema(schema)
|
Image = Image.FromSchema(schema)
|
||||||
|
ImageContacts = ImageContacts.FromSchema(schema)
|
||||||
ImageEvents = ImageEvents.FromSchema(schema)
|
ImageEvents = ImageEvents.FromSchema(schema)
|
||||||
ImageLinks = ImageLinks.FromSchema(schema)
|
ImageLinks = ImageLinks.FromSchema(schema)
|
||||||
ImageLocations = ImageLocations.FromSchema(schema)
|
ImageLocations = ImageLocations.FromSchema(schema)
|
||||||
|
@ -13,25 +13,27 @@ import (
|
|||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// This prompt is probably shit.
|
||||||
const eventLocationPrompt = `
|
const eventLocationPrompt = `
|
||||||
You are an agent that extracts events and locations from an image.
|
You are an agent that extracts events, locations, and organizers from an image. Your primary tasks are to identify and create locations and organizers before creating events. Follow these steps:
|
||||||
Your job is to check if an image has an event or a location and use the correct tools to extract this information.
|
|
||||||
|
|
||||||
If you find an event, you should look for a location for this event on the image, it is possible an event doesn't have a location.
|
Identify and Create Locations:
|
||||||
Only create an event if you see an event on the image, not all locations have an associated event.
|
|
||||||
|
|
||||||
It is possible that there is no location or event on an image.
|
Check if the image contains a location.
|
||||||
|
If a location is found, check if it exists in the listLocations.
|
||||||
|
If the location does not exist, create it first.
|
||||||
|
Always reuse existing locations from listLocations to avoid duplicates.
|
||||||
|
|
||||||
You should ask for a list of locations, as the user is likely to have this location saved. Reuse existing locations where possible.
|
Identify and Create Events:
|
||||||
|
|
||||||
Always reuse existing locations from listLocations. Do not create duplicates.
|
Check if the image contains an event. An event should have a name and a date.
|
||||||
|
If an event is found, ensure you have a location (from step 1) and an organizer (from step 2) before creating the event.
|
||||||
|
Events must have an associated location and organizer. Do not create an event without these.
|
||||||
|
If possible, return a start time and an end time as ISO datetime strings.
|
||||||
|
Handling Images Without Events or Locations:
|
||||||
|
|
||||||
Do not create an event if you don't see any dates, or a name indicating an event.
|
It is possible that the image does not contain an event or a location. In such cases, do not create an event.
|
||||||
|
Always prioritize the creation of locations and organizers before events. Ensure that all events have an associated location and organizer.
|
||||||
Events can have an associated location, if you think there is a location, then you must either use a location from listLocations or you must create it first.
|
|
||||||
Wherever possible, find the location in the image.
|
|
||||||
|
|
||||||
When possible return a start time as a ISO datetime string, as well as an end date time.
|
|
||||||
`
|
`
|
||||||
|
|
||||||
// TODO: this should be read directly from a file on load.
|
// TODO: this should be read directly from a file on load.
|
||||||
@ -80,18 +82,22 @@ const TOOLS = `
|
|||||||
},
|
},
|
||||||
"startDateTime": {
|
"startDateTime": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The start time as an ISO string"
|
"description": "The start time as an ISO string"
|
||||||
},
|
},
|
||||||
"endDateTime": {
|
"endDateTime": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The end time as an ISO string"
|
"description": "The end time as an ISO string"
|
||||||
},
|
},
|
||||||
"locationId": {
|
"locationId": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The ID of the location, available by listLocations"
|
"description": "The ID of the location, available by listLocations"
|
||||||
|
},
|
||||||
|
"organizerName": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The name of the organizer"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["name", "startDateTime", "endDateTime"]
|
"required": ["name"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -114,11 +120,13 @@ type EventLocationAgent struct {
|
|||||||
|
|
||||||
eventModel models.EventModel
|
eventModel models.EventModel
|
||||||
locationModel models.LocationModel
|
locationModel models.LocationModel
|
||||||
|
contactModel models.ContactModel
|
||||||
|
|
||||||
toolHandler ToolsHandlers
|
toolHandler ToolsHandlers
|
||||||
}
|
}
|
||||||
|
|
||||||
type ListLocationArguments struct{}
|
type ListLocationArguments struct{}
|
||||||
|
type ListOrganizerArguments struct{}
|
||||||
|
|
||||||
type CreateLocationArguments struct {
|
type CreateLocationArguments struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
@ -126,6 +134,12 @@ type CreateLocationArguments struct {
|
|||||||
Coordinates *string `json:"coordinates,omitempty"`
|
Coordinates *string `json:"coordinates,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CreateOrganizerArguments struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
PhoneNumber *string `json:"phoneNumber,omitempty"`
|
||||||
|
Email *string `json:"email,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
type AttachImageLocationArguments struct {
|
type AttachImageLocationArguments struct {
|
||||||
LocationId string `json:"locationId"`
|
LocationId string `json:"locationId"`
|
||||||
}
|
}
|
||||||
@ -135,6 +149,7 @@ type CreateEventArguments struct {
|
|||||||
StartDateTime string `json:"startDateTime"`
|
StartDateTime string `json:"startDateTime"`
|
||||||
EndDateTime string `json:"endDateTime"`
|
EndDateTime string `json:"endDateTime"`
|
||||||
LocationId string `json:"locationId"`
|
LocationId string `json:"locationId"`
|
||||||
|
OrganizerName string `json:"organizerName"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (agent EventLocationAgent) GetLocations(userId uuid.UUID, imageId uuid.UUID, imageName string, imageData []byte) error {
|
func (agent EventLocationAgent) GetLocations(userId uuid.UUID, imageId uuid.UUID, imageName string, imageData []byte) error {
|
||||||
@ -251,7 +266,7 @@ func (handler ToolsHandlers) Handle(info ToolHandlerInfo, request *AgentRequestB
|
|||||||
return string(stringResponse), nil
|
return string(stringResponse), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLocationEventAgent(locationModel models.LocationModel, eventModel models.EventModel) (EventLocationAgent, error) {
|
func NewLocationEventAgent(locationModel models.LocationModel, eventModel models.EventModel, contactModel models.ContactModel) (EventLocationAgent, error) {
|
||||||
client, err := CreateAgentClient(eventLocationPrompt)
|
client, err := CreateAgentClient(eventLocationPrompt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return EventLocationAgent{}, err
|
return EventLocationAgent{}, err
|
||||||
@ -261,6 +276,7 @@ func NewLocationEventAgent(locationModel models.LocationModel, eventModel models
|
|||||||
client: client,
|
client: client,
|
||||||
locationModel: locationModel,
|
locationModel: locationModel,
|
||||||
eventModel: eventModel,
|
eventModel: eventModel,
|
||||||
|
contactModel: contactModel,
|
||||||
}
|
}
|
||||||
|
|
||||||
toolHandler := ToolsHandlers{
|
toolHandler := ToolsHandlers{
|
||||||
@ -317,7 +333,7 @@ func NewLocationEventAgent(locationModel models.LocationModel, eventModel models
|
|||||||
Fn: func(info ToolHandlerInfo, args CreateEventArguments, call ToolCall) (model.Events, error) {
|
Fn: func(info ToolHandlerInfo, args CreateEventArguments, call ToolCall) (model.Events, error) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
layout := "2006-01-02T15:04:05"
|
layout := "2006-01-02T15:04:05Z"
|
||||||
|
|
||||||
startTime, err := time.Parse(layout, args.StartDateTime)
|
startTime, err := time.Parse(layout, args.StartDateTime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -339,6 +355,14 @@ func NewLocationEventAgent(locationModel models.LocationModel, eventModel models
|
|||||||
return event, err
|
return event, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
organizer, err := agent.contactModel.Save(ctx, info.userId, model.Contacts{
|
||||||
|
Name: args.Name,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return event, err
|
||||||
|
}
|
||||||
|
|
||||||
_, err = agent.eventModel.SaveToImage(ctx, info.imageId, event.ID)
|
_, err = agent.eventModel.SaveToImage(ctx, info.imageId, event.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return event, err
|
return event, err
|
||||||
@ -349,7 +373,12 @@ func NewLocationEventAgent(locationModel models.LocationModel, eventModel models
|
|||||||
return event, err
|
return event, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return agent.eventModel.UpdateLocation(ctx, event.ID, locationId)
|
event, err = agent.eventModel.UpdateLocation(ctx, event.ID, locationId)
|
||||||
|
if err != nil {
|
||||||
|
return event, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return agent.eventModel.UpdateOrganizer(ctx, event.ID, organizer.ID)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,6 +80,7 @@ func main() {
|
|||||||
locationModel := models.NewLocationModel(db)
|
locationModel := models.NewLocationModel(db)
|
||||||
eventModel := models.NewEventModel(db)
|
eventModel := models.NewEventModel(db)
|
||||||
userModel := models.NewUserModel(db)
|
userModel := models.NewUserModel(db)
|
||||||
|
contactModel := models.NewContactModel(db)
|
||||||
|
|
||||||
listener := pq.NewListener(os.Getenv("DB_CONNECTION"), time.Second, time.Second, func(event pq.ListenerEventType, err error) {
|
listener := pq.NewListener(os.Getenv("DB_CONNECTION"), time.Second, time.Second, func(event pq.ListenerEventType, err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -108,7 +109,7 @@ func main() {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
locationAgent, err := agents.NewLocationEventAgent(locationModel, eventModel)
|
locationAgent, err := agents.NewLocationEventAgent(locationModel, eventModel, contactModel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
70
backend/models/contacts.go
Normal file
70
backend/models/contacts.go
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"screenmark/screenmark/.gen/haystack/haystack/model"
|
||||||
|
. "screenmark/screenmark/.gen/haystack/haystack/table"
|
||||||
|
|
||||||
|
. "github.com/go-jet/jet/v2/postgres"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ContactModel struct {
|
||||||
|
dbPool *sql.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m ContactModel) List(ctx context.Context, userId uuid.UUID) ([]model.Contacts, error) {
|
||||||
|
listContactsStmt := SELECT(Contacts.AllColumns).
|
||||||
|
FROM(
|
||||||
|
Contacts.
|
||||||
|
INNER_JOIN(UserContacts, UserContacts.ContactID.EQ(Contacts.ID)),
|
||||||
|
).
|
||||||
|
WHERE(UserContacts.UserID.EQ(UUID(userId)))
|
||||||
|
|
||||||
|
locations := []model.Contacts{}
|
||||||
|
|
||||||
|
err := listContactsStmt.QueryContext(ctx, m.dbPool, &locations)
|
||||||
|
return locations, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m ContactModel) Save(ctx context.Context, userId uuid.UUID, contact model.Contacts) (model.Contacts, error) {
|
||||||
|
// TODO: make this a transaction
|
||||||
|
|
||||||
|
insertContactStmt := Contacts.
|
||||||
|
INSERT(Contacts.Name, Contacts.Description, Contacts.PhoneNumber, Contacts.Email).
|
||||||
|
VALUES(contact.Name, contact.Description, contact.PhoneNumber, contact.Email).
|
||||||
|
RETURNING(Contacts.AllColumns)
|
||||||
|
|
||||||
|
insertedContact := model.Contacts{}
|
||||||
|
err := insertContactStmt.QueryContext(ctx, m.dbPool, &insertedContact)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return insertedContact, err
|
||||||
|
}
|
||||||
|
|
||||||
|
insertUserContactStmt := UserContacts.
|
||||||
|
INSERT(UserContacts.UserID, UserContacts.ContactID).
|
||||||
|
VALUES(userId, insertedContact.ID)
|
||||||
|
|
||||||
|
_, err = insertUserContactStmt.ExecContext(ctx, m.dbPool)
|
||||||
|
|
||||||
|
return insertedContact, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m ContactModel) SaveToImage(ctx context.Context, imageId uuid.UUID, contactId uuid.UUID) (model.ImageContacts, error) {
|
||||||
|
insertImageContactStmt := ImageLocations.
|
||||||
|
INSERT(ImageContacts.ImageID, ImageContacts.ContactID).
|
||||||
|
VALUES(imageId, contactId).
|
||||||
|
RETURNING(ImageContacts.AllColumns)
|
||||||
|
|
||||||
|
imageContact := model.ImageContacts{}
|
||||||
|
err := insertImageContactStmt.QueryContext(ctx, m.dbPool, &imageContact)
|
||||||
|
|
||||||
|
return imageContact, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewContactModel(db *sql.DB) ContactModel {
|
||||||
|
return ContactModel{dbPool: db}
|
||||||
|
}
|
@ -62,6 +62,19 @@ func (m EventModel) UpdateLocation(ctx context.Context, eventId uuid.UUID, locat
|
|||||||
return updatedEvent, err
|
return updatedEvent, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m EventModel) UpdateOrganizer(ctx context.Context, eventId uuid.UUID, organizerId uuid.UUID) (model.Events, error) {
|
||||||
|
updateEventContactStmt := Events.
|
||||||
|
UPDATE(Events.OrganizerID).
|
||||||
|
SET(organizerId).
|
||||||
|
WHERE(Events.ID.EQ(UUID(eventId))).
|
||||||
|
RETURNING(Events.AllColumns)
|
||||||
|
|
||||||
|
updatedEvent := model.Events{}
|
||||||
|
err := updateEventContactStmt.QueryContext(ctx, m.dbPool, &updatedEvent)
|
||||||
|
|
||||||
|
return updatedEvent, err
|
||||||
|
}
|
||||||
|
|
||||||
func NewEventModel(db *sql.DB) EventModel {
|
func NewEventModel(db *sql.DB) EventModel {
|
||||||
return EventModel{dbPool: db}
|
return EventModel{dbPool: db}
|
||||||
}
|
}
|
||||||
|
@ -69,31 +69,6 @@ CREATE TABLE haystack.user_locations (
|
|||||||
user_id UUID NOT NULL REFERENCES haystack.users (id)
|
user_id UUID NOT NULL REFERENCES haystack.users (id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE haystack.events (
|
|
||||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
||||||
|
|
||||||
-- It seems name and description are frequent. We could use table inheritance.
|
|
||||||
name TEXT NOT NULL,
|
|
||||||
description TEXT,
|
|
||||||
|
|
||||||
start_date_time TIMESTAMP,
|
|
||||||
end_date_time TIMESTAMP,
|
|
||||||
|
|
||||||
location_id UUID REFERENCES haystack.locations (id)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE haystack.image_events (
|
|
||||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
||||||
event_id UUID NOT NULL REFERENCES haystack.events (id),
|
|
||||||
image_id UUID NOT NULL REFERENCES haystack.image (id)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE haystack.user_events (
|
|
||||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
||||||
event_id UUID NOT NULL REFERENCES haystack.events (id),
|
|
||||||
user_id UUID NOT NULL REFERENCES haystack.users (id)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE haystack.contacts (
|
CREATE TABLE haystack.contacts (
|
||||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
|
||||||
@ -111,6 +86,38 @@ CREATE TABLE haystack.user_contacts (
|
|||||||
contact_id UUID NOT NULL REFERENCES haystack.contacts (id)
|
contact_id UUID NOT NULL REFERENCES haystack.contacts (id)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE TABLE haystack.image_contacts (
|
||||||
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
image_id UUID NOT NULL REFERENCES haystack.image (id),
|
||||||
|
contact_id UUID NOT NULL REFERENCES haystack.contacts (id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE haystack.events (
|
||||||
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
|
||||||
|
-- It seems name and description are frequent. We could use table inheritance.
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
description TEXT,
|
||||||
|
|
||||||
|
start_date_time TIMESTAMP,
|
||||||
|
end_date_time TIMESTAMP,
|
||||||
|
|
||||||
|
location_id UUID REFERENCES haystack.locations (id),
|
||||||
|
organizer_id UUID REFERENCES haystack.contacts (id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE haystack.image_events (
|
||||||
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
event_id UUID NOT NULL REFERENCES haystack.events (id),
|
||||||
|
image_id UUID NOT NULL REFERENCES haystack.image (id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE haystack.user_events (
|
||||||
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
event_id UUID NOT NULL REFERENCES haystack.events (id),
|
||||||
|
user_id UUID NOT NULL REFERENCES haystack.users (id)
|
||||||
|
);
|
||||||
|
|
||||||
/* -----| Indexes |----- */
|
/* -----| Indexes |----- */
|
||||||
|
|
||||||
CREATE INDEX user_tags_index ON haystack.user_tags(tag);
|
CREATE INDEX user_tags_index ON haystack.user_tags(tag);
|
||||||
|
@ -3,16 +3,13 @@
|
|||||||
"type": "function",
|
"type": "function",
|
||||||
"function": {
|
"function": {
|
||||||
"name": "createLocation",
|
"name": "createLocation",
|
||||||
"description": "Creates a location",
|
"description": "Creates a location. No not use if you think an existing location is suitable!",
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"name": {
|
"name": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"coordinates": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"address": {
|
"address": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
@ -43,34 +40,27 @@
|
|||||||
"name": {
|
"name": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"datetime": {
|
"startDateTime": {
|
||||||
"type": "string"
|
"type": "string",
|
||||||
|
"description": "The start time as an ISO string"
|
||||||
|
},
|
||||||
|
"endDateTime": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The end time as an ISO string"
|
||||||
},
|
},
|
||||||
"locationId": {
|
"locationId": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The ID of the location, available by `listLocations`"
|
"description": "The ID of the location, available by listLocations"
|
||||||
|
},
|
||||||
|
"organizerName": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The name of the organizer"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["name"]
|
"required": ["name"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"type": "function",
|
|
||||||
"function": {
|
|
||||||
"name": "attachImageLocation",
|
|
||||||
"description": "Add a location to an image",
|
|
||||||
"parameters": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"locationId": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": ["locationId"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "function",
|
"type": "function",
|
||||||
"function": {
|
"function": {
|
||||||
|
Reference in New Issue
Block a user