drizzle-cube 0.3.25 → 0.3.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. package/README.md +6 -0
  2. package/dist/adapters/express/index.cjs +1 -1
  3. package/dist/adapters/express/index.js +1 -1
  4. package/dist/adapters/fastify/index.cjs +1 -1
  5. package/dist/adapters/fastify/index.js +1 -1
  6. package/dist/adapters/hono/index.cjs +1 -1
  7. package/dist/adapters/hono/index.js +1 -1
  8. package/dist/adapters/{mcp-transport-B4BZSsMC.js → mcp-transport-CXGL1hg7.js} +1655 -1624
  9. package/dist/adapters/{mcp-transport-C8pLznZG.cjs → mcp-transport-ConlvewL.cjs} +73 -73
  10. package/dist/adapters/nextjs/index.cjs +1 -1
  11. package/dist/adapters/nextjs/index.js +1 -1
  12. package/dist/adapters/utils.cjs +1 -1
  13. package/dist/adapters/utils.js +5 -5
  14. package/dist/client/charts.js +12 -12
  15. package/dist/client/chunks/{DashboardEditModal-CVMSvpJ-.js → DashboardEditModal-t5XeTZom.js} +45 -45
  16. package/dist/client/chunks/DashboardEditModal-t5XeTZom.js.map +1 -0
  17. package/dist/client/chunks/{RetentionCombinedChart-BVKWmxc-.js → RetentionCombinedChart-SsBGHJWi.js} +9 -9
  18. package/dist/client/chunks/RetentionCombinedChart-SsBGHJWi.js.map +1 -0
  19. package/dist/client/chunks/{RetentionHeatmap-BiqfhGYk.js → RetentionHeatmap-BHYU8MXY.js} +8 -8
  20. package/dist/client/chunks/RetentionHeatmap-BHYU8MXY.js.map +1 -0
  21. package/dist/client/chunks/{analysis-builder-CuTR61Ct.js → analysis-builder-CKVYG9jJ.js} +67 -67
  22. package/dist/client/chunks/analysis-builder-CKVYG9jJ.js.map +1 -0
  23. package/dist/client/chunks/{analysis-builder-shared-D7iqklYk.js → analysis-builder-shared-CF8Vx1oD.js} +8 -8
  24. package/dist/client/chunks/analysis-builder-shared-CF8Vx1oD.js.map +1 -0
  25. package/dist/client/chunks/{chart-activity-grid-BcMRkaq4.js → chart-activity-grid-Bpu_-8uT.js} +5 -5
  26. package/dist/client/chunks/{chart-activity-grid-BcMRkaq4.js.map → chart-activity-grid-Bpu_-8uT.js.map} +1 -1
  27. package/dist/client/chunks/{chart-area-KlBSb_ur.js → chart-area-DcvLkvGb.js} +8 -8
  28. package/dist/client/chunks/chart-area-DcvLkvGb.js.map +1 -0
  29. package/dist/client/chunks/{chart-bar-D1i2jmIg.js → chart-bar-CNfm5iMY.js} +7 -7
  30. package/dist/client/chunks/chart-bar-CNfm5iMY.js.map +1 -0
  31. package/dist/client/chunks/{chart-bubble-BFjnOwNZ.js → chart-bubble-KA-RYWR8.js} +4 -4
  32. package/dist/client/chunks/{chart-bubble-BFjnOwNZ.js.map → chart-bubble-KA-RYWR8.js.map} +1 -1
  33. package/dist/client/chunks/{chart-data-table-CYMMAHau.js → chart-data-table-Cq14arji.js} +9 -9
  34. package/dist/client/chunks/chart-data-table-Cq14arji.js.map +1 -0
  35. package/dist/client/chunks/{chart-funnel-BH7r4HWZ.js → chart-funnel-DFKWS49U.js} +7 -7
  36. package/dist/client/chunks/chart-funnel-DFKWS49U.js.map +1 -0
  37. package/dist/client/chunks/{chart-heat-map-DyGtODLE.js → chart-heat-map-D2g0dbKz.js} +5 -5
  38. package/dist/client/chunks/chart-heat-map-D2g0dbKz.js.map +1 -0
  39. package/dist/client/chunks/{chart-kpi-delta-Bk396suk.js → chart-kpi-delta-Cc-jiBd0.js} +30 -30
  40. package/dist/client/chunks/chart-kpi-delta-Cc-jiBd0.js.map +1 -0
  41. package/dist/client/chunks/{chart-kpi-number-CIGqZ5Dw.js → chart-kpi-number-BXolYaZA.js} +8 -8
  42. package/dist/client/chunks/chart-kpi-number-BXolYaZA.js.map +1 -0
  43. package/dist/client/chunks/{chart-kpi-text-iwlaSQCi.js → chart-kpi-text-PA8oyypA.js} +7 -7
  44. package/dist/client/chunks/chart-kpi-text-PA8oyypA.js.map +1 -0
  45. package/dist/client/chunks/{chart-line-BKqhoW9A.js → chart-line-BOrtUdOD.js} +8 -8
  46. package/dist/client/chunks/chart-line-BOrtUdOD.js.map +1 -0
  47. package/dist/client/chunks/{chart-markdown-CiPhRY9s.js → chart-markdown-Cget3iEq.js} +6 -6
  48. package/dist/client/chunks/chart-markdown-Cget3iEq.js.map +1 -0
  49. package/dist/client/chunks/{chart-pie-BNr-GgTh.js → chart-pie-B-Sbsvd2.js} +7 -7
  50. package/dist/client/chunks/chart-pie-B-Sbsvd2.js.map +1 -0
  51. package/dist/client/chunks/{chart-radar-CYrGVYEQ.js → chart-radar-CezgvXhm.js} +6 -6
  52. package/dist/client/chunks/chart-radar-CezgvXhm.js.map +1 -0
  53. package/dist/client/chunks/{chart-radial-bar-2PR3ucIR.js → chart-radial-bar-COBPiBxm.js} +6 -6
  54. package/dist/client/chunks/chart-radial-bar-COBPiBxm.js.map +1 -0
  55. package/dist/client/chunks/{chart-sankey-C7w7h2ZV.js → chart-sankey-O4WQBRDk.js} +27 -27
  56. package/dist/client/chunks/{chart-sankey-C7w7h2ZV.js.map → chart-sankey-O4WQBRDk.js.map} +1 -1
  57. package/dist/client/chunks/{chart-scatter-D3Z9bl8H.js → chart-scatter-BVF0n9DR.js} +22 -22
  58. package/dist/client/chunks/chart-scatter-BVF0n9DR.js.map +1 -0
  59. package/dist/client/chunks/{chart-sunburst-C4ydFeaK.js → chart-sunburst-DZzVj_6S.js} +4 -4
  60. package/dist/client/chunks/{chart-sunburst-C4ydFeaK.js.map → chart-sunburst-DZzVj_6S.js.map} +1 -1
  61. package/dist/client/chunks/{chart-tree-map-DCCmMyz1.js → chart-tree-map-CeEtNuo6.js} +6 -6
  62. package/dist/client/chunks/chart-tree-map-CeEtNuo6.js.map +1 -0
  63. package/dist/client/chunks/{charts-core-DIW3Dd7n.js → charts-core-DF99lItO.js} +4 -4
  64. package/dist/client/chunks/charts-core-DF99lItO.js.map +1 -0
  65. package/dist/client/chunks/{charts-loader-BCBnMYjH.js → charts-loader-AkRviD9H.js} +22 -22
  66. package/dist/client/chunks/{charts-loader-BCBnMYjH.js.map → charts-loader-AkRviD9H.js.map} +1 -1
  67. package/dist/client/chunks/{core-BITzuqYm.js → core-Bso4ultM.js} +2 -2
  68. package/dist/client/chunks/{core-BITzuqYm.js.map → core-Bso4ultM.js.map} +1 -1
  69. package/dist/client/chunks/{hooks-Dd_nnv0J.js → hooks-B69r8rwU.js} +4 -4
  70. package/dist/client/chunks/{hooks-Dd_nnv0J.js.map → hooks-B69r8rwU.js.map} +1 -1
  71. package/dist/client/chunks/{providers-BjxD1ZmC.js → providers-CxlSRYvE.js} +2 -2
  72. package/dist/client/chunks/{providers-BjxD1ZmC.js.map → providers-CxlSRYvE.js.map} +1 -1
  73. package/dist/client/chunks/{syntaxHighlighting-Cmqp7_Mx.js → syntaxHighlighting-yTdSle2t.js} +2 -2
  74. package/dist/client/chunks/{syntaxHighlighting-Cmqp7_Mx.js.map → syntaxHighlighting-yTdSle2t.js.map} +1 -1
  75. package/dist/client/chunks/{useDirtyStateTracking-B5g-bw7a.js → useDirtyStateTracking-GZtwGRu7.js} +3 -3
  76. package/dist/client/chunks/{useDirtyStateTracking-B5g-bw7a.js.map → useDirtyStateTracking-GZtwGRu7.js.map} +1 -1
  77. package/dist/client/chunks/{vendor-CJRtj0__.js → vendor-B_H-VRhj.js} +97 -99
  78. package/dist/client/chunks/vendor-B_H-VRhj.js.map +1 -0
  79. package/dist/client/components.js +4 -4
  80. package/dist/client/components.js.map +1 -1
  81. package/dist/client/hooks.js +3 -3
  82. package/dist/client/index.js +10 -10
  83. package/dist/client/index.js.map +1 -1
  84. package/dist/client/providers.js +1 -1
  85. package/dist/client/styles.css +1 -1
  86. package/dist/client/utils.js +6 -6
  87. package/dist/client-bundle-stats.html +1 -1
  88. package/dist/server/index.cjs +20 -20
  89. package/dist/server/index.d.ts +10 -0
  90. package/dist/server/index.js +674 -643
  91. package/package.json +1 -1
  92. package/dist/client/chunks/DashboardEditModal-CVMSvpJ-.js.map +0 -1
  93. package/dist/client/chunks/RetentionCombinedChart-BVKWmxc-.js.map +0 -1
  94. package/dist/client/chunks/RetentionHeatmap-BiqfhGYk.js.map +0 -1
  95. package/dist/client/chunks/analysis-builder-CuTR61Ct.js.map +0 -1
  96. package/dist/client/chunks/analysis-builder-shared-D7iqklYk.js.map +0 -1
  97. package/dist/client/chunks/chart-area-KlBSb_ur.js.map +0 -1
  98. package/dist/client/chunks/chart-bar-D1i2jmIg.js.map +0 -1
  99. package/dist/client/chunks/chart-data-table-CYMMAHau.js.map +0 -1
  100. package/dist/client/chunks/chart-funnel-BH7r4HWZ.js.map +0 -1
  101. package/dist/client/chunks/chart-heat-map-DyGtODLE.js.map +0 -1
  102. package/dist/client/chunks/chart-kpi-delta-Bk396suk.js.map +0 -1
  103. package/dist/client/chunks/chart-kpi-number-CIGqZ5Dw.js.map +0 -1
  104. package/dist/client/chunks/chart-kpi-text-iwlaSQCi.js.map +0 -1
  105. package/dist/client/chunks/chart-line-BKqhoW9A.js.map +0 -1
  106. package/dist/client/chunks/chart-markdown-CiPhRY9s.js.map +0 -1
  107. package/dist/client/chunks/chart-pie-BNr-GgTh.js.map +0 -1
  108. package/dist/client/chunks/chart-radar-CYrGVYEQ.js.map +0 -1
  109. package/dist/client/chunks/chart-radial-bar-2PR3ucIR.js.map +0 -1
  110. package/dist/client/chunks/chart-scatter-D3Z9bl8H.js.map +0 -1
  111. package/dist/client/chunks/chart-tree-map-DCCmMyz1.js.map +0 -1
  112. package/dist/client/chunks/charts-core-DIW3Dd7n.js.map +0 -1
  113. package/dist/client/chunks/vendor-CJRtj0__.js.map +0 -1
@@ -1,20 +1,20 @@
1
- "use strict";const B=require("./utils.cjs"),U=Symbol.for("drizzle:entityKind");function I(d,e){if(!d||typeof d!="object")return!1;if(d instanceof e)return!0;if(!Object.prototype.hasOwnProperty.call(e,U))throw new Error(`Class "${e.name??"<unknown>"}" doesn't look like a Drizzle entity. If this is incorrect and the class is provided by Drizzle, please report this as a bug.`);let t=Object.getPrototypeOf(d).constructor;if(t)for(;t;){if(U in t&&t[U]===e[U])return!0;t=Object.getPrototypeOf(t)}return!1}class ee{constructor(e,t){this.table=e,this.config=t,this.name=t.name,this.keyAsName=t.keyAsName,this.notNull=t.notNull,this.default=t.default,this.defaultFn=t.defaultFn,this.onUpdateFn=t.onUpdateFn,this.hasDefault=t.hasDefault,this.primary=t.primaryKey,this.isUnique=t.isUnique,this.uniqueName=t.uniqueName,this.uniqueType=t.uniqueType,this.dataType=t.dataType,this.columnType=t.columnType,this.generated=t.generated,this.generatedIdentity=t.generatedIdentity}static[U]="Column";name;keyAsName;primary;notNull;default;defaultFn;onUpdateFn;hasDefault;isUnique;uniqueName;uniqueType;dataType;columnType;enumValues=void 0;generated=void 0;generatedIdentity=void 0;config;mapFromDriverValue(e){return e}mapToDriverValue(e){return e}shouldDisableInsert(){return this.config.generated!==void 0&&this.config.generated.type!=="byDefault"}}const ge=Symbol.for("drizzle:Name"),Oe=Symbol.for("drizzle:isPgEnum");function ft(d){return!!d&&typeof d=="function"&&Oe in d&&d[Oe]===!0}class Ye{static[U]="Subquery";constructor(e,t,n,s=!1,i=[]){this._={brand:"Subquery",sql:e,selectedFields:t,alias:n,isWith:s,usedTables:i}}}const pt={startActiveSpan(d,e){return e()}},Z=Symbol.for("drizzle:ViewBaseConfig"),be=Symbol.for("drizzle:Schema"),Ie=Symbol.for("drizzle:Columns"),Le=Symbol.for("drizzle:ExtraConfigColumns"),ye=Symbol.for("drizzle:OriginalName"),Ce=Symbol.for("drizzle:BaseName"),ue=Symbol.for("drizzle:IsAlias"),Me=Symbol.for("drizzle:ExtraConfigBuilder"),ht=Symbol.for("drizzle:IsDrizzleTable");class x{static[U]="Table";static Symbol={Name:ge,Schema:be,OriginalName:ye,Columns:Ie,ExtraConfigColumns:Le,BaseName:Ce,IsAlias:ue,ExtraConfigBuilder:Me};[ge];[ye];[be];[Ie];[Le];[Ce];[ue]=!1;[ht]=!0;[Me]=void 0;constructor(e,t,n){this[ge]=this[ye]=e,this[be]=t,this[Ce]=n}}function Xe(d){return d!=null&&typeof d.getSQL=="function"}function gt(d){const e={sql:"",params:[]};for(const t of d)e.sql+=t.sql,e.params.push(...t.params),t.typings?.length&&(e.typings||(e.typings=[]),e.typings.push(...t.typings));return e}class L{static[U]="StringChunk";value;constructor(e){this.value=Array.isArray(e)?e:[e]}getSQL(){return new F([this])}}class F{constructor(e){this.queryChunks=e;for(const t of e)if(I(t,x)){const n=t[x.Symbol.Schema];this.usedTables.push(n===void 0?t[x.Symbol.Name]:n+"."+t[x.Symbol.Name])}}static[U]="SQL";decoder=Ze;shouldInlineParams=!1;usedTables=[];append(e){return this.queryChunks.push(...e.queryChunks),this}toQuery(e){return pt.startActiveSpan("drizzle.buildSQL",t=>{const n=this.buildQueryFromSourceParams(this.queryChunks,e);return t?.setAttributes({"drizzle.query.text":n.sql,"drizzle.query.params":JSON.stringify(n.params)}),n})}buildQueryFromSourceParams(e,t){const n=Object.assign({},t,{inlineParams:t.inlineParams||this.shouldInlineParams,paramStartIndex:t.paramStartIndex||{value:0}}),{casing:s,escapeName:i,escapeParam:o,prepareTyping:a,inlineParams:u,paramStartIndex:c}=n;return gt(e.map(l=>{if(I(l,L))return{sql:l.value.join(""),params:[]};if(I(l,Ne))return{sql:i(l.value),params:[]};if(l===void 0)return{sql:"",params:[]};if(Array.isArray(l)){const m=[new L("(")];for(const[f,p]of l.entries())m.push(p),f<l.length-1&&m.push(new L(", "));return m.push(new L(")")),this.buildQueryFromSourceParams(m,n)}if(I(l,F))return this.buildQueryFromSourceParams(l.queryChunks,{...n,inlineParams:u||l.shouldInlineParams});if(I(l,x)){const m=l[x.Symbol.Schema],f=l[x.Symbol.Name];return{sql:m===void 0||l[ue]?i(f):i(m)+"."+i(f),params:[]}}if(I(l,ee)){const m=s.getColumnCasing(l);if(t.invokeSource==="indexes")return{sql:i(m),params:[]};const f=l.table[x.Symbol.Schema];return{sql:l.table[ue]||f===void 0?i(l.table[x.Symbol.Name])+"."+i(m):i(f)+"."+i(l.table[x.Symbol.Name])+"."+i(m),params:[]}}if(I(l,tt)){const m=l[Z].schema,f=l[Z].name;return{sql:m===void 0||l[Z].isAlias?i(f):i(m)+"."+i(f),params:[]}}if(I(l,le)){if(I(l.value,ce))return{sql:o(c.value++,l),params:[l],typings:["none"]};const m=l.value===null?null:l.encoder.mapToDriverValue(l.value);if(I(m,F))return this.buildQueryFromSourceParams([m],n);if(u)return{sql:this.mapInlineParam(m,n),params:[]};let f=["none"];return a&&(f=[a(l.encoder)]),{sql:o(c.value++,m),params:[m],typings:f}}return I(l,ce)?{sql:o(c.value++,l),params:[l],typings:["none"]}:I(l,F.Aliased)&&l.fieldAlias!==void 0?{sql:i(l.fieldAlias),params:[]}:I(l,Ye)?l._.isWith?{sql:i(l._.alias),params:[]}:this.buildQueryFromSourceParams([new L("("),l._.sql,new L(") "),new Ne(l._.alias)],n):ft(l)?l.schema?{sql:i(l.schema)+"."+i(l.enumName),params:[]}:{sql:i(l.enumName),params:[]}:Xe(l)?l.shouldOmitSQLParens?.()?this.buildQueryFromSourceParams([l.getSQL()],n):this.buildQueryFromSourceParams([new L("("),l.getSQL(),new L(")")],n):u?{sql:this.mapInlineParam(l,n),params:[]}:{sql:o(c.value++,l),params:[l],typings:["none"]}}))}mapInlineParam(e,{escapeString:t}){if(e===null)return"null";if(typeof e=="number"||typeof e=="boolean")return e.toString();if(typeof e=="string")return t(e);if(typeof e=="object"){const n=e.toString();return t(n==="[object Object]"?JSON.stringify(e):n)}throw new Error("Unexpected param value: "+e)}getSQL(){return this}as(e){return e===void 0?this:new F.Aliased(this,e)}mapWith(e){return this.decoder=typeof e=="function"?{mapFromDriverValue:e}:e,this}inlineParams(){return this.shouldInlineParams=!0,this}if(e){return e?this:void 0}}class Ne{constructor(e){this.value=e}static[U]="Name";brand;getSQL(){return new F([this])}}function bt(d){return typeof d=="object"&&d!==null&&"mapToDriverValue"in d&&typeof d.mapToDriverValue=="function"}const Ze={mapFromDriverValue:d=>d},et={mapToDriverValue:d=>d};({...Ze,...et});class le{constructor(e,t=et){this.value=e,this.encoder=t}static[U]="Param";brand;getSQL(){return new F([this])}}function r(d,...e){const t=[];(e.length>0||d.length>0&&d[0]!=="")&&t.push(new L(d[0]));for(const[n,s]of e.entries())t.push(s,new L(d[n+1]));return new F(t)}(d=>{function e(){return new F([])}d.empty=e;function t(u){return new F(u)}d.fromList=t;function n(u){return new F([new L(u)])}d.raw=n;function s(u,c){const l=[];for(const[m,f]of u.entries())m>0&&c!==void 0&&l.push(c),l.push(f);return new F(l)}d.join=s;function i(u){return new Ne(u)}d.identifier=i;function o(u){return new ce(u)}d.placeholder=o;function a(u,c){return new le(u,c)}d.param=a})(r||(r={}));(d=>{class e{constructor(n,s){this.sql=n,this.fieldAlias=s}static[U]="SQL.Aliased";isSelectionField=!1;getSQL(){return this.sql}clone(){return new e(this.sql,this.fieldAlias)}}d.Aliased=e})(F||(F={}));class ce{constructor(e){this.name=e}static[U]="Placeholder";getSQL(){return new F([this])}}const yt=Symbol.for("drizzle:IsDrizzleView");class tt{static[U]="View";[Z];[yt]=!0;constructor({name:e,schema:t,selectedFields:n,query:s}){this[Z]={name:e,originalName:e,schema:t,selectedFields:n,query:s,isExisting:!s,isAlias:!1}}getSQL(){return new F([this])}}ee.prototype.getSQL=function(){return new F([this])};x.prototype.getSQL=function(){return new F([this])};Ye.prototype.getSQL=function(){return new F([this])};function M(d,e){return bt(e)&&!Xe(d)&&!I(d,le)&&!I(d,ce)&&!I(d,ee)&&!I(d,x)&&!I(d,tt)?new le(d,e):d}const P=(d,e)=>r`${d} = ${M(e,d)}`,je=(d,e)=>r`${d} <> ${M(e,d)}`;function _(...d){const e=d.filter(t=>t!==void 0);if(e.length!==0)return e.length===1?new F(e):new F([new L("("),r.join(e,new L(" and ")),new L(")")])}function ie(...d){const e=d.filter(t=>t!==void 0);if(e.length!==0)return e.length===1?new F(e):new F([new L("("),r.join(e,new L(" or ")),new L(")")])}const we=(d,e)=>r`${d} > ${M(e,d)}`,Y=(d,e)=>r`${d} >= ${M(e,d)}`,$e=(d,e)=>r`${d} < ${M(e,d)}`,X=(d,e)=>r`${d} <= ${M(e,d)}`;function Ee(d,e){return Array.isArray(e)?e.length===0?r`false`:r`${d} in ${e.map(t=>M(t,d))}`:r`${d} in ${M(e,d)}`}function Ue(d,e){return Array.isArray(e)?e.length===0?r`true`:r`${d} not in ${e.map(t=>M(t,d))}`:r`${d} not in ${M(e,d)}`}function ke(d){return r`${d} is null`}function xe(d){return r`${d} is not null`}function Ct(d,e){if(Array.isArray(e)){if(e.length===0)throw new Error("arrayContains requires at least one value");const t=r`${M(e,d)}`;return r`${d} @> ${t}`}return r`${d} @> ${M(e,d)}`}function wt(d,e){if(Array.isArray(e)){if(e.length===0)throw new Error("arrayContained requires at least one value");const t=r`${M(e,d)}`;return r`${d} <@ ${t}`}return r`${d} <@ ${M(e,d)}`}function $t(d,e){if(Array.isArray(e)){if(e.length===0)throw new Error("arrayOverlaps requires at least one value");const t=r`${M(e,d)}`;return r`${d} && ${t}`}return r`${d} && ${M(e,d)}`}function Be(d){return r`${d} asc`}function Et(d){return r`${d} desc`}function De(d){return r`count(${d||r.raw("*")})`.mapWith(Number)}function Tt(d){return r`count(distinct ${d})`.mapWith(Number)}function W(d){return r`sum(${d})`.mapWith(String)}function z(d){return r`max(${d})`.mapWith(I(d,ee)?d:String)}function re(d){return r`min(${d})`.mapWith(I(d,ee)?d:String)}class fe{preprocessCalculatedTemplate(e){return e}buildPattern(e,t){switch(e){case"contains":case"notContains":return`%${t}%`;case"startsWith":return`${t}%`;case"endsWith":return`%${t}`;default:return t}}parseISODuration(e){const t={years:0,months:0,days:0,hours:0,minutes:0,seconds:0},n=/^P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+(?:\.\d+)?)S)?)?$/,s=e.match(n);if(!s)throw new Error(`Invalid ISO 8601 duration format: ${e}`);return t.years=parseInt(s[1]||"0",10),t.months=parseInt(s[2]||"0",10),t.days=parseInt(s[3]||"0",10),t.hours=parseInt(s[4]||"0",10),t.minutes=parseInt(s[5]||"0",10),t.seconds=parseFloat(s[6]||"0"),t}durationToSeconds(e){const t=this.parseISODuration(e);return t.years*365*24*60*60+t.months*30*24*60*60+t.days*24*60*60+t.hours*60*60+t.minutes*60+t.seconds}}class St extends fe{getEngineType(){return"postgres"}supportsLateralJoins(){return!0}buildIntervalFromISO(e){const t=this.parseISODuration(e),n=[];t.years&&n.push(`${t.years} years`),t.months&&n.push(`${t.months} months`),t.days&&n.push(`${t.days} days`),t.hours&&n.push(`${t.hours} hours`),t.minutes&&n.push(`${t.minutes} minutes`),t.seconds&&n.push(`${t.seconds} seconds`);const s=n.join(" ")||"0 seconds";return r`INTERVAL '${r.raw(s)}'`}buildTimeDifferenceSeconds(e,t){return r`EXTRACT(EPOCH FROM (${e} - ${t}))`}buildDateAddInterval(e,t){const n=this.buildIntervalFromISO(t);return r`(${e} + ${n})`}buildConditionalAggregation(e,t,n){const s=e.toUpperCase();return e==="count"&&!t?r`COUNT(*) FILTER (WHERE ${n})`:r`${r.raw(s)}(${t}) FILTER (WHERE ${n})`}buildDateDiffPeriods(e,t,n){switch(n){case"day":return r`(${t}::date - ${e}::date)`;case"week":return r`FLOOR((${t}::date - ${e}::date) / 7)`;case"month":return r`(EXTRACT(YEAR FROM AGE(${t}::timestamp, ${e}::timestamp)) * 12 + EXTRACT(MONTH FROM AGE(${t}::timestamp, ${e}::timestamp)))::integer`;default:throw new Error(`Unsupported date diff unit: ${n}`)}}buildPeriodSeriesSubquery(e){return r`(SELECT generate_series(0, ${e}) as period_number) p`}buildTimeDimension(e,t){switch(e){case"year":return r`DATE_TRUNC('year', ${t}::timestamp)`;case"quarter":return r`DATE_TRUNC('quarter', ${t}::timestamp)`;case"month":return r`DATE_TRUNC('month', ${t}::timestamp)`;case"week":return r`DATE_TRUNC('week', ${t}::timestamp)`;case"day":return r`DATE_TRUNC('day', ${t}::timestamp)::timestamp`;case"hour":return r`DATE_TRUNC('hour', ${t}::timestamp)`;case"minute":return r`DATE_TRUNC('minute', ${t}::timestamp)`;case"second":return r`DATE_TRUNC('second', ${t}::timestamp)`;default:return t}}buildStringCondition(e,t,n){switch(t){case"contains":return r`${e} ILIKE ${`%${n}%`}`;case"notContains":return r`${e} NOT ILIKE ${`%${n}%`}`;case"startsWith":return r`${e} ILIKE ${`${n}%`}`;case"endsWith":return r`${e} ILIKE ${`%${n}`}`;case"like":return r`${e} LIKE ${n}`;case"notLike":return r`${e} NOT LIKE ${n}`;case"ilike":return r`${e} ILIKE ${n}`;case"regex":return r`${e} ~* ${n}`;case"notRegex":return r`${e} !~* ${n}`;default:throw new Error(`Unsupported string operator: ${t}`)}}castToType(e,t){switch(t){case"timestamp":return r`${e}::timestamp`;case"decimal":return r`${e}::decimal`;case"integer":return r`${e}::integer`;default:throw new Error(`Unsupported cast type: ${t}`)}}buildAvg(e){return r`COALESCE(AVG(${e}), 0)`}buildCaseWhen(e,t){const n=e.map(s=>r`WHEN ${s.when} THEN ${s.then}`).reduce((s,i)=>r`${s} ${i}`);return t!==void 0?r`CASE ${n} ELSE ${t} END`:r`CASE ${n} END`}buildBooleanLiteral(e){return e?r`TRUE`:r`FALSE`}convertFilterValue(e){return e}prepareDateValue(e){return e}isTimestampInteger(){return!1}convertTimeDimensionResult(e){return e}getCapabilities(){return{supportsStddev:!0,supportsVariance:!0,supportsPercentile:!0,supportsWindowFunctions:!0,supportsFrameClause:!0,supportsLateralJoins:!0,supportsPercentileSubqueries:!0}}buildStddev(e,t=!1){const n=t?"STDDEV_SAMP":"STDDEV_POP";return r`COALESCE(${r.raw(n)}(${e}), 0)`}buildVariance(e,t=!1){const n=t?"VAR_SAMP":"VAR_POP";return r`COALESCE(${r.raw(n)}(${e}), 0)`}buildPercentile(e,t){const n=t/100;return r`PERCENTILE_CONT(${n}) WITHIN GROUP (ORDER BY ${e})`}buildWindowFunction(e,t,n,s,i){const o=n&&n.length>0?r`PARTITION BY ${r.join(n,r`, `)}`:r``,a=s&&s.length>0?r`ORDER BY ${r.join(s.map(f=>f.direction==="desc"?r`${f.field} DESC`:r`${f.field} ASC`),r`, `)}`:r``;let u=r``;if(i?.frame){const{type:f,start:p,end:h}=i.frame,g=f.toUpperCase(),y=p==="unbounded"?"UNBOUNDED PRECEDING":typeof p=="number"?`${p} PRECEDING`:"CURRENT ROW",b=h==="unbounded"?"UNBOUNDED FOLLOWING":h==="current"?"CURRENT ROW":typeof h=="number"?`${h} FOLLOWING`:"CURRENT ROW";u=r`${r.raw(g)} BETWEEN ${r.raw(y)} AND ${r.raw(b)}`}const c=[];n&&n.length>0&&c.push(o),s&&s.length>0&&c.push(a),i?.frame&&c.push(u);const l=c.length>0?r.join(c,r` `):r``,m=r`OVER (${l})`;switch(e){case"lag":return r`LAG(${t}, ${i?.offset??1}${i?.defaultValue!==void 0?r`, ${i.defaultValue}`:r``}) ${m}`;case"lead":return r`LEAD(${t}, ${i?.offset??1}${i?.defaultValue!==void 0?r`, ${i.defaultValue}`:r``}) ${m}`;case"rank":return r`RANK() ${m}`;case"denseRank":return r`DENSE_RANK() ${m}`;case"rowNumber":return r`ROW_NUMBER() ${m}`;case"ntile":return r`NTILE(${i?.nTile??4}) ${m}`;case"firstValue":return r`FIRST_VALUE(${t}) ${m}`;case"lastValue":return r`LAST_VALUE(${t}) ${m}`;case"movingAvg":return r`AVG(${t}) ${m}`;case"movingSum":return r`SUM(${t}) ${m}`;default:throw new Error(`Unsupported window function: ${e}`)}}}class nt extends fe{getEngineType(){return"mysql"}supportsLateralJoins(){return!0}buildIntervalFromISO(e){const t=this.parseISODuration(e),n=[];t.years&&n.push(`${t.years} YEAR`),t.months&&n.push(`${t.months} MONTH`),t.days&&n.push(`${t.days} DAY`),t.hours&&n.push(`${t.hours} HOUR`),t.minutes&&n.push(`${t.minutes} MINUTE`),t.seconds&&n.push(`${t.seconds} SECOND`);const s=this.durationToSeconds(e);return r`${s}`}buildTimeDifferenceSeconds(e,t){return r`TIMESTAMPDIFF(SECOND, ${t}, ${e})`}buildDateAddInterval(e,t){const n=this.parseISODuration(t);let s=e;return n.years&&(s=r`DATE_ADD(${s}, INTERVAL ${n.years} YEAR)`),n.months&&(s=r`DATE_ADD(${s}, INTERVAL ${n.months} MONTH)`),n.days&&(s=r`DATE_ADD(${s}, INTERVAL ${n.days} DAY)`),n.hours&&(s=r`DATE_ADD(${s}, INTERVAL ${n.hours} HOUR)`),n.minutes&&(s=r`DATE_ADD(${s}, INTERVAL ${n.minutes} MINUTE)`),n.seconds&&(s=r`DATE_ADD(${s}, INTERVAL ${n.seconds} SECOND)`),s}buildConditionalAggregation(e,t,n){const s=e.toUpperCase();return e==="count"&&!t?r`COUNT(CASE WHEN ${n} THEN 1 END)`:r`${r.raw(s)}(CASE WHEN ${n} THEN ${t} END)`}buildDateDiffPeriods(e,t,n){const s=n.toUpperCase();return r`TIMESTAMPDIFF(${r.raw(s)}, ${e}, ${t})`}buildPeriodSeriesSubquery(e){return r`(
1
+ "use strict";const P=require("./utils.cjs"),x=Symbol.for("drizzle:entityKind");function L(d,e){if(!d||typeof d!="object")return!1;if(d instanceof e)return!0;if(!Object.prototype.hasOwnProperty.call(e,x))throw new Error(`Class "${e.name??"<unknown>"}" doesn't look like a Drizzle entity. If this is incorrect and the class is provided by Drizzle, please report this as a bug.`);let t=Object.getPrototypeOf(d).constructor;if(t)for(;t;){if(x in t&&t[x]===e[x])return!0;t=Object.getPrototypeOf(t)}return!1}class te{constructor(e,t){this.table=e,this.config=t,this.name=t.name,this.keyAsName=t.keyAsName,this.notNull=t.notNull,this.default=t.default,this.defaultFn=t.defaultFn,this.onUpdateFn=t.onUpdateFn,this.hasDefault=t.hasDefault,this.primary=t.primaryKey,this.isUnique=t.isUnique,this.uniqueName=t.uniqueName,this.uniqueType=t.uniqueType,this.dataType=t.dataType,this.columnType=t.columnType,this.generated=t.generated,this.generatedIdentity=t.generatedIdentity}static[x]="Column";name;keyAsName;primary;notNull;default;defaultFn;onUpdateFn;hasDefault;isUnique;uniqueName;uniqueType;dataType;columnType;enumValues=void 0;generated=void 0;generatedIdentity=void 0;config;mapFromDriverValue(e){return e}mapToDriverValue(e){return e}shouldDisableInsert(){return this.config.generated!==void 0&&this.config.generated.type!=="byDefault"}}const ge=Symbol.for("drizzle:Name"),Oe=Symbol.for("drizzle:isPgEnum");function ft(d){return!!d&&typeof d=="function"&&Oe in d&&d[Oe]===!0}class Ye{static[x]="Subquery";constructor(e,t,n,s=!1,i=[]){this._={brand:"Subquery",sql:e,selectedFields:t,alias:n,isWith:s,usedTables:i}}}const pt={startActiveSpan(d,e){return e()}},ee=Symbol.for("drizzle:ViewBaseConfig"),be=Symbol.for("drizzle:Schema"),Ie=Symbol.for("drizzle:Columns"),Le=Symbol.for("drizzle:ExtraConfigColumns"),ye=Symbol.for("drizzle:OriginalName"),Ce=Symbol.for("drizzle:BaseName"),ue=Symbol.for("drizzle:IsAlias"),Me=Symbol.for("drizzle:ExtraConfigBuilder"),ht=Symbol.for("drizzle:IsDrizzleTable");class B{static[x]="Table";static Symbol={Name:ge,Schema:be,OriginalName:ye,Columns:Ie,ExtraConfigColumns:Le,BaseName:Ce,IsAlias:ue,ExtraConfigBuilder:Me};[ge];[ye];[be];[Ie];[Le];[Ce];[ue]=!1;[ht]=!0;[Me]=void 0;constructor(e,t,n){this[ge]=this[ye]=e,this[be]=t,this[Ce]=n}}function Xe(d){return d!=null&&typeof d.getSQL=="function"}function gt(d){const e={sql:"",params:[]};for(const t of d)e.sql+=t.sql,e.params.push(...t.params),t.typings?.length&&(e.typings||(e.typings=[]),e.typings.push(...t.typings));return e}class j{static[x]="StringChunk";value;constructor(e){this.value=Array.isArray(e)?e:[e]}getSQL(){return new F([this])}}class F{constructor(e){this.queryChunks=e;for(const t of e)if(L(t,B)){const n=t[B.Symbol.Schema];this.usedTables.push(n===void 0?t[B.Symbol.Name]:n+"."+t[B.Symbol.Name])}}static[x]="SQL";decoder=Ze;shouldInlineParams=!1;usedTables=[];append(e){return this.queryChunks.push(...e.queryChunks),this}toQuery(e){return pt.startActiveSpan("drizzle.buildSQL",t=>{const n=this.buildQueryFromSourceParams(this.queryChunks,e);return t?.setAttributes({"drizzle.query.text":n.sql,"drizzle.query.params":JSON.stringify(n.params)}),n})}buildQueryFromSourceParams(e,t){const n=Object.assign({},t,{inlineParams:t.inlineParams||this.shouldInlineParams,paramStartIndex:t.paramStartIndex||{value:0}}),{casing:s,escapeName:i,escapeParam:r,prepareTyping:a,inlineParams:u,paramStartIndex:c}=n;return gt(e.map(l=>{if(L(l,j))return{sql:l.value.join(""),params:[]};if(L(l,Ne))return{sql:i(l.value),params:[]};if(l===void 0)return{sql:"",params:[]};if(Array.isArray(l)){const m=[new j("(")];for(const[p,f]of l.entries())m.push(f),p<l.length-1&&m.push(new j(", "));return m.push(new j(")")),this.buildQueryFromSourceParams(m,n)}if(L(l,F))return this.buildQueryFromSourceParams(l.queryChunks,{...n,inlineParams:u||l.shouldInlineParams});if(L(l,B)){const m=l[B.Symbol.Schema],p=l[B.Symbol.Name];return{sql:m===void 0||l[ue]?i(p):i(m)+"."+i(p),params:[]}}if(L(l,te)){const m=s.getColumnCasing(l);if(t.invokeSource==="indexes")return{sql:i(m),params:[]};const p=l.table[B.Symbol.Schema];return{sql:l.table[ue]||p===void 0?i(l.table[B.Symbol.Name])+"."+i(m):i(p)+"."+i(l.table[B.Symbol.Name])+"."+i(m),params:[]}}if(L(l,tt)){const m=l[ee].schema,p=l[ee].name;return{sql:m===void 0||l[ee].isAlias?i(p):i(m)+"."+i(p),params:[]}}if(L(l,le)){if(L(l.value,ce))return{sql:r(c.value++,l),params:[l],typings:["none"]};const m=l.value===null?null:l.encoder.mapToDriverValue(l.value);if(L(m,F))return this.buildQueryFromSourceParams([m],n);if(u)return{sql:this.mapInlineParam(m,n),params:[]};let p=["none"];return a&&(p=[a(l.encoder)]),{sql:r(c.value++,m),params:[m],typings:p}}return L(l,ce)?{sql:r(c.value++,l),params:[l],typings:["none"]}:L(l,F.Aliased)&&l.fieldAlias!==void 0?{sql:i(l.fieldAlias),params:[]}:L(l,Ye)?l._.isWith?{sql:i(l._.alias),params:[]}:this.buildQueryFromSourceParams([new j("("),l._.sql,new j(") "),new Ne(l._.alias)],n):ft(l)?l.schema?{sql:i(l.schema)+"."+i(l.enumName),params:[]}:{sql:i(l.enumName),params:[]}:Xe(l)?l.shouldOmitSQLParens?.()?this.buildQueryFromSourceParams([l.getSQL()],n):this.buildQueryFromSourceParams([new j("("),l.getSQL(),new j(")")],n):u?{sql:this.mapInlineParam(l,n),params:[]}:{sql:r(c.value++,l),params:[l],typings:["none"]}}))}mapInlineParam(e,{escapeString:t}){if(e===null)return"null";if(typeof e=="number"||typeof e=="boolean")return e.toString();if(typeof e=="string")return t(e);if(typeof e=="object"){const n=e.toString();return t(n==="[object Object]"?JSON.stringify(e):n)}throw new Error("Unexpected param value: "+e)}getSQL(){return this}as(e){return e===void 0?this:new F.Aliased(this,e)}mapWith(e){return this.decoder=typeof e=="function"?{mapFromDriverValue:e}:e,this}inlineParams(){return this.shouldInlineParams=!0,this}if(e){return e?this:void 0}}class Ne{constructor(e){this.value=e}static[x]="Name";brand;getSQL(){return new F([this])}}function bt(d){return typeof d=="object"&&d!==null&&"mapToDriverValue"in d&&typeof d.mapToDriverValue=="function"}const Ze={mapFromDriverValue:d=>d},et={mapToDriverValue:d=>d};({...Ze,...et});class le{constructor(e,t=et){this.value=e,this.encoder=t}static[x]="Param";brand;getSQL(){return new F([this])}}function o(d,...e){const t=[];(e.length>0||d.length>0&&d[0]!=="")&&t.push(new j(d[0]));for(const[n,s]of e.entries())t.push(s,new j(d[n+1]));return new F(t)}(d=>{function e(){return new F([])}d.empty=e;function t(u){return new F(u)}d.fromList=t;function n(u){return new F([new j(u)])}d.raw=n;function s(u,c){const l=[];for(const[m,p]of u.entries())m>0&&c!==void 0&&l.push(c),l.push(p);return new F(l)}d.join=s;function i(u){return new Ne(u)}d.identifier=i;function r(u){return new ce(u)}d.placeholder=r;function a(u,c){return new le(u,c)}d.param=a})(o||(o={}));(d=>{class e{constructor(n,s){this.sql=n,this.fieldAlias=s}static[x]="SQL.Aliased";isSelectionField=!1;getSQL(){return this.sql}clone(){return new e(this.sql,this.fieldAlias)}}d.Aliased=e})(F||(F={}));class ce{constructor(e){this.name=e}static[x]="Placeholder";getSQL(){return new F([this])}}const yt=Symbol.for("drizzle:IsDrizzleView");class tt{static[x]="View";[ee];[yt]=!0;constructor({name:e,schema:t,selectedFields:n,query:s}){this[ee]={name:e,originalName:e,schema:t,selectedFields:n,query:s,isExisting:!s,isAlias:!1}}getSQL(){return new F([this])}}te.prototype.getSQL=function(){return new F([this])};B.prototype.getSQL=function(){return new F([this])};Ye.prototype.getSQL=function(){return new F([this])};function U(d,e){return bt(e)&&!Xe(d)&&!L(d,le)&&!L(d,ce)&&!L(d,te)&&!L(d,B)&&!L(d,tt)?new le(d,e):d}const Q=(d,e)=>o`${d} = ${U(e,d)}`,je=(d,e)=>o`${d} <> ${U(e,d)}`;function A(...d){const e=d.filter(t=>t!==void 0);if(e.length!==0)return e.length===1?new F(e):new F([new j("("),o.join(e,new j(" and ")),new j(")")])}function ie(...d){const e=d.filter(t=>t!==void 0);if(e.length!==0)return e.length===1?new F(e):new F([new j("("),o.join(e,new j(" or ")),new j(")")])}const we=(d,e)=>o`${d} > ${U(e,d)}`,X=(d,e)=>o`${d} >= ${U(e,d)}`,$e=(d,e)=>o`${d} < ${U(e,d)}`,Z=(d,e)=>o`${d} <= ${U(e,d)}`;function Ee(d,e){return Array.isArray(e)?e.length===0?o`false`:o`${d} in ${e.map(t=>U(t,d))}`:o`${d} in ${U(e,d)}`}function Ue(d,e){return Array.isArray(e)?e.length===0?o`true`:o`${d} not in ${e.map(t=>U(t,d))}`:o`${d} not in ${U(e,d)}`}function ke(d){return o`${d} is null`}function xe(d){return o`${d} is not null`}function Ct(d,e){if(Array.isArray(e)){if(e.length===0)throw new Error("arrayContains requires at least one value");const t=o`${U(e,d)}`;return o`${d} @> ${t}`}return o`${d} @> ${U(e,d)}`}function wt(d,e){if(Array.isArray(e)){if(e.length===0)throw new Error("arrayContained requires at least one value");const t=o`${U(e,d)}`;return o`${d} <@ ${t}`}return o`${d} <@ ${U(e,d)}`}function $t(d,e){if(Array.isArray(e)){if(e.length===0)throw new Error("arrayOverlaps requires at least one value");const t=o`${U(e,d)}`;return o`${d} && ${t}`}return o`${d} && ${U(e,d)}`}function Be(d){return o`${d} asc`}function Et(d){return o`${d} desc`}function De(d){return o`count(${d||o.raw("*")})`.mapWith(Number)}function Tt(d){return o`count(distinct ${d})`.mapWith(Number)}function K(d){return o`sum(${d})`.mapWith(String)}function J(d){return o`max(${d})`.mapWith(L(d,te)?d:String)}function re(d){return o`min(${d})`.mapWith(L(d,te)?d:String)}class fe{preprocessCalculatedTemplate(e){return e}buildPattern(e,t){switch(e){case"contains":case"notContains":return`%${t}%`;case"startsWith":return`${t}%`;case"endsWith":return`%${t}`;default:return t}}parseISODuration(e){const t={years:0,months:0,days:0,hours:0,minutes:0,seconds:0},n=/^P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+(?:\.\d+)?)S)?)?$/,s=e.match(n);if(!s)throw new Error(`Invalid ISO 8601 duration format: ${e}`);return t.years=parseInt(s[1]||"0",10),t.months=parseInt(s[2]||"0",10),t.days=parseInt(s[3]||"0",10),t.hours=parseInt(s[4]||"0",10),t.minutes=parseInt(s[5]||"0",10),t.seconds=parseFloat(s[6]||"0"),t}durationToSeconds(e){const t=this.parseISODuration(e);return t.years*365*24*60*60+t.months*30*24*60*60+t.days*24*60*60+t.hours*60*60+t.minutes*60+t.seconds}}class St extends fe{getEngineType(){return"postgres"}supportsLateralJoins(){return!0}buildIntervalFromISO(e){const t=this.parseISODuration(e),n=[];t.years&&n.push(`${t.years} years`),t.months&&n.push(`${t.months} months`),t.days&&n.push(`${t.days} days`),t.hours&&n.push(`${t.hours} hours`),t.minutes&&n.push(`${t.minutes} minutes`),t.seconds&&n.push(`${t.seconds} seconds`);const s=n.join(" ")||"0 seconds";return o`INTERVAL '${o.raw(s)}'`}buildTimeDifferenceSeconds(e,t){return o`EXTRACT(EPOCH FROM (${e} - ${t}))`}buildDateAddInterval(e,t){const n=this.buildIntervalFromISO(t);return o`(${e} + ${n})`}buildConditionalAggregation(e,t,n){const s=e.toUpperCase();return e==="count"&&!t?o`COUNT(*) FILTER (WHERE ${n})`:o`${o.raw(s)}(${t}) FILTER (WHERE ${n})`}buildDateDiffPeriods(e,t,n){switch(n){case"day":return o`(${t}::date - ${e}::date)`;case"week":return o`FLOOR((${t}::date - ${e}::date) / 7)`;case"month":return o`(EXTRACT(YEAR FROM AGE(${t}::timestamp, ${e}::timestamp)) * 12 + EXTRACT(MONTH FROM AGE(${t}::timestamp, ${e}::timestamp)))::integer`;default:throw new Error(`Unsupported date diff unit: ${n}`)}}buildPeriodSeriesSubquery(e){return o`(SELECT generate_series(0, ${e}) as period_number) p`}buildTimeDimension(e,t){switch(e){case"year":return o`DATE_TRUNC('year', ${t}::timestamp)`;case"quarter":return o`DATE_TRUNC('quarter', ${t}::timestamp)`;case"month":return o`DATE_TRUNC('month', ${t}::timestamp)`;case"week":return o`DATE_TRUNC('week', ${t}::timestamp)`;case"day":return o`DATE_TRUNC('day', ${t}::timestamp)::timestamp`;case"hour":return o`DATE_TRUNC('hour', ${t}::timestamp)`;case"minute":return o`DATE_TRUNC('minute', ${t}::timestamp)`;case"second":return o`DATE_TRUNC('second', ${t}::timestamp)`;default:return t}}buildStringCondition(e,t,n){switch(t){case"contains":return o`${e} ILIKE ${`%${n}%`}`;case"notContains":return o`${e} NOT ILIKE ${`%${n}%`}`;case"startsWith":return o`${e} ILIKE ${`${n}%`}`;case"endsWith":return o`${e} ILIKE ${`%${n}`}`;case"like":return o`${e} LIKE ${n}`;case"notLike":return o`${e} NOT LIKE ${n}`;case"ilike":return o`${e} ILIKE ${n}`;case"regex":return o`${e} ~* ${n}`;case"notRegex":return o`${e} !~* ${n}`;default:throw new Error(`Unsupported string operator: ${t}`)}}castToType(e,t){switch(t){case"timestamp":return o`${e}::timestamp`;case"decimal":return o`${e}::decimal`;case"integer":return o`${e}::integer`;default:throw new Error(`Unsupported cast type: ${t}`)}}buildAvg(e){return o`COALESCE(AVG(${e}), 0)`}buildCaseWhen(e,t){const n=e.map(s=>o`WHEN ${s.when} THEN ${s.then}`).reduce((s,i)=>o`${s} ${i}`);return t!==void 0?o`CASE ${n} ELSE ${t} END`:o`CASE ${n} END`}buildBooleanLiteral(e){return e?o`TRUE`:o`FALSE`}convertFilterValue(e){return e}prepareDateValue(e){return e}isTimestampInteger(){return!1}convertTimeDimensionResult(e){return e}getCapabilities(){return{supportsStddev:!0,supportsVariance:!0,supportsPercentile:!0,supportsWindowFunctions:!0,supportsFrameClause:!0,supportsLateralJoins:!0,supportsPercentileSubqueries:!0}}buildStddev(e,t=!1){const n=t?"STDDEV_SAMP":"STDDEV_POP";return o`COALESCE(${o.raw(n)}(${e}), 0)`}buildVariance(e,t=!1){const n=t?"VAR_SAMP":"VAR_POP";return o`COALESCE(${o.raw(n)}(${e}), 0)`}buildPercentile(e,t){const n=t/100;return o`PERCENTILE_CONT(${n}) WITHIN GROUP (ORDER BY ${e})`}buildWindowFunction(e,t,n,s,i){const r=n&&n.length>0?o`PARTITION BY ${o.join(n,o`, `)}`:o``,a=s&&s.length>0?o`ORDER BY ${o.join(s.map(p=>p.direction==="desc"?o`${p.field} DESC`:o`${p.field} ASC`),o`, `)}`:o``;let u=o``;if(i?.frame){const{type:p,start:f,end:h}=i.frame,g=p.toUpperCase(),y=f==="unbounded"?"UNBOUNDED PRECEDING":typeof f=="number"?`${f} PRECEDING`:"CURRENT ROW",b=h==="unbounded"?"UNBOUNDED FOLLOWING":h==="current"?"CURRENT ROW":typeof h=="number"?`${h} FOLLOWING`:"CURRENT ROW";u=o`${o.raw(g)} BETWEEN ${o.raw(y)} AND ${o.raw(b)}`}const c=[];n&&n.length>0&&c.push(r),s&&s.length>0&&c.push(a),i?.frame&&c.push(u);const l=c.length>0?o.join(c,o` `):o``,m=o`OVER (${l})`;switch(e){case"lag":return o`LAG(${t}, ${i?.offset??1}${i?.defaultValue!==void 0?o`, ${i.defaultValue}`:o``}) ${m}`;case"lead":return o`LEAD(${t}, ${i?.offset??1}${i?.defaultValue!==void 0?o`, ${i.defaultValue}`:o``}) ${m}`;case"rank":return o`RANK() ${m}`;case"denseRank":return o`DENSE_RANK() ${m}`;case"rowNumber":return o`ROW_NUMBER() ${m}`;case"ntile":return o`NTILE(${i?.nTile??4}) ${m}`;case"firstValue":return o`FIRST_VALUE(${t}) ${m}`;case"lastValue":return o`LAST_VALUE(${t}) ${m}`;case"movingAvg":return o`AVG(${t}) ${m}`;case"movingSum":return o`SUM(${t}) ${m}`;default:throw new Error(`Unsupported window function: ${e}`)}}}class nt extends fe{getEngineType(){return"mysql"}supportsLateralJoins(){return!0}buildIntervalFromISO(e){const t=this.parseISODuration(e),n=[];t.years&&n.push(`${t.years} YEAR`),t.months&&n.push(`${t.months} MONTH`),t.days&&n.push(`${t.days} DAY`),t.hours&&n.push(`${t.hours} HOUR`),t.minutes&&n.push(`${t.minutes} MINUTE`),t.seconds&&n.push(`${t.seconds} SECOND`);const s=this.durationToSeconds(e);return o`${s}`}buildTimeDifferenceSeconds(e,t){return o`TIMESTAMPDIFF(SECOND, ${t}, ${e})`}buildDateAddInterval(e,t){const n=this.parseISODuration(t);let s=e;return n.years&&(s=o`DATE_ADD(${s}, INTERVAL ${n.years} YEAR)`),n.months&&(s=o`DATE_ADD(${s}, INTERVAL ${n.months} MONTH)`),n.days&&(s=o`DATE_ADD(${s}, INTERVAL ${n.days} DAY)`),n.hours&&(s=o`DATE_ADD(${s}, INTERVAL ${n.hours} HOUR)`),n.minutes&&(s=o`DATE_ADD(${s}, INTERVAL ${n.minutes} MINUTE)`),n.seconds&&(s=o`DATE_ADD(${s}, INTERVAL ${n.seconds} SECOND)`),s}buildConditionalAggregation(e,t,n){const s=e.toUpperCase();return e==="count"&&!t?o`COUNT(CASE WHEN ${n} THEN 1 END)`:o`${o.raw(s)}(CASE WHEN ${n} THEN ${t} END)`}buildDateDiffPeriods(e,t,n){const s=n.toUpperCase();return o`TIMESTAMPDIFF(${o.raw(s)}, ${e}, ${t})`}buildPeriodSeriesSubquery(e){return o`(
2
2
  WITH RECURSIVE periods(period_number) AS (
3
3
  SELECT 0
4
4
  UNION ALL
5
5
  SELECT period_number + 1 FROM periods WHERE period_number < ${e}
6
6
  )
7
7
  SELECT period_number FROM periods
8
- ) p`}buildTimeDimension(e,t){const n={year:"%Y-01-01 00:00:00",quarter:"%Y-%q-01 00:00:00",month:"%Y-%m-01 00:00:00",week:"%Y-%u-01 00:00:00",day:"%Y-%m-%d 00:00:00",hour:"%Y-%m-%d %H:00:00",minute:"%Y-%m-%d %H:%i:00",second:"%Y-%m-%d %H:%i:%s"};switch(e){case"quarter":return r`DATE_ADD(MAKEDATE(YEAR(${t}), 1), INTERVAL (QUARTER(${t}) - 1) * 3 MONTH)`;case"week":return r`DATE_SUB(${t}, INTERVAL WEEKDAY(${t}) DAY)`;default:{const s=n[e];return s?r`STR_TO_DATE(DATE_FORMAT(${t}, ${s}), '%Y-%m-%d %H:%i:%s')`:t}}}buildStringCondition(e,t,n){switch(t){case"contains":return r`LOWER(${e}) LIKE ${`%${n.toLowerCase()}%`}`;case"notContains":return r`LOWER(${e}) NOT LIKE ${`%${n.toLowerCase()}%`}`;case"startsWith":return r`LOWER(${e}) LIKE ${`${n.toLowerCase()}%`}`;case"endsWith":return r`LOWER(${e}) LIKE ${`%${n.toLowerCase()}`}`;case"like":return r`${e} LIKE ${n}`;case"notLike":return r`${e} NOT LIKE ${n}`;case"ilike":return r`LOWER(${e}) LIKE ${n.toLowerCase()}`;case"regex":return r`${e} REGEXP ${n}`;case"notRegex":return r`${e} NOT REGEXP ${n}`;default:throw new Error(`Unsupported string operator: ${t}`)}}castToType(e,t){switch(t){case"timestamp":return r`CAST(${e} AS DATETIME)`;case"decimal":return r`CAST(${e} AS DECIMAL(10,2))`;case"integer":return r`CAST(${e} AS SIGNED INTEGER)`;default:throw new Error(`Unsupported cast type: ${t}`)}}buildAvg(e){return r`IFNULL(AVG(${e}), 0)`}buildCaseWhen(e,t){const n=e.map(s=>r`WHEN ${s.when} THEN ${s.then}`).reduce((s,i)=>r`${s} ${i}`);return t!==void 0?r`CASE ${n} ELSE ${t} END`:r`CASE ${n} END`}buildBooleanLiteral(e){return e?r`TRUE`:r`FALSE`}convertFilterValue(e){return e}prepareDateValue(e){return e}isTimestampInteger(){return!1}convertTimeDimensionResult(e){return e}getCapabilities(){return{supportsStddev:!0,supportsVariance:!0,supportsPercentile:!1,supportsWindowFunctions:!0,supportsFrameClause:!0,supportsLateralJoins:!0,supportsPercentileSubqueries:!1}}buildStddev(e,t=!1){const n=t?"STDDEV_SAMP":"STDDEV_POP";return r`IFNULL(${r.raw(n)}(${e}), 0)`}buildVariance(e,t=!1){const n=t?"VAR_SAMP":"VAR_POP";return r`IFNULL(${r.raw(n)}(${e}), 0)`}buildPercentile(e,t){return null}buildWindowFunction(e,t,n,s,i){const o=n&&n.length>0?r`PARTITION BY ${r.join(n,r`, `)}`:r``,a=s&&s.length>0?r`ORDER BY ${r.join(s.map(f=>f.direction==="desc"?r`${f.field} DESC`:r`${f.field} ASC`),r`, `)}`:r``;let u=r``;if(i?.frame){const{type:f,start:p,end:h}=i.frame,g=f.toUpperCase(),y=p==="unbounded"?"UNBOUNDED PRECEDING":typeof p=="number"?`${p} PRECEDING`:"CURRENT ROW",b=h==="unbounded"?"UNBOUNDED FOLLOWING":h==="current"?"CURRENT ROW":typeof h=="number"?`${h} FOLLOWING`:"CURRENT ROW";u=r`${r.raw(g)} BETWEEN ${r.raw(y)} AND ${r.raw(b)}`}const c=[];n&&n.length>0&&c.push(o),s&&s.length>0&&c.push(a),i?.frame&&c.push(u);const l=c.length>0?r.join(c,r` `):r``,m=r`OVER (${l})`;switch(e){case"lag":return r`LAG(${t}, ${i?.offset??1}${i?.defaultValue!==void 0?r`, ${i.defaultValue}`:r``}) ${m}`;case"lead":return r`LEAD(${t}, ${i?.offset??1}${i?.defaultValue!==void 0?r`, ${i.defaultValue}`:r``}) ${m}`;case"rank":return r`RANK() ${m}`;case"denseRank":return r`DENSE_RANK() ${m}`;case"rowNumber":return r`ROW_NUMBER() ${m}`;case"ntile":return r`NTILE(${i?.nTile??4}) ${m}`;case"firstValue":return r`FIRST_VALUE(${t}) ${m}`;case"lastValue":return r`LAST_VALUE(${t}) ${m}`;case"movingAvg":return r`AVG(${t}) ${m}`;case"movingSum":return r`SUM(${t}) ${m}`;default:throw new Error(`Unsupported window function: ${e}`)}}}class Nt extends fe{getEngineType(){return"sqlite"}supportsLateralJoins(){return!1}buildIntervalFromISO(e){const t=this.durationToSeconds(e);return r`${t}`}buildTimeDifferenceSeconds(e,t){return r`(${e} - ${t})`}buildDateAddInterval(e,t){const n=this.durationToSeconds(t);return r`(${e} + ${n})`}buildConditionalAggregation(e,t,n){const s=e.toUpperCase();return e==="count"&&!t?r`COUNT(CASE WHEN ${n} THEN 1 END)`:r`${r.raw(s)}(CASE WHEN ${n} THEN ${t} END)`}buildDateDiffPeriods(e,t,n){switch(n){case"day":return r`CAST((julianday(datetime(${t}, 'unixepoch')) - julianday(datetime(${e}, 'unixepoch'))) AS INTEGER)`;case"week":return r`CAST((julianday(datetime(${t}, 'unixepoch')) - julianday(datetime(${e}, 'unixepoch'))) / 7 AS INTEGER)`;case"month":return r`((CAST(strftime('%Y', datetime(${t}, 'unixepoch')) AS INTEGER) - CAST(strftime('%Y', datetime(${e}, 'unixepoch')) AS INTEGER)) * 12 + (CAST(strftime('%m', datetime(${t}, 'unixepoch')) AS INTEGER) - CAST(strftime('%m', datetime(${e}, 'unixepoch')) AS INTEGER)))`;default:throw new Error(`Unsupported date diff unit for SQLite: ${n}`)}}buildPeriodSeriesSubquery(e){return r`(
8
+ ) p`}buildTimeDimension(e,t){const n={year:"%Y-01-01 00:00:00",quarter:"%Y-%q-01 00:00:00",month:"%Y-%m-01 00:00:00",week:"%Y-%u-01 00:00:00",day:"%Y-%m-%d 00:00:00",hour:"%Y-%m-%d %H:00:00",minute:"%Y-%m-%d %H:%i:00",second:"%Y-%m-%d %H:%i:%s"};switch(e){case"quarter":return o`DATE_ADD(MAKEDATE(YEAR(${t}), 1), INTERVAL (QUARTER(${t}) - 1) * 3 MONTH)`;case"week":return o`DATE_SUB(${t}, INTERVAL WEEKDAY(${t}) DAY)`;default:{const s=n[e];return s?o`STR_TO_DATE(DATE_FORMAT(${t}, ${s}), '%Y-%m-%d %H:%i:%s')`:t}}}buildStringCondition(e,t,n){switch(t){case"contains":return o`LOWER(${e}) LIKE ${`%${n.toLowerCase()}%`}`;case"notContains":return o`LOWER(${e}) NOT LIKE ${`%${n.toLowerCase()}%`}`;case"startsWith":return o`LOWER(${e}) LIKE ${`${n.toLowerCase()}%`}`;case"endsWith":return o`LOWER(${e}) LIKE ${`%${n.toLowerCase()}`}`;case"like":return o`${e} LIKE ${n}`;case"notLike":return o`${e} NOT LIKE ${n}`;case"ilike":return o`LOWER(${e}) LIKE ${n.toLowerCase()}`;case"regex":return o`${e} REGEXP ${n}`;case"notRegex":return o`${e} NOT REGEXP ${n}`;default:throw new Error(`Unsupported string operator: ${t}`)}}castToType(e,t){switch(t){case"timestamp":return o`CAST(${e} AS DATETIME)`;case"decimal":return o`CAST(${e} AS DECIMAL(10,2))`;case"integer":return o`CAST(${e} AS SIGNED INTEGER)`;default:throw new Error(`Unsupported cast type: ${t}`)}}buildAvg(e){return o`IFNULL(AVG(${e}), 0)`}buildCaseWhen(e,t){const n=e.map(s=>o`WHEN ${s.when} THEN ${s.then}`).reduce((s,i)=>o`${s} ${i}`);return t!==void 0?o`CASE ${n} ELSE ${t} END`:o`CASE ${n} END`}buildBooleanLiteral(e){return e?o`TRUE`:o`FALSE`}convertFilterValue(e){return e}prepareDateValue(e){return e}isTimestampInteger(){return!1}convertTimeDimensionResult(e){return e}getCapabilities(){return{supportsStddev:!0,supportsVariance:!0,supportsPercentile:!1,supportsWindowFunctions:!0,supportsFrameClause:!0,supportsLateralJoins:!0,supportsPercentileSubqueries:!1}}buildStddev(e,t=!1){const n=t?"STDDEV_SAMP":"STDDEV_POP";return o`IFNULL(${o.raw(n)}(${e}), 0)`}buildVariance(e,t=!1){const n=t?"VAR_SAMP":"VAR_POP";return o`IFNULL(${o.raw(n)}(${e}), 0)`}buildPercentile(e,t){return null}buildWindowFunction(e,t,n,s,i){const r=n&&n.length>0?o`PARTITION BY ${o.join(n,o`, `)}`:o``,a=s&&s.length>0?o`ORDER BY ${o.join(s.map(p=>p.direction==="desc"?o`${p.field} DESC`:o`${p.field} ASC`),o`, `)}`:o``;let u=o``;if(i?.frame){const{type:p,start:f,end:h}=i.frame,g=p.toUpperCase(),y=f==="unbounded"?"UNBOUNDED PRECEDING":typeof f=="number"?`${f} PRECEDING`:"CURRENT ROW",b=h==="unbounded"?"UNBOUNDED FOLLOWING":h==="current"?"CURRENT ROW":typeof h=="number"?`${h} FOLLOWING`:"CURRENT ROW";u=o`${o.raw(g)} BETWEEN ${o.raw(y)} AND ${o.raw(b)}`}const c=[];n&&n.length>0&&c.push(r),s&&s.length>0&&c.push(a),i?.frame&&c.push(u);const l=c.length>0?o.join(c,o` `):o``,m=o`OVER (${l})`;switch(e){case"lag":return o`LAG(${t}, ${i?.offset??1}${i?.defaultValue!==void 0?o`, ${i.defaultValue}`:o``}) ${m}`;case"lead":return o`LEAD(${t}, ${i?.offset??1}${i?.defaultValue!==void 0?o`, ${i.defaultValue}`:o``}) ${m}`;case"rank":return o`RANK() ${m}`;case"denseRank":return o`DENSE_RANK() ${m}`;case"rowNumber":return o`ROW_NUMBER() ${m}`;case"ntile":return o`NTILE(${i?.nTile??4}) ${m}`;case"firstValue":return o`FIRST_VALUE(${t}) ${m}`;case"lastValue":return o`LAST_VALUE(${t}) ${m}`;case"movingAvg":return o`AVG(${t}) ${m}`;case"movingSum":return o`SUM(${t}) ${m}`;default:throw new Error(`Unsupported window function: ${e}`)}}}class Nt extends fe{getEngineType(){return"sqlite"}supportsLateralJoins(){return!1}buildIntervalFromISO(e){const t=this.durationToSeconds(e);return o`${t}`}buildTimeDifferenceSeconds(e,t){return o`(${e} - ${t})`}buildDateAddInterval(e,t){const n=this.durationToSeconds(t);return o`(${e} + ${n})`}buildConditionalAggregation(e,t,n){const s=e.toUpperCase();return e==="count"&&!t?o`COUNT(CASE WHEN ${n} THEN 1 END)`:o`${o.raw(s)}(CASE WHEN ${n} THEN ${t} END)`}buildDateDiffPeriods(e,t,n){switch(n){case"day":return o`CAST((julianday(datetime(${t}, 'unixepoch')) - julianday(datetime(${e}, 'unixepoch'))) AS INTEGER)`;case"week":return o`CAST((julianday(datetime(${t}, 'unixepoch')) - julianday(datetime(${e}, 'unixepoch'))) / 7 AS INTEGER)`;case"month":return o`((CAST(strftime('%Y', datetime(${t}, 'unixepoch')) AS INTEGER) - CAST(strftime('%Y', datetime(${e}, 'unixepoch')) AS INTEGER)) * 12 + (CAST(strftime('%m', datetime(${t}, 'unixepoch')) AS INTEGER) - CAST(strftime('%m', datetime(${e}, 'unixepoch')) AS INTEGER)))`;default:throw new Error(`Unsupported date diff unit for SQLite: ${n}`)}}buildPeriodSeriesSubquery(e){return o`(
9
9
  WITH RECURSIVE periods(period_number) AS (
10
10
  SELECT 0
11
11
  UNION ALL
12
12
  SELECT period_number + 1 FROM periods WHERE period_number < ${e}
13
13
  )
14
14
  SELECT period_number FROM periods
15
- ) p`}buildTimeDimension(e,t){switch(e){case"year":return r`datetime(${t}, 'unixepoch', 'start of year')`;case"quarter":{const n=r`datetime(${t}, 'unixepoch')`;return r`datetime(${n}, 'start of year',
16
- '+' || (((CAST(strftime('%m', ${n}) AS INTEGER) - 1) / 3) * 3) || ' months')`}case"month":return r`datetime(${t}, 'unixepoch', 'start of month')`;case"week":return r`date(datetime(${t}, 'unixepoch'), 'weekday 1', '-6 days')`;case"day":return r`datetime(${t}, 'unixepoch', 'start of day')`;case"hour":{const n=r`datetime(${t}, 'unixepoch')`;return r`datetime(strftime('%Y-%m-%d %H:00:00', ${n}))`}case"minute":{const n=r`datetime(${t}, 'unixepoch')`;return r`datetime(strftime('%Y-%m-%d %H:%M:00', ${n}))`}case"second":{const n=r`datetime(${t}, 'unixepoch')`;return r`datetime(strftime('%Y-%m-%d %H:%M:%S', ${n}))`}default:return r`datetime(${t}, 'unixepoch')`}}buildStringCondition(e,t,n){switch(t){case"contains":return r`LOWER(${e}) LIKE ${`%${n.toLowerCase()}%`}`;case"notContains":return r`LOWER(${e}) NOT LIKE ${`%${n.toLowerCase()}%`}`;case"startsWith":return r`LOWER(${e}) LIKE ${`${n.toLowerCase()}%`}`;case"endsWith":return r`LOWER(${e}) LIKE ${`%${n.toLowerCase()}`}`;case"like":return r`${e} LIKE ${n}`;case"notLike":return r`${e} NOT LIKE ${n}`;case"ilike":return r`LOWER(${e}) LIKE ${n.toLowerCase()}`;case"regex":return r`${e} GLOB ${n}`;case"notRegex":return r`${e} NOT GLOB ${n}`;default:throw new Error(`Unsupported string operator: ${t}`)}}castToType(e,t){switch(t){case"timestamp":return r`datetime(${e} / 1000, 'unixepoch')`;case"decimal":return r`CAST(${e} AS REAL)`;case"integer":return r`CAST(${e} AS INTEGER)`;default:throw new Error(`Unsupported cast type: ${t}`)}}buildAvg(e){return r`IFNULL(AVG(${e}), 0)`}buildCaseWhen(e,t){const n=e.map(s=>s.then&&typeof s.then=="object"&&(s.then.queryChunks||s.then._||s.then.sql)?r`WHEN ${s.when} THEN ${r.raw("(")}${s.then}${r.raw(")")}`:r`WHEN ${s.when} THEN ${s.then}`).reduce((s,i)=>r`${s} ${i}`);return t!==void 0?t&&typeof t=="object"&&(t.queryChunks||t._||t.sql)?r`CASE ${n} ELSE ${r.raw("(")}${t}${r.raw(")")} END`:r`CASE ${n} ELSE ${t} END`:r`CASE ${n} END`}buildBooleanLiteral(e){return e?r`1`:r`0`}preprocessCalculatedTemplate(e){const t=/(\{[^}]+\})\s*\/\s*/g;return e.replace(t,(n,s)=>`${s.replace(/\{([^}]+)\}/,"CAST({$1} AS REAL)")} / `)}convertFilterValue(e){return typeof e=="boolean"?e?1:0:e instanceof Date?e.getTime():Array.isArray(e)?e.map(t=>this.convertFilterValue(t)):e}prepareDateValue(e){if(!(e instanceof Date)){if(typeof e=="number")return e;if(typeof e=="string")return new Date(e).getTime();throw new Error(`prepareDateValue expects a Date object, got ${typeof e}`)}return e.getTime()}isTimestampInteger(){return!0}convertTimeDimensionResult(e){return e}getCapabilities(){return{supportsStddev:!1,supportsVariance:!1,supportsPercentile:!1,supportsWindowFunctions:!0,supportsFrameClause:!0,supportsLateralJoins:!1,supportsPercentileSubqueries:!1}}buildStddev(e,t=!1){return null}buildVariance(e,t=!1){return null}buildPercentile(e,t){return null}buildWindowFunction(e,t,n,s,i){const o=n&&n.length>0?r`PARTITION BY ${r.join(n,r`, `)}`:r``,a=s&&s.length>0?r`ORDER BY ${r.join(s.map(f=>f.direction==="desc"?r`${f.field} DESC`:r`${f.field} ASC`),r`, `)}`:r``;let u=r``;if(i?.frame){const{type:f,start:p,end:h}=i.frame,g=f.toUpperCase(),y=p==="unbounded"?"UNBOUNDED PRECEDING":typeof p=="number"?`${p} PRECEDING`:"CURRENT ROW",b=h==="unbounded"?"UNBOUNDED FOLLOWING":h==="current"?"CURRENT ROW":typeof h=="number"?`${h} FOLLOWING`:"CURRENT ROW";u=r`${r.raw(g)} BETWEEN ${r.raw(y)} AND ${r.raw(b)}`}const c=[];n&&n.length>0&&c.push(o),s&&s.length>0&&c.push(a),i?.frame&&c.push(u);const l=c.length>0?r.join(c,r` `):r``,m=r`OVER (${l})`;switch(e){case"lag":return r`LAG(${t}, ${i?.offset??1}${i?.defaultValue!==void 0?r`, ${i.defaultValue}`:r``}) ${m}`;case"lead":return r`LEAD(${t}, ${i?.offset??1}${i?.defaultValue!==void 0?r`, ${i.defaultValue}`:r``}) ${m}`;case"rank":return r`RANK() ${m}`;case"denseRank":return r`DENSE_RANK() ${m}`;case"rowNumber":return r`ROW_NUMBER() ${m}`;case"ntile":return r`NTILE(${i?.nTile??4}) ${m}`;case"firstValue":return r`FIRST_VALUE(${t}) ${m}`;case"lastValue":return r`LAST_VALUE(${t}) ${m}`;case"movingAvg":return r`AVG(${t}) ${m}`;case"movingSum":return r`SUM(${t}) ${m}`;default:throw new Error(`Unsupported window function: ${e}`)}}}class Dt extends nt{getEngineType(){return"singlestore"}}class At extends fe{getEngineType(){return"duckdb"}supportsLateralJoins(){return!1}buildIntervalFromISO(e){const t=this.parseISODuration(e),n=[];t.years&&n.push(`${t.years} years`),t.months&&n.push(`${t.months} months`),t.days&&n.push(`${t.days} days`),t.hours&&n.push(`${t.hours} hours`),t.minutes&&n.push(`${t.minutes} minutes`),t.seconds&&n.push(`${t.seconds} seconds`);const s=n.join(" ")||"0 seconds";return r`INTERVAL '${r.raw(s)}'`}buildTimeDifferenceSeconds(e,t){return r`(EPOCH(${e}) - EPOCH(${t}))`}buildDateAddInterval(e,t){const n=this.buildIntervalFromISO(t);return r`(${e} + ${n})`}buildConditionalAggregation(e,t,n){const s=e.toUpperCase();return e==="count"&&!t?r`COUNT(*) FILTER (WHERE ${n})`:r`${r.raw(s)}(${t}) FILTER (WHERE ${n})`}buildDateDiffPeriods(e,t,n){return r`DATE_DIFF('${r.raw(n)}', ${e}::timestamp, ${t}::timestamp)`}buildPeriodSeriesSubquery(e){return r`(SELECT UNNEST(generate_series(0, ${e})) as period_number) p`}buildTimeDimension(e,t){switch(e){case"year":return r`DATE_TRUNC('year', ${t}::timestamp)`;case"quarter":return r`DATE_TRUNC('quarter', ${t}::timestamp)`;case"month":return r`DATE_TRUNC('month', ${t}::timestamp)`;case"week":return r`DATE_TRUNC('week', ${t}::timestamp)`;case"day":return r`DATE_TRUNC('day', ${t}::timestamp)::timestamp`;case"hour":return r`DATE_TRUNC('hour', ${t}::timestamp)`;case"minute":return r`DATE_TRUNC('minute', ${t}::timestamp)`;case"second":return r`DATE_TRUNC('second', ${t}::timestamp)`;default:return t}}buildStringCondition(e,t,n){switch(t){case"contains":return r`${e} ILIKE ${`%${n}%`}`;case"notContains":return r`${e} NOT ILIKE ${`%${n}%`}`;case"startsWith":return r`${e} ILIKE ${`${n}%`}`;case"endsWith":return r`${e} ILIKE ${`%${n}`}`;case"like":return r`${e} LIKE ${n}`;case"notLike":return r`${e} NOT LIKE ${n}`;case"ilike":return r`${e} ILIKE ${n}`;case"regex":return r`regexp_matches(${e}, ${n})`;case"notRegex":return r`NOT regexp_matches(${e}, ${n})`;default:throw new Error(`Unsupported string operator: ${t}`)}}castToType(e,t){switch(t){case"timestamp":return r`${e}::timestamp`;case"decimal":return r`${e}::decimal`;case"integer":return r`${e}::integer`;default:throw new Error(`Unsupported cast type: ${t}`)}}buildAvg(e){return r`COALESCE(AVG(${e}), 0)`}buildCaseWhen(e,t){const n=e.map(s=>r`WHEN ${s.when} THEN ${s.then}`).reduce((s,i)=>r`${s} ${i}`);return t!==void 0?r`CASE ${n} ELSE ${t} END`:r`CASE ${n} END`}buildBooleanLiteral(e){return e?r`TRUE`:r`FALSE`}convertFilterValue(e){return e}prepareDateValue(e){return e}isTimestampInteger(){return!1}convertTimeDimensionResult(e){return e}getCapabilities(){return{supportsStddev:!0,supportsVariance:!0,supportsPercentile:!0,supportsWindowFunctions:!0,supportsFrameClause:!0,supportsLateralJoins:!1,supportsPercentileSubqueries:!1}}buildStddev(e,t=!1){const n=t?"STDDEV_SAMP":"STDDEV_POP";return r`COALESCE(${r.raw(n)}(${e}), 0)`}buildVariance(e,t=!1){const n=t?"VAR_SAMP":"VAR_POP";return r`COALESCE(${r.raw(n)}(${e}), 0)`}buildPercentile(e,t){const n=t/100;return r`QUANTILE_CONT(${e}, ${n})`}buildWindowFunction(e,t,n,s,i){const o=n&&n.length>0?r`PARTITION BY ${r.join(n,r`, `)}`:r``,a=s&&s.length>0?r`ORDER BY ${r.join(s.map(f=>f.direction==="desc"?r`${f.field} DESC`:r`${f.field} ASC`),r`, `)}`:r``;let u=r``;if(i?.frame){const{type:f,start:p,end:h}=i.frame,g=f.toUpperCase(),y=p==="unbounded"?"UNBOUNDED PRECEDING":typeof p=="number"?`${p} PRECEDING`:"CURRENT ROW",b=h==="unbounded"?"UNBOUNDED FOLLOWING":h==="current"?"CURRENT ROW":typeof h=="number"?`${h} FOLLOWING`:"CURRENT ROW";u=r`${r.raw(g)} BETWEEN ${r.raw(y)} AND ${r.raw(b)}`}const c=[];n&&n.length>0&&c.push(o),s&&s.length>0&&c.push(a),i?.frame&&c.push(u);const l=c.length>0?r.join(c,r` `):r``,m=r`OVER (${l})`;switch(e){case"lag":return r`LAG(${t}, ${i?.offset??1}${i?.defaultValue!==void 0?r`, ${i.defaultValue}`:r``}) ${m}`;case"lead":return r`LEAD(${t}, ${i?.offset??1}${i?.defaultValue!==void 0?r`, ${i.defaultValue}`:r``}) ${m}`;case"rank":return r`RANK() ${m}`;case"denseRank":return r`DENSE_RANK() ${m}`;case"rowNumber":return r`ROW_NUMBER() ${m}`;case"ntile":return r`NTILE(${i?.nTile??4}) ${m}`;case"firstValue":return r`FIRST_VALUE(${t}) ${m}`;case"lastValue":return r`LAST_VALUE(${t}) ${m}`;case"movingAvg":return r`AVG(${t}) ${m}`;case"movingSum":return r`SUM(${t}) ${m}`;default:throw new Error(`Unsupported window function: ${e}`)}}}function _t(d){switch(d){case"postgres":return new St;case"mysql":return new nt;case"sqlite":return new Nt;case"singlestore":return new Dt;case"duckdb":return new At;default:throw new Error(`Unsupported database engine: ${d}`)}}class pe{constructor(e,t,n){this.db=e,this.schema=t;const s=n||this.getEngineType();this.databaseAdapter=_t(s)}databaseAdapter}function vt(d,e){const t=[],n=[];let s=!1,i,o,a;const u=[];for(const l of d){const m=l.match(/Planning Time:\s*([\d.]+)\s*ms/i);if(m){i=parseFloat(m[1]);continue}const f=l.match(/Execution Time:\s*([\d.]+)\s*ms/i);if(f){o=parseFloat(f[1]);continue}const p=Rt(l);if(p){p.type.includes("Seq Scan")&&(s=!0),p.index&&n.push(p.index),t.length===0&&p.estimatedCost!==void 0&&(a=p.estimatedCost);const h=l.search(/\S/);for(;u.length>0&&u[u.length-1].indent>=h;)u.pop();if(u.length===0)t.push(p);else{const g=u[u.length-1].op;g.children||(g.children=[]),g.children.push(p)}u.push({indent:h,op:p})}}const c={database:"postgres",planningTime:i,executionTime:o,totalCost:a,hasSequentialScans:s,usedIndexes:[...new Set(n)]};return{operations:t,summary:c,raw:d.join(`
17
- `),sql:e}}function Rt(d){const e=d.replace(/^[\s->]+/,"").trim();if(!e)return null;const t=e.match(/^([A-Za-z][A-Za-z0-9 ]+?)(?:\s+using\s+(\S+))?(?:\s+on\s+(\S+))?(?:\s+\w+)?(?:\s+\(cost=([\d.]+)\.\.([\d.]+)\s+rows=(\d+)(?:\s+width=\d+)?\))?(?:\s+\(actual time=([\d.]+)\.\.([\d.]+)\s+rows=(\d+)\s+loops=(\d+)\))?/i);if(!t)return e.match(/^Filter:\s*(.+)$/i)||e.match(/^(Hash Cond|Join Filter|Index Cond):\s*(.+)$/i),null;const n=t[1].trim(),s=t[2]||void 0,i=t[3]||void 0,o=t[5]?parseFloat(t[5]):void 0,a=t[6]?parseInt(t[6],10):void 0,u=t[9]?parseInt(t[9],10):void 0,c={type:n,table:i,index:s,estimatedRows:a,estimatedCost:o};u!==void 0&&(c.actualRows=u);const l=d.match(/Filter:\s*(.+?)(?:\)|$)/i);return l&&(c.filter=l[1].trim()),c}class Ft extends pe{async execute(e,t){if(e&&typeof e=="object"&&typeof e.execute=="function"){const s=await e.execute();return Array.isArray(s)?s.map(i=>this.convertNumericFields(i,t)):s}if(!this.db.execute)throw new Error("PostgreSQL database instance must have an execute method");const n=await this.db.execute(e);return Array.isArray(n)?n.map(s=>this.convertNumericFields(s,t)):n}convertNumericFields(e,t){if(!e||typeof e!="object")return e;const n={};for(const[s,i]of Object.entries(e))t&&t.includes(s)?n[s]=this.coerceToNumber(i):n[s]=i;return n}coerceToNumber(e){if(e==null||typeof e=="number")return e;if(typeof e=="bigint")return Number(e);if(e&&typeof e=="object"){if(typeof e.toString=="function"){const t=e.toString();if(/^-?\d+(\.\d+)?$/.test(t))return t.includes(".")?parseFloat(t):parseInt(t,10)}if(e.constructor?.name==="Numeric"||e.constructor?.name==="Decimal"||"digits"in e||"sign"in e){const t=e.toString();return parseFloat(t)}return e}if(typeof e=="string"){if(/^-?\d+(\.\d+)?$/.test(e))return e.includes(".")?parseFloat(e):parseInt(e,10);if(!isNaN(parseFloat(e))&&isFinite(parseFloat(e)))return parseFloat(e)}return e}getEngineType(){return"postgres"}async explainQuery(e,t,n){const s=n?.analyze?"EXPLAIN ANALYZE":"EXPLAIN";if(!this.db.execute)throw new Error("PostgreSQL database instance must have an execute method");const i=await this.db.execute(r`${r.raw(s)} ${r.raw(e.replace(/\$(\d+)/g,(a,u)=>{const c=parseInt(u,10)-1,l=t[c];return l===null?"NULL":typeof l=="number"?String(l):typeof l=="boolean"?l?"TRUE":"FALSE":l instanceof Date?`'${l.toISOString()}'`:`'${String(l).replace(/'/g,"''")}'`}))}`),o=[];if(Array.isArray(i)){for(const a of i)if(a&&typeof a=="object"){const u=a["QUERY PLAN"]||a["query plan"]||a.queryplan;typeof u=="string"&&o.push(u)}}return vt(o,{sql:e,params:t})}async getTableIndexes(e){if(!e||e.length===0)return[];if(!this.db.execute)throw new Error("PostgreSQL database instance must have an execute method");try{const t=e.map(s=>`'${s.toLowerCase()}'`).join(","),n=await this.db.execute(r`
15
+ ) p`}buildTimeDimension(e,t){switch(e){case"year":return o`datetime(${t}, 'unixepoch', 'start of year')`;case"quarter":{const n=o`datetime(${t}, 'unixepoch')`;return o`datetime(${n}, 'start of year',
16
+ '+' || (((CAST(strftime('%m', ${n}) AS INTEGER) - 1) / 3) * 3) || ' months')`}case"month":return o`datetime(${t}, 'unixepoch', 'start of month')`;case"week":return o`date(datetime(${t}, 'unixepoch'), 'weekday 1', '-6 days')`;case"day":return o`datetime(${t}, 'unixepoch', 'start of day')`;case"hour":{const n=o`datetime(${t}, 'unixepoch')`;return o`datetime(strftime('%Y-%m-%d %H:00:00', ${n}))`}case"minute":{const n=o`datetime(${t}, 'unixepoch')`;return o`datetime(strftime('%Y-%m-%d %H:%M:00', ${n}))`}case"second":{const n=o`datetime(${t}, 'unixepoch')`;return o`datetime(strftime('%Y-%m-%d %H:%M:%S', ${n}))`}default:return o`datetime(${t}, 'unixepoch')`}}buildStringCondition(e,t,n){switch(t){case"contains":return o`LOWER(${e}) LIKE ${`%${n.toLowerCase()}%`}`;case"notContains":return o`LOWER(${e}) NOT LIKE ${`%${n.toLowerCase()}%`}`;case"startsWith":return o`LOWER(${e}) LIKE ${`${n.toLowerCase()}%`}`;case"endsWith":return o`LOWER(${e}) LIKE ${`%${n.toLowerCase()}`}`;case"like":return o`${e} LIKE ${n}`;case"notLike":return o`${e} NOT LIKE ${n}`;case"ilike":return o`LOWER(${e}) LIKE ${n.toLowerCase()}`;case"regex":return o`${e} GLOB ${n}`;case"notRegex":return o`${e} NOT GLOB ${n}`;default:throw new Error(`Unsupported string operator: ${t}`)}}castToType(e,t){switch(t){case"timestamp":return o`datetime(${e} / 1000, 'unixepoch')`;case"decimal":return o`CAST(${e} AS REAL)`;case"integer":return o`CAST(${e} AS INTEGER)`;default:throw new Error(`Unsupported cast type: ${t}`)}}buildAvg(e){return o`IFNULL(AVG(${e}), 0)`}buildCaseWhen(e,t){const n=e.map(s=>s.then&&typeof s.then=="object"&&(s.then.queryChunks||s.then._||s.then.sql)?o`WHEN ${s.when} THEN ${o.raw("(")}${s.then}${o.raw(")")}`:o`WHEN ${s.when} THEN ${s.then}`).reduce((s,i)=>o`${s} ${i}`);return t!==void 0?t&&typeof t=="object"&&(t.queryChunks||t._||t.sql)?o`CASE ${n} ELSE ${o.raw("(")}${t}${o.raw(")")} END`:o`CASE ${n} ELSE ${t} END`:o`CASE ${n} END`}buildBooleanLiteral(e){return e?o`1`:o`0`}preprocessCalculatedTemplate(e){const t=/(\{[^}]+\})\s*\/\s*/g;return e.replace(t,(n,s)=>`${s.replace(/\{([^}]+)\}/,"CAST({$1} AS REAL)")} / `)}convertFilterValue(e){return typeof e=="boolean"?e?1:0:e instanceof Date?e.getTime():Array.isArray(e)?e.map(t=>this.convertFilterValue(t)):e}prepareDateValue(e){if(!(e instanceof Date)){if(typeof e=="number")return e;if(typeof e=="string")return new Date(e).getTime();throw new Error(`prepareDateValue expects a Date object, got ${typeof e}`)}return e.getTime()}isTimestampInteger(){return!0}convertTimeDimensionResult(e){return e}getCapabilities(){return{supportsStddev:!1,supportsVariance:!1,supportsPercentile:!1,supportsWindowFunctions:!0,supportsFrameClause:!0,supportsLateralJoins:!1,supportsPercentileSubqueries:!1}}buildStddev(e,t=!1){return null}buildVariance(e,t=!1){return null}buildPercentile(e,t){return null}buildWindowFunction(e,t,n,s,i){const r=n&&n.length>0?o`PARTITION BY ${o.join(n,o`, `)}`:o``,a=s&&s.length>0?o`ORDER BY ${o.join(s.map(p=>p.direction==="desc"?o`${p.field} DESC`:o`${p.field} ASC`),o`, `)}`:o``;let u=o``;if(i?.frame){const{type:p,start:f,end:h}=i.frame,g=p.toUpperCase(),y=f==="unbounded"?"UNBOUNDED PRECEDING":typeof f=="number"?`${f} PRECEDING`:"CURRENT ROW",b=h==="unbounded"?"UNBOUNDED FOLLOWING":h==="current"?"CURRENT ROW":typeof h=="number"?`${h} FOLLOWING`:"CURRENT ROW";u=o`${o.raw(g)} BETWEEN ${o.raw(y)} AND ${o.raw(b)}`}const c=[];n&&n.length>0&&c.push(r),s&&s.length>0&&c.push(a),i?.frame&&c.push(u);const l=c.length>0?o.join(c,o` `):o``,m=o`OVER (${l})`;switch(e){case"lag":return o`LAG(${t}, ${i?.offset??1}${i?.defaultValue!==void 0?o`, ${i.defaultValue}`:o``}) ${m}`;case"lead":return o`LEAD(${t}, ${i?.offset??1}${i?.defaultValue!==void 0?o`, ${i.defaultValue}`:o``}) ${m}`;case"rank":return o`RANK() ${m}`;case"denseRank":return o`DENSE_RANK() ${m}`;case"rowNumber":return o`ROW_NUMBER() ${m}`;case"ntile":return o`NTILE(${i?.nTile??4}) ${m}`;case"firstValue":return o`FIRST_VALUE(${t}) ${m}`;case"lastValue":return o`LAST_VALUE(${t}) ${m}`;case"movingAvg":return o`AVG(${t}) ${m}`;case"movingSum":return o`SUM(${t}) ${m}`;default:throw new Error(`Unsupported window function: ${e}`)}}}class Dt extends nt{getEngineType(){return"singlestore"}}class At extends fe{getEngineType(){return"duckdb"}supportsLateralJoins(){return!1}buildIntervalFromISO(e){const t=this.parseISODuration(e),n=[];t.years&&n.push(`${t.years} years`),t.months&&n.push(`${t.months} months`),t.days&&n.push(`${t.days} days`),t.hours&&n.push(`${t.hours} hours`),t.minutes&&n.push(`${t.minutes} minutes`),t.seconds&&n.push(`${t.seconds} seconds`);const s=n.join(" ")||"0 seconds";return o`INTERVAL '${o.raw(s)}'`}buildTimeDifferenceSeconds(e,t){return o`(EPOCH(${e}) - EPOCH(${t}))`}buildDateAddInterval(e,t){const n=this.buildIntervalFromISO(t);return o`(${e} + ${n})`}buildConditionalAggregation(e,t,n){const s=e.toUpperCase();return e==="count"&&!t?o`COUNT(*) FILTER (WHERE ${n})`:o`${o.raw(s)}(${t}) FILTER (WHERE ${n})`}buildDateDiffPeriods(e,t,n){return o`DATE_DIFF('${o.raw(n)}', ${e}::timestamp, ${t}::timestamp)`}buildPeriodSeriesSubquery(e){return o`(SELECT UNNEST(generate_series(0, ${e})) as period_number) p`}buildTimeDimension(e,t){switch(e){case"year":return o`DATE_TRUNC('year', ${t}::timestamp)`;case"quarter":return o`DATE_TRUNC('quarter', ${t}::timestamp)`;case"month":return o`DATE_TRUNC('month', ${t}::timestamp)`;case"week":return o`DATE_TRUNC('week', ${t}::timestamp)`;case"day":return o`DATE_TRUNC('day', ${t}::timestamp)::timestamp`;case"hour":return o`DATE_TRUNC('hour', ${t}::timestamp)`;case"minute":return o`DATE_TRUNC('minute', ${t}::timestamp)`;case"second":return o`DATE_TRUNC('second', ${t}::timestamp)`;default:return t}}buildStringCondition(e,t,n){switch(t){case"contains":return o`${e} ILIKE ${`%${n}%`}`;case"notContains":return o`${e} NOT ILIKE ${`%${n}%`}`;case"startsWith":return o`${e} ILIKE ${`${n}%`}`;case"endsWith":return o`${e} ILIKE ${`%${n}`}`;case"like":return o`${e} LIKE ${n}`;case"notLike":return o`${e} NOT LIKE ${n}`;case"ilike":return o`${e} ILIKE ${n}`;case"regex":return o`regexp_matches(${e}, ${n})`;case"notRegex":return o`NOT regexp_matches(${e}, ${n})`;default:throw new Error(`Unsupported string operator: ${t}`)}}castToType(e,t){switch(t){case"timestamp":return o`${e}::timestamp`;case"decimal":return o`${e}::decimal`;case"integer":return o`${e}::integer`;default:throw new Error(`Unsupported cast type: ${t}`)}}buildAvg(e){return o`COALESCE(AVG(${e}), 0)`}buildCaseWhen(e,t){const n=e.map(s=>o`WHEN ${s.when} THEN ${s.then}`).reduce((s,i)=>o`${s} ${i}`);return t!==void 0?o`CASE ${n} ELSE ${t} END`:o`CASE ${n} END`}buildBooleanLiteral(e){return e?o`TRUE`:o`FALSE`}convertFilterValue(e){return e}prepareDateValue(e){return e}isTimestampInteger(){return!1}convertTimeDimensionResult(e){return e}getCapabilities(){return{supportsStddev:!0,supportsVariance:!0,supportsPercentile:!0,supportsWindowFunctions:!0,supportsFrameClause:!0,supportsLateralJoins:!1,supportsPercentileSubqueries:!1}}buildStddev(e,t=!1){const n=t?"STDDEV_SAMP":"STDDEV_POP";return o`COALESCE(${o.raw(n)}(${e}), 0)`}buildVariance(e,t=!1){const n=t?"VAR_SAMP":"VAR_POP";return o`COALESCE(${o.raw(n)}(${e}), 0)`}buildPercentile(e,t){const n=t/100;return o`QUANTILE_CONT(${e}, ${n})`}buildWindowFunction(e,t,n,s,i){const r=n&&n.length>0?o`PARTITION BY ${o.join(n,o`, `)}`:o``,a=s&&s.length>0?o`ORDER BY ${o.join(s.map(p=>p.direction==="desc"?o`${p.field} DESC`:o`${p.field} ASC`),o`, `)}`:o``;let u=o``;if(i?.frame){const{type:p,start:f,end:h}=i.frame,g=p.toUpperCase(),y=f==="unbounded"?"UNBOUNDED PRECEDING":typeof f=="number"?`${f} PRECEDING`:"CURRENT ROW",b=h==="unbounded"?"UNBOUNDED FOLLOWING":h==="current"?"CURRENT ROW":typeof h=="number"?`${h} FOLLOWING`:"CURRENT ROW";u=o`${o.raw(g)} BETWEEN ${o.raw(y)} AND ${o.raw(b)}`}const c=[];n&&n.length>0&&c.push(r),s&&s.length>0&&c.push(a),i?.frame&&c.push(u);const l=c.length>0?o.join(c,o` `):o``,m=o`OVER (${l})`;switch(e){case"lag":return o`LAG(${t}, ${i?.offset??1}${i?.defaultValue!==void 0?o`, ${i.defaultValue}`:o``}) ${m}`;case"lead":return o`LEAD(${t}, ${i?.offset??1}${i?.defaultValue!==void 0?o`, ${i.defaultValue}`:o``}) ${m}`;case"rank":return o`RANK() ${m}`;case"denseRank":return o`DENSE_RANK() ${m}`;case"rowNumber":return o`ROW_NUMBER() ${m}`;case"ntile":return o`NTILE(${i?.nTile??4}) ${m}`;case"firstValue":return o`FIRST_VALUE(${t}) ${m}`;case"lastValue":return o`LAST_VALUE(${t}) ${m}`;case"movingAvg":return o`AVG(${t}) ${m}`;case"movingSum":return o`SUM(${t}) ${m}`;default:throw new Error(`Unsupported window function: ${e}`)}}}function _t(d){switch(d){case"postgres":return new St;case"mysql":return new nt;case"sqlite":return new Nt;case"singlestore":return new Dt;case"duckdb":return new At;default:throw new Error(`Unsupported database engine: ${d}`)}}class pe{constructor(e,t,n){this.db=e,this.schema=t;const s=n||this.getEngineType();this.databaseAdapter=_t(s)}databaseAdapter}function vt(d,e){const t=[],n=[];let s=!1,i,r,a;const u=[];for(const l of d){const m=l.match(/Planning Time:\s*([\d.]+)\s*ms/i);if(m){i=parseFloat(m[1]);continue}const p=l.match(/Execution Time:\s*([\d.]+)\s*ms/i);if(p){r=parseFloat(p[1]);continue}const f=Rt(l);if(f){f.type.includes("Seq Scan")&&(s=!0),f.index&&n.push(f.index),t.length===0&&f.estimatedCost!==void 0&&(a=f.estimatedCost);const h=l.search(/\S/);for(;u.length>0&&u[u.length-1].indent>=h;)u.pop();if(u.length===0)t.push(f);else{const g=u[u.length-1].op;g.children||(g.children=[]),g.children.push(f)}u.push({indent:h,op:f})}}const c={database:"postgres",planningTime:i,executionTime:r,totalCost:a,hasSequentialScans:s,usedIndexes:[...new Set(n)]};return{operations:t,summary:c,raw:d.join(`
17
+ `),sql:e}}function Rt(d){const e=d.replace(/^[\s->]+/,"").trim();if(!e)return null;const t=e.match(/^([A-Za-z][A-Za-z0-9 ]+?)(?:\s+using\s+(\S+))?(?:\s+on\s+(\S+))?(?:\s+\w+)?(?:\s+\(cost=([\d.]+)\.\.([\d.]+)\s+rows=(\d+)(?:\s+width=\d+)?\))?(?:\s+\(actual time=([\d.]+)\.\.([\d.]+)\s+rows=(\d+)\s+loops=(\d+)\))?/i);if(!t)return e.match(/^Filter:\s*(.+)$/i)||e.match(/^(Hash Cond|Join Filter|Index Cond):\s*(.+)$/i),null;const n=t[1].trim(),s=t[2]||void 0,i=t[3]||void 0,r=t[5]?parseFloat(t[5]):void 0,a=t[6]?parseInt(t[6],10):void 0,u=t[9]?parseInt(t[9],10):void 0,c={type:n,table:i,index:s,estimatedRows:a,estimatedCost:r};u!==void 0&&(c.actualRows=u);const l=d.match(/Filter:\s*(.+?)(?:\)|$)/i);return l&&(c.filter=l[1].trim()),c}class Ft extends pe{async execute(e,t){if(e&&typeof e=="object"&&typeof e.execute=="function"){const s=await e.execute();return Array.isArray(s)?s.map(i=>this.convertNumericFields(i,t)):s}if(!this.db.execute)throw new Error("PostgreSQL database instance must have an execute method");const n=await this.db.execute(e);return Array.isArray(n)?n.map(s=>this.convertNumericFields(s,t)):n}convertNumericFields(e,t){if(!e||typeof e!="object")return e;const n={};for(const[s,i]of Object.entries(e))t&&t.includes(s)?n[s]=this.coerceToNumber(i):n[s]=i;return n}coerceToNumber(e){if(e==null||typeof e=="number")return e;if(typeof e=="bigint")return Number(e);if(e&&typeof e=="object"){if(typeof e.toString=="function"){const t=e.toString();if(/^-?\d+(\.\d+)?$/.test(t))return t.includes(".")?parseFloat(t):parseInt(t,10)}if(e.constructor?.name==="Numeric"||e.constructor?.name==="Decimal"||"digits"in e||"sign"in e){const t=e.toString();return parseFloat(t)}return e}if(typeof e=="string"){if(/^-?\d+(\.\d+)?$/.test(e))return e.includes(".")?parseFloat(e):parseInt(e,10);if(!isNaN(parseFloat(e))&&isFinite(parseFloat(e)))return parseFloat(e)}return e}getEngineType(){return"postgres"}async explainQuery(e,t,n){const s=n?.analyze?"EXPLAIN ANALYZE":"EXPLAIN";if(!this.db.execute)throw new Error("PostgreSQL database instance must have an execute method");const i=await this.db.execute(o`${o.raw(s)} ${o.raw(e.replace(/\$(\d+)/g,(a,u)=>{const c=parseInt(u,10)-1,l=t[c];return l===null?"NULL":typeof l=="number"?String(l):typeof l=="boolean"?l?"TRUE":"FALSE":l instanceof Date?`'${l.toISOString()}'`:`'${String(l).replace(/'/g,"''")}'`}))}`),r=[];if(Array.isArray(i)){for(const a of i)if(a&&typeof a=="object"){const u=a["QUERY PLAN"]||a["query plan"]||a.queryplan;typeof u=="string"&&r.push(u)}}return vt(r,{sql:e,params:t})}async getTableIndexes(e){if(!e||e.length===0)return[];if(!this.db.execute)throw new Error("PostgreSQL database instance must have an execute method");try{const t=e.map(s=>`'${s.toLowerCase()}'`).join(","),n=await this.db.execute(o`
18
18
  SELECT
19
19
  t.relname as table_name,
20
20
  i.relname as index_name,
@@ -28,11 +28,11 @@
28
28
  JOIN LATERAL unnest(ix.indkey) WITH ORDINALITY AS k(attnum, n) ON true
29
29
  JOIN pg_attribute a ON a.attrelid = t.oid AND a.attnum = k.attnum
30
30
  WHERE n.nspname = 'public'
31
- AND t.relname IN (${r.raw(t)})
31
+ AND t.relname IN (${o.raw(t)})
32
32
  GROUP BY t.relname, i.relname, ix.indisunique, ix.indisprimary
33
33
  ORDER BY t.relname, i.relname
34
- `);return Array.isArray(n)?n.map(s=>({table_name:s.table_name,index_name:s.index_name,columns:s.columns.split(","),is_unique:s.is_unique,is_primary:s.is_primary})):[]}catch(t){return console.warn("Failed to get table indexes:",t),[]}}}function Pe(d,e){return new Ft(d,e,"postgres")}function Ot(d,e){const t=e?.toLowerCase()||"";switch(d.toLowerCase()){case"all":return"Seq Scan";case"index":return t.includes("using index")?"Index Only Scan":"Index Scan";case"range":return"Index Range Scan";case"ref":case"eq_ref":return"Index Lookup";case"const":case"system":return"Const Lookup";case"null":return"No Table";default:return`MySQL ${d}`}}function It(d,e){const t=[],n=[];let s=!1,i=0;for(const u of d){const c=Ot(u.type,u.Extra);u.type.toLowerCase()==="all"&&(s=!0),u.key&&n.push(u.key);const l={type:c,table:u.table||void 0,index:u.key||void 0,estimatedRows:u.rows,estimatedCost:u.rows};if(u.Extra){const m=[];u.Extra.includes("Using where")&&m.push("WHERE filter applied"),u.Extra.includes("Using filesort")&&m.push("Filesort required"),u.Extra.includes("Using temporary")&&m.push("Temporary table required"),u.Extra.includes("Using join buffer")&&m.push("Join buffer used"),m.length>0&&(l.details=m.join("; ")),l.filter=u.Extra}t.push(l),i+=u.rows}const o={database:"mysql",planningTime:void 0,executionTime:void 0,totalCost:i,hasSequentialScans:s,usedIndexes:[...new Set(n)]},a=["id select_type table type possible_keys key rows Extra",...d.map(u=>`${u.id} ${u.select_type} ${u.table||"NULL"} ${u.type} ${u.possible_keys||"NULL"} ${u.key||"NULL"} ${u.rows} ${u.Extra||""}`)];return{operations:t,summary:o,raw:a.join(`
35
- `),sql:e}}class st extends pe{async execute(e,t){if(e&&typeof e=="object"&&typeof e.execute=="function"){const s=await e.execute();return Array.isArray(s)?s.map(i=>this.convertNumericFields(i,t)):s}if(!this.db.execute)throw new Error("MySQL database instance must have an execute method");const n=await this.db.execute(e);return Array.isArray(n)?n.map(s=>this.convertNumericFields(s,t)):n}convertNumericFields(e,t){if(!e||typeof e!="object")return e;const n={};for(const[s,i]of Object.entries(e))t&&t.includes(s)?n[s]=this.coerceToNumber(i):n[s]=i;return n}coerceToNumber(e){if(e==null||typeof e=="number")return e;if(typeof e=="string"){if(/^-?\d+(\.\d+)?$/.test(e))return e.includes(".")?parseFloat(e):parseInt(e,10);if(!isNaN(parseFloat(e))&&isFinite(parseFloat(e)))return parseFloat(e)}return e}getEngineType(){return"mysql"}async explainQuery(e,t,n){let s=e,i=0;s=s.replace(/\?/g,()=>{const c=t[i++];return c===null?"NULL":typeof c=="number"?String(c):typeof c=="boolean"?c?"1":"0":c instanceof Date?`'${c.toISOString().slice(0,19).replace("T"," ")}'`:`'${String(c).replace(/'/g,"''")}'`});const o=n?.analyze?"EXPLAIN ANALYZE":"EXPLAIN";if(!this.db.execute)throw new Error("MySQL database instance must have an execute method");const a=await this.db.execute(r.raw(`${o} ${s}`)),u=[];if(Array.isArray(a))for(const c of a)c&&typeof c=="object"&&u.push({id:c.id||1,select_type:c.select_type||"SIMPLE",table:c.table||null,partitions:c.partitions||null,type:c.type||"ALL",possible_keys:c.possible_keys||null,key:c.key||null,key_len:c.key_len||null,ref:c.ref||null,rows:Number(c.rows)||0,filtered:Number(c.filtered)||100,Extra:c.Extra||null});return It(u,{sql:e,params:t})}async getTableIndexes(e){if(!e||e.length===0)return[];if(!this.db.execute)throw new Error("MySQL database instance must have an execute method");try{const t=e.map(s=>`'${s.toLowerCase()}'`).join(","),n=await this.db.execute(r`
34
+ `);return Array.isArray(n)?n.map(s=>({table_name:s.table_name,index_name:s.index_name,columns:s.columns.split(","),is_unique:s.is_unique,is_primary:s.is_primary})):[]}catch(t){return console.warn("Failed to get table indexes:",t),[]}}}function Pe(d,e){return new Ft(d,e,"postgres")}function Ot(d,e){const t=e?.toLowerCase()||"";switch(d.toLowerCase()){case"all":return"Seq Scan";case"index":return t.includes("using index")?"Index Only Scan":"Index Scan";case"range":return"Index Range Scan";case"ref":case"eq_ref":return"Index Lookup";case"const":case"system":return"Const Lookup";case"null":return"No Table";default:return`MySQL ${d}`}}function It(d,e){const t=[],n=[];let s=!1,i=0;for(const u of d){const c=Ot(u.type,u.Extra);u.type.toLowerCase()==="all"&&(s=!0),u.key&&n.push(u.key);const l={type:c,table:u.table||void 0,index:u.key||void 0,estimatedRows:u.rows,estimatedCost:u.rows};if(u.Extra){const m=[];u.Extra.includes("Using where")&&m.push("WHERE filter applied"),u.Extra.includes("Using filesort")&&m.push("Filesort required"),u.Extra.includes("Using temporary")&&m.push("Temporary table required"),u.Extra.includes("Using join buffer")&&m.push("Join buffer used"),m.length>0&&(l.details=m.join("; ")),l.filter=u.Extra}t.push(l),i+=u.rows}const r={database:"mysql",planningTime:void 0,executionTime:void 0,totalCost:i,hasSequentialScans:s,usedIndexes:[...new Set(n)]},a=["id select_type table type possible_keys key rows Extra",...d.map(u=>`${u.id} ${u.select_type} ${u.table||"NULL"} ${u.type} ${u.possible_keys||"NULL"} ${u.key||"NULL"} ${u.rows} ${u.Extra||""}`)];return{operations:t,summary:r,raw:a.join(`
35
+ `),sql:e}}class st extends pe{async execute(e,t){if(e&&typeof e=="object"&&typeof e.execute=="function"){const s=await e.execute();return Array.isArray(s)?s.map(i=>this.convertNumericFields(i,t)):s}if(!this.db.execute)throw new Error("MySQL database instance must have an execute method");const n=await this.db.execute(e);return Array.isArray(n)?n.map(s=>this.convertNumericFields(s,t)):n}convertNumericFields(e,t){if(!e||typeof e!="object")return e;const n={};for(const[s,i]of Object.entries(e))t&&t.includes(s)?n[s]=this.coerceToNumber(i):n[s]=i;return n}coerceToNumber(e){if(e==null||typeof e=="number")return e;if(typeof e=="string"){if(/^-?\d+(\.\d+)?$/.test(e))return e.includes(".")?parseFloat(e):parseInt(e,10);if(!isNaN(parseFloat(e))&&isFinite(parseFloat(e)))return parseFloat(e)}return e}getEngineType(){return"mysql"}async explainQuery(e,t,n){let s=e,i=0;s=s.replace(/\?/g,()=>{const c=t[i++];return c===null?"NULL":typeof c=="number"?String(c):typeof c=="boolean"?c?"1":"0":c instanceof Date?`'${c.toISOString().slice(0,19).replace("T"," ")}'`:`'${String(c).replace(/'/g,"''")}'`});const r=n?.analyze?"EXPLAIN ANALYZE":"EXPLAIN";if(!this.db.execute)throw new Error("MySQL database instance must have an execute method");const a=await this.db.execute(o.raw(`${r} ${s}`)),u=[];if(Array.isArray(a))for(const c of a)c&&typeof c=="object"&&u.push({id:c.id||1,select_type:c.select_type||"SIMPLE",table:c.table||null,partitions:c.partitions||null,type:c.type||"ALL",possible_keys:c.possible_keys||null,key:c.key||null,key_len:c.key_len||null,ref:c.ref||null,rows:Number(c.rows)||0,filtered:Number(c.filtered)||100,Extra:c.Extra||null});return It(u,{sql:e,params:t})}async getTableIndexes(e){if(!e||e.length===0)return[];if(!this.db.execute)throw new Error("MySQL database instance must have an execute method");try{const t=e.map(s=>`'${s.toLowerCase()}'`).join(","),n=await this.db.execute(o`
36
36
  SELECT
37
37
  TABLE_NAME as table_name,
38
38
  INDEX_NAME as index_name,
@@ -41,12 +41,12 @@
41
41
  CASE WHEN INDEX_NAME = 'PRIMARY' THEN TRUE ELSE FALSE END as is_primary
42
42
  FROM INFORMATION_SCHEMA.STATISTICS
43
43
  WHERE TABLE_SCHEMA = DATABASE()
44
- AND LOWER(TABLE_NAME) IN (${r.raw(t)})
44
+ AND LOWER(TABLE_NAME) IN (${o.raw(t)})
45
45
  GROUP BY TABLE_NAME, INDEX_NAME, NON_UNIQUE
46
46
  ORDER BY TABLE_NAME, INDEX_NAME
47
- `);return Array.isArray(n)?n.map(s=>({table_name:s.table_name,index_name:s.index_name,columns:s.columns.split(","),is_unique:!!s.is_unique,is_primary:!!s.is_primary})):[]}catch(t){return console.warn("Failed to get table indexes:",t),[]}}}function Lt(d,e){return new st(d,e,"mysql")}function Mt(d){const e=d.toLowerCase(),t=d.match(/^SCAN\s+(\S+)/i);if(t)return{type:"Seq Scan",table:t[1]};const n=d.match(/^SEARCH\s+(\S+)\s+USING\s+(?:COVERING\s+)?INDEX\s+(\S+)(?:\s+\((.+)\))?/i);if(n)return{type:"Index Scan",table:n[1],index:n[2],filter:n[3]};const s=d.match(/^SEARCH\s+(\S+)\s+USING\s+INTEGER\s+PRIMARY\s+KEY\s+\((.+)\)/i);if(s)return{type:"Primary Key Lookup",table:s[1],filter:s[2]};const i=d.match(/^SEARCH\s+(\S+)/i);return i?{type:"Search",table:i[1]}:e.includes("temp b-tree")?e.includes("order by")?{type:"Sort"}:e.includes("group by")?{type:"Group"}:e.includes("distinct")?{type:"Distinct"}:{type:"Temp B-Tree"}:e.includes("compound")?{type:"Compound Query"}:e.includes("subquery")?{type:"Subquery"}:e.includes("co-routine")?{type:"Coroutine"}:{type:d}}function jt(d,e){const t=[],n=[];let s=!1;const i=new Map;for(const u of d){const c=Mt(u.detail);c.type==="Seq Scan"&&(s=!0),c.index&&n.push(c.index);const l={type:c.type,table:c.table,index:c.index,filter:c.filter,details:u.detail};if(i.set(u.id,l),u.parent===0)t.push(l);else{const m=i.get(u.parent);m?(m.children||(m.children=[]),m.children.push(l)):t.push(l)}}const o={database:"sqlite",planningTime:void 0,executionTime:void 0,totalCost:void 0,hasSequentialScans:s,usedIndexes:[...new Set(n)]},a=["id parent detail",...d.map(u=>`${u.id} ${u.parent} ${u.detail}`)];return{operations:t,summary:o,raw:a.join(`
48
- `),sql:e}}class Ut extends pe{async execute(e,t){if(e&&typeof e=="object"&&typeof e.execute=="function"){const n=await e.execute();return Array.isArray(n)?n.map(s=>this.convertNumericFields(s,t)):n}try{if(this.db.all){const n=this.db.all(e);return Array.isArray(n)?n.map(s=>this.convertNumericFields(s,t)):n}else{if(this.db.run)return this.db.run(e);throw new Error("SQLite database instance must have an all() or run() method")}}catch(n){throw new Error(`SQLite execution failed: ${n instanceof Error?n.message:"Unknown error"}`)}}convertNumericFields(e,t){if(!e||typeof e!="object")return e;const n={};for(const[s,i]of Object.entries(e))t&&t.includes(s)?n[s]=this.coerceToNumber(i):n[s]=i;return n}coerceToNumber(e){if(e==null||typeof e=="number")return e;if(typeof e=="string"){if(/^-?\d+(\.\d+)?$/.test(e))return e.includes(".")?parseFloat(e):parseInt(e,10);if(!isNaN(parseFloat(e))&&isFinite(parseFloat(e)))return parseFloat(e)}return e}getEngineType(){return"sqlite"}async explainQuery(e,t,n){let s=e,i=0;s=s.replace(/\?/g,()=>{const c=t[i++];return c===null?"NULL":typeof c=="number"?String(c):typeof c=="boolean"?c?"1":"0":c instanceof Date?`'${c.toISOString()}'`:`'${String(c).replace(/'/g,"''")}'`});const o=`EXPLAIN QUERY PLAN ${s}`;let a=[];if(this.db.all)a=this.db.all(r.raw(o));else throw new Error("SQLite database instance must have an all() method for EXPLAIN");const u=[];if(Array.isArray(a))for(const c of a)c&&typeof c=="object"&&u.push({id:Number(c.id)||0,parent:Number(c.parent)||0,notused:Number(c.notused)||0,detail:String(c.detail||"")});return jt(u,{sql:e,params:t})}async getTableIndexes(e){if(!e||e.length===0)return[];if(!this.db.all)throw new Error("SQLite database instance must have an all() method");try{const t=[];for(const n of e){const s=this.db.all(r.raw(`SELECT name, "unique", origin FROM pragma_index_list('${n.toLowerCase()}')`));if(Array.isArray(s))for(const i of s){const o=i.name,a=!!i.unique,u=i.origin,c=this.db.all(r.raw(`SELECT name FROM pragma_index_info('${o}') ORDER BY seqno`)),l=[];if(Array.isArray(c))for(const m of c){const f=m.name;typeof f=="string"&&l.push(f)}t.push({table_name:n.toLowerCase(),index_name:o,columns:l,is_unique:a,is_primary:u==="pk"})}}return t}catch(t){return console.warn("Failed to get table indexes:",t),[]}}}function Qe(d,e){return new Ut(d,e,"sqlite")}class kt extends st{getEngineType(){return"singlestore"}}function xt(d,e){return new kt(d,e)}function Bt(d,e){const t=[],n=[];let s=!1,i;const o=[];for(const u of d){if(/^[┌├└│─┐┤┘]+$/.test(u.trim())||/EXPLANATION|QUERY PLAN/i.test(u))continue;const c=Qt(u);if(c){(c.type.includes("SEQ_SCAN")||c.type.includes("TABLE_SCAN"))&&(s=!0),c.type.includes("INDEX_SCAN")&&c.index&&n.push(c.index),t.length===0&&c.estimatedCost!==void 0&&(i=c.estimatedCost);const l=Pt(u);for(;o.length>0&&o[o.length-1].indent>=l;)o.pop();if(o.length===0)t.push(c);else{const m=o[o.length-1].op;m.children||(m.children=[]),m.children.push(c)}o.push({indent:l,op:c})}}const a={database:"duckdb",planningTime:void 0,executionTime:void 0,totalCost:i,hasSequentialScans:s,usedIndexes:[...new Set(n)]};return{operations:t,summary:a,raw:d.join(`
49
- `),sql:e}}function Pt(d){let e=0;for(const t of d)if(t===" "||t==="│"||t==="├"||t==="└"||t==="─")e++;else break;return e}function Qt(d){const e=d.replace(/[┌├└│─┐┤┘]/g,"").replace(/^\s*/,"").trim();if(!e||e.match(/^\(cost=([\d.]+)\s+rows=(\d+)\)$/i))return null;const n=e.match(/^([A-Z_]+)(?:\s+(\S+))?(?:\s+on\s+(\S+))?(?:\s+\(cost=([\d.]+)\s+rows=(\d+)\))?/i);if(!n){const l=e.match(/^FILTER\s+(.+)$/i);return l?{type:"FILTER",filter:l[1]}:null}const s=n[1].toUpperCase();let i=n[2]||void 0,o=n[3]||void 0;const a=n[4]?parseFloat(n[4]):void 0,u=n[5]?parseInt(n[5],10):void 0;if(s==="INDEX_SCAN"){const l=i,m=o;o=l,i=m}return{type:s,table:i,index:o,estimatedRows:u,estimatedCost:a}}class Wt extends pe{async execute(e,t){if(e&&typeof e=="object"&&typeof e.execute=="function")try{const n=await e.execute();return Array.isArray(n)?n.map(s=>this.convertNumericFields(s,t)):n}catch(n){const s=this.extractSqlFromQuery(e);throw console.error("[DuckDB] Query execution failed:",{error:n instanceof Error?n.message:String(n),sql:s.sql,params:s.params}),n}if(!this.db.execute)throw new Error("DuckDB database instance must have an execute method");try{const n=await this.db.execute(e);return Array.isArray(n)?n.map(s=>this.convertNumericFields(s,t)):n}catch(n){const s=this.extractSqlFromQuery(e);throw console.error("[DuckDB] Query execution failed:",{error:n instanceof Error?n.message:String(n),sql:s.sql,params:s.params}),n}}extractSqlFromQuery(e){try{if(e&&typeof e.toSQL=="function"){const{sql:t,params:n}=e.toSQL();return{sql:t,params:n}}if(e&&typeof e.getSQL=="function"){const t=e.getSQL();if(t&&typeof t.toSQL=="function"){const{sql:n,params:s}=t.toSQL();return{sql:n,params:s}}}return{sql:String(e),params:[]}}catch{return{sql:"[unable to extract SQL]",params:[]}}}convertNumericFields(e,t){if(!e||typeof e!="object")return e;const n={};for(const[s,i]of Object.entries(e))t&&t.includes(s)?n[s]=this.coerceToNumber(i):n[s]=i;return n}coerceToNumber(e){if(e==null||typeof e=="number")return e;if(typeof e=="bigint")return Number(e);if(e&&typeof e=="object"){if(typeof e.toString=="function"){const t=e.toString();if(/^-?\d+(\.\d+)?$/.test(t))return t.includes(".")?parseFloat(t):parseInt(t,10)}return e}if(typeof e=="string"){if(/^-?\d+(\.\d+)?$/.test(e))return e.includes(".")?parseFloat(e):parseInt(e,10);if(!isNaN(parseFloat(e))&&isFinite(parseFloat(e)))return parseFloat(e)}return e}getEngineType(){return"duckdb"}async explainQuery(e,t,n){const s=n?.analyze?"EXPLAIN ANALYZE":"EXPLAIN";if(!this.db.execute)throw new Error("DuckDB database instance must have an execute method");const i=await this.db.execute(r`${r.raw(s)} ${r.raw(e.replace(/\$(\d+)/g,(a,u)=>{const c=parseInt(u,10)-1,l=t[c];return l===null?"NULL":typeof l=="number"?String(l):typeof l=="boolean"?l?"TRUE":"FALSE":l instanceof Date?`'${l.toISOString()}'`:`'${String(l).replace(/'/g,"''")}'`}))}`),o=[];if(Array.isArray(i)){for(const a of i)if(a&&typeof a=="object"){const u=a.explain_value||a["QUERY PLAN"]||a.query_plan||a.Plan||Object.values(a)[0];typeof u=="string"&&o.push(u)}}return Bt(o,{sql:e,params:t})}async getTableIndexes(e){if(!e||e.length===0)return[];if(!this.db.execute)throw new Error("DuckDB database instance must have an execute method");try{const t=e.map(s=>`'${s.toLowerCase()}'`).join(","),n=await this.db.execute(r`
47
+ `);return Array.isArray(n)?n.map(s=>({table_name:s.table_name,index_name:s.index_name,columns:s.columns.split(","),is_unique:!!s.is_unique,is_primary:!!s.is_primary})):[]}catch(t){return console.warn("Failed to get table indexes:",t),[]}}}function Lt(d,e){return new st(d,e,"mysql")}function Mt(d){const e=d.toLowerCase(),t=d.match(/^SCAN\s+(\S+)/i);if(t)return{type:"Seq Scan",table:t[1]};const n=d.match(/^SEARCH\s+(\S+)\s+USING\s+(?:COVERING\s+)?INDEX\s+(\S+)(?:\s+\((.+)\))?/i);if(n)return{type:"Index Scan",table:n[1],index:n[2],filter:n[3]};const s=d.match(/^SEARCH\s+(\S+)\s+USING\s+INTEGER\s+PRIMARY\s+KEY\s+\((.+)\)/i);if(s)return{type:"Primary Key Lookup",table:s[1],filter:s[2]};const i=d.match(/^SEARCH\s+(\S+)/i);return i?{type:"Search",table:i[1]}:e.includes("temp b-tree")?e.includes("order by")?{type:"Sort"}:e.includes("group by")?{type:"Group"}:e.includes("distinct")?{type:"Distinct"}:{type:"Temp B-Tree"}:e.includes("compound")?{type:"Compound Query"}:e.includes("subquery")?{type:"Subquery"}:e.includes("co-routine")?{type:"Coroutine"}:{type:d}}function jt(d,e){const t=[],n=[];let s=!1;const i=new Map;for(const u of d){const c=Mt(u.detail);c.type==="Seq Scan"&&(s=!0),c.index&&n.push(c.index);const l={type:c.type,table:c.table,index:c.index,filter:c.filter,details:u.detail};if(i.set(u.id,l),u.parent===0)t.push(l);else{const m=i.get(u.parent);m?(m.children||(m.children=[]),m.children.push(l)):t.push(l)}}const r={database:"sqlite",planningTime:void 0,executionTime:void 0,totalCost:void 0,hasSequentialScans:s,usedIndexes:[...new Set(n)]},a=["id parent detail",...d.map(u=>`${u.id} ${u.parent} ${u.detail}`)];return{operations:t,summary:r,raw:a.join(`
48
+ `),sql:e}}class Ut extends pe{async execute(e,t){if(e&&typeof e=="object"&&typeof e.execute=="function"){const n=await e.execute();return Array.isArray(n)?n.map(s=>this.convertNumericFields(s,t)):n}try{if(this.db.all){const n=this.db.all(e);return Array.isArray(n)?n.map(s=>this.convertNumericFields(s,t)):n}else{if(this.db.run)return this.db.run(e);throw new Error("SQLite database instance must have an all() or run() method")}}catch(n){throw new Error(`SQLite execution failed: ${n instanceof Error?n.message:"Unknown error"}`)}}convertNumericFields(e,t){if(!e||typeof e!="object")return e;const n={};for(const[s,i]of Object.entries(e))t&&t.includes(s)?n[s]=this.coerceToNumber(i):n[s]=i;return n}coerceToNumber(e){if(e==null||typeof e=="number")return e;if(typeof e=="string"){if(/^-?\d+(\.\d+)?$/.test(e))return e.includes(".")?parseFloat(e):parseInt(e,10);if(!isNaN(parseFloat(e))&&isFinite(parseFloat(e)))return parseFloat(e)}return e}getEngineType(){return"sqlite"}async explainQuery(e,t,n){let s=e,i=0;s=s.replace(/\?/g,()=>{const c=t[i++];return c===null?"NULL":typeof c=="number"?String(c):typeof c=="boolean"?c?"1":"0":c instanceof Date?`'${c.toISOString()}'`:`'${String(c).replace(/'/g,"''")}'`});const r=`EXPLAIN QUERY PLAN ${s}`;let a=[];if(this.db.all)a=this.db.all(o.raw(r));else throw new Error("SQLite database instance must have an all() method for EXPLAIN");const u=[];if(Array.isArray(a))for(const c of a)c&&typeof c=="object"&&u.push({id:Number(c.id)||0,parent:Number(c.parent)||0,notused:Number(c.notused)||0,detail:String(c.detail||"")});return jt(u,{sql:e,params:t})}async getTableIndexes(e){if(!e||e.length===0)return[];if(!this.db.all)throw new Error("SQLite database instance must have an all() method");try{const t=[];for(const n of e){const s=this.db.all(o.raw(`SELECT name, "unique", origin FROM pragma_index_list('${n.toLowerCase()}')`));if(Array.isArray(s))for(const i of s){const r=i.name,a=!!i.unique,u=i.origin,c=this.db.all(o.raw(`SELECT name FROM pragma_index_info('${r}') ORDER BY seqno`)),l=[];if(Array.isArray(c))for(const m of c){const p=m.name;typeof p=="string"&&l.push(p)}t.push({table_name:n.toLowerCase(),index_name:r,columns:l,is_unique:a,is_primary:u==="pk"})}}return t}catch(t){return console.warn("Failed to get table indexes:",t),[]}}}function Qe(d,e){return new Ut(d,e,"sqlite")}class kt extends st{getEngineType(){return"singlestore"}}function xt(d,e){return new kt(d,e)}function Bt(d,e){const t=[],n=[];let s=!1,i;const r=[];for(const u of d){if(/^[┌├└│─┐┤┘]+$/.test(u.trim())||/EXPLANATION|QUERY PLAN/i.test(u))continue;const c=Qt(u);if(c){(c.type.includes("SEQ_SCAN")||c.type.includes("TABLE_SCAN"))&&(s=!0),c.type.includes("INDEX_SCAN")&&c.index&&n.push(c.index),t.length===0&&c.estimatedCost!==void 0&&(i=c.estimatedCost);const l=Pt(u);for(;r.length>0&&r[r.length-1].indent>=l;)r.pop();if(r.length===0)t.push(c);else{const m=r[r.length-1].op;m.children||(m.children=[]),m.children.push(c)}r.push({indent:l,op:c})}}const a={database:"duckdb",planningTime:void 0,executionTime:void 0,totalCost:i,hasSequentialScans:s,usedIndexes:[...new Set(n)]};return{operations:t,summary:a,raw:d.join(`
49
+ `),sql:e}}function Pt(d){let e=0;for(const t of d)if(t===" "||t==="│"||t==="├"||t==="└"||t==="─")e++;else break;return e}function Qt(d){const e=d.replace(/[┌├└│─┐┤┘]/g,"").replace(/^\s*/,"").trim();if(!e||e.match(/^\(cost=([\d.]+)\s+rows=(\d+)\)$/i))return null;const n=e.match(/^([A-Z_]+)(?:\s+(\S+))?(?:\s+on\s+(\S+))?(?:\s+\(cost=([\d.]+)\s+rows=(\d+)\))?/i);if(!n){const l=e.match(/^FILTER\s+(.+)$/i);return l?{type:"FILTER",filter:l[1]}:null}const s=n[1].toUpperCase();let i=n[2]||void 0,r=n[3]||void 0;const a=n[4]?parseFloat(n[4]):void 0,u=n[5]?parseInt(n[5],10):void 0;if(s==="INDEX_SCAN"){const l=i,m=r;r=l,i=m}return{type:s,table:i,index:r,estimatedRows:u,estimatedCost:a}}class Wt extends pe{async execute(e,t){if(e&&typeof e=="object"&&typeof e.execute=="function")try{const n=await e.execute();return Array.isArray(n)?n.map(s=>this.convertNumericFields(s,t)):n}catch(n){const s=this.extractSqlFromQuery(e);throw console.error("[DuckDB] Query execution failed:",{error:n instanceof Error?n.message:String(n),sql:s.sql,params:s.params}),n}if(!this.db.execute)throw new Error("DuckDB database instance must have an execute method");try{const n=await this.db.execute(e);return Array.isArray(n)?n.map(s=>this.convertNumericFields(s,t)):n}catch(n){const s=this.extractSqlFromQuery(e);throw console.error("[DuckDB] Query execution failed:",{error:n instanceof Error?n.message:String(n),sql:s.sql,params:s.params}),n}}extractSqlFromQuery(e){try{if(e&&typeof e.toSQL=="function"){const{sql:t,params:n}=e.toSQL();return{sql:t,params:n}}if(e&&typeof e.getSQL=="function"){const t=e.getSQL();if(t&&typeof t.toSQL=="function"){const{sql:n,params:s}=t.toSQL();return{sql:n,params:s}}}return{sql:String(e),params:[]}}catch{return{sql:"[unable to extract SQL]",params:[]}}}convertNumericFields(e,t){if(!e||typeof e!="object")return e;const n={};for(const[s,i]of Object.entries(e))t&&t.includes(s)?n[s]=this.coerceToNumber(i):n[s]=i;return n}coerceToNumber(e){if(e==null||typeof e=="number")return e;if(typeof e=="bigint")return Number(e);if(e&&typeof e=="object"){if(typeof e.toString=="function"){const t=e.toString();if(/^-?\d+(\.\d+)?$/.test(t))return t.includes(".")?parseFloat(t):parseInt(t,10)}return e}if(typeof e=="string"){if(/^-?\d+(\.\d+)?$/.test(e))return e.includes(".")?parseFloat(e):parseInt(e,10);if(!isNaN(parseFloat(e))&&isFinite(parseFloat(e)))return parseFloat(e)}return e}getEngineType(){return"duckdb"}async explainQuery(e,t,n){const s=n?.analyze?"EXPLAIN ANALYZE":"EXPLAIN";if(!this.db.execute)throw new Error("DuckDB database instance must have an execute method");const i=await this.db.execute(o`${o.raw(s)} ${o.raw(e.replace(/\$(\d+)/g,(a,u)=>{const c=parseInt(u,10)-1,l=t[c];return l===null?"NULL":typeof l=="number"?String(l):typeof l=="boolean"?l?"TRUE":"FALSE":l instanceof Date?`'${l.toISOString()}'`:`'${String(l).replace(/'/g,"''")}'`}))}`),r=[];if(Array.isArray(i)){for(const a of i)if(a&&typeof a=="object"){const u=a.explain_value||a["QUERY PLAN"]||a.query_plan||a.Plan||Object.values(a)[0];typeof u=="string"&&r.push(u)}}return Bt(r,{sql:e,params:t})}async getTableIndexes(e){if(!e||e.length===0)return[];if(!this.db.execute)throw new Error("DuckDB database instance must have an execute method");try{const t=e.map(s=>`'${s.toLowerCase()}'`).join(","),n=await this.db.execute(o`
50
50
  SELECT
51
51
  table_name,
52
52
  index_name,
@@ -54,115 +54,115 @@
54
54
  is_unique,
55
55
  is_primary
56
56
  FROM duckdb_indexes()
57
- WHERE LOWER(table_name) IN (${r.raw(t)})
57
+ WHERE LOWER(table_name) IN (${o.raw(t)})
58
58
  GROUP BY table_name, index_name, is_unique, is_primary
59
59
  ORDER BY table_name, index_name
60
- `);return Array.isArray(n)?n.map(s=>({table_name:s.table_name,index_name:s.index_name,columns:typeof s.columns=="string"?s.columns.split(","):[],is_unique:!!s.is_unique,is_primary:!!s.is_primary})):[]}catch(t){return console.warn("Failed to get table indexes:",t),[]}}}function qt(d,e){return new Wt(d,e,"duckdb")}function We(d,e,t){if(t)switch(t){case"postgres":return Pe(d,e);case"mysql":return Lt(d,e);case"sqlite":return Qe(d,e);case"singlestore":return xt(d,e);case"duckdb":return qt(d,e)}if(d.all&&d.run)return Qe(d,e);if(d.execute)return Pe(d,e);throw new Error("Unable to determine database engine type. Please specify engineType parameter.")}function q(d){return typeof d=="function"?d():d}function Ae(d,e){if(e)return e;switch(d){case"belongsTo":return"inner";case"hasOne":return"left";case"hasMany":return"left";case"belongsToMany":return"left";default:return"left"}}function _e(d){return d&&typeof d=="object"?r`${r`${d}`}`:d}function R(d,e){const t=typeof d=="function"?d(e):d;return _e(t)}function Kt(d,e){if(d.relationship!=="belongsToMany"||!d.through)throw new Error("expandBelongsToManyJoin can only be called on belongsToMany relationships with through configuration");const{table:t,sourceKey:n,targetKey:s,securitySql:i}=d.through,o=[];for(const l of n){const m=l.as||P;o.push(m(l.source,l.target))}const a=[];for(const l of s){const m=l.as||P;a.push(m(l.source,l.target))}let u;if(i){const l=i(e);u=Array.isArray(l)?l:[l]}const c=Ae("belongsToMany",d.sqlJoinType);return{junctionJoins:[{joinType:c,table:t,condition:_(...o)},{joinType:c,table:t,condition:_(...a)}],junctionSecurityConditions:u}}function de(d){if("and"in d)return`and:[${d.and.map(de).sort().join(",")}]`;if("or"in d)return`or:[${d.or.map(de).sort().join(",")}]`;const e=d,t=JSON.stringify(Array.isArray(e.values)?[...e.values].sort():e.values),n=e.dateRange?`:dr:${JSON.stringify(e.dateRange)}`:"";return`${e.member}:${e.operator}:${t}${n}`}function it(d,e){return`timeDim:${d}:${JSON.stringify(e)}`}class qe{cache=new Map;stats={hits:0,misses:0};getOrBuild(e,t){const n=this.cache.get(e);if(n!==void 0)return this.stats.hits++,n;const s=t();return s&&this.cache.set(e,s),this.stats.misses++,s}has(e){return this.cache.has(e)}get(e){const t=this.cache.get(e);return t!==void 0&&this.stats.hits++,t}preload(e){for(const{key:t,sql:n}of e)this.cache.has(t)||this.cache.set(t,n)}set(e,t){this.cache.set(e,t)}getStats(){return{...this.stats,cacheSize:this.cache.size}}clear(){this.cache.clear(),this.stats={hits:0,misses:0}}}function ve(d){const e=[];for(const t of d)"and"in t&&t.and?e.push(...ve(t.and)):"or"in t&&t.or?e.push(...ve(t.or)):"member"in t&&e.push(t);return e}function zt(d,e,t={}){const n=t.keyPrefix??"drizzle-cube:",s=Vt(d),i=Ke(JSON.stringify(s));let o=`${n}query:${i}`;if(t.includeSecurityContext!==!1){const a=t.securityContextSerializer?t.securityContextSerializer(e):JSON.stringify(me(e)),u=Ke(a);o+=`:ctx:${u}`}return o}function Vt(d){return{measures:d.measures?[...d.measures].sort():void 0,dimensions:d.dimensions?[...d.dimensions].sort():void 0,filters:d.filters?Q(d.filters):void 0,timeDimensions:d.timeDimensions?Yt(d.timeDimensions):void 0,limit:d.limit,offset:d.offset,order:d.order?me(d.order):void 0,fillMissingDatesValue:d.fillMissingDatesValue,funnel:d.funnel?Jt(d.funnel):void 0,flow:d.flow?Gt(d.flow):void 0,retention:d.retention?Ht(d.retention):void 0}}function Jt(d){return{bindingKey:d.bindingKey,timeDimension:d.timeDimension,steps:d.steps.map(e=>{const t={name:e.name,filter:e.filter?Array.isArray(e.filter)?Q(e.filter):Q([e.filter])[0]:void 0,timeToConvert:e.timeToConvert};return"cube"in e&&e.cube&&(t.cube=e.cube),t}),includeTimeMetrics:d.includeTimeMetrics,globalTimeWindow:d.globalTimeWindow}}function Gt(d){return{bindingKey:d.bindingKey,timeDimension:d.timeDimension,eventDimension:d.eventDimension,startingStep:{name:d.startingStep.name,filter:d.startingStep.filter?Array.isArray(d.startingStep.filter)?Q(d.startingStep.filter):Q([d.startingStep.filter])[0]:void 0},stepsBefore:d.stepsBefore,stepsAfter:d.stepsAfter,entityLimit:d.entityLimit,outputMode:d.outputMode,joinStrategy:d.joinStrategy}}function Ht(d){return{timeDimension:d.timeDimension,bindingKey:d.bindingKey,dateRange:d.dateRange,granularity:d.granularity,periods:d.periods,retentionType:d.retentionType,cohortFilters:d.cohortFilters?Array.isArray(d.cohortFilters)?Q(d.cohortFilters):Q([d.cohortFilters])[0]:void 0,activityFilters:d.activityFilters?Array.isArray(d.activityFilters)?Q(d.activityFilters):Q([d.activityFilters])[0]:void 0,breakdownDimensions:d.breakdownDimensions}}function Q(d){return[...d].map(e=>{if("and"in e&&e.and)return{and:Q(e.and)};if("or"in e&&e.or)return{or:Q(e.or)};const t=e;return{...t,values:t.values?[...t.values].sort():t.values}}).sort((e,t)=>JSON.stringify(e).localeCompare(JSON.stringify(t)))}function Yt(d){return[...d].map(e=>({dimension:e.dimension,granularity:e.granularity,dateRange:e.dateRange,fillMissingDates:e.fillMissingDates,compareDateRange:e.compareDateRange?[...e.compareDateRange].sort((t,n)=>{const s=Array.isArray(t)?t.join("-"):t,i=Array.isArray(n)?n.join("-"):n;return s.localeCompare(i)}):void 0})).sort((e,t)=>e.dimension.localeCompare(t.dimension))}function me(d){return d===null||typeof d!="object"?d:Array.isArray(d)?d.map(me):Object.keys(d).sort().reduce((e,t)=>(e[t]=me(d[t]),e),{})}function Ke(d){let e=2166136261;for(let t=0;t<d.length;t++)e^=d.charCodeAt(t),e=e*16777619>>>0;return e.toString(16).padStart(8,"0")}class te{constructor(e){this.databaseAdapter=e}buildTimeDimensionExpression(e,t,n){const s=R(e,n);return t?this.databaseAdapter.buildTimeDimension(t,s):s instanceof F?s:r`${s}`}buildDateRangeCondition(e,t){if(!t)return null;if(Array.isArray(t)&&t.length>=2){const n=this.normalizeDate(t[0]);let s=this.normalizeDate(t[1]);if(!n||!s)return null;if(typeof t[1]=="string"&&/^\d{4}-\d{2}-\d{2}$/.test(t[1].trim())){const i=typeof s=="number"?new Date(s*(this.databaseAdapter.getEngineType()==="sqlite"?1e3:1)):new Date(s),o=new Date(i);o.setUTCHours(23,59,59,999),this.databaseAdapter.isTimestampInteger()?s=this.databaseAdapter.getEngineType()==="sqlite"?Math.floor(o.getTime()/1e3):o.getTime():s=o.toISOString()}return _(Y(e,n),X(e,s))}if(typeof t=="string"){const n=this.parseRelativeDateRange(t);if(n){let l,m;return this.databaseAdapter.isTimestampInteger()?this.databaseAdapter.getEngineType()==="sqlite"?(l=Math.floor(n.start.getTime()/1e3),m=Math.floor(n.end.getTime()/1e3)):(l=n.start.getTime(),m=n.end.getTime()):(l=n.start.toISOString(),m=n.end.toISOString()),_(Y(e,l),X(e,m))}const s=this.normalizeDate(t);if(!s)return null;const i=typeof s=="number"?new Date(s*(this.databaseAdapter.getEngineType()==="sqlite"?1e3:1)):new Date(s),o=new Date(i);o.setUTCHours(0,0,0,0);const a=new Date(i);a.setUTCHours(23,59,59,999);let u,c;return this.databaseAdapter.isTimestampInteger()?this.databaseAdapter.getEngineType()==="sqlite"?(u=Math.floor(o.getTime()/1e3),c=Math.floor(a.getTime()/1e3)):(u=o.getTime(),c=a.getTime()):(u=o.toISOString(),c=a.toISOString()),_(Y(e,u),X(e,c))}return null}parseRelativeDateRange(e){const t=new Date,n=e.toLowerCase().trim(),s=t.getUTCFullYear(),i=t.getUTCMonth(),o=t.getUTCDate(),a=t.getUTCDay();if(n==="today"){const f=new Date(t);f.setUTCHours(0,0,0,0);const p=new Date(t);return p.setUTCHours(23,59,59,999),{start:f,end:p}}if(n==="yesterday"){const f=new Date(t);f.setUTCDate(o-1),f.setUTCHours(0,0,0,0);const p=new Date(t);return p.setUTCDate(o-1),p.setUTCHours(23,59,59,999),{start:f,end:p}}if(n==="this week"){const f=a===0?-6:1-a,p=new Date(t);p.setUTCDate(o+f),p.setUTCHours(0,0,0,0);const h=new Date(p);return h.setUTCDate(p.getUTCDate()+6),h.setUTCHours(23,59,59,999),{start:p,end:h}}if(n==="this month"){const f=new Date(Date.UTC(s,i,1,0,0,0,0)),p=new Date(Date.UTC(s,i+1,0,23,59,59,999));return{start:f,end:p}}if(n==="this quarter"){const f=Math.floor(i/3),p=new Date(Date.UTC(s,f*3,1,0,0,0,0)),h=new Date(Date.UTC(s,f*3+3,0,23,59,59,999));return{start:p,end:h}}if(n==="this year"){const f=new Date(Date.UTC(s,0,1,0,0,0,0)),p=new Date(Date.UTC(s,11,31,23,59,59,999));return{start:f,end:p}}const u=n.match(/^last\s+(\d+)\s+days?$/);if(u){const f=parseInt(u[1],10),p=new Date(t);p.setUTCDate(o-f+1),p.setUTCHours(0,0,0,0);const h=new Date(t);return h.setUTCHours(23,59,59,999),{start:p,end:h}}const c=n.match(/^last\s+(\d+)\s+weeks?$/);if(c){const p=parseInt(c[1],10)*7,h=new Date(t);h.setUTCDate(o-p+1),h.setUTCHours(0,0,0,0);const g=new Date(t);return g.setUTCHours(23,59,59,999),{start:h,end:g}}if(n==="last week"){const f=a===0?-13:-6-a,p=new Date(t);p.setUTCDate(o+f),p.setUTCHours(0,0,0,0);const h=new Date(p);return h.setUTCDate(p.getUTCDate()+6),h.setUTCHours(23,59,59,999),{start:p,end:h}}if(n==="last month"){const f=new Date(Date.UTC(s,i-1,1,0,0,0,0)),p=new Date(Date.UTC(s,i,0,23,59,59,999));return{start:f,end:p}}if(n==="last quarter"){const f=Math.floor(i/3),p=f===0?3:f-1,h=f===0?s-1:s,g=new Date(Date.UTC(h,p*3,1,0,0,0,0)),y=new Date(Date.UTC(h,p*3+3,0,23,59,59,999));return{start:g,end:y}}if(n==="last year"){const f=new Date(Date.UTC(s-1,0,1,0,0,0,0)),p=new Date(Date.UTC(s-1,11,31,23,59,59,999));return{start:f,end:p}}if(n==="last 12 months"){const f=new Date(Date.UTC(s,i-11,1,0,0,0,0)),p=new Date(t);return p.setUTCHours(23,59,59,999),{start:f,end:p}}const l=n.match(/^last\s+(\d+)\s+months?$/);if(l){const f=parseInt(l[1],10),p=new Date(Date.UTC(s,i-f+1,1,0,0,0,0)),h=new Date(t);return h.setUTCHours(23,59,59,999),{start:p,end:h}}const m=n.match(/^last\s+(\d+)\s+years?$/);if(m){const f=parseInt(m[1],10),p=new Date(Date.UTC(s-f,0,1,0,0,0,0)),h=new Date(t);return h.setUTCHours(23,59,59,999),{start:p,end:h}}return null}normalizeDate(e){if(!e)return null;if(e instanceof Date)return isNaN(e.getTime())?null:this.databaseAdapter.isTimestampInteger()?this.databaseAdapter.getEngineType()==="sqlite"?Math.floor(e.getTime()/1e3):e.getTime():e.toISOString();if(typeof e=="number"){const n=e<1e10?e*1e3:e,s=new Date(n);return isNaN(s.getTime())?null:this.databaseAdapter.isTimestampInteger()?this.databaseAdapter.getEngineType()==="sqlite"?Math.floor(n/1e3):n:s.toISOString()}if(typeof e=="string"){if(/^\d{4}-\d{2}-\d{2}$/.test(e.trim())){const s=new Date(e+"T00:00:00Z");return isNaN(s.getTime())?null:this.databaseAdapter.isTimestampInteger()?this.databaseAdapter.getEngineType()==="sqlite"?Math.floor(s.getTime()/1e3):s.getTime():s.toISOString()}const n=new Date(e);return isNaN(n.getTime())?null:this.databaseAdapter.isTimestampInteger()?this.databaseAdapter.getEngineType()==="sqlite"?Math.floor(n.getTime()/1e3):n.getTime():n.toISOString()}const t=new Date(e);return isNaN(t.getTime())?null:this.databaseAdapter.isTimestampInteger()?this.databaseAdapter.getEngineType()==="sqlite"?Math.floor(t.getTime()/1e3):t.getTime():t.toISOString()}}class he{constructor(e,t){this.databaseAdapter=e,this.dateTimeBuilder=t}buildFilterCondition(e,t,n,s,i){if(i!==void 0){if(t!=="inDateRange")throw new Error(`dateRange can only be used with 'inDateRange' operator, but got '${t}'. Use explicit date values in the 'values' array for other date operators.`);if(s&&s.type!=="time")throw new Error(`dateRange can only be used on time dimensions, but field '${s.name||"unknown"}' has type '${s.type}'`);return this.dateTimeBuilder.buildDateRangeCondition(e,i)}if(!n||n.length===0)return t==="equals"?this.databaseAdapter.buildBooleanLiteral(!1):null;const o=n.filter(u=>!(u==null||u===""||typeof u=="string"&&u.includes("\0"))).map(this.databaseAdapter.convertFilterValue);if(o.length===0&&!["set","notSet"].includes(t))return t==="equals"?this.databaseAdapter.buildBooleanLiteral(!1):null;const a=o[0];switch(t){case"equals":if(o.length>1){if(s?.type==="time"){const u=o.map(c=>this.dateTimeBuilder.normalizeDate(c)||c);return Ee(e,u)}return Ee(e,o)}else if(o.length===1){const u=s?.type==="time"&&this.dateTimeBuilder.normalizeDate(a)||a;return P(e,u)}return this.databaseAdapter.buildBooleanLiteral(!1);case"notEquals":return o.length>1?Ue(e,o):o.length===1?je(e,a):null;case"contains":return this.databaseAdapter.buildStringCondition(e,"contains",a);case"notContains":return this.databaseAdapter.buildStringCondition(e,"notContains",a);case"startsWith":return this.databaseAdapter.buildStringCondition(e,"startsWith",a);case"endsWith":return this.databaseAdapter.buildStringCondition(e,"endsWith",a);case"gt":return we(e,a);case"gte":return Y(e,a);case"lt":return $e(e,a);case"lte":return X(e,a);case"set":return xe(e);case"notSet":return ke(e);case"inDateRange":if(o.length>=2){const u=this.dateTimeBuilder.normalizeDate(o[0]);let c=this.dateTimeBuilder.normalizeDate(o[1]);if(u&&c){const l=n[1];if(typeof l=="string"&&/^\d{4}-\d{2}-\d{2}$/.test(l.trim())){const m=typeof c=="number"?new Date(c*(this.databaseAdapter.getEngineType()==="sqlite"?1e3:1)):new Date(c),f=new Date(m);f.setUTCHours(23,59,59,999),this.databaseAdapter.isTimestampInteger()?c=this.databaseAdapter.getEngineType()==="sqlite"?Math.floor(f.getTime()/1e3):f.getTime():c=f.toISOString()}return _(Y(e,u),X(e,c))}}return null;case"beforeDate":{const u=this.dateTimeBuilder.normalizeDate(a);return u?$e(e,u):null}case"afterDate":{const u=this.dateTimeBuilder.normalizeDate(a);return u?we(e,u):null}case"between":return o.length>=2?_(Y(e,o[0]),X(e,o[1])):null;case"notBetween":return o.length>=2?ie($e(e,o[0]),we(e,o[1])):null;case"in":return o.length>0?Ee(e,o):null;case"notIn":return o.length>0?Ue(e,o):null;case"like":return this.databaseAdapter.buildStringCondition(e,"like",a);case"notLike":return this.databaseAdapter.buildStringCondition(e,"notLike",a);case"ilike":return this.databaseAdapter.buildStringCondition(e,"ilike",a);case"regex":return this.databaseAdapter.buildStringCondition(e,"regex",a);case"notRegex":return this.databaseAdapter.buildStringCondition(e,"notRegex",a);case"isEmpty":return ie(ke(e),P(e,""));case"isNotEmpty":return _(xe(e),je(e,""));case"arrayContains":return this.databaseAdapter.getEngineType()==="postgres"?Ct(e,o):null;case"arrayOverlaps":return this.databaseAdapter.getEngineType()==="postgres"?$t(e,o):null;case"arrayContained":return this.databaseAdapter.getEngineType()==="postgres"?wt(e,o):null;default:return null}}buildLogicalFilter(e,t,n){if("and"in e&&e.and){const s=e.and.map(i=>this.buildSingleFilter(i,t,n)).filter(i=>i!==null);return s.length>0?s.length===1?s[0]:_(...s):null}if("or"in e&&e.or){const s=e.or.map(i=>this.buildSingleFilter(i,t,n)).filter(i=>i!==null);return s.length>0?s.length===1?s[0]:ie(...s):null}return null}buildSingleFilter(e,t,n){if("and"in e||"or"in e)return this.buildLogicalFilter(e,t,n);const s=e,[i,o]=s.member.split("."),a=t.get(i);if(!a)return null;const u=a.dimensions?.[o];if(!u)return null;const c=R(u.sql,n);return this.buildFilterCondition(c,s.operator,s.values,u,s.dateRange)}}class J{dependencyGraph;cubes;constructor(e){this.cubes=e instanceof Map?e:new Map([[e.name,e]]),this.dependencyGraph=new Map}extractDependencies(e){const t=/\{([^}]+)\}/g,n=e.matchAll(t),s=[];for(const i of n){const o=i[1].trim();if(o.includes(".")){const[a,u]=o.split(".");s.push({measureName:o,cubeName:a.trim(),fieldName:u.trim()})}else s.push({measureName:o,cubeName:null,fieldName:o})}return s}buildGraph(e){for(const[t,n]of Object.entries(e.measures))if(n.type==="calculated"&&n.calculatedSql){const s=`${e.name}.${t}`,i=this.extractDependencies(n.calculatedSql),o=new Set;for(const a of i){const c=`${a.cubeName||e.name}.${a.fieldName}`;o.add(c)}this.dependencyGraph.set(s,{id:s,dependencies:o,inDegree:0})}this.calculateInDegrees()}buildGraphForMultipleCubes(e){for(const t of e.values())this.buildGraph(t)}calculateInDegrees(){for(const e of this.dependencyGraph.values())e.inDegree=0;for(const e of this.dependencyGraph.values())for(const t of e.dependencies){const n=this.dependencyGraph.get(t);n&&n.inDegree++}}topologicalSort(e){const t=new Map,n=[],s=[];for(const i of e){const o=this.dependencyGraph.get(i);o&&t.set(i,{id:o.id,dependencies:new Set(o.dependencies),inDegree:0})}for(const i of t.values()){let o=0;for(const a of i.dependencies)t.has(a)&&o++;i.inDegree=o}for(const[i,o]of t)o.inDegree===0&&n.push(i);for(;n.length>0;){const i=n.shift();s.push(i);for(const[o,a]of t)a.dependencies.has(i)&&(a.inDegree--,a.inDegree===0&&n.push(o))}if(s.length<t.size){const i=this.detectCycle();throw new Error(`Circular dependency detected in calculated measures: ${i?i.join(" -> "):"unknown cycle"}`)}return s}detectCycle(){const e=new Set,t=new Set,n=[];for(const s of this.dependencyGraph.keys())if(!e.has(s)){const i=this.dfs(s,e,t,n);if(i)return i}return null}dfs(e,t,n,s){t.add(e),n.add(e),s.push(e);const i=this.dependencyGraph.get(e);if(!i)return s.pop(),n.delete(e),null;for(const o of i.dependencies)if(t.has(o)){if(n.has(o)){const a=s.indexOf(o);return[...s.slice(a),o]}}else{const a=this.dfs(o,t,n,s);if(a)return a}return s.pop(),n.delete(e),null}getAllDependencies(e){const t=new Set,n=new Set,s=i=>{if(n.has(i))return;n.add(i);const o=this.dependencyGraph.get(i);if(o)for(const a of o.dependencies)t.add(a),s(a)};return s(e),t}validateDependencies(e){for(const[t,n]of Object.entries(e.measures))if(n.type==="calculated"&&n.calculatedSql){const s=this.extractDependencies(n.calculatedSql);for(const i of s){const o=i.cubeName||e.name,a=this.cubes.get(o);if(!a)throw new Error(`Calculated measure '${e.name}.${t}' references unknown cube '${o}'`);if(!a.measures[i.fieldName])throw new Error(`Calculated measure '${e.name}.${t}' references unknown measure '${i.measureName}'`);if(o===e.name&&i.fieldName===t)throw new Error(`Calculated measure '${e.name}.${t}' cannot reference itself`)}}}populateDependencies(e){for(const[,t]of Object.entries(e.measures))if(t.type==="calculated"&&t.calculatedSql&&!t.dependencies){const n=this.extractDependencies(t.calculatedSql);t.dependencies=n.map(s=>s.measureName)}}static isCalculatedMeasure(e){return e.type==="calculated"&&!!e.calculatedSql}}function Xt(d,e){const{cube:t,allCubes:n,resolvedMeasures:s}=e,i=Re(d),o=new Map;for(const m of i){const{originalRef:f,cubeName:p,fieldName:h}=m,g=p||t.name;if(!n.get(g))throw new Error(`Cannot substitute {${f}}: cube '${g}' not found`);const b=`${g}.${h}`,w=s.get(b);if(!w)throw new Error(`Cannot substitute {${f}}: measure '${b}' not resolved yet. Ensure measures are resolved in dependency order.`);const $=w(),S=r`${$}`;o.set(f,S)}const a=[],u=[];let c=0;for(const m of i){const f=`{${m.originalRef}}`,p=d.indexOf(f,c);if(p>=0){a.push(d.substring(c,p));const h=o.get(m.originalRef);h&&u.push(h),c=p+f.length}}if(a.push(d.substring(c)),u.length===0)return r.raw(d);const l=[];for(let m=0;m<a.length;m++)a[m]&&l.push(new L(a[m])),m<u.length&&l.push(u[m]);return r.join(l,r.raw(""))}function Re(d){const e=/\{([^}]+)\}/g,t=d.matchAll(e),n=[];for(const s of t){const i=s[1].trim();if(i.includes(".")){const[o,a]=i.split(".").map(u=>u.trim());n.push({originalRef:i,cubeName:o,fieldName:a})}else n.push({originalRef:i,cubeName:null,fieldName:i})}return n}function Zt(d){const e=[];let t=0;for(let o=0;o<d.length;o++)if(d[o]==="{")t++;else if(d[o]==="}"&&(t--,t<0)){e.push(`Unmatched closing brace at position ${o}`);break}t>0&&e.push("Unmatched opening brace in template"),/\{\s*\}/.test(d)&&e.push("Empty member reference {} found in template"),/\{[^}]*\{/.test(d)&&e.push("Nested braces are not allowed in member references");const i=Re(d);for(const o of i){const a=o.cubeName?`${o.cubeName}.${o.fieldName}`:o.fieldName;/^[a-zA-Z_][a-zA-Z0-9_.]*$/.test(a)||e.push(`Invalid member reference {${o.originalRef}}: must start with letter or underscore, and contain only letters, numbers, underscores, and dots`),a.split(".").length>2&&e.push(`Invalid member reference {${o.originalRef}}: only one dot allowed (Cube.measure format)`)}return{isValid:e.length===0,errors:e}}function Te(d,e){const t=Re(d),n=new Set;for(const s of t){const o=`${s.cubeName||e}.${s.fieldName}`;n.add(o)}return Array.from(n)}class O{constructor(e){this.databaseAdapter=e}buildResolvedMeasures(e,t,n,s){const i=new Map,o=[],a=[],u=new Set(e),c=new J(t);for(const l of t.values())c.buildGraph(l);for(const l of e){const[m,f]=l.split("."),p=t.get(m);if(p&&p.measures&&p.measures[f]){const h=p.measures[f];if(O.isPostAggregationWindow(h)){const g=O.getWindowBaseMeasure(h,m);g&&u.add(g);continue}J.isCalculatedMeasure(h)?(a.push(l),Te(h.calculatedSql,m).forEach(b=>u.add(b)),c.getAllDependencies(l).forEach(b=>{const[w,$]=b.split("."),S=t.get(w);if(S&&S.measures[$]){const C=S.measures[$];J.isCalculatedMeasure(C)&&Te(C.calculatedSql,w).forEach(T=>u.add(T))}})):o.push(l)}}for(const l of u){const[m,f]=l.split("."),p=t.get(m);if(p&&p.measures&&p.measures[f]){const h=p.measures[f];if(O.isPostAggregationWindow(h))continue;J.isCalculatedMeasure(h)?a.includes(l)||a.push(l):o.includes(l)||o.push(l)}}for(const l of o){const[m,f]=l.split("."),p=t.get(m),h=p.measures[f];if(s){const g=s(l,h,p);i.set(l,()=>g)}else i.set(l,()=>this.buildMeasureExpression(h,n,p))}if(a.length>0){const l=c.topologicalSort(a);for(const m of l){const[f,p]=m.split("."),h=t.get(f),g=h.measures[p];i.set(m,()=>this.buildCalculatedMeasure(g,h,t,i,n))}}return i}buildCalculatedMeasure(e,t,n,s,i){if(!e.calculatedSql)throw new Error(`Calculated measure '${t.name}.${e.name}' missing calculatedSql property`);const o=this.databaseAdapter.preprocessCalculatedTemplate(e.calculatedSql);return Xt(o,{cube:t,allCubes:n,resolvedMeasures:s})}buildCTECalculatedMeasure(e,t,n,s,i){if(!e.calculatedSql)throw new Error(`Calculated measure '${t.name}.${e.name||"unknown"}' missing calculatedSql property`);const o=new Map,a=Te(e.calculatedSql,t.name);for(const u of a){const[c,l]=u.split("."),m=s.get(c);if(m&&m.measures[l]){const f=m.measures[l];if(n.measures.includes(u)){const p=r`${r.identifier(n.cteAlias)}.${r.identifier(l)}`;let h;switch(f.type){case"count":case"countDistinct":case"sum":h=W(p);break;case"avg":h=this.databaseAdapter.buildAvg(p);break;case"min":h=re(p);break;case"max":h=z(p);break;case"number":h=W(p);break;default:h=W(p)}o.set(u,()=>h)}}}return this.buildCalculatedMeasure(e,t,s,o,i)}buildHavingMeasureExpression(e,t,n,s,i){if(i&&i.preAggregationCTEs){const o=i.preAggregationCTEs.find(a=>a.cube.name===e);if(o&&o.measures.includes(`${e}.${t}`))if(n.type==="calculated"&&n.calculatedSql){const a=i.primaryCube.name===e?i.primaryCube:i.joinCubes?.find(c=>c.cube.name===e)?.cube;if(!a)throw new Error(`Cube ${e} not found in query plan`);const u=new Map([[i.primaryCube.name,i.primaryCube]]);if(i.joinCubes)for(const c of i.joinCubes)u.set(c.cube.name,c.cube);return this.buildCTECalculatedMeasure(n,a,o,u,s)}else{const a=r`${r.identifier(o.cteAlias)}.${r.identifier(t)}`;switch(n.type){case"count":case"countDistinct":case"sum":return W(a);case"avg":return this.databaseAdapter.buildAvg(a);case"min":return re(a);case"max":return z(a);case"number":return W(a);default:return W(a)}}}return this.buildMeasureExpression(n,s)}buildMeasureExpression(e,t,n){if(e.type==="calculated")throw new Error(`Cannot build calculated measure '${e.name}' directly. Use buildCalculatedMeasure instead.`);if(O.isPostAggregationWindow(e))throw new Error(`Post-aggregation window measure '${e.name}' should be built via buildPostAggregationWindowExpression, not buildMeasureExpression.`);if(!e.sql)throw new Error(`Measure '${e.name}' of type '${e.type}' is missing required 'sql' property. Only calculated measures and post-aggregation window functions can omit 'sql'.`);let s=R(e.sql,t);if(e.filters&&e.filters.length>0){const i=e.filters.map(o=>{const a=o(t);return a?r`(${a})`:void 0}).filter(Boolean);if(i.length>0){const o=i.length===1?i[0]:_(...i);s=this.databaseAdapter.buildCaseWhen([{when:o,then:s}])}}switch(e.type){case"count":return De(s);case"countDistinct":return Tt(s);case"sum":return W(s);case"avg":return this.databaseAdapter.buildAvg(s);case"min":return re(s);case"max":return z(s);case"number":return s;case"stddev":case"stddevSamp":{const i=e.type==="stddevSamp"||e.statisticalConfig?.useSample,o=this.databaseAdapter.buildStddev(s,i);return o===null?(console.warn(`[drizzle-cube] ${e.type} not supported on ${this.databaseAdapter.getEngineType()}, returning NULL`),r`MAX(NULL)`):o}case"variance":case"varianceSamp":{const i=e.type==="varianceSamp"||e.statisticalConfig?.useSample,o=this.databaseAdapter.buildVariance(s,i);return o===null?(console.warn(`[drizzle-cube] ${e.type} not supported on ${this.databaseAdapter.getEngineType()}, returning NULL`),r`MAX(NULL)`):o}case"percentile":case"median":case"p95":case"p99":{let i;switch(e.type){case"median":i=50;break;case"p95":i=95;break;case"p99":i=99;break;default:i=e.statisticalConfig?.percentile??50}const o=this.databaseAdapter.buildPercentile(s,i);return o===null?(console.warn(`[drizzle-cube] ${e.type} not supported on ${this.databaseAdapter.getEngineType()}, returning NULL`),r`MAX(NULL)`):o}case"lag":case"lead":case"rank":case"denseRank":case"rowNumber":case"ntile":case"firstValue":case"lastValue":case"movingAvg":case"movingSum":{const i=e.windowConfig||{};let o;if(i.partitionBy&&i.partitionBy.length>0&&n){const c=i.partitionBy.map(l=>{const m=l.includes(".")?l.split(".")[1]:l,f=n.dimensions?.[m];return f?R(f.sql,t):(console.warn(`[drizzle-cube] Window function partition dimension '${l}' not found in cube '${n.name}'`),null)}).filter(l=>l!==null);c.length>0&&(o=c)}let a;if(i.orderBy&&i.orderBy.length>0&&n){const c=i.orderBy.map(l=>{const m=l.field.includes(".")?l.field.split(".")[1]:l.field,f=n.dimensions?.[m];if(f)return{field:R(f.sql,t),direction:l.direction};const p=n.measures?.[m];return p&&p.sql?{field:R(p.sql,t),direction:l.direction}:(console.warn(`[drizzle-cube] Window function order field '${l.field}' not found in cube '${n.name}'`),null)}).filter(l=>l!==null);c.length>0&&(a=c)}const u=this.databaseAdapter.buildWindowFunction(e.type,["rank","denseRank","rowNumber"].includes(e.type)?null:s,o,a,{offset:i.offset,defaultValue:i.defaultValue,nTile:i.nTile,frame:i.frame});return u===null?(console.warn(`[drizzle-cube] ${e.type} not supported on ${this.databaseAdapter.getEngineType()}, returning NULL`),r`NULL`):u}default:return De(s)}}static WINDOW_FUNCTION_TYPES=["lag","lead","rank","denseRank","rowNumber","ntile","firstValue","lastValue","movingAvg","movingSum"];static isWindowFunction(e){return O.WINDOW_FUNCTION_TYPES.includes(e)}static categorizeMeasures(e,t){const n=[],s=[];for(const i of e){const[o,a]=i.split("."),u=t.get(o);if(u?.measures?.[a]){const c=u.measures[a];O.isWindowFunction(c.type)?n.push(i):s.push(i)}}return{windowMeasures:n,aggregateMeasures:s}}static hasWindowFunctions(e,t){const{windowMeasures:n}=O.categorizeMeasures(e,t);return n.length>0}static isPostAggregationWindow(e){return O.isWindowFunction(e.type)&&e.windowConfig?.measure!==void 0}static getWindowBaseMeasure(e,t){if(!e.windowConfig?.measure)return null;const n=e.windowConfig.measure;return n.includes(".")?n:`${t}.${n}`}static getDefaultWindowOperation(e){switch(e){case"lag":case"lead":return"difference";default:return"raw"}}static categorizeForPostAggregation(e,t){const n=[],s=[],i=new Set;for(const o of e){const[a,u]=o.split("."),c=t.get(a);if(c?.measures?.[u]){const l=c.measures[u];if(O.isPostAggregationWindow(l)){s.push(o);const m=O.getWindowBaseMeasure(l,a);m&&i.add(m)}else O.isWindowFunction(l.type)||n.push(o)}}return{aggregateMeasures:n,postAggWindowMeasures:s,requiredBaseMeasures:i}}static hasPostAggregationWindows(e,t){const{postAggWindowMeasures:n}=O.categorizeForPostAggregation(e,t);return n.length>0}}class en{constructor(e){this.dateTimeBuilder=e}isWindowFunctionType(e){return["lag","lead","rank","denseRank","rowNumber","ntile","firstValue","lastValue","movingAvg","movingSum"].includes(e)}isAggregateFunctionType(e){return["count","countDistinct","sum","avg","min","max","stddev","stddevSamp","variance","varianceSamp","median","p95","p99","percentile","number"].includes(e)}buildGroupByFields(e,t,n,s){const i=[],o=e instanceof Map?e:new Map([[e.name,e]]),a=t.dimensions&&t.dimensions.length>0||t.timeDimensions&&t.timeDimensions.length>0,u=t.measures&&t.measures.length>0,c=a&&!u;let l=!1;for(const m of t.measures||[]){const[f,p]=m.split("."),h=o.get(f);if(h&&h.measures&&h.measures[p]){const g=h.measures[p];if(this.isAggregateFunctionType(g.type)||g.type==="calculated"){l=!0;break}if(O.isPostAggregationWindow(g)){const y=O.getWindowBaseMeasure(g,f);if(y){const[b,w]=y.split("."),S=o.get(b)?.measures?.[w];if(S&&this.isAggregateFunctionType(S.type)){l=!0;break}}}}}if(!l&&!c)return[];if(t.dimensions)for(const m of t.dimensions){const[f,p]=m.split("."),h=o.get(f);if(h&&h.dimensions&&h.dimensions[p])if(s?.preAggregationCTEs?.some(y=>y.cube.name===f)){const y=s.preAggregationCTEs.find(w=>w.cube.name===f),b=y.joinKeys.find(w=>w.targetColumn===p);if(b&&b.sourceColumnObj)i.push(b.sourceColumnObj);else{const w=r`${r.identifier(y.cteAlias)}.${r.identifier(p)}`;i.push(w)}}else{const y=h.dimensions[p],b=R(y.sql,n);i.push(b)}}if(t.timeDimensions)for(const m of t.timeDimensions){const[f,p]=m.dimension.split("."),h=o.get(f);if(h&&h.dimensions&&h.dimensions[p])if(s?.preAggregationCTEs?.some(y=>y.cube.name===f)){const y=s.preAggregationCTEs.find(w=>w.cube.name===f),b=y.joinKeys.find(w=>w.targetColumn===p);if(b&&b.sourceColumnObj){const w=this.dateTimeBuilder.buildTimeDimensionExpression(b.sourceColumnObj,m.granularity,n);i.push(w)}else{const w=r`${r.identifier(y.cteAlias)}.${r.identifier(p)}`;i.push(w)}}else{const y=h.dimensions[p],b=this.dateTimeBuilder.buildTimeDimensionExpression(y.sql,m.granularity,n);i.push(b)}}return i}}class tn{dateTimeBuilder;filterBuilder;groupByBuilder;measureBuilder;constructor(e){this.dateTimeBuilder=new te(e),this.filterBuilder=new he(e,this.dateTimeBuilder),this.groupByBuilder=new en(this.dateTimeBuilder),this.measureBuilder=new O(e)}buildResolvedMeasures(e,t,n,s){return this.measureBuilder.buildResolvedMeasures(e,t,n,s)}buildSelections(e,t,n){const s={},i=e instanceof Map?e:new Map([[e.name,e]]);if(t.dimensions)for(const o of t.dimensions){const[a,u]=o.split("."),c=i.get(a);if(c&&c.dimensions&&c.dimensions[u]){const l=c.dimensions[u],m=R(l.sql,n);s[o]=r`${m}`.as(o)}}if(t.measures){const o=this.buildResolvedMeasures(t.measures,i,n);for(const a of t.measures){const u=o.get(a);if(u){const c=u();s[a]=r`${c}`.as(a)}}}if(t.timeDimensions)for(const o of t.timeDimensions){const[a,u]=o.dimension.split("."),c=i.get(a);if(c&&c.dimensions&&c.dimensions[u]){const l=c.dimensions[u],m=this.buildTimeDimensionExpression(l.sql,o.granularity,n);s[o.dimension]=r`${m}`.as(o.dimension)}}return Object.keys(s).length===0&&(s.count=De()),s}buildCalculatedMeasure(e,t,n,s,i){return this.measureBuilder.buildCalculatedMeasure(e,t,n,s,i)}buildCTECalculatedMeasure(e,t,n,s,i){return this.measureBuilder.buildCTECalculatedMeasure(e,t,n,s,i)}buildHavingMeasureExpression(e,t,n,s,i){return this.measureBuilder.buildHavingMeasureExpression(e,t,n,s,i)}buildMeasureExpression(e,t,n){return this.measureBuilder.buildMeasureExpression(e,t,n)}buildTimeDimensionExpression(e,t,n){return this.dateTimeBuilder.buildTimeDimensionExpression(e,t,n)}buildWhereConditions(e,t,n,s,i){const o=[],a=e instanceof Map?e:new Map([[e.name,e]]),u=new Set;if(t.filters&&t.filters.length>0)for(const c of t.filters){if(i&&"member"in c){const[m]=c.member.split(".");if(a.has(m)&&i.has(m)&&!u.has(m)){const p=i.get(m);o.push(...p),u.add(m);continue}else if(u.has(m))continue}const l=this.processFilter(c,a,n,"where",s);l&&o.push(l)}if(t.timeDimensions)for(const c of t.timeDimensions){const[l,m]=c.dimension.split("."),f=a.get(l);if(f&&f.dimensions[m]&&c.dateRange){if(s?.preAggregationCTEs&&s.preAggregationCTEs.some(b=>b.cube.name===l))continue;if(n.filterCache){const y=it(c.dimension,c.dateRange),b=n.filterCache.get(y);if(b){o.push(b);continue}}const p=f.dimensions[m],h=R(p.sql,n),g=this.buildDateRangeCondition(h,c.dateRange);g&&o.push(g)}}return o}buildHavingConditions(e,t,n,s){const i=[],o=e instanceof Map?e:new Map([[e.name,e]]);if(t.filters&&t.filters.length>0)for(const a of t.filters){const u=this.processFilter(a,o,n,"having",s);u&&i.push(u)}return i}processFilter(e,t,n,s,i){if("and"in e||"or"in e){const p=e;if(p.and){const h=p.and.map(g=>this.processFilter(g,t,n,s,i)).filter(g=>g!==null);return h.length>0?_(...h):null}if(p.or){const h=p.or.map(g=>this.processFilter(g,t,n,s,i)).filter(g=>g!==null);return h.length>0?ie(...h):null}}const o=e,[a,u]=o.member.split("."),c=t.get(a);if(!c)return null;const l=c.dimensions[u],m=c.measures[u],f=l||m;if(!f)return null;if(s==="where"&&l){if(i?.preAggregationCTEs&&i.preAggregationCTEs.some(y=>y.cube.name===a))return null;const p=["arrayContains","arrayOverlaps","arrayContained"].includes(o.operator);if(!p&&n.filterCache){const g=de(e),y=n.filterCache.get(g);if(y)return y}const h=p?typeof l.sql=="function"?l.sql(n):l.sql:R(l.sql,n);return this.buildFilterCondition(h,o.operator,o.values,f,o.dateRange)}else{if(s==="where"&&m)return null;if(s==="having"&&m){const p=this.buildHavingMeasureExpression(a,u,m,n,i);return this.buildFilterCondition(p,o.operator,o.values,f,o.dateRange)}}return null}buildFilterCondition(e,t,n,s,i){return this.filterBuilder.buildFilterCondition(e,t,n,s,i)}buildDateRangeCondition(e,t){return this.dateTimeBuilder.buildDateRangeCondition(e,t)}buildGroupByFields(e,t,n,s){return this.groupByBuilder.buildGroupByFields(e,t,n,s)}buildOrderBy(e,t){const n=[],s=t||[...e.measures||[],...e.dimensions||[],...e.timeDimensions?.map(i=>i.dimension)||[]];if(e.order&&Object.keys(e.order).length>0)for(const[i,o]of Object.entries(e.order)){if(!s.includes(i))throw new Error(`Cannot order by '${i}': field is not selected in the query`);const a=o==="desc"?Et(r.identifier(i)):Be(r.identifier(i));n.push(a)}if(e.timeDimensions&&e.timeDimensions.length>0){const i=new Set(Object.keys(e.order||{})),o=[...e.timeDimensions].sort((a,u)=>a.dimension.localeCompare(u.dimension));for(const a of o)i.has(a.dimension)||n.push(Be(r.identifier(a.dimension)))}return n}collectNumericFields(e,t){const n=[],s=e instanceof Map?e:new Map([[e.name,e]]);if(t.measures&&n.push(...t.measures),t.dimensions)for(const i of t.dimensions){const[o,a]=i.split("."),u=s.get(o);if(u){const c=u.dimensions[a];c&&c.type==="number"&&n.push(i)}}return n}applyLimitAndOffset(e,t){let n=t.limit;t.offset!==void 0&&t.offset>0&&n===void 0&&(n=50);let s=e;if(n!==void 0){if(n<0)throw new Error("Limit must be non-negative");s=s.limit(n)}if(t.offset!==void 0){if(t.offset<0)throw new Error("Offset must be non-negative");s=s.offset(t.offset)}return s}buildFilterConditionPublic(e,t,n,s,i){return this.buildFilterCondition(e,t,n,s,i)}buildLogicalFilter(e,t,n){return this.filterBuilder.buildLogicalFilter(e,t,n)}}class oe{cubes;connectivityCache=new Map;constructor(e){this.cubes=e}findPath(e,t,n=new Set){if(e===t)return[];const s=this.getCacheKey(e,t,n),i=this.getFromCache(s);if(i!==void 0)return i;const o=[{cube:e,path:[]}],a=new Set([e,...n]);for(;o.length>0;){const{cube:u,path:c}=o.shift(),l=this.cubes.get(u);if(l?.joins)for(const[,m]of Object.entries(l.joins)){const p=q(m.targetCube).name;if(a.has(p))continue;const h=[...c,{fromCube:u,toCube:p,joinDef:m}];if(p===t)return this.setInCache(s,h),h;a.add(p),o.push({cube:p,path:h})}}return this.setInCache(s,null),null}findPathPreferring(e,t,n,s=new Set){const i=this.findAllPaths(e,t,new Set);if(i.length===0)return this.findPath(e,t,s);const o=i.map(a=>{let u=0;a.some((m,f)=>m.joinDef.preferredFor?.includes(t)&&f===0)&&(u+=10);const l=a.filter(m=>n.has(m.toCube)).length;return u+=l,u-=a.length-1,{path:a,score:u,usesProcessed:a.some(m=>s.has(m.toCube))}});return o.sort((a,u)=>u.score!==a.score?u.score-a.score:a.usesProcessed!==u.usesProcessed?a.usesProcessed?-1:1:a.path.length-u.path.length),o[0].path}findAllPaths(e,t,n,s=4){if(e===t)return[[]];const i=[],o=[{cube:e,path:[],visited:new Set([e,...n])}];for(;o.length>0;){const{cube:a,path:u,visited:c}=o.shift();if(u.length>=s)continue;const l=this.cubes.get(a);if(l?.joins)for(const[,m]of Object.entries(l.joins)){const p=q(m.targetCube).name;if(c.has(p))continue;const h=[...u,{fromCube:a,toCube:p,joinDef:m}];if(p===t)i.push(h);else{const g=new Set(c);g.add(p),o.push({cube:p,path:h,visited:g})}}}return i}canReachAll(e,t){const n=t.filter(s=>s!==e);for(const s of n){const i=this.findPath(e,s,new Set);if(!i||i.length===0)return!1}return!0}buildJoinCondition(e,t,n){const s=[];for(const i of e.on){const o=t?r`${r.identifier(t)}.${r.identifier(i.source.name)}`:_e(i.source),a=n?r`${r.identifier(n)}.${r.identifier(i.target.name)}`:_e(i.target),u=i.as||P;s.push(u(o,a))}return _(...s)}getReachableCubes(e){const t=new Set([e]),n=[e];for(;n.length>0;){const s=n.shift(),i=this.cubes.get(s);if(i?.joins)for(const[,o]of Object.entries(i.joins)){const u=q(o.targetCube).name;t.has(u)||(t.add(u),n.push(u))}}return t}getCacheKey(e,t,n){const s=Array.from(n).sort().join(",");return`${e}:${t}:${s}`}getFromCache(e){const t=this.connectivityCache.get(e);if(t)return t.path}setInCache(e,t){this.connectivityCache.set(e,{path:t})}}class rt{resolverCache=new WeakMap;getResolver(e){let t=this.resolverCache.get(e);return t||(t=new oe(e),this.resolverCache.set(e,t)),t}analyzeCubeUsage(e){const t=new Set;if(e.measures)for(const n of e.measures){const[s]=n.split(".");t.add(s)}if(e.dimensions)for(const n of e.dimensions){const[s]=n.split(".");t.add(s)}if(e.timeDimensions)for(const n of e.timeDimensions){const[s]=n.dimension.split(".");t.add(s)}if(e.filters)for(const n of e.filters)this.extractCubeNamesFromFilter(n,t);return t}extractCubeNamesFromFilter(e,t){if("and"in e||"or"in e){const n=e.and||e.or||[];for(const s of n)this.extractCubeNamesFromFilter(s,t);return}if("member"in e){const[n]=e.member.split(".");n&&t.add(n)}}extractMeasuresFromFilters(e,t){const n=[];if(!e.filters)return n;for(const s of e.filters)this.extractMeasuresFromFilter(s,t,n);return n}extractMeasuresFromFilter(e,t,n){if("and"in e||"or"in e){const s=e.and||e.or||[];for(const i of s)this.extractMeasuresFromFilter(i,t,n);return}if("member"in e){const s=e.member,[i,o]=s.split(".");i===t.name&&t.measures&&t.measures[o]&&n.push(s)}}createQueryPlan(e,t,n){const s=this.analyzeCubeUsage(t),i=Array.from(s);if(i.length===0)throw new Error("No cubes found in query");const o=this.choosePrimaryCube(i,t,e),a=e.get(o);if(!a)throw new Error(`Primary cube '${o}' not found`);if(i.length===1)return{primaryCube:a,joinCubes:[],selections:{},whereConditions:[],groupByFields:[]};const u=this.buildJoinPlan(e,a,i,n,t),c=this.planPreAggregationCTEs(e,a,u,t,n),l=this.generateWarnings(t,c);return{primaryCube:a,joinCubes:u,selections:{},whereConditions:[],groupByFields:[],preAggregationCTEs:c,warnings:l.length>0?l:void 0}}choosePrimaryCube(e,t,n){return e.length===1?e[0]:n?this.analyzePrimaryCubeSelection(e,t,n).selectedCube:[...e].sort()[0]}buildJoinPlan(e,t,n,s,i){const o=this.getResolver(e),a=[],u=new Set([t.name]),c=new Set;if(i.measures)for(const f of i.measures){const[p]=f.split(".");c.add(p)}const l=new Set;for(const f of c){if(f===t.name)continue;this.findHasManyJoinDef(t,f)&&l.add(f)}const m=n.filter(f=>f!==t.name);for(const f of m){if(u.has(f))continue;const p=new Set([...u].filter(g=>!l.has(g))),h=o.findPathPreferring(t.name,f,c,p);if(!h||h.length===0)throw new Error(`No join path found from '${t.name}' to '${f}'`);for(const{toCube:g,joinDef:y}of h){if(u.has(g))continue;const b=e.get(g);if(!b)throw new Error(`Cube '${g}' not found`);if(y.relationship==="belongsToMany"&&y.through){const w=Kt(y,s.securityContext);a.push({cube:b,alias:`${g.toLowerCase()}_cube`,joinType:w.junctionJoins[1].joinType,joinCondition:w.junctionJoins[1].condition,junctionTable:{table:y.through.table,alias:`junction_${g.toLowerCase()}`,joinType:w.junctionJoins[0].joinType,joinCondition:w.junctionJoins[0].condition,securitySql:y.through.securitySql}})}else{const w=o.buildJoinCondition(y,null,null),$=Ae(y.relationship,y.sqlJoinType);a.push({cube:b,alias:`${g.toLowerCase()}_cube`,joinType:$,joinCondition:w})}u.add(g)}}return a}planPreAggregationCTEs(e,t,n,s,i){const o=[];if(!s.measures||s.measures.length===0)return o;const a=this.detectHasManyInQuery(e,t,n);if(a.length===0)return o;const u=new Set;for(const l of s.measures){const[m]=l.split(".");u.add(m)}for(const l of e.values())this.extractMeasuresFromFilters(s,l).length>0&&u.add(l.name);const c=[];for(const l of n)c.push({cube:l.cube,alias:l.alias,isPrimary:!1});for(const{cube:l,alias:m,isPrimary:f}of c){const p=this.getCTEReason(l,t,a,s);if(!p)continue;const h=s.measures.filter(N=>N.startsWith(l.name+".")),g=this.extractMeasuresFromFilters(s,l),y=[...new Set([...h,...g])];if(y.length===0)continue;const b=this.analyzeJoinPathToPrimary(e,t,l.name,i);let w,$;if(b?.hasIntermediateHasMany&&b.intermediateJoins.length>0)w=b.correctJoinKeys,$=b.intermediateJoins;else{const N=f?this.findJoinInfoToCube(e,t.name):this.findJoinInfoForCube(e,t,l.name);if(!N)continue;w=f?N.joinDef.on.map(A=>({sourceColumn:A.target.name,targetColumn:A.source.name,sourceColumnObj:A.target,targetColumnObj:A.source})):N.joinDef.on.map(A=>({sourceColumn:A.source.name,targetColumn:A.target.name,sourceColumnObj:A.source,targetColumnObj:A.target})),$=void 0}const S=this.findPropagatingFilters(s,l,e),C=new Map([[l.name,l]]),{aggregateMeasures:E,requiredBaseMeasures:T}=O.categorizeForPostAggregation(y,C),D=[...new Set([...E,...Array.from(T).filter(N=>N.startsWith(l.name+"."))])];if(D.length>0){const N=this.expandCalculatedMeasureDependencies(l,D),A=this.findDownstreamJoinKeys(l,s,e);o.push({cube:l,alias:m,cteAlias:`${l.name.toLowerCase()}_agg`,joinKeys:w,measures:N,propagatingFilters:S.length>0?S:void 0,downstreamJoinKeys:A.length>0?A:void 0,intermediateJoins:$&&$.length>0?$:void 0,cteType:"aggregate",cteReason:p})}}return o}findJoinInfoToCube(e,t){for(const[,n]of e)if(n.name!==t&&n.joins){for(const[,s]of Object.entries(n.joins))if(q(s.targetCube).name===t)return{sourceCube:n,joinDef:s}}return null}analyzeJoinPathToPrimary(e,t,n,s){const o=this.getResolver(e).findPath(t.name,n);if(!o||o.length===0)return null;const a=o.map(p=>({fromCube:p.fromCube,toCube:p.toCube,joinDef:p.joinDef}));if(!a.slice(0,-1).some(p=>p.joinDef.relationship==="hasMany"))return{path:a,hasIntermediateHasMany:!1,intermediateJoins:[],correctJoinKeys:[]};const l=[];for(let p=0;p<a.length-1;p++){const h=a[p],g=a[p+1],y=e.get(h.toCube);if(!y)continue;const w=y.sql(s).where,$=g.joinDef.on[0]?.source,S=h.joinDef.on[0]?.target;l.push({cube:y,joinDef:g.joinDef,securityFilter:w,primaryJoinColumn:S,cteJoinColumn:$})}const f=a[0].joinDef.on.map(p=>({sourceColumn:p.source.name,targetColumn:p.target.name,sourceColumnObj:p.source,targetColumnObj:p.target}));return{path:a,hasIntermediateHasMany:!0,intermediateJoins:l,correctJoinKeys:f}}detectHasManyInQuery(e,t,n){const s=[],i=new Set,o=new Set;o.add(t.name);for(const a of n)o.add(a.cube.name);for(const[a,u]of e)if(!i.has(a)&&(i.add(a),!!u.joins)){for(const[,c]of Object.entries(u.joins))if(c.relationship==="hasMany"){const l=q(c.targetCube);(o.has(a)||o.has(l.name))&&s.push({fromCube:a,toCube:l.name,joinDef:c})}}return s}getCTEReason(e,t,n,s){if(n.some(a=>a.toCube===e.name)&&s.measures?.some(u=>u.startsWith(e.name+".")))return"hasMany";if(!s.measures?.some(a=>a.startsWith(e.name+".")))return null;for(const a of n)if(a.fromCube!==e.name&&a.toCube!==e.name)return"fanOutPrevention";return null}findJoinInfoForCube(e,t,n){if(t.joins){for(const[,s]of Object.entries(t.joins))if(q(s.targetCube).name===n)return{sourceCube:t,joinDef:s}}for(const[,s]of e)if(s.name!==t.name&&s.joins){for(const[,i]of Object.entries(s.joins))if(q(i.targetCube).name===n)return{sourceCube:s,joinDef:i}}return null}findDownstreamJoinKeys(e,t,n){const s=[],i=new Set;if(t.dimensions)for(const o of t.dimensions){const[a]=o.split(".");a!==e.name&&i.add(a)}if(t.timeDimensions)for(const o of t.timeDimensions){const[a]=o.dimension.split(".");a!==e.name&&i.add(a)}if(e.joins)for(const[,o]of Object.entries(e.joins)){const u=q(o.targetCube).name;if(i.has(u)){const c=o.on.map(l=>({sourceColumn:l.source.name,targetColumn:l.target.name,sourceColumnObj:l.source,targetColumnObj:l.target}));s.push({targetCubeName:u,joinKeys:c})}}return s}expandCalculatedMeasureDependencies(e,t){const n=new Set,s=[...t];for(;s.length>0;){const i=s.pop();if(n.has(i))continue;n.add(i);const[,o]=i.split(".");if(!e.measures||!e.measures[o])continue;const a=e.measures[o];if(a.type==="calculated"&&a.calculatedSql){const u=this.extractDependenciesFromTemplate(a.calculatedSql,e.name);for(const c of u)n.has(c)||s.push(c)}}return Array.from(n)}extractDependenciesFromTemplate(e,t){const n=/\{([^}]+)\}/g,s=e.matchAll(n),i=[];for(const o of s){const a=o[1].trim();a.includes(".")?i.push(a):i.push(`${t}.${a}`)}return i}findHasManyJoinDef(e,t){if(!e.joins)return null;for(const[,n]of Object.entries(e.joins))if(q(n.targetCube).name===t&&n.relationship==="hasMany")return n;return null}findPropagatingFilters(e,t,n){const s=[];if(!e.filters)return s;const i=new Set;if(this.extractFilterCubeNamesToSet(e.filters,i),e.timeDimensions){for(const o of e.timeDimensions)if(o.dateRange){const[a]=o.dimension.split(".");a&&i.add(a)}}for(const o of i){if(o===t.name)continue;const a=n.get(o);if(a?.joins){for(const[,u]of Object.entries(a.joins))if(q(u.targetCube).name===t.name&&u.relationship==="hasMany"){const l=this.extractFiltersForCube(e.filters,o),m=this.extractTimeDimensionFiltersForCube(e,o),f=[...l,...m];f.length>0&&u.on.length>0&&s.push({sourceCube:a,filters:f,joinConditions:u.on.map(p=>({source:p.source,target:p.target}))})}}}return s}extractFilterCubeNamesToSet(e,t){for(const n of e){if("and"in n||"or"in n){const s=n.and||n.or||[];this.extractFilterCubeNamesToSet(s,t);continue}if("member"in n){const[s]=n.member.split(".");s&&t.add(s)}}}extractFiltersForCube(e,t){const n=[];for(const s of e){if("and"in s){const i=this.extractFiltersForCube(s.and||[],t);i.length>0&&n.push({and:i});continue}if("or"in s){const i=s.or||[];if(this.allFiltersFromCube(i,t)){const a=this.extractFiltersForCube(i,t);a.length>0&&n.push({or:a})}continue}if("member"in s){const[i]=s.member.split(".");i===t&&n.push(s)}}return n}allFiltersFromCube(e,t){for(const n of e){if("and"in n){if(!this.allFiltersFromCube(n.and||[],t))return!1;continue}if("or"in n){if(!this.allFiltersFromCube(n.or||[],t))return!1;continue}if("member"in n){const[s]=n.member.split(".");if(s!==t)return!1}}return!0}extractTimeDimensionFiltersForCube(e,t){const n=[];if(!e.timeDimensions)return n;for(const s of e.timeDimensions){const[i]=s.dimension.split(".");i===t&&s.dateRange&&n.push({member:s.dimension,operator:"inDateRange",values:Array.isArray(s.dateRange)?s.dateRange:[s.dateRange]})}return n}analyzeQueryPlan(e,t,n){const s=this.analyzeCubeUsage(t),i=Array.from(s);if(i.length===0)return{timestamp:new Date().toISOString(),cubeCount:0,cubesInvolved:[],primaryCube:{selectedCube:"",reason:"single_cube",explanation:"No cubes found in query"},joinPaths:[],preAggregations:[],querySummary:{queryType:"single_cube",joinCount:0,cteCount:0,hasPreAggregation:!1},warnings:["No cubes found in query - add measures or dimensions"]};const o=this.analyzePrimaryCubeSelection(i,t,e),a=o.selectedCube,u={timestamp:new Date().toISOString(),cubeCount:i.length,cubesInvolved:i.sort(),primaryCube:o,joinPaths:[],preAggregations:[],querySummary:{queryType:"single_cube",joinCount:0,cteCount:0,hasPreAggregation:!1},warnings:[]};if(i.length>1){const c=i.filter(g=>g!==a);for(const g of c)u.joinPaths.push(this.analyzeJoinPath(e,a,g));const l=e.get(a);l&&(u.preAggregations=this.analyzePreAggregations(e,l,c,t));const m=u.joinPaths.filter(g=>g.pathFound),f=u.joinPaths.filter(g=>!g.pathFound);u.querySummary.joinCount=m.length,u.querySummary.cteCount=u.preAggregations.length,u.querySummary.hasPreAggregation=u.preAggregations.length>0;const p=new Map;for(const g of i){const y=e.get(g);y&&p.set(g,y)}const h=O.hasPostAggregationWindows(t.measures||[],p);u.querySummary.hasWindowFunctions=h,u.preAggregations.length>0?u.querySummary.queryType="multi_cube_cte":u.querySummary.queryType="multi_cube_join";for(const g of f)u.warnings.push(`No join path found to cube '${g.targetCube}'. Check that joins are defined correctly.`);h&&u.warnings.push("Query contains post-aggregation window functions which will be applied to aggregated results.")}return u}analyzePrimaryCubeSelection(e,t,n){if(e.length===1)return{selectedCube:e[0],reason:"single_cube",explanation:"Only one cube is used in this query"};const s=[],i=(t.dimensions||[]).map(l=>l.split(".")[0]),o=new Map;for(const l of i)o.set(l,(o.get(l)||0)+1);const a=this.getResolver(n);for(const l of e){const m=n.get(l),f=o.get(l)||0,p=m?.joins?Object.keys(m.joins).length:0,h=a.canReachAll(l,e);s.push({cubeName:l,dimensionCount:f,joinCount:p,canReachAll:h})}if(t.dimensions&&t.dimensions.length>0){const l=Math.max(...s.map(m=>m.dimensionCount));if(l>0){const m=s.filter(f=>f.dimensionCount===l).sort((f,p)=>f.cubeName.localeCompare(p.cubeName));for(const f of m)if(f.canReachAll)return{selectedCube:f.cubeName,reason:"most_dimensions",explanation:`Selected because it has ${f.dimensionCount} dimension${f.dimensionCount!==1?"s":""} in the query (defines the analytical grain)`,candidates:s}}}const u=s.filter(l=>l.canReachAll);if(u.length>0){const l=Math.max(...u.map(f=>f.joinCount)),m=u.filter(f=>f.joinCount===l).sort((f,p)=>f.cubeName.localeCompare(p.cubeName))[0];return{selectedCube:m.cubeName,reason:"most_connected",explanation:`Selected because it has ${m.joinCount} join relationship${m.joinCount!==1?"s":""} and can reach all other cubes`,candidates:s}}return{selectedCube:[...e].sort()[0],reason:"alphabetical_fallback",explanation:"Selected alphabetically as fallback (no cube could reach all others)",candidates:s}}analyzeJoinPath(e,t,n){const i=this.getResolver(e).findPath(t,n),o=[t];if(i)for(const u of i)o.push(u.toCube);if(!i||i.length===0)return{targetCube:n,pathFound:!1,error:`No join path found from '${t}' to '${n}'. Ensure the target cube has a relationship defined (belongsTo, hasOne, hasMany, or belongsToMany).`,visitedCubes:o};const a=i.map(u=>{const c=Ae(u.joinDef.relationship,u.joinDef.sqlJoinType),l=u.joinDef.on.map(f=>({sourceColumn:f.source.name,targetColumn:f.target.name})),m={fromCube:u.fromCube,toCube:u.toCube,relationship:u.joinDef.relationship,joinType:c,joinColumns:l};if(u.joinDef.relationship==="belongsToMany"&&u.joinDef.through){const f=u.joinDef.through;m.junctionTable={tableName:f.table[Symbol.for("drizzle:Name")]||"junction_table",sourceColumns:f.sourceKey.map(p=>p.target.name),targetColumns:f.targetKey.map(p=>p.source.name)}}return m});return{targetCube:n,pathFound:!0,path:a,pathLength:a.length,visitedCubes:o}}analyzePreAggregations(e,t,n,s){const i=[];if(!s.measures||s.measures.length===0)return i;for(const o of n){const a=this.findHasManyJoinDef(t,o);if(!a)continue;const u=e.get(o);if(!u)continue;const c=s.measures.filter(w=>w.startsWith(o+".")),l=this.extractMeasuresFromFilters(s,u),m=[...new Set([...c,...l])];if(m.length===0)continue;const f=a.on.map(w=>({sourceColumn:w.source.name,targetColumn:w.target.name})),p=new Map([[o,u]]),{aggregateMeasures:h,postAggWindowMeasures:g,requiredBaseMeasures:y}=O.categorizeForPostAggregation(m,p),b=[...new Set([...h,...Array.from(y).filter(w=>w.startsWith(o+"."))])];if(b.length>0){const w=g.length>0;i.push({cubeName:o,cteAlias:`${o.toLowerCase()}_agg`,reason:w?`hasMany relationship from ${t.name} - requires pre-aggregation; includes base measures for post-aggregation window functions`:`hasMany relationship from ${t.name} - requires pre-aggregation to prevent row duplication (fan-out)`,reasonType:"hasMany",measures:b,joinKeys:f,cteType:"aggregate"})}}return i}generateWarnings(e,t){const n=[],s=this.checkFanOutNoDimensions(e,t);return s&&n.push(s),n}checkFanOutNoDimensions(e,t){if(!t||t.length===0||!e.measures||e.measures.length===0)return null;const n=new Set;for(const o of e.measures){const[a]=o.split(".");n.add(a)}if(n.size<2)return null;const s=e.dimensions&&e.dimensions.length>0,i=e.timeDimensions?.some(o=>o.granularity);return s||i?null:{code:"FAN_OUT_NO_DIMENSIONS",message:"Query combines measures from multiple cubes with hasMany relationships but has no dimensions. Results are aggregated at the join key level, which may produce unexpected totals.",severity:"warning",cubes:[...n].sort(),measures:e.measures,suggestion:"Add a dimension to see per-group breakdowns, or add a time dimension with granularity."}}}class nn{constructor(e){this.queryBuilder=e}buildPreAggregationCTE(e,t,n,s,i){const o=e.cube,a=o.sql(n),u=e.intermediateJoins&&e.intermediateJoins.length>0,c={};if(u&&e.intermediateJoins){const E=e.intermediateJoins[0].primaryJoinColumn;if(E){const T=E.name;c[T]=E}}else for(const C of e.joinKeys)if(C.targetColumnObj){c[C.targetColumn]=C.targetColumnObj;for(const[E,T]of Object.entries(o.dimensions||{}))T.sql===C.targetColumnObj&&E!==C.targetColumn&&(c[E]=r`${C.targetColumnObj}`.as(E))}if(e.downstreamJoinKeys)for(const C of e.downstreamJoinKeys)for(const E of C.joinKeys)E.sourceColumnObj&&(c[E.sourceColumn]=E.sourceColumnObj);const l=o.name,m=new Map([[l,o]]),f=this.queryBuilder.buildResolvedMeasures(e.measures,m,n);for(const C of e.measures){const[,E]=C.split("."),T=f.get(C);if(T){const D=T();c[E]=r`${D}`.as(E)}}if(t.dimensions)for(const C of t.dimensions){const[E,T]=C.split(".");if(E===l&&o.dimensions&&o.dimensions[T]){const D=o.dimensions[T],N=this.queryBuilder.buildMeasureExpression({sql:D.sql,type:"number"},n);c[T]=r`${N}`.as(T)}}if(t.timeDimensions)for(const C of t.timeDimensions){const[E,T]=C.dimension.split(".");if(E===l&&o.dimensions&&o.dimensions[T]){const D=o.dimensions[T],N=this.queryBuilder.buildTimeDimensionExpression(D.sql,C.granularity,n);c[T]=r`${N}`.as(T)}}if(Object.keys(c).length===0)return null;let p=n.db.select(c).from(a.from);if(u&&e.intermediateJoins)for(const C of e.intermediateJoins){const E=C.cube.sql(n),D=[P(C.cteJoinColumn,C.joinDef.on[0]?.target)];C.securityFilter&&D.push(C.securityFilter),p=p.leftJoin(E.from,_(...D))}const h=s?{...s,preAggregationCTEs:s.preAggregationCTEs?.filter(C=>C.cube.name!==o.name)}:void 0,g=this.queryBuilder.buildWhereConditions(o,t,n,h,i),y=[];if(t.timeDimensions)for(const C of t.timeDimensions){const[E,T]=C.dimension.split(".");if(E===l&&o.dimensions&&o.dimensions[T]&&C.dateRange){const D=o.dimensions[T],N=this.queryBuilder.buildMeasureExpression({sql:D.sql,type:"number"},n),A=this.queryBuilder.buildDateRangeCondition(N,C.dateRange);A&&y.push(A)}}if(t.filters){for(const C of t.filters)if(!("and"in C)&&!("or"in C)&&"member"in C&&"operator"in C){const E=C,[T,D]=E.member.split(".");if(T===l&&o.dimensions&&o.dimensions[D]){const N=o.dimensions[D];if(E.operator==="inDateRange"){const A=this.queryBuilder.buildMeasureExpression({sql:N.sql,type:"number"},n),v=this.queryBuilder.buildDateRangeCondition(A,E.values);v&&y.push(v)}}}}if(e.propagatingFilters&&e.propagatingFilters.length>0)for(const C of e.propagatingFilters){const E=this.buildPropagatingFilterSubquery(C,n);E&&y.push(E)}const b=[];if(a.where&&b.push(a.where),b.push(...g,...y),b.length>0){const C=b.length===1?b[0]:_(...b);p=p.where(C)}const w=[],$=new Set,S=C=>{const E=C?.name||(typeof C=="string"?C:null);E&&!$.has(E)?($.add(E),w.push(C)):E||w.push(C)};if(u&&e.intermediateJoins){const C=e.intermediateJoins[0];C.primaryJoinColumn&&S(C.primaryJoinColumn)}else for(const C of e.joinKeys)C.targetColumnObj&&S(C.targetColumnObj);if(e.downstreamJoinKeys)for(const C of e.downstreamJoinKeys)for(const E of C.joinKeys)E.sourceColumnObj&&S(E.sourceColumnObj);if(t.dimensions)for(const C of t.dimensions){const[E,T]=C.split(".");if(E===l&&o.dimensions&&o.dimensions[T]){const D=o.dimensions[T],N=R(D.sql,n);w.push(N)}}if(t.timeDimensions)for(const C of t.timeDimensions){const[E,T]=C.dimension.split(".");if(E===l&&o.dimensions&&o.dimensions[T]){const D=o.dimensions[T],N=this.queryBuilder.buildTimeDimensionExpression(D.sql,C.granularity,n);w.push(N)}}return w.length>0&&(p=p.groupBy(...w)),n.db.$with(e.cteAlias).as(p)}buildCTEJoinCondition(e,t,n){const s=n.preAggregationCTEs?.find(o=>o.cube.name===e.cube.name);if(!s)throw new Error(`CTE info not found for cube ${e.cube.name}`);const i=[];if(s.intermediateJoins&&s.intermediateJoins.length>0){const o=s.intermediateJoins[0],a=s.joinKeys[0]?.sourceColumnObj,u=r`${r.identifier(t)}.${r.identifier(o.primaryJoinColumn.name)}`;i.push(P(a,u))}else for(const o of s.joinKeys){const a=o.sourceColumnObj||r.identifier(o.sourceColumn),u=r`${r.identifier(t)}.${r.identifier(o.targetColumn)}`;i.push(P(a,u))}return i.length===1?i[0]:_(...i)}buildPropagatingFilterSubquery(e,t){const n=e.sourceCube,s=n.sql(t),i=[];if(s.where&&i.push(s.where),e.preBuiltFilterSQL)i.push(e.preBuiltFilterSQL);else{const u={filters:e.filters},c=new Map([[n.name,n]]),l=this.queryBuilder.buildWhereConditions(c,u,t);i.push(...l)}if(i.length===0)return null;const o=i.length===1?i[0]:_(...i),a=e.joinConditions;if(a.length===1){const{source:u,target:c}=a[0],l=t.db.select({pk:u}).from(s.from).where(o);return r`${c} IN ${l}`}else{const u=a.map(m=>P(m.source,m.target)),c=_(...u,o),l=t.db.select({one:r`1`}).from(s.from).where(c);return r`EXISTS ${l}`}}}function sn(d,e,t){const n=[];let s=ze(new Date(d),t);const i=ze(new Date(e),t),o=1e4;for(;s<=i&&n.length<o;)n.push(new Date(s)),s=rn(s,t);return n}function ze(d,e){const t=new Date(d);switch(e){case"second":t.setUTCMilliseconds(0);break;case"minute":t.setUTCSeconds(0,0);break;case"hour":t.setUTCMinutes(0,0,0);break;case"day":t.setUTCHours(0,0,0,0);break;case"week":{const n=t.getUTCDay(),s=n===0?6:n-1;t.setUTCDate(t.getUTCDate()-s),t.setUTCHours(0,0,0,0);break}case"month":t.setUTCDate(1),t.setUTCHours(0,0,0,0);break;case"quarter":{const n=Math.floor(t.getUTCMonth()/3)*3;t.setUTCMonth(n,1),t.setUTCHours(0,0,0,0);break}case"year":t.setUTCMonth(0,1),t.setUTCHours(0,0,0,0);break}return t}function rn(d,e){const t=new Date(d);switch(e){case"second":t.setUTCSeconds(t.getUTCSeconds()+1);break;case"minute":t.setUTCMinutes(t.getUTCMinutes()+1);break;case"hour":t.setUTCHours(t.getUTCHours()+1);break;case"day":t.setUTCDate(t.getUTCDate()+1);break;case"week":t.setUTCDate(t.getUTCDate()+7);break;case"month":t.setUTCMonth(t.getUTCMonth()+1);break;case"quarter":t.setUTCMonth(t.getUTCMonth()+3);break;case"year":t.setUTCFullYear(t.getUTCFullYear()+1);break}return t}function on(d){if(d instanceof Date)return d.toISOString();if(typeof d=="string"){const e=new Date(d);if(!isNaN(e.getTime()))return e.toISOString()}return String(d)}function an(d,e){return e.length===0?"__all__":e.map(t=>String(d[t]??"")).join("|||")}function un(d,e){const{timeDimensionKey:t,granularity:n,dateRange:s,fillValue:i,measures:o,dimensions:a}=e,u=sn(s[0],s[1],n);if(u.length===0)return d;const c=new Map;for(const m of d){const f=an(m,a),p=on(m[t]);c.has(f)||c.set(f,new Map),c.get(f).set(p,m)}c.size===0&&a.length===0&&c.set("__all__",new Map);const l=[];for(const[m,f]of c){const p=f.size>0?f.values().next().value:null;for(const h of u){const g=h.toISOString(),y=f.get(g);if(y)l.push(y);else{const b={[t]:g};if(p)for(const w of a)b[w]=p[w];for(const w of o)b[w]=i;l.push(b)}}}return l}function ln(d){if(!d)return null;if(Array.isArray(d)){if(d.length<2)return null;const t=new Date(d[0]),n=new Date(d[1]);return isNaN(t.getTime())||isNaN(n.getTime())?null:[t,n]}const e=new Date(d);return isNaN(e.getTime())?null:[e,e]}function Ve(d,e,t){if(!e.timeDimensions||e.timeDimensions.length===0)return d;const n=e.timeDimensions.filter(u=>{const c=u.fillMissingDates!==!1,l=u.granularity&&u.dateRange;return c&&l});if(n.length===0)return d;const s=e.fillMissingDatesValue===void 0?0:e.fillMissingDatesValue,i=new Set(e.timeDimensions.map(u=>u.dimension)),o=(e.dimensions||[]).filter(u=>!i.has(u));let a=d;for(const u of n){const c=ln(u.dateRange);if(!c)continue;const l={timeDimensionKey:u.dimension,granularity:u.granularity,dateRange:c,fillValue:s,measures:t,dimensions:o};a=un(a,l)}return a}class cn{dateTimeBuilder;constructor(e){this.dateTimeBuilder=new te(e)}hasComparison(e){return e.timeDimensions?.some(t=>t.compareDateRange&&t.compareDateRange.length>=2)??!1}getComparisonTimeDimension(e){return e.timeDimensions?.find(t=>t.compareDateRange&&t.compareDateRange.length>=2)}normalizePeriods(e){const t=[];for(let n=0;n<e.length;n++){const s=e[n];let i,o,a;if(typeof s=="string"){const u=this.dateTimeBuilder.parseRelativeDateRange(s);if(u)i=u.start,o=u.end,a=s;else{const c=new Date(s);if(!isNaN(c.getTime()))i=new Date(c),i.setUTCHours(0,0,0,0),o=new Date(c),o.setUTCHours(23,59,59,999),a=s;else continue}}else{if(i=new Date(s[0]),o=new Date(s[1]),isNaN(i.getTime())||isNaN(o.getTime()))continue;/^\d{4}-\d{2}-\d{2}$/.test(s[1])&&o.setUTCHours(23,59,59,999),a=`${s[0]} - ${s[1]}`}t.push({start:i,end:o,label:a,index:n})}return t}createPeriodQuery(e,t){return{...e,timeDimensions:e.timeDimensions?.map(n=>n.compareDateRange?{...n,dateRange:[t.start.toISOString(),t.end.toISOString()],compareDateRange:void 0}:n)}}calculatePeriodDayIndex(e,t,n){const s=typeof e=="string"?new Date(e):e,i=t.getTime(),o=s.getTime();switch(n){case"second":return Math.floor((o-i)/1e3);case"minute":return Math.floor((o-i)/(1e3*60));case"hour":return Math.floor((o-i)/(1e3*60*60));case"day":return Math.floor((o-i)/(1e3*60*60*24));case"week":return Math.floor((o-i)/(1e3*60*60*24*7));case"month":{const a=t.getUTCFullYear(),u=t.getUTCMonth(),c=s.getUTCFullYear(),l=s.getUTCMonth();return(c-a)*12+(l-u)}case"quarter":{const a=t.getUTCFullYear(),u=Math.floor(t.getUTCMonth()/3),c=s.getUTCFullYear(),l=Math.floor(s.getUTCMonth()/3);return(c-a)*4+(l-u)}case"year":return s.getUTCFullYear()-t.getUTCFullYear();default:return Math.floor((o-i)/(1e3*60*60*24))}}addPeriodMetadata(e,t,n,s){return e.map(i=>{const o=i[n];let a=0;if(o){const u=typeof o=="string"?new Date(o):o instanceof Date?o:null;u&&!isNaN(u.getTime())&&(a=this.calculatePeriodDayIndex(u,t.start,s))}return{...i,__period:t.label,__periodIndex:t.index,__periodDayIndex:a}})}mergeComparisonResults(e,t,n){const s=[];let i={measures:{},dimensions:{},segments:{},timeDimensions:{}};const o=e.map(u=>u.period);for(const{result:u,period:c}of e){const l=this.addPeriodMetadata(u.data,c,t.dimension,n);s.push(...l),i={measures:{...i.measures,...u.annotation.measures},dimensions:{...i.dimensions,...u.annotation.dimensions},segments:{...i.segments,...u.annotation.segments},timeDimensions:{...i.timeDimensions,...u.annotation.timeDimensions}}}const a={ranges:o.map(u=>[u.start.toISOString().split("T")[0],u.end.toISOString().split("T")[0]]),labels:o.map(u=>u.label),timeDimension:t.dimension,granularity:n};return{data:s,annotation:{...i,periods:a}}}sortComparisonResults(e,t){return[...e].sort((n,s)=>{const i=n.__periodIndex-s.__periodIndex;if(i!==0)return i;const o=n[t],a=s[t];return typeof o=="string"&&typeof a=="string"?new Date(o).getTime()-new Date(a).getTime():0})}}class dn{constructor(e){this.databaseAdapter=e,this.dateTimeBuilder=new te(e),this.filterBuilder=new he(e,this.dateTimeBuilder)}filterBuilder;dateTimeBuilder;hasFunnel(e){return e.funnel!==void 0&&e.funnel.steps.length>=2}validateConfig(e,t){const n=[];if(e.steps.length<2&&n.push("Funnel must have at least 2 steps"),typeof e.bindingKey=="string"){const[s,i]=e.bindingKey.split(".");if(!s||!i)n.push(`Invalid binding key format: ${e.bindingKey}. Expected 'CubeName.dimensionName'`);else{const o=t.get(s);o?o.dimensions?.[i]||n.push(`Binding key dimension not found: ${i} in cube ${s}`):n.push(`Binding key cube not found: ${s}`)}}else if(Array.isArray(e.bindingKey))for(const s of e.bindingKey){const i=t.get(s.cube);if(!i)n.push(`Binding key mapping cube not found: ${s.cube}`);else{const[,o]=s.dimension.split(".");i.dimensions?.[o]||n.push(`Binding key dimension not found: ${o} in cube ${s.cube}`)}}if(typeof e.timeDimension=="string"){const[s,i]=e.timeDimension.split(".");if(!s||!i)n.push(`Invalid time dimension format: ${e.timeDimension}. Expected 'CubeName.dimensionName'`);else{const o=t.get(s);o?o.dimensions?.[i]||n.push(`Time dimension not found: ${i} in cube ${s}`):n.push(`Time dimension cube not found: ${s}`)}}for(let s=0;s<e.steps.length;s++){const i=e.steps[s];if(i.name||n.push(`Step ${s} must have a name`),"cube"in i&&i.cube&&(t.get(i.cube)||n.push(`Step ${s} cube not found: ${i.cube}`)),i.filter){let o;"cube"in i&&i.cube?o=i.cube:typeof e.bindingKey=="string"&&([o]=e.bindingKey.split("."));const a=o?new oe(t):null,u=Array.isArray(i.filter)?i.filter:[i.filter];for(const c of u)if("member"in c){const[l,m]=c.member.split("."),f=t.get(l);if(!f)n.push(`Step ${s} filter cube not found: ${l}`);else if(f.dimensions?.[m]||(f.measures?.[m]?n.push(`Step ${s} filter '${l}.${m}' is a measure. Funnel step filters only support dimensions, not measures.`):n.push(`Step ${s} filter member not found: ${m} in cube ${l}`)),o&&l!==o&&a){const p=a.findPath(o,l);(!p||p.length===0)&&n.push(`Step ${s} filter '${l}.${m}' requires a join from '${o}' but no join path was found. Define a join relationship between these cubes.`)}}}i.timeToConvert&&s>0&&(/^P(?:\d+Y)?(?:\d+M)?(?:\d+D)?(?:T(?:\d+H)?(?:\d+M)?(?:\d+(?:\.\d+)?S)?)?$/.test(i.timeToConvert)||n.push(`Step ${s} timeToConvert must be ISO 8601 duration format: ${i.timeToConvert}`))}return{isValid:n.length===0,errors:n}}buildFunnelQuery(e,t,n){const s=this.resolveSteps(e,t,n),i=[];for(let c=0;c<s.length;c++){const l=c>0?i[c-1]:void 0;i.push(this.buildStepCTE(s[c],n,l))}const o=this.buildFunnelResultsCTE(i,s,e,n),a=this.buildAggregationCTE(o,i,s,e,n),u=[...i,o,a];return n.db.with(...u).select().from(a)}transformResult(e,t){if(!e||e.length===0)return[];const n=e[0],s=[],i=Number(n.step_0_count)||0;for(let o=0;o<t.steps.length;o++){const a=t.steps[o],u=Number(n[`step_${o}_count`])||0,c=o>0&&Number(n[`step_${o-1}_count`])||0,l={step:a.name,stepIndex:o,count:u,conversionRate:o===0?null:c>0?u/c:0,cumulativeConversionRate:i>0?u/i:0};t.includeTimeMetrics&&o>0&&(l.avgSecondsToConvert=n[`step_${o}_avg_seconds`]!==null?Number(n[`step_${o}_avg_seconds`]):null,l.minSecondsToConvert=n[`step_${o}_min_seconds`]!==null?Number(n[`step_${o}_min_seconds`]):null,l.maxSecondsToConvert=n[`step_${o}_max_seconds`]!==null?Number(n[`step_${o}_max_seconds`]):null,n[`step_${o}_median_seconds`]!==void 0&&(l.medianSecondsToConvert=n[`step_${o}_median_seconds`]!==null?Number(n[`step_${o}_median_seconds`]):null),n[`step_${o}_p90_seconds`]!==void 0&&(l.p90SecondsToConvert=n[`step_${o}_p90_seconds`]!==null?Number(n[`step_${o}_p90_seconds`]):null)),s.push(l)}return s}extractFilterCubeNames(e){const t=new Set;if(!e.filter)return t;const n=Array.isArray(e.filter)?e.filter:[e.filter],s=i=>{if("and"in i&&i.and)for(const o of i.and)s(o);else if("or"in i&&i.or)for(const o of i.or)s(o);else if("type"in i&&"filters"in i){const o=i;for(const a of o.filters||[])s(a)}else if("member"in i){const[o]=i.member.split(".");t.add(o)}};for(const i of n)s(i);return t}resolveSteps(e,t,n){const s=new oe(t);return e.steps.map((i,o)=>{const a=this.resolveCubeForStep(i,e,t),u=this.resolveBindingKey(e,a,n),c=this.resolveTimeDimension(e,a,n),l=this.buildStepFilters(i,a,t,n),m=this.extractFilterCubeNames(i),f=[];for(const p of m)if(p!==a.name){const h=t.get(p);if(h){const g=s.findPath(a.name,p);g&&g.length>0&&f.push({cube:h,joinPath:g})}}return{name:i.name,index:o,cube:a,bindingKeyExpr:u,timeExpr:c,filterConditions:l,timeToConvert:i.timeToConvert,joinedCubes:f}})}resolveCubeForStep(e,t,n){if("cube"in e&&e.cube){const s=n.get(e.cube);if(!s)throw new Error(`Cube not found for step: ${e.cube}`);return s}if(typeof t.bindingKey=="string"){const[s]=t.bindingKey.split("."),i=n.get(s);if(!i)throw new Error(`Cube not found for binding key: ${t.bindingKey}`);return i}throw new Error("Cannot resolve cube for step - multi-cube funnel requires cube specification in each step")}resolveBindingKey(e,t,n){if(typeof e.bindingKey=="string"){const[,a]=e.bindingKey.split("."),u=t.dimensions?.[a];if(!u)throw new Error(`Binding key dimension not found: ${e.bindingKey}`);return R(u.sql,n)}const s=e.bindingKey.find(a=>a.cube===t.name);if(!s)throw new Error(`No binding key mapping found for cube: ${t.name}`);const[,i]=s.dimension.split("."),o=t.dimensions?.[i];if(!o)throw new Error(`Binding key dimension not found: ${s.dimension}`);return R(o.sql,n)}resolveTimeDimension(e,t,n){if(typeof e.timeDimension=="string"){const[,a]=e.timeDimension.split("."),u=t.dimensions?.[a];if(!u)throw new Error(`Time dimension not found: ${e.timeDimension}`);return R(u.sql,n)}const s=e.timeDimension.find(a=>a.cube===t.name);if(!s)throw new Error(`No time dimension mapping found for cube: ${t.name}`);const[,i]=s.dimension.split("."),o=t.dimensions?.[i];if(!o)throw new Error(`Time dimension not found: ${s.dimension}`);return R(o.sql,n)}buildStepFilters(e,t,n,s){if(!e.filter)return[];const i=Array.isArray(e.filter)?e.filter:[e.filter],o=[];for(const a of i){const u=this.buildFilterCondition(a,t,n,s);u&&o.push(u)}return o}buildFilterCondition(e,t,n,s){const i="and"in e||"or"in e,o="type"in e&&"filters"in e&&(e.type==="and"||e.type==="or");if(i||o){const g=[];let y;if(o){const b=e;y=b.type==="and";for(const w of b.filters||[]){const $=this.buildFilterCondition(w,t,n,s);$&&g.push($)}}else{const b=e;y="and"in b&&!!b.and;const w=b.and||b.or||[];for(const $ of w){const S=this.buildFilterCondition($,t,n,s);S&&g.push(S)}}return g.length===0?null:g.length===1?g[0]:y?_(...g):r`(${r.join(g,r` OR `)})`}const a=e,[u,c]=a.member.split("."),l=a.dateRange!==void 0;if(a.operator!=="set"&&a.operator!=="notSet"&&!l&&(!a.values||a.values.length===0||a.values[0]===void 0||a.values[0]===""))return null;const f=n.get(u);if(!f)return null;if(u!==t.name){const y=new oe(n).findPath(t.name,u);if(!y||y.length===0)return console.warn(`Funnel filter: Cannot filter by '${u}.${c}' in step using '${t.name}'. No join path found. Filter will be skipped.`),null}const p=f.dimensions?.[c];if(!p)return null;const h=R(p.sql,s);return this.filterBuilder.buildFilterCondition(h,a.operator,a.values||[],p,a.dateRange)}buildStepCTE(e,t,n){return e.index===0?this.buildFirstStepCTE(e,t):this.buildSubsequentStepCTE(e,t,n)}buildFirstStepCTE(e,t){const n=`step_${e.index}`,s=e.cube.sql(t),i=[];s.where&&i.push(s.where),i.push(...e.filterConditions);let o=t.db.select({binding_key:r`${e.bindingKeyExpr}`.as("binding_key"),step_time:r`MIN(${e.timeExpr})`.as("step_time")}).from(s.from);if(o=this.addCrossJoinsToQuery(o,e,t,i),i.length>0){const a=i.length===1?i[0]:_(...i);o=o.where(a)}return o=o.groupBy(e.bindingKeyExpr),t.db.$with(n).as(o)}buildSubsequentStepCTE(e,t,n){const s=`step_${e.index}`,i=`step_${e.index-1}`,o=e.cube.sql(t),a=[];o.where&&a.push(o.where),a.push(...e.filterConditions);const u=r`${r.identifier(i)}.step_time`;let c=r`${e.timeExpr} > ${u}`;if(e.timeToConvert){const m=this.databaseAdapter.buildDateAddInterval(u,e.timeToConvert);c=r`${c} AND ${e.timeExpr} <= ${m}`}a.push(c);let l=t.db.select({binding_key:r`${e.bindingKeyExpr}`.as("binding_key"),step_time:r`MIN(${e.timeExpr})`.as("step_time")}).from(o.from).innerJoin(n,r`${e.bindingKeyExpr} = ${r.identifier(i)}.binding_key`);if(l=this.addCrossJoinsToQuery(l,e,t,a),a.length>0){const m=a.length===1?a[0]:_(...a);l=l.where(m)}return l=l.groupBy(e.bindingKeyExpr),t.db.$with(s).as(l)}addCrossJoinsToQuery(e,t,n,s){if(t.joinedCubes.length===0)return e;for(const i of t.joinedCubes)for(const o of i.joinPath){const a=o.joinDef,u=[];for(const f of a.on)f.as?u.push(f.as(f.source,f.target)):u.push(P(f.source,f.target));const c=u.length===1?u[0]:_(...u),m=i.cube.sql(n);e=e.leftJoin(m.from,c),m.where&&s.push(m.where)}return e}buildFunnelResultsCTE(e,t,n,s){const i={binding_key:r`s0.binding_key`,step_0_time:r`s0.step_time`};for(let l=1;l<t.length;l++)i[`step_${l}_time`]=r`s${r.raw(String(l))}.step_time`;let o=r`${r.identifier("step_0")} s0`;for(let l=1;l<t.length;l++)o=r`${o}
61
- LEFT JOIN ${r.identifier(`step_${l}`)} s${r.raw(String(l))} ON s0.binding_key = s${r.raw(String(l))}.binding_key`;const a=Object.entries(i).map(([l,m])=>r`${m} AS ${r.identifier(l)}`),u=r`SELECT ${r.join(a,r`, `)} FROM ${o}`,c={binding_key:r`binding_key`.as("binding_key"),step_0_time:r`step_0_time`.as("step_0_time")};for(let l=1;l<t.length;l++)c[`step_${l}_time`]=r`${r.identifier(`step_${l}_time`)}`.as(`step_${l}_time`);return s.db.$with("funnel_joined").as(s.db.select(c).from(r`(${u}) as _inner`))}buildAggregationCTE(e,t,n,s,i){const o={};o.step_0_count=r`COUNT(*)`.as("step_0_count");for(let u=1;u<n.length;u++)o[`step_${u}_count`]=r`COUNT(${r.identifier(`step_${u}_time`)})`.as(`step_${u}_count`);if(s.includeTimeMetrics)for(let u=1;u<n.length;u++){const c=r.identifier(`step_${u}_time`),l=r.identifier(`step_${u-1}_time`),m=this.databaseAdapter.buildTimeDifferenceSeconds(r`${c}`,r`${l}`),f=r`${c} IS NOT NULL`;o[`step_${u}_avg_seconds`]=this.databaseAdapter.buildConditionalAggregation("avg",m,f).as(`step_${u}_avg_seconds`),o[`step_${u}_min_seconds`]=this.databaseAdapter.buildConditionalAggregation("min",m,f).as(`step_${u}_min_seconds`),o[`step_${u}_max_seconds`]=this.databaseAdapter.buildConditionalAggregation("max",m,f).as(`step_${u}_max_seconds`);const p=this.databaseAdapter.getCapabilities(),h=this.databaseAdapter.buildPercentile(m,50);h&&p.supportsPercentileSubqueries&&(o[`step_${u}_median_seconds`]=r`(SELECT ${h} FROM ${r.identifier("funnel_joined")} WHERE ${c} IS NOT NULL)`.as(`step_${u}_median_seconds`));const g=this.databaseAdapter.buildPercentile(m,90);g&&p.supportsPercentileSubqueries&&(o[`step_${u}_p90_seconds`]=r`(SELECT ${g} FROM ${r.identifier("funnel_joined")} WHERE ${c} IS NOT NULL)`.as(`step_${u}_p90_seconds`))}const a=i.db.select(o).from(e);return i.db.$with("funnel_metrics").as(a)}}class mn{filterBuilder;dateTimeBuilder;databaseAdapter;constructor(e){this.databaseAdapter=e,this.dateTimeBuilder=new te(e),this.filterBuilder=new he(e,this.dateTimeBuilder)}hasFlow(e){return e.flow!==void 0&&e.flow.startingStep!==void 0&&e.flow.eventDimension!==void 0}validateConfig(e,t){const n=[],s=[],i=this.databaseAdapter.getEngineType(),o=this.databaseAdapter.supportsLateralJoins();if(i==="sqlite")return n.push("Flow queries are not supported on SQLite. Use PostgreSQL or MySQL for flow analysis."),{isValid:!1,errors:n,warnings:s};if(typeof e.bindingKey=="string"){const[a,u]=e.bindingKey.split(".");if(!a||!u)n.push(`Invalid binding key format: ${e.bindingKey}. Expected 'CubeName.dimensionName'`);else{const c=t.get(a);c?c.dimensions?.[u]||n.push(`Binding key dimension not found: ${u} in cube ${a}`):n.push(`Binding key cube not found: ${a}`)}}else if(Array.isArray(e.bindingKey))for(const a of e.bindingKey){const u=t.get(a.cube);if(!u)n.push(`Binding key mapping cube not found: ${a.cube}`);else{const[,c]=a.dimension.split(".");u.dimensions?.[c]||n.push(`Binding key dimension not found: ${c} in cube ${a.cube}`)}}if(typeof e.timeDimension=="string"){const[a,u]=e.timeDimension.split(".");if(!a||!u)n.push(`Invalid time dimension format: ${e.timeDimension}. Expected 'CubeName.dimensionName'`);else{const c=t.get(a);c?c.dimensions?.[u]||n.push(`Time dimension not found: ${u} in cube ${a}`):n.push(`Time dimension cube not found: ${a}`)}}if(e.eventDimension){const[a,u]=e.eventDimension.split(".");if(!a||!u)n.push(`Invalid event dimension format: ${e.eventDimension}. Expected 'CubeName.dimensionName'`);else{const c=t.get(a);c?c.dimensions?.[u]||n.push(`Event dimension not found: ${u} in cube ${a}`):n.push(`Event dimension cube not found: ${a}`)}}else n.push("Event dimension is required for flow analysis");return e.startingStep?(e.startingStep.filter||n.push("Starting step must have at least one filter"),e.startingStep.name||s.push("Starting step has no name - using default")):n.push("Starting step is required for flow analysis"),(e.stepsBefore<0||e.stepsBefore>5)&&n.push(`stepsBefore must be between 0 and 5, got: ${e.stepsBefore}`),(e.stepsAfter<0||e.stepsAfter>5)&&n.push(`stepsAfter must be between 0 and 5, got: ${e.stepsAfter}`),(e.stepsBefore>=4||e.stepsAfter>=4)&&s.push("High step depth (4-5) may impact query performance on large datasets"),e.joinStrategy&&!["auto","lateral","window"].includes(e.joinStrategy)?n.push(`Invalid joinStrategy: ${e.joinStrategy}`):e.joinStrategy==="lateral"&&!o&&n.push("Lateral joins are not supported on this database"),{isValid:n.length===0,errors:n,warnings:s}}buildFlowQuery(e,t,n){if(this.databaseAdapter.getEngineType()==="sqlite")throw new Error("Flow queries are not supported on SQLite. Use PostgreSQL or MySQL for flow analysis.");const i=this.databaseAdapter.supportsLateralJoins(),o=e.joinStrategy??"auto",a=o==="lateral"||o==="auto"&&i;if(o==="lateral"&&!i)throw new Error("Lateral joins are not supported on this database");const u={...e,stepsBefore:e.outputMode==="sunburst"?0:e.stepsBefore},c=this.resolveFlowConfig(u,t,n),l=[],m=this.buildStartingEntitiesCTE(u,c,n);l.push(m);const f=a?this.buildBeforeCTEsLateral(u,c,n):this.buildBeforeCTEsWindow(u,c,n);l.push(...f);const p=a?this.buildAfterCTEsLateral(u,c,n):this.buildAfterCTEsWindow(u,c,n);l.push(...p);const h=this.buildNodesAggregationCTE(u,n);l.push(h);const g=this.buildLinksAggregationCTE(u,n);l.push(g);const y=this.buildFinalResultCTE(n);return l.push(y),n.db.with(...l).select().from(y)}transformResult(e){if(!e||e.length===0)return{nodes:[],links:[]};const t=[],n=[];for(const s of e){const i=s.record_type;i==="node"?t.push({id:String(s.id),name:String(s.name),layer:Number(s.layer),value:Number(s.value)}):i==="link"&&n.push({source:String(s.source_id),target:String(s.target_id),value:Number(s.value)})}return t.sort((s,i)=>s.layer-i.layer),{nodes:t,links:n}}resolveFlowConfig(e,t,n){const s=this.resolveCube(e,t),i=s.sql(n);return{cube:s,cubeBase:i,bindingKeyExpr:this.resolveBindingKey(e,s,n),timeExpr:this.resolveTimeDimension(e,s,n),eventExpr:this.resolveEventDimension(e,s,n),startingStepFilters:this.buildStartingStepFilters(e,s,n)}}resolveCube(e,t){let n;if(typeof e.bindingKey=="string")[n]=e.bindingKey.split(".");else if(Array.isArray(e.bindingKey)&&e.bindingKey.length>0)n=e.bindingKey[0].cube;else throw new Error("Cannot resolve cube for flow query");const s=t.get(n);if(!s)throw new Error(`Cube not found: ${n}`);return s}resolveBindingKey(e,t,n){if(typeof e.bindingKey=="string"){const[,a]=e.bindingKey.split("."),u=t.dimensions?.[a];if(!u)throw new Error(`Binding key dimension not found: ${e.bindingKey}`);return R(u.sql,n)}const s=e.bindingKey.find(a=>a.cube===t.name);if(!s)throw new Error(`No binding key mapping found for cube: ${t.name}`);const[,i]=s.dimension.split("."),o=t.dimensions?.[i];if(!o)throw new Error(`Binding key dimension not found: ${s.dimension}`);return R(o.sql,n)}resolveTimeDimension(e,t,n){if(typeof e.timeDimension=="string"){const[,a]=e.timeDimension.split("."),u=t.dimensions?.[a];if(!u)throw new Error(`Time dimension not found: ${e.timeDimension}`);return R(u.sql,n)}const s=e.timeDimension.find(a=>a.cube===t.name);if(!s)throw new Error(`No time dimension mapping found for cube: ${t.name}`);const[,i]=s.dimension.split("."),o=t.dimensions?.[i];if(!o)throw new Error(`Time dimension not found: ${s.dimension}`);return R(o.sql,n)}resolveEventDimension(e,t,n){const[,s]=e.eventDimension.split("."),i=t.dimensions?.[s];if(!i)throw new Error(`Event dimension not found: ${e.eventDimension}`);return R(i.sql,n)}buildStartingStepFilters(e,t,n){if(!e.startingStep.filter)return[];const s=Array.isArray(e.startingStep.filter)?e.startingStep.filter:[e.startingStep.filter],i=[];for(const o of s){const a=this.buildFilterCondition(o,t,n);a&&i.push(a)}return i}buildFilterCondition(e,t,n){if("and"in e||"or"in e){const u=e,c=[],l=u.and||u.or||[];for(const m of l){const f=this.buildFilterCondition(m,t,n);f&&c.push(f)}return c.length===0?null:c.length===1?c[0]:"and"in e?_(...c):r`(${r.join(c,r` OR `)})`}if("type"in e&&"filters"in e){const u=e,c=[];for(const l of u.filters||[]){const m=this.buildFilterCondition(l,t,n);m&&c.push(m)}return c.length===0?null:c.length===1?c[0]:u.type==="and"?_(...c):r`(${r.join(c,r` OR `)})`}const s=e,[,i]=s.member.split("."),o=t.dimensions?.[i];if(!o)return null;const a=R(o.sql,n);return this.filterBuilder.buildFilterCondition(a,s.operator,s.values||[],o,s.dateRange)}buildStartingEntitiesCTE(e,t,n){const{cubeBase:s,bindingKeyExpr:i,timeExpr:o,eventExpr:a,startingStepFilters:u}=t,c=[];s.where&&c.push(s.where),c.push(...u);let l=n.db.select({binding_key:r`${i}`.as("binding_key"),start_time:r`MIN(${o})`.as("start_time"),event_type:r`${a}`.as("event_type"),event_path:r`${a}`.as("event_path")}).from(s.from);if(c.length>0){const m=c.length===1?c[0]:_(...c);l=l.where(m)}return l=l.groupBy(i,a),e.entityLimit&&(l=l.limit(e.entityLimit)),n.db.$with("starting_entities").as(l)}buildBeforeCTEsLateral(e,t,n){const{cubeBase:s,bindingKeyExpr:i,timeExpr:o,eventExpr:a}=t,u=[],c=e.outputMode==="sunburst";for(let l=1;l<=e.stepsBefore;l++){const m=l===1?"starting_entities":`before_step_${l-1}`,f=l===1?"start_time":"step_time",p=`before_step_${l}`,h=[];s.where&&h.push(s.where),h.push(r`${i} = ${r.identifier(m)}.binding_key`,r`${o} < ${r.identifier(m)}.${r.identifier(f)}`);const g=h.length===1?h[0]:_(...h),y=c?r`${a} || ${"→"} || ${r.identifier(m)}.event_path`:r`${a}`,b=n.db.select({binding_key:r`${i}`.as("binding_key"),step_time:r`${o}`.as("step_time"),event_type:r`${a}`.as("event_type"),event_path:y.as("event_path")}).from(s.from).where(g).orderBy(r`${o} DESC`).limit(1),w=n.db.$with(p).as(n.db.select({binding_key:r`e.binding_key`.as("binding_key"),step_time:r`e.step_time`.as("step_time"),event_type:r`e.event_type`.as("event_type"),event_path:r`e.event_path`.as("event_path")}).from(r`${r.identifier(m)}`).crossJoinLateral(b.as("e")));u.push(w)}return u}buildAfterCTEsLateral(e,t,n){const{cubeBase:s,bindingKeyExpr:i,timeExpr:o,eventExpr:a}=t,u=[],c=e.outputMode==="sunburst";for(let l=1;l<=e.stepsAfter;l++){const m=l===1?"starting_entities":`after_step_${l-1}`,f=l===1?"start_time":"step_time",p=`after_step_${l}`,h=[];s.where&&h.push(s.where),h.push(r`${i} = ${r.identifier(m)}.binding_key`,r`${o} > ${r.identifier(m)}.${r.identifier(f)}`);const g=h.length===1?h[0]:_(...h),y=c?r`${r.identifier(m)}.event_path || ${"→"} || ${a}`:r`${a}`,b=n.db.select({binding_key:r`${i}`.as("binding_key"),step_time:r`${o}`.as("step_time"),event_type:r`${a}`.as("event_type"),event_path:y.as("event_path")}).from(s.from).where(g).orderBy(r`${o} ASC`).limit(1),w=n.db.$with(p).as(n.db.select({binding_key:r`e.binding_key`.as("binding_key"),step_time:r`e.step_time`.as("step_time"),event_type:r`e.event_type`.as("event_type"),event_path:r`e.event_path`.as("event_path")}).from(r`${r.identifier(m)}`).crossJoinLateral(b.as("e")));u.push(w)}return u}buildBeforeCTEsWindow(e,t,n){const{cubeBase:s,bindingKeyExpr:i,timeExpr:o,eventExpr:a}=t,u=[],c=e.outputMode==="sunburst";for(let l=1;l<=e.stepsBefore;l++){const m=l===1?"starting_entities":`before_step_${l-1}`,f=l===1?"start_time":"step_time",p=`before_step_${l}`,h=[];s.where&&h.push(s.where),h.push(r`${o} < ${r.identifier(m)}.${r.identifier(f)}`);const g=h.length===1?h[0]:_(...h),y=c?r`${a} || ${"→"} || ${r.identifier(m)}.event_path`:r`${a}`,b=n.db.select({binding_key:r`${i}`.as("binding_key"),step_time:r`${o}`.as("step_time"),event_type:r`${a}`.as("event_type"),event_path:y.as("event_path"),rn:r`ROW_NUMBER() OVER (PARTITION BY ${i} ORDER BY ${o} DESC)`.as("rn")}).from(s.from).innerJoin(r`${r.identifier(m)}`,r`${i} = ${r.identifier(m)}.binding_key`).where(g),w=n.db.select({binding_key:r`binding_key`.as("binding_key"),step_time:r`step_time`.as("step_time"),event_type:r`event_type`.as("event_type"),event_path:r`event_path`.as("event_path")}).from(b.as("ranked")).where(r`rn = 1`);u.push(n.db.$with(p).as(w))}return u}buildAfterCTEsWindow(e,t,n){const{cubeBase:s,bindingKeyExpr:i,timeExpr:o,eventExpr:a}=t,u=[],c=e.outputMode==="sunburst";for(let l=1;l<=e.stepsAfter;l++){const m=l===1?"starting_entities":`after_step_${l-1}`,f=l===1?"start_time":"step_time",p=`after_step_${l}`,h=[];s.where&&h.push(s.where),h.push(r`${o} > ${r.identifier(m)}.${r.identifier(f)}`);const g=h.length===1?h[0]:_(...h),y=c?r`${r.identifier(m)}.event_path || ${"→"} || ${a}`:r`${a}`,b=n.db.select({binding_key:r`${i}`.as("binding_key"),step_time:r`${o}`.as("step_time"),event_type:r`${a}`.as("event_type"),event_path:y.as("event_path"),rn:r`ROW_NUMBER() OVER (PARTITION BY ${i} ORDER BY ${o} ASC)`.as("rn")}).from(s.from).innerJoin(r`${r.identifier(m)}`,r`${i} = ${r.identifier(m)}.binding_key`).where(g),w=n.db.select({binding_key:r`binding_key`.as("binding_key"),step_time:r`step_time`.as("step_time"),event_type:r`event_type`.as("event_type"),event_path:r`event_path`.as("event_path")}).from(b.as("ranked")).where(r`rn = 1`);u.push(n.db.$with(p).as(w))}return u}buildNodesAggregationCTE(e,t){const n=[],s=e.outputMode==="sunburst";for(let a=e.stepsBefore;a>=1;a--){const u=-a,c=`before_step_${a}`;s?n.push(r`
60
+ `);return Array.isArray(n)?n.map(s=>({table_name:s.table_name,index_name:s.index_name,columns:typeof s.columns=="string"?s.columns.split(","):[],is_unique:!!s.is_unique,is_primary:!!s.is_primary})):[]}catch(t){return console.warn("Failed to get table indexes:",t),[]}}}function Kt(d,e){return new Wt(d,e,"duckdb")}function We(d,e,t){if(t)switch(t){case"postgres":return Pe(d,e);case"mysql":return Lt(d,e);case"sqlite":return Qe(d,e);case"singlestore":return xt(d,e);case"duckdb":return Kt(d,e)}if(d.all&&d.run)return Qe(d,e);if(d.execute)return Pe(d,e);throw new Error("Unable to determine database engine type. Please specify engineType parameter.")}function q(d){return typeof d=="function"?d():d}function Ae(d,e){if(e)return e;switch(d){case"belongsTo":return"inner";case"hasOne":return"left";case"hasMany":return"left";case"belongsToMany":return"left";default:return"left"}}function _e(d){return d&&typeof d=="object"?o`${o`${d}`}`:d}function v(d,e){const t=typeof d=="function"?d(e):d;return _e(t)}function qt(d,e){if(d.relationship!=="belongsToMany"||!d.through)throw new Error("expandBelongsToManyJoin can only be called on belongsToMany relationships with through configuration");const{table:t,sourceKey:n,targetKey:s,securitySql:i}=d.through,r=[];for(const l of n){const m=l.as||Q;r.push(m(l.source,l.target))}const a=[];for(const l of s){const m=l.as||Q;a.push(m(l.source,l.target))}let u;if(i){const l=i(e);u=Array.isArray(l)?l:[l]}const c=Ae("belongsToMany",d.sqlJoinType);return{junctionJoins:[{joinType:c,table:t,condition:A(...r)},{joinType:c,table:t,condition:A(...a)}],junctionSecurityConditions:u}}function de(d){if("and"in d)return`and:[${d.and.map(de).sort().join(",")}]`;if("or"in d)return`or:[${d.or.map(de).sort().join(",")}]`;const e=d,t=JSON.stringify(Array.isArray(e.values)?[...e.values].sort():e.values),n=e.dateRange?`:dr:${JSON.stringify(e.dateRange)}`:"";return`${e.member}:${e.operator}:${t}${n}`}function it(d,e){return`timeDim:${d}:${JSON.stringify(e)}`}class Ke{cache=new Map;stats={hits:0,misses:0};getOrBuild(e,t){const n=this.cache.get(e);if(n!==void 0)return this.stats.hits++,n;const s=t();return s&&this.cache.set(e,s),this.stats.misses++,s}has(e){return this.cache.has(e)}get(e){const t=this.cache.get(e);return t!==void 0&&this.stats.hits++,t}preload(e){for(const{key:t,sql:n}of e)this.cache.has(t)||this.cache.set(t,n)}set(e,t){this.cache.set(e,t)}getStats(){return{...this.stats,cacheSize:this.cache.size}}clear(){this.cache.clear(),this.stats={hits:0,misses:0}}}function ve(d){const e=[];for(const t of d)"and"in t&&t.and?e.push(...ve(t.and)):"or"in t&&t.or?e.push(...ve(t.or)):"member"in t&&e.push(t);return e}function zt(d,e,t={}){const n=t.keyPrefix??"drizzle-cube:",s=Vt(d),i=qe(JSON.stringify(s));let r=`${n}query:${i}`;if(t.includeSecurityContext!==!1){const a=t.securityContextSerializer?t.securityContextSerializer(e):JSON.stringify(me(e)),u=qe(a);r+=`:ctx:${u}`}return r}function Vt(d){return{measures:d.measures?[...d.measures].sort():void 0,dimensions:d.dimensions?[...d.dimensions].sort():void 0,filters:d.filters?W(d.filters):void 0,timeDimensions:d.timeDimensions?Yt(d.timeDimensions):void 0,limit:d.limit,offset:d.offset,order:d.order?me(d.order):void 0,fillMissingDatesValue:d.fillMissingDatesValue,funnel:d.funnel?Jt(d.funnel):void 0,flow:d.flow?Gt(d.flow):void 0,retention:d.retention?Ht(d.retention):void 0}}function Jt(d){return{bindingKey:d.bindingKey,timeDimension:d.timeDimension,steps:d.steps.map(e=>{const t={name:e.name,filter:e.filter?Array.isArray(e.filter)?W(e.filter):W([e.filter])[0]:void 0,timeToConvert:e.timeToConvert};return"cube"in e&&e.cube&&(t.cube=e.cube),t}),includeTimeMetrics:d.includeTimeMetrics,globalTimeWindow:d.globalTimeWindow}}function Gt(d){return{bindingKey:d.bindingKey,timeDimension:d.timeDimension,eventDimension:d.eventDimension,startingStep:{name:d.startingStep.name,filter:d.startingStep.filter?Array.isArray(d.startingStep.filter)?W(d.startingStep.filter):W([d.startingStep.filter])[0]:void 0},stepsBefore:d.stepsBefore,stepsAfter:d.stepsAfter,entityLimit:d.entityLimit,outputMode:d.outputMode,joinStrategy:d.joinStrategy}}function Ht(d){return{timeDimension:d.timeDimension,bindingKey:d.bindingKey,dateRange:d.dateRange,granularity:d.granularity,periods:d.periods,retentionType:d.retentionType,cohortFilters:d.cohortFilters?Array.isArray(d.cohortFilters)?W(d.cohortFilters):W([d.cohortFilters])[0]:void 0,activityFilters:d.activityFilters?Array.isArray(d.activityFilters)?W(d.activityFilters):W([d.activityFilters])[0]:void 0,breakdownDimensions:d.breakdownDimensions}}function W(d){return[...d].map(e=>{if("and"in e&&e.and)return{and:W(e.and)};if("or"in e&&e.or)return{or:W(e.or)};const t=e;return{...t,values:t.values?[...t.values].sort():t.values}}).sort((e,t)=>JSON.stringify(e).localeCompare(JSON.stringify(t)))}function Yt(d){return[...d].map(e=>({dimension:e.dimension,granularity:e.granularity,dateRange:e.dateRange,fillMissingDates:e.fillMissingDates,compareDateRange:e.compareDateRange?[...e.compareDateRange].sort((t,n)=>{const s=Array.isArray(t)?t.join("-"):t,i=Array.isArray(n)?n.join("-"):n;return s.localeCompare(i)}):void 0})).sort((e,t)=>e.dimension.localeCompare(t.dimension))}function me(d){return d===null||typeof d!="object"?d:Array.isArray(d)?d.map(me):Object.keys(d).sort().reduce((e,t)=>(e[t]=me(d[t]),e),{})}function qe(d){let e=2166136261;for(let t=0;t<d.length;t++)e^=d.charCodeAt(t),e=e*16777619>>>0;return e.toString(16).padStart(8,"0")}class ne{constructor(e){this.databaseAdapter=e}buildTimeDimensionExpression(e,t,n){const s=v(e,n);return t?this.databaseAdapter.buildTimeDimension(t,s):s instanceof F?s:o`${s}`}buildDateRangeCondition(e,t){if(!t)return null;if(Array.isArray(t)&&t.length>=2){const n=this.normalizeDate(t[0]);let s=this.normalizeDate(t[1]);if(!n||!s)return null;if(typeof t[1]=="string"&&/^\d{4}-\d{2}-\d{2}$/.test(t[1].trim())){const i=typeof s=="number"?new Date(s*(this.databaseAdapter.getEngineType()==="sqlite"?1e3:1)):new Date(s),r=new Date(i);r.setUTCHours(23,59,59,999),this.databaseAdapter.isTimestampInteger()?s=this.databaseAdapter.getEngineType()==="sqlite"?Math.floor(r.getTime()/1e3):r.getTime():s=r.toISOString()}return A(X(e,n),Z(e,s))}if(typeof t=="string"){const n=this.parseRelativeDateRange(t);if(n){let l,m;return this.databaseAdapter.isTimestampInteger()?this.databaseAdapter.getEngineType()==="sqlite"?(l=Math.floor(n.start.getTime()/1e3),m=Math.floor(n.end.getTime()/1e3)):(l=n.start.getTime(),m=n.end.getTime()):(l=n.start.toISOString(),m=n.end.toISOString()),A(X(e,l),Z(e,m))}const s=this.normalizeDate(t);if(!s)return null;const i=typeof s=="number"?new Date(s*(this.databaseAdapter.getEngineType()==="sqlite"?1e3:1)):new Date(s),r=new Date(i);r.setUTCHours(0,0,0,0);const a=new Date(i);a.setUTCHours(23,59,59,999);let u,c;return this.databaseAdapter.isTimestampInteger()?this.databaseAdapter.getEngineType()==="sqlite"?(u=Math.floor(r.getTime()/1e3),c=Math.floor(a.getTime()/1e3)):(u=r.getTime(),c=a.getTime()):(u=r.toISOString(),c=a.toISOString()),A(X(e,u),Z(e,c))}return null}parseRelativeDateRange(e){const t=new Date,n=e.toLowerCase().trim(),s=t.getUTCFullYear(),i=t.getUTCMonth(),r=t.getUTCDate(),a=t.getUTCDay();if(n==="today"){const p=new Date(t);p.setUTCHours(0,0,0,0);const f=new Date(t);return f.setUTCHours(23,59,59,999),{start:p,end:f}}if(n==="yesterday"){const p=new Date(t);p.setUTCDate(r-1),p.setUTCHours(0,0,0,0);const f=new Date(t);return f.setUTCDate(r-1),f.setUTCHours(23,59,59,999),{start:p,end:f}}if(n==="this week"){const p=a===0?-6:1-a,f=new Date(t);f.setUTCDate(r+p),f.setUTCHours(0,0,0,0);const h=new Date(f);return h.setUTCDate(f.getUTCDate()+6),h.setUTCHours(23,59,59,999),{start:f,end:h}}if(n==="this month"){const p=new Date(Date.UTC(s,i,1,0,0,0,0)),f=new Date(Date.UTC(s,i+1,0,23,59,59,999));return{start:p,end:f}}if(n==="this quarter"){const p=Math.floor(i/3),f=new Date(Date.UTC(s,p*3,1,0,0,0,0)),h=new Date(Date.UTC(s,p*3+3,0,23,59,59,999));return{start:f,end:h}}if(n==="this year"){const p=new Date(Date.UTC(s,0,1,0,0,0,0)),f=new Date(Date.UTC(s,11,31,23,59,59,999));return{start:p,end:f}}const u=n.match(/^last\s+(\d+)\s+days?$/);if(u){const p=parseInt(u[1],10),f=new Date(t);f.setUTCDate(r-p+1),f.setUTCHours(0,0,0,0);const h=new Date(t);return h.setUTCHours(23,59,59,999),{start:f,end:h}}const c=n.match(/^last\s+(\d+)\s+weeks?$/);if(c){const f=parseInt(c[1],10)*7,h=new Date(t);h.setUTCDate(r-f+1),h.setUTCHours(0,0,0,0);const g=new Date(t);return g.setUTCHours(23,59,59,999),{start:h,end:g}}if(n==="last week"){const p=a===0?-13:-6-a,f=new Date(t);f.setUTCDate(r+p),f.setUTCHours(0,0,0,0);const h=new Date(f);return h.setUTCDate(f.getUTCDate()+6),h.setUTCHours(23,59,59,999),{start:f,end:h}}if(n==="last month"){const p=new Date(Date.UTC(s,i-1,1,0,0,0,0)),f=new Date(Date.UTC(s,i,0,23,59,59,999));return{start:p,end:f}}if(n==="last quarter"){const p=Math.floor(i/3),f=p===0?3:p-1,h=p===0?s-1:s,g=new Date(Date.UTC(h,f*3,1,0,0,0,0)),y=new Date(Date.UTC(h,f*3+3,0,23,59,59,999));return{start:g,end:y}}if(n==="last year"){const p=new Date(Date.UTC(s-1,0,1,0,0,0,0)),f=new Date(Date.UTC(s-1,11,31,23,59,59,999));return{start:p,end:f}}if(n==="last 12 months"){const p=new Date(Date.UTC(s,i-11,1,0,0,0,0)),f=new Date(t);return f.setUTCHours(23,59,59,999),{start:p,end:f}}const l=n.match(/^last\s+(\d+)\s+months?$/);if(l){const p=parseInt(l[1],10),f=new Date(Date.UTC(s,i-p+1,1,0,0,0,0)),h=new Date(t);return h.setUTCHours(23,59,59,999),{start:f,end:h}}const m=n.match(/^last\s+(\d+)\s+years?$/);if(m){const p=parseInt(m[1],10),f=new Date(Date.UTC(s-p,0,1,0,0,0,0)),h=new Date(t);return h.setUTCHours(23,59,59,999),{start:f,end:h}}return null}normalizeDate(e){if(!e)return null;if(e instanceof Date)return isNaN(e.getTime())?null:this.databaseAdapter.isTimestampInteger()?this.databaseAdapter.getEngineType()==="sqlite"?Math.floor(e.getTime()/1e3):e.getTime():e.toISOString();if(typeof e=="number"){const n=e<1e10?e*1e3:e,s=new Date(n);return isNaN(s.getTime())?null:this.databaseAdapter.isTimestampInteger()?this.databaseAdapter.getEngineType()==="sqlite"?Math.floor(n/1e3):n:s.toISOString()}if(typeof e=="string"){if(/^\d{4}-\d{2}-\d{2}$/.test(e.trim())){const s=new Date(e+"T00:00:00Z");return isNaN(s.getTime())?null:this.databaseAdapter.isTimestampInteger()?this.databaseAdapter.getEngineType()==="sqlite"?Math.floor(s.getTime()/1e3):s.getTime():s.toISOString()}const n=new Date(e);return isNaN(n.getTime())?null:this.databaseAdapter.isTimestampInteger()?this.databaseAdapter.getEngineType()==="sqlite"?Math.floor(n.getTime()/1e3):n.getTime():n.toISOString()}const t=new Date(e);return isNaN(t.getTime())?null:this.databaseAdapter.isTimestampInteger()?this.databaseAdapter.getEngineType()==="sqlite"?Math.floor(t.getTime()/1e3):t.getTime():t.toISOString()}}class he{constructor(e,t){this.databaseAdapter=e,this.dateTimeBuilder=t}buildFilterCondition(e,t,n,s,i){if(i!==void 0){if(t!=="inDateRange")throw new Error(`dateRange can only be used with 'inDateRange' operator, but got '${t}'. Use explicit date values in the 'values' array for other date operators.`);if(s&&s.type!=="time")throw new Error(`dateRange can only be used on time dimensions, but field '${s.name||"unknown"}' has type '${s.type}'`);return this.dateTimeBuilder.buildDateRangeCondition(e,i)}if(!n||n.length===0)return t==="equals"?this.databaseAdapter.buildBooleanLiteral(!1):null;const r=n.filter(u=>!(u==null||u===""||typeof u=="string"&&u.includes("\0"))).map(this.databaseAdapter.convertFilterValue);if(r.length===0&&!["set","notSet"].includes(t))return t==="equals"?this.databaseAdapter.buildBooleanLiteral(!1):null;const a=r[0];switch(t){case"equals":if(r.length>1){if(s?.type==="time"){const u=r.map(c=>this.dateTimeBuilder.normalizeDate(c)||c);return Ee(e,u)}return Ee(e,r)}else if(r.length===1){const u=s?.type==="time"&&this.dateTimeBuilder.normalizeDate(a)||a;return Q(e,u)}return this.databaseAdapter.buildBooleanLiteral(!1);case"notEquals":return r.length>1?Ue(e,r):r.length===1?je(e,a):null;case"contains":return this.databaseAdapter.buildStringCondition(e,"contains",a);case"notContains":return this.databaseAdapter.buildStringCondition(e,"notContains",a);case"startsWith":return this.databaseAdapter.buildStringCondition(e,"startsWith",a);case"endsWith":return this.databaseAdapter.buildStringCondition(e,"endsWith",a);case"gt":return we(e,a);case"gte":return X(e,a);case"lt":return $e(e,a);case"lte":return Z(e,a);case"set":return xe(e);case"notSet":return ke(e);case"inDateRange":if(r.length>=2){const u=this.dateTimeBuilder.normalizeDate(r[0]);let c=this.dateTimeBuilder.normalizeDate(r[1]);if(u&&c){const l=n[1];if(typeof l=="string"&&/^\d{4}-\d{2}-\d{2}$/.test(l.trim())){const m=typeof c=="number"?new Date(c*(this.databaseAdapter.getEngineType()==="sqlite"?1e3:1)):new Date(c),p=new Date(m);p.setUTCHours(23,59,59,999),this.databaseAdapter.isTimestampInteger()?c=this.databaseAdapter.getEngineType()==="sqlite"?Math.floor(p.getTime()/1e3):p.getTime():c=p.toISOString()}return A(X(e,u),Z(e,c))}}return null;case"beforeDate":{const u=this.dateTimeBuilder.normalizeDate(a);return u?$e(e,u):null}case"afterDate":{const u=this.dateTimeBuilder.normalizeDate(a);return u?we(e,u):null}case"between":return r.length>=2?A(X(e,r[0]),Z(e,r[1])):null;case"notBetween":return r.length>=2?ie($e(e,r[0]),we(e,r[1])):null;case"in":return r.length>0?Ee(e,r):null;case"notIn":return r.length>0?Ue(e,r):null;case"like":return this.databaseAdapter.buildStringCondition(e,"like",a);case"notLike":return this.databaseAdapter.buildStringCondition(e,"notLike",a);case"ilike":return this.databaseAdapter.buildStringCondition(e,"ilike",a);case"regex":return this.databaseAdapter.buildStringCondition(e,"regex",a);case"notRegex":return this.databaseAdapter.buildStringCondition(e,"notRegex",a);case"isEmpty":return ie(ke(e),Q(e,""));case"isNotEmpty":return A(xe(e),je(e,""));case"arrayContains":return this.databaseAdapter.getEngineType()==="postgres"?Ct(e,r):null;case"arrayOverlaps":return this.databaseAdapter.getEngineType()==="postgres"?$t(e,r):null;case"arrayContained":return this.databaseAdapter.getEngineType()==="postgres"?wt(e,r):null;default:return null}}buildLogicalFilter(e,t,n){if("and"in e&&e.and){const s=e.and.map(i=>this.buildSingleFilter(i,t,n)).filter(i=>i!==null);return s.length>0?s.length===1?s[0]:A(...s):null}if("or"in e&&e.or){const s=e.or.map(i=>this.buildSingleFilter(i,t,n)).filter(i=>i!==null);return s.length>0?s.length===1?s[0]:ie(...s):null}return null}buildSingleFilter(e,t,n){if("and"in e||"or"in e)return this.buildLogicalFilter(e,t,n);const s=e,[i,r]=s.member.split("."),a=t.get(i);if(!a)return null;const u=a.dimensions?.[r];if(!u)return null;const c=v(u.sql,n);return this.buildFilterCondition(c,s.operator,s.values,u,s.dateRange)}}class H{dependencyGraph;cubes;constructor(e){this.cubes=e instanceof Map?e:new Map([[e.name,e]]),this.dependencyGraph=new Map}extractDependencies(e){const t=/\{([^}]+)\}/g,n=e.matchAll(t),s=[];for(const i of n){const r=i[1].trim();if(r.includes(".")){const[a,u]=r.split(".");s.push({measureName:r,cubeName:a.trim(),fieldName:u.trim()})}else s.push({measureName:r,cubeName:null,fieldName:r})}return s}buildGraph(e){for(const[t,n]of Object.entries(e.measures))if(n.type==="calculated"&&n.calculatedSql){const s=`${e.name}.${t}`,i=this.extractDependencies(n.calculatedSql),r=new Set;for(const a of i){const c=`${a.cubeName||e.name}.${a.fieldName}`;r.add(c)}this.dependencyGraph.set(s,{id:s,dependencies:r,inDegree:0})}this.calculateInDegrees()}buildGraphForMultipleCubes(e){for(const t of e.values())this.buildGraph(t)}calculateInDegrees(){for(const e of this.dependencyGraph.values())e.inDegree=0;for(const e of this.dependencyGraph.values())for(const t of e.dependencies){const n=this.dependencyGraph.get(t);n&&n.inDegree++}}topologicalSort(e){const t=new Map,n=[],s=[];for(const i of e){const r=this.dependencyGraph.get(i);r&&t.set(i,{id:r.id,dependencies:new Set(r.dependencies),inDegree:0})}for(const i of t.values()){let r=0;for(const a of i.dependencies)t.has(a)&&r++;i.inDegree=r}for(const[i,r]of t)r.inDegree===0&&n.push(i);for(;n.length>0;){const i=n.shift();s.push(i);for(const[r,a]of t)a.dependencies.has(i)&&(a.inDegree--,a.inDegree===0&&n.push(r))}if(s.length<t.size){const i=this.detectCycle();throw new Error(`Circular dependency detected in calculated measures: ${i?i.join(" -> "):"unknown cycle"}`)}return s}detectCycle(){const e=new Set,t=new Set,n=[];for(const s of this.dependencyGraph.keys())if(!e.has(s)){const i=this.dfs(s,e,t,n);if(i)return i}return null}dfs(e,t,n,s){t.add(e),n.add(e),s.push(e);const i=this.dependencyGraph.get(e);if(!i)return s.pop(),n.delete(e),null;for(const r of i.dependencies)if(t.has(r)){if(n.has(r)){const a=s.indexOf(r);return[...s.slice(a),r]}}else{const a=this.dfs(r,t,n,s);if(a)return a}return s.pop(),n.delete(e),null}getAllDependencies(e){const t=new Set,n=new Set,s=i=>{if(n.has(i))return;n.add(i);const r=this.dependencyGraph.get(i);if(r)for(const a of r.dependencies)t.add(a),s(a)};return s(e),t}validateDependencies(e){for(const[t,n]of Object.entries(e.measures))if(n.type==="calculated"&&n.calculatedSql){const s=this.extractDependencies(n.calculatedSql);for(const i of s){const r=i.cubeName||e.name,a=this.cubes.get(r);if(!a)throw new Error(`Calculated measure '${e.name}.${t}' references unknown cube '${r}'`);if(!a.measures[i.fieldName])throw new Error(`Calculated measure '${e.name}.${t}' references unknown measure '${i.measureName}'`);if(r===e.name&&i.fieldName===t)throw new Error(`Calculated measure '${e.name}.${t}' cannot reference itself`)}}}populateDependencies(e){for(const[,t]of Object.entries(e.measures))if(t.type==="calculated"&&t.calculatedSql&&!t.dependencies){const n=this.extractDependencies(t.calculatedSql);t.dependencies=n.map(s=>s.measureName)}}static isCalculatedMeasure(e){return e.type==="calculated"&&!!e.calculatedSql}}function Xt(d,e){const{cube:t,allCubes:n,resolvedMeasures:s}=e,i=Re(d),r=new Map;for(const m of i){const{originalRef:p,cubeName:f,fieldName:h}=m,g=f||t.name;if(!n.get(g))throw new Error(`Cannot substitute {${p}}: cube '${g}' not found`);const b=`${g}.${h}`,w=s.get(b);if(!w)throw new Error(`Cannot substitute {${p}}: measure '${b}' not resolved yet. Ensure measures are resolved in dependency order.`);const _=w(),$=o`${_}`;r.set(p,$)}const a=[],u=[];let c=0;for(const m of i){const p=`{${m.originalRef}}`,f=d.indexOf(p,c);if(f>=0){a.push(d.substring(c,f));const h=r.get(m.originalRef);h&&u.push(h),c=f+p.length}}if(a.push(d.substring(c)),u.length===0)return o.raw(d);const l=[];for(let m=0;m<a.length;m++)a[m]&&l.push(new j(a[m])),m<u.length&&l.push(u[m]);return o.join(l,o.raw(""))}function Re(d){const e=/\{([^}]+)\}/g,t=d.matchAll(e),n=[];for(const s of t){const i=s[1].trim();if(i.includes(".")){const[r,a]=i.split(".").map(u=>u.trim());n.push({originalRef:i,cubeName:r,fieldName:a})}else n.push({originalRef:i,cubeName:null,fieldName:i})}return n}function Zt(d){const e=[];let t=0;for(let r=0;r<d.length;r++)if(d[r]==="{")t++;else if(d[r]==="}"&&(t--,t<0)){e.push(`Unmatched closing brace at position ${r}`);break}t>0&&e.push("Unmatched opening brace in template"),/\{\s*\}/.test(d)&&e.push("Empty member reference {} found in template"),/\{[^}]*\{/.test(d)&&e.push("Nested braces are not allowed in member references");const i=Re(d);for(const r of i){const a=r.cubeName?`${r.cubeName}.${r.fieldName}`:r.fieldName;/^[a-zA-Z_][a-zA-Z0-9_.]*$/.test(a)||e.push(`Invalid member reference {${r.originalRef}}: must start with letter or underscore, and contain only letters, numbers, underscores, and dots`),a.split(".").length>2&&e.push(`Invalid member reference {${r.originalRef}}: only one dot allowed (Cube.measure format)`)}return{isValid:e.length===0,errors:e}}function Te(d,e){const t=Re(d),n=new Set;for(const s of t){const r=`${s.cubeName||e}.${s.fieldName}`;n.add(r)}return Array.from(n)}class I{constructor(e){this.databaseAdapter=e}buildResolvedMeasures(e,t,n,s){const i=new Map,r=[],a=[],u=new Set(e),c=new H(t);for(const l of t.values())c.buildGraph(l);for(const l of e){const[m,p]=l.split("."),f=t.get(m);if(f&&f.measures&&f.measures[p]){const h=f.measures[p];if(I.isPostAggregationWindow(h)){const g=I.getWindowBaseMeasure(h,m);g&&u.add(g);continue}H.isCalculatedMeasure(h)?(a.push(l),Te(h.calculatedSql,m).forEach(b=>u.add(b)),c.getAllDependencies(l).forEach(b=>{const[w,_]=b.split("."),$=t.get(w);if($&&$.measures[_]){const C=$.measures[_];H.isCalculatedMeasure(C)&&Te(C.calculatedSql,w).forEach(T=>u.add(T))}})):r.push(l)}}for(const l of u){const[m,p]=l.split("."),f=t.get(m);if(f&&f.measures&&f.measures[p]){const h=f.measures[p];if(I.isPostAggregationWindow(h))continue;H.isCalculatedMeasure(h)?a.includes(l)||a.push(l):r.includes(l)||r.push(l)}}for(const l of r){const[m,p]=l.split("."),f=t.get(m),h=f.measures[p];if(s){const g=s(l,h,f);i.set(l,()=>g)}else i.set(l,()=>this.buildMeasureExpression(h,n,f))}if(a.length>0){const l=c.topologicalSort(a);for(const m of l){const[p,f]=m.split("."),h=t.get(p),g=h.measures[f];i.set(m,()=>this.buildCalculatedMeasure(g,h,t,i,n))}}return i}buildCalculatedMeasure(e,t,n,s,i){if(!e.calculatedSql)throw new Error(`Calculated measure '${t.name}.${e.name}' missing calculatedSql property`);const r=this.databaseAdapter.preprocessCalculatedTemplate(e.calculatedSql);return Xt(r,{cube:t,allCubes:n,resolvedMeasures:s})}buildCTECalculatedMeasure(e,t,n,s,i){if(!e.calculatedSql)throw new Error(`Calculated measure '${t.name}.${e.name||"unknown"}' missing calculatedSql property`);const r=new Map,a=Te(e.calculatedSql,t.name);for(const u of a){const[c,l]=u.split("."),m=s.get(c);if(m&&m.measures[l]){const p=m.measures[l];if(n.measures.includes(u)){const f=o`${o.identifier(n.cteAlias)}.${o.identifier(l)}`;let h;switch(p.type){case"count":case"countDistinct":case"sum":h=K(f);break;case"avg":h=this.databaseAdapter.buildAvg(f);break;case"min":h=re(f);break;case"max":h=J(f);break;case"number":h=K(f);break;default:h=K(f)}r.set(u,()=>h)}}}return this.buildCalculatedMeasure(e,t,s,r,i)}buildHavingMeasureExpression(e,t,n,s,i){if(i&&i.preAggregationCTEs){const r=i.preAggregationCTEs.find(a=>a.cube.name===e);if(r&&r.measures.includes(`${e}.${t}`))if(n.type==="calculated"&&n.calculatedSql){const a=i.primaryCube.name===e?i.primaryCube:i.joinCubes?.find(c=>c.cube.name===e)?.cube;if(!a)throw new Error(`Cube ${e} not found in query plan`);const u=new Map([[i.primaryCube.name,i.primaryCube]]);if(i.joinCubes)for(const c of i.joinCubes)u.set(c.cube.name,c.cube);return this.buildCTECalculatedMeasure(n,a,r,u,s)}else{const a=o`${o.identifier(r.cteAlias)}.${o.identifier(t)}`;switch(n.type){case"count":case"countDistinct":case"sum":return K(a);case"avg":return this.databaseAdapter.buildAvg(a);case"min":return re(a);case"max":return J(a);case"number":return K(a);default:return K(a)}}}return this.buildMeasureExpression(n,s)}buildMeasureExpression(e,t,n){if(e.type==="calculated")throw new Error(`Cannot build calculated measure '${e.name}' directly. Use buildCalculatedMeasure instead.`);if(I.isPostAggregationWindow(e))throw new Error(`Post-aggregation window measure '${e.name}' should be built via buildPostAggregationWindowExpression, not buildMeasureExpression.`);if(!e.sql)throw new Error(`Measure '${e.name}' of type '${e.type}' is missing required 'sql' property. Only calculated measures and post-aggregation window functions can omit 'sql'.`);let s=v(e.sql,t);if(e.filters&&e.filters.length>0){const i=e.filters.map(r=>{const a=r(t);return a?o`(${a})`:void 0}).filter(Boolean);if(i.length>0){const r=i.length===1?i[0]:A(...i);s=this.databaseAdapter.buildCaseWhen([{when:r,then:s}])}}switch(e.type){case"count":return De(s);case"countDistinct":return Tt(s);case"sum":return K(s);case"avg":return this.databaseAdapter.buildAvg(s);case"min":return re(s);case"max":return J(s);case"number":return s;case"stddev":case"stddevSamp":{const i=e.type==="stddevSamp"||e.statisticalConfig?.useSample,r=this.databaseAdapter.buildStddev(s,i);return r===null?(console.warn(`[drizzle-cube] ${e.type} not supported on ${this.databaseAdapter.getEngineType()}, returning NULL`),o`MAX(NULL)`):r}case"variance":case"varianceSamp":{const i=e.type==="varianceSamp"||e.statisticalConfig?.useSample,r=this.databaseAdapter.buildVariance(s,i);return r===null?(console.warn(`[drizzle-cube] ${e.type} not supported on ${this.databaseAdapter.getEngineType()}, returning NULL`),o`MAX(NULL)`):r}case"percentile":case"median":case"p95":case"p99":{let i;switch(e.type){case"median":i=50;break;case"p95":i=95;break;case"p99":i=99;break;default:i=e.statisticalConfig?.percentile??50}const r=this.databaseAdapter.buildPercentile(s,i);return r===null?(console.warn(`[drizzle-cube] ${e.type} not supported on ${this.databaseAdapter.getEngineType()}, returning NULL`),o`MAX(NULL)`):r}case"lag":case"lead":case"rank":case"denseRank":case"rowNumber":case"ntile":case"firstValue":case"lastValue":case"movingAvg":case"movingSum":{const i=e.windowConfig||{};let r;if(i.partitionBy&&i.partitionBy.length>0&&n){const c=i.partitionBy.map(l=>{const m=l.includes(".")?l.split(".")[1]:l,p=n.dimensions?.[m];return p?v(p.sql,t):(console.warn(`[drizzle-cube] Window function partition dimension '${l}' not found in cube '${n.name}'`),null)}).filter(l=>l!==null);c.length>0&&(r=c)}let a;if(i.orderBy&&i.orderBy.length>0&&n){const c=i.orderBy.map(l=>{const m=l.field.includes(".")?l.field.split(".")[1]:l.field,p=n.dimensions?.[m];if(p)return{field:v(p.sql,t),direction:l.direction};const f=n.measures?.[m];return f&&f.sql?{field:v(f.sql,t),direction:l.direction}:(console.warn(`[drizzle-cube] Window function order field '${l.field}' not found in cube '${n.name}'`),null)}).filter(l=>l!==null);c.length>0&&(a=c)}const u=this.databaseAdapter.buildWindowFunction(e.type,["rank","denseRank","rowNumber"].includes(e.type)?null:s,r,a,{offset:i.offset,defaultValue:i.defaultValue,nTile:i.nTile,frame:i.frame});return u===null?(console.warn(`[drizzle-cube] ${e.type} not supported on ${this.databaseAdapter.getEngineType()}, returning NULL`),o`NULL`):u}default:return De(s)}}static WINDOW_FUNCTION_TYPES=["lag","lead","rank","denseRank","rowNumber","ntile","firstValue","lastValue","movingAvg","movingSum"];static isWindowFunction(e){return I.WINDOW_FUNCTION_TYPES.includes(e)}static categorizeMeasures(e,t){const n=[],s=[];for(const i of e){const[r,a]=i.split("."),u=t.get(r);if(u?.measures?.[a]){const c=u.measures[a];I.isWindowFunction(c.type)?n.push(i):s.push(i)}}return{windowMeasures:n,aggregateMeasures:s}}static hasWindowFunctions(e,t){const{windowMeasures:n}=I.categorizeMeasures(e,t);return n.length>0}static isPostAggregationWindow(e){return I.isWindowFunction(e.type)&&e.windowConfig?.measure!==void 0}static getWindowBaseMeasure(e,t){if(!e.windowConfig?.measure)return null;const n=e.windowConfig.measure;return n.includes(".")?n:`${t}.${n}`}static getDefaultWindowOperation(e){switch(e){case"lag":case"lead":return"difference";default:return"raw"}}static categorizeForPostAggregation(e,t){const n=[],s=[],i=new Set;for(const r of e){const[a,u]=r.split("."),c=t.get(a);if(c?.measures?.[u]){const l=c.measures[u];if(I.isPostAggregationWindow(l)){s.push(r);const m=I.getWindowBaseMeasure(l,a);m&&i.add(m)}else I.isWindowFunction(l.type)||n.push(r)}}return{aggregateMeasures:n,postAggWindowMeasures:s,requiredBaseMeasures:i}}static hasPostAggregationWindows(e,t){const{postAggWindowMeasures:n}=I.categorizeForPostAggregation(e,t);return n.length>0}}class en{constructor(e){this.dateTimeBuilder=e}isWindowFunctionType(e){return["lag","lead","rank","denseRank","rowNumber","ntile","firstValue","lastValue","movingAvg","movingSum"].includes(e)}isAggregateFunctionType(e){return["count","countDistinct","sum","avg","min","max","stddev","stddevSamp","variance","varianceSamp","median","p95","p99","percentile","number"].includes(e)}buildGroupByFields(e,t,n,s){const i=[],r=e instanceof Map?e:new Map([[e.name,e]]),a=t.dimensions&&t.dimensions.length>0||t.timeDimensions&&t.timeDimensions.length>0,u=t.measures&&t.measures.length>0,c=a&&!u;let l=!1;for(const m of t.measures||[]){const[p,f]=m.split("."),h=r.get(p);if(h&&h.measures&&h.measures[f]){const g=h.measures[f];if(this.isAggregateFunctionType(g.type)||g.type==="calculated"){l=!0;break}if(I.isPostAggregationWindow(g)){const y=I.getWindowBaseMeasure(g,p);if(y){const[b,w]=y.split("."),$=r.get(b)?.measures?.[w];if($&&this.isAggregateFunctionType($.type)){l=!0;break}}}}}if(!l&&!c)return[];if(t.dimensions)for(const m of t.dimensions){const[p,f]=m.split("."),h=r.get(p);if(h&&h.dimensions&&h.dimensions[f])if(s?.preAggregationCTEs?.some(y=>y.cube.name===p)){const y=s.preAggregationCTEs.find(w=>w.cube.name===p),b=y.joinKeys.find(w=>w.targetColumn===f);if(b&&b.sourceColumnObj)i.push(b.sourceColumnObj);else{const w=o`${o.identifier(y.cteAlias)}.${o.identifier(f)}`;i.push(w)}}else{const y=h.dimensions[f],b=v(y.sql,n);i.push(b)}}if(t.timeDimensions)for(const m of t.timeDimensions){const[p,f]=m.dimension.split("."),h=r.get(p);if(h&&h.dimensions&&h.dimensions[f])if(s?.preAggregationCTEs?.some(y=>y.cube.name===p)){const y=s.preAggregationCTEs.find(w=>w.cube.name===p),b=y.joinKeys.find(w=>w.targetColumn===f);if(b&&b.sourceColumnObj){const w=this.dateTimeBuilder.buildTimeDimensionExpression(b.sourceColumnObj,m.granularity,n);i.push(w)}else{const w=o`${o.identifier(y.cteAlias)}.${o.identifier(f)}`;i.push(w)}}else{const y=h.dimensions[f],b=this.dateTimeBuilder.buildTimeDimensionExpression(y.sql,m.granularity,n);i.push(b)}}return i}}class tn{dateTimeBuilder;filterBuilder;groupByBuilder;measureBuilder;constructor(e){this.dateTimeBuilder=new ne(e),this.filterBuilder=new he(e,this.dateTimeBuilder),this.groupByBuilder=new en(this.dateTimeBuilder),this.measureBuilder=new I(e)}buildResolvedMeasures(e,t,n,s){return this.measureBuilder.buildResolvedMeasures(e,t,n,s)}buildSelections(e,t,n){const s={},i=e instanceof Map?e:new Map([[e.name,e]]);if(t.dimensions)for(const r of t.dimensions){const[a,u]=r.split("."),c=i.get(a);if(c&&c.dimensions&&c.dimensions[u]){const l=c.dimensions[u],m=v(l.sql,n);s[r]=o`${m}`.as(r)}}if(t.measures){const r=this.buildResolvedMeasures(t.measures,i,n);for(const a of t.measures){const u=r.get(a);if(u){const c=u();s[a]=o`${c}`.as(a)}}}if(t.timeDimensions)for(const r of t.timeDimensions){const[a,u]=r.dimension.split("."),c=i.get(a);if(c&&c.dimensions&&c.dimensions[u]){const l=c.dimensions[u],m=this.buildTimeDimensionExpression(l.sql,r.granularity,n);s[r.dimension]=o`${m}`.as(r.dimension)}}return Object.keys(s).length===0&&(s.count=De()),s}buildCalculatedMeasure(e,t,n,s,i){return this.measureBuilder.buildCalculatedMeasure(e,t,n,s,i)}buildCTECalculatedMeasure(e,t,n,s,i){return this.measureBuilder.buildCTECalculatedMeasure(e,t,n,s,i)}buildHavingMeasureExpression(e,t,n,s,i){return this.measureBuilder.buildHavingMeasureExpression(e,t,n,s,i)}buildMeasureExpression(e,t,n){return this.measureBuilder.buildMeasureExpression(e,t,n)}buildTimeDimensionExpression(e,t,n){return this.dateTimeBuilder.buildTimeDimensionExpression(e,t,n)}buildWhereConditions(e,t,n,s,i){const r=[],a=e instanceof Map?e:new Map([[e.name,e]]),u=new Set;if(t.filters&&t.filters.length>0)for(const c of t.filters){if(i&&"member"in c){const[m]=c.member.split(".");if(a.has(m)&&i.has(m)&&!u.has(m)){const f=i.get(m);r.push(...f),u.add(m);continue}else if(u.has(m))continue}const l=this.processFilter(c,a,n,"where",s);l&&r.push(l)}if(t.timeDimensions)for(const c of t.timeDimensions){const[l,m]=c.dimension.split("."),p=a.get(l);if(p&&p.dimensions[m]&&c.dateRange){if(s?.preAggregationCTEs&&s.preAggregationCTEs.some(b=>b.cube.name===l))continue;if(n.filterCache){const y=it(c.dimension,c.dateRange),b=n.filterCache.get(y);if(b){r.push(b);continue}}const f=p.dimensions[m],h=v(f.sql,n),g=this.buildDateRangeCondition(h,c.dateRange);g&&r.push(g)}}return r}buildHavingConditions(e,t,n,s){const i=[],r=e instanceof Map?e:new Map([[e.name,e]]);if(t.filters&&t.filters.length>0)for(const a of t.filters){const u=this.processFilter(a,r,n,"having",s);u&&i.push(u)}return i}processFilter(e,t,n,s,i){if("and"in e||"or"in e){const f=e;if(f.and){const h=f.and.map(g=>this.processFilter(g,t,n,s,i)).filter(g=>g!==null);return h.length>0?A(...h):null}if(f.or){const h=f.or.map(g=>this.processFilter(g,t,n,s,i)).filter(g=>g!==null);return h.length>0?ie(...h):null}}const r=e,[a,u]=r.member.split("."),c=t.get(a);if(!c)return null;const l=c.dimensions[u],m=c.measures[u],p=l||m;if(!p)return null;if(s==="where"&&l){if(i?.preAggregationCTEs&&i.preAggregationCTEs.some(y=>y.cube.name===a))return null;const f=["arrayContains","arrayOverlaps","arrayContained"].includes(r.operator);if(!f&&n.filterCache){const g=de(e),y=n.filterCache.get(g);if(y)return y}const h=f?typeof l.sql=="function"?l.sql(n):l.sql:v(l.sql,n);return this.buildFilterCondition(h,r.operator,r.values,p,r.dateRange)}else{if(s==="where"&&m)return null;if(s==="having"&&m){const f=this.buildHavingMeasureExpression(a,u,m,n,i);return this.buildFilterCondition(f,r.operator,r.values,p,r.dateRange)}}return null}buildFilterCondition(e,t,n,s,i){return this.filterBuilder.buildFilterCondition(e,t,n,s,i)}buildDateRangeCondition(e,t){return this.dateTimeBuilder.buildDateRangeCondition(e,t)}buildGroupByFields(e,t,n,s){return this.groupByBuilder.buildGroupByFields(e,t,n,s)}buildOrderBy(e,t){const n=[],s=t||[...e.measures||[],...e.dimensions||[],...e.timeDimensions?.map(i=>i.dimension)||[]];if(e.order&&Object.keys(e.order).length>0)for(const[i,r]of Object.entries(e.order)){if(!s.includes(i))throw new Error(`Cannot order by '${i}': field is not selected in the query`);const a=r==="desc"?Et(o.identifier(i)):Be(o.identifier(i));n.push(a)}if(e.timeDimensions&&e.timeDimensions.length>0){const i=new Set(Object.keys(e.order||{})),r=[...e.timeDimensions].sort((a,u)=>a.dimension.localeCompare(u.dimension));for(const a of r)i.has(a.dimension)||n.push(Be(o.identifier(a.dimension)))}return n}collectNumericFields(e,t){const n=[],s=e instanceof Map?e:new Map([[e.name,e]]);if(t.measures&&n.push(...t.measures),t.dimensions)for(const i of t.dimensions){const[r,a]=i.split("."),u=s.get(r);if(u){const c=u.dimensions[a];c&&c.type==="number"&&n.push(i)}}return n}applyLimitAndOffset(e,t){let n=t.limit;t.offset!==void 0&&t.offset>0&&n===void 0&&(n=50);let s=e;if(n!==void 0){if(n<0)throw new Error("Limit must be non-negative");s=s.limit(n)}if(t.offset!==void 0){if(t.offset<0)throw new Error("Offset must be non-negative");s=s.offset(t.offset)}return s}buildFilterConditionPublic(e,t,n,s,i){return this.buildFilterCondition(e,t,n,s,i)}buildLogicalFilter(e,t,n){return this.filterBuilder.buildLogicalFilter(e,t,n)}}class oe{cubes;connectivityCache=new Map;constructor(e){this.cubes=e}findPath(e,t,n=new Set){if(e===t)return[];const s=this.getCacheKey(e,t,n),i=this.getFromCache(s);if(i!==void 0)return i;const r=[{cube:e,path:[]}],a=new Set([e,...n]);for(;r.length>0;){const{cube:u,path:c}=r.shift(),l=this.cubes.get(u);if(l?.joins)for(const[,m]of Object.entries(l.joins)){const f=q(m.targetCube).name;if(a.has(f))continue;const h=[...c,{fromCube:u,toCube:f,joinDef:m}];if(f===t)return this.setInCache(s,h),h;a.add(f),r.push({cube:f,path:h})}}return this.setInCache(s,null),null}findPathPreferring(e,t,n,s=new Set){const i=this.findAllPaths(e,t,new Set);if(i.length===0)return this.findPath(e,t,s);const r=i.map(a=>{let u=0;a.some((m,p)=>m.joinDef.preferredFor?.includes(t)&&p===0)&&(u+=10);const l=a.filter(m=>n.has(m.toCube)).length;return u+=l,u-=a.length-1,{path:a,score:u,usesProcessed:a.some(m=>s.has(m.toCube))}});return r.sort((a,u)=>u.score!==a.score?u.score-a.score:a.usesProcessed!==u.usesProcessed?a.usesProcessed?-1:1:a.path.length-u.path.length),r[0].path}findAllPaths(e,t,n,s=4){if(e===t)return[[]];const i=[],r=[{cube:e,path:[],visited:new Set([e,...n])}];for(;r.length>0;){const{cube:a,path:u,visited:c}=r.shift();if(u.length>=s)continue;const l=this.cubes.get(a);if(l?.joins)for(const[,m]of Object.entries(l.joins)){const f=q(m.targetCube).name;if(c.has(f))continue;const h=[...u,{fromCube:a,toCube:f,joinDef:m}];if(f===t)i.push(h);else{const g=new Set(c);g.add(f),r.push({cube:f,path:h,visited:g})}}}return i}canReachAll(e,t){const n=t.filter(s=>s!==e);for(const s of n){const i=this.findPath(e,s,new Set);if(!i||i.length===0)return!1}return!0}buildJoinCondition(e,t,n){const s=[];for(const i of e.on){const r=t?o`${o.identifier(t)}.${o.identifier(i.source.name)}`:_e(i.source),a=n?o`${o.identifier(n)}.${o.identifier(i.target.name)}`:_e(i.target),u=i.as||Q;s.push(u(r,a))}return A(...s)}getReachableCubes(e){const t=new Set([e]),n=[e];for(;n.length>0;){const s=n.shift(),i=this.cubes.get(s);if(i?.joins)for(const[,r]of Object.entries(i.joins)){const u=q(r.targetCube).name;t.has(u)||(t.add(u),n.push(u))}}return t}getCacheKey(e,t,n){const s=Array.from(n).sort().join(",");return`${e}:${t}:${s}`}getFromCache(e){const t=this.connectivityCache.get(e);if(t)return t.path}setInCache(e,t){this.connectivityCache.set(e,{path:t})}}class rt{resolverCache=new WeakMap;getResolver(e){let t=this.resolverCache.get(e);return t||(t=new oe(e),this.resolverCache.set(e,t)),t}analyzeCubeUsage(e){const t=new Set;if(e.measures)for(const n of e.measures){const[s]=n.split(".");t.add(s)}if(e.dimensions)for(const n of e.dimensions){const[s]=n.split(".");t.add(s)}if(e.timeDimensions)for(const n of e.timeDimensions){const[s]=n.dimension.split(".");t.add(s)}if(e.filters)for(const n of e.filters)this.extractCubeNamesFromFilter(n,t);return t}extractCubeNamesFromFilter(e,t){if("and"in e||"or"in e){const n=e.and||e.or||[];for(const s of n)this.extractCubeNamesFromFilter(s,t);return}if("member"in e){const[n]=e.member.split(".");n&&t.add(n)}}extractMeasuresFromFilters(e,t){const n=[];if(!e.filters)return n;for(const s of e.filters)this.extractMeasuresFromFilter(s,t,n);return n}extractMeasuresFromFilter(e,t,n){if("and"in e||"or"in e){const s=e.and||e.or||[];for(const i of s)this.extractMeasuresFromFilter(i,t,n);return}if("member"in e){const s=e.member,[i,r]=s.split(".");i===t.name&&t.measures&&t.measures[r]&&n.push(s)}}createQueryPlan(e,t,n){const s=this.analyzeCubeUsage(t),i=Array.from(s);if(i.length===0)throw new Error("No cubes found in query");const r=this.choosePrimaryCube(i,t,e),a=e.get(r);if(!a)throw new Error(`Primary cube '${r}' not found`);if(i.length===1)return{primaryCube:a,joinCubes:[],selections:{},whereConditions:[],groupByFields:[]};const u=this.buildJoinPlan(e,a,i,n,t),c=this.planPreAggregationCTEs(e,a,u,t,n),l=this.generateWarnings(t,c);return{primaryCube:a,joinCubes:u,selections:{},whereConditions:[],groupByFields:[],preAggregationCTEs:c,warnings:l.length>0?l:void 0}}choosePrimaryCube(e,t,n){return e.length===1?e[0]:n?this.analyzePrimaryCubeSelection(e,t,n).selectedCube:[...e].sort()[0]}buildJoinPlan(e,t,n,s,i){const r=this.getResolver(e),a=[],u=new Set([t.name]),c=new Set;if(i.measures)for(const p of i.measures){const[f]=p.split(".");c.add(f)}const l=new Set;for(const p of c){if(p===t.name)continue;this.findHasManyJoinDef(t,p)&&l.add(p)}const m=n.filter(p=>p!==t.name);for(const p of m){if(u.has(p))continue;const f=new Set([...u].filter(g=>!l.has(g))),h=r.findPathPreferring(t.name,p,c,f);if(!h||h.length===0)throw new Error(`No join path found from '${t.name}' to '${p}'`);for(const{toCube:g,joinDef:y}of h){if(u.has(g))continue;const b=e.get(g);if(!b)throw new Error(`Cube '${g}' not found`);if(y.relationship==="belongsToMany"&&y.through){const w=qt(y,s.securityContext);a.push({cube:b,alias:`${g.toLowerCase()}_cube`,joinType:w.junctionJoins[1].joinType,joinCondition:w.junctionJoins[1].condition,junctionTable:{table:y.through.table,alias:`junction_${g.toLowerCase()}`,joinType:w.junctionJoins[0].joinType,joinCondition:w.junctionJoins[0].condition,securitySql:y.through.securitySql}})}else{const w=r.buildJoinCondition(y,null,null),_=Ae(y.relationship,y.sqlJoinType);a.push({cube:b,alias:`${g.toLowerCase()}_cube`,joinType:_,joinCondition:w})}u.add(g)}}return a}planPreAggregationCTEs(e,t,n,s,i){const r=[];if(!s.measures||s.measures.length===0)return r;const a=this.detectHasManyInQuery(e,t,n);if(a.length===0)return r;const u=new Set;for(const l of s.measures){const[m]=l.split(".");u.add(m)}for(const l of e.values())this.extractMeasuresFromFilters(s,l).length>0&&u.add(l.name);const c=[];for(const l of n)c.push({cube:l.cube,alias:l.alias,isPrimary:!1});for(const{cube:l,alias:m,isPrimary:p}of c){const f=this.getCTEReason(l,t,a,s);if(!f)continue;const h=s.measures.filter(S=>S.startsWith(l.name+".")),g=this.extractMeasuresFromFilters(s,l),y=[...new Set([...h,...g])];if(y.length===0)continue;const b=this.analyzeJoinPathToPrimary(e,t,l.name,i);let w,_;if(b?.hasIntermediateHasMany&&b.intermediateJoins.length>0)w=b.correctJoinKeys,_=b.intermediateJoins;else{const S=p?this.findJoinInfoToCube(e,t.name):this.findJoinInfoForCube(e,t,l.name);if(!S)continue;w=p?S.joinDef.on.map(D=>({sourceColumn:D.target.name,targetColumn:D.source.name,sourceColumnObj:D.target,targetColumnObj:D.source})):S.joinDef.on.map(D=>({sourceColumn:D.source.name,targetColumn:D.target.name,sourceColumnObj:D.source,targetColumnObj:D.target})),_=void 0}const $=this.findPropagatingFilters(s,l,e),C=new Map([[l.name,l]]),{aggregateMeasures:E,requiredBaseMeasures:T}=I.categorizeForPostAggregation(y,C),N=[...new Set([...E,...Array.from(T).filter(S=>S.startsWith(l.name+"."))])];if(N.length>0){const S=this.expandCalculatedMeasureDependencies(l,N),D=this.findDownstreamJoinKeys(l,s,e);r.push({cube:l,alias:m,cteAlias:`${l.name.toLowerCase()}_agg`,joinKeys:w,measures:S,propagatingFilters:$.length>0?$:void 0,downstreamJoinKeys:D.length>0?D:void 0,intermediateJoins:_&&_.length>0?_:void 0,cteType:"aggregate",cteReason:f})}}return r}findJoinInfoToCube(e,t){for(const[,n]of e)if(n.name!==t&&n.joins){for(const[,s]of Object.entries(n.joins))if(q(s.targetCube).name===t)return{sourceCube:n,joinDef:s}}return null}analyzeJoinPathToPrimary(e,t,n,s){const r=this.getResolver(e).findPath(t.name,n);if(!r||r.length===0)return null;const a=r.map(f=>({fromCube:f.fromCube,toCube:f.toCube,joinDef:f.joinDef}));if(!a.slice(0,-1).some(f=>f.joinDef.relationship==="hasMany"))return{path:a,hasIntermediateHasMany:!1,intermediateJoins:[],correctJoinKeys:[]};const l=[];for(let f=0;f<a.length-1;f++){const h=a[f],g=a[f+1],y=e.get(h.toCube);if(!y)continue;const w=y.sql(s).where,_=g.joinDef.on[0]?.source,$=h.joinDef.on[0]?.target;l.push({cube:y,joinDef:g.joinDef,securityFilter:w,primaryJoinColumn:$,cteJoinColumn:_})}const p=a[0].joinDef.on.map(f=>({sourceColumn:f.source.name,targetColumn:f.target.name,sourceColumnObj:f.source,targetColumnObj:f.target}));return{path:a,hasIntermediateHasMany:!0,intermediateJoins:l,correctJoinKeys:p}}detectHasManyInQuery(e,t,n){const s=[],i=new Set,r=new Set;r.add(t.name);for(const a of n)r.add(a.cube.name);for(const[a,u]of e)if(!i.has(a)&&(i.add(a),!!u.joins)){for(const[,c]of Object.entries(u.joins))if(c.relationship==="hasMany"){const l=q(c.targetCube);(r.has(a)||r.has(l.name))&&s.push({fromCube:a,toCube:l.name,joinDef:c})}}return s}getCTEReason(e,t,n,s){if(n.some(a=>a.toCube===e.name)&&s.measures?.some(u=>u.startsWith(e.name+".")))return"hasMany";if(!s.measures?.some(a=>a.startsWith(e.name+".")))return null;for(const a of n)if(a.fromCube!==e.name&&a.toCube!==e.name)return"fanOutPrevention";return null}findJoinInfoForCube(e,t,n){if(t.joins){for(const[,s]of Object.entries(t.joins))if(q(s.targetCube).name===n)return{sourceCube:t,joinDef:s}}for(const[,s]of e)if(s.name!==t.name&&s.joins){for(const[,i]of Object.entries(s.joins))if(q(i.targetCube).name===n)return{sourceCube:s,joinDef:i}}return null}findDownstreamJoinKeys(e,t,n){const s=[],i=new Set;if(t.dimensions)for(const r of t.dimensions){const[a]=r.split(".");a!==e.name&&i.add(a)}if(t.timeDimensions)for(const r of t.timeDimensions){const[a]=r.dimension.split(".");a!==e.name&&i.add(a)}if(e.joins)for(const[,r]of Object.entries(e.joins)){const u=q(r.targetCube).name;if(i.has(u)){const c=r.on.map(l=>({sourceColumn:l.source.name,targetColumn:l.target.name,sourceColumnObj:l.source,targetColumnObj:l.target}));s.push({targetCubeName:u,joinKeys:c})}}return s}expandCalculatedMeasureDependencies(e,t){const n=new Set,s=[...t];for(;s.length>0;){const i=s.pop();if(n.has(i))continue;n.add(i);const[,r]=i.split(".");if(!e.measures||!e.measures[r])continue;const a=e.measures[r];if(a.type==="calculated"&&a.calculatedSql){const u=this.extractDependenciesFromTemplate(a.calculatedSql,e.name);for(const c of u)n.has(c)||s.push(c)}}return Array.from(n)}extractDependenciesFromTemplate(e,t){const n=/\{([^}]+)\}/g,s=e.matchAll(n),i=[];for(const r of s){const a=r[1].trim();a.includes(".")?i.push(a):i.push(`${t}.${a}`)}return i}findHasManyJoinDef(e,t){if(!e.joins)return null;for(const[,n]of Object.entries(e.joins))if(q(n.targetCube).name===t&&n.relationship==="hasMany")return n;return null}findPropagatingFilters(e,t,n){const s=[];if(!e.filters)return s;const i=new Set;if(this.extractFilterCubeNamesToSet(e.filters,i),e.timeDimensions){for(const r of e.timeDimensions)if(r.dateRange){const[a]=r.dimension.split(".");a&&i.add(a)}}for(const r of i){if(r===t.name)continue;const a=n.get(r);if(a?.joins){for(const[,u]of Object.entries(a.joins))if(q(u.targetCube).name===t.name&&u.relationship==="hasMany"){const l=this.extractFiltersForCube(e.filters,r),m=this.extractTimeDimensionFiltersForCube(e,r),p=[...l,...m];p.length>0&&u.on.length>0&&s.push({sourceCube:a,filters:p,joinConditions:u.on.map(f=>({source:f.source,target:f.target}))})}}}return s}extractFilterCubeNamesToSet(e,t){for(const n of e){if("and"in n||"or"in n){const s=n.and||n.or||[];this.extractFilterCubeNamesToSet(s,t);continue}if("member"in n){const[s]=n.member.split(".");s&&t.add(s)}}}extractFiltersForCube(e,t){const n=[];for(const s of e){if("and"in s){const i=this.extractFiltersForCube(s.and||[],t);i.length>0&&n.push({and:i});continue}if("or"in s){const i=s.or||[];if(this.allFiltersFromCube(i,t)){const a=this.extractFiltersForCube(i,t);a.length>0&&n.push({or:a})}continue}if("member"in s){const[i]=s.member.split(".");i===t&&n.push(s)}}return n}allFiltersFromCube(e,t){for(const n of e){if("and"in n){if(!this.allFiltersFromCube(n.and||[],t))return!1;continue}if("or"in n){if(!this.allFiltersFromCube(n.or||[],t))return!1;continue}if("member"in n){const[s]=n.member.split(".");if(s!==t)return!1}}return!0}extractTimeDimensionFiltersForCube(e,t){const n=[];if(!e.timeDimensions)return n;for(const s of e.timeDimensions){const[i]=s.dimension.split(".");i===t&&s.dateRange&&n.push({member:s.dimension,operator:"inDateRange",values:Array.isArray(s.dateRange)?s.dateRange:[s.dateRange]})}return n}analyzeQueryPlan(e,t,n){const s=this.analyzeCubeUsage(t),i=Array.from(s);if(i.length===0)return{timestamp:new Date().toISOString(),cubeCount:0,cubesInvolved:[],primaryCube:{selectedCube:"",reason:"single_cube",explanation:"No cubes found in query"},joinPaths:[],preAggregations:[],querySummary:{queryType:"single_cube",joinCount:0,cteCount:0,hasPreAggregation:!1},warnings:["No cubes found in query - add measures or dimensions"]};const r=this.analyzePrimaryCubeSelection(i,t,e),a=r.selectedCube,u={timestamp:new Date().toISOString(),cubeCount:i.length,cubesInvolved:i.sort(),primaryCube:r,joinPaths:[],preAggregations:[],querySummary:{queryType:"single_cube",joinCount:0,cteCount:0,hasPreAggregation:!1},warnings:[]};if(i.length>1){const c=i.filter(g=>g!==a);for(const g of c)u.joinPaths.push(this.analyzeJoinPath(e,a,g));const l=e.get(a);l&&(u.preAggregations=this.analyzePreAggregations(e,l,c,t));const m=u.joinPaths.filter(g=>g.pathFound),p=u.joinPaths.filter(g=>!g.pathFound);u.querySummary.joinCount=m.length,u.querySummary.cteCount=u.preAggregations.length,u.querySummary.hasPreAggregation=u.preAggregations.length>0;const f=new Map;for(const g of i){const y=e.get(g);y&&f.set(g,y)}const h=I.hasPostAggregationWindows(t.measures||[],f);u.querySummary.hasWindowFunctions=h,u.preAggregations.length>0?u.querySummary.queryType="multi_cube_cte":u.querySummary.queryType="multi_cube_join";for(const g of p)u.warnings.push(`No join path found to cube '${g.targetCube}'. Check that joins are defined correctly.`);h&&u.warnings.push("Query contains post-aggregation window functions which will be applied to aggregated results.")}return u}analyzePrimaryCubeSelection(e,t,n){if(e.length===1)return{selectedCube:e[0],reason:"single_cube",explanation:"Only one cube is used in this query"};const s=[],i=(t.dimensions||[]).map(l=>l.split(".")[0]),r=new Map;for(const l of i)r.set(l,(r.get(l)||0)+1);const a=this.getResolver(n);for(const l of e){const m=n.get(l),p=r.get(l)||0,f=m?.joins?Object.keys(m.joins).length:0,h=a.canReachAll(l,e);s.push({cubeName:l,dimensionCount:p,joinCount:f,canReachAll:h})}if(t.dimensions&&t.dimensions.length>0){const l=Math.max(...s.map(m=>m.dimensionCount));if(l>0){const m=s.filter(p=>p.dimensionCount===l).sort((p,f)=>p.cubeName.localeCompare(f.cubeName));for(const p of m)if(p.canReachAll)return{selectedCube:p.cubeName,reason:"most_dimensions",explanation:`Selected because it has ${p.dimensionCount} dimension${p.dimensionCount!==1?"s":""} in the query (defines the analytical grain)`,candidates:s}}}const u=s.filter(l=>l.canReachAll);if(u.length>0){const l=Math.max(...u.map(p=>p.joinCount)),m=u.filter(p=>p.joinCount===l).sort((p,f)=>p.cubeName.localeCompare(f.cubeName))[0];return{selectedCube:m.cubeName,reason:"most_connected",explanation:`Selected because it has ${m.joinCount} join relationship${m.joinCount!==1?"s":""} and can reach all other cubes`,candidates:s}}return{selectedCube:[...e].sort()[0],reason:"alphabetical_fallback",explanation:"Selected alphabetically as fallback (no cube could reach all others)",candidates:s}}analyzeJoinPath(e,t,n){const i=this.getResolver(e).findPath(t,n),r=[t];if(i)for(const u of i)r.push(u.toCube);if(!i||i.length===0)return{targetCube:n,pathFound:!1,error:`No join path found from '${t}' to '${n}'. Ensure the target cube has a relationship defined (belongsTo, hasOne, hasMany, or belongsToMany).`,visitedCubes:r};const a=i.map(u=>{const c=Ae(u.joinDef.relationship,u.joinDef.sqlJoinType),l=u.joinDef.on.map(p=>({sourceColumn:p.source.name,targetColumn:p.target.name})),m={fromCube:u.fromCube,toCube:u.toCube,relationship:u.joinDef.relationship,joinType:c,joinColumns:l};if(u.joinDef.relationship==="belongsToMany"&&u.joinDef.through){const p=u.joinDef.through;m.junctionTable={tableName:p.table[Symbol.for("drizzle:Name")]||"junction_table",sourceColumns:p.sourceKey.map(f=>f.target.name),targetColumns:p.targetKey.map(f=>f.source.name)}}return m});return{targetCube:n,pathFound:!0,path:a,pathLength:a.length,visitedCubes:r}}analyzePreAggregations(e,t,n,s){const i=[];if(!s.measures||s.measures.length===0)return i;for(const r of n){const a=this.findHasManyJoinDef(t,r);if(!a)continue;const u=e.get(r);if(!u)continue;const c=s.measures.filter(w=>w.startsWith(r+".")),l=this.extractMeasuresFromFilters(s,u),m=[...new Set([...c,...l])];if(m.length===0)continue;const p=a.on.map(w=>({sourceColumn:w.source.name,targetColumn:w.target.name})),f=new Map([[r,u]]),{aggregateMeasures:h,postAggWindowMeasures:g,requiredBaseMeasures:y}=I.categorizeForPostAggregation(m,f),b=[...new Set([...h,...Array.from(y).filter(w=>w.startsWith(r+"."))])];if(b.length>0){const w=g.length>0;i.push({cubeName:r,cteAlias:`${r.toLowerCase()}_agg`,reason:w?`hasMany relationship from ${t.name} - requires pre-aggregation; includes base measures for post-aggregation window functions`:`hasMany relationship from ${t.name} - requires pre-aggregation to prevent row duplication (fan-out)`,reasonType:"hasMany",measures:b,joinKeys:p,cteType:"aggregate"})}}return i}generateWarnings(e,t){const n=[],s=this.checkFanOutNoDimensions(e,t);return s&&n.push(s),n}checkFanOutNoDimensions(e,t){if(!t||t.length===0||!e.measures||e.measures.length===0)return null;const n=new Set;for(const r of e.measures){const[a]=r.split(".");n.add(a)}if(n.size<2)return null;const s=e.dimensions&&e.dimensions.length>0,i=e.timeDimensions?.some(r=>r.granularity);return s||i?null:{code:"FAN_OUT_NO_DIMENSIONS",message:"Query combines measures from multiple cubes with hasMany relationships but has no dimensions. Results are aggregated at the join key level, which may produce unexpected totals.",severity:"warning",cubes:[...n].sort(),measures:e.measures,suggestion:"Add a dimension to see per-group breakdowns, or add a time dimension with granularity."}}}class nn{constructor(e){this.queryBuilder=e}buildPreAggregationCTE(e,t,n,s,i){const r=e.cube,a=r.sql(n),u=e.intermediateJoins&&e.intermediateJoins.length>0,c={};if(u&&e.intermediateJoins){const E=e.intermediateJoins[0].primaryJoinColumn;if(E){const T=E.name;c[T]=E}}else for(const C of e.joinKeys)if(C.targetColumnObj){c[C.targetColumn]=C.targetColumnObj;for(const[E,T]of Object.entries(r.dimensions||{}))T.sql===C.targetColumnObj&&E!==C.targetColumn&&(c[E]=o`${C.targetColumnObj}`.as(E))}if(e.downstreamJoinKeys)for(const C of e.downstreamJoinKeys)for(const E of C.joinKeys)E.sourceColumnObj&&(c[E.sourceColumn]=E.sourceColumnObj);const l=r.name,m=new Map([[l,r]]),p=this.queryBuilder.buildResolvedMeasures(e.measures,m,n);for(const C of e.measures){const[,E]=C.split("."),T=p.get(C);if(T){const N=T();c[E]=o`${N}`.as(E)}}if(t.dimensions)for(const C of t.dimensions){const[E,T]=C.split(".");if(E===l&&r.dimensions&&r.dimensions[T]){const N=r.dimensions[T],S=this.queryBuilder.buildMeasureExpression({sql:N.sql,type:"number"},n);c[T]=o`${S}`.as(T)}}if(t.timeDimensions)for(const C of t.timeDimensions){const[E,T]=C.dimension.split(".");if(E===l&&r.dimensions&&r.dimensions[T]){const N=r.dimensions[T],S=this.queryBuilder.buildTimeDimensionExpression(N.sql,C.granularity,n);c[T]=o`${S}`.as(T)}}if(Object.keys(c).length===0)return null;let f=n.db.select(c).from(a.from);if(u&&e.intermediateJoins)for(const C of e.intermediateJoins){const E=C.cube.sql(n),N=[Q(C.cteJoinColumn,C.joinDef.on[0]?.target)];C.securityFilter&&N.push(C.securityFilter),f=f.leftJoin(E.from,A(...N))}const h=s?{...s,preAggregationCTEs:s.preAggregationCTEs?.filter(C=>C.cube.name!==r.name)}:void 0,g=this.queryBuilder.buildWhereConditions(r,t,n,h,i),y=[];if(t.timeDimensions)for(const C of t.timeDimensions){const[E,T]=C.dimension.split(".");if(E===l&&r.dimensions&&r.dimensions[T]&&C.dateRange){const N=r.dimensions[T],S=this.queryBuilder.buildMeasureExpression({sql:N.sql,type:"number"},n),D=this.queryBuilder.buildDateRangeCondition(S,C.dateRange);D&&y.push(D)}}if(t.filters){for(const C of t.filters)if(!("and"in C)&&!("or"in C)&&"member"in C&&"operator"in C){const E=C,[T,N]=E.member.split(".");if(T===l&&r.dimensions&&r.dimensions[N]){const S=r.dimensions[N];if(E.operator==="inDateRange"){const D=this.queryBuilder.buildMeasureExpression({sql:S.sql,type:"number"},n),O=this.queryBuilder.buildDateRangeCondition(D,E.values);O&&y.push(O)}}}}if(e.propagatingFilters&&e.propagatingFilters.length>0)for(const C of e.propagatingFilters){const E=this.buildPropagatingFilterSubquery(C,n);E&&y.push(E)}const b=[];if(a.where&&b.push(a.where),b.push(...g,...y),b.length>0){const C=b.length===1?b[0]:A(...b);f=f.where(C)}const w=[],_=new Set,$=C=>{const E=C?.name||(typeof C=="string"?C:null);E&&!_.has(E)?(_.add(E),w.push(C)):E||w.push(C)};if(u&&e.intermediateJoins){const C=e.intermediateJoins[0];C.primaryJoinColumn&&$(C.primaryJoinColumn)}else for(const C of e.joinKeys)C.targetColumnObj&&$(C.targetColumnObj);if(e.downstreamJoinKeys)for(const C of e.downstreamJoinKeys)for(const E of C.joinKeys)E.sourceColumnObj&&$(E.sourceColumnObj);if(t.dimensions)for(const C of t.dimensions){const[E,T]=C.split(".");if(E===l&&r.dimensions&&r.dimensions[T]){const N=r.dimensions[T],S=v(N.sql,n);w.push(S)}}if(t.timeDimensions)for(const C of t.timeDimensions){const[E,T]=C.dimension.split(".");if(E===l&&r.dimensions&&r.dimensions[T]){const N=r.dimensions[T],S=this.queryBuilder.buildTimeDimensionExpression(N.sql,C.granularity,n);w.push(S)}}return w.length>0&&(f=f.groupBy(...w)),n.db.$with(e.cteAlias).as(f)}buildCTEJoinCondition(e,t,n){const s=n.preAggregationCTEs?.find(r=>r.cube.name===e.cube.name);if(!s)throw new Error(`CTE info not found for cube ${e.cube.name}`);const i=[];if(s.intermediateJoins&&s.intermediateJoins.length>0){const r=s.intermediateJoins[0],a=s.joinKeys[0]?.sourceColumnObj,u=o`${o.identifier(t)}.${o.identifier(r.primaryJoinColumn.name)}`;i.push(Q(a,u))}else for(const r of s.joinKeys){const a=r.sourceColumnObj||o.identifier(r.sourceColumn),u=o`${o.identifier(t)}.${o.identifier(r.targetColumn)}`;i.push(Q(a,u))}return i.length===1?i[0]:A(...i)}buildPropagatingFilterSubquery(e,t){const n=e.sourceCube,s=n.sql(t),i=[];if(s.where&&i.push(s.where),e.preBuiltFilterSQL)i.push(e.preBuiltFilterSQL);else{const u={filters:e.filters},c=new Map([[n.name,n]]),l=this.queryBuilder.buildWhereConditions(c,u,t);i.push(...l)}if(i.length===0)return null;const r=i.length===1?i[0]:A(...i),a=e.joinConditions;if(a.length===1){const{source:u,target:c}=a[0],l=t.db.select({pk:u}).from(s.from).where(r);return o`${c} IN ${l}`}else{const u=a.map(m=>Q(m.source,m.target)),c=A(...u,r),l=t.db.select({one:o`1`}).from(s.from).where(c);return o`EXISTS ${l}`}}}function sn(d,e,t){const n=[];let s=ze(new Date(d),t);const i=ze(new Date(e),t),r=1e4;for(;s<=i&&n.length<r;)n.push(new Date(s)),s=rn(s,t);return n}function ze(d,e){const t=new Date(d);switch(e){case"second":t.setUTCMilliseconds(0);break;case"minute":t.setUTCSeconds(0,0);break;case"hour":t.setUTCMinutes(0,0,0);break;case"day":t.setUTCHours(0,0,0,0);break;case"week":{const n=t.getUTCDay(),s=n===0?6:n-1;t.setUTCDate(t.getUTCDate()-s),t.setUTCHours(0,0,0,0);break}case"month":t.setUTCDate(1),t.setUTCHours(0,0,0,0);break;case"quarter":{const n=Math.floor(t.getUTCMonth()/3)*3;t.setUTCMonth(n,1),t.setUTCHours(0,0,0,0);break}case"year":t.setUTCMonth(0,1),t.setUTCHours(0,0,0,0);break}return t}function rn(d,e){const t=new Date(d);switch(e){case"second":t.setUTCSeconds(t.getUTCSeconds()+1);break;case"minute":t.setUTCMinutes(t.getUTCMinutes()+1);break;case"hour":t.setUTCHours(t.getUTCHours()+1);break;case"day":t.setUTCDate(t.getUTCDate()+1);break;case"week":t.setUTCDate(t.getUTCDate()+7);break;case"month":t.setUTCMonth(t.getUTCMonth()+1);break;case"quarter":t.setUTCMonth(t.getUTCMonth()+3);break;case"year":t.setUTCFullYear(t.getUTCFullYear()+1);break}return t}function on(d){if(d instanceof Date)return d.toISOString();if(typeof d=="string"){const e=new Date(d);if(!isNaN(e.getTime()))return e.toISOString()}return String(d)}function an(d,e){return e.length===0?"__all__":e.map(t=>String(d[t]??"")).join("|||")}function un(d,e){const{timeDimensionKey:t,granularity:n,dateRange:s,fillValue:i,measures:r,dimensions:a}=e,u=sn(s[0],s[1],n);if(u.length===0)return d;const c=new Map;for(const m of d){const p=an(m,a),f=on(m[t]);c.has(p)||c.set(p,new Map),c.get(p).set(f,m)}c.size===0&&a.length===0&&c.set("__all__",new Map);const l=[];for(const[m,p]of c){const f=p.size>0?p.values().next().value:null;for(const h of u){const g=h.toISOString(),y=p.get(g);if(y)l.push(y);else{const b={[t]:g};if(f)for(const w of a)b[w]=f[w];for(const w of r)b[w]=i;l.push(b)}}}return l}function ln(d){if(!d)return null;if(Array.isArray(d)){if(d.length<2)return null;const t=new Date(d[0]),n=new Date(d[1]);return isNaN(t.getTime())||isNaN(n.getTime())?null:[t,n]}const e=new Date(d);return isNaN(e.getTime())?null:[e,e]}function Ve(d,e,t){if(!e.timeDimensions||e.timeDimensions.length===0)return d;const n=e.timeDimensions.filter(u=>{const c=u.fillMissingDates!==!1,l=u.granularity&&u.dateRange;return c&&l});if(n.length===0)return d;const s=e.fillMissingDatesValue===void 0?0:e.fillMissingDatesValue,i=new Set(e.timeDimensions.map(u=>u.dimension)),r=(e.dimensions||[]).filter(u=>!i.has(u));let a=d;for(const u of n){const c=ln(u.dateRange);if(!c)continue;const l={timeDimensionKey:u.dimension,granularity:u.granularity,dateRange:c,fillValue:s,measures:t,dimensions:r};a=un(a,l)}return a}class cn{dateTimeBuilder;constructor(e){this.dateTimeBuilder=new ne(e)}hasComparison(e){return e.timeDimensions?.some(t=>t.compareDateRange&&t.compareDateRange.length>=2)??!1}getComparisonTimeDimension(e){return e.timeDimensions?.find(t=>t.compareDateRange&&t.compareDateRange.length>=2)}normalizePeriods(e){const t=[];for(let n=0;n<e.length;n++){const s=e[n];let i,r,a;if(typeof s=="string"){const u=this.dateTimeBuilder.parseRelativeDateRange(s);if(u)i=u.start,r=u.end,a=s;else{const c=new Date(s);if(!isNaN(c.getTime()))i=new Date(c),i.setUTCHours(0,0,0,0),r=new Date(c),r.setUTCHours(23,59,59,999),a=s;else continue}}else{if(i=new Date(s[0]),r=new Date(s[1]),isNaN(i.getTime())||isNaN(r.getTime()))continue;/^\d{4}-\d{2}-\d{2}$/.test(s[1])&&r.setUTCHours(23,59,59,999),a=`${s[0]} - ${s[1]}`}t.push({start:i,end:r,label:a,index:n})}return t}createPeriodQuery(e,t){return{...e,timeDimensions:e.timeDimensions?.map(n=>n.compareDateRange?{...n,dateRange:[t.start.toISOString(),t.end.toISOString()],compareDateRange:void 0}:n)}}calculatePeriodDayIndex(e,t,n){const s=typeof e=="string"?new Date(e):e,i=t.getTime(),r=s.getTime();switch(n){case"second":return Math.floor((r-i)/1e3);case"minute":return Math.floor((r-i)/(1e3*60));case"hour":return Math.floor((r-i)/(1e3*60*60));case"day":return Math.floor((r-i)/(1e3*60*60*24));case"week":return Math.floor((r-i)/(1e3*60*60*24*7));case"month":{const a=t.getUTCFullYear(),u=t.getUTCMonth(),c=s.getUTCFullYear(),l=s.getUTCMonth();return(c-a)*12+(l-u)}case"quarter":{const a=t.getUTCFullYear(),u=Math.floor(t.getUTCMonth()/3),c=s.getUTCFullYear(),l=Math.floor(s.getUTCMonth()/3);return(c-a)*4+(l-u)}case"year":return s.getUTCFullYear()-t.getUTCFullYear();default:return Math.floor((r-i)/(1e3*60*60*24))}}addPeriodMetadata(e,t,n,s){return e.map(i=>{const r=i[n];let a=0;if(r){const u=typeof r=="string"?new Date(r):r instanceof Date?r:null;u&&!isNaN(u.getTime())&&(a=this.calculatePeriodDayIndex(u,t.start,s))}return{...i,__period:t.label,__periodIndex:t.index,__periodDayIndex:a}})}mergeComparisonResults(e,t,n){const s=[];let i={measures:{},dimensions:{},segments:{},timeDimensions:{}};const r=e.map(u=>u.period);for(const{result:u,period:c}of e){const l=this.addPeriodMetadata(u.data,c,t.dimension,n);s.push(...l),i={measures:{...i.measures,...u.annotation.measures},dimensions:{...i.dimensions,...u.annotation.dimensions},segments:{...i.segments,...u.annotation.segments},timeDimensions:{...i.timeDimensions,...u.annotation.timeDimensions}}}const a={ranges:r.map(u=>[u.start.toISOString().split("T")[0],u.end.toISOString().split("T")[0]]),labels:r.map(u=>u.label),timeDimension:t.dimension,granularity:n};return{data:s,annotation:{...i,periods:a}}}sortComparisonResults(e,t){return[...e].sort((n,s)=>{const i=n.__periodIndex-s.__periodIndex;if(i!==0)return i;const r=n[t],a=s[t];return typeof r=="string"&&typeof a=="string"?new Date(r).getTime()-new Date(a).getTime():0})}}class dn{constructor(e){this.databaseAdapter=e,this.dateTimeBuilder=new ne(e),this.filterBuilder=new he(e,this.dateTimeBuilder)}filterBuilder;dateTimeBuilder;hasFunnel(e){return e.funnel!==void 0&&e.funnel.steps.length>=2}validateConfig(e,t){const n=[];if(e.steps.length<2&&n.push("Funnel must have at least 2 steps"),typeof e.bindingKey=="string"){const[s,i]=e.bindingKey.split(".");if(!s||!i)n.push(`Invalid binding key format: ${e.bindingKey}. Expected 'CubeName.dimensionName'`);else{const r=t.get(s);r?r.dimensions?.[i]||n.push(`Binding key dimension not found: ${i} in cube ${s}`):n.push(`Binding key cube not found: ${s}`)}}else if(Array.isArray(e.bindingKey))for(const s of e.bindingKey){const i=t.get(s.cube);if(!i)n.push(`Binding key mapping cube not found: ${s.cube}`);else{const[,r]=s.dimension.split(".");i.dimensions?.[r]||n.push(`Binding key dimension not found: ${r} in cube ${s.cube}`)}}if(typeof e.timeDimension=="string"){const[s,i]=e.timeDimension.split(".");if(!s||!i)n.push(`Invalid time dimension format: ${e.timeDimension}. Expected 'CubeName.dimensionName'`);else{const r=t.get(s);r?r.dimensions?.[i]||n.push(`Time dimension not found: ${i} in cube ${s}`):n.push(`Time dimension cube not found: ${s}`)}}for(let s=0;s<e.steps.length;s++){const i=e.steps[s];if(i.name||n.push(`Step ${s} must have a name`),"cube"in i&&i.cube&&(t.get(i.cube)||n.push(`Step ${s} cube not found: ${i.cube}`)),i.filter){let r;"cube"in i&&i.cube?r=i.cube:typeof e.bindingKey=="string"&&([r]=e.bindingKey.split("."));const a=r?new oe(t):null,u=Array.isArray(i.filter)?i.filter:[i.filter];for(const c of u)if("member"in c){const[l,m]=c.member.split("."),p=t.get(l);if(!p)n.push(`Step ${s} filter cube not found: ${l}`);else if(p.dimensions?.[m]||(p.measures?.[m]?n.push(`Step ${s} filter '${l}.${m}' is a measure. Funnel step filters only support dimensions, not measures.`):n.push(`Step ${s} filter member not found: ${m} in cube ${l}`)),r&&l!==r&&a){const f=a.findPath(r,l);(!f||f.length===0)&&n.push(`Step ${s} filter '${l}.${m}' requires a join from '${r}' but no join path was found. Define a join relationship between these cubes.`)}}}i.timeToConvert&&s>0&&(/^P(?:\d+Y)?(?:\d+M)?(?:\d+D)?(?:T(?:\d+H)?(?:\d+M)?(?:\d+(?:\.\d+)?S)?)?$/.test(i.timeToConvert)||n.push(`Step ${s} timeToConvert must be ISO 8601 duration format: ${i.timeToConvert}`))}return{isValid:n.length===0,errors:n}}buildFunnelQuery(e,t,n){const s=this.resolveSteps(e,t,n),i=[];for(let c=0;c<s.length;c++){const l=c>0?i[c-1]:void 0;i.push(this.buildStepCTE(s[c],n,l))}const r=this.buildFunnelResultsCTE(i,s,e,n),a=this.buildAggregationCTE(r,i,s,e,n),u=[...i,r,a];return n.db.with(...u).select().from(a)}transformResult(e,t){if(!e||e.length===0)return[];const n=e[0],s=[],i=Number(n.step_0_count)||0;for(let r=0;r<t.steps.length;r++){const a=t.steps[r],u=Number(n[`step_${r}_count`])||0,c=r>0&&Number(n[`step_${r-1}_count`])||0,l={step:a.name,stepIndex:r,count:u,conversionRate:r===0?null:c>0?u/c:0,cumulativeConversionRate:i>0?u/i:0};t.includeTimeMetrics&&r>0&&(l.avgSecondsToConvert=n[`step_${r}_avg_seconds`]!==null?Number(n[`step_${r}_avg_seconds`]):null,l.minSecondsToConvert=n[`step_${r}_min_seconds`]!==null?Number(n[`step_${r}_min_seconds`]):null,l.maxSecondsToConvert=n[`step_${r}_max_seconds`]!==null?Number(n[`step_${r}_max_seconds`]):null,n[`step_${r}_median_seconds`]!==void 0&&(l.medianSecondsToConvert=n[`step_${r}_median_seconds`]!==null?Number(n[`step_${r}_median_seconds`]):null),n[`step_${r}_p90_seconds`]!==void 0&&(l.p90SecondsToConvert=n[`step_${r}_p90_seconds`]!==null?Number(n[`step_${r}_p90_seconds`]):null)),s.push(l)}return s}extractFilterCubeNames(e){const t=new Set;if(!e.filter)return t;const n=Array.isArray(e.filter)?e.filter:[e.filter],s=i=>{if("and"in i&&i.and)for(const r of i.and)s(r);else if("or"in i&&i.or)for(const r of i.or)s(r);else if("type"in i&&"filters"in i){const r=i;for(const a of r.filters||[])s(a)}else if("member"in i){const[r]=i.member.split(".");t.add(r)}};for(const i of n)s(i);return t}resolveSteps(e,t,n){const s=new oe(t);return e.steps.map((i,r)=>{const a=this.resolveCubeForStep(i,e,t),u=this.resolveBindingKey(e,a,n),c=this.resolveTimeDimension(e,a,n),l=this.buildStepFilters(i,a,t,n),m=this.extractFilterCubeNames(i),p=[];for(const f of m)if(f!==a.name){const h=t.get(f);if(h){const g=s.findPath(a.name,f);g&&g.length>0&&p.push({cube:h,joinPath:g})}}return{name:i.name,index:r,cube:a,bindingKeyExpr:u,timeExpr:c,filterConditions:l,timeToConvert:i.timeToConvert,joinedCubes:p}})}resolveCubeForStep(e,t,n){if("cube"in e&&e.cube){const s=n.get(e.cube);if(!s)throw new Error(`Cube not found for step: ${e.cube}`);return s}if(typeof t.bindingKey=="string"){const[s]=t.bindingKey.split("."),i=n.get(s);if(!i)throw new Error(`Cube not found for binding key: ${t.bindingKey}`);return i}throw new Error("Cannot resolve cube for step - multi-cube funnel requires cube specification in each step")}resolveBindingKey(e,t,n){if(typeof e.bindingKey=="string"){const[,a]=e.bindingKey.split("."),u=t.dimensions?.[a];if(!u)throw new Error(`Binding key dimension not found: ${e.bindingKey}`);return v(u.sql,n)}const s=e.bindingKey.find(a=>a.cube===t.name);if(!s)throw new Error(`No binding key mapping found for cube: ${t.name}`);const[,i]=s.dimension.split("."),r=t.dimensions?.[i];if(!r)throw new Error(`Binding key dimension not found: ${s.dimension}`);return v(r.sql,n)}resolveTimeDimension(e,t,n){if(typeof e.timeDimension=="string"){const[,a]=e.timeDimension.split("."),u=t.dimensions?.[a];if(!u)throw new Error(`Time dimension not found: ${e.timeDimension}`);return v(u.sql,n)}const s=e.timeDimension.find(a=>a.cube===t.name);if(!s)throw new Error(`No time dimension mapping found for cube: ${t.name}`);const[,i]=s.dimension.split("."),r=t.dimensions?.[i];if(!r)throw new Error(`Time dimension not found: ${s.dimension}`);return v(r.sql,n)}buildStepFilters(e,t,n,s){if(!e.filter)return[];const i=Array.isArray(e.filter)?e.filter:[e.filter],r=[];for(const a of i){const u=this.buildFilterCondition(a,t,n,s);u&&r.push(u)}return r}buildFilterCondition(e,t,n,s){const i="and"in e||"or"in e,r="type"in e&&"filters"in e&&(e.type==="and"||e.type==="or");if(i||r){const g=[];let y;if(r){const b=e;y=b.type==="and";for(const w of b.filters||[]){const _=this.buildFilterCondition(w,t,n,s);_&&g.push(_)}}else{const b=e;y="and"in b&&!!b.and;const w=b.and||b.or||[];for(const _ of w){const $=this.buildFilterCondition(_,t,n,s);$&&g.push($)}}return g.length===0?null:g.length===1?g[0]:y?A(...g):o`(${o.join(g,o` OR `)})`}const a=e,[u,c]=a.member.split("."),l=a.dateRange!==void 0;if(a.operator!=="set"&&a.operator!=="notSet"&&!l&&(!a.values||a.values.length===0||a.values[0]===void 0||a.values[0]===""))return null;const p=n.get(u);if(!p)return null;if(u!==t.name){const y=new oe(n).findPath(t.name,u);if(!y||y.length===0)return console.warn(`Funnel filter: Cannot filter by '${u}.${c}' in step using '${t.name}'. No join path found. Filter will be skipped.`),null}const f=p.dimensions?.[c];if(!f)return null;const h=v(f.sql,s);return this.filterBuilder.buildFilterCondition(h,a.operator,a.values||[],f,a.dateRange)}buildStepCTE(e,t,n){return e.index===0?this.buildFirstStepCTE(e,t):this.buildSubsequentStepCTE(e,t,n)}buildFirstStepCTE(e,t){const n=`step_${e.index}`,s=e.cube.sql(t),i=[];s.where&&i.push(s.where),i.push(...e.filterConditions);let r=t.db.select({binding_key:o`${e.bindingKeyExpr}`.as("binding_key"),step_time:o`MIN(${e.timeExpr})`.as("step_time")}).from(s.from);if(r=this.addCrossJoinsToQuery(r,e,t,i),i.length>0){const a=i.length===1?i[0]:A(...i);r=r.where(a)}return r=r.groupBy(e.bindingKeyExpr),t.db.$with(n).as(r)}buildSubsequentStepCTE(e,t,n){const s=`step_${e.index}`,i=`step_${e.index-1}`,r=e.cube.sql(t),a=[];r.where&&a.push(r.where),a.push(...e.filterConditions);const u=o`${o.identifier(i)}.step_time`;let c=o`${e.timeExpr} > ${u}`;if(e.timeToConvert){const m=this.databaseAdapter.buildDateAddInterval(u,e.timeToConvert);c=o`${c} AND ${e.timeExpr} <= ${m}`}a.push(c);let l=t.db.select({binding_key:o`${e.bindingKeyExpr}`.as("binding_key"),step_time:o`MIN(${e.timeExpr})`.as("step_time")}).from(r.from).innerJoin(n,o`${e.bindingKeyExpr} = ${o.identifier(i)}.binding_key`);if(l=this.addCrossJoinsToQuery(l,e,t,a),a.length>0){const m=a.length===1?a[0]:A(...a);l=l.where(m)}return l=l.groupBy(e.bindingKeyExpr),t.db.$with(s).as(l)}addCrossJoinsToQuery(e,t,n,s){if(t.joinedCubes.length===0)return e;for(const i of t.joinedCubes)for(const r of i.joinPath){const a=r.joinDef,u=[];for(const p of a.on)p.as?u.push(p.as(p.source,p.target)):u.push(Q(p.source,p.target));const c=u.length===1?u[0]:A(...u),m=i.cube.sql(n);e=e.leftJoin(m.from,c),m.where&&s.push(m.where)}return e}buildFunnelResultsCTE(e,t,n,s){const i={binding_key:o`s0.binding_key`,step_0_time:o`s0.step_time`};for(let l=1;l<t.length;l++)i[`step_${l}_time`]=o`s${o.raw(String(l))}.step_time`;let r=o`${o.identifier("step_0")} s0`;for(let l=1;l<t.length;l++)r=o`${r}
61
+ LEFT JOIN ${o.identifier(`step_${l}`)} s${o.raw(String(l))} ON s0.binding_key = s${o.raw(String(l))}.binding_key`;const a=Object.entries(i).map(([l,m])=>o`${m} AS ${o.identifier(l)}`),u=o`SELECT ${o.join(a,o`, `)} FROM ${r}`,c={binding_key:o`binding_key`.as("binding_key"),step_0_time:o`step_0_time`.as("step_0_time")};for(let l=1;l<t.length;l++)c[`step_${l}_time`]=o`${o.identifier(`step_${l}_time`)}`.as(`step_${l}_time`);return s.db.$with("funnel_joined").as(s.db.select(c).from(o`(${u}) as _inner`))}buildAggregationCTE(e,t,n,s,i){const r={};r.step_0_count=o`COUNT(*)`.as("step_0_count");for(let u=1;u<n.length;u++)r[`step_${u}_count`]=o`COUNT(${o.identifier(`step_${u}_time`)})`.as(`step_${u}_count`);if(s.includeTimeMetrics)for(let u=1;u<n.length;u++){const c=o.identifier(`step_${u}_time`),l=o.identifier(`step_${u-1}_time`),m=this.databaseAdapter.buildTimeDifferenceSeconds(o`${c}`,o`${l}`),p=o`${c} IS NOT NULL`;r[`step_${u}_avg_seconds`]=this.databaseAdapter.buildConditionalAggregation("avg",m,p).as(`step_${u}_avg_seconds`),r[`step_${u}_min_seconds`]=this.databaseAdapter.buildConditionalAggregation("min",m,p).as(`step_${u}_min_seconds`),r[`step_${u}_max_seconds`]=this.databaseAdapter.buildConditionalAggregation("max",m,p).as(`step_${u}_max_seconds`);const f=this.databaseAdapter.getCapabilities(),h=this.databaseAdapter.buildPercentile(m,50);h&&f.supportsPercentileSubqueries&&(r[`step_${u}_median_seconds`]=o`(SELECT ${h} FROM ${o.identifier("funnel_joined")} WHERE ${c} IS NOT NULL)`.as(`step_${u}_median_seconds`));const g=this.databaseAdapter.buildPercentile(m,90);g&&f.supportsPercentileSubqueries&&(r[`step_${u}_p90_seconds`]=o`(SELECT ${g} FROM ${o.identifier("funnel_joined")} WHERE ${c} IS NOT NULL)`.as(`step_${u}_p90_seconds`))}const a=i.db.select(r).from(e);return i.db.$with("funnel_metrics").as(a)}}class mn{filterBuilder;dateTimeBuilder;databaseAdapter;constructor(e){this.databaseAdapter=e,this.dateTimeBuilder=new ne(e),this.filterBuilder=new he(e,this.dateTimeBuilder)}hasFlow(e){return e.flow!==void 0&&e.flow.startingStep!==void 0&&e.flow.eventDimension!==void 0}validateConfig(e,t){const n=[],s=[],i=this.databaseAdapter.getEngineType(),r=this.databaseAdapter.supportsLateralJoins();if(i==="sqlite")return n.push("Flow queries are not supported on SQLite. Use PostgreSQL or MySQL for flow analysis."),{isValid:!1,errors:n,warnings:s};if(typeof e.bindingKey=="string"){const[a,u]=e.bindingKey.split(".");if(!a||!u)n.push(`Invalid binding key format: ${e.bindingKey}. Expected 'CubeName.dimensionName'`);else{const c=t.get(a);c?c.dimensions?.[u]||n.push(`Binding key dimension not found: ${u} in cube ${a}`):n.push(`Binding key cube not found: ${a}`)}}else if(Array.isArray(e.bindingKey))for(const a of e.bindingKey){const u=t.get(a.cube);if(!u)n.push(`Binding key mapping cube not found: ${a.cube}`);else{const[,c]=a.dimension.split(".");u.dimensions?.[c]||n.push(`Binding key dimension not found: ${c} in cube ${a.cube}`)}}if(typeof e.timeDimension=="string"){const[a,u]=e.timeDimension.split(".");if(!a||!u)n.push(`Invalid time dimension format: ${e.timeDimension}. Expected 'CubeName.dimensionName'`);else{const c=t.get(a);c?c.dimensions?.[u]||n.push(`Time dimension not found: ${u} in cube ${a}`):n.push(`Time dimension cube not found: ${a}`)}}if(e.eventDimension){const[a,u]=e.eventDimension.split(".");if(!a||!u)n.push(`Invalid event dimension format: ${e.eventDimension}. Expected 'CubeName.dimensionName'`);else{const c=t.get(a);c?c.dimensions?.[u]||n.push(`Event dimension not found: ${u} in cube ${a}`):n.push(`Event dimension cube not found: ${a}`)}}else n.push("Event dimension is required for flow analysis");return e.startingStep?(e.startingStep.filter||n.push("Starting step must have at least one filter"),e.startingStep.name||s.push("Starting step has no name - using default")):n.push("Starting step is required for flow analysis"),(e.stepsBefore<0||e.stepsBefore>5)&&n.push(`stepsBefore must be between 0 and 5, got: ${e.stepsBefore}`),(e.stepsAfter<0||e.stepsAfter>5)&&n.push(`stepsAfter must be between 0 and 5, got: ${e.stepsAfter}`),(e.stepsBefore>=4||e.stepsAfter>=4)&&s.push("High step depth (4-5) may impact query performance on large datasets"),e.joinStrategy&&!["auto","lateral","window"].includes(e.joinStrategy)?n.push(`Invalid joinStrategy: ${e.joinStrategy}`):e.joinStrategy==="lateral"&&!r&&n.push("Lateral joins are not supported on this database"),{isValid:n.length===0,errors:n,warnings:s}}buildFlowQuery(e,t,n){if(this.databaseAdapter.getEngineType()==="sqlite")throw new Error("Flow queries are not supported on SQLite. Use PostgreSQL or MySQL for flow analysis.");const i=this.databaseAdapter.supportsLateralJoins(),r=e.joinStrategy??"auto",a=r==="lateral"||r==="auto"&&i;if(r==="lateral"&&!i)throw new Error("Lateral joins are not supported on this database");const u={...e,stepsBefore:e.outputMode==="sunburst"?0:e.stepsBefore},c=this.resolveFlowConfig(u,t,n),l=[],m=this.buildStartingEntitiesCTE(u,c,n);l.push(m);const p=a?this.buildBeforeCTEsLateral(u,c,n):this.buildBeforeCTEsWindow(u,c,n);l.push(...p);const f=a?this.buildAfterCTEsLateral(u,c,n):this.buildAfterCTEsWindow(u,c,n);l.push(...f);const h=this.buildNodesAggregationCTE(u,n);l.push(h);const g=this.buildLinksAggregationCTE(u,n);l.push(g);const y=this.buildFinalResultCTE(n);return l.push(y),n.db.with(...l).select().from(y)}transformResult(e){if(!e||e.length===0)return{nodes:[],links:[]};const t=[],n=[];for(const s of e){const i=s.record_type;i==="node"?t.push({id:String(s.id),name:String(s.name),layer:Number(s.layer),value:Number(s.value)}):i==="link"&&n.push({source:String(s.source_id),target:String(s.target_id),value:Number(s.value)})}return t.sort((s,i)=>s.layer-i.layer),{nodes:t,links:n}}resolveFlowConfig(e,t,n){const s=this.resolveCube(e,t),i=s.sql(n);return{cube:s,cubeBase:i,bindingKeyExpr:this.resolveBindingKey(e,s,n),timeExpr:this.resolveTimeDimension(e,s,n),eventExpr:this.resolveEventDimension(e,s,n),startingStepFilters:this.buildStartingStepFilters(e,s,n)}}resolveCube(e,t){let n;if(typeof e.bindingKey=="string")[n]=e.bindingKey.split(".");else if(Array.isArray(e.bindingKey)&&e.bindingKey.length>0)n=e.bindingKey[0].cube;else throw new Error("Cannot resolve cube for flow query");const s=t.get(n);if(!s)throw new Error(`Cube not found: ${n}`);return s}resolveBindingKey(e,t,n){if(typeof e.bindingKey=="string"){const[,a]=e.bindingKey.split("."),u=t.dimensions?.[a];if(!u)throw new Error(`Binding key dimension not found: ${e.bindingKey}`);return v(u.sql,n)}const s=e.bindingKey.find(a=>a.cube===t.name);if(!s)throw new Error(`No binding key mapping found for cube: ${t.name}`);const[,i]=s.dimension.split("."),r=t.dimensions?.[i];if(!r)throw new Error(`Binding key dimension not found: ${s.dimension}`);return v(r.sql,n)}resolveTimeDimension(e,t,n){if(typeof e.timeDimension=="string"){const[,a]=e.timeDimension.split("."),u=t.dimensions?.[a];if(!u)throw new Error(`Time dimension not found: ${e.timeDimension}`);return v(u.sql,n)}const s=e.timeDimension.find(a=>a.cube===t.name);if(!s)throw new Error(`No time dimension mapping found for cube: ${t.name}`);const[,i]=s.dimension.split("."),r=t.dimensions?.[i];if(!r)throw new Error(`Time dimension not found: ${s.dimension}`);return v(r.sql,n)}resolveEventDimension(e,t,n){const[,s]=e.eventDimension.split("."),i=t.dimensions?.[s];if(!i)throw new Error(`Event dimension not found: ${e.eventDimension}`);return v(i.sql,n)}buildStartingStepFilters(e,t,n){if(!e.startingStep.filter)return[];const s=Array.isArray(e.startingStep.filter)?e.startingStep.filter:[e.startingStep.filter],i=[];for(const r of s){const a=this.buildFilterCondition(r,t,n);a&&i.push(a)}return i}buildFilterCondition(e,t,n){if("and"in e||"or"in e){const u=e,c=[],l=u.and||u.or||[];for(const m of l){const p=this.buildFilterCondition(m,t,n);p&&c.push(p)}return c.length===0?null:c.length===1?c[0]:"and"in e?A(...c):o`(${o.join(c,o` OR `)})`}if("type"in e&&"filters"in e){const u=e,c=[];for(const l of u.filters||[]){const m=this.buildFilterCondition(l,t,n);m&&c.push(m)}return c.length===0?null:c.length===1?c[0]:u.type==="and"?A(...c):o`(${o.join(c,o` OR `)})`}const s=e,[,i]=s.member.split("."),r=t.dimensions?.[i];if(!r)return null;const a=v(r.sql,n);return this.filterBuilder.buildFilterCondition(a,s.operator,s.values||[],r,s.dateRange)}buildStartingEntitiesCTE(e,t,n){const{cubeBase:s,bindingKeyExpr:i,timeExpr:r,eventExpr:a,startingStepFilters:u}=t,c=[];s.where&&c.push(s.where),c.push(...u);let l=n.db.select({binding_key:o`${i}`.as("binding_key"),start_time:o`MIN(${r})`.as("start_time"),event_type:o`${a}`.as("event_type"),event_path:o`${a}`.as("event_path")}).from(s.from);if(c.length>0){const m=c.length===1?c[0]:A(...c);l=l.where(m)}return l=l.groupBy(i,a),e.entityLimit&&(l=l.limit(e.entityLimit)),n.db.$with("starting_entities").as(l)}buildBeforeCTEsLateral(e,t,n){const{cubeBase:s,bindingKeyExpr:i,timeExpr:r,eventExpr:a}=t,u=[],c=e.outputMode==="sunburst";for(let l=1;l<=e.stepsBefore;l++){const m=l===1?"starting_entities":`before_step_${l-1}`,p=l===1?"start_time":"step_time",f=`before_step_${l}`,h=[];s.where&&h.push(s.where),h.push(o`${i} = ${o.identifier(m)}.binding_key`,o`${r} < ${o.identifier(m)}.${o.identifier(p)}`);const g=h.length===1?h[0]:A(...h),y=c?o`${a} || ${"→"} || ${o.identifier(m)}.event_path`:o`${a}`,b=n.db.select({binding_key:o`${i}`.as("binding_key"),step_time:o`${r}`.as("step_time"),event_type:o`${a}`.as("event_type"),event_path:y.as("event_path")}).from(s.from).where(g).orderBy(o`${r} DESC`).limit(1),w=n.db.$with(f).as(n.db.select({binding_key:o`e.binding_key`.as("binding_key"),step_time:o`e.step_time`.as("step_time"),event_type:o`e.event_type`.as("event_type"),event_path:o`e.event_path`.as("event_path")}).from(o`${o.identifier(m)}`).crossJoinLateral(b.as("e")));u.push(w)}return u}buildAfterCTEsLateral(e,t,n){const{cubeBase:s,bindingKeyExpr:i,timeExpr:r,eventExpr:a}=t,u=[],c=e.outputMode==="sunburst";for(let l=1;l<=e.stepsAfter;l++){const m=l===1?"starting_entities":`after_step_${l-1}`,p=l===1?"start_time":"step_time",f=`after_step_${l}`,h=[];s.where&&h.push(s.where),h.push(o`${i} = ${o.identifier(m)}.binding_key`,o`${r} > ${o.identifier(m)}.${o.identifier(p)}`);const g=h.length===1?h[0]:A(...h),y=c?o`${o.identifier(m)}.event_path || ${"→"} || ${a}`:o`${a}`,b=n.db.select({binding_key:o`${i}`.as("binding_key"),step_time:o`${r}`.as("step_time"),event_type:o`${a}`.as("event_type"),event_path:y.as("event_path")}).from(s.from).where(g).orderBy(o`${r} ASC`).limit(1),w=n.db.$with(f).as(n.db.select({binding_key:o`e.binding_key`.as("binding_key"),step_time:o`e.step_time`.as("step_time"),event_type:o`e.event_type`.as("event_type"),event_path:o`e.event_path`.as("event_path")}).from(o`${o.identifier(m)}`).crossJoinLateral(b.as("e")));u.push(w)}return u}buildBeforeCTEsWindow(e,t,n){const{cubeBase:s,bindingKeyExpr:i,timeExpr:r,eventExpr:a}=t,u=[],c=e.outputMode==="sunburst";for(let l=1;l<=e.stepsBefore;l++){const m=l===1?"starting_entities":`before_step_${l-1}`,p=l===1?"start_time":"step_time",f=`before_step_${l}`,h=[];s.where&&h.push(s.where),h.push(o`${r} < ${o.identifier(m)}.${o.identifier(p)}`);const g=h.length===1?h[0]:A(...h),y=c?o`${a} || ${"→"} || ${o.identifier(m)}.event_path`:o`${a}`,b=n.db.select({binding_key:o`${i}`.as("binding_key"),step_time:o`${r}`.as("step_time"),event_type:o`${a}`.as("event_type"),event_path:y.as("event_path"),rn:o`ROW_NUMBER() OVER (PARTITION BY ${i} ORDER BY ${r} DESC)`.as("rn")}).from(s.from).innerJoin(o`${o.identifier(m)}`,o`${i} = ${o.identifier(m)}.binding_key`).where(g),w=n.db.select({binding_key:o`binding_key`.as("binding_key"),step_time:o`step_time`.as("step_time"),event_type:o`event_type`.as("event_type"),event_path:o`event_path`.as("event_path")}).from(b.as("ranked")).where(o`rn = 1`);u.push(n.db.$with(f).as(w))}return u}buildAfterCTEsWindow(e,t,n){const{cubeBase:s,bindingKeyExpr:i,timeExpr:r,eventExpr:a}=t,u=[],c=e.outputMode==="sunburst";for(let l=1;l<=e.stepsAfter;l++){const m=l===1?"starting_entities":`after_step_${l-1}`,p=l===1?"start_time":"step_time",f=`after_step_${l}`,h=[];s.where&&h.push(s.where),h.push(o`${r} > ${o.identifier(m)}.${o.identifier(p)}`);const g=h.length===1?h[0]:A(...h),y=c?o`${o.identifier(m)}.event_path || ${"→"} || ${a}`:o`${a}`,b=n.db.select({binding_key:o`${i}`.as("binding_key"),step_time:o`${r}`.as("step_time"),event_type:o`${a}`.as("event_type"),event_path:y.as("event_path"),rn:o`ROW_NUMBER() OVER (PARTITION BY ${i} ORDER BY ${r} ASC)`.as("rn")}).from(s.from).innerJoin(o`${o.identifier(m)}`,o`${i} = ${o.identifier(m)}.binding_key`).where(g),w=n.db.select({binding_key:o`binding_key`.as("binding_key"),step_time:o`step_time`.as("step_time"),event_type:o`event_type`.as("event_type"),event_path:o`event_path`.as("event_path")}).from(b.as("ranked")).where(o`rn = 1`);u.push(n.db.$with(f).as(w))}return u}buildNodesAggregationCTE(e,t){const n=[],s=e.outputMode==="sunburst";for(let a=e.stepsBefore;a>=1;a--){const u=-a,c=`before_step_${a}`;s?n.push(o`
62
62
  SELECT
63
- ${r.raw(`'before_${a}_'`)} || event_path AS node_id,
63
+ ${o.raw(`'before_${a}_'`)} || event_path AS node_id,
64
64
  event_type AS name,
65
- ${r.raw(String(u))} AS layer,
65
+ ${o.raw(String(u))} AS layer,
66
66
  COUNT(*) AS value
67
- FROM ${r.identifier(c)}
67
+ FROM ${o.identifier(c)}
68
68
  GROUP BY event_path, event_type
69
- `):n.push(r`
69
+ `):n.push(o`
70
70
  SELECT
71
- ${r.raw(`'before_${a}_'`)} || event_type AS node_id,
71
+ ${o.raw(`'before_${a}_'`)} || event_type AS node_id,
72
72
  event_type AS name,
73
- ${r.raw(String(u))} AS layer,
73
+ ${o.raw(String(u))} AS layer,
74
74
  COUNT(*) AS value
75
- FROM ${r.identifier(c)}
75
+ FROM ${o.identifier(c)}
76
76
  GROUP BY event_type
77
- `)}n.push(r`
77
+ `)}n.push(o`
78
78
  SELECT
79
- ${r.raw("'start_'")} || event_type AS node_id,
79
+ ${o.raw("'start_'")} || event_type AS node_id,
80
80
  event_type AS name,
81
81
  0 AS layer,
82
82
  COUNT(*) AS value
83
83
  FROM starting_entities
84
84
  GROUP BY event_type
85
- `);for(let a=1;a<=e.stepsAfter;a++){const u=a,c=`after_step_${a}`;s?n.push(r`
85
+ `);for(let a=1;a<=e.stepsAfter;a++){const u=a,c=`after_step_${a}`;s?n.push(o`
86
86
  SELECT
87
- ${r.raw(`'after_${a}_'`)} || event_path AS node_id,
87
+ ${o.raw(`'after_${a}_'`)} || event_path AS node_id,
88
88
  event_type AS name,
89
- ${r.raw(String(u))} AS layer,
89
+ ${o.raw(String(u))} AS layer,
90
90
  COUNT(*) AS value
91
- FROM ${r.identifier(c)}
91
+ FROM ${o.identifier(c)}
92
92
  GROUP BY event_path, event_type
93
- `):n.push(r`
93
+ `):n.push(o`
94
94
  SELECT
95
- ${r.raw(`'after_${a}_'`)} || event_type AS node_id,
95
+ ${o.raw(`'after_${a}_'`)} || event_type AS node_id,
96
96
  event_type AS name,
97
- ${r.raw(String(u))} AS layer,
97
+ ${o.raw(String(u))} AS layer,
98
98
  COUNT(*) AS value
99
- FROM ${r.identifier(c)}
99
+ FROM ${o.identifier(c)}
100
100
  GROUP BY event_type
101
- `)}const i=r.join(n,r` UNION ALL `),o=t.db.select({node_id:r`node_id`.as("node_id"),name:r`name`.as("name"),layer:r`layer`.as("layer"),value:r`value`.as("value")}).from(r`(${i}) AS nodes_union`);return t.db.$with("nodes_agg").as(o)}buildLinksAggregationCTE(e,t){const n=[],s=e.outputMode==="sunburst";for(let a=e.stepsBefore;a>=2;a--){const u=`before_step_${a}`,c=`before_step_${a-1}`;s?n.push(r`
101
+ `)}const i=o.join(n,o` UNION ALL `),r=t.db.select({node_id:o`node_id`.as("node_id"),name:o`name`.as("name"),layer:o`layer`.as("layer"),value:o`value`.as("value")}).from(o`(${i}) AS nodes_union`);return t.db.$with("nodes_agg").as(r)}buildLinksAggregationCTE(e,t){const n=[],s=e.outputMode==="sunburst";for(let a=e.stepsBefore;a>=2;a--){const u=`before_step_${a}`,c=`before_step_${a-1}`;s?n.push(o`
102
102
  SELECT
103
- ${r.raw(`'before_${a}_'`)} || f.event_path AS source_id,
104
- ${r.raw(`'before_${a-1}_'`)} || t.event_path AS target_id,
103
+ ${o.raw(`'before_${a}_'`)} || f.event_path AS source_id,
104
+ ${o.raw(`'before_${a-1}_'`)} || t.event_path AS target_id,
105
105
  COUNT(*) AS value
106
- FROM ${r.identifier(u)} f
107
- INNER JOIN ${r.identifier(c)} t ON f.binding_key = t.binding_key
106
+ FROM ${o.identifier(u)} f
107
+ INNER JOIN ${o.identifier(c)} t ON f.binding_key = t.binding_key
108
108
  GROUP BY f.event_path, t.event_path
109
- `):n.push(r`
109
+ `):n.push(o`
110
110
  SELECT
111
- ${r.raw(`'before_${a}_'`)} || f.event_type AS source_id,
112
- ${r.raw(`'before_${a-1}_'`)} || t.event_type AS target_id,
111
+ ${o.raw(`'before_${a}_'`)} || f.event_type AS source_id,
112
+ ${o.raw(`'before_${a-1}_'`)} || t.event_type AS target_id,
113
113
  COUNT(*) AS value
114
- FROM ${r.identifier(u)} f
115
- INNER JOIN ${r.identifier(c)} t ON f.binding_key = t.binding_key
114
+ FROM ${o.identifier(u)} f
115
+ INNER JOIN ${o.identifier(c)} t ON f.binding_key = t.binding_key
116
116
  GROUP BY f.event_type, t.event_type
117
- `)}e.stepsBefore>=1&&(s?n.push(r`
117
+ `)}e.stepsBefore>=1&&(s?n.push(o`
118
118
  SELECT
119
- ${r.raw("'before_1_'")} || b.event_path AS source_id,
120
- ${r.raw("'start_'")} || s.event_type AS target_id,
119
+ ${o.raw("'before_1_'")} || b.event_path AS source_id,
120
+ ${o.raw("'start_'")} || s.event_type AS target_id,
121
121
  COUNT(*) AS value
122
122
  FROM before_step_1 b
123
123
  INNER JOIN starting_entities s ON b.binding_key = s.binding_key
124
124
  GROUP BY b.event_path, s.event_type
125
- `):n.push(r`
125
+ `):n.push(o`
126
126
  SELECT
127
- ${r.raw("'before_1_'")} || b.event_type AS source_id,
128
- ${r.raw("'start_'")} || s.event_type AS target_id,
127
+ ${o.raw("'before_1_'")} || b.event_type AS source_id,
128
+ ${o.raw("'start_'")} || s.event_type AS target_id,
129
129
  COUNT(*) AS value
130
130
  FROM before_step_1 b
131
131
  INNER JOIN starting_entities s ON b.binding_key = s.binding_key
132
132
  GROUP BY b.event_type, s.event_type
133
- `)),e.stepsAfter>=1&&(s?n.push(r`
133
+ `)),e.stepsAfter>=1&&(s?n.push(o`
134
134
  SELECT
135
- ${r.raw("'start_'")} || s.event_type AS source_id,
136
- ${r.raw("'after_1_'")} || a.event_path AS target_id,
135
+ ${o.raw("'start_'")} || s.event_type AS source_id,
136
+ ${o.raw("'after_1_'")} || a.event_path AS target_id,
137
137
  COUNT(*) AS value
138
138
  FROM starting_entities s
139
139
  INNER JOIN after_step_1 a ON s.binding_key = a.binding_key
140
140
  GROUP BY s.event_type, a.event_path
141
- `):n.push(r`
141
+ `):n.push(o`
142
142
  SELECT
143
- ${r.raw("'start_'")} || s.event_type AS source_id,
144
- ${r.raw("'after_1_'")} || a.event_type AS target_id,
143
+ ${o.raw("'start_'")} || s.event_type AS source_id,
144
+ ${o.raw("'after_1_'")} || a.event_type AS target_id,
145
145
  COUNT(*) AS value
146
146
  FROM starting_entities s
147
147
  INNER JOIN after_step_1 a ON s.binding_key = a.binding_key
148
148
  GROUP BY s.event_type, a.event_type
149
- `));for(let a=1;a<e.stepsAfter;a++){const u=`after_step_${a}`,c=`after_step_${a+1}`;s?n.push(r`
149
+ `));for(let a=1;a<e.stepsAfter;a++){const u=`after_step_${a}`,c=`after_step_${a+1}`;s?n.push(o`
150
150
  SELECT
151
- ${r.raw(`'after_${a}_'`)} || f.event_path AS source_id,
152
- ${r.raw(`'after_${a+1}_'`)} || t.event_path AS target_id,
151
+ ${o.raw(`'after_${a}_'`)} || f.event_path AS source_id,
152
+ ${o.raw(`'after_${a+1}_'`)} || t.event_path AS target_id,
153
153
  COUNT(*) AS value
154
- FROM ${r.identifier(u)} f
155
- INNER JOIN ${r.identifier(c)} t ON f.binding_key = t.binding_key
154
+ FROM ${o.identifier(u)} f
155
+ INNER JOIN ${o.identifier(c)} t ON f.binding_key = t.binding_key
156
156
  GROUP BY f.event_path, t.event_path
157
- `):n.push(r`
157
+ `):n.push(o`
158
158
  SELECT
159
- ${r.raw(`'after_${a}_'`)} || f.event_type AS source_id,
160
- ${r.raw(`'after_${a+1}_'`)} || t.event_type AS target_id,
159
+ ${o.raw(`'after_${a}_'`)} || f.event_type AS source_id,
160
+ ${o.raw(`'after_${a+1}_'`)} || t.event_type AS target_id,
161
161
  COUNT(*) AS value
162
- FROM ${r.identifier(u)} f
163
- INNER JOIN ${r.identifier(c)} t ON f.binding_key = t.binding_key
162
+ FROM ${o.identifier(u)} f
163
+ INNER JOIN ${o.identifier(c)} t ON f.binding_key = t.binding_key
164
164
  GROUP BY f.event_type, t.event_type
165
- `)}if(n.length===0){const a=t.db.select({source_id:r`NULL`.as("source_id"),target_id:r`NULL`.as("target_id"),value:r`0`.as("value")}).from(r`(SELECT 1) AS empty`).where(r`1 = 0`);return t.db.$with("links_agg").as(a)}const i=r.join(n,r` UNION ALL `),o=t.db.select({source_id:r`source_id`.as("source_id"),target_id:r`target_id`.as("target_id"),value:r`value`.as("value")}).from(r`(${i}) AS links_union`);return t.db.$with("links_agg").as(o)}buildFinalResultCTE(e){const t=r`
165
+ `)}if(n.length===0){const a=t.db.select({source_id:o`NULL`.as("source_id"),target_id:o`NULL`.as("target_id"),value:o`0`.as("value")}).from(o`(SELECT 1) AS empty`).where(o`1 = 0`);return t.db.$with("links_agg").as(a)}const i=o.join(n,o` UNION ALL `),r=t.db.select({source_id:o`source_id`.as("source_id"),target_id:o`target_id`.as("target_id"),value:o`value`.as("value")}).from(o`(${i}) AS links_union`);return t.db.$with("links_agg").as(r)}buildFinalResultCTE(e){const t=o`
166
166
  SELECT
167
167
  'node' AS record_type,
168
168
  node_id AS id,
@@ -183,22 +183,22 @@
183
183
  target_id AS target_id
184
184
  FROM links_agg
185
185
  WHERE source_id IS NOT NULL
186
- `,n=e.db.select({record_type:r`record_type`.as("record_type"),id:r`id`.as("id"),name:r`name`.as("name"),layer:r`layer`.as("layer"),value:r`value`.as("value"),source_id:r`source_id`.as("source_id"),target_id:r`target_id`.as("target_id")}).from(r`(${t}) AS final_union`);return e.db.$with("final_result").as(n)}}function Je(d){return Array.isArray(d)}function ot(d){return typeof d=="object"&&d!==null&&"cube"in d}function Ge(d){if(ot(d))return d.cube;const e=d.indexOf(".");if(e===-1)throw new Error(`Invalid time dimension format: ${d}. Expected 'CubeName.dimensionName'`);return d.substring(0,e)}function He(d){if(ot(d))return d.dimension;const e=d.indexOf(".");if(e===-1)throw new Error(`Invalid time dimension format: ${d}. Expected 'CubeName.dimensionName'`);return d.substring(e+1)}class fn{constructor(e){this.databaseAdapter=e,this.dateTimeBuilder=new te(e),this.filterBuilder=new he(e,this.dateTimeBuilder)}filterBuilder;dateTimeBuilder;hasRetention(e){return e.retention!==void 0&&e.retention.timeDimension!=null&&e.retention.bindingKey!=null}validateConfig(e,t){const n=[];try{const o=Ge(e.timeDimension),a=He(e.timeDimension),u=t.get(o);u?u.dimensions?.[a]||n.push(`Time dimension not found: ${a} in cube ${o}`):n.push(`Cube not found: ${o}`)}catch{n.push(`Invalid time dimension format: ${e.timeDimension}`)}if(Je(e.bindingKey))for(const o of e.bindingKey){const a=t.get(o.cube);if(!a)n.push(`Binding key mapping cube not found: ${o.cube}`);else{const u=this.extractDimensionName(o.dimension);a.dimensions?.[u]||n.push(`Binding key dimension not found: ${u} in cube ${o.cube}`)}}else{const[o,a]=e.bindingKey.split(".");if(!o||!a)n.push(`Invalid binding key format: ${e.bindingKey}. Expected 'CubeName.dimensionName'`);else{const u=t.get(o);u?u.dimensions?.[a]||n.push(`Binding key dimension not found: ${a} in cube ${o}`):n.push(`Binding key cube not found: ${o}`)}}if(e.breakdownDimensions&&e.breakdownDimensions.length>0)for(const o of e.breakdownDimensions){const[a,u]=o.split(".");if(!a||!u)n.push(`Invalid breakdown dimension format: ${o}. Expected 'CubeName.dimensionName'`);else{const c=t.get(a);c?c.dimensions?.[u]||n.push(`Breakdown dimension not found: ${u} in cube ${a}`):n.push(`Breakdown dimension cube not found: ${a}`)}}if(e.periods<1&&n.push("Periods must be at least 1"),e.periods>52&&n.push("Periods cannot exceed 52 (performance limit)"),["day","week","month"].includes(e.granularity)||n.push(`Invalid granularity: ${e.granularity}`),["classic","rolling"].includes(e.retentionType)||n.push(`Invalid retention type: ${e.retentionType}`),!e.dateRange)n.push("Date range is required");else{if(!e.dateRange.start)n.push("Date range start is required");else{const o=new Date(e.dateRange.start);isNaN(o.getTime())&&n.push("Invalid date range start format")}if(!e.dateRange.end)n.push("Date range end is required");else{const o=new Date(e.dateRange.end);isNaN(o.getTime())&&n.push("Invalid date range end format")}if(e.dateRange.start&&e.dateRange.end){const o=new Date(e.dateRange.start),a=new Date(e.dateRange.end);!isNaN(o.getTime())&&!isNaN(a.getTime())&&o>a&&n.push("Date range start must be before or equal to end")}}return{isValid:n.length===0,errors:n}}buildRetentionQuery(e,t,n){const s=this.resolveConfig(e,t,n),i=s.breakdowns.length,o=this.buildCohortBaseCTE(e,s,n),a=this.buildActivityPeriodsCTE(e,s,n),u=this.buildCohortSizesCTE(e,n,i),c=this.buildRetentionCountsCTE(e,n,i),l=s.breakdowns.length>0,m={period:r`rc.period_number`.as("period"),cohort_size:r`cs.cohort_size`.as("cohort_size"),retained_users:r`rc.retained_users`.as("retained_users"),retention_rate:r`CAST(rc.retained_users AS NUMERIC) / NULLIF(cs.cohort_size, 0)`.as("retention_rate")};for(let h=0;h<s.breakdowns.length;h++)m[`breakdown_${h}`]=r.raw(`rc.breakdown_${h}`).as(`breakdown_${h}`);let f=n.db.with(o,a,u,c).select(m).from(r`retention_counts rc`);if(l){const h=s.breakdowns.map((y,b)=>r`COALESCE(CAST(rc.breakdown_${r.raw(String(b))} AS TEXT), '') = COALESCE(CAST(cs.breakdown_${r.raw(String(b))} AS TEXT), '')`),g=h.length===1?h[0]:r.join(h,r` AND `);f=f.innerJoin(r`cohort_sizes cs`,g)}else f=f.innerJoin(r`cohort_sizes cs`,r`1 = 1`);const p=[];for(let h=0;h<s.breakdowns.length;h++)p.push(r.raw(`rc.breakdown_${h}`));return p.push(r`rc.period_number`),f=f.orderBy(...p),f}transformResult(e,t){const n=t.breakdownDimensions||[],s=n.length>0;return e.map(i=>{const o={period:Number(i.period),cohortSize:Number(i.cohort_size),retainedUsers:Number(i.retained_users),retentionRate:i.retention_rate!==null?Number(i.retention_rate):0};if(s){const a={};for(let u=0;u<n.length;u++){const c=n[u],l=i[`breakdown_${u}`];a[c]=l!==void 0?String(l):null}o.breakdownValues=a}return o})}resolveConfig(e,t,n){const s=Ge(e.timeDimension),i=He(e.timeDimension),o=t.get(s);if(!o)throw new Error(`Cube not found: ${s}`);const a=o.dimensions?.[i];if(!a)throw new Error(`Time dimension not found: ${i}`);const u=R(a.sql,n),c=this.resolveBindingKey(e.bindingKey,o,t,n),l=this.buildFilterConditions(e.cohortFilters,o,t,n),m=this.buildFilterConditions(e.activityFilters,o,t,n),f=[];if(e.breakdownDimensions&&e.breakdownDimensions.length>0)for(const p of e.breakdownDimensions){const[h,g]=p.split("."),y=t.get(h);if(y&&y.dimensions?.[g]){const b=R(y.dimensions[g].sql,n);f.push({dimension:p,expr:b})}}return{cube:o,bindingKeyExpr:c,timeExpr:u,cohortFilterConditions:l,activityFilterConditions:m,breakdowns:f}}resolveBindingKey(e,t,n,s){if(Je(e)){const c=e.find(p=>p.cube===t.name);if(!c)throw new Error(`No binding key mapping found for cube: ${t.name}`);const l=this.extractDimensionName(c.dimension),m=n.get(c.cube);if(!m)throw new Error(`Binding key cube not found: ${c.cube}`);const f=m.dimensions?.[l];if(!f)throw new Error(`Binding key dimension not found: ${c.dimension}`);return R(f.sql,s)}const[i,o]=e.split("."),a=n.get(i);if(!a)throw new Error(`Binding key cube not found: ${i}`);const u=a.dimensions?.[o];if(!u)throw new Error(`Binding key dimension not found: ${e}`);return R(u.sql,s)}buildFilterConditions(e,t,n,s){if(!e)return[];const i=Array.isArray(e)?e:[e],o=[];for(const a of i){const u=this.buildSingleFilterCondition(a,t,n,s);u&&o.push(u)}return o}buildSingleFilterCondition(e,t,n,s){if("and"in e||"or"in e){const m=e,f=[],p="and"in m&&!!m.and,h=m.and||m.or||[];for(const g of h){const y=this.buildSingleFilterCondition(g,t,n,s);y&&f.push(y)}return f.length===0?null:f.length===1?f[0]:p?_(...f):r`(${r.join(f,r` OR `)})`}const i=e,[o,a]=i.member.split("."),u=n.get(o);if(!u)return null;const c=u.dimensions?.[a];if(!c)return null;const l=R(c.sql,s);return this.filterBuilder.buildFilterCondition(l,i.operator,i.values||[],c,i.dateRange)}buildCohortBaseCTE(e,t,n){const s=t.cube.sql(n),i=[];if(s.where&&i.push(s.where),i.push(...t.cohortFilterConditions),e.dateRange){const l=this.buildDateRangeCondition(t.timeExpr,e.dateRange);i.push(l)}const o=this.databaseAdapter.buildTimeDimension(e.granularity,t.timeExpr),a={binding_key:r`${t.bindingKeyExpr}`.as("binding_key"),cohort_entry:r`MIN(${o})`.as("cohort_entry")};for(let l=0;l<t.breakdowns.length;l++){const{expr:m}=t.breakdowns[l];a[`breakdown_${l}`]=r`MIN(${m})`.as(`breakdown_${l}`)}let u=n.db.select(a).from(s.from);if(i.length>0){const l=i.length===1?i[0]:_(...i);u=u.where(l)}const c=[t.bindingKeyExpr];for(let l=0;l<t.breakdowns.length;l++)c.push(t.breakdowns[l].expr);if(u=u.groupBy(...c),e.dateRange){const l=this.buildDateRangeHavingCondition(o,e.dateRange);u=u.having(l)}return n.db.$with("cohort_base").as(u)}buildDateRangeCondition(e,t){return r`${e} >= ${t.start}::date AND ${e} < (${t.end}::date + interval '1 day')`}buildDateRangeHavingCondition(e,t){return r`MIN(${e}) >= ${t.start}::date AND MIN(${e}) < (${t.end}::date + interval '1 day')`}buildActivityPeriodsCTE(e,t,n){const s=t.cube.sql(n),i=[];s.where&&i.push(s.where),i.push(...t.activityFilterConditions),i.push(r`${t.timeExpr} >= cohort_base.cohort_entry`);const o=this.databaseAdapter.buildTimeDimension(e.granularity,t.timeExpr),a=this.buildPeriodNumberExpression(r`cohort_base.cohort_entry`,o,e.granularity),u={binding_key:r`cohort_base.binding_key`.as("binding_key"),period_number:a.as("period_number")};for(let m=0;m<t.breakdowns.length;m++)u[`breakdown_${m}`]=r.raw(`cohort_base.breakdown_${m}`).as(`breakdown_${m}`);let c=n.db.select(u).from(s.from).innerJoin(r`cohort_base`,r`${t.bindingKeyExpr} = cohort_base.binding_key`);if(i.length>0){const m=i.length===1?i[0]:_(...i);c=c.where(m)}const l=[r`cohort_base.binding_key`,a];for(let m=0;m<t.breakdowns.length;m++)l.push(r.raw(`cohort_base.breakdown_${m}`));return c=c.groupBy(...l),n.db.$with("activity_periods").as(c)}buildCohortSizesCTE(e,t,n){if(n>0){const o={cohort_size:r`COUNT(*)`.as("cohort_size")},a=[];for(let c=0;c<n;c++)o[`breakdown_${c}`]=r.raw(`breakdown_${c}`).as(`breakdown_${c}`),a.push(r.raw(`breakdown_${c}`));const u=t.db.select(o).from(r`cohort_base`).groupBy(...a);return t.db.$with("cohort_sizes").as(u)}const i=t.db.select({cohort_size:r`COUNT(*)`.as("cohort_size")}).from(r`cohort_base`);return t.db.$with("cohort_sizes").as(i)}buildRetentionCountsCTE(e,t,n){let s;if(e.retentionType==="rolling")s=this.buildRollingRetentionCountsQuery(e,t,n);else{const i={period_number:r`period_number`.as("period_number"),retained_users:r`COUNT(DISTINCT binding_key)`.as("retained_users")},o=[r`period_number`];for(let a=0;a<n;a++)i[`breakdown_${a}`]=r.raw(`breakdown_${a}`).as(`breakdown_${a}`),o.push(r.raw(`breakdown_${a}`));s=t.db.select(i).from(r`activity_periods`).where(r`period_number >= 0 AND period_number <= ${e.periods}`).groupBy(...o)}return t.db.$with("retention_counts").as(s)}buildRollingRetentionCountsQuery(e,t,n){const s=[];for(let l=0;l<n;l++)s.push(`breakdown_${l}`);const i=s.length>0?`, ${s.join(", ")}`:"",o=r`(
186
+ `,n=e.db.select({record_type:o`record_type`.as("record_type"),id:o`id`.as("id"),name:o`name`.as("name"),layer:o`layer`.as("layer"),value:o`value`.as("value"),source_id:o`source_id`.as("source_id"),target_id:o`target_id`.as("target_id")}).from(o`(${t}) AS final_union`);return e.db.$with("final_result").as(n)}}function Je(d){return Array.isArray(d)}function ot(d){return typeof d=="object"&&d!==null&&"cube"in d}function Ge(d){if(ot(d))return d.cube;const e=d.indexOf(".");if(e===-1)throw new Error(`Invalid time dimension format: ${d}. Expected 'CubeName.dimensionName'`);return d.substring(0,e)}function He(d){if(ot(d))return d.dimension;const e=d.indexOf(".");if(e===-1)throw new Error(`Invalid time dimension format: ${d}. Expected 'CubeName.dimensionName'`);return d.substring(e+1)}class fn{constructor(e){this.databaseAdapter=e,this.dateTimeBuilder=new ne(e),this.filterBuilder=new he(e,this.dateTimeBuilder)}filterBuilder;dateTimeBuilder;hasRetention(e){return e.retention!==void 0&&e.retention.timeDimension!=null&&e.retention.bindingKey!=null}validateConfig(e,t){const n=[];try{const r=Ge(e.timeDimension),a=He(e.timeDimension),u=t.get(r);u?u.dimensions?.[a]||n.push(`Time dimension not found: ${a} in cube ${r}`):n.push(`Cube not found: ${r}`)}catch{n.push(`Invalid time dimension format: ${e.timeDimension}`)}if(Je(e.bindingKey))for(const r of e.bindingKey){const a=t.get(r.cube);if(!a)n.push(`Binding key mapping cube not found: ${r.cube}`);else{const u=this.extractDimensionName(r.dimension);a.dimensions?.[u]||n.push(`Binding key dimension not found: ${u} in cube ${r.cube}`)}}else{const[r,a]=e.bindingKey.split(".");if(!r||!a)n.push(`Invalid binding key format: ${e.bindingKey}. Expected 'CubeName.dimensionName'`);else{const u=t.get(r);u?u.dimensions?.[a]||n.push(`Binding key dimension not found: ${a} in cube ${r}`):n.push(`Binding key cube not found: ${r}`)}}if(e.breakdownDimensions&&e.breakdownDimensions.length>0)for(const r of e.breakdownDimensions){const[a,u]=r.split(".");if(!a||!u)n.push(`Invalid breakdown dimension format: ${r}. Expected 'CubeName.dimensionName'`);else{const c=t.get(a);c?c.dimensions?.[u]||n.push(`Breakdown dimension not found: ${u} in cube ${a}`):n.push(`Breakdown dimension cube not found: ${a}`)}}if(e.periods<1&&n.push("Periods must be at least 1"),e.periods>52&&n.push("Periods cannot exceed 52 (performance limit)"),["day","week","month"].includes(e.granularity)||n.push(`Invalid granularity: ${e.granularity}`),["classic","rolling"].includes(e.retentionType)||n.push(`Invalid retention type: ${e.retentionType}`),!e.dateRange)n.push("Date range is required");else{if(!e.dateRange.start)n.push("Date range start is required");else{const r=new Date(e.dateRange.start);isNaN(r.getTime())&&n.push("Invalid date range start format")}if(!e.dateRange.end)n.push("Date range end is required");else{const r=new Date(e.dateRange.end);isNaN(r.getTime())&&n.push("Invalid date range end format")}if(e.dateRange.start&&e.dateRange.end){const r=new Date(e.dateRange.start),a=new Date(e.dateRange.end);!isNaN(r.getTime())&&!isNaN(a.getTime())&&r>a&&n.push("Date range start must be before or equal to end")}}return{isValid:n.length===0,errors:n}}buildRetentionQuery(e,t,n){const s=this.resolveConfig(e,t,n),i=s.breakdowns.length,r=this.buildCohortBaseCTE(e,s,n),a=this.buildActivityPeriodsCTE(e,s,n),u=this.buildCohortSizesCTE(e,n,i),c=this.buildRetentionCountsCTE(e,n,i),l=s.breakdowns.length>0,m={period:o`rc.period_number`.as("period"),cohort_size:o`cs.cohort_size`.as("cohort_size"),retained_users:o`rc.retained_users`.as("retained_users"),retention_rate:o`CAST(rc.retained_users AS NUMERIC) / NULLIF(cs.cohort_size, 0)`.as("retention_rate")};for(let h=0;h<s.breakdowns.length;h++)m[`breakdown_${h}`]=o.raw(`rc.breakdown_${h}`).as(`breakdown_${h}`);let p=n.db.with(r,a,u,c).select(m).from(o`retention_counts rc`);if(l){const h=s.breakdowns.map((y,b)=>o`COALESCE(CAST(rc.breakdown_${o.raw(String(b))} AS TEXT), '') = COALESCE(CAST(cs.breakdown_${o.raw(String(b))} AS TEXT), '')`),g=h.length===1?h[0]:o.join(h,o` AND `);p=p.innerJoin(o`cohort_sizes cs`,g)}else p=p.innerJoin(o`cohort_sizes cs`,o`1 = 1`);const f=[];for(let h=0;h<s.breakdowns.length;h++)f.push(o.raw(`rc.breakdown_${h}`));return f.push(o`rc.period_number`),p=p.orderBy(...f),p}transformResult(e,t){const n=t.breakdownDimensions||[],s=n.length>0;return e.map(i=>{const r={period:Number(i.period),cohortSize:Number(i.cohort_size),retainedUsers:Number(i.retained_users),retentionRate:i.retention_rate!==null?Number(i.retention_rate):0};if(s){const a={};for(let u=0;u<n.length;u++){const c=n[u],l=i[`breakdown_${u}`];a[c]=l!==void 0?String(l):null}r.breakdownValues=a}return r})}resolveConfig(e,t,n){const s=Ge(e.timeDimension),i=He(e.timeDimension),r=t.get(s);if(!r)throw new Error(`Cube not found: ${s}`);const a=r.dimensions?.[i];if(!a)throw new Error(`Time dimension not found: ${i}`);const u=v(a.sql,n),c=this.resolveBindingKey(e.bindingKey,r,t,n),l=this.buildFilterConditions(e.cohortFilters,r,t,n),m=this.buildFilterConditions(e.activityFilters,r,t,n),p=[];if(e.breakdownDimensions&&e.breakdownDimensions.length>0)for(const f of e.breakdownDimensions){const[h,g]=f.split("."),y=t.get(h);if(y&&y.dimensions?.[g]){const b=v(y.dimensions[g].sql,n);p.push({dimension:f,expr:b})}}return{cube:r,bindingKeyExpr:c,timeExpr:u,cohortFilterConditions:l,activityFilterConditions:m,breakdowns:p}}resolveBindingKey(e,t,n,s){if(Je(e)){const c=e.find(f=>f.cube===t.name);if(!c)throw new Error(`No binding key mapping found for cube: ${t.name}`);const l=this.extractDimensionName(c.dimension),m=n.get(c.cube);if(!m)throw new Error(`Binding key cube not found: ${c.cube}`);const p=m.dimensions?.[l];if(!p)throw new Error(`Binding key dimension not found: ${c.dimension}`);return v(p.sql,s)}const[i,r]=e.split("."),a=n.get(i);if(!a)throw new Error(`Binding key cube not found: ${i}`);const u=a.dimensions?.[r];if(!u)throw new Error(`Binding key dimension not found: ${e}`);return v(u.sql,s)}buildFilterConditions(e,t,n,s){if(!e)return[];const i=Array.isArray(e)?e:[e],r=[];for(const a of i){const u=this.buildSingleFilterCondition(a,t,n,s);u&&r.push(u)}return r}buildSingleFilterCondition(e,t,n,s){if("and"in e||"or"in e){const m=e,p=[],f="and"in m&&!!m.and,h=m.and||m.or||[];for(const g of h){const y=this.buildSingleFilterCondition(g,t,n,s);y&&p.push(y)}return p.length===0?null:p.length===1?p[0]:f?A(...p):o`(${o.join(p,o` OR `)})`}const i=e,[r,a]=i.member.split("."),u=n.get(r);if(!u)return null;const c=u.dimensions?.[a];if(!c)return null;const l=v(c.sql,s);return this.filterBuilder.buildFilterCondition(l,i.operator,i.values||[],c,i.dateRange)}buildCohortBaseCTE(e,t,n){const s=t.cube.sql(n),i=[];if(s.where&&i.push(s.where),i.push(...t.cohortFilterConditions),e.dateRange){const l=this.buildDateRangeCondition(t.timeExpr,e.dateRange);i.push(l)}const r=this.databaseAdapter.buildTimeDimension(e.granularity,t.timeExpr),a={binding_key:o`${t.bindingKeyExpr}`.as("binding_key"),cohort_entry:o`MIN(${r})`.as("cohort_entry")};for(let l=0;l<t.breakdowns.length;l++){const{expr:m}=t.breakdowns[l];a[`breakdown_${l}`]=o`MIN(${m})`.as(`breakdown_${l}`)}let u=n.db.select(a).from(s.from);if(i.length>0){const l=i.length===1?i[0]:A(...i);u=u.where(l)}const c=[t.bindingKeyExpr];for(let l=0;l<t.breakdowns.length;l++)c.push(t.breakdowns[l].expr);if(u=u.groupBy(...c),e.dateRange){const l=this.buildDateRangeHavingCondition(r,e.dateRange);u=u.having(l)}return n.db.$with("cohort_base").as(u)}buildDateRangeCondition(e,t){return o`${e} >= ${t.start}::date AND ${e} < (${t.end}::date + interval '1 day')`}buildDateRangeHavingCondition(e,t){return o`MIN(${e}) >= ${t.start}::date AND MIN(${e}) < (${t.end}::date + interval '1 day')`}buildActivityPeriodsCTE(e,t,n){const s=t.cube.sql(n),i=[];s.where&&i.push(s.where),i.push(...t.activityFilterConditions),i.push(o`${t.timeExpr} >= cohort_base.cohort_entry`);const r=this.databaseAdapter.buildTimeDimension(e.granularity,t.timeExpr),a=this.buildPeriodNumberExpression(o`cohort_base.cohort_entry`,r,e.granularity),u={binding_key:o`cohort_base.binding_key`.as("binding_key"),period_number:a.as("period_number")};for(let m=0;m<t.breakdowns.length;m++)u[`breakdown_${m}`]=o.raw(`cohort_base.breakdown_${m}`).as(`breakdown_${m}`);let c=n.db.select(u).from(s.from).innerJoin(o`cohort_base`,o`${t.bindingKeyExpr} = cohort_base.binding_key`);if(i.length>0){const m=i.length===1?i[0]:A(...i);c=c.where(m)}const l=[o`cohort_base.binding_key`,a];for(let m=0;m<t.breakdowns.length;m++)l.push(o.raw(`cohort_base.breakdown_${m}`));return c=c.groupBy(...l),n.db.$with("activity_periods").as(c)}buildCohortSizesCTE(e,t,n){if(n>0){const r={cohort_size:o`COUNT(*)`.as("cohort_size")},a=[];for(let c=0;c<n;c++)r[`breakdown_${c}`]=o.raw(`breakdown_${c}`).as(`breakdown_${c}`),a.push(o.raw(`breakdown_${c}`));const u=t.db.select(r).from(o`cohort_base`).groupBy(...a);return t.db.$with("cohort_sizes").as(u)}const i=t.db.select({cohort_size:o`COUNT(*)`.as("cohort_size")}).from(o`cohort_base`);return t.db.$with("cohort_sizes").as(i)}buildRetentionCountsCTE(e,t,n){let s;if(e.retentionType==="rolling")s=this.buildRollingRetentionCountsQuery(e,t,n);else{const i={period_number:o`period_number`.as("period_number"),retained_users:o`COUNT(DISTINCT binding_key)`.as("retained_users")},r=[o`period_number`];for(let a=0;a<n;a++)i[`breakdown_${a}`]=o.raw(`breakdown_${a}`).as(`breakdown_${a}`),r.push(o.raw(`breakdown_${a}`));s=t.db.select(i).from(o`activity_periods`).where(o`period_number >= 0 AND period_number <= ${e.periods}`).groupBy(...r)}return t.db.$with("retention_counts").as(s)}buildRollingRetentionCountsQuery(e,t,n){const s=[];for(let l=0;l<n;l++)s.push(`breakdown_${l}`);const i=s.length>0?`, ${s.join(", ")}`:"",r=o`(
187
187
  SELECT
188
188
  binding_key,
189
- ${r.raw(s.map(l=>`${l}`).join(", ")+(s.length>0?",":""))}
189
+ ${o.raw(s.map(l=>`${l}`).join(", ")+(s.length>0?",":""))}
190
190
  MAX(period_number) as max_period
191
191
  FROM activity_periods
192
192
  WHERE period_number >= 0 AND period_number <= ${e.periods}
193
- GROUP BY binding_key${r.raw(i)}
194
- )`,a=this.databaseAdapter.buildPeriodSeriesSubquery(e.periods),u={period_number:r`p.period_number`.as("period_number"),retained_users:r`COUNT(DISTINCT CASE WHEN ump.max_period >= p.period_number THEN ump.binding_key END)`.as("retained_users")},c=[r`p.period_number`];for(let l=0;l<n;l++)u[`breakdown_${l}`]=r.raw(`ump.breakdown_${l}`).as(`breakdown_${l}`),c.push(r.raw(`ump.breakdown_${l}`));return t.db.select(u).from(r`${o} ump`).crossJoin(a).groupBy(...c)}buildPeriodNumberExpression(e,t,n){return this.databaseAdapter.buildDateDiffPeriods(e,t,n)}extractDimensionName(e){const t=e.split(".");return t.length>1?t[1]:t[0]}}class V{constructor(e,t){if(this.dbExecutor=e,this.databaseAdapter=e.databaseAdapter,!this.databaseAdapter)throw new Error("DatabaseExecutor must have a databaseAdapter property");this.queryBuilder=new tn(this.databaseAdapter),this.queryPlanner=new rt,this.cteBuilder=new nn(this.queryBuilder),this.comparisonQueryBuilder=new cn(this.databaseAdapter),this.funnelQueryBuilder=new dn(this.databaseAdapter),this.flowQueryBuilder=new mn(this.databaseAdapter),this.retentionQueryBuilder=new fn(this.databaseAdapter),this.cacheConfig=t}queryBuilder;queryPlanner;cteBuilder;databaseAdapter;comparisonQueryBuilder;funnelQueryBuilder;flowQueryBuilder;retentionQueryBuilder;cacheConfig;async execute(e,t,n,s){try{if(this.funnelQueryBuilder.hasFunnel(t)){const b=this.funnelQueryBuilder.validateConfig(t.funnel,e);if(!b.isValid)throw new Error(`Funnel validation failed: ${b.errors.join(", ")}`)}else if(this.flowQueryBuilder.hasFlow(t)){const b=this.flowQueryBuilder.validateConfig(t.flow,e);if(!b.isValid)throw new Error(`Flow validation failed: ${b.errors.join(", ")}`)}else if(this.retentionQueryBuilder.hasRetention(t)){const b=this.retentionQueryBuilder.validateConfig(t.retention,e);if(!b.isValid)throw new Error(`Retention validation failed: ${b.errors.join(", ")}`)}else{const b=at(e,t);if(!b.isValid)throw new Error(`Query validation failed: ${b.errors.join(", ")}`)}let i;if(this.cacheConfig?.enabled!==!1&&this.cacheConfig?.provider)if(i=zt(t,n,this.cacheConfig),s?.skipCache)this.cacheConfig.onCacheEvent?.({type:"miss",key:i,durationMs:0});else try{const b=Date.now(),w=await this.cacheConfig.provider.get(i);if(w)return this.cacheConfig.onCacheEvent?.({type:"hit",key:i,durationMs:Date.now()-b}),{...w.value,cache:w.metadata?{hit:!0,cachedAt:new Date(w.metadata.cachedAt).toISOString(),ttlMs:w.metadata.ttlMs,ttlRemainingMs:w.metadata.ttlRemainingMs}:{hit:!0,cachedAt:new Date().toISOString(),ttlMs:0,ttlRemainingMs:0}};this.cacheConfig.onCacheEvent?.({type:"miss",key:i,durationMs:Date.now()-b})}catch(b){this.cacheConfig.onError?.(b,"get")}if(this.comparisonQueryBuilder.hasComparison(t))return this.executeComparisonQueryWithCache(e,t,n,i);if(this.funnelQueryBuilder.hasFunnel(t))return this.executeFunnelQueryWithCache(e,t,n,i);if(this.flowQueryBuilder.hasFlow(t))return this.executeFlowQueryWithCache(e,t,n,i);if(this.retentionQueryBuilder.hasRetention(t))return this.executeRetentionQueryWithCache(e,t,n,i);const o=new qe,a={db:this.dbExecutor.db,schema:this.dbExecutor.schema,securityContext:n,filterCache:o};this.preloadFilterCache(t,o,e,a);const u=this.queryPlanner.createQueryPlan(e,t,a);this.validateSecurityContext(u,a);const c=this.buildUnifiedQuery(u,t,a),l=this.queryBuilder.collectNumericFields(e,t),m=await this.dbExecutor.execute(c,l),f=Array.isArray(m)?m.map(b=>{const w={...b};if(t.timeDimensions){for(const $ of t.timeDimensions)if($.dimension in w){let S=w[$.dimension];if(typeof S=="string"&&S.match(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/)){const C=S.replace(" ","T"),E=!C.endsWith("Z")&&!C.includes("+")?C+"Z":C;S=new Date(E)}S=this.databaseAdapter.convertTimeDimensionResult(S),w[$.dimension]=S}}return w}):[m],p=t.measures||[],h=Ve(f,t,p),g=this.generateAnnotations(u,t),y={data:h,annotation:g,warnings:u.warnings?.length?u.warnings:void 0};if(i&&this.cacheConfig?.provider)try{const b=Date.now();await this.cacheConfig.provider.set(i,y,this.cacheConfig.defaultTtlMs??3e5),this.cacheConfig.onCacheEvent?.({type:"set",key:i,durationMs:Date.now()-b})}catch(b){this.cacheConfig.onError?.(b,"set")}return y}catch(i){if(i instanceof Error){let o=i;for(;o.cause instanceof Error;)o=o.cause;let a=o.message;const u=o;throw u.code&&(a+=` [${u.code}]`),u.detail&&(a+=` Detail: ${u.detail}`),u.hint&&(a+=` Hint: ${u.hint}`),i.message=`Query execution failed: ${a}`,i}throw new Error("Query execution failed: Unknown error")}}async executeQuery(e,t,n){const s=new Map;return s.set(e.name,e),this.execute(s,t,n)}async executeComparisonQueryWithCache(e,t,n,s){const i=await this.executeComparisonQuery(e,t,n);if(s&&this.cacheConfig?.provider)try{const o=Date.now();await this.cacheConfig.provider.set(s,i,this.cacheConfig.defaultTtlMs??3e5),this.cacheConfig.onCacheEvent?.({type:"set",key:s,durationMs:Date.now()-o})}catch(o){this.cacheConfig.onError?.(o,"set")}return i}async executeComparisonQuery(e,t,n){const s=this.comparisonQueryBuilder.getComparisonTimeDimension(t);if(!s||!s.compareDateRange)throw new Error("No compareDateRange found in query");const i=this.comparisonQueryBuilder.normalizePeriods(s.compareDateRange);if(i.length<2)throw new Error("compareDateRange requires at least 2 periods");const o=s.granularity||"day",a=i.map(async l=>{const m=this.comparisonQueryBuilder.createPeriodQuery(t,l);return{result:await this.executeStandardQuery(e,m,n),period:l}}),u=await Promise.all(a),c=this.comparisonQueryBuilder.mergeComparisonResults(u,s,o);return c.data=this.comparisonQueryBuilder.sortComparisonResults(c.data,s.dimension),c}async executeFunnelQueryWithCache(e,t,n,s){const i=await this.executeFunnelQuery(e,t,n);if(s&&this.cacheConfig?.provider)try{const o=Date.now();await this.cacheConfig.provider.set(s,i,this.cacheConfig.defaultTtlMs??3e5),this.cacheConfig.onCacheEvent?.({type:"set",key:s,durationMs:Date.now()-o})}catch(o){this.cacheConfig.onError?.(o,"set")}return{...i,cache:{hit:!1}}}async executeFunnelQuery(e,t,n){const s=t.funnel,i=this.funnelQueryBuilder.validateConfig(s,e);if(!i.isValid)throw new Error(`Funnel validation failed: ${i.errors.join(", ")}`);const o={db:this.dbExecutor.db,schema:this.dbExecutor.schema,securityContext:n},u=await this.funnelQueryBuilder.buildFunnelQuery(s,e,o),c=this.funnelQueryBuilder.transformResult(u,s),l={measures:{},dimensions:{},segments:{},timeDimensions:{}};return l.funnel={config:s,steps:s.steps.map((m,f)=>({name:m.name,index:f,timeToConvert:m.timeToConvert}))},{data:c,annotation:l}}async executeFlowQueryWithCache(e,t,n,s){const i=await this.executeFlowQuery(e,t,n);if(s&&this.cacheConfig?.provider)try{const o=Date.now();await this.cacheConfig.provider.set(s,i,this.cacheConfig.defaultTtlMs??3e5),this.cacheConfig.onCacheEvent?.({type:"set",key:s,durationMs:Date.now()-o})}catch(o){this.cacheConfig.onError?.(o,"set")}return{...i,cache:{hit:!1}}}async executeFlowQuery(e,t,n){const s=t.flow,i=this.flowQueryBuilder.validateConfig(s,e);if(!i.isValid)throw new Error(`Flow validation failed: ${i.errors.join(", ")}`);const o={db:this.dbExecutor.db,schema:this.dbExecutor.schema,securityContext:n},u=await this.flowQueryBuilder.buildFlowQuery(s,e,o),c=this.flowQueryBuilder.transformResult(u),l={measures:{},dimensions:{},segments:{},timeDimensions:{}};return l.flow={config:s,startingStep:{name:s.startingStep.name},stepsBefore:s.stepsBefore,stepsAfter:s.stepsAfter},{data:[c],annotation:l}}async executeRetentionQueryWithCache(e,t,n,s){const i=await this.executeRetentionQuery(e,t,n);if(s&&this.cacheConfig?.provider)try{const o=Date.now();await this.cacheConfig.provider.set(s,i,this.cacheConfig.defaultTtlMs??3e5),this.cacheConfig.onCacheEvent?.({type:"set",key:s,durationMs:Date.now()-o})}catch(o){this.cacheConfig.onError?.(o,"set")}return{...i,cache:{hit:!1}}}async executeRetentionQuery(e,t,n){const s=t.retention,i=this.retentionQueryBuilder.validateConfig(s,e);if(!i.isValid)throw new Error(`Retention validation failed: ${i.errors.join(", ")}`);const o={db:this.dbExecutor.db,schema:this.dbExecutor.schema,securityContext:n},u=await this.retentionQueryBuilder.buildRetentionQuery(s,e,o),c=this.retentionQueryBuilder.transformResult(u,s),l={measures:{},dimensions:{},segments:{},timeDimensions:{}};return l.retention={config:s,granularity:s.granularity,periods:s.periods,retentionType:s.retentionType,breakdownDimensions:s.breakdownDimensions},{data:c,annotation:l}}async executeStandardQuery(e,t,n){const s=new qe,i={db:this.dbExecutor.db,schema:this.dbExecutor.schema,securityContext:n,filterCache:s};this.preloadFilterCache(t,s,e,i);const o=this.queryPlanner.createQueryPlan(e,t,i),a=this.buildUnifiedQuery(o,t,i),u=this.queryBuilder.collectNumericFields(e,t),c=await this.dbExecutor.execute(a,u),l=Array.isArray(c)?c.map(h=>{const g={...h};if(t.timeDimensions){for(const y of t.timeDimensions)if(y.dimension in g){let b=g[y.dimension];if(typeof b=="string"&&b.match(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/)){const w=b.replace(" ","T"),$=!w.endsWith("Z")&&!w.includes("+")?w+"Z":w;b=new Date($)}b=this.databaseAdapter.convertTimeDimensionResult(b),g[y.dimension]=b}}return g}):[c],m=t.measures||[],f=Ve(l,t,m),p=this.generateAnnotations(o,t);return{data:f,annotation:p}}validateSecurityContext(e,t){const n=typeof process<"u"?process.env?.NODE_ENV:void 0,s=typeof process<"u"?process.env?.DRIZZLE_CUBE_WARN_SECURITY:void 0;if(n!=="development"&&!s)return;const i=[e.primaryCube];for(const a of e.joinCubes||[])i.push(a.cube);for(const a of e.preAggregationCTEs||[])i.push(a.cube);const o=new Set;for(const a of i)if(!o.has(a.name)){o.add(a.name);try{if(a.public)continue;a.sql(t).where||console.warn(`[drizzle-cube] WARNING: Cube '${a.name}' has no security filtering. If this cube contains public data, add 'public: true' to suppress this warning. Otherwise, ensure sql() returns: { from: table, where: eq(table.orgId, ctx.securityContext.orgId) }`)}catch{}}}buildUnifiedQuery(e,t,n){const s=new Map;if(e.preAggregationCTEs&&e.preAggregationCTEs.length>0){for(const $ of e.preAggregationCTEs)if($.propagatingFilters&&$.propagatingFilters.length>0)for(const S of $.propagatingFilters){const C=S.sourceCube.name;if(!s.has(C)){const T={filters:S.filters},D=new Map([[C,S.sourceCube]]),N=this.queryBuilder.buildWhereConditions(D,T,n);s.set(C,N)}const E=s.get(C);E&&E.length>0&&(S.preBuiltFilterSQL=E.length===1?E[0]:_(...E))}}const i=[],o=new Map,a=new Map;if(e.preAggregationCTEs&&e.preAggregationCTEs.length>0)for(const $ of e.preAggregationCTEs){const S=this.cteBuilder.buildPreAggregationCTE($,t,n,e,s);if(S&&(i.push(S),o.set($.cube.name,$.cteAlias),$.downstreamJoinKeys))for(const C of $.downstreamJoinKeys)a.set(C.targetCubeName,{cteAlias:$.cteAlias,joinKeys:C.joinKeys})}const u=e.primaryCube.sql(n),l={...this.queryBuilder.buildSelections(e.joinCubes.length>0?this.getCubesFromPlan(e):e.primaryCube,t,n)};if(e.preAggregationCTEs)for(const $ of e.preAggregationCTEs){const S=$.cube.name;for(const C of $.measures)if(l[C]){const[,E]=C.split("."),T=this.getCubesFromPlan(e).get(S);if(T&&T.measures&&T.measures[E]){const D=T.measures[E],N=r`${r.identifier($.cteAlias)}.${r.identifier(E)}`;let A;if(D.type==="calculated"&&D.calculatedSql){const v=this.getCubesFromPlan(e);A=this.queryBuilder.buildCTECalculatedMeasure(D,T,$,v,n)}else{const v=$.cteReason==="fanOutPrevention";switch(D.type){case"count":case"countDistinct":case"sum":A=v?z(N):W(N);break;case"avg":A=v?z(N):this.databaseAdapter.buildAvg(N);break;case"min":A=re(N);break;case"max":A=z(N);break;case"number":A=v?z(N):W(N);break;default:A=v?z(N):W(N)}}l[C]=r`${A}`.as(C)}}for(const C in l){const[E,T]=C.split(".");if(E===S){const D=this.getCubesFromPlan(e).get(S),N=D&&D.dimensions?.[T],A=C.startsWith(S+".");if(N||A){let v=$.joinKeys.find(j=>j.targetColumn===T);if(!v&&D?.dimensions?.[T]){const j=D.dimensions[T].sql;v=$.joinKeys.find(k=>k.targetColumnObj===j)}v?l[C]=r`${r.identifier($.cteAlias)}.${r.identifier(T)}`.as(C):A&&D?.dimensions?.[T]&&(l[C]=r`${r.identifier($.cteAlias)}.${r.identifier(T)}`.as(C))}}}}if(t.measures){const $=this.getCubesFromPlan(e);for(const S of t.measures){const[C,E]=S.split("."),T=$.get(C);if(T?.measures?.[E]){const D=T.measures[E];if(O.isPostAggregationWindow(D)){const N=O.getWindowBaseMeasure(D,C);if(N){const[A,v]=N.split("."),j=$.get(A);if(j?.measures?.[v]){const k=j.measures[v],G=e.preAggregationCTEs?.find(se=>se.cube?.name===A&&se.measures?.includes(N));let H;if(G){const se=r`${r.identifier(G.cteAlias)}.${r.identifier(v)}`;H=r`sum(${se})`}else H=this.queryBuilder.buildMeasureExpression(k,n,j);l[N]||(l[N]=r`${H}`.as(N));const ne=this.buildPostAggregationWindowExpression(D,H,t,n,T,e);ne&&(l[S]=r`${ne}`.as(S))}}}}}}const m=[];let f=n.db.select(l).from(u.from);if(i.length>0&&(f=n.db.with(...i).select(l).from(u.from)),u.joins)for(const $ of u.joins)switch($.type||"left"){case"left":f=f.leftJoin($.table,$.on);break;case"inner":f=f.innerJoin($.table,$.on);break;case"right":f=f.rightJoin($.table,$.on);break;case"full":f=f.fullJoin($.table,$.on);break}const p=new Set,h=new Set;if(e.preAggregationCTEs){for(const $ of e.preAggregationCTEs)if($.intermediateJoins&&$.intermediateJoins.length>0)for(const S of $.intermediateJoins)h.add(S.cube.name)}if(e.joinCubes&&e.joinCubes.length>0)for(const $ of e.joinCubes){const S=$.cube.name;if(h.has(S)&&!o.has(S))continue;const C=o.get($.cube.name);if($.junctionTable){const v=$.junctionTable,j=[];if(v.securitySql){const k=v.securitySql(n.securityContext);Array.isArray(k)?j.push(...k):j.push(k)}try{switch(v.joinType||"left"){case"left":f=f.leftJoin(v.table,v.joinCondition);break;case"inner":f=f.innerJoin(v.table,v.joinCondition);break;case"right":f=f.rightJoin(v.table,v.joinCondition);break;case"full":f=f.fullJoin(v.table,v.joinCondition);break}j.length>0&&m.push(...j)}catch{}}let E,T,D;if(C)E=r`${r.identifier(C)}`,T=this.cteBuilder.buildCTEJoinCondition($,C,e),D=void 0;else{const v=a.get($.cube.name),j=$.cube.sql(n);if(E=j.from,D=j.where,v){const k=[];for(const G of v.joinKeys){const H=r`${r.identifier(v.cteAlias)}.${r.identifier(G.sourceColumn)}`,ne=G.targetColumnObj||r.identifier(G.targetColumn);k.push(P(H,ne))}T=k.length===1?k[0]:_(...k)}else T=$.joinCondition}const N=$.joinType||"left",A=N!=="inner"&&D?_(T,D):T;try{switch(N){case"left":f=f.leftJoin(E,A),D&&p.add($.cube.name);break;case"inner":f=f.innerJoin(E,T);break;case"right":f=f.rightJoin(E,A),D&&p.add($.cube.name);break;case"full":f=f.fullJoin(E,A),D&&p.add($.cube.name);break}}catch{}}if(u.where&&m.push(u.where),e.joinCubes&&e.joinCubes.length>0)for(const $ of e.joinCubes){const S=$.cube.name;if(o.get(S)||h.has(S)||p.has(S))continue;const E=$.cube.sql(n);E.where&&m.push(E.where)}const g=this.queryBuilder.buildWhereConditions(e.joinCubes.length>0?this.getCubesFromPlan(e):e.primaryCube,t,n,e,s);if(g.length>0&&m.push(...g),m.length>0){const $=m.length===1?m[0]:_(...m);f=f.where($)}const y=this.queryBuilder.buildGroupByFields(e.joinCubes.length>0?this.getCubesFromPlan(e):e.primaryCube,t,n,e);y.length>0&&(f=f.groupBy(...y));const b=this.queryBuilder.buildHavingConditions(e.joinCubes.length>0?this.getCubesFromPlan(e):e.primaryCube,t,n,e);if(b.length>0){const $=b.length===1?b[0]:_(...b);f=f.having($)}const w=this.queryBuilder.buildOrderBy(t);return w.length>0&&(f=f.orderBy(...w)),f=this.queryBuilder.applyLimitAndOffset(f,t),f}getCubesFromPlan(e){const t=new Map;if(t.set(e.primaryCube.name,e.primaryCube),e.joinCubes)for(const n of e.joinCubes)t.set(n.cube.name,n.cube);return t}async generateSQL(e,t,n){const s=new Map;return s.set(e.name,e),this.generateUnifiedSQL(s,t,n)}async generateMultiCubeSQL(e,t,n){return this.generateUnifiedSQL(e,t,n)}async dryRunFunnel(e,t,n){if(!this.funnelQueryBuilder.hasFunnel(t))throw new Error("Query does not contain a valid funnel configuration");const s=t.funnel,i=this.funnelQueryBuilder.validateConfig(s,e);if(!i.isValid)throw new Error(`Funnel validation failed: ${i.errors.join(", ")}`);const o={db:this.dbExecutor.db,schema:this.dbExecutor.schema,securityContext:n},u=this.funnelQueryBuilder.buildFunnelQuery(s,e,o).toSQL();return{sql:u.sql,params:u.params}}async dryRunFlow(e,t,n){if(!this.flowQueryBuilder.hasFlow(t))throw new Error("Query does not contain a valid flow configuration");const s=t.flow,i=this.flowQueryBuilder.validateConfig(s,e);if(!i.isValid)throw new Error(`Flow validation failed: ${i.errors.join(", ")}`);const o={db:this.dbExecutor.db,schema:this.dbExecutor.schema,securityContext:n},u=this.flowQueryBuilder.buildFlowQuery(s,e,o).toSQL();return{sql:u.sql,params:u.params}}async dryRunRetention(e,t,n){if(!this.retentionQueryBuilder.hasRetention(t))throw new Error("Query does not contain a valid retention configuration");const s=t.retention,i=this.retentionQueryBuilder.validateConfig(s,e);if(!i.isValid)throw new Error(`Retention validation failed: ${i.errors.join(", ")}`);const o={db:this.dbExecutor.db,schema:this.dbExecutor.schema,securityContext:n},u=this.retentionQueryBuilder.buildRetentionQuery(s,e,o).toSQL();return{sql:u.sql,params:u.params}}async explainQuery(e,t,n,s){let i;return this.funnelQueryBuilder.hasFunnel(t)?i=await this.dryRunFunnel(e,t,n):this.flowQueryBuilder.hasFlow(t)?i=await this.dryRunFlow(e,t,n):this.retentionQueryBuilder.hasRetention(t)?i=await this.dryRunRetention(e,t,n):i=await this.generateUnifiedSQL(e,t,n),this.dbExecutor.explainQuery(i.sql,i.params||[],s)}async generateUnifiedSQL(e,t,n){const s={db:this.dbExecutor.db,schema:this.dbExecutor.schema,securityContext:n},i=this.queryPlanner.createQueryPlan(e,t,s),a=this.buildUnifiedQuery(i,t,s).toSQL();return{sql:a.sql,params:a.params}}generateAnnotations(e,t){const n={},s={},i={},o=[e.primaryCube].filter(Boolean);if(e.joinCubes&&e.joinCubes.length>0&&o.push(...e.joinCubes.map(a=>a.cube).filter(Boolean)),t.measures)for(const a of t.measures){const[u,c]=a.split("."),l=o.find(m=>m?.name===u);if(l&&l.measures[c]){const m=l.measures[c];n[a]={title:m.title||c,shortTitle:m.title||c,type:m.type}}}if(t.dimensions)for(const a of t.dimensions){const[u,c]=a.split("."),l=o.find(m=>m?.name===u);if(l&&l.dimensions?.[c]){const m=l.dimensions[c];s[a]={title:m.title||c,shortTitle:m.title||c,type:m.type}}}if(t.timeDimensions)for(const a of t.timeDimensions){const[u,c]=a.dimension.split("."),l=o.find(m=>m?.name===u);if(l&&l.dimensions?.[c]){const m=l.dimensions[c];i[a.dimension]={title:m.title||c,shortTitle:m.title||c,type:m.type,granularity:a.granularity}}}return{measures:n,dimensions:s,segments:{},timeDimensions:i}}preloadFilterCache(e,t,n,s){if(e.filters&&e.filters.length>0){const i=ve(e.filters);for(const o of i){const a=de(o);if(t.has(a))continue;const[u,c]=o.member.split("."),l=n.get(u);if(!l)continue;const m=l.dimensions?.[c];if(!m||["arrayContains","arrayOverlaps","arrayContained"].includes(o.operator))continue;const p=R(m.sql,s),h=this.queryBuilder.buildFilterConditionPublic(p,o.operator,o.values,m,o.dateRange);h&&t.set(a,h)}}if(e.timeDimensions){for(const i of e.timeDimensions)if(i.dateRange){const o=it(i.dimension,i.dateRange);if(t.has(o))continue;const[a,u]=i.dimension.split("."),c=n.get(a);if(!c)continue;const l=c.dimensions?.[u];if(!l)continue;const m=R(l.sql,s),f=this.queryBuilder.buildDateRangeCondition(m,i.dateRange);f&&t.set(o,f)}}}buildPostAggregationWindowExpression(e,t,n,s,i,o){const a=e.windowConfig||{},u=(p,h)=>{if(!o?.preAggregationCTEs)return null;const g=o.preAggregationCTEs.find(y=>y.cube?.name===p);return g&&g.cteAlias?r`${r.identifier(g.cteAlias)}.${r.identifier(h)}`:null};let c;if(a.orderBy&&a.orderBy.length>0)c=a.orderBy.map(p=>{const h=p.field.includes(".")?p.field.split(".")[1]:p.field;if(n.timeDimensions)for(const b of n.timeDimensions){const[w,$]=b.dimension.split(".");if($===h){const S=u(w,h);if(S)return{field:S,direction:p.direction};const C=i.dimensions?.[$];if(C)return{field:this.queryBuilder.buildTimeDimensionExpression(C.sql,b.granularity,s),direction:p.direction}}}const g=i.dimensions?.[h];if(g)return{field:R(g.sql,s),direction:p.direction};const y=a.measure?.includes(".")?a.measure.split(".")[1]:a.measure;return h===y||p.field===a.measure?{field:t,direction:p.direction}:null}).filter(p=>p!==null);else if(n.timeDimensions&&n.timeDimensions.length>0){const p=n.timeDimensions[0],[h,g]=p.dimension.split("."),y=u(h,g);if(y)c=[{field:y,direction:"asc"}];else{const b=i.name===h?i:void 0;if(b?.dimensions?.[g]){const w=b.dimensions[g];c=[{field:this.queryBuilder.buildTimeDimensionExpression(w.sql,p.granularity,s),direction:"asc"}]}}}let l;a.partitionBy&&a.partitionBy.length>0&&(l=a.partitionBy.map(p=>{const h=p.includes(".")?p.split(".")[1]:p,g=i.dimensions?.[h];return g?R(g.sql,s):null}).filter(p=>p!==null));const m=this.databaseAdapter.buildWindowFunction(e.type,t,l,c,{offset:a.offset,defaultValue:a.defaultValue,nTile:a.nTile,frame:a.frame});if(!m)return null;switch(a.operation||O.getDefaultWindowOperation(e.type)){case"difference":return r`${t} - ${m}`;case"ratio":return r`${t} / NULLIF(${m}, 0)`;case"percentChange":return r`((${t} - ${m}) / NULLIF(${m}, 0)) * 100`;default:return m}}}const pn={name:"drizzle-cube-mcp-guide",description:"How to use drizzle-cube MCP tools to generate and run queries",messages:[{role:"user",content:{type:"text",text:["You are an analyst agent using drizzle-cube MCP.","","Workflow:","1) tools/call name=discover {topic|intent} - Find cubes and understand schema","2) Construct your query using the schema from discover (see cross-cube joins below)","3) tools/call name=validate {query} - Optional: fix schema issues","4) tools/call name=load {query} - Execute and get results","","CRITICAL - CROSS-CUBE JOINS:",'The "joins" property in discover results shows relationships between cubes.',"You can include dimensions from ANY related cube in your query!","Example: If Productivity joins to Employees, query:",'{ "measures": ["Productivity.totalPullRequests"], "dimensions": ["Employees.name"] }',"The system automatically joins the cubes for you.","","Query shapes:","- Regular: { measures, dimensions, filters[], timeDimensions[], order, limit, offset }","- Funnel: { funnel: { bindingKey, timeDimension, steps[], includeTimeMetrics? } }","- Flow: { flow: { bindingKey, eventDimension, steps?, window? } }","- Retention: { retention: { bindingKey, timeDimension, periods, granularity, retentionType, breakdownDimensions } }","","Time handling:",'- For AGGREGATED TOTALS (e.g., "last 3 months"): use filters with inDateRange, NOT timeDimensions','- For TIME SERIES (e.g., "by month"): use timeDimensions with granularity',"- You can combine both when needed","","Filters: flat arrays of { member, operator, values }. Do not nest arrays.","Do NOT hallucinate cube/field names—always use discover first."].join(`
193
+ GROUP BY binding_key${o.raw(i)}
194
+ )`,a=this.databaseAdapter.buildPeriodSeriesSubquery(e.periods),u={period_number:o`p.period_number`.as("period_number"),retained_users:o`COUNT(DISTINCT CASE WHEN ump.max_period >= p.period_number THEN ump.binding_key END)`.as("retained_users")},c=[o`p.period_number`];for(let l=0;l<n;l++)u[`breakdown_${l}`]=o.raw(`ump.breakdown_${l}`).as(`breakdown_${l}`),c.push(o.raw(`ump.breakdown_${l}`));return t.db.select(u).from(o`${r} ump`).crossJoin(a).groupBy(...c)}buildPeriodNumberExpression(e,t,n){return this.databaseAdapter.buildDateDiffPeriods(e,t,n)}extractDimensionName(e){const t=e.split(".");return t.length>1?t[1]:t[0]}}class G{constructor(e,t){if(this.dbExecutor=e,this.databaseAdapter=e.databaseAdapter,!this.databaseAdapter)throw new Error("DatabaseExecutor must have a databaseAdapter property");this.queryBuilder=new tn(this.databaseAdapter),this.queryPlanner=new rt,this.cteBuilder=new nn(this.queryBuilder),this.comparisonQueryBuilder=new cn(this.databaseAdapter),this.funnelQueryBuilder=new dn(this.databaseAdapter),this.flowQueryBuilder=new mn(this.databaseAdapter),this.retentionQueryBuilder=new fn(this.databaseAdapter),this.cacheConfig=t}queryBuilder;queryPlanner;cteBuilder;databaseAdapter;comparisonQueryBuilder;funnelQueryBuilder;flowQueryBuilder;retentionQueryBuilder;cacheConfig;async execute(e,t,n,s){try{if(this.funnelQueryBuilder.hasFunnel(t)){const b=this.funnelQueryBuilder.validateConfig(t.funnel,e);if(!b.isValid)throw new Error(`Funnel validation failed: ${b.errors.join(", ")}`)}else if(this.flowQueryBuilder.hasFlow(t)){const b=this.flowQueryBuilder.validateConfig(t.flow,e);if(!b.isValid)throw new Error(`Flow validation failed: ${b.errors.join(", ")}`)}else if(this.retentionQueryBuilder.hasRetention(t)){const b=this.retentionQueryBuilder.validateConfig(t.retention,e);if(!b.isValid)throw new Error(`Retention validation failed: ${b.errors.join(", ")}`)}else{const b=at(e,t);if(!b.isValid)throw new Error(`Query validation failed: ${b.errors.join(", ")}`)}let i;if(this.cacheConfig?.enabled!==!1&&this.cacheConfig?.provider)if(i=zt(t,n,this.cacheConfig),s?.skipCache)this.cacheConfig.onCacheEvent?.({type:"miss",key:i,durationMs:0});else try{const b=Date.now(),w=await this.cacheConfig.provider.get(i);if(w)return this.cacheConfig.onCacheEvent?.({type:"hit",key:i,durationMs:Date.now()-b}),{...w.value,cache:w.metadata?{hit:!0,cachedAt:new Date(w.metadata.cachedAt).toISOString(),ttlMs:w.metadata.ttlMs,ttlRemainingMs:w.metadata.ttlRemainingMs}:{hit:!0,cachedAt:new Date().toISOString(),ttlMs:0,ttlRemainingMs:0}};this.cacheConfig.onCacheEvent?.({type:"miss",key:i,durationMs:Date.now()-b})}catch(b){this.cacheConfig.onError?.(b,"get")}if(this.comparisonQueryBuilder.hasComparison(t))return this.executeComparisonQueryWithCache(e,t,n,i);if(this.funnelQueryBuilder.hasFunnel(t))return this.executeFunnelQueryWithCache(e,t,n,i);if(this.flowQueryBuilder.hasFlow(t))return this.executeFlowQueryWithCache(e,t,n,i);if(this.retentionQueryBuilder.hasRetention(t))return this.executeRetentionQueryWithCache(e,t,n,i);const r=new Ke,a={db:this.dbExecutor.db,schema:this.dbExecutor.schema,securityContext:n,filterCache:r};this.preloadFilterCache(t,r,e,a);const u=this.queryPlanner.createQueryPlan(e,t,a);this.validateSecurityContext(u,a);const c=this.buildUnifiedQuery(u,t,a),l=this.queryBuilder.collectNumericFields(e,t),m=await this.dbExecutor.execute(c,l),p=Array.isArray(m)?m.map(b=>{const w={...b};if(t.timeDimensions){for(const _ of t.timeDimensions)if(_.dimension in w){let $=w[_.dimension];if(typeof $=="string"&&$.match(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/)){const C=$.replace(" ","T"),E=!C.endsWith("Z")&&!C.includes("+")?C+"Z":C;$=new Date(E)}$=this.databaseAdapter.convertTimeDimensionResult($),w[_.dimension]=$}}return w}):[m],f=t.measures||[],h=Ve(p,t,f),g=this.generateAnnotations(u,t),y={data:h,annotation:g,warnings:u.warnings?.length?u.warnings:void 0};if(i&&this.cacheConfig?.provider)try{const b=Date.now();await this.cacheConfig.provider.set(i,y,this.cacheConfig.defaultTtlMs??3e5),this.cacheConfig.onCacheEvent?.({type:"set",key:i,durationMs:Date.now()-b})}catch(b){this.cacheConfig.onError?.(b,"set")}return y}catch(i){if(i instanceof Error){let r=i;for(;r.cause instanceof Error;)r=r.cause;let a=r.message;const u=r;throw u.code&&(a+=` [${u.code}]`),u.detail&&(a+=` Detail: ${u.detail}`),u.hint&&(a+=` Hint: ${u.hint}`),i.message=`Query execution failed: ${a}`,i}throw new Error("Query execution failed: Unknown error")}}async executeQuery(e,t,n){const s=new Map;return s.set(e.name,e),this.execute(s,t,n)}async executeComparisonQueryWithCache(e,t,n,s){const i=await this.executeComparisonQuery(e,t,n);if(s&&this.cacheConfig?.provider)try{const r=Date.now();await this.cacheConfig.provider.set(s,i,this.cacheConfig.defaultTtlMs??3e5),this.cacheConfig.onCacheEvent?.({type:"set",key:s,durationMs:Date.now()-r})}catch(r){this.cacheConfig.onError?.(r,"set")}return i}async executeComparisonQuery(e,t,n){const s=this.comparisonQueryBuilder.getComparisonTimeDimension(t);if(!s||!s.compareDateRange)throw new Error("No compareDateRange found in query");const i=this.comparisonQueryBuilder.normalizePeriods(s.compareDateRange);if(i.length<2)throw new Error("compareDateRange requires at least 2 periods");const r=s.granularity||"day",a=i.map(async l=>{const m=this.comparisonQueryBuilder.createPeriodQuery(t,l);return{result:await this.executeStandardQuery(e,m,n),period:l}}),u=await Promise.all(a),c=this.comparisonQueryBuilder.mergeComparisonResults(u,s,r);return c.data=this.comparisonQueryBuilder.sortComparisonResults(c.data,s.dimension),c}async executeFunnelQueryWithCache(e,t,n,s){const i=await this.executeFunnelQuery(e,t,n);if(s&&this.cacheConfig?.provider)try{const r=Date.now();await this.cacheConfig.provider.set(s,i,this.cacheConfig.defaultTtlMs??3e5),this.cacheConfig.onCacheEvent?.({type:"set",key:s,durationMs:Date.now()-r})}catch(r){this.cacheConfig.onError?.(r,"set")}return{...i,cache:{hit:!1}}}async executeFunnelQuery(e,t,n){const s=t.funnel,i=this.funnelQueryBuilder.validateConfig(s,e);if(!i.isValid)throw new Error(`Funnel validation failed: ${i.errors.join(", ")}`);const r={db:this.dbExecutor.db,schema:this.dbExecutor.schema,securityContext:n},u=await this.funnelQueryBuilder.buildFunnelQuery(s,e,r),c=this.funnelQueryBuilder.transformResult(u,s),l={measures:{},dimensions:{},segments:{},timeDimensions:{}};return l.funnel={config:s,steps:s.steps.map((m,p)=>({name:m.name,index:p,timeToConvert:m.timeToConvert}))},{data:c,annotation:l}}async executeFlowQueryWithCache(e,t,n,s){const i=await this.executeFlowQuery(e,t,n);if(s&&this.cacheConfig?.provider)try{const r=Date.now();await this.cacheConfig.provider.set(s,i,this.cacheConfig.defaultTtlMs??3e5),this.cacheConfig.onCacheEvent?.({type:"set",key:s,durationMs:Date.now()-r})}catch(r){this.cacheConfig.onError?.(r,"set")}return{...i,cache:{hit:!1}}}async executeFlowQuery(e,t,n){const s=t.flow,i=this.flowQueryBuilder.validateConfig(s,e);if(!i.isValid)throw new Error(`Flow validation failed: ${i.errors.join(", ")}`);const r={db:this.dbExecutor.db,schema:this.dbExecutor.schema,securityContext:n},u=await this.flowQueryBuilder.buildFlowQuery(s,e,r),c=this.flowQueryBuilder.transformResult(u),l={measures:{},dimensions:{},segments:{},timeDimensions:{}};return l.flow={config:s,startingStep:{name:s.startingStep.name},stepsBefore:s.stepsBefore,stepsAfter:s.stepsAfter},{data:[c],annotation:l}}async executeRetentionQueryWithCache(e,t,n,s){const i=await this.executeRetentionQuery(e,t,n);if(s&&this.cacheConfig?.provider)try{const r=Date.now();await this.cacheConfig.provider.set(s,i,this.cacheConfig.defaultTtlMs??3e5),this.cacheConfig.onCacheEvent?.({type:"set",key:s,durationMs:Date.now()-r})}catch(r){this.cacheConfig.onError?.(r,"set")}return{...i,cache:{hit:!1}}}async executeRetentionQuery(e,t,n){const s=t.retention,i=this.retentionQueryBuilder.validateConfig(s,e);if(!i.isValid)throw new Error(`Retention validation failed: ${i.errors.join(", ")}`);const r={db:this.dbExecutor.db,schema:this.dbExecutor.schema,securityContext:n},u=await this.retentionQueryBuilder.buildRetentionQuery(s,e,r),c=this.retentionQueryBuilder.transformResult(u,s),l={measures:{},dimensions:{},segments:{},timeDimensions:{}};return l.retention={config:s,granularity:s.granularity,periods:s.periods,retentionType:s.retentionType,breakdownDimensions:s.breakdownDimensions},{data:c,annotation:l}}async executeStandardQuery(e,t,n){const s=new Ke,i={db:this.dbExecutor.db,schema:this.dbExecutor.schema,securityContext:n,filterCache:s};this.preloadFilterCache(t,s,e,i);const r=this.queryPlanner.createQueryPlan(e,t,i),a=this.buildUnifiedQuery(r,t,i),u=this.queryBuilder.collectNumericFields(e,t),c=await this.dbExecutor.execute(a,u),l=Array.isArray(c)?c.map(h=>{const g={...h};if(t.timeDimensions){for(const y of t.timeDimensions)if(y.dimension in g){let b=g[y.dimension];if(typeof b=="string"&&b.match(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/)){const w=b.replace(" ","T"),_=!w.endsWith("Z")&&!w.includes("+")?w+"Z":w;b=new Date(_)}b=this.databaseAdapter.convertTimeDimensionResult(b),g[y.dimension]=b}}return g}):[c],m=t.measures||[],p=Ve(l,t,m),f=this.generateAnnotations(r,t);return{data:p,annotation:f}}validateSecurityContext(e,t){const n=typeof process<"u"?process.env?.NODE_ENV:void 0,s=typeof process<"u"?process.env?.DRIZZLE_CUBE_WARN_SECURITY:void 0;if(n!=="development"&&!s)return;const i=[e.primaryCube];for(const a of e.joinCubes||[])i.push(a.cube);for(const a of e.preAggregationCTEs||[])i.push(a.cube);const r=new Set;for(const a of i)if(!r.has(a.name)){r.add(a.name);try{if(a.public)continue;a.sql(t).where||console.warn(`[drizzle-cube] WARNING: Cube '${a.name}' has no security filtering. If this cube contains public data, add 'public: true' to suppress this warning. Otherwise, ensure sql() returns: { from: table, where: eq(table.orgId, ctx.securityContext.orgId) }`)}catch{}}}buildUnifiedQuery(e,t,n){const s=new Map;if(e.preAggregationCTEs&&e.preAggregationCTEs.length>0){for(const $ of e.preAggregationCTEs)if($.propagatingFilters&&$.propagatingFilters.length>0)for(const C of $.propagatingFilters){const E=C.sourceCube.name;if(!s.has(E)){const N={filters:C.filters},S=new Map([[E,C.sourceCube]]),D=this.queryBuilder.buildWhereConditions(S,N,n);s.set(E,D)}const T=s.get(E);T&&T.length>0&&(C.preBuiltFilterSQL=T.length===1?T[0]:A(...T))}}const i=[],r=new Map,a=new Map;if(e.preAggregationCTEs&&e.preAggregationCTEs.length>0)for(const $ of e.preAggregationCTEs){const C=this.cteBuilder.buildPreAggregationCTE($,t,n,e,s);if(C&&(i.push(C),r.set($.cube.name,$.cteAlias),$.downstreamJoinKeys))for(const E of $.downstreamJoinKeys)a.set(E.targetCubeName,{cteAlias:$.cteAlias,joinKeys:E.joinKeys})}const u=e.primaryCube.sql(n),c=e.joinCubes.length>0?this.getCubesFromPlan(e):new Map([[e.primaryCube.name,e.primaryCube]]),m={...this.queryBuilder.buildSelections(e.joinCubes.length>0?c:e.primaryCube,t,n)};if(e.preAggregationCTEs)for(const $ of e.preAggregationCTEs){const C=$.cube.name;for(const E of $.measures)if(m[E]){const[,T]=E.split("."),N=c.get(C);if(N&&N.measures&&N.measures[T]){const S=N.measures[T],D=o`${o.identifier($.cteAlias)}.${o.identifier(T)}`;let O;if(S.type==="calculated"&&S.calculatedSql)O=this.queryBuilder.buildCTECalculatedMeasure(S,N,$,c,n);else{const R=$.cteReason==="fanOutPrevention",k=this.shouldUseMaxForHasManyAtJoinKeyGrain($,t,c),M=R||k;switch(S.type){case"count":case"countDistinct":case"sum":O=M?J(D):K(D);break;case"avg":O=M?J(D):this.databaseAdapter.buildAvg(D);break;case"min":O=re(D);break;case"max":O=J(D);break;case"number":O=M?J(D):K(D);break;default:O=M?J(D):K(D)}}m[E]=o`${O}`.as(E)}}for(const E in m){const[T,N]=E.split(".");if(T===C){const S=c.get(C),D=S&&S.dimensions?.[N],O=E.startsWith(C+".");if(D||O){let R=$.joinKeys.find(k=>k.targetColumn===N);if(!R&&S?.dimensions?.[N]){const k=S.dimensions[N].sql;R=$.joinKeys.find(M=>M.targetColumnObj===k)}R?m[E]=o`${o.identifier($.cteAlias)}.${o.identifier(N)}`.as(E):O&&S?.dimensions?.[N]&&(m[E]=o`${o.identifier($.cteAlias)}.${o.identifier(N)}`.as(E))}}}}if(t.measures)for(const $ of t.measures){const[C,E]=$.split("."),T=c.get(C);if(T?.measures?.[E]){const N=T.measures[E];if(I.isPostAggregationWindow(N)){const S=I.getWindowBaseMeasure(N,C);if(S){const[D,O]=S.split("."),R=c.get(D);if(R?.measures?.[O]){const k=R.measures[O],M=e.preAggregationCTEs?.find(Y=>Y.cube?.name===D&&Y.measures?.includes(S));let V;if(M){const Y=o`${o.identifier(M.cteAlias)}.${o.identifier(O)}`;V=o`sum(${Y})`}else V=this.queryBuilder.buildMeasureExpression(k,n,R);m[S]||(m[S]=o`${V}`.as(S));const se=this.buildPostAggregationWindowExpression(N,V,t,n,T,e);se&&(m[$]=o`${se}`.as($))}}}}}const p=[];let f=n.db.select(m).from(u.from);if(i.length>0&&(f=n.db.with(...i).select(m).from(u.from)),u.joins)for(const $ of u.joins)switch($.type||"left"){case"left":f=f.leftJoin($.table,$.on);break;case"inner":f=f.innerJoin($.table,$.on);break;case"right":f=f.rightJoin($.table,$.on);break;case"full":f=f.fullJoin($.table,$.on);break}const h=new Set,g=new Set;if(e.preAggregationCTEs){for(const $ of e.preAggregationCTEs)if($.intermediateJoins&&$.intermediateJoins.length>0)for(const C of $.intermediateJoins)g.add(C.cube.name)}if(e.joinCubes&&e.joinCubes.length>0)for(const $ of e.joinCubes){const C=$.cube.name;if(g.has(C)&&!r.has(C))continue;const E=r.get($.cube.name);if($.junctionTable){const R=$.junctionTable,k=[];if(R.securitySql){const M=R.securitySql(n.securityContext);Array.isArray(M)?k.push(...M):k.push(M)}try{switch(R.joinType||"left"){case"left":f=f.leftJoin(R.table,R.joinCondition);break;case"inner":f=f.innerJoin(R.table,R.joinCondition);break;case"right":f=f.rightJoin(R.table,R.joinCondition);break;case"full":f=f.fullJoin(R.table,R.joinCondition);break}k.length>0&&p.push(...k)}catch{}}let T,N,S;if(E)T=o`${o.identifier(E)}`,N=this.cteBuilder.buildCTEJoinCondition($,E,e),S=void 0;else{const R=a.get($.cube.name),k=$.cube.sql(n);if(T=k.from,S=k.where,R){const M=[];for(const V of R.joinKeys){const se=o`${o.identifier(R.cteAlias)}.${o.identifier(V.sourceColumn)}`,Y=V.targetColumnObj||o.identifier(V.targetColumn);M.push(Q(se,Y))}N=M.length===1?M[0]:A(...M)}else N=$.joinCondition}const D=$.joinType||"left",O=D!=="inner"&&S?A(N,S):N;try{switch(D){case"left":f=f.leftJoin(T,O),S&&h.add($.cube.name);break;case"inner":f=f.innerJoin(T,N);break;case"right":f=f.rightJoin(T,O),S&&h.add($.cube.name);break;case"full":f=f.fullJoin(T,O),S&&h.add($.cube.name);break}}catch{}}if(u.where&&p.push(u.where),e.joinCubes&&e.joinCubes.length>0)for(const $ of e.joinCubes){const C=$.cube.name;if(r.get(C)||g.has(C)||h.has(C))continue;const T=$.cube.sql(n);T.where&&p.push(T.where)}const y=this.queryBuilder.buildWhereConditions(e.joinCubes.length>0?this.getCubesFromPlan(e):e.primaryCube,t,n,e,s);if(y.length>0&&p.push(...y),p.length>0){const $=p.length===1?p[0]:A(...p);f=f.where($)}const b=this.queryBuilder.buildGroupByFields(e.joinCubes.length>0?this.getCubesFromPlan(e):e.primaryCube,t,n,e);b.length>0&&(f=f.groupBy(...b));const w=this.queryBuilder.buildHavingConditions(e.joinCubes.length>0?this.getCubesFromPlan(e):e.primaryCube,t,n,e);if(w.length>0){const $=w.length===1?w[0]:A(...w);f=f.having($)}const _=this.queryBuilder.buildOrderBy(t);return _.length>0&&(f=f.orderBy(..._)),f=this.queryBuilder.applyLimitAndOffset(f,t),f}getCubesFromPlan(e){const t=new Map;if(t.set(e.primaryCube.name,e.primaryCube),e.joinCubes)for(const n of e.joinCubes)t.set(n.cube.name,n.cube);return t}shouldUseMaxForHasManyAtJoinKeyGrain(e,t,n){return e.cteReason!=="hasMany"||e.downstreamJoinKeys&&e.downstreamJoinKeys.length>0||e.intermediateJoins&&e.intermediateJoins.length>0||!!!(t.dimensions&&t.dimensions.length>0||t.timeDimensions&&t.timeDimensions.length>0)||!!(t.dimensions?.some(r=>r.startsWith(`${e.cube.name}.`))||t.timeDimensions?.some(r=>r.dimension.startsWith(`${e.cube.name}.`)))?!1:e.joinKeys.length>0&&e.joinKeys.every(r=>!!r.sourceColumnObj&&this.queryGroupsByColumn(r.sourceColumnObj,t,n))}queryGroupsByColumn(e,t,n){if(t.dimensions)for(const s of t.dimensions){const[i,r]=s.split(".");if(n.get(i)?.dimensions?.[r]?.sql===e)return!0}if(t.timeDimensions)for(const s of t.timeDimensions){if(s.granularity)continue;const[i,r]=s.dimension.split(".");if(n.get(i)?.dimensions?.[r]?.sql===e)return!0}return!1}async generateSQL(e,t,n){const s=new Map;return s.set(e.name,e),this.generateUnifiedSQL(s,t,n)}async generateMultiCubeSQL(e,t,n){return this.generateUnifiedSQL(e,t,n)}async dryRunFunnel(e,t,n){if(!this.funnelQueryBuilder.hasFunnel(t))throw new Error("Query does not contain a valid funnel configuration");const s=t.funnel,i=this.funnelQueryBuilder.validateConfig(s,e);if(!i.isValid)throw new Error(`Funnel validation failed: ${i.errors.join(", ")}`);const r={db:this.dbExecutor.db,schema:this.dbExecutor.schema,securityContext:n},u=this.funnelQueryBuilder.buildFunnelQuery(s,e,r).toSQL();return{sql:u.sql,params:u.params}}async dryRunFlow(e,t,n){if(!this.flowQueryBuilder.hasFlow(t))throw new Error("Query does not contain a valid flow configuration");const s=t.flow,i=this.flowQueryBuilder.validateConfig(s,e);if(!i.isValid)throw new Error(`Flow validation failed: ${i.errors.join(", ")}`);const r={db:this.dbExecutor.db,schema:this.dbExecutor.schema,securityContext:n},u=this.flowQueryBuilder.buildFlowQuery(s,e,r).toSQL();return{sql:u.sql,params:u.params}}async dryRunRetention(e,t,n){if(!this.retentionQueryBuilder.hasRetention(t))throw new Error("Query does not contain a valid retention configuration");const s=t.retention,i=this.retentionQueryBuilder.validateConfig(s,e);if(!i.isValid)throw new Error(`Retention validation failed: ${i.errors.join(", ")}`);const r={db:this.dbExecutor.db,schema:this.dbExecutor.schema,securityContext:n},u=this.retentionQueryBuilder.buildRetentionQuery(s,e,r).toSQL();return{sql:u.sql,params:u.params}}async explainQuery(e,t,n,s){let i;return this.funnelQueryBuilder.hasFunnel(t)?i=await this.dryRunFunnel(e,t,n):this.flowQueryBuilder.hasFlow(t)?i=await this.dryRunFlow(e,t,n):this.retentionQueryBuilder.hasRetention(t)?i=await this.dryRunRetention(e,t,n):i=await this.generateUnifiedSQL(e,t,n),this.dbExecutor.explainQuery(i.sql,i.params||[],s)}async generateUnifiedSQL(e,t,n){const s={db:this.dbExecutor.db,schema:this.dbExecutor.schema,securityContext:n},i=this.queryPlanner.createQueryPlan(e,t,s),a=this.buildUnifiedQuery(i,t,s).toSQL();return{sql:a.sql,params:a.params}}generateAnnotations(e,t){const n={},s={},i={},r=[e.primaryCube].filter(Boolean);if(e.joinCubes&&e.joinCubes.length>0&&r.push(...e.joinCubes.map(a=>a.cube).filter(Boolean)),t.measures)for(const a of t.measures){const[u,c]=a.split("."),l=r.find(m=>m?.name===u);if(l&&l.measures[c]){const m=l.measures[c];n[a]={title:m.title||c,shortTitle:m.title||c,type:m.type}}}if(t.dimensions)for(const a of t.dimensions){const[u,c]=a.split("."),l=r.find(m=>m?.name===u);if(l&&l.dimensions?.[c]){const m=l.dimensions[c];s[a]={title:m.title||c,shortTitle:m.title||c,type:m.type}}}if(t.timeDimensions)for(const a of t.timeDimensions){const[u,c]=a.dimension.split("."),l=r.find(m=>m?.name===u);if(l&&l.dimensions?.[c]){const m=l.dimensions[c];i[a.dimension]={title:m.title||c,shortTitle:m.title||c,type:m.type,granularity:a.granularity}}}return{measures:n,dimensions:s,segments:{},timeDimensions:i}}preloadFilterCache(e,t,n,s){if(e.filters&&e.filters.length>0){const i=ve(e.filters);for(const r of i){const a=de(r);if(t.has(a))continue;const[u,c]=r.member.split("."),l=n.get(u);if(!l)continue;const m=l.dimensions?.[c];if(!m||["arrayContains","arrayOverlaps","arrayContained"].includes(r.operator))continue;const f=v(m.sql,s),h=this.queryBuilder.buildFilterConditionPublic(f,r.operator,r.values,m,r.dateRange);h&&t.set(a,h)}}if(e.timeDimensions){for(const i of e.timeDimensions)if(i.dateRange){const r=it(i.dimension,i.dateRange);if(t.has(r))continue;const[a,u]=i.dimension.split("."),c=n.get(a);if(!c)continue;const l=c.dimensions?.[u];if(!l)continue;const m=v(l.sql,s),p=this.queryBuilder.buildDateRangeCondition(m,i.dateRange);p&&t.set(r,p)}}}buildPostAggregationWindowExpression(e,t,n,s,i,r){const a=e.windowConfig||{},u=(f,h)=>{if(!r?.preAggregationCTEs)return null;const g=r.preAggregationCTEs.find(y=>y.cube?.name===f);return g&&g.cteAlias?o`${o.identifier(g.cteAlias)}.${o.identifier(h)}`:null};let c;if(a.orderBy&&a.orderBy.length>0)c=a.orderBy.map(f=>{const h=f.field.includes(".")?f.field.split(".")[1]:f.field;if(n.timeDimensions)for(const b of n.timeDimensions){const[w,_]=b.dimension.split(".");if(_===h){const $=u(w,h);if($)return{field:$,direction:f.direction};const C=i.dimensions?.[_];if(C)return{field:this.queryBuilder.buildTimeDimensionExpression(C.sql,b.granularity,s),direction:f.direction}}}const g=i.dimensions?.[h];if(g)return{field:v(g.sql,s),direction:f.direction};const y=a.measure?.includes(".")?a.measure.split(".")[1]:a.measure;return h===y||f.field===a.measure?{field:t,direction:f.direction}:null}).filter(f=>f!==null);else if(n.timeDimensions&&n.timeDimensions.length>0){const f=n.timeDimensions[0],[h,g]=f.dimension.split("."),y=u(h,g);if(y)c=[{field:y,direction:"asc"}];else{const b=i.name===h?i:void 0;if(b?.dimensions?.[g]){const w=b.dimensions[g];c=[{field:this.queryBuilder.buildTimeDimensionExpression(w.sql,f.granularity,s),direction:"asc"}]}}}let l;a.partitionBy&&a.partitionBy.length>0&&(l=a.partitionBy.map(f=>{const h=f.includes(".")?f.split(".")[1]:f,g=i.dimensions?.[h];return g?v(g.sql,s):null}).filter(f=>f!==null));const m=this.databaseAdapter.buildWindowFunction(e.type,t,l,c,{offset:a.offset,defaultValue:a.defaultValue,nTile:a.nTile,frame:a.frame});if(!m)return null;switch(a.operation||I.getDefaultWindowOperation(e.type)){case"difference":return o`${t} - ${m}`;case"ratio":return o`${t} / NULLIF(${m}, 0)`;case"percentChange":return o`((${t} - ${m}) / NULLIF(${m}, 0)) * 100`;default:return m}}}const pn={name:"drizzle-cube-mcp-guide",description:"How to use drizzle-cube MCP tools to generate and run queries",messages:[{role:"user",content:{type:"text",text:["You are an analyst agent using drizzle-cube MCP.","","Workflow:","1) tools/call name=discover {topic|intent} - Find cubes and understand schema","2) Construct your query using the schema from discover (see cross-cube joins below)","3) tools/call name=validate {query} - Optional: fix schema issues","4) tools/call name=load {query} - Execute and get results","","CRITICAL - CROSS-CUBE JOINS:",'The "joins" property in discover results shows relationships between cubes.',"You can include dimensions from ANY related cube in your query!","Example: If Productivity joins to Employees, query:",'{ "measures": ["Productivity.totalPullRequests"], "dimensions": ["Employees.name"] }',"The system automatically joins the cubes for you.","","Query shapes:","- Regular: { measures, dimensions, filters[], timeDimensions[], order, limit, offset }","- Funnel: { funnel: { bindingKey, timeDimension, steps[], includeTimeMetrics? } }","- Flow: { flow: { bindingKey, eventDimension, steps?, window? } }","- Retention: { retention: { bindingKey, timeDimension, periods, granularity, retentionType, breakdownDimensions } }","","Time handling:",'- For AGGREGATED TOTALS (e.g., "last 3 months"): use filters with inDateRange, NOT timeDimensions','- For TIME SERIES (e.g., "by month"): use timeDimensions with granularity',"- You can combine both when needed","","Filters: flat arrays of { member, operator, values }. Do not nest arrays.","Do NOT hallucinate cube/field names—always use discover first."].join(`
195
195
  `)}}]},hn={name:"drizzle-cube-query-rules",description:"Key generation rules aligned with Gemini single-step prompt",messages:[{role:"user",content:{type:"text",text:["Rules (keep JSON only):","- Use only measures/dimensions/timeDimensions from schema.","- timeDimensions: include granularity when grouping; use inDateRange filter for relative windows; combine when both requested.","- Funnel detection keywords: funnel, conversion, journey, drop off, step by step; use funnel format only if eventStream metadata exists.","- Funnel rules: bindingKey/timeDimension from cube metadata; include time filter on step 0 (default last 6 months) using inDateRange; steps ordered; flat filters.","- Chart selection: line/area for time trends; bar for categories; scatter for 2-measure correlations; bubble for 3-measure correlations; funnel for funnels.","- Correlation keywords (correlation/relationship/vs/compare) -> scatter/bubble, never line.","- Prefer .name fields over .id; avoid Id dimensions unless requested.","- Filters: flat array of {member, operator, values}; operators equals, notEquals, contains, notContains, gt, gte, lt, lte, inDateRange, set, notSet."].join(`
196
196
  `)}}]},gn={name:"drizzle-cube-query-building",description:"CRITICAL: Complete guide for building valid queries of all types with examples",messages:[{role:"user",content:{type:"text",text:["# Drizzle Cube Query Building Guide","","## CRITICAL: Cross-Cube Joins","","You can combine measures from one cube with dimensions from RELATED cubes!",'Check the "joins" property in discover results to see relationships.',"",'Example: "Top 5 employees by pull requests last 3 months"',"- Productivity cube has: measures (totalPullRequests), dimensions (date)","- Productivity joins to Employees (via employeeId)","- Employees cube has: dimensions (name, department)","","Query combining BOTH cubes:","```json","{",' "measures": ["Productivity.totalPullRequests"],',' "dimensions": ["Employees.name"],',' "filters": [',' { "member": "Productivity.date", "operator": "inDateRange", "values": ["last 3 months"] }'," ],",' "order": { "Productivity.totalPullRequests": "desc" },',' "limit": 5',"}","```","The system AUTOMATICALLY joins Productivity to Employees for you!","","---","","## Date Filtering vs Time Grouping","","### For AGGREGATED TOTALS (no time breakdown)","Use `filters` with `inDateRange` operator. Do NOT use timeDimensions.","","```json","{",' "measures": ["Productivity.totalPullRequests"],',' "dimensions": ["Employees.name"],',' "filters": [{ "member": "Productivity.date", "operator": "inDateRange", "values": ["last 3 months"] }],',' "order": { "Productivity.totalPullRequests": "desc" },',' "limit": 5',"}","```","Result: 5 rows total, one per employee, with SUMMED pull requests.","","### For TIME SERIES (grouped by period)","Use `timeDimensions` WITH `granularity`.","","```json","{",' "measures": ["Productivity.totalPullRequests"],',' "timeDimensions": [{ "dimension": "Productivity.date", "dateRange": "last 3 months", "granularity": "month" }]',"}","```","Result: 3 rows (one per month) with pull request totals.","","### WRONG: timeDimensions without granularity","```json","// DON'T DO THIS - groups by DAY, returns ~90 rows!",'{ "timeDimensions": [{ "dimension": "X.date", "dateRange": "last 3 months" }] }',"```","","---","","## Regular Query Structure","","```json","{",' "measures": ["Cube.measure1", "Cube.measure2"],',' "dimensions": ["Cube.dimension1", "RelatedCube.dimension"],',' "filters": [',' { "member": "Cube.field", "operator": "equals", "values": ["value"] },',' { "member": "Cube.date", "operator": "inDateRange", "values": ["last 30 days"] }'," ],",' "timeDimensions": [],',' "order": { "Cube.measure1": "desc" },',' "limit": 100,',' "offset": 0',"}","```","","### Filter Operators","- String: equals, notEquals, contains, notContains, startsWith, endsWith","- Numeric: gt, gte, lt, lte","- Null: set, notSet","- Date: inDateRange, beforeDate, afterDate","","### Date Range Values",'- Relative: "last 7 days", "last 3 months", "last year", "this week", "this month"','- Absolute: ["2024-01-01", "2024-03-31"]',"","---","","## Funnel Query Structure","","Use when: conversion analysis, user journeys, step-by-step analysis","Requires: Cube with eventStream metadata","","```json","{",' "funnel": {',' "bindingKey": "Events.userId",',' "timeDimension": "Events.timestamp",',' "steps": ['," {",' "name": "Step 1",',' "filter": [',' { "member": "Events.eventType", "operator": "equals", "values": ["signup"] },',' { "member": "Events.timestamp", "operator": "inDateRange", "values": ["last 6 months"] }'," ]"," },"," {",' "name": "Step 2",',' "filter": [',' { "member": "Events.eventType", "operator": "equals", "values": ["purchase"] }'," ],",' "timeToConvert": { "value": 7, "unit": "day" }'," }"," ],",' "includeTimeMetrics": true'," }","}","```","","IMPORTANT: Put time filter (inDateRange) ONLY on step 0!","","---","","## Flow Query Structure","","Use when: analyzing event sequences, path analysis","","```json","{",' "flow": {',' "bindingKey": "Events.sessionId",',' "eventDimension": "Events.eventType",',' "timeDimension": "Events.timestamp",',' "stepsBefore": 2,',' "stepsAfter": 2,',' "startingStep": "checkout"'," }","}","```","","---","","## Retention Query Structure","","Use when: cohort analysis, user retention tracking","","```json","{",' "retention": {',' "bindingKey": "Users.id",',' "timeDimension": "Events.timestamp",',' "periods": 8,',' "granularity": "week",',' "retentionType": "rolling",',' "breakdownDimensions": ["Events.country"]'," }","}","```","","---","","## Common Mistakes to Avoid","","1. Using timeDimensions when you want aggregated totals → Use filters with inDateRange instead","2. Omitting granularity in timeDimensions → Results in day-level grouping","3. Guessing field names → Always use discover first to get actual schema","4. Nested filter arrays → Filters must be flat: [{ member, operator, values }]",'5. Missing date filter for "last N" queries → Always add inDateRange filter'].join(`
197
197
  `)}}]},bn={name:"drizzle-cube-date-filtering",description:"CRITICAL: How to correctly filter by date vs group by time period - the #1 source of query mistakes",messages:[{role:"user",content:{type:"text",text:["# Date Filtering vs Time Grouping - CRITICAL GUIDE","","This is the most common mistake when building queries. These are TWO DIFFERENT operations.","","## Quick Decision Tree","","```","User wants data over a time period?",'├── Wants AGGREGATED TOTALS (e.g., "total sales last month")',"│ └── Use: filters with inDateRange operator","│",'└── Wants TIME SERIES breakdown (e.g., "daily sales last month")'," └── Use: timeDimensions with granularity","```","","## For Aggregated Totals (MOST COMMON)","",'When user says: "last 3 months", "over the past year", "in Q1", "since January"',"","```json","{",' "measures": ["Sales.totalRevenue"],',' "dimensions": ["Products.category"],',' "filters": [',' { "member": "Sales.date", "operator": "inDateRange", "values": ["last 3 months"] }'," ]","}","```","","Result: One row per category with TOTAL revenue over the 3-month period.","","## For Time Series (Trend Analysis)","",'When user says: "by month", "per week", "daily trend", "over time"',"","```json","{",' "measures": ["Sales.totalRevenue"],',' "timeDimensions": [',' { "dimension": "Sales.date", "dateRange": "last 3 months", "granularity": "month" }'," ]","}","```","","Result: Multiple rows, one per month.","","## WRONG: timeDimensions Without Granularity","","```json","// This returns ~90 rows (daily) instead of aggregates!","{",' "timeDimensions": [{ "dimension": "Sales.date", "dateRange": "last 3 months" }]',"}","```","","## Both: Filter AND Group","",'When user wants: "monthly breakdown for last quarter"',"","```json","{",' "measures": ["Sales.totalRevenue"],',' "filters": [',' { "member": "Sales.date", "operator": "inDateRange", "values": ["last quarter"] }'," ],",' "timeDimensions": [',' { "dimension": "Sales.date", "granularity": "month" }'," ]","}","```","","## Summary Table","","| User Request | Use | Example |","|-------------|-----|---------|",'| "total for last 3 months" | filters + inDateRange | { filters: [{ operator: "inDateRange", values: ["last 3 months"] }] } |','| "top 5 last quarter" | filters + inDateRange | Same as above + order + limit |','| "monthly trend" | timeDimensions + granularity | { timeDimensions: [{ granularity: "month" }] } |','| "daily breakdown last week" | timeDimensions | { timeDimensions: [{ dateRange: "last week", granularity: "day" }] } |'].join(`
198
- `)}}]},yn=[pn,hn,gn,bn];function Cn(){return yn}class Fe{cubes=new Map;dbExecutor;metadataCache;cacheConfig;constructor(e){e?.databaseExecutor?this.dbExecutor=e.databaseExecutor:e?.drizzle&&(this.dbExecutor=We(e.drizzle,e.schema,e.engineType)),this.cacheConfig=e?.cache}setDatabaseExecutor(e){this.dbExecutor=e}getEngineType(){return this.dbExecutor?.getEngineType()}setDrizzle(e,t,n){this.dbExecutor=We(e,t,n)}hasExecutor(){return!!this.dbExecutor}registerCube(e){e.meta&&console.log(`[DEBUG] registerCube: ${e.name} has meta:`,JSON.stringify(e.meta)),this.validateCalculatedMeasures(e),new J(this.cubes).populateDependencies(e),this.cubes.set(e.name,e),this.invalidateMetadataCache()}validateCalculatedMeasures(e){const t=[];for(const[n,s]of Object.entries(e.measures))if(s.type==="calculated"){if(!s.calculatedSql){t.push(`Calculated measure '${e.name}.${n}' must have calculatedSql property`);continue}const i=Zt(s.calculatedSql);if(!i.isValid){t.push(`Invalid calculatedSql syntax in '${e.name}.${n}': ${i.errors.join(", ")}`);continue}const o=new Map(this.cubes);o.set(e.name,e);const a=new J(o);try{a.validateDependencies(e)}catch(u){t.push(u instanceof Error?u.message:String(u))}}if(t.length===0){const n=new Map(this.cubes);n.set(e.name,e);const s=new J(n);s.buildGraph(e);const i=s.detectCycle();i&&t.push(`Circular dependency detected in calculated measures: ${i.join(" -> ")}`)}if(t.length>0)throw new Error(`Calculated measure validation failed for cube '${e.name}':
198
+ `)}}]},yn=[pn,hn,gn,bn];function Cn(){return yn}class Fe{cubes=new Map;dbExecutor;metadataCache;cacheConfig;constructor(e){e?.databaseExecutor?this.dbExecutor=e.databaseExecutor:e?.drizzle&&(this.dbExecutor=We(e.drizzle,e.schema,e.engineType)),this.cacheConfig=e?.cache}setDatabaseExecutor(e){this.dbExecutor=e}getEngineType(){return this.dbExecutor?.getEngineType()}setDrizzle(e,t,n){this.dbExecutor=We(e,t,n)}hasExecutor(){return!!this.dbExecutor}registerCube(e){e.meta&&console.log(`[DEBUG] registerCube: ${e.name} has meta:`,JSON.stringify(e.meta)),this.validateCalculatedMeasures(e),new H(this.cubes).populateDependencies(e),this.cubes.set(e.name,e),this.invalidateMetadataCache()}validateCalculatedMeasures(e){const t=[];for(const[n,s]of Object.entries(e.measures))if(s.type==="calculated"){if(!s.calculatedSql){t.push(`Calculated measure '${e.name}.${n}' must have calculatedSql property`);continue}const i=Zt(s.calculatedSql);if(!i.isValid){t.push(`Invalid calculatedSql syntax in '${e.name}.${n}': ${i.errors.join(", ")}`);continue}const r=new Map(this.cubes);r.set(e.name,e);const a=new H(r);try{a.validateDependencies(e)}catch(u){t.push(u instanceof Error?u.message:String(u))}}if(t.length===0){const n=new Map(this.cubes);n.set(e.name,e);const s=new H(n);s.buildGraph(e);const i=s.detectCycle();i&&t.push(`Circular dependency detected in calculated measures: ${i.join(" -> ")}`)}if(t.length>0)throw new Error(`Calculated measure validation failed for cube '${e.name}':
199
199
  ${t.join(`
200
- `)}`)}getCube(e){return this.cubes.get(e)}getAllCubes(){return Array.from(this.cubes.values())}getAllCubesMap(){return this.cubes}async execute(e,t,n){if(!this.dbExecutor)throw new Error("Database executor not configured");return new V(this.dbExecutor,this.cacheConfig).execute(this.cubes,e,t,n)}async executeMultiCubeQuery(e,t,n){return this.execute(e,t,n)}async executeQuery(e,t,n){if(!this.cubes.get(e))throw new Error(`Cube '${e}' not found`);return this.execute(t,n)}getMetadata(){return this.metadataCache?this.metadataCache:(this.metadataCache=Array.from(this.cubes.values()).map(e=>this.generateCubeMetadata(e)),this.metadataCache)}getColumnName(e){if(e&&e.name||e&&e.columnType&&e.name)return e.name;if(typeof e=="string")return e;if(e&&typeof e=="object"){if(e._.name)return e._.name;if(e.name)return e.name;if(e.columnName)return e.columnName}return"unknown_column"}static DEFAULT_TIME_GRANULARITIES=["year","quarter","month","week","day","hour"];generateCubeMetadata(e){const t=Object.keys(e.measures),n=Object.keys(e.dimensions),s=new Array(t.length),i=new Array(n.length);for(let c=0;c<t.length;c++){const l=t[c],m=e.measures[l];let f;m.drillMembers&&m.drillMembers.length>0&&(f=m.drillMembers.map(p=>p.includes(".")?p:`${e.name}.${p}`)),s[c]={name:`${e.name}.${l}`,title:m.title||l,shortTitle:m.title||l,type:m.type,format:void 0,description:m.description,synonyms:m.synonyms,drillMembers:f}}for(let c=0;c<n.length;c++){const l=n[c],m=e.dimensions[l];let f;m.type==="time"&&(f=m.granularities||Fe.DEFAULT_TIME_GRANULARITIES),i[c]={name:`${e.name}.${l}`,title:m.title||l,shortTitle:m.title||l,type:m.type,format:void 0,description:m.description,synonyms:m.synonyms,granularities:f}}const o=[];if(e.joins)for(const[,c]of Object.entries(e.joins)){const l=typeof c.targetCube=="function"?c.targetCube():c.targetCube;o.push({targetCube:l.name,relationship:c.relationship,joinFields:c.on.map(m=>({sourceField:this.getColumnName(m.source),targetField:this.getColumnName(m.target)}))})}const a=[];if(e.hierarchies)for(const[,c]of Object.entries(e.hierarchies))a.push({name:c.name,title:c.title||c.name,cubeName:e.name,levels:c.levels.map(l=>l.includes(".")?l:`${e.name}.${l}`)});const u={name:e.name,title:e.title||e.name,description:e.description,exampleQuestions:e.exampleQuestions,measures:s,dimensions:i,segments:[],relationships:o.length>0?o:void 0,hierarchies:a.length>0?a:void 0,meta:e.meta};return e.meta&&console.log(`[DEBUG] Cube ${e.name} has meta:`,JSON.stringify(e.meta)),u}async generateSQL(e,t,n){const s=this.getCube(e);if(!s)throw new Error(`Cube '${e}' not found`);if(!this.dbExecutor)throw new Error("Database executor not configured");const o=await new V(this.dbExecutor).generateSQL(s,t,n),a=this.dbExecutor.getEngineType();return{sql:B.formatSqlString(o.sql,a),params:o.params}}async generateMultiCubeSQL(e,t){if(!this.dbExecutor)throw new Error("Database executor not configured");const s=await new V(this.dbExecutor).generateMultiCubeSQL(this.cubes,e,t),i=this.dbExecutor.getEngineType();return{sql:B.formatSqlString(s.sql,i),params:s.params}}async dryRunFunnel(e,t){if(!this.dbExecutor)throw new Error("Database executor not configured");const s=await new V(this.dbExecutor).dryRunFunnel(this.cubes,e,t),i=this.dbExecutor.getEngineType();return{sql:B.formatSqlString(s.sql,i),params:s.params}}async dryRunFlow(e,t){if(!this.dbExecutor)throw new Error("Database executor not configured");const s=await new V(this.dbExecutor).dryRunFlow(this.cubes,e,t),i=this.dbExecutor.getEngineType();return{sql:B.formatSqlString(s.sql,i),params:s.params}}async dryRunRetention(e,t){if(!this.dbExecutor)throw new Error("Database executor not configured");const s=await new V(this.dbExecutor).dryRunRetention(this.cubes,e,t),i=this.dbExecutor.getEngineType();return{sql:B.formatSqlString(s.sql,i),params:s.params}}async explainQuery(e,t,n){if(!this.dbExecutor)throw new Error("Database executor not configured");return new V(this.dbExecutor).explainQuery(this.cubes,e,t,n)}hasCube(e){return this.cubes.has(e)}removeCube(e){const t=this.cubes.delete(e);return t&&this.invalidateMetadataCache(),t}clearCubes(){this.cubes.clear(),this.invalidateMetadataCache()}invalidateMetadataCache(){this.metadataCache=void 0}getCubeNames(){return Array.from(this.cubes.keys())}validateQuery(e){return at(this.cubes,e)}analyzeQuery(e,t){if(!this.dbExecutor)throw new Error("Database executor not configured");const n=new rt,s={db:this.dbExecutor.db,schema:this.dbExecutor.schema,securityContext:t};return n.analyzeQueryPlan(this.cubes,e,s)}}function at(d,e){const t=[];if(e.funnel!==void 0&&e.funnel.steps?.length>=2){const s=e.funnel.bindingKey;if(typeof s=="string"){const[i]=s.split(".");i&&!d.has(i)&&t.push(`Funnel binding key cube not found: ${i}`)}else if(Array.isArray(s))for(const i of s)d.has(i.cube)||t.push(`Funnel binding key cube not found: ${i.cube}`);return{isValid:t.length===0,errors:t}}if(e.flow!==void 0&&e.flow.startingStep!==void 0&&e.flow.eventDimension!==void 0){const s=e.flow.bindingKey;if(typeof s=="string"){const[i]=s.split(".");i&&!d.has(i)&&t.push(`Flow binding key cube not found: ${i}`)}return{isValid:t.length===0,errors:t}}if(e.retention!==void 0&&e.retention.timeDimension!=null&&e.retention.bindingKey!=null){const s=wn(e.retention.timeDimension);s&&!d.has(s)&&t.push(`Retention cube not found: ${s}`);const i=e.retention.bindingKey;if(typeof i=="string"){const[o]=i.split(".");o&&!d.has(o)&&t.push(`Retention binding key cube not found: ${o}`)}else if(Array.isArray(i))for(const o of i)d.has(o.cube)||t.push(`Retention binding key cube not found: ${o.cube}`);if(e.retention.breakdownDimensions&&Array.isArray(e.retention.breakdownDimensions))for(const o of e.retention.breakdownDimensions){const[a]=o.split(".");a&&!d.has(a)&&t.push(`Retention breakdown cube not found: ${a}`)}return{isValid:t.length===0,errors:t}}const n=new Set;if(e.measures)for(const s of e.measures){const[i,o]=s.split(".");if(!i||!o){t.push(`Invalid measure format: ${s}. Expected format: 'CubeName.fieldName'`);continue}n.add(i);const a=d.get(i);if(!a){t.push(`Cube '${i}' not found (referenced in measure '${s}')`);continue}a.measures[o]||t.push(`Measure '${o}' not found on cube '${i}'`)}if(e.dimensions)for(const s of e.dimensions){const[i,o]=s.split(".");if(!i||!o){t.push(`Invalid dimension format: ${s}. Expected format: 'CubeName.fieldName'`);continue}n.add(i);const a=d.get(i);if(!a){t.push(`Cube '${i}' not found (referenced in dimension '${s}')`);continue}a.dimensions[o]||t.push(`Dimension '${o}' not found on cube '${i}'`)}if(e.timeDimensions)for(const s of e.timeDimensions){const[i,o]=s.dimension.split(".");if(!i||!o){t.push(`Invalid timeDimension format: ${s.dimension}. Expected format: 'CubeName.fieldName'`);continue}n.add(i);const a=d.get(i);if(!a){t.push(`Cube '${i}' not found (referenced in timeDimension '${s.dimension}')`);continue}a.dimensions[o]||t.push(`TimeDimension '${o}' not found on cube '${i}' (must be a dimension with time type)`)}if(e.filters)for(const s of e.filters)ut(s,d,t,n);return n.size===0&&t.push("Query must reference at least one cube through measures, dimensions, or filters"),{isValid:t.length===0,errors:t}}function ut(d,e,t,n){if("and"in d||"or"in d){const a=d.and||d.or||[];for(const u of a)ut(u,e,t,n);return}if(!("member"in d)){t.push("Filter must have a member field");return}const[s,i]=d.member.split(".");if(!s||!i){t.push(`Invalid filter member format: ${d.member}. Expected format: 'CubeName.fieldName'`);return}n.add(s);const o=e.get(s);if(!o){t.push(`Cube '${s}' not found (referenced in filter '${d.member}')`);return}!o.dimensions[i]&&!o.measures[i]&&t.push(`Filter field '${i}' not found on cube '${s}' (must be a dimension or measure)`)}function wn(d){if(typeof d=="string"){const[e]=d.split(".");return e||null}return d.cube}const ae=["2025-11-25","2025-06-18","2025-03-26"],lt="2025-11-25";function $n(d){const t=Fn(d["mcp-protocol-version"])||lt;return{ok:ae.includes(t),negotiated:ae.includes(t)?t:null,supported:ae}}function En(d){if(!d)return!1;const e=d.split(",").map(s=>s.trim().toLowerCase()),t=e.includes("text/event-stream"),n=e.includes("application/json");return t&&!n}const Tn="mcp-session-id";function Sn(d){if(!d)return!1;const e=d.split(",").map(s=>s.trim().toLowerCase().split(";")[0]),t=e.some(s=>s==="application/json"),n=e.some(s=>s==="text/event-stream");return t&&n}function Nn(d,e={}){const{allowMissingOrigin:t=!0,allowedOrigins:n}=e;if(!d)return t?{valid:!0}:{valid:!1,reason:"Origin header is required"};if(!n||n.length===0)return{valid:!0};let s;try{s=new URL(d)}catch{return{valid:!1,reason:"Invalid Origin header format"}}return n.map(o=>{try{return new URL(o).origin}catch{return o}}).includes(s.origin)?{valid:!0}:{valid:!1,reason:"Origin not in allowed list"}}function Dn(d,e,t){const n=[];return e&&n.push(`id: ${e}`),t&&t>0&&n.push(`retry: ${t}`),n.push("event: message"),n.push(`data: ${JSON.stringify(d)}`),n.push(""),n.join(`
201
- `)}function An(d,e,t,n){return{jsonrpc:"2.0",id:d??null,error:{code:e,message:t,...n!==void 0?{data:n}:{}}}}function _n(d,e){return{jsonrpc:"2.0",id:d??null,result:e}}function vn(d){if(!d||typeof d!="object")return null;const e=d;return e.jsonrpc!=="2.0"||typeof e.method!="string"?null:{jsonrpc:"2.0",method:e.method,id:e.id,params:e.params}}async function Rn(d,e,t){const{semanticLayer:n,extractSecurityContext:s,rawRequest:i,rawResponse:o}=t,a=t.prompts??dt,u=t.resources??mt;switch(d){case"initialize":{const c=e?.protocolVersion;let l;return c&&ae.includes(c)?l=c:l=lt,{protocolVersion:l,capabilities:{tools:{listChanged:!1},resources:{listChanged:!1},prompts:{listChanged:!1},sampling:{}},sessionId:ct(),serverInfo:{name:"drizzle-cube",version:typeof process<"u"?process.env?.npm_package_version||"dev":"worker"}}}case"list_tools":case"tools/list":return{tools:In(),nextCursor:""};case"call_tool":case"tools/call":return Ln(e,t);case"resources/list":return{resources:u.map(({uri:c,name:l,description:m,mimeType:f})=>({uri:c,name:l,description:m,mimeType:f})),nextCursor:""};case"resources/templates/list":return{resourceTemplates:[],nextCursor:""};case"resources/read":{const c=e?.uri,l=u.find(m=>m.uri===c)||u[0];if(!l)throw K(-32602,"resource not found");return{contents:[{uri:l.uri,mimeType:l.mimeType,text:l.text}]}}case"prompts/list":return{prompts:a.map(({name:c,description:l})=>({name:c,description:l})),nextCursor:""};case"ping":return{};case"notifications/initialized":return{};case"prompts/get":{const c=e?.name,l=a.find(m=>m.name===c)||a[0];if(!l)throw K(-32602,"prompt not found");return{name:l.name,description:l.description,messages:l.messages}}case"discover":return B.handleDiscover(n,e||{});case"validate":{const c=e||{};if(!c.query)throw K(-32602,"query is required");return B.handleValidate(n,c)}case"load":{const c=e||{};if(!c.query)throw K(-32602,"query is required");const l=await s(i,o);return B.handleLoad(n,l,c)}default:throw K(-32601,`Unknown MCP method: ${d}`)}}function K(d,e,t){const n=new Error(e);return n.code=d,n}function Fn(d){return d?Array.isArray(d)?d[0]||null:d:null}function On(d){return d.id===void 0||d.id===null}function ct(){return`evt-${B.generateRequestId()}`}function In(){return[{name:"discover",description:`Find relevant cubes based on topic or intent. Call this FIRST to understand available data.
200
+ `)}`)}getCube(e){return this.cubes.get(e)}getAllCubes(){return Array.from(this.cubes.values())}getAllCubesMap(){return this.cubes}async execute(e,t,n){if(!this.dbExecutor)throw new Error("Database executor not configured");return new G(this.dbExecutor,this.cacheConfig).execute(this.cubes,e,t,n)}async executeMultiCubeQuery(e,t,n){return this.execute(e,t,n)}async executeQuery(e,t,n){if(!this.cubes.get(e))throw new Error(`Cube '${e}' not found`);return this.execute(t,n)}getMetadata(){return this.metadataCache?this.metadataCache:(this.metadataCache=Array.from(this.cubes.values()).map(e=>this.generateCubeMetadata(e)),this.metadataCache)}getColumnName(e){if(e&&e.name||e&&e.columnType&&e.name)return e.name;if(typeof e=="string")return e;if(e&&typeof e=="object"){if(e._.name)return e._.name;if(e.name)return e.name;if(e.columnName)return e.columnName}return"unknown_column"}static DEFAULT_TIME_GRANULARITIES=["year","quarter","month","week","day","hour"];generateCubeMetadata(e){const t=Object.keys(e.measures),n=Object.keys(e.dimensions),s=new Array(t.length),i=new Array(n.length);for(let c=0;c<t.length;c++){const l=t[c],m=e.measures[l];let p;m.drillMembers&&m.drillMembers.length>0&&(p=m.drillMembers.map(f=>f.includes(".")?f:`${e.name}.${f}`)),s[c]={name:`${e.name}.${l}`,title:m.title||l,shortTitle:m.title||l,type:m.type,format:void 0,description:m.description,synonyms:m.synonyms,drillMembers:p}}for(let c=0;c<n.length;c++){const l=n[c],m=e.dimensions[l];let p;m.type==="time"&&(p=m.granularities||Fe.DEFAULT_TIME_GRANULARITIES),i[c]={name:`${e.name}.${l}`,title:m.title||l,shortTitle:m.title||l,type:m.type,format:void 0,description:m.description,synonyms:m.synonyms,granularities:p}}const r=[];if(e.joins)for(const[,c]of Object.entries(e.joins)){const l=typeof c.targetCube=="function"?c.targetCube():c.targetCube;r.push({targetCube:l.name,relationship:c.relationship,joinFields:c.on.map(m=>({sourceField:this.getColumnName(m.source),targetField:this.getColumnName(m.target)}))})}const a=[];if(e.hierarchies)for(const[,c]of Object.entries(e.hierarchies))a.push({name:c.name,title:c.title||c.name,cubeName:e.name,levels:c.levels.map(l=>l.includes(".")?l:`${e.name}.${l}`)});const u={name:e.name,title:e.title||e.name,description:e.description,exampleQuestions:e.exampleQuestions,measures:s,dimensions:i,segments:[],relationships:r.length>0?r:void 0,hierarchies:a.length>0?a:void 0,meta:e.meta};return e.meta&&console.log(`[DEBUG] Cube ${e.name} has meta:`,JSON.stringify(e.meta)),u}async generateSQL(e,t,n){const s=this.getCube(e);if(!s)throw new Error(`Cube '${e}' not found`);if(!this.dbExecutor)throw new Error("Database executor not configured");const r=await new G(this.dbExecutor).generateSQL(s,t,n),a=this.dbExecutor.getEngineType();return{sql:P.formatSqlString(r.sql,a),params:r.params}}async generateMultiCubeSQL(e,t){if(!this.dbExecutor)throw new Error("Database executor not configured");const s=await new G(this.dbExecutor).generateMultiCubeSQL(this.cubes,e,t),i=this.dbExecutor.getEngineType();return{sql:P.formatSqlString(s.sql,i),params:s.params}}async dryRunFunnel(e,t){if(!this.dbExecutor)throw new Error("Database executor not configured");const s=await new G(this.dbExecutor).dryRunFunnel(this.cubes,e,t),i=this.dbExecutor.getEngineType();return{sql:P.formatSqlString(s.sql,i),params:s.params}}async dryRunFlow(e,t){if(!this.dbExecutor)throw new Error("Database executor not configured");const s=await new G(this.dbExecutor).dryRunFlow(this.cubes,e,t),i=this.dbExecutor.getEngineType();return{sql:P.formatSqlString(s.sql,i),params:s.params}}async dryRunRetention(e,t){if(!this.dbExecutor)throw new Error("Database executor not configured");const s=await new G(this.dbExecutor).dryRunRetention(this.cubes,e,t),i=this.dbExecutor.getEngineType();return{sql:P.formatSqlString(s.sql,i),params:s.params}}async explainQuery(e,t,n){if(!this.dbExecutor)throw new Error("Database executor not configured");return new G(this.dbExecutor).explainQuery(this.cubes,e,t,n)}hasCube(e){return this.cubes.has(e)}removeCube(e){const t=this.cubes.delete(e);return t&&this.invalidateMetadataCache(),t}clearCubes(){this.cubes.clear(),this.invalidateMetadataCache()}invalidateMetadataCache(){this.metadataCache=void 0}getCubeNames(){return Array.from(this.cubes.keys())}validateQuery(e){return at(this.cubes,e)}analyzeQuery(e,t){if(!this.dbExecutor)throw new Error("Database executor not configured");const n=new rt,s={db:this.dbExecutor.db,schema:this.dbExecutor.schema,securityContext:t};return n.analyzeQueryPlan(this.cubes,e,s)}}function at(d,e){const t=[];if(e.funnel!==void 0&&e.funnel.steps?.length>=2){const s=e.funnel.bindingKey;if(typeof s=="string"){const[i]=s.split(".");i&&!d.has(i)&&t.push(`Funnel binding key cube not found: ${i}`)}else if(Array.isArray(s))for(const i of s)d.has(i.cube)||t.push(`Funnel binding key cube not found: ${i.cube}`);return{isValid:t.length===0,errors:t}}if(e.flow!==void 0&&e.flow.startingStep!==void 0&&e.flow.eventDimension!==void 0){const s=e.flow.bindingKey;if(typeof s=="string"){const[i]=s.split(".");i&&!d.has(i)&&t.push(`Flow binding key cube not found: ${i}`)}return{isValid:t.length===0,errors:t}}if(e.retention!==void 0&&e.retention.timeDimension!=null&&e.retention.bindingKey!=null){const s=wn(e.retention.timeDimension);s&&!d.has(s)&&t.push(`Retention cube not found: ${s}`);const i=e.retention.bindingKey;if(typeof i=="string"){const[r]=i.split(".");r&&!d.has(r)&&t.push(`Retention binding key cube not found: ${r}`)}else if(Array.isArray(i))for(const r of i)d.has(r.cube)||t.push(`Retention binding key cube not found: ${r.cube}`);if(e.retention.breakdownDimensions&&Array.isArray(e.retention.breakdownDimensions))for(const r of e.retention.breakdownDimensions){const[a]=r.split(".");a&&!d.has(a)&&t.push(`Retention breakdown cube not found: ${a}`)}return{isValid:t.length===0,errors:t}}const n=new Set;if(e.measures)for(const s of e.measures){const[i,r]=s.split(".");if(!i||!r){t.push(`Invalid measure format: ${s}. Expected format: 'CubeName.fieldName'`);continue}n.add(i);const a=d.get(i);if(!a){t.push(`Cube '${i}' not found (referenced in measure '${s}')`);continue}a.measures[r]||t.push(`Measure '${r}' not found on cube '${i}'`)}if(e.dimensions)for(const s of e.dimensions){const[i,r]=s.split(".");if(!i||!r){t.push(`Invalid dimension format: ${s}. Expected format: 'CubeName.fieldName'`);continue}n.add(i);const a=d.get(i);if(!a){t.push(`Cube '${i}' not found (referenced in dimension '${s}')`);continue}a.dimensions[r]||t.push(`Dimension '${r}' not found on cube '${i}'`)}if(e.timeDimensions)for(const s of e.timeDimensions){const[i,r]=s.dimension.split(".");if(!i||!r){t.push(`Invalid timeDimension format: ${s.dimension}. Expected format: 'CubeName.fieldName'`);continue}n.add(i);const a=d.get(i);if(!a){t.push(`Cube '${i}' not found (referenced in timeDimension '${s.dimension}')`);continue}a.dimensions[r]||t.push(`TimeDimension '${r}' not found on cube '${i}' (must be a dimension with time type)`)}if(e.filters)for(const s of e.filters)ut(s,d,t,n);return n.size===0&&t.push("Query must reference at least one cube through measures, dimensions, or filters"),{isValid:t.length===0,errors:t}}function ut(d,e,t,n){if("and"in d||"or"in d){const a=d.and||d.or||[];for(const u of a)ut(u,e,t,n);return}if(!("member"in d)){t.push("Filter must have a member field");return}const[s,i]=d.member.split(".");if(!s||!i){t.push(`Invalid filter member format: ${d.member}. Expected format: 'CubeName.fieldName'`);return}n.add(s);const r=e.get(s);if(!r){t.push(`Cube '${s}' not found (referenced in filter '${d.member}')`);return}!r.dimensions[i]&&!r.measures[i]&&t.push(`Filter field '${i}' not found on cube '${s}' (must be a dimension or measure)`)}function wn(d){if(typeof d=="string"){const[e]=d.split(".");return e||null}return d.cube}const ae=["2025-11-25","2025-06-18","2025-03-26"],lt="2025-11-25";function $n(d){const t=Fn(d["mcp-protocol-version"])||lt;return{ok:ae.includes(t),negotiated:ae.includes(t)?t:null,supported:ae}}function En(d){if(!d)return!1;const e=d.split(",").map(s=>s.trim().toLowerCase()),t=e.includes("text/event-stream"),n=e.includes("application/json");return t&&!n}const Tn="mcp-session-id";function Sn(d){if(!d)return!1;const e=d.split(",").map(s=>s.trim().toLowerCase().split(";")[0]),t=e.some(s=>s==="application/json"),n=e.some(s=>s==="text/event-stream");return t&&n}function Nn(d,e={}){const{allowMissingOrigin:t=!0,allowedOrigins:n}=e;if(!d)return t?{valid:!0}:{valid:!1,reason:"Origin header is required"};if(!n||n.length===0)return{valid:!0};let s;try{s=new URL(d)}catch{return{valid:!1,reason:"Invalid Origin header format"}}return n.map(r=>{try{return new URL(r).origin}catch{return r}}).includes(s.origin)?{valid:!0}:{valid:!1,reason:"Origin not in allowed list"}}function Dn(d,e,t){const n=[];return e&&n.push(`id: ${e}`),t&&t>0&&n.push(`retry: ${t}`),n.push("event: message"),n.push(`data: ${JSON.stringify(d)}`),n.push(""),n.join(`
201
+ `)}function An(d,e,t,n){return{jsonrpc:"2.0",id:d??null,error:{code:e,message:t,...n!==void 0?{data:n}:{}}}}function _n(d,e){return{jsonrpc:"2.0",id:d??null,result:e}}function vn(d){if(!d||typeof d!="object")return null;const e=d;return e.jsonrpc!=="2.0"||typeof e.method!="string"?null:{jsonrpc:"2.0",method:e.method,id:e.id,params:e.params}}async function Rn(d,e,t){const{semanticLayer:n,extractSecurityContext:s,rawRequest:i,rawResponse:r}=t,a=t.prompts??dt,u=t.resources??mt;switch(d){case"initialize":{const c=e?.protocolVersion;let l;return c&&ae.includes(c)?l=c:l=lt,{protocolVersion:l,capabilities:{tools:{listChanged:!1},resources:{listChanged:!1},prompts:{listChanged:!1},sampling:{}},sessionId:ct(),serverInfo:{name:"drizzle-cube",version:typeof process<"u"?process.env?.npm_package_version||"dev":"worker"}}}case"list_tools":case"tools/list":return{tools:In(),nextCursor:""};case"call_tool":case"tools/call":return Ln(e,t);case"resources/list":return{resources:u.map(({uri:c,name:l,description:m,mimeType:p})=>({uri:c,name:l,description:m,mimeType:p})),nextCursor:""};case"resources/templates/list":return{resourceTemplates:[],nextCursor:""};case"resources/read":{const c=e?.uri,l=u.find(m=>m.uri===c)||u[0];if(!l)throw z(-32602,"resource not found");return{contents:[{uri:l.uri,mimeType:l.mimeType,text:l.text}]}}case"prompts/list":return{prompts:a.map(({name:c,description:l})=>({name:c,description:l})),nextCursor:""};case"ping":return{};case"notifications/initialized":return{};case"prompts/get":{const c=e?.name,l=a.find(m=>m.name===c)||a[0];if(!l)throw z(-32602,"prompt not found");return{name:l.name,description:l.description,messages:l.messages}}case"discover":return P.handleDiscover(n,e||{});case"validate":{const c=e||{};if(!c.query)throw z(-32602,"query is required");return P.handleValidate(n,c)}case"load":{const c=e||{};if(!c.query)throw z(-32602,"query is required");const l=await s(i,r);return P.handleLoad(n,l,c)}default:throw z(-32601,`Unknown MCP method: ${d}`)}}function z(d,e,t){const n=new Error(e);return n.code=d,n}function Fn(d){return d?Array.isArray(d)?d[0]||null:d:null}function On(d){return d.id===void 0||d.id===null}function ct(){return`evt-${P.generateRequestId()}`}function In(){return[{name:"discover",description:`Find relevant cubes based on topic or intent. Call this FIRST to understand available data.
202
202
 
203
203
  Returns cubes with:
204
204
  - All measures and dimensions with their types
@@ -252,6 +252,6 @@ QUERY CONSTRUCTION RULES:
252
252
  - filters: [{ member, operator, values }] - Use 'inDateRange' for date filtering
253
253
  - timeDimensions: [{ dimension, granularity, dateRange }] - ONLY for time series
254
254
  - order: { "Cube.field": "asc"|"desc" }
255
- - limit: number`}}}}]}async function Ln(d,e){const{semanticLayer:t,extractSecurityContext:n,rawRequest:s,rawResponse:i}=e,o=d||{};if(!o.name)throw K(-32602,"name is required for tools/call");const a=o.arguments;switch(o.name){case"discover":return Se(await B.handleDiscover(t,a||{}));case"validate":{const u=a||{};if(!u.query)throw K(-32602,"query is required");return Se(await B.handleValidate(t,u))}case"load":{const u=a||{};if(!u.query)throw K(-32602,"query is required");const c=await n(s,i);return Se(await B.handleLoad(t,c,u))}default:throw K(-32601,`Unknown tool: ${o.name}`)}}function Se(d){return{content:[{type:"text",text:typeof d=="string"?d:JSON.stringify(d)}],isError:!1}}const dt=Cn(),mt=[{uri:"drizzle-cube://quickstart",name:"Drizzle Cube MCP Quickstart",description:"Minimal guide for using discover/suggest/validate/load",mimeType:"text/markdown",text:["# Drizzle Cube MCP Quickstart","","Tools:","- discover: { topic?, intent?, limit?, minScore? } → cubes list","- suggest: { naturalLanguage, cube? } → draft query","- validate: { query } → corrected query + issues","- load: { query } → data + annotation","","Recommended flow:","1) tools/list",'2) tools/call name=discover intent="<goal>"','3) tools/call name=suggest naturalLanguage="<goal>"',"4) tools/call name=validate query=<from suggest>","5) tools/call name=load query=<validated>","","Query shapes supported:","- regular Cube.js-style query { measures, dimensions, filters, timeDimensions, order, limit, offset }","- funnel { bindingKey, timeDimension, steps[], includeTimeMetrics? }","- flow { bindingKey, eventDimension, steps?, window? }","- retention { bindingKey, timeDimension, periods, granularity, retentionType, breakdownDimensions }","","Filter rules: flat arrays of { member, operator, values }; do not nest arrays."].join(`
255
+ - limit: number`}}}}]}async function Ln(d,e){const{semanticLayer:t,extractSecurityContext:n,rawRequest:s,rawResponse:i}=e,r=d||{};if(!r.name)throw z(-32602,"name is required for tools/call");const a=r.arguments;switch(r.name){case"discover":return Se(await P.handleDiscover(t,a||{}));case"validate":{const u=a||{};if(!u.query)throw z(-32602,"query is required");return Se(await P.handleValidate(t,u))}case"load":{const u=a||{};if(!u.query)throw z(-32602,"query is required");const c=await n(s,i);return Se(await P.handleLoad(t,c,u))}default:throw z(-32601,`Unknown tool: ${r.name}`)}}function Se(d){return{content:[{type:"text",text:typeof d=="string"?d:JSON.stringify(d)}],isError:!1}}const dt=Cn(),mt=[{uri:"drizzle-cube://quickstart",name:"Drizzle Cube MCP Quickstart",description:"Minimal guide for using discover/suggest/validate/load",mimeType:"text/markdown",text:["# Drizzle Cube MCP Quickstart","","Tools:","- discover: { topic?, intent?, limit?, minScore? } → cubes list","- suggest: { naturalLanguage, cube? } → draft query","- validate: { query } → corrected query + issues","- load: { query } → data + annotation","","Recommended flow:","1) tools/list",'2) tools/call name=discover intent="<goal>"','3) tools/call name=suggest naturalLanguage="<goal>"',"4) tools/call name=validate query=<from suggest>","5) tools/call name=load query=<validated>","","Query shapes supported:","- regular Cube.js-style query { measures, dimensions, filters, timeDimensions, order, limit, offset }","- funnel { bindingKey, timeDimension, steps[], includeTimeMetrics? }","- flow { bindingKey, eventDimension, steps?, window? }","- retention { bindingKey, timeDimension, periods, granularity, retentionType, breakdownDimensions }","","Filter rules: flat arrays of { member, operator, values }; do not nest arrays."].join(`
256
256
  `)},{uri:"drizzle-cube://query-shapes",name:"Query Shapes Reference",description:"Detailed schema examples for regular, funnel, flow, and retention queries",mimeType:"text/markdown",text:["# Query Shapes","","## Regular query","```json","{",' "measures": ["Sales.count"],',' "dimensions": ["Sales.channel"],',' "filters": [ { "member": "Sales.status", "operator": "equals", "values": ["paid"] } ],',' "timeDimensions": [ { "dimension": "Sales.createdAt", "dateRange": "last 30 days", "granularity": "day" } ],',' "order": { "Sales.createdAt": "asc" },',' "limit": 500',"}","```","","## Funnel","```json","{",' "funnel": {',' "bindingKey": "Events.userId",',' "timeDimension": "Events.timestamp",',' "steps": [',' { "name": "Signup", "filter": [{ "member": "Events.eventType", "operator": "equals", "values": ["signup"] }] },',' { "name": "Purchase", "filter": [{ "member": "Events.eventType", "operator": "equals", "values": ["purchase"] }] }'," ],",' "includeTimeMetrics": true'," }","}","```","","## Flow","```json","{",' "flow": {',' "bindingKey": "Events.sessionId",',' "eventDimension": "Events.eventType",',' "steps": ["view", "add_to_cart", "checkout"],',' "window": { "unit": "minute", "value": 30 }'," }","}","```","","## Retention","```json","{",' "retention": {',' "bindingKey": "Users.id",',' "timeDimension": "Events.timestamp",',' "periods": 8,',' "granularity": "week",',' "retentionType": "rolling",',' "breakdownDimensions": ["Events.country"]'," }","}","```","","### Filter rules","- Always a flat array of filter objects: [{ member, operator, values }]","- For funnels, put time filter (inDateRange) only on step 0","- Operators: equals, notEquals, inDateRange, gt, gte, lt, lte, contains, notContains, set, notSet","","### Time handling",'- Relative ranges ("last 3 months") -> add ONLY an inDateRange filter on the time dimension (do NOT add timeDimensions unless grouping is requested).','- Grouping ("by month/week/day") -> add timeDimensions entry with granularity.',"- Both can be combined: inDateRange filter + timeDimensions granularity."].join(`
257
257
  `)}];function Mn(){return mt}function jn(){return dt}exports.MCP_SESSION_ID_HEADER=Tn;exports.SemanticLayerCompiler=Fe;exports.buildJsonRpcError=An;exports.buildJsonRpcResult=_n;exports.dispatchMcpMethod=Rn;exports.getDefaultPrompts=jn;exports.getDefaultResources=Mn;exports.isNotification=On;exports.negotiateProtocol=$n;exports.parseJsonRpc=vn;exports.primeEventId=ct;exports.serializeSseEvent=Dn;exports.validateAcceptHeader=Sn;exports.validateOriginHeader=Nn;exports.wantsEventStream=En;