Load author data
This commit is contained in:
parent
0caf6f03d2
commit
d56b1ef995
122
db.c
122
db.c
@ -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);
|
||||||
|
20
extern.h
20
extern.h
@ -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);
|
||||||
|
|
||||||
|
108
main.c
108
main.c
@ -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);
|
||||||
|
|
||||||
kjson_array_open(&req);
|
if (id >= 0)
|
||||||
Author **authors = kcalloc(per, sizeof(Author));
|
a = db_author_load(r, id);
|
||||||
res = db_authors_load(r, authors, per, per * (page-1));
|
if (id >= 0 && NULL == a) {
|
||||||
while (i < res) {
|
puterror(&req, "Unknown author");
|
||||||
|
} else if (id >= 0) {
|
||||||
kjson_obj_open(&req);
|
kjson_obj_open(&req);
|
||||||
kjson_putintp(&req, "id", authors[i]->id);
|
kjson_putintp(&req, "id", a->a.id);
|
||||||
kjson_putstringp(&req, "name", authors[i]->name);
|
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);
|
kjson_obj_close(&req);
|
||||||
db_author_free(authors[i]);
|
} else {
|
||||||
i++;
|
kjson_array_open(&req);
|
||||||
|
AuthorAdv **authors = kcalloc(per, sizeof(AuthorAdv));
|
||||||
|
res = db_authors_load(r, authors, per, per * (page-1));
|
||||||
|
while (i < res) {
|
||||||
|
kjson_obj_open(&req);
|
||||||
|
kjson_putintp(&req, "id", authors[i]->a.id);
|
||||||
|
kjson_putstringp(&req, "name", authors[i]->a.name);
|
||||||
|
kjson_putintp(&req, "count", authors[i]->count);
|
||||||
|
kjson_obj_close(&req);
|
||||||
|
db_author_adv_free(authors[i]);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
free(authors);
|
||||||
|
kjson_array_close(&req);
|
||||||
}
|
}
|
||||||
free(authors);
|
|
||||||
kjson_array_close(&req);
|
|
||||||
|
|
||||||
kjson_close(&req);
|
kjson_close(&req);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user