mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-02-16 10:58:30 -05:00
Consolidate context request endpoints into a single request endpoint (#2205)
* Create new endpoint consolidating previous 2 * Clarify comment * Removes two separate endpoints to get and generate * Rename classes for get context request * Update src/Microsoft.SqlTools.ServiceLayer/Metadata/MetadataService.cs Co-authored-by: Charles Gagnon <chgagnon@microsoft.com> * Update src/Microsoft.SqlTools.ServiceLayer/Metadata/MetadataService.cs Co-authored-by: Charles Gagnon <chgagnon@microsoft.com> * Code review changes * Throw exception and localize ex messages --------- Co-authored-by: Charles Gagnon <chgagnon@microsoft.com>
This commit is contained in:
@@ -445,6 +445,14 @@ namespace Microsoft.SqlTools.ServiceLayer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string FailedToFindConnectionInfoAboutTheServer
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Keys.GetString(Keys.FailedToFindConnectionInfoAboutTheServer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static string PeekDefinitionNoResultsError
|
public static string PeekDefinitionNoResultsError
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@@ -11450,6 +11458,9 @@ namespace Microsoft.SqlTools.ServiceLayer
|
|||||||
public const string FailedToGenerateServerContextualizationScripts = "FailedToGenerateServerContextualizationScripts";
|
public const string FailedToGenerateServerContextualizationScripts = "FailedToGenerateServerContextualizationScripts";
|
||||||
|
|
||||||
|
|
||||||
|
public const string FailedToFindConnectionInfoAboutTheServer = "FailedToFindConnectionInfoAboutTheServer";
|
||||||
|
|
||||||
|
|
||||||
public const string SerializationServiceUnsupportedFormat = "SerializationServiceUnsupportedFormat";
|
public const string SerializationServiceUnsupportedFormat = "SerializationServiceUnsupportedFormat";
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -435,6 +435,10 @@
|
|||||||
<value>Failed to generate server contextualization scripts</value>
|
<value>Failed to generate server contextualization scripts</value>
|
||||||
<comment></comment>
|
<comment></comment>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="FailedToFindConnectionInfoAboutTheServer" xml:space="preserve">
|
||||||
|
<value>Failed to find connection info about the server</value>
|
||||||
|
<comment></comment>
|
||||||
|
</data>
|
||||||
<data name="SerializationServiceUnsupportedFormat" xml:space="preserve">
|
<data name="SerializationServiceUnsupportedFormat" xml:space="preserve">
|
||||||
<value>Unsupported Save Format: {0}</value>
|
<value>Unsupported Save Format: {0}</value>
|
||||||
<comment>.
|
<comment>.
|
||||||
|
|||||||
@@ -195,6 +195,8 @@ WritingServerContextualizationToCacheError (string message) = An error was encou
|
|||||||
|
|
||||||
FailedToGenerateServerContextualizationScripts = Failed to generate server contextualization scripts
|
FailedToGenerateServerContextualizationScripts = Failed to generate server contextualization scripts
|
||||||
|
|
||||||
|
FailedToFindConnectionInfoAboutTheServer = Failed to find connection info about the server
|
||||||
|
|
||||||
############################################################################
|
############################################################################
|
||||||
# Serialization Service
|
# Serialization Service
|
||||||
|
|
||||||
|
|||||||
@@ -7259,6 +7259,11 @@ The Query Processor estimates that implementing the following index could improv
|
|||||||
<target state="new">Failed to generate server contextualization scripts</target>
|
<target state="new">Failed to generate server contextualization scripts</target>
|
||||||
<note></note>
|
<note></note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="FailedToFindConnectionInfoAboutTheServer">
|
||||||
|
<source>Failed to find connection info about the server</source>
|
||||||
|
<target state="new">Failed to find connection info about the server</target>
|
||||||
|
<note></note>
|
||||||
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
</xliff>
|
</xliff>
|
||||||
@@ -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
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The URI of the connection to generate context for.
|
|
||||||
/// </summary>
|
|
||||||
public string OwnerUri { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class GenerateServerContextualizationResult
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The generated server context.
|
|
||||||
/// </summary>
|
|
||||||
public string? Context { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generate server context request endpoint.
|
|
||||||
/// </summary>
|
|
||||||
public class GenerateServerContextualizationRequest
|
|
||||||
{
|
|
||||||
public static readonly RequestType<GenerateServerContextualizationParams, GenerateServerContextualizationResult> Type =
|
|
||||||
RequestType<GenerateServerContextualizationParams, GenerateServerContextualizationResult>.Create("metadata/generateServerContext");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
//
|
//
|
||||||
// Copyright (c) Microsoft. All rights reserved.
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
// 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
|
public class GetServerContextualizationParams
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The URI of the connection to generate scripts for.
|
/// The URI to generate and retrieve server contextualization for.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string OwnerUri { get; set; }
|
public string OwnerUri { get; set; }
|
||||||
}
|
}
|
||||||
@@ -18,9 +18,9 @@ namespace Microsoft.SqlTools.ServiceLayer.Metadata.Contracts
|
|||||||
public class GetServerContextualizationResult
|
public class GetServerContextualizationResult
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The generated server context.
|
/// The generated context.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string? Context { get; set; }
|
public string Context { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class GetServerContextualizationRequest
|
public class GetServerContextualizationRequest
|
||||||
|
|||||||
@@ -59,7 +59,6 @@ namespace Microsoft.SqlTools.ServiceLayer.Metadata
|
|||||||
serviceHost.SetRequestHandler(MetadataListRequest.Type, HandleMetadataListRequest, true);
|
serviceHost.SetRequestHandler(MetadataListRequest.Type, HandleMetadataListRequest, true);
|
||||||
serviceHost.SetRequestHandler(TableMetadataRequest.Type, HandleGetTableRequest, true);
|
serviceHost.SetRequestHandler(TableMetadataRequest.Type, HandleGetTableRequest, true);
|
||||||
serviceHost.SetRequestHandler(ViewMetadataRequest.Type, HandleGetViewRequest, true);
|
serviceHost.SetRequestHandler(ViewMetadataRequest.Type, HandleGetViewRequest, true);
|
||||||
serviceHost.SetRequestHandler(GenerateServerContextualizationRequest.Type, HandleGenerateServerContextualizationNotification, true);
|
|
||||||
serviceHost.SetRequestHandler(GetServerContextualizationRequest.Type, HandleGetServerContextualizationRequest, true);
|
serviceHost.SetRequestHandler(GetServerContextualizationRequest.Type, HandleGetServerContextualizationRequest, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,79 +120,11 @@ namespace Microsoft.SqlTools.ServiceLayer.Metadata
|
|||||||
await HandleGetTableOrViewRequest(metadataParams, "view", requestContext);
|
await HandleGetTableOrViewRequest(metadataParams, "view", requestContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Handles the event for generating server contextualization scripts.
|
|
||||||
/// </summary>
|
|
||||||
internal static Task HandleGenerateServerContextualizationNotification(GenerateServerContextualizationParams contextualizationParams,
|
|
||||||
RequestContext<GenerateServerContextualizationResult> requestContext)
|
|
||||||
{
|
|
||||||
_ = Task.Factory.StartNew(async () =>
|
|
||||||
{
|
|
||||||
await GenerateServerContextualization(contextualizationParams, requestContext);
|
|
||||||
},
|
|
||||||
CancellationToken.None,
|
|
||||||
TaskCreationOptions.None,
|
|
||||||
TaskScheduler.Default);
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generates the contextualization scripts for a server. The generated context is in the form of create scripts for
|
/// Generates the contextualization scripts for a server. The generated context is in the form of create scripts for
|
||||||
/// database objects like tables and views.
|
/// database objects like tables and views.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="contextualizationParams">The contextualization parameters.</param>
|
/// <param name="contextualizationParams">The contextualization parameters.</param>
|
||||||
internal static async Task GenerateServerContextualization(GenerateServerContextualizationParams contextualizationParams, RequestContext<GenerateServerContextualizationResult> 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Handles the request for getting database server contextualization scripts.
|
|
||||||
/// </summary>
|
|
||||||
internal static Task HandleGetServerContextualizationRequest(GetServerContextualizationParams contextualizationParams,
|
internal static Task HandleGetServerContextualizationRequest(GetServerContextualizationParams contextualizationParams,
|
||||||
RequestContext<GetServerContextualizationResult> requestContext)
|
RequestContext<GetServerContextualizationResult> requestContext)
|
||||||
{
|
{
|
||||||
@@ -208,26 +139,46 @@ namespace Microsoft.SqlTools.ServiceLayer.Metadata
|
|||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets server contextualization scripts. The retrieved scripts are create scripts for database objects like tables and views.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="contextualizationParams">The contextualization parameters to get context.</param>
|
|
||||||
/// <param name="requestContext">The request context for the request.</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
internal static async Task GetServerContextualization(GetServerContextualizationParams contextualizationParams, RequestContext<GetServerContextualizationResult> requestContext)
|
internal static async Task GetServerContextualization(GetServerContextualizationParams contextualizationParams, RequestContext<GetServerContextualizationResult> requestContext)
|
||||||
{
|
{
|
||||||
MetadataService.ConnectionServiceInstance.TryFindConnection(contextualizationParams.OwnerUri, out ConnectionInfo connectionInfo);
|
MetadataService.ConnectionServiceInstance.TryFindConnection(contextualizationParams.OwnerUri, out ConnectionInfo connectionInfo);
|
||||||
// When the filed context is too old don't read it
|
if (connectionInfo == null)
|
||||||
if (MetadataScriptTempFileStream.IsScriptTempFileUpdateNeeded(connectionInfo.ConnectionDetails.ServerName))
|
|
||||||
{
|
{
|
||||||
await requestContext.SendResult(new GetServerContextualizationResult
|
Logger.Error("Failed to find connection info about the server.");
|
||||||
{
|
throw new Exception(SR.FailedToFindConnectionInfoAboutTheServer);
|
||||||
Context = null
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
else
|
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
|
try
|
||||||
{
|
{
|
||||||
@@ -240,14 +191,9 @@ namespace Microsoft.SqlTools.ServiceLayer.Metadata
|
|||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger.Error("Failed to read scripts from the script cache");
|
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.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -133,42 +133,6 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Metadata
|
|||||||
requestContext.VerifyAll();
|
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<RequestContext<GenerateServerContextualizationResult>>();
|
|
||||||
mockGenerateRequestContext.Setup(x => x.SendResult(It.IsAny<GenerateServerContextualizationResult>()))
|
|
||||||
.Callback<GenerateServerContextualizationResult>(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]
|
[Test]
|
||||||
public async Task VerifyGetServerContextualizationRequest()
|
public async Task VerifyGetServerContextualizationRequest()
|
||||||
{
|
{
|
||||||
@@ -194,28 +158,19 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Metadata
|
|||||||
{
|
{
|
||||||
OwnerUri = connectionResult.ConnectionInfo.OwnerUri
|
OwnerUri = connectionResult.ConnectionInfo.OwnerUri
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// First call generates context, stores it in temp file and returns the generated context
|
||||||
await MetadataService.GetServerContextualization(getServerContextualizationParams, mockGetServerContextualizationRequestContext.Object);
|
await MetadataService.GetServerContextualization(getServerContextualizationParams, mockGetServerContextualizationRequestContext.Object);
|
||||||
|
|
||||||
Assert.IsNull(actualGetServerContextualizationResponse.Context);
|
Assert.IsTrue(actualGetServerContextualizationResponse.Context.Contains(firstCreateTableScript));
|
||||||
Assert.IsNull(actualGetServerContextualizationResponse.Context);
|
Assert.IsTrue(actualGetServerContextualizationResponse.Context.Contains(secondCreateTableScript));
|
||||||
|
|
||||||
var generateServerContextualizationParams = new GenerateServerContextualizationParams
|
// Second call gets the context from the temp file and returns that read file context.
|
||||||
{
|
await MetadataService.GetServerContextualization(getServerContextualizationParams, mockGetServerContextualizationRequestContext.Object);
|
||||||
OwnerUri = connectionResult.ConnectionInfo.OwnerUri
|
|
||||||
};
|
|
||||||
|
|
||||||
var actualGenerateServerContextResponse = new GenerateServerContextualizationResult();
|
|
||||||
var mockGenerateRequestContext = new Mock<RequestContext<GenerateServerContextualizationResult>>();
|
|
||||||
mockGenerateRequestContext.Setup(x => x.SendResult(It.IsAny<GenerateServerContextualizationResult>()))
|
|
||||||
.Callback<GenerateServerContextualizationResult>(actual => actualGenerateServerContextResponse = actual)
|
|
||||||
.Returns(Task.CompletedTask);
|
|
||||||
await MetadataService.GenerateServerContextualization(generateServerContextualizationParams, mockGenerateRequestContext.Object);
|
|
||||||
|
|
||||||
DeleteTestTable(sqlConn, this.testTableSchema, this.testTableName);
|
DeleteTestTable(sqlConn, this.testTableSchema, this.testTableName);
|
||||||
DeleteTestTable(sqlConn, this.testTableSchema, this.testTableName2);
|
DeleteTestTable(sqlConn, this.testTableSchema, this.testTableName2);
|
||||||
|
|
||||||
await MetadataService.GetServerContextualization(getServerContextualizationParams, mockGetServerContextualizationRequestContext.Object);
|
|
||||||
|
|
||||||
Assert.IsTrue(actualGetServerContextualizationResponse.Context.Contains(firstCreateTableScript));
|
Assert.IsTrue(actualGetServerContextualizationResponse.Context.Contains(firstCreateTableScript));
|
||||||
Assert.IsTrue(actualGetServerContextualizationResponse.Context.Contains(secondCreateTableScript));
|
Assert.IsTrue(actualGetServerContextualizationResponse.Context.Contains(secondCreateTableScript));
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user