From 3ba22c94ac38c7bdea8da35378b547b0345167b5 Mon Sep 17 00:00:00 2001 From: Benjamin Russell Date: Thu, 4 Aug 2016 14:48:58 -0700 Subject: [PATCH] WIP for QueryExecution, mostly complete --- .../Contracts/QueryDisposeRequest.cs | 4 +- .../QueryExecuteCompleteNotification.cs | 21 ++- .../Contracts/QueryExecuteRequest.cs | 2 +- .../Contracts/QueryExecuteSubsetRequest.cs} | 9 +- .../Contracts/ResultSetSubset.cs | 13 ++ .../Contracts/ResultSetSummary.cs | 12 +- .../QueryExecution/Query.cs | 144 +++++++++++++++++ .../QueryExecution/QueryExecutionService.cs | 153 ++++++++++++++++++ .../Contracts => QueryExecution}/ResultSet.cs | 2 +- .../Contracts/ResultSetSubset.cs | 11 -- .../QueryExecutionServices/Query.cs | 69 -------- .../QueryExecutionService.cs | 89 ---------- 12 files changed, 338 insertions(+), 191 deletions(-) rename src/Microsoft.SqlTools.ServiceLayer/{QueryExecutionServices => QueryExecution}/Contracts/QueryDisposeRequest.cs (89%) rename src/Microsoft.SqlTools.ServiceLayer/{QueryExecutionServices => QueryExecution}/Contracts/QueryExecuteCompleteNotification.cs (51%) rename src/Microsoft.SqlTools.ServiceLayer/{QueryExecutionServices => QueryExecution}/Contracts/QueryExecuteRequest.cs (94%) rename src/Microsoft.SqlTools.ServiceLayer/{QueryExecutionServices/Contracts/QueryExecuteResultsRequest.cs => QueryExecution/Contracts/QueryExecuteSubsetRequest.cs} (85%) create mode 100644 src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/ResultSetSubset.cs rename src/Microsoft.SqlTools.ServiceLayer/{QueryExecutionServices => QueryExecution}/Contracts/ResultSetSummary.cs (59%) create mode 100644 src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Query.cs create mode 100644 src/Microsoft.SqlTools.ServiceLayer/QueryExecution/QueryExecutionService.cs rename src/Microsoft.SqlTools.ServiceLayer/{QueryExecutionServices/Contracts => QueryExecution}/ResultSet.cs (92%) delete mode 100644 src/Microsoft.SqlTools.ServiceLayer/QueryExecutionServices/Contracts/ResultSetSubset.cs delete mode 100644 src/Microsoft.SqlTools.ServiceLayer/QueryExecutionServices/Query.cs delete mode 100644 src/Microsoft.SqlTools.ServiceLayer/QueryExecutionServices/QueryExecutionService.cs diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecutionServices/Contracts/QueryDisposeRequest.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/QueryDisposeRequest.cs similarity index 89% rename from src/Microsoft.SqlTools.ServiceLayer/QueryExecutionServices/Contracts/QueryDisposeRequest.cs rename to src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/QueryDisposeRequest.cs index e34e7dbc..51e1b5dd 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/QueryExecutionServices/Contracts/QueryDisposeRequest.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/QueryDisposeRequest.cs @@ -6,14 +6,14 @@ using System; using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts; -namespace Microsoft.SqlTools.ServiceLayer.QueryExecutionServices.Contracts +namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts { /// /// Parameters for the query dispose request /// public class QueryDisposeParams { - public Guid QueryId { get; set; } + public string OwnerUri { get; set; } } /// diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecutionServices/Contracts/QueryExecuteCompleteNotification.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/QueryExecuteCompleteNotification.cs similarity index 51% rename from src/Microsoft.SqlTools.ServiceLayer/QueryExecutionServices/Contracts/QueryExecuteCompleteNotification.cs rename to src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/QueryExecuteCompleteNotification.cs index 22a210c2..b5c69941 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/QueryExecutionServices/Contracts/QueryExecuteCompleteNotification.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/QueryExecuteCompleteNotification.cs @@ -1,12 +1,14 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; +using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts; -namespace Microsoft.SqlTools.ServiceLayer.QueryExecutionServices.Contracts +namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts { - public class QueryExecuteCompleteNotification + public class QueryExecuteCompleteParams { + /// + /// URI for the editor that owns the query + /// + public string OwnerUri { get; set; } + /// /// Any messages that came back from the server during execution of the query /// @@ -22,4 +24,11 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecutionServices.Contracts /// public ResultSetSummary[] ResultSetSummaries { get; set; } } + + public class QueryExecuteCompleteEvent + { + public static readonly + EventType Type = + EventType.Create("query/complete"); + } } diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecutionServices/Contracts/QueryExecuteRequest.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/QueryExecuteRequest.cs similarity index 94% rename from src/Microsoft.SqlTools.ServiceLayer/QueryExecutionServices/Contracts/QueryExecuteRequest.cs rename to src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/QueryExecuteRequest.cs index 95fd1548..59453fb9 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/QueryExecutionServices/Contracts/QueryExecuteRequest.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/QueryExecuteRequest.cs @@ -6,7 +6,7 @@ using System; using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts; -namespace Microsoft.SqlTools.ServiceLayer.QueryExecutionServices.Contracts +namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts { /// /// Parameters for the query execute request diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecutionServices/Contracts/QueryExecuteResultsRequest.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/QueryExecuteSubsetRequest.cs similarity index 85% rename from src/Microsoft.SqlTools.ServiceLayer/QueryExecutionServices/Contracts/QueryExecuteResultsRequest.cs rename to src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/QueryExecuteSubsetRequest.cs index 7a31dcb4..7cd607a6 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/QueryExecutionServices/Contracts/QueryExecuteResultsRequest.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/QueryExecuteSubsetRequest.cs @@ -6,7 +6,7 @@ using System; using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts; -namespace Microsoft.SqlTools.ServiceLayer.QueryExecutionServices.Contracts +namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts { /// /// Parameters for a query result subset retrieval request @@ -16,7 +16,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecutionServices.Contracts /// /// ID of the query to look up the results for /// - public Guid QueryId { get; set; } + public string OwnerId { get; set; } /// /// Index of the result set to get the results from @@ -38,11 +38,12 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecutionServices.Contracts } /// - /// + /// Parameters for the result of a subset retrieval request /// public class QueryExecuteSubsetResult { - + public string Message { get; set; } + public ResultSetSubset ResultSubset { get; set; } } public class QueryExecuteSubsetRequest diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/ResultSetSubset.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/ResultSetSubset.cs new file mode 100644 index 00000000..a9256581 --- /dev/null +++ b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/ResultSetSubset.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts +{ + public class ResultSetSubset + { + public int RowCount { get; set; } + public object[][] Rows { get; set; } + } +} diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecutionServices/Contracts/ResultSetSummary.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/ResultSetSummary.cs similarity index 59% rename from src/Microsoft.SqlTools.ServiceLayer/QueryExecutionServices/Contracts/ResultSetSummary.cs rename to src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/ResultSetSummary.cs index b989c135..416aafb8 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/QueryExecutionServices/Contracts/ResultSetSummary.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/ResultSetSummary.cs @@ -1,10 +1,6 @@ -using System; -using System.Collections.Generic; -using System.Data.Common; -using System.Linq; -using System.Threading.Tasks; +using System.Data.Common; -namespace Microsoft.SqlTools.ServiceLayer.QueryExecutionServices.Contracts +namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts { public class ResultSetSummary { @@ -16,11 +12,11 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecutionServices.Contracts /// /// The number of rows that was returned with the resultset /// - public long RowCount { get; set; } + public int RowCount { get; set; } /// /// Details about the columns that are provided as solutions /// - public DbColumn ColumnInfo { get; set; } + public DbColumn[] ColumnInfo { get; set; } } } diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Query.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Query.cs new file mode 100644 index 00000000..e146270f --- /dev/null +++ b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Query.cs @@ -0,0 +1,144 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Data.Common; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.SqlTools.ServiceLayer.Connection; +using Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts; + +namespace Microsoft.SqlTools.ServiceLayer.QueryExecution +{ + public class Query //: IDisposable + { + #region Properties + + public string QueryText { get; set; } + + public ConnectionInfo EditorConnection { get; set; } + + private readonly CancellationTokenSource cancellationSource; + + public List ResultSets { get; set; } + + public ResultSetSummary[] ResultSummary + { + get + { + return ResultSets.Select((set, index) => new ResultSetSummary + { + ColumnInfo = set.Columns, + Id = index, + RowCount = set.Rows.Count + }).ToArray(); + } + } + + public bool HasExecuted { get; set; } + + #endregion + + public Query(string queryText, ConnectionInfo connection) + { + // Sanity check for input + if (queryText == null) + { + throw new ArgumentNullException(nameof(queryText), "Query text cannot be null"); + } + if (connection == null) + { + throw new ArgumentNullException(nameof(connection), "Connection cannot be null"); + } + + // Initialize the internal state + QueryText = queryText; + EditorConnection = connection; + HasExecuted = false; + ResultSets = new List(); + cancellationSource = new CancellationTokenSource(); + } + + public async Task Execute() + { + // Sanity check to make sure we haven't already run this query + if (HasExecuted) + { + throw new InvalidOperationException("Query has already executed."); + } + + // Create a connection from the connection details + using (DbConnection conn = EditorConnection.Factory.CreateSqlConnection(EditorConnection.ConnectionDetails)) + { + await conn.OpenAsync(cancellationSource.Token); + + // Create a command that we'll use for executing the query + using (DbCommand command = conn.CreateCommand()) + { + command.CommandText = QueryText; + command.CommandType = CommandType.Text; + + // Execute the command to get back a reader + using (DbDataReader reader = await command.ExecuteReaderAsync(cancellationSource.Token)) + { + do + { + // Create a new result set that we'll use to store all the data + ResultSet resultSet = new ResultSet(); + if (reader.CanGetColumnSchema()) + { + resultSet.Columns = reader.GetColumnSchema().ToArray(); + } + + // Read until we hit the end of the result set + while (await reader.ReadAsync(cancellationSource.Token)) + { + resultSet.AddRow(reader); + } + + // Add the result set to the results of the query + ResultSets.Add(resultSet); + } while (await reader.NextResultAsync(cancellationSource.Token)); + } + } + } + + // Mark that we have executed + HasExecuted = true; + } + + public ResultSetSubset GetSubset(int resultSetIndex, int startRow, int rowCount) + { + // Sanity check that the results are available + if (!HasExecuted) + { + throw new InvalidOperationException("The query has not completed, yet."); + } + + // Sanity check to make sure we have valid numbers + if (resultSetIndex < 0 || resultSetIndex >= ResultSets.Count) + { + throw new ArgumentOutOfRangeException(nameof(resultSetIndex), "Result set index cannot be less than 0" + + "or greater than the number of result sets"); + } + ResultSet targetResultSet = ResultSets[resultSetIndex]; + if (startRow < 0 || startRow >= targetResultSet.Rows.Count) + { + throw new ArgumentOutOfRangeException(nameof(startRow), "Start row cannot be less than 0 " + + "or greater than the number of rows in the resultset"); + } + if (rowCount <= 0) + { + throw new ArgumentOutOfRangeException(nameof(rowCount), "Row count must be a positive integer"); + } + + // Retrieve the subset of the results as per the request + object[][] rows = targetResultSet.Rows.Skip(startRow).Take(rowCount).ToArray(); + return new ResultSetSubset + { + Rows = rows, + RowCount = rows.Length + }; + } + } +} diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/QueryExecutionService.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/QueryExecutionService.cs new file mode 100644 index 00000000..d8ff0811 --- /dev/null +++ b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/QueryExecutionService.cs @@ -0,0 +1,153 @@ +using System; +using System.Collections.Concurrent; +using System.Threading.Tasks; +using Microsoft.SqlTools.ServiceLayer.Connection; +using Microsoft.SqlTools.ServiceLayer.Hosting; +using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol; +using Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts; + +namespace Microsoft.SqlTools.ServiceLayer.QueryExecution +{ + public sealed class QueryExecutionService + { + #region Singleton Instance Implementation + + private static readonly Lazy instance = new Lazy(() => new QueryExecutionService()); + + public static QueryExecutionService Instance + { + get { return instance.Value; } + } + + private QueryExecutionService() { } + + #endregion + + #region Properties + + private readonly Lazy> queries = + new Lazy>(() => new ConcurrentDictionary()); + + private ConcurrentDictionary ActiveQueries + { + get { return queries.Value; } + } + + #endregion + + #region Public Methods + + /// + /// + /// + /// + public void InitializeService(ServiceHost serviceHost) + { + // Register handlers for requests + serviceHost.SetRequestHandler(QueryExecuteRequest.Type, HandleExecuteRequest); + serviceHost.SetRequestHandler(QueryExecuteSubsetRequest.Type, HandleResultSubsetRequest); + serviceHost.SetRequestHandler(QueryDisposeRequest.Type, HandleDisposeRequest); + + // Register handlers for events + } + + #endregion + + #region Request Handlers + + private async Task HandleExecuteRequest(QueryExecuteParams executeParams, + RequestContext requestContext) + { + // Attempt to get the connection for the editor + ConnectionInfo connectionInfo; + if(!ConnectionService.Instance.TryFindConnection(executeParams.OwnerUri, out connectionInfo)) + { + await requestContext.SendError("This editor is not connected to a database."); + return; + } + + // If there is already an in-flight query, error out + Query newQuery = new Query(executeParams.QueryText, connectionInfo); + if (!ActiveQueries.TryAdd(executeParams.OwnerUri, newQuery)) + { + await requestContext.SendError("A query is already in progress for this editor session." + + "Please cancel this query or wait for its completion."); + return; + } + + // Launch the query and respond with successfully launching it + Task executeTask = newQuery.Execute(); + await requestContext.SendResult(new QueryExecuteResult + { + Messages = null + }); + + // Wait for query execution and then send back the results + await Task.WhenAll(executeTask); + QueryExecuteCompleteParams eventParams = new QueryExecuteCompleteParams + { + Error = false, + Messages = new string[]{}, // TODO: Figure out how to get messages back from the server + OwnerUri = executeParams.OwnerUri, + ResultSetSummaries = newQuery.ResultSummary + }; + await requestContext.SendEvent(QueryExecuteCompleteEvent.Type, eventParams); + } + + private async Task HandleResultSubsetRequest(QueryExecuteSubsetParams subsetParams, + RequestContext requestContext) + { + // Attempt to load the query + Query query; + if (!ActiveQueries.TryGetValue(subsetParams.OwnerId, out query)) + { + var errorResult = new QueryExecuteSubsetResult + { + Message = "The requested query does not exist." + }; + await requestContext.SendResult(errorResult); + return; + } + + try + { + // Retrieve the requested subset and return it + var result = new QueryExecuteSubsetResult + { + Message = null, + ResultSubset = query.GetSubset( + subsetParams.ResultSetIndex, subsetParams.RowsStartIndex, subsetParams.RowsCount) + }; + await requestContext.SendResult(result); + } + catch (Exception e) + { + await requestContext.SendResult(new QueryExecuteSubsetResult + { + Message = e.Message + }); + } + } + + private async Task HandleDisposeRequest(QueryDisposeParams disposeParams, + RequestContext requestContext) + { + // Attempt to remove the query for the owner uri + Query result; + if (!ActiveQueries.TryRemove(disposeParams.OwnerUri, out result)) + { + await requestContext.SendError("Failed to dispose query, ID not found."); + return; + } + + // Success + await requestContext.SendResult(new QueryDisposeResult + { + Messages = null + }); + } + + #endregion + + } +} diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecutionServices/Contracts/ResultSet.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/ResultSet.cs similarity index 92% rename from src/Microsoft.SqlTools.ServiceLayer/QueryExecutionServices/Contracts/ResultSet.cs rename to src/Microsoft.SqlTools.ServiceLayer/QueryExecution/ResultSet.cs index c3ec6f3d..5de88521 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/QueryExecutionServices/Contracts/ResultSet.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/ResultSet.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Data.Common; -namespace Microsoft.SqlTools.ServiceLayer.QueryExecutionServices.Contracts +namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts { public class ResultSet { diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecutionServices/Contracts/ResultSetSubset.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecutionServices/Contracts/ResultSetSubset.cs deleted file mode 100644 index 092e58b3..00000000 --- a/src/Microsoft.SqlTools.ServiceLayer/QueryExecutionServices/Contracts/ResultSetSubset.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Microsoft.SqlTools.ServiceLayer.QueryExecutionServices.Contracts -{ - public class ResultSetSubset - { - } -} diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecutionServices/Query.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecutionServices/Query.cs deleted file mode 100644 index d2a49bb3..00000000 --- a/src/Microsoft.SqlTools.ServiceLayer/QueryExecutionServices/Query.cs +++ /dev/null @@ -1,69 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Data; -using System.Data.Common; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.SqlTools.ServiceLayer.QueryExecutionServices.Contracts; - -namespace Microsoft.SqlTools.ServiceLayer.QueryExecutionServices -{ - public class Query //: IDisposable - { - public string QueryText { get; set; } - - public DbConnection SqlConnection { get; set; } - - private readonly CancellationTokenSource cancellationSource; - - public List ResultSets { get; set; } - - public Query(string queryText, DbConnection connection) - { - QueryText = queryText; - SqlConnection = connection; - ResultSets = new List(); - cancellationSource = new CancellationTokenSource(); - } - - public async Task Execute() - { - // Open the connection, if it's not already open - if ((SqlConnection.State & ConnectionState.Open) == 0) - { - await SqlConnection.OpenAsync(cancellationSource.Token); - } - - // Create a command that we'll use for executing the query - using (DbCommand command = SqlConnection.CreateCommand()) - { - command.CommandText = QueryText; - command.CommandType = CommandType.Text; - - // Execute the command to get back a reader - using (DbDataReader reader = await command.ExecuteReaderAsync(cancellationSource.Token)) - { - do - { - // Create a new result set that we'll use to store all the data - ResultSet resultSet = new ResultSet(); - if (reader.CanGetColumnSchema()) - { - resultSet.Columns = reader.GetColumnSchema().ToArray(); - } - - // Read until we hit the end of the result set - while (await reader.ReadAsync(cancellationSource.Token)) - { - resultSet.AddRow(reader); - } - - // Add the result set to the results of the query - ResultSets.Add(resultSet); - } while (await reader.NextResultAsync(cancellationSource.Token)); - } - } - } - } -} diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecutionServices/QueryExecutionService.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecutionServices/QueryExecutionService.cs deleted file mode 100644 index b3ec4886..00000000 --- a/src/Microsoft.SqlTools.ServiceLayer/QueryExecutionServices/QueryExecutionService.cs +++ /dev/null @@ -1,89 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Threading.Tasks; -using Microsoft.SqlTools.ServiceLayer.Hosting; -using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol; -using Microsoft.SqlTools.ServiceLayer.QueryExecutionServices.Contracts; - -namespace Microsoft.SqlTools.ServiceLayer.QueryExecutionServices -{ - public sealed class QueryExecutionService - { - #region Singleton Instance Implementation - - private static readonly Lazy instance = new Lazy(() => new QueryExecutionService()); - - public static QueryExecutionService Instance - { - get { return instance.Value; } - } - - private QueryExecutionService() { } - - #endregion - - #region Properties - - private readonly Lazy> queries = - new Lazy>(() => new ConcurrentDictionary()); - - private ConcurrentDictionary Queries - { - get { return queries.Value; } - } - - #endregion - - #region Public Methods - - /// - /// - /// - /// - public void InitializeService(ServiceHost serviceHost) - { - // Register handlers for requests - serviceHost.SetRequestHandler(QueryExecuteRequest.Type, HandleExecuteRequest); - serviceHost.SetRequestHandler(QueryExecuteSubsetRequest.Type, HandleResultSubsetRequest); - serviceHost.SetRequestHandler(QueryDisposeRequest.Type, HandleDisposeRequest); - - // Register handlers for events - } - - #endregion - - #region Request Handlers - - private async Task HandleExecuteRequest(QueryExecuteParams executeParams, - RequestContext requestContext) - { - - } - - private async Task HandleResultSubsetRequest(QueryExecuteSubsetParams subsetParams, - RequestContext requestContext) - { - await Task.FromResult(0); - } - - private async Task HandleDisposeRequest(QueryDisposeParams disposeParams, - RequestContext requestContext) - { - string messages = null; - - Query result; - if (!Queries.TryRemove(disposeParams., out result)) - { - messages = "Failed to dispose query, ID not found."; - } - - await requestContext.SendResult(new QueryDisposeResult - { - Messages = messages - }); - } - - #endregion - - } -}