Updated: db index and repository interface

This commit is contained in:
Aleksandr Soloshenko 2023-09-25 23:38:02 +07:00
parent 38ff76cdaf
commit 29598c4f5f
6 changed files with 99 additions and 17 deletions

View File

@ -0,0 +1,15 @@
-- +goose Up
-- +goose StatementBegin
CREATE UNIQUE INDEX IF NOT EXISTS `unq_messages_id_device` ON `messages`(`ext_id`, `device_id`);
-- +goose StatementEnd
-- +goose StatementBegin
DROP INDEX IF EXISTS `unq_messages_device_id` ON `messages`;
-- +goose StatementEnd
--
-- +goose Down
-- +goose StatementBegin
CREATE UNIQUE INDEX IF NOT EXISTS `unq_messages_device_id` ON `messages`(`device_id`, `ext_id`);
-- +goose StatementEnd
-- +goose StatementBegin
DROP INDEX IF EXISTS `unq_messages_id_device` ON `messages`;
-- +goose StatementEnd

View File

@ -19,18 +19,18 @@ type thirdPartyHandler struct {
messagesSvc *services.MessagesService
}
// @Summary Поставить сообщение в очередь
// @Description Ставит сообщение в очередь на отправку. Если идентификатор не указан, то он будет сгенерирован автоматически
// @Security ApiAuth
// @Tags Пользователь, Сообщения
// @Accept json
// @Produce json
// @Param request body smsgateway.Message true "Сообщение"
// @Success 201 {object} smsgateway.MessageState "Сообщение поставлено в очередь"
// @Failure 401 {object} smsgateway.ErrorResponse "Ошибка авторизации"
// @Failure 400 {object} smsgateway.ErrorResponse "Некорректный запрос"
// @Failure 500 {object} smsgateway.ErrorResponse "Внутренняя ошибка сервера"
// @Router /3rdparty/v1/message [post]
// @Summary Поставить сообщение в очередь
// @Description Ставит сообщение в очередь на отправку. Если идентификатор не указан, то он будет сгенерирован автоматически
// @Security ApiAuth
// @Tags Пользователь, Сообщения
// @Accept json
// @Produce json
// @Param request body smsgateway.Message true "Сообщение"
// @Success 201 {object} smsgateway.MessageState "Сообщение поставлено в очередь"
// @Failure 401 {object} smsgateway.ErrorResponse "Ошибка авторизации"
// @Failure 400 {object} smsgateway.ErrorResponse "Некорректный запрос"
// @Failure 500 {object} smsgateway.ErrorResponse "Внутренняя ошибка сервера"
// @Router /3rdparty/v1/message [post]
func (h *thirdPartyHandler) postMessage(user models.User, c *fiber.Ctx) error {
req := smsgateway.Message{}
if err := h.BodyParserValidator(c, &req); err != nil {
@ -54,6 +54,12 @@ func (h *thirdPartyHandler) postMessage(user models.User, c *fiber.Ctx) error {
return c.Status(fiber.StatusCreated).JSON(state)
}
func (h *thirdPartyHandler) getMessage(user models.User, c *fiber.Ctx) error {
// id := c.Params("id")
return fiber.ErrNotImplemented
}
func (h *thirdPartyHandler) authorize(handler func(models.User, *fiber.Ctx) error) fiber.Handler {
return func(c *fiber.Ctx) error {
username := c.Locals("username").(string)
@ -77,6 +83,7 @@ func (h *thirdPartyHandler) register(router fiber.Router) {
}))
router.Post("/message", h.authorize(h.postMessage))
router.Get("/message/:id", h.authorize(h.getMessage))
}
func newThirdPartyHandler(validator *validator.Validate, authSvc *services.AuthService, messagesSvc *services.MessagesService) *thirdPartyHandler {

View File

@ -42,8 +42,8 @@ type Device struct {
type Message struct {
ID uint64 `gorm:"primaryKey;type:BIGINT UNSIGNED;autoIncrement"`
DeviceID string `gorm:"not null;type:char(21);uniqueIndex:unq_messages_device_id;index:idx_messages_device_state"`
ExtID string `gorm:"not null;type:varchar(36);uniqueIndex:unq_messages_device_id"`
DeviceID string `gorm:"not null;type:char(21);uniqueIndex:unq_messages_id_device,priority:2;index:idx_messages_device_state"`
ExtID string `gorm:"not null;type:varchar(36);uniqueIndex:unq_messages_id_device,priority:1"`
Message string `gorm:"not null;type:tinytext"`
State MessageState `gorm:"not null;type:enum('Pending','Sent','Delivered','Failed');default:Pending;index:idx_messages_device_state"`

View File

@ -24,8 +24,24 @@ func (r *MessagesRepository) SelectPending(deviceID string) (messages []models.M
return
}
func (r *MessagesRepository) Get(deviceID, ID string) (message models.Message, err error) {
err = r.db.Where("device_id = ? AND ext_id = ?", deviceID, ID).Take(&message).Error
func (r *MessagesRepository) Get(ID string, filter MessagesSelectFilter, options ...MessagesSelectOptions) (message models.Message, err error) {
query := r.db.Model(&message).
Where("ext_id = ?", ID)
if filter.DeviceID != "" {
query = query.Where("device_id = ?", filter.DeviceID)
}
if len(options) > 0 {
if options[0].WithRecipients {
query = query.Preload("Recipients")
}
if options[0].WithDevice {
query = query.Preload("Device")
}
}
err = query.Take(&message).Error
return
}
@ -55,3 +71,13 @@ func NewMessagesRepository(db *gorm.DB) *MessagesRepository {
db: db,
}
}
// /////////////////////////////////////////////////////////////////////////////
type MessagesSelectFilter struct {
DeviceID string
}
type MessagesSelectOptions struct {
WithRecipients bool
WithDevice bool
}

View File

@ -9,6 +9,7 @@ import (
"bitbucket.org/capcom6/smsgatewaybackend/internal/smsgateway/models"
"bitbucket.org/capcom6/smsgatewaybackend/internal/smsgateway/repositories"
"bitbucket.org/capcom6/smsgatewaybackend/pkg/slices"
"bitbucket.org/capcom6/smsgatewaybackend/pkg/smsgateway"
"bitbucket.org/soft-c/gohelpers/pkg/filters"
"github.com/jaevor/go-nanoid"
@ -52,7 +53,7 @@ func (s *MessagesService) SelectPending(deviceID string) ([]smsgateway.Message,
}
func (s *MessagesService) UpdateState(deviceID string, message smsgateway.MessageState) error {
existing, err := s.Messages.Get(deviceID, message.ID)
existing, err := s.Messages.Get(message.ID, repositories.MessagesSelectFilter{DeviceID: deviceID})
if err != nil {
return err
}
@ -63,6 +64,15 @@ func (s *MessagesService) UpdateState(deviceID string, message smsgateway.Messag
return s.Messages.UpdateState(&existing)
}
func (s *MessagesService) GetState(deviceID, ID string) (smsgateway.MessageState, error) {
message, err := s.Messages.Get(ID, repositories.MessagesSelectFilter{DeviceID: deviceID}, repositories.MessagesSelectOptions{WithRecipients: true})
if err != nil {
return smsgateway.MessageState{}, fmt.Errorf("can't get message for device %s and ID %s: %w", deviceID, ID, err)
}
return modelToMessageState(message), nil
}
func (s *MessagesService) Enqeue(device models.Device, message smsgateway.Message) (smsgateway.MessageState, error) {
state := smsgateway.MessageState{
ID: "",
@ -148,3 +158,18 @@ func (s *MessagesService) recipientsStateToModel(input []smsgateway.RecipientSta
return output
}
func modelToMessageState(input models.Message) smsgateway.MessageState {
return smsgateway.MessageState{
ID: input.ExtID,
State: smsgateway.ProcessState(input.State),
Recipients: slices.Map(input.Recipients, modelToRecipientState),
}
}
func modelToRecipientState(input models.MessageRecipient) smsgateway.RecipientState {
return smsgateway.RecipientState{
PhoneNumber: input.PhoneNumber,
State: smsgateway.ProcessState(input.State),
}
}

9
pkg/slices/map.go Normal file
View File

@ -0,0 +1,9 @@
package slices
func Map[T, U any](slice []T, f func(T) U) []U {
result := make([]U, len(slice))
for i, v := range slice {
result[i] = f(v)
}
return result
}