feat: sorting for primitive fields

# Conflicts:
#	frontend/src/App.vue
This commit is contained in:
2025-03-12 15:47:49 +07:00
parent e655bb5d5f
commit 10c7a9bac8
14 changed files with 123 additions and 71 deletions

View File

@@ -18,7 +18,7 @@ func ErrorDialog(title string, message string) {
application.ErrorDialog().SetTitle(title).SetMessage(message).Show()
}
func SaveFileDialog(title string, filename string) (string, error) {
func SaveFileDialog(filename string) (string, error) {
selection, err := application.SaveFileDialog().SetFilename(filename).PromptForSingleSelection()
if err != nil {
return "", err

View File

@@ -329,7 +329,7 @@ func ApplyStyleHeaders(file *excelize.File, sheetName string, headers TableHeade
}
func WriteData(file *excelize.File, filename string) error {
filepath, err := dialogs.SaveFileDialog("Экспорт данных", filename)
filepath, err := dialogs.SaveFileDialog(filename)
if !strings.HasSuffix(filepath, ".xlsx") {
filepath += ".xlsx"

View File

@@ -4,31 +4,30 @@ import (
"app/internal/dal"
"app/internal/database"
"app/internal/models"
"app/internal/utils"
"errors"
"gorm.io/gen/field"
"gorm.io/gorm"
)
type AuthorService struct{}
type AuthorService struct {
}
type Author = models.Author
func (service *AuthorService) Create(item Author) (Author, error) {
ReplaceEmptySlicesWithNil(&item)
utils.ReplaceEmptySlicesWithNil(&item)
err := dal.Author.Create(&item)
if err != nil {
return item, err
}
err = AppendAssociations(database.GetInstance(), &item)
err = utils.AppendAssociations(database.GetInstance(), &item)
return item, err
}
func (service *AuthorService) GetAll() ([]*Author, error) {
var authors []*Author
authors, err := dal.Author.Preload(field.Associations).Find()
return authors, err
}
func (service *AuthorService) GetById(id uint) (*Author, error) {
item, err := dal.Author.Preload(field.Associations).Where(dal.Author.Id.Eq(id)).First()
if err != nil {
@@ -40,16 +39,13 @@ func (service *AuthorService) GetById(id uint) (*Author, error) {
}
return item, nil
}
func (service *AuthorService) Update(item Author) (Author, error) {
ReplaceEmptySlicesWithNil(&item)
utils.ReplaceEmptySlicesWithNil(&item)
_, err := dal.Author.Updates(&item)
if err != nil {
return item, err
}
err = UpdateAssociations(database.GetInstance(), &item)
err = utils.UpdateAssociations(database.GetInstance(), &item)
if err != nil {
return item, err
@@ -57,13 +53,15 @@ func (service *AuthorService) Update(item Author) (Author, error) {
return item, err
}
func (service *AuthorService) Delete(id uint) error {
_, err := dal.Author.Unscoped().Where(dal.Author.Id.Eq(id)).Delete()
return err
}
func (service *AuthorService) Count() (int64, error) {
amount, err := dal.Author.Count()
return amount, err
}
func (service *AuthorService) SortedByOrder(fieldsSortOrder map[string]string) ([]*Author, error) {
return utils.SortByOrder(fieldsSortOrder, Author{})
}

View File

@@ -4,6 +4,7 @@ import (
"app/internal/dal"
"app/internal/database"
"app/internal/models"
"app/internal/utils"
"errors"
"gorm.io/gen/field"
@@ -15,12 +16,12 @@ type CommentService struct {
type Comment = models.Comment
func (service *CommentService) Create(item Comment) (Comment, error) {
ReplaceEmptySlicesWithNil(&item)
utils.ReplaceEmptySlicesWithNil(&item)
err := dal.Comment.Preload(field.Associations).Create(&item)
if err != nil {
return item, err
}
err = AppendAssociations(database.GetInstance(), &item)
err = utils.AppendAssociations(database.GetInstance(), &item)
return item, err
}
@@ -43,13 +44,13 @@ func (service *CommentService) GetById(id uint) (*Comment, error) {
}
func (service *CommentService) Update(item Comment) (Comment, error) {
ReplaceEmptySlicesWithNil(&item)
utils.ReplaceEmptySlicesWithNil(&item)
err := dal.Comment.Preload(field.Associations).Save(&item)
if err != nil {
return item, err
}
err = UpdateAssociations(database.GetInstance(), &item)
err = utils.UpdateAssociations(database.GetInstance(), &item)
if err != nil {
return item, err

View File

@@ -6,6 +6,7 @@ import (
"app/internal/dialogs"
"app/internal/extras/excel"
"app/internal/models"
"app/internal/utils"
"errors"
"fmt"
@@ -17,12 +18,12 @@ type PostService struct{}
type Post = models.Post
func (service *PostService) Create(item Post) (Post, error) {
ReplaceEmptySlicesWithNil(&item)
utils.ReplaceEmptySlicesWithNil(&item)
err := dal.Post.Preload(field.Associations).Create(&item)
if err != nil {
return item, err
}
err = AppendAssociations(database.GetInstance(), &item)
err = utils.AppendAssociations(database.GetInstance(), &item)
return item, err
}
func (service *PostService) GetAll() ([]*Post, error) {
@@ -43,12 +44,12 @@ func (service *PostService) GetById(id uint) (*Post, error) {
}
func (service *PostService) Update(item Post) (Post, error) {
ReplaceEmptySlicesWithNil(&item)
utils.ReplaceEmptySlicesWithNil(&item)
err := dal.Post.Preload(field.Associations).Save(&item)
if err != nil {
return item, err
}
err = UpdateAssociations(database.GetInstance(), &item)
err = utils.UpdateAssociations(database.GetInstance(), &item)
if err != nil {
return item, err
}

View File

@@ -6,6 +6,7 @@ import (
"app/internal/dialogs"
"app/internal/extras/excel"
"app/internal/models"
"app/internal/utils"
"errors"
"gorm.io/gen/field"
"gorm.io/gorm"
@@ -17,12 +18,12 @@ type PostTypeService struct {
type PostType = models.PostType
func (service *PostTypeService) Create(item PostType) (PostType, error) {
ReplaceEmptySlicesWithNil(&item)
utils.ReplaceEmptySlicesWithNil(&item)
err := dal.PostType.Preload(field.Associations).Create(&item)
if err != nil {
return item, err
}
err = AppendAssociations(database.GetInstance(), &item)
err = utils.AppendAssociations(database.GetInstance(), &item)
return item, err
}
func (service *PostTypeService) GetAll() ([]*PostType, error) {
@@ -42,12 +43,12 @@ func (service *PostTypeService) GetById(id uint) (*PostType, error) {
return item, nil
}
func (service *PostTypeService) Update(item PostType) (PostType, error) {
ReplaceEmptySlicesWithNil(&item)
utils.ReplaceEmptySlicesWithNil(&item)
err := dal.PostType.Preload(field.Associations).Save(&item)
if err != nil {
return item, err
}
err = UpdateAssociations(database.GetInstance(), &item)
err = utils.UpdateAssociations(database.GetInstance(), &item)
if err != nil {
return item, err
}

View File

@@ -1,41 +0,0 @@
package services
import (
"errors"
"reflect"
"gorm.io/gorm"
)
func UpdateAssociations(db *gorm.DB, item interface{}) error {
// We expect a pointer to a struct so we can do db.Model(item).
val := reflect.ValueOf(item)
if val.Kind() != reflect.Ptr {
return errors.New("item must be a pointer to a struct")
}
elem := val.Elem()
if elem.Kind() != reflect.Struct {
return errors.New("item must be a pointer to a struct")
}
t := elem.Type()
for i := 0; i < elem.NumField(); i++ {
fieldVal := elem.Field(i)
fieldType := t.Field(i)
// Only process exported fields (capitalized) and slices.
if fieldType.PkgPath == "" && fieldVal.Kind() == reflect.Slice {
// For clarity, the association name is the struct field name by default.
assocName := fieldType.Name
// Replace the association with the current slice value.
// If you only want to replace on non-nil or non-empty slices, you can add extra checks here.
if err := db.Model(item).Association(assocName).Replace(fieldVal.Interface()); err != nil {
return err
}
}
}
return nil
}

View File

@@ -1,4 +1,4 @@
package services
package utils
import (
"errors"

View File

@@ -1,4 +1,4 @@
package services
package utils
import "reflect"

40
internal/utils/sorting.go Normal file
View File

@@ -0,0 +1,40 @@
package utils
import (
"app/internal/database"
"errors"
"fmt"
"reflect"
)
// SortByOrder Order items by specified field and a sort type
// Example: SortByOrder(map[string]string{"name": "ASC"}, &models.Post{})
// ASC - по возрастанию (от А до Я)
// DESC - по убыванию (от Я до А)
func SortByOrder[T any](fieldsSortOrder map[string]string, entity T) ([]*T, error) {
var (
orderQuery string
items []*T
)
for name, order := range fieldsSortOrder {
structInfo := reflect.ValueOf(entity).Type()
_, fieldExist := structInfo.FieldByName(name)
if !fieldExist {
return nil, errors.New(fmt.Sprintf("Field `%s` not found", name))
}
if order != "ASC" && order != "DESC" {
return nil, errors.New(fmt.Sprintf("Field `%s` can only be sorted by ASC or DESC", name))
}
orderQuery += fmt.Sprintf("%s %s", name, order)
}
result := database.GetInstance().Order(orderQuery).Find(&items)
if result.Error != nil {
return items, result.Error
}
return items, nil
}

View File

@@ -0,0 +1,41 @@
package utils
import (
"errors"
"reflect"
"gorm.io/gorm"
)
func UpdateAssociations(db *gorm.DB, item interface{}) error {
// We expect a pointer to a struct so we can do db.Model(item).
val := reflect.ValueOf(item)
if val.Kind() != reflect.Ptr {
return errors.New("item must be a pointer to a struct")
}
elem := val.Elem()
if elem.Kind() != reflect.Struct {
return errors.New("item must be a pointer to a struct")
}
t := elem.Type()
for i := 0; i < elem.NumField(); i++ {
fieldVal := elem.Field(i)
fieldType := t.Field(i)
// Only process exported fields (capitalized) and slices.
if fieldType.PkgPath == "" && fieldVal.Kind() == reflect.Slice {
// For clarity, the association name is the struct field name by default.
assocName := fieldType.Name
// Replace the association with the current slice value.
// If you only want to replace on non-nil or non-empty slices, you can add extra checks here.
if err := db.Model(item).Association(assocName).Replace(fieldVal.Interface()); err != nil {
return err
}
}
}
return nil
}