diff --git a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.cs b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.cs index a4ad4361..352651f1 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.cs @@ -445,6 +445,14 @@ namespace Microsoft.SqlTools.ServiceLayer } } + public static string FailedToFindConnectionInfoAboutTheServer + { + get + { + return Keys.GetString(Keys.FailedToFindConnectionInfoAboutTheServer); + } + } + public static string PeekDefinitionNoResultsError { get @@ -11450,6 +11458,9 @@ namespace Microsoft.SqlTools.ServiceLayer public const string FailedToGenerateServerContextualizationScripts = "FailedToGenerateServerContextualizationScripts"; + public const string FailedToFindConnectionInfoAboutTheServer = "FailedToFindConnectionInfoAboutTheServer"; + + public const string SerializationServiceUnsupportedFormat = "SerializationServiceUnsupportedFormat"; diff --git a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.resx b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.resx index 2a43274e..fb7e9c00 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.resx +++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.resx @@ -435,6 +435,10 @@ Failed to generate server contextualization scripts + + Failed to find connection info about the server + + Unsupported Save Format: {0} . diff --git a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.strings b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.strings index 10eea2ed..7add8bfb 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.strings +++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.strings @@ -195,6 +195,8 @@ WritingServerContextualizationToCacheError (string message) = An error was encou FailedToGenerateServerContextualizationScripts = Failed to generate server contextualization scripts +FailedToFindConnectionInfoAboutTheServer = Failed to find connection info about the server + ############################################################################ # Serialization Service diff --git a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.xlf b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.xlf index df29513f..89efe848 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.xlf +++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.xlf @@ -7259,6 +7259,11 @@ The Query Processor estimates that implementing the following index could improv Failed to generate server contextualization scripts + + Failed to find connection info about the server + Failed to find connection info about the server + + \ No newline at end of file diff --git a/src/Microsoft.SqlTools.ServiceLayer/Metadata/Contracts/GenerateServerContextualizationRequest.cs b/src/Microsoft.SqlTools.ServiceLayer/Metadata/Contracts/GenerateServerContextualizationRequest.cs deleted file mode 100644 index 9774c230..00000000 --- a/src/Microsoft.SqlTools.ServiceLayer/Metadata/Contracts/GenerateServerContextualizationRequest.cs +++ /dev/null @@ -1,34 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. -// - -using Microsoft.SqlTools.Hosting.Protocol.Contracts; - -namespace Microsoft.SqlTools.ServiceLayer.Metadata.Contracts -{ - public class GenerateServerContextualizationParams - { - /// - /// The URI of the connection to generate context for. - /// - public string OwnerUri { get; set; } - } - - public class GenerateServerContextualizationResult - { - /// - /// The generated server context. - /// - public string? Context { get; set; } - } - - /// - /// Generate server context request endpoint. - /// - public class GenerateServerContextualizationRequest - { - public static readonly RequestType Type = - RequestType.Create("metadata/generateServerContext"); - } -} diff --git a/src/Microsoft.SqlTools.ServiceLayer/Metadata/Contracts/GetServerContextualizationRequest.cs b/src/Microsoft.SqlTools.ServiceLayer/Metadata/Contracts/GetServerContextualizationRequest.cs index acf0464e..177c6080 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Metadata/Contracts/GetServerContextualizationRequest.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Metadata/Contracts/GetServerContextualizationRequest.cs @@ -1,4 +1,4 @@ -// +// // Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. // @@ -10,7 +10,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Metadata.Contracts public class GetServerContextualizationParams { /// - /// The URI of the connection to generate scripts for. + /// The URI to generate and retrieve server contextualization for. /// public string OwnerUri { get; set; } } @@ -18,9 +18,9 @@ namespace Microsoft.SqlTools.ServiceLayer.Metadata.Contracts public class GetServerContextualizationResult { /// - /// The generated server context. + /// The generated context. /// - public string? Context { get; set; } + public string Context { get; set; } } public class GetServerContextualizationRequest diff --git a/src/Microsoft.SqlTools.ServiceLayer/Metadata/MetadataService.cs b/src/Microsoft.SqlTools.ServiceLayer/Metadata/MetadataService.cs index b46812e8..e3fe7a34 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Metadata/MetadataService.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Metadata/MetadataService.cs @@ -59,7 +59,6 @@ namespace Microsoft.SqlTools.ServiceLayer.Metadata serviceHost.SetRequestHandler(MetadataListRequest.Type, HandleMetadataListRequest, true); serviceHost.SetRequestHandler(TableMetadataRequest.Type, HandleGetTableRequest, true); serviceHost.SetRequestHandler(ViewMetadataRequest.Type, HandleGetViewRequest, true); - serviceHost.SetRequestHandler(GenerateServerContextualizationRequest.Type, HandleGenerateServerContextualizationNotification, true); serviceHost.SetRequestHandler(GetServerContextualizationRequest.Type, HandleGetServerContextualizationRequest, true); } @@ -121,79 +120,11 @@ namespace Microsoft.SqlTools.ServiceLayer.Metadata await HandleGetTableOrViewRequest(metadataParams, "view", requestContext); } - /// - /// Handles the event for generating server contextualization scripts. - /// - internal static Task HandleGenerateServerContextualizationNotification(GenerateServerContextualizationParams contextualizationParams, - RequestContext requestContext) - { - _ = Task.Factory.StartNew(async () => - { - await GenerateServerContextualization(contextualizationParams, requestContext); - }, - CancellationToken.None, - TaskCreationOptions.None, - TaskScheduler.Default); - - return Task.CompletedTask; - } - /// /// Generates the contextualization scripts for a server. The generated context is in the form of create scripts for /// database objects like tables and views. /// /// The contextualization parameters. - internal static async Task GenerateServerContextualization(GenerateServerContextualizationParams contextualizationParams, RequestContext requestContext) - { - MetadataService.ConnectionServiceInstance.TryFindConnection(contextualizationParams.OwnerUri, out ConnectionInfo connectionInfo); - - if (connectionInfo != null) - { - using (SqlConnection sqlConn = ConnectionService.OpenSqlConnection(connectionInfo, "metadata")) - { - // If scripts have been generated within the last 30 days then there isn't a need to go through the process - // of generating scripts again. - if (MetadataScriptTempFileStream.IsScriptTempFileUpdateNeeded(connectionInfo.ConnectionDetails.ServerName)) - { - var scripts = SmoScripterHelpers.GenerateAllServerTableScripts(sqlConn)?.ToArray(); - if (scripts != null) - { - try - { - await requestContext.SendResult(new GenerateServerContextualizationResult() - { - Context = string.Join('\n', scripts) - }); - - MetadataScriptTempFileStream.Write(connectionInfo.ConnectionDetails.ServerName, scripts); - } - catch (Exception ex) - { - Logger.Error($"An error was encountered while writing server contextualization scripts to the cache. Error: {ex.Message}"); - await requestContext.SendError(ex); - } - } - else - { - Logger.Error("Failed to generate server contextualization scripts"); - await requestContext.SendError(SR.FailedToGenerateServerContextualizationScripts); - } - } - else - { - var generateContextResult = new GenerateServerContextualizationResult() - { - Context = null - }; - await requestContext.SendResult(generateContextResult); - } - } - } - } - - /// - /// Handles the request for getting database server contextualization scripts. - /// internal static Task HandleGetServerContextualizationRequest(GetServerContextualizationParams contextualizationParams, RequestContext requestContext) { @@ -208,26 +139,46 @@ namespace Microsoft.SqlTools.ServiceLayer.Metadata return Task.CompletedTask; } - /// - /// Gets server contextualization scripts. The retrieved scripts are create scripts for database objects like tables and views. - /// - /// The contextualization parameters to get context. - /// The request context for the request. - /// internal static async Task GetServerContextualization(GetServerContextualizationParams contextualizationParams, RequestContext requestContext) { MetadataService.ConnectionServiceInstance.TryFindConnection(contextualizationParams.OwnerUri, out ConnectionInfo connectionInfo); - // When the filed context is too old don't read it - if (MetadataScriptTempFileStream.IsScriptTempFileUpdateNeeded(connectionInfo.ConnectionDetails.ServerName)) + if (connectionInfo == null) { - await requestContext.SendResult(new GetServerContextualizationResult - { - Context = null - }); + Logger.Error("Failed to find connection info about the server."); + throw new Exception(SR.FailedToFindConnectionInfoAboutTheServer); } else { - if (connectionInfo != null) + if (MetadataScriptTempFileStream.IsScriptTempFileUpdateNeeded(connectionInfo.ConnectionDetails.ServerName)) + { + using (SqlConnection sqlConn = ConnectionService.OpenSqlConnection(connectionInfo, "metadata")) + { + var scripts = SmoScripterHelpers.GenerateAllServerTableScripts(sqlConn)?.ToArray(); + if (scripts != null) + { + try + { + await requestContext.SendResult(new GetServerContextualizationResult() + { + Context = string.Join('\n', scripts) + }); + + MetadataScriptTempFileStream.Write(connectionInfo.ConnectionDetails.ServerName, scripts); + } + catch (Exception ex) + { + Logger.Error($"An error was encountered while generating server contextualization scripts. Error: {ex.Message}"); + throw; + } + } + else + { + Logger.Error("Failed to generate server contextualization scripts"); + throw new Exception(SR.FailedToGenerateServerContextualizationScripts); + } + } + } + else { try { @@ -240,14 +191,9 @@ namespace Microsoft.SqlTools.ServiceLayer.Metadata catch (Exception ex) { Logger.Error("Failed to read scripts from the script cache"); - await requestContext.SendError(ex); + throw; } } - else - { - Logger.Error("Failed to find connection info about the server."); - await requestContext.SendError("Failed to find connection info about the server."); - } } } diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Metadata/MetadataServiceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Metadata/MetadataServiceTests.cs index df02efb4..226d03e1 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Metadata/MetadataServiceTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Metadata/MetadataServiceTests.cs @@ -133,42 +133,6 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Metadata requestContext.VerifyAll(); } - [Test] - public async Task VerifyGenerateServerContextualizationNotification() - { - this.testTableName += new Random().Next(1000000, 9999999).ToString(); - this.testTableName2 += new Random().Next(0, 999999).ToString(); - - var connectionResult = LiveConnectionHelper.InitLiveConnectionInfo(null); - var sqlConn = ConnectionService.OpenSqlConnection(connectionResult.ConnectionInfo); - - CreateTestTable(sqlConn, this.testTableSchema, this.testTableName); - CreateTestTable(sqlConn, this.testTableSchema, this.testTableName2); - - var generateServerContextualizationParams = new GenerateServerContextualizationParams - { - OwnerUri = connectionResult.ConnectionInfo.OwnerUri - }; - - var actualGenerateServerContextResponse = new GenerateServerContextualizationResult(); - var mockGenerateRequestContext = new Mock>(); - mockGenerateRequestContext.Setup(x => x.SendResult(It.IsAny())) - .Callback(result => actualGenerateServerContextResponse = result) - .Returns(Task.CompletedTask); - await MetadataService.GenerateServerContextualization(generateServerContextualizationParams, mockGenerateRequestContext.Object); - - DeleteTestTable(sqlConn, this.testTableSchema, this.testTableName); - DeleteTestTable(sqlConn, this.testTableSchema, this.testTableName2); - - var firstCreateTableScript = $"CREATE TABLE [{this.testTableSchema}].[{this.testTableName}]([id] [int] NULL)"; - var secondCreateTableScript = $"CREATE TABLE [{this.testTableSchema}].[{this.testTableName2}]([id] [int] NULL)"; - - Assert.IsTrue(actualGenerateServerContextResponse.Context.Contains(firstCreateTableScript)); - Assert.IsTrue(actualGenerateServerContextResponse.Context.Contains(secondCreateTableScript)); - - DeleteServerContextualizationTempFile(sqlConn.DataSource); - } - [Test] public async Task VerifyGetServerContextualizationRequest() { @@ -194,28 +158,19 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Metadata { OwnerUri = connectionResult.ConnectionInfo.OwnerUri }; + + // First call generates context, stores it in temp file and returns the generated context await MetadataService.GetServerContextualization(getServerContextualizationParams, mockGetServerContextualizationRequestContext.Object); - Assert.IsNull(actualGetServerContextualizationResponse.Context); - Assert.IsNull(actualGetServerContextualizationResponse.Context); + Assert.IsTrue(actualGetServerContextualizationResponse.Context.Contains(firstCreateTableScript)); + Assert.IsTrue(actualGetServerContextualizationResponse.Context.Contains(secondCreateTableScript)); - var generateServerContextualizationParams = new GenerateServerContextualizationParams - { - OwnerUri = connectionResult.ConnectionInfo.OwnerUri - }; - - var actualGenerateServerContextResponse = new GenerateServerContextualizationResult(); - var mockGenerateRequestContext = new Mock>(); - mockGenerateRequestContext.Setup(x => x.SendResult(It.IsAny())) - .Callback(actual => actualGenerateServerContextResponse = actual) - .Returns(Task.CompletedTask); - await MetadataService.GenerateServerContextualization(generateServerContextualizationParams, mockGenerateRequestContext.Object); + // Second call gets the context from the temp file and returns that read file context. + await MetadataService.GetServerContextualization(getServerContextualizationParams, mockGetServerContextualizationRequestContext.Object); DeleteTestTable(sqlConn, this.testTableSchema, this.testTableName); DeleteTestTable(sqlConn, this.testTableSchema, this.testTableName2); - await MetadataService.GetServerContextualization(getServerContextualizationParams, mockGetServerContextualizationRequestContext.Object); - Assert.IsTrue(actualGetServerContextualizationResponse.Context.Contains(firstCreateTableScript)); Assert.IsTrue(actualGetServerContextualizationResponse.Context.Contains(secondCreateTableScript));