drizzle-cube
Version: 
Drizzle ORM-first semantic layer with Cube.js compatibility. Type-safe analytics and dashboards with SQL injection protection.
212 lines (211 loc) • 5.73 kB
JavaScript
import { S as j, c as i, f as q, a as $, b as h, h as v } from "../compiler-CVega_Gv.js";
const Q = function(a, C, p) {
  const {
    cubes: g,
    drizzle: w,
    schema: x,
    extractSecurityContext: y,
    engineType: S,
    cors: f,
    basePath: d = "/cubejs-api/v1",
    bodyLimit: b = 10485760
    // 10MB
  } = C;
  if (!g || g.length === 0)
    return p(new Error("At least one cube must be provided in the cubes array"));
  f && a.register(import("@fastify/cors"), f), a.addHook("onRequest", async (r, t) => {
    r.method === "POST" && (r.body = void 0);
  });
  const o = new j({
    drizzle: w,
    schema: x,
    engineType: S
  });
  g.forEach((r) => {
    o.registerCube(r);
  }), a.post(`${d}/load`, {
    bodyLimit: b,
    schema: {
      body: {
        type: "object",
        additionalProperties: !0
      }
    }
  }, async (r, t) => {
    try {
      const e = r.body, s = e.query || e, u = await y(r), n = o.validateQuery(s);
      if (!n.isValid)
        return t.status(400).send(i(
          `Query validation failed: ${n.errors.join(", ")}`,
          400
        ));
      const c = await o.executeMultiCubeQuery(s, u);
      return q(s, c, o);
    } catch (e) {
      return r.log.error(e, "Query execution error"), t.status(500).send(i(
        e instanceof Error ? e.message : "Query execution failed",
        500
      ));
    }
  }), a.get(`${d}/load`, {
    schema: {
      querystring: {
        type: "object",
        properties: {
          query: { type: "string" }
        },
        required: ["query"]
      }
    }
  }, async (r, t) => {
    try {
      const { query: e } = r.query;
      let s;
      try {
        s = JSON.parse(e);
      } catch {
        return t.status(400).send(i(
          "Invalid JSON in query parameter",
          400
        ));
      }
      const u = await y(r), n = o.validateQuery(s);
      if (!n.isValid)
        return t.status(400).send(i(
          `Query validation failed: ${n.errors.join(", ")}`,
          400
        ));
      const c = await o.executeMultiCubeQuery(s, u);
      return q(s, c, o);
    } catch (e) {
      return r.log.error(e, "Query execution error"), t.status(500).send(i(
        e instanceof Error ? e.message : "Query execution failed",
        500
      ));
    }
  }), a.get(`${d}/meta`, async (r, t) => {
    try {
      const e = o.getMetadata();
      return $(e);
    } catch (e) {
      return r.log.error(e, "Metadata error"), t.status(500).send(i(
        e instanceof Error ? e.message : "Failed to fetch metadata",
        500
      ));
    }
  }), a.post(`${d}/sql`, {
    bodyLimit: b,
    schema: {
      body: {
        type: "object",
        additionalProperties: !0
      }
    }
  }, async (r, t) => {
    try {
      const e = r.body, s = await y(r), u = o.validateQuery(e);
      if (!u.isValid)
        return t.status(400).send(i(
          `Query validation failed: ${u.errors.join(", ")}`,
          400
        ));
      const n = e.measures?.[0] || e.dimensions?.[0];
      if (!n)
        return t.status(400).send(i(
          "No measures or dimensions specified",
          400
        ));
      const c = n.split(".")[0], m = await o.generateSQL(c, e, s);
      return h(e, m);
    } catch (e) {
      return r.log.error(e, "SQL generation error"), t.status(500).send(i(
        e instanceof Error ? e.message : "SQL generation failed",
        500
      ));
    }
  }), a.get(`${d}/sql`, {
    schema: {
      querystring: {
        type: "object",
        properties: {
          query: { type: "string" }
        },
        required: ["query"]
      }
    }
  }, async (r, t) => {
    try {
      const { query: e } = r.query, s = JSON.parse(e), u = await y(r), n = o.validateQuery(s);
      if (!n.isValid)
        return t.status(400).send(i(
          `Query validation failed: ${n.errors.join(", ")}`,
          400
        ));
      const c = s.measures?.[0] || s.dimensions?.[0];
      if (!c)
        return t.status(400).send(i(
          "No measures or dimensions specified",
          400
        ));
      const m = c.split(".")[0], E = await o.generateSQL(m, s, u);
      return h(s, E);
    } catch (e) {
      return r.log.error(e, "SQL generation error"), t.status(500).send(i(
        e instanceof Error ? e.message : "SQL generation failed",
        500
      ));
    }
  }), a.post(`${d}/dry-run`, {
    bodyLimit: b,
    schema: {
      body: {
        type: "object",
        additionalProperties: !0
      }
    }
  }, async (r, t) => {
    try {
      const e = r.body, s = e.query || e, u = await y(r);
      return await v(s, u, o);
    } catch (e) {
      return r.log.error(e, "Dry-run error"), t.status(400).send({
        error: e instanceof Error ? e.message : "Dry-run validation failed",
        valid: !1
      });
    }
  }), a.get(`${d}/dry-run`, {
    schema: {
      querystring: {
        type: "object",
        properties: {
          query: { type: "string" }
        },
        required: ["query"]
      }
    }
  }, async (r, t) => {
    try {
      const { query: e } = r.query, s = JSON.parse(e), u = await y(r);
      return await v(s, u, o);
    } catch (e) {
      return r.log.error(e, "Dry-run error"), t.status(400).send({
        error: e instanceof Error ? e.message : "Dry-run validation failed",
        valid: !1
      });
    }
  }), a.setErrorHandler(async (r, t, e) => (t.log.error(r, "Fastify cube adapter error"), e.statusCode < 400 && e.status(500), i(r, e.statusCode))), p();
};
async function L(l, a) {
  await l.register(Q, a);
}
function R(l) {
  const a = require("fastify")({
    logger: !0
  });
  return a.register(Q, l), a;
}
export {
  R as createCubeApp,
  Q as cubePlugin,
  L as registerCubeRoutes
};