From 231b115a952f8d9f7213fbdb541f1081e2bb5cc8 Mon Sep 17 00:00:00 2001 From: Meutel Date: Sun, 8 Jan 2017 16:30:06 +0100 Subject: [PATCH] Series data, split db.c --- Makefile | 2 +- db.c | 594 +--------------------------------------------------- db_author.c | 172 +++++++++++++++ db_book.c | 444 +++++++++++++++++++++++++++++++++++++++ db_series.c | 282 +++++++++++++++++++++++++ extern.h | 52 +++++ main.c | 62 +++++- 7 files changed, 1011 insertions(+), 597 deletions(-) create mode 100644 db_author.c create mode 100644 db_book.c create mode 100644 db_series.c diff --git a/Makefile b/Makefile index b1ded72..d03bf49 100644 --- a/Makefile +++ b/Makefile @@ -58,7 +58,7 @@ APIDOCS = /var/www/htdocs/api-docs sinclude GNUmakefile.local DATABASE = metadata.db -OBJS = db.o json.o main.o +OBJS = db.o db_author.o db_book.o db_series.o json.o main.o HTMLS = index.html book.html author.html JSMINS = index.min.js book.min.js author.min.js diff --git a/db.c b/db.c index ededb3a..470b5f9 100644 --- a/db.c +++ b/db.c @@ -28,105 +28,7 @@ #include "extern.h" -enum stmt { - STMT_BOOK, - STMT_BOOK_TAGS, - STMT_BOOK_AUTHORS, - STMT_BOOK_DATA, - STMT_BOOKS, - STMT_BOOKS_COUNT, - STMT_BOOKS_TAGS, - STMT_BOOKS_AUTHORS, - STMT_AUTHORS, - STMT_AUTHOR_BOOKS, - STMT_AUTHORS_AUTHORS, - STMT_AUTHOR, - STMT__MAX -}; - -static const char *const stmts[STMT__MAX] = { - /* 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 */ - "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 ORDER BY id LIMIT ? OFFSET ?", - /* STMT_BOOKS_COUNT */ - "SELECT count(id) FROM books", - /* STMT_BOOKS_TAGS */ - "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 ORDER BY id LIMIT ? OFFSET ?)", - /* STMT_BOOKS_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 id FROM books ORDER BY id LIMIT ? OFFSET ?)", - /* STMT_AUTHORS */ - "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 = ?", -}; - -/* - * Linked list authors of book. - */ -struct bookauth { - Author *a; - BookAdv *b; - struct bookauth *p; -}; - -/* - * Linked list tags of book. - */ -struct booktag { - char *tag; - BookAdv *b; - struct booktag *p; -}; - -/* - * Linked list book data. - */ -struct bookdata { - BookData *d; - BookFull *b; - struct bookdata *p; -}; - -static char * +char * strornull(struct ksqlstmt *stmt, int col) { if (ksql_stmt_isnull(stmt, col)) @@ -134,500 +36,6 @@ strornull(struct ksqlstmt *stmt, int col) return(kstrdup(ksql_stmt_str(stmt, col))); } -static void -db_series_unfill(Series *p) -{ - if (NULL == p) - return; - free(p->name); -} - -void -db_series_free(Series *p) -{ - db_series_unfill(p); - free(p); -} - -static void -db_book_unfill(Book *p) -{ - if (NULL == p) - return; - free(p->title); - db_series_unfill(&p->s); -} - -static void -db_author_unfill(Author *p) { - if (NULL == p) - return; - free(p->name); -} - -void -db_author_adv_free(AuthorAdv *p) -{ - db_author_unfill(&p->a); - free(p); -} - -void -db_author_free(Author *p) { - db_author_unfill(p); - free(p); -} - -static void -db_book_data_unfill(BookData *p) { - if (NULL == p) - return; - free(p->name); - free(p->format); -} - -void -db_book_free(Book *p) -{ - db_book_unfill(p); - free(p); -} - -void -db_book_adv_free(BookAdv *p) -{ - if (NULL == p) - return; - size_t i; - - db_book_unfill(&p->b); - for (i = 0; i < p->asize; i++) { - db_author_unfill(p->a[i]); - } - for (i = 0; i < p->tsize; i++) { - free(p->tags[i]); - } - free(p); -} - -void -db_book_full_unfill(BookFull *p) -{ - if (NULL == p) - return; - for (size_t i = 0; i < p->dsize; i++) { - db_book_data_unfill(p->data[i]); - } - free(p->isbn); - free(p->lccn); - free(p->path); - free(p->uuid); - free(p->lang); - free(p->publisher); -} - -void -db_book_full_free(BookFull *p) -{ - if (NULL == p) - return; - db_book_unfill(&p->ba.b); - for (size_t i = 0; i < p->ba.asize; i++) { - db_author_unfill(p->ba.a[i]); - } - db_book_full_unfill(p); - free(p); -} - -static void -db_book_fill(Book *book, struct ksqlstmt *stmt) -{ - book->id = ksql_stmt_int(stmt, 0); - book->title = kstrdup(ksql_stmt_str(stmt, 1)); - if ( ksql_stmt_isnull(stmt, 4) ) { - book->s.id = -1; - } else { - book->s_idx = ksql_stmt_double(stmt, 2); - book->s.name = kstrdup(ksql_stmt_str(stmt, 3)); - book->s.id = ksql_stmt_int(stmt, 4); - } -} - -int -db_books_count(struct kreq *r) -{ - int count; - struct ksqlstmt *stmt; - - ksql_stmt_alloc(r->arg, &stmt, - stmts[STMT_BOOKS_COUNT], - STMT_BOOKS_COUNT); - if (KSQL_ROW != ksql_stmt_step(stmt)) { - ksql_stmt_free(stmt); - return(0); - } - count = ksql_stmt_int(stmt, 0); - ksql_stmt_free(stmt); - return(count); -} - -static void -db_assign_book_tags(struct booktag *list) -{ - struct booktag *item = NULL; - struct booktag *p = NULL; - - p = list; - while (NULL != p) { - if (NULL != p->b && NULL == p->b->tags && p->b->tsize > 0) { - p->b->tags = kcalloc(p->b->tsize, sizeof(char*)); - p->b->tsize = 0; // use as counter for insert - } - p->b->tags[p->b->tsize] = p->tag; - p->b->tsize++; - item = p; - p = p->p; - free(item); - } -} - -static void -db_assign_book_authors(struct bookauth *list) -{ - struct bookauth *item = NULL; - struct bookauth *p = NULL; - - p = list; - while (NULL != p) { - if (NULL != p->b && NULL == p->b->a && p->b->asize > 0) { - p->b->a = kcalloc(p->b->asize, sizeof(Author)); - p->b->asize = 0; // use as counter for insert - } - p->b->a[p->b->asize] = p->a;// add author - p->b->asize++; - item = p; - p = p->p; - free(item); - } -} - -static struct booktag * -db_load_books_tags(struct kreq *r, BookAdv **books, int count, int limit, int offset) -{ - struct ksqlstmt *stmt; - struct booktag *p = NULL; - struct booktag *item = NULL; - int i; - int64_t bid; - - ksql_stmt_alloc(r->arg, &stmt, - stmts[STMT_BOOKS_TAGS], - STMT_BOOKS_TAGS); - ksql_bind_int(stmt, 0, limit); - ksql_bind_int(stmt, 1, offset); - while (KSQL_ROW == ksql_stmt_step(stmt)) { - item = kcalloc(1, sizeof(struct booktag)); - item->tag = kstrdup(ksql_stmt_str(stmt, 0)); - bid = ksql_stmt_int(stmt, 1); - for (i = 0; i < count && NULL == item->b; i++) { - if (books[i]->b.id == bid) { - item->b = books[i]; - item->b->tsize++; - } - } - item->p = p; - p = item; - } - ksql_stmt_free(stmt); - return p; -} - -static struct bookauth * -db_load_books_authors(BookAdv **books, int count, struct ksqlstmt *stmt) -{ - struct bookauth *p = NULL; - struct bookauth *item = NULL; - int i; - int64_t bid; - - while (KSQL_ROW == ksql_stmt_step(stmt)) { - // add author to list, link related book and increment asize - item = kcalloc(1, sizeof(struct bookauth)); - item->a = kcalloc(1, sizeof(Author)); - item->a->id = ksql_stmt_int(stmt, 0); - item->a->name = kstrdup(ksql_stmt_str(stmt, 1)); - bid = ksql_stmt_int(stmt, 2); - for (i = 0; i < count && NULL == item->b; i++) { - if (books[i]->b.id == bid) { - item->b = books[i]; - item->b->asize++; - } - } - item->p = p; - p = item; - } - return p; -} - -int -db_books_load(struct kreq *r, BookAdv **books, int limit, int offset) -{ - if (limit < 0 || offset < 0) { - return 0; - } - struct ksqlstmt *stmt; - struct bookauth *p_a; - struct booktag *p_t; - int count = 0; - - ksql_stmt_alloc(r->arg, &stmt, - stmts[STMT_BOOKS], - STMT_BOOKS); - ksql_bind_int(stmt, 0, limit); - ksql_bind_int(stmt, 1, offset); - while (KSQL_ROW == ksql_stmt_step(stmt)) { - books[count] = kcalloc(1, sizeof(BookAdv)); - db_book_fill(&books[count]->b,stmt); - books[count]->asize = 0; - books[count]->tsize = 0; - count++; - } - ksql_stmt_free(stmt); - - 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); - - p_t = db_load_books_tags(r, books, count, limit, offset); - db_assign_book_tags(p_t); - - return count; -} - -static void -db_book_full_tags(BookAdv *b, struct kreq *r, int64_t id) -{ - struct ksqlstmt *stmt; - struct booktag *p = NULL; - struct booktag *item = NULL; - - ksql_stmt_alloc(r->arg, &stmt, - stmts[STMT_BOOK_TAGS], - STMT_BOOK_TAGS); - ksql_bind_int(stmt, 0, id); - while (KSQL_ROW == ksql_stmt_step(stmt)) { - item = kcalloc(1, sizeof(struct booktag)); - item->tag = kstrdup(ksql_stmt_str(stmt, 0)); - item->b = b; - item->b->tsize++; - - item->p = p; - p = item; - } - ksql_stmt_free(stmt); - - db_assign_book_tags(p); -} - -static void -db_book_full_authors(BookAdv *b, struct kreq *r, int64_t id) { - struct ksqlstmt *stmt; - struct bookauth *p = NULL; - struct bookauth *item = NULL; - - ksql_stmt_alloc(r->arg, &stmt, - stmts[STMT_BOOK_AUTHORS], - STMT_BOOK_AUTHORS); - ksql_bind_int(stmt, 0, id); - while (KSQL_ROW == ksql_stmt_step(stmt)) { - item = kcalloc(1, sizeof(struct bookauth)); - item->a = kcalloc(1, sizeof(Author)); - item->a->id = ksql_stmt_int(stmt, 0); - item->a->name = kstrdup(ksql_stmt_str(stmt, 1)); - item->b = b; - item->b->asize++; - item->p = p; - p = item; - } - ksql_stmt_free(stmt); - - // assign authors to book - db_assign_book_authors(p); -} - -static void -db_book_full_data(BookFull *b, struct kreq *r, int64_t id) { - struct ksqlstmt *stmt; - struct bookdata *p = NULL; - struct bookdata *item = NULL; - - ksql_stmt_alloc(r->arg, &stmt, - stmts[STMT_BOOK_DATA], - STMT_BOOK_DATA); - ksql_bind_int(stmt, 0, id); - while (KSQL_ROW == ksql_stmt_step(stmt)) { - item = kcalloc(1, sizeof(struct bookdata)); - item->d = kcalloc(1, sizeof(BookData)); - item->d->name = kstrdup(ksql_stmt_str(stmt, 0)); - item->d->format = kstrdup(ksql_stmt_str(stmt, 1)); - item->d->size = ksql_stmt_int(stmt, 2); - item->b = b; - item->b->dsize++; - item->p = p; - p = item; - } - - ksql_stmt_free(stmt); - - while (NULL != p) { - if (NULL != p->b && NULL == p->b->data && p->b->dsize > 0) { - p->b->data = kcalloc(p->b->dsize, sizeof(BookData)); - p->b->dsize = 0; // use as counter for insert - } - p->b->data[p->b->dsize] = p->d; - p->b->dsize++; - item = p; - p = p->p; - free(item); - } -} - -BookFull * -db_book_load(struct kreq *r, int64_t id) -{ - struct ksqlstmt *stmt; - BookFull *book; - - ksql_stmt_alloc(r->arg, &stmt, - stmts[STMT_BOOK], - STMT_BOOK); - ksql_bind_int(stmt, 0, id); - if (KSQL_ROW != ksql_stmt_step(stmt)) { - ksql_stmt_free(stmt); - return(NULL); - } - book = kcalloc(1, sizeof(BookFull)); - db_book_fill(&book->ba.b, stmt); - - book->timestamp = ksql_stmt_int(stmt, 5); - book->pubdate = ksql_stmt_int(stmt, 6); - book->isbn = strornull(stmt, 7); - book->lccn = strornull(stmt, 8); - book->path = strornull(stmt, 9); - book->uuid = strornull(stmt, 10); - book->has_cover = ksql_stmt_int(stmt, 11); - book->lang = strornull(stmt, 12); - book->publisher = strornull(stmt, 13); - - ksql_stmt_free(stmt); - - db_book_full_tags(&book->ba, r, id); - db_book_full_authors(&book->ba, r, id); - db_book_full_data(book, r, id); - - 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; ibooks[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 -db_authors_load(struct kreq *r, AuthorAdv **authors, int limit, int offset) -{ - if (limit < 0 || offset < 0) { - return 0; - } - struct ksqlstmt *stmt; - int count = 0; - - ksql_stmt_alloc(r->arg, &stmt, - stmts[STMT_AUTHORS], - STMT_AUTHORS); - ksql_bind_int(stmt, 0, limit); - ksql_bind_int(stmt, 1, offset); - while (KSQL_ROW == ksql_stmt_step(stmt)) { - authors[count] = kcalloc(1, sizeof(AuthorAdv)); - authors[count]->a.id = ksql_stmt_int(stmt, 0); - authors[count]->a.name = kstrdup(ksql_stmt_str(stmt, 1)); - authors[count]->count = ksql_stmt_int(stmt, 2); - count++; - } - ksql_stmt_free(stmt); - - return count; -} - /* * Open the database and stash the resulting handle in the d */ diff --git a/db_author.c b/db_author.c new file mode 100644 index 0000000..3ae58d2 --- /dev/null +++ b/db_author.c @@ -0,0 +1,172 @@ +/* $Id$ */ +/* + * Copyright (c) 2016 Kristaps Dzonsons + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "ksql.h" + +#include "extern.h" + +enum stmt { + STMT_AUTHORS, + STMT_AUTHOR_BOOKS, + STMT_AUTHORS_AUTHORS, + STMT_AUTHOR, + STMT__MAX +}; + +static const char *const stmts[STMT__MAX] = { + /* STMT_AUTHORS */ + "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 = ?", +}; + +void +db_author_unfill(Author *p) +{ + if (NULL == p) + return; + free(p->name); +} + +void +db_author_adv_free(AuthorAdv *p) +{ + db_author_unfill(&p->a); + free(p); +} + +void +db_author_free(Author *p) { + db_author_unfill(p); + free(p); +} +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; ibooks[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 +db_authors_load(struct kreq *r, AuthorAdv **authors, int limit, int offset) +{ + if (limit < 0 || offset < 0) { + return 0; + } + struct ksqlstmt *stmt; + int count = 0; + + ksql_stmt_alloc(r->arg, &stmt, + stmts[STMT_AUTHORS], + STMT_AUTHORS); + ksql_bind_int(stmt, 0, limit); + ksql_bind_int(stmt, 1, offset); + while (KSQL_ROW == ksql_stmt_step(stmt)) { + authors[count] = kcalloc(1, sizeof(AuthorAdv)); + authors[count]->a.id = ksql_stmt_int(stmt, 0); + authors[count]->a.name = kstrdup(ksql_stmt_str(stmt, 1)); + authors[count]->count = ksql_stmt_int(stmt, 2); + count++; + } + ksql_stmt_free(stmt); + + return count; +} + diff --git a/db_book.c b/db_book.c new file mode 100644 index 0000000..1b2150e --- /dev/null +++ b/db_book.c @@ -0,0 +1,444 @@ +/* $Id$ */ +/* + * Copyright (c) 2016 Kristaps Dzonsons + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "ksql.h" + +#include "extern.h" + +enum stmt { + STMT_BOOK, + STMT_BOOK_TAGS, + STMT_BOOK_AUTHORS, + STMT_BOOK_DATA, + STMT_BOOKS, + STMT_BOOKS_COUNT, + STMT_BOOKS_TAGS, + STMT_BOOKS_AUTHORS, + STMT__MAX +}; + +static const char *const stmts[STMT__MAX] = { + /* 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 */ + "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 ORDER BY id LIMIT ? OFFSET ?", + /* STMT_BOOKS_COUNT */ + "SELECT count(id) FROM books", + /* STMT_BOOKS_TAGS */ + "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 ORDER BY id LIMIT ? OFFSET ?)", + /* STMT_BOOKS_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 id FROM books ORDER BY id LIMIT ? OFFSET ?)", +}; + +static void +db_book_unfill(Book *p) +{ + if (NULL == p) + return; + free(p->title); + db_series_unfill(&p->s); +} + +static void +db_book_data_unfill(BookData *p) { + if (NULL == p) + return; + free(p->name); + free(p->format); +} + +void +db_book_free(Book *p) +{ + db_book_unfill(p); + free(p); +} + +void +db_book_adv_free(BookAdv *p) +{ + if (NULL == p) + return; + size_t i; + + db_book_unfill(&p->b); + for (i = 0; i < p->asize; i++) { + db_author_unfill(p->a[i]); + } + for (i = 0; i < p->tsize; i++) { + free(p->tags[i]); + } + free(p); +} + +void +db_book_full_unfill(BookFull *p) +{ + if (NULL == p) + return; + for (size_t i = 0; i < p->dsize; i++) { + db_book_data_unfill(p->data[i]); + } + free(p->isbn); + free(p->lccn); + free(p->path); + free(p->uuid); + free(p->lang); + free(p->publisher); +} + +void +db_book_full_free(BookFull *p) +{ + if (NULL == p) + return; + db_book_unfill(&p->ba.b); + for (size_t i = 0; i < p->ba.asize; i++) { + db_author_unfill(p->ba.a[i]); + } + db_book_full_unfill(p); + free(p); +} + +void +db_book_fill(Book *book, struct ksqlstmt *stmt) +{ + book->id = ksql_stmt_int(stmt, 0); + book->title = kstrdup(ksql_stmt_str(stmt, 1)); + if ( ksql_stmt_isnull(stmt, 4) ) { + book->s.id = -1; + } else { + book->s_idx = ksql_stmt_double(stmt, 2); + book->s.name = kstrdup(ksql_stmt_str(stmt, 3)); + book->s.id = ksql_stmt_int(stmt, 4); + } +} + +int +db_books_count(struct kreq *r) +{ + int count; + struct ksqlstmt *stmt; + + ksql_stmt_alloc(r->arg, &stmt, + stmts[STMT_BOOKS_COUNT], + STMT_BOOKS_COUNT); + if (KSQL_ROW != ksql_stmt_step(stmt)) { + ksql_stmt_free(stmt); + return(0); + } + count = ksql_stmt_int(stmt, 0); + ksql_stmt_free(stmt); + return(count); +} + +static void +db_assign_book_tags(struct booktag *list) +{ + struct booktag *item = NULL; + struct booktag *p = NULL; + + p = list; + while (NULL != p) { + if (NULL != p->b && NULL == p->b->tags && p->b->tsize > 0) { + p->b->tags = kcalloc(p->b->tsize, sizeof(char*)); + p->b->tsize = 0; // use as counter for insert + } + p->b->tags[p->b->tsize] = p->tag; + p->b->tsize++; + item = p; + p = p->p; + free(item); + } +} + +void +db_assign_book_authors(struct bookauth *list) +{ + struct bookauth *item = NULL; + struct bookauth *p = NULL; + + p = list; + while (NULL != p) { + if (NULL != p->b && NULL == p->b->a && p->b->asize > 0) { + p->b->a = kcalloc(p->b->asize, sizeof(Author)); + p->b->asize = 0; // use as counter for insert + } + p->b->a[p->b->asize] = p->a;// add author + p->b->asize++; + item = p; + p = p->p; + free(item); + } +} + +static struct booktag * +db_load_books_tags(struct kreq *r, BookAdv **books, int count, int limit, int offset) +{ + struct ksqlstmt *stmt; + struct booktag *p = NULL; + struct booktag *item = NULL; + int i; + int64_t bid; + + ksql_stmt_alloc(r->arg, &stmt, + stmts[STMT_BOOKS_TAGS], + STMT_BOOKS_TAGS); + ksql_bind_int(stmt, 0, limit); + ksql_bind_int(stmt, 1, offset); + while (KSQL_ROW == ksql_stmt_step(stmt)) { + item = kcalloc(1, sizeof(struct booktag)); + item->tag = kstrdup(ksql_stmt_str(stmt, 0)); + bid = ksql_stmt_int(stmt, 1); + for (i = 0; i < count && NULL == item->b; i++) { + if (books[i]->b.id == bid) { + item->b = books[i]; + item->b->tsize++; + } + } + item->p = p; + p = item; + } + ksql_stmt_free(stmt); + return p; +} + +struct bookauth * +db_load_books_authors(BookAdv **books, int count, struct ksqlstmt *stmt) +{ + struct bookauth *p = NULL; + struct bookauth *item = NULL; + int i; + int64_t bid; + + while (KSQL_ROW == ksql_stmt_step(stmt)) { + // add author to list, link related book and increment asize + item = kcalloc(1, sizeof(struct bookauth)); + item->a = kcalloc(1, sizeof(Author)); + item->a->id = ksql_stmt_int(stmt, 0); + item->a->name = kstrdup(ksql_stmt_str(stmt, 1)); + bid = ksql_stmt_int(stmt, 2); + for (i = 0; i < count && NULL == item->b; i++) { + if (books[i]->b.id == bid) { + item->b = books[i]; + item->b->asize++; + } + } + item->p = p; + p = item; + } + return p; +} + +int +db_books_load(struct kreq *r, BookAdv **books, int limit, int offset) +{ + if (limit < 0 || offset < 0) { + return 0; + } + struct ksqlstmt *stmt; + struct bookauth *p_a; + struct booktag *p_t; + int count = 0; + + ksql_stmt_alloc(r->arg, &stmt, + stmts[STMT_BOOKS], + STMT_BOOKS); + ksql_bind_int(stmt, 0, limit); + ksql_bind_int(stmt, 1, offset); + while (KSQL_ROW == ksql_stmt_step(stmt)) { + books[count] = kcalloc(1, sizeof(BookAdv)); + db_book_fill(&books[count]->b,stmt); + books[count]->asize = 0; + books[count]->tsize = 0; + count++; + } + ksql_stmt_free(stmt); + + 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); + + p_t = db_load_books_tags(r, books, count, limit, offset); + db_assign_book_tags(p_t); + + return count; +} + +static void +db_book_full_tags(BookAdv *b, struct kreq *r, int64_t id) +{ + struct ksqlstmt *stmt; + struct booktag *p = NULL; + struct booktag *item = NULL; + + ksql_stmt_alloc(r->arg, &stmt, + stmts[STMT_BOOK_TAGS], + STMT_BOOK_TAGS); + ksql_bind_int(stmt, 0, id); + while (KSQL_ROW == ksql_stmt_step(stmt)) { + item = kcalloc(1, sizeof(struct booktag)); + item->tag = kstrdup(ksql_stmt_str(stmt, 0)); + item->b = b; + item->b->tsize++; + + item->p = p; + p = item; + } + ksql_stmt_free(stmt); + + db_assign_book_tags(p); +} + +static void +db_book_full_authors(BookAdv *b, struct kreq *r, int64_t id) { + struct ksqlstmt *stmt; + struct bookauth *p = NULL; + struct bookauth *item = NULL; + + ksql_stmt_alloc(r->arg, &stmt, + stmts[STMT_BOOK_AUTHORS], + STMT_BOOK_AUTHORS); + ksql_bind_int(stmt, 0, id); + while (KSQL_ROW == ksql_stmt_step(stmt)) { + item = kcalloc(1, sizeof(struct bookauth)); + item->a = kcalloc(1, sizeof(Author)); + item->a->id = ksql_stmt_int(stmt, 0); + item->a->name = kstrdup(ksql_stmt_str(stmt, 1)); + item->b = b; + item->b->asize++; + item->p = p; + p = item; + } + ksql_stmt_free(stmt); + + // assign authors to book + db_assign_book_authors(p); +} + +static void +db_book_full_data(BookFull *b, struct kreq *r, int64_t id) { + struct ksqlstmt *stmt; + struct bookdata *p = NULL; + struct bookdata *item = NULL; + + ksql_stmt_alloc(r->arg, &stmt, + stmts[STMT_BOOK_DATA], + STMT_BOOK_DATA); + ksql_bind_int(stmt, 0, id); + while (KSQL_ROW == ksql_stmt_step(stmt)) { + item = kcalloc(1, sizeof(struct bookdata)); + item->d = kcalloc(1, sizeof(BookData)); + item->d->name = kstrdup(ksql_stmt_str(stmt, 0)); + item->d->format = kstrdup(ksql_stmt_str(stmt, 1)); + item->d->size = ksql_stmt_int(stmt, 2); + item->b = b; + item->b->dsize++; + item->p = p; + p = item; + } + + ksql_stmt_free(stmt); + + while (NULL != p) { + if (NULL != p->b && NULL == p->b->data && p->b->dsize > 0) { + p->b->data = kcalloc(p->b->dsize, sizeof(BookData)); + p->b->dsize = 0; // use as counter for insert + } + p->b->data[p->b->dsize] = p->d; + p->b->dsize++; + item = p; + p = p->p; + free(item); + } +} + +BookFull * +db_book_load(struct kreq *r, int64_t id) +{ + struct ksqlstmt *stmt; + BookFull *book; + + ksql_stmt_alloc(r->arg, &stmt, + stmts[STMT_BOOK], + STMT_BOOK); + ksql_bind_int(stmt, 0, id); + if (KSQL_ROW != ksql_stmt_step(stmt)) { + ksql_stmt_free(stmt); + return(NULL); + } + book = kcalloc(1, sizeof(BookFull)); + db_book_fill(&book->ba.b, stmt); + + book->timestamp = ksql_stmt_int(stmt, 5); + book->pubdate = ksql_stmt_int(stmt, 6); + book->isbn = strornull(stmt, 7); + book->lccn = strornull(stmt, 8); + book->path = strornull(stmt, 9); + book->uuid = strornull(stmt, 10); + book->has_cover = ksql_stmt_int(stmt, 11); + book->lang = strornull(stmt, 12); + book->publisher = strornull(stmt, 13); + + ksql_stmt_free(stmt); + + db_book_full_tags(&book->ba, r, id); + db_book_full_authors(&book->ba, r, id); + db_book_full_data(book, r, id); + + return book; +} + diff --git a/db_series.c b/db_series.c new file mode 100644 index 0000000..bf173f4 --- /dev/null +++ b/db_series.c @@ -0,0 +1,282 @@ +/* $Id$ */ +/* + * Copyright (c) 2016 Kristaps Dzonsons + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "ksql.h" + +#include "extern.h" + +enum stmt { + STMT_SERIES, + STMT_SERIES_AUTHORS, + STMT_SERIE, + STMT_SERIE_BOOKS, + STMT_SERIE_AUTHORS, + STMT__MAX +}; + +static const char *const stmts[STMT__MAX] = { + /* STMT_SERIES */ + "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 ORDER BY series.id LIMIT ? OFFSET ?", + /* STMT_SERIES_AUTHORS */ + "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 ORDER BY series.id LIMIT ? OFFSET ?)", + /* STMT_SERIE */ + "SELECT series.id, series.name FROM series WHERE series.id = ?", + /* STMT_SERIE_BOOKS */ + "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 = ?", + /* STMT_SERIE_AUTHORS */ + "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 = ?", +}; + +struct seriesbook { + SeriesFull *s; + Book *b; + struct seriesbook *p; +}; + +struct seriesauth { + SeriesAdv *s; + Author *a; + struct seriesauth *p; +}; + +void +db_series_unfill(Series *p) +{ + if (NULL == p) + return; + free(p->name); +} + +void +db_series_free(Series *p) +{ + if (NULL == p) + return; + db_series_unfill(p); + free(p); +} + +void +db_series_adv_free(SeriesAdv *p) +{ + if (NULL == p) + return; + db_series_unfill(&p->s); + free(p); +} + +static void +db_assign_series_authors(struct seriesauth *list) +{ + struct seriesauth *item = NULL; + struct seriesauth *p = NULL; + + p = list; + while (NULL != p) { + if (NULL != p->s && NULL == p->s->a && p->s->asize > 0) { + p->s->a = kcalloc(p->s->asize, sizeof(Author)); + p->s->asize = 0; // use as counter for insert + } + p->s->a[p->s->asize] = p->a; + p->s->asize++; + item = p; + p = p->p; + free(item); + } +} + +static struct seriesauth * +db_load_series_authors(SeriesAdv **series, int count, struct ksqlstmt *stmt) +{ + struct seriesauth *item = NULL; + struct seriesauth *p = NULL; + int64_t sid = -1; + int i = 0; + + while (KSQL_ROW == ksql_stmt_step(stmt)) { + item = kcalloc(1, sizeof(struct seriesauth)); + item->a = kcalloc(1, sizeof(Author)); + item->a->id = ksql_stmt_int(stmt, 0); + item->a->name = kstrdup(ksql_stmt_str(stmt, 1)); + sid = ksql_stmt_int(stmt, 2); + for (i = 0; i < count && NULL == item->s; i++) { + if (series[i]->s.id == sid) { + item->s = series[i]; + item->s->asize++; + } + } + item->p = p; + p = item; + } + return p; +} + +static struct seriesbook* +db_load_series_books(struct kreq *r, SeriesFull *series, int64_t id) +{ + struct ksqlstmt *stmt; + struct seriesbook *p = NULL; + struct seriesbook *item = NULL; + + ksql_stmt_alloc(r->arg, &stmt, + stmts[STMT_SERIE_BOOKS], + STMT_SERIE_BOOKS); + ksql_bind_int(stmt, 0, id); + while (KSQL_ROW == ksql_stmt_step(stmt)) { + item = kcalloc(1,sizeof(struct seriesbook)); + Book *b = kcalloc(1, sizeof(Book)); + b->id = ksql_stmt_int(stmt, 0); + b->title = kstrdup(ksql_stmt_str(stmt, 1)); + b->s_idx = ksql_stmt_int(stmt, 2); + b->s = series->s.s; + item->b = b; + item->s = series; + series->s.books++; + + item->p = p; + p = item; + } + ksql_stmt_free(stmt); + + return p; +} + +static void +db_assign_series_books(struct seriesbook *list) +{ + struct seriesbook *p = NULL; + struct seriesbook *item = NULL; + + p = list; + while (NULL != p) { + if (NULL != p->s && NULL == p->s->b && p->s->s.books > 0) { + p->s->b = kcalloc(p->s->s.books, sizeof(Book)); + p->s->s.books = 0; // use as counter for insert + } + p->s->b[p->s->s.books] = p->b; + p->s->s.books++; + item = p; + p = p->p; + free(item); + } +} + +SeriesFull * +db_serie_load(struct kreq *r, int64_t id) +{ + struct ksqlstmt *stmt; + SeriesFull *series; + struct seriesauth *p = NULL; + struct seriesauth *item = NULL; + struct seriesbook *list = NULL; + + ksql_stmt_alloc(r->arg, &stmt, + stmts[STMT_SERIE], + STMT_SERIE); + ksql_bind_int(stmt, 0, id); + if (KSQL_ROW != ksql_stmt_step(stmt)) { + ksql_stmt_free(stmt); + return(NULL); + } + series = kcalloc(1, sizeof(SeriesFull)); + series->s.s.id = ksql_stmt_int(stmt, 0); + series->s.s.name = kstrdup(ksql_stmt_str(stmt, 1)); + series->s.books = 0; + series->s.asize = 0; + ksql_stmt_free(stmt); + + list = db_load_series_books(r, series, id); + db_assign_series_books(list); + + ksql_stmt_alloc(r->arg, &stmt, + stmts[STMT_SERIE_AUTHORS], + STMT_SERIE_AUTHORS); + ksql_bind_int(stmt, 0, id); + while (KSQL_ROW == ksql_stmt_step(stmt)) { + item = kcalloc(1, sizeof(struct seriesauth)); + item->a = kcalloc(1, sizeof(Author)); + item->a->id = ksql_stmt_int(stmt, 0); + item->a->name = kstrdup(ksql_stmt_str(stmt, 1)); + item->s = &series->s; + item->s->asize++; + + item->p = p; + p = item; + } + ksql_stmt_free(stmt); + + db_assign_series_authors(p); + + return series; +} + +int +db_series_load(struct kreq *r, SeriesAdv **series, int limit, int offset) +{ + if (limit < 0 || offset < 0) { + return 0; + } + struct ksqlstmt *stmt; + int count = 0; + struct seriesauth *p = NULL; + + ksql_stmt_alloc(r->arg, &stmt, + stmts[STMT_SERIES], + STMT_SERIES); + ksql_bind_int(stmt, 0, limit); + ksql_bind_int(stmt, 1, offset); + while (KSQL_ROW == ksql_stmt_step(stmt)) { + series[count] = kcalloc(1, sizeof(SeriesAdv)); + series[count]->s.id = ksql_stmt_int(stmt, 0); + series[count]->s.name = kstrdup(ksql_stmt_str(stmt, 1)); + series[count]->books = ksql_stmt_int(stmt, 2); + series[count]->asize = 0; + count++; + } + ksql_stmt_free(stmt); + + ksql_stmt_alloc(r->arg, &stmt, + stmts[STMT_SERIES_AUTHORS], + STMT_SERIES_AUTHORS); + ksql_bind_int(stmt, 0, limit); + ksql_bind_int(stmt, 1, offset); + p = db_load_series_authors(series, count, stmt); + ksql_stmt_free(stmt); + + db_assign_series_authors(p); + + return count; +} diff --git a/extern.h b/extern.h index eabd777..ddc63a2 100644 --- a/extern.h +++ b/extern.h @@ -14,6 +14,8 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "ksql.h" + #ifndef EXTERN_H #define EXTERN_H @@ -100,6 +102,47 @@ typedef struct char *publisher; } BookFull; +typedef struct +{ + Series s; + int64_t books; + Author **a; + size_t asize; +} SeriesAdv; + +typedef struct +{ + SeriesAdv s; + Book **b; +} SeriesFull; + +/* + * Linked list authors of book. + */ +struct bookauth { + Author *a; + BookAdv *b; + struct bookauth *p; +}; + +/* + * Linked list tags of book. + */ +struct booktag { + char *tag; + BookAdv *b; + struct booktag *p; +}; + +/* + * Linked list book data. + */ +struct bookdata { + BookData *d; + BookFull *b; + struct bookdata *p; +}; + __BEGIN_DECLS BookFull *db_book_load(struct kreq *r, int64_t id); @@ -108,14 +151,23 @@ int db_books_count(struct kreq *r); void db_book_free(Book *p); void db_book_adv_free(BookAdv *p); void db_book_full_free(BookFull *p); +void db_book_fill(Book *book, struct ksqlstmt *stmt); +struct bookauth * db_load_books_authors(BookAdv **books, int count, struct ksqlstmt *stmt); +void db_assign_book_authors(struct bookauth *list); +void db_author_unfill(Author *p); 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_adv_free(AuthorAdv *p); +void db_series_unfill(Series *p); +int db_series_load(struct kreq *r, SeriesAdv **series, int limit, int offset); +SeriesFull *db_serie_load(struct kreq *r, int64_t id); void db_series_free(Series *p); +void db_series_adv_free(SeriesAdv *p); +char * strornull(struct ksqlstmt *stmt, int col); void db_close(struct kreq *); int db_open(struct kreq *, const char *); diff --git a/main.c b/main.c index 4825dc2..38ea655 100644 --- a/main.c +++ b/main.c @@ -313,12 +313,68 @@ static void sendseries(struct kreq *r) { struct kjsonreq req; + int res, i = 0; + SeriesFull *s = NULL; + + int page = initpage(r); + int per = initperpage(r); + int64_t id = idfrompath(r); http_open(r, KHTTP_200); kjson_open(&req, r); - kjson_obj_open(&req); - kjson_putstringp(&req, "data", "series"); - kjson_obj_close(&req); + + if (id >= 0) + s = db_serie_load(r, id); + if (id >= 0 && NULL == s) { + puterror(&req, "Unknown series"); + } else if (id >= 0) { + kjson_obj_open(&req); + kjson_putintp(&req, "id", s->s.s.id); + kjson_putstringp(&req, "name", s->s.s.name); + if (s->s.books>0) { + kjson_arrayp_open(&req, "books"); + for (int64_t j = 0; js.books; j++) { + putbook(&req, s->b[j]); + kjson_obj_close(&req); + } + kjson_array_close(&req); + } + if (s->s.asize > 0) { + kjson_arrayp_open(&req, "authors"); + for (size_t j=0; js.asize; j++) { + putauthor(&req, s->s.a[j]); + kjson_obj_close(&req); + } + kjson_array_close(&req); + } + kjson_obj_close(&req); + } else { + kjson_array_open(&req); + SeriesAdv **series = kcalloc(per, sizeof(SeriesAdv)); + res = db_series_load(r, series, per, per * (page-1)); + while (i < res) { + kjson_obj_open(&req); + kjson_putintp(&req, "id", series[i]->s.id); + kjson_putstringp(&req, "name", series[i]->s.name); + kjson_putintp(&req, "count", series[i]->books); + if (series[i]->asize > 0) { + kjson_arrayp_open(&req, "authors"); + for (size_t j=0; jasize; j++) { + kjson_obj_open(&req); + kjson_putintp(&req, "id", series[i]->a[j]->id); + kjson_putstringp(&req, "name", series[i]->a[j]->name); + kjson_obj_close(&req); + } + kjson_array_close(&req); + } + kjson_obj_close(&req); + db_series_adv_free(series[i]); + i++; + } + free(series); + kjson_array_close(&req); + } + kjson_close(&req); }