fixed db trigger, system types and oe tests (#331)

* fixed db trigger, system types and oe tests
This commit is contained in:
Leila Lali
2017-04-28 09:44:45 -07:00
committed by GitHub
parent c4227c2e24
commit c46032c71f
13 changed files with 690 additions and 565 deletions

View File

@@ -4,7 +4,9 @@
//
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes
{
@@ -76,6 +78,22 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes
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}]";
return filter;

View File

@@ -1,353 +1,363 @@
//
// 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.Composition;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.SqlTools.Extensibility;
using Microsoft.SqlTools.Hosting;
using Microsoft.SqlTools.Hosting.Protocol;
using Microsoft.SqlTools.ServiceLayer.Connection;
using Microsoft.SqlTools.ServiceLayer.Connection.Contracts;
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Contracts;
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes;
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel;
using Microsoft.SqlTools.Utility;
namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer
{
/// <summary>
/// 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.
/// </summary>
[Export(typeof(IHostedService))]
public class ObjectExplorerService : HostedService<ObjectExplorerService>, IComposableService
{
internal const string uriPrefix = "objectexplorer://";
// Instance of the connection service, used to get the connection info for a given owner URI
private ConnectionService connectionService;
private IProtocolEndpoint serviceHost;
private Dictionary<string, ObjectExplorerSession> sessionMap;
private readonly Lazy<Dictionary<string, HashSet<ChildFactory>>> applicableNodeChildFactories;
private IMultiServiceProvider serviceProvider;
/// <summary>
/// Singleton constructor
/// </summary>
public ObjectExplorerService()
{
sessionMap = new Dictionary<string, ObjectExplorerSession>();
applicableNodeChildFactories = new Lazy<Dictionary<string, HashSet<ChildFactory>>>(() => PopulateFactories());
}
/// <summary>
/// Internal for testing only
/// </summary>
internal ObjectExplorerService(ExtensionServiceProvider serviceProvider)
: this()
{
SetServiceProvider(serviceProvider);
}
private Dictionary<string, HashSet<ChildFactory>> ApplicableNodeChildFactories
{
get
{
return applicableNodeChildFactories.Value;
}
}
/// <summary>
/// As an <see cref="IComposableService"/>, this will be set whenever the service is initialized
/// via an <see cref="IMultiServiceProvider"/>
/// </summary>
/// <param name="provider"></param>
public override void SetServiceProvider(IMultiServiceProvider provider)
{
Validate.IsNotNull(nameof(provider), provider);
serviceProvider = provider;
connectionService = provider.GetService<ConnectionService>();
}
/// <summary>
/// Initializes the service with the service host and registers request handlers.
/// </summary>
/// <param name="serviceHost">The service host instance to register with</param>
public override void InitializeService(IProtocolEndpoint serviceHost)
{
Logger.Write(LogLevel.Verbose, "ObjectExplorer service initialized");
this.serviceHost = serviceHost;
// Register handlers for requests
serviceHost.SetRequestHandler(CreateSessionRequest.Type, HandleCreateSessionRequest);
serviceHost.SetRequestHandler(ExpandRequest.Type, HandleExpandRequest);
}
internal async Task HandleCreateSessionRequest(ConnectionDetails connectionDetails, RequestContext<CreateSessionResponse> context)
{
Logger.Write(LogLevel.Verbose, "HandleCreateSessionRequest");
Func<Task<CreateSessionResponse>> doCreateSession = async () =>
{
Validate.IsNotNull(nameof(connectionDetails), connectionDetails);
Validate.IsNotNull(nameof(context), context);
string uri = GenerateUri(connectionDetails);
ObjectExplorerSession session;
if (!sessionMap.TryGetValue(uri, out session))
{
// Establish a connection to the specified server/database
session = await DoCreateSession(connectionDetails, uri);
}
CreateSessionResponse response;
if (session == null)
{
response = new CreateSessionResponse() { Success = false };
}
else
{
// Else we have a session available, response with existing session information
response = new CreateSessionResponse()
{
Success = true,
RootNode = session.Root.ToNodeInfo(),
SessionId = session.Uri
};
}
return response;
};
await HandleRequestAsync(doCreateSession, context, "HandleCreateSessionRequest");
}
internal async Task<NodeInfo[]> ExpandNode(ObjectExplorerSession session, string nodePath)
{
return await Task.Factory.StartNew(() =>
{
NodeInfo[] nodes = null;
TreeNode node = session.Root.FindNodeByPath(nodePath);
if(node != null)
{
nodes = node.Expand().Select(x => x.ToNodeInfo()).ToArray();
}
return nodes;
});
}
/// <summary>
/// Establishes a new session and stores its information
/// </summary>
/// <returns><see cref="ObjectExplorerSession"/> object if successful, null if unsuccessful</returns>
internal async Task<ObjectExplorerSession> DoCreateSession(ConnectionDetails connectionDetails, string uri)
{
ObjectExplorerSession session;
ConnectParams connectParams = new ConnectParams() { OwnerUri = uri, Connection = connectionDetails };
ConnectionCompleteParams connectionResult = await Connect(connectParams);
if (connectionResult == null)
{
return null;
}
session = ObjectExplorerSession.CreateSession(connectionResult, serviceProvider);
sessionMap[uri] = session;
return session;
}
private async Task<ConnectionCompleteParams> Connect(ConnectParams connectParams)
{
try
{
// open connection based on request details
ConnectionCompleteParams result = await connectionService.Connect(connectParams);
if(result != null && !string.IsNullOrEmpty(result.ConnectionId))
{
return result;
}
else
{
await serviceHost.SendEvent(ConnectionCompleteNotification.Type, result);
return null;
}
}
catch (Exception ex)
{
// Send a connection failed error message in this case.
ConnectionCompleteParams result = new ConnectionCompleteParams()
{
Messages = ex.ToString()
};
await serviceHost.SendEvent(ConnectionCompleteNotification.Type, result);
return null;
}
}
internal async Task HandleExpandRequest(ExpandParams expandParams, RequestContext<ExpandResponse> context)
{
Logger.Write(LogLevel.Verbose, "HandleExpandRequest");
Func<Task<ExpandResponse>> expandNode = async () =>
{
Validate.IsNotNull(nameof(expandParams), expandParams);
Validate.IsNotNull(nameof(context), context);
string uri = expandParams.SessionId;
ObjectExplorerSession session = null;
NodeInfo[] nodes = null;
if (sessionMap.ContainsKey(uri))
{
session = sessionMap[uri];
}
else
{
//TODO: error
}
if (session != null)
{
// Establish a connection to the specified server/database
nodes = await ExpandNode(session, expandParams.NodePath);
}
ExpandResponse response;
response = new ExpandResponse() { Nodes = nodes, SessionId = uri };
return response;
};
await HandleRequestAsync(expandNode, context, "HandleExpandRequest");
}
private async Task HandleRequestAsync<T>(Func<Task<T>> handler, RequestContext<T> requestContext, string requestType)
{
Logger.Write(LogLevel.Verbose, requestType);
try
{
T result = await handler();
await requestContext.SendResult(result);
}
catch (Exception ex)
{
await requestContext.SendError(ex.ToString());
}
}
/// <summary>
/// Generates a URI for object explorer using a similar pattern to Mongo DB (which has URI-based database definition)
/// as this should ensure uniqueness
/// </summary>
/// <param name="details"></param>
/// <returns>string representing a URI</returns>
/// <remarks>Internal for testing purposes only</remarks>
internal static string GenerateUri(ConnectionDetails details)
{
Validate.IsNotNull("details", details);
string uri = string.Format(CultureInfo.InvariantCulture, "{0}{1}", uriPrefix, Uri.EscapeUriString(details.ServerName));
uri = AppendIfExists(uri, "databaseName", details.DatabaseName);
uri = AppendIfExists(uri, "user", details.UserName);
return uri;
}
private static string AppendIfExists(string uri, string propertyName, string propertyValue)
{
if (!string.IsNullOrEmpty(propertyValue))
{
uri += string.Format(CultureInfo.InvariantCulture, ";{0}={1}", propertyName, Uri.EscapeUriString(propertyValue));
}
return uri;
}
public IEnumerable<ChildFactory> GetApplicableChildFactories(TreeNode item)
{
if (ApplicableNodeChildFactories != null)
{
HashSet<ChildFactory> applicableFactories;
if (ApplicableNodeChildFactories.TryGetValue(item.NodeTypeId.ToString(), out applicableFactories))
{
return applicableFactories;
}
}
return null;
}
internal Dictionary<string, HashSet<ChildFactory>> PopulateFactories()
{
VerifyServicesInitialized();
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>())
{
var parents = factory.ApplicableParents();
if (parents != null)
{
foreach (var parent in parents)
{
AddToApplicableChildFactories(childFactories, factory, parent);
}
}
}
return childFactories;
}
private void VerifyServicesInitialized()
{
if (serviceProvider == null)
{
throw new InvalidOperationException(SqlTools.Hosting.SR.ServiceProviderNotSet);
}
if (connectionService == null)
{
throw new InvalidOperationException(SqlTools.Hosting.SR.ServiceProviderNotSet);
}
}
private static void AddToApplicableChildFactories(Dictionary<string, HashSet<ChildFactory>> childFactories, ChildFactory factory, string parent)
{
HashSet<ChildFactory> applicableFactories;
if (!childFactories.TryGetValue(parent, out applicableFactories))
{
applicableFactories = new HashSet<ChildFactory>();
childFactories[parent] = applicableFactories;
}
applicableFactories.Add(factory);
}
internal class ObjectExplorerSession
{
private ConnectionService connectionService;
private IMultiServiceProvider serviceProvider;
// TODO decide whether a cache is needed to handle lookups in elements with a large # children
//private const int Cachesize = 10000;
//private Cache<string, NodeMapping> cache;
public ObjectExplorerSession(string uri, TreeNode root, IMultiServiceProvider serviceProvider, ConnectionService connectionService)
{
Validate.IsNotNullOrEmptyString("uri", uri);
Validate.IsNotNull("root", root);
Uri = uri;
Root = root;
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>());
//
// 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.Composition;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.SqlTools.Extensibility;
using Microsoft.SqlTools.Hosting;
using Microsoft.SqlTools.Hosting.Protocol;
using Microsoft.SqlTools.ServiceLayer.Connection;
using Microsoft.SqlTools.ServiceLayer.Connection.Contracts;
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Contracts;
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes;
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel;
using Microsoft.SqlTools.Utility;
namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer
{
/// <summary>
/// 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.
/// </summary>
[Export(typeof(IHostedService))]
public class ObjectExplorerService : HostedService<ObjectExplorerService>, IComposableService
{
internal const string uriPrefix = "objectexplorer://";
// Instance of the connection service, used to get the connection info for a given owner URI
private ConnectionService connectionService;
private IProtocolEndpoint serviceHost;
private Dictionary<string, ObjectExplorerSession> sessionMap;
private readonly Lazy<Dictionary<string, HashSet<ChildFactory>>> applicableNodeChildFactories;
private IMultiServiceProvider serviceProvider;
/// <summary>
/// Singleton constructor
/// </summary>
public ObjectExplorerService()
{
sessionMap = new Dictionary<string, ObjectExplorerSession>();
applicableNodeChildFactories = new Lazy<Dictionary<string, HashSet<ChildFactory>>>(() => PopulateFactories());
}
/// <summary>
/// Internal for testing only
/// </summary>
internal ObjectExplorerService(ExtensionServiceProvider serviceProvider)
: this()
{
SetServiceProvider(serviceProvider);
}
private Dictionary<string, HashSet<ChildFactory>> ApplicableNodeChildFactories
{
get
{
return applicableNodeChildFactories.Value;
}
}
/// <summary>
/// As an <see cref="IComposableService"/>, this will be set whenever the service is initialized
/// via an <see cref="IMultiServiceProvider"/>
/// </summary>
/// <param name="provider"></param>
public override void SetServiceProvider(IMultiServiceProvider provider)
{
Validate.IsNotNull(nameof(provider), provider);
serviceProvider = provider;
connectionService = provider.GetService<ConnectionService>();
}
/// <summary>
/// Initializes the service with the service host and registers request handlers.
/// </summary>
/// <param name="serviceHost">The service host instance to register with</param>
public override void InitializeService(IProtocolEndpoint serviceHost)
{
Logger.Write(LogLevel.Verbose, "ObjectExplorer service initialized");
this.serviceHost = serviceHost;
// Register handlers for requests
serviceHost.SetRequestHandler(CreateSessionRequest.Type, HandleCreateSessionRequest);
serviceHost.SetRequestHandler(ExpandRequest.Type, HandleExpandRequest);
}
public void CloseSession(string uri)
{
ObjectExplorerSession session;
if (sessionMap.TryGetValue(uri, out session))
{
// Establish a connection to the specified server/database
sessionMap.Remove(session.Uri);
}
}
internal async Task HandleCreateSessionRequest(ConnectionDetails connectionDetails, RequestContext<CreateSessionResponse> context)
{
Logger.Write(LogLevel.Verbose, "HandleCreateSessionRequest");
Func<Task<CreateSessionResponse>> doCreateSession = async () =>
{
Validate.IsNotNull(nameof(connectionDetails), connectionDetails);
Validate.IsNotNull(nameof(context), context);
string uri = GenerateUri(connectionDetails);
ObjectExplorerSession session;
if (!sessionMap.TryGetValue(uri, out session))
{
// Establish a connection to the specified server/database
session = await DoCreateSession(connectionDetails, uri);
}
CreateSessionResponse response;
if (session == null)
{
response = new CreateSessionResponse() { Success = false };
}
else
{
// Else we have a session available, response with existing session information
response = new CreateSessionResponse()
{
Success = true,
RootNode = session.Root.ToNodeInfo(),
SessionId = session.Uri
};
}
return response;
};
await HandleRequestAsync(doCreateSession, context, "HandleCreateSessionRequest");
}
internal async Task<NodeInfo[]> ExpandNode(ObjectExplorerSession session, string nodePath)
{
return await Task.Factory.StartNew(() =>
{
NodeInfo[] nodes = null;
TreeNode node = session.Root.FindNodeByPath(nodePath);
if(node != null)
{
nodes = node.Expand().Select(x => x.ToNodeInfo()).ToArray();
}
return nodes;
});
}
/// <summary>
/// Establishes a new session and stores its information
/// </summary>
/// <returns><see cref="ObjectExplorerSession"/> object if successful, null if unsuccessful</returns>
internal async Task<ObjectExplorerSession> DoCreateSession(ConnectionDetails connectionDetails, string uri)
{
ObjectExplorerSession session;
ConnectParams connectParams = new ConnectParams() { OwnerUri = uri, Connection = connectionDetails };
ConnectionCompleteParams connectionResult = await Connect(connectParams);
if (connectionResult == null)
{
return null;
}
session = ObjectExplorerSession.CreateSession(connectionResult, serviceProvider);
sessionMap[uri] = session;
return session;
}
private async Task<ConnectionCompleteParams> Connect(ConnectParams connectParams)
{
try
{
// open connection based on request details
ConnectionCompleteParams result = await connectionService.Connect(connectParams);
if(result != null && !string.IsNullOrEmpty(result.ConnectionId))
{
return result;
}
else
{
await serviceHost.SendEvent(ConnectionCompleteNotification.Type, result);
return null;
}
}
catch (Exception ex)
{
// Send a connection failed error message in this case.
ConnectionCompleteParams result = new ConnectionCompleteParams()
{
Messages = ex.ToString()
};
await serviceHost.SendEvent(ConnectionCompleteNotification.Type, result);
return null;
}
}
internal async Task HandleExpandRequest(ExpandParams expandParams, RequestContext<ExpandResponse> context)
{
Logger.Write(LogLevel.Verbose, "HandleExpandRequest");
Func<Task<ExpandResponse>> expandNode = async () =>
{
Validate.IsNotNull(nameof(expandParams), expandParams);
Validate.IsNotNull(nameof(context), context);
string uri = expandParams.SessionId;
ObjectExplorerSession session = null;
NodeInfo[] nodes = null;
if (sessionMap.ContainsKey(uri))
{
session = sessionMap[uri];
}
else
{
//TODO: error
}
if (session != null)
{
// Establish a connection to the specified server/database
nodes = await ExpandNode(session, expandParams.NodePath);
}
ExpandResponse response;
response = new ExpandResponse() { Nodes = nodes, SessionId = uri };
return response;
};
await HandleRequestAsync(expandNode, context, "HandleExpandRequest");
}
private async Task HandleRequestAsync<T>(Func<Task<T>> handler, RequestContext<T> requestContext, string requestType)
{
Logger.Write(LogLevel.Verbose, requestType);
try
{
T result = await handler();
await requestContext.SendResult(result);
}
catch (Exception ex)
{
await requestContext.SendError(ex.ToString());
}
}
/// <summary>
/// Generates a URI for object explorer using a similar pattern to Mongo DB (which has URI-based database definition)
/// as this should ensure uniqueness
/// </summary>
/// <param name="details"></param>
/// <returns>string representing a URI</returns>
/// <remarks>Internal for testing purposes only</remarks>
internal static string GenerateUri(ConnectionDetails details)
{
Validate.IsNotNull("details", details);
string uri = string.Format(CultureInfo.InvariantCulture, "{0}{1}", uriPrefix, Uri.EscapeUriString(details.ServerName));
uri = AppendIfExists(uri, "databaseName", details.DatabaseName);
uri = AppendIfExists(uri, "user", details.UserName);
return uri;
}
private static string AppendIfExists(string uri, string propertyName, string propertyValue)
{
if (!string.IsNullOrEmpty(propertyValue))
{
uri += string.Format(CultureInfo.InvariantCulture, ";{0}={1}", propertyName, Uri.EscapeUriString(propertyValue));
}
return uri;
}
public IEnumerable<ChildFactory> GetApplicableChildFactories(TreeNode item)
{
if (ApplicableNodeChildFactories != null)
{
HashSet<ChildFactory> applicableFactories;
if (ApplicableNodeChildFactories.TryGetValue(item.NodeTypeId.ToString(), out applicableFactories))
{
return applicableFactories;
}
}
return null;
}
internal Dictionary<string, HashSet<ChildFactory>> PopulateFactories()
{
VerifyServicesInitialized();
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>())
{
var parents = factory.ApplicableParents();
if (parents != null)
{
foreach (var parent in parents)
{
AddToApplicableChildFactories(childFactories, factory, parent);
}
}
}
return childFactories;
}
private void VerifyServicesInitialized()
{
if (serviceProvider == null)
{
throw new InvalidOperationException(SqlTools.Hosting.SR.ServiceProviderNotSet);
}
if (connectionService == null)
{
throw new InvalidOperationException(SqlTools.Hosting.SR.ServiceProviderNotSet);
}
}
private static void AddToApplicableChildFactories(Dictionary<string, HashSet<ChildFactory>> childFactories, ChildFactory factory, string parent)
{
HashSet<ChildFactory> applicableFactories;
if (!childFactories.TryGetValue(parent, out applicableFactories))
{
applicableFactories = new HashSet<ChildFactory>();
childFactories[parent] = applicableFactories;
}
applicableFactories.Add(factory);
}
internal class ObjectExplorerSession
{
private ConnectionService connectionService;
private IMultiServiceProvider serviceProvider;
// TODO decide whether a cache is needed to handle lookups in elements with a large # children
//private const int Cachesize = 10000;
//private Cache<string, NodeMapping> cache;
public ObjectExplorerSession(string uri, TreeNode root, IMultiServiceProvider serviceProvider, ConnectionService connectionService)
{
Validate.IsNotNullOrEmptyString("uri", uri);
Validate.IsNotNull("root", root);
Uri = uri;
Root = root;
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))
{
// 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);
databaseNode.Label = rootNode.Label;
session.Root = databaseNode;
}
return session;
}
}
}
}
}
return session;
}
}
}
}

View File

@@ -23,7 +23,6 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
public override IEnumerable<TreeNode> Expand(TreeNode parent)
{
//parent.BeginChildrenInit();
try
{
List<TreeNode> allChildren = new List<TreeNode>();
@@ -35,7 +34,6 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
}
finally
{
//parent.EndChildrenInit();
}
}
@@ -62,10 +60,15 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
}
SmoQueryContext context = parent.GetContextAs<SmoQueryContext>();
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));
var filters = this.Filters;
var validForFlag = ServerVersionHelper.GetValidForFlag(context.SqlServerType);
foreach (var querier in queriers)
{
string propertyFilter = GetProperyFilter(filters, querier.GetType(), validForFlag);
@@ -77,7 +80,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
Console.WriteLine("smoObject should not be null");
}
TreeNode childNode = CreateChild(parent, smoObject);
if (childNode != null && !ShouldFilterNode(childNode, validForFlag))
if (childNode != null && PassesFinalFilters(childNode, smoObject) && !ShouldFilterNode(childNode, validForFlag))
{
allChildren.Add(childNode);
}
@@ -102,15 +105,14 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
private string GetProperyFilter(IEnumerable<NodeFilter> filters, Type querierType, ValidForFlag validForFlag)
{
string filter = "";
string filter = string.Empty;
if (filters != null)
{
var filterToApply = filters.FirstOrDefault(f => f.CanApplyFilter(querierType, validForFlag));
filter = "";
if (filterToApply != null)
var filtersToApply = filters.Where(f => f.CanApplyFilter(querierType, validForFlag)).ToList();
filter = string.Empty;
if (filtersToApply.Any())
{
filter = filterToApply.ToPropertyFilterString();
filter = NodeFilter.ConcatProperties(filtersToApply);
}
}

View File

@@ -923,7 +923,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
[Export(typeof(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; } }
@@ -937,7 +937,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
HashSet<string> urns = null;
if (hasFilter)
{
string urn = $"{parentDatabase.Urn.ToString()}/Trigger" + filter;
string urn = $"{parentDatabase.Urn.ToString()}/DatabaseDdlTrigger" + filter;
Enumerator en = new Enumerator();
Request request = new Request(new Urn(urn));
ServerConnection serverConnection = new ServerConnection(context.Server.ConnectionContext.SqlConnectionObject);
@@ -948,11 +948,11 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
{
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
{
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))]
internal partial class SqlUserDefinedDataTypeQuerier: SmoQuerier
{
@@ -2802,15 +2762,15 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
public override IEnumerable<SqlSmoObject> Query(SmoQueryContext context, string filter)
{
Server parentServer = context.Parent as Server;
if (parentServer != null)
Database parentDatabase = context.Parent as Database;
if (parentDatabase != null)
{
var retValue = parentServer.SystemDataTypes;
var retValue = parentDatabase.Parent.SystemDataTypes;
bool hasFilter = !string.IsNullOrEmpty(filter);
HashSet<string> urns = null;
if (hasFilter)
{
string urn = $"{parentServer.Urn.ToString()}/SystemDataType" + filter;
string urn = $"{parentDatabase.Urn.ToString()}/SystemDataType" + filter;
Enumerator en = new Enumerator();
Request request = new Request(new Urn(urn));
ServerConnection serverConnection = new ServerConnection(context.Server.ConnectionContext.SqlConnectionObject);

View File

@@ -52,7 +52,9 @@
<Node Name="SqlFullTextIndex" Parent="Table" Collection="False" />
<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" >
<NavigationPath Parent="Database" Field="Assemblies" />
</Node>
@@ -61,7 +63,6 @@
<Node Name="SqlDefault" Parent="Database" />
<Node Name="SqlSequence" Parent="Database" />
<Node Name="SqlSystemDataType" Parent="Server" />
<Node Name="SqlUserDefinedDataType" Parent="Database" />
<Node Name="SqlUserDefinedTableType" Parent="Database" />
@@ -129,7 +130,9 @@
<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
<Node Name="SqlRoute"/>
-->

View File

@@ -216,6 +216,7 @@
<Child Name="ScalarValuedFunctions"/>
<Child Name="AggregateFunctions"/>
</Node>
<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="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="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="SystemClrDataTypes" LocLabel="SR.SchemaHierarchy_SystemCLRDataTypes" BaseClass="ModelBased" Strategy="MultipleElementsOfType" NodeType="SystemClrDataType" ChildQuerierTypes="SqlUserDefinedType" 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="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="SqlBuiltInType" ValidFor="Sql2008|Sql2012|Sql2014|Sql2016|SqlvNext|AzureV11|AzureV12"/>
<!-- Childs of ExternalResources -->
<Node Name="ExternalDataSources" LocLabel="SR.SchemaHierarchy_ExternalDataSources" BaseClass="ModelBased" NodeType="ExternalDataSource" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlExternalDataSource" ValidFor="Sql2016|SqlvNext|AzureV12"/>

View File

@@ -2393,7 +2393,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
{
get
{
return new [] { typeof(SqlUserDefinedTypeQuerier), };
return new [] { typeof(SqlBuiltInTypeQuerier), };
}
}
@@ -2417,7 +2417,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
{
get
{
return new [] { typeof(SqlUserDefinedTypeQuerier), };
return new [] { typeof(SqlBuiltInTypeQuerier), };
}
}