Code style (go vet, go lint)

This commit is contained in:
Meutel 2017-08-06 20:25:20 +02:00
parent 0362051918
commit 2943d217a7
9 changed files with 346 additions and 313 deletions

View File

@ -16,93 +16,89 @@ import (
)
const (
TPL_BOOKS = "book.html"
TPL_AUTHORS = "author.html"
TPL_SERIES = "series.html"
TPL_INDEX = "index.html"
TPL_SEARCH = "search.html"
TPL_ABOUT = "about.html"
tplBooks = "book.html"
tplAuthors = "author.html"
tplSeries = "series.html"
tplIndex = "index.html"
tplSearch = "search.html"
tplAbout = "about.html"
PARAM_LIST = "list"
PARAM_ORDER = "order"
PARAM_SORT = "sort"
PARAM_PAGE = "page"
PARAM_PERPAGE = "perpage"
PARAM_TERM = "term"
pList = "list"
pOrder = "order"
pSort = "sort"
pPage = "page"
pPerPage = "perpage"
pTerm = "term"
LIST_AUTHORS = "authors"
LIST_SERIES = "series"
LIST_BOOKS = "books"
URL_INDEX = "/"
URL_BOOKS = "/books/"
URL_AUTHORS = "/authors/"
URL_SERIES = "/series/"
URL_SEARCH = "/search/"
URL_ABOUT = "/about/"
URL_JS = "/js/"
URL_CSS = "/css/"
URL_FONTS = "/fonts/"
URL_CALIBRE = "/calibre/"
// URLIndex url of index page
URLIndex = "/"
// URLBooks url of books page
URLBooks = "/books/"
// URLAuthors url of authors page
URLAuthors = "/authors/"
// URLSeries url of series page
URLSeries = "/series/"
// URLSearch url of search page
URLSearch = "/search/"
// URLAbout url of about page
URLAbout = "/about/"
// URLJs url of js assets
URLJs = "/js/"
// URLCss url of css assets
URLCss = "/css/"
// URLFonts url of fonts assets
URLFonts = "/fonts/"
// URLCalibre url of calibre resources (covers, ebooks files)
URLCalibre = "/calibre/"
)
// Bouquins contains application common resources: templates, database
type Bouquins struct {
*template.Template
*sql.DB
Tpl *template.Template
DB *sql.DB
}
/*
* A book series.
*/
// Series is a book series.
type Series struct {
Id int64 `json:"id,omitempty"`
ID int64 `json:"id,omitempty"`
Name string `json:"name,omitempty"`
}
/*
* A book. Generic data.
*/
// Book contains basic data on book
type Book struct {
Id int64 `json:"id,omitempty"`
ID int64 `json:"id,omitempty"`
Title string `json:"title,omitempty"`
SeriesIndex float64 `json:"series_idx,omitempty"`
Series *Series `json:"series,omitempty"`
}
/*
* An author.
*/
// Author contains basic data on author
type Author struct {
Id int64 `json:"id,omitempty"`
ID int64 `json:"id,omitempty"`
Name string `json:"name,omitempty"`
}
/*
* Author and number of books.
*/
// AuthorAdv extends Author with number of books
type AuthorAdv struct {
Author
Count int `json:"count,omitempty"`
}
/*
* Downloadable book data.
*/
// BookData contains data for dowloadable book
type BookData struct {
Size int64 `json:"size,omitempty"`
Format string `json:"format,omitempty"`
Name string `json:"name,omitempty"`
}
/*
* A book. Advanced data: authors, tags.
*/
// BookAdv extends Book with authors and tags
type BookAdv struct {
Book
Authors []*Author `json:"authors,omitempty"`
Tags []string `json:"tags,omitempty"`
}
// AuthorFull extends Author with books, series and co-authors
type AuthorFull struct {
Author
Books []*Book `json:"books,omitempty"`
@ -110,6 +106,7 @@ type AuthorFull struct {
CoAuthors []*Author `json:"coauthors,omitempty"`
}
// BookFull extends BookAdv with all available data
type BookFull struct {
BookAdv
Data []*BookData `json:"data,omitempty"`
@ -118,98 +115,111 @@ type BookFull struct {
Isbn string `json:"isbn,omitempty"`
Lccn string `json:"lccn,omitempty"`
Path string `json:"path,omitempty"`
Uuid string `json:"uuid,omitempty"`
Has_cover bool `json:"has_cover,omitempty"`
UUID string `json:"uuid,omitempty"`
HasCover bool `json:"has_cover,omitempty"`
Lang string `json:"lang,omitempty"`
Publisher string `json:"publisher,omitempty"`
}
// SeriesAdv extends Series with count of books and authors
type SeriesAdv struct {
Series
Count int64 `json:"count,omitempty"`
Authors []*Author `json:"authors,omitempty"`
}
// SeriesFull extends SeriesAdv with related books
type SeriesFull struct {
SeriesAdv
Books []*Book `json:"books,omitempty"`
}
type BouquinsModel struct {
// Model is basic page model
type Model struct {
Title string
Page string
}
// Constructor BouquinsModel
func NewBouquinsModel(title, page string) *BouquinsModel {
return &BouquinsModel{title, page}
// NewModel constuctor for Model
func NewModel(title, page string) *Model {
return &Model{title, page}
}
// IndexModel is the model for index page
type IndexModel struct {
BouquinsModel
Model
BooksCount int64 `json:"count"`
}
// Constructor IndexModel
// NewIndexModel constructor IndexModel
func NewIndexModel(title string, count int64) *IndexModel {
return &IndexModel{*NewBouquinsModel(title, "index"), count}
return &IndexModel{*NewModel(title, "index"), count}
}
type SearchModel struct {
BouquinsModel
}
func NewSearchModel() *SearchModel {
return &SearchModel{*NewBouquinsModel("Recherche", "search")}
// NewSearchModel constuctor for search page
func NewSearchModel() *Model {
return NewModel("Recherche", "search")
}
// ResultsModel is a generic model for list pages
type ResultsModel struct {
Type string `json:"type,omitempty"`
More bool `json:"more"`
CountResults int `json:"count,omitempty"`
}
// BooksResultsModel is the model for list of books
type BooksResultsModel struct {
ResultsModel
Results []*BookAdv `json:"results,omitempty"`
}
// NewBooksResultsModel constuctor for BooksResultsModel
func NewBooksResultsModel(books []*BookAdv, more bool, count int) *BooksResultsModel {
return &BooksResultsModel{ResultsModel{"books", more, count}, books}
}
// AuthorsResultsModel is the model for list of authors
type AuthorsResultsModel struct {
ResultsModel
Results []*AuthorAdv `json:"results,omitempty"`
}
// NewAuthorsResultsModel constuctor for AuthorsResultsModel
func NewAuthorsResultsModel(authors []*AuthorAdv, more bool, count int) *AuthorsResultsModel {
return &AuthorsResultsModel{ResultsModel{"authors", more, count}, authors}
}
// SeriesResultsModel is the model for list of series
type SeriesResultsModel struct {
ResultsModel
Results []*SeriesAdv `json:"results,omitempty"`
}
// NewSeriesResultsModel constuctor for SeriesResultsModel
func NewSeriesResultsModel(series []*SeriesAdv, more bool, count int) *SeriesResultsModel {
return &SeriesResultsModel{ResultsModel{"series", more, count}, series}
}
// BookModel is the model for single book page
type BookModel struct {
BouquinsModel
Model
*BookFull
}
// SeriesModel is the model for single series page
type SeriesModel struct {
BouquinsModel
Model
*SeriesFull
}
// AuthorModel is the model for single author page
type AuthorModel struct {
BouquinsModel
Model
*AuthorFull
}
// ReqParams contains request parameters for searches and lists
type ReqParams struct {
Limit int
Offset int
@ -219,7 +229,7 @@ type ReqParams struct {
AllWords bool
}
// add functions to templates
// TemplatesFunc adds functions to templates
func TemplatesFunc() *template.Template {
return template.New("").Funcs(template.FuncMap{
"humanSize": func(sz int64) string {
@ -237,18 +247,18 @@ func TemplatesFunc() *template.Template {
// output page with template
func (app *Bouquins) render(res http.ResponseWriter, tpl string, model interface{}) error {
return app.Template.ExecuteTemplate(res, tpl, model)
return app.Tpl.ExecuteTemplate(res, tpl, model)
}
// output as JSON
func writeJson(res http.ResponseWriter, model interface{}) error {
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 {
func isJSON(req *http.Request) bool {
return req.Header.Get("Accept") == "application/json"
}
@ -268,7 +278,7 @@ func paramInt(name string, req *http.Request) int {
// get order parameter
func paramOrder(req *http.Request) string {
val := req.URL.Query().Get(PARAM_ORDER)
val := req.URL.Query().Get(pOrder)
if val == "desc" || val == "asc" {
return val
}
@ -277,23 +287,23 @@ func paramOrder(req *http.Request) string {
// get common request parameters
func params(req *http.Request) *ReqParams {
page, perpage := paramInt(PARAM_PAGE, req), paramInt(PARAM_PERPAGE, req)
page, perpage := paramInt(pPage, req), paramInt(pPerPage, req)
limit := perpage
if perpage == 0 {
limit = DEF_LIM
limit = defaultLimit
}
offset := perpage * (page - 1)
if offset < 0 {
offset = 0
}
sort := req.URL.Query().Get(PARAM_SORT)
sort := req.URL.Query().Get(pSort)
order := paramOrder(req)
terms := req.URL.Query()[PARAM_TERM]
terms := req.URL.Query()[pTerm]
return &ReqParams{limit, offset, sort, order, terms, false}
}
// single element or list elements page
func listOrId(res http.ResponseWriter, req *http.Request, url string,
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) {
@ -308,40 +318,40 @@ func listOrId(res http.ResponseWriter, req *http.Request, url string,
// LIST ELEMENTS PAGES //
func (app *Bouquins) BooksListPage(res http.ResponseWriter, req *http.Request) error {
if isJson(req) {
func (app *Bouquins) booksListPage(res http.ResponseWriter, req *http.Request) error {
if isJSON(req) {
books, count, more, err := app.BooksAdv(params(req))
if err != nil {
return err
}
return writeJson(res, NewBooksResultsModel(books, more, count))
return writeJSON(res, NewBooksResultsModel(books, more, count))
}
return errors.New("Invalid mime")
}
func (app *Bouquins) AuthorsListPage(res http.ResponseWriter, req *http.Request) error {
if isJson(req) {
func (app *Bouquins) authorsListPage(res http.ResponseWriter, req *http.Request) error {
if isJSON(req) {
authors, count, more, err := app.AuthorsAdv(params(req))
if err != nil {
return err
}
return writeJson(res, NewAuthorsResultsModel(authors, more, count))
return writeJSON(res, NewAuthorsResultsModel(authors, more, count))
}
return errors.New("Invalid mime")
}
func (app *Bouquins) SeriesListPage(res http.ResponseWriter, req *http.Request) error {
if isJson(req) {
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 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 {
func (app *Bouquins) bookPage(idParam string, res http.ResponseWriter, req *http.Request) error {
id, err := strconv.Atoi(idParam)
if err != nil {
return err
@ -350,9 +360,9 @@ func (app *Bouquins) BookPage(idParam string, res http.ResponseWriter, req *http
if err != nil {
return err
}
return app.render(res, TPL_BOOKS, &BookModel{*NewBouquinsModel(book.Title, "book"), book})
return app.render(res, tplBooks, &BookModel{*NewModel(book.Title, "book"), book})
}
func (app *Bouquins) AuthorPage(idParam string, res http.ResponseWriter, req *http.Request) error {
func (app *Bouquins) authorPage(idParam string, res http.ResponseWriter, req *http.Request) error {
id, err := strconv.Atoi(idParam)
if err != nil {
return err
@ -361,9 +371,9 @@ func (app *Bouquins) AuthorPage(idParam string, res http.ResponseWriter, req *ht
if err != nil {
return err
}
return app.render(res, TPL_AUTHORS, &AuthorModel{*NewBouquinsModel(author.Name, "author"), author})
return app.render(res, tplAuthors, &AuthorModel{*NewModel(author.Name, "author"), author})
}
func (app *Bouquins) SeriePage(idParam string, res http.ResponseWriter, req *http.Request) error {
func (app *Bouquins) seriePage(idParam string, res http.ResponseWriter, req *http.Request) error {
id, err := strconv.Atoi(idParam)
if err != nil {
return err
@ -372,34 +382,45 @@ func (app *Bouquins) SeriePage(idParam string, res http.ResponseWriter, req *htt
if err != nil {
return err
}
return app.render(res, TPL_SERIES, &SeriesModel{*NewBouquinsModel(series.Name, "series"), series})
return app.render(res, tplSeries, &SeriesModel{*NewModel(series.Name, "series"), series})
}
// ROUTES //
// BooksPage displays a single books or a returns a list of books
func (app *Bouquins) BooksPage(res http.ResponseWriter, req *http.Request) error {
return listOrId(res, req, URL_BOOKS, app.BooksListPage, app.BookPage)
return listOrID(res, req, URLBooks, app.booksListPage, app.bookPage)
}
// AuthorsPage displays a single author or returns a list of authors
func (app *Bouquins) AuthorsPage(res http.ResponseWriter, req *http.Request) error {
return listOrId(res, req, URL_AUTHORS, app.AuthorsListPage, app.AuthorPage)
return listOrID(res, req, URLAuthors, app.authorsListPage, app.authorPage)
}
// SeriesPage displays a single series or returns a list of series
func (app *Bouquins) SeriesPage(res http.ResponseWriter, req *http.Request) error {
return listOrId(res, req, URL_SERIES, app.SeriesListPage, app.SeriePage)
return listOrID(res, req, URLSeries, app.seriesListPage, app.seriePage)
}
// SearchPage displays search form and results
func (app *Bouquins) SearchPage(res http.ResponseWriter, req *http.Request) error {
return app.render(res, TPL_SEARCH, NewSearchModel())
return app.render(res, tplSearch, NewSearchModel())
}
// AboutPage displays about page
func (app *Bouquins) AboutPage(res http.ResponseWriter, req *http.Request) error {
return app.render(res, TPL_ABOUT, NewBouquinsModel("A propos", "about"))
return app.render(res, tplAbout, NewModel("A propos", "about"))
}
// IndexPage displays index page: list of books/authors/series
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)
if isJSON(req) {
return writeJSON(res, model)
}
return app.render(res, TPL_INDEX, model)
return app.render(res, tplIndex, model)
}

View File

@ -2,48 +2,47 @@ package bouquins
import (
"database/sql"
"errors"
"fmt"
"log"
)
const (
STMT_BOOKS0 = `SELECT books.id AS id,title,series_index,name as series_name,series.id AS series_id
sqlBooks0 = `SELECT books.id AS id,title,series_index,name as series_name,series.id AS series_id
FROM books LEFT OUTER JOIN books_series_link ON books.id = books_series_link.book
LEFT OUTER JOIN series ON series.id = books_series_link.series `
STMT_BOOKS_TAGS0 = `SELECT name, books_tags_link.book as book FROM tags, books_tags_link
sqlBooksTags0 = `SELECT name, books_tags_link.book as book FROM tags, books_tags_link
WHERE tags.id = books_tags_link.tag AND books_tags_link.book IN ( SELECT id FROM books `
STMT_BOOKS_AUTHORS0 = `SELECT authors.id, authors.name, books_authors_link.book as book
sqlBooksAuthors0 = `SELECT authors.id, authors.name, books_authors_link.book as book
FROM authors, books_authors_link WHERE books_authors_link.author = authors.id
AND books_authors_link.book IN ( SELECT id FROM books `
STMT_SEARCH_TERM_BOOKS = " books.sort like ? "
sqlBooksTerm = " books.sort like ? "
STMT_SERIES0 = `SELECT series.id, series.name, count(book) FROM series
sqlSeries0 = `SELECT series.id, series.name, count(book) FROM series
LEFT OUTER JOIN books_series_link ON books_series_link.series = series.id
GROUP BY series.id `
STMT_SERIES_AUTHORS0 = `SELECT DISTINCT authors.id, authors.name, books_series_link.series
sqlSeriesAuthors0 = `SELECT DISTINCT authors.id, authors.name, books_series_link.series
FROM authors, books_authors_link, books_series_link
WHERE books_authors_link.book = books_series_link.book AND books_authors_link.author = authors.id
AND books_series_link.series IN ( SELECT id FROM series `
STMT_SERIES_SEARCH = "SELECT series.id, series.name FROM series WHERE "
STMT_SEARCH_TERM_SERIES = " series.sort like ? "
sqlSeriesSearch = "SELECT series.id, series.name FROM series WHERE "
sqlSeriesTerm = " series.sort like ? "
STMT_AUTHORS0 = `SELECT authors.id, authors.name, count(book) as count FROM authors, books_authors_link
sqlAuthors0 = `SELECT authors.id, authors.name, count(book) as count FROM authors, books_authors_link
WHERE authors.id = books_authors_link.author GROUP BY author `
STMT_AUTHORS_SEARCH = "SELECT id, name FROM authors WHERE "
STMT_SEARCH_TERM_AUTHOR = " sort like ? "
sqlAuthorsSearch = "SELECT id, name FROM authors WHERE "
sqlAuthorsTerm = " sort like ? "
STMT_PAGE = " LIMIT ? OFFSET ?"
STMT_WHERE = " WHERE "
STMT_BOOL_AND = " AND "
STMT_BOOL_OR = " OR "
sqlPage = " LIMIT ? OFFSET ?"
sqlWhere = " WHERE "
sqlAnd = " AND "
sqlOr = " OR "
STMT_SEARCH_ORDER_BOOKS = " ORDER BY books.sort"
STMT_SEARCH_ORDER_AUTHORS = " ORDER BY authors.sort"
STMT_SEARCH_ORDER_SERIES = " ORDER BY series.sort"
sqlBooksOrder = " ORDER BY books.sort"
sqlAuthorsOrder = " ORDER BY authors.sort"
sqlSeriesOrder = " ORDER BY series.sort"
STMT_BOOKS_COUNT = "SELECT count(id) FROM books"
STMT_BOOK = `SELECT books.id AS id,title, series_index, series.name AS series_name, series.id AS series_id,
sqlBooksCount = "SELECT count(id) FROM books"
sqlBook = `SELECT books.id AS id,title, series_index, series.name AS series_name, series.id AS series_id,
strftime('%s', timestamp), strftime('%Y', pubdate), isbn,lccn,path,uuid,has_cover,
languages.lang_code, publishers.name AS pubname FROM books
LEFT OUTER JOIN books_languages_link ON books_languages_link.book = books.id
@ -54,118 +53,121 @@ const (
LEFT OUTER JOIN books_publishers_link ON books.id = books_publishers_link.book
LEFT OUTER JOIN publishers ON publishers.id = books_publishers_link.publisher
WHERE books.id = ?`
STMT_BOOK_TAGS = "SELECT name FROM tags, books_tags_link WHERE tags.id = books_tags_link.tag AND books_tags_link.book = ?"
STMT_BOOK_AUTHORS = `SELECT authors.id, authors.name, books_authors_link.book as book
sqlBookTags = "SELECT name FROM tags, books_tags_link WHERE tags.id = books_tags_link.tag AND books_tags_link.book = ?"
sqlBookAuthors = `SELECT authors.id, authors.name, books_authors_link.book as book
FROM authors, books_authors_link WHERE books_authors_link.author = authors.id
AND books_authors_link.book = ?`
STMT_BOOK_DATA = "SELECT data.name, data.format, data.uncompressed_size FROM data WHERE data.book = ?"
STMT_BOOKS_ID_ASC = STMT_BOOKS0 + " ORDER BY id" + STMT_PAGE
STMT_BOOKS_ID_DESC = STMT_BOOKS0 + "ORDER BY id DESC" + STMT_PAGE
STMT_BOOKS_TITLE_ASC = STMT_BOOKS0 + "ORDER BY books.sort" + STMT_PAGE
STMT_BOOKS_TITLE_DESC = STMT_BOOKS0 + "ORDER BY books.sort DESC" + STMT_PAGE
STMT_BOOKS_TAGS_ID_ASC = STMT_BOOKS_TAGS0 + "ORDER BY id" + STMT_PAGE + ")"
STMT_BOOKS_TAGS_ID_DESC = STMT_BOOKS_TAGS0 + "ORDER BY id DESC" + STMT_PAGE + ")"
STMT_BOOKS_TAGS_TITLE_ASC = STMT_BOOKS_TAGS0 + "ORDER BY books.sort" + STMT_PAGE + ")"
STMT_BOOKS_TAGS_TITLE_DESC = STMT_BOOKS_TAGS0 + "ORDER BY books.sort DESC" + STMT_PAGE + ")"
STMT_BOOKS_AUTHORS_ID_ASC = STMT_BOOKS_AUTHORS0 + "ORDER BY id" + STMT_PAGE + ")"
STMT_BOOKS_AUTHORS_ID_DESC = STMT_BOOKS_AUTHORS0 + "ORDER BY id DESC" + STMT_PAGE + ")"
STMT_BOOKS_AUTHORS_TITLE_ASC = STMT_BOOKS_AUTHORS0 + "ORDER BY books.sort" + STMT_PAGE + ")"
STMT_BOOKS_AUTHORS_TITLE_DESC = STMT_BOOKS_AUTHORS0 + "ORDER BY books.sort DESC" + STMT_PAGE + ")"
sqlBookData = "SELECT data.name, data.format, data.uncompressed_size FROM data WHERE data.book = ?"
sqlBooksIDAsc = sqlBooks0 + " ORDER BY id" + sqlPage
sqlBooksIDDesc = sqlBooks0 + "ORDER BY id DESC" + sqlPage
sqlBooksTitleAsc = sqlBooks0 + "ORDER BY books.sort" + sqlPage
sqlBooksTitleDesc = sqlBooks0 + "ORDER BY books.sort DESC" + sqlPage
sqlBooksTagsIDAsc = sqlBooksTags0 + "ORDER BY id" + sqlPage + ")"
sqlBooksTagsIDDesc = sqlBooksTags0 + "ORDER BY id DESC" + sqlPage + ")"
sqlBooksTagsTitleAsc = sqlBooksTags0 + "ORDER BY books.sort" + sqlPage + ")"
sqlBooksTagsTitleDesc = sqlBooksTags0 + "ORDER BY books.sort DESC" + sqlPage + ")"
sqlBooksAuthorsIDAsc = sqlBooksAuthors0 + "ORDER BY id" + sqlPage + ")"
sqlBooksAuthorsIDDesc = sqlBooksAuthors0 + "ORDER BY id DESC" + sqlPage + ")"
sqlBooksAuthorsTitleAsc = sqlBooksAuthors0 + "ORDER BY books.sort" + sqlPage + ")"
sqlBooksAuthorsTitleDesc = sqlBooksAuthors0 + "ORDER BY books.sort DESC" + sqlPage + ")"
STMT_SERIES_ID_ASC = STMT_SERIES0 + " ORDER BY series.id" + STMT_PAGE
STMT_SERIES_ID_DESC = STMT_SERIES0 + " ORDER BY series.id DESC" + STMT_PAGE
STMT_SERIES_NAME_ASC = STMT_SERIES0 + " ORDER BY series.sort" + STMT_PAGE
STMT_SERIES_NAME_DESC = STMT_SERIES0 + " ORDER BY series.sort DESC" + STMT_PAGE
STMT_SERIES_AUTHORS_ID_ASC = STMT_SERIES_AUTHORS0 + " ORDER BY series.id" + STMT_PAGE + ")"
STMT_SERIES_AUTHORS_ID_DESC = STMT_SERIES_AUTHORS0 + " ORDER BY series.id DESC" + STMT_PAGE + ")"
STMT_SERIES_AUTHORS_NAME_ASC = STMT_SERIES_AUTHORS0 + " ORDER BY series.sort" + STMT_PAGE + ")"
STMT_SERIES_AUTHORS_NAME_DESC = STMT_SERIES_AUTHORS0 + " ORDER BY series.sort DESC" + STMT_PAGE + ")"
STMT_SERIE = "SELECT series.id, series.name FROM series WHERE series.id = ?"
STMT_SERIE_BOOKS = `SELECT books.id, title, series_index FROM books
sqlSeriesIDAsc = sqlSeries0 + " ORDER BY series.id" + sqlPage
sqlSeriesIDDesc = sqlSeries0 + " ORDER BY series.id DESC" + sqlPage
sqlSeriesNameAsc = sqlSeries0 + " ORDER BY series.sort" + sqlPage
sqlSeriesNameDesc = sqlSeries0 + " ORDER BY series.sort DESC" + sqlPage
sqlSeriesAuthorsIDAsc = sqlSeriesAuthors0 + " ORDER BY series.id" + sqlPage + ")"
sqlSeriesAuthorsIDDesc = sqlSeriesAuthors0 + " ORDER BY series.id DESC" + sqlPage + ")"
sqlSeriesAuthorsNameAsc = sqlSeriesAuthors0 + " ORDER BY series.sort" + sqlPage + ")"
sqlSeriesAuthorsNameDesc = sqlSeriesAuthors0 + " ORDER BY series.sort DESC" + sqlPage + ")"
sqlSerie = "SELECT series.id, series.name FROM series WHERE series.id = ?"
sqlSerieBooks = `SELECT books.id, title, series_index FROM books
LEFT OUTER JOIN books_series_link ON books.id = books_series_link.book
WHERE books_series_link.series = ? ORDER BY series_index ASC`
STMT_SERIE_AUTHORS = `SELECT DISTINCT authors.id, authors.name
sqlSerieAuthors = `SELECT DISTINCT authors.id, authors.name
FROM authors, books_authors_link, books_series_link
WHERE books_authors_link.book = books_series_link.book AND books_authors_link.author = authors.id
AND books_series_link.series = ?`
STMT_AUTHORS_ID_ASC = STMT_AUTHORS0 + "ORDER BY authors.id " + STMT_PAGE
STMT_AUTHORS_ID_DESC = STMT_AUTHORS0 + "ORDER BY authors.id DESC " + STMT_PAGE
STMT_AUTHORS_NAME_ASC = STMT_AUTHORS0 + "ORDER BY authors.sort " + STMT_PAGE
STMT_AUTHORS_NAME_DESC = STMT_AUTHORS0 + "ORDER BY authors.sort DESC " + STMT_PAGE
STMT_AUTHOR_BOOKS = `SELECT books.id AS id,title,series_index,name as series_name,series.id AS series_id
sqlAuthorsIDAsc = sqlAuthors0 + "ORDER BY authors.id " + sqlPage
sqlAuthorsIDDesc = sqlAuthors0 + "ORDER BY authors.id DESC " + sqlPage
sqlAuthorsNameAsc = sqlAuthors0 + "ORDER BY authors.sort " + sqlPage
sqlAuthorsNameDesc = sqlAuthors0 + "ORDER BY authors.sort DESC " + sqlPage
sqlAuthorBooks = `SELECT books.id AS id,title,series_index,name as series_name,series.id AS series_id
FROM books LEFT OUTER JOIN books_series_link ON books.id = books_series_link.book
LEFT OUTER JOIN series ON series.id = books_series_link.series
LEFT OUTER JOIN books_authors_link ON books.id = books_authors_link.book
WHERE books_authors_link.author = ? ORDER BY id`
STMT_AUTHOR_AUTHORS = `SELECT DISTINCT authors.id, authors.name
sqlAuthorAuthors = `SELECT DISTINCT authors.id, authors.name
FROM authors, books_authors_link WHERE books_authors_link.author = authors.id
AND books_authors_link.book IN ( SELECT books.id FROM books LEFT OUTER JOIN books_authors_link
ON books.id = books_authors_link.book WHERE books_authors_link.author = ? ORDER BY books.id)
AND authors.id != ? ORDER BY authors.id`
STMT_AUTHOR = "SELECT name FROM authors WHERE id = ?"
sqlAuthor = "SELECT name FROM authors WHERE id = ?"
DEF_LIM = 10
defaultLimit = 10
BOOKS QueryType = iota
BOOKS_TAGS
BOOKS_AUTHORS
BOOK
BOOK_TAGS
BOOK_DATA
BOOK_AUTHORS
BOOKS_COUNT
SERIE
SERIES
SERIES_AUTHORS
SERIE_AUTHORS
SERIE_BOOKS
AUTHORS
AUTHOR
AUTHOR_BOOKS
AUTHOR_COAUTHORS
qtBook QueryType = iota
qtBookTags
qtBookData
qtBookAuthors
qtBookCount
qtBooks
qtBooksTags
qtBooksAuthors
qtSerie
qtSerieAuthors
qtSerieBooks
qtSeries
qtSeriesAuthors
qtAuthor
qtAuthorBooks
qtAuthorCoauthors
qtAuthors
)
var QUERIES = map[Query]string{
Query{BOOKS, true, true}: STMT_BOOKS_TITLE_DESC,
Query{BOOKS, true, false}: STMT_BOOKS_TITLE_ASC,
Query{BOOKS, false, true}: STMT_BOOKS_ID_DESC,
Query{BOOKS, false, false}: STMT_BOOKS_ID_ASC,
Query{BOOKS_TAGS, true, true}: STMT_BOOKS_TAGS_TITLE_DESC,
Query{BOOKS_TAGS, true, false}: STMT_BOOKS_TAGS_TITLE_ASC,
Query{BOOKS_TAGS, false, true}: STMT_BOOKS_TAGS_ID_DESC,
Query{BOOKS_TAGS, false, false}: STMT_BOOKS_TAGS_ID_ASC,
Query{BOOKS_AUTHORS, true, true}: STMT_BOOKS_AUTHORS_TITLE_DESC,
Query{BOOKS_AUTHORS, true, false}: STMT_BOOKS_AUTHORS_TITLE_ASC,
Query{BOOKS_AUTHORS, false, true}: STMT_BOOKS_AUTHORS_ID_DESC,
Query{BOOKS_AUTHORS, false, false}: STMT_BOOKS_AUTHORS_ID_ASC,
Query{BOOK, false, false}: STMT_BOOK,
Query{BOOK_TAGS, false, false}: STMT_BOOK_TAGS,
Query{BOOK_DATA, false, false}: STMT_BOOK_DATA,
Query{BOOK_AUTHORS, false, false}: STMT_BOOK_AUTHORS,
Query{BOOKS_COUNT, false, false}: STMT_BOOKS_COUNT,
Query{SERIE, false, false}: STMT_SERIE,
Query{SERIES, true, true}: STMT_SERIES_NAME_DESC,
Query{SERIES, true, false}: STMT_SERIES_NAME_ASC,
Query{SERIES, false, true}: STMT_SERIES_ID_DESC,
Query{SERIES, false, false}: STMT_SERIES_ID_ASC,
Query{SERIES_AUTHORS, true, true}: STMT_SERIES_AUTHORS_NAME_DESC,
Query{SERIES_AUTHORS, true, false}: STMT_SERIES_AUTHORS_NAME_ASC,
Query{SERIES_AUTHORS, false, true}: STMT_SERIES_AUTHORS_ID_DESC,
Query{SERIES_AUTHORS, false, false}: STMT_SERIES_AUTHORS_ID_ASC,
Query{SERIE_AUTHORS, false, false}: STMT_SERIE_AUTHORS,
Query{SERIE_BOOKS, false, false}: STMT_SERIE_BOOKS,
Query{AUTHORS, true, true}: STMT_AUTHORS_NAME_DESC,
Query{AUTHORS, true, false}: STMT_AUTHORS_NAME_ASC,
Query{AUTHORS, false, true}: STMT_AUTHORS_ID_DESC,
Query{AUTHORS, false, false}: STMT_AUTHORS_ID_ASC,
Query{AUTHOR, false, false}: STMT_AUTHOR,
Query{AUTHOR_BOOKS, false, false}: STMT_AUTHOR_BOOKS,
Query{AUTHOR_COAUTHORS, false, false}: STMT_AUTHOR_AUTHORS,
var queries = map[Query]string{
Query{qtBooks, true, true}: sqlBooksTitleDesc,
Query{qtBooks, true, false}: sqlBooksTitleAsc,
Query{qtBooks, false, true}: sqlBooksIDDesc,
Query{qtBooks, false, false}: sqlBooksIDAsc,
Query{qtBooksTags, true, true}: sqlBooksTagsTitleDesc,
Query{qtBooksTags, true, false}: sqlBooksTagsTitleAsc,
Query{qtBooksTags, false, true}: sqlBooksTagsIDDesc,
Query{qtBooksTags, false, false}: sqlBooksTagsIDAsc,
Query{qtBooksAuthors, true, true}: sqlBooksAuthorsTitleDesc,
Query{qtBooksAuthors, true, false}: sqlBooksAuthorsTitleAsc,
Query{qtBooksAuthors, false, true}: sqlBooksAuthorsIDDesc,
Query{qtBooksAuthors, false, false}: sqlBooksAuthorsIDAsc,
Query{qtBook, false, false}: sqlBook,
Query{qtBookTags, false, false}: sqlBookTags,
Query{qtBookData, false, false}: sqlBookData,
Query{qtBookAuthors, false, false}: sqlBookAuthors,
Query{qtBookCount, false, false}: sqlBooksCount,
Query{qtSerie, false, false}: sqlSerie,
Query{qtSeries, true, true}: sqlSeriesNameDesc,
Query{qtSeries, true, false}: sqlSeriesNameAsc,
Query{qtSeries, false, true}: sqlSeriesIDDesc,
Query{qtSeries, false, false}: sqlSeriesIDAsc,
Query{qtSeriesAuthors, true, true}: sqlSeriesAuthorsNameDesc,
Query{qtSeriesAuthors, true, false}: sqlSeriesAuthorsNameAsc,
Query{qtSeriesAuthors, false, true}: sqlSeriesAuthorsIDDesc,
Query{qtSeriesAuthors, false, false}: sqlSeriesAuthorsIDAsc,
Query{qtSerieAuthors, false, false}: sqlSerieAuthors,
Query{qtSerieBooks, false, false}: sqlSerieBooks,
Query{qtAuthors, true, true}: sqlAuthorsNameDesc,
Query{qtAuthors, true, false}: sqlAuthorsNameAsc,
Query{qtAuthors, false, true}: sqlAuthorsIDDesc,
Query{qtAuthors, false, false}: sqlAuthorsIDAsc,
Query{qtAuthor, false, false}: sqlAuthor,
Query{qtAuthorBooks, false, false}: sqlAuthorBooks,
Query{qtAuthorCoauthors, false, false}: sqlAuthorAuthors,
}
var STMTS = make(map[Query]*sql.Stmt)
var stmts = make(map[Query]*sql.Stmt)
// QueryType is a type of query, with variants for sort and order
type QueryType uint
// Query is a key for SQL queries catalog
type Query struct {
Type QueryType
SortField bool // sort by name or title
@ -179,10 +181,10 @@ func (app *Bouquins) searchHelper(all bool, terms []string, stub, termExpr, orde
queryTerms = append(queryTerms, "%"+term+"%")
query += termExpr
if i < len(terms)-1 && all {
query += STMT_BOOL_AND
query += sqlAnd
}
if i < len(terms)-1 && !all {
query += STMT_BOOL_OR
query += sqlOr
}
}
query += orderExpr
@ -200,18 +202,20 @@ func (app *Bouquins) searchHelper(all bool, terms []string, stub, termExpr, orde
}
// PREPARED STATEMENTS //
// PrepareAll prepares statement for (almost) all queries
func (app *Bouquins) PrepareAll() error {
errcount := 0
for q, v := range QUERIES {
for q, v := range queries {
stmt, err := app.DB.Prepare(v)
if err != nil {
log.Println(err, v)
errcount++
}
STMTS[q] = stmt
stmts[q] = stmt
}
if errcount > 0 {
return errors.New(fmt.Sprintf("%d errors on queries, see logs", errcount))
return fmt.Errorf("%d errors on queries, see logs", errcount)
}
return nil
}
@ -228,9 +232,9 @@ func (app *Bouquins) psSortSeries(qt QueryType, sort, order string) (*sql.Stmt,
}
func (app *Bouquins) psSort(sortNameField string, qt QueryType, sort, order string) (*sql.Stmt, error) {
q := Query{qt, sort == sortNameField, order == "desc"}
query := QUERIES[q]
query := queries[q]
log.Println(query)
stmt := STMTS[q]
stmt := stmts[q]
if stmt == nil {
log.Println("Missing statement for ", q)
var err error

View File

@ -7,7 +7,7 @@ import (
// 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)
rows, err := app.searchHelper(all, terms, sqlAuthorsSearch, sqlAuthorsTerm, sqlAuthorsOrder)
if err != nil {
return nil, 0, err
}
@ -17,7 +17,7 @@ func (app *Bouquins) searchAuthors(limit int, terms []string, all bool) ([]*Auth
for rows.Next() {
if len(authors) <= limit {
author := new(AuthorAdv)
if err := rows.Scan(&author.Id, &author.Name); err != nil {
if err := rows.Scan(&author.ID, &author.Name); err != nil {
return nil, 0, err
}
authors = append(authors, author)
@ -32,7 +32,7 @@ func (app *Bouquins) searchAuthors(limit int, terms []string, all bool) ([]*Auth
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)
stmt, err := app.psSortAuthors(qtAuthors, sort, order)
if err != nil {
return nil, false, err
}
@ -47,7 +47,7 @@ func (app *Bouquins) queryAuthors(limit, offset int, sort, order string) ([]*Aut
more = true
} else {
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, false, err
}
authors = append(authors, author)
@ -60,11 +60,11 @@ func (app *Bouquins) queryAuthors(limit, offset int, sort, order string) ([]*Aut
}
func (app *Bouquins) queryAuthorBooks(author *AuthorFull) error {
stmt, err := app.ps(AUTHOR_BOOKS)
stmt, err := app.ps(qtAuthorBooks)
if err != nil {
return err
}
rows, err := stmt.Query(author.Id)
rows, err := stmt.Query(author.ID)
if err != nil {
return err
}
@ -72,14 +72,14 @@ func (app *Bouquins) queryAuthorBooks(author *AuthorFull) error {
series := make(map[int64]*Series, 0)
for rows.Next() {
book := new(Book)
var seriesId sql.NullInt64
var seriesID sql.NullInt64
var seriesName sql.NullString
if err = rows.Scan(&book.Id, &book.Title, &book.SeriesIndex, &seriesName, &seriesId); err != nil {
if err = rows.Scan(&book.ID, &book.Title, &book.SeriesIndex, &seriesName, &seriesID); err != nil {
return err
}
if seriesId.Valid && seriesName.Valid {
series[seriesId.Int64] = &Series{
seriesId.Int64,
if seriesID.Valid && seriesName.Valid {
series[seriesID.Int64] = &Series{
seriesID.Int64,
seriesName.String,
}
}
@ -96,18 +96,18 @@ func (app *Bouquins) queryAuthorBooks(author *AuthorFull) error {
}
func (app *Bouquins) queryAuthorAuthors(author *AuthorFull) error {
stmt, err := app.ps(AUTHOR_COAUTHORS)
stmt, err := app.ps(qtAuthorCoauthors)
if err != nil {
return err
}
rows, err := stmt.Query(author.Id, author.Id)
rows, err := stmt.Query(author.ID, author.ID)
if err != nil {
return err
}
defer rows.Close()
for rows.Next() {
coauthor := new(Author)
if err = rows.Scan(&coauthor.Id, &coauthor.Name); err != nil {
if err = rows.Scan(&coauthor.ID, &coauthor.Name); err != nil {
return err
}
author.CoAuthors = append(author.CoAuthors, coauthor)
@ -119,12 +119,12 @@ func (app *Bouquins) queryAuthorAuthors(author *AuthorFull) error {
}
func (app *Bouquins) queryAuthor(id int64) (*AuthorFull, error) {
stmt, err := app.ps(AUTHOR)
stmt, err := app.ps(qtAuthor)
if err != nil {
return nil, err
}
author := new(AuthorFull)
author.Id = id
author.ID = id
err = stmt.QueryRow(id).Scan(&author.Name)
if err != nil {
return nil, err
@ -134,6 +134,7 @@ func (app *Bouquins) queryAuthor(id int64) (*AuthorFull, error) {
// DB LOADS //
// AuthorsAdv loads a list of authors
func (app *Bouquins) AuthorsAdv(params *ReqParams) ([]*AuthorAdv, int, bool, error) {
limit, offset, sort, order := params.Limit, params.Offset, params.Sort, params.Order
if len(params.Terms) > 0 {
@ -147,6 +148,7 @@ func (app *Bouquins) AuthorsAdv(params *ReqParams) ([]*AuthorAdv, int, bool, err
return authors, 0, more, nil
}
// AuthorFull loads an author
func (app *Bouquins) AuthorFull(id int64) (*AuthorFull, error) {
author, err := app.queryAuthor(id)
if err != nil {

View File

@ -7,15 +7,15 @@ import (
// MERGE SUB QUERIES //
func assignAuthorsTagsBooks(books []*BookAdv, authors map[int64][]*Author, tags map[int64][]string) {
for _, b := range books {
b.Authors = authors[b.Id]
b.Tags = tags[b.Id]
b.Authors = authors[b.ID]
b.Tags = tags[b.ID]
}
}
// SUB QUERIES //
func (app *Bouquins) searchBooks(limit int, terms []string, all bool) ([]*BookAdv, int, error) {
rows, err := app.searchHelper(all, terms, STMT_BOOKS0+STMT_WHERE, STMT_SEARCH_TERM_BOOKS, STMT_SEARCH_ORDER_BOOKS)
rows, err := app.searchHelper(all, terms, sqlBooks0+sqlWhere, sqlBooksTerm, sqlBooksOrder)
if err != nil {
return nil, 0, err
}
@ -25,15 +25,15 @@ func (app *Bouquins) searchBooks(limit int, terms []string, all bool) ([]*BookAd
for rows.Next() {
if len(books) <= limit {
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 {
var seriesName sql.NullString
var seriesID sql.NullInt64
if err := rows.Scan(&book.ID, &book.Title, &book.SeriesIndex, &seriesName, &seriesID); err != nil {
return nil, 0, err
}
if series_name.Valid && series_id.Valid {
if seriesName.Valid && seriesID.Valid {
book.Series = &Series{
series_id.Int64,
series_name.String,
seriesID.Int64,
seriesName.String,
}
}
books = append(books, book)
@ -48,7 +48,7 @@ func (app *Bouquins) searchBooks(limit int, terms []string, all bool) ([]*BookAd
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)
stmt, err := app.psSortBooks(qtBooks, sort, order)
if err != nil {
return nil, false, err
}
@ -63,15 +63,15 @@ func (app *Bouquins) queryBooks(limit, offset int, sort, order string) ([]*BookA
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 {
var seriesName sql.NullString
var seriesID sql.NullInt64
if err := rows.Scan(&book.ID, &book.Title, &book.SeriesIndex, &seriesName, &seriesID); err != nil {
return nil, false, err
}
if series_name.Valid && series_id.Valid {
if seriesName.Valid && seriesID.Valid {
book.Series = &Series{
series_id.Int64,
series_name.String,
seriesID.Int64,
seriesName.String,
}
}
books = append(books, book)
@ -85,7 +85,7 @@ func (app *Bouquins) queryBooks(limit, offset int, sort, order string) ([]*BookA
func (app *Bouquins) queryBooksAuthors(limit, offset int, sort, order string) (map[int64][]*Author, error) {
authors := make(map[int64][]*Author)
stmt, err := app.psSortBooks(BOOKS_AUTHORS, sort, order)
stmt, err := app.psSortBooks(qtBooksAuthors, sort, order)
if err != nil {
return nil, err
}
@ -97,7 +97,7 @@ func (app *Bouquins) queryBooksAuthors(limit, offset int, sort, order string) (m
for rows.Next() {
author := new(Author)
var book int64
if err := rows.Scan(&author.Id, &author.Name, &book); err != nil {
if err := rows.Scan(&author.ID, &author.Name, &book); err != nil {
return nil, err
}
if authors[book] == nil {
@ -113,7 +113,7 @@ func (app *Bouquins) queryBooksAuthors(limit, offset int, sort, order string) (m
}
func (app *Bouquins) queryBooksTags(limit, offset int, sort, order string) (map[int64][]string, error) {
stmt, err := app.psSortBooks(BOOKS_TAGS, sort, order)
stmt, err := app.psSortBooks(qtBooksTags, sort, order)
if err != nil {
return nil, err
}
@ -143,23 +143,23 @@ func (app *Bouquins) queryBooksTags(limit, offset int, sort, order string) (map[
}
func (app *Bouquins) queryBook(id int64) (*BookFull, error) {
stmt, err := app.ps(BOOK)
stmt, err := app.ps(qtBook)
if err != nil {
return nil, err
}
book := new(BookFull)
var seriesIdx sql.NullFloat64
var seriesId, timestamp, pubdate sql.NullInt64
var seriesID, timestamp, pubdate sql.NullInt64
var seriesName, isbn, lccn, uuid, lang, publisher sql.NullString
var cover sql.NullBool
err = stmt.QueryRow(id).Scan(&book.Id, &book.Title, &seriesIdx, &seriesName, &seriesId,
err = stmt.QueryRow(id).Scan(&book.ID, &book.Title, &seriesIdx, &seriesName, &seriesID,
&timestamp, &pubdate, &isbn, &lccn, &book.Path, &uuid, &cover, &lang, &publisher)
if err != nil {
return nil, err
}
if seriesId.Valid && seriesName.Valid && seriesIdx.Valid {
if seriesID.Valid && seriesName.Valid && seriesIdx.Valid {
book.SeriesIndex = seriesIdx.Float64
book.Series = &Series{seriesId.Int64, seriesName.String}
book.Series = &Series{seriesID.Int64, seriesName.String}
}
if timestamp.Valid {
book.Timestamp = timestamp.Int64
@ -174,7 +174,7 @@ func (app *Bouquins) queryBook(id int64) (*BookFull, error) {
book.Lccn = lccn.String
}
if uuid.Valid {
book.Uuid = uuid.String
book.UUID = uuid.String
}
if lang.Valid {
book.Lang = lang.String
@ -183,16 +183,16 @@ func (app *Bouquins) queryBook(id int64) (*BookFull, error) {
book.Publisher = publisher.String
}
if cover.Valid {
book.Has_cover = cover.Bool
book.HasCover = cover.Bool
}
return book, nil
}
func (app *Bouquins) queryBookTags(book *BookFull) error {
stmt, err := app.ps(BOOK_TAGS)
stmt, err := app.ps(qtBookTags)
if err != nil {
return err
}
rows, err := stmt.Query(book.Id)
rows, err := stmt.Query(book.ID)
if err != nil {
return err
}
@ -210,11 +210,11 @@ func (app *Bouquins) queryBookTags(book *BookFull) error {
return nil
}
func (app *Bouquins) queryBookData(book *BookFull) error {
stmt, err := app.ps(BOOK_DATA)
stmt, err := app.ps(qtBookData)
if err != nil {
return err
}
rows, err := stmt.Query(book.Id)
rows, err := stmt.Query(book.ID)
if err != nil {
return err
}
@ -232,19 +232,19 @@ func (app *Bouquins) queryBookData(book *BookFull) error {
return nil
}
func (app *Bouquins) queryBookAuthors(book *BookFull) error {
stmt, err := app.ps(BOOK_AUTHORS)
stmt, err := app.ps(qtBookAuthors)
if err != nil {
return err
}
rows, err := stmt.Query(book.Id)
rows, err := stmt.Query(book.ID)
if err != nil {
return err
}
defer rows.Close()
for rows.Next() {
author := new(Author)
var bookId int64
if err = rows.Scan(&author.Id, &author.Name, &bookId); err != nil {
var bookID int64
if err = rows.Scan(&author.ID, &author.Name, &bookID); err != nil {
return err
}
book.Authors = append(book.Authors, author)
@ -257,9 +257,10 @@ func (app *Bouquins) queryBookAuthors(book *BookFull) error {
// DB LOADS //
// BookCount counts books in database
func (app *Bouquins) BookCount() (int64, error) {
var count int64
stmt, err := app.ps(BOOKS_COUNT)
stmt, err := app.ps(qtBookCount)
if err != nil {
return 0, err
}
@ -268,6 +269,7 @@ func (app *Bouquins) BookCount() (int64, error) {
return count, err
}
// BookFull loads a book
func (app *Bouquins) BookFull(id int64) (*BookFull, error) {
book, err := app.queryBook(id)
if err != nil {
@ -288,6 +290,7 @@ func (app *Bouquins) BookFull(id int64) (*BookFull, error) {
return book, nil
}
// BooksAdv loads a list of books
func (app *Bouquins) BooksAdv(params *ReqParams) ([]*BookAdv, int, bool, error) {
limit, offset, sort, order := params.Limit, params.Offset, params.Sort, params.Order
if len(params.Terms) > 0 {

View File

@ -4,14 +4,14 @@ package bouquins
func assignAuthorsSeries(series []*SeriesAdv, authors map[int64][]*Author) {
for _, s := range series {
s.Authors = authors[s.Id]
s.Authors = authors[s.ID]
}
}
// SUB QUERIES //
func (app *Bouquins) searchSeries(limit int, terms []string, all bool) ([]*SeriesAdv, int, error) {
rows, err := app.searchHelper(all, terms, STMT_SERIES_SEARCH, STMT_SEARCH_TERM_SERIES, STMT_SEARCH_ORDER_SERIES)
rows, err := app.searchHelper(all, terms, sqlSeriesSearch, sqlSeriesTerm, sqlSeriesOrder)
if err != nil {
return nil, 0, err
}
@ -21,7 +21,7 @@ func (app *Bouquins) searchSeries(limit int, terms []string, all bool) ([]*Serie
for rows.Next() {
if len(series) <= limit {
serie := new(SeriesAdv)
if err := rows.Scan(&serie.Id, &serie.Name); err != nil {
if err := rows.Scan(&serie.ID, &serie.Name); err != nil {
return nil, 0, err
}
series = append(series, serie)
@ -36,7 +36,7 @@ func (app *Bouquins) searchSeries(limit int, terms []string, all bool) ([]*Serie
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)
stmt, err := app.psSortSeries(qtSeries, sort, order)
if err != nil {
return nil, false, err
}
@ -51,7 +51,7 @@ func (app *Bouquins) querySeriesList(limit, offset int, sort, order string) ([]*
more = true
} else {
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, false, err
}
series = append(series, serie)
@ -64,7 +64,7 @@ func (app *Bouquins) querySeriesList(limit, offset int, sort, order string) ([]*
}
func (app *Bouquins) querySeriesListAuthors(limit, offset int, sort, order string) (map[int64][]*Author, error) {
authors := make(map[int64][]*Author)
stmt, err := app.psSortBooks(SERIES_AUTHORS, sort, order)
stmt, err := app.psSortBooks(qtSeriesAuthors, sort, order)
if err != nil {
return nil, err
}
@ -75,14 +75,14 @@ func (app *Bouquins) querySeriesListAuthors(limit, offset int, sort, order strin
defer rows.Close()
for rows.Next() {
author := new(Author)
var serId int64
if err := rows.Scan(&author.Id, &author.Name, &serId); err != nil {
var seriesID int64
if err := rows.Scan(&author.ID, &author.Name, &seriesID); err != nil {
return nil, err
}
if authors[serId] == nil {
authors[serId] = append(make([]*Author, 0), author)
if authors[seriesID] == nil {
authors[seriesID] = append(make([]*Author, 0), author)
} else {
authors[serId] = append(authors[serId], author)
authors[seriesID] = append(authors[seriesID], author)
}
}
if err := rows.Err(); err != nil {
@ -92,27 +92,27 @@ func (app *Bouquins) querySeriesListAuthors(limit, offset int, sort, order strin
}
func (app *Bouquins) querySeries(id int64) (*SeriesFull, error) {
stmt, err := app.ps(SERIE)
stmt, err := app.ps(qtSerie)
if err != nil {
return nil, err
}
series := new(SeriesFull)
err = stmt.QueryRow(id).Scan(&series.Id, &series.Name)
err = stmt.QueryRow(id).Scan(&series.ID, &series.Name)
return series, nil
}
func (app *Bouquins) querySeriesAuthors(series *SeriesFull) error {
stmt, err := app.ps(SERIE_AUTHORS)
stmt, err := app.ps(qtSerieAuthors)
if err != nil {
return err
}
rows, err := stmt.Query(series.Id)
rows, err := stmt.Query(series.ID)
if err != nil {
return err
}
defer rows.Close()
for rows.Next() {
author := new(Author)
if err = rows.Scan(&author.Id, &author.Name); err != nil {
if err = rows.Scan(&author.ID, &author.Name); err != nil {
return err
}
series.Authors = append(series.Authors, author)
@ -123,18 +123,18 @@ func (app *Bouquins) querySeriesAuthors(series *SeriesFull) error {
return nil
}
func (app *Bouquins) querySeriesBooks(series *SeriesFull) error {
stmt, err := app.ps(SERIE_BOOKS)
stmt, err := app.ps(qtSerieBooks)
if err != nil {
return err
}
rows, err := stmt.Query(series.Id)
rows, err := stmt.Query(series.ID)
if err != nil {
return err
}
defer rows.Close()
for rows.Next() {
book := new(Book)
if err = rows.Scan(&book.Id, &book.Title, &book.SeriesIndex); err != nil {
if err = rows.Scan(&book.ID, &book.Title, &book.SeriesIndex); err != nil {
return err
}
series.Books = append(series.Books, book)
@ -147,6 +147,7 @@ func (app *Bouquins) querySeriesBooks(series *SeriesFull) error {
// DB LOADS //
// SeriesFull loads a series
func (app *Bouquins) SeriesFull(id int64) (*SeriesFull, error) {
series, err := app.querySeries(id)
if err != nil {
@ -163,6 +164,7 @@ func (app *Bouquins) SeriesFull(id int64) (*SeriesFull, error) {
return series, nil
}
// SeriesAdv loads a list of series
func (app *Bouquins) SeriesAdv(params *ReqParams) ([]*SeriesAdv, int, bool, error) {
limit, offset, sort, order := params.Limit, params.Offset, params.Sort, params.Order
if len(params.Terms) > 0 {

33
main.go
View File

@ -9,9 +9,10 @@ import (
_ "github.com/mattn/go-sqlite3"
. "meutel.net/meutel/go-bouquins/bouquins"
"meutel.net/meutel/go-bouquins/bouquins"
)
// BouquinsConf App configuration
type BouquinsConf struct {
BindAddress string `json:"bind-address"`
DbPath string `json:"db-path"`
@ -20,7 +21,7 @@ type BouquinsConf struct {
var db *sql.DB
// load config
// ReadConfig loads configuration file and initialize default value
func ReadConfig() (*BouquinsConf, error) {
conf := new(BouquinsConf)
confPath := "bouquins.json"
@ -55,7 +56,7 @@ func initApp() *BouquinsConf {
log.Fatalln(err)
}
tpl, err := TemplatesFunc().ParseGlob("templates/*.html")
tpl, err := bouquins.TemplatesFunc().ParseGlob("templates/*.html")
if err != nil {
log.Fatalln(err)
}
@ -63,7 +64,7 @@ func initApp() *BouquinsConf {
if err != nil {
log.Fatalln(err)
}
app := &Bouquins{tpl, db}
app := &bouquins.Bouquins{Tpl: tpl, DB: db}
err = app.PrepareAll()
if err != nil {
log.Fatalln(err)
@ -74,10 +75,10 @@ func initApp() *BouquinsConf {
}
func assets(calibre string) {
http.Handle(URL_JS, http.FileServer(http.Dir("assets")))
http.Handle(URL_CSS, http.FileServer(http.Dir("assets")))
http.Handle(URL_FONTS, http.FileServer(http.Dir("assets")))
http.Handle(URL_CALIBRE, http.StripPrefix(URL_CALIBRE, http.FileServer(http.Dir(calibre))))
http.Handle(bouquins.URLJs, http.FileServer(http.Dir("assets")))
http.Handle(bouquins.URLCss, http.FileServer(http.Dir("assets")))
http.Handle(bouquins.URLFonts, http.FileServer(http.Dir("assets")))
http.Handle(bouquins.URLCalibre, http.StripPrefix(bouquins.URLCalibre, http.FileServer(http.Dir(calibre))))
}
func handle(f func(res http.ResponseWriter, req *http.Request) error) func(res http.ResponseWriter, req *http.Request) {
@ -90,17 +91,17 @@ func handle(f func(res http.ResponseWriter, req *http.Request) error) func(res h
}
}
func handleUrl(url string, f func(res http.ResponseWriter, req *http.Request) error) {
func handleURL(url string, f func(res http.ResponseWriter, req *http.Request) error) {
http.HandleFunc(url, handle(f))
}
func router(app *Bouquins) {
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 router(app *bouquins.Bouquins) {
handleURL(bouquins.URLIndex, app.IndexPage)
handleURL(bouquins.URLBooks, app.BooksPage)
handleURL(bouquins.URLAuthors, app.AuthorsPage)
handleURL(bouquins.URLSeries, app.SeriesPage)
handleURL(bouquins.URLSearch, app.SearchPage)
handleURL(bouquins.URLAbout, app.AboutPage)
}
func main() {

View File

@ -1,6 +1,6 @@
{{ template "header.html" . }}
<div class="container" id="author">
{{ if .Id }}
{{ if .ID }}
<div class="page-header">
<h1>
<span class="glyphicon glyphicon-user"></span>
@ -21,7 +21,7 @@
{{ range .Books }}
<ul class="list-unstyled">
<li><span class="glyphicon glyphicon-book"></span>
<a href="/books/{{ .Id }}">{{ .Title }}</a>
<a href="/books/{{ .ID }}">{{ .Title }}</a>
</li>
</ul>
{{ end }}
@ -33,7 +33,7 @@
{{ range .Series }}
<ul class="list-unstyled">
<li><span class="glyphicon glyphicon-list"></span>
<a href="/series/{{ .Id }}">{{ .Name }}</a>
<a href="/series/{{ .ID }}">{{ .Name }}</a>
</li>
</ul>
{{ end }}
@ -46,7 +46,7 @@
{{ range .CoAuthors }}
<ul class="list-unstyled">
<li> <span class="glyphicon glyphicon-user"></span>
<a href="/authors/{{ .Id }}">{{ .Name }}</a>
<a href="/authors/{{ .ID }}">{{ .Name }}</a>
</li>
</ul>
{{ end }}

View File

@ -1,8 +1,8 @@
{{ template "header.html" . }}
<div class="container" id="app">
{{ if .Id }}
{{ if .ID }}
<div class="page-header">
{{ if .Has_cover }}
{{ if .HasCover }}
<div class="row">
<img src="{{ bookCover .BookFull }}" alt="Pas de couverture" title="Couverture" class="img-responsive img-rounded" width="400px"/>
</div>
@ -34,7 +34,7 @@
<ul>
{{ range .Authors }}
<li>
<a href="/authors/{{.Id}}">{{ .Name }}</a>
<a href="/authors/{{.ID}}">{{ .Name }}</a>
</li>
{{ end }}
</ul>
@ -44,7 +44,7 @@
<span class="glyphicon glyphicon-list"></span> Serie
</h2>
<div>
<a href="/series/{{ .Series.Id }}">{{ .Series.Name }}</a>
<a href="/series/{{ .Series.ID }}">{{ .Series.Name }}</a>
<span class="badge">{{ .SeriesIndex }}</span>
</div>
{{ end }}

View File

@ -1,6 +1,6 @@
{{ template "header.html" . }}
<div class="container" id="app">
{{ if .Id }}
{{ if .ID }}
<div class="page-header">
<h1>
<span class="glyphicon glyphicon-list"></span>
@ -13,7 +13,7 @@
<ul>
{{ range .Books }}
<li class="list-unstyled">{{ .SeriesIndex }}.
<a href="/books/{{ .Id }}">{{ .Title }}</a>
<a href="/books/{{ .ID }}">{{ .Title }}</a>
</li>
{{ end }}
</ul>
@ -24,7 +24,7 @@
{{ range .Authors }}
<li class="list-unstyled">
<span class="glyphicon glyphicon-user"></span>
<a href="/authors/{{ .Id }}">{{ .Name }}</a>
<a href="/authors/{{ .ID }}">{{ .Name }}</a>
</li>
{{ end }}
</ul>