diff --git a/api/internal/domain/chapter.go b/api/internal/domain/chapter.go index 945e5d0..c534b4f 100644 --- a/api/internal/domain/chapter.go +++ b/api/internal/domain/chapter.go @@ -4,14 +4,14 @@ import "cloud.google.com/go/firestore" type CursorOptions struct { NovelID string `json:"novel_id"` - Cursor string `json:"cursor"` + Cursor int `json:"cursor"` Limit int `json:"limit"` SortBy firestore.Direction `json:"sort_by"` } type CursorResponse struct { - Chapters []Chapter `json:"chapters"` - NextCursor string `json:"next_cursor"` + Chapters []FrontendChapter `json:"chapters"` + NextCursor int `json:"next_cursor"` } // Chapter struct used on backend @@ -29,11 +29,8 @@ type Chapter struct { // Chapter struct used on frontend type FrontendChapter struct { - ID string `json:"id"` - Title string `json:"title"` - Author string `json:"author"` - Description string `json:"description"` - CreatedAt string `json:"creation_date"` - UpdatedAt string `json:"update_date"` - Content string `json:"content"` + ID string `json:"id"` + Title string `json:"title"` + UpdatedAt string `json:"update_date"` + Content string `json:"content"` } diff --git a/api/internal/infrastructure/collections/chapters.go b/api/internal/infrastructure/collections/chapters.go index b500a15..84af87f 100644 --- a/api/internal/infrastructure/collections/chapters.go +++ b/api/internal/infrastructure/collections/chapters.go @@ -7,23 +7,23 @@ import ( "errors" "fmt" "net/http" - "sort" "time" "cloud.google.com/go/firestore" - "github.com/fvbommel/sortorder" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) func (c *Client) CursorPagination(options domain.CursorOptions, ctx context.Context) (*domain.CursorResponse, error) { coll := c.Client.Collection("novels").Doc(options.NovelID).Collection("chapters") - query := coll.OrderBy(firestore.DocumentID, options.SortBy) + query := coll.OrderBy("Index", options.SortBy) limit := min(max(options.Limit, 1), 100) - if options.Cursor == "" { - snaps, err := query.Limit(limit + 1).Documents(ctx).GetAll() + snapshots := []*firestore.DocumentSnapshot{} + + if options.Cursor == 0 { + snaps, err := query.Limit(1).Documents(ctx).GetAll() if err != nil { return nil, err } @@ -35,17 +35,16 @@ func (c *Client) CursorPagination(options domain.CursorOptions, ctx context.Cont } } - options.Cursor = snaps[0].Ref.ID - } - - chapter, err := c.GetChapterById(options.NovelID, options.Cursor, ctx) - if err != nil { - return nil, err - } - - snapshots, err := query.StartAt(chapter.ID).Limit(limit + 1).Documents(ctx).GetAll() - if err != nil { - return nil, err + snapshots, err = query.StartAt(snaps[0]).Limit(limit + 1).Documents(ctx).GetAll() + if err != nil { + return nil, err + } + } else { + var err error + snapshots, err = query.StartAt(options.Cursor).Limit(limit + 1).Documents(ctx).GetAll() + if err != nil { + return nil, err + } } if len(snapshots) == 0 { @@ -55,10 +54,13 @@ func (c *Client) CursorPagination(options domain.CursorOptions, ctx context.Cont } } - chapters := make([]domain.Chapter, 0, limit) - nextCursor := "" + nextCursor := 0 if len(snapshots) > limit { - nextCursor = snapshots[len(snapshots)-1].Ref.ID + var chapter domain.Chapter + if err := snapshots[len(snapshots)-1].DataTo(&chapter); err != nil { + return nil, err + } + nextCursor = chapter.Index } snapLen := len(snapshots) - 1 @@ -66,26 +68,24 @@ func (c *Client) CursorPagination(options domain.CursorOptions, ctx context.Cont snapLen++ } + chapters := []domain.FrontendChapter{} for _, snapshot := range snapshots[:snapLen] { var chapter domain.Chapter if err := snapshot.DataTo(&chapter); err != nil { return nil, err } - chapters = append(chapters, chapter) + chapters = append(chapters, domain.FrontendChapter{ + ID: chapter.ID, + Title: chapter.Title, + UpdatedAt: chapter.UpdatedAt, + Content: chapter.Content, + }) } - sort.Slice(chapters, func(i, j int) bool { - if options.SortBy == firestore.Asc { - return sortorder.NaturalLess(chapters[i].Title, chapters[j].Title) - } else { - return sortorder.NaturalLess(chapters[j].Title, chapters[i].Title) - } - }) - return &domain.CursorResponse{ Chapters: chapters, NextCursor: nextCursor, - }, err + }, nil } func (c *Client) BatchUploadChapters(novelId string, chapters []domain.Chapter, ctx context.Context) error { diff --git a/api/internal/interfaces/rest/handlers/chapters.go b/api/internal/interfaces/rest/handlers/chapters.go index ba15397..23b7902 100644 --- a/api/internal/interfaces/rest/handlers/chapters.go +++ b/api/internal/interfaces/rest/handlers/chapters.go @@ -6,7 +6,6 @@ import ( firestore_services "Codex-Backend/api/internal/usecases/collections" "net/http" "strconv" - "strings" "cloud.google.com/go/firestore" "github.com/gin-gonic/gin" @@ -26,20 +25,16 @@ func GetPaginatedChapters(c *gin.Context) { options := domain.CursorOptions{ NovelID: novelId, - Cursor: "", + Cursor: 0, Limit: 100, SortBy: firestore.Desc, } if cursor, exists := c.GetQuery("cursor"); exists { - split := strings.Split(cursor, "_") - if len(split) != 2 || split[0] != "chapter" { - c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{ - "error": "Invalid cursor format", - }) - return + curs, err := strconv.Atoi(cursor) + if err == nil { + options.Cursor = curs } - options.Cursor = cursor } if limit, exists := c.GetQuery("limit"); exists { diff --git a/go.mod b/go.mod index f7d8abf..342ed5a 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,6 @@ require ( firebase.google.com/go v3.13.0+incompatible github.com/JohannesKaufmann/html-to-markdown/v2 v2.3.3 github.com/PuerkitoBio/goquery v1.10.3 - github.com/fvbommel/sortorder v1.1.0 github.com/gin-contrib/cors v1.7.3 github.com/gin-gonic/gin v1.10.0 github.com/golang-jwt/jwt/v5 v5.2.2 diff --git a/go.sum b/go.sum index ec1d49c..68ac9e0 100644 --- a/go.sum +++ b/go.sum @@ -37,8 +37,6 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/fvbommel/sortorder v1.1.0 h1:fUmoe+HLsBTctBDoaBwpQo5N+nrCp8g/BjKb/6ZQmYw= -github.com/fvbommel/sortorder v1.1.0/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8= github.com/gin-contrib/cors v1.7.3 h1:hV+a5xp8hwJoTw7OY+a70FsL8JkVVFTXw9EcfrYUdns=