From 5193b9f368453cf3dc85303e71fb38754d069684 Mon Sep 17 00:00:00 2001 From: Frank Elsinga Date: Sun, 15 Oct 2023 21:22:56 +0200 Subject: [PATCH 01/13] migrated cafeteria statistics to a view --- server/backend/cafeteria.go | 48 +++++++---------- .../cron/average_rating_computation.go | 22 -------- server/backend/migration/20231015000000.go | 54 +++++++++++++++++++ server/model/cafeteria_rating_average.go | 16 ------ server/model/cafeteria_rating_statistic.go | 10 ++++ 5 files changed, 82 insertions(+), 68 deletions(-) create mode 100644 server/backend/migration/20231015000000.go delete mode 100644 server/model/cafeteria_rating_average.go create mode 100644 server/model/cafeteria_rating_statistic.go diff --git a/server/backend/cafeteria.go b/server/backend/cafeteria.go index 3fa7a355..b84c8364 100644 --- a/server/backend/cafeteria.go +++ b/server/backend/cafeteria.go @@ -34,46 +34,34 @@ const ( NAME ModelType = 3 ) -// GetCafeteriaRatings RPC Endpoint +// ListCanteenRatings RPC Endpoint // Allows to query ratings for a specific cafeteria. // It returns the average rating, max/min rating as well as a number of actual ratings and the average ratings for // all cafeteria rating tags which were used to rate this cafeteria. // The parameter limit defines how many actual ratings should be returned. // The optional parameters from and to can define an interval in which the queried ratings have been stored. // If these aren't specified, the newest ratings will be returned as the default -func (s *CampusServer) GetCafeteriaRatings(ctx context.Context, input *pb.ListCanteenRatingsRequest) (*pb.ListCanteenRatingsReply, error) { - var result model.CafeteriaRatingAverage //get the average rating for this specific cafeteria +func (s *CampusServer) ListCanteenRatings(ctx context.Context, input *pb.ListCanteenRatingsRequest) (*pb.ListCanteenRatingsReply, error) { + var statsForCanteen model.CafeteriaRatingStatistic tx := s.db.WithContext(ctx) cafeteriaId := getIDForCafeteriaName(input.CanteenId, tx) - res := tx.Model(&model.CafeteriaRatingAverage{}). - Where("cafeteriaId = ?", cafeteriaId). - First(&result) - - if res.Error != nil { - log.WithError(res.Error).Error("Error while querying the cafeteria with Id ", cafeteriaId) - return nil, status.Error(codes.Internal, "This cafeteria has not yet been rated.") + err := tx.First(&statsForCanteen, "cafeteriaId = ?", cafeteriaId).Error + if errors.Is(err, gorm.ErrRecordNotFound) { + return nil, status.Error(codes.NotFound, "No cafeteria with this Id found.") } - - if res.RowsAffected > 0 { - ratings := queryLastCafeteriaRatingsWithLimit(input, cafeteriaId, tx) - cafeteriaTags := queryTags(cafeteriaId, -1, CAFETERIA, tx) - - return &pb.ListCanteenRatingsReply{ - Avg: result.Average, - Std: result.Std, - Min: result.Min, - Max: result.Max, - Rating: ratings, - RatingTags: cafeteriaTags, - }, nil - } else { - return &pb.ListCanteenRatingsReply{ - Avg: -1, - Std: -1, - Min: -1, - Max: -1, - }, nil + if err != nil { + log.WithError(err).Error("Error while querying the cafeteria with Id ", cafeteriaId) + return nil, status.Error(codes.Internal, "could not query the cafeteria with the given Id") } + + return &pb.ListCanteenRatingsReply{ + Avg: statsForCanteen.Average, + Std: statsForCanteen.Std, + Min: statsForCanteen.Min, + Max: statsForCanteen.Max, + Rating: queryLastCafeteriaRatingsWithLimit(input, cafeteriaId, tx), + RatingTags: queryTags(cafeteriaId, -1, CAFETERIA, tx), + }, nil } // queryLastCafeteriaRatingsWithLimit diff --git a/server/backend/cron/average_rating_computation.go b/server/backend/cron/average_rating_computation.go index 24bd0a6c..b3941a00 100644 --- a/server/backend/cron/average_rating_computation.go +++ b/server/backend/cron/average_rating_computation.go @@ -9,7 +9,6 @@ import ( // This cronjob precomputes average ratings of all cafeteria ratings, dish ratings and all three types of tags. // They are grouped (e.g. All Ratings for "Mensa_garching") and the computed values will then be stored in a table with the suffix "_result" func (c *CronService) averageRatingComputation() error { - computeAverageForCafeteria(c) computeAverageForDishesInCafeterias(c) computeAverageCafeteriaTags(c) computeAverageForDishesInCafeteriasTags(c) @@ -103,24 +102,3 @@ func computeAverageForDishesInCafeterias(c *CronService) { } } } - -func computeAverageForCafeteria(c *CronService) { - var results []model.CafeteriaRatingAverage - err := c.db.Model(&model.CafeteriaRating{}). - Select("cafeteriaID, AVG(points) as average, MAX(points) as max, MIN(points) as min, STD(points) as std"). - Group("cafeteriaID").Find(&results).Error - - if err != nil { - log.WithError(err).Error("while precomputing average cafeteria ratings.") - } else if len(results) > 0 { - errDelete := c.db.Where("1=1").Delete(&model.CafeteriaRatingAverage{}).Error - if errDelete != nil { - log.WithError(errDelete).Error("Error while deleting old averages in the table.") - } - - err := c.db.Model(&model.CafeteriaRatingAverage{}).Create(&results).Error - if err != nil { - log.WithError(err).Error("while creating a new average cafeteria rating in the database.") - } - } -} diff --git a/server/backend/migration/20231015000000.go b/server/backend/migration/20231015000000.go new file mode 100644 index 00000000..04d62eb2 --- /dev/null +++ b/server/backend/migration/20231015000000.go @@ -0,0 +1,54 @@ +package migration + +import ( + "github.com/go-gormigrate/gormigrate/v2" + "gorm.io/gorm" +) + +// CafeteriaRatingAverage stores all precomputed values for the cafeteria ratings +type CafeteriaRatingAverage struct { + CafeteriaRatingAverage int64 `gorm:"primary_key;AUTO_INCREMENT;column:cafeteriaRatingAverage;type:int;not null;"` + CafeteriaID int64 `gorm:"column:cafeteriaID;foreignKey:cafeteria;type:int;not null;"` + Average float64 `gorm:"column:average;type:float;not null;"` + Min int32 `gorm:"column:min;type:int;not null;"` + Max int32 `gorm:"column:max;type:int;not null;"` + Std float64 `gorm:"column:std;type:float;not null;"` +} + +// TableName sets the insert table name for this struct type +func (n *CafeteriaRatingAverage) TableName() string { + return "cafeteria_rating_average" +} + +// migrate20231015000000 +// migrates the static data for the canteen rating system and adds the necessary cronjob entries +func (m TumDBMigrator) migrate20231015000000() *gormigrate.Migration { + return &gormigrate.Migration{ + ID: "20231015000000", + Migrate: func(tx *gorm.DB) error { + tables:= []string{"cafeteria_rating_average"} + for _, table := range tables { + if err := tx.Migrator().DropTable(table); err != nil { + return err + } + } + if err := tx.Exec(`create view cafeteria_rating_statistics as +SELECT cafeteriaID, Avg(points) AS average, MIN(points) AS min, Max(points) AS max, STD(points) AS std +FROM cafeteria_rating +GROUP BY cafeteriaID +ORDER BY COUNT(cafeteriaID) DESC, average DESC`).Error; err != nil { + return err + } + return nil + }, + Rollback: func(tx *gorm.DB) error { + createdViews := []string{"cafeteria_rating_statistics"} + for _, view := range createdViews { + if err := tx.Exec("DROP VIEW IF EXISTS " + view).Error; err != nil { + return err + } + } + return tx.AutoMigrate(&CafeteriaRatingAverage{}) + }, + } +} diff --git a/server/model/cafeteria_rating_average.go b/server/model/cafeteria_rating_average.go deleted file mode 100644 index cb624a95..00000000 --- a/server/model/cafeteria_rating_average.go +++ /dev/null @@ -1,16 +0,0 @@ -package model - -// CafeteriaRatingAverage stores all precomputed values for the cafeteria ratings -type CafeteriaRatingAverage struct { - CafeteriaRatingAverage int64 `gorm:"primary_key;AUTO_INCREMENT;column:cafeteriaRatingAverage;type:int;not null;" json:"canteenRatingAverage" ` - CafeteriaID int64 `gorm:"column:cafeteriaID;foreignKey:cafeteria;type:int;not null;" json:"canteenID"` - Average float64 `gorm:"column:average;type:float;not null;" json:"average" ` - Min int32 `gorm:"column:min;type:int;not null;" json:"min"` - Max int32 `gorm:"column:max;type:int;not null;" json:"max"` - Std float64 `gorm:"column:std;type:float;not null;" json:"std"` -} - -// TableName sets the insert table name for this struct type -func (n *CafeteriaRatingAverage) TableName() string { - return "cafeteria_rating_average" -} diff --git a/server/model/cafeteria_rating_statistic.go b/server/model/cafeteria_rating_statistic.go new file mode 100644 index 00000000..7af0faeb --- /dev/null +++ b/server/model/cafeteria_rating_statistic.go @@ -0,0 +1,10 @@ +package model + +// CafeteriaRatingStatistic is a view for statistics of cafeteria ratings +type CafeteriaRatingStatistic struct { + CafeteriaID int64 `gorm:"column:cafeteriaID;foreignKey:cafeteria;type:int;not null;"` + Average float64 `gorm:"column:average;type:float;not null;"` + Min int32 `gorm:"column:min;type:int;not null;"` + Max int32 `gorm:"column:max;type:int;not null;"` + Std float64 `gorm:"column:std;type:float;not null;"` +} From 6ffe6b4d3431af12c9bc731e2faac4a8da611f4f Mon Sep 17 00:00:00 2001 From: Frank Elsinga Date: Sun, 15 Oct 2023 21:47:18 +0200 Subject: [PATCH 02/13] migrated DishRating --- server/api/tumdev/campus_backend.proto | 6 +++ server/backend/cafeteria.go | 54 ++++++------------- .../cron/average_rating_computation.go | 21 -------- server/backend/migration/20220713000000.go | 37 +++++++++++-- server/backend/migration/20231015000000.go | 29 ++++++++-- server/model/dish_rating_average.go | 17 ------ server/model/dish_rating_statistic.go | 11 ++++ 7 files changed, 92 insertions(+), 83 deletions(-) delete mode 100644 server/model/dish_rating_average.go create mode 100644 server/model/dish_rating_statistic.go diff --git a/server/api/tumdev/campus_backend.proto b/server/api/tumdev/campus_backend.proto index d0e5c86e..ce8204ba 100644 --- a/server/api/tumdev/campus_backend.proto +++ b/server/api/tumdev/campus_backend.proto @@ -49,6 +49,7 @@ service Campus { }; } + // Allows to query ratings for a specific dish in a specific cafeteria. rpc GetDishRatings(GetDishRatingsRequest) returns (GetDishRatingsReply) { option (google.api.http) = { post: "/dish/rating/get", @@ -323,10 +324,15 @@ message GetDishRatingsRequest { } message GetDishRatingsReply { + // a number of actual ratings repeated SingleRatingReply rating = 1; + // average rating for all dish rating tags which were used to rate this dish in this cafeteria double avg = 2; + // std of all dish rating tags which were used to rate this dish in this cafeteria double std = 3; + // minimum of all dish rating tags which were used to rate this dish in this cafeteria int32 min = 4; + // maximum of all dish rating tags which were used to rate this dish in this cafeteria int32 max = 5; repeated RatingTagResult rating_tags = 6; repeated RatingTagResult name_tags = 7; diff --git a/server/backend/cafeteria.go b/server/backend/cafeteria.go index b84c8364..b5c9f930 100644 --- a/server/backend/cafeteria.go +++ b/server/backend/cafeteria.go @@ -126,53 +126,31 @@ func queryLastCafeteriaRatingsWithLimit(input *pb.ListCanteenRatingsRequest, caf } } -// GetDishRatings RPC Endpoint -// Allows to query ratings for a specific dish in a specific cafeteria. -// It returns the average rating, max/min rating as well as a number of actual ratings and the average ratings for -// all dish rating tags which were used to rate this dish in this cafeteria. Additionally, the average, max/min are -// returned for every name tag which matches the name of the dish. -// The parameter limit defines how many actual ratings should be returned. -// The optional parameters from and to can define a interval in which the queried ratings have been stored. -// If these aren't specified, the newest ratings will be returned as the default func (s *CampusServer) GetDishRatings(ctx context.Context, input *pb.GetDishRatingsRequest) (*pb.GetDishRatingsReply, error) { - var result model.DishRatingAverage //get the average rating for this specific dish tx := s.db.WithContext(ctx) cafeteriaID := getIDForCafeteriaName(input.CanteenId, tx) dishID := getIDForDishName(input.Dish, cafeteriaID, tx) - err := tx.Model(&model.DishRatingAverage{}). - Where("cafeteriaID = ? AND dishID = ?", cafeteriaID, dishID). - First(&result) - - if err.Error != nil { + var statsForDish model.DishRatingStatistic + err := tx.First(&statsForDish, "cafeteriaID = ? AND dishID = ?", cafeteriaID, dishID).Error + if errors.Is(err, gorm.ErrRecordNotFound) { + return nil, status.Error(codes.NotFound, "No cafeteria with this Id found.") + } + if err != nil { fields := log.Fields{"dishID": dishID, "cafeteriaID": cafeteriaID} - log.WithError(err.Error).WithFields(fields).Error("Error while querying the average ratings") + log.WithError(err).WithFields(fields).Error("Error while querying the average ratings") return nil, status.Error(codes.Internal, "This dish has not yet been rated.") } - if err.RowsAffected > 0 { - ratings := queryLastDishRatingsWithLimit(input, cafeteriaID, dishID, tx) - dishTags := queryTags(cafeteriaID, dishID, DISH, tx) - nameTags := queryTags(cafeteriaID, dishID, NAME, tx) - - return &pb.GetDishRatingsReply{ - Avg: result.Average, - Std: result.Std, - Min: result.Min, - Max: result.Max, - Rating: ratings, - RatingTags: dishTags, - NameTags: nameTags, - }, nil - } else { - return &pb.GetDishRatingsReply{ - Avg: -1, - Min: -1, - Max: -1, - Std: -1, - }, nil - } - + return &pb.GetDishRatingsReply{ + Avg: statsForDish.Average, + Std: statsForDish.Std, + Min: statsForDish.Min, + Max: statsForDish.Max, + Rating: queryLastDishRatingsWithLimit(input, cafeteriaID, dishID, tx), + RatingTags: queryTags(cafeteriaID, dishID, DISH, tx), + NameTags: queryTags(cafeteriaID, dishID, NAME, tx), + }, nil } // queryLastDishRatingsWithLimit diff --git a/server/backend/cron/average_rating_computation.go b/server/backend/cron/average_rating_computation.go index b3941a00..6532ea06 100644 --- a/server/backend/cron/average_rating_computation.go +++ b/server/backend/cron/average_rating_computation.go @@ -9,7 +9,6 @@ import ( // This cronjob precomputes average ratings of all cafeteria ratings, dish ratings and all three types of tags. // They are grouped (e.g. All Ratings for "Mensa_garching") and the computed values will then be stored in a table with the suffix "_result" func (c *CronService) averageRatingComputation() error { - computeAverageForDishesInCafeterias(c) computeAverageCafeteriaTags(c) computeAverageForDishesInCafeteriasTags(c) computeAverageNameTags(c) @@ -82,23 +81,3 @@ func computeAverageCafeteriaTags(c *CronService) { } } } - -func computeAverageForDishesInCafeterias(c *CronService) { - var results []model.DishRatingAverage - err := c.db.Model(&model.DishRating{}). - Select("cafeteriaID, dishID, AVG(points) as average, MAX(points) as max, MIN(points) as min, STD(points) as std"). - Group("cafeteriaID,dishID").Scan(&results).Error - - if err != nil { - log.WithError(err).Error("while precomputing average dish ratings.") - } else if len(results) > 0 { - errDelete := c.db.Where("1=1").Delete(&model.DishRatingAverage{}).Error - if errDelete != nil { - log.WithError(errDelete).Error("Error while deleting old averages in the table.") - } - err := c.db.Model(&model.DishRatingAverage{}).Create(&results).Error - if err != nil { - log.WithError(err).Error("while creating a new average dish rating in the database.") - } - } -} diff --git a/server/backend/migration/20220713000000.go b/server/backend/migration/20220713000000.go index 0f3eadf5..6a017138 100644 --- a/server/backend/migration/20220713000000.go +++ b/server/backend/migration/20220713000000.go @@ -6,17 +6,46 @@ import ( "gorm.io/gorm" ) -//migrate20210709193000 +// InitialCafeteriaRatingAverage stores all precomputed values for the cafeteria ratings +type InitialCafeteriaRatingAverage struct { + CafeteriaRatingAverage int64 `gorm:"primary_key;AUTO_INCREMENT;column:cafeteriaRatingAverage;type:int;not null;"` + CafeteriaID int64 `gorm:"column:cafeteriaID;foreignKey:cafeteria;type:int;not null;"` + Average float64 `gorm:"column:average;type:float;not null;"` + Min int32 `gorm:"column:min;type:int;not null;"` + Max int32 `gorm:"column:max;type:int;not null;"` + Std float64 `gorm:"column:std;type:float;not null;"` +} + +// TableName sets the insert table name for this struct type +func (n *InitialCafeteriaRatingAverage) TableName() string { + return "cafeteria_rating_average" +} + +// InitialDishRatingAverage stores all precomputed values for the cafeteria ratings +type InitialDishRatingAverage struct { + DishRatingAverage int64 `gorm:"primary_key;AUTO_INCREMENT;column:dishRatingAverage;type:int;not null;"` + CafeteriaID int64 `gorm:"column:cafeteriaID;foreignKey:cafeteria;type:int;not null;"` + DishID int64 `gorm:"column:dishID;foreignKey:dish;type:int;not null;"` + Average float64 `gorm:"column:average;type:float;not null;"` + Min int32 `gorm:"column:min;type:int;not null;"` + Max int32 `gorm:"column:max;type:int;not null;"` + Std float64 `gorm:"column:std;type:float;not null;"` +} + +// TableName sets the insert table name for this struct type +func (n *InitialDishRatingAverage) TableName() string { + return "dish_rating_average" +} +// migrate20220713000000 func (m TumDBMigrator) migrate20220713000000() *gormigrate.Migration { return &gormigrate.Migration{ ID: "20220713000000", Migrate: func(tx *gorm.DB) error { - if err := tx.AutoMigrate( &model.Cafeteria{}, &model.CafeteriaRating{}, - &model.CafeteriaRatingAverage{}, + &InitialCafeteriaRatingAverage{}, &model.CafeteriaRatingTag{}, &model.CafeteriaRatingTagsAverage{}, &model.CafeteriaRatingTagOption{}, @@ -28,7 +57,7 @@ func (m TumDBMigrator) migrate20220713000000() *gormigrate.Migration { &model.DishNameTag{}, &model.DishNameTagAverage{}, &model.DishRating{}, - &model.DishRatingAverage{}, + &InitialDishRatingAverage{}, &model.DishRatingTag{}, &model.DishRatingTagAverage{}, &model.DishRatingTagOption{}, diff --git a/server/backend/migration/20231015000000.go b/server/backend/migration/20231015000000.go index 04d62eb2..d5829073 100644 --- a/server/backend/migration/20231015000000.go +++ b/server/backend/migration/20231015000000.go @@ -20,13 +20,29 @@ func (n *CafeteriaRatingAverage) TableName() string { return "cafeteria_rating_average" } +// DishRatingAverage stores all precomputed values for the cafeteria ratings +type DishRatingAverage struct { + DishRatingAverage int64 `gorm:"primary_key;AUTO_INCREMENT;column:dishRatingAverage;type:int;not null;"` + CafeteriaID int64 `gorm:"column:cafeteriaID;foreignKey:cafeteria;type:int;not null;"` + DishID int64 `gorm:"column:dishID;foreignKey:dish;type:int;not null;"` + Average float64 `gorm:"column:average;type:float;not null;"` + Min int32 `gorm:"column:min;type:int;not null;"` + Max int32 `gorm:"column:max;type:int;not null;"` + Std float64 `gorm:"column:std;type:float;not null;"` +} + +// TableName sets the insert table name for this struct type +func (n *DishRatingAverage) TableName() string { + return "dish_rating_average" +} + // migrate20231015000000 // migrates the static data for the canteen rating system and adds the necessary cronjob entries func (m TumDBMigrator) migrate20231015000000() *gormigrate.Migration { return &gormigrate.Migration{ ID: "20231015000000", Migrate: func(tx *gorm.DB) error { - tables:= []string{"cafeteria_rating_average"} + tables := []string{"cafeteria_rating_average", "dish_rating_average"} for _, table := range tables { if err := tx.Migrator().DropTable(table); err != nil { return err @@ -39,16 +55,23 @@ GROUP BY cafeteriaID ORDER BY COUNT(cafeteriaID) DESC, average DESC`).Error; err != nil { return err } + if err := tx.Exec(`create view dish_rating_statistics as +SELECT cafeteriaID, dishID, AVG(points) as average, MAX(points) as max, MIN(points) as min, STD(points) as std +FROM dish_rating +GROUP BY cafeteriaID,dishID +ORDER BY COUNT(*) DESC, average DESC`).Error; err != nil { + return err + } return nil }, Rollback: func(tx *gorm.DB) error { - createdViews := []string{"cafeteria_rating_statistics"} + createdViews := []string{"cafeteria_rating_statistics", "dish_rating_statistics"} for _, view := range createdViews { if err := tx.Exec("DROP VIEW IF EXISTS " + view).Error; err != nil { return err } } - return tx.AutoMigrate(&CafeteriaRatingAverage{}) + return tx.AutoMigrate(&CafeteriaRatingAverage{}, &DishRatingAverage{}) }, } } diff --git a/server/model/dish_rating_average.go b/server/model/dish_rating_average.go deleted file mode 100644 index 2db0571c..00000000 --- a/server/model/dish_rating_average.go +++ /dev/null @@ -1,17 +0,0 @@ -package model - -// DishRatingAverage stores all precomputed values for the cafeteria ratings -type DishRatingAverage struct { - DishRatingAverage int64 `gorm:"primary_key;AUTO_INCREMENT;column:dishRatingAverage;type:int;not null;" json:"dishRatingAverage" ` - CafeteriaID int64 `gorm:"column:cafeteriaID;foreignKey:cafeteria;type:int;not null;" json:"cafeteriaID"` - DishID int64 `gorm:"column:dishID;foreignKey:dish;type:int;not null;" json:"dishID"` - Average float64 `gorm:"column:average;type:float;not null;" json:"average" ` - Min int32 `gorm:"column:min;type:int;not null;" json:"min"` - Max int32 `gorm:"column:max;type:int;not null;" json:"max"` - Std float64 `gorm:"column:std;type:float;not null;" json:"std"` -} - -// TableName sets the insert table name for this struct type -func (n *DishRatingAverage) TableName() string { - return "dish_rating_average" -} diff --git a/server/model/dish_rating_statistic.go b/server/model/dish_rating_statistic.go new file mode 100644 index 00000000..46e3890f --- /dev/null +++ b/server/model/dish_rating_statistic.go @@ -0,0 +1,11 @@ +package model + +// DishRatingStatistic stores all precomputed values for the cafeteria ratings +type DishRatingStatistic struct { + CafeteriaID int64 `gorm:"column:cafeteriaID;foreignKey:cafeteria;type:int;not null;"` + DishID int64 `gorm:"column:dishID;foreignKey:dish;type:int;not null;"` + Average float64 `gorm:"column:average;type:float;not null;"` + Min int32 `gorm:"column:min;type:int;not null;"` + Max int32 `gorm:"column:max;type:int;not null;"` + Std float64 `gorm:"column:std;type:float;not null;"` +} From 83099a9e9dbeb9f8266e4df5de7e5f7767840481 Mon Sep 17 00:00:00 2001 From: Frank Elsinga Date: Sun, 15 Oct 2023 22:12:44 +0200 Subject: [PATCH 03/13] migrated dish_rating_tag_average --- server/backend/cafeteria.go | 2 +- .../cron/average_rating_computation.go | 32 +++-------------- server/backend/migration/20231015000000.go | 36 +++++++++++++++---- server/model/dish_rating_tag_average.go | 18 ---------- server/model/dish_rating_tag_statistic.go | 12 +++++++ 5 files changed, 47 insertions(+), 53 deletions(-) delete mode 100644 server/model/dish_rating_tag_average.go create mode 100644 server/model/dish_rating_tag_statistic.go diff --git a/server/backend/cafeteria.go b/server/backend/cafeteria.go index b5c9f930..0a540161 100644 --- a/server/backend/cafeteria.go +++ b/server/backend/cafeteria.go @@ -255,7 +255,7 @@ func queryTags(cafeteriaID int32, dishID int32, ratingType ModelType, tx *gorm.D var err error if ratingType == DISH { err = tx.Table("dish_rating_tag_option options"). - Joins("JOIN dish_rating_tag_average results ON options.dishRatingTagOption = results.tagID"). + Joins("JOIN dish_rating_tag_statistics results ON options.dishRatingTagOption = results.tagID"). Select("options.dishRatingTagOption as tagId, results.average as avg, "+ "results.min as min, results.max as max, results.std as std"). Where("results.cafeteriaID = ? AND results.dishID = ?", cafeteriaID, dishID). diff --git a/server/backend/cron/average_rating_computation.go b/server/backend/cron/average_rating_computation.go index 6532ea06..6f72984b 100644 --- a/server/backend/cron/average_rating_computation.go +++ b/server/backend/cron/average_rating_computation.go @@ -10,7 +10,6 @@ import ( // They are grouped (e.g. All Ratings for "Mensa_garching") and the computed values will then be stored in a table with the suffix "_result" func (c *CronService) averageRatingComputation() error { computeAverageCafeteriaTags(c) - computeAverageForDishesInCafeteriasTags(c) computeAverageNameTags(c) return nil @@ -18,10 +17,10 @@ func (c *CronService) averageRatingComputation() error { func computeAverageNameTags(c *CronService) { var results []model.DishNameTagAverage - err := c.db.Raw("SELECT mr.cafeteriaID as cafeteriaID, mnt.tagnameID as tagID, AVG(mnt.points) as average, MAX(mnt.points) as max, MIN(mnt.points) as min, STD(mnt.points) as std" + - " FROM dish_rating mr" + - " JOIN dish_name_tag mnt ON mr.dishRating = mnt.correspondingRating" + - " GROUP BY mr.cafeteriaID, mnt.tagnameID").Scan(&results).Error + err := c.db.Raw(`SELECT mr.cafeteriaID as cafeteriaID, mnt.tagnameID as tagID, AVG(mnt.points) as average, MAX(mnt.points) as max, MIN(mnt.points) as min, STD(mnt.points) as std +FROM dish_rating mr +JOIN dish_name_tag mnt ON mr.dishRating = mnt.correspondingRating +GROUP BY mr.cafeteriaID, mnt.tagnameID`).Scan(&results).Error if err != nil { log.WithError(err).Error("while precomputing average name tags.") @@ -37,29 +36,6 @@ func computeAverageNameTags(c *CronService) { } } -func computeAverageForDishesInCafeteriasTags(c *CronService) { - var results []model.DishRatingTagAverage //todo namen im select anpassen - err := c.db.Raw("SELECT mr.dishID as dishID, mr.cafeteriaID as cafeteriaID, mrt.tagID as tagID, AVG(mrt.points) as average, MAX(mrt.points) as max, MIN(mrt.points) as min, STD(mrt.points) as std" + - " FROM dish_rating mr" + - " JOIN dish_rating_tag mrt ON mr.dishRating = mrt.parentRating" + - " GROUP BY mr.cafeteriaID, mrt.tagID, mr.dishID").Scan(&results).Error - - if err != nil { - log.WithError(err).Error("while precomputing average dish tags.") - } else if len(results) > 0 { - errDelete := c.db.Where("1=1").Delete(&model.DishRatingTagAverage{}).Error - if errDelete != nil { - log.WithError(errDelete).Error("Error while deleting old averages in the table.") - } - - err := c.db.Model(&model.DishRatingTagAverage{}).Create(&results).Error - if err != nil { - log.WithError(err).Error("while creating a new average dish tag rating in the database.") - } - - } -} - func computeAverageCafeteriaTags(c *CronService) { var results []model.CafeteriaRatingTagsAverage err := c.db.Raw("SELECT cr.cafeteriaID as cafeteriaID, crt.tagID as tagID, AVG(crt.points) as average, MAX(crt.points) as max, MIN(crt.points) as min, STD(crt.points) as std" + diff --git a/server/backend/migration/20231015000000.go b/server/backend/migration/20231015000000.go index d5829073..91c57685 100644 --- a/server/backend/migration/20231015000000.go +++ b/server/backend/migration/20231015000000.go @@ -36,42 +36,66 @@ func (n *DishRatingAverage) TableName() string { return "dish_rating_average" } +// DishRatingTagAverage stores all precomputed values for the cafeteria ratings +type DishRatingTagAverage struct { + DishRatingTagsAverage int64 `gorm:"primary_key;AUTO_INCREMENT;column:dishRatingTagsAverage;type:int;not null;"` + CafeteriaID int64 `gorm:"column:cafeteriaID;foreignKey:cafeteria;type:int;not null;"` + TagID int64 `gorm:"column:tagID;foreignKey:tagID;type:int;not null;"` + DishID int64 `gorm:"column:dishID;foreignKey:dishID;type:int;not null;"` + Average float32 `gorm:"column:average;type:float;not null;"` + Min int8 `gorm:"column:min;type:int;not null;"` + Max int8 `gorm:"column:max;type:int;not null;"` + Std float32 `gorm:"column:std;type:float;not null;"` +} + +// TableName sets the insert table name for this struct type +func (n *DishRatingTagAverage) TableName() string { + return "dish_rating_tag_average" +} + // migrate20231015000000 // migrates the static data for the canteen rating system and adds the necessary cronjob entries func (m TumDBMigrator) migrate20231015000000() *gormigrate.Migration { return &gormigrate.Migration{ ID: "20231015000000", Migrate: func(tx *gorm.DB) error { - tables := []string{"cafeteria_rating_average", "dish_rating_average"} + tables := []string{"cafeteria_rating_average", "dish_rating_average", "dish_rating_tag_average"} for _, table := range tables { if err := tx.Migrator().DropTable(table); err != nil { return err } } - if err := tx.Exec(`create view cafeteria_rating_statistics as + if err := tx.Exec(`CREATE VIEW cafeteria_rating_statistics AS SELECT cafeteriaID, Avg(points) AS average, MIN(points) AS min, Max(points) AS max, STD(points) AS std FROM cafeteria_rating GROUP BY cafeteriaID -ORDER BY COUNT(cafeteriaID) DESC, average DESC`).Error; err != nil { +ORDER BY COUNT(*) DESC, average DESC`).Error; err != nil { return err } - if err := tx.Exec(`create view dish_rating_statistics as + if err := tx.Exec(`CREATE VIEW dish_rating_statistics AS SELECT cafeteriaID, dishID, AVG(points) as average, MAX(points) as max, MIN(points) as min, STD(points) as std FROM dish_rating GROUP BY cafeteriaID,dishID ORDER BY COUNT(*) DESC, average DESC`).Error; err != nil { return err } + if err := tx.Exec(`CREATE VIEW dish_rating_tag_statistics AS +SELECT mr.dishID as dishID, mr.cafeteriaID as cafeteriaID, mrt.tagID as tagID, AVG(mrt.points) as average, MAX(mrt.points) as max, MIN(mrt.points) as min, STD(mrt.points) as std +FROM dish_rating mr +JOIN dish_rating_tag mrt ON mr.dishRating = mrt.parentRating +GROUP BY mr.cafeteriaID, mrt.tagID, mr.dishID`).Error; err != nil { + return err + } return nil }, Rollback: func(tx *gorm.DB) error { - createdViews := []string{"cafeteria_rating_statistics", "dish_rating_statistics"} + createdViews := []string{"cafeteria_rating_statistics", "dish_rating_statistics", "dish_rating_tag_statistics"} for _, view := range createdViews { if err := tx.Exec("DROP VIEW IF EXISTS " + view).Error; err != nil { return err } } - return tx.AutoMigrate(&CafeteriaRatingAverage{}, &DishRatingAverage{}) + return tx.AutoMigrate(&CafeteriaRatingAverage{}, &DishRatingAverage{}, &DishRatingTagAverage{}) }, } } diff --git a/server/model/dish_rating_tag_average.go b/server/model/dish_rating_tag_average.go deleted file mode 100644 index b1535171..00000000 --- a/server/model/dish_rating_tag_average.go +++ /dev/null @@ -1,18 +0,0 @@ -package model - -// DishRatingTagAverage stores all precomputed values for the cafeteria ratings -type DishRatingTagAverage struct { - DishRatingTagsAverage int64 `gorm:"primary_key;AUTO_INCREMENT;column:dishRatingTagsAverage;type:int;not null;" json:"dishRatingTagsAverage" ` - CafeteriaID int64 `gorm:"column:cafeteriaID;foreignKey:cafeteria;type:int;not null;" json:"cafeteriaID"` - TagID int64 `gorm:"column:tagID;foreignKey:tagID;type:int;not null;" json:"tagID"` - DishID int64 `gorm:"column:dishID;foreignKey:dishID;type:int;not null;" json:"dishID"` - Average float32 `gorm:"column:average;type:float;not null;" json:"average" ` - Min int8 `gorm:"column:min;type:int;not null;" json:"min"` - Max int8 `gorm:"column:max;type:int;not null;" json:"max"` - Std float32 `gorm:"column:std;type:float;not null;" json:"std"` -} - -// TableName sets the insert table name for this struct type -func (n *DishRatingTagAverage) TableName() string { - return "dish_rating_tag_average" -} diff --git a/server/model/dish_rating_tag_statistic.go b/server/model/dish_rating_tag_statistic.go new file mode 100644 index 00000000..c272ea1c --- /dev/null +++ b/server/model/dish_rating_tag_statistic.go @@ -0,0 +1,12 @@ +package model + +// DishRatingTagStatistic stores all precomputed values for the cafeteria ratings +type DishRatingTagStatistic struct { + CafeteriaID int64 `gorm:"column:cafeteriaID;foreignKey:cafeteria;type:int;not null;" json:"cafeteriaID"` + TagID int64 `gorm:"column:tagID;foreignKey:tagID;type:int;not null;" json:"tagID"` + DishID int64 `gorm:"column:dishID;foreignKey:dishID;type:int;not null;" json:"dishID"` + Average float32 `gorm:"column:average;type:float;not null;" json:"average" ` + Min int8 `gorm:"column:min;type:int;not null;" json:"min"` + Max int8 `gorm:"column:max;type:int;not null;" json:"max"` + Std float32 `gorm:"column:std;type:float;not null;" json:"std"` +} From cbfd6f82f3d82bca4d34f43a9fcee7da66369efa Mon Sep 17 00:00:00 2001 From: Frank Elsinga Date: Sun, 15 Oct 2023 22:22:19 +0200 Subject: [PATCH 04/13] migrated ...rating_tag_average --- server/backend/cafeteria.go | 2 +- .../cron/average_rating_computation.go | 23 ------------ server/backend/migration/20220713000000.go | 37 ++++++++++++++++++- server/backend/migration/20231015000000.go | 29 +++++++++++++-- server/model/cafeteria_rating_tag_average.go | 17 --------- .../model/cafeteria_rating_tag_statistic.go | 11 ++++++ server/model/dish_rating_statistic.go | 2 +- server/model/dish_rating_tag_statistic.go | 2 +- 8 files changed, 75 insertions(+), 48 deletions(-) delete mode 100644 server/model/cafeteria_rating_tag_average.go create mode 100644 server/model/cafeteria_rating_tag_statistic.go diff --git a/server/backend/cafeteria.go b/server/backend/cafeteria.go index 0a540161..84b762d4 100644 --- a/server/backend/cafeteria.go +++ b/server/backend/cafeteria.go @@ -262,7 +262,7 @@ func queryTags(cafeteriaID int32, dishID int32, ratingType ModelType, tx *gorm.D Scan(&results).Error } else if ratingType == CAFETERIA { err = tx.Table("cafeteria_rating_tag_option options"). - Joins("JOIN cafeteria_rating_tag_average results ON options.cafeteriaRatingTagOption = results.tagID"). + Joins("JOIN cafeteria_rating_tag_statistics results ON options.cafeteriaRatingTagOption = results.tagID"). Select("options.cafeteriaRatingTagOption as tagId, results.average as avg, "+ "results.min as min, results.max as max, results.std as std"). Where("results.cafeteriaID = ?", cafeteriaID). diff --git a/server/backend/cron/average_rating_computation.go b/server/backend/cron/average_rating_computation.go index 6f72984b..4fc08f3f 100644 --- a/server/backend/cron/average_rating_computation.go +++ b/server/backend/cron/average_rating_computation.go @@ -9,7 +9,6 @@ import ( // This cronjob precomputes average ratings of all cafeteria ratings, dish ratings and all three types of tags. // They are grouped (e.g. All Ratings for "Mensa_garching") and the computed values will then be stored in a table with the suffix "_result" func (c *CronService) averageRatingComputation() error { - computeAverageCafeteriaTags(c) computeAverageNameTags(c) return nil @@ -35,25 +34,3 @@ GROUP BY mr.cafeteriaID, mnt.tagnameID`).Scan(&results).Error } } } - -func computeAverageCafeteriaTags(c *CronService) { - var results []model.CafeteriaRatingTagsAverage - err := c.db.Raw("SELECT cr.cafeteriaID as cafeteriaID, crt.tagID as tagID, AVG(crt.points) as average, MAX(crt.points) as max, MIN(crt.points) as min, STD(crt.points) as std" + - " FROM cafeteria_rating cr" + - " JOIN cafeteria_rating_tag crt ON cr.cafeteriaRating = crt.correspondingRating" + - " GROUP BY cr.cafeteriaID, crt.tagID").Scan(&results).Error - - if err != nil { - log.WithError(err).Error("while precomputing average cafeteria tags.") - } else if len(results) > 0 { - errDelete := c.db.Where("1=1").Delete(&model.CafeteriaRatingTagsAverage{}).Error - if errDelete != nil { - log.WithError(errDelete).Error("Error while deleting old averages in the table.") - } - - err := c.db.Model(&model.CafeteriaRatingTagsAverage{}).Create(&results).Error - if err != nil { - log.WithError(err).Error("while creating a new average cafeteria tag rating in the database.") - } - } -} diff --git a/server/backend/migration/20220713000000.go b/server/backend/migration/20220713000000.go index 6a017138..fb99a33e 100644 --- a/server/backend/migration/20220713000000.go +++ b/server/backend/migration/20220713000000.go @@ -37,6 +37,39 @@ func (n *InitialDishRatingAverage) TableName() string { return "dish_rating_average" } +// InitialDishRatingTagAverage stores all precomputed values for the cafeteria ratings +type InitialDishRatingTagAverage struct { + DishRatingTagsAverage int64 `gorm:"primary_key;AUTO_INCREMENT;column:dishRatingTagsAverage;type:int;not null;"` + CafeteriaID int64 `gorm:"column:cafeteriaID;foreignKey:cafeteria;type:int;not null;"` + TagID int64 `gorm:"column:tagID;foreignKey:tagID;type:int;not null;"` + DishID int64 `gorm:"column:dishID;foreignKey:dishID;type:int;not null;"` + Average float32 `gorm:"column:average;type:float;not null;"` + Min int8 `gorm:"column:min;type:int;not null;"` + Max int8 `gorm:"column:max;type:int;not null;"` + Std float32 `gorm:"column:std;type:float;not null;"` +} + +// TableName sets the insert table name for this struct type +func (n *InitialDishRatingTagAverage) TableName() string { + return "dish_rating_tag_average" +} + +// InitialCafeteriaRatingTagsAverage stores all precomputed values for the cafeteria ratings +type InitialCafeteriaRatingTagsAverage struct { + CafeteriaRatingTagsAverage int64 `gorm:"primary_key;AUTO_INCREMENT;column:cafeteriaRatingTagsAverage;type:int;not null;" json:"canteenRatingTagsAverage"` + CafeteriaID int64 `gorm:"column:cafeteriaID;foreignKey:cafeteria;type:int;not null;" json:"canteenID"` + TagID int64 `gorm:"column:tagID;foreignKey:cafeteriaRatingTagOption;type:int;not null;" json:"tagID"` + Average float32 `gorm:"column:average;type:float;not null;" json:"average"` + Min int8 `gorm:"column:min;type:int;not null;" json:"min"` + Max int8 `gorm:"column:max;type:int;not null;" json:"max"` + Std float32 `gorm:"column:std;type:float;not null;" json:"std"` +} + +// TableName sets the insert table name for this struct type +func (n *InitialCafeteriaRatingTagsAverage) TableName() string { + return "cafeteria_rating_tag_average" +} + // migrate20220713000000 func (m TumDBMigrator) migrate20220713000000() *gormigrate.Migration { return &gormigrate.Migration{ @@ -47,7 +80,7 @@ func (m TumDBMigrator) migrate20220713000000() *gormigrate.Migration { &model.CafeteriaRating{}, &InitialCafeteriaRatingAverage{}, &model.CafeteriaRatingTag{}, - &model.CafeteriaRatingTagsAverage{}, + &InitialCafeteriaRatingTagsAverage{}, &model.CafeteriaRatingTagOption{}, &model.Dish{}, &model.DishesOfTheWeek{}, @@ -59,7 +92,7 @@ func (m TumDBMigrator) migrate20220713000000() *gormigrate.Migration { &model.DishRating{}, &InitialDishRatingAverage{}, &model.DishRatingTag{}, - &model.DishRatingTagAverage{}, + &InitialDishRatingTagAverage{}, &model.DishRatingTagOption{}, &model.DishToDishNameTag{}, ); err != nil { diff --git a/server/backend/migration/20231015000000.go b/server/backend/migration/20231015000000.go index 91c57685..0c81ed8b 100644 --- a/server/backend/migration/20231015000000.go +++ b/server/backend/migration/20231015000000.go @@ -53,13 +53,29 @@ func (n *DishRatingTagAverage) TableName() string { return "dish_rating_tag_average" } +// CafeteriaRatingTagsAverage stores all precomputed values for the cafeteria ratings +type CafeteriaRatingTagsAverage struct { + CafeteriaRatingTagsAverage int64 `gorm:"primary_key;AUTO_INCREMENT;column:cafeteriaRatingTagsAverage;type:int;not null;" json:"canteenRatingTagsAverage"` + CafeteriaID int64 `gorm:"column:cafeteriaID;foreignKey:cafeteria;type:int;not null;" json:"canteenID"` + TagID int64 `gorm:"column:tagID;foreignKey:cafeteriaRatingTagOption;type:int;not null;" json:"tagID"` + Average float32 `gorm:"column:average;type:float;not null;" json:"average"` + Min int8 `gorm:"column:min;type:int;not null;" json:"min"` + Max int8 `gorm:"column:max;type:int;not null;" json:"max"` + Std float32 `gorm:"column:std;type:float;not null;" json:"std"` +} + +// TableName sets the insert table name for this struct type +func (n *CafeteriaRatingTagsAverage) TableName() string { + return "cafeteria_rating_tag_average" +} + // migrate20231015000000 // migrates the static data for the canteen rating system and adds the necessary cronjob entries func (m TumDBMigrator) migrate20231015000000() *gormigrate.Migration { return &gormigrate.Migration{ ID: "20231015000000", Migrate: func(tx *gorm.DB) error { - tables := []string{"cafeteria_rating_average", "dish_rating_average", "dish_rating_tag_average"} + tables := []string{"cafeteria_rating_average", "dish_rating_average", "dish_rating_tag_average", "cafeteria_rating_tag_average"} for _, table := range tables { if err := tx.Migrator().DropTable(table); err != nil { return err @@ -86,16 +102,23 @@ JOIN dish_rating_tag mrt ON mr.dishRating = mrt.parentRating GROUP BY mr.cafeteriaID, mrt.tagID, mr.dishID`).Error; err != nil { return err } + if err := tx.Exec(`CREATE VIEW cafeteria_rating_tag_statistics AS +SELECT cr.cafeteriaID as cafeteriaID, crt.tagID as tagID, AVG(crt.points) as average, MAX(crt.points) as max, MIN(crt.points) as min, STD(crt.points) as std +FROM cafeteria_rating cr +JOIN cafeteria_rating_tag crt ON cr.cafeteriaRating = crt.correspondingRating +GROUP BY cr.cafeteriaID, crt.tagID`).Error; err != nil { + return err + } return nil }, Rollback: func(tx *gorm.DB) error { - createdViews := []string{"cafeteria_rating_statistics", "dish_rating_statistics", "dish_rating_tag_statistics"} + createdViews := []string{"cafeteria_rating_statistics", "dish_rating_statistics", "dish_rating_tag_statistics", "cafeteria_rating_tag_average"} for _, view := range createdViews { if err := tx.Exec("DROP VIEW IF EXISTS " + view).Error; err != nil { return err } } - return tx.AutoMigrate(&CafeteriaRatingAverage{}, &DishRatingAverage{}, &DishRatingTagAverage{}) + return tx.AutoMigrate(&CafeteriaRatingAverage{}, &DishRatingAverage{}, &DishRatingTagAverage{}, &CafeteriaRatingTagsAverage{}) }, } } diff --git a/server/model/cafeteria_rating_tag_average.go b/server/model/cafeteria_rating_tag_average.go deleted file mode 100644 index 6c1abeb7..00000000 --- a/server/model/cafeteria_rating_tag_average.go +++ /dev/null @@ -1,17 +0,0 @@ -package model - -// CafeteriaRatingTagsAverage stores all precomputed values for the cafeteria ratings -type CafeteriaRatingTagsAverage struct { - CafeteriaRatingTagsAverage int64 `gorm:"primary_key;AUTO_INCREMENT;column:cafeteriaRatingTagsAverage;type:int;not null;" json:"canteenRatingTagsAverage"` - CafeteriaID int64 `gorm:"column:cafeteriaID;foreignKey:cafeteria;type:int;not null;" json:"canteenID"` - TagID int64 `gorm:"column:tagID;foreignKey:cafeteriaRatingTagOption;type:int;not null;" json:"tagID"` - Average float32 `gorm:"column:average;type:float;not null;" json:"average"` - Min int8 `gorm:"column:min;type:int;not null;" json:"min"` - Max int8 `gorm:"column:max;type:int;not null;" json:"max"` - Std float32 `gorm:"column:std;type:float;not null;" json:"std"` -} - -// TableName sets the insert table name for this struct type -func (n *CafeteriaRatingTagsAverage) TableName() string { - return "cafeteria_rating_tag_average" -} diff --git a/server/model/cafeteria_rating_tag_statistic.go b/server/model/cafeteria_rating_tag_statistic.go new file mode 100644 index 00000000..7793df17 --- /dev/null +++ b/server/model/cafeteria_rating_tag_statistic.go @@ -0,0 +1,11 @@ +package model + +// CafeteriaRatingTagsStatistic is a view for statistics of cafeteria rating tags +type CafeteriaRatingTagsStatistic struct { + CafeteriaID int64 `gorm:"column:cafeteriaID;foreignKey:cafeteria;type:int;not null;" json:"canteenID"` + TagID int64 `gorm:"column:tagID;foreignKey:cafeteriaRatingTagOption;type:int;not null;" json:"tagID"` + Average float32 `gorm:"column:average;type:float;not null;" json:"average"` + Min int8 `gorm:"column:min;type:int;not null;" json:"min"` + Max int8 `gorm:"column:max;type:int;not null;" json:"max"` + Std float32 `gorm:"column:std;type:float;not null;" json:"std"` +} diff --git a/server/model/dish_rating_statistic.go b/server/model/dish_rating_statistic.go index 46e3890f..bbf56c04 100644 --- a/server/model/dish_rating_statistic.go +++ b/server/model/dish_rating_statistic.go @@ -1,6 +1,6 @@ package model -// DishRatingStatistic stores all precomputed values for the cafeteria ratings +// DishRatingStatistic is a view for statistics of dish ratings type DishRatingStatistic struct { CafeteriaID int64 `gorm:"column:cafeteriaID;foreignKey:cafeteria;type:int;not null;"` DishID int64 `gorm:"column:dishID;foreignKey:dish;type:int;not null;"` diff --git a/server/model/dish_rating_tag_statistic.go b/server/model/dish_rating_tag_statistic.go index c272ea1c..7eb41c65 100644 --- a/server/model/dish_rating_tag_statistic.go +++ b/server/model/dish_rating_tag_statistic.go @@ -1,6 +1,6 @@ package model -// DishRatingTagStatistic stores all precomputed values for the cafeteria ratings +// DishRatingTagStatistic is a view for statistics of dish rating tags type DishRatingTagStatistic struct { CafeteriaID int64 `gorm:"column:cafeteriaID;foreignKey:cafeteria;type:int;not null;" json:"cafeteriaID"` TagID int64 `gorm:"column:tagID;foreignKey:tagID;type:int;not null;" json:"tagID"` From 9fe80eafc14d0d49073752551f6d2a9b9cb86d5a Mon Sep 17 00:00:00 2001 From: Frank Elsinga Date: Sun, 15 Oct 2023 22:23:35 +0200 Subject: [PATCH 05/13] cleanup --- server/backend/migration/20220713000000.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/server/backend/migration/20220713000000.go b/server/backend/migration/20220713000000.go index fb99a33e..6ed1e2b6 100644 --- a/server/backend/migration/20220713000000.go +++ b/server/backend/migration/20220713000000.go @@ -78,9 +78,7 @@ func (m TumDBMigrator) migrate20220713000000() *gormigrate.Migration { if err := tx.AutoMigrate( &model.Cafeteria{}, &model.CafeteriaRating{}, - &InitialCafeteriaRatingAverage{}, &model.CafeteriaRatingTag{}, - &InitialCafeteriaRatingTagsAverage{}, &model.CafeteriaRatingTagOption{}, &model.Dish{}, &model.DishesOfTheWeek{}, @@ -90,11 +88,13 @@ func (m TumDBMigrator) migrate20220713000000() *gormigrate.Migration { &model.DishNameTag{}, &model.DishNameTagAverage{}, &model.DishRating{}, - &InitialDishRatingAverage{}, &model.DishRatingTag{}, - &InitialDishRatingTagAverage{}, &model.DishRatingTagOption{}, &model.DishToDishNameTag{}, + &InitialCafeteriaRatingAverage{}, + &InitialCafeteriaRatingTagsAverage{}, + &InitialDishRatingAverage{}, + &InitialDishRatingTagAverage{}, ); err != nil { return err } From f888dd7dea91052a3320e873166fd0d1ed12c10a Mon Sep 17 00:00:00 2001 From: Frank Elsinga Date: Sun, 15 Oct 2023 22:29:57 +0200 Subject: [PATCH 06/13] migrated dish_name_tag_average --- server/backend/cafeteria.go | 2 +- .../cron/average_rating_computation.go | 36 ------------------- server/backend/cron/cronjobs.go | 15 ++------ server/backend/migration/20220713000000.go | 18 +++++++++- server/backend/migration/20231015000000.go | 29 +++++++++++++-- server/model/dish_name_tag_average.go | 17 --------- server/model/dish_name_tag_statistic.go | 11 ++++++ 7 files changed, 57 insertions(+), 71 deletions(-) delete mode 100644 server/backend/cron/average_rating_computation.go delete mode 100644 server/model/dish_name_tag_average.go create mode 100644 server/model/dish_name_tag_statistic.go diff --git a/server/backend/cafeteria.go b/server/backend/cafeteria.go index 84b762d4..1c409d0b 100644 --- a/server/backend/cafeteria.go +++ b/server/backend/cafeteria.go @@ -271,7 +271,7 @@ func queryTags(cafeteriaID int32, dishID int32, ratingType ModelType, tx *gorm.D err = tx.Table("dish_to_dish_name_tag mapping"). Where("mapping.dishID = ?", dishID). Select("mapping.nameTagID as tag"). - Joins("JOIN dish_name_tag_average results ON mapping.nameTagID = results.tagID"). + Joins("JOIN dish_name_tag_statistic results ON mapping.nameTagID = results.tagID"). Joins("JOIN dish_name_tag_option options ON mapping.nameTagID = options.dishNameTagOption"). Select("mapping.nameTagID as tagId, results.average as avg, " + "results.min as min, results.max as max, results.std as std"). diff --git a/server/backend/cron/average_rating_computation.go b/server/backend/cron/average_rating_computation.go deleted file mode 100644 index 4fc08f3f..00000000 --- a/server/backend/cron/average_rating_computation.go +++ /dev/null @@ -1,36 +0,0 @@ -package cron - -import ( - "github.com/TUM-Dev/Campus-Backend/server/model" - log "github.com/sirupsen/logrus" -) - -// averageRatingComputation -// This cronjob precomputes average ratings of all cafeteria ratings, dish ratings and all three types of tags. -// They are grouped (e.g. All Ratings for "Mensa_garching") and the computed values will then be stored in a table with the suffix "_result" -func (c *CronService) averageRatingComputation() error { - computeAverageNameTags(c) - - return nil -} - -func computeAverageNameTags(c *CronService) { - var results []model.DishNameTagAverage - err := c.db.Raw(`SELECT mr.cafeteriaID as cafeteriaID, mnt.tagnameID as tagID, AVG(mnt.points) as average, MAX(mnt.points) as max, MIN(mnt.points) as min, STD(mnt.points) as std -FROM dish_rating mr -JOIN dish_name_tag mnt ON mr.dishRating = mnt.correspondingRating -GROUP BY mr.cafeteriaID, mnt.tagnameID`).Scan(&results).Error - - if err != nil { - log.WithError(err).Error("while precomputing average name tags.") - } else if len(results) > 0 { - errDelete := c.db.Where("1=1").Delete(&model.DishNameTagAverage{}).Error // Does not work with "true" - if errDelete != nil { - log.WithError(errDelete).Error("Error while deleting old averages in the table.") - } - err := c.db.Model(&model.DishNameTagAverage{}).Create(&results).Error - if err != nil { - log.WithError(err).Error("while creating a new average name tag rating in the database.") - } - } -} diff --git a/server/backend/cron/cronjobs.go b/server/backend/cron/cronjobs.go index 95ba45a2..8249c286 100644 --- a/server/backend/cron/cronjobs.go +++ b/server/backend/cron/cronjobs.go @@ -50,23 +50,16 @@ func New(db *gorm.DB) *CronService { func (c *CronService) Run() error { log.WithField("MensaCronActive", env.IsMensaCronActive()).Debug("running cron service") - g := new(errgroup.Group) - - if env.IsMensaCronActive() { - g.Go(func() error { return c.dishNameDownloadCron() }) - g.Go(func() error { return c.averageRatingComputation() }) - } - for { + g := new(errgroup.Group) log.Trace("Cron: checking for pending") var res []model.Crontab c.db.Model(&model.Crontab{}). - Where("`interval` > 0 AND (lastRun+`interval`) < ? AND type IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", + Where("`interval` > 0 AND (lastRun+`interval`) < ? AND type IN (?, ?, ?, ?, ?, ?, ?, ?, ?)", time.Now().Unix(), NewsType, FileDownloadType, - AverageRatingComputation, DishNameDownload, CanteenHeadcount, IOSNotifications, @@ -106,10 +99,6 @@ func (c *CronService) Run() error { if env.IsMensaCronActive() { g.Go(c.dishNameDownloadCron) } - case AverageRatingComputation: //call every five minutes between 11AM and 4 PM on weekdays - if env.IsMensaCronActive() { - g.Go(c.averageRatingComputation) - } case NewExamResultsHook: g.Go(func() error { return c.newExamResultsHookCron() }) case MovieType: diff --git a/server/backend/migration/20220713000000.go b/server/backend/migration/20220713000000.go index 6ed1e2b6..a92c1fee 100644 --- a/server/backend/migration/20220713000000.go +++ b/server/backend/migration/20220713000000.go @@ -70,6 +70,22 @@ func (n *InitialCafeteriaRatingTagsAverage) TableName() string { return "cafeteria_rating_tag_average" } +// InitialDishNameTagAverage stores all precomputed values for the DishName ratings +type InitialDishNameTagAverage struct { + DishNameTagAverage int64 `gorm:"primary_key;AUTO_INCREMENT;column:dishNameTagAverage;type:int;not null;" json:"dishNameTagAverage" ` + CafeteriaID int64 `gorm:"column:cafeteriaID;foreignKey:cafeteria;type:int;not null;" json:"cafeteriaID"` + TagID int64 `gorm:"column:tagID;foreignKey:DishNameTagOption;type:int;not null;" json:"tagID"` + Average float32 `gorm:"column:average;type:float;not null;" json:"average" ` + Min int8 `gorm:"column:min;type:int;not null;" json:"min"` + Max int8 `gorm:"column:max;type:int;not null;" json:"max"` + Std float32 `gorm:"column:std;type:float;not null;" json:"std"` +} + +// TableName sets the insert table name for this struct type +func (n *InitialDishNameTagAverage) TableName() string { + return "dish_name_tag_average" +} + // migrate20220713000000 func (m TumDBMigrator) migrate20220713000000() *gormigrate.Migration { return &gormigrate.Migration{ @@ -86,11 +102,11 @@ func (m TumDBMigrator) migrate20220713000000() *gormigrate.Migration { &model.DishNameTagOptionIncluded{}, &model.DishNameTagOptionExcluded{}, &model.DishNameTag{}, - &model.DishNameTagAverage{}, &model.DishRating{}, &model.DishRatingTag{}, &model.DishRatingTagOption{}, &model.DishToDishNameTag{}, + &InitialDishNameTagAverage{}, &InitialCafeteriaRatingAverage{}, &InitialCafeteriaRatingTagsAverage{}, &InitialDishRatingAverage{}, diff --git a/server/backend/migration/20231015000000.go b/server/backend/migration/20231015000000.go index 0c81ed8b..9bf26d06 100644 --- a/server/backend/migration/20231015000000.go +++ b/server/backend/migration/20231015000000.go @@ -69,13 +69,29 @@ func (n *CafeteriaRatingTagsAverage) TableName() string { return "cafeteria_rating_tag_average" } +// DishNameTagAverage stores all precomputed values for the DishName ratings +type DishNameTagAverage struct { + DishNameTagAverage int64 `gorm:"primary_key;AUTO_INCREMENT;column:dishNameTagAverage;type:int;not null;" json:"dishNameTagAverage" ` + CafeteriaID int64 `gorm:"column:cafeteriaID;foreignKey:cafeteria;type:int;not null;" json:"cafeteriaID"` + TagID int64 `gorm:"column:tagID;foreignKey:DishNameTagOption;type:int;not null;" json:"tagID"` + Average float32 `gorm:"column:average;type:float;not null;" json:"average" ` + Min int8 `gorm:"column:min;type:int;not null;" json:"min"` + Max int8 `gorm:"column:max;type:int;not null;" json:"max"` + Std float32 `gorm:"column:std;type:float;not null;" json:"std"` +} + +// TableName sets the insert table name for this struct type +func (n *DishNameTagAverage) TableName() string { + return "dish_name_tag_average" +} + // migrate20231015000000 // migrates the static data for the canteen rating system and adds the necessary cronjob entries func (m TumDBMigrator) migrate20231015000000() *gormigrate.Migration { return &gormigrate.Migration{ ID: "20231015000000", Migrate: func(tx *gorm.DB) error { - tables := []string{"cafeteria_rating_average", "dish_rating_average", "dish_rating_tag_average", "cafeteria_rating_tag_average"} + tables := []string{"cafeteria_rating_average", "dish_rating_average", "dish_rating_tag_average", "cafeteria_rating_tag_average", "dish_name_tag_average"} for _, table := range tables { if err := tx.Migrator().DropTable(table); err != nil { return err @@ -109,16 +125,23 @@ JOIN cafeteria_rating_tag crt ON cr.cafeteriaRating = crt.correspondingRating GROUP BY cr.cafeteriaID, crt.tagID`).Error; err != nil { return err } + if err := tx.Exec(`CREATE VIEW dish_name_tag_statistics AS +SELECT mr.cafeteriaID as cafeteriaID, mnt.tagnameID as tagID, AVG(mnt.points) as average, MAX(mnt.points) as max, MIN(mnt.points) as min, STD(mnt.points) as std +FROM dish_rating mr +JOIN dish_name_tag mnt ON mr.dishRating = mnt.correspondingRating +GROUP BY mr.cafeteriaID, mnt.tagnameID`).Error; err != nil { + return err + } return nil }, Rollback: func(tx *gorm.DB) error { - createdViews := []string{"cafeteria_rating_statistics", "dish_rating_statistics", "dish_rating_tag_statistics", "cafeteria_rating_tag_average"} + createdViews := []string{"cafeteria_rating_statistics", "dish_rating_statistics", "dish_rating_tag_statistics", "cafeteria_rating_tag_statistics", "dish_name_tag_statistics"} for _, view := range createdViews { if err := tx.Exec("DROP VIEW IF EXISTS " + view).Error; err != nil { return err } } - return tx.AutoMigrate(&CafeteriaRatingAverage{}, &DishRatingAverage{}, &DishRatingTagAverage{}, &CafeteriaRatingTagsAverage{}) + return tx.AutoMigrate(&CafeteriaRatingAverage{}, &DishRatingAverage{}, &DishRatingTagAverage{}, &CafeteriaRatingTagsAverage{}, &DishNameTagAverage{}) }, } } diff --git a/server/model/dish_name_tag_average.go b/server/model/dish_name_tag_average.go deleted file mode 100644 index 2ee05076..00000000 --- a/server/model/dish_name_tag_average.go +++ /dev/null @@ -1,17 +0,0 @@ -package model - -// DishNameTagAverage stores all precomputed values for the DishName ratings -type DishNameTagAverage struct { - DishNameTagAverage int64 `gorm:"primary_key;AUTO_INCREMENT;column:dishNameTagAverage;type:int;not null;" json:"dishNameTagAverage" ` - CafeteriaID int64 `gorm:"column:cafeteriaID;foreignKey:cafeteria;type:int;not null;" json:"cafeteriaID"` - TagID int64 `gorm:"column:tagID;foreignKey:DishNameTagOption;type:int;not null;" json:"tagID"` - Average float32 `gorm:"column:average;type:float;not null;" json:"average" ` - Min int8 `gorm:"column:min;type:int;not null;" json:"min"` - Max int8 `gorm:"column:max;type:int;not null;" json:"max"` - Std float32 `gorm:"column:std;type:float;not null;" json:"std"` -} - -// TableName sets the insert table name for this struct type -func (n *DishNameTagAverage) TableName() string { - return "dish_name_tag_average" -} diff --git a/server/model/dish_name_tag_statistic.go b/server/model/dish_name_tag_statistic.go new file mode 100644 index 00000000..44539206 --- /dev/null +++ b/server/model/dish_name_tag_statistic.go @@ -0,0 +1,11 @@ +package model + +// DishNameTagStatistic is a view for statistics of DishName ratings +type DishNameTagStatistic struct { + CafeteriaID int64 `gorm:"column:cafeteriaID;foreignKey:cafeteria;type:int;not null;" json:"cafeteriaID"` + TagID int64 `gorm:"column:tagID;foreignKey:DishNameTagOption;type:int;not null;" json:"tagID"` + Average float32 `gorm:"column:average;type:float;not null;" json:"average" ` + Min int8 `gorm:"column:min;type:int;not null;" json:"min"` + Max int8 `gorm:"column:max;type:int;not null;" json:"max"` + Std float32 `gorm:"column:std;type:float;not null;" json:"std"` +} From 1527f10875bc944fd20797a2c276dfd5f0d851d3 Mon Sep 17 00:00:00 2001 From: Frank Elsinga Date: Sun, 15 Oct 2023 22:47:44 +0200 Subject: [PATCH 07/13] removed the AverageRatingComputation cron job --- server/backend/cron/cronjobs.go | 31 ++++++++------------- server/backend/migration/20231015000000.go | 32 ++++++++++++++++++---- 2 files changed, 37 insertions(+), 26 deletions(-) diff --git a/server/backend/cron/cronjobs.go b/server/backend/cron/cronjobs.go index 8249c286..82d9b2a8 100644 --- a/server/backend/cron/cronjobs.go +++ b/server/backend/cron/cronjobs.go @@ -25,16 +25,15 @@ var StorageDir = "/Storage/" // target location of files // names for cron jobs as specified in database const ( - NewsType = "news" - FileDownloadType = "fileDownload" - DishNameDownload = "dishNameDownload" - AverageRatingComputation = "averageRatingComputation" - CanteenHeadcount = "canteenHeadCount" - IOSNotifications = "iosNotifications" - IOSActivityReset = "iosActivityReset" - NewExamResultsHook = "newExamResultsHook" - MovieType = "movie" - FeedbackEmail = "feedbackEmail" + NewsType = "news" + FileDownloadType = "fileDownload" + DishNameDownload = "dishNameDownload" + CanteenHeadcount = "canteenHeadCount" + IOSNotifications = "iosNotifications" + IOSActivityReset = "iosActivityReset" + NewExamResultsHook = "newExamResultsHook" + MovieType = "movie" + FeedbackEmail = "feedbackEmail" /* MensaType = "mensa" AlarmType = "alarm" */ @@ -72,18 +71,10 @@ func (c *CronService) Run() error { for _, cronjob := range res { // Persist run to DB right away - var offset int32 = 0 - if env.IsMensaCronActive() { - if cronjob.Type.String == AverageRatingComputation { - if time.Now().Hour() == 16 { - offset = 18 * 3600 // fast-forward 18 Hours to the next day + does not need to be computed overnight - } - } - } - cronFields := log.Fields{"Cron (id)": cronjob.Cron, "type": cronjob.Type.String, "offset": offset, "LastRun": cronjob.LastRun, "interval": cronjob.Interval, "id (not real id)": cronjob.ID.Int64} + cronFields := log.Fields{"Cron (id)": cronjob.Cron, "type": cronjob.Type.String, "LastRun": cronjob.LastRun, "interval": cronjob.Interval, "id (not real id)": cronjob.ID.Int64} log.WithFields(cronFields).Trace("Running cronjob") - cronjob.LastRun = int32(time.Now().Unix()) + offset + cronjob.LastRun = int32(time.Now().Unix()) c.db.Save(&cronjob) // Run each job in a separate goroutine, so we can parallelize them diff --git a/server/backend/migration/20231015000000.go b/server/backend/migration/20231015000000.go index 9bf26d06..8872a8f5 100644 --- a/server/backend/migration/20231015000000.go +++ b/server/backend/migration/20231015000000.go @@ -1,7 +1,9 @@ package migration import ( + "github.com/TUM-Dev/Campus-Backend/server/model" "github.com/go-gormigrate/gormigrate/v2" + "github.com/guregu/null" "gorm.io/gorm" ) @@ -91,12 +93,21 @@ func (m TumDBMigrator) migrate20231015000000() *gormigrate.Migration { return &gormigrate.Migration{ ID: "20231015000000", Migrate: func(tx *gorm.DB) error { + // cronjob + if err := tx.Delete(&model.Crontab{}, "type = 'averageRatingComputation'").Error; err != nil { + return err + } + if err := SafeEnumAdd(tx, &model.Crontab{}, "type", "averageRatingComputation"); err != nil { + return err + } + // tables tables := []string{"cafeteria_rating_average", "dish_rating_average", "dish_rating_tag_average", "cafeteria_rating_tag_average", "dish_name_tag_average"} for _, table := range tables { if err := tx.Migrator().DropTable(table); err != nil { return err } } + // views if err := tx.Exec(`CREATE VIEW cafeteria_rating_statistics AS SELECT cafeteriaID, Avg(points) AS average, MIN(points) AS min, Max(points) AS max, STD(points) AS std FROM cafeteria_rating @@ -125,23 +136,32 @@ JOIN cafeteria_rating_tag crt ON cr.cafeteriaRating = crt.correspondingRating GROUP BY cr.cafeteriaID, crt.tagID`).Error; err != nil { return err } - if err := tx.Exec(`CREATE VIEW dish_name_tag_statistics AS + return tx.Exec(`CREATE VIEW dish_name_tag_statistics AS SELECT mr.cafeteriaID as cafeteriaID, mnt.tagnameID as tagID, AVG(mnt.points) as average, MAX(mnt.points) as max, MIN(mnt.points) as min, STD(mnt.points) as std FROM dish_rating mr JOIN dish_name_tag mnt ON mr.dishRating = mnt.correspondingRating -GROUP BY mr.cafeteriaID, mnt.tagnameID`).Error; err != nil { - return err - } - return nil +GROUP BY mr.cafeteriaID, mnt.tagnameID`).Error }, Rollback: func(tx *gorm.DB) error { + // views createdViews := []string{"cafeteria_rating_statistics", "dish_rating_statistics", "dish_rating_tag_statistics", "cafeteria_rating_tag_statistics", "dish_name_tag_statistics"} for _, view := range createdViews { if err := tx.Exec("DROP VIEW IF EXISTS " + view).Error; err != nil { return err } } - return tx.AutoMigrate(&CafeteriaRatingAverage{}, &DishRatingAverage{}, &DishRatingTagAverage{}, &CafeteriaRatingTagsAverage{}, &DishNameTagAverage{}) + // tables + if err := tx.AutoMigrate(&CafeteriaRatingAverage{}, &DishRatingAverage{}, &DishRatingTagAverage{}, &CafeteriaRatingTagsAverage{}, &DishNameTagAverage{}); err != nil { + return err + } + // cronjob + if err := SafeEnumRemove(tx, &model.Crontab{}, "type", "averageRatingComputation"); err != nil { + return err + } + return tx.Create(&model.Crontab{ + Interval: 300, + Type: null.StringFrom("averageRatingComputation"), + }).Error }, } } From be7d0976bec98c094ece2f30e6acd350f027fb85 Mon Sep 17 00:00:00 2001 From: Frank Elsinga Date: Sun, 15 Oct 2023 22:48:21 +0200 Subject: [PATCH 08/13] fixed a part of the crontab I missed --- server/model/crontab.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/model/crontab.go b/server/model/crontab.go index 79d310af..d40d5d6c 100644 --- a/server/model/crontab.go +++ b/server/model/crontab.go @@ -14,6 +14,6 @@ type Crontab struct { Cron int64 `gorm:"primary_key;AUTO_INCREMENT;column:cron;type:int;" json:"cron"` Interval int32 `gorm:"column:interval;type:int;default:7200;" json:"interval"` LastRun int32 `gorm:"column:lastRun;type:int;default:0;" json:"last_run"` - Type null.String `gorm:"column:type;type:enum ('news', 'mensa', 'movie', 'roomfinder', 'alarm', 'fileDownload','dishNameDownload','averageRatingComputation', 'iosNotifications', 'iosActivityReset', 'canteenHeadCount', 'newExamResultsHook');" json:"type"` + Type null.String `gorm:"column:type;type:enum ('news', 'mensa', 'movie', 'roomfinder', 'alarm', 'fileDownload','dishNameDownload', 'iosNotifications', 'iosActivityReset', 'canteenHeadCount', 'newExamResultsHook');" json:"type"` ID null.Int `gorm:"column:id;type:int;" json:"id"` } From 9ff7f2c4f03e064f9e35b9d254c483c49d375cac Mon Sep 17 00:00:00 2001 From: Frank Elsinga Date: Mon, 16 Oct 2023 00:55:37 +0200 Subject: [PATCH 09/13] rebase --- server/api/tumdev/campus_backend.pb.go | 19 ++++++++++++------- server/api/tumdev/campus_backend.swagger.json | 16 +++++++++++----- server/api/tumdev/campus_backend_grpc.pb.go | 2 ++ server/backend/rpcserver.go | 1 + 4 files changed, 26 insertions(+), 12 deletions(-) diff --git a/server/api/tumdev/campus_backend.pb.go b/server/api/tumdev/campus_backend.pb.go index ba82b550..f7986690 100644 --- a/server/api/tumdev/campus_backend.pb.go +++ b/server/api/tumdev/campus_backend.pb.go @@ -1432,13 +1432,18 @@ type GetDishRatingsReply struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Rating []*SingleRatingReply `protobuf:"bytes,1,rep,name=rating,proto3" json:"rating,omitempty"` - Avg float64 `protobuf:"fixed64,2,opt,name=avg,proto3" json:"avg,omitempty"` - Std float64 `protobuf:"fixed64,3,opt,name=std,proto3" json:"std,omitempty"` - Min int32 `protobuf:"varint,4,opt,name=min,proto3" json:"min,omitempty"` - Max int32 `protobuf:"varint,5,opt,name=max,proto3" json:"max,omitempty"` - RatingTags []*RatingTagResult `protobuf:"bytes,6,rep,name=rating_tags,json=ratingTags,proto3" json:"rating_tags,omitempty"` - NameTags []*RatingTagResult `protobuf:"bytes,7,rep,name=name_tags,json=nameTags,proto3" json:"name_tags,omitempty"` + // a number of actual ratings + Rating []*SingleRatingReply `protobuf:"bytes,1,rep,name=rating,proto3" json:"rating,omitempty"` + // average rating for all dish rating tags which were used to rate this dish in this cafeteria + Avg float64 `protobuf:"fixed64,2,opt,name=avg,proto3" json:"avg,omitempty"` + // std of all dish rating tags which were used to rate this dish in this cafeteria + Std float64 `protobuf:"fixed64,3,opt,name=std,proto3" json:"std,omitempty"` + // minimum of all dish rating tags which were used to rate this dish in this cafeteria + Min int32 `protobuf:"varint,4,opt,name=min,proto3" json:"min,omitempty"` + // maximum of all dish rating tags which were used to rate this dish in this cafeteria + Max int32 `protobuf:"varint,5,opt,name=max,proto3" json:"max,omitempty"` + RatingTags []*RatingTagResult `protobuf:"bytes,6,rep,name=rating_tags,json=ratingTags,proto3" json:"rating_tags,omitempty"` + NameTags []*RatingTagResult `protobuf:"bytes,7,rep,name=name_tags,json=nameTags,proto3" json:"name_tags,omitempty"` } func (x *GetDishRatingsReply) Reset() { diff --git a/server/api/tumdev/campus_backend.swagger.json b/server/api/tumdev/campus_backend.swagger.json index a56468eb..cb616949 100644 --- a/server/api/tumdev/campus_backend.swagger.json +++ b/server/api/tumdev/campus_backend.swagger.json @@ -426,6 +426,7 @@ }, "/dish/rating/get": { "post": { + "summary": "Allows to query ratings for a specific dish in a specific cafeteria.", "operationId": "Campus_GetDishRatings", "responses": { "200": { @@ -1177,23 +1178,28 @@ "items": { "type": "object", "$ref": "#/definitions/apiSingleRatingReply" - } + }, + "title": "a number of actual ratings" }, "avg": { "type": "number", - "format": "double" + "format": "double", + "title": "average rating for all dish rating tags which were used to rate this dish in this cafeteria" }, "std": { "type": "number", - "format": "double" + "format": "double", + "title": "std of all dish rating tags which were used to rate this dish in this cafeteria" }, "min": { "type": "integer", - "format": "int32" + "format": "int32", + "title": "minimum of all dish rating tags which were used to rate this dish in this cafeteria" }, "max": { "type": "integer", - "format": "int32" + "format": "int32", + "title": "maximum of all dish rating tags which were used to rate this dish in this cafeteria" }, "ratingTags": { "type": "array", diff --git a/server/api/tumdev/campus_backend_grpc.pb.go b/server/api/tumdev/campus_backend_grpc.pb.go index f68f154f..9087d013 100644 --- a/server/api/tumdev/campus_backend_grpc.pb.go +++ b/server/api/tumdev/campus_backend_grpc.pb.go @@ -60,6 +60,7 @@ type CampusClient interface { SearchRooms(ctx context.Context, in *SearchRoomsRequest, opts ...grpc.CallOption) (*SearchRoomsReply, error) // This endpoint retrieves Canteen Ratings from the Backend. ListCanteenRatings(ctx context.Context, in *ListCanteenRatingsRequest, opts ...grpc.CallOption) (*ListCanteenRatingsReply, error) + // Allows to query ratings for a specific dish in a specific cafeteria. GetDishRatings(ctx context.Context, in *GetDishRatingsRequest, opts ...grpc.CallOption) (*GetDishRatingsReply, error) CreateCanteenRating(ctx context.Context, in *CreateCanteenRatingRequest, opts ...grpc.CallOption) (*CreateCanteenRatingReply, error) CreateDishRating(ctx context.Context, in *CreateDishRatingRequest, opts ...grpc.CallOption) (*CreateDishRatingReply, error) @@ -383,6 +384,7 @@ type CampusServer interface { SearchRooms(context.Context, *SearchRoomsRequest) (*SearchRoomsReply, error) // This endpoint retrieves Canteen Ratings from the Backend. ListCanteenRatings(context.Context, *ListCanteenRatingsRequest) (*ListCanteenRatingsReply, error) + // Allows to query ratings for a specific dish in a specific cafeteria. GetDishRatings(context.Context, *GetDishRatingsRequest) (*GetDishRatingsReply, error) CreateCanteenRating(context.Context, *CreateCanteenRatingRequest) (*CreateCanteenRatingReply, error) CreateDishRating(context.Context, *CreateDishRatingRequest) (*CreateDishRatingReply, error) diff --git a/server/backend/rpcserver.go b/server/backend/rpcserver.go index 477aabab..aed6b256 100644 --- a/server/backend/rpcserver.go +++ b/server/backend/rpcserver.go @@ -3,6 +3,7 @@ package backend import ( "context" "errors" + pb "github.com/TUM-Dev/Campus-Backend/server/api/tumdev" "github.com/TUM-Dev/Campus-Backend/server/backend/ios_notifications/apns" "github.com/TUM-Dev/Campus-Backend/server/model" From abf0ce5c98aec21d9cf8baea6c6f6eb994035bbc Mon Sep 17 00:00:00 2001 From: Frank Elsinga Date: Sun, 22 Oct 2023 01:43:37 +0200 Subject: [PATCH 10/13] fixed the migration not being added to the list of migrations --- server/backend/migration/migration.go | 1 + 1 file changed, 1 insertion(+) diff --git a/server/backend/migration/migration.go b/server/backend/migration/migration.go index 710c333f..5e3d5948 100644 --- a/server/backend/migration/migration.go +++ b/server/backend/migration/migration.go @@ -54,6 +54,7 @@ func (m TumDBMigrator) Migrate() error { m.migrate20230904100000(), m.migrate20230826000000(), m.migrate20231003000000(), + m.migrate20231015000000(), }) err := mig.Migrate() return err From 99be6a8b8594e18fc127bd7105e4021e25c47c7f Mon Sep 17 00:00:00 2001 From: Frank Elsinga Date: Mon, 23 Oct 2023 17:12:26 +0200 Subject: [PATCH 11/13] Fixed migrating the crontabs migrating the wrong way around --- server/backend/migration/20231015000000.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/backend/migration/20231015000000.go b/server/backend/migration/20231015000000.go index 8872a8f5..b784133d 100644 --- a/server/backend/migration/20231015000000.go +++ b/server/backend/migration/20231015000000.go @@ -97,7 +97,7 @@ func (m TumDBMigrator) migrate20231015000000() *gormigrate.Migration { if err := tx.Delete(&model.Crontab{}, "type = 'averageRatingComputation'").Error; err != nil { return err } - if err := SafeEnumAdd(tx, &model.Crontab{}, "type", "averageRatingComputation"); err != nil { + if err := SafeEnumRemove(tx, &model.Crontab{}, "type", "averageRatingComputation"); err != nil { return err } // tables @@ -155,7 +155,7 @@ GROUP BY mr.cafeteriaID, mnt.tagnameID`).Error return err } // cronjob - if err := SafeEnumRemove(tx, &model.Crontab{}, "type", "averageRatingComputation"); err != nil { + if err := SafeEnumAdd(tx, &model.Crontab{}, "type", "averageRatingComputation"); err != nil { return err } return tx.Create(&model.Crontab{ From 5af3b5b157225a1f8a3d13fc655a1b23a32daf4c Mon Sep 17 00:00:00 2001 From: Frank Elsinga Date: Thu, 26 Oct 2023 11:13:16 +0200 Subject: [PATCH 12/13] remvoed the views from auto migrations --- server/backend/migration/20231015000000.go | 2 +- server/backend/migration/migration.go | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/server/backend/migration/20231015000000.go b/server/backend/migration/20231015000000.go index b784133d..9a0ed791 100644 --- a/server/backend/migration/20231015000000.go +++ b/server/backend/migration/20231015000000.go @@ -89,7 +89,7 @@ func (n *DishNameTagAverage) TableName() string { // migrate20231015000000 // migrates the static data for the canteen rating system and adds the necessary cronjob entries -func (m TumDBMigrator) migrate20231015000000() *gormigrate.Migration { +func migrate20231015000000() *gormigrate.Migration { return &gormigrate.Migration{ ID: "20231015000000", Migrate: func(tx *gorm.DB) error { diff --git a/server/backend/migration/migration.go b/server/backend/migration/migration.go index 428778ee..168682df 100644 --- a/server/backend/migration/migration.go +++ b/server/backend/migration/migration.go @@ -14,23 +14,18 @@ func autoMigrate(db *gorm.DB) error { err := db.AutoMigrate( &model.Cafeteria{}, &model.CafeteriaRating{}, - &model.CafeteriaRatingAverage{}, &model.CafeteriaRatingTag{}, - &model.CafeteriaRatingTagAverage{}, &model.CafeteriaRatingTagOption{}, &model.CanteenHeadCount{}, &model.Crontab{}, &model.Device{}, &model.Dish{}, &model.DishNameTag{}, - &model.DishNameTagAverage{}, &model.DishNameTagOption{}, &model.DishNameTagOptionExcluded{}, &model.DishNameTagOptionIncluded{}, &model.DishRating{}, - &model.DishRatingAverage{}, &model.DishRatingTag{}, - &model.DishRatingTagAverage{}, &model.DishRatingTagOption{}, &model.DishToDishNameTag{}, &model.DishesOfTheWeek{}, From 44d5e366218445a7bb086f97919fc1609f834236 Mon Sep 17 00:00:00 2001 From: Frank Elsinga Date: Tue, 2 Jan 2024 22:09:20 +0100 Subject: [PATCH 13/13] linting fix --- server/backend/migration/migration.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/backend/migration/migration.go b/server/backend/migration/migration.go index 4bcfad06..cebebb32 100644 --- a/server/backend/migration/migration.go +++ b/server/backend/migration/migration.go @@ -73,7 +73,7 @@ func manualMigrate(db *gorm.DB) error { migrate20230904100000(), migrate20230826000000(), migrate20231003000000(), - migrate20231015000000(), + migrate20231015000000(), migrate20231023000000(), migrate20240101000000(), migrate20240102000000(),