Implementando métricas avançadas com SQL complexo e análises em tempo real
O dashboard do Restaurantix implementa métricas avançadas para análise de negócio em tempo real.
// src/http/routes/get-month-revenue.ts import { and, eq, gte, sql, sum, lte } from "drizzle-orm"; import { db } from "@/application/infra/db/connection"; import { orders } from "@/application/infra/db/schema"; import { auth } from "../auth"; import { UnauthorizedError } from "../errors/unauthorized-error"; import dayjs from "dayjs"; export const getMonthRevenue = auth.get( "/metrics/month-revenue", async ({ getCurrentUser }) => { const { restaurantId } = await getCurrentUser(); if (!restaurantId) { throw new UnauthorizedError(); } // Configurar período de análise const today = dayjs(); const lastMonth = today.subtract(1, "month"); const startOfLastMonth = lastMonth.startOf("month"); // Query com agrupamento por mês/ano const monthRevenue = await db .select({ monthWithYear: sql<string>`TO_CHAR(${orders.createdAt}, 'YYYY-MM')`, total: sum(orders.priceInCents).mapWith(Number), }) .from(orders) .where( and( eq(orders.restaurantId, restaurantId), gte(orders.createdAt, startOfLastMonth.toDate()), lte(orders.createdAt, today.toDate()), ), ) .groupBy(sql`TO_CHAR(${orders.createdAt}, 'YYYY-MM')`); // Calcular percentual de crescimento const diffFromLastMonth = currentMonthRevenue && lastMonthRevenue ? (currentMonthRevenue.total * 100) / lastMonthRevenue.total : null; return { currentMonthRevenue, lastMonthRevenue, diffFromLastMonth: diffFromLastMonth ? Number((diffFromLastMonth - 100).toFixed(2)) : 0, }; }, );
// src/http/routes/get-popular-products.ts import { sum, eq, desc, type SQLWrapper } from "drizzle-orm"; import { db } from "@/application/infra/db/connection"; import { orderItems, orders, products } from "@/application/infra/db/schema"; import { auth } from "@/http/auth"; import { UnauthorizedError } from "@/http/errors/unauthorized-error"; export const getPopularProducts = auth.get( "/metrics/popular-products", async ({ getCurrentUser }) => { const { restaurantId } = await getCurrentUser(); if (!restaurantId) { throw new UnauthorizedError(); } // Query com múltiplos JOINs const popularProducts = await db .select({ productName: products.name, amount: sum(orderItems.quantity).mapWith(Number), }) .from(orderItems) .leftJoin(orders, eq(orders.id, orderItems.orderId)) .leftJoin(products, eq(products.id, orderItems.productId)) .where(eq(orders.restaurantId, restaurantId)) .groupBy(products.name) .orderBy((fields: { amount: SQLWrapper }) => { return desc(fields.amount); }) .limit(50); return popularProducts; }, );
Implemente o sistema completo de métricas do Restaurantix: