diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceBase.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceBase.cs
index adb9bcf6..aff69352 100644
--- a/src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceBase.cs
+++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceBase.cs
@@ -7,9 +7,12 @@ using System.Collections.Generic;
using System.Threading;
using System.Data;
using System.Threading.Tasks;
-using Kusto.Language;
+using Microsoft.Kusto.ServiceLayer.DataSource.Intellisense;
using Microsoft.Kusto.ServiceLayer.Utility;
using Microsoft.Kusto.ServiceLayer.DataSource.Metadata;
+using Microsoft.Kusto.ServiceLayer.LanguageServices;
+using Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts;
+using Microsoft.Kusto.ServiceLayer.Workspace.Contracts;
namespace Microsoft.Kusto.ServiceLayer.DataSource
{
@@ -88,6 +91,14 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
public abstract string GenerateAlterFunctionScript(string functionName);
public abstract string GenerateExecuteFunctionScript(string functionName);
+ public abstract ScriptFileMarker[] GetSemanticMarkers(ScriptParseInfo parseInfo, ScriptFile scriptFile, string queryText);
+
+ public abstract DefinitionResult GetDefinition(string queryText, int index, int startLine, int startColumn, bool throwOnError = false);
+
+ public abstract Hover GetHoverHelp(ScriptDocumentInfo scriptDocumentInfo, Position textPosition, bool throwOnError = false);
+
+ public abstract CompletionItem[] GetAutoCompleteSuggestions(ScriptDocumentInfo scriptDocumentInfo, Position textPosition,
+ bool throwOnError = false);
///
public DataSourceType DataSourceType { get; protected set; }
@@ -96,7 +107,6 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
public abstract string ClusterName { get; }
public abstract string DatabaseName { get; }
- public abstract GlobalState SchemaState { get; }
#endregion
}
diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceFactory.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceFactory.cs
index e54809db..24b27736 100644
--- a/src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceFactory.cs
+++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceFactory.cs
@@ -5,10 +5,10 @@ using Kusto.Data;
using Microsoft.Kusto.ServiceLayer.Connection.Contracts;
using Microsoft.Kusto.ServiceLayer.DataSource.Contracts;
using Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection;
-using Microsoft.Kusto.ServiceLayer.DataSource.DataSourceIntellisense;
+using Microsoft.Kusto.ServiceLayer.DataSource.Intellisense;
+using Microsoft.Kusto.ServiceLayer.LanguageServices;
using Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts;
using Microsoft.Kusto.ServiceLayer.Workspace.Contracts;
-using Microsoft.Kusto.ServiceLayer.LanguageServices.Completion;
using Microsoft.Kusto.ServiceLayer.Utility;
namespace Microsoft.Kusto.ServiceLayer.DataSource
@@ -26,7 +26,8 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
{
var kustoConnectionDetails = MapKustoConnectionDetails(connectionDetails);
var kustoClient = new KustoClient(kustoConnectionDetails, ownerUri);
- return new KustoDataSource(kustoClient);
+ var intellisenseClient = new KustoIntellisenseClient(kustoClient);
+ return new KustoDataSource(kustoClient, intellisenseClient);
}
default:
diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/IDataSource.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/IDataSource.cs
index 7429016f..13f777a2 100644
--- a/src/Microsoft.Kusto.ServiceLayer/DataSource/IDataSource.cs
+++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/IDataSource.cs
@@ -3,8 +3,11 @@ using System.Collections.Generic;
using System.Data;
using System.Threading;
using System.Threading.Tasks;
-using Kusto.Language;
+using Microsoft.Kusto.ServiceLayer.DataSource.Intellisense;
using Microsoft.Kusto.ServiceLayer.DataSource.Metadata;
+using Microsoft.Kusto.ServiceLayer.LanguageServices;
+using Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts;
+using Microsoft.Kusto.ServiceLayer.Workspace.Contracts;
namespace Microsoft.Kusto.ServiceLayer.DataSource
{
@@ -27,8 +30,6 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
/// The current database name, if there is one.
///
string DatabaseName { get; }
-
- GlobalState SchemaState { get; }
///
/// Executes a query.
@@ -111,5 +112,10 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
///
///
string GenerateExecuteFunctionScript(string functionName);
+
+ ScriptFileMarker[] GetSemanticMarkers(ScriptParseInfo parseInfo, ScriptFile scriptFile, string queryText);
+ DefinitionResult GetDefinition(string queryText, int index, int startLine, int startColumn, bool throwOnError = false);
+ Hover GetHoverHelp(ScriptDocumentInfo scriptDocumentInfo, Position textPosition, bool throwOnError = false);
+ CompletionItem[] GetAutoCompleteSuggestions(ScriptDocumentInfo scriptDocumentInfo, Position textPosition, bool throwOnError = false);
}
}
\ No newline at end of file
diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/IKustoClient.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/IKustoClient.cs
index de2bed90..9be38305 100644
--- a/src/Microsoft.Kusto.ServiceLayer/DataSource/IKustoClient.cs
+++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/IKustoClient.cs
@@ -2,17 +2,11 @@ using System.Collections.Generic;
using System.Data;
using System.Threading;
using System.Threading.Tasks;
-using Kusto.Language;
namespace Microsoft.Kusto.ServiceLayer.DataSource
{
public interface IKustoClient
{
- ///
- /// SchemaState used for getting intellisense info.
- ///
- GlobalState SchemaState { get; }
-
string ClusterName { get; }
string DatabaseName { get; }
diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/Intellisense/IIntellisenseClient.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/Intellisense/IIntellisenseClient.cs
new file mode 100644
index 00000000..9c373ab6
--- /dev/null
+++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/Intellisense/IIntellisenseClient.cs
@@ -0,0 +1,15 @@
+using Microsoft.Kusto.ServiceLayer.LanguageServices;
+using Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts;
+using Microsoft.Kusto.ServiceLayer.Workspace.Contracts;
+
+namespace Microsoft.Kusto.ServiceLayer.DataSource.Intellisense
+{
+ public interface IIntellisenseClient
+ {
+ void UpdateDatabase(string databaseName);
+ ScriptFileMarker[] GetSemanticMarkers(ScriptParseInfo parseInfo, ScriptFile scriptFile, string queryText);
+ DefinitionResult GetDefinition(string queryText, int index, int startLine, int startColumn, bool throwOnError = false);
+ Hover GetHoverHelp(ScriptDocumentInfo scriptDocumentInfo, Position textPosition, bool throwOnError = false);
+ CompletionItem[] GetAutoCompleteSuggestions(ScriptDocumentInfo scriptDocumentInfo, Position textPosition, bool throwOnError = false);
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceIntellisense/KustoIntellisenseHelper.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/Intellisense/KustoIntellisenseClient.cs
similarity index 55%
rename from src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceIntellisense/KustoIntellisenseHelper.cs
rename to src/Microsoft.Kusto.ServiceLayer/DataSource/Intellisense/KustoIntellisenseClient.cs
index d5533106..8345c056 100644
--- a/src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceIntellisense/KustoIntellisenseHelper.cs
+++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/Intellisense/KustoIntellisenseClient.cs
@@ -1,32 +1,141 @@
-//
-// 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.Collections.Generic;
using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
using Kusto.Language;
-using KustoDiagnostic = Kusto.Language.Diagnostic;
using Kusto.Language.Editor;
-using Kusto.Language.Syntax;
using Kusto.Language.Symbols;
+using Kusto.Language.Syntax;
using Microsoft.Kusto.ServiceLayer.LanguageServices;
using Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts;
-using Microsoft.Kusto.ServiceLayer.LanguageServices.Completion;
using Microsoft.Kusto.ServiceLayer.Workspace.Contracts;
+using Diagnostic = Kusto.Language.Diagnostic;
-namespace Microsoft.Kusto.ServiceLayer.DataSource.DataSourceIntellisense
+namespace Microsoft.Kusto.ServiceLayer.DataSource.Intellisense
{
- ///
- /// Kusto specific class for intellisense helper functions.
- ///
- public class KustoIntellisenseHelper
+ public class KustoIntellisenseClient : IIntellisenseClient
{
+ private readonly IKustoClient _kustoClient;
+
+ ///
+ /// SchemaState used for getting intellisense info.
+ ///
+ private GlobalState _schemaState;
+
+ public KustoIntellisenseClient(IKustoClient kustoClient)
+ {
+ _kustoClient = kustoClient;
+ _schemaState = LoadSchemaState(kustoClient.DatabaseName, kustoClient.ClusterName);
+ }
+
+ public void UpdateDatabase(string databaseName)
+ {
+ _schemaState = LoadSchemaState(databaseName, _kustoClient.ClusterName);
+ }
+
+ private GlobalState LoadSchemaState(string databaseName, string clusterName)
+ {
+ IEnumerable tableSchemas = Enumerable.Empty();
+ IEnumerable functionSchemas = Enumerable.Empty();
+
+ if (!string.IsNullOrWhiteSpace(databaseName))
+ {
+ var source = new CancellationTokenSource();
+ Parallel.Invoke(() =>
+ {
+ tableSchemas =
+ _kustoClient.ExecuteQueryAsync($".show database {databaseName} schema", source.Token, databaseName)
+ .Result;
+ },
+ () =>
+ {
+ functionSchemas = _kustoClient.ExecuteQueryAsync(".show functions", source.Token, databaseName).Result;
+ });
+ }
+
+ return AddOrUpdateDatabase(tableSchemas, functionSchemas, GlobalState.Default, databaseName,
+ clusterName);
+ }
+
+ ///
+ /// Loads the schema for the specified database and returns a new with the database added or updated.
+ ///
+ private GlobalState AddOrUpdateDatabase(IEnumerable tableSchemas,
+ IEnumerable functionSchemas, GlobalState globals,
+ string databaseName, string clusterName)
+ {
+ // try and show error from here.
+ DatabaseSymbol databaseSymbol = null;
+
+ if (databaseName != null)
+ {
+ databaseSymbol = LoadDatabase(tableSchemas, functionSchemas, databaseName);
+ }
+
+ if (databaseSymbol == null)
+ {
+ return globals;
+ }
+
+ var cluster = globals.GetCluster(clusterName);
+ if (cluster == null)
+ {
+ cluster = new ClusterSymbol(clusterName, new[] {databaseSymbol}, isOpen: true);
+ globals = globals.AddOrUpdateCluster(cluster);
+ }
+ else
+ {
+ cluster = cluster.AddOrUpdateDatabase(databaseSymbol);
+ globals = globals.AddOrUpdateCluster(cluster);
+ }
+
+ return globals.WithCluster(cluster).WithDatabase(databaseSymbol);
+ }
+
+ ///
+ /// Loads the schema for the specified database into a .
+ ///
+ private DatabaseSymbol LoadDatabase(IEnumerable tableSchemas,
+ IEnumerable functionSchemas,
+ string databaseName)
+ {
+ if (tableSchemas == null)
+ {
+ return null;
+ }
+
+ tableSchemas = tableSchemas
+ .Where(r => !string.IsNullOrEmpty(r.TableName) && !string.IsNullOrEmpty(r.ColumnName))
+ .ToArray();
+
+ var members = new List();
+ foreach (var table in tableSchemas.GroupBy(s => s.TableName))
+ {
+ var columns = table.Select(s => new ColumnSymbol(s.ColumnName, GetKustoType(s.ColumnType))).ToList();
+ var tableSymbol = new TableSymbol(table.Key, columns);
+ members.Add(tableSymbol);
+ }
+
+ if (functionSchemas == null)
+ {
+ return null;
+ }
+
+ foreach (var fun in functionSchemas)
+ {
+ var parameters = TranslateParameters(fun.Parameters);
+ var functionSymbol = new FunctionSymbol(fun.Name, fun.Body, parameters);
+ members.Add(functionSymbol);
+ }
+
+ return new DatabaseSymbol(databaseName, members);
+ }
+
///
/// Convert CLR type name into a Kusto scalar type.
///
- private static ScalarSymbol GetKustoType(string clrTypeName)
+ private ScalarSymbol GetKustoType(string clrTypeName)
{
switch (clrTypeName)
{
@@ -96,220 +205,121 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource.DataSourceIntellisense
throw new InvalidOperationException($"Unhandled clr type: {clrTypeName}");
}
}
-
- private static IReadOnlyList NoParameters = new Parameter[0];
-
+
///
/// Translate Kusto parameter list declaration into into list of instances.
///
- private static IReadOnlyList TranslateParameters(string parameters)
+ private IReadOnlyList TranslateParameters(string parameters)
{
parameters = parameters.Trim();
if (string.IsNullOrEmpty(parameters) || parameters == "()")
- return NoParameters;
+ {
+ return new Parameter[0];
+ }
if (parameters[0] != '(')
+ {
parameters = "(" + parameters;
+ }
+
if (parameters[parameters.Length - 1] != ')')
+ {
parameters = parameters + ")";
+ }
var query = "let fn = " + parameters + " { };";
var code = KustoCode.ParseAndAnalyze(query);
var let = code.Syntax.GetFirstDescendant();
- FunctionSymbol function = let.Name.ReferencedSymbol is VariableSymbol variable
+ FunctionSymbol function = let.Name.ReferencedSymbol is VariableSymbol variable
? variable.Type as FunctionSymbol
: let.Name.ReferencedSymbol as FunctionSymbol;
return function.Signatures[0].Parameters;
}
- ///
- /// Loads the schema for the specified databasea into a a .
- ///
- private static DatabaseSymbol LoadDatabaseAsync(IEnumerable tableSchemas,
- IEnumerable functionSchemas,
- string databaseName)
+ public ScriptFileMarker[] GetSemanticMarkers(ScriptParseInfo parseInfo, ScriptFile scriptFile, string queryText)
{
- if (tableSchemas == null)
+ var kustoCodeService = new KustoCodeService(queryText, _schemaState);
+ var script = CodeScript.From(queryText, _schemaState);
+ var parseResult = new List();
+
+ foreach (var codeBlock in script.Blocks)
{
- return null;
+ parseResult.AddRange(codeBlock.Service.GetDiagnostics());
}
- tableSchemas = tableSchemas
- .Where(r => !string.IsNullOrEmpty(r.TableName) && !string.IsNullOrEmpty(r.ColumnName))
- .ToArray();
-
- var members = new List();
- foreach (var table in tableSchemas.GroupBy(s => s.TableName))
- {
- var columns = table.Select(s => new ColumnSymbol(s.ColumnName, GetKustoType(s.ColumnType))).ToList();
- var tableSymbol = new TableSymbol(table.Key, columns);
- members.Add(tableSymbol);
- }
-
- if (functionSchemas == null)
- {
- return null;
- }
-
- foreach (var fun in functionSchemas)
- {
- var parameters = TranslateParameters(fun.Parameters);
- var functionSymbol = new FunctionSymbol(fun.Name, fun.Body, parameters);
- members.Add(functionSymbol);
- }
-
- return new DatabaseSymbol(databaseName, members);
- }
-
- public static CompletionItemKind CreateCompletionItemKind(CompletionKind kustoKind)
- {
- CompletionItemKind kind = CompletionItemKind.Variable;
- switch (kustoKind)
- {
- case CompletionKind.Syntax:
- kind = CompletionItemKind.Module;
- break;
- case CompletionKind.Column:
- kind = CompletionItemKind.Field;
- break;
- case CompletionKind.Variable:
- kind = CompletionItemKind.Variable;
- break;
- case CompletionKind.Table:
- kind = CompletionItemKind.File;
- break;
- case CompletionKind.Database:
- kind = CompletionItemKind.Method;
- break;
- case CompletionKind.LocalFunction:
- case CompletionKind.DatabaseFunction:
- case CompletionKind.BuiltInFunction:
- case CompletionKind.AggregateFunction:
- kind = CompletionItemKind.Function;
- break;
- default:
- kind = CompletionItemKind.Keyword;
- break;
- }
-
- return kind;
- }
-
- ///
- /// Gets default keyword when user if not connected to any Kusto cluster.
- ///
- public static LanguageServices.Contracts.CompletionItem[] GetDefaultKeywords(
- ScriptDocumentInfo scriptDocumentInfo, Position textDocumentPosition)
- {
- var kustoCodeService = new KustoCodeService(scriptDocumentInfo.Contents, GlobalState.Default);
- var script = CodeScript.From(scriptDocumentInfo.Contents, GlobalState.Default);
- script.TryGetTextPosition(textDocumentPosition.Line + 1, textDocumentPosition.Character,
- out int position); // Gets the actual offset based on line and local offset
- var completion = kustoCodeService.GetCompletionItems(position);
-
- List completions =
- new List();
- foreach (var autoCompleteItem in completion.Items)
- {
- var label = autoCompleteItem.DisplayText;
- // convert the completion item candidates into vscode format CompletionItems
- completions.Add(AutoCompleteHelper.CreateCompletionItem(label, label + " keyword", label,
- CompletionItemKind.Keyword, scriptDocumentInfo.StartLine, scriptDocumentInfo.StartColumn,
- textDocumentPosition.Character));
- }
-
- return completions.ToArray();
- }
-
- ///
- /// Gets default diagnostics when user if not connected to any Kusto cluster.
- ///
- public static ScriptFileMarker[] GetDefaultDiagnostics(ScriptParseInfo parseInfo, ScriptFile scriptFile,
- string queryText)
- {
- var kustoCodeService = new KustoCodeService(queryText, GlobalState.Default);
- var script = CodeScript.From(queryText, GlobalState.Default);
- var parseResult = kustoCodeService.GetDiagnostics();
-
parseInfo.ParseResult = parseResult;
-
- // build a list of Kusto script file markers from the errors.
- List markers = new List();
- if (parseResult != null && parseResult.Count() > 0)
+
+ if (!parseResult.Any())
{
- foreach (var error in parseResult)
- {
- script.TryGetLineAndOffset(error.Start, out var startLine, out var startOffset);
- script.TryGetLineAndOffset(error.End, out var endLine, out var endOffset);
+ return Array.Empty();
+ }
+
+ // build a list of Kusto script file markers from the errors.
+ var markers = new List();
+
+ foreach (var error in parseResult)
+ {
+ script.TryGetLineAndOffset(error.Start, out var startLine, out var startOffset);
+ script.TryGetLineAndOffset(error.End, out var endLine, out var endOffset);
- // vscode specific format for error markers.
- markers.Add(new ScriptFileMarker()
+ // vscode specific format for error markers.
+ markers.Add(new ScriptFileMarker
+ {
+ Message = error.Message,
+ Level = ScriptFileMarkerLevel.Error,
+ ScriptRegion = new ScriptRegion
{
- Message = error.Message,
- Level = ScriptFileMarkerLevel.Error,
- ScriptRegion = new ScriptRegion()
- {
- File = scriptFile.FilePath,
- StartLineNumber = startLine,
- StartColumnNumber = startOffset,
- StartOffset = 0,
- EndLineNumber = endLine,
- EndColumnNumber = endOffset,
- EndOffset = 0
- }
- });
- }
+ File = scriptFile.FilePath,
+ StartLineNumber = startLine,
+ StartColumnNumber = startOffset,
+ StartOffset = 0,
+ EndLineNumber = endLine,
+ EndColumnNumber = endOffset,
+ EndOffset = 0
+ }
+ });
}
return markers.ToArray();
}
-
- ///
- /// Loads the schema for the specified database and returns a new with the database added or updated.
- ///
- public static GlobalState AddOrUpdateDatabase(IEnumerable tableSchemas,
- IEnumerable functionSchemas, GlobalState globals,
- string databaseName, string clusterName)
+
+ public DefinitionResult GetDefinition(string queryText, int index, int startLine, int startColumn, bool throwOnError = false)
{
- // try and show error from here.
- DatabaseSymbol databaseSymbol = null;
+ //TODOKusto: API wasnt working properly, need to check that part.
+ var abc = KustoCode.ParseAndAnalyze(queryText, _schemaState);
+ var kustoCodeService = new KustoCodeService(abc);
+ //var kustoCodeService = new KustoCodeService(queryText, globals);
+ var relatedInfo = kustoCodeService.GetRelatedElements(index);
- if (databaseName != null)
+ if (relatedInfo != null && relatedInfo.Elements.Count > 1)
{
- databaseSymbol = LoadDatabaseAsync(tableSchemas, functionSchemas, databaseName);
}
- if (databaseSymbol == null)
- {
- return globals;
- }
-
- var cluster = globals.GetCluster(clusterName);
- if (cluster == null)
- {
- cluster = new ClusterSymbol(clusterName, new[] {databaseSymbol}, isOpen: true);
- globals = globals.AddOrUpdateCluster(cluster);
- }
- else
- {
- cluster = cluster.AddOrUpdateDatabase(databaseSymbol);
- globals = globals.AddOrUpdateCluster(cluster);
- }
-
- globals = globals.WithCluster(cluster).WithDatabase(databaseSymbol);
-
- return globals;
+ return null;
}
-
- ///
- public static LanguageServices.Contracts.CompletionItem[] GetAutoCompleteSuggestions(
- ScriptDocumentInfo scriptDocumentInfo, Position textPosition, GlobalState schemaState,
- bool throwOnError = false)
+
+ public Hover GetHoverHelp(ScriptDocumentInfo scriptDocumentInfo, Position textPosition, bool throwOnError = false)
{
- var script = CodeScript.From(scriptDocumentInfo.Contents, schemaState);
+ var script = CodeScript.From(scriptDocumentInfo.Contents, _schemaState);
+ script.TryGetTextPosition(textPosition.Line + 1, textPosition.Character + 1, out int position);
+
+ var codeBlock = script.GetBlockAtPosition(position);
+ var quickInfo = codeBlock.Service.GetQuickInfo(position);
+
+ return AutoCompleteHelper.ConvertQuickInfoToHover(
+ quickInfo.Text,
+ "kusto",
+ scriptDocumentInfo.StartLine,
+ scriptDocumentInfo.StartColumn,
+ textPosition.Character);
+ }
+
+ public LanguageServices.Contracts.CompletionItem[] GetAutoCompleteSuggestions(ScriptDocumentInfo scriptDocumentInfo, Position textPosition, bool throwOnError = false)
+ {
+ var script = CodeScript.From(scriptDocumentInfo.Contents, _schemaState);
script.TryGetTextPosition(textPosition.Line + 1, textPosition.Character + 1,
out int position); // Gets the actual offset based on line and local offset
@@ -334,86 +344,29 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource.DataSourceIntellisense
return completions.ToArray();
}
-
- ///
- public static Hover GetHoverHelp(ScriptDocumentInfo scriptDocumentInfo, Position textPosition,
- GlobalState schemaState, bool throwOnError = false)
+
+ private CompletionItemKind CreateCompletionItemKind(CompletionKind kustoKind)
{
- var script = CodeScript.From(scriptDocumentInfo.Contents, schemaState);
- script.TryGetTextPosition(textPosition.Line + 1, textPosition.Character + 1, out int position);
-
- var codeBlock = script.GetBlockAtPosition(position);
- var quickInfo = codeBlock.Service.GetQuickInfo(position);
-
- return AutoCompleteHelper.ConvertQuickInfoToHover(
- quickInfo.Text,
- "kusto",
- scriptDocumentInfo.StartLine,
- scriptDocumentInfo.StartColumn,
- textPosition.Character);
- }
-
- ///
- public static DefinitionResult GetDefinition(string queryText, int index, int startLine, int startColumn,
- GlobalState schemaState, bool throwOnError = false)
- {
- var abc = KustoCode.ParseAndAnalyze(queryText,
- schemaState); //TODOKusto: API wasnt working properly, need to check that part.
- var kustoCodeService = new KustoCodeService(abc);
- //var kustoCodeService = new KustoCodeService(queryText, globals);
- var relatedInfo = kustoCodeService.GetRelatedElements(index);
-
- if (relatedInfo != null && relatedInfo.Elements.Count > 1)
+ switch (kustoKind)
{
+ case CompletionKind.Syntax:
+ return CompletionItemKind.Module;
+ case CompletionKind.Column:
+ return CompletionItemKind.Field;
+ case CompletionKind.Variable:
+ return CompletionItemKind.Variable;
+ case CompletionKind.Table:
+ return CompletionItemKind.File;
+ case CompletionKind.Database:
+ return CompletionItemKind.Method;
+ case CompletionKind.LocalFunction:
+ case CompletionKind.DatabaseFunction:
+ case CompletionKind.BuiltInFunction:
+ case CompletionKind.AggregateFunction:
+ return CompletionItemKind.Function;
+ default:
+ return CompletionItemKind.Keyword;
}
-
- return null;
- }
-
- ///
- public static ScriptFileMarker[] GetSemanticMarkers(ScriptParseInfo parseInfo, ScriptFile scriptFile,
- string queryText, GlobalState schemaState)
- {
- var kustoCodeService = new KustoCodeService(queryText, schemaState);
- var script = CodeScript.From(queryText, schemaState);
- var parseResult = new List();
-
- foreach (var codeBlock in script.Blocks)
- {
- parseResult.AddRange(codeBlock.Service.GetDiagnostics());
- }
-
- parseInfo.ParseResult = parseResult;
-
- // build a list of Kusto script file markers from the errors.
- List markers = new List();
- if (parseResult != null && parseResult.Any())
- {
- foreach (var error in parseResult)
- {
- script.TryGetLineAndOffset(error.Start, out var startLine, out var startOffset);
- script.TryGetLineAndOffset(error.End, out var endLine, out var endOffset);
-
- // vscode specific format for error markers.
- markers.Add(new ScriptFileMarker()
- {
- Message = error.Message,
- Level = ScriptFileMarkerLevel.Error,
- ScriptRegion = new ScriptRegion()
- {
- File = scriptFile.FilePath,
- StartLineNumber = startLine,
- StartColumnNumber = startOffset,
- StartOffset = 0,
- EndLineNumber = endLine,
- EndColumnNumber = endOffset,
- EndOffset = 0
- }
- });
- }
- }
-
- return markers.ToArray();
}
}
-}
+}
\ No newline at end of file
diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/Intellisense/KustoIntellisenseHelper.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/Intellisense/KustoIntellisenseHelper.cs
new file mode 100644
index 00000000..764c7543
--- /dev/null
+++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/Intellisense/KustoIntellisenseHelper.cs
@@ -0,0 +1,90 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System.Collections.Generic;
+using System.Linq;
+using Kusto.Language;
+using Kusto.Language.Editor;
+using Microsoft.Kusto.ServiceLayer.LanguageServices;
+using Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts;
+using Microsoft.Kusto.ServiceLayer.Workspace.Contracts;
+
+namespace Microsoft.Kusto.ServiceLayer.DataSource.Intellisense
+{
+ ///
+ /// Kusto specific class for intellisense helper functions.
+ ///
+ public class KustoIntellisenseHelper
+ {
+ ///
+ /// Gets default keyword when user if not connected to any Kusto cluster.
+ ///
+ public static LanguageServices.Contracts.CompletionItem[] GetDefaultKeywords(
+ ScriptDocumentInfo scriptDocumentInfo, Position textDocumentPosition)
+ {
+ var kustoCodeService = new KustoCodeService(scriptDocumentInfo.Contents, GlobalState.Default);
+ var script = CodeScript.From(scriptDocumentInfo.Contents, GlobalState.Default);
+ script.TryGetTextPosition(textDocumentPosition.Line + 1, textDocumentPosition.Character,
+ out int position); // Gets the actual offset based on line and local offset
+ var completion = kustoCodeService.GetCompletionItems(position);
+
+ List completions =
+ new List();
+ foreach (var autoCompleteItem in completion.Items)
+ {
+ var label = autoCompleteItem.DisplayText;
+ // convert the completion item candidates into vscode format CompletionItems
+ completions.Add(AutoCompleteHelper.CreateCompletionItem(label, label + " keyword", label,
+ CompletionItemKind.Keyword, scriptDocumentInfo.StartLine, scriptDocumentInfo.StartColumn,
+ textDocumentPosition.Character));
+ }
+
+ return completions.ToArray();
+ }
+
+ ///
+ /// Gets default diagnostics when user if not connected to any Kusto cluster.
+ ///
+ public static ScriptFileMarker[] GetDefaultDiagnostics(ScriptParseInfo parseInfo, ScriptFile scriptFile,
+ string queryText)
+ {
+ var kustoCodeService = new KustoCodeService(queryText, GlobalState.Default);
+ var script = CodeScript.From(queryText, GlobalState.Default);
+ var parseResult = kustoCodeService.GetDiagnostics();
+
+ parseInfo.ParseResult = parseResult;
+
+ // build a list of Kusto script file markers from the errors.
+ List markers = new List();
+ if (parseResult != null && parseResult.Count() > 0)
+ {
+ foreach (var error in parseResult)
+ {
+ script.TryGetLineAndOffset(error.Start, out var startLine, out var startOffset);
+ script.TryGetLineAndOffset(error.End, out var endLine, out var endOffset);
+
+ // vscode specific format for error markers.
+ markers.Add(new ScriptFileMarker()
+ {
+ Message = error.Message,
+ Level = ScriptFileMarkerLevel.Error,
+ ScriptRegion = new ScriptRegion
+ {
+ File = scriptFile.FilePath,
+ StartLineNumber = startLine,
+ StartColumnNumber = startOffset,
+ StartOffset = 0,
+ EndLineNumber = endLine,
+ EndColumnNumber = endOffset,
+ EndOffset = 0
+ }
+ });
+ }
+ }
+
+ return markers.ToArray();
+ }
+ }
+}
diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceIntellisense/ScriptParseInfo.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/Intellisense/ScriptParseInfo.cs
similarity index 95%
rename from src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceIntellisense/ScriptParseInfo.cs
rename to src/Microsoft.Kusto.ServiceLayer/DataSource/Intellisense/ScriptParseInfo.cs
index d92433a3..0035bef5 100644
--- a/src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceIntellisense/ScriptParseInfo.cs
+++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/Intellisense/ScriptParseInfo.cs
@@ -7,7 +7,7 @@ using System.Collections.Generic;
using Kusto.Language;
using Kusto.Language.Editor;
-namespace Microsoft.Kusto.ServiceLayer.DataSource.DataSourceIntellisense
+namespace Microsoft.Kusto.ServiceLayer.DataSource.Intellisense
{
///
/// Data Source specific class for storing cached metadata regarding a parsed KQL file.
diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceIntellisense/ShowDatabaseSchemaResult.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/Intellisense/ShowDatabaseSchemaResult.cs
similarity index 84%
rename from src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceIntellisense/ShowDatabaseSchemaResult.cs
rename to src/Microsoft.Kusto.ServiceLayer/DataSource/Intellisense/ShowDatabaseSchemaResult.cs
index d194d72d..6aecafc4 100644
--- a/src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceIntellisense/ShowDatabaseSchemaResult.cs
+++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/Intellisense/ShowDatabaseSchemaResult.cs
@@ -1,4 +1,4 @@
-namespace Microsoft.Kusto.ServiceLayer.DataSource.DataSourceIntellisense
+namespace Microsoft.Kusto.ServiceLayer.DataSource.Intellisense
{
public class ShowDatabaseSchemaResult
{
diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceIntellisense/ShowDatabasesResult.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/Intellisense/ShowDatabasesResult.cs
similarity index 82%
rename from src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceIntellisense/ShowDatabasesResult.cs
rename to src/Microsoft.Kusto.ServiceLayer/DataSource/Intellisense/ShowDatabasesResult.cs
index 0cbb930a..75813c67 100644
--- a/src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceIntellisense/ShowDatabasesResult.cs
+++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/Intellisense/ShowDatabasesResult.cs
@@ -1,4 +1,4 @@
-namespace Microsoft.Kusto.ServiceLayer.DataSource.DataSourceIntellisense
+namespace Microsoft.Kusto.ServiceLayer.DataSource.Intellisense
{
public class ShowDatabasesResult
{
diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceIntellisense/ShowFunctionsResult.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/Intellisense/ShowFunctionsResult.cs
similarity index 73%
rename from src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceIntellisense/ShowFunctionsResult.cs
rename to src/Microsoft.Kusto.ServiceLayer/DataSource/Intellisense/ShowFunctionsResult.cs
index 812da976..72961ec4 100644
--- a/src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceIntellisense/ShowFunctionsResult.cs
+++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/Intellisense/ShowFunctionsResult.cs
@@ -1,4 +1,4 @@
-namespace Microsoft.Kusto.ServiceLayer.DataSource.DataSourceIntellisense
+namespace Microsoft.Kusto.ServiceLayer.DataSource.Intellisense
{
public class ShowFunctionsResult
{
diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/KustoClient.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/KustoClient.cs
index 69af13c5..2c062e7e 100644
--- a/src/Microsoft.Kusto.ServiceLayer/DataSource/KustoClient.cs
+++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/KustoClient.cs
@@ -16,7 +16,6 @@ using Kusto.Language;
using Kusto.Language.Editor;
using Microsoft.Kusto.ServiceLayer.Connection;
using Microsoft.Kusto.ServiceLayer.DataSource.Contracts;
-using Microsoft.Kusto.ServiceLayer.DataSource.DataSourceIntellisense;
using Microsoft.Kusto.ServiceLayer.Utility;
namespace Microsoft.Kusto.ServiceLayer.DataSource
@@ -30,12 +29,7 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private ICslQueryProvider _kustoQueryProvider;
-
- ///
- /// SchemaState used for getting intellisense info.
- ///
- public GlobalState SchemaState { get; private set; }
-
+
public string ClusterName { get; private set; }
public string DatabaseName { get; private set; }
@@ -43,7 +37,6 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
{
_ownerUri = ownerUri;
Initialize(connectionDetails);
- SchemaState = LoadSchemaState();
}
private string ParseDatabaseName(string databaseName)
@@ -55,31 +48,6 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
: databaseName;
}
- private GlobalState LoadSchemaState()
- {
- IEnumerable tableSchemas = Enumerable.Empty();
- IEnumerable functionSchemas = Enumerable.Empty();
-
- if (!string.IsNullOrWhiteSpace(DatabaseName))
- {
- var source = new CancellationTokenSource();
- Parallel.Invoke(() =>
- {
- tableSchemas =
- ExecuteQueryAsync($".show database {DatabaseName} schema", source.Token, DatabaseName)
- .Result;
- },
- () =>
- {
- functionSchemas = ExecuteQueryAsync(".show functions", source.Token, DatabaseName).Result;
- });
- }
-
- return KustoIntellisenseHelper.AddOrUpdateDatabase(tableSchemas, functionSchemas,
- GlobalState.Default,
- DatabaseName, ClusterName);
- }
-
private void Initialize(DataSourceConnectionDetails connectionDetails)
{
var stringBuilder = GetKustoConnectionStringBuilder(connectionDetails);
@@ -275,7 +243,6 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
public void UpdateDatabase(string databaseName)
{
DatabaseName = ParseDatabaseName(databaseName);
- SchemaState = LoadSchemaState();
}
public void Dispose()
diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/KustoDataSource.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/KustoDataSource.cs
index 95458e99..ba54f84b 100644
--- a/src/Microsoft.Kusto.ServiceLayer/DataSource/KustoDataSource.cs
+++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/KustoDataSource.cs
@@ -14,10 +14,13 @@ using System.Threading.Tasks;
using Kusto.Cloud.Platform.Data;
using Kusto.Data;
using Kusto.Data.Data;
-using Kusto.Language;
+using Microsoft.Kusto.ServiceLayer.DataSource.Intellisense;
using Microsoft.Kusto.ServiceLayer.DataSource.Metadata;
using Microsoft.Kusto.ServiceLayer.DataSource.Models;
+using Microsoft.Kusto.ServiceLayer.LanguageServices;
+using Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts;
using Microsoft.Kusto.ServiceLayer.Utility;
+using Microsoft.Kusto.ServiceLayer.Workspace.Contracts;
namespace Microsoft.Kusto.ServiceLayer.DataSource
{
@@ -26,7 +29,8 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
///
public class KustoDataSource : DataSourceBase
{
- private IKustoClient _kustoClient;
+ private readonly IKustoClient _kustoClient;
+ private readonly IIntellisenseClient _intellisenseClient;
///
/// List of databases.
@@ -56,8 +60,6 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
public override string DatabaseName => _kustoClient.DatabaseName;
public override string ClusterName => _kustoClient.ClusterName;
-
- public override GlobalState SchemaState => _kustoClient.SchemaState;
// Some clusters have this signature. Queries might slightly differ for Aria
private const string AriaProxyURL = "kusto.aria.microsoft.com";
@@ -77,9 +79,10 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
///
/// Prevents a default instance of the class from being created.
///
- public KustoDataSource(IKustoClient kustoClient)
+ public KustoDataSource(IKustoClient kustoClient, IIntellisenseClient intellisenseClient)
{
_kustoClient = kustoClient;
+ _intellisenseClient = intellisenseClient;
// Check if a connection can be made
ValidationUtils.IsTrue(Exists().Result,
$"Unable to connect. ClusterName = {ClusterName}, DatabaseName = {DatabaseName}");
@@ -246,6 +249,7 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
public override void UpdateDatabase(string databaseName)
{
_kustoClient.UpdateDatabase(databaseName);
+ _intellisenseClient.UpdateDatabase(databaseName);
}
///
@@ -803,12 +807,32 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
? string.Empty
: $"{functionInfo.Name}{functionInfo.Parameters}";
}
-
+
private string GenerateMetadataKey(string databaseName, string objectName)
{
return string.IsNullOrWhiteSpace(objectName) ? databaseName : $"{databaseName}.{objectName}";
}
+ public override ScriptFileMarker[] GetSemanticMarkers(ScriptParseInfo parseInfo, ScriptFile scriptFile, string queryText)
+ {
+ return _intellisenseClient.GetSemanticMarkers(parseInfo, scriptFile, queryText);
+ }
+
+ public override DefinitionResult GetDefinition(string queryText, int index, int startLine, int startColumn, bool throwOnError = false)
+ {
+ return _intellisenseClient.GetDefinition(queryText, index, startLine, startColumn, throwOnError);
+ }
+
+ public override Hover GetHoverHelp(ScriptDocumentInfo scriptDocumentInfo, Position textPosition, bool throwOnError = false)
+ {
+ return _intellisenseClient.GetHoverHelp(scriptDocumentInfo, textPosition, throwOnError);
+ }
+
+ public override CompletionItem[] GetAutoCompleteSuggestions(ScriptDocumentInfo scriptDocumentInfo, Position textPosition, bool throwOnError = false)
+ {
+ return _intellisenseClient.GetAutoCompleteSuggestions(scriptDocumentInfo, textPosition, throwOnError);
+ }
+
#endregion
}
}
diff --git a/src/Microsoft.Kusto.ServiceLayer/HostLoader.cs b/src/Microsoft.Kusto.ServiceLayer/HostLoader.cs
index 165c8a16..40c472a8 100644
--- a/src/Microsoft.Kusto.ServiceLayer/HostLoader.cs
+++ b/src/Microsoft.Kusto.ServiceLayer/HostLoader.cs
@@ -78,7 +78,7 @@ namespace Microsoft.Kusto.ServiceLayer
WorkspaceService.Instance.InitializeService(serviceHost);
serviceProvider.RegisterSingleService(WorkspaceService.Instance);
- LanguageService.Instance.InitializeService(serviceHost, connectedBindingQueue, dataSourceFactory);
+ LanguageService.Instance.InitializeService(serviceHost, connectedBindingQueue);
serviceProvider.RegisterSingleService(LanguageService.Instance);
ConnectionService.Instance.InitializeService(serviceHost, dataSourceConnectionFactory, connectedBindingQueue, dataSourceFactory);
diff --git a/src/Microsoft.Kusto.ServiceLayer/LanguageServices/LanguageService.cs b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/LanguageService.cs
index a0b10605..f756d489 100644
--- a/src/Microsoft.Kusto.ServiceLayer/LanguageServices/LanguageService.cs
+++ b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/LanguageService.cs
@@ -15,10 +15,9 @@ using Microsoft.SqlServer.Management.SqlParser.Parser;
using Microsoft.SqlServer.Management.SqlParser.SqlCodeDom;
using Microsoft.SqlTools.Hosting.Protocol;
using Microsoft.Kusto.ServiceLayer.DataSource;
-using Microsoft.Kusto.ServiceLayer.DataSource.DataSourceIntellisense;
using Microsoft.Kusto.ServiceLayer.Connection;
using Microsoft.Kusto.ServiceLayer.Connection.Contracts;
-using Microsoft.Kusto.ServiceLayer.LanguageServices.Completion;
+using Microsoft.Kusto.ServiceLayer.DataSource.Intellisense;
using Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts;
using Microsoft.Kusto.ServiceLayer.Utility;
using Microsoft.Kusto.ServiceLayer.Workspace;
@@ -67,9 +66,6 @@ namespace Microsoft.Kusto.ServiceLayer.LanguageServices
internal const int PeekDefinitionTimeout = 10 * OneSecond;
- // For testability only
- internal Task DelayedDiagnosticsTask = null;
-
private ConnectionService connectionService = null;
private WorkspaceService workspaceServiceInstance;
@@ -209,7 +205,7 @@ namespace Microsoft.Kusto.ServiceLayer.LanguageServices
///
///
///
- public void InitializeService(ServiceHost serviceHost, IConnectedBindingQueue connectedBindingQueue, IDataSourceFactory dataSourceFactory)
+ public void InitializeService(ServiceHost serviceHost, IConnectedBindingQueue connectedBindingQueue)
{
_bindingQueue = connectedBindingQueue;
// Register the requests that this service will handle
@@ -766,18 +762,16 @@ namespace Microsoft.Kusto.ServiceLayer.LanguageServices
connInfo.TryGetConnection("Default", out connection);
IDataSource dataSource = connection.GetUnderlyingConnection();
- return KustoIntellisenseHelper.GetDefinition(scriptFile.Contents, textDocumentPosition.Position.Character, 1, 1, dataSource.SchemaState);
+ return dataSource.GetDefinition(scriptFile.Contents, textDocumentPosition.Position.Character, 1, 1);
}
- else
+
+ // User is not connected.
+ return new DefinitionResult
{
- // User is not connected.
- return new DefinitionResult
- {
- IsErrorResult = true,
- Message = SR.PeekDefinitionNotConnectedError,
- Locations = null
- };
- }
+ IsErrorResult = true,
+ Message = SR.PeekDefinitionNotConnectedError,
+ Locations = null
+ };
}
///
@@ -809,9 +803,8 @@ namespace Microsoft.Kusto.ServiceLayer.LanguageServices
ReliableDataSourceConnection connection;
connInfo.TryGetConnection("Default", out connection);
- IDataSource dataSource = connection.GetUnderlyingConnection();
-
- return KustoIntellisenseHelper.GetHoverHelp(scriptDocumentInfo, textDocumentPosition.Position, dataSource.SchemaState);
+ IDataSource dataSource = connection.GetUnderlyingConnection();
+ return dataSource.GetHoverHelp(scriptDocumentInfo, textDocumentPosition.Position);
});
queueItem.ItemProcessed.WaitOne();
@@ -855,14 +848,17 @@ namespace Microsoft.Kusto.ServiceLayer.LanguageServices
ScriptDocumentInfo scriptDocumentInfo = new ScriptDocumentInfo(textDocumentPosition, scriptFile, scriptParseInfo);
- if(connInfo != null){
+ if (connInfo != null)
+ {
ReliableDataSourceConnection connection;
connInfo.TryGetConnection("Default", out connection);
IDataSource dataSource = connection.GetUnderlyingConnection();
-
- resultCompletionItems = KustoIntellisenseHelper.GetAutoCompleteSuggestions(scriptDocumentInfo, textDocumentPosition.Position, dataSource.SchemaState);
+
+ resultCompletionItems =
+ dataSource.GetAutoCompleteSuggestions(scriptDocumentInfo, textDocumentPosition.Position);
}
- else{
+ else
+ {
resultCompletionItems = DataSourceFactory.GetDefaultAutoComplete(DataSourceType.Kusto, scriptDocumentInfo, textDocumentPosition.Position);
}
@@ -932,7 +928,7 @@ namespace Microsoft.Kusto.ServiceLayer.LanguageServices
existingRequestCancellation = new CancellationTokenSource();
Task.Factory.StartNew(
() =>
- this.DelayedDiagnosticsTask = DelayThenInvokeDiagnostics(
+ DelayThenInvokeDiagnostics(
LanguageService.DiagnosticParseDelay,
filesToAnalyze,
eventContext,
@@ -1000,17 +996,19 @@ namespace Microsoft.Kusto.ServiceLayer.LanguageServices
ConnectionServiceInstance.TryFindConnection(
scriptFile.ClientUri,
out connInfo);
-
- if(connInfo != null){
+
+ if (connInfo != null)
+ {
connInfo.TryGetConnection("Default", out var connection);
IDataSource dataSource = connection.GetUnderlyingConnection();
-
- semanticMarkers = KustoIntellisenseHelper.GetSemanticMarkers(parseInfo, scriptFile, scriptFile.Contents, dataSource.SchemaState);
- }
- else{
+
+ semanticMarkers = dataSource.GetSemanticMarkers(parseInfo, scriptFile, scriptFile.Contents);
+ }
+ else
+ {
semanticMarkers = DataSourceFactory.GetDefaultSemanticMarkers(DataSourceType.Kusto, parseInfo, scriptFile, scriptFile.Contents);
}
-
+
Logger.Write(TraceEventType.Verbose, "Analysis complete.");
await DiagnosticsHelper.PublishScriptDiagnostics(scriptFile, semanticMarkers, eventContext);
diff --git a/src/Microsoft.Kusto.ServiceLayer/LanguageServices/ScriptDocumentInfo.cs b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/ScriptDocumentInfo.cs
index 0f8eb968..eb54e066 100644
--- a/src/Microsoft.Kusto.ServiceLayer/LanguageServices/ScriptDocumentInfo.cs
+++ b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/ScriptDocumentInfo.cs
@@ -3,12 +3,12 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
+using Microsoft.Kusto.ServiceLayer.DataSource.Intellisense;
+using Microsoft.Kusto.ServiceLayer.Workspace.Contracts;
using Microsoft.SqlServer.Management.SqlParser.Parser;
using Microsoft.SqlTools.Utility;
-using Microsoft.Kusto.ServiceLayer.DataSource.DataSourceIntellisense;
-using Microsoft.Kusto.ServiceLayer.Workspace.Contracts;
-namespace Microsoft.Kusto.ServiceLayer.LanguageServices.Completion
+namespace Microsoft.Kusto.ServiceLayer.LanguageServices
{
///
/// A class to calculate the numbers used by SQL parser using the text positions and content
diff --git a/test/Microsoft.Kusto.ServiceLayer.UnitTests/DataSource/DataSourceFactoryTests.cs b/test/Microsoft.Kusto.ServiceLayer.UnitTests/DataSource/DataSourceFactoryTests.cs
index f90b827a..6d403b3b 100644
--- a/test/Microsoft.Kusto.ServiceLayer.UnitTests/DataSource/DataSourceFactoryTests.cs
+++ b/test/Microsoft.Kusto.ServiceLayer.UnitTests/DataSource/DataSourceFactoryTests.cs
@@ -2,8 +2,8 @@ using System;
using System.Collections.Generic;
using Microsoft.Kusto.ServiceLayer.Connection.Contracts;
using Microsoft.Kusto.ServiceLayer.DataSource;
-using Microsoft.Kusto.ServiceLayer.DataSource.DataSourceIntellisense;
-using Microsoft.Kusto.ServiceLayer.LanguageServices.Completion;
+using Microsoft.Kusto.ServiceLayer.DataSource.Intellisense;
+using Microsoft.Kusto.ServiceLayer.LanguageServices;
using Microsoft.Kusto.ServiceLayer.Workspace.Contracts;
using NUnit.Framework;
diff --git a/test/Microsoft.Kusto.ServiceLayer.UnitTests/DataSource/DataSourceIntellisense/KustoIntellisenseClientTests.cs b/test/Microsoft.Kusto.ServiceLayer.UnitTests/DataSource/DataSourceIntellisense/KustoIntellisenseClientTests.cs
new file mode 100644
index 00000000..42295401
--- /dev/null
+++ b/test/Microsoft.Kusto.ServiceLayer.UnitTests/DataSource/DataSourceIntellisense/KustoIntellisenseClientTests.cs
@@ -0,0 +1,174 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.Kusto.ServiceLayer.DataSource;
+using Microsoft.Kusto.ServiceLayer.DataSource.Intellisense;
+using Microsoft.Kusto.ServiceLayer.LanguageServices;
+using Microsoft.Kusto.ServiceLayer.Workspace.Contracts;
+using Moq;
+using NUnit.Framework;
+
+namespace Microsoft.Kusto.ServiceLayer.UnitTests.DataSource.DataSourceIntellisense
+{
+ public class KustoIntellisenseClientTests
+ {
+ private Mock GetMockKustoClient()
+ {
+ var kustoClientMock = new Mock();
+ kustoClientMock.Setup(x => x.ClusterName).Returns("https://fake.url.com");
+ kustoClientMock.Setup(x => x.DatabaseName).Returns("FakeDatabaseName");
+
+ var databaseSchema = new ShowDatabaseSchemaResult
+ {
+ DatabaseName = "FakeDatabaseName",
+ TableName = "FakeTableName",
+ ColumnName = "FakeColumnName",
+ ColumnType = "bool",
+ IsDefaultTable = false,
+ IsDefaultColumn = false,
+ PrettyName = "Fake Table Name",
+ Version = "",
+ Folder = "FakeTableFolder",
+ DocName = ""
+ };
+
+ var databaseSchemaResults = new List {databaseSchema} as IEnumerable;
+ kustoClientMock.Setup(x => x.ExecuteQueryAsync(It.IsAny(), It.IsAny(), "FakeDatabaseName"))
+ .Returns(Task.FromResult(databaseSchemaResults));
+
+ var functionSchema = new ShowFunctionsResult
+ {
+ Name = "FakeFunctionName",
+ Parameters = "a:real, b:real",
+ Body = "a+b",
+ Folder = "FakeFunctionFolder",
+ DocString = ""
+ };
+
+ var functionSchemaResults = new List {functionSchema} as IEnumerable;
+ kustoClientMock.Setup(x => x.ExecuteQueryAsync(It.IsAny(), It.IsAny(), "FakeDatabaseName"))
+ .Returns(Task.FromResult(functionSchemaResults));
+
+ return kustoClientMock;
+ }
+
+ [Test]
+ public void GetSemanticMarkers_Returns_Error_For_InvalidText()
+ {
+ var kustoClientMock = GetMockKustoClient();
+
+ var client = new KustoIntellisenseClient(kustoClientMock.Object);
+ var semanticMarkers = client.GetSemanticMarkers(new ScriptParseInfo(), new ScriptFile("", "", ""), "InvalidText");
+
+ var semanticMarker = semanticMarkers.Single();
+ Assert.AreEqual(ScriptFileMarkerLevel.Error, semanticMarker.Level);
+ Assert.AreEqual("The name 'InvalidText' does not refer to any known column, table, variable or function.", semanticMarker.Message);
+ Assert.IsNotNull(semanticMarker.ScriptRegion);
+ }
+
+ [Test]
+ public void GetSemanticMarkers_Returns_Zero_SemanticMarkers_For_ValidQueryText()
+ {
+ var kustoClientMock = GetMockKustoClient();
+
+ var client = new KustoIntellisenseClient(kustoClientMock.Object);
+ var queryText = @".show commands";
+ var semanticMarkers = client.GetSemanticMarkers(new ScriptParseInfo(), new ScriptFile("", "", ""), queryText);
+
+ Assert.AreEqual(0, semanticMarkers.Length);
+ }
+
+ [Test]
+ public void GetDefinition_Returns_Null()
+ {
+ var kustoClientMock = GetMockKustoClient();
+ var client = new KustoIntellisenseClient(kustoClientMock.Object);
+ var definition = client.GetDefinition("queryText", 0, 1, 1);
+
+ // finish these assertions once the function is implemented
+ Assert.IsNull(definition);
+ }
+
+ [Test]
+ public void GetHoverHelp_Returns_Hover()
+ {
+ var kustoClientMock = GetMockKustoClient();
+ var client = new KustoIntellisenseClient(kustoClientMock.Object);
+ var textDocumentPosition = new TextDocumentPosition
+ {
+ Position = new Position()
+ };
+ var scriptFile = new ScriptFile("", "", "");
+ var scriptParseInfo = new ScriptParseInfo();
+ var documentInfo = new ScriptDocumentInfo(textDocumentPosition, scriptFile, scriptParseInfo);
+
+ var hover = client.GetHoverHelp(documentInfo, new Position());
+
+ Assert.IsNotNull(hover);
+ }
+
+ [Test]
+ public void GetAutoCompleteSuggestions_Returns_CompletionItems()
+ {
+ var kustoClientMock = GetMockKustoClient();
+ var client = new KustoIntellisenseClient(kustoClientMock.Object);
+
+ var position = new Position();
+ var textDocumentPosition = new TextDocumentPosition
+ {
+ Position = position
+ };
+ var scriptFile = new ScriptFile("", "", "");
+ var scriptParseInfo = new ScriptParseInfo();
+ var documentInfo = new ScriptDocumentInfo(textDocumentPosition, scriptFile, scriptParseInfo);
+ var items = client.GetAutoCompleteSuggestions(documentInfo, position);
+
+ Assert.AreEqual(20, items.Length);
+ }
+ [Test]
+ public void UpdateDatabase_Updates_SchemaState()
+ {
+ var kustoClientMock = GetMockKustoClient();
+
+ var databaseSchema = new ShowDatabaseSchemaResult
+ {
+ DatabaseName = "NewDatabaseName",
+ TableName = "NewTableName",
+ ColumnName = "NewColumnName",
+ ColumnType = "bool",
+ IsDefaultTable = false,
+ IsDefaultColumn = false,
+ PrettyName = "New Table Name",
+ Version = "",
+ Folder = "NewTableFolder",
+ DocName = ""
+ };
+
+ var databaseSchemaResults = new List {databaseSchema} as IEnumerable;
+ kustoClientMock.Setup(x => x.ExecuteQueryAsync(It.IsAny(), It.IsAny(), "NewDatabaseName"))
+ .Returns(Task.FromResult(databaseSchemaResults));
+
+ var client = new KustoIntellisenseClient(kustoClientMock.Object);
+ client.UpdateDatabase("NewDatabaseName");
+
+ var position = new Position();
+ var textDocumentPosition = new TextDocumentPosition
+ {
+ Position = position
+ };
+ var scriptFile = new ScriptFile("", "", "");
+ var scriptParseInfo = new ScriptParseInfo();
+ var documentInfo = new ScriptDocumentInfo(textDocumentPosition, scriptFile, scriptParseInfo);
+ var items = client.GetAutoCompleteSuggestions(documentInfo, position);
+
+ Assert.AreEqual(19, items.Length);
+ var tableItem = items.FirstOrDefault(x => x.Detail == "Table");
+
+ // assert new table is being returned to show database has changed
+ Assert.IsNotNull(tableItem);
+ Assert.AreEqual("NewTableName", tableItem.InsertText);
+ Assert.AreEqual("NewTableName", tableItem.Label);
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Microsoft.Kusto.ServiceLayer.UnitTests/DataSource/DataSourceIntellisense/KustoIntellisenseHelperTests.cs b/test/Microsoft.Kusto.ServiceLayer.UnitTests/DataSource/DataSourceIntellisense/KustoIntellisenseHelperTests.cs
index 1f45e269..ec24b83e 100644
--- a/test/Microsoft.Kusto.ServiceLayer.UnitTests/DataSource/DataSourceIntellisense/KustoIntellisenseHelperTests.cs
+++ b/test/Microsoft.Kusto.ServiceLayer.UnitTests/DataSource/DataSourceIntellisense/KustoIntellisenseHelperTests.cs
@@ -1,8 +1,5 @@
-using System.Linq;
-using Kusto.Language.Editor;
-using Microsoft.Kusto.ServiceLayer.DataSource.DataSourceIntellisense;
-using Microsoft.Kusto.ServiceLayer.LanguageServices.Completion;
-using Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts;
+using Microsoft.Kusto.ServiceLayer.DataSource.Intellisense;
+using Microsoft.Kusto.ServiceLayer.LanguageServices;
using Microsoft.Kusto.ServiceLayer.Workspace.Contracts;
using NUnit.Framework;
@@ -10,37 +7,6 @@ namespace Microsoft.Kusto.ServiceLayer.UnitTests.DataSource.DataSourceIntellisen
{
public class KustoIntellisenseHelperTests
{
- [TestCase(CompletionKind.Syntax, CompletionItemKind.Module)]
- [TestCase(CompletionKind.Column, CompletionItemKind.Field)]
- [TestCase(CompletionKind.Variable, CompletionItemKind.Variable)]
- [TestCase(CompletionKind.Table, CompletionItemKind.File)]
- [TestCase(CompletionKind.Database, CompletionItemKind.Method)]
- [TestCase(CompletionKind.LocalFunction, CompletionItemKind.Function)]
- [TestCase(CompletionKind.DatabaseFunction, CompletionItemKind.Function)]
- [TestCase(CompletionKind.BuiltInFunction, CompletionItemKind.Function)]
- [TestCase(CompletionKind.AggregateFunction, CompletionItemKind.Function)]
- [TestCase(CompletionKind.Unknown, CompletionItemKind.Keyword)]
- [TestCase(CompletionKind.Keyword, CompletionItemKind.Keyword)]
- [TestCase(CompletionKind.Punctuation, CompletionItemKind.Keyword)]
- [TestCase(CompletionKind.Identifier, CompletionItemKind.Keyword)]
- [TestCase(CompletionKind.Example, CompletionItemKind.Keyword)]
- [TestCase(CompletionKind.ScalarPrefix, CompletionItemKind.Keyword)]
- [TestCase(CompletionKind.TabularPrefix, CompletionItemKind.Keyword)]
- [TestCase(CompletionKind.TabularSuffix, CompletionItemKind.Keyword)]
- [TestCase(CompletionKind.QueryPrefix, CompletionItemKind.Keyword)]
- [TestCase(CompletionKind.CommandPrefix, CompletionItemKind.Keyword)]
- [TestCase(CompletionKind.ScalarInfix, CompletionItemKind.Keyword)]
- [TestCase(CompletionKind.RenderChart, CompletionItemKind.Keyword)]
- [TestCase(CompletionKind.Parameter, CompletionItemKind.Keyword)]
- [TestCase(CompletionKind.Cluster, CompletionItemKind.Keyword)]
- [TestCase(CompletionKind.MaterialiedView, CompletionItemKind.Keyword)]
- [TestCase(CompletionKind.ScalarType, CompletionItemKind.Keyword)]
- public void CreateCompletionItemKind_Returns_Kind(CompletionKind completionKind, CompletionItemKind expected)
- {
- var result = KustoIntellisenseHelper.CreateCompletionItemKind(completionKind);
- Assert.AreEqual(expected, result);
- }
-
[Test]
public void GetDefaultKeywords_Returns_Keywords()
{
diff --git a/test/Microsoft.Kusto.ServiceLayer.UnitTests/DataSource/KustoClientTests.cs b/test/Microsoft.Kusto.ServiceLayer.UnitTests/DataSource/KustoClientTests.cs
new file mode 100644
index 00000000..396aa4af
--- /dev/null
+++ b/test/Microsoft.Kusto.ServiceLayer.UnitTests/DataSource/KustoClientTests.cs
@@ -0,0 +1,58 @@
+using System;
+using Microsoft.Kusto.ServiceLayer.DataSource;
+using Microsoft.Kusto.ServiceLayer.DataSource.Contracts;
+using NUnit.Framework;
+
+namespace Microsoft.Kusto.ServiceLayer.UnitTests.DataSource
+{
+ public class KustoClientTests
+ {
+ [Test]
+ public void Constructor_Throws_ArgumentException_For_MissingToken()
+ {
+ var connectionDetails = new DataSourceConnectionDetails
+ {
+ UserToken = ""
+ };
+
+ Assert.Throws(() => new KustoClient(connectionDetails, "ownerUri"));
+ }
+
+ [Test]
+ public void Constructor_Sets_ClusterName_With_DefaultDatabaseName()
+ {
+ string clusterName = "https://fake.url.com";
+ var connectionDetails = new DataSourceConnectionDetails
+ {
+ UserToken = "UserToken",
+ ServerName = clusterName,
+ DatabaseName = "",
+ AuthenticationType = "AzureMFA"
+ };
+
+ var client = new KustoClient(connectionDetails, "ownerUri");
+
+ Assert.AreEqual(clusterName, client.ClusterName);
+ Assert.AreEqual("NetDefaultDB", client.DatabaseName);
+ }
+
+ [TestCase("dstsAuth")]
+ [TestCase("AzureMFA")]
+ public void Constructor_Creates_Client_With_Valid_AuthenticationType(string authenticationType)
+ {
+ string clusterName = "https://fake.url.com";
+ var connectionDetails = new DataSourceConnectionDetails
+ {
+ UserToken = "UserToken",
+ ServerName = clusterName,
+ DatabaseName = "FakeDatabaseName",
+ AuthenticationType = authenticationType
+ };
+
+ var client = new KustoClient(connectionDetails, "ownerUri");
+
+ Assert.AreEqual(clusterName, client.ClusterName);
+ Assert.AreEqual("FakeDatabaseName", client.DatabaseName);
+ }
+ }
+}
\ No newline at end of file