Support connecting with a connection string (#334)

- Add support for connecting with a connection string by passing it as one of the connection parameters
- If a connection string is present, it will override any other parameters that are present
This commit is contained in:
Matt Irvine
2017-05-01 21:01:26 -07:00
committed by GitHub
parent 0b39408eae
commit fb239ac956
6 changed files with 1184 additions and 1099 deletions

View File

@@ -14,7 +14,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.Contracts
/// A URI identifying the owner of the connection. This will most commonly be a file in the workspace /// A URI identifying the owner of the connection. This will most commonly be a file in the workspace
/// or a virtual file representing an object in a database. /// or a virtual file representing an object in a database.
/// </summary> /// </summary>
public string OwnerUri { get; set; } public string OwnerUri { get; set; }
/// <summary> /// <summary>
/// Contains the required parameters to initialize a connection to a database. /// Contains the required parameters to initialize a connection to a database.
/// A connection will identified by its server name, database name and user name. /// A connection will identified by its server name, database name and user name.

View File

@@ -24,6 +24,11 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.Contracts
{ {
errorMessage = SR.ConnectionParamsValidateNullConnection; errorMessage = SR.ConnectionParamsValidateNullConnection;
} }
else if (!string.IsNullOrEmpty(parameters.Connection.ConnectionString))
{
// Do not check other connection parameters if a connection string is present
return string.IsNullOrEmpty(errorMessage);
}
else if (string.IsNullOrEmpty(parameters.Connection.ServerName)) else if (string.IsNullOrEmpty(parameters.Connection.ServerName))
{ {
errorMessage = SR.ConnectionParamsValidateNullServerName; errorMessage = SR.ConnectionParamsValidateNullServerName;

View File

@@ -5,7 +5,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using Microsoft.SqlTools.Utility; using Microsoft.SqlTools.Utility;
namespace Microsoft.SqlTools.ServiceLayer.Connection.Contracts namespace Microsoft.SqlTools.ServiceLayer.Connection.Contracts
@@ -443,6 +443,22 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.Contracts
} }
} }
/// <summary>
/// Gets or sets a string value to be used as the connection string. If given, all other options will be ignored.
/// </summary>
public string ConnectionString
{
get
{
return GetOptionValue<string>("connectionString");
}
set
{
SetOptionValue("connectionString", value);
}
}
private T GetOptionValue<T>(string name) private T GetOptionValue<T>(string name)
{ {
T result = default(T); T result = default(T);
@@ -485,33 +501,33 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.Contracts
{ {
Options.Add(name, value); Options.Add(name, value);
} }
} }
public bool IsComparableTo(ConnectionDetails other) public bool IsComparableTo(ConnectionDetails other)
{ {
if (other == null) if (other == null)
{ {
return false; return false;
} }
if (!string.Equals(ServerName, other.ServerName) if (ServerName != other.ServerName
|| !string.Equals(AuthenticationType, other.AuthenticationType) || AuthenticationType != other.AuthenticationType
|| !string.Equals(UserName, other.UserName)) || UserName != other.UserName)
{ {
return false; return false;
} }
// For database name, only compare if neither is empty. This is important // For database name, only compare if neither is empty. This is important
// Since it allows for handling of connections to the default database, but is // Since it allows for handling of connections to the default database, but is
// not a 100% accurate heuristic. // not a 100% accurate heuristic.
if (!string.IsNullOrEmpty(DatabaseName) if (!string.IsNullOrEmpty(DatabaseName)
&& !string.IsNullOrEmpty(other.DatabaseName) && !string.IsNullOrEmpty(other.DatabaseName)
&& !string.Equals(DatabaseName, other.DatabaseName)) && DatabaseName != other.DatabaseName)
{ {
return false; return false;
} }
return true; return true;
} }
} }
} }

View File

@@ -325,10 +325,10 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Connection
.Returns((string connString) => .Returns((string connString) =>
{ {
dummySqlConnection.ConnectionString = connString; dummySqlConnection.ConnectionString = connString;
SqlConnectionStringBuilder scsb = new SqlConnectionStringBuilder(connString); SqlConnectionStringBuilder scsb = new SqlConnectionStringBuilder(connString);
// Database name is respected. Follow heuristic where empty DB name really means Master // Database name is respected. Follow heuristic where empty DB name really means Master
var dbName = string.IsNullOrEmpty(scsb.InitialCatalog) ? masterDbName : scsb.InitialCatalog; var dbName = string.IsNullOrEmpty(scsb.InitialCatalog) ? masterDbName : scsb.InitialCatalog;
dummySqlConnection.SetDatabase(dbName); dummySqlConnection.SetDatabase(dbName);
return dummySqlConnection; return dummySqlConnection;
}); });
@@ -1210,5 +1210,37 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Connection
await Assert.ThrowsAsync<InvalidOperationException>( await Assert.ThrowsAsync<InvalidOperationException>(
() => service.GetOrOpenConnection(TestObjects.ScriptUri, ConnectionType.Query)); () => service.GetOrOpenConnection(TestObjects.ScriptUri, ConnectionType.Query));
} }
[Fact]
public async Task ConnectionWithConnectionStringSucceeds()
{
var connectionParameters = TestObjects.GetTestConnectionParams(true);
var connectionResult = await TestObjects.GetTestConnectionService().Connect(connectionParameters);
Assert.NotEmpty(connectionResult.ConnectionId);
}
[Fact]
public async Task ConnectionWithBadConnectionStringFails()
{
var connectionParameters = TestObjects.GetTestConnectionParams(true);
connectionParameters.Connection.ConnectionString = "thisisnotavalidconnectionstring";
var connectionResult = await TestObjects.GetTestConnectionService().Connect(connectionParameters);
Assert.NotEmpty(connectionResult.ErrorMessage);
}
[Fact]
public async Task ConnectionWithConnectionStringOverridesParameters()
{
var connectionParameters = TestObjects.GetTestConnectionParams();
connectionParameters.Connection.ServerName = "overriddenServerName";
var connectionString = TestObjects.GetTestConnectionParams(true).Connection.ConnectionString;
connectionParameters.Connection.ConnectionString = connectionString;
// Connect and verify that the server name has been overridden
var connectionResult = await TestObjects.GetTestConnectionService().Connect(connectionParameters);
Assert.NotEqual(connectionParameters.Connection.ServerName, connectionResult.ConnectionSummary.ServerName);
}
} }
} }

View File

@@ -44,12 +44,12 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Utility
GetTestConnectionDetails()); GetTestConnectionDetails());
} }
public static ConnectParams GetTestConnectionParams() public static ConnectParams GetTestConnectionParams(bool useConnectionString = false)
{ {
return new ConnectParams() return new ConnectParams()
{ {
OwnerUri = ScriptUri, OwnerUri = ScriptUri,
Connection = GetTestConnectionDetails() Connection = GetTestConnectionDetails(useConnectionString)
}; };
} }
@@ -66,8 +66,8 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Utility
ServerEdition = "Developer Edition", ServerEdition = "Developer Edition",
ServerLevel = "" ServerLevel = ""
}; };
} }
/// <summary> /// <summary>
/// Creates a test sql connection factory instance /// Creates a test sql connection factory instance
/// </summary> /// </summary>
@@ -80,8 +80,16 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Utility
/// <summary> /// <summary>
/// Creates a test connection details object /// Creates a test connection details object
/// </summary> /// </summary>
public static ConnectionDetails GetTestConnectionDetails() public static ConnectionDetails GetTestConnectionDetails(bool useConnectionString = false)
{ {
if (useConnectionString)
{
return new ConnectionDetails()
{
ConnectionString = "User ID=user;PWD=password;Database=databaseName;Server=serverName"
};
}
return new ConnectionDetails() return new ConnectionDetails()
{ {
UserName = "user", UserName = "user",
@@ -214,9 +222,9 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Utility
} }
public override string ConnectionString { get; set; } public override string ConnectionString { get; set; }
public override string Database public override string Database
{ {
get { return _database; } get { return _database; }
} }
public override ConnectionState State { get; } public override ConnectionState State { get; }
@@ -233,13 +241,13 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Utility
// No Op // No Op
} }
/// <summary> /// <summary>
/// Test helper method to set the database value /// Test helper method to set the database value
/// </summary> /// </summary>
/// <param name="database"></param> /// <param name="database"></param>
public void SetDatabase(string database) public void SetDatabase(string database)
{ {
this._database = database; this._database = database;
} }
} }