Database, queries books

This commit is contained in:
Meutel 2017-07-30 20:14:20 +02:00
parent 8df3f87a23
commit e56b436928
5 changed files with 222 additions and 18 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
*.swp *.swp
*~ *~
go-bouquins go-bouquins
calibre.db

View File

@ -1,20 +1,22 @@
package bouquins package bouquins
import ( import (
"database/sql"
"html/template" "html/template"
"log" "log"
"net/http" "net/http"
) )
const ( const (
TPL_BOOKS = "books.html" TPL_BOOKS = "book.html"
TPL_AUTHORS = "authors.html" TPL_AUTHORS = "author.html"
TPL_SERIES = "series.html" TPL_SERIES = "series.html"
TPL_INDEX = "index.html" TPL_INDEX = "index.html"
) )
type Bouquins struct { type Bouquins struct {
*template.Template *template.Template
*sql.DB
} }
/* /*
@ -129,8 +131,6 @@ func NewIndexModel(title string, count int64) *IndexModel {
} }
} }
// ROUTES //
func (app *Bouquins) render(res http.ResponseWriter, tpl string, model interface{}) { func (app *Bouquins) render(res http.ResponseWriter, tpl string, model interface{}) {
err := app.Template.ExecuteTemplate(res, tpl, model) err := app.Template.ExecuteTemplate(res, tpl, model)
if err != nil { if err != nil {
@ -138,8 +138,18 @@ func (app *Bouquins) render(res http.ResponseWriter, tpl string, model interface
} }
} }
// ROUTES //
func (app *Bouquins) IndexPage(res http.ResponseWriter, req *http.Request) { func (app *Bouquins) IndexPage(res http.ResponseWriter, req *http.Request) {
model := NewIndexModel("", 123) count, err := app.BookCount()
if err != nil {
log.Print(err)
}
model := NewIndexModel("", count)
model.Books, err = app.BooksAdv(0, 0)
if err != nil {
log.Print(err)
}
app.render(res, TPL_INDEX, model) app.render(res, TPL_INDEX, model)
} }
func (app *Bouquins) BooksPage(res http.ResponseWriter, req *http.Request) { func (app *Bouquins) BooksPage(res http.ResponseWriter, req *http.Request) {

181
bouquins/db.go Normal file
View File

@ -0,0 +1,181 @@
package bouquins
import (
"database/sql"
)
const (
STMT_PAGE = " LIMIT ? OFFSET ?"
STMT_BOOKS0 = `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
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
FROM authors, books_authors_link WHERE books_authors_link.author = authors.id
AND books_authors_link.book IN ( SELECT id FROM books `
STMT_WHERE = " WHERE "
STMT_SEARCH_TERM = " books.sort like ? "
STMT_BOOL_AND = " AND "
STMT_BOOL_OR = " OR "
STMT_SEARCH_ORDER = " ORDER BY books.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,
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
LEFT OUTER JOIN languages ON languages.id = books_languages_link.lang_code
LEFT OUTER JOIN data ON data.book = books.id
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_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
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 + ")"
DEF_LIM = 10
)
// 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]
}
}
// SUB QUERIES //
func (app *Bouquins) queryBooks(limit, offset int) ([]*BookAdv, error) {
books := make([]*BookAdv, 0, limit)
stmt, err := app.DB.Prepare(STMT_BOOKS_ID_ASC)
if err != nil {
return nil, err
}
rows, err := stmt.Query(limit, offset)
if err != nil {
return nil, err
}
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,
}
}
books = append(books, book)
}
if err := rows.Err(); err != nil {
return nil, err
}
return books, nil
}
func (app *Bouquins) queryBooksAuthors(limit, offset int) (map[int64][]*Author, error) {
authors := make(map[int64][]*Author)
stmt, err := app.DB.Prepare(STMT_BOOKS_AUTHORS_ID_ASC)
if err != nil {
return nil, err
}
rows, err := stmt.Query(limit, offset)
if err != nil {
return nil, err
}
for rows.Next() {
author := new(Author)
var book int64
if err := rows.Scan(&author.Id, &author.Name, &book); err != nil {
return nil, err
}
if authors[book] == nil {
authors[book] = append(make([]*Author, 0), author)
} else {
authors[book] = append(authors[book], author)
}
}
if err := rows.Err(); err != nil {
return nil, err
}
return authors, nil
}
func (app *Bouquins) queryBooksTags(limit, offset int) (map[int64][]string, error) {
tags := make(map[int64][]string)
stmt, err := app.DB.Prepare(STMT_BOOKS_TAGS_ID_ASC)
if err != nil {
return nil, err
}
rows, err := stmt.Query(limit, offset)
if err != nil {
return nil, err
}
for rows.Next() {
var tag string
var book int64
if err := rows.Scan(&tag, &book); err != nil {
return nil, err
}
bookTags := tags[book]
if bookTags == nil {
bookTags = make([]string, 1)
tags[book] = bookTags
}
tags[book] = append(bookTags, tag)
}
if err := rows.Err(); err != nil {
return nil, err
}
return tags, nil
}
// DB LOADS //
func (app *Bouquins) BookCount() (int64, error) {
var count int64
row := app.DB.QueryRow(STMT_BOOKS_COUNT)
err := row.Scan(&count)
return count, err
}
func (app *Bouquins) BooksAdv(limit int, offset int) ([]*BookAdv, error) {
if limit == 0 {
limit = DEF_LIM
}
books, err := app.queryBooks(limit, offset)
if err != nil {
return nil, err
}
authors, err := app.queryBooksAuthors(limit, offset)
if err != nil {
return nil, err
}
tags, err := app.queryBooksTags(limit, offset)
if err != nil {
return nil, err
}
assignAuthorsTagsBooks(books, authors, tags)
return books, nil
}

10
main.go
View File

@ -1,6 +1,8 @@
package main package main
import ( import (
"database/sql"
_ "github.com/mattn/go-sqlite3"
"html/template" "html/template"
"log" "log"
"net/http" "net/http"
@ -18,13 +20,20 @@ const (
FONTS = "/fonts/" FONTS = "/fonts/"
) )
var db *sql.DB
func init() { func init() {
tpl, err := template.ParseGlob("templates/*.html") tpl, err := template.ParseGlob("templates/*.html")
if err != nil { if err != nil {
log.Fatalln(err) log.Fatalln(err)
} }
db, err = sql.Open("sqlite3", "calibre.db")
if err != nil {
log.Fatalln(err)
}
app := &bouquins.Bouquins{ app := &bouquins.Bouquins{
tpl, tpl,
db,
} }
assets() assets()
router(app) router(app)
@ -44,5 +53,6 @@ func router(app *bouquins.Bouquins) {
} }
func main() { func main() {
defer db.Close()
http.ListenAndServe(":9000", nil) http.ListenAndServe(":9000", nil)
} }

View File

@ -36,7 +36,7 @@
<td> <td>
{{ range .Authors }} {{ range .Authors }}
<span class="glyphicon glyphicon-user"></span> <span class="glyphicon glyphicon-user"></span>
<a :href="/authors?id={{ .Id }}">{{ .Name }}</a>&nbsp; <a href="/authors?id={{ .Id }}">{{ .Name }}</a>&nbsp;
{{ end }} {{ end }}
</td> </td>
{{ end }} {{ end }}
@ -55,13 +55,13 @@
<tr v-for="author in authors"> <tr v-for="author in authors">
<td> <td>
<span class="glyphicon glyphicon-user"></span> <span class="glyphicon glyphicon-user"></span>
<a :href="'author.html?id='+author.id">{{ .Author.Name }}</a> <a href="'author.html?id='+author.id">{{ .Author.Name }}</a>
</td> </td>
<td>{{ .Author.Count }}</td> <td>{{ .Author.Count }}</td>
</tr> </tr>
</table> </table>
{{ end }} {{ end }}
{{ if .Books }} {{ if ne (len .Books) 0 }}
<table class="table table-striped"> <table class="table table-striped">
<tr> <tr>
<th> <th>
@ -71,23 +71,25 @@
<th>Auteur(s)</th> <th>Auteur(s)</th>
<th>Serie</th> <th>Serie</th>
</tr> </tr>
<tr v-for="book in books"> {{ range .Books }}
<tr>
<td><span class="glyphicon glyphicon-book"></span> <td><span class="glyphicon glyphicon-book"></span>
<a :href="'book.html?id='+book.id">{{ .Book.Title }}</a></td> <a href="/books?id={{ .Id }}">{{ .Title }}</a></td>
<td> <td>
<template v-for="author in book.authors"> {{ range .Authors }}
<span class="glyphicon glyphicon-user"></span> <span class="glyphicon glyphicon-user"></span>
<a :href="'author.html?id='+author.id">{{ .Author.Name }}</a> <a href="/authors?id={{ .Id }}">{{ .Name }}</a>
</template> {{ end }}
</td> </td>
<td> <td>
<template v-if="book.series"> {{ if .Series }}
<span class="glyphicon glyphicon-list"></span> <span class="glyphicon glyphicon-list"></span>
<a :href="'series.html?id='+book.series.id">{{ .Book.Series.Name }}</a> <a href="/series?id={{ .Series.Id }}">{{ .Series.Name }}</a>
<span class="badge">{{/* .Book.Series ? Book.Series.Idx : '' */}}</span> <span class="badge">{{ .Book.SeriesIndex }}</span>
</template> {{ end }}
</td> </td>
</tr> </tr>
{{ end }}
</table> </table>
{{ end }} {{ end }}
{{ if (ne (len .Books) 0) or (ne (len .Authors) 0) or (ne (len .Series) 0) }} {{ if (ne (len .Books) 0) or (ne (len .Authors) 0) or (ne (len .Series) 0) }}