This commit is contained in:
Meutel 2017-08-05 19:40:58 +02:00
parent c8fc680331
commit e724ac4e5a
6 changed files with 143 additions and 103 deletions

View File

@ -68,33 +68,63 @@ Vue.component('result-cell', {
}); });
Vue.component('paginate', { Vue.component('paginate', {
template: '#paginate-template', template: '#paginate-template',
props: ['page'], props: ['page','more'],
methods: { methods: {
prevPage: function() { prevPage: function() {
if (this.page > 1) this.$emit('prev');
}, },
nextPage: function() { nextPage: function() {
if (this.more) this.$emit('next');
} }
} }
}); });
var index = new Vue({ var index = new Vue({
el: '#index', el: '#index',
data: { data: {
url: '',
page: 0, page: 0,
perpage: 20, perpage: 20,
more: false,
sort_by: null, sort_by: null,
order_desc: false, order_desc: false,
cols: [], cols: [],
results: [] results: []
}, },
methods: { 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() { showSeries: function() {
this.sendQuery('/series/', this.stdError, this.loadResults); this.url = '/series/';
this.updateResults();
}, },
showAuthors: function() { showAuthors: function() {
this.sendQuery('/authors/', this.stdError, this.loadResults); this.url = '/authors/';
this.updateResults();
}, },
showBooks: function() { showBooks: function() {
this.sendQuery('/books/', this.stdError, this.loadResults); this.url = '/books/';
this.updateResults();
}, },
loadCols: function(type) { loadCols: function(type) {
switch (type) { switch (type) {
@ -122,10 +152,14 @@ var index = new Vue({
}, },
loadResults(resp) { loadResults(resp) {
this.results = []; this.results = [];
this.page = 1; this.more = resp.more;
this.loadCols(resp.type); this.loadCols(resp.type);
if (resp.results) if (resp.results) {
this.results = resp.results; this.results = resp.results;
if (this.page == 0) this.page = 1;
} else {
this.page = 0;
}
}, },
sendQuery: function(url, error, success) { sendQuery: function(url, error, success) {
var xmh = new XMLHttpRequest(); var xmh = new XMLHttpRequest();

View File

@ -24,8 +24,8 @@ const (
PARAM_LIST = "list" PARAM_LIST = "list"
PARAM_ORDER = "order" PARAM_ORDER = "order"
PARAM_SORT = "sort" PARAM_SORT = "sort"
PARAM_LIMIT = "limit" PARAM_PAGE = "page"
PARAM_OFFSET = "offset" PARAM_PERPAGE = "perpage"
LIST_AUTHORS = "authors" LIST_AUTHORS = "authors"
LIST_SERIES = "series" LIST_SERIES = "series"
@ -161,14 +161,15 @@ func NewIndexModel(title, js string, count int64) *IndexModel {
type ResultsModel struct { type ResultsModel struct {
Type string `json:"type,omitempty"` Type string `json:"type,omitempty"`
More bool `json:"more"`
} }
type BooksResultsModel struct { type BooksResultsModel struct {
ResultsModel ResultsModel
Results []*BookAdv `json:"results,omitempty"` Results []*BookAdv `json:"results,omitempty"`
} }
func NewBooksResultsModel(books []*BookAdv) *BooksResultsModel { func NewBooksResultsModel(books []*BookAdv, more bool) *BooksResultsModel {
return &BooksResultsModel{ResultsModel{"books"}, books} return &BooksResultsModel{ResultsModel{"books", more}, books}
} }
type AuthorsResultsModel struct { type AuthorsResultsModel struct {
@ -176,8 +177,8 @@ type AuthorsResultsModel struct {
Results []*AuthorAdv `json:"results,omitempty"` Results []*AuthorAdv `json:"results,omitempty"`
} }
func NewAuthorsResultsModel(authors []*AuthorAdv) *AuthorsResultsModel { func NewAuthorsResultsModel(authors []*AuthorAdv, more bool) *AuthorsResultsModel {
return &AuthorsResultsModel{ResultsModel{"authors"}, authors} return &AuthorsResultsModel{ResultsModel{"authors", more}, authors}
} }
type SeriesResultsModel struct { type SeriesResultsModel struct {
@ -185,8 +186,8 @@ type SeriesResultsModel struct {
Results []*SeriesAdv `json:"results,omitempty"` Results []*SeriesAdv `json:"results,omitempty"`
} }
func NewSeriesResultsModel(series []*SeriesAdv) *SeriesResultsModel { func NewSeriesResultsModel(series []*SeriesAdv, more bool) *SeriesResultsModel {
return &SeriesResultsModel{ResultsModel{"series"}, series} return &SeriesResultsModel{ResultsModel{"series", more}, series}
} }
type BookModel struct { type BookModel struct {
@ -249,6 +250,22 @@ func paramOrder(req *http.Request) string {
return "" 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 // // ROUTES //
func (app *Bouquins) IndexPage(res http.ResponseWriter, req *http.Request) { 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) log.Print(err)
} }
model := NewIndexModel("", "index.js", count) 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) { if isJson(req) {
err := writeJson(res, model) err := writeJson(res, model)
if err != nil { 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 { func (app *Bouquins) BooksListPage(res http.ResponseWriter, req *http.Request) error {
if isJson(req) { if isJson(req) {
books, err := app.BooksAdv(10, 0, "", "") books, more, err := app.BooksAdv(paramPaginate(req))
if err != nil { if err != nil {
return err return err
} }
return writeJson(res, NewBooksResultsModel(books)) return writeJson(res, NewBooksResultsModel(books, more))
} }
return errors.New("Invalid mime") 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 { func (app *Bouquins) AuthorsListPage(res http.ResponseWriter, req *http.Request) error {
if isJson(req) { if isJson(req) {
authors, err := app.AuthorsAdv(10, 0, "", "") authors, more, err := app.AuthorsAdv(paramPaginate(req))
if err != nil { if err != nil {
return err return err
} }
return writeJson(res, NewAuthorsResultsModel(authors)) return writeJson(res, NewAuthorsResultsModel(authors, more))
} }
return errors.New("Invalid mime") 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 { func (app *Bouquins) SeriesListPage(res http.ResponseWriter, req *http.Request) error {
if isJson(req) { if isJson(req) {
series, err := app.SeriesAdv(10, 0, "", "") series, more, err := app.SeriesAdv(paramPaginate(req))
if err != nil { if err != nil {
return err return err
} }
return writeJson(res, NewSeriesResultsModel(series)) return writeJson(res, NewSeriesResultsModel(series, more))
} }
return errors.New("Invalid mime") return errors.New("Invalid mime")
} }

View File

@ -6,28 +6,33 @@ import (
// SUB QUERIES // // 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) authors := make([]*AuthorAdv, 0, limit)
stmt, err := app.psSortAuthors(AUTHORS, sort, order) stmt, err := app.psSortAuthors(AUTHORS, sort, order)
if err != nil { 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 { if err != nil {
return nil, err return nil, false, err
} }
defer rows.Close() defer rows.Close()
more := false
for rows.Next() { for rows.Next() {
if len(authors) == limit {
more = true
} else {
author := new(AuthorAdv) author := new(AuthorAdv)
if err := rows.Scan(&author.Id, &author.Name, &author.Count); err != nil { if err := rows.Scan(&author.Id, &author.Name, &author.Count); err != nil {
return nil, err return nil, false, err
} }
authors = append(authors, author) authors = append(authors, author)
} }
if err := rows.Err(); err != nil {
return nil, err
} }
return authors, nil if err := rows.Err(); err != nil {
return nil, false, err
}
return authors, more, nil
} }
func (app *Bouquins) queryAuthorBooks(author *AuthorFull) error { func (app *Bouquins) queryAuthorBooks(author *AuthorFull) error {
@ -105,15 +110,12 @@ func (app *Bouquins) queryAuthor(id int64) (*AuthorFull, error) {
// DB LOADS // // DB LOADS //
func (app *Bouquins) AuthorsAdv(limit, offset int, sort, order string) ([]*AuthorAdv, error) { func (app *Bouquins) AuthorsAdv(limit, offset int, sort, order string) ([]*AuthorAdv, bool, error) {
if limit == 0 { authors, more, err := app.queryAuthors(limit, offset, sort, order)
limit = DEF_LIM
}
authors, err := app.queryAuthors(limit, offset, sort, order)
if err != nil { 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) { func (app *Bouquins) AuthorFull(id int64) (*AuthorFull, error) {

View File

@ -12,23 +12,27 @@ func assignAuthorsTagsBooks(books []*BookAdv, authors map[int64][]*Author, tags
// SUB QUERIES // // 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) books := make([]*BookAdv, 0, limit)
stmt, err := app.psSortBooks(BOOKS, sort, order) stmt, err := app.psSortBooks(BOOKS, sort, order)
if err != nil { 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 { if err != nil {
return nil, err return nil, false, err
} }
defer rows.Close() defer rows.Close()
more := false
for rows.Next() { for rows.Next() {
if len(books) == limit {
more = true
} else {
book := new(BookAdv) book := new(BookAdv)
var series_name sql.NullString var series_name sql.NullString
var series_id sql.NullInt64 var series_id sql.NullInt64
if err := rows.Scan(&book.Id, &book.Title, &book.SeriesIndex, &series_name, &series_id); err != nil { if err := rows.Scan(&book.Id, &book.Title, &book.SeriesIndex, &series_name, &series_id); err != nil {
return nil, err return nil, false, err
} }
if series_name.Valid && series_id.Valid { if series_name.Valid && series_id.Valid {
book.Series = &Series{ book.Series = &Series{
@ -38,10 +42,11 @@ func (app *Bouquins) queryBooks(limit, offset int, sort, order string) ([]*BookA
} }
books = append(books, book) books = append(books, book)
} }
if err := rows.Err(); err != nil {
return nil, err
} }
return books, nil if err := rows.Err(); err != nil {
return nil, false, err
}
return books, more, nil
} }
func (app *Bouquins) queryBooksAuthors(limit, offset int, sort, order string) (map[int64][]*Author, error) { 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 return book, nil
} }
func (app *Bouquins) BooksAdv(limit, offset int, sort, order string) ([]*BookAdv, error) { func (app *Bouquins) BooksAdv(limit, offset int, sort, order string) ([]*BookAdv, bool, error) {
if limit == 0 { books, more, err := app.queryBooks(limit, offset, sort, order)
limit = DEF_LIM
}
books, err := app.queryBooks(limit, offset, sort, order)
if err != nil { if err != nil {
return nil, err return nil, false, err
} }
authors, err := app.queryBooksAuthors(limit, offset, sort, order) authors, err := app.queryBooksAuthors(limit, offset, sort, order)
if err != nil { if err != nil {
return nil, err return nil, false, err
} }
tags, err := app.queryBooksTags(limit, offset, sort, order) tags, err := app.queryBooksTags(limit, offset, sort, order)
if err != nil { if err != nil {
return nil, err return nil, false, err
} }
assignAuthorsTagsBooks(books, authors, tags) assignAuthorsTagsBooks(books, authors, tags)
return books, nil return books, more, nil
} }

View File

@ -10,28 +10,33 @@ func assignAuthorsSeries(series []*SeriesAdv, authors map[int64][]*Author) {
// SUB QUERIES // // 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) series := make([]*SeriesAdv, 0, limit)
stmt, err := app.psSortSeries(SERIES, sort, order) stmt, err := app.psSortSeries(SERIES, sort, order)
if err != nil { 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 { if err != nil {
return nil, err return nil, false, err
} }
defer rows.Close() defer rows.Close()
more := false
for rows.Next() { for rows.Next() {
if len(series) == limit {
more = true
} else {
serie := new(SeriesAdv) serie := new(SeriesAdv)
if err := rows.Scan(&serie.Id, &serie.Name, &serie.Count); err != nil { if err := rows.Scan(&serie.Id, &serie.Name, &serie.Count); err != nil {
return nil, err return nil, false, err
} }
series = append(series, serie) series = append(series, serie)
} }
if err := rows.Err(); err != nil {
return nil, err
} }
return series, nil if err := rows.Err(); err != nil {
return nil, false, err
}
return series, more, nil
} }
func (app *Bouquins) querySeriesListAuthors(limit, offset int, sort, order string) (map[int64][]*Author, error) { func (app *Bouquins) querySeriesListAuthors(limit, offset int, sort, order string) (map[int64][]*Author, error) {
authors := make(map[int64][]*Author) authors := make(map[int64][]*Author)
@ -134,18 +139,15 @@ func (app *Bouquins) SeriesFull(id int64) (*SeriesFull, error) {
return series, nil return series, nil
} }
func (app *Bouquins) SeriesAdv(limit, offset int, sort, order string) ([]*SeriesAdv, error) { func (app *Bouquins) SeriesAdv(limit, offset int, sort, order string) ([]*SeriesAdv, bool, error) {
if limit == 0 { series, more, err := app.querySeriesList(limit, offset, sort, order)
limit = DEF_LIM
}
series, err := app.querySeriesList(limit, offset, sort, order)
if err != nil { if err != nil {
return nil, err return nil, false, err
} }
authors, err := app.querySeriesListAuthors(limit, offset, sort, order) authors, err := app.querySeriesListAuthors(limit, offset, sort, order)
if err != nil { if err != nil {
return nil, err return nil, false, err
} }
assignAuthorsSeries(series, authors) assignAuthorsSeries(series, authors)
return series, nil return series, more, nil
} }

View File

@ -8,7 +8,7 @@
<button class="btn btn-primary" type="button" @click="showSeries">Series</button> <button class="btn btn-primary" type="button" @click="showSeries">Series</button>
</div> </div>
<div class="table-responsive"> <div class="table-responsive">
<paginate :page="page"></paginate> <paginate v-on:next="updatePage(1)" v-on:prev="updatePage(-1)" :page="page" :more="more"></paginate>
<results :results="results" :cols="cols" :sort_by="sort_by" :order_desc="order_desc"></results> <results :results="results" :cols="cols" :sort_by="sort_by" :order_desc="order_desc"></results>
<paginate :page="page"></paginate> <paginate :page="page"></paginate>
</div> </div>
@ -35,7 +35,7 @@
<nav aria-label="Pages" v-if="page > 0"> <nav aria-label="Pages" v-if="page > 0">
<ul class="pager"> <ul class="pager">
<li class="previous" v-bind:class="{ disabled: page <= 1 }"><a href="#" @click="prevPage"><span aria-hidden="true">&larr;</span> Précédents</a></li> <li class="previous" v-bind:class="{ disabled: page <= 1 }"><a href="#" @click="prevPage"><span aria-hidden="true">&larr;</span> Précédents</a></li>
<li class="next"><a href="#" @click="nextPage">Suivants <span aria-hidden="true">&rarr;</span></a></li> <li class="next" v-bind:class="{ disabled: !more }"><a href="#" @click="nextPage">Suivants <span aria-hidden="true">&rarr;</span></a></li>
</ul> </ul>
</nav> </nav>
</script> </script>