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