drizzle-cube
Version:
Drizzle ORM-first semantic layer with Cube.js compatibility. Type-safe analytics and dashboards with SQL injection protection.
225 lines (224 loc) • 7.67 kB
JavaScript
import { Hono as x } from "hono";
import { S as Q, f as p, h as v, a as b, b as w, c as g } from "../compiler-Duyh6Jp-.js";
var A = (q) => {
const u = {
...{
origin: "*",
allowMethods: ["GET", "HEAD", "PUT", "POST", "DELETE", "PATCH"],
allowHeaders: [],
exposeHeaders: []
},
...q
}, j = /* @__PURE__ */ ((i) => typeof i == "string" ? i === "*" ? () => i : (n) => i === n ? n : null : typeof i == "function" ? i : (n) => i.includes(n) ? n : null)(u.origin), y = ((i) => typeof i == "function" ? i : Array.isArray(i) ? () => i : () => [])(u.allowMethods);
return async function(n, c) {
function f(o, r) {
n.res.headers.set(o, r);
}
const l = await j(n.req.header("origin") || "", n);
if (l && f("Access-Control-Allow-Origin", l), u.credentials && f("Access-Control-Allow-Credentials", "true"), u.exposeHeaders?.length && f("Access-Control-Expose-Headers", u.exposeHeaders.join(",")), n.req.method === "OPTIONS") {
u.origin !== "*" && f("Vary", "Origin"), u.maxAge != null && f("Access-Control-Max-Age", u.maxAge.toString());
const o = await y(n.req.header("origin") || "", n);
o.length && f("Access-Control-Allow-Methods", o.join(","));
let r = u.allowHeaders;
if (!r?.length) {
const e = n.req.header("Access-Control-Request-Headers");
e && (r = e.split(/\s*,\s*/));
}
return r?.length && (f("Access-Control-Allow-Headers", r.join(",")), n.res.headers.append("Vary", "Access-Control-Request-Headers")), n.res.headers.delete("Content-Length"), n.res.headers.delete("Content-Type"), new Response(null, {
headers: n.res.headers,
status: 204,
statusText: "No Content"
});
}
await c(), u.origin !== "*" && n.header("Vary", "Origin", { append: !0 });
};
};
function E(q) {
const {
cubes: m,
drizzle: u,
schema: j,
extractSecurityContext: y,
engineType: i,
cors: n,
basePath: c = "/cubejs-api/v1",
cache: f
} = q;
if (!m || m.length === 0)
throw new Error("At least one cube must be provided in the cubes array");
const l = new x();
n && l.use("/*", A(n));
const o = new Q({
drizzle: u,
schema: j,
engineType: i,
cache: f
});
return m.forEach((r) => {
o.registerCube(r);
}), l.post(`${c}/load`, async (r) => {
try {
const e = await r.req.json(), t = e.query || e, a = await y(r), s = o.validateQuery(t);
if (!s.isValid)
return r.json({
error: `Query validation failed: ${s.errors.join(", ")}`
}, 400);
const d = await o.executeMultiCubeQuery(t, a);
return r.json(p(t, d, o));
} catch (e) {
return console.error("Query execution error:", e), r.json({
error: e instanceof Error ? e.message : "Query execution failed"
}, 500);
}
}), l.get(`${c}/load`, async (r) => {
try {
const e = r.req.query("query");
if (!e)
return r.json({
error: "Query parameter is required"
}, 400);
let t;
try {
t = JSON.parse(e);
} catch {
return r.json({
error: "Invalid JSON in query parameter"
}, 400);
}
const a = await y(r), s = o.validateQuery(t);
if (!s.isValid)
return r.json({
error: `Query validation failed: ${s.errors.join(", ")}`
}, 400);
const d = await o.executeMultiCubeQuery(t, a);
return r.json(p(t, d, o));
} catch (e) {
return console.error("Query execution error:", e), r.json({
error: e instanceof Error ? e.message : "Query execution failed"
}, 500);
}
}), l.post(`${c}/batch`, async (r) => {
try {
const e = await r.req.json(), { queries: t } = e;
if (!t || !Array.isArray(t))
return r.json({
error: 'Request body must contain a "queries" array'
}, 400);
if (t.length === 0)
return r.json({
error: "Queries array cannot be empty"
}, 400);
const a = await y(r), s = await v(t, a, o);
return r.json(s);
} catch (e) {
return console.error("Batch execution error:", e), r.json({
error: e instanceof Error ? e.message : "Batch execution failed"
}, 500);
}
}), l.get(`${c}/meta`, (r) => {
try {
const e = o.getMetadata();
return r.json(b(e));
} catch (e) {
return console.error("Metadata error:", e), r.json({
error: e instanceof Error ? e.message : "Failed to fetch metadata"
}, 500);
}
}), l.post(`${c}/sql`, async (r) => {
try {
const e = await r.req.json(), t = await y(r), a = o.validateQuery(e);
if (!a.isValid)
return r.json({
error: `Query validation failed: ${a.errors.join(", ")}`
}, 400);
const s = e.measures?.[0] || e.dimensions?.[0];
if (!s)
return r.json({
error: "No measures or dimensions specified"
}, 400);
const d = s.split(".")[0], h = await o.generateSQL(d, e, t);
return r.json(w(e, h));
} catch (e) {
return console.error("SQL generation error:", e), r.json({
error: e instanceof Error ? e.message : "SQL generation failed"
}, 500);
}
}), l.get(`${c}/sql`, async (r) => {
try {
const e = r.req.query("query");
if (!e)
return r.json({
error: "Query parameter is required"
}, 400);
const t = JSON.parse(e), a = await y(r), s = o.validateQuery(t);
if (!s.isValid)
return r.json({
error: `Query validation failed: ${s.errors.join(", ")}`
}, 400);
const d = t.measures?.[0] || t.dimensions?.[0];
if (!d)
return r.json({
error: "No measures or dimensions specified"
}, 400);
const h = d.split(".")[0], C = await o.generateSQL(h, t, a);
return r.json(w(t, C));
} catch (e) {
return console.error("SQL generation error:", e), r.json({
error: e instanceof Error ? e.message : "SQL generation failed"
}, 500);
}
}), l.post(`${c}/dry-run`, async (r) => {
try {
const e = await r.req.json(), t = e.query || e, a = await y(r), s = await g(t, a, o);
return r.json(s);
} catch (e) {
return console.error("Dry-run error:", e), r.json({
error: e instanceof Error ? e.message : "Dry-run validation failed",
valid: !1
}, 400);
}
}), l.get(`${c}/dry-run`, async (r) => {
try {
const e = r.req.query("query");
if (!e)
return r.json({
error: "Query parameter is required",
valid: !1
}, 400);
const t = JSON.parse(e), a = await y(r), s = await g(t, a, o);
return r.json(s);
} catch (e) {
return console.error("Dry-run error:", e), r.json({
error: e instanceof Error ? e.message : "Dry-run validation failed",
valid: !1
}, 400);
}
}), l.post(`${c}/explain`, async (r) => {
try {
const e = await r.req.json(), t = e.query || e, a = e.options || {}, s = await y(r), d = o.validateQuery(t);
if (!d.isValid)
return r.json({
error: `Query validation failed: ${d.errors.join(", ")}`
}, 400);
const h = await o.explainQuery(t, s, a);
return r.json(h);
} catch (e) {
return console.error("Explain error:", e), r.json({
error: e instanceof Error ? e.message : "Explain query failed"
}, 500);
}
}), l;
}
function S(q, m) {
const u = E(m);
return q.route("/", u), q;
}
function H(q) {
const m = new x();
return S(m, q);
}
export {
H as createCubeApp,
E as createCubeRoutes,
S as mountCubeRoutes
};