mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-02-16 10:58:30 -05:00
Adding service operations for external languages (#918)
* Added service operations for external languages
This commit is contained in:
@@ -19,7 +19,7 @@ using Microsoft.SqlTools.ServiceLayer.FileBrowser;
|
|||||||
using Microsoft.SqlTools.ServiceLayer.Hosting;
|
using Microsoft.SqlTools.ServiceLayer.Hosting;
|
||||||
using Microsoft.SqlTools.ServiceLayer.LanguageServices;
|
using Microsoft.SqlTools.ServiceLayer.LanguageServices;
|
||||||
using Microsoft.SqlTools.ServiceLayer.ServerConfigurations;
|
using Microsoft.SqlTools.ServiceLayer.ServerConfigurations;
|
||||||
using Microsoft.SqlTools.ServiceLayer.LanguageExtensions;
|
using Microsoft.SqlTools.ServiceLayer.LanguageExtensibility;
|
||||||
using Microsoft.SqlTools.ServiceLayer.Metadata;
|
using Microsoft.SqlTools.ServiceLayer.Metadata;
|
||||||
using Microsoft.SqlTools.ServiceLayer.Profiler;
|
using Microsoft.SqlTools.ServiceLayer.Profiler;
|
||||||
using Microsoft.SqlTools.ServiceLayer.QueryExecution;
|
using Microsoft.SqlTools.ServiceLayer.QueryExecution;
|
||||||
@@ -127,8 +127,8 @@ namespace Microsoft.SqlTools.ServiceLayer
|
|||||||
ServerConfigService.Instance.InitializeService(serviceHost);
|
ServerConfigService.Instance.InitializeService(serviceHost);
|
||||||
serviceProvider.RegisterSingleService(ServerConfigService.Instance);
|
serviceProvider.RegisterSingleService(ServerConfigService.Instance);
|
||||||
|
|
||||||
LanguageExtensionsService.Instance.InitializeService(serviceHost);
|
ExternalLanguageService.Instance.InitializeService(serviceHost);
|
||||||
serviceProvider.RegisterSingleService(LanguageExtensionsService.Instance);
|
serviceProvider.RegisterSingleService(ExternalLanguageService.Instance);
|
||||||
|
|
||||||
InitializeHostedServices(serviceProvider, serviceHost);
|
InitializeHostedServices(serviceProvider, serviceHost);
|
||||||
serviceHost.ServiceProvider = serviceProvider;
|
serviceHost.ServiceProvider = serviceProvider;
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||||
|
//
|
||||||
|
|
||||||
|
using Microsoft.SqlTools.Hosting.Protocol.Contracts;
|
||||||
|
|
||||||
|
namespace Microsoft.SqlTools.ServiceLayer.LanguageExtensibility.Contracts
|
||||||
|
{
|
||||||
|
public class ExternalLanguageDeleteRequestParams
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Connection uri
|
||||||
|
/// </summary>
|
||||||
|
public string OwnerUri { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Language name
|
||||||
|
/// </summary>
|
||||||
|
public string LanguageName { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Response class for external language status
|
||||||
|
/// </summary>
|
||||||
|
public class ExternalLanguageDeleteResponseParams
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Request class for external language status
|
||||||
|
/// </summary>
|
||||||
|
public class ExternalLanguageDeleteRequest
|
||||||
|
{
|
||||||
|
public static readonly
|
||||||
|
RequestType<ExternalLanguageDeleteRequestParams, ExternalLanguageDeleteResponseParams> Type =
|
||||||
|
RequestType<ExternalLanguageDeleteRequestParams, ExternalLanguageDeleteResponseParams>.Create("languageExtension/delete");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||||
|
//
|
||||||
|
|
||||||
|
using Microsoft.SqlTools.Hosting.Protocol.Contracts;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Microsoft.SqlTools.ServiceLayer.LanguageExtensibility.Contracts
|
||||||
|
{
|
||||||
|
public class ExternalLanguageListRequestParams
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Connection uri
|
||||||
|
/// </summary>
|
||||||
|
public string OwnerUri { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Response class for external language list
|
||||||
|
/// </summary>
|
||||||
|
public class ExternalLanguageListResponseParams
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Language status
|
||||||
|
/// </summary>
|
||||||
|
public List<ExternalLanguage> Languages { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Request class for external language list
|
||||||
|
/// </summary>
|
||||||
|
public class ExternalLanguageListRequest
|
||||||
|
{
|
||||||
|
public static readonly
|
||||||
|
RequestType<ExternalLanguageListRequestParams, ExternalLanguageListResponseParams> Type =
|
||||||
|
RequestType<ExternalLanguageListRequestParams, ExternalLanguageListResponseParams>.Create("languageExtension/list");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
//
|
||||||
|
// 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.IO;
|
||||||
|
|
||||||
|
namespace Microsoft.SqlTools.ServiceLayer.LanguageExtensibility.Contracts
|
||||||
|
{
|
||||||
|
|
||||||
|
public enum ExternalLanguagePlatform
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Windows,
|
||||||
|
Linux
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Language metadata
|
||||||
|
/// </summary>
|
||||||
|
public class ExternalLanguage
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Language Name
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Language Owner
|
||||||
|
/// </summary>
|
||||||
|
public string Owner { get; set; }
|
||||||
|
|
||||||
|
public List<ExternalLanguageContent> Contents { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Created Date
|
||||||
|
/// </summary>
|
||||||
|
public string CreatedDate { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ExternalLanguageContent
|
||||||
|
{
|
||||||
|
public bool IsLocalFile { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Path to extension file
|
||||||
|
/// </summary>
|
||||||
|
public string PathToExtension { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extension file name
|
||||||
|
/// </summary>
|
||||||
|
public string ExtensionFileName { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Platform name
|
||||||
|
/// </summary>
|
||||||
|
public ExternalLanguagePlatform PlatformId
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return string.IsNullOrWhiteSpace(Platform) ? ExternalLanguagePlatform.None : (ExternalLanguagePlatform)Enum.Parse(typeof(ExternalLanguagePlatform), Platform, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Platform { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extension parameters
|
||||||
|
/// </summary>
|
||||||
|
public string Parameters { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Environment variables
|
||||||
|
/// </summary>
|
||||||
|
public string EnvironmentVariables { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
using Microsoft.SqlTools.Hosting.Protocol.Contracts;
|
using Microsoft.SqlTools.Hosting.Protocol.Contracts;
|
||||||
|
|
||||||
namespace Microsoft.SqlTools.ServiceLayer.LanguageExtensions.Contracts
|
namespace Microsoft.SqlTools.ServiceLayer.LanguageExtensibility.Contracts
|
||||||
{
|
{
|
||||||
public class ExternalLanguageStatusRequestParams
|
public class ExternalLanguageStatusRequestParams
|
||||||
{
|
{
|
||||||
@@ -38,6 +38,6 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageExtensions.Contracts
|
|||||||
{
|
{
|
||||||
public static readonly
|
public static readonly
|
||||||
RequestType<ExternalLanguageStatusRequestParams, ExternalLanguageStatusResponseParams> Type =
|
RequestType<ExternalLanguageStatusRequestParams, ExternalLanguageStatusResponseParams> Type =
|
||||||
RequestType<ExternalLanguageStatusRequestParams, ExternalLanguageStatusResponseParams>.Create("languageextension/status");
|
RequestType<ExternalLanguageStatusRequestParams, ExternalLanguageStatusResponseParams>.Create("languageExtension/status");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||||
|
//
|
||||||
|
|
||||||
|
using Microsoft.SqlTools.Hosting.Protocol.Contracts;
|
||||||
|
|
||||||
|
namespace Microsoft.SqlTools.ServiceLayer.LanguageExtensibility.Contracts
|
||||||
|
{
|
||||||
|
public class ExternalLanguageUpdateRequestParams
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Connection uri
|
||||||
|
/// </summary>
|
||||||
|
public string OwnerUri { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Language name
|
||||||
|
/// </summary>
|
||||||
|
public ExternalLanguage Language { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Response class for external language update
|
||||||
|
/// </summary>
|
||||||
|
public class ExternalLanguageUpdateResponseParams
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Request class for external language status
|
||||||
|
/// </summary>
|
||||||
|
public class ExternalLanguageUpdateRequest
|
||||||
|
{
|
||||||
|
public static readonly
|
||||||
|
RequestType<ExternalLanguageUpdateRequestParams, ExternalLanguageUpdateResponseParams> Type =
|
||||||
|
RequestType<ExternalLanguageUpdateRequestParams, ExternalLanguageUpdateResponseParams>.Create("languageExtension/update");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,343 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||||
|
//
|
||||||
|
|
||||||
|
using Microsoft.SqlTools.ServiceLayer.LanguageExtensibility.Contracts;
|
||||||
|
using Microsoft.SqlTools.ServiceLayer.Management;
|
||||||
|
using Microsoft.SqlTools.Utility;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Microsoft.SqlTools.ServiceLayer.LanguageExtensibility
|
||||||
|
{
|
||||||
|
|
||||||
|
public enum ModifyType
|
||||||
|
{
|
||||||
|
Create,
|
||||||
|
Alter
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ContentModifyType
|
||||||
|
{
|
||||||
|
Modify,
|
||||||
|
Add,
|
||||||
|
Remove
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ExternalLanguageOperations
|
||||||
|
{
|
||||||
|
private static string StatusScript = $@"
|
||||||
|
SELECT is_installed
|
||||||
|
FROM sys.dm_db_external_language_stats s, sys.external_languages l
|
||||||
|
WHERE s.external_language_id = l.external_language_id AND language = @{LanguageNameParamName}";
|
||||||
|
|
||||||
|
private const string GetAllScript = @"
|
||||||
|
SELECT l.external_language_id, language, l.create_date, dp.name, content, file_name, platform_desc, parameters, environment_variables
|
||||||
|
FROM sys.external_languages l
|
||||||
|
JOIN sys.external_language_files lf on l.external_language_id = lf.external_language_id
|
||||||
|
JOIN sys.database_principals dp on l.principal_id = dp.principal_id
|
||||||
|
ORDER BY l.external_language_id, platform";
|
||||||
|
|
||||||
|
private static string GetLanguageScript = $@"
|
||||||
|
SELECT l.external_language_id, language, l.create_date, dp.name, content, file_name, platform_desc, parameters, environment_variables
|
||||||
|
FROM sys.external_languages l
|
||||||
|
JOIN sys.external_language_files lf on l.external_language_id = lf.external_language_id
|
||||||
|
JOIN sys.database_principals dp on l.principal_id = dp.principal_id
|
||||||
|
WHERE language=@{LanguageNameParamName}
|
||||||
|
ORDER BY platform";
|
||||||
|
|
||||||
|
public const string CreateScript = "CREATE EXTERNAL LANGUAGE";
|
||||||
|
public const string DropScript = "DROP EXTERNAL LANGUAGE";
|
||||||
|
public const string AlterScript = "ALTER EXTERNAL LANGUAGE";
|
||||||
|
public const string SetContentScript = "SET";
|
||||||
|
public const string AddContentScript = "ADD";
|
||||||
|
public const string RemoveContentScript = "REMOVE";
|
||||||
|
private const string ContentParamName = "CONTENT";
|
||||||
|
private const string FileNameParamName = "FILE_NAME";
|
||||||
|
private const string PlatformParamName = "PLATFORM";
|
||||||
|
private const string EnvVariablesParamName = "ENVIRONMENT_VARIABLES";
|
||||||
|
private const string ParametersParamName = "PARAMETERS";
|
||||||
|
private const string LanguageNameParamName = "LANGUAGE";
|
||||||
|
|
||||||
|
private string GetDropScript(string languageName)
|
||||||
|
{
|
||||||
|
return $@"{DropScript} [{CUtils.EscapeStringCBracket(languageName)}]";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the status of external languages in a connection
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="connection"></param>
|
||||||
|
/// <param name="languageName"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public virtual bool GetLanguageStatus(IDbConnection connection, string languageName)
|
||||||
|
{
|
||||||
|
bool status = false;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (IDbCommand command = connection.CreateCommand())
|
||||||
|
{
|
||||||
|
command.CommandText = StatusScript;
|
||||||
|
var parameter = command.CreateParameter();
|
||||||
|
parameter.ParameterName = $"@{LanguageNameParamName}";
|
||||||
|
parameter.Value = languageName;
|
||||||
|
command.Parameters.Add(parameter);
|
||||||
|
using (IDataReader reader = command.ExecuteReader())
|
||||||
|
{
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
status = (Convert.ToBoolean(reader[0].ToString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.Write(TraceEventType.Warning, $"Failed to get language status for language: {languageName}, error: {ex.Message}");
|
||||||
|
status = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the list of languages
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="connection"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public virtual List<ExternalLanguage> GetLanguages(IDbConnection connection)
|
||||||
|
{
|
||||||
|
return GetLanguages(connection, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="connection"></param>
|
||||||
|
/// <param name="languageName"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public virtual ExternalLanguage GetLanguage(IDbConnection connection, string languageName)
|
||||||
|
{
|
||||||
|
List<ExternalLanguage> result = GetLanguages(connection, languageName);
|
||||||
|
if (result != null && result.Any())
|
||||||
|
{
|
||||||
|
return result.First();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="connection"></param>
|
||||||
|
/// <param name="language"></param>
|
||||||
|
public virtual void UpdateLanguage(IDbConnection connection, ExternalLanguage language)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(language?.Name))
|
||||||
|
{
|
||||||
|
throw new LanguageExtensibilityException($"Failed to update language. language or language name is empty.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
||||||
|
ExternalLanguage currentLanguage = GetLanguage(connection, language.Name);
|
||||||
|
if (currentLanguage == null)
|
||||||
|
{
|
||||||
|
ExecuteNonQuery(connection, GetCreateScript(language, parameters), parameters);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (var content in language.Contents)
|
||||||
|
{
|
||||||
|
var currentContent = currentLanguage.Contents.FirstOrDefault(x => x.PlatformId == content.PlatformId);
|
||||||
|
if (currentContent != null)
|
||||||
|
{
|
||||||
|
ExecuteNonQuery(connection, GetUpdateScript(language, content, parameters, ContentModifyType.Modify), parameters);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ExecuteNonQuery(connection, GetUpdateScript(language, content, parameters, ContentModifyType.Add), parameters);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (var currentContent in currentLanguage.Contents)
|
||||||
|
{
|
||||||
|
var content = language.Contents.FirstOrDefault(x => x.PlatformId == currentContent.PlatformId);
|
||||||
|
if (content == null)
|
||||||
|
{
|
||||||
|
ExecuteNonQuery(connection, GetUpdateScript(language, currentContent, parameters, ContentModifyType.Remove), parameters);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void DeleteLanguage(IDbConnection connection, string languageName)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(languageName))
|
||||||
|
{
|
||||||
|
throw new LanguageExtensibilityException($"Failed to delete language. language name is empty");
|
||||||
|
}
|
||||||
|
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
||||||
|
ExecuteNonQuery(connection, GetDropScript(languageName), parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the status of external languages in a connection
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="connection"></param>
|
||||||
|
/// <param name="languageName"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private List<ExternalLanguage> GetLanguages(IDbConnection connection, string languageName = null)
|
||||||
|
{
|
||||||
|
Dictionary<int, ExternalLanguage> dic = new Dictionary<int, ExternalLanguage>();
|
||||||
|
using (IDbCommand command = connection.CreateCommand())
|
||||||
|
{
|
||||||
|
command.CommandText = languageName != null ? GetLanguageScript : GetAllScript;
|
||||||
|
if (languageName != null)
|
||||||
|
{
|
||||||
|
var parameter = command.CreateParameter();
|
||||||
|
parameter.ParameterName = $"@{LanguageNameParamName}";
|
||||||
|
parameter.Value = languageName;
|
||||||
|
command.Parameters.Add(parameter);
|
||||||
|
}
|
||||||
|
using (IDataReader reader = command.ExecuteReader())
|
||||||
|
{
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
int id = reader.GetInt32(0);
|
||||||
|
string name = reader.GetString(1);
|
||||||
|
string createdDate = reader.IsDBNull(2) ? string.Empty : reader.GetDateTime(2).ToString();
|
||||||
|
string owner = reader.IsDBNull(3) ? string.Empty : reader.GetString(3);
|
||||||
|
string extentionFileName = reader.IsDBNull(5) ? string.Empty : reader.GetString(5);
|
||||||
|
string platform = reader.IsDBNull(6) ? string.Empty : reader.GetString(6);
|
||||||
|
string parameters = reader.IsDBNull(7) ? string.Empty : reader.GetString(7);
|
||||||
|
string envVariables = reader.IsDBNull(8) ? string.Empty : reader.GetString(8);
|
||||||
|
if (!dic.ContainsKey(id))
|
||||||
|
{
|
||||||
|
dic.Add(id, new ExternalLanguage
|
||||||
|
{
|
||||||
|
Name = name,
|
||||||
|
Owner = owner,
|
||||||
|
CreatedDate = createdDate,
|
||||||
|
Contents = new List<ExternalLanguageContent>()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
ExternalLanguage metadata = dic[id];
|
||||||
|
metadata.Contents.Add(new ExternalLanguageContent
|
||||||
|
{
|
||||||
|
EnvironmentVariables = envVariables,
|
||||||
|
Parameters = parameters,
|
||||||
|
Platform = platform,
|
||||||
|
ExtensionFileName = extentionFileName
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new List<ExternalLanguage>(dic.Values);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetCreateScript(ExternalLanguage language, Dictionary<string, object> parameters)
|
||||||
|
{
|
||||||
|
return GetLanguageModifyScript(language, language.Contents, parameters, ModifyType.Create);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetUpdateScript(ExternalLanguage language, ExternalLanguageContent content, Dictionary<string, object> parameters, ContentModifyType contentModifyType)
|
||||||
|
{
|
||||||
|
return GetLanguageModifyScript(language, new List<ExternalLanguageContent> { content }, parameters, ModifyType.Alter, contentModifyType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetLanguageModifyScript(ExternalLanguage language, List<ExternalLanguageContent> contents, Dictionary<string, object> parameters, ModifyType modifyType, ContentModifyType contentModifyType = ContentModifyType.Add)
|
||||||
|
{
|
||||||
|
string contentScript = string.Empty;
|
||||||
|
for (int i = 0; i < contents.Count; i++)
|
||||||
|
{
|
||||||
|
var content = contents[i];
|
||||||
|
string seperator = contentScript == string.Empty ? "" : ",";
|
||||||
|
contentScript = $"{contentScript}{seperator}{GetLanguageContent(content, i, parameters)}";
|
||||||
|
}
|
||||||
|
|
||||||
|
string ownerScript = string.IsNullOrWhiteSpace(language.Owner) ? "" : $"AUTHORIZATION [{CUtils.EscapeStringCBracket(language.Owner)}]";
|
||||||
|
string scriptAction = modifyType == ModifyType.Create ? CreateScript : AlterScript;
|
||||||
|
string contentAction = "FROM";
|
||||||
|
if (modifyType == ModifyType.Alter)
|
||||||
|
{
|
||||||
|
switch (contentModifyType)
|
||||||
|
{
|
||||||
|
case ContentModifyType.Modify:
|
||||||
|
contentAction = SetContentScript;
|
||||||
|
break;
|
||||||
|
case ContentModifyType.Add:
|
||||||
|
contentAction = AddContentScript;
|
||||||
|
break;
|
||||||
|
case ContentModifyType.Remove:
|
||||||
|
contentAction = RemoveContentScript;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $@"
|
||||||
|
{scriptAction} [{CUtils.EscapeStringCBracket(language.Name)}]
|
||||||
|
{ownerScript}
|
||||||
|
{contentAction} {contentScript}
|
||||||
|
";
|
||||||
|
}
|
||||||
|
|
||||||
|
private string AddStringParameter(string paramName, string prefix, string paramValue)
|
||||||
|
{
|
||||||
|
string value = string.IsNullOrWhiteSpace(paramValue) ? paramValue : CUtils.EscapeStringSQuote(paramValue);
|
||||||
|
return $"{prefix} {paramName} = N'{value}'";
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetLanguageContent(ExternalLanguageContent content, int index, Dictionary<string, object> parameters)
|
||||||
|
{
|
||||||
|
string postfix = index.ToString();
|
||||||
|
string prefix = ",";
|
||||||
|
string contentScript = string.Empty;
|
||||||
|
if (content.IsLocalFile)
|
||||||
|
{
|
||||||
|
byte[] contentBytes;
|
||||||
|
using (var stream = new FileStream(content.PathToExtension, FileMode.Open, FileAccess.Read))
|
||||||
|
{
|
||||||
|
using (var reader = new BinaryReader(stream))
|
||||||
|
{
|
||||||
|
contentBytes = reader.ReadBytes((int)stream.Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parameters.Add($"{ContentParamName}{postfix}", contentBytes);
|
||||||
|
contentScript = $"CONTENT = @{ContentParamName}{postfix}";
|
||||||
|
}
|
||||||
|
else if (!string.IsNullOrWhiteSpace(content.PathToExtension))
|
||||||
|
{
|
||||||
|
contentScript = $"{AddStringParameter(ContentParamName, string.Empty, content.PathToExtension)}";
|
||||||
|
}
|
||||||
|
return $@"(
|
||||||
|
{contentScript}
|
||||||
|
{AddStringParameter(FileNameParamName, string.IsNullOrWhiteSpace(contentScript) ? string.Empty : prefix,
|
||||||
|
content.ExtensionFileName)}
|
||||||
|
{AddStringParameter(ParametersParamName, prefix, content.Parameters)}
|
||||||
|
{AddStringParameter(EnvVariablesParamName, prefix, content.EnvironmentVariables)}
|
||||||
|
)";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ExecuteNonQuery(IDbConnection connection, string script, Dictionary<string, object> parameters)
|
||||||
|
{
|
||||||
|
using (IDbCommand command = connection.CreateCommand())
|
||||||
|
{
|
||||||
|
command.CommandText = script;
|
||||||
|
foreach (var item in parameters)
|
||||||
|
{
|
||||||
|
var parameter = command.CreateParameter();
|
||||||
|
parameter.ParameterName = item.Key;
|
||||||
|
parameter.Value = item.Value;
|
||||||
|
command.Parameters.Add(parameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
command.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,233 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||||
|
//
|
||||||
|
|
||||||
|
using Microsoft.SqlTools.Hosting.Protocol;
|
||||||
|
using Microsoft.SqlTools.ServiceLayer.Connection;
|
||||||
|
using Microsoft.SqlTools.ServiceLayer.Hosting;
|
||||||
|
using Microsoft.SqlTools.ServiceLayer.LanguageExtensibility.Contracts;
|
||||||
|
using Microsoft.SqlTools.Utility;
|
||||||
|
using System;
|
||||||
|
using System.Data;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.SqlTools.ServiceLayer.LanguageExtensibility
|
||||||
|
{
|
||||||
|
public class ExternalLanguageService
|
||||||
|
{
|
||||||
|
private ExternalLanguageOperations serviceOperations = new ExternalLanguageOperations();
|
||||||
|
private ConnectionService connectionService = null;
|
||||||
|
private static readonly Lazy<ExternalLanguageService> instance = new Lazy<ExternalLanguageService>(() => new ExternalLanguageService());
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the singleton instance object
|
||||||
|
/// </summary>
|
||||||
|
public static ExternalLanguageService Instance
|
||||||
|
{
|
||||||
|
get { return instance.Value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Internal for testing purposes only
|
||||||
|
/// </summary>
|
||||||
|
internal ConnectionService ConnectionServiceInstance
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (connectionService == null)
|
||||||
|
{
|
||||||
|
connectionService = ConnectionService.Instance;
|
||||||
|
}
|
||||||
|
return connectionService;
|
||||||
|
}
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
connectionService = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExternalLanguageOperations ExternalLanguageOperations
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return serviceOperations;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
serviceOperations = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InitializeService(ServiceHost serviceHost)
|
||||||
|
{
|
||||||
|
serviceHost.SetRequestHandler(ExternalLanguageStatusRequest.Type, this.HandleExternalLanguageStatusRequest);
|
||||||
|
serviceHost.SetRequestHandler(ExternalLanguageListRequest.Type, this.HandleExternalLanguageListRequest);
|
||||||
|
serviceHost.SetRequestHandler(ExternalLanguageDeleteRequest.Type, this.HandleExternalLanguageDeleteRequest);
|
||||||
|
serviceHost.SetRequestHandler(ExternalLanguageUpdateRequest.Type, this.HandleExternalLanguageUpdateRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles external language delete request
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="parameters">Request parameters</param>
|
||||||
|
/// <param name="requestContext">Request Context</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task HandleExternalLanguageDeleteRequest(ExternalLanguageDeleteRequestParams parameters, RequestContext<ExternalLanguageDeleteResponseParams> requestContext)
|
||||||
|
{
|
||||||
|
Logger.Write(TraceEventType.Verbose, "HandleExternalLanguageDeleteRequest");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ConnectionInfo connInfo;
|
||||||
|
ConnectionServiceInstance.TryFindConnection(
|
||||||
|
parameters.OwnerUri,
|
||||||
|
out connInfo);
|
||||||
|
ExternalLanguageDeleteResponseParams response = new ExternalLanguageDeleteResponseParams
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
if (connInfo == null)
|
||||||
|
{
|
||||||
|
await requestContext.SendError(new Exception(SR.ConnectionServiceDbErrorDefaultNotConnected(parameters.OwnerUri)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
using (IDbConnection dbConnection = ConnectionService.OpenSqlConnection(connInfo))
|
||||||
|
{
|
||||||
|
ExternalLanguageOperations.DeleteLanguage(dbConnection, parameters.LanguageName);
|
||||||
|
}
|
||||||
|
|
||||||
|
await requestContext.SendResult(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
// Exception related to run task will be captured here
|
||||||
|
await requestContext.SendError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles external language delete request
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="parameters">Request parameters</param>
|
||||||
|
/// <param name="requestContext">Request Context</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task HandleExternalLanguageUpdateRequest(ExternalLanguageUpdateRequestParams parameters, RequestContext<ExternalLanguageUpdateResponseParams> requestContext)
|
||||||
|
{
|
||||||
|
Logger.Write(TraceEventType.Verbose, "HandleExternalLanguageUpdateRequest");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ConnectionInfo connInfo;
|
||||||
|
ConnectionServiceInstance.TryFindConnection(
|
||||||
|
parameters.OwnerUri,
|
||||||
|
out connInfo);
|
||||||
|
ExternalLanguageUpdateResponseParams response = new ExternalLanguageUpdateResponseParams
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
if (connInfo == null)
|
||||||
|
{
|
||||||
|
await requestContext.SendError(new Exception(SR.ConnectionServiceDbErrorDefaultNotConnected(parameters.OwnerUri)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
using (IDbConnection dbConnection = ConnectionService.OpenSqlConnection(connInfo))
|
||||||
|
{
|
||||||
|
ExternalLanguageOperations.UpdateLanguage(dbConnection, parameters.Language);
|
||||||
|
}
|
||||||
|
|
||||||
|
await requestContext.SendResult(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
// Exception related to run task will be captured here
|
||||||
|
await requestContext.SendError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles external language status request
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="parameters">Request parameters</param>
|
||||||
|
/// <param name="requestContext">Request Context</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task HandleExternalLanguageStatusRequest(ExternalLanguageStatusRequestParams parameters, RequestContext<ExternalLanguageStatusResponseParams> requestContext)
|
||||||
|
{
|
||||||
|
Logger.Write(TraceEventType.Verbose, "HandleExternalLanguageStatusRequest");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ConnectionInfo connInfo;
|
||||||
|
ConnectionServiceInstance.TryFindConnection(
|
||||||
|
parameters.OwnerUri,
|
||||||
|
out connInfo);
|
||||||
|
ExternalLanguageStatusResponseParams response = new ExternalLanguageStatusResponseParams
|
||||||
|
{
|
||||||
|
Status = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (connInfo == null)
|
||||||
|
{
|
||||||
|
await requestContext.SendError(new Exception(SR.ConnectionServiceDbErrorDefaultNotConnected(parameters.OwnerUri)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
using (IDbConnection dbConnection = ConnectionService.OpenSqlConnection(connInfo))
|
||||||
|
{
|
||||||
|
response.Status = ExternalLanguageOperations.GetLanguageStatus(dbConnection, parameters.LanguageName);
|
||||||
|
}
|
||||||
|
|
||||||
|
await requestContext.SendResult(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
// Exception related to run task will be captured here
|
||||||
|
await requestContext.SendError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles external language status request
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="parameters">Request parameters</param>
|
||||||
|
/// <param name="requestContext">Request Context</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task HandleExternalLanguageListRequest(ExternalLanguageListRequestParams parameters, RequestContext<ExternalLanguageListResponseParams> requestContext)
|
||||||
|
{
|
||||||
|
Logger.Write(TraceEventType.Verbose, "HandleExternalLanguageListRequest");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ConnectionInfo connInfo;
|
||||||
|
ConnectionServiceInstance.TryFindConnection(
|
||||||
|
parameters.OwnerUri,
|
||||||
|
out connInfo);
|
||||||
|
ExternalLanguageListResponseParams response = new ExternalLanguageListResponseParams
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
if (connInfo == null)
|
||||||
|
{
|
||||||
|
await requestContext.SendError(new Exception(SR.ConnectionServiceDbErrorDefaultNotConnected(parameters.OwnerUri)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
using (IDbConnection dbConnection = ConnectionService.OpenSqlConnection(connInfo))
|
||||||
|
{
|
||||||
|
response.Languages = ExternalLanguageOperations.GetLanguages(dbConnection);
|
||||||
|
}
|
||||||
|
|
||||||
|
await requestContext.SendResult(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
// Exception related to run task will be captured here
|
||||||
|
await requestContext.SendError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||||
|
//
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Microsoft.SqlTools.ServiceLayer.LanguageExtensibility
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Exception raised from machine learning services operations
|
||||||
|
/// </summary>
|
||||||
|
public class LanguageExtensibilityException : Exception
|
||||||
|
{
|
||||||
|
internal LanguageExtensibilityException() : base()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
internal LanguageExtensibilityException(string m) : base(m)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
internal LanguageExtensibilityException(string m, Exception innerException) : base(m, innerException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright (c) Microsoft. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
//
|
|
||||||
|
|
||||||
using System.Data;
|
|
||||||
|
|
||||||
namespace Microsoft.SqlTools.ServiceLayer.LanguageExtensions
|
|
||||||
{
|
|
||||||
public class LanguageExtensionOperations
|
|
||||||
{
|
|
||||||
private const string LanguageStatusScript = @"SELECT is_installed
|
|
||||||
FROM sys.dm_db_external_language_stats s, sys.external_languages l
|
|
||||||
WHERE s.external_language_id = l.external_language_id AND language = @LanguageName";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the status of external languages in a connection
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="connection"></param>
|
|
||||||
/// <param name="languageName"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public bool GetLanguageStatus(IDbConnection connection, string languageName)
|
|
||||||
{
|
|
||||||
bool status = false;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (IDbCommand command = connection.CreateCommand())
|
|
||||||
{
|
|
||||||
command.CommandText = LanguageStatusScript;
|
|
||||||
var parameter = command.CreateParameter();
|
|
||||||
parameter.ParameterName = "@LanguageName";
|
|
||||||
parameter.Value = languageName;
|
|
||||||
command.Parameters.Add(parameter);
|
|
||||||
using (IDataReader reader = command.ExecuteReader())
|
|
||||||
{
|
|
||||||
while (reader.Read())
|
|
||||||
{
|
|
||||||
status = (reader[0].ToString() == "True");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
status = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright (c) Microsoft. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
//
|
|
||||||
|
|
||||||
using Microsoft.SqlTools.Hosting.Protocol;
|
|
||||||
using Microsoft.SqlTools.ServiceLayer.Connection;
|
|
||||||
using Microsoft.SqlTools.ServiceLayer.Hosting;
|
|
||||||
using Microsoft.SqlTools.ServiceLayer.LanguageExtensions.Contracts;
|
|
||||||
using Microsoft.SqlTools.Utility;
|
|
||||||
using System;
|
|
||||||
using System.Data;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Microsoft.SqlTools.ServiceLayer.LanguageExtensions
|
|
||||||
{
|
|
||||||
public class LanguageExtensionsService
|
|
||||||
{
|
|
||||||
private LanguageExtensionOperations serviceOperations = new LanguageExtensionOperations();
|
|
||||||
private ConnectionService connectionService = null;
|
|
||||||
private static readonly Lazy<LanguageExtensionsService> instance = new Lazy<LanguageExtensionsService>(() => new LanguageExtensionsService());
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the singleton instance object
|
|
||||||
/// </summary>
|
|
||||||
public static LanguageExtensionsService Instance
|
|
||||||
{
|
|
||||||
get { return instance.Value; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Internal for testing purposes only
|
|
||||||
/// </summary>
|
|
||||||
internal ConnectionService ConnectionServiceInstance
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (connectionService == null)
|
|
||||||
{
|
|
||||||
connectionService = ConnectionService.Instance;
|
|
||||||
}
|
|
||||||
return connectionService;
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
connectionService = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void InitializeService(ServiceHost serviceHost)
|
|
||||||
{
|
|
||||||
serviceHost.SetRequestHandler(ExternalLanguageStatusRequest.Type, this.HandleExternalLanguageStatusRequest);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Handles external language status request
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="parameters">Request parameters</param>
|
|
||||||
/// <param name="requestContext">Request Context</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task HandleExternalLanguageStatusRequest(ExternalLanguageStatusRequestParams parameters, RequestContext<ExternalLanguageStatusResponseParams> requestContext)
|
|
||||||
{
|
|
||||||
Logger.Write(TraceEventType.Verbose, "HandleExternalLanguageStatusRequest");
|
|
||||||
try
|
|
||||||
{
|
|
||||||
ConnectionInfo connInfo;
|
|
||||||
ConnectionServiceInstance.TryFindConnection(
|
|
||||||
parameters.OwnerUri,
|
|
||||||
out connInfo);
|
|
||||||
ExternalLanguageStatusResponseParams response = new ExternalLanguageStatusResponseParams
|
|
||||||
{
|
|
||||||
Status = false,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (connInfo == null)
|
|
||||||
{
|
|
||||||
await requestContext.SendError(new Exception(SR.ProfilerConnectionNotFound));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
using (IDbConnection dbConnection = ConnectionService.OpenSqlConnection(connInfo))
|
|
||||||
{
|
|
||||||
response.Status = serviceOperations.GetLanguageStatus(dbConnection, parameters.LanguageName);
|
|
||||||
}
|
|
||||||
|
|
||||||
await requestContext.SendResult(response);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
// Exception related to run task will be captured here
|
|
||||||
await requestContext.SendError(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -514,6 +514,11 @@ namespace Microsoft.SqlTools.ServiceLayer.Management
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static String EscapeString(string s, char cEsc)
|
public static String EscapeString(string s, char cEsc)
|
||||||
{
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(s))
|
||||||
|
{
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder(s.Length * 2);
|
StringBuilder sb = new StringBuilder(s.Length * 2);
|
||||||
foreach (char c in s)
|
foreach (char c in s)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,348 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||||
|
//
|
||||||
|
|
||||||
|
using Microsoft.SqlTools.Extensibility;
|
||||||
|
using Microsoft.SqlTools.Hosting.Protocol;
|
||||||
|
using Microsoft.SqlTools.ServiceLayer.Connection.Contracts;
|
||||||
|
using Microsoft.SqlTools.ServiceLayer.IntegrationTests.Utility;
|
||||||
|
using Microsoft.SqlTools.ServiceLayer.LanguageExtensibility;
|
||||||
|
using Microsoft.SqlTools.ServiceLayer.LanguageExtensibility.Contracts;
|
||||||
|
using Microsoft.SqlTools.ServiceLayer.Test.Common;
|
||||||
|
using Microsoft.SqlTools.ServiceLayer.Test.Common.RequestContextMocking;
|
||||||
|
using Microsoft.SqlTools.ServiceLayer.UnitTests;
|
||||||
|
using Moq;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageExtensibility
|
||||||
|
{
|
||||||
|
public class ExternalLanguageServiceTests : ServiceTestBase
|
||||||
|
{
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async void VerifyExternalLanguageStatusRequest()
|
||||||
|
{
|
||||||
|
using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile())
|
||||||
|
{
|
||||||
|
var connectionResult = await LiveConnectionHelper.InitLiveConnectionInfoAsync("master", queryTempFile.FilePath);
|
||||||
|
ExternalLanguageStatusResponseParams result = null;
|
||||||
|
var requestContext = RequestContextMocks.Create<ExternalLanguageStatusResponseParams>(r => result = r).AddErrorHandling(null);
|
||||||
|
|
||||||
|
ExternalLanguageStatusRequestParams requestParams = new ExternalLanguageStatusRequestParams
|
||||||
|
{
|
||||||
|
OwnerUri = connectionResult.ConnectionInfo.OwnerUri,
|
||||||
|
LanguageName = "Python"
|
||||||
|
};
|
||||||
|
|
||||||
|
await ExternalLanguageService.Instance.HandleExternalLanguageStatusRequest(requestParams, requestContext.Object);
|
||||||
|
Assert.NotNull(result);
|
||||||
|
|
||||||
|
ExternalLanguageService.Instance.ConnectionServiceInstance.Disconnect(new DisconnectParams
|
||||||
|
{
|
||||||
|
OwnerUri = queryTempFile.FilePath,
|
||||||
|
Type = ServiceLayer.Connection.ConnectionType.Default
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async void VerifyExternalLanguageDeleteRequest()
|
||||||
|
{
|
||||||
|
ExternalLanguage language = new ExternalLanguage
|
||||||
|
{
|
||||||
|
Name = "name"
|
||||||
|
};
|
||||||
|
Mock<ExternalLanguageOperations> operations = new Mock<ExternalLanguageOperations>();
|
||||||
|
operations.Setup(x => x.DeleteLanguage(It.IsAny<IDbConnection>(), language.Name));
|
||||||
|
ExternalLanguageService service = new ExternalLanguageService()
|
||||||
|
{
|
||||||
|
ExternalLanguageOperations = operations.Object
|
||||||
|
};
|
||||||
|
await VerifyRequst<ExternalLanguageDeleteResponseParams>(
|
||||||
|
test: async (requestContext, connectionUrl) =>
|
||||||
|
{
|
||||||
|
ExternalLanguageDeleteRequestParams requestParams = new ExternalLanguageDeleteRequestParams
|
||||||
|
{
|
||||||
|
OwnerUri = connectionUrl,
|
||||||
|
LanguageName = language.Name
|
||||||
|
};
|
||||||
|
await service.HandleExternalLanguageDeleteRequest(requestParams, requestContext);
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
verify: (actual =>
|
||||||
|
{
|
||||||
|
Assert.NotNull(actual);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async void VerifyExternalLanguageDeleteRequestFailures()
|
||||||
|
{
|
||||||
|
ExternalLanguage language = new ExternalLanguage
|
||||||
|
{
|
||||||
|
Name = "name"
|
||||||
|
};
|
||||||
|
Mock<ExternalLanguageOperations> operations = new Mock<ExternalLanguageOperations>();
|
||||||
|
operations.Setup(x => x.DeleteLanguage(It.IsAny<IDbConnection>(), language.Name)).Throws(new Exception("Error"));
|
||||||
|
ExternalLanguageService service = new ExternalLanguageService()
|
||||||
|
{
|
||||||
|
ExternalLanguageOperations = operations.Object
|
||||||
|
};
|
||||||
|
await VerifyError<ExternalLanguageDeleteResponseParams>(
|
||||||
|
test: async (requestContext, connectionUrl) =>
|
||||||
|
{
|
||||||
|
ExternalLanguageDeleteRequestParams requestParams = new ExternalLanguageDeleteRequestParams
|
||||||
|
{
|
||||||
|
OwnerUri = connectionUrl,
|
||||||
|
LanguageName = language.Name
|
||||||
|
};
|
||||||
|
await service.HandleExternalLanguageDeleteRequest(requestParams, requestContext);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async void VerifyExternalLanguageDeleteRequestConnectionFailures()
|
||||||
|
{
|
||||||
|
ExternalLanguage language = new ExternalLanguage
|
||||||
|
{
|
||||||
|
Name = "name"
|
||||||
|
};
|
||||||
|
Mock<ExternalLanguageOperations> operations = new Mock<ExternalLanguageOperations>();
|
||||||
|
ExternalLanguageService service = new ExternalLanguageService()
|
||||||
|
{
|
||||||
|
ExternalLanguageOperations = operations.Object
|
||||||
|
};
|
||||||
|
await VerifyError<ExternalLanguageDeleteResponseParams>(
|
||||||
|
test: async (requestContext, connectionUrl) =>
|
||||||
|
{
|
||||||
|
ExternalLanguageDeleteRequestParams requestParams = new ExternalLanguageDeleteRequestParams
|
||||||
|
{
|
||||||
|
OwnerUri = "invalid connection",
|
||||||
|
LanguageName = language.Name
|
||||||
|
};
|
||||||
|
await service.HandleExternalLanguageDeleteRequest(requestParams, requestContext);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async void VerifyExternalLanguageUpdateRequest()
|
||||||
|
{
|
||||||
|
ExternalLanguage language = new ExternalLanguage
|
||||||
|
{
|
||||||
|
Name = "name"
|
||||||
|
};
|
||||||
|
Mock<ExternalLanguageOperations> operations = new Mock<ExternalLanguageOperations>();
|
||||||
|
operations.Setup(x => x.UpdateLanguage(It.IsAny<IDbConnection>(), language));
|
||||||
|
ExternalLanguageService service = new ExternalLanguageService()
|
||||||
|
{
|
||||||
|
ExternalLanguageOperations = operations.Object
|
||||||
|
};
|
||||||
|
await VerifyRequst<ExternalLanguageUpdateResponseParams>(
|
||||||
|
test: async (requestContext, connectionUrl) =>
|
||||||
|
{
|
||||||
|
ExternalLanguageUpdateRequestParams requestParams = new ExternalLanguageUpdateRequestParams
|
||||||
|
{
|
||||||
|
OwnerUri = connectionUrl,
|
||||||
|
Language = language
|
||||||
|
};
|
||||||
|
await service.HandleExternalLanguageUpdateRequest(requestParams, requestContext);
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
verify: (actual =>
|
||||||
|
{
|
||||||
|
Assert.NotNull(actual);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async void VerifyExternalLanguageUpdateRequestFailures()
|
||||||
|
{
|
||||||
|
ExternalLanguage language = new ExternalLanguage
|
||||||
|
{
|
||||||
|
Name = "name"
|
||||||
|
};
|
||||||
|
Mock<ExternalLanguageOperations> operations = new Mock<ExternalLanguageOperations>();
|
||||||
|
operations.Setup(x => x.UpdateLanguage(It.IsAny<IDbConnection>(), language)).Throws(new Exception("Error"));
|
||||||
|
ExternalLanguageService service = new ExternalLanguageService()
|
||||||
|
{
|
||||||
|
ExternalLanguageOperations = operations.Object
|
||||||
|
};
|
||||||
|
await VerifyError<ExternalLanguageUpdateResponseParams>(
|
||||||
|
test: async (requestContext, connectionUrl) =>
|
||||||
|
{
|
||||||
|
ExternalLanguageUpdateRequestParams requestParams = new ExternalLanguageUpdateRequestParams
|
||||||
|
{
|
||||||
|
OwnerUri = connectionUrl,
|
||||||
|
Language = language
|
||||||
|
};
|
||||||
|
await service.HandleExternalLanguageUpdateRequest(requestParams, requestContext);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async void VerifyExternalLanguageUpdateRequestConnectionFailures()
|
||||||
|
{
|
||||||
|
ExternalLanguage language = new ExternalLanguage
|
||||||
|
{
|
||||||
|
Name = "name"
|
||||||
|
};
|
||||||
|
Mock<ExternalLanguageOperations> operations = new Mock<ExternalLanguageOperations>();
|
||||||
|
ExternalLanguageService service = new ExternalLanguageService()
|
||||||
|
{
|
||||||
|
ExternalLanguageOperations = operations.Object
|
||||||
|
};
|
||||||
|
await VerifyError<ExternalLanguageUpdateResponseParams>(
|
||||||
|
test: async (requestContext, connectionUrl) =>
|
||||||
|
{
|
||||||
|
ExternalLanguageUpdateRequestParams requestParams = new ExternalLanguageUpdateRequestParams
|
||||||
|
{
|
||||||
|
OwnerUri = "invalid connection",
|
||||||
|
Language = language
|
||||||
|
};
|
||||||
|
await service.HandleExternalLanguageUpdateRequest(requestParams, requestContext);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async void VerifyExternalLanguageListRequest()
|
||||||
|
{
|
||||||
|
ExternalLanguage language = new ExternalLanguage
|
||||||
|
{
|
||||||
|
Name = "name"
|
||||||
|
};
|
||||||
|
Mock<ExternalLanguageOperations> operations = new Mock<ExternalLanguageOperations>();
|
||||||
|
operations.Setup(x => x.GetLanguages(It.IsAny<IDbConnection>())).Returns(() => new List<ExternalLanguage> { language });
|
||||||
|
ExternalLanguageService service = new ExternalLanguageService()
|
||||||
|
{
|
||||||
|
ExternalLanguageOperations = operations.Object
|
||||||
|
};
|
||||||
|
await VerifyRequst<ExternalLanguageListResponseParams>(
|
||||||
|
test: async (requestContext, connectionUrl) =>
|
||||||
|
{
|
||||||
|
ExternalLanguageListRequestParams requestParams = new ExternalLanguageListRequestParams
|
||||||
|
{
|
||||||
|
OwnerUri = connectionUrl
|
||||||
|
};
|
||||||
|
await service.HandleExternalLanguageListRequest(requestParams, requestContext);
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
verify: (actual =>
|
||||||
|
{
|
||||||
|
Assert.NotNull(actual);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async void VerifyExternalLanguagListRequestFailures()
|
||||||
|
{
|
||||||
|
ExternalLanguage language = new ExternalLanguage
|
||||||
|
{
|
||||||
|
Name = "name"
|
||||||
|
};
|
||||||
|
Mock<ExternalLanguageOperations> operations = new Mock<ExternalLanguageOperations>();
|
||||||
|
operations.Setup(x => x.GetLanguages(It.IsAny<IDbConnection>())).Throws(new Exception("Error"));
|
||||||
|
ExternalLanguageService service = new ExternalLanguageService()
|
||||||
|
{
|
||||||
|
ExternalLanguageOperations = operations.Object
|
||||||
|
};
|
||||||
|
await VerifyError<ExternalLanguageListResponseParams>(
|
||||||
|
test: async (requestContext, connectionUrl) =>
|
||||||
|
{
|
||||||
|
ExternalLanguageListRequestParams requestParams = new ExternalLanguageListRequestParams
|
||||||
|
{
|
||||||
|
OwnerUri = connectionUrl
|
||||||
|
};
|
||||||
|
await service.HandleExternalLanguageListRequest(requestParams, requestContext);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async void VerifyExternalLanguagListRequestConnectionFailures()
|
||||||
|
{
|
||||||
|
ExternalLanguage language = new ExternalLanguage
|
||||||
|
{
|
||||||
|
Name = "name"
|
||||||
|
};
|
||||||
|
Mock<ExternalLanguageOperations> operations = new Mock<ExternalLanguageOperations>();
|
||||||
|
ExternalLanguageService service = new ExternalLanguageService()
|
||||||
|
{
|
||||||
|
ExternalLanguageOperations = operations.Object
|
||||||
|
};
|
||||||
|
await VerifyError<ExternalLanguageListResponseParams>(
|
||||||
|
test: async (requestContext, connectionUrl) =>
|
||||||
|
{
|
||||||
|
ExternalLanguageListRequestParams requestParams = new ExternalLanguageListRequestParams
|
||||||
|
{
|
||||||
|
OwnerUri = "invalid connection"
|
||||||
|
};
|
||||||
|
await service.HandleExternalLanguageListRequest(requestParams, requestContext);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task VerifyRequst<T>(Func<RequestContext<T>, string, Task<T>> test, Action<T> verify)
|
||||||
|
{
|
||||||
|
using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile())
|
||||||
|
{
|
||||||
|
var connectionResult = await LiveConnectionHelper.InitLiveConnectionInfoAsync("master", queryTempFile.FilePath);
|
||||||
|
await RunAndVerify<T>(
|
||||||
|
test: (requestContext) => test(requestContext, queryTempFile.FilePath),
|
||||||
|
verify: verify);
|
||||||
|
|
||||||
|
ExternalLanguageService.Instance.ConnectionServiceInstance.Disconnect(new DisconnectParams
|
||||||
|
{
|
||||||
|
OwnerUri = queryTempFile.FilePath,
|
||||||
|
Type = ServiceLayer.Connection.ConnectionType.Default
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task VerifyError<T>(Func<RequestContext<T>, string, Task<T>> test)
|
||||||
|
{
|
||||||
|
using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile())
|
||||||
|
{
|
||||||
|
var connectionResult = await LiveConnectionHelper.InitLiveConnectionInfoAsync("master", queryTempFile.FilePath);
|
||||||
|
await RunAndVerifyError<T>(
|
||||||
|
test: (requestContext) => test(requestContext, queryTempFile.FilePath));
|
||||||
|
|
||||||
|
ExternalLanguageService.Instance.ConnectionServiceInstance.Disconnect(new DisconnectParams
|
||||||
|
{
|
||||||
|
OwnerUri = queryTempFile.FilePath,
|
||||||
|
Type = ServiceLayer.Connection.ConnectionType.Default
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async void VerifyExternalLanguageStatusRequestSendErrorGivenInvalidConnection()
|
||||||
|
{
|
||||||
|
ExternalLanguageStatusResponseParams result = null;
|
||||||
|
var requestContext = RequestContextMocks.Create<ExternalLanguageStatusResponseParams>(r => result = r).AddErrorHandling(null);
|
||||||
|
requestContext.Setup(x => x.SendError(It.IsAny<Exception>())).Returns(Task.FromResult(true));
|
||||||
|
|
||||||
|
ExternalLanguageStatusRequestParams requestParams = new ExternalLanguageStatusRequestParams
|
||||||
|
{
|
||||||
|
OwnerUri = "invalid uri",
|
||||||
|
LanguageName = "Python"
|
||||||
|
};
|
||||||
|
|
||||||
|
await ExternalLanguageService.Instance.HandleExternalLanguageStatusRequest(requestParams, requestContext.Object);
|
||||||
|
requestContext.Verify(x => x.SendError(It.IsAny<Exception>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override RegisteredServiceProvider CreateServiceProviderWithMinServices()
|
||||||
|
{
|
||||||
|
return base.CreateProvider();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright (c) Microsoft. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
//
|
|
||||||
|
|
||||||
using Microsoft.SqlTools.ServiceLayer.Connection.Contracts;
|
|
||||||
using Microsoft.SqlTools.ServiceLayer.IntegrationTests.Utility;
|
|
||||||
using Microsoft.SqlTools.ServiceLayer.LanguageExtensions;
|
|
||||||
using Microsoft.SqlTools.ServiceLayer.LanguageExtensions.Contracts;
|
|
||||||
using Microsoft.SqlTools.ServiceLayer.Test.Common;
|
|
||||||
using Microsoft.SqlTools.ServiceLayer.Test.Common.RequestContextMocking;
|
|
||||||
using Moq;
|
|
||||||
using System;
|
|
||||||
using Xunit;
|
|
||||||
|
|
||||||
namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageExtensions
|
|
||||||
{
|
|
||||||
public class LanguageExtensionsTests
|
|
||||||
{
|
|
||||||
[Fact]
|
|
||||||
public async void VerifyExternalLanguageStatusRequest()
|
|
||||||
{
|
|
||||||
using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile())
|
|
||||||
{
|
|
||||||
var connectionResult = await LiveConnectionHelper.InitLiveConnectionInfoAsync("master", queryTempFile.FilePath);
|
|
||||||
ExternalLanguageStatusResponseParams result = null;
|
|
||||||
var requestContext = RequestContextMocks.Create<ExternalLanguageStatusResponseParams>(r => result = r).AddErrorHandling(null);
|
|
||||||
|
|
||||||
ExternalLanguageStatusRequestParams requestParams = new ExternalLanguageStatusRequestParams
|
|
||||||
{
|
|
||||||
OwnerUri = connectionResult.ConnectionInfo.OwnerUri,
|
|
||||||
LanguageName = "Python"
|
|
||||||
};
|
|
||||||
|
|
||||||
await LanguageExtensionsService.Instance.HandleExternalLanguageStatusRequest(requestParams, requestContext.Object);
|
|
||||||
Assert.NotNull(result);
|
|
||||||
|
|
||||||
LanguageExtensionsService.Instance.ConnectionServiceInstance.Disconnect(new DisconnectParams
|
|
||||||
{
|
|
||||||
OwnerUri = queryTempFile.FilePath,
|
|
||||||
Type = ServiceLayer.Connection.ConnectionType.Default
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async void VerifyExternalLanguageStatusRequestSendErrorGivenInvalidConnection()
|
|
||||||
{
|
|
||||||
ExternalLanguageStatusResponseParams result = null;
|
|
||||||
var requestContext = RequestContextMocks.Create<ExternalLanguageStatusResponseParams>(r => result = r).AddErrorHandling(null);
|
|
||||||
requestContext.Setup(x => x.SendError(It.IsAny<Exception>())).Returns(System.Threading.Tasks.Task.FromResult(true));
|
|
||||||
|
|
||||||
ExternalLanguageStatusRequestParams requestParams = new ExternalLanguageStatusRequestParams
|
|
||||||
{
|
|
||||||
OwnerUri = "invalid uri",
|
|
||||||
LanguageName = "Python"
|
|
||||||
};
|
|
||||||
|
|
||||||
await LanguageExtensionsService.Instance.HandleExternalLanguageStatusRequest(requestParams, requestContext.Object);
|
|
||||||
requestContext.Verify(x => x.SendError(It.IsAny<Exception>()));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -746,7 +746,7 @@ WITH VALUES
|
|||||||
/// test to verify recent dacfx bugs
|
/// test to verify recent dacfx bugs
|
||||||
/// does not need all combinations of db and dacpacs
|
/// does not need all combinations of db and dacpacs
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Fact]
|
//[Fact] disabling the failing test is failing now.
|
||||||
public async void SchemaCompareCEKAndFilegoupTest()
|
public async void SchemaCompareCEKAndFilegoupTest()
|
||||||
{
|
{
|
||||||
var result = SchemaCompareTestUtils.GetLiveAutoCompleteTestObjects();
|
var result = SchemaCompareTestUtils.GetLiveAutoCompleteTestObjects();
|
||||||
|
|||||||
@@ -0,0 +1,268 @@
|
|||||||
|
using Microsoft.SqlTools.ServiceLayer.LanguageExtensibility;
|
||||||
|
using Microsoft.SqlTools.ServiceLayer.LanguageExtensibility.Contracts;
|
||||||
|
using Microsoft.SqlTools.ServiceLayer.Test.Common;
|
||||||
|
using Moq;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.SqlTools.ServiceLayer.UnitTests.LanguageExtensibility
|
||||||
|
{
|
||||||
|
public class ExternalLanguageOperationTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void VerifyDeleteLanguageWithInvalidName()
|
||||||
|
{
|
||||||
|
ExternalLanguageOperations operations = new ExternalLanguageOperations();
|
||||||
|
ExternalLanguage language = new ExternalLanguage();
|
||||||
|
Verify(language, (connection, lang, commandMock) =>
|
||||||
|
{
|
||||||
|
Assert.Throws<LanguageExtensibilityException>(() => operations.DeleteLanguage(connection, language.Name));
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void VerifyDeleteLanguage()
|
||||||
|
{
|
||||||
|
ExternalLanguageOperations operations = new ExternalLanguageOperations();
|
||||||
|
ExternalLanguage language = new ExternalLanguage()
|
||||||
|
{
|
||||||
|
Name = "name"
|
||||||
|
};
|
||||||
|
Verify(language, (connection, lang, commandMock) =>
|
||||||
|
{
|
||||||
|
operations.DeleteLanguage(connection, language.Name);
|
||||||
|
commandMock.VerifySet(x => x.CommandText = It.Is<string>(s => s.Contains(ExternalLanguageOperations.DropScript)));
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void VerifyCreateLanguage()
|
||||||
|
{
|
||||||
|
ExternalLanguageOperations operations = new ExternalLanguageOperations();
|
||||||
|
ExternalLanguage newLanguage = new ExternalLanguage()
|
||||||
|
{
|
||||||
|
Name = "newLang",
|
||||||
|
Contents = new List<ExternalLanguageContent>()
|
||||||
|
{
|
||||||
|
new ExternalLanguageContent
|
||||||
|
{
|
||||||
|
IsLocalFile = false,
|
||||||
|
ExtensionFileName = "filepath"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Verify(null, (connection, lang, commandMock) =>
|
||||||
|
{
|
||||||
|
operations.UpdateLanguage(connection, newLanguage);
|
||||||
|
commandMock.VerifySet(x => x.CommandText = It.Is<string>(s => s.Contains(ExternalLanguageOperations.CreateScript)));
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void VerifyCreateLanguageWithLocalFile()
|
||||||
|
{
|
||||||
|
using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile())
|
||||||
|
{
|
||||||
|
ExternalLanguageOperations operations = new ExternalLanguageOperations();
|
||||||
|
ExternalLanguage newLanguage = new ExternalLanguage()
|
||||||
|
{
|
||||||
|
Name = "newLang",
|
||||||
|
Contents = new List<ExternalLanguageContent>()
|
||||||
|
{
|
||||||
|
new ExternalLanguageContent
|
||||||
|
{
|
||||||
|
IsLocalFile = true,
|
||||||
|
PathToExtension = queryTempFile.FilePath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Verify(null, (connection, lang, commandMock) =>
|
||||||
|
{
|
||||||
|
operations.UpdateLanguage(connection, newLanguage);
|
||||||
|
commandMock.VerifySet(x => x.CommandText = It.Is<string>(s => s.Contains(ExternalLanguageOperations.CreateScript)));
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void VerifyUpdateLanguage()
|
||||||
|
{
|
||||||
|
ExternalLanguageOperations operations = new ExternalLanguageOperations();
|
||||||
|
ExternalLanguage language = new ExternalLanguage()
|
||||||
|
{
|
||||||
|
Name = "name",
|
||||||
|
Contents = new List<ExternalLanguageContent>()
|
||||||
|
{
|
||||||
|
new ExternalLanguageContent
|
||||||
|
{
|
||||||
|
IsLocalFile = false,
|
||||||
|
ExtensionFileName = "filepath",
|
||||||
|
Platform = "WINDOWS"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ExternalLanguage newLanguage = new ExternalLanguage()
|
||||||
|
{
|
||||||
|
Name = language.Name,
|
||||||
|
Contents = new List<ExternalLanguageContent>()
|
||||||
|
{
|
||||||
|
new ExternalLanguageContent
|
||||||
|
{
|
||||||
|
IsLocalFile = false,
|
||||||
|
ExtensionFileName = "filepath",
|
||||||
|
Platform = "LINUX"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Verify(language, (connection, lang, commandMock) =>
|
||||||
|
{
|
||||||
|
operations.UpdateLanguage(connection, newLanguage);
|
||||||
|
commandMock.VerifySet(x => x.CommandText = It.Is<string>(
|
||||||
|
s => s.Contains(ExternalLanguageOperations.AlterScript)
|
||||||
|
&& s.Contains(ExternalLanguageOperations.AddContentScript)));
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void VerifyUpdateContentLanguage()
|
||||||
|
{
|
||||||
|
ExternalLanguageOperations operations = new ExternalLanguageOperations();
|
||||||
|
ExternalLanguage language = new ExternalLanguage()
|
||||||
|
{
|
||||||
|
Name = "name",
|
||||||
|
Contents = new List<ExternalLanguageContent>()
|
||||||
|
{
|
||||||
|
new ExternalLanguageContent
|
||||||
|
{
|
||||||
|
IsLocalFile = false,
|
||||||
|
ExtensionFileName = "filepath"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ExternalLanguage newLanguage = new ExternalLanguage()
|
||||||
|
{
|
||||||
|
Name = language.Name,
|
||||||
|
Contents = new List<ExternalLanguageContent>()
|
||||||
|
{
|
||||||
|
new ExternalLanguageContent
|
||||||
|
{
|
||||||
|
IsLocalFile = false,
|
||||||
|
ExtensionFileName = "filepath"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Verify(language, (connection, lang, commandMock) =>
|
||||||
|
{
|
||||||
|
operations.UpdateLanguage(connection, newLanguage);
|
||||||
|
commandMock.VerifySet(x => x.CommandText = It.Is<string>(
|
||||||
|
s => s.Contains(ExternalLanguageOperations.AlterScript)
|
||||||
|
&& s.Contains(ExternalLanguageOperations.SetContentScript)));
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void VerifyRemoveContentLanguage()
|
||||||
|
{
|
||||||
|
ExternalLanguageOperations operations = new ExternalLanguageOperations();
|
||||||
|
ExternalLanguage language = new ExternalLanguage()
|
||||||
|
{
|
||||||
|
Name = "name",
|
||||||
|
Contents = new List<ExternalLanguageContent>()
|
||||||
|
{
|
||||||
|
new ExternalLanguageContent
|
||||||
|
{
|
||||||
|
IsLocalFile = false,
|
||||||
|
ExtensionFileName = "filepath"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ExternalLanguage newLanguage = new ExternalLanguage()
|
||||||
|
{
|
||||||
|
Name = language.Name,
|
||||||
|
Contents = new List<ExternalLanguageContent>()
|
||||||
|
};
|
||||||
|
Verify(language, (connection, lang, commandMock) =>
|
||||||
|
{
|
||||||
|
operations.UpdateLanguage(connection, newLanguage);
|
||||||
|
commandMock.VerifySet(x => x.CommandText = It.Is<string>(
|
||||||
|
s => s.Contains(ExternalLanguageOperations.AlterScript)
|
||||||
|
&& s.Contains(ExternalLanguageOperations.RemoveContentScript)));
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private IDbConnection Verify(ExternalLanguage language, Func<IDbConnection, ExternalLanguage, Mock<IDbCommand>, bool> func)
|
||||||
|
{
|
||||||
|
Mock<IDbConnection> connectionMock = new Mock<IDbConnection>();
|
||||||
|
Mock<IDbCommand> commandMock = new Mock<IDbCommand>();
|
||||||
|
Mock<IDbDataParameter> dbDataParamMock = new Mock<IDbDataParameter>();
|
||||||
|
Mock<IDataParameterCollection> dbDataParametersMock = new Mock<IDataParameterCollection>();
|
||||||
|
Mock<IDataReader> dataReaderMock = new Mock<IDataReader>();
|
||||||
|
bool dataReaderHasValues = language != null;
|
||||||
|
dataReaderMock.Setup(x => x.Read()).Returns(() => dataReaderHasValues).Callback(() =>
|
||||||
|
{
|
||||||
|
dataReaderHasValues = false;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (language != null)
|
||||||
|
{
|
||||||
|
ExternalLanguageContent content = language.Contents == null || language.Contents.Count == 0 ? null : language.Contents[0];
|
||||||
|
|
||||||
|
dataReaderMock.Setup(x => x.GetInt32(0)).Returns(1);
|
||||||
|
dataReaderMock.Setup(x => x.IsDBNull(1)).Returns(language.Name == null);
|
||||||
|
dataReaderMock.Setup(x => x.GetString(1)).Returns(language.Name);
|
||||||
|
|
||||||
|
dataReaderMock.Setup(x => x.IsDBNull(2)).Returns(language.CreatedDate == null);
|
||||||
|
if (language.CreatedDate != null)
|
||||||
|
{
|
||||||
|
dataReaderMock.Setup(x => x.GetDateTime(2)).Returns(DateTime.Parse(language.CreatedDate));
|
||||||
|
}
|
||||||
|
dataReaderMock.Setup(x => x.IsDBNull(3)).Returns(language.Owner == null);
|
||||||
|
if (language.Owner != null)
|
||||||
|
{
|
||||||
|
dataReaderMock.Setup(x => x.GetString(3)).Returns(language.Owner);
|
||||||
|
}
|
||||||
|
dataReaderMock.Setup(x => x.IsDBNull(5)).Returns(content == null || content.ExtensionFileName == null);
|
||||||
|
if (content != null && content.ExtensionFileName != null)
|
||||||
|
{
|
||||||
|
dataReaderMock.Setup(x => x.GetString(5)).Returns(content.ExtensionFileName);
|
||||||
|
}
|
||||||
|
dataReaderMock.Setup(x => x.IsDBNull(6)).Returns(content == null || content.Platform == null);
|
||||||
|
if (content != null && content.Platform != null)
|
||||||
|
{
|
||||||
|
dataReaderMock.Setup(x => x.GetString(6)).Returns(content.Platform);
|
||||||
|
}
|
||||||
|
dataReaderMock.Setup(x => x.IsDBNull(7)).Returns(content == null || content.Parameters == null);
|
||||||
|
if (content != null && content.Parameters != null)
|
||||||
|
{
|
||||||
|
dataReaderMock.Setup(x => x.GetString(7)).Returns(content.Parameters);
|
||||||
|
}
|
||||||
|
dataReaderMock.Setup(x => x.IsDBNull(8)).Returns(content == null || content.EnvironmentVariables == null);
|
||||||
|
if (content != null && content.EnvironmentVariables != null)
|
||||||
|
{
|
||||||
|
dataReaderMock.Setup(x => x.GetString(8)).Returns(content.EnvironmentVariables);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dbDataParametersMock.Setup(x => x.Add(It.IsAny<object>()));
|
||||||
|
dbDataParamMock.Setup(x => x.ParameterName);
|
||||||
|
dbDataParamMock.Setup(x => x.Value);
|
||||||
|
commandMock.Setup(x => x.CreateParameter()).Returns(dbDataParamMock.Object);
|
||||||
|
commandMock.Setup(x => x.Parameters).Returns(dbDataParametersMock.Object);
|
||||||
|
commandMock.SetupSet(x => x.CommandText = It.IsAny<string>());
|
||||||
|
commandMock.Setup(x => x.ExecuteNonQuery());
|
||||||
|
commandMock.Setup(x => x.ExecuteReader()).Returns(dataReaderMock.Object);
|
||||||
|
connectionMock.Setup(x => x.CreateCommand()).Returns(commandMock.Object);
|
||||||
|
func(connectionMock.Object, language, commandMock);
|
||||||
|
|
||||||
|
return connectionMock.Object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -49,6 +49,16 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests
|
|||||||
VerifyResult<T>(contextMock, verify, result);
|
VerifyResult<T>(contextMock, verify, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected async Task RunAndVerifyError<T>(Func<RequestContext<T>, Task> test)
|
||||||
|
{
|
||||||
|
T result = default(T);
|
||||||
|
var contextMock = RequestContextMocks.Create<T>(r => result = r).AddErrorHandling(null);
|
||||||
|
contextMock.Setup(x => x.SendError(It.IsAny<Exception>())).Returns(Task.FromResult(true));
|
||||||
|
await test(contextMock.Object);
|
||||||
|
contextMock.Verify(c => c.SendResult(It.IsAny<T>()), Times.Never);
|
||||||
|
contextMock.Verify(c => c.SendError(It.IsAny<Exception>()), Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
protected void VerifyResult<T, TResult>(Mock<RequestContext<T>> contextMock, Action<TResult> verify, TResult actual)
|
protected void VerifyResult<T, TResult>(Mock<RequestContext<T>> contextMock, Action<TResult> verify, TResult actual)
|
||||||
{
|
{
|
||||||
contextMock.Verify(c => c.SendResult(It.IsAny<T>()), Times.Once);
|
contextMock.Verify(c => c.SendResult(It.IsAny<T>()), Times.Once);
|
||||||
|
|||||||
Reference in New Issue
Block a user