예제 #1
0
        public virtual bool QueryFilterIsSupported(MappedSearchRequest request)
        {
            if (string.IsNullOrEmpty(request.TextFilter))
            {
                return(true);
            }

            // we can only support the text search if its searching the table we are summarizing by

            var queryColumns = request.TextFilterColumns;

            if ((queryColumns == null || !queryColumns.Any()) && _constants.TextSearchColumnId > 0)
            {
                // set queryColumns to the default column
                var defaultTextSearchColumn = _columnProvider.GetColumnMapping(1, _constants.TextSearchColumnId);
                queryColumns = new List <ReportColumnMapping>()
                {
                    defaultTextSearchColumn
                };
            }

            foreach (var column in queryColumns)
            {
                if (column.KnownTable != request.SummarizeByColumn.KnownTable)
                {
                    return(false);
                }
            }

            return(true);
        }
예제 #2
0
 protected override void BuildGroupBy(
     SelectQuery query,
     ReportColumnMapping groupByColumn,
     MappedSearchRequest request)
 {
     base.BuildGroupBy(query, request.SummarizeByColumn, request);
 }
예제 #3
0
        // Restrict
        protected override List <ReportColumnMapping> RestrictColumns(MappedSearchRequest request)
        {
            var allColumns = request.SelectedAndDependantColumns;

            // only non claculated columns in this table
            var result = allColumns.Where(x =>
                                          x.KnownTable == _fromTableName &&
                                          !QueryHelpers.IsCalculatedColumn(x)
                                          )

                         // remove the _C column used for getting group counts
                         .Where(x => QueryHelpers.GetFieldName(x) != _constants.CountKeyAlias).ToList();

            if (_primaryKeyColumnId > 0 && result.All(x => x.Id != _primaryKeyColumnId))
            {
                result.Add(QueryHelpers.GetColumnMapping(_primaryKeyColumnId));
            }

            // add the currency key column if its in this table
            if (result.All(x => x.Id != _constants.CurrencyColumnId))
            {
                var currencyCol = base.GetCurrencyColumn();
                if (currencyCol != null && currencyCol.KnownTable == _fromTableName)
                {
                    result.Add(currencyCol);
                }
            }


            return(result);
        }
        // Build
        public override Query Build(MappedSearchRequest request)
        {
            var result = new Query();

            using (new DebugTimer("SearchQueryBuilder.Build"))
            {
                Dictionary <string, CommonTableExpression> cteDict;
                AddCommonTableExpressions(request, result, out cteDict);

                var selectQuery = new SelectQuery();
                result.SelectQuery = selectQuery;

                var restrictedColumns = RestrictColumns(request);

                BuildSelect(selectQuery, restrictedColumns, RestrictSort(request), RestrictGroupBy(request), request);
                BuildFrom(selectQuery, restrictedColumns, request.GroupByColumn, request.SortByColumn, request);
                BuildGroupBy(selectQuery, RestrictGroupBy(request), request);
                BuildWhere(selectQuery, request.TextFilter, RestrictFilters(request, isWhere: true), request);
                BuildHaving(selectQuery, RestrictFilters(request, isWhere: false), request.GroupByColumn, request);
                BuildOrderBy(selectQuery, RestrictSort(request, forOrderBy: true), request);
                BuildPaging(selectQuery, request);

                RemoveUnusedCommonTableExpressions(result, cteDict);

                AddParameters(result);
            }

            return(result);
        }
        // Restrict
        protected override List <ReportColumnMapping> RestrictColumns(MappedSearchRequest request)
        {
            var result = base.RestrictColumns(request);

            result = RemoveDateColumnsIfNonDateQuery(request, result);
            return(result);
        }
예제 #6
0
        public override void SelectGroupKey(SelectQuery query, MappedSearchRequest request)
        {
            if (QueryHelpers.IsStatsColumn(request.GroupByColumn))
            {
                // we cannot group by a stats column, so we need to group by the column stats join onto

                // get the stats relationship to the data join table
                var statsRelationship =
                    _tableMappings.GetAllTableRelationships()
                    .FirstOrDefault(x => x.Table1 is StatsTableMapping || x.Table2 is StatsTableMapping);

                if (statsRelationship != null)
                {
                    var dataTable = statsRelationship.Table1.TableType == TableType.Data
                        ? statsRelationship.Table1
                        : statsRelationship.Table2;

                    var primaryKeyColumn = _columnProvider.Find(_constants.DataSourceId, dataTable.KnownTableName,
                                                                dataTable.PrimaryKey, null);
                    if (primaryKeyColumn != null && primaryKeyColumn.Count == 1)
                    {
                        var groupCol = primaryKeyColumn.First();
                        query.Select(dataTable.Alias, groupCol.FieldName, _constants.GroupKeyAlias, Aggregate.Min);
                    }
                }
            }
            else
            {
                base.SelectGroupKey(query, request);
            }
        }
        // Restrict
        protected override List <ReportColumnMapping> RestrictColumns(MappedSearchRequest request)
        {
            using (new DebugTimer("DateStatsCteQueryBuilder.Build"))
            {
                var selectedColumnsPlusFilters = request.SelectedAndDependantColumns.ToList();

                // remove NON stats columns, action stats columns & calculated stats columns
                var result = selectedColumnsPlusFilters.Where(IsRawStatColumn).ToList();

                foreach (var col in _foreignKeyColumnIds)
                {
                    if (result.All(x => x.Id != col))
                    {
                        result.Add(QueryHelpers.GetColumnMapping(col));
                    }
                }

                AddColumnsForGroupBy(request, result);

                if (result.All(x => x.Id != _constants.DateStatColumnId))
                {
                    result.Add(QueryHelpers.GetColumnMapping(_constants.DateStatColumnId));
                }

                var currency = GetCurrencyColumn();
                if (currency != null)
                {
                    result.Add(currency);
                }

                return(result);
            }
        }
예제 #8
0
        public MappedSearchRequest Map(SearchRequest request)
        {
            var result = new MappedSearchRequest()
            {
                DateEnd                   = request.DateEnd,
                DateStart                 = request.DateStart,
                DateRangeType             = request.DateRangeType,
                DebugMode                 = request.DebugMode,
                GetCount                  = request.GetCount,
                PageIndex                 = request.PageIndex,
                PageSize                  = request.PageSize,
                TextFilter                = request.TextFilter ?? request.Query, // TODO: Remove Query.
                TemporalAggregation       = request.TemporalAggregation,
                ExcludeRecordsWithNoStats = request.ExcludeRecordsWithNoStats,
                SortDescending            = request.SortDescending,
            };

            result.GroupByColumn     = GetColumnMapping(request.GroupByColumn);
            result.SummarizeByColumn = GetColumnMapping(request.SummarizeByColumn);
            result.SortByColumn      = GetColumnMapping(request.SortByColumn);
            result.SelectedColumns   = GetColumnMappings(request.SelectedColumns);
            result.TextFilterColumns = GetColumnMappings(request.TextFilterColumns);

            result.Filters = GetMappedFilters(request.Filters);

            result.DependantColumns = GetDependantColumnMappings(result);

            return(result);
        }
예제 #9
0
 protected virtual List <ReportColumnMapping> RemoveDateColumnsIfNonDateQuery(MappedSearchRequest request, List <ReportColumnMapping> result)
 {
     if (!IsDateQuery(request))
     {
         result = result.Where(x => !IsDateColumn(x)).ToList();
     }
     return(result);
 }
예제 #10
0
        public List <ReportColumnMapping> GetAllTransposeStatsColumns(MappedSearchRequest request)
        {
            var allTransposeStatsColumns = request.SelectedAndDependantColumns
                                           .Where(x => QueryHelpers.IsTransposeStatColumn(x))
                                           .ToList();

            return(allTransposeStatsColumns);
        }
예제 #11
0
 protected override ReportColumnMapping RestrictSort(MappedSearchRequest request, bool forOrderBy = false)
 {
     if (request.SortByColumn != null)
     {
         // remove stats columns
         return(QueryHelpers.IsStatsColumn(request.SortByColumn) ? null : request.SortByColumn);
     }
     return(null);
 }
        protected virtual void AddColumnsForGroupBy(MappedSearchRequest request, List <ReportColumnMapping> result)
        {
            var column = RestrictGroupBy(request);

            if (result.All(x => x.Id != column.Id))
            {
                result.Add(column);
            }
        }
 protected override ReportColumnMapping RestrictSort(MappedSearchRequest request, bool forOrderBy = false)
 {
     if (request.SortByColumn != null)
     {
         return(request.SortByColumn.Id > 0 &&
                IsRawStatColumn(request.SortByColumn)
                 ? request.SortByColumn : null);
     }
     return(null);
 }
예제 #14
0
        // Restrict
        protected override List <ReportColumnMapping> RestrictColumns(MappedSearchRequest request)
        {
            var result = request.SelectedColumns.ToList();

            result.AddRange(request.DependantColumns);

            // remove stats columns
            result = result.Where(x => !QueryHelpers.IsStatsColumn(x)).ToList();
            return(result);
        }
        public override Column GetColumnSelector(ReportColumnMapping col, MappedSearchRequest request, bool dontAggregate = false, bool useFieldAlias = false)
        {
            var result = _dataSourceComponents.QueryBuilderBase.GetColumnSelector(col, request, dontAggregate: dontAggregate, useFieldAlias: useFieldAlias);

            if (result.Field.Name.StartsWith("_C_"))
            {
                result.Field.Name = _constants.CountKeyAlias;
            }

            return(result);
        }
예제 #16
0
        private void BuildTextSearchWhereFIlters(
            SelectQuery query,
            string queryText,
            MappedSearchRequest request)
        {
            if (!string.IsNullOrEmpty(queryText) && CanFilterOnText())
            {
                var canUseFullText = false;

                var queryColumns = request.TextFilterColumns;
                if ((queryColumns == null || !queryColumns.Any()) && _constants.TextSearchColumnId > 0)
                {
                    // set queryColumns to the default column
                    var defaultTextSearchColumn = _columnProvider.GetColumnMapping(_constants.DataSourceId, _constants.TextSearchColumnId);
                    queryColumns = new List <ReportColumnMapping>()
                    {
                        defaultTextSearchColumn
                    };
                    canUseFullText = _constants.FullTextSearchEnabled;
                }

                if (!queryColumns.Any())
                {
                    // do nothing
                    return;
                }

                // Add Text Search
                if (queryText.StartsWith("*"))
                {
                    queryText      = queryText.Substring(1); // remove the *
                    canUseFullText = false;
                }

                if (canUseFullText)
                {
                    // we are using the default column (and there's only 1)
                    var tableMapping = _tableMappings.GetTableMapping(queryColumns.First().KnownTable);
                    query.WhereColumnContains(tableMapping.Alias, queryColumns.First().FieldName, queryText, ContainsMode.FreeText);
                }
                else
                {
                    var filters = new WhereFilterCollection();

                    foreach (var column in queryColumns)
                    {
                        var tableMapping = _tableMappings.GetTableMapping(column.KnownTable);
                        filters.WhereColumnLike(tableMapping.Alias, column.FieldName, queryText, LikeMode.FreeText);
                    }

                    query.WhereCollection(Combine.Or, filters);
                }
            }
        }
        protected override string GetFieldAlias(ReportColumnMapping column, MappedSearchRequest request)
        {
            var result = QueryHelpers.GetFieldName(column);

            // to allow selecting both min and max together (not working with custom columns - its complicated)
            // depends on DefaultStatsQueryBuilder.GetColumnSelector()
//            if (RestrictGroupBy(request).Id != column.Id && result != _constants.CountKeyAlias)
//            {
//                result += "_" + column.FieldAggregationMethod;
//            }
            return(result);
        }
예제 #18
0
        public override void BuildFrom(
            SelectQuery query,
            List <ReportColumnMapping> selectedColumns,
            ReportColumnMapping groupByColumn,
            ReportColumnMapping sortByColumn,
            MappedSearchRequest request)
        {
            var fromTableName = request.SummarizeByColumn.KnownTable;
            var fromTable     = _tableMappings.GetTableMapping(fromTableName);

            query.From(fromTable.DbTableName, fromTable.Alias);
        }
예제 #19
0
        public override void BuildFrom(
            SelectQuery query,
            List <ReportColumnMapping> selectedColumns,
            ReportColumnMapping groupByColumn,
            ReportColumnMapping sortByColumn,
            MappedSearchRequest request)
        {
            // idea here is to be able to get a key which can be joined on, so select from the table we're building the CTE from
            // then join on the tables required to get to the join key (which can be used as the group key)

            _rootTableName = request.GroupByColumn.KnownTable;
            var fromTable = _tableMappings.GetTableMapping(_fromTableName);

            var addedTables = new List <string>();

            if (CanJoinTables(_fromTableName, _rootTableName))
            {
                query.From(fromTable.DbTableName, fromTable.Alias);
            }
            else
            {
                var graphBuilder      = new TableRelationshipGraphBuilder();
                var relationshipGraph = graphBuilder.Build(_tableMappings.GetAllTableRelationships(), _rootTableName);

                // todo : use path
                //var path = graphBuilder.GetPathFromTableToRoot(relationshipGraph, _fromTableName);

                var distance = graphBuilder.GetDistance(relationshipGraph, _fromTableName);

                query.From(fromTable.DbTableName, fromTable.Alias);

                string currentTableName = fromTable.KnownTableName;
                while (distance > 1)
                {
                    var potentialNodes = graphBuilder.GetByDistance(relationshipGraph, distance - 1);
                    var parentNode     = potentialNodes.SingleOrDefault(x => x.Relations.Any(y => y.TableName == currentTableName));
                    if (parentNode == null)
                    {
                        throw new Exception(string.Format("Could not find a relationship between {0} and {1}", currentTableName, relationshipGraph.TableName));
                    }
                    JoinTables(query, parentNode.TableName, currentTableName);
                    currentTableName = parentNode.TableName;
                    distance--;
                    addedTables.Add(parentNode.TableName);
                    if (CanJoinTables(_fromTableName, currentTableName) && CanJoinTables(currentTableName, _rootTableName))
                    {
                        break;
                    }
                }
            }
        }
예제 #20
0
        protected override ReportColumnMapping RestrictSort(MappedSearchRequest request, bool forOrderBy = false)
        {
            if (forOrderBy)
            {
                return(request.SortByColumn);
            }

            if (request.SortByColumn != null)
            {
                // remove data columns
                return(request.SortByColumn.Id > 0 && QueryHelpers.IsStatsColumn(request.SortByColumn) ? request.SortByColumn : null);
            }
            return(null);
        }
예제 #21
0
        /// <summary>
        /// Gets the Column with alias for non calculated columns
        /// Gets the Column without alias for calculated columns and handles the conversion of calculated columns to sql
        /// For calculated colums, the column will be expanded to a full formula
        /// Sets the result on the column mapping so that it doesnt need to be re-calculated - this works with the cache
        /// </summary>
        public virtual Column GetColumnSelector(ReportColumnMapping col, MappedSearchRequest request, bool dontAggregate = false, bool useFieldAlias = false)
        {
            var cached = col.CalculatedValues.GetColumnTableAndField(dontAggregate, useFieldAlias);

            if (cached != null)
            {
                return(new Column(cached[0], cached[1]));
            }

            var result = GetColumSelectorInternal(col, dontAggregate, useFieldAlias);

            col.CalculatedValues.SetColumnTableAndField(dontAggregate, useFieldAlias, result.TableAlias, result.Field.Name);

            return(result);
        }
예제 #22
0
        protected override List <MappedSearchRequestFilter> RestrictFilters(MappedSearchRequest request, bool isWhere)
        {
            if (request.Filters == null || !request.Filters.Any())
            {
                return(request.Filters);
            }

            // remove stats columns
            var result = request.Filters.Where(x => !QueryHelpers.IsStatsColumn(x.Column));

            // remove aggregated columns for where filters and non aggregated columns for having filters
            result = result.Where(x => x.ProcessBeforeAggregation == isWhere);

            return(result.ToList());
        }
예제 #23
0
        public virtual bool FiltersAreSupported(MappedSearchRequest request)
        {
            if (request.Filters != null)
            {
                foreach (var filter in request.Filters)
                {
                    if (filter.Column.KnownTable != request.SummarizeByColumn.KnownTable)
                    {
                        return(false);
                    }
                }
            }

            return(true);
        }
예제 #24
0
        protected override List <MappedSearchRequestFilter> RestrictFilters(MappedSearchRequest request, bool isWhere)
        {
            if (request.Filters == null || !request.Filters.Any())
            {
                return(request.Filters);
            }

            // remove aggregated columns for where filters and non aggregated columns for having filters
            var result = request.Filters.Where(x => x.ProcessBeforeAggregation == isWhere);

            if (!isWhere)
            {
                result = result.Where(x => !x.Column.IsCalculated);
            }

            return(result.ToList());
        }
예제 #25
0
        public virtual void BuildFrom(
            SelectQuery query,
            List <ReportColumnMapping> selectedColumns,
            ReportColumnMapping groupByColumn,
            ReportColumnMapping sortByColumn,
            MappedSearchRequest request)
        {
            var tables = request.SelectedAndDependantColumns.Select(x => x.KnownTable).ToList();

            tables.Add(groupByColumn.KnownTable);
            tables = tables.Distinct().ToList();

            var currencyColumn = GetCurrencyColumn();

            if (currencyColumn != null && !tables.Contains(currencyColumn.KnownTable))
            {
                tables.Add(currencyColumn.KnownTable);
            }

            var rootTableMapping = _tableMappings.GetTableMapping(_constants.RootTableName);

            query.From(rootTableMapping.DbTableName, rootTableMapping.Alias);

            var graphBuilder = new TableRelationshipGraphBuilder();
            // bulild a graph of the table relationships to calculate the distance from the root table
            // include missing tables needed for joins
            // order the tables by distance
            var relationshipGraph = graphBuilder.Build(_tableMappings.GetAllTableRelationships(), _constants.RootTableName);

            graphBuilder.TrimToTables(relationshipGraph, tables);
            tables = graphBuilder.GetAllTables(relationshipGraph).Union(tables).Distinct().ToList();

            tables = tables.OrderBy(x => graphBuilder.GetDistance(relationshipGraph, x)).ToList();

            // dictionary of TableName, IsAggregated for tables which have been added to the query
            var addedTables = new Dictionary <string, bool> {
                { _constants.RootTableName, false }
            };

            foreach (var table in tables.Distinct())
            {
                AddFromTableJoin(query, groupByColumn, table, ref addedTables, graphBuilder, relationshipGraph);
            }
        }
        // Build
        public override void BuildFrom(
            SelectQuery query,
            List <ReportColumnMapping> selectedColumns,
            ReportColumnMapping groupByColumn,
            ReportColumnMapping sortByColumn,
            MappedSearchRequest request)
        {
            var statsRelationships = _tableMappings.GetAllTableRelationships()
                                     .Where(x => x.Table1 is StatsTableMapping || x.Table2 is StatsTableMapping)
                                     .ToList();


            // get the data table which joins onto the stats table
            var graphBuilder  = new TableRelationshipGraphBuilder();
            var dataJoinTable = _dataSourceComponents.StatsQueryBuilder.GetDataJoinTable(request.GroupByColumn, statsRelationships, graphBuilder);

            //-- Find out which stats table or view we need to query to satisfy the requested temporal
            // aggregation and type of date range.
            var statsTableName = GetStatsTableName(
                _statsTableName,
                dataJoinTable,
                request.TemporalAggregation,
                request.DateRangeType,
                request.DateStart,
                request.DateEnd);

            query.From(statsTableName, _statsTableAlias);
            JoinTables(query, dataJoinTable, _statsTableName);

            // join up to the root table
            var addedTables = new Dictionary <string, bool> {
                { dataJoinTable, false }
            };

            _dataSourceComponents.StatsQueryBuilder.AddDataTableJoinsUpToRoot(query, dataJoinTable, graphBuilder, addedTables);

            var currencyColumn = GetCurrencyColumn();

            if (currencyColumn != null && !addedTables.ContainsKey(currencyColumn.KnownTable))
            {
                var relationshipGraph = graphBuilder.Build(_tableMappings.GetAllTableRelationships(), _constants.RootTableName);
                AddFromTableJoin(query, groupByColumn, currencyColumn.KnownTable, ref addedTables, graphBuilder, relationshipGraph);
            }
        }
예제 #27
0
        public virtual string GetStatsTableName(string groupTable, MappedSearchRequest request)
        {
            // Do we need to query the daily or hourly tables?
            if (IsDateQuery(request))
            {
                // This request requires us to query the daily or hourly tables. The DateStatsCteQueryBuilder
                // will take care of building a CTE that does that and will call it "dateStats". It's the view
                // that will contain the stats.
                return("dateStats");
            }

            // We don't need to query the daily or hourly stats tables. I.e. this is a
            // straighforward request to query lifetime stats from the lifetime stats tables.

            // Get the name of the Lifetime stats table we need to query. If we've been asked to return stats data
            // grouped by AdGroup, we'll have to query the AdGroupLifetime table. But for all other groupings,
            // we can get the data we need from the CampaignLifetime table.
            return(GetStatsTableName(_statsTableName, groupTable, request.TemporalAggregation, request.DateRangeType, request.DateStart, request.DateStart));
        }
        // Restrict
        protected override List <ReportColumnMapping> RestrictColumns(MappedSearchRequest request)
        {
            var allTransposeStatColumns = _dataSourceComponents.StatsQueryBuilder.GetAllTransposeStatsColumns(request)
                                          // calculations are not performed in the transpose stats query
                                          .Where(x => !x.IsCalculated);

            var result = new List <ReportColumnMapping>();

            // add any columns needed by calculations
            foreach (var found in allTransposeStatColumns)
            {
                if (result.All(x => x.FieldName != found.FieldName))
                {
                    result.Add(found);
                }
            }

            return(result);
        }
예제 #29
0
        protected override List <CommonTableExpression> BuildCommonTableExpressions(MappedSearchRequest request)
        {
            var result = new List <CommonTableExpression>();

            // build the date stats CTE
            if (IsDateQuery(request))
            {
                using (new DebugTimer("StatsQueryBuilder.BuildCommonTableExpressions - date"))
                {
                    var dateStatsQuery = _dataSourceComponents.DateStatsQueryBuilder.Build(request);

                    var cte = new CommonTableExpression
                    {
                        Alias = _dateStatsTableAlias,
                        Query = dateStatsQuery.SelectQuery
                    };
                    result.Add(cte);
                }
            }


            // bulid the transpose stats CTE
            var allTransposeStatsColumns = GetAllTransposeStatsColumns(request);

            if (allTransposeStatsColumns != null && allTransposeStatsColumns.Any())
            {
                using (new DebugTimer("StatsQueryBuilder.BuildCommonTableExpressions - transpose"))
                {
                    var transposeCteQuery = _dataSourceComponents.TransposeStatsQueryBuilder.Build(request);

                    var transposeStatsCte = new CommonTableExpression
                    {
                        Alias = _transposeStatsTableAlias,
                        Query = transposeCteQuery.SelectQuery
                    };

                    result.Add(transposeStatsCte);
                }
            }

            return(result);
        }
예제 #30
0
        protected virtual void HandleSelectCountColumn(MappedSearchRequest request, Column field)
        {
            var columnTable = _tableMappings.GetAllTables().FirstOrDefault(x => x.Alias == field.TableAlias);

            if (columnTable == null ||
                columnTable.KnownTableName == request.GroupByColumn.KnownTable ||
                !GroupByIsChildTable(field.TableAlias, request.GroupByColumn) ||
                columnTable.TableType == TableType.Stats)
            {
                field.TableAlias = null;
                field.Field.Name = "1";

                // when there are multiple stats in a date range, inherit the count from the date stats table
                if (columnTable != null && columnTable.TableType == TableType.Stats && IsDateQuery(request))
                {
                    field.TableAlias = "Stats";
                    field.Field.Name = "_C";
                }
            }
        }