/// <summary> /// Creates a new result context /// </summary> public BisResultContext(BiQueryDefinition definition, IDictionary <String, Object> arguments, IBiDataSource source, IEnumerable <dynamic> results, DateTime startTime ) { this.Arguments = arguments; this.Dataset = results; this.DataSource = source; this.QueryDefinition = definition; this.StartTime = startTime; this.StopTime = DateTime.Now; }
/// <summary> /// DI constructor /// </summary> public LocalBiRenderService(IServiceManager serviceManager, IJobManagerService jobManager, IBiMetadataRepository metadataRepository, IBiDataSource defaultDataSource = null) { this.m_serviceManager = serviceManager; var job = serviceManager.CreateInjected <BiMaterializeJob>(); jobManager.AddJob(job, JobStartType.TimerOnly); // Set default job if (jobManager.GetJobSchedules(job)?.Any() != true) { jobManager.SetJobSchedule(job, new DayOfWeek[] { DayOfWeek.Monday, DayOfWeek.Tuesday, DayOfWeek.Wednesday, DayOfWeek.Thursday, DayOfWeek.Friday, DayOfWeek.Saturday, DayOfWeek.Sunday }, new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, 0, 0, 0)); // First run for tomorrow } // Scan and initialize all BI materialized views ApplicationServiceContext.Current.Started += (o, e) => { foreach (var itm in metadataRepository.Query <BiQueryDefinition>(x => x.MetaData.Status == BiDefinitionStatus.Active, 0, 100)) { try { IBiDataSource dataSource = null; var queryDefinition = BiUtils.ResolveRefs(itm) as BiQueryDefinition; var providerType = queryDefinition.DataSources.FirstOrDefault()?.ProviderType; if (providerType != null) { dataSource = this.m_serviceManager.CreateInjected(providerType) as IBiDataSource; } else { dataSource = defaultDataSource; } this.m_tracer.TraceInfo("Materializing views for {0}", queryDefinition.Id); dataSource.CreateMaterializedView(queryDefinition); } catch (Exception ex) { this.m_tracer.TraceWarning("Could not initialize materialized views for {0} - {1}", itm.Id, ex.Message); } } }; }
/// <summary> /// DI applet BI repository /// </summary> public AppletBiRepository(IAppletManagerService appletManager, IServiceManager serviceManager, IPolicyEnforcementService policyEnforcementService, IAppletSolutionManagerService solutionManagerService = null, IBiDataSource defaultDataSource = null) { this.m_appletManager = appletManager; this.m_policyEnforcementService = policyEnforcementService; this.m_solutionManagerService = solutionManagerService; this.m_serviceManager = serviceManager; this.m_defaultDataSource = defaultDataSource; // Re-scans the loaded applets for definitions when the collection has changed this.m_appletManager.Applets.CollectionChanged += (oa, ea) => { this.LoadAllDefinitions(); }; if (this.m_solutionManagerService.Solutions is INotifyCollectionChanged notify) { notify.CollectionChanged += (oa, eo) => { this.LoadAllDefinitions(); }; } //this.LoadAllDefinitions(); }
/// <summary> /// Hydrate the query /// </summary> /// <param name="queryId"></param> /// <returns></returns> private BisResultContext HydrateQuery(String queryId) { AuditData audit = new AuditData(DateTimeOffset.Now, ActionType.Execute, OutcomeIndicator.Success, EventIdentifierType.Query, AuditUtil.CreateAuditActionCode(EventTypeCodes.SecondaryUseQuery)); try { // First we want to grab the appropriate source for this ID var viewDef = this.m_metadataRepository.Get <BiViewDefinition>(queryId); if (viewDef == null) { var queryDef = this.m_metadataRepository.Get <BiQueryDefinition>(queryId); if (queryDef == null) // Parameter value { var parmDef = this.m_metadataRepository.Get <BiParameterDefinition>(queryId); if (parmDef == null) { throw new KeyNotFoundException($"Could not find a Parameter, Query or View to hydrate named {queryId}"); } queryDef = parmDef?.Values as BiQueryDefinition; queryDef.Id = queryDef.Id ?? queryId; } viewDef = new BiViewDefinition() { Id = queryDef.Id, Query = queryDef }; } viewDef = SanteDB.BI.Util.BiUtils.ResolveRefs(viewDef) as BiViewDefinition; var dsource = viewDef.Query?.DataSources.FirstOrDefault(o => o.Name == "main") ?? viewDef.Query?.DataSources.FirstOrDefault(); if (dsource == null) { throw new KeyNotFoundException("Query does not contain a data source"); } IBiDataSource providerImplementation = null; if (dsource.ProviderType != null && this.m_metadataRepository.IsLocal) { providerImplementation = this.m_serviceManager.CreateInjected(dsource.ProviderType) as IBiDataSource; } else { providerImplementation = ApplicationServiceContext.Current.GetService <IBiDataSource>(); // Global default } // Populate data about the query audit.AuditableObjects.Add(new AuditableObject() { IDTypeCode = AuditableObjectIdType.ReportNumber, LifecycleType = AuditableObjectLifecycle.Report, ObjectId = queryId, QueryData = RestOperationContext.Current.IncomingRequest.Url.Query, Role = AuditableObjectRole.Query, Type = AuditableObjectType.SystemObject }); var parameters = this.CreateParameterDictionary(); // Aggregations and groups? if (RestOperationContext.Current.IncomingRequest.QueryString["_groupBy"] != null) { var aggRx = new Regex(@"(\w*)\((.*?)\)"); viewDef.AggregationDefinitions = new List <BiAggregationDefinition>() { new BiAggregationDefinition() { Groupings = RestOperationContext.Current.IncomingRequest.QueryString.GetValues("_groupBy").Select(o => new BiSqlColumnReference() { ColumnSelector = o.Contains("::") ? $"CAST({o.Substring(0, o.IndexOf(":"))} AS {o.Substring(o.IndexOf(":") + 2)})" : o, Name = o.Contains("::") ? o.Substring(0, o.IndexOf(":")) : o }).ToList(), Columns = RestOperationContext.Current.IncomingRequest.QueryString.GetValues("_select").Select(o => { var match = aggRx.Match(o); if (!match.Success) { throw new InvalidOperationException("Aggregation function must be in format AGGREGATOR(COLUMN)"); } return(new BiAggregateSqlColumnReference() { Aggregation = (BiAggregateFunction)Enum.Parse(typeof(BiAggregateFunction), match.Groups[1].Value, true), ColumnSelector = match.Groups[2].Value, Name = match.Groups[2].Value }); }).ToList() } }; } int offset = 0, count = 100; if (!Int32.TryParse(RestOperationContext.Current.IncomingRequest.QueryString["_offset"] ?? "0", out offset)) { throw new FormatException("_offset is not in the correct format"); } if (!Int32.TryParse(RestOperationContext.Current.IncomingRequest.QueryString["_count"] ?? "100", out count)) { throw new FormatException("_count is not in the correct format"); } var queryData = providerImplementation.ExecuteView(viewDef, parameters, offset, count); return(queryData); } catch (KeyNotFoundException) { audit.Outcome = OutcomeIndicator.MinorFail; throw; } catch (Exception e) { audit.Outcome = OutcomeIndicator.MinorFail; this.m_tracer.TraceError("Error rendering query: {0}", e); throw new FaultException(500, $"Error rendering query {queryId}", e); } finally { AuditUtil.AddLocalDeviceActor(audit); AuditUtil.AddUserActor(audit); AuditUtil.SendAudit(audit); } }
/// <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); }