Factorize go

This commit is contained in:
Meutel 2017-08-06 18:49:40 +02:00
parent 606afb279d
commit e9257fe6a7
6 changed files with 137 additions and 193 deletions

View File

@ -219,12 +219,9 @@ type ReqParams struct {
AllWords bool
}
func (app *Bouquins) render(res http.ResponseWriter, tpl string, model interface{}) error {
return app.Template.ExecuteTemplate(res, tpl, model)
}
// add functions to templates
func TemplatesFunc() *template.Template {
tpl := template.New("")
tpl.Funcs(template.FuncMap{
return template.New("").Funcs(template.FuncMap{
"humanSize": func(sz int64) string {
return datasize.ByteSize(sz).HumanReadable()
},
@ -236,17 +233,26 @@ func TemplatesFunc() *template.Template {
return "/calibre/" + url.PathEscape(book.Path) + "/" + url.PathEscape(data.Name) + "." + strings.ToLower(data.Format)
},
})
return tpl
}
// output page with template
func (app *Bouquins) render(res http.ResponseWriter, tpl string, model interface{}) error {
return app.Template.ExecuteTemplate(res, tpl, model)
}
// output as JSON
func writeJson(res http.ResponseWriter, model interface{}) error {
res.Header().Set("Content-Type", "application/json")
enc := json.NewEncoder(res)
return enc.Encode(model)
}
// test if JSON requested
func isJson(req *http.Request) bool {
return req.Header.Get("Accept") == "application/json"
}
// get integer parameter
func paramInt(name string, req *http.Request) int {
val := req.URL.Query().Get(name)
if val == "" {
@ -259,6 +265,8 @@ func paramInt(name string, req *http.Request) int {
}
return valInt
}
// get order parameter
func paramOrder(req *http.Request) string {
val := req.URL.Query().Get(PARAM_ORDER)
if val == "desc" || val == "asc" {
@ -267,6 +275,7 @@ func paramOrder(req *http.Request) string {
return ""
}
// get common request parameters
func params(req *http.Request) *ReqParams {
page, perpage := paramInt(PARAM_PAGE, req), paramInt(PARAM_PERPAGE, req)
limit := perpage
@ -283,27 +292,22 @@ func params(req *http.Request) *ReqParams {
return &ReqParams{limit, offset, sort, order, terms, false}
}
// ROUTES //
func (app *Bouquins) IndexPage(res http.ResponseWriter, req *http.Request) {
count, err := app.BookCount()
if err != nil {
log.Print(err)
}
model := NewIndexModel("", count)
if isJson(req) {
err := writeJson(res, model)
if err != nil {
log.Println(err)
http.Error(res, err.Error(), 500)
}
} else {
err = app.render(res, TPL_INDEX, model)
if err != nil {
log.Println(err)
// single element or list elements page
func listOrId(res http.ResponseWriter, req *http.Request, url string,
listFunc func(res http.ResponseWriter, req *http.Request) error,
idFunc func(idParam string, res http.ResponseWriter, req *http.Request) error) error {
if !strings.HasPrefix(req.URL.Path, url) {
return errors.New("Invalid URL") // FIXME 404
}
idParam := req.URL.Path[len(url):]
if len(idParam) == 0 {
return listFunc(res, req)
}
return idFunc(idParam, res, req)
}
// LIST ELEMENTS PAGES //
func (app *Bouquins) BooksListPage(res http.ResponseWriter, req *http.Request) error {
if isJson(req) {
books, count, more, err := app.BooksAdv(params(req))
@ -314,35 +318,6 @@ func (app *Bouquins) BooksListPage(res http.ResponseWriter, req *http.Request) e
}
return errors.New("Invalid mime")
}
func (app *Bouquins) BookPage(idParam string, res http.ResponseWriter, req *http.Request) error {
id, err := strconv.Atoi(idParam)
if err != nil {
return nil
}
book, err := app.BookFull(int64(id))
if err != nil {
return nil
}
return app.render(res, TPL_BOOKS, &BookModel{*NewBouquinsModel(book.Title, "book"), book})
}
func (app *Bouquins) BooksPage(res http.ResponseWriter, req *http.Request) {
var err error
var idParam = ""
if strings.HasPrefix(req.URL.Path, URL_BOOKS) {
idParam = req.URL.Path[len(URL_BOOKS):]
} else {
err = errors.New("Invalid URL") // FIXME 404
}
if len(idParam) == 0 {
err = app.BooksListPage(res, req)
} else {
err = app.BookPage(idParam, res, req)
}
if err != nil {
log.Println(err)
http.Error(res, err.Error(), 500)
}
}
func (app *Bouquins) AuthorsListPage(res http.ResponseWriter, req *http.Request) error {
if isJson(req) {
authors, count, more, err := app.AuthorsAdv(params(req))
@ -353,6 +328,30 @@ func (app *Bouquins) AuthorsListPage(res http.ResponseWriter, req *http.Request)
}
return errors.New("Invalid mime")
}
func (app *Bouquins) SeriesListPage(res http.ResponseWriter, req *http.Request) error {
if isJson(req) {
series, count, more, err := app.SeriesAdv(params(req))
if err != nil {
return err
}
return writeJson(res, NewSeriesResultsModel(series, more, count))
}
return errors.New("Invalid mime")
}
// SINGLE ELEMENT PAGES //
func (app *Bouquins) BookPage(idParam string, res http.ResponseWriter, req *http.Request) error {
id, err := strconv.Atoi(idParam)
if err != nil {
return err
}
book, err := app.BookFull(int64(id))
if err != nil {
return err
}
return app.render(res, TPL_BOOKS, &BookModel{*NewBouquinsModel(book.Title, "book"), book})
}
func (app *Bouquins) AuthorPage(idParam string, res http.ResponseWriter, req *http.Request) error {
id, err := strconv.Atoi(idParam)
if err != nil {
@ -364,34 +363,6 @@ func (app *Bouquins) AuthorPage(idParam string, res http.ResponseWriter, req *ht
}
return app.render(res, TPL_AUTHORS, &AuthorModel{*NewBouquinsModel(author.Name, "author"), author})
}
func (app *Bouquins) AuthorsPage(res http.ResponseWriter, req *http.Request) {
var err error
var idParam = ""
if strings.HasPrefix(req.URL.Path, URL_AUTHORS) {
idParam = req.URL.Path[len(URL_AUTHORS):]
} else {
err = errors.New("Invalid URL") // FIXME 404
}
if len(idParam) == 0 {
err = app.AuthorsListPage(res, req)
} else {
err = app.AuthorPage(idParam, res, req)
}
if err != nil {
log.Println(err)
http.Error(res, err.Error(), 500)
}
}
func (app *Bouquins) SeriesListPage(res http.ResponseWriter, req *http.Request) error {
if isJson(req) {
series, count, more, err := app.SeriesAdv(params(req))
if err != nil {
return err
}
return writeJson(res, NewSeriesResultsModel(series, more, count))
}
return errors.New("Invalid mime")
}
func (app *Bouquins) SeriePage(idParam string, res http.ResponseWriter, req *http.Request) error {
id, err := strconv.Atoi(idParam)
if err != nil {
@ -403,34 +374,32 @@ func (app *Bouquins) SeriePage(idParam string, res http.ResponseWriter, req *htt
}
return app.render(res, TPL_SERIES, &SeriesModel{*NewBouquinsModel(series.Name, "series"), series})
}
func (app *Bouquins) SeriesPage(res http.ResponseWriter, req *http.Request) {
var err error
var idParam = ""
if strings.HasPrefix(req.URL.Path, URL_SERIES) {
idParam = req.URL.Path[len(URL_SERIES):]
} else {
err = errors.New("Invalid URL") // FIXME 404
}
if len(idParam) == 0 {
err = app.SeriesListPage(res, req)
} else {
err = app.SeriePage(idParam, res, req)
}
if err != nil {
log.Println(err)
http.Error(res, err.Error(), 500)
}
// ROUTES //
func (app *Bouquins) BooksPage(res http.ResponseWriter, req *http.Request) error {
return listOrId(res, req, URL_BOOKS, app.BooksListPage, app.BookPage)
}
func (app *Bouquins) SearchPage(res http.ResponseWriter, req *http.Request) {
model := NewSearchModel()
err := app.render(res, TPL_SEARCH, model)
if err != nil {
log.Println(err)
}
func (app *Bouquins) AuthorsPage(res http.ResponseWriter, req *http.Request) error {
return listOrId(res, req, URL_AUTHORS, app.AuthorsListPage, app.AuthorPage)
}
func (app *Bouquins) AboutPage(res http.ResponseWriter, req *http.Request) {
err := app.render(res, TPL_ABOUT, NewBouquinsModel("A propos", "about"))
if err != nil {
log.Println(err)
}
func (app *Bouquins) SeriesPage(res http.ResponseWriter, req *http.Request) error {
return listOrId(res, req, URL_SERIES, app.SeriesListPage, app.SeriePage)
}
func (app *Bouquins) SearchPage(res http.ResponseWriter, req *http.Request) error {
return app.render(res, TPL_SEARCH, NewSearchModel())
}
func (app *Bouquins) AboutPage(res http.ResponseWriter, req *http.Request) error {
return app.render(res, TPL_ABOUT, NewBouquinsModel("A propos", "about"))
}
func (app *Bouquins) IndexPage(res http.ResponseWriter, req *http.Request) error {
count, err := app.BookCount()
if err != nil {
return err
}
model := NewIndexModel("", count)
if isJson(req) {
return writeJson(res, model)
}
return app.render(res, TPL_INDEX, model)
}

View File

@ -172,6 +172,33 @@ type Query struct {
Desc bool
}
func (app *Bouquins) searchHelper(all bool, terms []string, stub, termExpr, orderExpr string) (*sql.Rows, error) {
query := stub
queryTerms := make([]interface{}, 0, len(terms))
for i, term := range terms {
queryTerms = append(queryTerms, "%"+term+"%")
query += termExpr
if i < len(terms)-1 && all {
query += STMT_BOOL_AND
}
if i < len(terms)-1 && !all {
query += STMT_BOOL_OR
}
}
query += orderExpr
log.Println("Search:", query)
stmt, err := app.DB.Prepare(query)
if err != nil {
return nil, err
}
rows, err := stmt.Query(queryTerms...)
if err != nil {
return nil, err
}
return rows, nil
}
// PREPARED STATEMENTS //
func (app *Bouquins) PrepareAll() error {
errcount := 0
@ -217,5 +244,5 @@ func (app *Bouquins) psSort(sortNameField string, qt QueryType, sort, order stri
// prepared statement without sort
func (app *Bouquins) ps(qt QueryType) (*sql.Stmt, error) {
return app.psSortBooks(qt, "", "")
return app.psSort("any", qt, "", "")
}

View File

@ -2,37 +2,17 @@ package bouquins
import (
"database/sql"
"log"
)
// SUB QUERIES //
func (app *Bouquins) searchAuthors(limit int, terms []string, all bool) ([]*AuthorAdv, int, error) {
rows, err := app.searchHelper(all, terms, STMT_AUTHORS_SEARCH, STMT_SEARCH_TERM_AUTHOR, STMT_SEARCH_ORDER_AUTHORS)
if err != nil {
return nil, 0, err
}
authors := make([]*AuthorAdv, 0, limit)
count := 0
query := STMT_AUTHORS_SEARCH
queryTerms := make([]interface{}, 0, len(terms))
for i, term := range terms {
queryTerms = append(queryTerms, "%"+term+"%")
query += STMT_SEARCH_TERM_AUTHOR
if i < len(terms)-1 && all {
query += STMT_BOOL_AND
}
if i < len(terms)-1 && !all {
query += STMT_BOOL_OR
}
}
query += STMT_SEARCH_ORDER_AUTHORS
log.Println("Search:", query)
stmt, err := app.DB.Prepare(query)
if err != nil {
return nil, 0, err
}
rows, err := stmt.Query(queryTerms...)
if err != nil {
return nil, 0, err
}
defer rows.Close()
for rows.Next() {
if len(authors) <= limit {

View File

@ -2,7 +2,6 @@ package bouquins
import (
"database/sql"
"log"
)
// MERGE SUB QUERIES //
@ -16,34 +15,13 @@ func assignAuthorsTagsBooks(books []*BookAdv, authors map[int64][]*Author, tags
// SUB QUERIES //
func (app *Bouquins) searchBooks(limit int, terms []string, all bool) ([]*BookAdv, int, error) {
books := make([]*BookAdv, 0, limit)
// FIXME factorize searchAuthors,searchSeries
count := 0
query := STMT_BOOKS0 + STMT_WHERE
queryTerms := make([]interface{}, 0, len(terms))
for i, term := range terms {
queryTerms = append(queryTerms, "%"+term+"%")
query += STMT_SEARCH_TERM_BOOKS
if i < len(terms)-1 && all {
query += STMT_BOOL_AND
}
if i < len(terms)-1 && !all {
query += STMT_BOOL_OR
}
}
query += STMT_SEARCH_ORDER_BOOKS
log.Println("Search:", query)
stmt, err := app.DB.Prepare(query)
if err != nil {
return nil, 0, err
}
rows, err := stmt.Query(queryTerms...)
rows, err := app.searchHelper(all, terms, STMT_BOOKS0+STMT_WHERE, STMT_SEARCH_TERM_BOOKS, STMT_SEARCH_ORDER_BOOKS)
if err != nil {
return nil, 0, err
}
defer rows.Close()
// FIXME factorize queryBooks
books := make([]*BookAdv, 0, limit)
count := 0
for rows.Next() {
if len(books) <= limit {
book := new(BookAdv)

View File

@ -1,7 +1,5 @@
package bouquins
import "log"
// MERGE SUB QUERIES //
func assignAuthorsSeries(series []*SeriesAdv, authors map[int64][]*Author) {
@ -13,32 +11,13 @@ func assignAuthorsSeries(series []*SeriesAdv, authors map[int64][]*Author) {
// SUB QUERIES //
func (app *Bouquins) searchSeries(limit int, terms []string, all bool) ([]*SeriesAdv, int, error) {
series := make([]*SeriesAdv, 0, limit)
count := 0
query := STMT_SERIES_SEARCH
queryTerms := make([]interface{}, 0, len(terms))
for i, term := range terms {
queryTerms = append(queryTerms, "%"+term+"%")
query += STMT_SEARCH_TERM_SERIES
if i < len(terms)-1 && all {
query += STMT_BOOL_AND
}
if i < len(terms)-1 && !all {
query += STMT_BOOL_OR
}
}
query += STMT_SEARCH_ORDER_SERIES
log.Println("Search:", query)
stmt, err := app.DB.Prepare(query)
if err != nil {
return nil, 0, err
}
rows, err := stmt.Query(queryTerms...)
rows, err := app.searchHelper(all, terms, STMT_SERIES_SEARCH, STMT_SEARCH_TERM_SERIES, STMT_SEARCH_ORDER_SERIES)
if err != nil {
return nil, 0, err
}
defer rows.Close()
series := make([]*SeriesAdv, 0, limit)
count := 0
for rows.Next() {
if len(series) <= limit {
serie := new(SeriesAdv)

31
main.go
View File

@ -63,10 +63,7 @@ func initApp() *BouquinsConf {
if err != nil {
log.Fatalln(err)
}
app := &Bouquins{
tpl,
db,
}
app := &Bouquins{tpl, db}
err = app.PrepareAll()
if err != nil {
log.Fatalln(err)
@ -83,13 +80,27 @@ func assets(calibre string) {
http.Handle(URL_CALIBRE, http.StripPrefix(URL_CALIBRE, http.FileServer(http.Dir(calibre))))
}
func handle(f func(res http.ResponseWriter, req *http.Request) error) func(res http.ResponseWriter, req *http.Request) {
return func(res http.ResponseWriter, req *http.Request) {
err := f(res, req)
if err != nil {
log.Println(err)
http.Error(res, err.Error(), 500)
}
}
}
func handleUrl(url string, f func(res http.ResponseWriter, req *http.Request) error) {
http.HandleFunc(url, handle(f))
}
func router(app *Bouquins) {
http.HandleFunc(URL_INDEX, app.IndexPage)
http.HandleFunc(URL_BOOKS, app.BooksPage)
http.HandleFunc(URL_AUTHORS, app.AuthorsPage)
http.HandleFunc(URL_SERIES, app.SeriesPage)
http.HandleFunc(URL_SEARCH, app.SearchPage)
http.HandleFunc(URL_ABOUT, app.AboutPage)
handleUrl(URL_INDEX, app.IndexPage)
handleUrl(URL_BOOKS, app.BooksPage)
handleUrl(URL_AUTHORS, app.AuthorsPage)
handleUrl(URL_SERIES, app.SeriesPage)
handleUrl(URL_SEARCH, app.SearchPage)
handleUrl(URL_ABOUT, app.AboutPage)
}
func main() {