parent
5889fad361
commit
3bcf92b638
@ -0,0 +1,47 @@
|
||||
-- Un usuario solo puede tener un carrito. Antes había únicamente un índice no
|
||||
-- único y dos primeras peticiones simultáneas podían crear dos carritos.
|
||||
--
|
||||
-- La migración conserva el carrito más antiguo de cada usuario, copia en él
|
||||
-- los elementos de los demás y elimina los duplicados antes de crear la guarda.
|
||||
|
||||
WITH canonicos AS (
|
||||
SELECT usuario_id, min(creado_en) AS primera_fecha
|
||||
FROM carrito
|
||||
WHERE usuario_id IS NOT NULL
|
||||
GROUP BY usuario_id
|
||||
), elegidos AS (
|
||||
SELECT c.usuario_id, min(c.id) AS carrito_id
|
||||
FROM carrito c
|
||||
INNER JOIN canonicos x
|
||||
ON x.usuario_id = c.usuario_id AND x.primera_fecha = c.creado_en
|
||||
GROUP BY c.usuario_id
|
||||
)
|
||||
INSERT INTO carrito_item (carrito_id, cancion_id, anadido_en)
|
||||
SELECT e.carrito_id, ci.cancion_id, min(ci.anadido_en)
|
||||
FROM carrito c
|
||||
INNER JOIN elegidos e ON e.usuario_id = c.usuario_id
|
||||
INNER JOIN carrito_item ci ON ci.carrito_id = c.id
|
||||
WHERE c.id <> e.carrito_id
|
||||
GROUP BY e.carrito_id, ci.cancion_id
|
||||
ON CONFLICT (carrito_id, cancion_id) DO NOTHING;--> statement-breakpoint
|
||||
|
||||
WITH canonicos AS (
|
||||
SELECT usuario_id, min(creado_en) AS primera_fecha
|
||||
FROM carrito
|
||||
WHERE usuario_id IS NOT NULL
|
||||
GROUP BY usuario_id
|
||||
), elegidos AS (
|
||||
SELECT c.usuario_id, min(c.id) AS carrito_id
|
||||
FROM carrito c
|
||||
INNER JOIN canonicos x
|
||||
ON x.usuario_id = c.usuario_id AND x.primera_fecha = c.creado_en
|
||||
GROUP BY c.usuario_id
|
||||
)
|
||||
DELETE FROM carrito c
|
||||
USING elegidos e
|
||||
WHERE c.usuario_id = e.usuario_id AND c.id <> e.carrito_id;--> statement-breakpoint
|
||||
|
||||
DROP INDEX IF EXISTS "carrito_usuario";--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX "carrito_usuario_unico"
|
||||
ON "carrito" ("usuario_id")
|
||||
WHERE "usuario_id" IS NOT NULL;
|
||||
@ -0,0 +1,33 @@
|
||||
/** Registro auditable del inicio de una descarga autorizada. */
|
||||
|
||||
import { eq } from 'drizzle-orm';
|
||||
import { db } from './db';
|
||||
import { cancion, descarga } from './db/schema';
|
||||
|
||||
export interface EntregaIniciada {
|
||||
usuarioId: string;
|
||||
cancionSlug: string;
|
||||
ip: string | null;
|
||||
agente: string | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registra que el servidor ha empezado a entregar el archivo. No afirma que el
|
||||
* navegador haya terminado de guardarlo: HTTP no proporciona ese acuse.
|
||||
*/
|
||||
export async function registrarEntregaIniciada(datos: EntregaIniciada): Promise<void> {
|
||||
const [tema] = await db
|
||||
.select({ id: cancion.id })
|
||||
.from(cancion)
|
||||
.where(eq(cancion.slug, datos.cancionSlug))
|
||||
.limit(1);
|
||||
|
||||
if (!tema) throw new Error(`No existe la canción descargada «${datos.cancionSlug}».`);
|
||||
|
||||
await db.insert(descarga).values({
|
||||
usuarioId: datos.usuarioId,
|
||||
cancionId: tema.id,
|
||||
ip: datos.ip,
|
||||
agente: datos.agente
|
||||
});
|
||||
}
|
||||
Loading…
Reference in new issue