UNPKG

drizzle-cube

Version:

Drizzle ORM-first semantic layer with Cube.js compatibility. Type-safe analytics and dashboards with SQL injection protection.

2 lines 316 kB
"use strict";const V=Symbol.for("drizzle:entityKind");function d(T,E){if(!T||typeof T!="object")return!1;if(T instanceof E)return!0;if(!Object.prototype.hasOwnProperty.call(E,V))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 e=Object.getPrototypeOf(T).constructor;if(e)for(;e;){if(V in e&&e[V]===E[V])return!0;e=Object.getPrototypeOf(e)}return!1}class RE{constructor(E,e){this.table=E,this.config=e,this.name=e.name,this.keyAsName=e.keyAsName,this.notNull=e.notNull,this.default=e.default,this.defaultFn=e.defaultFn,this.onUpdateFn=e.onUpdateFn,this.hasDefault=e.hasDefault,this.primary=e.primaryKey,this.isUnique=e.isUnique,this.uniqueName=e.uniqueName,this.uniqueType=e.uniqueType,this.dataType=e.dataType,this.columnType=e.columnType,this.generated=e.generated,this.generatedIdentity=e.generatedIdentity}static[V]="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 iE=Symbol.for("drizzle:Name"),TT=Symbol.for("drizzle:isPgEnum");function oe(T){return!!T&&typeof T=="function"&&TT in T&&T[TT]===!0}class xT{static[V]="Subquery";constructor(E,e,R,A=!1,S=[]){this._={brand:"Subquery",sql:E,selectedFields:e,alias:R,isWith:A,usedTables:S}}}const De={startActiveSpan(T,E){return E()}},TE=Symbol.for("drizzle:ViewBaseConfig"),aE=Symbol.for("drizzle:Schema"),eT=Symbol.for("drizzle:Columns"),RT=Symbol.for("drizzle:ExtraConfigColumns"),oE=Symbol.for("drizzle:OriginalName"),DE=Symbol.for("drizzle:BaseName"),sE=Symbol.for("drizzle:IsAlias"),AT=Symbol.for("drizzle:ExtraConfigBuilder"),Pe=Symbol.for("drizzle:IsDrizzleTable");class W{static[V]="Table";static Symbol={Name:iE,Schema:aE,OriginalName:oE,Columns:eT,ExtraConfigColumns:RT,BaseName:DE,IsAlias:sE,ExtraConfigBuilder:AT};[iE];[oE];[aE];[eT];[RT];[DE];[sE]=!1;[Pe]=!0;[AT]=void 0;constructor(E,e,R){this[iE]=this[oE]=E,this[aE]=e,this[DE]=R}}function vT(T){return T!=null&&typeof T.getSQL=="function"}function Me(T){const E={sql:"",params:[]};for(const e of T)E.sql+=e.sql,E.params.push(...e.params),e.typings?.length&&(E.typings||(E.typings=[]),E.typings.push(...e.typings));return E}class f{static[V]="StringChunk";value;constructor(E){this.value=Array.isArray(E)?E:[E]}getSQL(){return new H([this])}}class H{constructor(E){this.queryChunks=E;for(const e of E)if(d(e,W)){const R=e[W.Symbol.Schema];this.usedTables.push(R===void 0?e[W.Symbol.Name]:R+"."+e[W.Symbol.Name])}}static[V]="SQL";decoder=QT;shouldInlineParams=!1;usedTables=[];append(E){return this.queryChunks.push(...E.queryChunks),this}toQuery(E){return De.startActiveSpan("drizzle.buildSQL",e=>{const R=this.buildQueryFromSourceParams(this.queryChunks,E);return e?.setAttributes({"drizzle.query.text":R.sql,"drizzle.query.params":JSON.stringify(R.params)}),R})}buildQueryFromSourceParams(E,e){const R=Object.assign({},e,{inlineParams:e.inlineParams||this.shouldInlineParams,paramStartIndex:e.paramStartIndex||{value:0}}),{casing:A,escapeName:S,escapeParam:I,prepareTyping:t,inlineParams:s,paramStartIndex:O}=R;return Me(E.map(N=>{if(d(N,f))return{sql:N.value.join(""),params:[]};if(d(N,ZE))return{sql:S(N.value),params:[]};if(N===void 0)return{sql:"",params:[]};if(Array.isArray(N)){const C=[new f("(")];for(const[L,n]of N.entries())C.push(n),L<N.length-1&&C.push(new f(", "));return C.push(new f(")")),this.buildQueryFromSourceParams(C,R)}if(d(N,H))return this.buildQueryFromSourceParams(N.queryChunks,{...R,inlineParams:s||N.shouldInlineParams});if(d(N,W)){const C=N[W.Symbol.Schema],L=N[W.Symbol.Name];return{sql:C===void 0||N[sE]?S(L):S(C)+"."+S(L),params:[]}}if(d(N,RE)){const C=A.getColumnCasing(N);if(e.invokeSource==="indexes")return{sql:S(C),params:[]};const L=N.table[W.Symbol.Schema];return{sql:N.table[sE]||L===void 0?S(N.table[W.Symbol.Name])+"."+S(C):S(L)+"."+S(N.table[W.Symbol.Name])+"."+S(C),params:[]}}if(d(N,qT)){const C=N[TE].schema,L=N[TE].name;return{sql:C===void 0||N[TE].isAlias?S(L):S(C)+"."+S(L),params:[]}}if(d(N,CE)){if(d(N.value,rE))return{sql:I(O.value++,N),params:[N],typings:["none"]};const C=N.value===null?null:N.encoder.mapToDriverValue(N.value);if(d(C,H))return this.buildQueryFromSourceParams([C],R);if(s)return{sql:this.mapInlineParam(C,R),params:[]};let L=["none"];return t&&(L=[t(N.encoder)]),{sql:I(O.value++,C),params:[C],typings:L}}return d(N,rE)?{sql:I(O.value++,N),params:[N],typings:["none"]}:d(N,H.Aliased)&&N.fieldAlias!==void 0?{sql:S(N.fieldAlias),params:[]}:d(N,xT)?N._.isWith?{sql:S(N._.alias),params:[]}:this.buildQueryFromSourceParams([new f("("),N._.sql,new f(") "),new ZE(N._.alias)],R):oe(N)?N.schema?{sql:S(N.schema)+"."+S(N.enumName),params:[]}:{sql:S(N.enumName),params:[]}:vT(N)?N.shouldOmitSQLParens?.()?this.buildQueryFromSourceParams([N.getSQL()],R):this.buildQueryFromSourceParams([new f("("),N.getSQL(),new f(")")],R):s?{sql:this.mapInlineParam(N,R),params:[]}:{sql:I(O.value++,N),params:[N],typings:["none"]}}))}mapInlineParam(E,{escapeString:e}){if(E===null)return"null";if(typeof E=="number"||typeof E=="boolean")return E.toString();if(typeof E=="string")return e(E);if(typeof E=="object"){const R=E.toString();return e(R==="[object Object]"?JSON.stringify(E):R)}throw new Error("Unexpected param value: "+E)}getSQL(){return this}as(E){return E===void 0?this:new H.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 ZE{constructor(E){this.value=E}static[V]="Name";brand;getSQL(){return new H([this])}}function Ue(T){return typeof T=="object"&&T!==null&&"mapToDriverValue"in T&&typeof T.mapToDriverValue=="function"}const QT={mapFromDriverValue:T=>T},ZT={mapToDriverValue:T=>T};({...QT,...ZT});class CE{constructor(E,e=ZT){this.value=E,this.encoder=e}static[V]="Param";brand;getSQL(){return new H([this])}}function r(T,...E){const e=[];(E.length>0||T.length>0&&T[0]!=="")&&e.push(new f(T[0]));for(const[R,A]of E.entries())e.push(A,new f(T[R+1]));return new H(e)}(T=>{function E(){return new H([])}T.empty=E;function e(s){return new H(s)}T.fromList=e;function R(s){return new H([new f(s)])}T.raw=R;function A(s,O){const N=[];for(const[C,L]of s.entries())C>0&&O!==void 0&&N.push(O),N.push(L);return new H(N)}T.join=A;function S(s){return new ZE(s)}T.identifier=S;function I(s){return new rE(s)}T.placeholder=I;function t(s,O){return new CE(s,O)}T.param=t})(r||(r={}));(T=>{class E{constructor(R,A){this.sql=R,this.fieldAlias=A}static[V]="SQL.Aliased";isSelectionField=!1;getSQL(){return this.sql}clone(){return new E(this.sql,this.fieldAlias)}}T.Aliased=E})(H||(H={}));class rE{constructor(E){this.name=E}static[V]="Placeholder";getSQL(){return new H([this])}}const le=Symbol.for("drizzle:IsDrizzleView");class qT{static[V]="View";[TE];[le]=!0;constructor({name:E,schema:e,selectedFields:R,query:A}){this[TE]={name:E,originalName:E,schema:e,selectedFields:R,query:A,isExisting:!A,isAlias:!1}}getSQL(){return new H([this])}}RE.prototype.getSQL=function(){return new H([this])};W.prototype.getSQL=function(){return new H([this])};xT.prototype.getSQL=function(){return new H([this])};function g(T,E){return Ue(E)&&!vT(T)&&!d(T,CE)&&!d(T,rE)&&!d(T,RE)&&!d(T,W)&&!d(T,qT)?new CE(T,E):T}const k=(T,E)=>r`${T} = ${g(E,T)}`,ST=(T,E)=>r`${T} <> ${g(E,T)}`;function h(...T){const E=T.filter(e=>e!==void 0);if(E.length!==0)return E.length===1?new H(E):new H([new f("("),r.join(E,new f(" and ")),new f(")")])}function PE(...T){const E=T.filter(e=>e!==void 0);if(E.length!==0)return E.length===1?new H(E):new H([new f("("),r.join(E,new f(" or ")),new f(")")])}const ME=(T,E)=>r`${T} > ${g(E,T)}`,Q=(T,E)=>r`${T} >= ${g(E,T)}`,UE=(T,E)=>r`${T} < ${g(E,T)}`,Z=(T,E)=>r`${T} <= ${g(E,T)}`;function lE(T,E){return Array.isArray(E)?E.length===0?r`false`:r`${T} in ${E.map(e=>g(e,T))}`:r`${T} in ${g(E,T)}`}function IT(T,E){return Array.isArray(E)?E.length===0?r`true`:r`${T} not in ${E.map(e=>g(e,T))}`:r`${T} not in ${g(E,T)}`}function NT(T){return r`${T} is null`}function OT(T){return r`${T} is not null`}function tT(T){return r`${T} asc`}function ce(T){return r`${T} desc`}function cE(T){return r`count(${T||r.raw("*")})`.mapWith(Number)}function ue(T){return r`count(distinct ${T})`.mapWith(Number)}function y(T){return r`sum(${T})`.mapWith(String)}function AE(T){return r`max(${T})`.mapWith(d(T,RE)?T:String)}function SE(T){return r`min(${T})`.mapWith(d(T,RE)?T:String)}class jE{preprocessCalculatedTemplate(E){return E}buildPattern(E,e){switch(E){case"contains":case"notContains":return`%${e}%`;case"startsWith":return`${e}%`;case"endsWith":return`%${e}`;default:return e}}}class Ge extends jE{getEngineType(){return"postgres"}buildTimeDimension(E,e){switch(E){case"year":return r`DATE_TRUNC('year', ${e}::timestamp)`;case"quarter":return r`DATE_TRUNC('quarter', ${e}::timestamp)`;case"month":return r`DATE_TRUNC('month', ${e}::timestamp)`;case"week":return r`DATE_TRUNC('week', ${e}::timestamp)`;case"day":return r`DATE_TRUNC('day', ${e}::timestamp)::timestamp`;case"hour":return r`DATE_TRUNC('hour', ${e}::timestamp)`;case"minute":return r`DATE_TRUNC('minute', ${e}::timestamp)`;case"second":return r`DATE_TRUNC('second', ${e}::timestamp)`;default:return e}}buildStringCondition(E,e,R){switch(e){case"contains":return r`${E} ILIKE ${`%${R}%`}`;case"notContains":return r`${E} NOT ILIKE ${`%${R}%`}`;case"startsWith":return r`${E} ILIKE ${`${R}%`}`;case"endsWith":return r`${E} ILIKE ${`%${R}`}`;case"like":return r`${E} LIKE ${R}`;case"notLike":return r`${E} NOT LIKE ${R}`;case"ilike":return r`${E} ILIKE ${R}`;case"regex":return r`${E} ~* ${R}`;case"notRegex":return r`${E} !~* ${R}`;default:throw new Error(`Unsupported string operator: ${e}`)}}castToType(E,e){switch(e){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: ${e}`)}}buildAvg(E){return r`COALESCE(AVG(${E}), 0)`}buildCaseWhen(E,e){const R=E.map(A=>r`WHEN ${A.when} THEN ${A.then}`).reduce((A,S)=>r`${A} ${S}`);return e!==void 0?r`CASE ${R} ELSE ${e} END`:r`CASE ${R} END`}buildBooleanLiteral(E){return E?r`TRUE`:r`FALSE`}convertFilterValue(E){return E}prepareDateValue(E){return E}isTimestampInteger(){return!1}convertTimeDimensionResult(E){return E}}class jT extends jE{getEngineType(){return"mysql"}buildTimeDimension(E,e){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 r`DATE_ADD(MAKEDATE(YEAR(${e}), 1), INTERVAL (QUARTER(${e}) - 1) * 3 MONTH)`;case"week":return r`DATE_SUB(${e}, INTERVAL WEEKDAY(${e}) DAY)`;default:const A=R[E];return A?r`STR_TO_DATE(DATE_FORMAT(${e}, ${A}), '%Y-%m-%d %H:%i:%s')`:e}}buildStringCondition(E,e,R){switch(e){case"contains":return r`LOWER(${E}) LIKE ${`%${R.toLowerCase()}%`}`;case"notContains":return r`LOWER(${E}) NOT LIKE ${`%${R.toLowerCase()}%`}`;case"startsWith":return r`LOWER(${E}) LIKE ${`${R.toLowerCase()}%`}`;case"endsWith":return r`LOWER(${E}) LIKE ${`%${R.toLowerCase()}`}`;case"like":return r`${E} LIKE ${R}`;case"notLike":return r`${E} NOT LIKE ${R}`;case"ilike":return r`LOWER(${E}) LIKE ${R.toLowerCase()}`;case"regex":return r`${E} REGEXP ${R}`;case"notRegex":return r`${E} NOT REGEXP ${R}`;default:throw new Error(`Unsupported string operator: ${e}`)}}castToType(E,e){switch(e){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: ${e}`)}}buildAvg(E){return r`IFNULL(AVG(${E}), 0)`}buildCaseWhen(E,e){const R=E.map(A=>r`WHEN ${A.when} THEN ${A.then}`).reduce((A,S)=>r`${A} ${S}`);return e!==void 0?r`CASE ${R} ELSE ${e} END`:r`CASE ${R} END`}buildBooleanLiteral(E){return E?r`TRUE`:r`FALSE`}convertFilterValue(E){return E}prepareDateValue(E){return E}isTimestampInteger(){return!1}convertTimeDimensionResult(E){return E}}class me extends jE{getEngineType(){return"sqlite"}buildTimeDimension(E,e){switch(E){case"year":return r`datetime(${e}, 'unixepoch', 'start of year')`;case"quarter":const R=r`datetime(${e}, 'unixepoch')`;return r`datetime(${R}, 'start of year', '+' || (((CAST(strftime('%m', ${R}) AS INTEGER) - 1) / 3) * 3) || ' months')`;case"month":return r`datetime(${e}, 'unixepoch', 'start of month')`;case"week":return r`date(datetime(${e}, 'unixepoch'), 'weekday 1', '-6 days')`;case"day":return r`datetime(${e}, 'unixepoch', 'start of day')`;case"hour":const A=r`datetime(${e}, 'unixepoch')`;return r`datetime(strftime('%Y-%m-%d %H:00:00', ${A}))`;case"minute":const S=r`datetime(${e}, 'unixepoch')`;return r`datetime(strftime('%Y-%m-%d %H:%M:00', ${S}))`;case"second":const I=r`datetime(${e}, 'unixepoch')`;return r`datetime(strftime('%Y-%m-%d %H:%M:%S', ${I}))`;default:return r`datetime(${e}, 'unixepoch')`}}buildStringCondition(E,e,R){switch(e){case"contains":return r`LOWER(${E}) LIKE ${`%${R.toLowerCase()}%`}`;case"notContains":return r`LOWER(${E}) NOT LIKE ${`%${R.toLowerCase()}%`}`;case"startsWith":return r`LOWER(${E}) LIKE ${`${R.toLowerCase()}%`}`;case"endsWith":return r`LOWER(${E}) LIKE ${`%${R.toLowerCase()}`}`;case"like":return r`${E} LIKE ${R}`;case"notLike":return r`${E} NOT LIKE ${R}`;case"ilike":return r`LOWER(${E}) LIKE ${R.toLowerCase()}`;case"regex":return r`${E} GLOB ${R}`;case"notRegex":return r`${E} NOT GLOB ${R}`;default:throw new Error(`Unsupported string operator: ${e}`)}}castToType(E,e){switch(e){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: ${e}`)}}buildAvg(E){return r`IFNULL(AVG(${E}), 0)`}buildCaseWhen(E,e){const R=E.map(A=>A.then&&typeof A.then=="object"&&(A.then.queryChunks||A.then._||A.then.sql)?r`WHEN ${A.when} THEN ${r.raw("(")}${A.then}${r.raw(")")}`:r`WHEN ${A.when} THEN ${A.then}`).reduce((A,S)=>r`${A} ${S}`);return e!==void 0?e&&typeof e=="object"&&(e.queryChunks||e._||e.sql)?r`CASE ${R} ELSE ${r.raw("(")}${e}${r.raw(")")} END`:r`CASE ${R} ELSE ${e} END`:r`CASE ${R} END`}buildBooleanLiteral(E){return E?r`1`:r`0`}preprocessCalculatedTemplate(E){const e=/(\{[^}]+\})\s*\/\s*/g;return E.replace(e,(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(e=>this.convertFilterValue(e)):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}}class He extends jT{getEngineType(){return"singlestore"}}function de(T){switch(T){case"postgres":return new Ge;case"mysql":return new jT;case"sqlite":return new me;case"singlestore":return new He;default:throw new Error(`Unsupported database engine: ${T}`)}}class kE{constructor(E,e,R){this.db=E,this.schema=e;const A=R||this.getEngineType();this.databaseAdapter=de(A)}databaseAdapter}class Be extends kE{async execute(E,e){if(E&&typeof E=="object"&&typeof E.execute=="function"){const A=await E.execute();return Array.isArray(A)?A.map(S=>this.convertNumericFields(S,e)):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,e)):R}convertNumericFields(E,e){if(!E||typeof E!="object")return E;const R={};for(const[A,S]of Object.entries(E))e&&e.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 e=E.toString();if(/^-?\d+(\.\d+)?$/.test(e))return e.includes(".")?parseFloat(e):parseInt(e,10)}if(E.constructor?.name==="Numeric"||E.constructor?.name==="Decimal"||"digits"in E||"sign"in E){const e=E.toString();return parseFloat(e)}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 sT(T,E){return new Be(T,E,"postgres")}class kT extends kE{async execute(E,e){if(E&&typeof E=="object"&&typeof E.execute=="function"){const A=await E.execute();return Array.isArray(A)?A.map(S=>this.convertNumericFields(S,e)):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,e)):R}convertNumericFields(E,e){if(!E||typeof E!="object")return E;const R={};for(const[A,S]of Object.entries(E))e&&e.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 pe(T,E){return new kT(T,E,"mysql")}class Fe extends kE{async execute(E,e){if(E&&typeof E=="object"&&typeof E.execute=="function"){const R=await E.execute();return Array.isArray(R)?R.map(A=>this.convertNumericFields(A,e)):R}try{if(this.db.all){const R=this.db.all(E);return Array.isArray(R)?R.map(A=>this.convertNumericFields(A,e)):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,e){if(!E||typeof E!="object")return E;const R={};for(const[A,S]of Object.entries(E))e&&e.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 CT(T,E){return new Fe(T,E,"sqlite")}class Ye extends kT{getEngineType(){return"singlestore"}}function fe(T,E){return new Ye(T,E)}function rT(T,E,e){if(e)switch(e){case"postgres":return sT(T,E);case"mysql":return pe(T,E);case"sqlite":return CT(T,E);case"singlestore":return fe(T,E)}if(T.all&&T.run)return CT(T,E);if(T.execute)return sT(T,E);throw new Error("Unable to determine database engine type. Please specify engineType parameter.")}function LT(T){return typeof T=="function"?T():T}function zT(T,E){if(E)return E;switch(T){case"belongsTo":return"inner";case"hasOne":return"left";case"hasMany":return"left";case"belongsToMany":return"left";default:return"left"}}function he(T){return T&&typeof T=="object"?r`${r`${T}`}`:T}function w(T,E){const e=typeof T=="function"?T(E):T;return he(e)}function Ve(T,E){if(T.relationship!=="belongsToMany"||!T.through)throw new Error("expandBelongsToManyJoin can only be called on belongsToMany relationships with through configuration");const{table:e,sourceKey:R,targetKey:A,securitySql:S}=T.through,I=[];for(const N of R){const C=N.as||k;I.push(C(N.source,N.target))}const t=[];for(const N of A){const C=N.as||k;t.push(C(N.source,N.target))}let s;if(S){const N=S(E);s=Array.isArray(N)?N:[N]}const O=zT("belongsToMany",T.sqlJoinType);return{junctionJoins:[{joinType:O,table:e,condition:h(...I)},{joinType:O,table:e,condition:h(...t)}],junctionSecurityConditions:s}}class J{dependencyGraph;cubes;constructor(E){this.cubes=E instanceof Map?E:new Map([[E.name,E]]),this.dependencyGraph=new Map}extractDependencies(E){const e=/\{([^}]+)\}/g,R=E.matchAll(e),A=[];for(const S of R){const I=S[1].trim();if(I.includes(".")){const[t,s]=I.split(".");A.push({measureName:I,cubeName:t.trim(),fieldName:s.trim()})}else A.push({measureName:I,cubeName:null,fieldName:I})}return A}buildGraph(E){for(const[e,R]of Object.entries(E.measures))if(R.type==="calculated"&&R.calculatedSql){const A=`${E.name}.${e}`,S=this.extractDependencies(R.calculatedSql),I=new Set;for(const t of S){const O=`${t.cubeName||E.name}.${t.fieldName}`;I.add(O)}this.dependencyGraph.set(A,{id:A,dependencies:I,inDegree:0})}this.calculateInDegrees()}buildGraphForMultipleCubes(E){for(const e of E.values())this.buildGraph(e)}calculateInDegrees(){for(const E of this.dependencyGraph.values())E.inDegree=0;for(const E of this.dependencyGraph.values())for(const e of E.dependencies){const R=this.dependencyGraph.get(e);R&&R.inDegree++}}topologicalSort(E){const e=new Map,R=[],A=[];for(const S of E){const I=this.dependencyGraph.get(S);I&&e.set(S,{id:I.id,dependencies:new Set(I.dependencies),inDegree:0})}for(const S of e.values()){let I=0;for(const t of S.dependencies)e.has(t)&&I++;S.inDegree=I}for(const[S,I]of e)I.inDegree===0&&R.push(S);for(;R.length>0;){const S=R.shift();A.push(S);for(const[I,t]of e)t.dependencies.has(S)&&(t.inDegree--,t.inDegree===0&&R.push(I))}if(A.length<e.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,e=new Set,R=[];for(const A of this.dependencyGraph.keys())if(!E.has(A)){const S=this.dfs(A,E,e,R);if(S)return S}return null}dfs(E,e,R,A){e.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 I of S.dependencies)if(e.has(I)){if(R.has(I)){const t=A.indexOf(I);return[...A.slice(t),I]}}else{const t=this.dfs(I,e,R,A);if(t)return t}return A.pop(),R.delete(E),null}getAllDependencies(E){const e=new Set,R=new Set,A=S=>{if(R.has(S))return;R.add(S);const I=this.dependencyGraph.get(S);if(I)for(const t of I.dependencies)e.add(t),A(t)};return A(E),e}validateDependencies(E){for(const[e,R]of Object.entries(E.measures))if(R.type==="calculated"&&R.calculatedSql){const A=this.extractDependencies(R.calculatedSql);for(const S of A){const I=S.cubeName||E.name,t=this.cubes.get(I);if(!t)throw new Error(`Calculated measure '${E.name}.${e}' references unknown cube '${I}'`);if(!t.measures[S.fieldName])throw new Error(`Calculated measure '${E.name}.${e}' references unknown measure '${S.measureName}'`);if(I===E.name&&S.fieldName===e)throw new Error(`Calculated measure '${E.name}.${e}' cannot reference itself`)}}}populateDependencies(E){for(const[,e]of Object.entries(E.measures))if(e.type==="calculated"&&e.calculatedSql&&!e.dependencies){const R=this.extractDependencies(e.calculatedSql);e.dependencies=R.map(A=>A.measureName)}}static isCalculatedMeasure(E){return E.type==="calculated"&&!!E.calculatedSql}}function We(T,E){const{cube:e,allCubes:R,resolvedMeasures:A}=E,S=zE(T),I=new Map;for(const C of S){const{originalRef:L,cubeName:n,fieldName:i}=C,o=n||e.name;if(!R.get(o))throw new Error(`Cannot substitute {${L}}: cube '${o}' not found`);const P=`${o}.${i}`,l=A.get(P);if(!l)throw new Error(`Cannot substitute {${L}}: measure '${P}' not resolved yet. Ensure measures are resolved in dependency order.`);const M=l(),G=r`${M}`;I.set(L,G)}const t=[],s=[];let O=0;for(const C of S){const L=`{${C.originalRef}}`,n=T.indexOf(L,O);if(n>=0){t.push(T.substring(O,n));const i=I.get(C.originalRef);i&&s.push(i),O=n+L.length}}if(t.push(T.substring(O)),s.length===0)return r.raw(T);const N=[];for(let C=0;C<t.length;C++)t[C]&&N.push(new f(t[C])),C<s.length&&N.push(s[C]);return r.join(N,r.raw(""))}function zE(T){const E=/\{([^}]+)\}/g,e=T.matchAll(E),R=[];for(const A of e){const S=A[1].trim();if(S.includes(".")){const[I,t]=S.split(".").map(s=>s.trim());R.push({originalRef:S,cubeName:I,fieldName:t})}else R.push({originalRef:S,cubeName:null,fieldName:S})}return R}function be(T){const E=[];let e=0;for(let I=0;I<T.length;I++)if(T[I]==="{")e++;else if(T[I]==="}"&&(e--,e<0)){E.push(`Unmatched closing brace at position ${I}`);break}e>0&&E.push("Unmatched opening brace in template"),/\{\s*\}/.test(T)&&E.push("Empty member reference {} found in template"),/\{[^}]*\{/.test(T)&&E.push("Nested braces are not allowed in member references");const S=zE(T);for(const I of S){const t=I.cubeName?`${I.cubeName}.${I.fieldName}`:I.fieldName;/^[a-zA-Z_][a-zA-Z0-9_.]*$/.test(t)||E.push(`Invalid member reference {${I.originalRef}}: must start with letter or underscore, and contain only letters, numbers, underscores, and dots`),t.split(".").length>2&&E.push(`Invalid member reference {${I.originalRef}}: only one dot allowed (Cube.measure format)`)}return{isValid:E.length===0,errors:E}}function uE(T,E){const e=zE(T),R=new Set;for(const A of e){const I=`${A.cubeName||E}.${A.fieldName}`;R.add(I)}return Array.from(R)}class Xe{constructor(E){this.databaseAdapter=E}buildResolvedMeasures(E,e,R,A){const S=new Map,I=[],t=[],s=new Set(E),O=new J(e);for(const N of e.values())O.buildGraph(N);for(const N of E){const[C,L]=N.split("."),n=e.get(C);if(n&&n.measures&&n.measures[L]){const i=n.measures[L];J.isCalculatedMeasure(i)?(t.push(N),uE(i.calculatedSql,C).forEach(P=>s.add(P)),O.getAllDependencies(N).forEach(P=>{const[l,M]=P.split("."),G=e.get(l);if(G&&G.measures[M]){const m=G.measures[M];J.isCalculatedMeasure(m)&&uE(m.calculatedSql,l).forEach(b=>s.add(b))}})):I.push(N)}}for(const N of s){const[C,L]=N.split("."),n=e.get(C);if(n&&n.measures&&n.measures[L]){const i=n.measures[L];J.isCalculatedMeasure(i)?t.includes(N)||t.push(N):I.includes(N)||I.push(N)}}for(const N of I){const[C,L]=N.split("."),n=e.get(C),i=n.measures[L];if(A){const o=A(N,i,n);S.set(N,()=>o)}else S.set(N,()=>this.buildMeasureExpression(i,R))}if(t.length>0){const N=O.topologicalSort(t);for(const C of N){const[L,n]=C.split("."),i=e.get(L),o=i.measures[n];S.set(C,()=>this.buildCalculatedMeasure(o,i,e,S,R))}}return S}buildSelections(E,e,R){const A={},S=E instanceof Map?E:new Map([[E.name,E]]);if(e.dimensions)for(const I of e.dimensions){const[t,s]=I.split("."),O=S.get(t);if(O&&O.dimensions&&O.dimensions[s]){const N=O.dimensions[s],C=w(N.sql,R);A[I]=r`${C}`.as(I)}}if(e.measures){const I=this.buildResolvedMeasures(e.measures,S,R);for(const t of e.measures){const s=I.get(t);if(s){const O=s();A[t]=r`${O}`.as(t)}}}if(e.timeDimensions)for(const I of e.timeDimensions){const[t,s]=I.dimension.split("."),O=S.get(t);if(O&&O.dimensions&&O.dimensions[s]){const N=O.dimensions[s],C=this.buildTimeDimensionExpression(N.sql,I.granularity,R);A[I.dimension]=r`${C}`.as(I.dimension)}}return Object.keys(A).length===0&&(A.count=cE()),A}buildCalculatedMeasure(E,e,R,A,S){if(!E.calculatedSql)throw new Error(`Calculated measure '${e.name}.${E.name}' missing calculatedSql property`);const I=this.databaseAdapter.preprocessCalculatedTemplate(E.calculatedSql);return We(I,{cube:e,allCubes:R,resolvedMeasures:A})}buildCTECalculatedMeasure(E,e,R,A,S){if(!E.calculatedSql)throw new Error(`Calculated measure '${e.name}.${E.name||"unknown"}' missing calculatedSql property`);const I=new Map,t=uE(E.calculatedSql,e.name);for(const s of t){const[O,N]=s.split("."),C=A.get(O);if(C&&C.measures[N]){const L=C.measures[N];if(R.measures.includes(s)){const n=r`${r.identifier(R.cteAlias)}.${r.identifier(N)}`;let i;switch(L.type){case"count":case"countDistinct":case"sum":i=y(n);break;case"avg":i=this.databaseAdapter.buildAvg(n);break;case"min":i=SE(n);break;case"max":i=AE(n);break;case"number":i=y(n);break;default:i=y(n)}I.set(s,()=>i)}}}return this.buildCalculatedMeasure(E,e,A,I,S)}buildHavingMeasureExpression(E,e,R,A,S){if(S&&S.preAggregationCTEs){const I=S.preAggregationCTEs.find(t=>t.cube.name===E);if(I&&I.measures.includes(`${E}.${e}`))if(R.type==="calculated"&&R.calculatedSql){const t=S.primaryCube.name===E?S.primaryCube:S.joinCubes?.find(O=>O.cube.name===E)?.cube;if(!t)throw new Error(`Cube ${E} not found in query plan`);const s=new Map([[S.primaryCube.name,S.primaryCube]]);if(S.joinCubes)for(const O of S.joinCubes)s.set(O.cube.name,O.cube);return this.buildCTECalculatedMeasure(R,t,I,s,A)}else{const t=r`${r.identifier(I.cteAlias)}.${r.identifier(e)}`;switch(R.type){case"count":case"countDistinct":case"sum":return y(t);case"avg":return this.databaseAdapter.buildAvg(t);case"min":return SE(t);case"max":return AE(t);case"number":return y(t);default:return y(t)}}}return this.buildMeasureExpression(R,A)}buildMeasureExpression(E,e){if(E.type==="calculated")throw new Error(`Cannot build calculated measure '${E.name}' directly. Use buildCalculatedMeasure instead.`);if(!E.sql)throw new Error(`Measure '${E.name}' of type '${E.type}' is missing required 'sql' property. Only calculated measures can omit 'sql'.`);let R=w(E.sql,e);if(E.filters&&E.filters.length>0){const A=E.filters.map(S=>{const I=S(e);return I?r`(${I})`:void 0}).filter(Boolean);if(A.length>0){const S=A.length===1?A[0]:h(...A);R=this.databaseAdapter.buildCaseWhen([{when:S,then:R}])}}switch(E.type){case"count":return cE(R);case"countDistinct":return ue(R);case"sum":return y(R);case"avg":return this.databaseAdapter.buildAvg(R);case"min":return SE(R);case"max":return AE(R);case"number":return R;default:return cE(R)}}buildTimeDimensionExpression(E,e,R){const A=w(E,R);return e?this.databaseAdapter.buildTimeDimension(e,A):A instanceof H?A:r`${A}`}buildWhereConditions(E,e,R,A){const S=[],I=E instanceof Map?E:new Map([[E.name,E]]);if(e.filters&&e.filters.length>0)for(const t of e.filters){const s=this.processFilter(t,I,R,"where",A);s&&S.push(s)}if(e.timeDimensions)for(const t of e.timeDimensions){const[s,O]=t.dimension.split("."),N=I.get(s);if(N&&N.dimensions[O]&&t.dateRange){if(A?.preAggregationCTEs&&A.preAggregationCTEs.some(o=>o.cube.name===s))continue;const C=N.dimensions[O],L=w(C.sql,R),n=this.buildDateRangeCondition(L,t.dateRange);n&&S.push(n)}}return S}buildHavingConditions(E,e,R,A){const S=[],I=E instanceof Map?E:new Map([[E.name,E]]);if(e.filters&&e.filters.length>0)for(const t of e.filters){const s=this.processFilter(t,I,R,"having",A);s&&S.push(s)}return S}processFilter(E,e,R,A,S){if("and"in E||"or"in E){const n=E;if(n.and){const i=n.and.map(o=>this.processFilter(o,e,R,A,S)).filter(o=>o!==null);return i.length>0?h(...i):null}if(n.or){const i=n.or.map(o=>this.processFilter(o,e,R,A,S)).filter(o=>o!==null);return i.length>0?PE(...i):null}}const I=E,[t,s]=I.member.split("."),O=e.get(t);if(!O)return null;const N=O.dimensions[s],C=O.measures[s],L=N||C;if(!L)return null;if(A==="where"&&N){if(S?.preAggregationCTEs&&S.preAggregationCTEs.some(o=>o.cube.name===t))return null;const n=w(N.sql,R);return this.buildFilterCondition(n,I.operator,I.values,L,I.dateRange)}else{if(A==="where"&&C)return null;if(A==="having"&&C){const n=this.buildHavingMeasureExpression(t,s,C,R,S);return this.buildFilterCondition(n,I.operator,I.values,L,I.dateRange)}}return null}buildFilterCondition(E,e,R,A,S){if(S!==void 0){if(e!=="inDateRange")throw new Error(`dateRange can only be used with 'inDateRange' operator, but got '${e}'. 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.buildDateRangeCondition(E,S)}if(!R||R.length===0)return e==="equals"?this.databaseAdapter.buildBooleanLiteral(!1):null;const I=R.filter(s=>!(s==null||s===""||typeof s=="string"&&s.includes("\0"))).map(this.databaseAdapter.convertFilterValue);if(I.length===0&&!["set","notSet"].includes(e))return e==="equals"?this.databaseAdapter.buildBooleanLiteral(!1):null;const t=I[0];switch(e){case"equals":if(I.length>1){if(A?.type==="time"){const s=I.map(O=>this.normalizeDate(O)||O);return lE(E,s)}return lE(E,I)}else if(I.length===1){const s=A?.type==="time"&&this.normalizeDate(t)||t;return k(E,s)}return this.databaseAdapter.buildBooleanLiteral(!1);case"notEquals":return I.length>1?IT(E,I):I.length===1?ST(E,t):null;case"contains":return this.databaseAdapter.buildStringCondition(E,"contains",t);case"notContains":return this.databaseAdapter.buildStringCondition(E,"notContains",t);case"startsWith":return this.databaseAdapter.buildStringCondition(E,"startsWith",t);case"endsWith":return this.databaseAdapter.buildStringCondition(E,"endsWith",t);case"gt":return ME(E,t);case"gte":return Q(E,t);case"lt":return UE(E,t);case"lte":return Z(E,t);case"set":return OT(E);case"notSet":return NT(E);case"inDateRange":if(I.length>=2){const s=this.normalizeDate(I[0]);let O=this.normalizeDate(I[1]);if(s&&O){const N=R[1];if(typeof N=="string"&&/^\d{4}-\d{2}-\d{2}$/.test(N.trim())){const C=typeof O=="number"?new Date(O*(this.databaseAdapter.getEngineType()==="sqlite"?1e3:1)):new Date(O),L=new Date(C);L.setUTCHours(23,59,59,999),this.databaseAdapter.isTimestampInteger()?O=this.databaseAdapter.getEngineType()==="sqlite"?Math.floor(L.getTime()/1e3):L.getTime():O=L.toISOString()}return h(Q(E,s),Z(E,O))}}return null;case"beforeDate":{const s=this.normalizeDate(t);return s?UE(E,s):null}case"afterDate":{const s=this.normalizeDate(t);return s?ME(E,s):null}case"between":return I.length>=2?h(Q(E,I[0]),Z(E,I[1])):null;case"notBetween":return I.length>=2?PE(UE(E,I[0]),ME(E,I[1])):null;case"in":return I.length>0?lE(E,I):null;case"notIn":return I.length>0?IT(E,I):null;case"like":return this.databaseAdapter.buildStringCondition(E,"like",t);case"notLike":return this.databaseAdapter.buildStringCondition(E,"notLike",t);case"ilike":return this.databaseAdapter.buildStringCondition(E,"ilike",t);case"regex":return this.databaseAdapter.buildStringCondition(E,"regex",t);case"notRegex":return this.databaseAdapter.buildStringCondition(E,"notRegex",t);case"isEmpty":return PE(NT(E),k(E,""));case"isNotEmpty":return h(OT(E),ST(E,""));default:return null}}buildDateRangeCondition(E,e){if(!e)return null;if(Array.isArray(e)&&e.length>=2){const R=this.normalizeDate(e[0]);let A=this.normalizeDate(e[1]);if(!R||!A)return null;if(typeof e[1]=="string"&&/^\d{4}-\d{2}-\d{2}$/.test(e[1].trim())){const S=typeof A=="number"?new Date(A*(this.databaseAdapter.getEngineType()==="sqlite"?1e3:1)):new Date(A),I=new Date(S);I.setUTCHours(23,59,59,999),this.databaseAdapter.isTimestampInteger()?A=this.databaseAdapter.getEngineType()==="sqlite"?Math.floor(I.getTime()/1e3):I.getTime():A=I.toISOString()}return h(Q(E,R),Z(E,A))}if(typeof e=="string"){const R=this.parseRelativeDateRange(e);if(R){let N,C;return this.databaseAdapter.isTimestampInteger()?this.databaseAdapter.getEngineType()==="sqlite"?(N=Math.floor(R.start.getTime()/1e3),C=Math.floor(R.end.getTime()/1e3)):(N=R.start.getTime(),C=R.end.getTime()):(N=R.start.toISOString(),C=R.end.toISOString()),h(Q(E,N),Z(E,C))}const A=this.normalizeDate(e);if(!A)return null;const S=typeof A=="number"?new Date(A*(this.databaseAdapter.getEngineType()==="sqlite"?1e3:1)):new Date(A),I=new Date(S);I.setUTCHours(0,0,0,0);const t=new Date(S);t.setUTCHours(23,59,59,999);let s,O;return this.databaseAdapter.isTimestampInteger()?this.databaseAdapter.getEngineType()==="sqlite"?(s=Math.floor(I.getTime()/1e3),O=Math.floor(t.getTime()/1e3)):(s=I.getTime(),O=t.getTime()):(s=I.toISOString(),O=t.toISOString()),h(Q(E,s),Z(E,O))}return null}parseRelativeDateRange(E){const e=new Date,R=E.toLowerCase().trim(),A=e.getUTCFullYear(),S=e.getUTCMonth(),I=e.getUTCDate(),t=e.getUTCDay();if(R==="today"){const L=new Date(e);L.setUTCHours(0,0,0,0);const n=new Date(e);return n.setUTCHours(23,59,59,999),{start:L,end:n}}if(R==="yesterday"){const L=new Date(e);L.setUTCDate(I-1),L.setUTCHours(0,0,0,0);const n=new Date(e);return n.setUTCDate(I-1),n.setUTCHours(23,59,59,999),{start:L,end:n}}if(R==="this week"){const L=t===0?-6:1-t,n=new Date(e);n.setUTCDate(I+L),n.setUTCHours(0,0,0,0);const i=new Date(n);return i.setUTCDate(n.getUTCDate()+6),i.setUTCHours(23,59,59,999),{start:n,end:i}}if(R==="this month"){const L=new Date(Date.UTC(A,S,1,0,0,0,0)),n=new Date(Date.UTC(A,S+1,0,23,59,59,999));return{start:L,end:n}}if(R==="this quarter"){const L=Math.floor(S/3),n=new Date(Date.UTC(A,L*3,1,0,0,0,0)),i=new Date(Date.UTC(A,L*3+3,0,23,59,59,999));return{start:n,end:i}}if(R==="this year"){const L=new Date(Date.UTC(A,0,1,0,0,0,0)),n=new Date(Date.UTC(A,11,31,23,59,59,999));return{start:L,end:n}}const s=R.match(/^last\s+(\d+)\s+days?$/);if(s){const L=parseInt(s[1],10),n=new Date(e);n.setUTCDate(I-L+1),n.setUTCHours(0,0,0,0);const i=new Date(e);return i.setUTCHours(23,59,59,999),{start:n,end:i}}const O=R.match(/^last\s+(\d+)\s+weeks?$/);if(O){const n=parseInt(O[1],10)*7,i=new Date(e);i.setUTCDate(I-n+1),i.setUTCHours(0,0,0,0);const o=new Date(e);return o.setUTCHours(23,59,59,999),{start:i,end:o}}if(R==="last week"){const L=t===0?-13:-6-t,n=new Date(e);n.setUTCDate(I+L),n.setUTCHours(0,0,0,0);const i=new Date(n);return i.setUTCDate(n.getUTCDate()+6),i.setUTCHours(23,59,59,999),{start:n,end:i}}if(R==="last month"){const L=new Date(Date.UTC(A,S-1,1,0,0,0,0)),n=new Date(Date.UTC(A,S,0,23,59,59,999));return{start:L,end:n}}if(R==="last quarter"){const L=Math.floor(S/3),n=L===0?3:L-1,i=L===0?A-1:A,o=new Date(Date.UTC(i,n*3,1,0,0,0,0)),u=new Date(Date.UTC(i,n*3+3,0,23,59,59,999));return{start:o,end:u}}if(R==="last year"){const L=new Date(Date.UTC(A-1,0,1,0,0,0,0)),n=new Date(Date.UTC(A-1,11,31,23,59,59,999));return{start:L,end:n}}if(R==="last 12 months"){const L=new Date(Date.UTC(A,S-11,1,0,0,0,0)),n=new Date(e);return n.setUTCHours(23,59,59,999),{start:L,end:n}}const N=R.match(/^last\s+(\d+)\s+months?$/);if(N){const L=parseInt(N[1],10),n=new Date(Date.UTC(A,S-L+1,1,0,0,0,0)),i=new Date(e);return i.setUTCHours(23,59,59,999),{start:n,end:i}}const C=R.match(/^last\s+(\d+)\s+years?$/);if(C){const L=parseInt(C[1],10),n=new Date(Date.UTC(A-L,0,1,0,0,0,0)),i=new Date(e);return i.setUTCHours(23,59,59,999),{start:n,end:i}}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 e=new Date(E);return isNaN(e.getTime())?null:this.databaseAdapter.isTimestampInteger()?this.databaseAdapter.getEngineType()==="sqlite"?Math.floor(e.getTime()/1e3):e.getTime():e.toISOString()}buildGroupByFields(E,e,R,A){const S=[];if(!(e.measures&&e.measures.length>0))return[];const t=E instanceof Map?E:new Map([[E.name,E]]);if(e.dimensions)for(const s of e.dimensions){const[O,N]=s.split("."),C=t.get(O);if(C&&C.dimensions&&C.dimensions[N])if(A?.preAggregationCTEs?.some(n=>n.cube.name===O)){const n=A.preAggregationCTEs.find(o=>o.cube.name===O),i=n.joinKeys.find(o=>o.targetColumn===N);if(i&&i.sourceColumnObj)S.push(i.sourceColumnObj);else{const o=r`${r.identifier(n.cteAlias)}.${r.identifier(N)}`;S.push(o)}}else{const n=C.dimensions[N],i=w(n.sql,R);S.push(i)}}if(e.timeDimensions)for(const s of e.timeDimensions){const[O,N]=s.dimension.split("."),C=t.get(O);if(C&&C.dimensions&&C.dimensions[N])if(A?.preAggregationCTEs?.some(n=>n.cube.name===O)){const n=A.preAggregationCTEs.find(o=>o.cube.name===O),i=n.joinKeys.find(o=>o.targetColumn===N);if(i&&i.sourceColumnObj){const o=this.buildTimeDimensionExpression(i.sourceColumnObj,s.granularity,R);S.push(o)}else{const o=r`${r.identifier(n.cteAlias)}.${r.identifier(N)}`;S.push(o)}}else{const n=C.dimensions[N],i=this.buildTimeDimensionExpression(n.sql,s.granularity,R);S.push(i)}}return S}buildOrderBy(E,e){const R=[],A=e||[...E.measures||[],...E.dimensions||[],...E.timeDimensions?.map(S=>S.dimension)||[]];if(E.order&&Object.keys(E.order).length>0)for(const[S,I]of Object.entries(E.order)){if(!A.includes(S))throw new Error(`Cannot order by '${S}': field is not selected in the query`);const t=I==="desc"?ce(r.identifier(S)):tT(r.identifier(S));R.push(t)}if(E.timeDimensions&&E.timeDimensions.length>0){const S=new Set(Object.keys(E.order||{})),I=[...E.timeDimensions].sort((t,s)=>t.dimension.localeCompare(s.dimension));for(const t of I)S.has(t.dimension)||R.push(tT(r.identifier(t.dimension)))}return R}collectNumericFields(E,e){const R=[],A=E instanceof Map?E:new Map([[E.name,E]]);if(e.measures&&R.push(...e.measures),e.dimensions)for(const S of e.dimensions){const[I,t]=S.split("."),s=A.get(I);if(s){const O=s.dimensions[t];O&&O.type==="number"&&R.push(S)}}return R}applyLimitAndOffset(E,e){let R=e.limit;e.offset!==void 0&&e.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(e.offset!==void 0){if(e.offset<0)throw new Error("Offset must be non-negative");A=A.offset(e.offset)}return A}}class ye{analyzeCubeUsage(E){const e=new Set;if(E.measures)for(const R of E.measures){const[A]=R.split(".");e.add(A)}if(E.dimensions)for(const R of E.dimensions){const[A]=R.split(".");e.add(A)}if(E.timeDimensions)for(const R of E.timeDimensions){const[A]=R.dimension.split(".");e.add(A)}if(E.filters)for(const R of E.filters)this.extractCubeNamesFromFilter(R,e);return e}extractCubeNamesFromFilter(E,e){if("and"in E||"or"in E){const R=E.and||E.or||[];for(const A of R)this.extractCubeNamesFromFilter(A,e);return}if("member"in E){const[R]=E.member.split(".");R&&e.add(R)}}extractMeasuresFromFilters(E,e){const R=[];if(!E.filters)return R;for(const A of E.filters)this.extractMeasuresFromFilter(A,e,R);return R}extractMeasuresFromFilter(E,e,R){if("and"in E||"or"in E){const A=E.and||E.or||[];for(const S of A)this.extractMeasuresFromFilter(S,e,R);return}if("member"in E){const A=E.member,[S]=A.split(".");S===e&&R.push(A)}}createQueryPlan(E,e,R){const A=this.analyzeCubeUsage(e),S=Array.from(A);if(S.length===0)throw new Error("No cubes found in query");const I=this.choosePrimaryCube(S,e,E),t=E.get(I);if(!t)throw new Error(`Primary cube '${I}' not found`);if(S.length===1)return{primaryCube:t,joinCubes:[],selections:{},whereConditions:[],groupByFields:[]};const s=this.buildJoinPlan(E,t,S,R),O=this.planPreAggregationCTEs(E,t,s,e);return{primaryCube:t,joinCubes:s,selections:{},whereConditions:[],groupByFields:[],preAggregationCTEs:O}}choosePrimaryCube(E,e,R){if(e.dimensions&&e.dimensions.length>0&&R){const A=e.dimensions.map(I=>I.split(".")[0]),S=new Map;for(const I of A)S.set(I,(S.get(I)||0)+1);if(S.size>0){const I=Math.max(...S.values()),t=[...S.entries()].filter(([,s])=>s===I).map(([s])=>s).sort();for(const s of t)if(this.canReachAllCubes(s,E,R))return s}}if(R){const A=new Map;for(const S of E)if(this.canReachAllCubes(S,E,R)){const I=R.get(S),t=I?.joins?Object.keys(I.joins).length:0;A.set(S,t)}if(A.size>0){const S=Math.max(...A.values());return[...A.entries()].filter(([,t])=>t===S).map(([t])=>t).sort()[0]}}return[...E].sort()[0]}canReachAllCubes(E,e,R){const A=e.filter(S=>S!==E);for(const S of A){const I=this.findJoinPath(R,E,S,new Set);if(!I||I.length===0)return!1}return!0}buildJoinPlan(E,e,R,A){const S=[],I=new Set([e.name]),t=R.filter(s=>s!==e.name);for(const s of t){if(I.has(s))continue;const O=this.findJoinPath(E,e.name,s,I);if(!O||O.length===0)throw new Error(`No join path found from '${e.name}' to '${s}'`);for(const{toCube:N,joinDef:C}of O){if(I.has(N))continue;const L=E.get(N);if(!L)throw new Error(`Cube '${N}' not found`);if(C.relationship==="belongsToMany"&&C.through){const n=Ve(C,A.securityContext);S.push({cube:L,alias:`${N.toLowerCase()}_cube`,joinType:n.junctionJoins[1].joinType,joinCondition:n.junctionJoins[1].condition,junctionTable:{table:C.through.table,alias:`junction_${N.toLowerCase()}`,joinType:n.junctionJoins[0].joinType,joinCondition:n.junctionJoins[0].condition,securitySql:C.through.securitySql}})}else{const n=this.buildJoinCondition(C,null,null),i=zT(C.relationship,C.sqlJoinType);S.push({cube:L,alias:`${N.toLowerCase()}_cube`,joinType:i,joinCondition:n})}I.add(N)}}return S}buildJoinCondition(E,e,R){const A=[];for(const S of E.on){const I=e?r`${r.identifier(e)}.${r.identifier(S.source.name)}`:S.source,t=R?r`${r.identifier(R)}.${r.identifier(S.target.name)}`:S.target,s=S.as||k;A.push(s(I,t))}return h(...A)}findJoinPath(E,e,R,A){if(e===R)return[];const S=[{cube:e,path:[]}],I=new Set([e,...A]);for(;S.length>0;){const{cube:t,path:s}=S.shift(),O=E.get(t);if(O?.joins)for(const[,N]of Object.entries(O.joins)){const L=LT(N.targetCube).name;if(I.has(L))continue;const n=[...s,{fromCube:t,toCube:L,joinDef:N}];if(L===R)return n;I.add(L),S.push({cube:L,path:n})}}return null}planPreAggregationCTEs(E,e,R,A){const S=[];if(!A.measures||A.measures.length===0)return S;for(const I of R){const t=this.findHasManyJoinDef(e,I.cube.name);if(!t)continue;const s=A.measures?A.measures.filter(n=>n.startsWith(I.cube.name+".")):[],O=this.extractMeasuresFromFilters(A,I.cube.name),N=[...new Set([...s,...O])];if(N.length===0)continue;const C=this.expandCalculatedMeasureDependencies(I.cube,N),L=t.on.map(n=>({sourceColumn:n.source.name,targetColumn:n.target.name,sourceColumnObj:n.source,targetColumnObj:n.target}));S.push({cube:I.cube,alias:I.alias,cteAlias:`${I.cube.name.toLowerCase()}_agg`,joinKeys:L,measures:C})}return S}expandCalculatedMeasureDependencies(E,e){const R=new Set,A=[...e];for(;A.length>0;){const S=A.pop();if(R.has(S))continue;R.add(S);const[,I]=S.split(".");if(!E.measures||!E.measures[I])continue;const t=E.measures[I];if(t.type==="calculated"&&t.calculatedSql){const s=this.extractDependenciesFromTemplate(t.calculatedSql,E.name);for(const O of s)R.has(O)||A.push(O)}}return Array.from(R)}extractDependenciesFromTemplate(E,e){const R=/\{([^}]+)\}/g,A=E.matchAll(R),S=[];for(const I of A){const t=I[1].trim();t.includes(".")?S.push(t):S.push(`${e}.${t}`)}return S}findHasManyJoinDef(E,e){if(!E.joins)return null;for(const[,R]of Object.entries(E.joins))if(LT(R.targetCube).name===e&&R.relationship==="hasMany")return R;return null}}class GE{constructor(E){if(this.dbExecutor=E,this.databaseAdapter=E.databaseAdapter,!this.databaseAdapter)throw new Error("DatabaseExecutor must have a databaseAdapter property");this.queryBuilder=new Xe(this.databaseAdapter),this.queryPlanner=new ye}queryBuilder;queryPlanner;databaseAdapter;async execute(E,e,R){try{const A=_e(E,e);if(!A.isValid)throw new Error(`Query validation failed: ${A.errors.join(", ")}`);const S={db:this.dbExecutor.db,schema:this.dbExecutor.schema,securityContext:R},I=this.queryPlanner.createQueryPlan(E,e,S),t=this.buildUnifiedQuery(I,e,S),s=this.queryBuilder.collectNumericFields(E,e),O=await this.dbExecutor.execute(t,s),N=Array.isArray(O)?O.map(L=>{const n={...L};if(e.timeDimensions){for(const i of e.timeDimensions)if(i.dimension in n){let o=n[i.dimension];if(typeof o=="string"&&o.match(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/)){const u=o.replace(" ","T"),P=!u.endsWith("Z")&&!u.includes("+")?u+"Z":u;o=new Date(P)}o=this.databaseAdapter.convertTimeDimensionResult(o),n[i.dimension]=o}}return n}):[O],C=this.generateAnnotations(I,e);return{data:N,annotation:C}}catch(A){throw new Error(`Query execution failed: ${A instanceof Error?A.message:"Unknown error"}`)}}async executeQuery(E,e,R){const A=new Map;return A.set(E.name,E),this.execute(A,e,R)}buildPreAggregationCTE(E,e,R,A){const S=E.cube,I=S.sql(R),t={};for(const P of E.joinKeys)if(P.targetColumnObj){t[P.targetColumn]=P.targetColumnObj;for(const[l,M]of Object.entries(S.dimensions||{}))M.sql===P.targetColumnObj&&l!==P.targetColumn&&(t[l]=r`${P.targetColumnObj}`.as(l))}const s=S.name,O=new Map([[s,S]]),N=this.queryBuilder.buildResolvedMeasures(E.measures,O,R);for(const P of E.measures){const[,l]=P.split("."),M=N.get(P);if(M){const G=M();t[l]=r`${G}`.as(l)}}if(e.dimensions)for(const P of e.dimensions){const[l,M]=P.split(".");if(l===s&&S.dimensions&&S.dimensions[M]){const G=S.dimensions[M],m=this.queryBuilder.buildMeasureExpression({sql:G.sql,type:"number"},R);t[M]=r`${m}`.as(M)}}if(e.timeDimensions)for(const P of e.timeDimensions){const[l,M]=P.dimension.split(".");if(l===s&&S.dimensions&&S.dimensions[M]){const G=S.dimensions[M],m=this.queryBuilder.buildTimeDimensionExpression(G.sql,P.granularity,R);t[M]=r`${m}`.as(M)}}if(Object.keys(t).length===0)return null;let C=R.db.select(t).from(I.from);const L=A?{...A,preAggregationCTEs:A.preAggregationCTEs?.filter(P=>P.cube.name!==S.name)}:void 0,n=this.queryBuilder.buildWhereConditions(S,e,R,L),i=[];if(e.timeDimensions)for(const P of e.timeDimensions){const[l,M]=P.dimension.split(".");if(l===s&&S.dimensions&&S.dimensions[M]&&P.dateRange){const G=S.dimensions[M],m=this.queryBuilder.buildMeasureExpression({sql:G.sql,type:"number"},R),B=this.queryBuilder.buildDateRangeCondition(m,P.dateRange);B&&i.push(B)}}if(e.filters){for(const P of e.filters)if(!("and"in P)&&!("or"in P)&&"member"in P&&"operator"in P){const l=P,[M,G]=l.member.split(".");if(M===s&&S.dimensions&&S.dimensions[G]){const m=S.dimensions[G];if(l.operator==="inDateRange"){const B=this.queryBuilder.buildMeasureExpression({sql:m.sql,type:"number"},R),b=this.queryBuilder.buildDateRangeCondition(B,l.values);b&&i.push(b)}}}}const o=[];if(I.where&&o.push(I.where),o.push(...n,...i),o.length>0){const P=o.length===1?o[0]:h(...o);C=C.where(P)}const u=[];for(const P of E.joinKeys)P.targetColumnObj&&u.push(P.targetColumnObj);if(e.dimensions)for(const P of e.dimensions){const[l,M]=P.split(".");if(