From e724ac4e5ad7163aab4cbce052e4ccfb2a685339 Mon Sep 17 00:00:00 2001 From: Meutel Date: Sat, 5 Aug 2017 19:40:58 +0200 Subject: [PATCH] Paginate --- assets/js/index.js | 46 +++++++++++++++++++++++++---- bouquins/bouquins.go | 68 +++++++++++++++++++++---------------------- bouquins/dbauthors.go | 36 ++++++++++++----------- bouquins/dbbooks.go | 54 +++++++++++++++++----------------- bouquins/dbseries.go | 38 ++++++++++++------------ templates/index.html | 4 +-- 6 files changed, 143 insertions(+), 103 deletions(-) diff --git a/assets/js/index.js b/assets/js/index.js index 940fc6c..bfeba0f 100644 --- a/assets/js/index.js +++ b/assets/js/index.js @@ -68,33 +68,63 @@ Vue.component('result-cell', { }); Vue.component('paginate', { template: '#paginate-template', - props: ['page'], + props: ['page','more'], methods: { prevPage: function() { + if (this.page > 1) this.$emit('prev'); }, nextPage: function() { + if (this.more) this.$emit('next'); } } }); var index = new Vue({ el: '#index', data: { + url: '', page: 0, perpage: 20, + more: false, sort_by: null, order_desc: false, cols: [], results: [] }, methods: { + updatePage: function(p) { + this.page += p; + this.updateResults(); + }, + order: function(query) { + if (this.order_desc) + return query + '&order=desc'; + return query; + }, + sort: function(query) { + if (this.sort_by) + return query + '&sort=' + this.sort_by; + return query; + }, + paginate: function(query) { + return query + '?page=' + this.page + '&perpage=' + this.perpage; + }, + params: function(url) { + return this.order(this.sort(this.paginate(url))); + }, + updateResults: function() { + this.sendQuery(this.params(this.url), this.stdError, this.loadResults); + }, showSeries: function() { - this.sendQuery('/series/', this.stdError, this.loadResults); + this.url = '/series/'; + this.updateResults(); }, showAuthors: function() { - this.sendQuery('/authors/', this.stdError, this.loadResults); + this.url = '/authors/'; + this.updateResults(); }, showBooks: function() { - this.sendQuery('/books/', this.stdError, this.loadResults); + this.url = '/books/'; + this.updateResults(); }, loadCols: function(type) { switch (type) { @@ -122,10 +152,14 @@ var index = new Vue({ }, loadResults(resp) { this.results = []; - this.page = 1; + this.more = resp.more; this.loadCols(resp.type); - if (resp.results) + if (resp.results) { this.results = resp.results; + if (this.page == 0) this.page = 1; + } else { + this.page = 0; + } }, sendQuery: function(url, error, success) { var xmh = new XMLHttpRequest(); diff --git a/bouquins/bouquins.go b/bouquins/bouquins.go index 3a95d41..a569ac9 100644 --- a/bouquins/bouquins.go +++ b/bouquins/bouquins.go @@ -21,11 +21,11 @@ const ( TPL_SERIES = "series.html" TPL_INDEX = "index.html" - PARAM_LIST = "list" - PARAM_ORDER = "order" - PARAM_SORT = "sort" - PARAM_LIMIT = "limit" - PARAM_OFFSET = "offset" + PARAM_LIST = "list" + PARAM_ORDER = "order" + PARAM_SORT = "sort" + PARAM_PAGE = "page" + PARAM_PERPAGE = "perpage" LIST_AUTHORS = "authors" LIST_SERIES = "series" @@ -161,14 +161,15 @@ func NewIndexModel(title, js string, count int64) *IndexModel { type ResultsModel struct { Type string `json:"type,omitempty"` + More bool `json:"more"` } type BooksResultsModel struct { ResultsModel Results []*BookAdv `json:"results,omitempty"` } -func NewBooksResultsModel(books []*BookAdv) *BooksResultsModel { - return &BooksResultsModel{ResultsModel{"books"}, books} +func NewBooksResultsModel(books []*BookAdv, more bool) *BooksResultsModel { + return &BooksResultsModel{ResultsModel{"books", more}, books} } type AuthorsResultsModel struct { @@ -176,8 +177,8 @@ type AuthorsResultsModel struct { Results []*AuthorAdv `json:"results,omitempty"` } -func NewAuthorsResultsModel(authors []*AuthorAdv) *AuthorsResultsModel { - return &AuthorsResultsModel{ResultsModel{"authors"}, authors} +func NewAuthorsResultsModel(authors []*AuthorAdv, more bool) *AuthorsResultsModel { + return &AuthorsResultsModel{ResultsModel{"authors", more}, authors} } type SeriesResultsModel struct { @@ -185,8 +186,8 @@ type SeriesResultsModel struct { Results []*SeriesAdv `json:"results,omitempty"` } -func NewSeriesResultsModel(series []*SeriesAdv) *SeriesResultsModel { - return &SeriesResultsModel{ResultsModel{"series"}, series} +func NewSeriesResultsModel(series []*SeriesAdv, more bool) *SeriesResultsModel { + return &SeriesResultsModel{ResultsModel{"series", more}, series} } type BookModel struct { @@ -249,6 +250,22 @@ func paramOrder(req *http.Request) string { return "" } +// return limit, offset, sort, order +func paramPaginate(req *http.Request) (int, int, string, string) { + page, perpage := paramInt(PARAM_PAGE, req), paramInt(PARAM_PERPAGE, req) + limit := perpage + if perpage == 0 { + limit = DEF_LIM + } + offset := perpage * (page - 1) + if offset < 0 { + offset = 0 + } + sort := req.URL.Query().Get(PARAM_SORT) + order := paramOrder(req) + return limit, offset, sort, order +} + // ROUTES // func (app *Bouquins) IndexPage(res http.ResponseWriter, req *http.Request) { @@ -257,23 +274,6 @@ func (app *Bouquins) IndexPage(res http.ResponseWriter, req *http.Request) { log.Print(err) } model := NewIndexModel("", "index.js", count) - /* - order, sort := paramOrder(req), req.URL.Query().Get(PARAM_SORT) - limit, offset := paramInt(PARAM_LIMIT, req), paramInt(PARAM_OFFSET, req) - switch req.URL.Query().Get(PARAM_LIST) { - case LIST_AUTHORS: - model.Authors, err = app.AuthorsAdv(limit, offset, sort, order) - case LIST_SERIES: - model.Series, err = app.SeriesAdv(limit, offset, sort, order) - case LIST_BOOKS: - fallthrough - default: - model.Books, err = app.BooksAdv(limit, offset, sort, order) - } - if err != nil { - log.Print(err) - } - */ if isJson(req) { err := writeJson(res, model) if err != nil { @@ -286,11 +286,11 @@ func (app *Bouquins) IndexPage(res http.ResponseWriter, req *http.Request) { } func (app *Bouquins) BooksListPage(res http.ResponseWriter, req *http.Request) error { if isJson(req) { - books, err := app.BooksAdv(10, 0, "", "") + books, more, err := app.BooksAdv(paramPaginate(req)) if err != nil { return err } - return writeJson(res, NewBooksResultsModel(books)) + return writeJson(res, NewBooksResultsModel(books, more)) } return errors.New("Invalid mime") } @@ -325,11 +325,11 @@ func (app *Bouquins) BooksPage(res http.ResponseWriter, req *http.Request) { } func (app *Bouquins) AuthorsListPage(res http.ResponseWriter, req *http.Request) error { if isJson(req) { - authors, err := app.AuthorsAdv(10, 0, "", "") + authors, more, err := app.AuthorsAdv(paramPaginate(req)) if err != nil { return err } - return writeJson(res, NewAuthorsResultsModel(authors)) + return writeJson(res, NewAuthorsResultsModel(authors, more)) } return errors.New("Invalid mime") } @@ -364,11 +364,11 @@ func (app *Bouquins) AuthorsPage(res http.ResponseWriter, req *http.Request) { } func (app *Bouquins) SeriesListPage(res http.ResponseWriter, req *http.Request) error { if isJson(req) { - series, err := app.SeriesAdv(10, 0, "", "") + series, more, err := app.SeriesAdv(paramPaginate(req)) if err != nil { return err } - return writeJson(res, NewSeriesResultsModel(series)) + return writeJson(res, NewSeriesResultsModel(series, more)) } return errors.New("Invalid mime") } diff --git a/bouquins/dbauthors.go b/bouquins/dbauthors.go index 2d77bf4..fb287c4 100644 --- a/bouquins/dbauthors.go +++ b/bouquins/dbauthors.go @@ -6,28 +6,33 @@ import ( // SUB QUERIES // -func (app *Bouquins) queryAuthors(limit, offset int, sort, order string) ([]*AuthorAdv, error) { +func (app *Bouquins) queryAuthors(limit, offset int, sort, order string) ([]*AuthorAdv, bool, error) { authors := make([]*AuthorAdv, 0, limit) stmt, err := app.psSortAuthors(AUTHORS, sort, order) if err != nil { - return nil, err + return nil, false, err } - rows, err := stmt.Query(limit, offset) + rows, err := stmt.Query(limit+1, offset) if err != nil { - return nil, err + return nil, false, err } defer rows.Close() + more := false for rows.Next() { - author := new(AuthorAdv) - if err := rows.Scan(&author.Id, &author.Name, &author.Count); err != nil { - return nil, err + if len(authors) == limit { + more = true + } else { + author := new(AuthorAdv) + if err := rows.Scan(&author.Id, &author.Name, &author.Count); err != nil { + return nil, false, err + } + authors = append(authors, author) } - authors = append(authors, author) } if err := rows.Err(); err != nil { - return nil, err + return nil, false, err } - return authors, nil + return authors, more, nil } func (app *Bouquins) queryAuthorBooks(author *AuthorFull) error { @@ -105,15 +110,12 @@ func (app *Bouquins) queryAuthor(id int64) (*AuthorFull, error) { // DB LOADS // -func (app *Bouquins) AuthorsAdv(limit, offset int, sort, order string) ([]*AuthorAdv, error) { - if limit == 0 { - limit = DEF_LIM - } - authors, err := app.queryAuthors(limit, offset, sort, order) +func (app *Bouquins) AuthorsAdv(limit, offset int, sort, order string) ([]*AuthorAdv, bool, error) { + authors, more, err := app.queryAuthors(limit, offset, sort, order) if err != nil { - return nil, err + return nil, false, err } - return authors, nil + return authors, more, nil } func (app *Bouquins) AuthorFull(id int64) (*AuthorFull, error) { diff --git a/bouquins/dbbooks.go b/bouquins/dbbooks.go index 134a6b8..7207af1 100644 --- a/bouquins/dbbooks.go +++ b/bouquins/dbbooks.go @@ -12,36 +12,41 @@ func assignAuthorsTagsBooks(books []*BookAdv, authors map[int64][]*Author, tags // SUB QUERIES // -func (app *Bouquins) queryBooks(limit, offset int, sort, order string) ([]*BookAdv, error) { +func (app *Bouquins) queryBooks(limit, offset int, sort, order string) ([]*BookAdv, bool, error) { books := make([]*BookAdv, 0, limit) stmt, err := app.psSortBooks(BOOKS, sort, order) if err != nil { - return nil, err + return nil, false, err } - rows, err := stmt.Query(limit, offset) + rows, err := stmt.Query(limit+1, offset) if err != nil { - return nil, err + return nil, false, err } defer rows.Close() + more := false for rows.Next() { - book := new(BookAdv) - var series_name sql.NullString - var series_id sql.NullInt64 - if err := rows.Scan(&book.Id, &book.Title, &book.SeriesIndex, &series_name, &series_id); err != nil { - return nil, err - } - if series_name.Valid && series_id.Valid { - book.Series = &Series{ - series_id.Int64, - series_name.String, + if len(books) == limit { + more = true + } else { + book := new(BookAdv) + var series_name sql.NullString + var series_id sql.NullInt64 + if err := rows.Scan(&book.Id, &book.Title, &book.SeriesIndex, &series_name, &series_id); err != nil { + return nil, false, err } + if series_name.Valid && series_id.Valid { + book.Series = &Series{ + series_id.Int64, + series_name.String, + } + } + books = append(books, book) } - books = append(books, book) } if err := rows.Err(); err != nil { - return nil, err + return nil, false, err } - return books, nil + return books, more, nil } func (app *Bouquins) queryBooksAuthors(limit, offset int, sort, order string) (map[int64][]*Author, error) { @@ -249,22 +254,19 @@ func (app *Bouquins) BookFull(id int64) (*BookFull, error) { return book, nil } -func (app *Bouquins) BooksAdv(limit, offset int, sort, order string) ([]*BookAdv, error) { - if limit == 0 { - limit = DEF_LIM - } - books, err := app.queryBooks(limit, offset, sort, order) +func (app *Bouquins) BooksAdv(limit, offset int, sort, order string) ([]*BookAdv, bool, error) { + books, more, err := app.queryBooks(limit, offset, sort, order) if err != nil { - return nil, err + return nil, false, err } authors, err := app.queryBooksAuthors(limit, offset, sort, order) if err != nil { - return nil, err + return nil, false, err } tags, err := app.queryBooksTags(limit, offset, sort, order) if err != nil { - return nil, err + return nil, false, err } assignAuthorsTagsBooks(books, authors, tags) - return books, nil + return books, more, nil } diff --git a/bouquins/dbseries.go b/bouquins/dbseries.go index 7e16201..6408f65 100644 --- a/bouquins/dbseries.go +++ b/bouquins/dbseries.go @@ -10,28 +10,33 @@ func assignAuthorsSeries(series []*SeriesAdv, authors map[int64][]*Author) { // SUB QUERIES // -func (app *Bouquins) querySeriesList(limit, offset int, sort, order string) ([]*SeriesAdv, error) { +func (app *Bouquins) querySeriesList(limit, offset int, sort, order string) ([]*SeriesAdv, bool, error) { series := make([]*SeriesAdv, 0, limit) stmt, err := app.psSortSeries(SERIES, sort, order) if err != nil { - return nil, err + return nil, false, err } - rows, err := stmt.Query(limit, offset) + rows, err := stmt.Query(limit+1, offset) if err != nil { - return nil, err + return nil, false, err } defer rows.Close() + more := false for rows.Next() { - serie := new(SeriesAdv) - if err := rows.Scan(&serie.Id, &serie.Name, &serie.Count); err != nil { - return nil, err + if len(series) == limit { + more = true + } else { + serie := new(SeriesAdv) + if err := rows.Scan(&serie.Id, &serie.Name, &serie.Count); err != nil { + return nil, false, err + } + series = append(series, serie) } - series = append(series, serie) } if err := rows.Err(); err != nil { - return nil, err + return nil, false, err } - return series, nil + return series, more, nil } func (app *Bouquins) querySeriesListAuthors(limit, offset int, sort, order string) (map[int64][]*Author, error) { authors := make(map[int64][]*Author) @@ -134,18 +139,15 @@ func (app *Bouquins) SeriesFull(id int64) (*SeriesFull, error) { return series, nil } -func (app *Bouquins) SeriesAdv(limit, offset int, sort, order string) ([]*SeriesAdv, error) { - if limit == 0 { - limit = DEF_LIM - } - series, err := app.querySeriesList(limit, offset, sort, order) +func (app *Bouquins) SeriesAdv(limit, offset int, sort, order string) ([]*SeriesAdv, bool, error) { + series, more, err := app.querySeriesList(limit, offset, sort, order) if err != nil { - return nil, err + return nil, false, err } authors, err := app.querySeriesListAuthors(limit, offset, sort, order) if err != nil { - return nil, err + return nil, false, err } assignAuthorsSeries(series, authors) - return series, nil + return series, more, nil } diff --git a/templates/index.html b/templates/index.html index aa517cd..0fa2cd8 100644 --- a/templates/index.html +++ b/templates/index.html @@ -8,7 +8,7 @@
- +
@@ -35,7 +35,7 @@