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