Created
September 5, 2022 13:09
-
-
Save jba/ddcc3908c813f5b4afc845a69107d925 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// https://gitlab.com/yoanyombapro/CubeMicroservices/-/blob/08ad700e385853134c5149155e2681c40db1195c/podinfo/pkg/database/user.go | |
package database | |
import ( | |
"context" | |
"database/sql" | |
"errors" | |
"time" | |
"github.com/jinzhu/gorm" | |
"go.uber.org/zap" | |
model "gitlab.com/yoanyombapro/CubeMicroservices/podinfo/pkg/models/proto" | |
) | |
// CreateUser creates a user account record in the database | |
func (db *Database) CreateUser(ctx context.Context, user model.User) (*model.User, error) { | |
transaction := func(tx *gorm.DB) (interface{}, error) { | |
var userOrm model.UserORM | |
// check if the user exists in the database based off of | |
// email and username | |
// Note: Email and Usernames must be unique across the entire database | |
recordNotFound := tx.Where(model.UserORM{Email: user.Email, UserName: user.UserName}).First(&userOrm).RecordNotFound() | |
// if the user does exist and the user account is not active, reactivate the user account | |
// and update the user state in the backend database | |
if !recordNotFound && !userOrm.IsActive { | |
userOrm.IsActive = true | |
if err := tx.Save(&userOrm).Error; err != nil { | |
db.Logger.Error("failed to create user", zap.Error(err)) | |
return nil, err | |
} | |
return convertUserOrmToGenericUser(ctx, userOrm) | |
} else if !recordNotFound { | |
db.Logger.Error("failed to create user because user already exists") | |
return nil, errors.New("user already exists") | |
} | |
// convert the input user field to orm | |
userOrm, err := user.ToORM(ctx) | |
if err != nil { | |
db.Logger.Error("failed to create user", zap.Error(err)) | |
return nil, err | |
} | |
// generate a random reset token for the user account | |
// and set it | |
userOrm.ResetToken = GenerateRandomToken(20) | |
currentTime := time.Now() | |
tokenExpirationTime := currentTime.Add(time.Hour * 24 * 10) | |
userOrm.ResetTokenExpiration = &tokenExpirationTime | |
// activate user account | |
userOrm.IsActive = true | |
// save the user to the database | |
if err := tx.Create(&userOrm).Error; err != nil { | |
db.Logger.Error("failed to create user", zap.Error(err)) | |
return nil, err | |
} | |
db.Logger.Info("user successfully created", | |
zap.String("id", string(userOrm.Id)), | |
zap.String("username", userOrm.UserName), | |
zap.String("email", userOrm.Email)) | |
return convertUserOrmToGenericUser(ctx, userOrm) | |
} | |
output, err := db.PerformComplexTransaction(transaction) | |
if err != nil { | |
return &model.User{}, err | |
} | |
createdUser := output.(*model.User) | |
return createdUser, nil | |
} | |
// convertUserOrmToGenericUser converts a user orm to generic type | |
func convertUserOrmToGenericUser(ctx context.Context, userOrm model.UserORM) (*model.User, error) { | |
createdUser, err := userOrm.ToPB(ctx) | |
if err != nil { | |
return nil, err | |
} | |
if err = createdUser.Validate(); err != nil { | |
return nil, err | |
} | |
return &createdUser, nil | |
} | |
// GetUserByID queries the database and obtains a user record by id | |
func (db *Database) GetUserByID(ctx context.Context, userID uint32) (*model.User, error) { | |
var userOrm model.UserORM | |
if recordNotFound := db.Engine.Where(model.UserORM{Id: userID}).First(&userOrm).RecordNotFound(); recordNotFound { | |
db.Logger.Error("user does not exist", zap.String("id", string(userID))) | |
return nil, errors.New("user does not exist") | |
} | |
// convert the obtained user ORM object to a user object and validate all fields are there | |
userObj, err := userOrm.ToPB(ctx) | |
if err != nil { | |
db.Logger.Error("failed to convert fields to protobuf format") | |
return nil, err | |
} | |
// perform field validation | |
if err = userObj.Validate(); err != nil { | |
db.Logger.Error("field validation failed") | |
return nil, err | |
} | |
db.Logger.Info("user successfully obtained user by id", | |
zap.String("id", string(userOrm.Id)), | |
zap.String("username", userOrm.UserName), | |
zap.String("email", userOrm.Email)) | |
return &userObj, nil | |
} | |
// CreateUserProfile creates a user profile and ties it to a user account record | |
// if the account record exists. | |
func (db *Database) CreateUserProfile(ctx context.Context, userID uint32, profile model.Profile) (*model.Profile, error) { | |
transaction := func(tx *gorm.DB) (interface{}, error) { | |
var userOrm *model.UserORM | |
// first validate the profile has all necessary fields of interest | |
if err := profile.Validate(); err != nil { | |
db.Logger.Error("profile field validation failed", zap.Error(err)) | |
return nil, err | |
} | |
// check that the user exists | |
exists, userOrm, err := db.GetUserIfExists(userID, "", "") | |
if !exists { | |
db.Logger.Error("user account does not exist. please create one and try again", zap.Error(err)) | |
return nil, err | |
} | |
if userOrm.Profile != nil && userOrm.Profile.Id != 0 { | |
db.Logger.Error("profile already exists") | |
return nil, errors.New("profile already exists") | |
} | |
// update the user ORM object with the profile ORM object | |
profileOrm, err := profile.ToORM(ctx) | |
if err != nil { | |
db.Logger.Error("failed to convert profile fields to orm type", zap.Error(err)) | |
return nil, err | |
} | |
userOrm.Profile = &profileOrm | |
// Updates only the relevant fields of interest in a user entity in the database | |
if err = tx.Save(&userOrm).Error; err != nil { | |
db.Logger.Error("failed to create user profile", zap.Error(err)) | |
return nil, err | |
} | |
profile.Id = userOrm.Profile.Id | |
db.Logger.Info("successfully created a profile for the user account", | |
zap.String("accountId", string(userOrm.Id)), | |
zap.String("profileId", string(profile.Id))) | |
return &profile, nil | |
} | |
output, err := db.PerformComplexTransaction(transaction) | |
if err != nil { | |
return nil, err | |
} | |
createdProfile := output.(*model.Profile) | |
return createdProfile, nil | |
} | |
// CreateUserSubscription creates a subscription and ties it to a user account record if the | |
// account record exists, and the subscription does not. if the subscription does indeed exist and is | |
// inactive, it is reactivated. | |
func (db *Database) CreateUserSubscription(ctx context.Context, userID uint32, subscription model.Subscriptions) error { | |
transaction := func(tx *gorm.DB) error { | |
var ( | |
userOrm *model.UserORM | |
subscriptionExist = false | |
) | |
// validate the subscription object | |
if subscription.SubscriptionName == "" || | |
subscription.StartDate == nil || | |
subscription.EndDate == nil || | |
subscription.SubscriptionStatus == "" { | |
db.Logger.Error("invalid subscription. missing subscription name, start date, enddate, or status", | |
zap.Any("subscription", subscription)) | |
return errors.New("invalid subscription") | |
} | |
// check and make sure the user account with the specified userid exists | |
exists, userOrm, err := db.GetUserIfExists(userID, "", "") | |
if !exists { | |
db.Logger.Error("user account does not exist", zap.Error(err)) | |
return err | |
} | |
// convert the subscription object to an ORM type | |
subscriptionOrm, err := subscription.ToORM(ctx) | |
if err != nil { | |
db.Logger.Error("failed to convert subscription to orm type", zap.Error(err)) | |
return err | |
} | |
subscriptions := make([]*model.SubscriptionsORM, len(userOrm.Subscriptions), len(userOrm.Subscriptions)) | |
for _, oldSubscription := range userOrm.Subscriptions { | |
if oldSubscription.SubscriptionName == subscriptionOrm.SubscriptionName && !subscriptionExist { | |
// activate the subscription if it is not already active | |
oldSubscription.IsActive = true | |
oldSubscription.EndDate = subscriptionOrm.EndDate | |
subscriptionExist = true | |
db.Logger.Info("re-activating subscripion", zap.String("id", string(subscriptionOrm.Id)), | |
zap.String("name", subscription.SubscriptionName)) | |
} | |
subscriptions = append(subscriptions, oldSubscription) | |
} | |
if !subscriptionExist { | |
subscriptions = append(subscriptions, &subscriptionOrm) | |
db.Logger.Info("new subscripion added to subscriptions list", zap.String("id", string(subscriptionOrm.Id)), | |
zap.String("name", subscription.SubscriptionName)) | |
} | |
userOrm.Subscriptions = subscriptions | |
// save the user with the updated subscriptions | |
if err = tx.Save(&userOrm).Error; err != nil { | |
db.Logger.Error("failed to create user subscription", zap.Error(err)) | |
return err | |
} | |
db.Logger.Info("successfully created user subscription") | |
return nil | |
} | |
return db.PerformTransaction(transaction) | |
} | |
// UpdateUser updates a user record if it already exists in the backend | |
func (db *Database) UpdateUser(ctx context.Context, userID uint32, user model.User) (*model.User, error) { | |
transaction := func(tx *gorm.DB) (interface{}, error) { | |
// first and foremost we check for the existence of the user | |
exists, _, err := db.GetUserIfExists(userID, "", "") | |
if !exists { | |
db.Logger.Error("failed to obtain user by id as user does not exist", zap.Error(err)) | |
return nil, err | |
} | |
// convert the user to an ORM type | |
userOrm, err := user.ToORM(ctx) | |
if err != nil { | |
db.Logger.Error("failed to convert user object to orm type", zap.Error(err)) | |
return nil, err | |
} | |
// update the actual user in the database | |
if err := tx.Save(&userOrm).Error; err != nil { | |
db.Logger.Error("failed to update user", zap.Error(err)) | |
return nil, err | |
} | |
db.Logger.Info("Successfully updated user", zap.String("id", string(userOrm.Id)), | |
zap.String("user name", string(userOrm.UserName))) | |
return &user, nil | |
} | |
output, err := db.PerformComplexTransaction(transaction) | |
if err != nil { | |
return &model.User{}, err | |
} | |
updatedUser := output.(*model.User) | |
return updatedUser, nil | |
} | |
// UpdateUserSubscription updates a subscription tied to a user account if it exists | |
func (db *Database) UpdateUserSubscription(ctx context.Context, userID uint32, subscriptionID uint32, newSubscription model.Subscriptions) (*model.Subscriptions, error) { | |
transaction := func(tx *gorm.DB) (interface{}, error) { | |
var ( | |
userOrm model.UserORM | |
updatedSubscriptions []*model.SubscriptionsORM | |
) | |
// validate the new version of the subscription | |
if err := newSubscription.Validate(); err != nil { | |
db.Logger.Error("invalid subscription", zap.Error(err)) | |
return nil, err | |
} | |
// convert the subscription to an ORM type | |
subscriptionOrm, err := newSubscription.ToORM(ctx) | |
if err != nil { | |
db.Logger.Error("failed to convert subscription to orm type", zap.Error(err)) | |
return nil, err | |
} | |
// we check for the existence of the user account | |
// and the subscription | |
exist, _, err := db.GetSubscriptionExistById(userID, subscriptionID) | |
if !exist { | |
db.Logger.Error("subscription does not exist", zap.Error(err)) | |
return nil, err | |
} | |
// obtain the user from the database | |
if err := tx.Where(model.UserORM{Id: userID}).First(&userOrm).Error; err != nil { | |
db.Logger.Error("failed to obtain user from backend database", zap.Error(err)) | |
return nil, err | |
} | |
// update the subscription if an existing version exists in the database | |
for _, oldSubscription := range userOrm.Subscriptions { | |
if oldSubscription.SubscriptionName == subscriptionOrm.SubscriptionName { | |
updatedSubscriptions = append(updatedSubscriptions, &subscriptionOrm) | |
db.Logger.Info("updated subscription and added to subscription list") | |
} else { | |
updatedSubscriptions = append(updatedSubscriptions, oldSubscription) | |
} | |
} | |
// update the subscription list tied to the user | |
userOrm.Subscriptions = updatedSubscriptions | |
// update the actual user in the database | |
if err := tx.Save(&userOrm).Error; err != nil { | |
db.Logger.Error("failed to successfully update subscription", zap.Error(err)) | |
return nil, err | |
} | |
db.Logger.Info("successfully updated subscription", | |
zap.String("userId", string(userID)), zap.String("subscriptionId", string(subscriptionID))) | |
return &newSubscription, nil | |
} | |
output, err := db.PerformComplexTransaction(transaction) | |
if err != nil { | |
return nil, err | |
} | |
updatedSubscription := output.(*model.Subscriptions) | |
return updatedSubscription, nil | |
} | |
// UpdateUserProfile updates a user profile tied to a user account if such profile exists | |
func (db *Database) UpdateUserProfile(ctx context.Context, userID, profileID uint32, newProfile model.Profile) (*model.Profile, error) { | |
transaction := func(tx *gorm.DB) (interface{}, error) { | |
var userOrm model.UserORM | |
// first and foremost we check for the existence of the user account | |
// and the profile | |
exist, _, err := db.GetUserProfileIfExists(userID) | |
if !exist { | |
db.Logger.Error("failed to obtain user profile as it does not exist", zap.Error(err)) | |
return nil, err | |
} | |
// obtain the user from the database | |
if err := tx.Where(model.UserORM{Id: userID}).First(&userOrm).Error; err != nil { | |
db.Logger.Error("failed to obtain user", zap.Error(err)) | |
return nil, err | |
} | |
// convert the profile to an ORM type | |
profileOrm, err := newProfile.ToORM(ctx) | |
if err != nil { | |
db.Logger.Error("failed to convert user profile to orm type", zap.Error(err)) | |
return nil, err | |
} | |
// update the profile tied to the user | |
userOrm.Profile = &profileOrm | |
// update the actual user in the database | |
if err := tx.Save(&userOrm).Error; err != nil { | |
db.Logger.Error("failed to update user profile", zap.Error(err)) | |
return nil, err | |
} | |
db.Logger.Info("successfully updated user profile", | |
zap.String("userId", string(userID)), zap.String("profileId", string(profileOrm.Id))) | |
return newProfile, nil | |
} | |
output, err := db.PerformComplexTransaction(transaction) | |
if err != nil { | |
return nil, err | |
} | |
updatedProfile := output.(*model.Profile) | |
return updatedProfile, nil | |
} | |
// DeleteUser deletes a user account and any reference objects tied to the user | |
func (db *Database) DeleteUser(ctx context.Context, userID uint32) error { | |
transaction := func(tx *gorm.DB) error { | |
var userOrm model.UserORM | |
if userID == 0 { | |
db.Logger.Error("invalid user id") | |
return errors.New("invalid user id") | |
} | |
exist, _, err := db.GetUserIfExists(userID, "", "") | |
if !exist { | |
db.Logger.Error("failed to obtain user by id. user does not exist", zap.Error(err)) | |
return err | |
} | |
if err = tx.Where(model.UserORM{Id: userID}).Delete(&userOrm).Error; err != nil { | |
db.Logger.Error("failed to successfully delete user account", zap.Error(err)) | |
return err | |
} | |
db.Logger.Info("successfully deleted user account", zap.String("userId", string(userID))) | |
return nil | |
} | |
return db.PerformTransaction(transaction) | |
} | |
// DeleteUserProfile deletes a user profile tied to a user account | |
func (db *Database) DeleteUserProfile(ctx context.Context, userID, profileID uint32) error { | |
transaction := func(tx *gorm.DB) error { | |
// check the user of interest has a profile to even delete | |
exist, profile, err := db.GetUserProfileIfExists(userID) | |
if !exist { | |
db.Logger.Error("failed to obtain user profile as it does not exist", zap.Error(err)) | |
return err | |
} | |
// attempt deletion of the profile | |
if err = tx.Where(model.ProfileORM{Id: profileID}).Delete(&profile).Error; err != nil { | |
db.Logger.Error("failed to delete user profile", zap.Error(err)) | |
return err | |
} | |
db.Logger.Info("successfully deleted user Profile", | |
zap.String("userId", string(userID)), zap.String("profileId", string(profileID))) | |
return nil | |
} | |
return db.PerformTransaction(transaction) | |
} | |
// DeleteUserSubscription deletes a subscription tied to a user account | |
func (db *Database) DeleteUserSubscription(ctx context.Context, userID, subscriptionID uint32) error { | |
transaction := func(tx *gorm.DB) error { | |
// get a subscription by id | |
exist, _, err := db.GetSubscriptionExistById(userID, subscriptionID) | |
if !exist { | |
db.Logger.Error("failed to get subscription by id as it does not exist", zap.Error(err)) | |
return err | |
} | |
// delete from subscriptions table in db where id == subscriptions id | |
if err = tx.Where(model.SubscriptionsORM{Id: subscriptionID}).Delete(&model.SubscriptionsORM{}).Error; err != nil { | |
db.Logger.Error("failed to delete subscription", zap.Error(err)) | |
return err | |
} | |
db.Logger.Info("successfully deleted subscription", | |
zap.String("userId", string(userID)), zap.String("subscriptionId", string(subscriptionID))) | |
return nil | |
} | |
return db.PerformTransaction(transaction) | |
} | |
// GetAllUsers obtains user records. The max number of records returned is defined | |
// by the limit input parameter. | |
func (db *Database) GetAllUsers(ctx context.Context, limit uint32) ([]model.User, error) { | |
transaction := func(tx *gorm.DB) (interface{}, error) { | |
var users = make([]model.User, limit, limit+1) | |
var iteration uint32 = 0 | |
rows, err := tx.Limit(limit).Model(&model.UserORM{}).Rows() | |
defer rows.Close() | |
if err != nil { | |
db.Logger.Error("failed to obtain set of user object from the database", zap.Error(err)) | |
return nil, err | |
} | |
for rows.Next() { | |
var entry model.UserORM | |
// scan the data that the row pointer points to into a userOrm object | |
if err := tx.ScanRows(rows, &entry); err != nil { | |
db.Logger.Error("failed to scan the returned row", zap.Error(err)) | |
return nil, err | |
} | |
user, err := entry.ToPB(ctx) | |
if err != nil { | |
db.Logger.Error("failed to convert orm type to pb type", zap.Error(err)) | |
return nil, err | |
} | |
if err = user.Validate(); err != nil { | |
db.Logger.Error("user object failed validation check", zap.Error(err)) | |
return nil, err | |
} | |
users = append(users, user) | |
iteration++ | |
if iteration == limit { | |
break | |
} | |
} | |
db.Logger.Info("successfully obtained users from backend database") | |
return users, rows.Close() | |
} | |
output, err := db.PerformComplexTransaction(transaction) | |
if err != nil { | |
return nil, err | |
} | |
users := output.([]model.User) | |
return users, nil | |
} | |
// GetAllUsersByAccountType obtains user records by account type. The upper bound on the number of | |
// user records returned is defined by the limit input parameter. | |
func (db *Database) GetAllUsersByAccountType(ctx context.Context, accountType string, limit uint32) ([]model.User, error) { | |
transaction := func(tx *gorm.DB) (interface{}, error) { | |
var ( | |
users = make([]model.User, limit) | |
) | |
rows, err := tx.Limit(limit).Where(model.UserORM{UserAccountType: accountType}).Model(&model.UserORM{}).Rows() | |
if err != nil { | |
db.Logger.Error("failed to obtain users by accounttypes", zap.Error(err)) | |
return nil, err | |
} | |
defer rows.Close() | |
for rows.Next() { | |
entry := model.UserORM{} | |
// scan the data that the row pointer points to into a userOrm object | |
if err := tx.ScanRows(rows, &entry); err != nil { | |
db.Logger.Error("failed to scan row", zap.Error(err)) | |
return nil, err | |
} | |
user, err := entry.ToPB(ctx) | |
if err != nil { | |
db.Logger.Error("failed to convert user orm type to pb type", zap.Error(err)) | |
return nil, err | |
} | |
if err = user.Validate(); err != nil { | |
db.Logger.Error("user validation failed", zap.Error(err)) | |
return nil, err | |
} | |
users = append(users, user) | |
} | |
db.Logger.Info("successfully obtained users by account type") | |
return users, rows.Close() | |
} | |
output, err := db.PerformComplexTransaction(transaction) | |
if err != nil { | |
return nil, err | |
} | |
users := output.([]model.User) | |
return users, nil | |
} | |
// GetAllUsersByIntent queries the database for all user records based on intent. The | |
// upper bound on the number of user records returned is defined by the limit input parameter. | |
func (db *Database) GetAllUsersByIntent(ctx context.Context, intent string, limit uint32) ([]model.User, error) { | |
transaction := func(tx *gorm.DB) (interface{}, error) { | |
var users = make([]model.User, limit, limit+10) | |
rows, err := tx.Limit(limit).Where(model.UserORM{Intent: intent}).Model(&model.UserORM{}).Rows() | |
if err != nil { | |
db.Logger.Error("failed to obtain users by intent", zap.Error(err)) | |
return nil, err | |
} | |
defer rows.Close() | |
for rows.Next() { | |
entry := model.UserORM{} | |
// scan the data that the row pointer points to into a userOrm object | |
if err := tx.ScanRows(rows, &entry); err != nil { | |
db.Logger.Error("failed to scan row", zap.Error(err)) | |
return nil, err | |
} | |
user, err := entry.ToPB(ctx) | |
if err != nil { | |
db.Logger.Error("failed to convert user orm type to pb type", zap.Error(err)) | |
return nil, err | |
} | |
if err = user.Validate(); err != nil { | |
db.Logger.Error("user validation call failed", zap.Error(err)) | |
return nil, err | |
} | |
users = append(users, user) | |
} | |
db.Logger.Info("successfully obtained user by intent") | |
return users, rows.Close() | |
} | |
output, err := db.PerformComplexTransaction(transaction) | |
if err != nil { | |
return nil, err | |
} | |
users := output.([]model.User) | |
return users, nil | |
} | |
// GetUserProfile queries the database for a user profile record based on user account id | |
func (db *Database) GetUserProfile(ctx context.Context, userID uint32) (model.Profile, error) { | |
transaction := func(tx *gorm.DB) (interface{}, error) { | |
// obtain the user of interest | |
user, err := db.GetUserByID(ctx, userID) | |
if err != nil { | |
db.Logger.Error("failed to obtain user account by id", zap.Error(err)) | |
return nil, err | |
} | |
// validate that the user has all necessary fields | |
if err = user.Validate(); err != nil { | |
db.Logger.Error("user validation failed", zap.Error(err)) | |
return nil, err | |
} | |
// from the user object extract the profile object | |
profile := user.Profile | |
if profile != nil { | |
if err = profile.Validate(); err != nil { | |
db.Logger.Error("user profile validation failed", zap.Error(err)) | |
return nil, err | |
} | |
db.Logger.Info("profile does not exist") | |
// return the profile object | |
return *profile, nil | |
} | |
db.Logger.Info("successfully returned user profile") | |
return model.Profile{}, errors.New("user profile does not exist") | |
} | |
output, err := db.PerformComplexTransaction(transaction) | |
if err != nil { | |
return model.Profile{}, err | |
} | |
profileData := output.(model.Profile) | |
return profileData, nil | |
} | |
// GetAllUserProfilesByType queries the database and returns all user profile records | |
// with a specified profile type. The upper bound on the number of records to return | |
// is defined by the limit input parameter. | |
func (db *Database) GetAllUserProfilesByType(ctx context.Context, profileType string, limit uint32) ([]model.Profile, error) { | |
transaction := func(tx *gorm.DB) (interface{}, error) { | |
var profiles = make([]model.Profile, limit, limit+10) | |
rows, err := tx.Limit(limit).Where(model.ProfileORM{ProfileType: profileType}).Model(&model.ProfileORM{}).Rows() | |
if err != nil { | |
db.Logger.Error("failed to obtain user by profile type") | |
return nil, err | |
} | |
defer rows.Close() | |
// obtain the value of interest from the rows returned by the query | |
for rows.Next() { | |
entry := model.ProfileORM{} | |
// scan the data that the row pointer points to into a userOrm object | |
if err := tx.ScanRows(rows, &entry); err != nil { | |
db.Logger.Error("failed to scan rows", zap.Error(err)) | |
return nil, err | |
} | |
profile, err := entry.ToPB(ctx) | |
if err != nil { | |
db.Logger.Error("failed to convert user orm type to pb type", zap.Error(err)) | |
return nil, err | |
} | |
if err = profile.Validate(); err != nil { | |
db.Logger.Error("user profile validation failed", zap.Error(err)) | |
return nil, err | |
} | |
profiles = append(profiles, profile) | |
} | |
db.Logger.Info("successfully returned user profile by profile types") | |
return profiles, rows.Close() | |
} | |
output, err := db.PerformComplexTransaction(transaction) | |
if err != nil { | |
return nil, err | |
} | |
profileData := output.([]model.Profile) | |
return profileData, nil | |
} | |
// GetAllUserProfiles queries the database and returns a set of user profile records. | |
// The upper bound on the number of records returned is defined by the limit | |
// input parameter. | |
func (db *Database) GetAllUserProfiles(ctx context.Context, limit uint32) ([]model.Profile, error) { | |
transaction := func(tx *gorm.DB) (interface{}, error) { | |
var profiles = make([]model.Profile, limit, limit+10) | |
rows, err := tx.Limit(limit).Model(&model.ProfileORM{}).Rows() | |
if err != nil { | |
db.Logger.Error(err.Error()) | |
return nil, err | |
} | |
defer rows.Close() | |
data, err := extractFromRows(rows, tx, model.ProfileORM{}) | |
if err != nil { | |
db.Logger.Error(err.Error()) | |
return nil, err | |
} | |
profilesOrm := make([]model.ProfileORM, len(data)) | |
for _, val := range data { | |
profilesOrm = append(profilesOrm, val.(model.ProfileORM)) | |
} | |
for _, profileOrm := range profilesOrm { | |
// convert to object type and validate | |
profile, err := profileOrm.ToPB(ctx) | |
if err != nil { | |
db.Logger.Error(err.Error()) | |
return nil, err | |
} | |
if err = profile.Validate(); err != nil { | |
db.Logger.Error(err.Error()) | |
return nil, err | |
} | |
profiles = append(profiles, profile) | |
} | |
db.Logger.Info("successfully obtained user profiles") | |
return profiles, rows.Close() | |
} | |
output, err := db.PerformComplexTransaction(transaction) | |
if err != nil { | |
return nil, err | |
} | |
profileData := output.([]model.Profile) | |
return profileData, nil | |
} | |
// GetAllUserProfilesByNationality queries the database for a list of profiles | |
// of a certain nationality. The maximal amount of records to return is defined | |
// by the limit input parameter | |
func (db *Database) GetAllUserProfilesByNationality(ctx context.Context, nationality string, limit uint32) ([]model.Profile, error) { | |
transaction := func(tx *gorm.DB) (interface{}, error) { | |
var profiles = make([]model.Profile, limit, limit+10) | |
// get all profiles by profile type by querying the database | |
rows, err := tx.Limit(limit).Where(model.ProfileORM{Nationality: nationality}).Model(&model.ProfileORM{}).Rows() | |
if err != nil { | |
db.Logger.Error(err.Error()) | |
return nil, err | |
} | |
defer rows.Close() | |
// obtain the value of interest from the rows returned by the query | |
for rows.Next() { | |
entry := model.ProfileORM{} | |
// scan the data that the row pointer points to into a userOrm object | |
if err := tx.ScanRows(rows, &entry); err != nil { | |
db.Logger.Error(err.Error()) | |
return nil, err | |
} | |
profile, err := entry.ToPB(ctx) | |
if err != nil { | |
db.Logger.Error(err.Error()) | |
return nil, err | |
} | |
if err = profile.Validate(); err != nil { | |
db.Logger.Error(err.Error()) | |
return nil, err | |
} | |
profiles = append(profiles, profile) | |
} | |
db.Logger.Info("Successfully obtained user profiles by nationality") | |
return profiles, rows.Close() | |
} | |
output, err := db.PerformComplexTransaction(transaction) | |
if err != nil { | |
return nil, err | |
} | |
profileData := output.([]model.Profile) | |
return profileData, nil | |
} | |
// GetAllUserSubscriptions queries the database for a user based off of the | |
// user id and returns a set of subscriptions the user has | |
func (db *Database) GetAllUserSubscriptions(ctx context.Context, user_id uint32) ([]model.Subscriptions, error) { | |
transaction := func(tx *gorm.DB) (interface{}, error) { | |
var subscriptions = make([]model.Subscriptions, 10, 20) | |
user, err := db.GetUserByID(ctx, user_id) | |
if err != nil { | |
return nil, err | |
} | |
for _, subscription := range user.GetSubscriptions() { | |
subscriptions = append(subscriptions, *subscription) | |
} | |
return subscriptions, nil | |
} | |
output, err := db.PerformComplexTransaction(transaction) | |
if err != nil { | |
return nil, err | |
} | |
subscriptions := output.([]model.Subscriptions) | |
return subscriptions, nil | |
} | |
// extractFromRows operates on database rows returned by a given query. It transforms the | |
// obtains row values into an ORM type and returns any errors that may have occurred throughout | |
// the lifecycle of the function call as well as an abstract type tied to the list of ORM | |
// types obtained from all rows | |
func extractFromRows(rows *sql.Rows, tx *gorm.DB, dbModel interface{}) ([]interface{}, error) { | |
var data = make([]interface{}, 20) | |
defer rows.Close() | |
// iterate over all rows obtained from the query | |
for rows.Next() { | |
// scan the data that the row pointer points to into a userOrm object | |
if err := tx.ScanRows(rows, &dbModel); err != nil { | |
return nil, err | |
} | |
data = append(data, dbModel) | |
} | |
// we call rows.close() again to reduce any potential | |
// side effects that may arise. It is much safer to reclose | |
// a database handle than to potential leave it open as a sideffect | |
// of some mishandled error | |
return data, rows.Close() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment