drizzle-cube
Version:
Drizzle ORM-first semantic layer with Cube.js compatibility. Type-safe analytics and dashboards with SQL injection protection.
2 lines • 335 kB
JavaScript
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const s=require("drizzle-orm");class YE{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}}}class KT extends YE{getEngineType(){return"postgres"}buildTimeDimension(E,T){switch(E){case"year":return s.sql`DATE_TRUNC('year', ${T}::timestamp)`;case"quarter":return s.sql`DATE_TRUNC('quarter', ${T}::timestamp)`;case"month":return s.sql`DATE_TRUNC('month', ${T}::timestamp)`;case"week":return s.sql`DATE_TRUNC('week', ${T}::timestamp)`;case"day":return s.sql`DATE_TRUNC('day', ${T}::timestamp)::timestamp`;case"hour":return s.sql`DATE_TRUNC('hour', ${T}::timestamp)`;case"minute":return s.sql`DATE_TRUNC('minute', ${T}::timestamp)`;case"second":return s.sql`DATE_TRUNC('second', ${T}::timestamp)`;default:return T}}buildStringCondition(E,T,R){switch(T){case"contains":return s.sql`${E} ILIKE ${`%${R}%`}`;case"notContains":return s.sql`${E} NOT ILIKE ${`%${R}%`}`;case"startsWith":return s.sql`${E} ILIKE ${`${R}%`}`;case"endsWith":return s.sql`${E} ILIKE ${`%${R}`}`;case"like":return s.sql`${E} LIKE ${R}`;case"notLike":return s.sql`${E} NOT LIKE ${R}`;case"ilike":return s.sql`${E} ILIKE ${R}`;case"regex":return s.sql`${E} ~* ${R}`;case"notRegex":return s.sql`${E} !~* ${R}`;default:throw new Error(`Unsupported string operator: ${T}`)}}castToType(E,T){switch(T){case"timestamp":return s.sql`${E}::timestamp`;case"decimal":return s.sql`${E}::decimal`;case"integer":return s.sql`${E}::integer`;default:throw new Error(`Unsupported cast type: ${T}`)}}buildAvg(E){return s.sql`COALESCE(AVG(${E}), 0)`}buildCaseWhen(E,T){const R=E.map(A=>s.sql`WHEN ${A.when} THEN ${A.then}`).reduce((A,S)=>s.sql`${A} ${S}`);return T!==void 0?s.sql`CASE ${R} ELSE ${T} END`:s.sql`CASE ${R} END`}buildBooleanLiteral(E){return E?s.sql`TRUE`:s.sql`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}}buildStddev(E,T=!1){const R=T?"STDDEV_SAMP":"STDDEV_POP";return s.sql`COALESCE(${s.sql.raw(R)}(${E}), 0)`}buildVariance(E,T=!1){const R=T?"VAR_SAMP":"VAR_POP";return s.sql`COALESCE(${s.sql.raw(R)}(${E}), 0)`}buildPercentile(E,T){const R=T/100;return s.sql`PERCENTILE_CONT(${R}) WITHIN GROUP (ORDER BY ${E})`}buildWindowFunction(E,T,R,A,S){const t=R&&R.length>0?s.sql`PARTITION BY ${s.sql.join(R,s.sql`, `)}`:s.sql``,I=A&&A.length>0?s.sql`ORDER BY ${s.sql.join(A.map(C=>C.direction==="desc"?s.sql`${C.field} DESC`:s.sql`${C.field} ASC`),s.sql`, `)}`:s.sql``;let r=s.sql``;if(S?.frame){const{type:C,start:i,end:L}=S.frame,M=C.toUpperCase(),a=i==="unbounded"?"UNBOUNDED PRECEDING":typeof i=="number"?`${i} PRECEDING`:"CURRENT ROW",U=L==="unbounded"?"UNBOUNDED FOLLOWING":L==="current"?"CURRENT ROW":typeof L=="number"?`${L} FOLLOWING`:"CURRENT ROW";r=s.sql`${s.sql.raw(M)} BETWEEN ${s.sql.raw(a)} AND ${s.sql.raw(U)}`}const N=[];R&&R.length>0&&N.push(t),A&&A.length>0&&N.push(I),S?.frame&&N.push(r);const n=N.length>0?s.sql.join(N,s.sql` `):s.sql``,O=s.sql`OVER (${n})`;switch(E){case"lag":return s.sql`LAG(${T}, ${S?.offset??1}${S?.defaultValue!==void 0?s.sql`, ${S.defaultValue}`:s.sql``}) ${O}`;case"lead":return s.sql`LEAD(${T}, ${S?.offset??1}${S?.defaultValue!==void 0?s.sql`, ${S.defaultValue}`:s.sql``}) ${O}`;case"rank":return s.sql`RANK() ${O}`;case"denseRank":return s.sql`DENSE_RANK() ${O}`;case"rowNumber":return s.sql`ROW_NUMBER() ${O}`;case"ntile":return s.sql`NTILE(${S?.nTile??4}) ${O}`;case"firstValue":return s.sql`FIRST_VALUE(${T}) ${O}`;case"lastValue":return s.sql`LAST_VALUE(${T}) ${O}`;case"movingAvg":return s.sql`AVG(${T}) ${O}`;case"movingSum":return s.sql`SUM(${T}) ${O}`;default:throw new Error(`Unsupported window function: ${E}`)}}}class MT extends YE{getEngineType(){return"mysql"}buildTimeDimension(E,T){const R={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 s.sql`DATE_ADD(MAKEDATE(YEAR(${T}), 1), INTERVAL (QUARTER(${T}) - 1) * 3 MONTH)`;case"week":return s.sql`DATE_SUB(${T}, INTERVAL WEEKDAY(${T}) DAY)`;default:{const A=R[E];return A?s.sql`STR_TO_DATE(DATE_FORMAT(${T}, ${A}), '%Y-%m-%d %H:%i:%s')`:T}}}buildStringCondition(E,T,R){switch(T){case"contains":return s.sql`LOWER(${E}) LIKE ${`%${R.toLowerCase()}%`}`;case"notContains":return s.sql`LOWER(${E}) NOT LIKE ${`%${R.toLowerCase()}%`}`;case"startsWith":return s.sql`LOWER(${E}) LIKE ${`${R.toLowerCase()}%`}`;case"endsWith":return s.sql`LOWER(${E}) LIKE ${`%${R.toLowerCase()}`}`;case"like":return s.sql`${E} LIKE ${R}`;case"notLike":return s.sql`${E} NOT LIKE ${R}`;case"ilike":return s.sql`LOWER(${E}) LIKE ${R.toLowerCase()}`;case"regex":return s.sql`${E} REGEXP ${R}`;case"notRegex":return s.sql`${E} NOT REGEXP ${R}`;default:throw new Error(`Unsupported string operator: ${T}`)}}castToType(E,T){switch(T){case"timestamp":return s.sql`CAST(${E} AS DATETIME)`;case"decimal":return s.sql`CAST(${E} AS DECIMAL(10,2))`;case"integer":return s.sql`CAST(${E} AS SIGNED INTEGER)`;default:throw new Error(`Unsupported cast type: ${T}`)}}buildAvg(E){return s.sql`IFNULL(AVG(${E}), 0)`}buildCaseWhen(E,T){const R=E.map(A=>s.sql`WHEN ${A.when} THEN ${A.then}`).reduce((A,S)=>s.sql`${A} ${S}`);return T!==void 0?s.sql`CASE ${R} ELSE ${T} END`:s.sql`CASE ${R} END`}buildBooleanLiteral(E){return E?s.sql`TRUE`:s.sql`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}}buildStddev(E,T=!1){const R=T?"STDDEV_SAMP":"STDDEV_POP";return s.sql`IFNULL(${s.sql.raw(R)}(${E}), 0)`}buildVariance(E,T=!1){const R=T?"VAR_SAMP":"VAR_POP";return s.sql`IFNULL(${s.sql.raw(R)}(${E}), 0)`}buildPercentile(E,T){return null}buildWindowFunction(E,T,R,A,S){const t=R&&R.length>0?s.sql`PARTITION BY ${s.sql.join(R,s.sql`, `)}`:s.sql``,I=A&&A.length>0?s.sql`ORDER BY ${s.sql.join(A.map(C=>C.direction==="desc"?s.sql`${C.field} DESC`:s.sql`${C.field} ASC`),s.sql`, `)}`:s.sql``;let r=s.sql``;if(S?.frame){const{type:C,start:i,end:L}=S.frame,M=C.toUpperCase(),a=i==="unbounded"?"UNBOUNDED PRECEDING":typeof i=="number"?`${i} PRECEDING`:"CURRENT ROW",U=L==="unbounded"?"UNBOUNDED FOLLOWING":L==="current"?"CURRENT ROW":typeof L=="number"?`${L} FOLLOWING`:"CURRENT ROW";r=s.sql`${s.sql.raw(M)} BETWEEN ${s.sql.raw(a)} AND ${s.sql.raw(U)}`}const N=[];R&&R.length>0&&N.push(t),A&&A.length>0&&N.push(I),S?.frame&&N.push(r);const n=N.length>0?s.sql.join(N,s.sql` `):s.sql``,O=s.sql`OVER (${n})`;switch(E){case"lag":return s.sql`LAG(${T}, ${S?.offset??1}${S?.defaultValue!==void 0?s.sql`, ${S.defaultValue}`:s.sql``}) ${O}`;case"lead":return s.sql`LEAD(${T}, ${S?.offset??1}${S?.defaultValue!==void 0?s.sql`, ${S.defaultValue}`:s.sql``}) ${O}`;case"rank":return s.sql`RANK() ${O}`;case"denseRank":return s.sql`DENSE_RANK() ${O}`;case"rowNumber":return s.sql`ROW_NUMBER() ${O}`;case"ntile":return s.sql`NTILE(${S?.nTile??4}) ${O}`;case"firstValue":return s.sql`FIRST_VALUE(${T}) ${O}`;case"lastValue":return s.sql`LAST_VALUE(${T}) ${O}`;case"movingAvg":return s.sql`AVG(${T}) ${O}`;case"movingSum":return s.sql`SUM(${T}) ${O}`;default:throw new Error(`Unsupported window function: ${E}`)}}}class wT extends YE{getEngineType(){return"sqlite"}buildTimeDimension(E,T){switch(E){case"year":return s.sql`datetime(${T}, 'unixepoch', 'start of year')`;case"quarter":{const R=s.sql`datetime(${T}, 'unixepoch')`;return s.sql`datetime(${R}, 'start of year',
'+' || (((CAST(strftime('%m', ${R}) AS INTEGER) - 1) / 3) * 3) || ' months')`}case"month":return s.sql`datetime(${T}, 'unixepoch', 'start of month')`;case"week":return s.sql`date(datetime(${T}, 'unixepoch'), 'weekday 1', '-6 days')`;case"day":return s.sql`datetime(${T}, 'unixepoch', 'start of day')`;case"hour":{const R=s.sql`datetime(${T}, 'unixepoch')`;return s.sql`datetime(strftime('%Y-%m-%d %H:00:00', ${R}))`}case"minute":{const R=s.sql`datetime(${T}, 'unixepoch')`;return s.sql`datetime(strftime('%Y-%m-%d %H:%M:00', ${R}))`}case"second":{const R=s.sql`datetime(${T}, 'unixepoch')`;return s.sql`datetime(strftime('%Y-%m-%d %H:%M:%S', ${R}))`}default:return s.sql`datetime(${T}, 'unixepoch')`}}buildStringCondition(E,T,R){switch(T){case"contains":return s.sql`LOWER(${E}) LIKE ${`%${R.toLowerCase()}%`}`;case"notContains":return s.sql`LOWER(${E}) NOT LIKE ${`%${R.toLowerCase()}%`}`;case"startsWith":return s.sql`LOWER(${E}) LIKE ${`${R.toLowerCase()}%`}`;case"endsWith":return s.sql`LOWER(${E}) LIKE ${`%${R.toLowerCase()}`}`;case"like":return s.sql`${E} LIKE ${R}`;case"notLike":return s.sql`${E} NOT LIKE ${R}`;case"ilike":return s.sql`LOWER(${E}) LIKE ${R.toLowerCase()}`;case"regex":return s.sql`${E} GLOB ${R}`;case"notRegex":return s.sql`${E} NOT GLOB ${R}`;default:throw new Error(`Unsupported string operator: ${T}`)}}castToType(E,T){switch(T){case"timestamp":return s.sql`datetime(${E} / 1000, 'unixepoch')`;case"decimal":return s.sql`CAST(${E} AS REAL)`;case"integer":return s.sql`CAST(${E} AS INTEGER)`;default:throw new Error(`Unsupported cast type: ${T}`)}}buildAvg(E){return s.sql`IFNULL(AVG(${E}), 0)`}buildCaseWhen(E,T){const R=E.map(A=>A.then&&typeof A.then=="object"&&(A.then.queryChunks||A.then._||A.then.sql)?s.sql`WHEN ${A.when} THEN ${s.sql.raw("(")}${A.then}${s.sql.raw(")")}`:s.sql`WHEN ${A.when} THEN ${A.then}`).reduce((A,S)=>s.sql`${A} ${S}`);return T!==void 0?T&&typeof T=="object"&&(T.queryChunks||T._||T.sql)?s.sql`CASE ${R} ELSE ${s.sql.raw("(")}${T}${s.sql.raw(")")} END`:s.sql`CASE ${R} ELSE ${T} END`:s.sql`CASE ${R} END`}buildBooleanLiteral(E){return E?s.sql`1`:s.sql`0`}preprocessCalculatedTemplate(E){const T=/(\{[^}]+\})\s*\/\s*/g;return E.replace(T,(R,A)=>`${A.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}}buildStddev(E,T=!1){return null}buildVariance(E,T=!1){return null}buildPercentile(E,T){return null}buildWindowFunction(E,T,R,A,S){const t=R&&R.length>0?s.sql`PARTITION BY ${s.sql.join(R,s.sql`, `)}`:s.sql``,I=A&&A.length>0?s.sql`ORDER BY ${s.sql.join(A.map(C=>C.direction==="desc"?s.sql`${C.field} DESC`:s.sql`${C.field} ASC`),s.sql`, `)}`:s.sql``;let r=s.sql``;if(S?.frame){const{type:C,start:i,end:L}=S.frame,M=C.toUpperCase(),a=i==="unbounded"?"UNBOUNDED PRECEDING":typeof i=="number"?`${i} PRECEDING`:"CURRENT ROW",U=L==="unbounded"?"UNBOUNDED FOLLOWING":L==="current"?"CURRENT ROW":typeof L=="number"?`${L} FOLLOWING`:"CURRENT ROW";r=s.sql`${s.sql.raw(M)} BETWEEN ${s.sql.raw(a)} AND ${s.sql.raw(U)}`}const N=[];R&&R.length>0&&N.push(t),A&&A.length>0&&N.push(I),S?.frame&&N.push(r);const n=N.length>0?s.sql.join(N,s.sql` `):s.sql``,O=s.sql`OVER (${n})`;switch(E){case"lag":return s.sql`LAG(${T}, ${S?.offset??1}${S?.defaultValue!==void 0?s.sql`, ${S.defaultValue}`:s.sql``}) ${O}`;case"lead":return s.sql`LEAD(${T}, ${S?.offset??1}${S?.defaultValue!==void 0?s.sql`, ${S.defaultValue}`:s.sql``}) ${O}`;case"rank":return s.sql`RANK() ${O}`;case"denseRank":return s.sql`DENSE_RANK() ${O}`;case"rowNumber":return s.sql`ROW_NUMBER() ${O}`;case"ntile":return s.sql`NTILE(${S?.nTile??4}) ${O}`;case"firstValue":return s.sql`FIRST_VALUE(${T}) ${O}`;case"lastValue":return s.sql`LAST_VALUE(${T}) ${O}`;case"movingAvg":return s.sql`AVG(${T}) ${O}`;case"movingSum":return s.sql`SUM(${T}) ${O}`;default:throw new Error(`Unsupported window function: ${E}`)}}}class JT extends MT{getEngineType(){return"singlestore"}}function xT(e){switch(e){case"postgres":return new KT;case"mysql":return new MT;case"sqlite":return new wT;case"singlestore":return new JT;default:throw new Error(`Unsupported database engine: ${e}`)}}class RE{constructor(E,T,R){this.db=E,this.schema=T;const A=R||this.getEngineType();this.databaseAdapter=xT(A)}databaseAdapter}class UT extends RE{async execute(E,T){if(E&&typeof E=="object"&&typeof E.execute=="function"){const A=await E.execute();return Array.isArray(A)?A.map(S=>this.convertNumericFields(S,T)):A}if(!this.db.execute)throw new Error("PostgreSQL database instance must have an execute method");const R=await this.db.execute(E);return Array.isArray(R)?R.map(A=>this.convertNumericFields(A,T)):R}convertNumericFields(E,T){if(!E||typeof E!="object")return E;const R={};for(const[A,S]of Object.entries(E))T&&T.includes(A)?R[A]=this.coerceToNumber(S):R[A]=S;return R}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"}}function pE(e,E){return new UT(e,E,"postgres")}class VE extends RE{async execute(E,T){if(E&&typeof E=="object"&&typeof E.execute=="function"){const A=await E.execute();return Array.isArray(A)?A.map(S=>this.convertNumericFields(S,T)):A}if(!this.db.execute)throw new Error("MySQL database instance must have an execute method");const R=await this.db.execute(E);return Array.isArray(R)?R.map(A=>this.convertNumericFields(A,T)):R}convertNumericFields(E,T){if(!E||typeof E!="object")return E;const R={};for(const[A,S]of Object.entries(E))T&&T.includes(A)?R[A]=this.coerceToNumber(S):R[A]=S;return R}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"}}function lT(e,E){return new VE(e,E,"mysql")}class cT extends RE{async execute(E,T){if(E&&typeof E=="object"&&typeof E.execute=="function"){const R=await E.execute();return Array.isArray(R)?R.map(A=>this.convertNumericFields(A,T)):R}try{if(this.db.all){const R=this.db.all(E);return Array.isArray(R)?R.map(A=>this.convertNumericFields(A,T)):R}else{if(this.db.run)return this.db.run(E);throw new Error("SQLite database instance must have an all() or run() method")}}catch(R){throw new Error(`SQLite execution failed: ${R instanceof Error?R.message:"Unknown error"}`)}}convertNumericFields(E,T){if(!E||typeof E!="object")return E;const R={};for(const[A,S]of Object.entries(E))T&&T.includes(A)?R[A]=this.coerceToNumber(S):R[A]=S;return R}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"}}function BE(e,E){return new cT(e,E,"sqlite")}class vT extends VE{getEngineType(){return"singlestore"}}function qT(e,E){return new vT(e,E)}function HE(e,E,T){if(T)switch(T){case"postgres":return pE(e,E);case"mysql":return lT(e,E);case"sqlite":return BE(e,E);case"singlestore":return qT(e,E)}if(e.all&&e.run)return BE(e,E);if(e.execute)return pE(e,E);throw new Error("Unable to determine database engine type. Please specify engineType parameter.")}function q(e){return typeof e=="function"?e():e}function EE(e,E){if(E)return E;switch(e){case"belongsTo":return"inner";case"hasOne":return"left";case"hasMany":return"left";case"belongsToMany":return"left";default:return"left"}}function FE(e){return e&&typeof e=="object"?s.sql`${s.sql`${e}`}`:e}function h(e,E){const T=typeof e=="function"?e(E):e;return FE(T)}function QT(e,E,T){return{...e,cubes:E,currentCube:T}}function ZT(e,E){return{name:e,...E}}function jT(e,E){if(e.relationship!=="belongsToMany"||!e.through)throw new Error("expandBelongsToManyJoin can only be called on belongsToMany relationships with through configuration");const{table:T,sourceKey:R,targetKey:A,securitySql:S}=e.through,t=[];for(const n of R){const O=n.as||s.eq;t.push(O(n.source,n.target))}const I=[];for(const n of A){const O=n.as||s.eq;I.push(O(n.source,n.target))}let r;if(S){const n=S(E);r=Array.isArray(n)?n:[n]}const N=EE("belongsToMany",e.sqlJoinType);return{junctionJoins:[{joinType:N,table:T,condition:s.and(...t)},{joinType:N,table:T,condition:s.and(...I)}],junctionSecurityConditions:r}}function TE(e){if("and"in e)return`and:[${e.and.map(TE).sort().join(",")}]`;if("or"in e)return`or:[${e.or.map(TE).sort().join(",")}]`;const E=e,T=JSON.stringify(Array.isArray(E.values)?[...E.values].sort():E.values),R=E.dateRange?`:dr:${JSON.stringify(E.dateRange)}`:"";return`${E.member}:${E.operator}:${T}${R}`}function uT(e,E){return`timeDim:${e}:${JSON.stringify(E)}`}class kT{cache=new Map;stats={hits:0,misses:0};getOrBuild(E,T){const R=this.cache.get(E);if(R!==void 0)return this.stats.hits++,R;const A=T();return A&&this.cache.set(E,A),this.stats.misses++,A}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:R}of E)this.cache.has(T)||this.cache.set(T,R)}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 fE(e){const E=[];for(const T of e)"and"in T&&T.and?E.push(...fE(T.and)):"or"in T&&T.or?E.push(...fE(T.or)):"member"in T&&E.push(T);return E}class zT{constructor(E){this.databaseAdapter=E}buildTimeDimensionExpression(E,T,R){const A=h(E,R);return T?this.databaseAdapter.buildTimeDimension(T,A):A instanceof s.SQL?A:s.sql`${A}`}buildDateRangeCondition(E,T){if(!T)return null;if(Array.isArray(T)&&T.length>=2){const R=this.normalizeDate(T[0]);let A=this.normalizeDate(T[1]);if(!R||!A)return null;if(typeof T[1]=="string"&&/^\d{4}-\d{2}-\d{2}$/.test(T[1].trim())){const S=typeof A=="number"?new Date(A*(this.databaseAdapter.getEngineType()==="sqlite"?1e3:1)):new Date(A),t=new Date(S);t.setUTCHours(23,59,59,999),this.databaseAdapter.isTimestampInteger()?A=this.databaseAdapter.getEngineType()==="sqlite"?Math.floor(t.getTime()/1e3):t.getTime():A=t.toISOString()}return s.and(s.gte(E,R),s.lte(E,A))}if(typeof T=="string"){const R=this.parseRelativeDateRange(T);if(R){let n,O;return this.databaseAdapter.isTimestampInteger()?this.databaseAdapter.getEngineType()==="sqlite"?(n=Math.floor(R.start.getTime()/1e3),O=Math.floor(R.end.getTime()/1e3)):(n=R.start.getTime(),O=R.end.getTime()):(n=R.start.toISOString(),O=R.end.toISOString()),s.and(s.gte(E,n),s.lte(E,O))}const A=this.normalizeDate(T);if(!A)return null;const S=typeof A=="number"?new Date(A*(this.databaseAdapter.getEngineType()==="sqlite"?1e3:1)):new Date(A),t=new Date(S);t.setUTCHours(0,0,0,0);const I=new Date(S);I.setUTCHours(23,59,59,999);let r,N;return this.databaseAdapter.isTimestampInteger()?this.databaseAdapter.getEngineType()==="sqlite"?(r=Math.floor(t.getTime()/1e3),N=Math.floor(I.getTime()/1e3)):(r=t.getTime(),N=I.getTime()):(r=t.toISOString(),N=I.toISOString()),s.and(s.gte(E,r),s.lte(E,N))}return null}parseRelativeDateRange(E){const T=new Date,R=E.toLowerCase().trim(),A=T.getUTCFullYear(),S=T.getUTCMonth(),t=T.getUTCDate(),I=T.getUTCDay();if(R==="today"){const C=new Date(T);C.setUTCHours(0,0,0,0);const i=new Date(T);return i.setUTCHours(23,59,59,999),{start:C,end:i}}if(R==="yesterday"){const C=new Date(T);C.setUTCDate(t-1),C.setUTCHours(0,0,0,0);const i=new Date(T);return i.setUTCDate(t-1),i.setUTCHours(23,59,59,999),{start:C,end:i}}if(R==="this week"){const C=I===0?-6:1-I,i=new Date(T);i.setUTCDate(t+C),i.setUTCHours(0,0,0,0);const L=new Date(i);return L.setUTCDate(i.getUTCDate()+6),L.setUTCHours(23,59,59,999),{start:i,end:L}}if(R==="this month"){const C=new Date(Date.UTC(A,S,1,0,0,0,0)),i=new Date(Date.UTC(A,S+1,0,23,59,59,999));return{start:C,end:i}}if(R==="this quarter"){const C=Math.floor(S/3),i=new Date(Date.UTC(A,C*3,1,0,0,0,0)),L=new Date(Date.UTC(A,C*3+3,0,23,59,59,999));return{start:i,end:L}}if(R==="this year"){const C=new Date(Date.UTC(A,0,1,0,0,0,0)),i=new Date(Date.UTC(A,11,31,23,59,59,999));return{start:C,end:i}}const r=R.match(/^last\s+(\d+)\s+days?$/);if(r){const C=parseInt(r[1],10),i=new Date(T);i.setUTCDate(t-C+1),i.setUTCHours(0,0,0,0);const L=new Date(T);return L.setUTCHours(23,59,59,999),{start:i,end:L}}const N=R.match(/^last\s+(\d+)\s+weeks?$/);if(N){const i=parseInt(N[1],10)*7,L=new Date(T);L.setUTCDate(t-i+1),L.setUTCHours(0,0,0,0);const M=new Date(T);return M.setUTCHours(23,59,59,999),{start:L,end:M}}if(R==="last week"){const C=I===0?-13:-6-I,i=new Date(T);i.setUTCDate(t+C),i.setUTCHours(0,0,0,0);const L=new Date(i);return L.setUTCDate(i.getUTCDate()+6),L.setUTCHours(23,59,59,999),{start:i,end:L}}if(R==="last month"){const C=new Date(Date.UTC(A,S-1,1,0,0,0,0)),i=new Date(Date.UTC(A,S,0,23,59,59,999));return{start:C,end:i}}if(R==="last quarter"){const C=Math.floor(S/3),i=C===0?3:C-1,L=C===0?A-1:A,M=new Date(Date.UTC(L,i*3,1,0,0,0,0)),a=new Date(Date.UTC(L,i*3+3,0,23,59,59,999));return{start:M,end:a}}if(R==="last year"){const C=new Date(Date.UTC(A-1,0,1,0,0,0,0)),i=new Date(Date.UTC(A-1,11,31,23,59,59,999));return{start:C,end:i}}if(R==="last 12 months"){const C=new Date(Date.UTC(A,S-11,1,0,0,0,0)),i=new Date(T);return i.setUTCHours(23,59,59,999),{start:C,end:i}}const n=R.match(/^last\s+(\d+)\s+months?$/);if(n){const C=parseInt(n[1],10),i=new Date(Date.UTC(A,S-C+1,1,0,0,0,0)),L=new Date(T);return L.setUTCHours(23,59,59,999),{start:i,end:L}}const O=R.match(/^last\s+(\d+)\s+years?$/);if(O){const C=parseInt(O[1],10),i=new Date(Date.UTC(A-C,0,1,0,0,0,0)),L=new Date(T);return L.setUTCHours(23,59,59,999),{start:i,end:L}}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 R=E<1e10?E*1e3:E,A=new Date(R);return isNaN(A.getTime())?null:this.databaseAdapter.isTimestampInteger()?this.databaseAdapter.getEngineType()==="sqlite"?Math.floor(R/1e3):R:A.toISOString()}if(typeof E=="string"){if(/^\d{4}-\d{2}-\d{2}$/.test(E.trim())){const A=new Date(E+"T00:00:00Z");return isNaN(A.getTime())?null:this.databaseAdapter.isTimestampInteger()?this.databaseAdapter.getEngineType()==="sqlite"?Math.floor(A.getTime()/1e3):A.getTime():A.toISOString()}const R=new Date(E);return isNaN(R.getTime())?null:this.databaseAdapter.isTimestampInteger()?this.databaseAdapter.getEngineType()==="sqlite"?Math.floor(R.getTime()/1e3):R.getTime():R.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 Ee{constructor(E,T){this.databaseAdapter=E,this.dateTimeBuilder=T}buildFilterCondition(E,T,R,A,S){if(S!==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(A&&A.type!=="time")throw new Error(`dateRange can only be used on time dimensions, but field '${A.name||"unknown"}' has type '${A.type}'`);return this.dateTimeBuilder.buildDateRangeCondition(E,S)}if(!R||R.length===0)return T==="equals"?this.databaseAdapter.buildBooleanLiteral(!1):null;const t=R.filter(r=>!(r==null||r===""||typeof r=="string"&&r.includes("\0"))).map(this.databaseAdapter.convertFilterValue);if(t.length===0&&!["set","notSet"].includes(T))return T==="equals"?this.databaseAdapter.buildBooleanLiteral(!1):null;const I=t[0];switch(T){case"equals":if(t.length>1){if(A?.type==="time"){const r=t.map(N=>this.dateTimeBuilder.normalizeDate(N)||N);return s.inArray(E,r)}return s.inArray(E,t)}else if(t.length===1){const r=A?.type==="time"&&this.dateTimeBuilder.normalizeDate(I)||I;return s.eq(E,r)}return this.databaseAdapter.buildBooleanLiteral(!1);case"notEquals":return t.length>1?s.notInArray(E,t):t.length===1?s.ne(E,I):null;case"contains":return this.databaseAdapter.buildStringCondition(E,"contains",I);case"notContains":return this.databaseAdapter.buildStringCondition(E,"notContains",I);case"startsWith":return this.databaseAdapter.buildStringCondition(E,"startsWith",I);case"endsWith":return this.databaseAdapter.buildStringCondition(E,"endsWith",I);case"gt":return s.gt(E,I);case"gte":return s.gte(E,I);case"lt":return s.lt(E,I);case"lte":return s.lte(E,I);case"set":return s.isNotNull(E);case"notSet":return s.isNull(E);case"inDateRange":if(t.length>=2){const r=this.dateTimeBuilder.normalizeDate(t[0]);let N=this.dateTimeBuilder.normalizeDate(t[1]);if(r&&N){const n=R[1];if(typeof n=="string"&&/^\d{4}-\d{2}-\d{2}$/.test(n.trim())){const O=typeof N=="number"?new Date(N*(this.databaseAdapter.getEngineType()==="sqlite"?1e3:1)):new Date(N),C=new Date(O);C.setUTCHours(23,59,59,999),this.databaseAdapter.isTimestampInteger()?N=this.databaseAdapter.getEngineType()==="sqlite"?Math.floor(C.getTime()/1e3):C.getTime():N=C.toISOString()}return s.and(s.gte(E,r),s.lte(E,N))}}return null;case"beforeDate":{const r=this.dateTimeBuilder.normalizeDate(I);return r?s.lt(E,r):null}case"afterDate":{const r=this.dateTimeBuilder.normalizeDate(I);return r?s.gt(E,r):null}case"between":return t.length>=2?s.and(s.gte(E,t[0]),s.lte(E,t[1])):null;case"notBetween":return t.length>=2?s.or(s.lt(E,t[0]),s.gt(E,t[1])):null;case"in":return t.length>0?s.inArray(E,t):null;case"notIn":return t.length>0?s.notInArray(E,t):null;case"like":return this.databaseAdapter.buildStringCondition(E,"like",I);case"notLike":return this.databaseAdapter.buildStringCondition(E,"notLike",I);case"ilike":return this.databaseAdapter.buildStringCondition(E,"ilike",I);case"regex":return this.databaseAdapter.buildStringCondition(E,"regex",I);case"notRegex":return this.databaseAdapter.buildStringCondition(E,"notRegex",I);case"isEmpty":return s.or(s.isNull(E),s.eq(E,""));case"isNotEmpty":return s.and(s.isNotNull(E),s.ne(E,""));case"arrayContains":return this.databaseAdapter.getEngineType()==="postgres"?s.arrayContains(E,t):null;case"arrayOverlaps":return this.databaseAdapter.getEngineType()==="postgres"?s.arrayOverlaps(E,t):null;case"arrayContained":return this.databaseAdapter.getEngineType()==="postgres"?s.arrayContained(E,t):null;default:return null}}buildLogicalFilter(E,T,R){if("and"in E&&E.and){const A=E.and.map(S=>this.buildSingleFilter(S,T,R)).filter(S=>S!==null);return A.length>0?A.length===1?A[0]:s.and(...A):null}if("or"in E&&E.or){const A=E.or.map(S=>this.buildSingleFilter(S,T,R)).filter(S=>S!==null);return A.length>0?A.length===1?A[0]:s.or(...A):null}return null}buildSingleFilter(E,T,R){if("and"in E||"or"in E)return this.buildLogicalFilter(E,T,R);const A=E,[S,t]=A.member.split("."),I=T.get(S);if(!I)return null;const r=I.dimensions?.[t];if(!r)return null;const N=h(r.sql,R);return this.buildFilterCondition(N,A.operator,A.values,r,A.dateRange)}}class Te{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"].includes(E)}buildGroupByFields(E,T,R,A){const S=[],t=E instanceof Map?E:new Map([[E.name,E]]);let I=!1,r=!1;for(const N of T.measures||[]){const[n,O]=N.split("."),C=t.get(n);if(C&&C.measures&&C.measures[O]){const i=C.measures[O];(this.isAggregateFunctionType(i.type)||i.type==="calculated")&&(I=!0),this.isWindowFunctionType(i.type)&&(r=!0)}}if(I&&r&&console.warn("[drizzle-cube] Warning: Mixing aggregate measures (count, sum, avg, etc.) with window functions (lag, lead, rank, etc.) in the same query may produce incorrect results. Window functions will operate on raw rows before aggregation. Consider separating these into different queries or using CTE pattern."),!I)return[];if(T.dimensions)for(const N of T.dimensions){const[n,O]=N.split("."),C=t.get(n);if(C&&C.dimensions&&C.dimensions[O])if(A?.preAggregationCTEs?.some(L=>L.cube.name===n)){const L=A.preAggregationCTEs.find(a=>a.cube.name===n),M=L.joinKeys.find(a=>a.targetColumn===O);if(M&&M.sourceColumnObj)S.push(M.sourceColumnObj);else{const a=s.sql`${s.sql.identifier(L.cteAlias)}.${s.sql.identifier(O)}`;S.push(a)}}else{const L=C.dimensions[O],M=h(L.sql,R);S.push(M)}}if(T.timeDimensions)for(const N of T.timeDimensions){const[n,O]=N.dimension.split("."),C=t.get(n);if(C&&C.dimensions&&C.dimensions[O])if(A?.preAggregationCTEs?.some(L=>L.cube.name===n)){const L=A.preAggregationCTEs.find(a=>a.cube.name===n),M=L.joinKeys.find(a=>a.targetColumn===O);if(M&&M.sourceColumnObj){const a=this.dateTimeBuilder.buildTimeDimensionExpression(M.sourceColumnObj,N.granularity,R);S.push(a)}else{const a=s.sql`${s.sql.identifier(L.cteAlias)}.${s.sql.identifier(O)}`;S.push(a)}}else{const L=C.dimensions[O],M=this.dateTimeBuilder.buildTimeDimensionExpression(L.sql,N.granularity,R);S.push(M)}}return S}}class y{dependencyGraph;cubes;constructor(E){this.cubes=E instanceof Map?E:new Map([[E.name,E]]),this.dependencyGraph=new Map}extractDependencies(E){const T=/\{([^}]+)\}/g,R=E.matchAll(T),A=[];for(const S of R){const t=S[1].trim();if(t.includes(".")){const[I,r]=t.split(".");A.push({measureName:t,cubeName:I.trim(),fieldName:r.trim()})}else A.push({measureName:t,cubeName:null,fieldName:t})}return A}buildGraph(E){for(const[T,R]of Object.entries(E.measures))if(R.type==="calculated"&&R.calculatedSql){const A=`${E.name}.${T}`,S=this.extractDependencies(R.calculatedSql),t=new Set;for(const I of S){const N=`${I.cubeName||E.name}.${I.fieldName}`;t.add(N)}this.dependencyGraph.set(A,{id:A,dependencies:t,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 R=this.dependencyGraph.get(T);R&&R.inDegree++}}topologicalSort(E){const T=new Map,R=[],A=[];for(const S of E){const t=this.dependencyGraph.get(S);t&&T.set(S,{id:t.id,dependencies:new Set(t.dependencies),inDegree:0})}for(const S of T.values()){let t=0;for(const I of S.dependencies)T.has(I)&&t++;S.inDegree=t}for(const[S,t]of T)t.inDegree===0&&R.push(S);for(;R.length>0;){const S=R.shift();A.push(S);for(const[t,I]of T)I.dependencies.has(S)&&(I.inDegree--,I.inDegree===0&&R.push(t))}if(A.length<T.size){const S=this.detectCycle();throw new Error(`Circular dependency detected in calculated measures: ${S?S.join(" -> "):"unknown cycle"}`)}return A}detectCycle(){const E=new Set,T=new Set,R=[];for(const A of this.dependencyGraph.keys())if(!E.has(A)){const S=this.dfs(A,E,T,R);if(S)return S}return null}dfs(E,T,R,A){T.add(E),R.add(E),A.push(E);const S=this.dependencyGraph.get(E);if(!S)return A.pop(),R.delete(E),null;for(const t of S.dependencies)if(T.has(t)){if(R.has(t)){const I=A.indexOf(t);return[...A.slice(I),t]}}else{const I=this.dfs(t,T,R,A);if(I)return I}return A.pop(),R.delete(E),null}getAllDependencies(E){const T=new Set,R=new Set,A=S=>{if(R.has(S))return;R.add(S);const t=this.dependencyGraph.get(S);if(t)for(const I of t.dependencies)T.add(I),A(I)};return A(E),T}validateDependencies(E){for(const[T,R]of Object.entries(E.measures))if(R.type==="calculated"&&R.calculatedSql){const A=this.extractDependencies(R.calculatedSql);for(const S of A){const t=S.cubeName||E.name,I=this.cubes.get(t);if(!I)throw new Error(`Calculated measure '${E.name}.${T}' references unknown cube '${t}'`);if(!I.measures[S.fieldName])throw new Error(`Calculated measure '${E.name}.${T}' references unknown measure '${S.measureName}'`);if(t===E.name&&S.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 R=this.extractDependencies(T.calculatedSql);T.dependencies=R.map(A=>A.measureName)}}static isCalculatedMeasure(E){return E.type==="calculated"&&!!E.calculatedSql}}function ee(e,E){const{cube:T,allCubes:R,resolvedMeasures:A}=E,S=bE(e),t=new Map;for(const O of S){const{originalRef:C,cubeName:i,fieldName:L}=O,M=i||T.name;if(!R.get(M))throw new Error(`Cannot substitute {${C}}: cube '${M}' not found`);const U=`${M}.${L}`,D=A.get(U);if(!D)throw new Error(`Cannot substitute {${C}}: measure '${U}' not resolved yet. Ensure measures are resolved in dependency order.`);const c=D(),l=s.sql`${c}`;t.set(C,l)}const I=[],r=[];let N=0;for(const O of S){const C=`{${O.originalRef}}`,i=e.indexOf(C,N);if(i>=0){I.push(e.substring(N,i));const L=t.get(O.originalRef);L&&r.push(L),N=i+C.length}}if(I.push(e.substring(N)),r.length===0)return s.sql.raw(e);const n=[];for(let O=0;O<I.length;O++)I[O]&&n.push(new s.StringChunk(I[O])),O<r.length&&n.push(r[O]);return s.sql.join(n,s.sql.raw(""))}function bE(e){const E=/\{([^}]+)\}/g,T=e.matchAll(E),R=[];for(const A of T){const S=A[1].trim();if(S.includes(".")){const[t,I]=S.split(".").map(r=>r.trim());R.push({originalRef:S,cubeName:t,fieldName:I})}else R.push({originalRef:S,cubeName:null,fieldName:S})}return R}function Re(e){const E=[];let T=0;for(let t=0;t<e.length;t++)if(e[t]==="{")T++;else if(e[t]==="}"&&(T--,T<0)){E.push(`Unmatched closing brace at position ${t}`);break}T>0&&E.push("Unmatched opening brace in template"),/\{\s*\}/.test(e)&&E.push("Empty member reference {} found in template"),/\{[^}]*\{/.test(e)&&E.push("Nested braces are not allowed in member references");const S=bE(e);for(const t of S){const I=t.cubeName?`${t.cubeName}.${t.fieldName}`:t.fieldName;/^[a-zA-Z_][a-zA-Z0-9_.]*$/.test(I)||E.push(`Invalid member reference {${t.originalRef}}: must start with letter or underscore, and contain only letters, numbers, underscores, and dots`),I.split(".").length>2&&E.push(`Invalid member reference {${t.originalRef}}: only one dot allowed (Cube.measure format)`)}return{isValid:E.length===0,errors:E}}function tE(e,E){const T=bE(e),R=new Set;for(const A of T){const t=`${A.cubeName||E}.${A.fieldName}`;R.add(t)}return Array.from(R)}class B{constructor(E){this.databaseAdapter=E}buildResolvedMeasures(E,T,R,A){const S=new Map,t=[],I=[],r=new Set(E),N=new y(T);for(const n of T.values())N.buildGraph(n);for(const n of E){const[O,C]=n.split("."),i=T.get(O);if(i&&i.measures&&i.measures[C]){const L=i.measures[C];if(B.isPostAggregationWindow(L)){const M=B.getWindowBaseMeasure(L,O);M&&r.add(M);continue}y.isCalculatedMeasure(L)?(I.push(n),tE(L.calculatedSql,O).forEach(U=>r.add(U)),N.getAllDependencies(n).forEach(U=>{const[D,c]=U.split("."),l=T.get(D);if(l&&l.measures[c]){const d=l.measures[c];y.isCalculatedMeasure(d)&&tE(d.calculatedSql,D).forEach(p=>r.add(p))}})):t.push(n)}}for(const n of r){const[O,C]=n.split("."),i=T.get(O);if(i&&i.measures&&i.measures[C]){const L=i.measures[C];if(B.isPostAggregationWindow(L))continue;y.isCalculatedMeasure(L)?I.includes(n)||I.push(n):t.includes(n)||t.push(n)}}for(const n of t){const[O,C]=n.split("."),i=T.get(O),L=i.measures[C];if(A){const M=A(n,L,i);S.set(n,()=>M)}else S.set(n,()=>this.buildMeasureExpression(L,R,i))}if(I.length>0){const n=N.topologicalSort(I);for(const O of n){const[C,i]=O.split("."),L=T.get(C),M=L.measures[i];S.set(O,()=>this.buildCalculatedMeasure(M,L,T,S,R))}}return S}buildCalculatedMeasure(E,T,R,A,S){if(!E.calculatedSql)throw new Error(`Calculated measure '${T.name}.${E.name}' missing calculatedSql property`);const t=this.databaseAdapter.preprocessCalculatedTemplate(E.calculatedSql);return ee(t,{cube:T,allCubes:R,resolvedMeasures:A})}buildCTECalculatedMeasure(E,T,R,A,S){if(!E.calculatedSql)throw new Error(`Calculated measure '${T.name}.${E.name||"unknown"}' missing calculatedSql property`);const t=new Map,I=tE(E.calculatedSql,T.name);for(const r of I){const[N,n]=r.split("."),O=A.get(N);if(O&&O.measures[n]){const C=O.measures[n];if(R.measures.includes(r)){const i=s.sql`${s.sql.identifier(R.cteAlias)}.${s.sql.identifier(n)}`;let L;switch(C.type){case"count":case"countDistinct":case"sum":L=s.sum(i);break;case"avg":L=this.databaseAdapter.buildAvg(i);break;case"min":L=s.min(i);break;case"max":L=s.max(i);break;case"number":L=s.sum(i);break;default:L=s.sum(i)}t.set(r,()=>L)}}}return this.buildCalculatedMeasure(E,T,A,t,S)}buildHavingMeasureExpression(E,T,R,A,S){if(S&&S.preAggregationCTEs){const t=S.preAggregationCTEs.find(I=>I.cube.name===E);if(t&&t.measures.includes(`${E}.${T}`))if(R.type==="calculated"&&R.calculatedSql){const I=S.primaryCube.name===E?S.primaryCube:S.joinCubes?.find(N=>N.cube.name===E)?.cube;if(!I)throw new Error(`Cube ${E} not found in query plan`);const r=new Map([[S.primaryCube.name,S.primaryCube]]);if(S.joinCubes)for(const N of S.joinCubes)r.set(N.cube.name,N.cube);return this.buildCTECalculatedMeasure(R,I,t,r,A)}else{const I=s.sql`${s.sql.identifier(t.cteAlias)}.${s.sql.identifier(T)}`;switch(R.type){case"count":case"countDistinct":case"sum":return s.sum(I);case"avg":return this.databaseAdapter.buildAvg(I);case"min":return s.min(I);case"max":return s.max(I);case"number":return s.sum(I);default:return s.sum(I)}}}return this.buildMeasureExpression(R,A)}buildMeasureExpression(E,T,R){if(E.type==="calculated")throw new Error(`Cannot build calculated measure '${E.name}' directly. Use buildCalculatedMeasure instead.`);if(B.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 A=h(E.sql,T);if(E.filters&&E.filters.length>0){const S=E.filters.map(t=>{const I=t(T);return I?s.sql`(${I})`:void 0}).filter(Boolean);if(S.length>0){const t=S.length===1?S[0]:s.and(...S);A=this.databaseAdapter.buildCaseWhen([{when:t,then:A}])}}switch(E.type){case"count":return s.count(A);case"countDistinct":return s.countDistinct(A);case"sum":return s.sum(A);case"avg":return this.databaseAdapter.buildAvg(A);case"min":return s.min(A);case"max":return s.max(A);case"number":return A;case"stddev":case"stddevSamp":{const S=E.type==="stddevSamp"||E.statisticalConfig?.useSample,t=this.databaseAdapter.buildStddev(A,S);return t===null?(console.warn(`[drizzle-cube] ${E.type} not supported on ${this.databaseAdapter.getEngineType()}, returning NULL`),s.sql`MAX(NULL)`):t}case"variance":case"varianceSamp":{const S=E.type==="varianceSamp"||E.statisticalConfig?.useSample,t=this.databaseAdapter.buildVariance(A,S);return t===null?(console.warn(`[drizzle-cube] ${E.type} not supported on ${this.databaseAdapter.getEngineType()}, returning NULL`),s.sql`MAX(NULL)`):t}case"percentile":case"median":case"p95":case"p99":{let S;switch(E.type){case"median":S=50;break;case"p95":S=95;break;case"p99":S=99;break;default:S=E.statisticalConfig?.percentile??50}const t=this.databaseAdapter.buildPercentile(A,S);return t===null?(console.warn(`[drizzle-cube] ${E.type} not supported on ${this.databaseAdapter.getEngineType()}, returning NULL`),s.sql`MAX(NULL)`):t}case"lag":case"lead":case"rank":case"denseRank":case"rowNumber":case"ntile":case"firstValue":case"lastValue":case"movingAvg":case"movingSum":{const S=E.windowConfig||{};let t;if(S.partitionBy&&S.partitionBy.length>0&&R){const N=S.partitionBy.map(n=>{const O=n.includes(".")?n.split(".")[1]:n,C=R.dimensions?.[O];return C?h(C.sql,T):(console.warn(`[drizzle-cube] Window function partition dimension '${n}' not found in cube '${R.name}'`),null)}).filter(n=>n!==null);N.length>0&&(t=N)}let I;if(S.orderBy&&S.orderBy.length>0&&R){const N=S.orderBy.map(n=>{const O=n.field.includes(".")?n.field.split(".")[1]:n.field,C=R.dimensions?.[O];if(C)return{field:h(C.sql,T),direction:n.direction};const i=R.measures?.[O];return i&&i.sql?{field:h(i.sql,T),direction:n.direction}:(console.warn(`[drizzle-cube] Window function order field '${n.field}' not found in cube '${R.name}'`),null)}).filter(n=>n!==null);N.length>0&&(I=N)}const r=this.databaseAdapter.buildWindowFunction(E.type,["rank","denseRank","rowNumber"].includes(E.type)?null:A,t,I,{offset:S.offset,defaultValue:S.defaultValue,nTile:S.nTile,frame:S.frame});return r===null?(console.warn(`[drizzle-cube] ${E.type} not supported on ${this.databaseAdapter.getEngineType()}, returning NULL`),s.sql`NULL`):r}default:return s.count(A)}}static WINDOW_FUNCTION_TYPES=["lag","lead","rank","denseRank","rowNumber","ntile","firstValue","lastValue","movingAvg","movingSum"];static isWindowFunction(E){return B.WINDOW_FUNCTION_TYPES.includes(E)}static categorizeMeasures(E,T){const R=[],A=[];for(const S of E){const[t,I]=S.split("."),r=T.get(t);if(r?.measures?.[I]){const N=r.measures[I];B.isWindowFunction(N.type)?R.push(S):A.push(S)}}return{windowMeasures:R,aggregateMeasures:A}}static hasWindowFunctions(E,T){const{windowMeasures:R}=B.categorizeMeasures(E,T);return R.length>0}static isPostAggregationWindow(E){return B.isWindowFunction(E.type)&&E.windowConfig?.measure!==void 0}static getWindowBaseMeasure(E,T){if(!E.windowConfig?.measure)return null;const R=E.windowConfig.measure;return R.includes(".")?R:`${T}.${R}`}static getDefaultWindowOperation(E){switch(E){case"lag":case"lead":return"difference";default:return"raw"}}static categorizeForPostAggregation(E,T){const R=[],A=[],S=new Set;for(const t of E){const[I,r]=t.split("."),N=T.get(I);if(N?.measures?.[r]){const n=N.measures[r];if(B.isPostAggregationWindow(n)){A.push(t);const O=B.getWindowBaseMeasure(n,I);O&&S.add(O)}else B.isWindowFunction(n.type)||R.push(t)}}return{aggregateMeasures:R,postAggWindowMeasures:A,requiredBaseMeasures:S}}static hasPostAggregationWindows(E,T){const{postAggWindowMeasures:R}=B.categorizeForPostAggregation(E,T);return R.length>0}}class GT{dateTimeBuilder;filterBuilder;groupByBuilder;measureBuilder;constructor(E){this.dateTimeBuilder=new zT(E),this.filterBuilder=new Ee(E,this.dateTimeBuilder),this.groupByBuilder=new Te(this.dateTimeBuilder),this.measureBuilder=new B(E)}buildResolvedMeasures(E,T,R,A){return this.measureBuilder.buildResolvedMeasures(E,T,R,A)}buildSelections(E,T,R){const A={},S=E instanceof Map?E:new Map([[E.name,E]]);if(T.dimensions)for(const t of T.dimensions){const[I,r]=t.split("."),N=S.get(I);if(N&&N.dimensions&&N.dimensions[r]){const n=N.dimensions[r],O=h(n.sql,R);A[t]=s.sql`${O}`.as(t)}}if(T.measures){const t=this.buildResolvedMeasures(T.measures,S,R);for(const I of T.measures){const r=t.get(I);if(r){const N=r();A[I]=s.sql`${N}`.as(I)}}}if(T.timeDimensions)for(const t of T.timeDimensions){const[I,r]=t.dimension.split("."),N=S.get(I);if(N&&N.dimensions&&N.dimensions[r]){const n=N.dimensions[r],O=this.buildTimeDimensionExpression(n.sql,t.granularity,R);A[t.dimension]=s.sql`${O}`.as(t.dimension)}}return Object.keys(A).length===0&&(A.count=s.count()),A}buildCalculatedMeasure(E,T,R,A,S){return this.measureBuilder.buildCalculatedMeasure(E,T,R,A,S)}buildCTECalculatedMeasure(E,T,R,A,S){return this.measureBuilder.buildCTECalculatedMeasure(E,T,R,A,S)}buildHavingMeasureExpression(E,T,R,A,S){return this.measureBuilder.buildHavingMeasureExpression(E,T,R,A,S)}buildMeasureExpression(E,T,R){return this.measureBuilder.buildMeasureExpression(E,T,R)}buildTimeDimensionExpression(E,T,R){return this.dateTimeBuilder.buildTimeDimensionExpression(E,T,R)}buildWhereConditions(E,T,R,A,S){const t=[],I=E instanceof Map?E:new Map([[E.name,E]]),r=new Set;if(T.filters&&T.filters.length>0)for(const N of T.filters){if(S&&"member"in N){const[O]=N.member.split(".");if(I.has(O)&&S.has(O)&&!r.has(O)){const i=S.get(O);t.push(...i),r.add(O);continue}else if(r.has(O))continue}const n=this.processFilter(N,I,R,"where",A);n&&t.push(n)}if(T.timeDimensions)for(const N of T.timeDimensions){const[n,O]=N.dimension.split("."),C=I.get(n);if(C&&C.dimensions[O]&&N.dateRange){if(A?.preAggregationCTEs&&A.preAggregationCTEs.some(U=>U.cube.name===n))continue;if(R.filterCache){const a=uT(N.dimension,N.dateRange),U=R.filterCache.get(a);if(U){t.push(U);continue}}const i=C.dimensions[O],L=h(i.sql,R),M=this.buildDateRangeCondition(L,N.dateRange);M&&t.push(M)}}return t}buildHavingConditions(E,T,R,A){const S=[],t=E instanceof Map?E:new Map([[E.name,E]]);if(T.filters&&T.filters.length>0)for(const I of T.filters){const r=this.processFilter(I,t,R,"having",A);r&&S.push(r)}return S}processFilter(E,T,R,A,S){if("and"in E||"or"in E){const i=E;if(i.and){const L=i.and.map(M=>this.processFilter(M,T,R,A,S)).filter(M=>M!==null);return L.length>0?s.and(...L):null}if(i.or){const L=i.or.map(M=>this.processFilter(M,T,R,A,S)).filter(M=>M!==null);return L.length>0?s.or(...L):null}}const t=E,[I,r]=t.member.split("."),N=T.get(I);if(!N)return null;const n=N.dimensions[r],O=N.measures[r],C=n||O;if(!C)return null;if(A==="where"&&n){if(S?.preAggregationCTEs&&S.preAggregationCTEs.some(a=>a.cube.name===I))return null;const i=["arrayContains","arrayOverlaps","arrayContained"].includes(t.operator);if(!i&&R.filterCache){const M=TE(E),a=R.filterCache.get(M);if(a)return a}const L=i?typeof n.sql=="function"?n.sql(R):n.sql:h(n.sql,R);return this.buildFilterCondition(L,t.operator,t.values,C,t.dateRange)}else{if(A==="where"&&O)return null;if(A==="having"&&O){const i=this.buildHavingMeasureExpression(I,r,O,R,S);return this.buildFilterCondition(i,t.operator,t.values,C,t.dateRange)}}return null}buildFilterCondition(E,T,R,A,S){return this.filterBuilder.buildFilterCondition(E,T,R,A,S)}buildDateRangeCondition(E,T){return this.dateTimeBuilder.buildDateRangeCondition(E,T)}buildGroupByFields(E,T,R,A){return this.groupByBuilder.buildGroupByFields(E,T,R,A)}buildOrderBy(E,T){const R=[],A=T||[...E.measures||[],...E.dimensions||[],...E.timeDimensions?.map(S=>S.dimension)||[]];if(E.order&&Object.keys(E.order).length>0)for(const[S,t]of Object.entries(E.order)){if(!A.includes(S))throw new Error(`Cannot order by '${S}': field is not selected in the query`);const I=t==="desc"?s.desc(s.sql.identifier(S)):s.asc(s.sql.identifier(S));R.push(I)}if(E.timeDimensions&&E.timeDimensions.length>0){const S=new Set(Object.keys(E.order||{})),t=[...E.timeDimensions].sort((I,r)=>I.dimension.localeCompare(r.dimension));for(const I of t)S.has(I.dimension)||R.push(s.asc(s.sql.identifier(I.dimension)))}return R}collectNumericFields(E,T){const R=[],A=E instanceof Map?E:new Map([[E.name,E]]);if(T.measures&&R.push(...T.measures),T.dimensions)for(const S of T.dimensions){const[t,I]=S.split("."),r=A.get(t);if(r){const N=r.dimensions[I];N&&N.type==="number"&&R.push(S)}}return R}applyLimitAndOffset(E,T){let R=T.limit;T.offset!==void 0&&T.offset>0&&R===void 0&&(R=50);let A=E;if(R!==void 0){if(R<0)throw new Error("Limit must be non-negative");A=A.limit(R)}if(T.offset!==void 0){if(T.offset<0)throw new Error("Offset must be non-negative");A=A.offset(T.offset)}return A}buildFilterConditionPublic(E,T,R,A,S){return this.buildFilterCondition(E,T,R,A,S)}buildLogicalFilter(E,T,R){return this.filterBuilder.buildLogicalFilter(E,T,R)}}class Ae{cubes;connectivityCache=new Map;constructor(E){this.cubes=E}findPath(E,T,R=new Set){if(E===T)return[];const A=this.getCacheKey(E,T,R),S=this.getFromCache(A);if(S!==void 0)return S;const t=[{cube:E,path:[]}],I=new Set([E,...R]);for(;t.length>0;){const{cube:r,path:N}=t.shift(),n=this.cubes.get(r);if(n?.joins)for(const[,O]of Object.entries(n.joins)){const i=q(O.targetCube).name;if(I.has(i))continue;const L=[...N,{fromCube:r,toCube:i,joinDef:O}];if(i===T)return this.setInCache(A,L),L;I.add(i),t.push({cube:i,path:L})}}return this.setInCache(A,null),null}canReachAll(E,T){const R=T.filter(A=>A!==E);for(const A of R){const S=this.findPath(E,A,new Set);if(!S||S.length===0)return!1}return!0}buildJoinCondition(E,T,R){const A=[];for(const S of E.on){const t=T?s.sql`${s.sql.identifier(T)}.${s.sql.identifier(S.source.name)}`:FE(S.source),I=R?s.sql`${s.sql.identifier(R)}.${s.sql.identifier(S.target.name)}`:FE(S.target),r=S.as||s.eq;A.push(r(t,I))}return s.and(...A)}getReachableCubes(E){const T=new Set([E]),R=[E];for(;R.length>0;){const A=R.shift(),S=this.cubes.get(A);if(S?.joins)for(const[,t]of Object.entries(S.joins)){const r=q(t.targetCube).name;T.has(r)||(T.add(r),R.push(r))}}return T}getCacheKey(E,T,R){const A=Array.from(R).sort().join(",");return`${E}:${T}:${A}`}getFromCache(E){const T=this.connectivityCache.get(E);if(T)return T.path}setInCache(E,T){this.connectivityCache.set(E,{path:T})}}class WE{resolverCache=new WeakMap;getResolver(E){let T=this.resolverCache.get(E);return T||(T=new Ae(E),this.resolverCache.set(E,T)),T}analyzeCubeUsage(E){const T=new Set;if(E.measures)for(const R of E.measures){const[A]=R.split(".");T.add(A)}if(E.dimensions)for(const R of E.dimensions){const[A]=R.split(".");T.add(A)}if(E.timeDimensions)for(const R of E.timeDimensions){const[A]=R.dimension.split(".");T.add(A)}if(E.filters)for(const R of E.filters)this.extractCubeNamesFromFilter(R,T);return T}extractCubeNamesFromFilter(E,T){if("and"in E||"or"in E){const R=E.and||E.or||[];for(const A of R)this.extractCubeNamesFromFilter(A,T);return}if("member"in E){const[R]=E.member.spli