mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-01-14 01:25:40 -05:00
Adding star expression expansion (#1270)
This commit is contained in:
@@ -25,6 +25,7 @@
|
||||
<PackageReference Update="Microsoft.Azure.Kusto.Language" Version="9.0.4"/>
|
||||
<PackageReference Update="Microsoft.SqlServer.Assessment" Version="[1.0.305]" />
|
||||
<PackageReference Update="Microsoft.SqlServer.Migration.Assessment" Version="1.0.20210902.7" />
|
||||
<PackageReference Update="Microsoft.SqlServer.Management.SqlParser" Version="160.21267.55" />
|
||||
<PackageReference Update="Microsoft.Azure.OperationalInsights" Version="1.0.0" />
|
||||
<PackageReference Update="Microsoft.CodeAnalysis.CSharp" Version="3.10.0" />
|
||||
<PackageReference Update="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="3.10.0" />
|
||||
|
||||
@@ -9,11 +9,15 @@ using System.Linq;
|
||||
using System.Threading;
|
||||
using Microsoft.SqlServer.Management.SqlParser.Binder;
|
||||
using Microsoft.SqlServer.Management.SqlParser.Intellisense;
|
||||
using Microsoft.SqlServer.Management.SqlParser.Metadata;
|
||||
using Microsoft.SqlServer.Management.SqlParser.MetadataProvider;
|
||||
using Microsoft.SqlServer.Management.SqlParser.Parser;
|
||||
using Microsoft.SqlServer.Management.SqlParser.SqlCodeDom;
|
||||
using Microsoft.SqlTools.ServiceLayer.Connection;
|
||||
using Microsoft.SqlTools.ServiceLayer.LanguageServices.Completion;
|
||||
using Microsoft.SqlTools.ServiceLayer.LanguageServices.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.SqlContext;
|
||||
using Microsoft.SqlTools.ServiceLayer.Management;
|
||||
using Microsoft.SqlTools.Utility;
|
||||
using Microsoft.SqlTools.ServiceLayer.Workspace;
|
||||
using Microsoft.SqlTools.ServiceLayer.Workspace.Contracts;
|
||||
@@ -728,5 +732,131 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
|
||||
return help;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Give suggestions for sql star expansion.
|
||||
/// </summary>
|
||||
/// <param name="scriptDocumentInfo">Document info containing the current cursor position</param>
|
||||
/// <returns>Completion item array containing the expanded star suggestion</returns>
|
||||
public static CompletionItem[] ExpandSqlStarExpression(ScriptDocumentInfo scriptDocumentInfo)
|
||||
{
|
||||
//Fetching the star expression node in sql script.
|
||||
SqlSelectStarExpression selectStarExpression = AutoCompleteHelper.TryGetSelectStarStatement(scriptDocumentInfo.ScriptParseInfo.ParseResult.Script, scriptDocumentInfo);
|
||||
if (selectStarExpression == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Getting SQL object identifier for star expressions like a.*
|
||||
SqlObjectIdentifier starObjectIdentifier = null;
|
||||
if (selectStarExpression.Children.Any())
|
||||
{
|
||||
starObjectIdentifier = (SqlObjectIdentifier)selectStarExpression.Children.ElementAt(0);
|
||||
}
|
||||
|
||||
List<ITabular> boundedTableList = selectStarExpression.BoundTables.ToList();
|
||||
|
||||
IList<string> columnNames = new List<string>();
|
||||
|
||||
/*
|
||||
We include table names in 2 conditions.
|
||||
1. When there are multiple tables to avoid column ambiguity
|
||||
2. When there is single table with an alias
|
||||
*/
|
||||
bool includeTableName = boundedTableList.Count > 1 || (boundedTableList.Count == 1 && boundedTableList[0] != boundedTableList[0].Unaliased);
|
||||
|
||||
// Handing case for object identifiers where the column names will contain the identifier for eg: a.* becomes a.column_name
|
||||
if (starObjectIdentifier != null)
|
||||
{
|
||||
string objectIdentifierName = starObjectIdentifier.ObjectName.ToString();
|
||||
ITabular relatedTable = boundedTableList.Single(t => t.Name == objectIdentifierName);
|
||||
columnNames = relatedTable.Columns.Select(c => String.Format("{0}.{1}", Utils.MakeSqlBracket(objectIdentifierName), Utils.MakeSqlBracket(c.Name))).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var table in boundedTableList)
|
||||
{
|
||||
foreach (var column in table.Columns)
|
||||
{
|
||||
if (includeTableName)
|
||||
{
|
||||
columnNames.Add($"{Utils.MakeSqlBracket(table.Name)}.{Utils.MakeSqlBracket(column.Name)}"); // Including table names in case of multiple tables to avoid column ambiguity errors.
|
||||
}
|
||||
else
|
||||
{
|
||||
columnNames.Add(Utils.MakeSqlBracket(column.Name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (columnNames == null || columnNames.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var insertText = String.Join(String.Format(",{0}", Environment.NewLine), columnNames.ToArray()); // Adding a new line after every column name
|
||||
var completionItems = new CompletionItem[] {
|
||||
new CompletionItem
|
||||
{
|
||||
InsertText = insertText,
|
||||
Label = insertText,
|
||||
Detail = insertText,
|
||||
Kind = CompletionItemKind.Text,
|
||||
/*
|
||||
Vscode/ADS only shows completion items that match the text present in the editor. However, in case of star expansion that is never going to happen as columns names are different than '*'.
|
||||
Therefore adding an explicit filterText that contains the original star expression to trick vscode/ADS into showing this suggestion item.
|
||||
*/
|
||||
FilterText = selectStarExpression.Sql,
|
||||
Preselect = true,
|
||||
TextEdit = new TextEdit {
|
||||
NewText = insertText,
|
||||
Range = new Range {
|
||||
Start = new Position{
|
||||
Line = scriptDocumentInfo.StartLine,
|
||||
Character = selectStarExpression.StartLocation.ColumnNumber - 1
|
||||
},
|
||||
End = new Position {
|
||||
Line = scriptDocumentInfo.StartLine,
|
||||
Character = selectStarExpression.EndLocation.ColumnNumber - 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
return completionItems;
|
||||
}
|
||||
|
||||
public static SqlSelectStarExpression TryGetSelectStarStatement(SqlCodeObject currentNode, ScriptDocumentInfo scriptDocumentInfo)
|
||||
{
|
||||
if(currentNode == null || scriptDocumentInfo == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Checking if the current node is a sql select star expression.
|
||||
if (currentNode is SqlSelectStarExpression)
|
||||
{
|
||||
return currentNode as SqlSelectStarExpression;
|
||||
}
|
||||
|
||||
// Visiting children to get the the sql select star expression.
|
||||
foreach (SqlCodeObject child in currentNode.Children)
|
||||
{
|
||||
// Visiting only those children where the cursor is present.
|
||||
int childStartLineNumber = child.StartLocation.LineNumber - 1;
|
||||
int childEndLineNumber = child.EndLocation.LineNumber - 1;
|
||||
SqlSelectStarExpression childStarExpression = TryGetSelectStarStatement(child, scriptDocumentInfo);
|
||||
if ((childStartLineNumber < scriptDocumentInfo.StartLine ||
|
||||
childStartLineNumber == scriptDocumentInfo.StartLine && child.StartLocation.ColumnNumber <= scriptDocumentInfo.StartColumn) &&
|
||||
(childEndLineNumber > scriptDocumentInfo.StartLine ||
|
||||
childEndLineNumber == scriptDocumentInfo.StartLine && child.EndLocation.ColumnNumber >= scriptDocumentInfo.EndColumn) &&
|
||||
childStarExpression != null)
|
||||
{
|
||||
return childStarExpression;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
/// Main class for Language Service functionality including anything that requires knowledge of
|
||||
/// the language to perform, such as definitions, intellisense, etc.
|
||||
/// </summary>
|
||||
public class LanguageService: IDisposable
|
||||
public class LanguageService : IDisposable
|
||||
{
|
||||
#region Singleton Instance Implementation
|
||||
|
||||
@@ -193,7 +193,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
{
|
||||
if (workspaceServiceInstance == null)
|
||||
{
|
||||
workspaceServiceInstance = WorkspaceService<SqlToolsSettings>.Instance;
|
||||
workspaceServiceInstance = WorkspaceService<SqlToolsSettings>.Instance;
|
||||
}
|
||||
return workspaceServiceInstance;
|
||||
}
|
||||
@@ -407,7 +407,8 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
if (result != null && result.Errors.Count() == 0)
|
||||
{
|
||||
syntaxResult.Parseable = true;
|
||||
} else
|
||||
}
|
||||
else
|
||||
{
|
||||
syntaxResult.Parseable = false;
|
||||
string[] errorMessages = new string[result.Errors.Count()];
|
||||
@@ -558,7 +559,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
};
|
||||
}
|
||||
|
||||
// turn off this code until needed (10/28/2016)
|
||||
// turn off this code until needed (10/28/2016)
|
||||
#if false
|
||||
private async Task HandleReferencesRequest(
|
||||
ReferencesParams referencesParams,
|
||||
@@ -796,19 +797,19 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
}
|
||||
|
||||
// Send a notification to signal that autocomplete is ready
|
||||
ServiceHostInstance.SendEvent(IntelliSenseReadyNotification.Type, new IntelliSenseReadyParams() {OwnerUri = connInfo.OwnerUri});
|
||||
ServiceHostInstance.SendEvent(IntelliSenseReadyNotification.Type, new IntelliSenseReadyParams() { OwnerUri = connInfo.OwnerUri });
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
// Send a notification to signal that autocomplete is ready
|
||||
await ServiceHostInstance.SendEvent(IntelliSenseReadyNotification.Type, new IntelliSenseReadyParams() {OwnerUri = rebuildParams.OwnerUri});
|
||||
await ServiceHostInstance.SendEvent(IntelliSenseReadyNotification.Type, new IntelliSenseReadyParams() { OwnerUri = rebuildParams.OwnerUri });
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(TraceEventType.Error, "Unknown error " + ex.ToString());
|
||||
await ServiceHostInstance.SendEvent(IntelliSenseReadyNotification.Type, new IntelliSenseReadyParams() {OwnerUri = rebuildParams.OwnerUri});
|
||||
await ServiceHostInstance.SendEvent(IntelliSenseReadyNotification.Type, new IntelliSenseReadyParams() { OwnerUri = rebuildParams.OwnerUri });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -873,14 +874,16 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
Validate.IsNotNull(nameof(changeParams), changeParams);
|
||||
Validate.IsNotNull(nameof(changeParams), changeParams.Uri);
|
||||
bool shouldBlock = false;
|
||||
if (SQL_LANG.Equals(changeParams.Language, StringComparison.OrdinalIgnoreCase)) {
|
||||
if (SQL_LANG.Equals(changeParams.Language, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
shouldBlock = !ServiceHost.ProviderName.Equals(changeParams.Flavor, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
if (SQL_CMD_LANG.Equals(changeParams.Language, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
shouldBlock = true; // the provider will continue to be mssql
|
||||
}
|
||||
if (shouldBlock) {
|
||||
if (shouldBlock)
|
||||
{
|
||||
this.nonMssqlUriMap.AddOrUpdate(changeParams.Uri, true, (k, oldValue) => true);
|
||||
if (CurrentWorkspace.ContainsFile(changeParams.Uri))
|
||||
{
|
||||
@@ -893,8 +896,8 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
this.nonMssqlUriMap.TryRemove(changeParams.Uri, out value);
|
||||
// should rebuild intellisense when re-considering as sql
|
||||
RebuildIntelliSenseParams param = new RebuildIntelliSenseParams { OwnerUri = changeParams.Uri };
|
||||
await HandleRebuildIntelliSenseNotification(param, eventContext);
|
||||
}
|
||||
await HandleRebuildIntelliSenseNotification(param, eventContext);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -939,27 +942,27 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
{
|
||||
if (connInfo == null || !parseInfo.IsConnected)
|
||||
{
|
||||
// parse on separate thread so stack size can be increased
|
||||
var parseThread = new Thread(() =>
|
||||
// parse on separate thread so stack size can be increased
|
||||
var parseThread = new Thread(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
// parse current SQL file contents to retrieve a list of errors
|
||||
ParseResult parseResult = Parser.IncrementalParse(
|
||||
scriptFile.Contents,
|
||||
parseInfo.ParseResult,
|
||||
this.DefaultParseOptions);
|
||||
scriptFile.Contents,
|
||||
parseInfo.ParseResult,
|
||||
this.DefaultParseOptions);
|
||||
|
||||
parseInfo.ParseResult = parseResult;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
parseInfo.ParseResult = parseResult;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// Log the exception but don't rethrow it to prevent parsing errors from crashing SQL Tools Service
|
||||
Logger.Write(TraceEventType.Error, string.Format("An unexpected error occured while parsing: {0}", e.ToString()));
|
||||
}
|
||||
}, ConnectedBindingQueue.QueueThreadStackSize);
|
||||
parseThread.Start();
|
||||
parseThread.Join();
|
||||
}
|
||||
}, ConnectedBindingQueue.QueueThreadStackSize);
|
||||
parseThread.Start();
|
||||
parseThread.Join();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1003,7 +1006,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
return null;
|
||||
});
|
||||
|
||||
queueItem.ItemProcessed.WaitOne();
|
||||
queueItem.ItemProcessed.WaitOne();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -1019,7 +1022,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Write(TraceEventType.Warning, "Binding metadata lock timeout in ParseAndBind");
|
||||
Logger.Write(TraceEventType.Warning, "Binding metadata lock timeout in ParseAndBind");
|
||||
}
|
||||
|
||||
return parseInfo.ParseResult;
|
||||
@@ -1062,7 +1065,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
PrepopulateCommonMetadata(info, scriptInfo, this.BindingQueue);
|
||||
|
||||
// Send a notification to signal that autocomplete is ready
|
||||
ServiceHostInstance.SendEvent(IntelliSenseReadyNotification.Type, new IntelliSenseReadyParams() {OwnerUri = info.OwnerUri});
|
||||
ServiceHostInstance.SendEvent(IntelliSenseReadyNotification.Type, new IntelliSenseReadyParams() { OwnerUri = info.OwnerUri });
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1249,7 +1252,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
}
|
||||
finally
|
||||
{
|
||||
Monitor.Exit(scriptParseInfo.BuildingMetadataLock);
|
||||
Monitor.Exit(scriptParseInfo.BuildingMetadataLock);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1656,6 +1659,13 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
this.currentCompletionParseInfo = scriptParseInfo;
|
||||
resultCompletionItems = result.CompletionItems;
|
||||
|
||||
// Expanding star expressions in query
|
||||
CompletionItem[] starExpansionSuggestion = AutoCompleteHelper.ExpandSqlStarExpression(scriptDocumentInfo);
|
||||
if (starExpansionSuggestion != null)
|
||||
{
|
||||
return starExpansionSuggestion;
|
||||
}
|
||||
|
||||
// if there are no completions then provide the default list
|
||||
if (resultCompletionItems == null)
|
||||
{
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
<PackageReference Include="System.Text.Encoding.CodePages" />
|
||||
<PackageReference Include="Microsoft.SqlServer.Assessment" />
|
||||
<PackageReference Include="Microsoft.SqlServer.Migration.Assessment" />
|
||||
<PackageReference Include="Microsoft.SqlServer.Management.SqlParser"/>
|
||||
<PackageReference Include="System.Text.Encoding.CodePages" />
|
||||
<PackageReference Include="Microsoft.SqlServer.TransactSql.ScriptDom.NRT">
|
||||
<Aliases>ASAScriptDom</Aliases>
|
||||
|
||||
@@ -401,5 +401,64 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServer
|
||||
Assert.True(notif.Diagnostics.Length == errors, $"Notification errors {notif.Diagnostics.Length} are not as expected {errors}");
|
||||
return true;
|
||||
}
|
||||
|
||||
[Test]
|
||||
//simple select star with single column in the table
|
||||
[TestCase("select * from wildcard_test_table", 0, 8, "CREATE TABLE wildcard_test_table(col1 int)", "[col1]")]
|
||||
//simple select star with multiple columns in the table
|
||||
[TestCase("select * from wildcard_test_table", 0, 8, "CREATE TABLE wildcard_test_table(col1 int, col2 int, \"col3\" int)", "[col1],\r\n[col2],\r\n[col3]")]
|
||||
//select star query with special characters in the table
|
||||
[TestCase("select * from wildcard_test_table", 0, 8, "CREATE TABLE wildcard_test_table(\"col[$$$#]\" int)", "[col[$$$#]]]")]
|
||||
//select star query for multiple tables
|
||||
[TestCase("select * from wildcard_test_table1 CROSS JOIN wildcard_test_table2", 0, 8, "CREATE TABLE wildcard_test_table1(table1col1 int); CREATE TABLE wildcard_test_table2(table2col1 int)", "[wildcard_test_table1].[table1col1],\r\n[wildcard_test_table2].[table2col1]")]
|
||||
//select star query with object identifier in associated with * eg: a.*
|
||||
[TestCase("select *, a.* from wildcard_test_table1 as a CROSS JOIN wildcard_test_table2", 0, 13, "CREATE TABLE wildcard_test_table1(table1col1 int); CREATE TABLE wildcard_test_table2(table2col1 int)", "[a].[table1col1]")]
|
||||
//select star query with nested from statement
|
||||
[TestCase("select * from (select col2 from wildcard_test_table1) as alias", 0, 8, "CREATE TABLE wildcard_test_table1(col1 int, col2 int)", "[col2]")]
|
||||
public async Task ExpandSqlStarExpressionsTest(string sqlStarQuery, int cursorLine, int cursorColumn, string createTableQueries, string expectedStarExpansionInsertText)
|
||||
{
|
||||
var testDb = SqlTestDb.CreateNew(TestServerType.OnPrem, false, null, null, "WildCardExpansionTest");
|
||||
try
|
||||
{
|
||||
var connectionInfoResult = LiveConnectionHelper.InitLiveConnectionInfo(testDb.DatabaseName);
|
||||
|
||||
var langService = LanguageService.Instance;
|
||||
await langService.UpdateLanguageServiceOnConnection(connectionInfoResult.ConnectionInfo);
|
||||
connectionInfoResult.ScriptFile.SetFileContents(sqlStarQuery);
|
||||
|
||||
var textDocumentPosition =
|
||||
connectionInfoResult.TextDocumentPosition ??
|
||||
new TextDocumentPosition()
|
||||
{
|
||||
TextDocument = new TextDocumentIdentifier
|
||||
{
|
||||
Uri = connectionInfoResult.ScriptFile.ClientUri
|
||||
},
|
||||
Position = new Position
|
||||
{
|
||||
Line = cursorLine,
|
||||
Character = cursorColumn //Position of the star expression
|
||||
}
|
||||
};
|
||||
|
||||
// Now create tables that should show up in the completion list
|
||||
testDb.RunQuery(createTableQueries);
|
||||
|
||||
// And refresh the cache
|
||||
await langService.HandleRebuildIntelliSenseNotification(
|
||||
new RebuildIntelliSenseParams() { OwnerUri = connectionInfoResult.ScriptFile.ClientUri },
|
||||
new TestEventContext());
|
||||
|
||||
// Now we should expect to see the star expansion show up in the completion list
|
||||
var starExpansionCompletionItem = await langService.GetCompletionItems(
|
||||
textDocumentPosition, connectionInfoResult.ScriptFile, connectionInfoResult.ConnectionInfo);
|
||||
|
||||
Assert.AreEqual(expectedStarExpansionInsertText, starExpansionCompletionItem[0].InsertText, "Star expansion not found");
|
||||
}
|
||||
finally
|
||||
{
|
||||
testDb.Cleanup();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,8 +5,10 @@
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SqlServer.Management.SqlParser.Parser;
|
||||
using Microsoft.SqlServer.Management.SqlParser.SqlCodeDom;
|
||||
using Microsoft.SqlTools.Hosting.Protocol;
|
||||
using Microsoft.SqlTools.ServiceLayer.LanguageServices;
|
||||
using Microsoft.SqlTools.ServiceLayer.LanguageServices.Completion;
|
||||
using Microsoft.SqlTools.ServiceLayer.LanguageServices.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.Workspace.Contracts;
|
||||
using Moq;
|
||||
@@ -186,5 +188,81 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.LanguageServer
|
||||
// verify that send result was called with a completion array
|
||||
requestContext.Verify(m => m.SendResult(It.IsAny<CompletionItem[]>()), Times.Once());
|
||||
}
|
||||
|
||||
public ScriptDocumentInfo CreateSqlStarTestFile(string sqlText, int startLine, int startColumn)
|
||||
{
|
||||
var uri = "file://nofile.sql";
|
||||
|
||||
var textDocumentPosition = new TextDocumentPosition()
|
||||
{
|
||||
TextDocument = new TextDocumentIdentifier()
|
||||
{
|
||||
Uri = uri
|
||||
},
|
||||
Position = new Position()
|
||||
{
|
||||
Line = startLine,
|
||||
Character = startColumn
|
||||
}
|
||||
};
|
||||
|
||||
var scriptFile = new ScriptFile()
|
||||
{
|
||||
ClientUri = uri,
|
||||
Contents = sqlText
|
||||
};
|
||||
|
||||
|
||||
ParseResult parseResult = langService.ParseAndBind(scriptFile, null);
|
||||
ScriptParseInfo scriptParseInfo = langService.GetScriptParseInfo(scriptFile.ClientUri, true);
|
||||
|
||||
return new ScriptDocumentInfo(textDocumentPosition, scriptFile, scriptParseInfo);
|
||||
}
|
||||
|
||||
[Test]
|
||||
//complete select query with the cursor at * should return a sqlselectstarexpression object.
|
||||
[TestCase("select * from sys.all_objects", 0, 8, "SelectStarExpression is not returned on complete select query with star")]
|
||||
//incomplete select query with the cursor at * should sqlselectstarexpression
|
||||
[TestCase("select * ", 0, 8, "SelectStarExpression is returned on an incomplete select query with star")]
|
||||
//method should return sqlselectstarexpression on *s with object identifiers.
|
||||
[TestCase("select a.* from sys.all_objects as a", 0, 10, "SelectStarExpression returned on star expression with object identifier")]
|
||||
public void TryGetSqlSelectStarStatementNotNullTests(string sqlQuery, int cursorLine, int cursorColumn, string errorValidationMessage)
|
||||
{
|
||||
InitializeTestObjects();
|
||||
var testFile = CreateSqlStarTestFile(sqlQuery, cursorLine, cursorColumn);
|
||||
Assert.NotNull(AutoCompleteHelper.TryGetSelectStarStatement(testFile.ScriptParseInfo.ParseResult.Script, testFile), errorValidationMessage);
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
//complete select query with the cursor not at * should return null.
|
||||
[TestCase("select * from sys.all_objects", 0, 0, "null is not returned when the cursor is not at a star expression")]
|
||||
//file with no text should return null
|
||||
[TestCase("", 0, 0, "null is not returned on file with empty sql text")]
|
||||
//file with out of bounds cursor position should return null
|
||||
[TestCase("select * from sys.all_objects", 0, 100, "null is not returned when the cursor is out of bounds.")]
|
||||
public void TryGetSqlSelectStarStatementNullTests(string sqlQuery, int cursorLine, int cursorColumn, string errorValidationMessage)
|
||||
{
|
||||
InitializeTestObjects();
|
||||
var testFile = CreateSqlStarTestFile(sqlQuery, cursorLine, cursorColumn);
|
||||
Assert.Null(AutoCompleteHelper.TryGetSelectStarStatement(testFile.ScriptParseInfo.ParseResult.Script, testFile), errorValidationMessage);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TryGetSqlSelectStarStatementNullFileTest()
|
||||
{
|
||||
Assert.Null(AutoCompleteHelper.TryGetSelectStarStatement(null, null), "null is not returned on null file");
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase("select a.*, * from sys.all_objects as a CROSS JOIN sys.databases", 0, 10, "a.*")]
|
||||
[TestCase("select a.*, * from sys.all_objects as a CROSS JOIN sys.databases", 0, 13, "*")]
|
||||
public void TryGetSqlSelectStarStatmentMulitpleStarExpressionsTest(string sqlQuery, int cursorLine, int cursorColumn, string expectedStarExpressionSqlText)
|
||||
{
|
||||
InitializeTestObjects();
|
||||
var testFile = CreateSqlStarTestFile(sqlQuery, cursorLine, cursorColumn);
|
||||
var starExpressionTest = AutoCompleteHelper.TryGetSelectStarStatement(testFile.ScriptParseInfo.ParseResult.Script, testFile).Sql;
|
||||
Assert.AreEqual(expectedStarExpressionSqlText, expectedStarExpressionSqlText, string.Format("correct SelectStarExpression is not returned."));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user