/// <summary> /// Gets or executes teh result context /// </summary> public BisResultContext GetOrExecuteQuery(string name) { BisResultContext retVal = null; if (!this.m_dataSources.TryGetValue(name, out retVal)) { var viewDef = this.m_report.DataSource.FirstOrDefault(o => o.Name == name); if (viewDef == null) { throw new KeyNotFoundException($"Datasource {name} not found"); } viewDef = BiUtils.ResolveRefs(viewDef); // Get the datasource for the execution engine var dsource = (viewDef as BiViewDefinition)?.Query?.DataSources.FirstOrDefault(o => o.Name == "main") ?? (viewDef as BiViewDefinition)?.Query?.DataSources.FirstOrDefault() ?? (viewDef as BiQueryDefinition)?.DataSources.FirstOrDefault(o => o.Name == "main") ?? (viewDef as BiQueryDefinition)?.DataSources.FirstOrDefault(); IBiDataSource providerImplementation = null; if (dsource.ProviderType != null) { providerImplementation = ApplicationServiceContext.Current.GetService <IServiceManager>().CreateInjected(dsource.ProviderType) as IBiDataSource; } else { providerImplementation = ApplicationServiceContext.Current.GetService <IBiDataSource>(); // Global default } // Load from cache instead of DB? var cacheService = ApplicationServiceContext.Current.GetService <IAdhocCacheService>(); var key = $"{name}?{String.Join("&", this.Parameters.Select(o => $"{o.Key}={o.Value}"))}"; var cacheResult = cacheService?.Get <IEnumerable <dynamic> >(key); int count = 10000; if (this.m_maxResultSetSize.HasValue) { count = this.m_maxResultSetSize.Value; } else if (this.Parameters.TryGetValue("_count", out var parameterCount) && Int32.TryParse(parameterCount.ToString(), out var tCount)) { count = tCount; } if (cacheResult != null) { return(new BisResultContext(null, this.Parameters, providerImplementation, cacheResult, DateTime.Now)); } else if (viewDef is BiViewDefinition) { retVal = providerImplementation.ExecuteView(viewDef as BiViewDefinition, this.Parameters, 0, count); } else if (viewDef is BiQueryDefinition) { retVal = providerImplementation.ExecuteQuery(viewDef as BiQueryDefinition, this.Parameters, null, 0, count); } else { throw new InvalidOperationException($"Cannot determine data source type of {name}"); } cacheService?.Add(key, retVal.Dataset, new TimeSpan(0, 1, 0)); this.m_dataSources.Add(name, retVal); } return(retVal); }
/// <summary> /// Pivot provider /// </summary> public BisResultContext Pivot(BisResultContext context, BiViewPivotDefinition pivot) { var buckets = new List <ExpandoObject>(); // First we must order by the pivot context.Dataset.OrderBy(o => (o as IDictionary <String, Object>)[pivot.Key]); // Algorithm for pivoting : IDictionary <String, Object> cobject = null; foreach (IDictionary <String, Object> itm in context.Dataset) { var key = itm[pivot.Key]; if (cobject == null || !key.Equals(cobject[pivot.Key]) && cobject.Count > 0) { cobject = new ExpandoObject(); cobject.Add(pivot.Key, key); buckets.Add(cobject as ExpandoObject); } // Same key, so lets create or accumulate var column = itm[pivot.Columns]; if (!cobject.ContainsKey(column.ToString())) { cobject.Add(column.ToString(), new List <Object>() { itm[pivot.Value] }); } else { var cvalue = cobject[column.ToString()] as List <Object>; var avalue = itm[pivot.Value]; cvalue.Add(avalue); } } // Now we have our buckets, we want to apply our aggregation function var colNames = new List <String>(); var aggBuckets = new List <ExpandoObject>(); foreach (IDictionary <String, Object> itm in buckets.ToArray()) { var newItm = new ExpandoObject() as IDictionary <String, Object>; foreach (var value in itm) { if (value.Key == pivot.Key) { newItm[pivot.Key] = value.Value; continue; // Don't de-bucket the object } var bucket = (value.Value as IEnumerable <Object>); newItm[value.Key] = this.Aggregate((value.Value as List <Object>), pivot.AggregateFunction); if (!colNames.Contains(value.Key)) { colNames.Add(value.Key); } } aggBuckets.Add(newItm as ExpandoObject); } // Add where necessary var output = new List <ExpandoObject>(); foreach (IDictionary <String, Object> itm in aggBuckets) { var tuple = (new ExpandoObject() as IDictionary <String, Object>); tuple[pivot.Key] = itm[pivot.Key]; foreach (var col in colNames) { if (itm.ContainsKey(col)) { tuple[col] = itm[col]; } else { tuple[col] = null; } } output.Add(tuple as ExpandoObject); } return(new BisResultContext(context.QueryDefinition, context.Arguments, context.DataSource, output, context.StartTime.DateTime)); }