From 8924c680054e7e8bd1e9a9d3208b031c493ab0fd Mon Sep 17 00:00:00 2001 From: gogacoder Date: Sat, 15 Mar 2025 18:16:00 +0700 Subject: [PATCH] fix: sorting --- .../app/internal/services/authorservice.ts | 7 +++- .../app/internal/services/commentservice.ts | 5 ++- .../app/internal/services/postservice.ts | 5 ++- .../app/internal/services/posttypeservice.ts | 5 ++- frontend/bindings/app/internal/utils/index.ts | 4 ++ .../bindings/app/internal/utils/models.ts | 31 ++++++++++++++ frontend/src/post/post.service.ts | 3 +- go.mod | 4 +- go.sum | 7 ++-- internal/services/author.go | 4 +- internal/services/comment.go | 2 +- internal/services/post.go | 2 +- internal/services/posttype.go | 2 +- internal/utils/search.go | 41 +++++++++++++++++++ internal/utils/sorting.go | 36 ++++++++++------ 15 files changed, 129 insertions(+), 29 deletions(-) create mode 100644 frontend/bindings/app/internal/utils/index.ts create mode 100644 frontend/bindings/app/internal/utils/models.ts create mode 100644 internal/utils/search.go diff --git a/frontend/bindings/app/internal/services/authorservice.ts b/frontend/bindings/app/internal/services/authorservice.ts index 8d42285..b57fcb5 100644 --- a/frontend/bindings/app/internal/services/authorservice.ts +++ b/frontend/bindings/app/internal/services/authorservice.ts @@ -8,6 +8,9 @@ import {Call as $Call, Create as $Create} from "@wailsio/runtime"; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore: Unused imports import * as models$0 from "../models/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as utils$0 from "../utils/models.js"; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore: Unused imports @@ -50,8 +53,8 @@ export function GetById(id: number): Promise<$models.Author | null> & { cancel() return $typingPromise; } -export function SortedByOrder(fieldsSortOrder: { [_: string]: string }): Promise<($models.Author | null)[]> & { cancel(): void } { - let $resultPromise = $Call.ByID(3046628691, fieldsSortOrder) as any; +export function SortedByOrder(fieldsSortingOrder: utils$0.SortField[]): Promise<($models.Author | null)[]> & { cancel(): void } { + let $resultPromise = $Call.ByID(3046628691, fieldsSortingOrder) as any; let $typingPromise = $resultPromise.then(($result: any) => { return $$createType2($result); }) as any; diff --git a/frontend/bindings/app/internal/services/commentservice.ts b/frontend/bindings/app/internal/services/commentservice.ts index baf2caa..7106730 100644 --- a/frontend/bindings/app/internal/services/commentservice.ts +++ b/frontend/bindings/app/internal/services/commentservice.ts @@ -8,6 +8,9 @@ import {Call as $Call, Create as $Create} from "@wailsio/runtime"; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore: Unused imports import * as models$0 from "../models/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as utils$0 from "../utils/models.js"; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore: Unused imports @@ -50,7 +53,7 @@ export function GetById(id: number): Promise<$models.Comment | null> & { cancel( return $typingPromise; } -export function SortedByOrder(fieldsSortOrder: { [_: string]: string }): Promise<($models.Comment | null)[]> & { cancel(): void } { +export function SortedByOrder(fieldsSortOrder: utils$0.SortField[]): Promise<($models.Comment | null)[]> & { cancel(): void } { let $resultPromise = $Call.ByID(4244533291, fieldsSortOrder) as any; let $typingPromise = $resultPromise.then(($result: any) => { return $$createType2($result); diff --git a/frontend/bindings/app/internal/services/postservice.ts b/frontend/bindings/app/internal/services/postservice.ts index f0476d3..ddd6996 100644 --- a/frontend/bindings/app/internal/services/postservice.ts +++ b/frontend/bindings/app/internal/services/postservice.ts @@ -8,6 +8,9 @@ import {Call as $Call, Create as $Create} from "@wailsio/runtime"; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore: Unused imports import * as models$0 from "../models/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as utils$0 from "../utils/models.js"; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore: Unused imports @@ -50,7 +53,7 @@ export function GetById(id: number): Promise<$models.Post | null> & { cancel(): return $typingPromise; } -export function SortedByOrder(fieldsSortOrder: { [_: string]: string }): Promise<($models.Post | null)[]> & { cancel(): void } { +export function SortedByOrder(fieldsSortOrder: utils$0.SortField[]): Promise<($models.Post | null)[]> & { cancel(): void } { let $resultPromise = $Call.ByID(471862744, fieldsSortOrder) as any; let $typingPromise = $resultPromise.then(($result: any) => { return $$createType2($result); diff --git a/frontend/bindings/app/internal/services/posttypeservice.ts b/frontend/bindings/app/internal/services/posttypeservice.ts index 3359d22..6229103 100644 --- a/frontend/bindings/app/internal/services/posttypeservice.ts +++ b/frontend/bindings/app/internal/services/posttypeservice.ts @@ -8,6 +8,9 @@ import {Call as $Call, Create as $Create} from "@wailsio/runtime"; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore: Unused imports import * as models$0 from "../models/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as utils$0 from "../utils/models.js"; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore: Unused imports @@ -50,7 +53,7 @@ export function GetById(id: number): Promise<$models.PostType | null> & { cancel return $typingPromise; } -export function SortedByOrder(fieldsSortOrder: { [_: string]: string }): Promise<($models.PostType | null)[]> & { cancel(): void } { +export function SortedByOrder(fieldsSortOrder: utils$0.SortField[]): Promise<($models.PostType | null)[]> & { cancel(): void } { let $resultPromise = $Call.ByID(1097313920, fieldsSortOrder) as any; let $typingPromise = $resultPromise.then(($result: any) => { return $$createType2($result); diff --git a/frontend/bindings/app/internal/utils/index.ts b/frontend/bindings/app/internal/utils/index.ts new file mode 100644 index 0000000..c9d993a --- /dev/null +++ b/frontend/bindings/app/internal/utils/index.ts @@ -0,0 +1,4 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +export * from "./models.js"; diff --git a/frontend/bindings/app/internal/utils/models.ts b/frontend/bindings/app/internal/utils/models.ts new file mode 100644 index 0000000..612c8a4 --- /dev/null +++ b/frontend/bindings/app/internal/utils/models.ts @@ -0,0 +1,31 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import {Create as $Create} from "@wailsio/runtime"; + +export class SortField { + "Name": string; + "Order": string; + + /** Creates a new SortField instance. */ + constructor($$source: Partial = {}) { + if (!("Name" in $$source)) { + this["Name"] = ""; + } + if (!("Order" in $$source)) { + this["Order"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new SortField instance from a string or object. + */ + static createFrom($$source: any = {}): SortField { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new SortField($$parsedSource as Partial); + } +} diff --git a/frontend/src/post/post.service.ts b/frontend/src/post/post.service.ts index dbc73ee..53abf9f 100644 --- a/frontend/src/post/post.service.ts +++ b/frontend/src/post/post.service.ts @@ -9,6 +9,7 @@ import { import type { Post } from "../../bindings/app/internal/services"; import type { IService } from "../types/service.type.ts"; import type {SortOptions} from "../types/sort-options.type.ts"; +import {SortField} from "../../bindings/app/internal/utils"; export default class PostService implements IService { async read(id: number) { @@ -36,6 +37,6 @@ export default class PostService implements IService { } async sort(options: SortOptions) { - return await SortedByOrder(options) as Post[] + return await SortedByOrder(Object.entries(options).map(item => ({Name: item[0], Order: item[1]}))) as Post[] } } diff --git a/go.mod b/go.mod index 0ff30aa..68231e9 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/wailsapp/wails/v3 v3.0.0-alpha.9 github.com/xuri/excelize/v2 v2.9.0 golang.org/x/text v0.23.0 - gorm.io/driver/sqlite v1.5.0 + gorm.io/driver/sqlite v1.5.7 gorm.io/gen v0.3.26 gorm.io/gorm v1.25.12 gorm.io/plugin/dbresolver v1.5.3 @@ -46,7 +46,7 @@ require ( github.com/lmittmann/tint v1.0.4 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-sqlite3 v1.14.22 // indirect + github.com/mattn/go-sqlite3 v1.14.24 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/ncruces/julianday v1.0.0 // indirect github.com/pjbgf/sha1cd v0.3.0 // indirect diff --git a/go.sum b/go.sum index b30de7a..ca2a9d4 100644 --- a/go.sum +++ b/go.sum @@ -99,8 +99,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= -github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= -github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM= +github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/microsoft/go-mssqldb v1.7.2 h1:CHkFJiObW7ItKTJfHo1QX7QBBD1iV+mn1eOyRP3b/PA= github.com/microsoft/go-mssqldb v1.7.2/go.mod h1:kOvZKUdrhhFQmxLZqbwUV0rHkNkZpthMITIb2Ko1IoA= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= @@ -251,8 +251,9 @@ gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo= gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM= gorm.io/driver/postgres v1.5.0 h1:u2FXTy14l45qc3UeCJ7QaAXZmZfDDv0YrthvmRq1l0U= gorm.io/driver/postgres v1.5.0/go.mod h1:FUZXzO+5Uqg5zzwzv4KK49R8lvGIyscBOqYrtI1Ce9A= -gorm.io/driver/sqlite v1.5.0 h1:zKYbzRCpBrT1bNijRnxLDJWPjVfImGEn0lSnUY5gZ+c= gorm.io/driver/sqlite v1.5.0/go.mod h1:kDMDfntV9u/vuMmz8APHtHF0b4nyBB7sfCieC6G8k8I= +gorm.io/driver/sqlite v1.5.7 h1:8NvsrhP0ifM7LX9G4zPB97NwovUakUxc+2V2uuf3Z1I= +gorm.io/driver/sqlite v1.5.7/go.mod h1:U+J8craQU6Fzkcvu8oLeAQmi50TkwPEhHDEjQZXDah4= gorm.io/driver/sqlserver v1.5.4 h1:xA+Y1KDNspv79q43bPyjDMUgHoYHLhXYmdFcYPobg8g= gorm.io/driver/sqlserver v1.5.4/go.mod h1:+frZ/qYmuna11zHPlh5oc2O6ZA/lS88Keb0XSH1Zh/g= gorm.io/gen v0.3.26 h1:sFf1j7vNStimPRRAtH4zz5NiHM+1dr6eA9aaRdplyhY= diff --git a/internal/services/author.go b/internal/services/author.go index 8d37a0b..ad65f01 100644 --- a/internal/services/author.go +++ b/internal/services/author.go @@ -61,6 +61,6 @@ 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{}) +func (service *AuthorService) SortedByOrder(fieldsSortingOrder []utils.SortField) ([]*Author, error) { + return utils.SortByOrder(fieldsSortingOrder, Author{}) } diff --git a/internal/services/comment.go b/internal/services/comment.go index 09b867a..881c525 100644 --- a/internal/services/comment.go +++ b/internal/services/comment.go @@ -61,6 +61,6 @@ func (service *CommentService) Count() (int64, error) { amount, err := dal.Comment.Count() return amount, err } -func (service *CommentService) SortedByOrder(fieldsSortOrder map[string]string) ([]*Comment, error) { +func (service *CommentService) SortedByOrder(fieldsSortOrder []utils.SortField) ([]*Comment, error) { return utils.SortByOrder(fieldsSortOrder, Comment{}) } diff --git a/internal/services/post.go b/internal/services/post.go index 525ae55..0fd154f 100644 --- a/internal/services/post.go +++ b/internal/services/post.go @@ -61,6 +61,6 @@ func (service *PostService) Count() (int64, error) { return amount, err } -func (service *PostService) SortedByOrder(fieldsSortOrder map[string]string) ([]*Post, error) { +func (service *PostService) SortedByOrder(fieldsSortOrder []utils.SortField) ([]*Post, error) { return utils.SortByOrder(fieldsSortOrder, Post{}) } diff --git a/internal/services/posttype.go b/internal/services/posttype.go index 5d1cf0b..fd082e1 100644 --- a/internal/services/posttype.go +++ b/internal/services/posttype.go @@ -60,6 +60,6 @@ func (service *PostTypeService) Count() (int64, error) { return amount, err } -func (service *PostTypeService) SortedByOrder(fieldsSortOrder map[string]string) ([]*PostType, error) { +func (service *PostTypeService) SortedByOrder(fieldsSortOrder []utils.SortField) ([]*PostType, error) { return utils.SortByOrder(fieldsSortOrder, PostType{}) } diff --git a/internal/utils/search.go b/internal/utils/search.go new file mode 100644 index 0000000..a340cf2 --- /dev/null +++ b/internal/utils/search.go @@ -0,0 +1,41 @@ +package utils + +import ( + "app/internal/database" + "fmt" + "github.com/kuzgoga/fogg" + "gorm.io/gorm/clause" + "reflect" +) + +func FindPhraseByAllFields[T any](phrase string, entity T) ([]*T, error) { + db := database.GetInstance().Preload(clause.Associations) + structType := reflect.TypeOf(entity) + + for i := 0; i < structType.NumField(); i++ { + field := structType.Field(i) + + tag, err := fogg.Parse(string(field.Tag)) + if err != nil { + return nil, fmt.Errorf("ошибка при разборе тэга '%s': %w", field.Name, err) + } + + if field.Type.Kind() == reflect.Pointer { + field.Type = field.Type.Elem() + } + + if field.Type.Kind() == reflect.String { + db.Where(fmt.Sprintf("`%s` like ?", field.Name), "%"+phrase+"%") + } else { + if tag.HasTag("ui") { + uiTag := tag.GetTag("ui") + nestedFieldPath := uiTag.GetParamOr("field", "") + if nestedFieldPath != "" { + db.Preload(fmt.Sprintf("%s.%s", field.Name, nestedFieldPath)) + } + } + } + + } + return nil, nil +} diff --git a/internal/utils/sorting.go b/internal/utils/sorting.go index 4a8dd93..de975ac 100644 --- a/internal/utils/sorting.go +++ b/internal/utils/sorting.go @@ -14,6 +14,11 @@ import ( import "gorm.io/gorm" +type SortField struct { + Name string + Order string +} + func GetTableName(model any, db *gorm.DB) (string, error) { stmt := &gorm.Statement{DB: db} if err := stmt.Parse(model); err != nil { @@ -38,36 +43,36 @@ func GetColumnName(model any, fieldName string, db *gorm.DB) (string, error) { var p = message.NewPrinter(language.Russian) -func SortByOrder[T any](fieldsSortOrder map[string]string, entity T) ([]*T, error) { +func SortByOrder[T any](fieldsSortingOrder []SortField, entity T) ([]*T, error) { var ( orderQuery []string items []*T joins []string ) - for name, order := range fieldsSortOrder { + for _, item := range fieldsSortingOrder { structInfo := reflect.ValueOf(entity).Type() - field, fieldExist := structInfo.FieldByName(name) + field, fieldExist := structInfo.FieldByName(item.Name) if !fieldExist { - return nil, errors.New(p.Sprintf("Field %s not found", name)) + return nil, errors.New(p.Sprintf("Field %s not found", item.Name)) } - if strings.ToUpper(order) != "ASC" && strings.ToUpper(order) != "DESC" { - return nil, errors.New(p.Sprintf("Field `%s` can only be sorted by ASC or DESC", name)) + if strings.ToUpper(item.Order) != "ASC" && strings.ToUpper(item.Order) != "DESC" { + return nil, errors.New(p.Sprintf("Field `%s` can only be sorted by ASC or DESC", item.Name)) } tag, err := fogg.Parse(string(field.Tag)) if err != nil { - return nil, errors.New(p.Sprintf("Failed to parse tag for `%s` failed: %s", name, err)) + return nil, errors.New(p.Sprintf("Failed to parse tag for `%s` failed: %s", item.Name, err)) } if !tag.HasTag("ui") { - return nil, errors.New(p.Sprintf("Field `%s` doesn't have ui tag", name)) + return nil, errors.New(p.Sprintf("Field `%s` doesn't have ui tag", item.Name)) } if field.Type.Kind() == reflect.Slice { - return nil, errors.New(p.Sprintf("Field `%s` is array and cannot be used for sorting", name)) + return nil, errors.New(p.Sprintf("Field `%s` is array and cannot be used for sorting", item.Name)) } fieldPath := tag.GetTag("ui").GetParamOr("field", "") @@ -80,23 +85,23 @@ func SortByOrder[T any](fieldsSortOrder map[string]string, entity T) ([]*T, erro if err != nil { return nil, errors.New(p.Sprintf("Failed to get column name: %s", err)) } - orderQuery = append(orderQuery, fmt.Sprintf("%s.%s %s", tableName, columnName, order)) + orderQuery = append(orderQuery, fmt.Sprintf("%s.%s %s", tableName, columnName, item.Order)) } else { fieldsPathParts := strings.Split(fieldPath, ".") if len(fieldsPathParts) > 1 { - return nil, errors.New(p.Sprintf("Too complex fieldPath for structure `%s`", name)) + return nil, errors.New(p.Sprintf("Too complex fieldPath for structure `%s`", item.Name)) } if len(fieldsPathParts) == 0 { - return nil, errors.New(p.Sprintf("Invalid field path for `%s` field", name)) + return nil, errors.New(p.Sprintf("Invalid field path for `%s` field", item.Name)) } joinPathParts := append([]string{field.Type.Name()}, fieldsPathParts...) joinField := strings.Join(joinPathParts, ".") joinTable := field.Type.Name() joins = append(joins, joinTable) - orderQuery = append(orderQuery, fmt.Sprintf("%s %s", joinField, order)) + orderQuery = append(orderQuery, fmt.Sprintf("%s %s", joinField, item.Order)) } } @@ -111,6 +116,11 @@ func SortByOrder[T any](fieldsSortOrder map[string]string, entity T) ([]*T, erro } result := db.Preload(clause.Associations).Find(&items) + fmt.Printf("Sort order: %#v\n", fieldsSortingOrder) + fmt.Printf("Result items: \n") + for _, item := range items { + fmt.Printf("%#v\n", *item) + } if result.Error != nil { return items, result.Error