Load author data

This commit is contained in:
Meutel 2017-01-07 19:16:11 +01:00
parent 0caf6f03d2
commit d56b1ef995
3 changed files with 195 additions and 55 deletions

122
db.c
View File

@ -38,6 +38,9 @@ enum stmt {
STMT_BOOKS_TAGS, STMT_BOOKS_TAGS,
STMT_BOOKS_AUTHORS, STMT_BOOKS_AUTHORS,
STMT_AUTHORS, STMT_AUTHORS,
STMT_AUTHOR_BOOKS,
STMT_AUTHORS_AUTHORS,
STMT_AUTHOR,
STMT__MAX STMT__MAX
}; };
@ -78,7 +81,22 @@ static const char *const stmts[STMT__MAX] = {
FROM authors, books_authors_link WHERE books_authors_link.author = authors.id \ FROM authors, books_authors_link WHERE books_authors_link.author = authors.id \
AND books_authors_link.book IN ( SELECT id FROM books ORDER BY id LIMIT ? OFFSET ?)", AND books_authors_link.book IN ( SELECT id FROM books ORDER BY id LIMIT ? OFFSET ?)",
/* STMT_AUTHORS */ /* STMT_AUTHORS */
"SELECT id, name FROM authors ORDER BY id LIMIT ? OFFSET ?", // TODO count books "SELECT authors.id, authors.name, count(book) as count FROM authors, books_authors_link \
WHERE authors.id = books_authors_link.author GROUP BY author \
ORDER BY authors.id LIMIT ? OFFSET ?",
/* STMT_AUTHOR_BOOKS */
"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_AUTHORS_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 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)",
/* STMT_AUTHOR */
"SELECT name FROM authors WHERE id = ?",
}; };
/* /*
@ -147,6 +165,13 @@ db_author_unfill(Author *p) {
free(p->name); free(p->name);
} }
void
db_author_adv_free(AuthorAdv *p)
{
db_author_unfill(&p->a);
free(p);
}
void void
db_author_free(Author *p) { db_author_free(Author *p) {
db_author_unfill(p); db_author_unfill(p);
@ -318,19 +343,13 @@ db_load_books_tags(struct kreq *r, BookAdv **books, int count, int limit, int of
} }
static struct bookauth * static struct bookauth *
db_load_books_authors(struct kreq *r, BookAdv **books, int count, int limit, int offset) db_load_books_authors(BookAdv **books, int count, struct ksqlstmt *stmt)
{ {
struct ksqlstmt *stmt;
struct bookauth *p = NULL; struct bookauth *p = NULL;
struct bookauth *item = NULL; struct bookauth *item = NULL;
int i; int i;
int64_t bid; int64_t bid;
ksql_stmt_alloc(r->arg, &stmt,
stmts[STMT_BOOKS_AUTHORS],
STMT_BOOKS_AUTHORS);
ksql_bind_int(stmt, 0, limit);
ksql_bind_int(stmt, 1, offset);
while (KSQL_ROW == ksql_stmt_step(stmt)) { while (KSQL_ROW == ksql_stmt_step(stmt)) {
// add author to list, link related book and increment asize // add author to list, link related book and increment asize
item = kcalloc(1, sizeof(struct bookauth)); item = kcalloc(1, sizeof(struct bookauth));
@ -347,7 +366,6 @@ db_load_books_authors(struct kreq *r, BookAdv **books, int count, int limit, int
item->p = p; item->p = p;
p = item; p = item;
} }
ksql_stmt_free(stmt);
return p; return p;
} }
@ -376,7 +394,13 @@ db_books_load(struct kreq *r, BookAdv **books, int limit, int offset)
} }
ksql_stmt_free(stmt); ksql_stmt_free(stmt);
p_a = db_load_books_authors(r, books, count, limit, offset); ksql_stmt_alloc(r->arg, &stmt,
stmts[STMT_BOOKS_AUTHORS],
STMT_BOOKS_AUTHORS);
ksql_bind_int(stmt, 0, limit);
ksql_bind_int(stmt, 1, offset);
p_a = db_load_books_authors(books, count, stmt);
ksql_stmt_free(stmt);
db_assign_book_authors(p_a); db_assign_book_authors(p_a);
p_t = db_load_books_tags(r, books, count, limit, offset); p_t = db_load_books_tags(r, books, count, limit, offset);
@ -509,8 +533,77 @@ db_book_load(struct kreq *r, int64_t id)
return book; return book;
} }
AuthorFull *
db_author_load(struct kreq *r, int64_t id)
{
struct ksqlstmt *stmt;
struct bookauth *item = NULL;
struct bookauth *p = NULL;
int books = 0;
BookAdv *b;
AuthorFull *a = kcalloc(1, sizeof(AuthorFull));
a->a.id = id;
ksql_stmt_alloc(r->arg, &stmt,
stmts[STMT_AUTHOR_BOOKS],
STMT_AUTHOR_BOOKS);
ksql_bind_int(stmt, 0, id);
while (KSQL_ROW == ksql_stmt_step(stmt)) {
books++;
b = kcalloc(1, sizeof(BookAdv));
b->asize = 0;
b->tsize = 0;
db_book_fill(&b->b, stmt);
item = kcalloc(1, sizeof(struct bookauth));
item->b = b;
item->a = &a->a;
item->p = p;
p = item;
}
ksql_stmt_free(stmt);
a->bsize = books;
if (books>0) {
a->books = kcalloc(books, sizeof(BookAdv));
while (NULL != p && books > 0) {
a->books[--books] = p->b;
item = p;
p = p->p;
free(item);
}
ksql_stmt_alloc(r->arg, &stmt,
stmts[STMT_AUTHORS_AUTHORS],
STMT_AUTHORS_AUTHORS);
ksql_bind_int(stmt, 0, id);
p = db_load_books_authors(a->books, a->bsize, stmt);
ksql_stmt_free(stmt);
db_assign_book_authors(p);
// get name from 1st book
for (size_t i=0; i<a->books[0]->asize; i++) {
if (a->a.id == a->books[0]->a[i]->id)
a->a.name = a->books[0]->a[i]->name;
}
} else {
// no books, get name
ksql_stmt_alloc(r->arg, &stmt,
stmts[STMT_AUTHOR],
STMT_AUTHOR);
ksql_bind_int(stmt, 0, id);
if (KSQL_ROW == ksql_stmt_step(stmt))
a->a.name = kstrdup(ksql_stmt_str(stmt, 0));
else
a = NULL;
ksql_stmt_free(stmt);
}
return a;
}
int int
db_authors_load(struct kreq *r, Author **authors, int limit, int offset) db_authors_load(struct kreq *r, AuthorAdv **authors, int limit, int offset)
{ {
if (limit < 0 || offset < 0) { if (limit < 0 || offset < 0) {
return 0; return 0;
@ -524,9 +617,10 @@ db_authors_load(struct kreq *r, Author **authors, int limit, int offset)
ksql_bind_int(stmt, 0, limit); ksql_bind_int(stmt, 0, limit);
ksql_bind_int(stmt, 1, offset); ksql_bind_int(stmt, 1, offset);
while (KSQL_ROW == ksql_stmt_step(stmt)) { while (KSQL_ROW == ksql_stmt_step(stmt)) {
authors[count] = kcalloc(1, sizeof(Author)); authors[count] = kcalloc(1, sizeof(AuthorAdv));
authors[count]->id = ksql_stmt_int(stmt, 0); authors[count]->a.id = ksql_stmt_int(stmt, 0);
authors[count]->name =kstrdup(ksql_stmt_str(stmt, 1)); authors[count]->a.name = kstrdup(ksql_stmt_str(stmt, 1));
authors[count]->count = ksql_stmt_int(stmt, 2);
count++; count++;
} }
ksql_stmt_free(stmt); ksql_stmt_free(stmt);

View File

@ -46,6 +46,15 @@ typedef struct
char *name; char *name;
} Author; } Author;
/*
* Author and number of books.
*/
typedef struct
{
Author a;
int count;
} AuthorAdv;
/* /*
* Downloadable book data. * Downloadable book data.
*/ */
@ -68,6 +77,13 @@ typedef struct
size_t tsize; size_t tsize;
} BookAdv; } BookAdv;
typedef struct
{
Author a;
BookAdv **books;
size_t bsize;
} AuthorFull;
typedef struct typedef struct
{ {
BookAdv ba; BookAdv ba;
@ -93,8 +109,10 @@ void db_book_free(Book *p);
void db_book_adv_free(BookAdv *p); void db_book_adv_free(BookAdv *p);
void db_book_full_free(BookFull *p); void db_book_full_free(BookFull *p);
int db_authors_load(struct kreq *r, Author **authors, int limit, int offset); AuthorFull *db_author_load(struct kreq *r, int64_t id);
int db_authors_load(struct kreq *r, AuthorAdv **authors, int limit, int offset);
void db_author_free(Author *p); void db_author_free(Author *p);
void db_author_adv_free(AuthorAdv *p);
void db_series_free(Series *p); void db_series_free(Series *p);

96
main.c
View File

@ -42,7 +42,6 @@ enum page {
}; };
enum key { enum key {
KEY_ID,
KEY_PAGE, KEY_PAGE,
KEY_PERPAGE, KEY_PERPAGE,
KEY__MAX KEY__MAX
@ -56,7 +55,6 @@ static const char *const pages[PAGE__MAX] = {
}; };
static const struct kvalid keys[KEY__MAX] = { static const struct kvalid keys[KEY__MAX] = {
{ kvalid_int, "id" }, /* KEY_ID */
{ kvalid_int, "page" }, /* KEY_PAGE */ { kvalid_int, "page" }, /* KEY_PAGE */
{ kvalid_int, "perpage" }, /* KEY_PERPAGE */ { kvalid_int, "perpage" }, /* KEY_PERPAGE */
}; };
@ -127,22 +125,6 @@ putbook(struct kjsonreq *req, Book *b)
} }
} }
static void
putbookdata(struct kjsonreq *req, BookFull *b)
{
if (b->dsize > 0) {
kjson_arrayp_open(req, "data");
for (size_t i=0;i<b->dsize;i++) {
kjson_obj_open(req);
kjson_putstringp(req, "name", b->data[i]->name);
kjson_putstringp(req, "format", b->data[i]->format);
kjson_putintp(req, "size", b->data[i]->size);
kjson_obj_close(req);
}
kjson_array_close(req);
}
}
static void static void
puttags(struct kjsonreq *req, BookAdv *b) puttags(struct kjsonreq *req, BookAdv *b)
{ {
@ -168,6 +150,32 @@ putauthors(struct kjsonreq *req, BookAdv *b)
} }
} }
static void
putbookadv(struct kjsonreq *req, BookAdv *ba)
{
putbook(req, &ba->b);
putauthors(req, ba);
puttags(req, ba);
kjson_obj_close(req);
db_book_adv_free(ba);
}
static void
putbookdata(struct kjsonreq *req, BookFull *b)
{
if (b->dsize > 0) {
kjson_arrayp_open(req, "data");
for (size_t i=0;i<b->dsize;i++) {
kjson_obj_open(req);
kjson_putstringp(req, "name", b->data[i]->name);
kjson_putstringp(req, "format", b->data[i]->format);
kjson_putintp(req, "size", b->data[i]->size);
kjson_obj_close(req);
}
kjson_array_close(req);
}
}
static void static void
putbookfull(struct kjsonreq *req, BookFull *b) putbookfull(struct kjsonreq *req, BookFull *b)
{ {
@ -195,6 +203,15 @@ initpage(struct kreq *r)
return 1; return 1;
} }
static int64_t
idfrompath(struct kreq *r)
{
const char *errid;
if (r->path[0] != '\0')
return strtonum(r->path, INT64_MIN, INT64_MAX, &errid);
return -1;
}
static int static int
initperpage(struct kreq *r) initperpage(struct kreq *r)
{ {
@ -207,18 +224,13 @@ static void
sendbooks(struct kreq *r) sendbooks(struct kreq *r)
{ {
struct kjsonreq req; struct kjsonreq req;
const char *errid;
int64_t id = -1;
BookFull *b = NULL; BookFull *b = NULL;
int res, i = 0; int res, i = 0;
int page = initpage(r); int page = initpage(r);
int per = initperpage(r); int per = initperpage(r);
int64_t id = idfrompath(r);
if (NULL != r->fieldmap[KEY_ID])
id = r->fieldmap[KEY_ID]->parsed.i;
if (r->path[0] != '\0')
id = strtonum(r->path, INT64_MIN, INT64_MAX, &errid);
if (id >= 0) { if (id >= 0) {
b = db_book_load(r, id); b = db_book_load(r, id);
} }
@ -238,12 +250,7 @@ sendbooks(struct kreq *r)
BookAdv **books = kcalloc(per, sizeof(BookAdv)); BookAdv **books = kcalloc(per, sizeof(BookAdv));
res = db_books_load(r, books, per, per * (page-1)); res = db_books_load(r, books, per, per * (page-1));
while (i < res) { while (i < res) {
Book b = books[i]->b; putbookadv(&req, books[i]);
putbook(&req, &b);
putauthors(&req, books[i]);
puttags(&req, books[i]);
kjson_obj_close(&req);
db_book_adv_free(books[i]);
i++; i++;
} }
free(books); free(books);
@ -257,26 +264,47 @@ sendauthors(struct kreq *r)
{ {
struct kjsonreq req; struct kjsonreq req;
int res, i = 0; int res, i = 0;
AuthorFull *a = NULL;
int page = initpage(r); int page = initpage(r);
int per = initperpage(r); int per = initperpage(r);
int64_t id = idfrompath(r);
http_open(r, KHTTP_200); http_open(r, KHTTP_200);
kjson_open(&req, r); kjson_open(&req, r);
if (id >= 0)
a = db_author_load(r, id);
if (id >= 0 && NULL == a) {
puterror(&req, "Unknown author");
} else if (id >= 0) {
kjson_obj_open(&req);
kjson_putintp(&req, "id", a->a.id);
kjson_putstringp(&req, "name", a->a.name);
if (a->bsize>0) {
kjson_arrayp_open(&req, "books");
for (size_t j = 0; j<a->bsize; j++) {
putbookadv(&req, a->books[j]);
}
kjson_array_close(&req);
}
kjson_obj_close(&req);
} else {
kjson_array_open(&req); kjson_array_open(&req);
Author **authors = kcalloc(per, sizeof(Author)); AuthorAdv **authors = kcalloc(per, sizeof(AuthorAdv));
res = db_authors_load(r, authors, per, per * (page-1)); res = db_authors_load(r, authors, per, per * (page-1));
while (i < res) { while (i < res) {
kjson_obj_open(&req); kjson_obj_open(&req);
kjson_putintp(&req, "id", authors[i]->id); kjson_putintp(&req, "id", authors[i]->a.id);
kjson_putstringp(&req, "name", authors[i]->name); kjson_putstringp(&req, "name", authors[i]->a.name);
kjson_putintp(&req, "count", authors[i]->count);
kjson_obj_close(&req); kjson_obj_close(&req);
db_author_free(authors[i]); db_author_adv_free(authors[i]);
i++; i++;
} }
free(authors); free(authors);
kjson_array_close(&req); kjson_array_close(&req);
}
kjson_close(&req); kjson_close(&req);
} }