mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-02-16 10:58:30 -05:00
Kusto Auth Refactor Tests (#1148)
* Refactored Kusto.ServiceLayer to pass ConnectionDetails to DataSourceFactory instead of connection string. Created KustoConnectionDetails to map needed details to KustoClient. * Removed unused ScriptingScriptOperation from KustoServiceLayer. * Created DstsAuthenticationManager and moved logic for getting DstsToken. Updated error message for failing to create KustoConnection. * Removed DstsAuthenticationManager.cs. Refactored DataSourceFactory to retrieve UserToken from ConnectionDetails. * Renamed AzureAccountToken in ConnectionDetails to AccountToken. Changed mapping to KustoConnectionDetails based on the AccountToken. * Removed Kusto.Data reference from ConnectionService and ScriptingListObjectsOperation. Moved creation of KustoConnectionStringBuilder to DataSourceFactory * Added accountToken validation to DataSourceFactory Create. * Renamed KustoConnectionDetails to DataSourceConnectionDetails. Renamed AzureToken to AuthToken. * Refactored SchemaState and intellisense out of KustoClient to KustoIntellisenseClient. Added IIntellisenseClient. Added unit tests for KustoIntellisenseClient and KustoClient. * Removed unused property dataSourceFactory from LanguageService > InitializeService. Moved KustoIntellisense functions from KustoIntellisenseHelper to KustoIntellisenseClient and made SchemaState private. Added IIntellisenseClient to IDataSource. * Renamed directory from DataSourceIntellisense to Intellisense and updated namespace. Fixed namespace in ScriptDocumentInfo.
This commit is contained in:
@@ -7,9 +7,12 @@ using System.Collections.Generic;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Kusto.Language;
|
using Microsoft.Kusto.ServiceLayer.DataSource.Intellisense;
|
||||||
using Microsoft.Kusto.ServiceLayer.Utility;
|
using Microsoft.Kusto.ServiceLayer.Utility;
|
||||||
using Microsoft.Kusto.ServiceLayer.DataSource.Metadata;
|
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
|
namespace Microsoft.Kusto.ServiceLayer.DataSource
|
||||||
{
|
{
|
||||||
@@ -88,6 +91,14 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
|
|||||||
public abstract string GenerateAlterFunctionScript(string functionName);
|
public abstract string GenerateAlterFunctionScript(string functionName);
|
||||||
|
|
||||||
public abstract string GenerateExecuteFunctionScript(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);
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public DataSourceType DataSourceType { get; protected set; }
|
public DataSourceType DataSourceType { get; protected set; }
|
||||||
@@ -96,7 +107,6 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
|
|||||||
public abstract string ClusterName { get; }
|
public abstract string ClusterName { get; }
|
||||||
|
|
||||||
public abstract string DatabaseName { get; }
|
public abstract string DatabaseName { get; }
|
||||||
public abstract GlobalState SchemaState { get; }
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ using Kusto.Data;
|
|||||||
using Microsoft.Kusto.ServiceLayer.Connection.Contracts;
|
using Microsoft.Kusto.ServiceLayer.Connection.Contracts;
|
||||||
using Microsoft.Kusto.ServiceLayer.DataSource.Contracts;
|
using Microsoft.Kusto.ServiceLayer.DataSource.Contracts;
|
||||||
using Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection;
|
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.LanguageServices.Contracts;
|
||||||
using Microsoft.Kusto.ServiceLayer.Workspace.Contracts;
|
using Microsoft.Kusto.ServiceLayer.Workspace.Contracts;
|
||||||
using Microsoft.Kusto.ServiceLayer.LanguageServices.Completion;
|
|
||||||
using Microsoft.Kusto.ServiceLayer.Utility;
|
using Microsoft.Kusto.ServiceLayer.Utility;
|
||||||
|
|
||||||
namespace Microsoft.Kusto.ServiceLayer.DataSource
|
namespace Microsoft.Kusto.ServiceLayer.DataSource
|
||||||
@@ -26,7 +26,8 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
|
|||||||
{
|
{
|
||||||
var kustoConnectionDetails = MapKustoConnectionDetails(connectionDetails);
|
var kustoConnectionDetails = MapKustoConnectionDetails(connectionDetails);
|
||||||
var kustoClient = new KustoClient(kustoConnectionDetails, ownerUri);
|
var kustoClient = new KustoClient(kustoConnectionDetails, ownerUri);
|
||||||
return new KustoDataSource(kustoClient);
|
var intellisenseClient = new KustoIntellisenseClient(kustoClient);
|
||||||
|
return new KustoDataSource(kustoClient, intellisenseClient);
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -3,8 +3,11 @@ using System.Collections.Generic;
|
|||||||
using System.Data;
|
using System.Data;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Kusto.Language;
|
using Microsoft.Kusto.ServiceLayer.DataSource.Intellisense;
|
||||||
using Microsoft.Kusto.ServiceLayer.DataSource.Metadata;
|
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
|
namespace Microsoft.Kusto.ServiceLayer.DataSource
|
||||||
{
|
{
|
||||||
@@ -28,8 +31,6 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
string DatabaseName { get; }
|
string DatabaseName { get; }
|
||||||
|
|
||||||
GlobalState SchemaState { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Executes a query.
|
/// Executes a query.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -111,5 +112,10 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
|
|||||||
/// <param name="functionName"></param>
|
/// <param name="functionName"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
string GenerateExecuteFunctionScript(string functionName);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,17 +2,11 @@ using System.Collections.Generic;
|
|||||||
using System.Data;
|
using System.Data;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Kusto.Language;
|
|
||||||
|
|
||||||
namespace Microsoft.Kusto.ServiceLayer.DataSource
|
namespace Microsoft.Kusto.ServiceLayer.DataSource
|
||||||
{
|
{
|
||||||
public interface IKustoClient
|
public interface IKustoClient
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// SchemaState used for getting intellisense info.
|
|
||||||
/// </summary>
|
|
||||||
GlobalState SchemaState { get; }
|
|
||||||
|
|
||||||
string ClusterName { get; }
|
string ClusterName { get; }
|
||||||
|
|
||||||
string DatabaseName { get; }
|
string DatabaseName { get; }
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Kusto.Language;
|
using Kusto.Language;
|
||||||
using KustoDiagnostic = Kusto.Language.Diagnostic;
|
|
||||||
using Kusto.Language.Editor;
|
using Kusto.Language.Editor;
|
||||||
using Kusto.Language.Syntax;
|
|
||||||
using Kusto.Language.Symbols;
|
using Kusto.Language.Symbols;
|
||||||
|
using Kusto.Language.Syntax;
|
||||||
using Microsoft.Kusto.ServiceLayer.LanguageServices;
|
using Microsoft.Kusto.ServiceLayer.LanguageServices;
|
||||||
using Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts;
|
using Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts;
|
||||||
using Microsoft.Kusto.ServiceLayer.LanguageServices.Completion;
|
|
||||||
using Microsoft.Kusto.ServiceLayer.Workspace.Contracts;
|
using Microsoft.Kusto.ServiceLayer.Workspace.Contracts;
|
||||||
|
using Diagnostic = Kusto.Language.Diagnostic;
|
||||||
|
|
||||||
namespace Microsoft.Kusto.ServiceLayer.DataSource.DataSourceIntellisense
|
namespace Microsoft.Kusto.ServiceLayer.DataSource.Intellisense
|
||||||
{
|
{
|
||||||
/// <summary>
|
public class KustoIntellisenseClient : IIntellisenseClient
|
||||||
/// Kusto specific class for intellisense helper functions.
|
|
||||||
/// </summary>
|
|
||||||
public class KustoIntellisenseHelper
|
|
||||||
{
|
{
|
||||||
|
private readonly IKustoClient _kustoClient;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// SchemaState used for getting intellisense info.
|
||||||
|
/// </summary>
|
||||||
|
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<ShowDatabaseSchemaResult> tableSchemas = Enumerable.Empty<ShowDatabaseSchemaResult>();
|
||||||
|
IEnumerable<ShowFunctionsResult> functionSchemas = Enumerable.Empty<ShowFunctionsResult>();
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(databaseName))
|
||||||
|
{
|
||||||
|
var source = new CancellationTokenSource();
|
||||||
|
Parallel.Invoke(() =>
|
||||||
|
{
|
||||||
|
tableSchemas =
|
||||||
|
_kustoClient.ExecuteQueryAsync<ShowDatabaseSchemaResult>($".show database {databaseName} schema", source.Token, databaseName)
|
||||||
|
.Result;
|
||||||
|
},
|
||||||
|
() =>
|
||||||
|
{
|
||||||
|
functionSchemas = _kustoClient.ExecuteQueryAsync<ShowFunctionsResult>(".show functions", source.Token, databaseName).Result;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return AddOrUpdateDatabase(tableSchemas, functionSchemas, GlobalState.Default, databaseName,
|
||||||
|
clusterName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Loads the schema for the specified database and returns a new <see cref="GlobalState"/> with the database added or updated.
|
||||||
|
/// </summary>
|
||||||
|
private GlobalState AddOrUpdateDatabase(IEnumerable<ShowDatabaseSchemaResult> tableSchemas,
|
||||||
|
IEnumerable<ShowFunctionsResult> 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Loads the schema for the specified database into a <see cref="DatabaseSymbol"/>.
|
||||||
|
/// </summary>
|
||||||
|
private DatabaseSymbol LoadDatabase(IEnumerable<ShowDatabaseSchemaResult> tableSchemas,
|
||||||
|
IEnumerable<ShowFunctionsResult> 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<Symbol>();
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Convert CLR type name into a Kusto scalar type.
|
/// Convert CLR type name into a Kusto scalar type.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static ScalarSymbol GetKustoType(string clrTypeName)
|
private ScalarSymbol GetKustoType(string clrTypeName)
|
||||||
{
|
{
|
||||||
switch (clrTypeName)
|
switch (clrTypeName)
|
||||||
{
|
{
|
||||||
@@ -97,219 +206,120 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource.DataSourceIntellisense
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IReadOnlyList<Parameter> NoParameters = new Parameter[0];
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Translate Kusto parameter list declaration into into list of <see cref="Parameter"/> instances.
|
/// Translate Kusto parameter list declaration into into list of <see cref="Parameter"/> instances.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static IReadOnlyList<Parameter> TranslateParameters(string parameters)
|
private IReadOnlyList<Parameter> TranslateParameters(string parameters)
|
||||||
{
|
{
|
||||||
parameters = parameters.Trim();
|
parameters = parameters.Trim();
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(parameters) || parameters == "()")
|
if (string.IsNullOrEmpty(parameters) || parameters == "()")
|
||||||
return NoParameters;
|
{
|
||||||
|
return new Parameter[0];
|
||||||
|
}
|
||||||
|
|
||||||
if (parameters[0] != '(')
|
if (parameters[0] != '(')
|
||||||
|
{
|
||||||
parameters = "(" + parameters;
|
parameters = "(" + parameters;
|
||||||
|
}
|
||||||
|
|
||||||
if (parameters[parameters.Length - 1] != ')')
|
if (parameters[parameters.Length - 1] != ')')
|
||||||
|
{
|
||||||
parameters = parameters + ")";
|
parameters = parameters + ")";
|
||||||
|
}
|
||||||
|
|
||||||
var query = "let fn = " + parameters + " { };";
|
var query = "let fn = " + parameters + " { };";
|
||||||
var code = KustoCode.ParseAndAnalyze(query);
|
var code = KustoCode.ParseAndAnalyze(query);
|
||||||
var let = code.Syntax.GetFirstDescendant<LetStatement>();
|
var let = code.Syntax.GetFirstDescendant<LetStatement>();
|
||||||
|
|
||||||
FunctionSymbol function = let.Name.ReferencedSymbol is VariableSymbol variable
|
FunctionSymbol function = let.Name.ReferencedSymbol is VariableSymbol variable
|
||||||
? variable.Type as FunctionSymbol
|
? variable.Type as FunctionSymbol
|
||||||
: let.Name.ReferencedSymbol as FunctionSymbol;
|
: let.Name.ReferencedSymbol as FunctionSymbol;
|
||||||
|
|
||||||
return function.Signatures[0].Parameters;
|
return function.Signatures[0].Parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
public ScriptFileMarker[] GetSemanticMarkers(ScriptParseInfo parseInfo, ScriptFile scriptFile, string queryText)
|
||||||
/// Loads the schema for the specified databasea into a a <see cref="DatabaseSymbol"/>.
|
|
||||||
/// </summary>
|
|
||||||
private static DatabaseSymbol LoadDatabaseAsync(IEnumerable<ShowDatabaseSchemaResult> tableSchemas,
|
|
||||||
IEnumerable<ShowFunctionsResult> functionSchemas,
|
|
||||||
string databaseName)
|
|
||||||
{
|
{
|
||||||
if (tableSchemas == null)
|
var kustoCodeService = new KustoCodeService(queryText, _schemaState);
|
||||||
|
var script = CodeScript.From(queryText, _schemaState);
|
||||||
|
var parseResult = new List<Diagnostic>();
|
||||||
|
|
||||||
|
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<Symbol>();
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets default keyword when user if not connected to any Kusto cluster.
|
|
||||||
/// </summary>
|
|
||||||
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<LanguageServices.Contracts.CompletionItem> completions =
|
|
||||||
new List<LanguageServices.Contracts.CompletionItem>();
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets default diagnostics when user if not connected to any Kusto cluster.
|
|
||||||
/// </summary>
|
|
||||||
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;
|
parseInfo.ParseResult = parseResult;
|
||||||
|
|
||||||
// build a list of Kusto script file markers from the errors.
|
if (!parseResult.Any())
|
||||||
List<ScriptFileMarker> markers = new List<ScriptFileMarker>();
|
|
||||||
if (parseResult != null && parseResult.Count() > 0)
|
|
||||||
{
|
{
|
||||||
foreach (var error in parseResult)
|
return Array.Empty<ScriptFileMarker>();
|
||||||
{
|
}
|
||||||
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.
|
// build a list of Kusto script file markers from the errors.
|
||||||
markers.Add(new ScriptFileMarker()
|
var markers = new List<ScriptFileMarker>();
|
||||||
|
|
||||||
|
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
|
||||||
{
|
{
|
||||||
Message = error.Message,
|
File = scriptFile.FilePath,
|
||||||
Level = ScriptFileMarkerLevel.Error,
|
StartLineNumber = startLine,
|
||||||
ScriptRegion = new ScriptRegion()
|
StartColumnNumber = startOffset,
|
||||||
{
|
StartOffset = 0,
|
||||||
File = scriptFile.FilePath,
|
EndLineNumber = endLine,
|
||||||
StartLineNumber = startLine,
|
EndColumnNumber = endOffset,
|
||||||
StartColumnNumber = startOffset,
|
EndOffset = 0
|
||||||
StartOffset = 0,
|
}
|
||||||
EndLineNumber = endLine,
|
});
|
||||||
EndColumnNumber = endOffset,
|
|
||||||
EndOffset = 0
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return markers.ToArray();
|
return markers.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
public DefinitionResult GetDefinition(string queryText, int index, int startLine, int startColumn, bool throwOnError = false)
|
||||||
/// Loads the schema for the specified database and returns a new <see cref="GlobalState"/> with the database added or updated.
|
|
||||||
/// </summary>
|
|
||||||
public static GlobalState AddOrUpdateDatabase(IEnumerable<ShowDatabaseSchemaResult> tableSchemas,
|
|
||||||
IEnumerable<ShowFunctionsResult> functionSchemas, GlobalState globals,
|
|
||||||
string databaseName, string clusterName)
|
|
||||||
{
|
{
|
||||||
// try and show error from here.
|
//TODOKusto: API wasnt working properly, need to check that part.
|
||||||
DatabaseSymbol databaseSymbol = null;
|
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 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
public Hover GetHoverHelp(ScriptDocumentInfo scriptDocumentInfo, Position textPosition, bool throwOnError = false)
|
||||||
public static LanguageServices.Contracts.CompletionItem[] GetAutoCompleteSuggestions(
|
|
||||||
ScriptDocumentInfo scriptDocumentInfo, Position textPosition, GlobalState schemaState,
|
|
||||||
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,
|
script.TryGetTextPosition(textPosition.Line + 1, textPosition.Character + 1,
|
||||||
out int position); // Gets the actual offset based on line and local offset
|
out int position); // Gets the actual offset based on line and local offset
|
||||||
|
|
||||||
@@ -335,85 +345,28 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource.DataSourceIntellisense
|
|||||||
return completions.ToArray();
|
return completions.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
private CompletionItemKind CreateCompletionItemKind(CompletionKind kustoKind)
|
||||||
public static Hover GetHoverHelp(ScriptDocumentInfo scriptDocumentInfo, Position textPosition,
|
|
||||||
GlobalState schemaState, bool throwOnError = false)
|
|
||||||
{
|
{
|
||||||
var script = CodeScript.From(scriptDocumentInfo.Contents, schemaState);
|
switch (kustoKind)
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
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<KustoDiagnostic>();
|
|
||||||
|
|
||||||
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<ScriptFileMarker> markers = new List<ScriptFileMarker>();
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Kusto specific class for intellisense helper functions.
|
||||||
|
/// </summary>
|
||||||
|
public class KustoIntellisenseHelper
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets default keyword when user if not connected to any Kusto cluster.
|
||||||
|
/// </summary>
|
||||||
|
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<LanguageServices.Contracts.CompletionItem> completions =
|
||||||
|
new List<LanguageServices.Contracts.CompletionItem>();
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets default diagnostics when user if not connected to any Kusto cluster.
|
||||||
|
/// </summary>
|
||||||
|
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<ScriptFileMarker> markers = new List<ScriptFileMarker>();
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,7 +7,7 @@ using System.Collections.Generic;
|
|||||||
using Kusto.Language;
|
using Kusto.Language;
|
||||||
using Kusto.Language.Editor;
|
using Kusto.Language.Editor;
|
||||||
|
|
||||||
namespace Microsoft.Kusto.ServiceLayer.DataSource.DataSourceIntellisense
|
namespace Microsoft.Kusto.ServiceLayer.DataSource.Intellisense
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Data Source specific class for storing cached metadata regarding a parsed KQL file.
|
/// Data Source specific class for storing cached metadata regarding a parsed KQL file.
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace Microsoft.Kusto.ServiceLayer.DataSource.DataSourceIntellisense
|
namespace Microsoft.Kusto.ServiceLayer.DataSource.Intellisense
|
||||||
{
|
{
|
||||||
public class ShowDatabaseSchemaResult
|
public class ShowDatabaseSchemaResult
|
||||||
{
|
{
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace Microsoft.Kusto.ServiceLayer.DataSource.DataSourceIntellisense
|
namespace Microsoft.Kusto.ServiceLayer.DataSource.Intellisense
|
||||||
{
|
{
|
||||||
public class ShowDatabasesResult
|
public class ShowDatabasesResult
|
||||||
{
|
{
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace Microsoft.Kusto.ServiceLayer.DataSource.DataSourceIntellisense
|
namespace Microsoft.Kusto.ServiceLayer.DataSource.Intellisense
|
||||||
{
|
{
|
||||||
public class ShowFunctionsResult
|
public class ShowFunctionsResult
|
||||||
{
|
{
|
||||||
@@ -16,7 +16,6 @@ using Kusto.Language;
|
|||||||
using Kusto.Language.Editor;
|
using Kusto.Language.Editor;
|
||||||
using Microsoft.Kusto.ServiceLayer.Connection;
|
using Microsoft.Kusto.ServiceLayer.Connection;
|
||||||
using Microsoft.Kusto.ServiceLayer.DataSource.Contracts;
|
using Microsoft.Kusto.ServiceLayer.DataSource.Contracts;
|
||||||
using Microsoft.Kusto.ServiceLayer.DataSource.DataSourceIntellisense;
|
|
||||||
using Microsoft.Kusto.ServiceLayer.Utility;
|
using Microsoft.Kusto.ServiceLayer.Utility;
|
||||||
|
|
||||||
namespace Microsoft.Kusto.ServiceLayer.DataSource
|
namespace Microsoft.Kusto.ServiceLayer.DataSource
|
||||||
@@ -31,11 +30,6 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
|
|||||||
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
|
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
|
||||||
private ICslQueryProvider _kustoQueryProvider;
|
private ICslQueryProvider _kustoQueryProvider;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// SchemaState used for getting intellisense info.
|
|
||||||
/// </summary>
|
|
||||||
public GlobalState SchemaState { get; private set; }
|
|
||||||
|
|
||||||
public string ClusterName { get; private set; }
|
public string ClusterName { get; private set; }
|
||||||
public string DatabaseName { get; private set; }
|
public string DatabaseName { get; private set; }
|
||||||
|
|
||||||
@@ -43,7 +37,6 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
|
|||||||
{
|
{
|
||||||
_ownerUri = ownerUri;
|
_ownerUri = ownerUri;
|
||||||
Initialize(connectionDetails);
|
Initialize(connectionDetails);
|
||||||
SchemaState = LoadSchemaState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private string ParseDatabaseName(string databaseName)
|
private string ParseDatabaseName(string databaseName)
|
||||||
@@ -55,31 +48,6 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
|
|||||||
: databaseName;
|
: databaseName;
|
||||||
}
|
}
|
||||||
|
|
||||||
private GlobalState LoadSchemaState()
|
|
||||||
{
|
|
||||||
IEnumerable<ShowDatabaseSchemaResult> tableSchemas = Enumerable.Empty<ShowDatabaseSchemaResult>();
|
|
||||||
IEnumerable<ShowFunctionsResult> functionSchemas = Enumerable.Empty<ShowFunctionsResult>();
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(DatabaseName))
|
|
||||||
{
|
|
||||||
var source = new CancellationTokenSource();
|
|
||||||
Parallel.Invoke(() =>
|
|
||||||
{
|
|
||||||
tableSchemas =
|
|
||||||
ExecuteQueryAsync<ShowDatabaseSchemaResult>($".show database {DatabaseName} schema", source.Token, DatabaseName)
|
|
||||||
.Result;
|
|
||||||
},
|
|
||||||
() =>
|
|
||||||
{
|
|
||||||
functionSchemas = ExecuteQueryAsync<ShowFunctionsResult>(".show functions", source.Token, DatabaseName).Result;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return KustoIntellisenseHelper.AddOrUpdateDatabase(tableSchemas, functionSchemas,
|
|
||||||
GlobalState.Default,
|
|
||||||
DatabaseName, ClusterName);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Initialize(DataSourceConnectionDetails connectionDetails)
|
private void Initialize(DataSourceConnectionDetails connectionDetails)
|
||||||
{
|
{
|
||||||
var stringBuilder = GetKustoConnectionStringBuilder(connectionDetails);
|
var stringBuilder = GetKustoConnectionStringBuilder(connectionDetails);
|
||||||
@@ -275,7 +243,6 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
|
|||||||
public void UpdateDatabase(string databaseName)
|
public void UpdateDatabase(string databaseName)
|
||||||
{
|
{
|
||||||
DatabaseName = ParseDatabaseName(databaseName);
|
DatabaseName = ParseDatabaseName(databaseName);
|
||||||
SchemaState = LoadSchemaState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
|||||||
@@ -14,10 +14,13 @@ using System.Threading.Tasks;
|
|||||||
using Kusto.Cloud.Platform.Data;
|
using Kusto.Cloud.Platform.Data;
|
||||||
using Kusto.Data;
|
using Kusto.Data;
|
||||||
using Kusto.Data.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.Metadata;
|
||||||
using Microsoft.Kusto.ServiceLayer.DataSource.Models;
|
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.Utility;
|
||||||
|
using Microsoft.Kusto.ServiceLayer.Workspace.Contracts;
|
||||||
|
|
||||||
namespace Microsoft.Kusto.ServiceLayer.DataSource
|
namespace Microsoft.Kusto.ServiceLayer.DataSource
|
||||||
{
|
{
|
||||||
@@ -26,7 +29,8 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class KustoDataSource : DataSourceBase
|
public class KustoDataSource : DataSourceBase
|
||||||
{
|
{
|
||||||
private IKustoClient _kustoClient;
|
private readonly IKustoClient _kustoClient;
|
||||||
|
private readonly IIntellisenseClient _intellisenseClient;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// List of databases.
|
/// List of databases.
|
||||||
@@ -57,8 +61,6 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
|
|||||||
|
|
||||||
public override string ClusterName => _kustoClient.ClusterName;
|
public override string ClusterName => _kustoClient.ClusterName;
|
||||||
|
|
||||||
public override GlobalState SchemaState => _kustoClient.SchemaState;
|
|
||||||
|
|
||||||
// Some clusters have this signature. Queries might slightly differ for Aria
|
// Some clusters have this signature. Queries might slightly differ for Aria
|
||||||
private const string AriaProxyURL = "kusto.aria.microsoft.com";
|
private const string AriaProxyURL = "kusto.aria.microsoft.com";
|
||||||
|
|
||||||
@@ -77,9 +79,10 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Prevents a default instance of the <see cref="IDataSource"/> class from being created.
|
/// Prevents a default instance of the <see cref="IDataSource"/> class from being created.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public KustoDataSource(IKustoClient kustoClient)
|
public KustoDataSource(IKustoClient kustoClient, IIntellisenseClient intellisenseClient)
|
||||||
{
|
{
|
||||||
_kustoClient = kustoClient;
|
_kustoClient = kustoClient;
|
||||||
|
_intellisenseClient = intellisenseClient;
|
||||||
// Check if a connection can be made
|
// Check if a connection can be made
|
||||||
ValidationUtils.IsTrue<ArgumentException>(Exists().Result,
|
ValidationUtils.IsTrue<ArgumentException>(Exists().Result,
|
||||||
$"Unable to connect. ClusterName = {ClusterName}, DatabaseName = {DatabaseName}");
|
$"Unable to connect. ClusterName = {ClusterName}, DatabaseName = {DatabaseName}");
|
||||||
@@ -246,6 +249,7 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
|
|||||||
public override void UpdateDatabase(string databaseName)
|
public override void UpdateDatabase(string databaseName)
|
||||||
{
|
{
|
||||||
_kustoClient.UpdateDatabase(databaseName);
|
_kustoClient.UpdateDatabase(databaseName);
|
||||||
|
_intellisenseClient.UpdateDatabase(databaseName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -809,6 +813,26 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
|
|||||||
return string.IsNullOrWhiteSpace(objectName) ? databaseName : $"{databaseName}.{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
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ namespace Microsoft.Kusto.ServiceLayer
|
|||||||
WorkspaceService<SqlToolsSettings>.Instance.InitializeService(serviceHost);
|
WorkspaceService<SqlToolsSettings>.Instance.InitializeService(serviceHost);
|
||||||
serviceProvider.RegisterSingleService(WorkspaceService<SqlToolsSettings>.Instance);
|
serviceProvider.RegisterSingleService(WorkspaceService<SqlToolsSettings>.Instance);
|
||||||
|
|
||||||
LanguageService.Instance.InitializeService(serviceHost, connectedBindingQueue, dataSourceFactory);
|
LanguageService.Instance.InitializeService(serviceHost, connectedBindingQueue);
|
||||||
serviceProvider.RegisterSingleService(LanguageService.Instance);
|
serviceProvider.RegisterSingleService(LanguageService.Instance);
|
||||||
|
|
||||||
ConnectionService.Instance.InitializeService(serviceHost, dataSourceConnectionFactory, connectedBindingQueue, dataSourceFactory);
|
ConnectionService.Instance.InitializeService(serviceHost, dataSourceConnectionFactory, connectedBindingQueue, dataSourceFactory);
|
||||||
|
|||||||
@@ -15,10 +15,9 @@ using Microsoft.SqlServer.Management.SqlParser.Parser;
|
|||||||
using Microsoft.SqlServer.Management.SqlParser.SqlCodeDom;
|
using Microsoft.SqlServer.Management.SqlParser.SqlCodeDom;
|
||||||
using Microsoft.SqlTools.Hosting.Protocol;
|
using Microsoft.SqlTools.Hosting.Protocol;
|
||||||
using Microsoft.Kusto.ServiceLayer.DataSource;
|
using Microsoft.Kusto.ServiceLayer.DataSource;
|
||||||
using Microsoft.Kusto.ServiceLayer.DataSource.DataSourceIntellisense;
|
|
||||||
using Microsoft.Kusto.ServiceLayer.Connection;
|
using Microsoft.Kusto.ServiceLayer.Connection;
|
||||||
using Microsoft.Kusto.ServiceLayer.Connection.Contracts;
|
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.LanguageServices.Contracts;
|
||||||
using Microsoft.Kusto.ServiceLayer.Utility;
|
using Microsoft.Kusto.ServiceLayer.Utility;
|
||||||
using Microsoft.Kusto.ServiceLayer.Workspace;
|
using Microsoft.Kusto.ServiceLayer.Workspace;
|
||||||
@@ -67,9 +66,6 @@ namespace Microsoft.Kusto.ServiceLayer.LanguageServices
|
|||||||
|
|
||||||
internal const int PeekDefinitionTimeout = 10 * OneSecond;
|
internal const int PeekDefinitionTimeout = 10 * OneSecond;
|
||||||
|
|
||||||
// For testability only
|
|
||||||
internal Task DelayedDiagnosticsTask = null;
|
|
||||||
|
|
||||||
private ConnectionService connectionService = null;
|
private ConnectionService connectionService = null;
|
||||||
|
|
||||||
private WorkspaceService<SqlToolsSettings> workspaceServiceInstance;
|
private WorkspaceService<SqlToolsSettings> workspaceServiceInstance;
|
||||||
@@ -209,7 +205,7 @@ namespace Microsoft.Kusto.ServiceLayer.LanguageServices
|
|||||||
/// <param name="context"></param>
|
/// <param name="context"></param>
|
||||||
/// <param name="dataSourceFactory"></param>
|
/// <param name="dataSourceFactory"></param>
|
||||||
/// <param name="connectedBindingQueue"></param>
|
/// <param name="connectedBindingQueue"></param>
|
||||||
public void InitializeService(ServiceHost serviceHost, IConnectedBindingQueue connectedBindingQueue, IDataSourceFactory dataSourceFactory)
|
public void InitializeService(ServiceHost serviceHost, IConnectedBindingQueue connectedBindingQueue)
|
||||||
{
|
{
|
||||||
_bindingQueue = connectedBindingQueue;
|
_bindingQueue = connectedBindingQueue;
|
||||||
// Register the requests that this service will handle
|
// Register the requests that this service will handle
|
||||||
@@ -766,18 +762,16 @@ namespace Microsoft.Kusto.ServiceLayer.LanguageServices
|
|||||||
connInfo.TryGetConnection("Default", out connection);
|
connInfo.TryGetConnection("Default", out connection);
|
||||||
IDataSource dataSource = connection.GetUnderlyingConnection();
|
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.
|
IsErrorResult = true,
|
||||||
return new DefinitionResult
|
Message = SR.PeekDefinitionNotConnectedError,
|
||||||
{
|
Locations = null
|
||||||
IsErrorResult = true,
|
};
|
||||||
Message = SR.PeekDefinitionNotConnectedError,
|
|
||||||
Locations = null
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -810,8 +804,7 @@ namespace Microsoft.Kusto.ServiceLayer.LanguageServices
|
|||||||
ReliableDataSourceConnection connection;
|
ReliableDataSourceConnection connection;
|
||||||
connInfo.TryGetConnection("Default", out connection);
|
connInfo.TryGetConnection("Default", out connection);
|
||||||
IDataSource dataSource = connection.GetUnderlyingConnection();
|
IDataSource dataSource = connection.GetUnderlyingConnection();
|
||||||
|
return dataSource.GetHoverHelp(scriptDocumentInfo, textDocumentPosition.Position);
|
||||||
return KustoIntellisenseHelper.GetHoverHelp(scriptDocumentInfo, textDocumentPosition.Position, dataSource.SchemaState);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
queueItem.ItemProcessed.WaitOne();
|
queueItem.ItemProcessed.WaitOne();
|
||||||
@@ -855,14 +848,17 @@ namespace Microsoft.Kusto.ServiceLayer.LanguageServices
|
|||||||
|
|
||||||
ScriptDocumentInfo scriptDocumentInfo = new ScriptDocumentInfo(textDocumentPosition, scriptFile, scriptParseInfo);
|
ScriptDocumentInfo scriptDocumentInfo = new ScriptDocumentInfo(textDocumentPosition, scriptFile, scriptParseInfo);
|
||||||
|
|
||||||
if(connInfo != null){
|
if (connInfo != null)
|
||||||
|
{
|
||||||
ReliableDataSourceConnection connection;
|
ReliableDataSourceConnection connection;
|
||||||
connInfo.TryGetConnection("Default", out connection);
|
connInfo.TryGetConnection("Default", out connection);
|
||||||
IDataSource dataSource = connection.GetUnderlyingConnection();
|
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);
|
resultCompletionItems = DataSourceFactory.GetDefaultAutoComplete(DataSourceType.Kusto, scriptDocumentInfo, textDocumentPosition.Position);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -932,7 +928,7 @@ namespace Microsoft.Kusto.ServiceLayer.LanguageServices
|
|||||||
existingRequestCancellation = new CancellationTokenSource();
|
existingRequestCancellation = new CancellationTokenSource();
|
||||||
Task.Factory.StartNew(
|
Task.Factory.StartNew(
|
||||||
() =>
|
() =>
|
||||||
this.DelayedDiagnosticsTask = DelayThenInvokeDiagnostics(
|
DelayThenInvokeDiagnostics(
|
||||||
LanguageService.DiagnosticParseDelay,
|
LanguageService.DiagnosticParseDelay,
|
||||||
filesToAnalyze,
|
filesToAnalyze,
|
||||||
eventContext,
|
eventContext,
|
||||||
@@ -1001,13 +997,15 @@ namespace Microsoft.Kusto.ServiceLayer.LanguageServices
|
|||||||
scriptFile.ClientUri,
|
scriptFile.ClientUri,
|
||||||
out connInfo);
|
out connInfo);
|
||||||
|
|
||||||
if(connInfo != null){
|
if (connInfo != null)
|
||||||
|
{
|
||||||
connInfo.TryGetConnection("Default", out var connection);
|
connInfo.TryGetConnection("Default", out var connection);
|
||||||
IDataSource dataSource = connection.GetUnderlyingConnection();
|
IDataSource dataSource = connection.GetUnderlyingConnection();
|
||||||
|
|
||||||
semanticMarkers = KustoIntellisenseHelper.GetSemanticMarkers(parseInfo, scriptFile, scriptFile.Contents, dataSource.SchemaState);
|
semanticMarkers = dataSource.GetSemanticMarkers(parseInfo, scriptFile, scriptFile.Contents);
|
||||||
}
|
}
|
||||||
else{
|
else
|
||||||
|
{
|
||||||
semanticMarkers = DataSourceFactory.GetDefaultSemanticMarkers(DataSourceType.Kusto, parseInfo, scriptFile, scriptFile.Contents);
|
semanticMarkers = DataSourceFactory.GetDefaultSemanticMarkers(DataSourceType.Kusto, parseInfo, scriptFile, scriptFile.Contents);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,12 +3,12 @@
|
|||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
using Microsoft.Kusto.ServiceLayer.DataSource.Intellisense;
|
||||||
|
using Microsoft.Kusto.ServiceLayer.Workspace.Contracts;
|
||||||
using Microsoft.SqlServer.Management.SqlParser.Parser;
|
using Microsoft.SqlServer.Management.SqlParser.Parser;
|
||||||
using Microsoft.SqlTools.Utility;
|
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
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A class to calculate the numbers used by SQL parser using the text positions and content
|
/// A class to calculate the numbers used by SQL parser using the text positions and content
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Microsoft.Kusto.ServiceLayer.Connection.Contracts;
|
using Microsoft.Kusto.ServiceLayer.Connection.Contracts;
|
||||||
using Microsoft.Kusto.ServiceLayer.DataSource;
|
using Microsoft.Kusto.ServiceLayer.DataSource;
|
||||||
using Microsoft.Kusto.ServiceLayer.DataSource.DataSourceIntellisense;
|
using Microsoft.Kusto.ServiceLayer.DataSource.Intellisense;
|
||||||
using Microsoft.Kusto.ServiceLayer.LanguageServices.Completion;
|
using Microsoft.Kusto.ServiceLayer.LanguageServices;
|
||||||
using Microsoft.Kusto.ServiceLayer.Workspace.Contracts;
|
using Microsoft.Kusto.ServiceLayer.Workspace.Contracts;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
|||||||
@@ -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<IKustoClient> GetMockKustoClient()
|
||||||
|
{
|
||||||
|
var kustoClientMock = new Mock<IKustoClient>();
|
||||||
|
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<ShowDatabaseSchemaResult> {databaseSchema} as IEnumerable<ShowDatabaseSchemaResult>;
|
||||||
|
kustoClientMock.Setup(x => x.ExecuteQueryAsync<ShowDatabaseSchemaResult>(It.IsAny<string>(), It.IsAny<CancellationToken>(), "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<ShowFunctionsResult> {functionSchema} as IEnumerable<ShowFunctionsResult>;
|
||||||
|
kustoClientMock.Setup(x => x.ExecuteQueryAsync<ShowFunctionsResult>(It.IsAny<string>(), It.IsAny<CancellationToken>(), "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<ShowDatabaseSchemaResult> {databaseSchema} as IEnumerable<ShowDatabaseSchemaResult>;
|
||||||
|
kustoClientMock.Setup(x => x.ExecuteQueryAsync<ShowDatabaseSchemaResult>(It.IsAny<string>(), It.IsAny<CancellationToken>(), "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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,5 @@
|
|||||||
using System.Linq;
|
using Microsoft.Kusto.ServiceLayer.DataSource.Intellisense;
|
||||||
using Kusto.Language.Editor;
|
using Microsoft.Kusto.ServiceLayer.LanguageServices;
|
||||||
using Microsoft.Kusto.ServiceLayer.DataSource.DataSourceIntellisense;
|
|
||||||
using Microsoft.Kusto.ServiceLayer.LanguageServices.Completion;
|
|
||||||
using Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts;
|
|
||||||
using Microsoft.Kusto.ServiceLayer.Workspace.Contracts;
|
using Microsoft.Kusto.ServiceLayer.Workspace.Contracts;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
|
||||||
@@ -10,37 +7,6 @@ namespace Microsoft.Kusto.ServiceLayer.UnitTests.DataSource.DataSourceIntellisen
|
|||||||
{
|
{
|
||||||
public class KustoIntellisenseHelperTests
|
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]
|
[Test]
|
||||||
public void GetDefaultKeywords_Returns_Keywords()
|
public void GetDefaultKeywords_Returns_Keywords()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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<ArgumentException>(() => 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user