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