mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-01-14 01:25:40 -05:00
Clean-up the autocomplete SMO integration.
This commit is contained in:
@@ -22,6 +22,7 @@ using Microsoft.SqlServer.Management.SqlParser.Parser;
|
||||
using Microsoft.SqlTools.ServiceLayer.Connection;
|
||||
using Microsoft.SqlTools.ServiceLayer.Connection.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.LanguageServices;
|
||||
using Microsoft.SqlTools.ServiceLayer.Test.QueryExecution;
|
||||
using Microsoft.SqlTools.ServiceLayer.Test.Utility;
|
||||
using Microsoft.SqlTools.ServiceLayer.Workspace.Contracts;
|
||||
using Microsoft.SqlTools.Test.Utility;
|
||||
@@ -38,91 +39,6 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.LanguageServices
|
||||
{
|
||||
#region "Diagnostics tests"
|
||||
|
||||
|
||||
// [Fact]
|
||||
// public void TestParseWideWorldImporters()
|
||||
// {
|
||||
// var sql = File.ReadAllText(@"e:\data\script.sql");
|
||||
// //string sql = @"SELECT ";
|
||||
// ParseOptions parseOptions = new ParseOptions();
|
||||
// ParseResult parseResult = Parser.IncrementalParse(
|
||||
// sql,
|
||||
// null,
|
||||
// parseOptions);
|
||||
// }
|
||||
|
||||
// [Fact]
|
||||
// public void TestSmo()
|
||||
// {
|
||||
// SqlConnectionStringBuilder connectionBuilder = new SqlConnectionStringBuilder();
|
||||
// connectionBuilder["Data Source"] = "sqltools11";
|
||||
// connectionBuilder["Integrated Security"] = false;
|
||||
// connectionBuilder["User Id"] = "sa";
|
||||
// connectionBuilder["Password"] = "Yukon900";
|
||||
// connectionBuilder["Initial Catalog"] = "master";
|
||||
// string connectionString = connectionBuilder.ToString();
|
||||
|
||||
// var conn = new SqlConnection(connectionString);
|
||||
// var sqlConn = new ServerConnection(conn);
|
||||
|
||||
// var server = new Server(sqlConn);
|
||||
// string s = "";
|
||||
// foreach (Database db2 in server.Databases)
|
||||
// {
|
||||
// s += db2.Name;
|
||||
// }
|
||||
|
||||
// var metadata = SmoMetadataProvider.CreateConnectedProvider(sqlConn);
|
||||
// var db = metadata.Server.Databases["master"];
|
||||
// }
|
||||
|
||||
// [Fact]
|
||||
// public void TestSmoMetadataProvider()
|
||||
// {
|
||||
// SqlConnectionStringBuilder connectionBuilder = new SqlConnectionStringBuilder();
|
||||
// //connectionBuilder["Data Source"] = "sqltools11";
|
||||
// connectionBuilder["Data Source"] = "localhost";
|
||||
// connectionBuilder["Integrated Security"] = false;
|
||||
// connectionBuilder["User Id"] = "sa";
|
||||
// connectionBuilder["Password"] = "Yukon900";
|
||||
// connectionBuilder["Initial Catalog"] = "master";
|
||||
|
||||
// try
|
||||
// {
|
||||
// var sqlConnection = new SqlConnection(connectionBuilder.ToString());
|
||||
// var connection = new ServerConnection(sqlConnection);
|
||||
// var metadataProvider = SmoMetadataProvider.CreateConnectedProvider(connection);
|
||||
// var binder = BinderProvider.CreateBinder(metadataProvider);
|
||||
// var displayInfoProvider = new MetadataDisplayInfoProvider();
|
||||
|
||||
// //string sql = @"SELECT * FROM sys.objects;";
|
||||
|
||||
// string sql = @"SELECT ";
|
||||
|
||||
// ParseOptions parseOptions = new ParseOptions();
|
||||
// ParseResult parseResult = Parser.IncrementalParse(
|
||||
// sql,
|
||||
// null,
|
||||
// parseOptions);
|
||||
|
||||
// List<ParseResult> parseResults = new List<ParseResult>();
|
||||
// parseResults.Add(parseResult);
|
||||
// binder.Bind(parseResults, "master", BindMode.Batch);
|
||||
|
||||
// var comp = Resolver.FindCompletions(parseResult, 1, 8, displayInfoProvider);
|
||||
// comp.Add(null);
|
||||
// }
|
||||
// finally
|
||||
// {
|
||||
// // Check if we failed to create a binder object. If so, we temporarely
|
||||
// // use a no-op binder which has the effect of turning off binding. We
|
||||
// // also set a timer that after the specified timeout expires removes
|
||||
// // the no-op timer (object becomes dead) which would give clients of
|
||||
// // this class an opportunity to remove it and create a new one.
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Verify that the latest SqlParser (2016 as of this writing) is used by default
|
||||
/// </summary>
|
||||
@@ -234,6 +150,29 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.LanguageServices
|
||||
|
||||
#region "Autocomplete Tests"
|
||||
|
||||
// This test currently requires a live database connection to initialize
|
||||
// SMO connected metadata provider. Since we don't want a live DB dependency
|
||||
// in the CI unit tests this scenario is currently disabled.
|
||||
//[Fact]
|
||||
public void AutoCompleteFindCompletions()
|
||||
{
|
||||
TextDocumentPosition textDocument;
|
||||
ConnectionInfo connInfo;
|
||||
ScriptFile scriptFile;
|
||||
Common.GetAutoCompleteTestObjects(out textDocument, out scriptFile, out connInfo);
|
||||
|
||||
textDocument.Position.Character = 7;
|
||||
scriptFile.Contents = "select ";
|
||||
|
||||
var autoCompleteService = AutoCompleteService.Instance;
|
||||
var completions = autoCompleteService.GetCompletionItems(
|
||||
textDocument,
|
||||
scriptFile,
|
||||
connInfo);
|
||||
|
||||
Assert.True(completions.Length > 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a mock db command that returns a predefined result set
|
||||
/// </summary>
|
||||
@@ -261,166 +200,6 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.LanguageServices
|
||||
return connectionMock.Object;
|
||||
}
|
||||
|
||||
#if false
|
||||
/// <summary>
|
||||
/// Verify that the autocomplete service returns tables for the current connection as suggestions
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void TablesAreReturnedAsAutocompleteSuggestions()
|
||||
{
|
||||
// Result set for the query of database tables
|
||||
Dictionary<string, string>[] data =
|
||||
{
|
||||
new Dictionary<string, string> { {"name", "master" } },
|
||||
new Dictionary<string, string> { {"name", "model" } }
|
||||
};
|
||||
|
||||
var mockFactory = new Mock<ISqlConnectionFactory>();
|
||||
mockFactory.Setup(factory => factory.CreateSqlConnection(It.IsAny<string>()))
|
||||
.Returns(CreateMockDbConnection(new[] {data}));
|
||||
|
||||
var connectionService = new ConnectionService(mockFactory.Object);
|
||||
var autocompleteService = new AutoCompleteService();
|
||||
autocompleteService.ConnectionServiceInstance = connectionService;
|
||||
autocompleteService.InitializeService(Microsoft.SqlTools.ServiceLayer.Hosting.ServiceHost.Instance);
|
||||
|
||||
// Open a connection
|
||||
// The cache should get updated as part of this
|
||||
ConnectParams connectionRequest = TestObjects.GetTestConnectionParams();
|
||||
var connectionResult = connectionService.Connect(connectionRequest);
|
||||
Assert.NotEmpty(connectionResult.ConnectionId);
|
||||
|
||||
// Check that there is one cache created in the auto complete service
|
||||
Assert.Equal(1, autocompleteService.GetCacheCount());
|
||||
|
||||
// Check that we get table suggestions for an autocomplete request
|
||||
TextDocumentPosition position = new TextDocumentPosition();
|
||||
position.TextDocument = new TextDocumentIdentifier();
|
||||
position.TextDocument.Uri = connectionRequest.OwnerUri;
|
||||
position.Position = new Position();
|
||||
position.Position.Line = 1;
|
||||
position.Position.Character = 1;
|
||||
var items = autocompleteService.GetCompletionItems(position);
|
||||
Assert.Equal(2, items.Length);
|
||||
Assert.Equal("master", items[0].Label);
|
||||
Assert.Equal("model", items[1].Label);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Verify that only one intellisense cache is created for two documents using
|
||||
/// the autocomplete service when they share a common connection.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void OnlyOneCacheIsCreatedForTwoDocumentsWithSameConnection()
|
||||
{
|
||||
var connectionService = new ConnectionService(TestObjects.GetTestSqlConnectionFactory());
|
||||
var autocompleteService = new AutoCompleteService();
|
||||
autocompleteService.ConnectionServiceInstance = connectionService;
|
||||
autocompleteService.InitializeService(Microsoft.SqlTools.ServiceLayer.Hosting.ServiceHost.Instance);
|
||||
|
||||
// Open two connections
|
||||
ConnectParams connectionRequest1 = TestObjects.GetTestConnectionParams();
|
||||
connectionRequest1.OwnerUri = "file:///my/first/file.sql";
|
||||
ConnectParams connectionRequest2 = TestObjects.GetTestConnectionParams();
|
||||
connectionRequest2.OwnerUri = "file:///my/second/file.sql";
|
||||
var connectionResult1 = connectionService.Connect(connectionRequest1);
|
||||
Assert.NotEmpty(connectionResult1.ConnectionId);
|
||||
var connectionResult2 = connectionService.Connect(connectionRequest2);
|
||||
Assert.NotEmpty(connectionResult2.ConnectionId);
|
||||
|
||||
// Verify that only one intellisense cache is created to service both URI's
|
||||
Assert.Equal(1, autocompleteService.GetCacheCount());
|
||||
}
|
||||
|
||||
#if false
|
||||
/// <summary>
|
||||
/// Verify that two different intellisense caches and corresponding autocomplete
|
||||
/// suggestions are provided for two documents with different connections.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void TwoCachesAreCreatedForTwoDocumentsWithDifferentConnections()
|
||||
{
|
||||
const string testDb1 = "my_db";
|
||||
const string testDb2 = "my_other_db";
|
||||
|
||||
// Result set for the query of database tables
|
||||
Dictionary<string, string>[] data1 =
|
||||
{
|
||||
new Dictionary<string, string> { {"name", "master" } },
|
||||
new Dictionary<string, string> { {"name", "model" } }
|
||||
};
|
||||
|
||||
Dictionary<string, string>[] data2 =
|
||||
{
|
||||
new Dictionary<string, string> { {"name", "master" } },
|
||||
new Dictionary<string, string> { {"name", "my_table" } },
|
||||
new Dictionary<string, string> { {"name", "my_other_table" } }
|
||||
};
|
||||
|
||||
var mockFactory = new Mock<ISqlConnectionFactory>();
|
||||
mockFactory.Setup(factory => factory.CreateSqlConnection(It.Is<string>(x => x.Contains(testDb1))))
|
||||
.Returns(CreateMockDbConnection(new[] {data1}));
|
||||
mockFactory.Setup(factory => factory.CreateSqlConnection(It.Is<string>(x => x.Contains(testDb2))))
|
||||
.Returns(CreateMockDbConnection(new[] {data2}));
|
||||
|
||||
var connectionService = new ConnectionService(mockFactory.Object);
|
||||
var autocompleteService = new AutoCompleteService();
|
||||
autocompleteService.ConnectionServiceInstance = connectionService;
|
||||
autocompleteService.InitializeService(Microsoft.SqlTools.ServiceLayer.Hosting.ServiceHost.Instance);
|
||||
|
||||
// Open connections
|
||||
// The cache should get updated as part of this
|
||||
ConnectParams connectionRequest = TestObjects.GetTestConnectionParams();
|
||||
connectionRequest.OwnerUri = "file:///my/first/sql/file.sql";
|
||||
connectionRequest.Connection.DatabaseName = testDb1;
|
||||
var connectionResult = connectionService.Connect(connectionRequest);
|
||||
Assert.NotEmpty(connectionResult.ConnectionId);
|
||||
|
||||
// Check that there is one cache created in the auto complete service
|
||||
Assert.Equal(1, autocompleteService.GetCacheCount());
|
||||
|
||||
// Open second connection
|
||||
ConnectParams connectionRequest2 = TestObjects.GetTestConnectionParams();
|
||||
connectionRequest2.OwnerUri = "file:///my/second/sql/file.sql";
|
||||
connectionRequest2.Connection.DatabaseName = testDb2;
|
||||
var connectionResult2 = connectionService.Connect(connectionRequest2);
|
||||
Assert.NotEmpty(connectionResult2.ConnectionId);
|
||||
|
||||
// Check that there are now two caches in the auto complete service
|
||||
Assert.Equal(2, autocompleteService.GetCacheCount());
|
||||
|
||||
// Check that we get 2 different table suggestions for autocomplete requests
|
||||
TextDocumentPosition position = new TextDocumentPosition();
|
||||
position.TextDocument = new TextDocumentIdentifier();
|
||||
position.TextDocument.Uri = connectionRequest.OwnerUri;
|
||||
position.Position = new Position();
|
||||
position.Position.Line = 1;
|
||||
position.Position.Character = 1;
|
||||
|
||||
var items = autocompleteService.GetCompletionItems(position);
|
||||
Assert.Equal(2, items.Length);
|
||||
Assert.Equal("master", items[0].Label);
|
||||
Assert.Equal("model", items[1].Label);
|
||||
|
||||
TextDocumentPosition position2 = new TextDocumentPosition();
|
||||
position2.TextDocument = new TextDocumentIdentifier();
|
||||
position2.TextDocument.Uri = connectionRequest2.OwnerUri;
|
||||
position2.Position = new Position();
|
||||
position2.Position.Line = 1;
|
||||
position2.Position.Character = 1;
|
||||
|
||||
var items2 = autocompleteService.GetCompletionItems(position2);
|
||||
Assert.Equal(3, items2.Length);
|
||||
Assert.Equal("master", items2[0].Label);
|
||||
Assert.Equal("my_table", items2[1].Label);
|
||||
Assert.Equal("my_other_table", items2[2].Label);
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -9,14 +9,19 @@ using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SqlServer.Management.SmoMetadataProvider;
|
||||
using Microsoft.SqlServer.Management.SqlParser.Binder;
|
||||
using Microsoft.SqlServer.Management.SqlParser.MetadataProvider;
|
||||
using Microsoft.SqlTools.ServiceLayer.Connection;
|
||||
using Microsoft.SqlTools.ServiceLayer.Connection.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol;
|
||||
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.LanguageServices;
|
||||
using Microsoft.SqlTools.ServiceLayer.QueryExecution;
|
||||
using Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.SqlContext;
|
||||
using Microsoft.SqlTools.ServiceLayer.Test.Utility;
|
||||
using Microsoft.SqlTools.ServiceLayer.Workspace.Contracts;
|
||||
using Moq;
|
||||
using Moq.Protected;
|
||||
|
||||
@@ -36,6 +41,16 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
|
||||
|
||||
public const int StandardColumns = 5;
|
||||
|
||||
public static string TestServer { get; set; }
|
||||
|
||||
public static string TestDatabase { get; set; }
|
||||
|
||||
static Common()
|
||||
{
|
||||
TestServer = "sqltools11";
|
||||
TestDatabase = "master";
|
||||
}
|
||||
|
||||
public static Dictionary<string, string>[] StandardTestData
|
||||
{
|
||||
get { return GetTestData(StandardRows, StandardColumns); }
|
||||
@@ -122,8 +137,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
|
||||
{
|
||||
UserName = "sa",
|
||||
Password = "Yukon900",
|
||||
DatabaseName = "AdventureWorks2016CTP3_2",
|
||||
ServerName = "sqltools11"
|
||||
DatabaseName = Common.TestDatabase,
|
||||
ServerName = Common.TestServer
|
||||
};
|
||||
|
||||
return new ConnectionInfo(CreateMockFactory(data, throwOnRead), OwnerUri, connDetails);
|
||||
@@ -133,6 +148,37 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
|
||||
|
||||
#region Service Mocking
|
||||
|
||||
public static void GetAutoCompleteTestObjects(
|
||||
out TextDocumentPosition textDocument,
|
||||
out ScriptFile scriptFile,
|
||||
out ConnectionInfo connInfo
|
||||
)
|
||||
{
|
||||
textDocument = new TextDocumentPosition();
|
||||
textDocument.TextDocument = new TextDocumentIdentifier();
|
||||
textDocument.TextDocument.Uri = Common.OwnerUri;
|
||||
textDocument.Position = new Position();
|
||||
textDocument.Position.Line = 0;
|
||||
textDocument.Position.Character = 0;
|
||||
|
||||
connInfo = Common.CreateTestConnectionInfo(null, false);
|
||||
var srvConn = ConnectionService.GetServerConnection(connInfo);
|
||||
var displayInfoProvider = new MetadataDisplayInfoProvider();
|
||||
var metadataProvider = SmoMetadataProvider.CreateConnectedProvider(srvConn);
|
||||
var binder = BinderProvider.CreateBinder(metadataProvider);
|
||||
|
||||
LanguageService.Instance.ScriptParseInfoMap.Add(textDocument.TextDocument.Uri,
|
||||
new ScriptParseInfo()
|
||||
{
|
||||
Binder = binder,
|
||||
MetadataProvider = metadataProvider,
|
||||
MetadataDisplayInfoProvider = displayInfoProvider
|
||||
});
|
||||
|
||||
scriptFile = new ScriptFile();
|
||||
scriptFile.ClientFilePath = textDocument.TextDocument.Uri;
|
||||
}
|
||||
|
||||
public static ConnectionDetails GetTestConnectionDetails()
|
||||
{
|
||||
return new ConnectionDetails
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"System.Runtime.Serialization.Primitives": "4.1.1",
|
||||
"System.Data.Common": "4.1.0",
|
||||
"System.Data.SqlClient": "4.1.0",
|
||||
"Microsoft.SqlServer.Smo": "140.1.2",
|
||||
"Microsoft.SqlServer.Smo": "140.1.5",
|
||||
"System.Security.SecureString": "4.0.0",
|
||||
"System.Collections.Specialized": "4.0.1",
|
||||
"System.ComponentModel.TypeConverter": "4.1.0",
|
||||
|
||||
Reference in New Issue
Block a user