package data import ( "errors" "slices" "time" "github.com/go-viper/mapstructure/v2" "github.com/google/uuid" "github.com/meilisearch/meilisearch-go" "gorm.io/datatypes" "gorm.io/gorm" "gorm.io/gorm/clause" ) type Event struct { Id uint `json:"id" gorm:"primarykey;autoincrement"` UUID uuid.UUID `json:"uuid" gorm:"type:uuid;uniqueIndex;not null"` EventId uuid.UUID `json:"event_id" gorm:"type:uuid;uniqueIndex;not null"` Name string `json:"name" gorm:"type:varchar(255);index;not null"` StartTime time.Time `json:"start_time" gorm:"index"` EndTime time.Time `json:"end_time" gorm:"index"` JoinedUsers datatypes.JSONSlice[uuid.UUID] `json:"joined_users"` } type EventSearchDoc struct { EventId string `json:"event_id"` Name string `json:"name"` StartTime time.Time `json:"start_time"` EndTime time.Time `json:"end_time"` } func (self *Event) GetEventById(eventId uuid.UUID) error { return Database.Transaction(func(tx *gorm.DB) error { if err := tx.Where("event_id = ?", eventId).First(&self).Error; err != nil { return err } return nil }) } func (self *Event) UpdateEventById(eventId uuid.UUID) error { return Database.Transaction(func(tx *gorm.DB) error { if err := tx.Model(&Event{}).Where("event_id = ?", eventId).Updates(&self).Error; err != nil { return err } // Update event to document index doc := EventSearchDoc{ EventId: self.EventId.String(), Name: self.Name, StartTime: self.StartTime, EndTime: self.EndTime, } index := MeiliSearch.Index("event") docPrimaryKey := "event_id" meiliOptions := &meilisearch.DocumentOptions{PrimaryKey: &docPrimaryKey} if _, err := index.UpdateDocuments([]EventSearchDoc{doc}, meiliOptions); err != nil { return err } return nil }) } func (self *Event) CreateEvent() error { if self.UUID == uuid.Nil { self.UUID = uuid.New() } if self.EventId == uuid.Nil { self.EventId = uuid.New() } return Database.Transaction(func(tx *gorm.DB) error { if err := tx.Create(&self).Error; err != nil { return err } // Add event to document index doc := EventSearchDoc{ EventId: self.EventId.String(), Name: self.Name, StartTime: self.StartTime, EndTime: self.EndTime, } index := MeiliSearch.Index("event") docPrimaryKey := "event_id" meiliOptions := &meilisearch.DocumentOptions{PrimaryKey: &docPrimaryKey} if _, err := index.AddDocuments([]EventSearchDoc{doc}, meiliOptions); err != nil { return err } return nil }) } func (self *Event) UserJoinEvent(userId, eventId uuid.UUID) error { return Database.Transaction(func(tx *gorm.DB) error { var event Event if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}). Where("event_id = ?", eventId). First(&event).Error; err != nil { return err } // Check if user already joined if slices.Contains(event.JoinedUsers, userId) { return errors.New("user already joined") } // Add user to list event.JoinedUsers = append(event.JoinedUsers, userId) if err := tx.Model(&Event{}).Where("event_id = ?", eventId).Update("joined_users", event.JoinedUsers).Error; err != nil { return err } *self = event return nil }) } func (self *Event) GetFullTable() (*[]Event, error) { var events []Event err := Database.Find(&events).Error if err != nil { return nil, err } return &events, err } func (self *Event) FastListEvents(limit, offset int64) (*[]EventSearchDoc, error) { index := MeiliSearch.Index("event") result, err := index.Search("", &meilisearch.SearchRequest{ Limit: limit, Offset: offset, }) if err != nil { return nil, err } var list []EventSearchDoc if err := mapstructure.Decode(result.Hits, &list); err != nil { return nil, err } return &list, nil }