mirror of
https://github.com/catdevnull/preciazo.git
synced 2024-11-22 22:26:19 +00:00
renderizar best selling en sitio!
This commit is contained in:
parent
ca9809178a
commit
65d1cc200c
5 changed files with 86 additions and 110 deletions
|
@ -42,6 +42,9 @@ importers:
|
|||
drizzle-orm:
|
||||
specifier: ^0.29.1
|
||||
version: 0.29.3(@types/better-sqlite3@7.6.8)(better-sqlite3@9.2.2)
|
||||
zod:
|
||||
specifier: ^3.22.4
|
||||
version: 3.22.4
|
||||
devDependencies:
|
||||
'@sveltejs/adapter-node':
|
||||
specifier: ^2.0.2
|
||||
|
@ -2859,4 +2862,3 @@ packages:
|
|||
|
||||
/zod@3.22.4:
|
||||
resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==}
|
||||
dev: true
|
||||
|
|
|
@ -14,8 +14,11 @@
|
|||
"format": "prettier --write ."
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/adapter-node": "^2.0.2",
|
||||
"@sveltejs/kit": "^2.0.0",
|
||||
"@sveltejs/vite-plugin-svelte": "^3.0.0",
|
||||
"@types/better-sqlite3": "^7.6.8",
|
||||
"@types/node": "^20.10.6",
|
||||
"autoprefixer": "^10.4.16",
|
||||
"db-datos": "workspace:^",
|
||||
"postcss": "^8.4.32",
|
||||
|
@ -28,10 +31,7 @@
|
|||
"tailwindcss": "^3.3.6",
|
||||
"tslib": "^2.4.1",
|
||||
"typescript": "^5.0.0",
|
||||
"vite": "^5.0.3",
|
||||
"@sveltejs/adapter-node": "^2.0.2",
|
||||
"@types/better-sqlite3": "^7.6.8",
|
||||
"@types/node": "^20.10.6"
|
||||
"vite": "^5.0.3"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
|
@ -39,6 +39,7 @@
|
|||
"chart.js": "^4.4.1",
|
||||
"chartjs-adapter-dayjs-4": "^1.0.4",
|
||||
"dayjs": "^1.11.10",
|
||||
"drizzle-orm": "^0.29.1"
|
||||
"drizzle-orm": "^0.29.1",
|
||||
"zod": "^3.22.4"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,19 @@
|
|||
<script lang="ts">
|
||||
export let product: { ean: string; name: string; imageUrl?: string | null };
|
||||
<script lang="ts" context="module">
|
||||
export type Product = { ean: string; name: string; imageUrl: string | null };
|
||||
</script>
|
||||
|
||||
<a href={`/ean/${product.ean}`} class="flex">
|
||||
<script lang="ts">
|
||||
export let product: Product;
|
||||
</script>
|
||||
|
||||
<a href={`/ean/${product.ean}`} class="flex gap-2">
|
||||
{#if product.imageUrl}
|
||||
<img src={product.imageUrl} alt={product.name} class="max-h-48" />
|
||||
<img
|
||||
src={product.imageUrl}
|
||||
alt={product.name}
|
||||
class="max-h-48"
|
||||
loading="lazy"
|
||||
/>
|
||||
{/if}
|
||||
<p class="text-xl">{product.name}</p>
|
||||
</a>
|
||||
|
|
|
@ -1,64 +1,60 @@
|
|||
import type { PageData, PageServerLoad } from "./$types";
|
||||
import { getDb, schema } from "$lib/server/db";
|
||||
const { precios } = schema;
|
||||
import { desc, sql } from "drizzle-orm";
|
||||
const { precios, bestSelling } = schema;
|
||||
import { desc, max, sql } from "drizzle-orm";
|
||||
import {
|
||||
Supermercado,
|
||||
hostBySupermercado,
|
||||
supermercados,
|
||||
} from "db-datos/supermercado";
|
||||
import z from "zod";
|
||||
import type { Product } from "$lib/ProductPreview.svelte";
|
||||
|
||||
let cache: Promise<{ key: Date; data: { precios: Precios } }> = doQuery();
|
||||
type Data = {
|
||||
category: string;
|
||||
products: Product[];
|
||||
}[];
|
||||
|
||||
let cache: Promise<{ key: Date; data: Data }> = doQuery();
|
||||
|
||||
async function doQuery() {
|
||||
const db = await getDb();
|
||||
console.time("ean");
|
||||
const eans = await db
|
||||
|
||||
const categories = await db
|
||||
.select({
|
||||
ean: precios.ean,
|
||||
fetchedAt: bestSelling.fetchedAt,
|
||||
category: bestSelling.category,
|
||||
eansJson: bestSelling.eansJson,
|
||||
})
|
||||
.from(precios)
|
||||
.groupBy(precios.ean)
|
||||
.orderBy(sql`random()`)
|
||||
.limit(50);
|
||||
console.timeEnd("ean");
|
||||
.from(bestSelling)
|
||||
.groupBy(bestSelling.category)
|
||||
.having(max(bestSelling.fetchedAt));
|
||||
|
||||
return;
|
||||
const categoriesWithProducts = await Promise.all(
|
||||
categories.map(async (category) => {
|
||||
const eans = z.array(z.string()).parse(JSON.parse(category.eansJson));
|
||||
|
||||
const precioss = await Promise.all(
|
||||
supermercados.map(
|
||||
async (
|
||||
supermercado,
|
||||
): Promise<
|
||||
[
|
||||
Supermercado,
|
||||
{ ean: string; name: string | null; imageUrl: string | null }[],
|
||||
]
|
||||
> => {
|
||||
const host = hostBySupermercado[supermercado];
|
||||
console.time(supermercado);
|
||||
const q = db
|
||||
const products = await db
|
||||
.select({
|
||||
ean: precios.ean,
|
||||
name: precios.name,
|
||||
imageUrl: precios.imageUrl,
|
||||
})
|
||||
.from(precios)
|
||||
.where(sql`${precios.ean} in ${eans}`)
|
||||
.groupBy(precios.ean)
|
||||
.having(sql`max(fetched_at)`)
|
||||
.where(
|
||||
sql`ean in ${eans.map((x) => x.ean)} and in_stock and url like ${`%${host}%`}`,
|
||||
.having(max(precios.fetchedAt));
|
||||
|
||||
return {
|
||||
category: category.category,
|
||||
products: eans
|
||||
.map((ean) => products.find((p) => p.ean === ean))
|
||||
.filter((x): x is Product => !!x && !!x.name),
|
||||
};
|
||||
}),
|
||||
);
|
||||
// console.debug(q.toSQL());
|
||||
const res = await q;
|
||||
console.timeEnd(supermercado);
|
||||
return [supermercado, res];
|
||||
},
|
||||
),
|
||||
);
|
||||
const data = { precios: precioss.flatMap(([_, r]) => r) };
|
||||
return { key: new Date(), data };
|
||||
|
||||
return { key: new Date(), data: categoriesWithProducts };
|
||||
}
|
||||
|
||||
setInterval(
|
||||
|
@ -69,14 +65,8 @@ setInterval(
|
|||
4 * 60 * 60 * 1000,
|
||||
);
|
||||
|
||||
type Precios = {
|
||||
ean: string;
|
||||
name: string | null;
|
||||
imageUrl: string | null;
|
||||
}[];
|
||||
|
||||
export const load: PageServerLoad = async ({
|
||||
params,
|
||||
}): Promise<{ precios: Precios }> => {
|
||||
return (await cache).data;
|
||||
}): Promise<{ data: Data }> => {
|
||||
return { data: (await cache).data };
|
||||
};
|
||||
|
|
|
@ -3,53 +3,27 @@
|
|||
import type { PageData } from "./$types";
|
||||
|
||||
export let data: PageData;
|
||||
$: precios = data.precios.filter(
|
||||
(d): d is { ean: string; name: string; imageUrl: string | null } =>
|
||||
!!d.name,
|
||||
);
|
||||
$: productos = precios.reduce(
|
||||
(prev, curr) => [
|
||||
...prev,
|
||||
...(prev.find((p) => p.ean === curr.ean) ? [] : [curr]),
|
||||
],
|
||||
[] as { ean: string; name: string; imageUrl: string | null }[],
|
||||
);
|
||||
|
||||
const categoryLabels: { [key in string]: string } = {
|
||||
almacen: "Almacen",
|
||||
bebidas: "Bebidas",
|
||||
"frutas-y-verduras": "Frutas y Verduras",
|
||||
};
|
||||
</script>
|
||||
|
||||
<h1 class="text-xl">WIP</h1>
|
||||
|
||||
<section>
|
||||
<h2 class="text-lg font-bold">Ejemplos</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="/ean/7790070410795">
|
||||
Cookies Sabor Vainilla Con Chips De Chocolate Exquisita Paq 300 Grm
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/ean/7794000006911">
|
||||
Sopa Instantánea KNORR QUICK Zapallo Romero Sobres 5 Un.
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/ean/7798062540253">Agua Saborizada Levité Pera 1,5 Lts.</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/ean/7790895000430">Gaseosa Coca-Cola Sabor Original 1,5 Lts.</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/ean/7792200000128">Bizcochos Agridulc 9 De Oro Paq 200 Grm</a>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2 class="text-lg font-bold">Random</h2>
|
||||
<ul class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3">
|
||||
{#each productos as product}
|
||||
<li>
|
||||
{#each data.data as { category, products }}
|
||||
<section class="my-6">
|
||||
<h2 class="text-2xl font-bold">
|
||||
{categoryLabels[category] ?? category}
|
||||
</h2>
|
||||
<ul
|
||||
class="grid max-w-full grid-flow-col grid-rows-2 gap-x-8 gap-y-4 overflow-x-auto"
|
||||
>
|
||||
{#each products as product}
|
||||
<li class="w-96">
|
||||
<ProductPreview {product} />
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
</section>
|
||||
</section>
|
||||
{/each}
|
||||
|
|
Loading…
Reference in a new issue