package queries import ( "time" "github.com/fiskerinc/cloud-services/pkg/common" "github.com/fiskerinc/cloud-services/pkg/validator" "github.com/go-pg/pg/v10/orm" "github.com/google/uuid" "github.com/pkg/errors" ) type SubscriptionsInterface interface { Delete(req *SubscriptionDeleteRequest) (orm.Result, error) Insert(subtype *common.Subscription) (orm.Result, error) Update(subtype *common.Subscription) (orm.Result, error) Select(filter *common.Subscription) ([]common.Subscription, error) Load(subtype *common.Subscription) error Count(filter *common.Subscription) (int, error) Create(subtype *common.SubscriptionType, carToDriver *common.CarToDriver) (*common.Subscription, error) } type Subscriptions struct { QueryBase } // Select returns list of drivers func (s *Subscriptions) Select(filter *common.Subscription) ([]common.Subscription, error) { subs := []common.Subscription{} query := s.GetDBConn().Model(&subs) s.selectFilter(query, filter) err := query.Select() return subs, errors.WithStack(err) } func (s *Subscriptions) selectFilter(query *orm.Query, filter *common.Subscription) { if filter.ID != 0 { query.Where("id = ?", filter.ID) } if filter.SubscriptionTypeID != uuid.Nil { query.Where("subscription_type_id = ?", filter.SubscriptionTypeID) } if filter.CarToDriverID != 0 { query.Where("car_to_driver_id = ?", filter.CarToDriverID) } if filter.Name != "" { query.Where("name = ?", filter.Name) } if filter.Name != "" { query.Where("destination = ?", filter.Destination) } } func (s *Subscriptions) Insert(subtype *common.Subscription) (orm.Result, error) { return s.insert(subtype) } func (s *Subscriptions) Update(subtype *common.Subscription) (orm.Result, error) { err := s.validateSubID(subtype) if err != nil { return nil, err } return s.GetDBConn().Model(subtype).Column("subscription_type_id", "car_to_driver_id", "name", "destination", "expires").WherePK().Update() } func (s *Subscriptions) Delete(req *SubscriptionDeleteRequest) (orm.Result, error) { if req.ID > 0 { return s.deleteByID(&common.Subscription{ID: req.ID}) } return s.deleteRequest(req) } func (s *Subscriptions) deleteByID(sub *common.Subscription) (orm.Result, error) { err := s.validateSubID(sub) if err != nil { return nil, err } return s.resultWithStack(s.GetDBConn().Model(sub).WherePK().Delete()) } func (s *Subscriptions) deleteRequest(req *SubscriptionDeleteRequest) (orm.Result, error) { err := validator.ValidateStruct(req) if err != nil { return nil, errors.WithStack(err) } return s.resultWithStack(s.GetDBConn().Model((*common.Subscription)(nil)).Exec(`DELETE FROM "subscriptions" AS "subs" WHERE (subs.id IN (SELECT subs2.id FROM "subscriptions" AS "subs2" JOIN car_to_drivers AS c ON (c.id = subs2.car_to_driver_id) WHERE (c.vin = ? AND subs2.name = ?)))`, req.VIN, req.Name)) } func (s *Subscriptions) Load(sub *common.Subscription) error { query := s.GetDBConn().Model(sub) if sub.ID != 0 { query.WherePK() } else if sub.SubscriptionTypeID != uuid.Nil && sub.CarToDriverID != 0 { query.Where("subscription_type_id = ?subscription_type_id AND driver_id = ?car_to_driver_id") } else { return errors.New("no id or subscription_type_id, driver_id") } return errors.WithStack(query.Select()) } func (s *Subscriptions) Count(filter *common.Subscription) (int, error) { query := s.GetDBConn().Model((*common.Subscription)(nil)) s.selectFilter(query, filter) count, err := query.Count() return count, errors.WithStack(err) } func (s *Subscriptions) validateSubID(subtype *common.Subscription) error { if subtype.ID == 0 { return errors.WithStack(&validator.FieldError{ ErrorMsg: "ID required", }) } return nil } func (s *Subscriptions) Create(subtype *common.SubscriptionType, carToDriver *common.CarToDriver) (*common.Subscription, error) { sub := common.Subscription{ Name: subtype.Name, Destination: subtype.Destination, CarToDriverID: carToDriver.ID, SubscriptionTypeID: subtype.ID, Expires: time.Now().Add(subtype.GetDuration()), } _, err := s.Insert(&sub) if err != nil { return nil, err } return &sub, nil } type SubscriptionDeleteRequest struct { ID int64 `json:"id"` Name string `json:"name" validate:"required,max=256"` VIN string `json:"vin" validate:"required,vin"` }