UNPKG

drizzle-cube

Version:

Drizzle ORM-first semantic layer with Cube.js compatibility. Type-safe analytics and dashboards with SQL injection protection.

213 lines (212 loc) 6.36 kB
import j, { Router as E } from "express"; import R from "cors"; import { S, d as s, f as x, h as $, a as L, b as Q, c as g } from "../compiler-Duyh6Jp-.js"; function N(f) { const { cubes: d, drizzle: m, schema: q, extractSecurityContext: y, engineType: v, cors: b, basePath: c = "/cubejs-api/v1", jsonLimit: h = "10mb", cache: w } = f; if (!d || d.length === 0) throw new Error("At least one cube must be provided in the cubes array"); const u = E(); b && u.use(R(b)), u.use(j.json({ limit: h })), u.use(j.urlencoded({ extended: !0, limit: h })); const a = new S({ drizzle: m, schema: q, engineType: v, cache: w }); return d.forEach((t) => { a.registerCube(t); }), u.post(`${c}/load`, async (t, r) => { try { const e = t.body.query || t.body, o = await y(t, r), n = a.validateQuery(e); if (!n.isValid) return r.status(400).json(s( `Query validation failed: ${n.errors.join(", ")}`, 400 )); const i = await a.executeMultiCubeQuery(e, o); r.json(x(e, i, a)); } catch (e) { console.error("Query execution error:", e), r.status(500).json(s( e instanceof Error ? e.message : "Query execution failed", 500 )); } }), u.get(`${c}/load`, async (t, r) => { try { const e = t.query.query; if (!e) return r.status(400).json(s( "Query parameter is required", 400 )); let o; try { o = JSON.parse(e); } catch { return r.status(400).json(s( "Invalid JSON in query parameter", 400 )); } const n = await y(t, r), i = a.validateQuery(o); if (!i.isValid) return r.status(400).json(s( `Query validation failed: ${i.errors.join(", ")}`, 400 )); const l = await a.executeMultiCubeQuery(o, n); r.json(x(o, l, a)); } catch (e) { console.error("Query execution error:", e), r.status(500).json(s( e instanceof Error ? e.message : "Query execution failed", 500 )); } }), u.post(`${c}/batch`, async (t, r) => { try { const { queries: e } = t.body; if (!e || !Array.isArray(e)) return r.status(400).json(s( 'Request body must contain a "queries" array', 400 )); if (e.length === 0) return r.status(400).json(s( "Queries array cannot be empty", 400 )); const o = await y(t, r), n = await $(e, o, a); r.json(n); } catch (e) { console.error("Batch execution error:", e), r.status(500).json(s( e instanceof Error ? e.message : "Batch execution failed", 500 )); } }), u.get(`${c}/meta`, (t, r) => { try { const e = a.getMetadata(); r.json(L(e)); } catch (e) { console.error("Metadata error:", e), r.status(500).json(s( e instanceof Error ? e.message : "Failed to fetch metadata", 500 )); } }), u.post(`${c}/sql`, async (t, r) => { try { const e = t.body, o = await y(t, r), n = a.validateQuery(e); if (!n.isValid) return r.status(400).json(s( `Query validation failed: ${n.errors.join(", ")}`, 400 )); const i = e.measures?.[0] || e.dimensions?.[0]; if (!i) return r.status(400).json(s( "No measures or dimensions specified", 400 )); const l = i.split(".")[0], p = await a.generateSQL(l, e, o); r.json(Q(e, p)); } catch (e) { console.error("SQL generation error:", e), r.status(500).json(s( e instanceof Error ? e.message : "SQL generation failed", 500 )); } }), u.get(`${c}/sql`, async (t, r) => { try { const e = t.query.query; if (!e) return r.status(400).json(s( "Query parameter is required", 400 )); const o = JSON.parse(e), n = await y(t, r), i = a.validateQuery(o); if (!i.isValid) return r.status(400).json(s( `Query validation failed: ${i.errors.join(", ")}`, 400 )); const l = o.measures?.[0] || o.dimensions?.[0]; if (!l) return r.status(400).json(s( "No measures or dimensions specified", 400 )); const p = l.split(".")[0], C = await a.generateSQL(p, o, n); r.json(Q(o, C)); } catch (e) { console.error("SQL generation error:", e), r.status(500).json(s( e instanceof Error ? e.message : "SQL generation failed", 500 )); } }), u.post(`${c}/dry-run`, async (t, r) => { try { const e = t.body.query || t.body, o = await y(t, r), n = await g(e, o, a); r.json(n); } catch (e) { console.error("Dry-run error:", e), r.status(400).json({ error: e instanceof Error ? e.message : "Dry-run validation failed", valid: !1 }); } }), u.get(`${c}/dry-run`, async (t, r) => { try { const e = t.query.query; if (!e) return r.status(400).json({ error: "Query parameter is required", valid: !1 }); const o = JSON.parse(e), n = await y(t, r), i = await g(o, n, a); r.json(i); } catch (e) { console.error("Dry-run error:", e), r.status(400).json({ error: e instanceof Error ? e.message : "Dry-run validation failed", valid: !1 }); } }), u.post(`${c}/explain`, async (t, r) => { try { const e = t.body.query || t.body, o = t.body.options || {}, n = await y(t, r), i = a.validateQuery(e); if (!i.isValid) return r.status(400).json({ error: `Query validation failed: ${i.errors.join(", ")}` }); const l = await a.explainQuery(e, n, o); r.json(l); } catch (e) { console.error("Explain error:", e), r.status(500).json({ error: e instanceof Error ? e.message : "Explain query failed" }); } }), u.use((t, r, e, o) => { console.error("Express adapter error:", t), e.headersSent || e.status(500).json(s(t, 500)); }), u; } function M(f, d) { const m = N(d); return f.use("/", m), f; } function J(f) { const d = j(); return M(d, f); } export { J as createCubeApp, N as createCubeRouter, M as mountCubeRoutes };