mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-02-16 10:58:30 -05:00
fixed db trigger, system types and oe tests (#331)
* fixed db trigger, system types and oe tests
This commit is contained in:
@@ -4,7 +4,9 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes
|
namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes
|
||||||
{
|
{
|
||||||
@@ -76,6 +78,22 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes
|
|||||||
filter = $"{filter} {orPrefix} @{Property} = {proeprtyValue}";
|
filter = $"{filter} {orPrefix} @{Property} = {proeprtyValue}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
filter = $"({filter})";
|
||||||
|
|
||||||
|
return filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ConcatProperties(IEnumerable<NodeFilter> filters)
|
||||||
|
{
|
||||||
|
string filter = "";
|
||||||
|
var list = filters.ToList();
|
||||||
|
for (int i = 0; i < list.Count; i++)
|
||||||
|
{
|
||||||
|
var value = list[i];
|
||||||
|
|
||||||
|
string orPrefix = i == 0 ? "" : "and";
|
||||||
|
filter = $"{filter} {orPrefix} {value.ToPropertyFilterString()}";
|
||||||
|
}
|
||||||
filter = $"[{filter}]";
|
filter = $"[{filter}]";
|
||||||
|
|
||||||
return filter;
|
return filter;
|
||||||
|
|||||||
@@ -1,353 +1,363 @@
|
|||||||
//
|
//
|
||||||
// Copyright (c) Microsoft. All rights reserved.
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
// 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 System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Composition;
|
using System.Composition;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.SqlTools.Extensibility;
|
using Microsoft.SqlTools.Extensibility;
|
||||||
using Microsoft.SqlTools.Hosting;
|
using Microsoft.SqlTools.Hosting;
|
||||||
using Microsoft.SqlTools.Hosting.Protocol;
|
using Microsoft.SqlTools.Hosting.Protocol;
|
||||||
using Microsoft.SqlTools.ServiceLayer.Connection;
|
using Microsoft.SqlTools.ServiceLayer.Connection;
|
||||||
using Microsoft.SqlTools.ServiceLayer.Connection.Contracts;
|
using Microsoft.SqlTools.ServiceLayer.Connection.Contracts;
|
||||||
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Contracts;
|
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Contracts;
|
||||||
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes;
|
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes;
|
||||||
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel;
|
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel;
|
||||||
using Microsoft.SqlTools.Utility;
|
using Microsoft.SqlTools.Utility;
|
||||||
|
|
||||||
namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer
|
namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A Service to support querying server and database information as an Object Explorer tree.
|
/// A Service to support querying server and database information as an Object Explorer tree.
|
||||||
/// The APIs used for this are modeled closely on the VSCode TreeExplorerNodeProvider API.
|
/// The APIs used for this are modeled closely on the VSCode TreeExplorerNodeProvider API.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Export(typeof(IHostedService))]
|
[Export(typeof(IHostedService))]
|
||||||
public class ObjectExplorerService : HostedService<ObjectExplorerService>, IComposableService
|
public class ObjectExplorerService : HostedService<ObjectExplorerService>, IComposableService
|
||||||
{
|
{
|
||||||
internal const string uriPrefix = "objectexplorer://";
|
internal const string uriPrefix = "objectexplorer://";
|
||||||
|
|
||||||
// Instance of the connection service, used to get the connection info for a given owner URI
|
// Instance of the connection service, used to get the connection info for a given owner URI
|
||||||
private ConnectionService connectionService;
|
private ConnectionService connectionService;
|
||||||
private IProtocolEndpoint serviceHost;
|
private IProtocolEndpoint serviceHost;
|
||||||
private Dictionary<string, ObjectExplorerSession> sessionMap;
|
private Dictionary<string, ObjectExplorerSession> sessionMap;
|
||||||
private readonly Lazy<Dictionary<string, HashSet<ChildFactory>>> applicableNodeChildFactories;
|
private readonly Lazy<Dictionary<string, HashSet<ChildFactory>>> applicableNodeChildFactories;
|
||||||
private IMultiServiceProvider serviceProvider;
|
private IMultiServiceProvider serviceProvider;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Singleton constructor
|
/// Singleton constructor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ObjectExplorerService()
|
public ObjectExplorerService()
|
||||||
{
|
{
|
||||||
sessionMap = new Dictionary<string, ObjectExplorerSession>();
|
sessionMap = new Dictionary<string, ObjectExplorerSession>();
|
||||||
applicableNodeChildFactories = new Lazy<Dictionary<string, HashSet<ChildFactory>>>(() => PopulateFactories());
|
applicableNodeChildFactories = new Lazy<Dictionary<string, HashSet<ChildFactory>>>(() => PopulateFactories());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Internal for testing only
|
/// Internal for testing only
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal ObjectExplorerService(ExtensionServiceProvider serviceProvider)
|
internal ObjectExplorerService(ExtensionServiceProvider serviceProvider)
|
||||||
: this()
|
: this()
|
||||||
{
|
{
|
||||||
SetServiceProvider(serviceProvider);
|
SetServiceProvider(serviceProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Dictionary<string, HashSet<ChildFactory>> ApplicableNodeChildFactories
|
private Dictionary<string, HashSet<ChildFactory>> ApplicableNodeChildFactories
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return applicableNodeChildFactories.Value;
|
return applicableNodeChildFactories.Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// As an <see cref="IComposableService"/>, this will be set whenever the service is initialized
|
/// As an <see cref="IComposableService"/>, this will be set whenever the service is initialized
|
||||||
/// via an <see cref="IMultiServiceProvider"/>
|
/// via an <see cref="IMultiServiceProvider"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="provider"></param>
|
/// <param name="provider"></param>
|
||||||
public override void SetServiceProvider(IMultiServiceProvider provider)
|
public override void SetServiceProvider(IMultiServiceProvider provider)
|
||||||
{
|
{
|
||||||
Validate.IsNotNull(nameof(provider), provider);
|
Validate.IsNotNull(nameof(provider), provider);
|
||||||
serviceProvider = provider;
|
serviceProvider = provider;
|
||||||
connectionService = provider.GetService<ConnectionService>();
|
connectionService = provider.GetService<ConnectionService>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes the service with the service host and registers request handlers.
|
/// Initializes the service with the service host and registers request handlers.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="serviceHost">The service host instance to register with</param>
|
/// <param name="serviceHost">The service host instance to register with</param>
|
||||||
public override void InitializeService(IProtocolEndpoint serviceHost)
|
public override void InitializeService(IProtocolEndpoint serviceHost)
|
||||||
{
|
{
|
||||||
Logger.Write(LogLevel.Verbose, "ObjectExplorer service initialized");
|
Logger.Write(LogLevel.Verbose, "ObjectExplorer service initialized");
|
||||||
this.serviceHost = serviceHost;
|
this.serviceHost = serviceHost;
|
||||||
// Register handlers for requests
|
// Register handlers for requests
|
||||||
serviceHost.SetRequestHandler(CreateSessionRequest.Type, HandleCreateSessionRequest);
|
serviceHost.SetRequestHandler(CreateSessionRequest.Type, HandleCreateSessionRequest);
|
||||||
serviceHost.SetRequestHandler(ExpandRequest.Type, HandleExpandRequest);
|
serviceHost.SetRequestHandler(ExpandRequest.Type, HandleExpandRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal async Task HandleCreateSessionRequest(ConnectionDetails connectionDetails, RequestContext<CreateSessionResponse> context)
|
public void CloseSession(string uri)
|
||||||
{
|
{
|
||||||
Logger.Write(LogLevel.Verbose, "HandleCreateSessionRequest");
|
ObjectExplorerSession session;
|
||||||
Func<Task<CreateSessionResponse>> doCreateSession = async () =>
|
if (sessionMap.TryGetValue(uri, out session))
|
||||||
{
|
{
|
||||||
Validate.IsNotNull(nameof(connectionDetails), connectionDetails);
|
// Establish a connection to the specified server/database
|
||||||
Validate.IsNotNull(nameof(context), context);
|
sessionMap.Remove(session.Uri);
|
||||||
|
}
|
||||||
string uri = GenerateUri(connectionDetails);
|
}
|
||||||
|
|
||||||
ObjectExplorerSession session;
|
internal async Task HandleCreateSessionRequest(ConnectionDetails connectionDetails, RequestContext<CreateSessionResponse> context)
|
||||||
if (!sessionMap.TryGetValue(uri, out session))
|
{
|
||||||
{
|
Logger.Write(LogLevel.Verbose, "HandleCreateSessionRequest");
|
||||||
// Establish a connection to the specified server/database
|
Func<Task<CreateSessionResponse>> doCreateSession = async () =>
|
||||||
session = await DoCreateSession(connectionDetails, uri);
|
{
|
||||||
}
|
Validate.IsNotNull(nameof(connectionDetails), connectionDetails);
|
||||||
|
Validate.IsNotNull(nameof(context), context);
|
||||||
CreateSessionResponse response;
|
|
||||||
if (session == null)
|
string uri = GenerateUri(connectionDetails);
|
||||||
{
|
|
||||||
response = new CreateSessionResponse() { Success = false };
|
ObjectExplorerSession session;
|
||||||
}
|
if (!sessionMap.TryGetValue(uri, out session))
|
||||||
else
|
{
|
||||||
{
|
// Establish a connection to the specified server/database
|
||||||
// Else we have a session available, response with existing session information
|
session = await DoCreateSession(connectionDetails, uri);
|
||||||
response = new CreateSessionResponse()
|
}
|
||||||
{
|
|
||||||
Success = true,
|
CreateSessionResponse response;
|
||||||
RootNode = session.Root.ToNodeInfo(),
|
if (session == null)
|
||||||
SessionId = session.Uri
|
{
|
||||||
};
|
response = new CreateSessionResponse() { Success = false };
|
||||||
}
|
}
|
||||||
return response;
|
else
|
||||||
};
|
{
|
||||||
|
// Else we have a session available, response with existing session information
|
||||||
await HandleRequestAsync(doCreateSession, context, "HandleCreateSessionRequest");
|
response = new CreateSessionResponse()
|
||||||
}
|
{
|
||||||
|
Success = true,
|
||||||
internal async Task<NodeInfo[]> ExpandNode(ObjectExplorerSession session, string nodePath)
|
RootNode = session.Root.ToNodeInfo(),
|
||||||
{
|
SessionId = session.Uri
|
||||||
return await Task.Factory.StartNew(() =>
|
};
|
||||||
{
|
}
|
||||||
NodeInfo[] nodes = null;
|
return response;
|
||||||
TreeNode node = session.Root.FindNodeByPath(nodePath);
|
};
|
||||||
if(node != null)
|
|
||||||
{
|
await HandleRequestAsync(doCreateSession, context, "HandleCreateSessionRequest");
|
||||||
nodes = node.Expand().Select(x => x.ToNodeInfo()).ToArray();
|
}
|
||||||
}
|
|
||||||
return nodes;
|
internal async Task<NodeInfo[]> ExpandNode(ObjectExplorerSession session, string nodePath)
|
||||||
});
|
{
|
||||||
}
|
return await Task.Factory.StartNew(() =>
|
||||||
|
{
|
||||||
/// <summary>
|
NodeInfo[] nodes = null;
|
||||||
/// Establishes a new session and stores its information
|
TreeNode node = session.Root.FindNodeByPath(nodePath);
|
||||||
/// </summary>
|
if(node != null)
|
||||||
/// <returns><see cref="ObjectExplorerSession"/> object if successful, null if unsuccessful</returns>
|
{
|
||||||
internal async Task<ObjectExplorerSession> DoCreateSession(ConnectionDetails connectionDetails, string uri)
|
nodes = node.Expand().Select(x => x.ToNodeInfo()).ToArray();
|
||||||
{
|
}
|
||||||
ObjectExplorerSession session;
|
return nodes;
|
||||||
|
});
|
||||||
ConnectParams connectParams = new ConnectParams() { OwnerUri = uri, Connection = connectionDetails };
|
}
|
||||||
|
|
||||||
ConnectionCompleteParams connectionResult = await Connect(connectParams);
|
/// <summary>
|
||||||
if (connectionResult == null)
|
/// Establishes a new session and stores its information
|
||||||
{
|
/// </summary>
|
||||||
return null;
|
/// <returns><see cref="ObjectExplorerSession"/> object if successful, null if unsuccessful</returns>
|
||||||
}
|
internal async Task<ObjectExplorerSession> DoCreateSession(ConnectionDetails connectionDetails, string uri)
|
||||||
|
{
|
||||||
session = ObjectExplorerSession.CreateSession(connectionResult, serviceProvider);
|
ObjectExplorerSession session;
|
||||||
sessionMap[uri] = session;
|
|
||||||
return session;
|
ConnectParams connectParams = new ConnectParams() { OwnerUri = uri, Connection = connectionDetails };
|
||||||
}
|
|
||||||
|
ConnectionCompleteParams connectionResult = await Connect(connectParams);
|
||||||
|
if (connectionResult == null)
|
||||||
private async Task<ConnectionCompleteParams> Connect(ConnectParams connectParams)
|
{
|
||||||
{
|
return null;
|
||||||
try
|
}
|
||||||
{
|
|
||||||
// open connection based on request details
|
session = ObjectExplorerSession.CreateSession(connectionResult, serviceProvider);
|
||||||
ConnectionCompleteParams result = await connectionService.Connect(connectParams);
|
sessionMap[uri] = session;
|
||||||
if(result != null && !string.IsNullOrEmpty(result.ConnectionId))
|
return session;
|
||||||
{
|
}
|
||||||
return result;
|
|
||||||
}
|
|
||||||
else
|
private async Task<ConnectionCompleteParams> Connect(ConnectParams connectParams)
|
||||||
{
|
{
|
||||||
await serviceHost.SendEvent(ConnectionCompleteNotification.Type, result);
|
try
|
||||||
return null;
|
{
|
||||||
}
|
// open connection based on request details
|
||||||
|
ConnectionCompleteParams result = await connectionService.Connect(connectParams);
|
||||||
}
|
if(result != null && !string.IsNullOrEmpty(result.ConnectionId))
|
||||||
catch (Exception ex)
|
{
|
||||||
{
|
return result;
|
||||||
// Send a connection failed error message in this case.
|
}
|
||||||
ConnectionCompleteParams result = new ConnectionCompleteParams()
|
else
|
||||||
{
|
{
|
||||||
Messages = ex.ToString()
|
await serviceHost.SendEvent(ConnectionCompleteNotification.Type, result);
|
||||||
};
|
return null;
|
||||||
await serviceHost.SendEvent(ConnectionCompleteNotification.Type, result);
|
}
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
catch (Exception ex)
|
||||||
|
{
|
||||||
internal async Task HandleExpandRequest(ExpandParams expandParams, RequestContext<ExpandResponse> context)
|
// Send a connection failed error message in this case.
|
||||||
{
|
ConnectionCompleteParams result = new ConnectionCompleteParams()
|
||||||
Logger.Write(LogLevel.Verbose, "HandleExpandRequest");
|
{
|
||||||
Func<Task<ExpandResponse>> expandNode = async () =>
|
Messages = ex.ToString()
|
||||||
{
|
};
|
||||||
Validate.IsNotNull(nameof(expandParams), expandParams);
|
await serviceHost.SendEvent(ConnectionCompleteNotification.Type, result);
|
||||||
Validate.IsNotNull(nameof(context), context);
|
return null;
|
||||||
|
}
|
||||||
string uri = expandParams.SessionId;
|
}
|
||||||
ObjectExplorerSession session = null;
|
|
||||||
NodeInfo[] nodes = null;
|
internal async Task HandleExpandRequest(ExpandParams expandParams, RequestContext<ExpandResponse> context)
|
||||||
if (sessionMap.ContainsKey(uri))
|
{
|
||||||
{
|
Logger.Write(LogLevel.Verbose, "HandleExpandRequest");
|
||||||
session = sessionMap[uri];
|
Func<Task<ExpandResponse>> expandNode = async () =>
|
||||||
}
|
{
|
||||||
else
|
Validate.IsNotNull(nameof(expandParams), expandParams);
|
||||||
{
|
Validate.IsNotNull(nameof(context), context);
|
||||||
//TODO: error
|
|
||||||
}
|
string uri = expandParams.SessionId;
|
||||||
|
ObjectExplorerSession session = null;
|
||||||
|
NodeInfo[] nodes = null;
|
||||||
if (session != null)
|
if (sessionMap.ContainsKey(uri))
|
||||||
{
|
{
|
||||||
// Establish a connection to the specified server/database
|
session = sessionMap[uri];
|
||||||
nodes = await ExpandNode(session, expandParams.NodePath);
|
}
|
||||||
}
|
else
|
||||||
|
{
|
||||||
ExpandResponse response;
|
//TODO: error
|
||||||
response = new ExpandResponse() { Nodes = nodes, SessionId = uri };
|
}
|
||||||
return response;
|
|
||||||
};
|
|
||||||
|
if (session != null)
|
||||||
await HandleRequestAsync(expandNode, context, "HandleExpandRequest");
|
{
|
||||||
}
|
// Establish a connection to the specified server/database
|
||||||
|
nodes = await ExpandNode(session, expandParams.NodePath);
|
||||||
private async Task HandleRequestAsync<T>(Func<Task<T>> handler, RequestContext<T> requestContext, string requestType)
|
}
|
||||||
{
|
|
||||||
Logger.Write(LogLevel.Verbose, requestType);
|
ExpandResponse response;
|
||||||
|
response = new ExpandResponse() { Nodes = nodes, SessionId = uri };
|
||||||
try
|
return response;
|
||||||
{
|
};
|
||||||
T result = await handler();
|
|
||||||
await requestContext.SendResult(result);
|
await HandleRequestAsync(expandNode, context, "HandleExpandRequest");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
|
||||||
{
|
private async Task HandleRequestAsync<T>(Func<Task<T>> handler, RequestContext<T> requestContext, string requestType)
|
||||||
await requestContext.SendError(ex.ToString());
|
{
|
||||||
}
|
Logger.Write(LogLevel.Verbose, requestType);
|
||||||
}
|
|
||||||
|
try
|
||||||
/// <summary>
|
{
|
||||||
/// Generates a URI for object explorer using a similar pattern to Mongo DB (which has URI-based database definition)
|
T result = await handler();
|
||||||
/// as this should ensure uniqueness
|
await requestContext.SendResult(result);
|
||||||
/// </summary>
|
}
|
||||||
/// <param name="details"></param>
|
catch (Exception ex)
|
||||||
/// <returns>string representing a URI</returns>
|
{
|
||||||
/// <remarks>Internal for testing purposes only</remarks>
|
await requestContext.SendError(ex.ToString());
|
||||||
internal static string GenerateUri(ConnectionDetails details)
|
}
|
||||||
{
|
}
|
||||||
Validate.IsNotNull("details", details);
|
|
||||||
string uri = string.Format(CultureInfo.InvariantCulture, "{0}{1}", uriPrefix, Uri.EscapeUriString(details.ServerName));
|
/// <summary>
|
||||||
uri = AppendIfExists(uri, "databaseName", details.DatabaseName);
|
/// Generates a URI for object explorer using a similar pattern to Mongo DB (which has URI-based database definition)
|
||||||
uri = AppendIfExists(uri, "user", details.UserName);
|
/// as this should ensure uniqueness
|
||||||
return uri;
|
/// </summary>
|
||||||
}
|
/// <param name="details"></param>
|
||||||
|
/// <returns>string representing a URI</returns>
|
||||||
private static string AppendIfExists(string uri, string propertyName, string propertyValue)
|
/// <remarks>Internal for testing purposes only</remarks>
|
||||||
{
|
internal static string GenerateUri(ConnectionDetails details)
|
||||||
if (!string.IsNullOrEmpty(propertyValue))
|
{
|
||||||
{
|
Validate.IsNotNull("details", details);
|
||||||
uri += string.Format(CultureInfo.InvariantCulture, ";{0}={1}", propertyName, Uri.EscapeUriString(propertyValue));
|
string uri = string.Format(CultureInfo.InvariantCulture, "{0}{1}", uriPrefix, Uri.EscapeUriString(details.ServerName));
|
||||||
}
|
uri = AppendIfExists(uri, "databaseName", details.DatabaseName);
|
||||||
return uri;
|
uri = AppendIfExists(uri, "user", details.UserName);
|
||||||
}
|
return uri;
|
||||||
|
}
|
||||||
public IEnumerable<ChildFactory> GetApplicableChildFactories(TreeNode item)
|
|
||||||
{
|
private static string AppendIfExists(string uri, string propertyName, string propertyValue)
|
||||||
if (ApplicableNodeChildFactories != null)
|
{
|
||||||
{
|
if (!string.IsNullOrEmpty(propertyValue))
|
||||||
HashSet<ChildFactory> applicableFactories;
|
{
|
||||||
if (ApplicableNodeChildFactories.TryGetValue(item.NodeTypeId.ToString(), out applicableFactories))
|
uri += string.Format(CultureInfo.InvariantCulture, ";{0}={1}", propertyName, Uri.EscapeUriString(propertyValue));
|
||||||
{
|
}
|
||||||
return applicableFactories;
|
return uri;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return null;
|
public IEnumerable<ChildFactory> GetApplicableChildFactories(TreeNode item)
|
||||||
}
|
{
|
||||||
|
if (ApplicableNodeChildFactories != null)
|
||||||
internal Dictionary<string, HashSet<ChildFactory>> PopulateFactories()
|
{
|
||||||
{
|
HashSet<ChildFactory> applicableFactories;
|
||||||
VerifyServicesInitialized();
|
if (ApplicableNodeChildFactories.TryGetValue(item.NodeTypeId.ToString(), out applicableFactories))
|
||||||
|
{
|
||||||
var childFactories = new Dictionary<string, HashSet<ChildFactory>>();
|
return applicableFactories;
|
||||||
// Create our list of all NodeType to ChildFactory objects so we can expand appropriately
|
}
|
||||||
foreach (var factory in serviceProvider.GetServices<ChildFactory>())
|
}
|
||||||
{
|
return null;
|
||||||
var parents = factory.ApplicableParents();
|
}
|
||||||
if (parents != null)
|
|
||||||
{
|
internal Dictionary<string, HashSet<ChildFactory>> PopulateFactories()
|
||||||
foreach (var parent in parents)
|
{
|
||||||
{
|
VerifyServicesInitialized();
|
||||||
AddToApplicableChildFactories(childFactories, factory, parent);
|
|
||||||
}
|
var childFactories = new Dictionary<string, HashSet<ChildFactory>>();
|
||||||
}
|
// Create our list of all NodeType to ChildFactory objects so we can expand appropriately
|
||||||
}
|
foreach (var factory in serviceProvider.GetServices<ChildFactory>())
|
||||||
return childFactories;
|
{
|
||||||
}
|
var parents = factory.ApplicableParents();
|
||||||
|
if (parents != null)
|
||||||
private void VerifyServicesInitialized()
|
{
|
||||||
{
|
foreach (var parent in parents)
|
||||||
if (serviceProvider == null)
|
{
|
||||||
{
|
AddToApplicableChildFactories(childFactories, factory, parent);
|
||||||
throw new InvalidOperationException(SqlTools.Hosting.SR.ServiceProviderNotSet);
|
}
|
||||||
}
|
}
|
||||||
if (connectionService == null)
|
}
|
||||||
{
|
return childFactories;
|
||||||
throw new InvalidOperationException(SqlTools.Hosting.SR.ServiceProviderNotSet);
|
}
|
||||||
}
|
|
||||||
}
|
private void VerifyServicesInitialized()
|
||||||
|
{
|
||||||
private static void AddToApplicableChildFactories(Dictionary<string, HashSet<ChildFactory>> childFactories, ChildFactory factory, string parent)
|
if (serviceProvider == null)
|
||||||
{
|
{
|
||||||
HashSet<ChildFactory> applicableFactories;
|
throw new InvalidOperationException(SqlTools.Hosting.SR.ServiceProviderNotSet);
|
||||||
if (!childFactories.TryGetValue(parent, out applicableFactories))
|
}
|
||||||
{
|
if (connectionService == null)
|
||||||
applicableFactories = new HashSet<ChildFactory>();
|
{
|
||||||
childFactories[parent] = applicableFactories;
|
throw new InvalidOperationException(SqlTools.Hosting.SR.ServiceProviderNotSet);
|
||||||
}
|
}
|
||||||
applicableFactories.Add(factory);
|
}
|
||||||
}
|
|
||||||
|
private static void AddToApplicableChildFactories(Dictionary<string, HashSet<ChildFactory>> childFactories, ChildFactory factory, string parent)
|
||||||
internal class ObjectExplorerSession
|
{
|
||||||
{
|
HashSet<ChildFactory> applicableFactories;
|
||||||
private ConnectionService connectionService;
|
if (!childFactories.TryGetValue(parent, out applicableFactories))
|
||||||
private IMultiServiceProvider serviceProvider;
|
{
|
||||||
|
applicableFactories = new HashSet<ChildFactory>();
|
||||||
// TODO decide whether a cache is needed to handle lookups in elements with a large # children
|
childFactories[parent] = applicableFactories;
|
||||||
//private const int Cachesize = 10000;
|
}
|
||||||
//private Cache<string, NodeMapping> cache;
|
applicableFactories.Add(factory);
|
||||||
|
}
|
||||||
public ObjectExplorerSession(string uri, TreeNode root, IMultiServiceProvider serviceProvider, ConnectionService connectionService)
|
|
||||||
{
|
internal class ObjectExplorerSession
|
||||||
Validate.IsNotNullOrEmptyString("uri", uri);
|
{
|
||||||
Validate.IsNotNull("root", root);
|
private ConnectionService connectionService;
|
||||||
Uri = uri;
|
private IMultiServiceProvider serviceProvider;
|
||||||
Root = root;
|
|
||||||
this.serviceProvider = serviceProvider;
|
// TODO decide whether a cache is needed to handle lookups in elements with a large # children
|
||||||
this.connectionService = connectionService;
|
//private const int Cachesize = 10000;
|
||||||
}
|
//private Cache<string, NodeMapping> cache;
|
||||||
|
|
||||||
public string Uri { get; private set; }
|
public ObjectExplorerSession(string uri, TreeNode root, IMultiServiceProvider serviceProvider, ConnectionService connectionService)
|
||||||
public TreeNode Root { get; private set; }
|
{
|
||||||
|
Validate.IsNotNullOrEmptyString("uri", uri);
|
||||||
public static ObjectExplorerSession CreateSession(ConnectionCompleteParams response, IMultiServiceProvider serviceProvider)
|
Validate.IsNotNull("root", root);
|
||||||
{
|
Uri = uri;
|
||||||
TreeNode rootNode = new ServerNode(response, serviceProvider);
|
Root = root;
|
||||||
var session = new ObjectExplorerSession(response.OwnerUri, rootNode, serviceProvider, serviceProvider.GetService<ConnectionService>());
|
this.serviceProvider = serviceProvider;
|
||||||
|
this.connectionService = connectionService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Uri { get; private set; }
|
||||||
|
public TreeNode Root { get; private set; }
|
||||||
|
|
||||||
|
public static ObjectExplorerSession CreateSession(ConnectionCompleteParams response, IMultiServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
TreeNode rootNode = new ServerNode(response, serviceProvider);
|
||||||
|
var session = new ObjectExplorerSession(response.OwnerUri, rootNode, serviceProvider, serviceProvider.GetService<ConnectionService>());
|
||||||
if (!ObjectExplorerUtils.IsSystemDatabaseConnection(response.ConnectionSummary.DatabaseName))
|
if (!ObjectExplorerUtils.IsSystemDatabaseConnection(response.ConnectionSummary.DatabaseName))
|
||||||
{
|
{
|
||||||
// Assuming the databases are in a folder under server node
|
// Assuming the databases are in a folder under server node
|
||||||
@@ -358,11 +368,11 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer
|
|||||||
var databaseNode = databases.FirstOrDefault(d => d.Label == response.ConnectionSummary.DatabaseName);
|
var databaseNode = databases.FirstOrDefault(d => d.Label == response.ConnectionSummary.DatabaseName);
|
||||||
databaseNode.Label = rootNode.Label;
|
databaseNode.Label = rootNode.Label;
|
||||||
session.Root = databaseNode;
|
session.Root = databaseNode;
|
||||||
}
|
}
|
||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
|
|||||||
|
|
||||||
public override IEnumerable<TreeNode> Expand(TreeNode parent)
|
public override IEnumerable<TreeNode> Expand(TreeNode parent)
|
||||||
{
|
{
|
||||||
//parent.BeginChildrenInit();
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
List<TreeNode> allChildren = new List<TreeNode>();
|
List<TreeNode> allChildren = new List<TreeNode>();
|
||||||
@@ -35,7 +34,6 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
//parent.EndChildrenInit();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,10 +60,15 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
|
|||||||
}
|
}
|
||||||
SmoQueryContext context = parent.GetContextAs<SmoQueryContext>();
|
SmoQueryContext context = parent.GetContextAs<SmoQueryContext>();
|
||||||
Validate.IsNotNull(nameof(context), context);
|
Validate.IsNotNull(nameof(context), context);
|
||||||
|
|
||||||
|
var validForFlag = ServerVersionHelper.GetValidForFlag(context.SqlServerType);
|
||||||
|
if (ShouldFilterNode(parent, validForFlag))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
IEnumerable<SmoQuerier> queriers = context.ServiceProvider.GetServices<SmoQuerier>(q => IsCompatibleQuerier(q));
|
IEnumerable<SmoQuerier> queriers = context.ServiceProvider.GetServices<SmoQuerier>(q => IsCompatibleQuerier(q));
|
||||||
var filters = this.Filters;
|
var filters = this.Filters;
|
||||||
var validForFlag = ServerVersionHelper.GetValidForFlag(context.SqlServerType);
|
|
||||||
|
|
||||||
foreach (var querier in queriers)
|
foreach (var querier in queriers)
|
||||||
{
|
{
|
||||||
string propertyFilter = GetProperyFilter(filters, querier.GetType(), validForFlag);
|
string propertyFilter = GetProperyFilter(filters, querier.GetType(), validForFlag);
|
||||||
@@ -77,7 +80,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
|
|||||||
Console.WriteLine("smoObject should not be null");
|
Console.WriteLine("smoObject should not be null");
|
||||||
}
|
}
|
||||||
TreeNode childNode = CreateChild(parent, smoObject);
|
TreeNode childNode = CreateChild(parent, smoObject);
|
||||||
if (childNode != null && !ShouldFilterNode(childNode, validForFlag))
|
if (childNode != null && PassesFinalFilters(childNode, smoObject) && !ShouldFilterNode(childNode, validForFlag))
|
||||||
{
|
{
|
||||||
allChildren.Add(childNode);
|
allChildren.Add(childNode);
|
||||||
}
|
}
|
||||||
@@ -102,15 +105,14 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
|
|||||||
|
|
||||||
private string GetProperyFilter(IEnumerable<NodeFilter> filters, Type querierType, ValidForFlag validForFlag)
|
private string GetProperyFilter(IEnumerable<NodeFilter> filters, Type querierType, ValidForFlag validForFlag)
|
||||||
{
|
{
|
||||||
string filter = "";
|
string filter = string.Empty;
|
||||||
if (filters != null)
|
if (filters != null)
|
||||||
{
|
{
|
||||||
var filterToApply = filters.FirstOrDefault(f => f.CanApplyFilter(querierType, validForFlag));
|
var filtersToApply = filters.Where(f => f.CanApplyFilter(querierType, validForFlag)).ToList();
|
||||||
filter = "";
|
filter = string.Empty;
|
||||||
|
if (filtersToApply.Any())
|
||||||
if (filterToApply != null)
|
|
||||||
{
|
{
|
||||||
filter = filterToApply.ToPropertyFilterString();
|
filter = NodeFilter.ConcatProperties(filtersToApply);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -923,7 +923,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
|
|||||||
[Export(typeof(SmoQuerier))]
|
[Export(typeof(SmoQuerier))]
|
||||||
internal partial class SqlDatabaseDdlTriggerQuerier: SmoQuerier
|
internal partial class SqlDatabaseDdlTriggerQuerier: SmoQuerier
|
||||||
{
|
{
|
||||||
Type[] supportedTypes = new Type[] { typeof(Trigger) };
|
Type[] supportedTypes = new Type[] { typeof(DatabaseDdlTrigger) };
|
||||||
|
|
||||||
public override Type[] SupportedObjectTypes { get { return supportedTypes; } }
|
public override Type[] SupportedObjectTypes { get { return supportedTypes; } }
|
||||||
|
|
||||||
@@ -937,7 +937,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
|
|||||||
HashSet<string> urns = null;
|
HashSet<string> urns = null;
|
||||||
if (hasFilter)
|
if (hasFilter)
|
||||||
{
|
{
|
||||||
string urn = $"{parentDatabase.Urn.ToString()}/Trigger" + filter;
|
string urn = $"{parentDatabase.Urn.ToString()}/DatabaseDdlTrigger" + filter;
|
||||||
Enumerator en = new Enumerator();
|
Enumerator en = new Enumerator();
|
||||||
Request request = new Request(new Urn(urn));
|
Request request = new Request(new Urn(urn));
|
||||||
ServerConnection serverConnection = new ServerConnection(context.Server.ConnectionContext.SqlConnectionObject);
|
ServerConnection serverConnection = new ServerConnection(context.Server.ConnectionContext.SqlConnectionObject);
|
||||||
@@ -948,11 +948,11 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
|
|||||||
{
|
{
|
||||||
if (hasFilter && urns != null)
|
if (hasFilter && urns != null)
|
||||||
{
|
{
|
||||||
return new SmoCollectionWrapper<Trigger>(retValue).Where(c => urns.Contains(c.Urn));
|
return new SmoCollectionWrapper<DatabaseDdlTrigger>(retValue).Where(c => urns.Contains(c.Urn));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return new SmoCollectionWrapper<Trigger>(retValue);
|
return new SmoCollectionWrapper<DatabaseDdlTrigger>(retValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1120,46 +1120,6 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Export(typeof(SmoQuerier))]
|
|
||||||
internal partial class SqlSystemDataTypeQuerier: SmoQuerier
|
|
||||||
{
|
|
||||||
Type[] supportedTypes = new Type[] { typeof(SystemDataType) };
|
|
||||||
|
|
||||||
public override Type[] SupportedObjectTypes { get { return supportedTypes; } }
|
|
||||||
|
|
||||||
public override IEnumerable<SqlSmoObject> Query(SmoQueryContext context, string filter)
|
|
||||||
{
|
|
||||||
Server parentServer = context.Parent as Server;
|
|
||||||
if (parentServer != null)
|
|
||||||
{
|
|
||||||
var retValue = parentServer.SystemDataTypes;
|
|
||||||
bool hasFilter = !string.IsNullOrEmpty(filter);
|
|
||||||
HashSet<string> urns = null;
|
|
||||||
if (hasFilter)
|
|
||||||
{
|
|
||||||
string urn = $"{parentServer.Urn.ToString()}/SystemDataType" + filter;
|
|
||||||
Enumerator en = new Enumerator();
|
|
||||||
Request request = new Request(new Urn(urn));
|
|
||||||
ServerConnection serverConnection = new ServerConnection(context.Server.ConnectionContext.SqlConnectionObject);
|
|
||||||
EnumResult result = en.Process(serverConnection, request);
|
|
||||||
urns = GetUrns(result);
|
|
||||||
}
|
|
||||||
if (retValue != null)
|
|
||||||
{
|
|
||||||
if (hasFilter && urns != null)
|
|
||||||
{
|
|
||||||
return new SmoCollectionWrapper<SystemDataType>(retValue).Where(c => urns.Contains(c.Urn));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return new SmoCollectionWrapper<SystemDataType>(retValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Enumerable.Empty<SqlSmoObject>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Export(typeof(SmoQuerier))]
|
[Export(typeof(SmoQuerier))]
|
||||||
internal partial class SqlUserDefinedDataTypeQuerier: SmoQuerier
|
internal partial class SqlUserDefinedDataTypeQuerier: SmoQuerier
|
||||||
{
|
{
|
||||||
@@ -2802,15 +2762,15 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
|
|||||||
|
|
||||||
public override IEnumerable<SqlSmoObject> Query(SmoQueryContext context, string filter)
|
public override IEnumerable<SqlSmoObject> Query(SmoQueryContext context, string filter)
|
||||||
{
|
{
|
||||||
Server parentServer = context.Parent as Server;
|
Database parentDatabase = context.Parent as Database;
|
||||||
if (parentServer != null)
|
if (parentDatabase != null)
|
||||||
{
|
{
|
||||||
var retValue = parentServer.SystemDataTypes;
|
var retValue = parentDatabase.Parent.SystemDataTypes;
|
||||||
bool hasFilter = !string.IsNullOrEmpty(filter);
|
bool hasFilter = !string.IsNullOrEmpty(filter);
|
||||||
HashSet<string> urns = null;
|
HashSet<string> urns = null;
|
||||||
if (hasFilter)
|
if (hasFilter)
|
||||||
{
|
{
|
||||||
string urn = $"{parentServer.Urn.ToString()}/SystemDataType" + filter;
|
string urn = $"{parentDatabase.Urn.ToString()}/SystemDataType" + filter;
|
||||||
Enumerator en = new Enumerator();
|
Enumerator en = new Enumerator();
|
||||||
Request request = new Request(new Urn(urn));
|
Request request = new Request(new Urn(urn));
|
||||||
ServerConnection serverConnection = new ServerConnection(context.Server.ConnectionContext.SqlConnectionObject);
|
ServerConnection serverConnection = new ServerConnection(context.Server.ConnectionContext.SqlConnectionObject);
|
||||||
|
|||||||
@@ -52,7 +52,9 @@
|
|||||||
<Node Name="SqlFullTextIndex" Parent="Table" Collection="False" />
|
<Node Name="SqlFullTextIndex" Parent="Table" Collection="False" />
|
||||||
<Node Name="SqlStatistic" Parent="TableViewBase"/>
|
<Node Name="SqlStatistic" Parent="TableViewBase"/>
|
||||||
|
|
||||||
<Node Name="SqlDatabaseDdlTrigger" Type="Trigger" Parent="Database"/>
|
<Node Name="SqlDatabaseDdlTrigger" Type="DatabaseDdlTrigger" Parent="Database">
|
||||||
|
<NavigationPath Parent="Database" Field="Triggers" />
|
||||||
|
</Node>
|
||||||
<Node Name="SqlAssembly" Type="SqlAssembly" Parent="Database" >
|
<Node Name="SqlAssembly" Type="SqlAssembly" Parent="Database" >
|
||||||
<NavigationPath Parent="Database" Field="Assemblies" />
|
<NavigationPath Parent="Database" Field="Assemblies" />
|
||||||
</Node>
|
</Node>
|
||||||
@@ -61,7 +63,6 @@
|
|||||||
<Node Name="SqlDefault" Parent="Database" />
|
<Node Name="SqlDefault" Parent="Database" />
|
||||||
<Node Name="SqlSequence" Parent="Database" />
|
<Node Name="SqlSequence" Parent="Database" />
|
||||||
|
|
||||||
<Node Name="SqlSystemDataType" Parent="Server" />
|
|
||||||
<Node Name="SqlUserDefinedDataType" Parent="Database" />
|
<Node Name="SqlUserDefinedDataType" Parent="Database" />
|
||||||
|
|
||||||
<Node Name="SqlUserDefinedTableType" Parent="Database" />
|
<Node Name="SqlUserDefinedTableType" Parent="Database" />
|
||||||
@@ -129,7 +130,9 @@
|
|||||||
|
|
||||||
<Node Name="SqlPartitionFunctionParameter" Parent="PartitionFunction" />
|
<Node Name="SqlPartitionFunctionParameter" Parent="PartitionFunction" />
|
||||||
|
|
||||||
<Node Name="SqlBuiltInType" Type="SystemDataType" Parent="Server"/>
|
<Node Name="SqlBuiltInType" Type="SystemDataType" Parent="Database">
|
||||||
|
<NavigationPath Parent="Database" Field="Parent.SystemDataTypes" />
|
||||||
|
</Node>
|
||||||
<!-- TODO Enable all types
|
<!-- TODO Enable all types
|
||||||
<Node Name="SqlRoute"/>
|
<Node Name="SqlRoute"/>
|
||||||
-->
|
-->
|
||||||
|
|||||||
@@ -216,6 +216,7 @@
|
|||||||
<Child Name="ScalarValuedFunctions"/>
|
<Child Name="ScalarValuedFunctions"/>
|
||||||
<Child Name="AggregateFunctions"/>
|
<Child Name="AggregateFunctions"/>
|
||||||
</Node>
|
</Node>
|
||||||
|
|
||||||
<Node Name="DatabaseTriggers" LocLabel="SR.SchemaHierarchy_DatabaseTriggers" BaseClass="ModelBased" NodeType="DatabaseTrigger" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlDatabaseDdlTrigger"/>
|
<Node Name="DatabaseTriggers" LocLabel="SR.SchemaHierarchy_DatabaseTriggers" BaseClass="ModelBased" NodeType="DatabaseTrigger" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlDatabaseDdlTrigger"/>
|
||||||
<Node Name="Assemblies" LocLabel="SR.SchemaHierarchy_Assemblies" BaseClass="ModelBased" Strategy="MultipleElementsOfType" NodeType="Assembly" ChildQuerierTypes="SqlAssembly" ValidFor="Sql2005|Sql2008|Sql2012|Sql2014|Sql2016|SqlvNext|AzureV12"/>
|
<Node Name="Assemblies" LocLabel="SR.SchemaHierarchy_Assemblies" BaseClass="ModelBased" Strategy="MultipleElementsOfType" NodeType="Assembly" ChildQuerierTypes="SqlAssembly" ValidFor="Sql2005|Sql2008|Sql2012|Sql2014|Sql2016|SqlvNext|AzureV12"/>
|
||||||
<Node Name="Types" LocLabel="SR.SchemaHierarchy_Types" BaseClass="ModelBased" >
|
<Node Name="Types" LocLabel="SR.SchemaHierarchy_Types" BaseClass="ModelBased" >
|
||||||
@@ -268,8 +269,8 @@
|
|||||||
<Node Name="SystemUnicodeCharacterStrings" LocLabel="SR.SchemaHierarchy_SystemUnicodeCharacterStrings" BaseClass="ModelBased" NodeType="SystemUnicodeCharacterString" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlBuiltInType"/>
|
<Node Name="SystemUnicodeCharacterStrings" LocLabel="SR.SchemaHierarchy_SystemUnicodeCharacterStrings" BaseClass="ModelBased" NodeType="SystemUnicodeCharacterString" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlBuiltInType"/>
|
||||||
<Node Name="SystemBinaryStrings" LocLabel="SR.SchemaHierarchy_SystemBinaryStrings" BaseClass="ModelBased" Strategy="MultipleElementsOfType" NodeType="SystemBinaryString" ChildQuerierTypes="SqlBuiltInType"/>
|
<Node Name="SystemBinaryStrings" LocLabel="SR.SchemaHierarchy_SystemBinaryStrings" BaseClass="ModelBased" Strategy="MultipleElementsOfType" NodeType="SystemBinaryString" ChildQuerierTypes="SqlBuiltInType"/>
|
||||||
<Node Name="SystemOtherDataTypes" LocLabel="SR.SchemaHierarchy_SystemOtherDataTypes" BaseClass="ModelBased" Strategy="MultipleElementsOfType" NodeType="SystemOtherDataType" ChildQuerierTypes="SqlBuiltInType"/>
|
<Node Name="SystemOtherDataTypes" LocLabel="SR.SchemaHierarchy_SystemOtherDataTypes" BaseClass="ModelBased" Strategy="MultipleElementsOfType" NodeType="SystemOtherDataType" ChildQuerierTypes="SqlBuiltInType"/>
|
||||||
<Node Name="SystemClrDataTypes" LocLabel="SR.SchemaHierarchy_SystemCLRDataTypes" BaseClass="ModelBased" Strategy="MultipleElementsOfType" NodeType="SystemClrDataType" ChildQuerierTypes="SqlUserDefinedType" ValidFor="Sql2005|Sql2008|Sql2012|Sql2014|Sql2016|SqlvNext|AzureV11|AzureV12"/>
|
<Node Name="SystemClrDataTypes" LocLabel="SR.SchemaHierarchy_SystemCLRDataTypes" BaseClass="ModelBased" Strategy="MultipleElementsOfType" NodeType="SystemClrDataType" ChildQuerierTypes="SqlBuiltInType" ValidFor="Sql2005|Sql2008|Sql2012|Sql2014|Sql2016|SqlvNext|AzureV11|AzureV12"/>
|
||||||
<Node Name="SystemSpatialDataTypes" LocLabel="SR.SchemaHierarchy_SystemSpatialDataTypes" BaseClass="ModelBased" Strategy="MultipleElementsOfType" NodeType="SystemSpatialDataType" ChildQuerierTypes="SqlUserDefinedType" ValidFor="Sql2008|Sql2012|Sql2014|Sql2016|SqlvNext|AzureV11|AzureV12"/>
|
<Node Name="SystemSpatialDataTypes" LocLabel="SR.SchemaHierarchy_SystemSpatialDataTypes" BaseClass="ModelBased" Strategy="MultipleElementsOfType" NodeType="SystemSpatialDataType" ChildQuerierTypes="SqlBuiltInType" ValidFor="Sql2008|Sql2012|Sql2014|Sql2016|SqlvNext|AzureV11|AzureV12"/>
|
||||||
|
|
||||||
<!-- Childs of ExternalResources -->
|
<!-- Childs of ExternalResources -->
|
||||||
<Node Name="ExternalDataSources" LocLabel="SR.SchemaHierarchy_ExternalDataSources" BaseClass="ModelBased" NodeType="ExternalDataSource" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlExternalDataSource" ValidFor="Sql2016|SqlvNext|AzureV12"/>
|
<Node Name="ExternalDataSources" LocLabel="SR.SchemaHierarchy_ExternalDataSources" BaseClass="ModelBased" NodeType="ExternalDataSource" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlExternalDataSource" ValidFor="Sql2016|SqlvNext|AzureV12"/>
|
||||||
|
|||||||
@@ -2393,7 +2393,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return new [] { typeof(SqlUserDefinedTypeQuerier), };
|
return new [] { typeof(SqlBuiltInTypeQuerier), };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2417,7 +2417,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return new [] { typeof(SqlUserDefinedTypeQuerier), };
|
return new [] { typeof(SqlBuiltInTypeQuerier), };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,9 +4,12 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.SqlTools.ServiceLayer.Connection;
|
using Microsoft.SqlTools.ServiceLayer.Connection;
|
||||||
using Microsoft.SqlTools.ServiceLayer.Connection.Contracts;
|
using Microsoft.SqlTools.ServiceLayer.Connection.Contracts;
|
||||||
@@ -14,6 +17,7 @@ using Microsoft.SqlTools.ServiceLayer.ObjectExplorer;
|
|||||||
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Contracts;
|
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Contracts;
|
||||||
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes;
|
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes;
|
||||||
using Microsoft.SqlTools.ServiceLayer.Test.Common;
|
using Microsoft.SqlTools.ServiceLayer.Test.Common;
|
||||||
|
using Microsoft.SqlTools.ServiceLayer.Test.Common.Baselined;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
using static Microsoft.SqlTools.ServiceLayer.ObjectExplorer.ObjectExplorerService;
|
using static Microsoft.SqlTools.ServiceLayer.ObjectExplorer.ObjectExplorerService;
|
||||||
|
|
||||||
@@ -33,8 +37,8 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectExplorer
|
|||||||
{
|
{
|
||||||
var session = await CreateSession(null, uri);
|
var session = await CreateSession(null, uri);
|
||||||
await ExpandServerNodeAndVerifyDatabaseHierachy(testDb.DatabaseName, session);
|
await ExpandServerNodeAndVerifyDatabaseHierachy(testDb.DatabaseName, session);
|
||||||
|
DisconnectConnection(uri);
|
||||||
}
|
}
|
||||||
CancelConnection(uri);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -47,9 +51,8 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectExplorer
|
|||||||
{
|
{
|
||||||
var session = await CreateSession("tempdb", uri);
|
var session = await CreateSession("tempdb", uri);
|
||||||
await ExpandServerNodeAndVerifyDatabaseHierachy(testDb.DatabaseName, session);
|
await ExpandServerNodeAndVerifyDatabaseHierachy(testDb.DatabaseName, session);
|
||||||
|
DisconnectConnection(uri);
|
||||||
}
|
}
|
||||||
CancelConnection(uri);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -62,15 +65,35 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectExplorer
|
|||||||
{
|
{
|
||||||
var session = await CreateSession(testDb.DatabaseName, uri);
|
var session = await CreateSession(testDb.DatabaseName, uri);
|
||||||
ExpandAndVerifyDatabaseNode(testDb.DatabaseName, session);
|
ExpandAndVerifyDatabaseNode(testDb.DatabaseName, session);
|
||||||
|
DisconnectConnection(uri);
|
||||||
}
|
}
|
||||||
CancelConnection(uri);
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async void VerifyAllSqlObjects()
|
||||||
|
{
|
||||||
|
var queryFileName = "AllSqlObjects.sql";
|
||||||
|
string uri = "AllSqlObjects";
|
||||||
|
string baselineFileName = "AllSqlObjects.txt";
|
||||||
|
string databaseName = null;
|
||||||
|
await TestServiceProvider.CalculateRunTime(() => VerifyObjectExplorerTest(databaseName, queryFileName, uri, baselineFileName), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
//[Fact]
|
||||||
|
//This takes take long to run so not a good test for CI builds
|
||||||
|
public async void VerifySystemObjects()
|
||||||
|
{
|
||||||
|
string queryFileName = null;
|
||||||
|
string uri = "SystemObjects";
|
||||||
|
string baselineFileName = null;
|
||||||
|
string databaseName = null;
|
||||||
|
await TestServiceProvider.CalculateRunTime(() => VerifyObjectExplorerTest(databaseName, queryFileName, uri, baselineFileName, true), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<ObjectExplorerSession> CreateSession(string databaseName, string uri)
|
private async Task<ObjectExplorerSession> CreateSession(string databaseName, string uri)
|
||||||
{
|
{
|
||||||
ConnectParams connectParams = TestServiceProvider.Instance.ConnectionProfileService.GetConnectionParameters(TestServerType.OnPrem, databaseName);
|
ConnectParams connectParams = TestServiceProvider.Instance.ConnectionProfileService.GetConnectionParameters(TestServerType.OnPrem, databaseName);
|
||||||
connectParams.Connection.Pooling = false;
|
//connectParams.Connection.Pooling = false;
|
||||||
ConnectionDetails details = connectParams.Connection;
|
ConnectionDetails details = connectParams.Connection;
|
||||||
|
|
||||||
var session = await _service.DoCreateSession(details, uri);
|
var session = await _service.DoCreateSession(details, uri);
|
||||||
@@ -136,23 +159,37 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectExplorer
|
|||||||
Assert.NotNull(tablesRoot);
|
Assert.NotNull(tablesRoot);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CancelConnection(string uri)
|
private void DisconnectConnection(string uri)
|
||||||
{
|
{
|
||||||
ConnectionService.Instance.CancelConnect(new CancelConnectParams
|
ConnectionService.Instance.Disconnect(new DisconnectParams
|
||||||
{
|
{
|
||||||
OwnerUri = uri,
|
OwnerUri = uri,
|
||||||
Type = ConnectionType.Default
|
Type = ConnectionType.Default
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ExpandTree(NodeInfo node, ObjectExplorerSession session)
|
private async Task ExpandTree(NodeInfo node, ObjectExplorerSession session, StringBuilder stringBuilder = null, bool verifySystemObjects = false)
|
||||||
{
|
{
|
||||||
if (node != null && !node.IsLeaf)
|
if (node != null && !node.IsLeaf)
|
||||||
{
|
{
|
||||||
var children = await _service.ExpandNode(session, node.NodePath);
|
var children = await _service.ExpandNode(session, node.NodePath);
|
||||||
foreach (var child in children)
|
foreach (var child in children)
|
||||||
{
|
{
|
||||||
await _service.ExpandNode(session, child.NodePath);
|
if (stringBuilder != null && child.NodeType != "Folder" && child.NodeType != "FileGroupFile")
|
||||||
|
{
|
||||||
|
stringBuilder.AppendLine($"NodeType: {child.NodeType} Label: {child.Label}");
|
||||||
|
}
|
||||||
|
if (!verifySystemObjects && (child.Label == SR.SchemaHierarchy_SystemStoredProcedures ||
|
||||||
|
child.Label == SR.SchemaHierarchy_SystemViews ||
|
||||||
|
child.Label == SR.SchemaHierarchy_SystemFunctions ||
|
||||||
|
child.Label == SR.SchemaHierarchy_SystemDataTypes))
|
||||||
|
{
|
||||||
|
// don't expand the system folders because then the test will take for ever
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await ExpandTree(child, session, stringBuilder, verifySystemObjects);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -160,7 +197,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectExplorer
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the children of a node with the given label
|
/// Returns the children of a node with the given label
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private async Task<NodeInfo[]> FindNodeByLabel(NodeInfo node, ObjectExplorerSession session, string nodeType, bool nodeFound = false)
|
private async Task<IList<NodeInfo>> FindNodeByLabel(NodeInfo node, ObjectExplorerSession session, string nodeType, bool nodeFound = false)
|
||||||
{
|
{
|
||||||
if (node != null && !node.IsLeaf)
|
if (node != null && !node.IsLeaf)
|
||||||
{
|
{
|
||||||
@@ -211,117 +248,25 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectExplorer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<bool> VerifyObjectExplorerTest(string databaseName, string queryFileName, string uri, string baselineFileName, bool verifySystemObjects = false)
|
||||||
[Fact]
|
|
||||||
public async void VerifyAdventureWorksDatabaseObjects()
|
|
||||||
{
|
{
|
||||||
var query = Scripts.AdventureWorksScript;
|
var query = string.IsNullOrEmpty(queryFileName) ? string.Empty : LoadScript(queryFileName);
|
||||||
string uri = "VerifyAdventureWorksDatabaseObjects";
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
string databaseName = null;
|
SqlTestDb testDb = SqlTestDb.CreateNew(TestServerType.OnPrem, false, databaseName, query, uri);
|
||||||
|
var session = await CreateSession(testDb.DatabaseName, uri);
|
||||||
|
await ExpandServerNodeAndVerifyDatabaseHierachy(testDb.DatabaseName, session, false);
|
||||||
|
await ExpandTree(session.Root.ToNodeInfo(), session, stringBuilder, verifySystemObjects);
|
||||||
|
|
||||||
using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile())
|
string baseline = string.IsNullOrEmpty(baselineFileName) ? string.Empty : LoadBaseLine(baselineFileName);
|
||||||
using (SqlTestDb testDb = SqlTestDb.CreateNew(TestServerType.OnPrem, true, databaseName, query, uri))
|
if (!string.IsNullOrEmpty(baseline))
|
||||||
{
|
{
|
||||||
var session = await CreateSession(testDb.DatabaseName, queryTempFile.FilePath);
|
string actual = stringBuilder.ToString();
|
||||||
var databaseNodeInfo = await ExpandServerNodeAndVerifyDatabaseHierachy(testDb.DatabaseName, session, false);
|
BaselinedTest.CompareActualWithBaseline(actual, baseline);
|
||||||
await ExpandTree(session.Root.ToNodeInfo(), session);
|
|
||||||
var tablesChildren = await FindNodeByLabel(databaseNodeInfo, session, SR.SchemaHierarchy_Tables);
|
|
||||||
|
|
||||||
var systemTables = await FindNodeByLabel(databaseNodeInfo, session, SR.SchemaHierarchy_SystemTables);
|
|
||||||
Assert.True(!systemTables.Any());
|
|
||||||
|
|
||||||
var externalTables = await FindNodeByLabel(databaseNodeInfo, session, SR.SchemaHierarchy_ExternalTables);
|
|
||||||
Assert.True(!externalTables.Any());
|
|
||||||
|
|
||||||
var fileTables = await FindNodeByLabel(databaseNodeInfo, session, SR.SchemaHierarchy_FileTables);
|
|
||||||
Assert.True(!fileTables.Any());
|
|
||||||
|
|
||||||
var allTables = tablesChildren.Where(x => x.NodeType != NodeTypes.Folder.ToString());
|
|
||||||
Assert.True(allTables.Any());
|
|
||||||
|
|
||||||
var storedProcedures = await FindNodeByLabel(databaseNodeInfo, session, SR.SchemaHierarchy_StoredProcedures);
|
|
||||||
Assert.True(storedProcedures.Any());
|
|
||||||
|
|
||||||
var views = await FindNodeByLabel(databaseNodeInfo, session, SR.SchemaHierarchy_Views);
|
|
||||||
Assert.True(views.Any());
|
|
||||||
|
|
||||||
var userDefinedDataTypes = await FindNodeByLabel(databaseNodeInfo, session, SR.SchemaHierarchy_UserDefinedDataTypes);
|
|
||||||
Assert.True(userDefinedDataTypes.Any());
|
|
||||||
|
|
||||||
var scalarValuedFunctions = await FindNodeByLabel(databaseNodeInfo, session, SR.SchemaHierarchy_ScalarValuedFunctions);
|
|
||||||
Assert.True(scalarValuedFunctions.Any());
|
|
||||||
|
|
||||||
}
|
}
|
||||||
CancelConnection(uri);
|
_service.CloseSession(session.Uri);
|
||||||
|
Thread.Sleep(3000);
|
||||||
}
|
testDb.Cleanup();
|
||||||
|
return true;
|
||||||
// [Fact]
|
|
||||||
public async void VerifySql2016Objects()
|
|
||||||
{
|
|
||||||
var query = LoadScript("Sql_2016_Additions.sql");
|
|
||||||
string uri = "VerifySql2016Objects";
|
|
||||||
string databaseName = null;
|
|
||||||
|
|
||||||
using (SqlTestDb testDb = SqlTestDb.CreateNew(TestServerType.OnPrem, false, databaseName, query, uri))
|
|
||||||
{
|
|
||||||
var session = await CreateSession(testDb.DatabaseName, uri);
|
|
||||||
var databaseNodeInfo = await ExpandServerNodeAndVerifyDatabaseHierachy(testDb.DatabaseName, session);
|
|
||||||
await FindNodeByLabel(databaseNodeInfo, session, SR.SchemaHierarchy_Tables);
|
|
||||||
}
|
|
||||||
CancelConnection(uri);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// [Fact]
|
|
||||||
public async void VerifySqlObjects()
|
|
||||||
{
|
|
||||||
var query = LoadScript("Sql_Additions.sql");
|
|
||||||
string uri = "VerifySqlObjects";
|
|
||||||
string databaseName = null;
|
|
||||||
|
|
||||||
using (SqlTestDb testDb = SqlTestDb.CreateNew(TestServerType.OnPrem, false, databaseName, query, uri))
|
|
||||||
{
|
|
||||||
var session = await CreateSession(testDb.DatabaseName, uri);
|
|
||||||
var databaseNodeInfo = await ExpandServerNodeAndVerifyDatabaseHierachy(testDb.DatabaseName, session);
|
|
||||||
await FindNodeByLabel(databaseNodeInfo, session, SR.SchemaHierarchy_Tables);
|
|
||||||
}
|
|
||||||
CancelConnection(uri);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// [Fact]
|
|
||||||
public async void VerifyFileTableTest()
|
|
||||||
{
|
|
||||||
var query = LoadScript("FileTableTest.sql");
|
|
||||||
string uri = "VerifyFileTableTest";
|
|
||||||
string databaseName = null;
|
|
||||||
|
|
||||||
using (SqlTestDb testDb = SqlTestDb.CreateNew(TestServerType.OnPrem, false, databaseName, query, uri))
|
|
||||||
{
|
|
||||||
var session = await CreateSession(testDb.DatabaseName, uri);
|
|
||||||
var databaseNodeInfo = await ExpandServerNodeAndVerifyDatabaseHierachy(testDb.DatabaseName, session);
|
|
||||||
await FindNodeByLabel(databaseNodeInfo, session, SR.SchemaHierarchy_Tables);
|
|
||||||
}
|
|
||||||
CancelConnection(uri);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//[Fact]
|
|
||||||
public async void VerifyColumnstoreindexSql16()
|
|
||||||
{
|
|
||||||
var query = LoadScript("ColumnstoreindexSql16.sql");
|
|
||||||
string uri = "VerifyColumnstoreindexSql16";
|
|
||||||
string databaseName = null;
|
|
||||||
|
|
||||||
using (SqlTestDb testDb = SqlTestDb.CreateNew(TestServerType.OnPrem, false, databaseName, query, uri))
|
|
||||||
{
|
|
||||||
var session = await CreateSession(testDb.DatabaseName, uri);
|
|
||||||
var databaseNodeInfo = await ExpandServerNodeAndVerifyDatabaseHierachy(testDb.DatabaseName, session);
|
|
||||||
await FindNodeByLabel(databaseNodeInfo, session, SR.SchemaHierarchy_Tables);
|
|
||||||
}
|
|
||||||
CancelConnection(uri);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string TestLocationDirectory
|
private static string TestLocationDirectory
|
||||||
@@ -341,15 +286,36 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectExplorer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DirectoryInfo BaselineFileDirectory
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
string d = Path.Combine(TestLocationDirectory, "Baselines");
|
||||||
|
return new DirectoryInfo(d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public FileInfo GetInputFile(string fileName)
|
public FileInfo GetInputFile(string fileName)
|
||||||
{
|
{
|
||||||
return new FileInfo(Path.Combine(InputFileDirectory.FullName, fileName));
|
return new FileInfo(Path.Combine(InputFileDirectory.FullName, fileName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public FileInfo GetBaseLineFile(string fileName)
|
||||||
|
{
|
||||||
|
return new FileInfo(Path.Combine(BaselineFileDirectory.FullName, fileName));
|
||||||
|
}
|
||||||
|
|
||||||
private string LoadScript(string fileName)
|
private string LoadScript(string fileName)
|
||||||
{
|
{
|
||||||
FileInfo inputFile = GetInputFile(fileName);
|
FileInfo inputFile = GetInputFile(fileName);
|
||||||
return TestUtilities.ReadTextAndNormalizeLineEndings(inputFile.FullName);
|
return TestUtilities.ReadTextAndNormalizeLineEndings(inputFile.FullName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string LoadBaseLine(string fileName)
|
||||||
|
{
|
||||||
|
FileInfo inputFile = GetBaseLineFile(fileName);
|
||||||
|
return TestUtilities.ReadTextAndNormalizeLineEndings(inputFile.FullName);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -272,7 +272,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Common.Baselined
|
|||||||
/// <param name="actualContent">Actual string</param>
|
/// <param name="actualContent">Actual string</param>
|
||||||
/// <param name="baselineContent">Expected string</param>
|
/// <param name="baselineContent">Expected string</param>
|
||||||
/// <remarks>Fails test if strings do not match; comparison is done using an InvariantCulture StringComparer</remarks>
|
/// <remarks>Fails test if strings do not match; comparison is done using an InvariantCulture StringComparer</remarks>
|
||||||
public void CompareActualWithBaseline(string actualContent, string baselineContent)
|
public static void CompareActualWithBaseline(string actualContent, string baselineContent)
|
||||||
{
|
{
|
||||||
|
|
||||||
int _compareResult = string.Compare(actualContent, baselineContent, StringComparison.OrdinalIgnoreCase);
|
int _compareResult = string.Compare(actualContent, baselineContent, StringComparison.OrdinalIgnoreCase);
|
||||||
|
|||||||
@@ -54,29 +54,26 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Common
|
|||||||
/// Create the test db if not already exists
|
/// Create the test db if not already exists
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static SqlTestDb CreateNew(
|
public static SqlTestDb CreateNew(
|
||||||
TestServerType serverType,
|
TestServerType serverType,
|
||||||
bool doNotCleanupDb = false,
|
bool doNotCleanupDb = false,
|
||||||
string databaseName = null,
|
string databaseName = null,
|
||||||
string query = null,
|
string query = null,
|
||||||
string dbNamePrefix = null)
|
string dbNamePrefix = null)
|
||||||
{
|
{
|
||||||
SqlTestDb testDb = new SqlTestDb();
|
SqlTestDb testDb = new SqlTestDb();
|
||||||
|
|
||||||
using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile())
|
databaseName = databaseName ?? GetUniqueDBName(dbNamePrefix);
|
||||||
|
string createDatabaseQuery = Scripts.CreateDatabaseQuery.Replace("#DatabaseName#", databaseName);
|
||||||
|
TestServiceProvider.Instance.RunQuery(serverType, MasterDatabaseName, createDatabaseQuery);
|
||||||
|
Console.WriteLine(string.Format(CultureInfo.InvariantCulture, "Test database '{0}' is created", databaseName));
|
||||||
|
if (!string.IsNullOrEmpty(query))
|
||||||
{
|
{
|
||||||
databaseName = databaseName ?? GetUniqueDBName(dbNamePrefix);
|
TestServiceProvider.Instance.RunQuery(serverType, databaseName, query);
|
||||||
string createDatabaseQuery = Scripts.CreateDatabaseQuery.Replace("#DatabaseName#", databaseName);
|
Console.WriteLine(string.Format(CultureInfo.InvariantCulture, "Test database '{0}' SQL types are created", databaseName));
|
||||||
TestServiceProvider.Instance.RunQuery(serverType, MasterDatabaseName, createDatabaseQuery);
|
|
||||||
Console.WriteLine(string.Format(CultureInfo.InvariantCulture, "Test database '{0}' is created", databaseName));
|
|
||||||
if (!string.IsNullOrEmpty(query))
|
|
||||||
{
|
|
||||||
TestServiceProvider.Instance.RunQuery(serverType, databaseName, query);
|
|
||||||
Console.WriteLine(string.Format(CultureInfo.InvariantCulture, "Test database '{0}' SQL types are created", databaseName));
|
|
||||||
}
|
|
||||||
testDb.DatabaseName = databaseName;
|
|
||||||
testDb.ServerType = serverType;
|
|
||||||
testDb.DoNotCleanupDb = doNotCleanupDb;
|
|
||||||
}
|
}
|
||||||
|
testDb.DatabaseName = databaseName;
|
||||||
|
testDb.ServerType = serverType;
|
||||||
|
testDb.DoNotCleanupDb = doNotCleanupDb;
|
||||||
|
|
||||||
return testDb;
|
return testDb;
|
||||||
}
|
}
|
||||||
@@ -111,13 +108,20 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Common
|
|||||||
|
|
||||||
public void Cleanup()
|
public void Cleanup()
|
||||||
{
|
{
|
||||||
if (!DoNotCleanupDb)
|
try
|
||||||
{
|
{
|
||||||
string dropDatabaseQuery = string.Format(CultureInfo.InvariantCulture,
|
if (!DoNotCleanupDb)
|
||||||
(ServerType == TestServerType.Azure ? Scripts.DropDatabaseIfExistAzure : Scripts.DropDatabaseIfExist), DatabaseName);
|
{
|
||||||
|
string dropDatabaseQuery = string.Format(CultureInfo.InvariantCulture,
|
||||||
|
(ServerType == TestServerType.Azure ? Scripts.DropDatabaseIfExistAzure : Scripts.DropDatabaseIfExist), DatabaseName);
|
||||||
|
|
||||||
Console.WriteLine(string.Format(CultureInfo.InvariantCulture, "Cleaning up database {0}", DatabaseName));
|
Console.WriteLine(string.Format(CultureInfo.InvariantCulture, "Cleaning up database {0}", DatabaseName));
|
||||||
TestServiceProvider.Instance.RunQuery(ServerType, MasterDatabaseName, dropDatabaseQuery);
|
TestServiceProvider.Instance.RunQuery(ServerType, MasterDatabaseName, dropDatabaseQuery);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine(string.Format(CultureInfo.InvariantCulture, "Failed to cleanup database: {0} error:{1}", DatabaseName, ex.Message));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,136 @@
|
|||||||
|
NodeType: Table Label: HumanResources.Employee
|
||||||
|
NodeType: Column Label: BusinessEntityID
|
||||||
|
NodeType: Column Label: NationalIDNumber
|
||||||
|
NodeType: Column Label: LoginID
|
||||||
|
NodeType: Column Label: OrganizationNode
|
||||||
|
NodeType: Column Label: OrganizationLevel
|
||||||
|
NodeType: Column Label: JobTitle
|
||||||
|
NodeType: Column Label: BirthDate
|
||||||
|
NodeType: Column Label: MaritalStatus
|
||||||
|
NodeType: Column Label: Gender
|
||||||
|
NodeType: Column Label: HireDate
|
||||||
|
NodeType: Column Label: SalariedFlag
|
||||||
|
NodeType: Column Label: VacationHours
|
||||||
|
NodeType: Column Label: SickLeaveHours
|
||||||
|
NodeType: Column Label: CurrentFlag
|
||||||
|
NodeType: Column Label: rowguid
|
||||||
|
NodeType: Column Label: ModifiedDate
|
||||||
|
NodeType: Key Label: FK_Employee_Person_BusinessEntityID
|
||||||
|
NodeType: Key Label: PK_Employee_BusinessEntityID
|
||||||
|
NodeType: Constraint Label: CK_Employee_BirthDate
|
||||||
|
NodeType: Constraint Label: CK_Employee_Gender
|
||||||
|
NodeType: Constraint Label: CK_Employee_HireDate
|
||||||
|
NodeType: Constraint Label: CK_Employee_MaritalStatus
|
||||||
|
NodeType: Constraint Label: CK_Employee_SickLeaveHours
|
||||||
|
NodeType: Constraint Label: CK_Employee_VacationHours
|
||||||
|
NodeType: Index Label: NonClusteredIndex-Login
|
||||||
|
NodeType: Statistic Label: NonClusteredIndex-Login
|
||||||
|
NodeType: Statistic Label: PK_Employee_BusinessEntityID
|
||||||
|
NodeType: Table Label: HumanResources.Employee_Temporal
|
||||||
|
NodeType: Column Label: BusinessEntityID
|
||||||
|
NodeType: Column Label: NationalIDNumber
|
||||||
|
NodeType: Column Label: LoginID
|
||||||
|
NodeType: Column Label: OrganizationNode
|
||||||
|
NodeType: Column Label: OrganizationLevel
|
||||||
|
NodeType: Column Label: JobTitle
|
||||||
|
NodeType: Column Label: BirthDate
|
||||||
|
NodeType: Column Label: MaritalStatus
|
||||||
|
NodeType: Column Label: Gender
|
||||||
|
NodeType: Column Label: HireDate
|
||||||
|
NodeType: Column Label: VacationHours
|
||||||
|
NodeType: Column Label: SickLeaveHours
|
||||||
|
NodeType: Column Label: ValidFrom
|
||||||
|
NodeType: Column Label: ValidTo
|
||||||
|
NodeType: Key Label: PK_Employee_History_BusinessEntityID
|
||||||
|
NodeType: Statistic Label: PK_Employee_History_BusinessEntityID
|
||||||
|
NodeType: Table Label: Person.Person
|
||||||
|
NodeType: Column Label: BusinessEntityID
|
||||||
|
NodeType: Column Label: PersonType
|
||||||
|
NodeType: Column Label: NameStyle
|
||||||
|
NodeType: Column Label: Title
|
||||||
|
NodeType: Column Label: FirstName
|
||||||
|
NodeType: Column Label: MiddleName
|
||||||
|
NodeType: Column Label: LastName
|
||||||
|
NodeType: Column Label: Suffix
|
||||||
|
NodeType: Column Label: EmailPromotion
|
||||||
|
NodeType: Column Label: AdditionalContactInfo
|
||||||
|
NodeType: Column Label: rowguid
|
||||||
|
NodeType: Column Label: ModifiedDate
|
||||||
|
NodeType: Key Label: PK_Person_BusinessEntityID
|
||||||
|
NodeType: Constraint Label: CK_Person_EmailPromotion
|
||||||
|
NodeType: Constraint Label: CK_Person_PersonType
|
||||||
|
NodeType: Trigger Label: TableTrigger
|
||||||
|
NodeType: Statistic Label: PK_Person_BusinessEntityID
|
||||||
|
NodeType: View Label: HumanResources.vEmployee
|
||||||
|
NodeType: Column Label: BusinessEntityID
|
||||||
|
NodeType: Column Label: Title
|
||||||
|
NodeType: Column Label: FirstName
|
||||||
|
NodeType: Column Label: MiddleName
|
||||||
|
NodeType: Column Label: LastName
|
||||||
|
NodeType: Column Label: Suffix
|
||||||
|
NodeType: Column Label: JobTitle
|
||||||
|
NodeType: Column Label: AdditionalContactInfo
|
||||||
|
NodeType: Synonym Label: dbo.MyProduct
|
||||||
|
NodeType: StoredProcedure Label: HumanResources.sp_GetEmployee_Person_Info_AsOf
|
||||||
|
NodeType: StoredProcedureParameter Label: @asOf
|
||||||
|
NodeType: TableValuedFunction Label: dbo.ufnGetContactInformation
|
||||||
|
NodeType: TableValuedFunctionParameter Label: @PersonID
|
||||||
|
NodeType: ScalarValuedFunction Label: dbo.fun1
|
||||||
|
NodeType: ScalarValuedFunction Label: dbo.ufnGetInventoryStock
|
||||||
|
NodeType: ScalarValuedFunctionParameter Label: @ProductID
|
||||||
|
NodeType: DatabaseTrigger Label: Trigger_2
|
||||||
|
NodeType: Assembly Label: Microsoft.SqlServer.Types
|
||||||
|
NodeType: UserDefinedDataType Label: dbo.AccountNumber
|
||||||
|
NodeType: UserDefinedDataType Label: dbo.Flag
|
||||||
|
NodeType: UserDefinedDataType Label: dbo.Name
|
||||||
|
NodeType: UserDefinedDataType Label: dbo.NameStyle
|
||||||
|
NodeType: UserDefinedDataType Label: dbo.OrderNumber
|
||||||
|
NodeType: UserDefinedDataType Label: dbo.Phone
|
||||||
|
NodeType: UserDefinedTableType Label: Demo.SalesOrderDetailType_inmem
|
||||||
|
NodeType: UserDefinedTableTypeColumn Label: OrderQty
|
||||||
|
NodeType: UserDefinedTableTypeColumn Label: ProductID
|
||||||
|
NodeType: UserDefinedTableTypeColumn Label: SpecialOfferID
|
||||||
|
NodeType: UserDefinedTableType Label: Demo.SalesOrderDetailType_ondisk
|
||||||
|
NodeType: UserDefinedTableTypeColumn Label: OrderQty
|
||||||
|
NodeType: UserDefinedTableTypeColumn Label: ProductID
|
||||||
|
NodeType: UserDefinedTableTypeColumn Label: SpecialOfferID
|
||||||
|
NodeType: XmlSchemaCollection Label: Person.AdditionalContactInfoSchemaCollection
|
||||||
|
NodeType: Rule Label: dbo.list_rule
|
||||||
|
NodeType: Default Label: dbo.phonedflt
|
||||||
|
NodeType: Sequence Label: Demo.ID_Seq
|
||||||
|
NodeType: FileGroup Label: PRIMARY
|
||||||
|
NodeType: FullTextCatalog Label: AW2014FullTextCatalog
|
||||||
|
NodeType: User Label: amy0
|
||||||
|
NodeType: User Label: dbo
|
||||||
|
NodeType: User Label: guest
|
||||||
|
NodeType: User Label: INFORMATION_SCHEMA
|
||||||
|
NodeType: User Label: sys
|
||||||
|
NodeType: DatabaseRole Label: db_accessadmin
|
||||||
|
NodeType: DatabaseRole Label: db_backupoperator
|
||||||
|
NodeType: DatabaseRole Label: db_datareader
|
||||||
|
NodeType: DatabaseRole Label: db_datawriter
|
||||||
|
NodeType: DatabaseRole Label: db_ddladmin
|
||||||
|
NodeType: DatabaseRole Label: db_denydatareader
|
||||||
|
NodeType: DatabaseRole Label: db_denydatawriter
|
||||||
|
NodeType: DatabaseRole Label: db_owner
|
||||||
|
NodeType: DatabaseRole Label: db_securityadmin
|
||||||
|
NodeType: DatabaseRole Label: public
|
||||||
|
NodeType: DatabaseRole Label: SalesManagers
|
||||||
|
NodeType: DatabaseRole Label: SalesPersons
|
||||||
|
NodeType: Schema Label: dbo
|
||||||
|
NodeType: Schema Label: db_accessadmin
|
||||||
|
NodeType: Schema Label: db_backupoperator
|
||||||
|
NodeType: Schema Label: db_datareader
|
||||||
|
NodeType: Schema Label: db_datawriter
|
||||||
|
NodeType: Schema Label: db_ddladmin
|
||||||
|
NodeType: Schema Label: db_denydatareader
|
||||||
|
NodeType: Schema Label: db_denydatawriter
|
||||||
|
NodeType: Schema Label: db_owner
|
||||||
|
NodeType: Schema Label: db_securityadmin
|
||||||
|
NodeType: Schema Label: Demo
|
||||||
|
NodeType: Schema Label: guest
|
||||||
|
NodeType: Schema Label: HumanResources
|
||||||
|
NodeType: Schema Label: INFORMATION_SCHEMA
|
||||||
|
NodeType: Schema Label: Person
|
||||||
|
NodeType: Schema Label: sys
|
||||||
|
NodeType: DatabaseEncryptionKey Label:
|
||||||
File diff suppressed because one or more lines are too long
@@ -6,6 +6,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Microsoft.SqlTools.Credentials;
|
using Microsoft.SqlTools.Credentials;
|
||||||
using Microsoft.SqlTools.ServiceLayer.Connection;
|
using Microsoft.SqlTools.ServiceLayer.Connection;
|
||||||
using Microsoft.SqlTools.ServiceLayer.Connection.Contracts;
|
using Microsoft.SqlTools.ServiceLayer.Connection.Contracts;
|
||||||
@@ -78,9 +80,12 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Common
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void RunQuery(TestServerType serverType, string databaseName, string queryText, bool throwOnError = false)
|
public void RunQuery(TestServerType serverType, string databaseName, string queryText, bool throwOnError = false)
|
||||||
{
|
{
|
||||||
|
string uri = "";
|
||||||
using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile())
|
using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile())
|
||||||
{
|
{
|
||||||
ConnectionInfo connInfo = InitLiveConnectionInfo(serverType, databaseName, queryTempFile.FilePath);
|
uri = queryTempFile.FilePath;
|
||||||
|
|
||||||
|
ConnectionInfo connInfo = InitLiveConnectionInfo(serverType, databaseName, uri);
|
||||||
Query query = new Query(queryText, connInfo, new QueryExecutionSettings(), MemoryFileSystem.GetFileStreamFactory());
|
Query query = new Query(queryText, connInfo, new QueryExecutionSettings(), MemoryFileSystem.GetFileStreamFactory());
|
||||||
query.Execute();
|
query.Execute();
|
||||||
query.ExecutionTask.Wait();
|
query.ExecutionTask.Wait();
|
||||||
@@ -96,7 +101,18 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Common
|
|||||||
string.Join(Environment.NewLine, errorBatches.Select(b => b.BatchText))));
|
string.Join(Environment.NewLine, errorBatches.Select(b => b.BatchText))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
DisconnectConnection(uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<T> CalculateRunTime<T>(Func<Task<T>> testToRun, bool printResult, [CallerMemberName] string testName = "")
|
||||||
|
{
|
||||||
|
TestTimer timer = new TestTimer() { PrintResult = printResult };
|
||||||
|
T result = await testToRun();
|
||||||
|
timer.EndAndPrint(testName);
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ConnectionInfo InitLiveConnectionInfo(TestServerType serverType, string databaseName, string scriptFilePath)
|
private ConnectionInfo InitLiveConnectionInfo(TestServerType serverType, string databaseName, string scriptFilePath)
|
||||||
@@ -119,6 +135,15 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Common
|
|||||||
return connInfo;
|
return connInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void DisconnectConnection(string uri)
|
||||||
|
{
|
||||||
|
ConnectionService.Instance.Disconnect(new DisconnectParams
|
||||||
|
{
|
||||||
|
OwnerUri = uri,
|
||||||
|
Type = ConnectionType.Default
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private static bool hasInitServices = false;
|
private static bool hasInitServices = false;
|
||||||
|
|
||||||
private static void InitializeTestServices()
|
private static void InitializeTestServices()
|
||||||
|
|||||||
Reference in New Issue
Block a user