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