This commit is contained in:
Cat /dev/Nulo 2024-08-04 15:30:59 -03:00
parent a3bdc59b73
commit 76db90618c
2 changed files with 68 additions and 19 deletions

View file

@ -213,6 +213,51 @@ order by fetched_at
Json(precios) Json(precios)
} }
async fn search(State(pool): State<SqlitePool>, Path(query): Path<String>) -> impl IntoResponse {
let sql_query = query
.clone()
.replace("\"", "\"\"")
.split(" ")
.map(|x| format!("\"{}\"", x))
.join(" ");
#[derive(Serialize)]
struct Result {
ean: String,
name: String,
image_url: String,
}
let results = sqlx::query!(
"with search_results as (
select f.ean from precios_fts f
where f.name match ? and f.ean != ''
group by f.ean
limit 100
)
select p.id, p.ean, p.name, p.image_url from search_results as s
join precios as p
on p.ean = s.ean
where p.fetched_at = (
SELECT MAX(fetched_at)
FROM precios as pf
WHERE pf.ean = s.ean and pf.name is not null
);",
sql_query
)
.fetch_all(&pool)
.await
.unwrap()
.into_iter()
.map(|r| Result {
ean: r.ean,
image_url: r.image_url.unwrap(),
name: r.name.unwrap(),
})
.collect_vec();
Json(results)
}
async fn get_info(State(pool): State<SqlitePool>) -> impl IntoResponse { async fn get_info(State(pool): State<SqlitePool>) -> impl IntoResponse {
#[derive(Serialize)] #[derive(Serialize)]
@ -267,6 +312,7 @@ async fn main() {
.route("/api/0/best-selling-products", get(get_best_selling)) .route("/api/0/best-selling-products", get(get_best_selling))
.route("/api/0/ean/:ean/history", get(get_product_history)) .route("/api/0/ean/:ean/history", get(get_product_history))
.route("/api/0/info", get(get_info)) .route("/api/0/info", get(get_info))
.route("/api/0/search/:query", get(search))
.with_state(pool); .with_state(pool);
let listener = tokio::net::TcpListener::bind("0.0.0.0:8000").await.unwrap(); let listener = tokio::net::TcpListener::bind("0.0.0.0:8000").await.unwrap();

View file

@ -1,26 +1,29 @@
import { sql } from "drizzle-orm"; import { z } from "zod";
import type { PageServerLoad } from "./$types"; import type { PageServerLoad } from "./$types";
import { getDb } from "$lib/server/db"; import { API_HOST } from "$lib";
import ky from "ky";
const zProductResult = z.object({
ean: z.string(),
name: z.string(),
image_url: z.string(),
});
async function search(query: string) {
return z
.array(zProductResult)
.parse(
await ky
.get(`${API_HOST}/api/0/search/${encodeURIComponent(query)}`)
.json(),
);
}
export const load: PageServerLoad = async ({ url }) => { export const load: PageServerLoad = async ({ url }) => {
const db = await getDb();
const query = url.searchParams.get("q"); const query = url.searchParams.get("q");
let results: null | { ean: string; name: string; imageUrl: string }[] = null; let results: null | { ean: string; name: string; image_url: string }[] = query
if (query) { ? await search(query)
const sQuery = query : null;
.replaceAll(`"`, `""`)
.split(" ")
.map((s) => `"${s}"`)
.join(" ");
console.debug(sQuery);
const sqlQuery = sql`select p.ean, p.name, p.image_url as imageUrl from precios_fts f
join precios p on p.ean = f.ean
where f.name match ${sQuery}
group by p.ean
having max(p.fetched_at)
order by p.in_stock desc;`;
results = db.all(sqlQuery);
}
return { query, results }; return { query, results };
}; };