Add scripting API implemented by the SqlScriptPublishModel (#316)

Update the ScriptingService to expose new scripting JSON-RPC APIs that use the SqlScriptPublishModel for script generation.

The SqlScriptPublishModel is the model behind the SSMS scripting wizard. To enable scripting for CLI tools, we've ported SqlScriptPublishModel to .NET Core. The SqlScriptPublishModel wraps the SMO scripting APIs for .sql script generation.

1) Added three new requests to the ScriptingService: ScriptingRequest, ScriptingListObjectsRequest, ScriptingCancelRequest.
2) Generating scripts are long running operations, so the ScriptingRequest and ScriptingListObjectsRequest kick off a long running scripting task and return immediately.
3) Long running scripting task reports progress and completion, and can be cancelled by a ScriptingCancelRequest request.
4) Bumped the SMO nuget package to 140.17049.0. This new version contains a signed SSMS_Rel build of SMO with the SqlScriptPublishModel.
5) For testing, adding the Northwind database schema

TODO (in later pull requests)
1) Integrate the new ScriptingService APIs with the ConnectionService
2) Integrate with the metadata support recently added
This commit is contained in:
Brian O'Neill
2017-04-24 16:10:20 -07:00
committed by GitHub
parent e65699ef75
commit 4aac4a4047
42 changed files with 7124 additions and 30 deletions

View File

@@ -0,0 +1,101 @@
//
// 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.Linq;
using System.Threading.Tasks;
using Microsoft.SqlServer.Management.Sdk.Sfc;
using Microsoft.SqlServer.Management.SqlScriptPublish;
using Microsoft.SqlTools.ServiceLayer.Scripting.Contracts;
using Microsoft.SqlTools.Utility;
namespace Microsoft.SqlTools.ServiceLayer.Scripting
{
/// <summary>
/// Extension methods used by the scripting service.
/// </summary>
internal static class ScriptingExtensionMethods
{
/// <summary>
/// Returns a list of ScriptingObject instances for the passed SqlScriptPublishModel instance.
/// </summary>
/// <param name="publishModel">The sql script publish model instance.</param>
/// <returns>The list of scripting objects.</returns>
public static List<ScriptingObject> GetDatabaseObjects(this SqlScriptPublishModel publishModel)
{
Validate.IsNotNull("publishModel", publishModel);
List<ScriptingObject> databaseObjects = new List<ScriptingObject>();
IEnumerable<DatabaseObjectType> objectTypes = publishModel.GetDatabaseObjectTypes();
Logger.Write(
LogLevel.Verbose,
string.Format(
"Loaded SMO object type count {0}, types: {1}",
objectTypes.Count(),
string.Join(", ", objectTypes)));
foreach (DatabaseObjectType objectType in objectTypes)
{
IEnumerable<KeyValuePair<string, string>> databaseObjectsOfType = publishModel.EnumChildrenForDatabaseObjectType(objectType);
Logger.Write(
LogLevel.Verbose,
string.Format(
"Loaded SMO urn object count {0} for type {1}, urns: {2}",
objectType,
databaseObjectsOfType.Count(),
string.Join(", ", databaseObjectsOfType.Select(p => p.Value))));
databaseObjects.AddRange(databaseObjectsOfType.Select(d => new Urn(d.Value).ToScriptingObject()));
}
return databaseObjects;
}
/// <summary>
/// Creates a SMO Urn instance based on the passed ScriptingObject instance.
/// </summary>
/// <param name="scriptingObject">The scripting object instance.</param>
/// <param name="database">The name of the database referenced by the Urn.</param>
/// <returns>The Urn instance.</returns>
public static Urn ToUrn(this ScriptingObject scriptingObject, string database)
{
Validate.IsNotNull("scriptingObject", scriptingObject);
Validate.IsNotNullOrWhitespaceString("database", database);
Validate.IsNotNullOrWhitespaceString("scriptingObject.Name", scriptingObject.Name);
Validate.IsNotNullOrWhitespaceString("scriptingObject.Type", scriptingObject.Type);
// Leaving the server name blank will automatically match whatever the server SMO is running against.
string urn = string.Format(
"Server/Database[@Name='{0}']/{1}[@Name='{2}' {3}]",
database,
scriptingObject.Type,
scriptingObject.Name,
scriptingObject.Schema != null ? string.Format("and @Schema = '{0}'", scriptingObject.Schema) : string.Empty);
return new Urn(urn);
}
/// <summary>
/// Creates a ScriptingObject instance based on the passed SMO Urn instance.
/// </summary>
/// <param name="urn">The urn instance.</param>
/// <returns>The scripting object instance.</returns>
public static ScriptingObject ToScriptingObject(this Urn urn)
{
Validate.IsNotNull("urn", urn);
return new ScriptingObject
{
Type = urn.Type,
Schema = urn.GetAttribute("Schema"),
Name = urn.GetAttribute("Name"),
};
}
}
}