mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-02-09 09:42:35 -05:00
Feature/peek def code gen (#215)
* Add codeGen for existing types * Modify code gen logic to match current code * Extend logic for new smo objects * Add logic to retrieve token type from QuickInfo * Remove duplicate types * Add tests for new types * Modify GetScript logic to use suggestions first * Add more tests * Modify codeGen to include quickInfo logic * Cake build changes to run CodeGen * CodeGen replace indentation * Refactor GetScript and add more tests * Refactor Resolver calls * Fix TestDriver test for Definition * Change quickInfo string case * Revert change sto .sln file * Fix typos in comments * change String to string * Rename test sql objects
This commit is contained in:
18
build.cake
18
build.cake
@@ -3,11 +3,13 @@
|
||||
#load "scripts/runhelpers.cake"
|
||||
#load "scripts/archiving.cake"
|
||||
#load "scripts/artifacts.cake"
|
||||
#tool "nuget:?package=Mono.TextTransform"
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.Net;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Cake.Common.IO
|
||||
|
||||
// Basic arguments
|
||||
var target = Argument("target", "Default");
|
||||
@@ -258,6 +260,7 @@ Task("TestCore")
|
||||
Task("Test")
|
||||
.IsDependentOn("Setup")
|
||||
.IsDependentOn("SRGen")
|
||||
.IsDependentOn("CodeGen")
|
||||
.IsDependentOn("BuildTest")
|
||||
.Does(() =>
|
||||
{
|
||||
@@ -306,6 +309,7 @@ Task("Test")
|
||||
Task("OnlyPublish")
|
||||
.IsDependentOn("Setup")
|
||||
.IsDependentOn("SRGen")
|
||||
.IsDependentOn("CodeGen")
|
||||
.Does(() =>
|
||||
{
|
||||
var project = buildPlan.MainProject;
|
||||
@@ -541,6 +545,20 @@ Task("SRGen")
|
||||
}
|
||||
});
|
||||
|
||||
/// <summary>
|
||||
/// Executes T4Template-based code generators
|
||||
/// </summary>
|
||||
Task("CodeGen")
|
||||
.Does(() =>
|
||||
{
|
||||
var t4Files = GetFiles(sourceFolder + "/**/*.tt");
|
||||
foreach(var t4Template in t4Files)
|
||||
{
|
||||
TransformTemplate(t4Template, new TextTransformSettings {});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Default Task aliases to Local.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Cake" version="0.10.1" />
|
||||
<package id="Cake" version="0.17.0" />
|
||||
<package id="Newtonsoft.Json" version="8.0.3" />
|
||||
<package id="Microsoft.DataTools.SrGen" version="1.0.2" />
|
||||
</packages>
|
||||
<package id="Mono.TextTransform" version="1.0.0" />
|
||||
</packages>
|
||||
@@ -123,4 +123,4 @@ Global
|
||||
{B6F4BECE-82EE-4AB6-99AC-108AEE466274} = {AB9CA2B8-6F70-431C-8A1D-67479D8A7BE4}
|
||||
{E7CF630E-E084-4DA4-BF69-F61BF0A8F5BE} = {AB9CA2B8-6F70-431C-8A1D-67479D8A7BE4}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
EndGlobal
|
||||
@@ -61,8 +61,8 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
|
||||
private ParseOptions defaultParseOptions = new ParseOptions(
|
||||
batchSeparator: LanguageService.DefaultBatchSeperator,
|
||||
isQuotedIdentifierSet: true,
|
||||
compatibilityLevel: DatabaseCompatibilityLevel.Current,
|
||||
isQuotedIdentifierSet: true,
|
||||
compatibilityLevel: DatabaseCompatibilityLevel.Current,
|
||||
transactSqlVersion: TransactSqlVersion.Current);
|
||||
|
||||
/// <summary>
|
||||
@@ -105,13 +105,13 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
|
||||
private static readonly Lazy<LanguageService> instance = new Lazy<LanguageService>(() => new LanguageService());
|
||||
|
||||
private Lazy<Dictionary<string, ScriptParseInfo>> scriptParseInfoMap
|
||||
private Lazy<Dictionary<string, ScriptParseInfo>> scriptParseInfoMap
|
||||
= new Lazy<Dictionary<string, ScriptParseInfo>>(() => new Dictionary<string, ScriptParseInfo>());
|
||||
|
||||
/// <summary>
|
||||
/// Gets a mapping dictionary for SQL file URIs to ScriptParseInfo objects
|
||||
/// </summary>
|
||||
internal Dictionary<string, ScriptParseInfo> ScriptParseInfoMap
|
||||
internal Dictionary<string, ScriptParseInfo> ScriptParseInfoMap
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -262,20 +262,20 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
}
|
||||
else
|
||||
{
|
||||
// get the current list of completion items and return to client
|
||||
// get the current list of completion items and return to client
|
||||
var scriptFile = LanguageService.WorkspaceServiceInstance.Workspace.GetFile(
|
||||
textDocumentPosition.TextDocument.Uri);
|
||||
|
||||
ConnectionInfo connInfo;
|
||||
LanguageService.ConnectionServiceInstance.TryFindConnection(
|
||||
scriptFile.ClientFilePath,
|
||||
scriptFile.ClientFilePath,
|
||||
out connInfo);
|
||||
|
||||
var completionItems = Instance.GetCompletionItems(
|
||||
textDocumentPosition, scriptFile, connInfo);
|
||||
|
||||
|
||||
await requestContext.SendResult(completionItems);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -322,7 +322,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
LanguageService.ConnectionServiceInstance.TryFindConnection(scriptFile.ClientFilePath, out connInfo);
|
||||
DefinitionResult definitionResult = LanguageService.Instance.GetDefinition(textDocumentPosition, scriptFile, connInfo);
|
||||
if (definitionResult != null)
|
||||
{
|
||||
{
|
||||
if (definitionResult.IsErrorResult)
|
||||
{
|
||||
await requestContext.SendError( new DefinitionError { message = definitionResult.Message });
|
||||
@@ -330,7 +330,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
else
|
||||
{
|
||||
await requestContext.SendResult(definitionResult.Locations);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
DocumentStatusHelper.SendStatusChange(requestContext, textDocumentPosition, DocumentStatusHelper.DefinitionRequestCompleted);
|
||||
@@ -382,10 +382,10 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
private static async Task HandleHoverRequest(
|
||||
TextDocumentPosition textDocumentPosition,
|
||||
RequestContext<Hover> requestContext)
|
||||
{
|
||||
{
|
||||
// check if Quick Info hover tooltips are enabled
|
||||
if (WorkspaceService<SqlToolsSettings>.Instance.CurrentSettings.IsQuickInfoEnabled)
|
||||
{
|
||||
{
|
||||
var scriptFile = WorkspaceService<SqlToolsSettings>.Instance.Workspace.GetFile(
|
||||
textDocumentPosition.TextDocument.Uri);
|
||||
|
||||
@@ -396,7 +396,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
}
|
||||
}
|
||||
|
||||
await requestContext.SendResult(new Hover());
|
||||
await requestContext.SendResult(new Hover());
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -404,42 +404,42 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
#region Handlers for Events from Other Services
|
||||
|
||||
/// <summary>
|
||||
/// Handle the file open notification
|
||||
/// Handle the file open notification
|
||||
/// </summary>
|
||||
/// <param name="scriptFile"></param>
|
||||
/// <param name="eventContext"></param>
|
||||
/// <returns></returns>
|
||||
public async Task HandleDidOpenTextDocumentNotification(
|
||||
ScriptFile scriptFile,
|
||||
ScriptFile scriptFile,
|
||||
EventContext eventContext)
|
||||
{
|
||||
// if not in the preview window and diagnostics are enabled then run diagnostics
|
||||
if (!IsPreviewWindow(scriptFile)
|
||||
&& WorkspaceService<SqlToolsSettings>.Instance.CurrentSettings.IsDiagnositicsEnabled)
|
||||
{
|
||||
await RunScriptDiagnostics(
|
||||
await RunScriptDiagnostics(
|
||||
new ScriptFile[] { scriptFile },
|
||||
eventContext);
|
||||
eventContext);
|
||||
}
|
||||
|
||||
await Task.FromResult(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles text document change events
|
||||
/// </summary>
|
||||
/// <param name="textChangeParams"></param>
|
||||
|
||||
/// <summary>
|
||||
/// Handles text document change events
|
||||
/// </summary>
|
||||
/// <param name="textChangeParams"></param>
|
||||
/// <param name="eventContext"></param>
|
||||
public async Task HandleDidChangeTextDocumentNotification(ScriptFile[] changedFiles, EventContext eventContext)
|
||||
{
|
||||
public async Task HandleDidChangeTextDocumentNotification(ScriptFile[] changedFiles, EventContext eventContext)
|
||||
{
|
||||
if (WorkspaceService<SqlToolsSettings>.Instance.CurrentSettings.IsDiagnositicsEnabled)
|
||||
{
|
||||
await this.RunScriptDiagnostics(
|
||||
changedFiles.ToArray(),
|
||||
eventContext);
|
||||
await this.RunScriptDiagnostics(
|
||||
changedFiles.ToArray(),
|
||||
eventContext);
|
||||
}
|
||||
|
||||
await Task.FromResult(true);
|
||||
await Task.FromResult(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -449,8 +449,8 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
/// <param name="oldSettings"></param>
|
||||
/// <param name="eventContext"></param>
|
||||
public async Task HandleDidChangeConfigurationNotification(
|
||||
SqlToolsSettings newSettings,
|
||||
SqlToolsSettings oldSettings,
|
||||
SqlToolsSettings newSettings,
|
||||
SqlToolsSettings oldSettings,
|
||||
EventContext eventContext)
|
||||
{
|
||||
bool oldEnableIntelliSense = oldSettings.SqlTools.IntelliSense.EnableIntellisense;
|
||||
@@ -480,7 +480,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -495,13 +495,13 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
{
|
||||
RemoveScriptParseInfo(ownerUri);
|
||||
|
||||
// currently this method is disabled, but we need to reimplement now that the
|
||||
// currently this method is disabled, but we need to reimplement now that the
|
||||
// implementation of the 'cache' has changed.
|
||||
await Task.FromResult(0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses the SQL text and binds it to the SMO metadata provider if connected
|
||||
/// Parses the SQL text and binds it to the SMO metadata provider if connected
|
||||
/// </summary>
|
||||
/// <param name="filePath"></param>
|
||||
/// <param name="sqlText"></param>
|
||||
@@ -531,7 +531,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
key: parseInfo.ConnectionKey,
|
||||
bindingTimeout: LanguageService.BindingTimeout,
|
||||
bindOperation: (bindingContext, cancelToken) =>
|
||||
{
|
||||
{
|
||||
try
|
||||
{
|
||||
ParseResult parseResult = Parser.IncrementalParse(
|
||||
@@ -544,8 +544,8 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
List<ParseResult> parseResults = new List<ParseResult>();
|
||||
parseResults.Add(parseResult);
|
||||
bindingContext.Binder.Bind(
|
||||
parseResults,
|
||||
connInfo.ConnectionDetails.DatabaseName,
|
||||
parseResults,
|
||||
connInfo.ConnectionDetails.DatabaseName,
|
||||
BindMode.Batch);
|
||||
}
|
||||
catch (ConnectionException)
|
||||
@@ -562,9 +562,9 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
});
|
||||
|
||||
queueItem.ItemProcessed.WaitOne();
|
||||
queueItem.ItemProcessed.WaitOne();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -580,9 +580,9 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Write(LogLevel.Warning, "Binding metadata lock timeout in ParseAndBind");
|
||||
Logger.Write(LogLevel.Warning, "Binding metadata lock timeout in ParseAndBind");
|
||||
}
|
||||
|
||||
|
||||
return parseInfo.ParseResult;
|
||||
}
|
||||
|
||||
@@ -592,16 +592,16 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
/// <param name="info"></param>
|
||||
public async Task UpdateLanguageServiceOnConnection(ConnectionInfo info)
|
||||
{
|
||||
await Task.Run(() =>
|
||||
await Task.Run(() =>
|
||||
{
|
||||
ScriptParseInfo scriptInfo = GetScriptParseInfo(info.OwnerUri, createIfNotExists: true);
|
||||
if (Monitor.TryEnter(scriptInfo.BuildingMetadataLock, LanguageService.OnConnectionWaitTimeout))
|
||||
{
|
||||
try
|
||||
{
|
||||
{
|
||||
scriptInfo.ConnectionKey = this.BindingQueue.AddConnectionContext(info);
|
||||
scriptInfo.IsConnected = true;
|
||||
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -614,7 +614,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
// (Tell Language Service that I am ready with Metadata Provider Object)
|
||||
Monitor.Exit(scriptInfo.BuildingMetadataLock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AutoCompleteHelper.PrepopulateCommonMetadata(info, scriptInfo, this.BindingQueue);
|
||||
|
||||
@@ -658,7 +658,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
key: scriptParseInfo.ConnectionKey,
|
||||
bindingTimeout: LanguageService.BindingTimeout,
|
||||
bindOperation: (bindingContext, cancelToken) =>
|
||||
{
|
||||
{
|
||||
foreach (var suggestion in scriptParseInfo.CurrentSuggestions)
|
||||
{
|
||||
if (string.Equals(suggestion.Title, completionItem.Label))
|
||||
@@ -667,25 +667,25 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
completionItem.Documentation = suggestion.Description;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return completionItem;
|
||||
}
|
||||
return completionItem;
|
||||
});
|
||||
|
||||
queueItem.ItemProcessed.WaitOne();
|
||||
queueItem.ItemProcessed.WaitOne();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// if any exceptions are raised looking up extended completion metadata
|
||||
// if any exceptions are raised looking up extended completion metadata
|
||||
// then just return the original completion item
|
||||
Logger.Write(LogLevel.Error, "Exeception in ResolveCompletionItem " + ex.ToString());
|
||||
}
|
||||
Logger.Write(LogLevel.Error, "Exception in ResolveCompletionItem " + ex.ToString());
|
||||
}
|
||||
finally
|
||||
{
|
||||
Monitor.Exit(scriptParseInfo.BuildingMetadataLock);
|
||||
}
|
||||
Monitor.Exit(scriptParseInfo.BuildingMetadataLock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
return completionItem;
|
||||
}
|
||||
@@ -725,25 +725,21 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
{
|
||||
try
|
||||
{
|
||||
// Queue the task with the binding queue
|
||||
// Queue the task with the binding queue
|
||||
QueueItem queueItem = this.BindingQueue.QueueBindingOperation(
|
||||
key: scriptParseInfo.ConnectionKey,
|
||||
bindingTimeout: LanguageService.PeekDefinitionTimeout,
|
||||
bindOperation: (bindingContext, cancelToken) =>
|
||||
{
|
||||
// Get suggestions for the token
|
||||
int parserLine = textDocumentPosition.Position.Line + 1;
|
||||
int parserColumn = textDocumentPosition.Position.Character + 1;
|
||||
IEnumerable<Declaration> declarationItems = Resolver.FindCompletions(
|
||||
scriptParseInfo.ParseResult,
|
||||
parserLine, parserColumn,
|
||||
bindingContext.MetadataDisplayInfoProvider);
|
||||
|
||||
// Match token with the suggestions(declaration items) returned
|
||||
|
||||
string schemaName = this.GetSchemaName(scriptParseInfo, textDocumentPosition.Position, scriptFile);
|
||||
// Script object using SMO
|
||||
PeekDefinition peekDefinition = new PeekDefinition(bindingContext.ServerConnection, connInfo);
|
||||
return peekDefinition.GetScript(declarationItems, tokenText, schemaName);
|
||||
return peekDefinition.GetScript(
|
||||
scriptParseInfo.ParseResult,
|
||||
textDocumentPosition.Position,
|
||||
bindingContext.MetadataDisplayInfoProvider,
|
||||
tokenText,
|
||||
schemaName);
|
||||
},
|
||||
timeoutOperation: (bindingContext) =>
|
||||
{
|
||||
@@ -813,7 +809,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
Token schemaToken = scriptParseInfo.ParseResult.Script.TokenManager.GetToken(schemaTokenIndex);
|
||||
return TextUtilities.RemoveSquareBracketSyntax(schemaToken.Text);
|
||||
}
|
||||
}
|
||||
}
|
||||
// if no schema name, returns null
|
||||
return null;
|
||||
}
|
||||
@@ -827,10 +823,10 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
{
|
||||
int startLine = textDocumentPosition.Position.Line;
|
||||
int startColumn = TextUtilities.PositionOfPrevDelimeter(
|
||||
scriptFile.Contents,
|
||||
scriptFile.Contents,
|
||||
textDocumentPosition.Position.Line,
|
||||
textDocumentPosition.Position.Character);
|
||||
int endColumn = textDocumentPosition.Position.Character;
|
||||
int endColumn = textDocumentPosition.Position.Character;
|
||||
|
||||
ScriptParseInfo scriptParseInfo = GetScriptParseInfo(textDocumentPosition.TextDocument.Uri);
|
||||
if (scriptParseInfo != null && scriptParseInfo.ParseResult != null)
|
||||
@@ -843,29 +839,29 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
key: scriptParseInfo.ConnectionKey,
|
||||
bindingTimeout: LanguageService.HoverTimeout,
|
||||
bindOperation: (bindingContext, cancelToken) =>
|
||||
{
|
||||
{
|
||||
// get the current quick info text
|
||||
Babel.CodeObjectQuickInfo quickInfo = Resolver.GetQuickInfo(
|
||||
scriptParseInfo.ParseResult,
|
||||
startLine + 1,
|
||||
endColumn + 1,
|
||||
scriptParseInfo.ParseResult,
|
||||
startLine + 1,
|
||||
endColumn + 1,
|
||||
bindingContext.MetadataDisplayInfoProvider);
|
||||
|
||||
|
||||
// convert from the parser format to the VS Code wire format
|
||||
return AutoCompleteHelper.ConvertQuickInfoToHover(
|
||||
quickInfo,
|
||||
quickInfo,
|
||||
startLine,
|
||||
startColumn,
|
||||
startColumn,
|
||||
endColumn);
|
||||
});
|
||||
|
||||
queueItem.ItemProcessed.WaitOne();
|
||||
return queueItem.GetResultAsT<Hover>();
|
||||
|
||||
queueItem.ItemProcessed.WaitOne();
|
||||
return queueItem.GetResultAsT<Hover>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
Monitor.Exit(scriptParseInfo.BuildingMetadataLock);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -880,7 +876,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
{
|
||||
int startLine = textDocumentPosition.Position.Line;
|
||||
int startColumn = TextUtilities.PositionOfPrevDelimeter(
|
||||
scriptFile.Contents,
|
||||
scriptFile.Contents,
|
||||
textDocumentPosition.Position.Line,
|
||||
textDocumentPosition.Position.Character);
|
||||
int endColumn = textDocumentPosition.Position.Character;
|
||||
@@ -895,12 +891,12 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
|
||||
ConnectionInfo connInfo;
|
||||
LanguageService.ConnectionServiceInstance.TryFindConnection(
|
||||
scriptFile.ClientFilePath,
|
||||
scriptFile.ClientFilePath,
|
||||
out connInfo);
|
||||
|
||||
// reparse and bind the SQL statement if needed
|
||||
if (RequiresReparse(scriptParseInfo, scriptFile))
|
||||
{
|
||||
{
|
||||
ParseAndBind(scriptFile, connInfo);
|
||||
}
|
||||
|
||||
@@ -914,14 +910,14 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
key: scriptParseInfo.ConnectionKey,
|
||||
bindingTimeout: LanguageService.BindingTimeout,
|
||||
bindOperation: (bindingContext, cancelToken) =>
|
||||
{
|
||||
{
|
||||
// get the list of possible current methods for signature help
|
||||
var methods = Resolver.FindMethods(
|
||||
scriptParseInfo.ParseResult,
|
||||
startLine + 1,
|
||||
endColumn + 1,
|
||||
scriptParseInfo.ParseResult,
|
||||
startLine + 1,
|
||||
endColumn + 1,
|
||||
bindingContext.MetadataDisplayInfoProvider);
|
||||
|
||||
|
||||
// get positional information on the current method
|
||||
var methodLocations = Resolver.GetMethodNameAndParams(scriptParseInfo.ParseResult,
|
||||
startLine + 1,
|
||||
@@ -941,14 +937,14 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
queueItem.ItemProcessed.WaitOne();
|
||||
return queueItem.GetResultAsT<SignatureHelp>();
|
||||
|
||||
queueItem.ItemProcessed.WaitOne();
|
||||
return queueItem.GetResultAsT<SignatureHelp>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
Monitor.Exit(scriptParseInfo.BuildingMetadataLock);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -974,14 +970,14 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
|
||||
// get the current script parse info object
|
||||
ScriptParseInfo scriptParseInfo = GetScriptParseInfo(textDocumentPosition.TextDocument.Uri);
|
||||
|
||||
|
||||
if (scriptParseInfo == null)
|
||||
{
|
||||
return AutoCompleteHelper.GetDefaultCompletionItems(ScriptDocumentInfo.CreateDefaultDocumentInfo(textDocumentPosition, scriptFile), useLowerCaseSuggestions);
|
||||
}
|
||||
|
||||
ScriptDocumentInfo scriptDocumentInfo = new ScriptDocumentInfo(textDocumentPosition, scriptFile, scriptParseInfo);
|
||||
|
||||
|
||||
// reparse and bind the SQL statement if needed
|
||||
if (RequiresReparse(scriptParseInfo, scriptFile))
|
||||
{
|
||||
@@ -1019,9 +1015,9 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
{
|
||||
ConnectionInfo connInfo;
|
||||
ConnectionService.Instance.TryFindConnection(
|
||||
scriptFile.ClientFilePath,
|
||||
scriptFile.ClientFilePath,
|
||||
out connInfo);
|
||||
|
||||
|
||||
var parseResult = ParseAndBind(scriptFile, connInfo);
|
||||
|
||||
// build a list of SQL script file markers from the errors
|
||||
@@ -1181,7 +1177,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
/// Internal for testing purposes only
|
||||
/// </summary>
|
||||
/// <param name="uri"></param>
|
||||
/// <param name="createIfNotExists">Creates a new instance if one doesn't exist</param>
|
||||
/// <param name="createIfNotExists">Creates a new instance if one doesn't exist</param>
|
||||
internal ScriptParseInfo GetScriptParseInfo(string uri, bool createIfNotExists = false)
|
||||
{
|
||||
lock (this.parseMapLock)
|
||||
@@ -1209,7 +1205,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
lock (this.parseMapLock)
|
||||
{
|
||||
if (this.ScriptParseInfoMap.ContainsKey(uri))
|
||||
{
|
||||
{
|
||||
return this.ScriptParseInfoMap.Remove(uri);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -4,17 +4,21 @@
|
||||
//
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.SqlServer.Management.Smo;
|
||||
using Microsoft.SqlServer.Management.Common;
|
||||
using Microsoft.SqlServer.Management.SqlParser.Intellisense;
|
||||
using Microsoft.SqlServer.Management.SqlParser.Parser;
|
||||
using Microsoft.SqlServer.Management.SqlParser.MetadataProvider;
|
||||
using Microsoft.SqlTools.ServiceLayer.Connection;
|
||||
using Microsoft.SqlTools.ServiceLayer.QueryExecution;
|
||||
using Microsoft.SqlTools.ServiceLayer.Utility;
|
||||
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol;
|
||||
using Microsoft.SqlTools.ServiceLayer.Workspace.Contracts;
|
||||
using Location = Microsoft.SqlTools.ServiceLayer.Workspace.Contracts.Location;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
{
|
||||
@@ -22,7 +26,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
/// Peek Definition/ Go to definition implementation
|
||||
/// Script sql objects and write create scripts to file
|
||||
/// </summary>
|
||||
internal class PeekDefinition
|
||||
internal partial class PeekDefinition
|
||||
{
|
||||
private bool error;
|
||||
private string errorMessage;
|
||||
@@ -37,9 +41,14 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
private Dictionary<DeclarationType, ScriptGetter> sqlScriptGetters =
|
||||
new Dictionary<DeclarationType, ScriptGetter>();
|
||||
|
||||
private Dictionary<string, ScriptGetter> sqlScriptGettersFromQuickInfo =
|
||||
new Dictionary<string, ScriptGetter>();
|
||||
|
||||
// Dictionary that holds the object name (as appears on the TSQL create statement)
|
||||
private Dictionary<DeclarationType, string> sqlObjectTypes = new Dictionary<DeclarationType, string>();
|
||||
|
||||
private Dictionary<string, string> sqlObjectTypesFromQuickInfo = new Dictionary<string, string>();
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a Peek Definition helper object
|
||||
/// </summary>
|
||||
@@ -48,7 +57,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
{
|
||||
this.serverConnection = serverConnection;
|
||||
this.connectionInfo = connInfo;
|
||||
this.tempPath = FileUtils.GetPeekDefinitionTempFolder();
|
||||
this.tempPath = FileUtils.GetPeekDefinitionTempFolder();
|
||||
Initialize();
|
||||
}
|
||||
|
||||
@@ -70,7 +79,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
{
|
||||
Logger.Write(LogLevel.Error, "Exception at PeekDefinition Database.get() : " + cfe.Message);
|
||||
this.error = true;
|
||||
this.errorMessage = (connectionInfo != null && connectionInfo.IsAzure)? SR.PeekDefinitionAzureError(cfe.Message) : SR.PeekDefinitionError(cfe.Message);
|
||||
this.errorMessage = (connectionInfo != null && connectionInfo.IsAzure) ? SR.PeekDefinitionAzureError(cfe.Message) : SR.PeekDefinitionError(cfe.Message);
|
||||
return null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -81,78 +90,23 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return this.database;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add getters for each sql object supported by peek definition
|
||||
/// </summary>
|
||||
private void Initialize()
|
||||
{
|
||||
//Add script getters for each sql object
|
||||
|
||||
//Add tables to supported types
|
||||
AddSupportedType(DeclarationType.Table, GetTableScripts, "Table");
|
||||
|
||||
//Add views to supported types
|
||||
AddSupportedType(DeclarationType.View, GetViewScripts, "view");
|
||||
|
||||
//Add stored procedures to supported types
|
||||
AddSupportedType(DeclarationType.StoredProcedure, GetStoredProcedureScripts, "Procedure");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add the given type, scriptgetter and the typeName string to the respective dictionaries
|
||||
/// </summary>
|
||||
private void AddSupportedType(DeclarationType type, ScriptGetter scriptGetter, string typeName)
|
||||
private void AddSupportedType(DeclarationType type, ScriptGetter scriptGetter, string typeName, string quickInfoType)
|
||||
{
|
||||
sqlScriptGetters.Add(type, scriptGetter);
|
||||
sqlObjectTypes.Add(type, typeName);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert a file to a location array containing a location object as expected by the extension
|
||||
/// </summary>
|
||||
internal Location[] GetLocationFromFile(string tempFileName, int lineNumber)
|
||||
{
|
||||
if (Path.DirectorySeparatorChar.Equals('/'))
|
||||
if (!string.IsNullOrEmpty(quickInfoType))
|
||||
{
|
||||
tempFileName = "file:" + tempFileName;
|
||||
sqlScriptGettersFromQuickInfo.Add(quickInfoType.ToLowerInvariant(), scriptGetter);
|
||||
sqlObjectTypesFromQuickInfo.Add(quickInfoType.ToLowerInvariant(), typeName);
|
||||
}
|
||||
else
|
||||
{
|
||||
tempFileName = new Uri(tempFileName).AbsoluteUri;
|
||||
}
|
||||
Location[] locations = new[] {
|
||||
new Location {
|
||||
Uri = tempFileName,
|
||||
Range = new Range {
|
||||
Start = new Position { Line = lineNumber, Character = 1},
|
||||
End = new Position { Line = lineNumber + 1, Character = 1}
|
||||
}
|
||||
}
|
||||
};
|
||||
return locations;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get line number for the create statement
|
||||
/// </summary>
|
||||
private int GetStartOfCreate(string script, string createString)
|
||||
{
|
||||
string[] lines = script.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
|
||||
for (int lineNumber = 0; lineNumber < lines.Length; lineNumber++)
|
||||
{
|
||||
if (lines[lineNumber].IndexOf(createString, StringComparison.OrdinalIgnoreCase) >= 0)
|
||||
{
|
||||
return lineNumber;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -162,45 +116,77 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
/// <param name="tokenText"></param>
|
||||
/// <param name="schemaName"></param>
|
||||
/// <returns>Location object of the script file</returns>
|
||||
internal DefinitionResult GetScript(IEnumerable<Declaration> declarationItems, string tokenText, string schemaName)
|
||||
internal DefinitionResult GetScript(ParseResult parseResult, Position position, IMetadataDisplayInfoProvider metadataDisplayInfoProvider, string tokenText, string schemaName)
|
||||
{
|
||||
foreach (Declaration declarationItem in declarationItems)
|
||||
int parserLine = position.Line + 1;
|
||||
int parserColumn = position.Character + 1;
|
||||
// Get DeclarationItems from The Intellisense Resolver for the selected token. The type of the selected token is extracted from the declarationItem.
|
||||
IEnumerable<Declaration> declarationItems = GetCompletionsForToken(parseResult, parserLine, parserColumn, metadataDisplayInfoProvider);
|
||||
if (declarationItems != null && declarationItems.Count() > 0)
|
||||
{
|
||||
if (declarationItem.Title == null)
|
||||
foreach (Declaration declarationItem in declarationItems)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (declarationItem.Title.Equals(tokenText))
|
||||
{
|
||||
// Script object using SMO based on type
|
||||
DeclarationType type = declarationItem.Type;
|
||||
if (sqlScriptGetters.ContainsKey(type) && sqlObjectTypes.ContainsKey(type))
|
||||
if (declarationItem.Title == null)
|
||||
{
|
||||
// On *nix and mac systems, the defaultSchema property throws an Exception when accessed.
|
||||
// This workaround ensures that a schema name is present by attempting
|
||||
// to get the schema name from the declaration item
|
||||
// If all fails, the default schema name is assumed to be "dbo"
|
||||
if ((connectionInfo != null && connectionInfo.ConnectionDetails.AuthenticationType.Equals(Constants.SqlLoginAuthenticationType)) && string.IsNullOrEmpty(schemaName))
|
||||
{
|
||||
string fullObjectName = declarationItem.DatabaseQualifiedName;
|
||||
schemaName = this.GetSchemaFromDatabaseQualifiedName(fullObjectName, tokenText);
|
||||
}
|
||||
Location[] locations = GetSqlObjectDefinition(
|
||||
sqlScriptGetters[type],
|
||||
tokenText,
|
||||
schemaName,
|
||||
sqlObjectTypes[type]
|
||||
);
|
||||
DefinitionResult result = new DefinitionResult
|
||||
{
|
||||
IsErrorResult = this.error,
|
||||
Message = this.errorMessage,
|
||||
Locations = locations
|
||||
};
|
||||
return result;
|
||||
continue;
|
||||
}
|
||||
// sql object type is currently not supported
|
||||
// if declarartionItem matches the selected token, script SMO using that type
|
||||
if (declarationItem.Title.Equals(tokenText))
|
||||
{
|
||||
return GetDefinitionUsingDeclarationType(declarationItem.Type, declarationItem.DatabaseQualifiedName, tokenText, schemaName);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// if no declarationItem matched the selected token, we try to find the type of the token using QuickInfo.Text
|
||||
string quickInfoText = GetQuickInfoForToken(parseResult, parserLine, parserColumn, metadataDisplayInfoProvider);
|
||||
return GetDefinitionUsingQuickInfoText(quickInfoText, tokenText, schemaName);
|
||||
}
|
||||
// no definition found
|
||||
return GetDefinitionErrorResult(SR.PeekDefinitionNoResultsError);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Script an object using the type extracted from quickInfo Text
|
||||
/// </summary>
|
||||
/// <param name="quickInfoText">the text from the quickInfo for the selected token</param>
|
||||
/// <param name="tokenText">The text of the selected token</param>
|
||||
/// <param name="schemaName">Schema name</param>
|
||||
/// <returns></returns>
|
||||
internal DefinitionResult GetDefinitionUsingQuickInfoText(string quickInfoText, string tokenText, string schemaName)
|
||||
{
|
||||
string tokenType = GetTokenTypeFromQuickInfo(quickInfoText, tokenText);
|
||||
if (tokenType != null)
|
||||
{
|
||||
if (sqlScriptGettersFromQuickInfo.ContainsKey(tokenType.ToLowerInvariant()))
|
||||
{
|
||||
// With SqlLogin authentication, the defaultSchema property throws an Exception when accessed.
|
||||
// This workaround ensures that a schema name is present by attempting
|
||||
// to get the schema name from the declaration item.
|
||||
// If all fails, the default schema name is assumed to be "dbo"
|
||||
if ((connectionInfo != null && connectionInfo.ConnectionDetails.AuthenticationType.Equals(Constants.SqlLoginAuthenticationType)) && string.IsNullOrEmpty(schemaName))
|
||||
{
|
||||
string fullObjectName = this.GetFullObjectNameFromQuickInfo(quickInfoText, tokenText);
|
||||
schemaName = this.GetSchemaFromDatabaseQualifiedName(fullObjectName, tokenText);
|
||||
}
|
||||
Location[] locations = GetSqlObjectDefinition(
|
||||
sqlScriptGettersFromQuickInfo[tokenType.ToLowerInvariant()],
|
||||
tokenText,
|
||||
schemaName,
|
||||
sqlObjectTypesFromQuickInfo[tokenType.ToLowerInvariant()]
|
||||
);
|
||||
DefinitionResult result = new DefinitionResult
|
||||
{
|
||||
IsErrorResult = this.error,
|
||||
Message = this.errorMessage,
|
||||
Locations = locations
|
||||
};
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If a type was found but is not in sqlScriptGettersFromQuickInfo, then the type is not supported
|
||||
return GetDefinitionErrorResult(SR.PeekDefinitionTypeNotSupportedError);
|
||||
}
|
||||
}
|
||||
@@ -209,97 +195,41 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return schema name from the full name of the database. If schema is missing return dbo as schema name.
|
||||
/// Script a object using the type extracted from declarationItem
|
||||
/// </summary>
|
||||
/// <param name="fullObjectName"> The full database qualified name(database.schema.object)</param>
|
||||
/// <param name="objectName"> Object name</param>
|
||||
/// <returns>Schema name</returns>
|
||||
internal string GetSchemaFromDatabaseQualifiedName(string fullObjectName, string objectName)
|
||||
{
|
||||
string[] tokens = fullObjectName.Split('.');
|
||||
for (int i = tokens.Length - 1; i > 0; i--)
|
||||
{
|
||||
if (tokens[i].Equals(objectName))
|
||||
{
|
||||
return tokens[i - 1];
|
||||
}
|
||||
}
|
||||
return "dbo";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Script a table using SMO
|
||||
/// </summary>
|
||||
/// <param name="tableName">Table name</param>
|
||||
/// <param name="declarationItem">The Declarartion object that matched with the selected token</param>
|
||||
/// <param name="tokenText">The text of the selected token</param>
|
||||
/// <param name="schemaName">Schema name</param>
|
||||
/// <returns>String collection of scripts</returns>
|
||||
internal StringCollection GetTableScripts(string tableName, string schemaName)
|
||||
/// <returns></returns>
|
||||
internal DefinitionResult GetDefinitionUsingDeclarationType(DeclarationType type, string databaseQualifiedName, string tokenText, string schemaName)
|
||||
{
|
||||
try
|
||||
if (sqlScriptGetters.ContainsKey(type) && sqlObjectTypes.ContainsKey(type))
|
||||
{
|
||||
Table table = string.IsNullOrEmpty(schemaName)
|
||||
? new Table(this.Database, tableName)
|
||||
: new Table(this.Database, tableName, schemaName);
|
||||
|
||||
table.Refresh();
|
||||
|
||||
return table.Script();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(LogLevel.Error, "Exception at PeekDefinition GetTableScripts : " + ex.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Script a view using SMO
|
||||
/// </summary>
|
||||
/// <param name="viewName">View name</param>
|
||||
/// <param name="schemaName">Schema name </param>
|
||||
/// <returns>String collection of scripts</returns>
|
||||
internal StringCollection GetViewScripts(string viewName, string schemaName)
|
||||
{
|
||||
try
|
||||
{
|
||||
View view = string.IsNullOrEmpty(schemaName)
|
||||
? new View(this.Database, viewName)
|
||||
: new View(this.Database, viewName, schemaName);
|
||||
|
||||
view.Refresh();
|
||||
|
||||
return view.Script();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(LogLevel.Error, "Exception at PeekDefinition GetViewScripts : " + ex.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Script a stored procedure using SMO
|
||||
/// </summary>
|
||||
/// <param name="storedProcedureName">Stored Procedure name</param>
|
||||
/// <param name="schemaName">Schema Name</param>
|
||||
/// <returns>String collection of scripts</returns>
|
||||
internal StringCollection GetStoredProcedureScripts(string sprocName, string schemaName)
|
||||
{
|
||||
try
|
||||
{
|
||||
StoredProcedure sproc = string.IsNullOrEmpty(schemaName)
|
||||
? new StoredProcedure(this.Database, sprocName)
|
||||
: new StoredProcedure(this.Database, sprocName, schemaName);
|
||||
|
||||
sproc.Refresh();
|
||||
|
||||
return sproc.Script();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(LogLevel.Error, "Exception at PeekDefinition GetStoredProcedureScripts : " + ex.Message);
|
||||
return null;
|
||||
// With SqlLogin authentication, the defaultSchema property throws an Exception when accessed.
|
||||
// This workaround ensures that a schema name is present by attempting
|
||||
// to get the schema name from the declaration item.
|
||||
// If all fails, the default schema name is assumed to be "dbo"
|
||||
if ((connectionInfo != null && connectionInfo.ConnectionDetails.AuthenticationType.Equals(Constants.SqlLoginAuthenticationType)) && string.IsNullOrEmpty(schemaName))
|
||||
{
|
||||
string fullObjectName = databaseQualifiedName;
|
||||
schemaName = this.GetSchemaFromDatabaseQualifiedName(fullObjectName, tokenText);
|
||||
}
|
||||
Location[] locations = GetSqlObjectDefinition(
|
||||
sqlScriptGetters[type],
|
||||
tokenText,
|
||||
schemaName,
|
||||
sqlObjectTypes[type]
|
||||
);
|
||||
DefinitionResult result = new DefinitionResult
|
||||
{
|
||||
IsErrorResult = this.error,
|
||||
Message = this.errorMessage,
|
||||
Locations = locations
|
||||
};
|
||||
return result;
|
||||
}
|
||||
// If a type was found but is not in sqlScriptGetters, then the type is not supported
|
||||
return GetDefinitionErrorResult(SR.PeekDefinitionTypeNotSupportedError);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -346,6 +276,71 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
}
|
||||
}
|
||||
|
||||
#region Helper Methods
|
||||
/// <summary>
|
||||
/// Return schema name from the full name of the database. If schema is missing return dbo as schema name.
|
||||
/// </summary>
|
||||
/// <param name="fullObjectName"> The full database qualified name(database.schema.object)</param>
|
||||
/// <param name="objectName"> Object name</param>
|
||||
/// <returns>Schema name</returns>
|
||||
internal string GetSchemaFromDatabaseQualifiedName(string fullObjectName, string objectName)
|
||||
{
|
||||
if(!string.IsNullOrEmpty(fullObjectName))
|
||||
{
|
||||
string[] tokens = fullObjectName.Split('.');
|
||||
for (int i = tokens.Length - 1; i > 0; i--)
|
||||
{
|
||||
if (tokens[i].Equals(objectName))
|
||||
{
|
||||
return tokens[i - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
return "dbo";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert a file to a location array containing a location object as expected by the extension
|
||||
/// </summary>
|
||||
internal Location[] GetLocationFromFile(string tempFileName, int lineNumber)
|
||||
{
|
||||
// Get absolute Uri based on uri format. This works around a dotnetcore URI bug for linux paths.
|
||||
if (Path.DirectorySeparatorChar.Equals('/'))
|
||||
{
|
||||
tempFileName = "file:" + tempFileName;
|
||||
}
|
||||
else
|
||||
{
|
||||
tempFileName = new Uri(tempFileName).AbsoluteUri;
|
||||
}
|
||||
// Create a location array containing the tempFile Uri, as expected by VSCode.
|
||||
Location[] locations = new[] {
|
||||
new Location {
|
||||
Uri = tempFileName,
|
||||
Range = new Range {
|
||||
Start = new Position { Line = lineNumber, Character = 1},
|
||||
End = new Position { Line = lineNumber + 1, Character = 1}
|
||||
}
|
||||
}
|
||||
};
|
||||
return locations;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get line number for the create statement
|
||||
/// </summary>
|
||||
private int GetStartOfCreate(string script, string createString)
|
||||
{
|
||||
string[] lines = script.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
|
||||
for (int lineNumber = 0; lineNumber < lines.Length; lineNumber++)
|
||||
{
|
||||
if (lines[lineNumber].IndexOf(createString, StringComparison.OrdinalIgnoreCase) >= 0)
|
||||
{
|
||||
return lineNumber;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/// <summary>
|
||||
/// Helper method to create definition error result object
|
||||
/// </summary>
|
||||
@@ -360,5 +355,75 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
Locations = null
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return full object name(database.schema.objectName) from the quickInfo text("type database.schema.objectName")
|
||||
/// </summary>
|
||||
/// <param name="quickInfoText">QuickInfo Text for this token</param>
|
||||
/// <param name="tokenText">Token Text</param>
|
||||
/// <returns></returns>
|
||||
internal string GetFullObjectNameFromQuickInfo(string quickInfoText, string tokenText)
|
||||
{
|
||||
if (string.IsNullOrEmpty(quickInfoText) || string.IsNullOrEmpty(tokenText))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
// extract full object name from quickInfo text
|
||||
string[] tokens = quickInfoText.Split(' ');
|
||||
List<string> tokenList = tokens.Where(el => el.Contains(tokenText)).ToList();
|
||||
return (tokenList?.Count() > 0) ? tokenList[0] : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return token type from the quickInfo text("type database.schema.objectName")
|
||||
/// </summary>
|
||||
/// <param name="quickInfoText">QuickInfo Text for this token</param>
|
||||
/// <param name="tokenText"Token Text></param>
|
||||
/// <returns></returns>
|
||||
internal string GetTokenTypeFromQuickInfo(string quickInfoText, string tokenText)
|
||||
{
|
||||
if (string.IsNullOrEmpty(quickInfoText) || string.IsNullOrEmpty(tokenText))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
// extract string denoting the token type from quickInfo text
|
||||
string[] tokens = quickInfoText.Split(' ');
|
||||
List<int> indexList = tokens.Select((s, i) => new { i, s }).Where(el => (el.s).Contains(tokenText)).Select(el => el.i).ToList();
|
||||
return (indexList?.Count() > 0) ? String.Join(" ", tokens.Take(indexList[0])) : null;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Wrapper method that calls Resolver.GetQuickInfo
|
||||
/// </summary>
|
||||
internal string GetQuickInfoForToken(ParseResult parseResult, int parserLine, int parserColumn, IMetadataDisplayInfoProvider metadataDisplayInfoProvider)
|
||||
{
|
||||
if (parseResult == null || metadataDisplayInfoProvider == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
Babel.CodeObjectQuickInfo quickInfo = Resolver.GetQuickInfo(
|
||||
parseResult, parserLine, parserColumn, metadataDisplayInfoProvider);
|
||||
return quickInfo?.Text;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wrapper method that calls Resolver.FindCompletions
|
||||
/// </summary>
|
||||
/// <param name="parseResult"></param>
|
||||
/// <param name="parserLine"></param>
|
||||
/// <param name="parserColumn"></param>
|
||||
/// <param name="metadataDisplayInfoProvider"></param>
|
||||
/// <returns></returns>
|
||||
internal IEnumerable<Declaration> GetCompletionsForToken(ParseResult parseResult, int parserLine, int parserColumn, IMetadataDisplayInfoProvider metadataDisplayInfoProvider)
|
||||
{
|
||||
if (parseResult == null || metadataDisplayInfoProvider == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return Resolver.FindCompletions(
|
||||
parseResult, parserLine, parserColumn, metadataDisplayInfoProvider);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using Microsoft.SqlServer.Management.Smo;
|
||||
using Microsoft.SqlServer.Management.SqlParser.Intellisense;
|
||||
using Microsoft.SqlTools.ServiceLayer.Utility;
|
||||
namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
{
|
||||
internal partial class PeekDefinition
|
||||
{
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
AddSupportedType(DeclarationType.Table, GetTableScripts, "Table", "table");
|
||||
AddSupportedType(DeclarationType.View, GetViewScripts, "View", "view");
|
||||
AddSupportedType(DeclarationType.StoredProcedure, GetStoredProcedureScripts, "Procedure", "stored procedure");
|
||||
AddSupportedType(DeclarationType.UserDefinedDataType, GetUserDefinedDataTypeScripts, "Type", "user-defined data type");
|
||||
AddSupportedType(DeclarationType.UserDefinedTableType, GetUserDefinedTableTypeScripts, "Type", "user-defined table type");
|
||||
AddSupportedType(DeclarationType.Synonym, GetSynonymScripts, "Synonym", "");
|
||||
AddSupportedType(DeclarationType.ScalarValuedFunction, GetScalarValuedFunctionScripts, "Function", "scalar-valued function");
|
||||
AddSupportedType(DeclarationType.TableValuedFunction, GetTableValuedFunctionScripts, "Function", "table-valued function");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Script a Table using SMO
|
||||
/// </summary>
|
||||
/// <param name="objectName">Table name</param>
|
||||
/// <param name="schemaName">Schema name</param>
|
||||
/// <returns>String collection of scripts</returns>
|
||||
internal StringCollection GetTableScripts(string objectName, string schemaName)
|
||||
{
|
||||
try
|
||||
{
|
||||
Table smoObject = string.IsNullOrEmpty(schemaName) ? new Table(this.Database, objectName) : new Table(this.Database, objectName, schemaName);
|
||||
smoObject.Refresh();
|
||||
return smoObject.Script();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(LogLevel.Error,"Exception at PeekDefinition GetTableScripts : " + ex.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Script a View using SMO
|
||||
/// </summary>
|
||||
/// <param name="objectName">View name</param>
|
||||
/// <param name="schemaName">Schema name</param>
|
||||
/// <returns>String collection of scripts</returns>
|
||||
internal StringCollection GetViewScripts(string objectName, string schemaName)
|
||||
{
|
||||
try
|
||||
{
|
||||
View smoObject = string.IsNullOrEmpty(schemaName) ? new View(this.Database, objectName) : new View(this.Database, objectName, schemaName);
|
||||
smoObject.Refresh();
|
||||
return smoObject.Script();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(LogLevel.Error,"Exception at PeekDefinition GetViewScripts : " + ex.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Script a StoredProcedure using SMO
|
||||
/// </summary>
|
||||
/// <param name="objectName">StoredProcedure name</param>
|
||||
/// <param name="schemaName">Schema name</param>
|
||||
/// <returns>String collection of scripts</returns>
|
||||
internal StringCollection GetStoredProcedureScripts(string objectName, string schemaName)
|
||||
{
|
||||
try
|
||||
{
|
||||
StoredProcedure smoObject = string.IsNullOrEmpty(schemaName) ? new StoredProcedure(this.Database, objectName) : new StoredProcedure(this.Database, objectName, schemaName);
|
||||
smoObject.Refresh();
|
||||
return smoObject.Script();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(LogLevel.Error,"Exception at PeekDefinition GetStoredProcedureScripts : " + ex.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Script a UserDefinedDataType using SMO
|
||||
/// </summary>
|
||||
/// <param name="objectName">UserDefinedDataType name</param>
|
||||
/// <param name="schemaName">Schema name</param>
|
||||
/// <returns>String collection of scripts</returns>
|
||||
internal StringCollection GetUserDefinedDataTypeScripts(string objectName, string schemaName)
|
||||
{
|
||||
try
|
||||
{
|
||||
UserDefinedDataType smoObject = string.IsNullOrEmpty(schemaName) ? new UserDefinedDataType(this.Database, objectName) : new UserDefinedDataType(this.Database, objectName, schemaName);
|
||||
smoObject.Refresh();
|
||||
return smoObject.Script();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(LogLevel.Error,"Exception at PeekDefinition GetUserDefinedDataTypeScripts : " + ex.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Script a UserDefinedTableType using SMO
|
||||
/// </summary>
|
||||
/// <param name="objectName">UserDefinedTableType name</param>
|
||||
/// <param name="schemaName">Schema name</param>
|
||||
/// <returns>String collection of scripts</returns>
|
||||
internal StringCollection GetUserDefinedTableTypeScripts(string objectName, string schemaName)
|
||||
{
|
||||
try
|
||||
{
|
||||
UserDefinedTableType smoObject = string.IsNullOrEmpty(schemaName) ? new UserDefinedTableType(this.Database, objectName) : new UserDefinedTableType(this.Database, objectName, schemaName);
|
||||
smoObject.Refresh();
|
||||
return smoObject.Script();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(LogLevel.Error,"Exception at PeekDefinition GetUserDefinedTableTypeScripts : " + ex.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Script a Synonym using SMO
|
||||
/// </summary>
|
||||
/// <param name="objectName">Synonym name</param>
|
||||
/// <param name="schemaName">Schema name</param>
|
||||
/// <returns>String collection of scripts</returns>
|
||||
internal StringCollection GetSynonymScripts(string objectName, string schemaName)
|
||||
{
|
||||
try
|
||||
{
|
||||
Synonym smoObject = string.IsNullOrEmpty(schemaName) ? new Synonym(this.Database, objectName) : new Synonym(this.Database, objectName, schemaName);
|
||||
smoObject.Refresh();
|
||||
return smoObject.Script();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(LogLevel.Error,"Exception at PeekDefinition GetSynonymScripts : " + ex.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Script a ScalarValuedFunction using SMO
|
||||
/// </summary>
|
||||
/// <param name="objectName">ScalarValuedFunction name</param>
|
||||
/// <param name="schemaName">Schema name</param>
|
||||
/// <returns>String collection of scripts</returns>
|
||||
internal StringCollection GetScalarValuedFunctionScripts(string objectName, string schemaName)
|
||||
{
|
||||
try
|
||||
{
|
||||
UserDefinedFunction smoObject = string.IsNullOrEmpty(schemaName) ? new UserDefinedFunction(this.Database, objectName) : new UserDefinedFunction(this.Database, objectName, schemaName);
|
||||
smoObject.Refresh();
|
||||
return smoObject.Script();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(LogLevel.Error,"Exception at PeekDefinition GetScalarValuedFunctionScripts : " + ex.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Script a TableValuedFunction using SMO
|
||||
/// </summary>
|
||||
/// <param name="objectName">TableValuedFunction name</param>
|
||||
/// <param name="schemaName">Schema name</param>
|
||||
/// <returns>String collection of scripts</returns>
|
||||
internal StringCollection GetTableValuedFunctionScripts(string objectName, string schemaName)
|
||||
{
|
||||
try
|
||||
{
|
||||
UserDefinedFunction smoObject = string.IsNullOrEmpty(schemaName) ? new UserDefinedFunction(this.Database, objectName) : new UserDefinedFunction(this.Database, objectName, schemaName);
|
||||
smoObject.Refresh();
|
||||
return smoObject.Script();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(LogLevel.Error,"Exception at PeekDefinition GetTableValuedFunctionScripts : " + ex.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
<#@ template debug="false" hostspecific="true" language="C#" #>
|
||||
<#@ output extension=".cs" #>
|
||||
<#@ assembly name="System.Xml.dll" #>
|
||||
<#@ import namespace="System" #>
|
||||
<#@ import namespace="System.Globalization" #>
|
||||
<#@ import namespace="System.Text" #>
|
||||
<#@ import namespace="System.Xml" #>
|
||||
<#@ import namespace="System.Collections.Generic" #>
|
||||
<#@ import namespace="System.IO" #>
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using Microsoft.SqlServer.Management.Smo;
|
||||
using Microsoft.SqlServer.Management.SqlParser.Intellisense;
|
||||
using Microsoft.SqlTools.ServiceLayer.Utility;
|
||||
namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
{
|
||||
internal partial class PeekDefinition
|
||||
{
|
||||
|
||||
<#
|
||||
///
|
||||
/// Generate Initialize method
|
||||
///
|
||||
var indent = " ";
|
||||
var directory = Path.GetDirectoryName(Host.TemplateFile);
|
||||
string xmlFile = Path.Combine(directory, "PeekDefinitionSupportedTypes.xml");
|
||||
var supportedTypes = GetSupportedTypes(xmlFile);
|
||||
if (supportedTypes != null && supportedTypes.Count > 0)
|
||||
{
|
||||
WriteLine("private void Initialize()");
|
||||
PushIndent(indent);
|
||||
PushIndent(indent);
|
||||
WriteLine("{");
|
||||
PushIndent(indent);
|
||||
foreach(var typeProperty in supportedTypes)
|
||||
{
|
||||
string functionCall = string.Format("AddSupportedType(DeclarationType.{0}, Get{0}Scripts, \"{1}\", \"{2}\");", typeProperty["Name"], typeProperty["CreateSyntax"], typeProperty["QuickInfoType"]);
|
||||
WriteLine(functionCall);
|
||||
}
|
||||
PopIndent();
|
||||
WriteLine("}\n");
|
||||
|
||||
///
|
||||
/// Generate scriptGetters for each type
|
||||
///
|
||||
|
||||
foreach(var typeProperty in supportedTypes)
|
||||
{
|
||||
string statement;
|
||||
// Write comments
|
||||
WriteLine("/// <summary>");
|
||||
WriteLine(string.Format("/// Script a {0} using SMO", typeProperty["Name"]));
|
||||
WriteLine("/// </summary>");
|
||||
WriteLine(string.Format("/// <param name=\"objectName\">{0} name</param>", typeProperty["Name"]));
|
||||
WriteLine(string.Format("/// <param name=\"schemaName\">Schema name</param>"));
|
||||
WriteLine("/// <returns>String collection of scripts</returns>");
|
||||
|
||||
WriteLine(string.Format("internal StringCollection Get{0}Scripts(string objectName, string schemaName)", typeProperty["Name"]));
|
||||
WriteLine("{");
|
||||
PushIndent(indent);
|
||||
|
||||
// Write try block to retrieve object and return script
|
||||
WriteLine("try");
|
||||
WriteLine("{");
|
||||
if(typeProperty["SupportsSchemaQuery"].IndexOf("true", StringComparison.OrdinalIgnoreCase) >= 0)
|
||||
{
|
||||
statement = string.Format("{0} smoObject = string.IsNullOrEmpty(schemaName) ? new {0}(this.Database, objectName) : new {0}(this.Database, objectName, schemaName);", typeProperty["AccessClass"]);
|
||||
}
|
||||
else
|
||||
{
|
||||
statement = string.Format("{0} smoObject = new {0}(this.Database, objectName);", typeProperty["Name"]);
|
||||
}
|
||||
PushIndent(indent);
|
||||
WriteLine(statement);
|
||||
WriteLine("smoObject.Refresh();");
|
||||
WriteLine("return smoObject.Script();");
|
||||
PopIndent();
|
||||
WriteLine("}");
|
||||
|
||||
// Write catch block to catch and log exceptions
|
||||
WriteLine("catch (Exception ex)");
|
||||
WriteLine("{");
|
||||
PushIndent(indent);
|
||||
statement = string.Format("LogLevel.Error,\"Exception at PeekDefinition Get{0}Scripts : \" + ex.Message", typeProperty["Name"]);
|
||||
WriteLine("Logger.Write(" + statement + ");");
|
||||
WriteLine("return null;");
|
||||
PopIndent();
|
||||
WriteLine("}");
|
||||
PopIndent();
|
||||
WriteLine("}\n");
|
||||
}
|
||||
}
|
||||
PopIndent();
|
||||
PopIndent();
|
||||
#>
|
||||
}
|
||||
}
|
||||
<#+
|
||||
///
|
||||
/// Get the supported types from the xml file
|
||||
///
|
||||
public static List<Dictionary<string, string>> GetSupportedTypes(string xmlFile)
|
||||
{
|
||||
List<Dictionary<string, string>> typeList = null;
|
||||
XmlDocument doc = new XmlDocument();
|
||||
doc.Load(xmlFile);
|
||||
XmlNodeList supportedTypes = doc.SelectNodes("/SupportedTypes/Type");
|
||||
if (supportedTypes != null)
|
||||
{
|
||||
typeList = new List<Dictionary<string, string>>();
|
||||
foreach (var type in supportedTypes)
|
||||
{
|
||||
XmlElement node = type as XmlElement;
|
||||
if (node != null)
|
||||
{
|
||||
string typeName = (node["Name"] != null) ? node["Name"].InnerText : null;
|
||||
string createSyntax = (node["CreateSyntax"] != null) ? node["CreateSyntax"].InnerText : null;
|
||||
string accessClass = (node["AccessClass"] != null) ? node["AccessClass"].InnerText : null;
|
||||
string supportsSchemaQuery = (node["SupportsSchemaQuery"] != null) ? node["SupportsSchemaQuery"].InnerText : null;
|
||||
string quickInfoType = (node["QuickInfoType"] != null) ? node["QuickInfoType"].InnerText : null;
|
||||
if (typeName != null && createSyntax != null && accessClass != null && supportsSchemaQuery!= null)
|
||||
{
|
||||
Dictionary<string, string> typeProperties = new Dictionary<string, string>();
|
||||
typeProperties.Add("Name", typeName);
|
||||
typeProperties.Add("CreateSyntax", createSyntax);
|
||||
typeProperties.Add("AccessClass", accessClass);
|
||||
typeProperties.Add("SupportsSchemaQuery", supportsSchemaQuery);
|
||||
typeProperties.Add("QuickInfoType", quickInfoType);
|
||||
typeList.Add(typeProperties);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
return typeList;
|
||||
}
|
||||
|
||||
#>
|
||||
@@ -0,0 +1,66 @@
|
||||
<!--
|
||||
For each supported type
|
||||
Name - As denoted in the Microsoft.SqlServer.Management.SqlParser.Intellisense.DeclarationType Enumeration for the object
|
||||
Create Syntax - The keyword used in the create t-sql statement for the object - e.g create TABLE, create PROCEDURE etc.
|
||||
AccessClass - The SMO class denoting the object e.g. Table, UserDefinedTableType etc.
|
||||
QuickInfoType - The type of the object as displayed in the Babel.CodeObjectQuickInfo.Text string (optional)
|
||||
SupportsSchemaQuery - Boolean denoting if the object can be queried/accessed using the schema name
|
||||
-->
|
||||
<SupportedTypes>
|
||||
<Type>
|
||||
<Name>Table</Name>
|
||||
<CreateSyntax>Table</CreateSyntax>
|
||||
<AccessClass>Table</AccessClass>
|
||||
<QuickInfoType>table</QuickInfoType>
|
||||
<SupportsSchemaQuery>true</SupportsSchemaQuery>
|
||||
</Type>
|
||||
<Type>
|
||||
<Name>View</Name>
|
||||
<CreateSyntax>View</CreateSyntax>
|
||||
<AccessClass>View</AccessClass>
|
||||
<QuickInfoType>view</QuickInfoType>
|
||||
<SupportsSchemaQuery>true</SupportsSchemaQuery>
|
||||
</Type>
|
||||
<Type>
|
||||
<Name>StoredProcedure</Name>
|
||||
<CreateSyntax>Procedure</CreateSyntax>
|
||||
<AccessClass>StoredProcedure</AccessClass>
|
||||
<QuickInfoType>stored procedure</QuickInfoType>
|
||||
<SupportsSchemaQuery>true</SupportsSchemaQuery>
|
||||
</Type>
|
||||
<Type>
|
||||
<Name>UserDefinedDataType</Name>
|
||||
<CreateSyntax>Type</CreateSyntax>
|
||||
<AccessClass>UserDefinedDataType</AccessClass>
|
||||
<QuickInfoType>user-defined data type</QuickInfoType>
|
||||
<SupportsSchemaQuery>true</SupportsSchemaQuery>
|
||||
</Type>
|
||||
<Type>
|
||||
<Name>UserDefinedTableType</Name>
|
||||
<CreateSyntax>Type</CreateSyntax>
|
||||
<AccessClass>UserDefinedTableType</AccessClass>
|
||||
<QuickInfoType>user-defined table type</QuickInfoType>
|
||||
<SupportsSchemaQuery>true</SupportsSchemaQuery>
|
||||
</Type>
|
||||
<Type>
|
||||
<Name>Synonym</Name>
|
||||
<CreateSyntax>Synonym</CreateSyntax>
|
||||
<AccessClass>Synonym</AccessClass>
|
||||
<QuickInfoType></QuickInfoType>
|
||||
<SupportsSchemaQuery>true</SupportsSchemaQuery>
|
||||
</Type>
|
||||
<Type>
|
||||
<Name>ScalarValuedFunction</Name>
|
||||
<CreateSyntax>Function</CreateSyntax>
|
||||
<AccessClass>UserDefinedFunction</AccessClass>
|
||||
<QuickInfoType>scalar-valued function</QuickInfoType>
|
||||
<SupportsSchemaQuery>true</SupportsSchemaQuery>
|
||||
</Type>
|
||||
<Type>
|
||||
<Name>TableValuedFunction</Name>
|
||||
<CreateSyntax>Function</CreateSyntax>
|
||||
<AccessClass>UserDefinedFunction</AccessClass>
|
||||
<QuickInfoType>table-valued function</QuickInfoType>
|
||||
<SupportsSchemaQuery>true</SupportsSchemaQuery>
|
||||
</Type>
|
||||
</SupportedTypes>
|
||||
@@ -4,29 +4,23 @@
|
||||
//
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.SqlServer.Management.Common;
|
||||
using Microsoft.SqlServer.Management.SqlParser.Binder;
|
||||
using Microsoft.SqlServer.Management.SqlParser.Intellisense;
|
||||
using Microsoft.SqlServer.Management.SqlParser.MetadataProvider;
|
||||
using Microsoft.SqlServer.Management.SqlParser.Parser;
|
||||
using Microsoft.SqlTools.ServiceLayer.Connection;
|
||||
using Microsoft.SqlServer.Management.SqlParser.MetadataProvider;
|
||||
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol;
|
||||
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.LanguageServices;
|
||||
using Microsoft.SqlTools.ServiceLayer.LanguageServices.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.LanguageServices.Completion;
|
||||
using Microsoft.SqlTools.ServiceLayer.SqlContext;
|
||||
using Microsoft.SqlTools.ServiceLayer.QueryExecution;
|
||||
using Microsoft.SqlTools.ServiceLayer.Test.QueryExecution;
|
||||
using Microsoft.SqlTools.ServiceLayer.Workspace;
|
||||
using Microsoft.SqlTools.ServiceLayer.Workspace.Contracts;
|
||||
using Microsoft.SqlTools.Test.Utility;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
using Location = Microsoft.SqlTools.ServiceLayer.Workspace.Contracts.Location;
|
||||
using Microsoft.SqlServer.Management.SqlParser.Intellisense;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServices
|
||||
{
|
||||
@@ -114,9 +108,10 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServices
|
||||
{
|
||||
Line = 0,
|
||||
// test for 'dbo'
|
||||
Character = 16
|
||||
Character = 15
|
||||
}
|
||||
};
|
||||
|
||||
TestConnectionResult connectionResult = await TestObjects.InitLiveConnectionInfo();
|
||||
connectionResult.ScriptFile.Contents = "select * from dbo.func ()";
|
||||
var languageService = new LanguageService();
|
||||
@@ -142,15 +137,20 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServices
|
||||
|
||||
PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo);
|
||||
string objectName = "from";
|
||||
|
||||
List<Declaration> declarations = new List<Declaration>();
|
||||
DefinitionResult result = peekDefinition.GetScript(declarations, objectName, null);
|
||||
Position position = new Position()
|
||||
{
|
||||
Line = 1,
|
||||
Character = 14
|
||||
};
|
||||
ScriptParseInfo scriptParseInfo = new ScriptParseInfo() { IsConnected = true };
|
||||
Mock<IBindingContext> bindingContextMock = new Mock<IBindingContext>();
|
||||
DefinitionResult result = peekDefinition.GetScript(scriptParseInfo.ParseResult, position, bindingContextMock.Object.MetadataDisplayInfoProvider, objectName, null);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.True(result.IsErrorResult);
|
||||
Assert.Equal(SR.PeekDefinitionNoResultsError, result.Message);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Test GetDefinition with a forced timeout. Expect a error result.
|
||||
/// </summary>
|
||||
@@ -164,9 +164,9 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServices
|
||||
ManualResetEvent mre = new ManualResetEvent(true); // Do not block
|
||||
Mock<QueueItem> itemMock = new Mock<QueueItem>();
|
||||
itemMock.Setup(i => i.ItemProcessed).Returns(mre);
|
||||
|
||||
|
||||
DefinitionResult timeoutResult = null;
|
||||
|
||||
|
||||
queueMock.Setup(q => q.QueueBindingOperation(
|
||||
It.IsAny<string>(),
|
||||
It.IsAny<Func<IBindingContext, CancellationToken, object>>(),
|
||||
@@ -174,7 +174,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServices
|
||||
It.IsAny<int?>(),
|
||||
It.IsAny<int?>()))
|
||||
.Callback<string, Func<IBindingContext, CancellationToken, object>, Func<IBindingContext, object>, int?, int?>(
|
||||
(key, bindOperation, timeoutOperation, blah, blah2) =>
|
||||
(key, bindOperation, timeoutOperation, t1, t2) =>
|
||||
{
|
||||
timeoutResult = (DefinitionResult) timeoutOperation((IBindingContext)null);
|
||||
itemMock.Object.Result = timeoutResult;
|
||||
@@ -306,6 +306,387 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServices
|
||||
Cleanup(locations);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test get definition for a scalar valued function object with active connection and explicit schema name. Expect non-null locations
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task GetScalarValuedFunctionDefinitionWithSchemaNameSuccessTest()
|
||||
{
|
||||
// Get live connectionInfo and serverConnection
|
||||
ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition();
|
||||
ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo);
|
||||
|
||||
PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo);
|
||||
string objectName = "pd_addTwo";
|
||||
string schemaName = "dbo";
|
||||
string objectType = "FUNCTION";
|
||||
|
||||
Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetScalarValuedFunctionScripts, objectName, schemaName, objectType);
|
||||
Assert.NotNull(locations);
|
||||
Cleanup(locations);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test get definition for a table valued function object with active connection and explicit schema name. Expect non-null locations
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task GetTableValuedFunctionDefinitionWithSchemaNameSuccessTest()
|
||||
{
|
||||
// Get live connectionInfo and serverConnection
|
||||
ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition();
|
||||
ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo);
|
||||
|
||||
PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo);
|
||||
string objectName = "pd_returnTable";
|
||||
string schemaName = "dbo";
|
||||
string objectType = "FUNCTION";
|
||||
|
||||
Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetTableValuedFunctionScripts, objectName, schemaName, objectType);
|
||||
Assert.NotNull(locations);
|
||||
Cleanup(locations);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test get definition for a scalar valued function object that doesn't exist with active connection. Expect null locations
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task GetScalarValuedFunctionDefinitionWithNonExistentFailureTest()
|
||||
{
|
||||
// Get live connectionInfo and serverConnection
|
||||
ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition();
|
||||
ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo);
|
||||
|
||||
PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo);
|
||||
string objectName = "doesNotExist";
|
||||
string schemaName = "dbo";
|
||||
string objectType = "FUNCTION";
|
||||
|
||||
Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetScalarValuedFunctionScripts, objectName, schemaName, objectType);
|
||||
Assert.Null(locations);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test get definition for a table valued function object that doesn't exist with active connection. Expect null locations
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task GetTableValuedFunctionDefinitionWithNonExistentObjectFailureTest()
|
||||
{
|
||||
// Get live connectionInfo and serverConnection
|
||||
ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition();
|
||||
ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo);
|
||||
|
||||
PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo);
|
||||
string objectName = "doesNotExist";
|
||||
string schemaName = "dbo";
|
||||
string objectType = "FUNCTION";
|
||||
|
||||
Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetTableValuedFunctionScripts, objectName, schemaName, objectType);
|
||||
Assert.Null(locations);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test get definition for a scalar valued function object with active connection. Expect non-null locations
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task GetScalarValuedFunctionDefinitionWithoutSchemaNameSuccessTest()
|
||||
{
|
||||
// Get live connectionInfo and serverConnection
|
||||
ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition();
|
||||
ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo);
|
||||
|
||||
PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo);
|
||||
string objectName = "pd_addTwo";
|
||||
string schemaName = null;
|
||||
string objectType = "FUNCTION";
|
||||
|
||||
Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetScalarValuedFunctionScripts, objectName, schemaName, objectType);
|
||||
Assert.NotNull(locations);
|
||||
Cleanup(locations);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test get definition for a table valued function object with active connection. Expect non-null locations
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task GetTableValuedFunctionDefinitionWithoutSchemaNameSuccessTest()
|
||||
{
|
||||
// Get live connectionInfo and serverConnection
|
||||
ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition();
|
||||
ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo);
|
||||
|
||||
PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo);
|
||||
string objectName = "pd_returnTable";
|
||||
string schemaName = null;
|
||||
string objectType = "FUNCTION";
|
||||
|
||||
Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetTableValuedFunctionScripts, objectName, schemaName, objectType);
|
||||
Assert.NotNull(locations);
|
||||
Cleanup(locations);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Test get definition for a user defined data type object with active connection and explicit schema name. Expect non-null locations
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task GetUserDefinedDataTypeDefinitionWithSchemaNameSuccessTest()
|
||||
{
|
||||
// Get live connectionInfo and serverConnection
|
||||
ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition();
|
||||
ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo);
|
||||
|
||||
PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo);
|
||||
string objectName = "pd_ssn";
|
||||
string schemaName = "dbo";
|
||||
string objectType = "Type";
|
||||
|
||||
Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetUserDefinedDataTypeScripts, objectName, schemaName, objectType);
|
||||
Assert.NotNull(locations);
|
||||
Cleanup(locations);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test get definition for a user defined data type object with active connection. Expect non-null locations
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task GetUserDefinedDataTypeDefinitionWithoutSchemaNameSuccessTest()
|
||||
{
|
||||
// Get live connectionInfo and serverConnection
|
||||
ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition();
|
||||
ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo);
|
||||
|
||||
PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo);
|
||||
string objectName = "pd_ssn";
|
||||
string schemaName = null;
|
||||
string objectType = "Type";
|
||||
|
||||
Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetUserDefinedDataTypeScripts, objectName, schemaName, objectType);
|
||||
Assert.NotNull(locations);
|
||||
Cleanup(locations);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test get definition for a user defined data type object that doesn't exist with active connection. Expect null locations
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task GetUserDefinedDataTypeDefinitionWithNonExistentFailureTest()
|
||||
{
|
||||
// Get live connectionInfo and serverConnection
|
||||
ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition();
|
||||
ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo);
|
||||
|
||||
PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo);
|
||||
string objectName = "doesNotExist";
|
||||
string schemaName = "dbo";
|
||||
string objectType = "Type";
|
||||
|
||||
Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetUserDefinedDataTypeScripts, objectName, schemaName, objectType);
|
||||
Assert.Null(locations);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test get definition for a user defined table type object with active connection and explicit schema name. Expect non-null locations
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task GetUserDefinedTableTypeDefinitionWithSchemaNameSuccessTest()
|
||||
{
|
||||
// Get live connectionInfo and serverConnection
|
||||
ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition();
|
||||
ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo);
|
||||
|
||||
PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo);
|
||||
string objectName = "pd_locationTableType";
|
||||
string schemaName = "dbo";
|
||||
string objectType = "Type";
|
||||
|
||||
Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetUserDefinedTableTypeScripts, objectName, schemaName, objectType);
|
||||
Assert.NotNull(locations);
|
||||
Cleanup(locations);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test get definition for a user defined table type object with active connection. Expect non-null locations
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task GetUserDefinedTableTypeDefinitionWithoutSchemaNameSuccessTest()
|
||||
{
|
||||
// Get live connectionInfo and serverConnection
|
||||
ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition();
|
||||
ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo);
|
||||
|
||||
PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo);
|
||||
string objectName = "pd_locationTableType";
|
||||
string schemaName = null;
|
||||
string objectType = "Type";
|
||||
|
||||
Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetUserDefinedTableTypeScripts, objectName, schemaName, objectType);
|
||||
Assert.NotNull(locations);
|
||||
Cleanup(locations);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test get definition for a user defined table type object that doesn't exist with active connection. Expect null locations
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task GetUserDefinedTableTypeDefinitionWithNonExistentFailureTest()
|
||||
{
|
||||
// Get live connectionInfo and serverConnection
|
||||
ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition();
|
||||
ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo);
|
||||
|
||||
PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo);
|
||||
string objectName = "doesNotExist";
|
||||
string schemaName = "dbo";
|
||||
string objectType = "Type";
|
||||
|
||||
Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetUserDefinedTableTypeScripts, objectName, schemaName, objectType);
|
||||
Assert.Null(locations);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test get definition for a synonym object with active connection and explicit schema name. Expect non-null locations
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task GetSynonymDefinitionWithSchemaNameSuccessTest()
|
||||
{
|
||||
// Get live connectionInfo and serverConnection
|
||||
ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition();
|
||||
ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo);
|
||||
|
||||
PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo);
|
||||
string objectName = "pd_testTable";
|
||||
string schemaName = "dbo";
|
||||
string objectType = "Synonym";
|
||||
|
||||
Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetSynonymScripts, objectName, schemaName, objectType);
|
||||
Assert.NotNull(locations);
|
||||
Cleanup(locations);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Test get definition for a Synonym object with active connection. Expect non-null locations
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task GetSynonymDefinitionWithoutSchemaNameSuccessTest()
|
||||
{
|
||||
// Get live connectionInfo and serverConnection
|
||||
ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition();
|
||||
ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo);
|
||||
|
||||
PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo);
|
||||
string objectName = "pd_testTable";
|
||||
string schemaName = null;
|
||||
string objectType = "Synonym";
|
||||
|
||||
Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetSynonymScripts, objectName, schemaName, objectType);
|
||||
Assert.NotNull(locations);
|
||||
Cleanup(locations);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test get definition for a Synonym object that doesn't exist with active connection. Expect null locations
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task GetSynonymDefinitionWithNonExistentFailureTest()
|
||||
{
|
||||
// Get live connectionInfo and serverConnection
|
||||
ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition();
|
||||
ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo);
|
||||
|
||||
PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo);
|
||||
string objectName = "doesNotExist";
|
||||
string schemaName = "dbo";
|
||||
string objectType = "Synonym";
|
||||
|
||||
Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetSynonymScripts, objectName, schemaName, objectType);
|
||||
Assert.Null(locations);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test get definition using declaration type for a view object with active connection
|
||||
/// Expect a non-null result with location
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task GetDefinitionUsingDeclarationTypeWithValidObjectTest()
|
||||
{
|
||||
ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition();
|
||||
ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo);
|
||||
|
||||
PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo);
|
||||
string objectName = "objects";
|
||||
string schemaName = "sys";
|
||||
|
||||
DefinitionResult result = peekDefinition.GetDefinitionUsingDeclarationType(DeclarationType.View, "master.sys.objects", objectName, schemaName);
|
||||
Assert.NotNull(result);
|
||||
Assert.NotNull(result.Locations);
|
||||
Assert.False(result.IsErrorResult);
|
||||
Cleanup(result.Locations);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test get definition using declaration type for a non existent view object with active connection
|
||||
/// Expect a non-null result with location
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task GetDefinitionUsingDeclarationTypeWithNonexistentObjectTest()
|
||||
{
|
||||
ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition();
|
||||
ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo);
|
||||
|
||||
PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo);
|
||||
string objectName = "doesNotExist";
|
||||
string schemaName = "sys";
|
||||
|
||||
DefinitionResult result = peekDefinition.GetDefinitionUsingDeclarationType(DeclarationType.View, "master.sys.objects", objectName, schemaName);
|
||||
Assert.NotNull(result);
|
||||
Assert.True(result.IsErrorResult);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test get definition using quickInfo text for a view object with active connection
|
||||
/// Expect a non-null result with location
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task GetDefinitionUsingQuickInfoTextWithValidObjectTest()
|
||||
{
|
||||
ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition();
|
||||
ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo);
|
||||
|
||||
PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo);
|
||||
string objectName = "objects";
|
||||
string schemaName = "sys";
|
||||
string quickInfoText = "view master.sys.objects";
|
||||
|
||||
DefinitionResult result = peekDefinition.GetDefinitionUsingQuickInfoText(quickInfoText, objectName, schemaName);
|
||||
Assert.NotNull(result);
|
||||
Assert.NotNull(result.Locations);
|
||||
Assert.False(result.IsErrorResult);
|
||||
Cleanup(result.Locations);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test get definition using quickInfo text for a view object with active connection
|
||||
/// Expect a non-null result with location
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task GetDefinitionUsingQuickInfoTextWithNonexistentObjectTest()
|
||||
{
|
||||
ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition();
|
||||
ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo);
|
||||
|
||||
PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo);
|
||||
string objectName = "doesNotExist";
|
||||
string schemaName = "sys";
|
||||
string quickInfoText = "view master.sys.objects";
|
||||
|
||||
DefinitionResult result = peekDefinition.GetDefinitionUsingQuickInfoText(quickInfoText, objectName, schemaName);
|
||||
Assert.NotNull(result);
|
||||
Assert.True(result.IsErrorResult);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to clean up script files
|
||||
/// </summary>
|
||||
|
||||
@@ -220,7 +220,155 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.LanguageServices
|
||||
FileUtils.SafeDirectoryDelete(FileUtils.PeekDefinitionTempFolder, true);
|
||||
Assert.False(Directory.Exists(FileUtils.PeekDefinitionTempFolder));
|
||||
// Expected not to throw any exception
|
||||
languageService.DeletePeekDefinitionScripts();
|
||||
languageService.DeletePeekDefinitionScripts();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test Extracting the full object name from quickInfoText.
|
||||
/// Given a valid object name string and a vaild quickInfo string containing the object name
|
||||
/// Expect the full object name (database.schema.objectName)
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void GetFullObjectNameFromQuickInfoWithValidStringsTest()
|
||||
{
|
||||
PeekDefinition peekDefinition = new PeekDefinition(null, null);
|
||||
string objectName = "testTable";
|
||||
string quickInfoText = "table master.dbo.testTable";
|
||||
string result = peekDefinition.GetFullObjectNameFromQuickInfo(quickInfoText, objectName);
|
||||
string expected = "master.dbo.testTable";
|
||||
Assert.Equal(expected, result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test Extracting the full object name from quickInfoText.
|
||||
/// Given a null object name string and a vaild quickInfo string containing the object name( and vice versa)
|
||||
/// Expect null
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void GetFullObjectNameFromQuickInfoWithNullStringsTest()
|
||||
{
|
||||
PeekDefinition peekDefinition = new PeekDefinition(null, null);
|
||||
string expected = null;
|
||||
|
||||
string objectName = null;
|
||||
string quickInfoText = "table master.dbo.testTable";
|
||||
string result = peekDefinition.GetFullObjectNameFromQuickInfo(quickInfoText, objectName);
|
||||
Assert.Equal(expected, result);
|
||||
|
||||
quickInfoText = null;
|
||||
objectName = "tableName";
|
||||
result = peekDefinition.GetFullObjectNameFromQuickInfo(quickInfoText, objectName);
|
||||
Assert.Equal(expected, result);
|
||||
|
||||
quickInfoText = null;
|
||||
objectName = null;
|
||||
result = peekDefinition.GetFullObjectNameFromQuickInfo(quickInfoText, objectName);
|
||||
Assert.Equal(expected, result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test Extracting the full object name from quickInfoText.
|
||||
/// Given a valid object name string and a vaild quickInfo string that does not contain the object name
|
||||
/// Expect null
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void GetFullObjectNameFromQuickInfoWithIncorrectObjectNameTest()
|
||||
{
|
||||
PeekDefinition peekDefinition = new PeekDefinition(null, null);
|
||||
string objectName = "test";
|
||||
string quickInfoText = "table master.dbo.tableName";
|
||||
string result = peekDefinition.GetFullObjectNameFromQuickInfo(quickInfoText, objectName);
|
||||
string expected = null;
|
||||
Assert.Equal(expected, result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test Extracting the object type from quickInfoText.
|
||||
/// Given a valid object name string and a vaild quickInfo string containing the object name
|
||||
/// Expect correct object type
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void GetTokenTypeFromQuickInfoWithValidStringsTest()
|
||||
{
|
||||
PeekDefinition peekDefinition = new PeekDefinition(null, null);
|
||||
string objectName = "tableName";
|
||||
string quickInfoText = "table master.dbo.tableName";
|
||||
string result = peekDefinition.GetTokenTypeFromQuickInfo(quickInfoText, objectName);
|
||||
string expected = "table";
|
||||
Assert.Equal(expected, result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test Extracting theobject type from quickInfoText.
|
||||
/// Given a null object name string and a vaild quickInfo string containing the object name( and vice versa)
|
||||
/// Expect null
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void GetTokenTypeFromQuickInfoWithNullStringsTest()
|
||||
{
|
||||
PeekDefinition peekDefinition = new PeekDefinition(null, null);
|
||||
string expected = null;
|
||||
|
||||
string objectName = null;
|
||||
string quickInfoText = "table master.dbo.testTable";
|
||||
string result = peekDefinition.GetTokenTypeFromQuickInfo(quickInfoText, objectName);
|
||||
Assert.Equal(expected, result);
|
||||
|
||||
quickInfoText = null;
|
||||
objectName = "tableName";
|
||||
result = peekDefinition.GetTokenTypeFromQuickInfo(quickInfoText, objectName);
|
||||
Assert.Equal(expected, result);
|
||||
|
||||
quickInfoText = null;
|
||||
objectName = null;
|
||||
result = peekDefinition.GetTokenTypeFromQuickInfo(quickInfoText, objectName);
|
||||
Assert.Equal(expected, result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test Extracting the object type from quickInfoText.
|
||||
/// Given a valid object name string and a vaild quickInfo string that does not containthe object name
|
||||
/// Expect null
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void GetTokenTypeFromQuickInfoWithIncorrectObjectNameTest()
|
||||
{
|
||||
PeekDefinition peekDefinition = new PeekDefinition(null, null);
|
||||
string objectName = "test";
|
||||
string quickInfoText = "table master.dbo.tableName";
|
||||
string result = peekDefinition.GetTokenTypeFromQuickInfo(quickInfoText, objectName);
|
||||
string expected = null;
|
||||
Assert.Equal(expected, result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// test Getting definition using quickInfo text without a live connection
|
||||
/// Expect an error result( because you cannot script without a live connection)
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void GetDefinitionUsingQuickInfoWithoutConnectionTest()
|
||||
{
|
||||
PeekDefinition peekDefinition = new PeekDefinition(null, null);
|
||||
string objectName = "tableName";
|
||||
string quickInfoText = "table master.dbo.tableName";
|
||||
DefinitionResult result = peekDefinition.GetDefinitionUsingQuickInfoText(quickInfoText, objectName, null);
|
||||
Assert.NotNull(result);
|
||||
Assert.True(result.IsErrorResult);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// test Getting definition using declarration Type without a live connection
|
||||
/// Expect an error result( because you cannot script without a live connection)
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void GetDefinitionUsingDeclarationItemWithoutConnectionTest()
|
||||
{
|
||||
PeekDefinition peekDefinition = new PeekDefinition(null, null);
|
||||
string objectName = "tableName";
|
||||
string fullObjectName = "master.dbo.tableName";
|
||||
DefinitionResult result = peekDefinition.GetDefinitionUsingDeclarationType(DeclarationType.Table, fullObjectName, objectName, null);
|
||||
Assert.NotNull(result);
|
||||
Assert.True(result.IsErrorResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
|
||||
};
|
||||
|
||||
await testService.RequestOpenDocumentNotification(openParams);
|
||||
|
||||
|
||||
Thread.Sleep(500);
|
||||
|
||||
bool connected = await testService.Connect(TestServerType.OnPrem, queryTempFile.FilePath);
|
||||
@@ -86,7 +86,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
|
||||
};
|
||||
|
||||
await testService.RequestOpenDocumentNotification(openParams);
|
||||
|
||||
|
||||
Thread.Sleep(500);
|
||||
|
||||
bool connected = await testService.Connect(TestServerType.OnPrem, queryTempFile.FilePath);
|
||||
@@ -136,7 +136,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
|
||||
};
|
||||
|
||||
await testService.RequestOpenDocumentNotification(openParams);
|
||||
|
||||
|
||||
Thread.Sleep(100);
|
||||
|
||||
var contentChanges = new TextDocumentChangeEvent[1];
|
||||
@@ -172,7 +172,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
|
||||
await testService.RequestChangeTextDocumentNotification(changeParams);
|
||||
|
||||
Thread.Sleep(100);
|
||||
|
||||
|
||||
contentChanges[0] = new TextDocumentChangeEvent
|
||||
{
|
||||
Range = new Range
|
||||
@@ -211,7 +211,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Peek Definition/ Go to definition
|
||||
/// Peek Definition/ Go to definition
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[Fact]
|
||||
@@ -238,16 +238,20 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
|
||||
};
|
||||
|
||||
await testService.RequestOpenDocumentNotification(openParams);
|
||||
|
||||
|
||||
Thread.Sleep(500);
|
||||
|
||||
bool connected = await testService.Connect(TestServerType.OnPrem, queryTempFile.FilePath);
|
||||
|
||||
// Wait for intellisense to be ready
|
||||
var readyParams = await testService.Driver.WaitForEvent(IntelliSenseReadyNotification.Type, 30000);
|
||||
Assert.NotNull(readyParams);
|
||||
Assert.True(connected, "Connection is successful");
|
||||
|
||||
Thread.Sleep(10000);
|
||||
|
||||
// Request definition for "objects"
|
||||
Location[] locations = await testService.RequestDefinition(queryTempFile.FilePath, query, lineNumber, position);
|
||||
|
||||
|
||||
Assert.True(locations != null, "Location is not null and not empty");
|
||||
await testService.Disconnect(queryTempFile.FilePath);
|
||||
}
|
||||
@@ -265,7 +269,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
|
||||
bool connected = await testService.Connect(TestServerType.OnPrem, queryTempFile.FilePath);
|
||||
Assert.True(connected, "Connection was not successful");
|
||||
|
||||
Thread.Sleep(500);
|
||||
Thread.Sleep(500);
|
||||
|
||||
var settings = new SqlToolsSettings();
|
||||
settings.SqlTools.IntelliSense.EnableIntellisense = false;
|
||||
@@ -422,10 +426,10 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
|
||||
|
||||
public async Task VerifyFunctionSignatureHelpParameter(
|
||||
TestServiceDriverProvider TestService,
|
||||
string ownerUri,
|
||||
int character,
|
||||
string expectedFunctionName,
|
||||
int expectedParameterIndex,
|
||||
string ownerUri,
|
||||
int character,
|
||||
string expectedFunctionName,
|
||||
int expectedParameterIndex,
|
||||
string expectedParameterName)
|
||||
{
|
||||
var position = new TextDocumentPosition()
|
||||
|
||||
Reference in New Issue
Block a user