collectKnownIdentifiers(resolveSymbol, path) { const identifiers = []; const self = this; if (path.node.type === 'Identifier') { this.matchAndPushIdentifier(path, resolveSymbol, identifiers); } path.traverse({ Identifier(p) { self.matchAndPushIdentifier(p, resolveSymbol, identifiers); } }); return R.uniq(identifiers); }
collectCubeNamesFor(fn) { const context = { cubeNames: [] }; this.evaluateSymbolSqlWithContext( fn, context ); return R.uniq(context.cubeNames); }
get dataSource() { const dataSources = R.uniq(this.allCubeNames.map(c => this.cubeDataSource(c))); if (dataSources.length > 1) { throw new UserError(`Joins across data sources aren't supported in community edition. Found data sources: ${dataSources.join(', ')}`); } return dataSources[0]; }
static hasCumulativeMeasures(query) { const measures = (query.measures.concat(query.measureFilters)); const collectLeafMeasures = query.collectLeafMeasures.bind(query); return R.pipe( R.map(m => query.collectFrom([m], collectLeafMeasures, 'collectLeafMeasures')), R.unnest, R.uniq, R.map(p => query.newMeasure(p)), R.any(m => m.isCumulative()) )(measures); }
static squashDimensions(query) { return R.pipe(R.uniq, R.sortBy(R.identity))( query.dimensions.concat(query.filters).map(d => d.dimension).concat(query.segments.map(s => s.segment)) ); }
const getQueryGranularity = (queries) => R.pipe( R.map(({ timeDimensions }) => timeDimensions[0] && timeDimensions[0].granularity || null), R.filter(Boolean), R.uniq )(queries)
const getPivotQuery = (queryType, queries) => { let [pivotQuery] = queries; if (queryType === QUERY_TYPE.BLENDING_QUERY) { pivotQuery = R.fromPairs( ['measures', 'dimensions'].map( (key) => [key, R.uniq(queries.reduce((memo, q) => memo.concat(q[key]), []))] ) ); const [granularity] = getQueryGranularity(queries); pivotQuery.timeDimensions = [{ dimension: 'time', granularity }]; } else if (queryType === QUERY_TYPE.COMPARE_DATE_RANGE_QUERY) { pivotQuery.dimensions = ['compareDateRange'].concat(pivotQuery.dimensions || []); } pivotQuery.queryType = queryType; return pivotQuery; }
fullKeyQueryAggregateMeasures() { const measureToHierarchy = this.collectRootMeasureToHieararchy(); const measuresToRender = (multiplied, cumulative) => R.pipe( R.values, R.flatten, R.filter( m => m.multiplied === multiplied && this.newMeasure(m.measure).isCumulative() === cumulative ), R.map(m => m.measure), R.uniq, R.map(m => this.newMeasure(m)) ); const multipliedMeasures = measuresToRender(true, false)(measureToHierarchy); const regularMeasures = measuresToRender(false, false)(measureToHierarchy); const cumulativeMeasures = R.pipe( R.map(multiplied => R.xprod([multiplied], measuresToRender(multiplied, true)(measureToHierarchy))), R.unnest )([false, true]); return { multipliedMeasures, regularMeasures, cumulativeMeasures }; }
initUngrouped() { this.ungrouped = this.options.ungrouped; if (this.ungrouped) { if (!this.options.allowUngroupedWithoutPrimaryKey) { const cubes = R.uniq([this.join.root].concat(this.join.joins.map(j => j.originalTo))); const primaryKeyNames = cubes.map(c => this.primaryKeyName(c)); const missingPrimaryKeys = primaryKeyNames.filter(key => !this.dimensions.find(d => d.dimension === key)); if (missingPrimaryKeys.length) { throw new UserError(`Ungrouped query requires primary keys to be present in dimensions: ${missingPrimaryKeys.map(k => `'${k}'`).join(', ')}. Pass allowUngroupedWithoutPrimaryKey option to disable this check.`); } } if (this.measures.length) { throw new UserError('Measures aren\'t allowed in ungrouped query'); } if (this.measureFilters.length) { throw new UserError('Measure filters aren\'t allowed in ungrouped query'); } } }
collectFrom(membersToCollectFrom, fn, methodName, cache) { return R.pipe( R.map(f => f.getMembers()), R.flatten, R.map(s => ( (cache || this.compilerCache).cache( ['collectFrom', methodName].concat( s.path() ? [s.path().join('.')] : [s.cube().name, s.expressionName || s.definition().sql] ), () => fn(() => this.traverseSymbol(s)) ) )), R.unnest, R.uniq, R.filter(R.identity) )( membersToCollectFrom ); }
collectMultipliedMeasures(fn) { const foundCompositeCubeMeasures = {}; this.evaluateSymbolSqlWithContext( fn, { compositeCubeMeasures: foundCompositeCubeMeasures } ); const renderContext = { measuresToRender: [], foundCompositeCubeMeasures, compositeCubeMeasures: {}, rootMeasure: {} }; this.evaluateSymbolSqlWithContext( fn, renderContext ); return renderContext.measuresToRender.length ? R.uniq(renderContext.measuresToRender) : [renderContext.rootMeasure.value]; }
prepareTableNamesToTables(tableNames) { this.tableNamesToTables = R.pipe( R.unnest, R.groupBy(n => n[0]), R.map(groupedNameToDef => groupedNameToDef.map(nameToDef => nameToDef[1])) )( tableNames.map(tableName => { const [schema, table] = this.parseTableName(tableName); const tableDefinition = this.resolveTableDefinition(tableName); const definition = { schema, table, tableDefinition, tableName }; const tableizeName = inflection.tableize(table); const parts = tableizeName.split('_'); const tableNamesFromParts = R.range(0, parts.length - 1).map(toDrop => inflection.tableize(R.drop(toDrop, parts).join('_'))); const names = R.uniq([table, tableizeName].concat(tableNamesFromParts)); return names.map(n => [n, definition]); }) ); }
static transformQueryToCanUseForm(query) { const sortedDimensions = this.squashDimensions(query); const measures = (query.measures.concat(query.measureFilters)); const measurePaths = R.uniq(measures.map(m => m.measure)); const collectLeafMeasures = query.collectLeafMeasures.bind(query); const leafMeasurePaths = R.map(m => query.collectFrom([m], collectLeafMeasures, 'collectLeafMeasures')), R.unnest, R.uniq )(measures);
R.compose(R.uniq, R.map(indexToJoin => indexToJoin[1]), R.sortBy(indexToJoin => indexToJoin[0])); return { joins: pairsSortedByIndex(result.joins),
collectSubQueryDimensionsFor(fn) { const context = { subQueryDimensions: [] }; this.evaluateSymbolSqlWithContext( fn, context ); return R.uniq(context.subQueryDimensions); }