embryo till sök

This commit is contained in:
florpan 2025-09-09 17:41:55 +02:00
parent 01e341fce0
commit e23822b30c
6 changed files with 76 additions and 12 deletions

View File

@ -10,7 +10,7 @@ const AuthorCard: Component<{ author: author }> = (props: {
<Card.Img <Card.Img
variant="top" variant="top"
class="padding-1" class="padding-1"
src={"/api/biiblan/authorcover/" + encodeURIComponent(props.author.id)} src={"/api/bibblan/authorcover/" + encodeURIComponent(props.author.id)}
/> />
<Card.Body> <Card.Body>
<Card.Title>{props.author.name}</Card.Title> <Card.Title>{props.author.name}</Card.Title>

View File

@ -5,13 +5,26 @@ import { author } from "../types/types";
const BookList: Component = () => { const BookList: Component = () => {
const [authors, setAuthors] = createSignal<author[]>([]); const [authors, setAuthors] = createSignal<author[]>([]);
const [query, setQuery] = createSignal("");
const update = (query: string) => {
setQuery(query);
BibblanService.getAuthors(query).then(setAuthors);
};
onMount(() => { onMount(() => {
BibblanService.getAuthors().then(setAuthors); BibblanService.getAuthors().then(setAuthors);
}); });
return ( return (
<div> <div>
<h1>Books!</h1> <h1>Authors!</h1>
<input
type="text"
class="form-control mb-3"
placeholder="Search..."
onInput={(e) => update(e.currentTarget.value)}
/>
<div class="book-grid d-flex flex-wrap justify-content-between gap-3 p-3"> <div class="book-grid d-flex flex-wrap justify-content-between gap-3 p-3">
<For each={authors()}>{(item) => <AuthorCard author={item} />}</For> <For each={authors()}>{(item) => <AuthorCard author={item} />}</For>
</div> </div>

View File

@ -1,4 +1,4 @@
import { createSignal, onMount, For, type Component } from "solid-js"; import { createSignal, onMount, For, Show, type Component } from "solid-js";
import { useParams } from "@solidjs/router"; import { useParams } from "@solidjs/router";
import BookCard from "./BookCard"; import BookCard from "./BookCard";
import BibblanService from "../services/bibblanservice"; import BibblanService from "../services/bibblanservice";
@ -6,7 +6,14 @@ import { book } from "../types/types";
const BookList: Component = () => { const BookList: Component = () => {
const [books, setBooks] = createSignal<book[]>([]); const [books, setBooks] = createSignal<book[]>([]);
const [query, setQuery] = createSignal("");
const params = useParams(); const params = useParams();
const update = (query: string) => {
setQuery(query);
BibblanService.getBooks(params.authorid, query).then(setBooks);
};
onMount(() => { onMount(() => {
BibblanService.getBooks(params.authorid).then(setBooks); BibblanService.getBooks(params.authorid).then(setBooks);
}); });
@ -14,6 +21,14 @@ const BookList: Component = () => {
return ( return (
<div> <div>
<h1>Books!</h1> <h1>Books!</h1>
<Show when={!params.authorid}>
<input
type="text"
class="form-control mb-3"
placeholder="Search..."
onInput={(e) => update(e.currentTarget.value)}
/>
</Show>
<div class="book-grid d-flex flex-wrap justify-content-between gap-3 p-3"> <div class="book-grid d-flex flex-wrap justify-content-between gap-3 p-3">
<For each={books()}>{(item) => <BookCard book={item} />}</For> <For each={books()}>{(item) => <BookCard book={item} />}</For>
</div> </div>

View File

@ -2,18 +2,27 @@ import { book, author } from "../types/types";
const BibblanService = { const BibblanService = {
getBooks: async ( getBooks: async (
authorid: string | undefined = undefined authorid: string | undefined = undefined,
query: string | undefined = undefined
): Promise<book[]> => { ): Promise<book[]> => {
let url = "/api/bibblan/books"; let url = "/api/bibblan/books";
if (authorid != undefined) { if (authorid != undefined) {
url += `/author/${authorid}`; url += `/author/${authorid}`;
} else if (query != undefined && query.length > 0) {
url += `?query=${encodeURIComponent(query)}`;
} }
const response = await fetch(url); const response = await fetch(url);
return response.json(); return response.json();
}, },
getAuthors: async (): Promise<author[]> => { getAuthors: async (
const response = await fetch("/api/bibblan/authors"); query: string | undefined = undefined
): Promise<author[]> => {
let url = "/api/bibblan/authors";
if (query != undefined && query.length > 0) {
url += `?query=${encodeURIComponent(query)}`;
}
const response = await fetch(url);
return response.json(); return response.json();
}, },
}; };

View File

@ -10,6 +10,7 @@ namespace Bibblan.Business.Services
public class BookFilter public class BookFilter
{ {
public int? Author; public int? Author;
public string? Query;
} }
public class DatabaseService public class DatabaseService
@ -29,14 +30,23 @@ namespace Bibblan.Business.Services
if(filter.Author != null) if(filter.Author != null)
{ {
query += $"id in (select book from books_authors_link where author = {filter.Author})"; query += $"id in (select book from books_authors_link where author = {filter.Author})";
} else if(!String.IsNullOrWhiteSpace(query))
{
filter.Query = filter.Query.ToLowerInvariant();
query += $"lower(title) like '%{filter.Query}%' or lower(author_sort) like '%{filter.Query}%'";
} }
} }
return conn.Query<Books>(query).Take(count).ToList(); return conn.Query<Books>(query).Take(count).ToList();
} }
public IEnumerable<AuthorVm> GetAuthors(int count) public IEnumerable<AuthorVm> GetAuthors(int count, BookFilter filter = null)
{ {
var query = "select a.id, a.name, count(bal.*) as bookcount\r\nfrom authors a\r\nleft join books_authors_link bal on a.id = bal.author\r\ngroup by a.id , a.name "; var query = "select a.id, a.name, count(bal.*) as bookcount\r\nfrom authors a\r\nleft join books_authors_link bal on a.id = bal.author\r\ngroup by a.id , a.name ";
if(!String.IsNullOrWhiteSpace(filter?.Query))
{
filter.Query = filter.Query.ToLowerInvariant();
query += $" having lower(a.name) like '%{filter.Query}%'";
}
var conn = new NpgsqlConnection(settings.BibblanConnection); var conn = new NpgsqlConnection(settings.BibblanConnection);
return conn.Query<AuthorVm>(query).Take(count).ToList(); return conn.Query<AuthorVm>(query).Take(count).ToList();

View File

@ -25,16 +25,26 @@ namespace Bibblan.Controllers
} }
[HttpGet("books")] [HttpGet("books")]
public IActionResult GetBooks() public IActionResult GetBooks(string query = null)
{ {
var authors = _db.GetBooks(100).ToList(); BookFilter filter = query != null ? new BookFilter
return Ok(authors); {
Query = query
} : null;
var books = _db.GetBooks(100,filter).ToList();
return Ok(books);
} }
[HttpGet("authors")] [HttpGet("authors")]
public IActionResult GetAuthors() public IActionResult GetAuthors(string query = null)
{ {
var authors = _db.GetAuthors(100).ToList(); BookFilter filter = query != null ? new BookFilter
{
Query = query
} : null;
var authors = _db.GetAuthors(100, filter).ToList();
return Ok(authors); return Ok(authors);
} }
@ -48,6 +58,13 @@ namespace Bibblan.Controllers
return Ok(authors); return Ok(authors);
} }
[HttpGet("authorcover/{authorid}")]
public IActionResult GetAuthorCover(int authorid)
{
//TODO: fixa vid tillfälle
return Ok(new { desc = "picture of banana goes here"});
}
} }
} }