Added the ability to automate any c# scripts for an upgrade process. I realize this is superceded already in 6.0

but we need a way to do this in 4.x too especially for this release since we need to run a script to fix some db
issues. I've added a framework using an UpgradeScriptManager and another install step + unit tests for some of the
UpgradeScriptManager methods.
This commit is contained in:
Shannon Deminick
2013-01-31 04:26:37 +06:00
parent 97556de447
commit a5bea7fc59
22 changed files with 601 additions and 56 deletions

View File

@@ -181,6 +181,31 @@ namespace Umbraco.Core.Configuration
SaveSetting("umbracoConfigurationStatus", value);
}
}
/// <summary>
/// Returns the configuration status version as a versoin object or null if it cannot parse
/// </summary>
/// <returns></returns>
internal static Version GetConfigurationVersion()
{
//create a real version out of the one stored in the settings
var configVersion = ConfigurationStatus.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
if (configVersion.Length == 0)
return null;
int major;
var minor = 0;
var patch = 0;
int currentPart;
if (configVersion.Length > 0 && int.TryParse(configVersion[0], out currentPart))
major = currentPart;
else
return null; //couldn't parse, no valid version
if (configVersion.Length > 1 && int.TryParse(configVersion[1], out currentPart)) minor = currentPart;
if (configVersion.Length > 2 && int.TryParse(configVersion[2], out currentPart)) patch = currentPart;
return new Version(major, minor, patch);
}
/// <summary>
/// Saves a setting into the configuration file.

View File

@@ -0,0 +1,66 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using NUnit.Framework;
using Umbraco.Web.Install.UpgradeScripts;
namespace Umbraco.Tests.Install
{
[TestFixture]
public class UpgradeScriptsTests
{
[TearDown]
public void TearDown()
{
UpgradeScriptManager.Clear();
}
[TestCase("0.0.0", "6.0.0", "4.10.0", true)]
[TestCase("4.10.0", "6.0.0", "4.10.0", true)]
[TestCase("4.10.0", "4.11.4", "4.10.0", true)]
[TestCase("4.11.0", "4.11.4", "4.10.0", false)]
[TestCase("4.11.0", "6.0.0", "4.10.0", false)]
[TestCase("6.0.0", "6.0.0", "6.0.0", false)] //this is not in range because it is up to 6.0 but not including 6.0
[TestCase("6.0.0", "6.0.0", "6.0.1", false)]
public void Test_Version_Range(string startVersion, string endVersion, string current, bool inRange)
{
var currVersionParts = current.Split('.').Select(int.Parse).ToArray();
var currentVersion = new Version(currVersionParts[0], currVersionParts[1], currVersionParts[2]);
var startVersionParts = startVersion.Split('.').Select(int.Parse).ToArray();
var endVersionParts = endVersion.Split('.').Select(int.Parse).ToArray();
UpgradeScriptManager.AddUpgradeScript<UpgradeScript1>(
new VersionRange(
new Version(startVersionParts[0], startVersionParts[1], startVersionParts[2]),
new Version(endVersionParts[0], endVersionParts[1], endVersionParts[2])));
Assert.AreEqual(inRange, UpgradeScriptManager.HasScriptsForVersion(currentVersion));
}
[Test]
public void Test_Specific_Version()
{
var currentVersion = new Version(4, 10, 0);
UpgradeScriptManager.AddUpgradeScript<UpgradeScript1>(
new VersionRange(
new Version(4, 10, 0)));
Assert.IsTrue(UpgradeScriptManager.HasScriptsForVersion(currentVersion));
Assert.IsFalse(UpgradeScriptManager.HasScriptsForVersion(new Version(4, 10, 11)));
Assert.IsFalse(UpgradeScriptManager.HasScriptsForVersion(new Version(4, 11, 0)));
}
public class UpgradeScript1 : IUpgradeScript
{
public void Execute()
{
Debug.WriteLine("Executing!");
}
}
}
}

View File

@@ -63,6 +63,7 @@
<ItemGroup>
<Compile Include="BusinessLogic\DictionaryTest.cs" />
<Compile Include="ContentStores\PublishMediaStoreTests.cs" />
<Compile Include="Install\UpgradeScriptsTests.cs" />
<Compile Include="PublishedContent\DynamicXmlTests.cs" />
<Compile Include="PublishedContent\PublishedContentDataTableTests.cs" />
<Compile Include="PublishedContent\PublishedContentTests.cs" />

View File

@@ -289,6 +289,13 @@
<Compile Include="install\steps\Skinning\LoadStarterKits.ascx.designer.cs">
<DependentUpon>loadStarterKits.ascx</DependentUpon>
</Compile>
<Compile Include="install\steps\UpgradeScripts.ascx.cs">
<DependentUpon>UpgradeScripts.ascx</DependentUpon>
<SubType>ASPXCodeBehind</SubType>
</Compile>
<Compile Include="install\steps\UpgradeScripts.ascx.designer.cs">
<DependentUpon>UpgradeScripts.ascx</DependentUpon>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Umbraco\developer\Macros\EditMacro.aspx.cs">
<DependentUpon>editMacro.aspx</DependentUpon>
@@ -418,6 +425,7 @@
<DependentUpon>UI.xml</DependentUpon>
</None>
<Content Include="Global.asax" />
<Content Include="install\steps\UpgradeScripts.ascx" />
<Content Include="Umbraco\config\lang\en_us.xml" />
<Content Include="Umbraco\config\lang\he.xml" />
<Content Include="Umbraco\config\lang\ja.xml" />

View File

@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Umbraco.Core.Configuration;
using umbraco.presentation.install;
using Umbraco.Web.Install.UpgradeScripts;
namespace Umbraco.Web.UI.Install.Steps
{
public partial class UpgradeScripts : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void RunScripts(object sender, EventArgs e)
{
//run the scripts and then go to the next step
UpgradeScriptManager.ExecuteScriptsForVersion(GlobalSettings.GetConfigurationVersion());
Helper.RedirectToNextStep(Page);
}
}
}

View File

@@ -0,0 +1,24 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Umbraco.Web.UI.Install.Steps {
public partial class UpgradeScripts {
/// <summary>
/// btnNext control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.LinkButton btnNext;
}
}

View File

@@ -0,0 +1,130 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Umbraco.Core;
using Umbraco.Core.IO;
using umbraco.cms.businesslogic;
using umbraco.cms.businesslogic.web;
namespace Umbraco.Web.Install.UpgradeScripts
{
/// <summary>
/// An upgrade script to fix a moving issue in 4.10+
/// http://issues.umbraco.org/issue/U4-1491
/// </summary>
public class ContentPathFix : IUpgradeScript
{
private readonly StringBuilder _report = new StringBuilder();
public void Execute()
{
//return;
if (ApplicationContext.Current == null) return;
if (HasBeenFixed()) return;
Fix();
WriteReport();
}
private void Fix()
{
AddReportLine("Starting fix paths script");
//fix content
AddReportLine("Fixing content");
foreach (var d in Document.GetRootDocuments())
{
FixPathsForChildren(d, content => ((Document)content).Children);
}
AddReportLine("Fixing content recycle bin");
var contentRecycleBin = new RecycleBin(RecycleBin.RecycleBinType.Content);
foreach (var d in contentRecycleBin.Children)
{
FixPathsForChildren(new Document(d.Id), content => ((Document)content).Children);
}
//fix media
AddReportLine("Fixing media");
foreach (var d in global::umbraco.cms.businesslogic.media.Media.GetRootMedias())
{
FixPathsForChildren(d, media => ((global::umbraco.cms.businesslogic.media.Media)media).Children);
}
AddReportLine("Fixing media recycle bin");
var mediaRecycleBin = new RecycleBin(RecycleBin.RecycleBinType.Media);
foreach (var d in mediaRecycleBin.Children)
{
FixPathsForChildren(new global::umbraco.cms.businesslogic.media.Media(d.Id), media => ((global::umbraco.cms.businesslogic.media.Media)media).Children);
}
AddReportLine("Complete!");
}
/// <summary>
/// Returns true if this script has run based on a temp file written to
/// ~/App_Data/TEMP/FixPaths/report.txt
/// </summary>
/// <returns></returns>
private bool HasBeenFixed()
{
return File.Exists(IOHelper.MapPath("~/App_Data/TEMP/FixPaths/report.txt"));
}
/// <summary>
/// Creates the report
/// </summary>
private void WriteReport()
{
var filePath = IOHelper.MapPath("~/App_Data/TEMP/FixPaths/report.txt");
Directory.CreateDirectory(Path.GetDirectoryName(filePath));
using (var writer = File.CreateText(IOHelper.MapPath("~/App_Data/TEMP/FixPaths/report.txt")))
{
writer.Write(_report.ToString());
}
}
/// <summary>
/// Recursively iterates over the children of the document and fixes the path
/// </summary>
/// <param name="d"></param>
/// <param name="getChildren">Callback to get the children of the conent item</param>
/// <remarks>
/// We cannot use GetDescendants() because that is based on the paths of documents and if they are invalid then
/// we cannot use that method.
/// </remarks>
private void FixPathsForChildren(Content d, Func<Content, IEnumerable<Content>> getChildren)
{
AddReportLine("Fixing paths for children of " + d.Id);
foreach (var c in getChildren(d))
{
FixPath(c);
if (c.HasChildren)
{
FixPathsForChildren(c, getChildren);
}
}
}
/// <summary>
/// Check if the path is correct based on the document's parent if it is not correct, then fix it
/// </summary>
/// <param name="d"></param>
private void FixPath(CMSNode d)
{
AddReportLine("Checking path for " + d.Id + ". Current = " + d.Path);
//check if the path is correct
var correctpath = d.Parent.Path + "," + d.Id.ToString();
if (d.Path != correctpath)
{
AddReportLine(" INVALID PATH DETECTED. Path for " + d.Id + " changed to: " + d.Parent.Path + "," + d.Id.ToString());
d.Path = correctpath;
d.Level = d.Parent.Level + 1;
}
}
private void AddReportLine(string str)
{
_report.AppendLine(string.Format("{0} - " + str, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")));
}
}
}

View File

@@ -0,0 +1,7 @@
namespace Umbraco.Web.Install.UpgradeScripts
{
internal interface IUpgradeScript
{
void Execute();
}
}

View File

@@ -0,0 +1,84 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Configuration;
using umbraco.DataLayer.Utility.Installer;
namespace Umbraco.Web.Install.UpgradeScripts
{
/// <summary>
/// Class used to register and execute upgrade scripts during install if they are required.
/// </summary>
internal static class UpgradeScriptManager
{
/// <summary>
/// Returns true if there are scripts to execute for the version
/// </summary>
/// <param name="version"></param>
/// <returns></returns>
public static bool HasScriptsForVersion(Version version)
{
return Scripts.Any(x => x.Item2.InRange(version));
}
/// <summary>
/// Executes all of the scripts for a database version
/// </summary>
/// <param name="version"></param>
/// <returns></returns>
public static void ExecuteScriptsForVersion(Version version)
{
var types = Scripts.Where(x => x.Item2.InRange(version)).Select(x => x.Item1);
foreach (var instance in types.Select(x => x()))
{
instance.Execute();
}
}
public static void AddUpgradeScript(Func<IUpgradeScript> script, VersionRange version)
{
Scripts.Add(new Tuple<Func<IUpgradeScript>, VersionRange>(script, version));
}
///// <summary>
///// Adds a script to execute for a database version
///// </summary>
///// <param name="assemblyQualifiedTypeName"></param>
///// <param name="version"></param>
//public static void AddUpgradeScript(string assemblyQualifiedTypeName, VersionRange version)
//{
// AddUpgradeScript(new Lazy<Type>(() => Type.GetType(assemblyQualifiedTypeName)), version);
//}
///// <summary>
///// Adds a script to execute for a database version
///// </summary>
///// <typeparam name="T"></typeparam>
///// <param name="version"></param>
//public static void AddUpgradeScript<T>(VersionRange version)
//{
// AddUpgradeScript(new Lazy<Type>(() => typeof(T)), version);
//}
/// <summary>
/// Used for testing
/// </summary>
internal static void Clear()
{
Scripts.Clear();
}
///// <summary>
///// Adds a script to execute for a database version
///// </summary>
///// <param name="type"></param>
///// <param name="version"></param>
//public static void AddUpgradeScript(Lazy<Type> type, VersionRange version)
//{
// Scripts.Add(new Tuple<Lazy<Type>, VersionRange>(type, version));
//}
private static readonly List<Tuple<Func<IUpgradeScript>, VersionRange>> Scripts = new List<Tuple<Func<IUpgradeScript>, VersionRange>>();
//private static readonly List<Tuple<Lazy<Type>, VersionRange>> Scripts = new List<Tuple<Lazy<Type>, VersionRange>>();
}
}

View File

@@ -0,0 +1,28 @@
using System;
using Umbraco.Core;
namespace Umbraco.Web.Install.UpgradeScripts
{
internal class UpgradeScriptRegistrar : IApplicationEventHandler
{
public void OnApplicationInitialized(UmbracoApplication httpApplication, ApplicationContext applicationContext)
{
//Add contnet path fixup for any version from 4.10 up to 4.11.4
UpgradeScriptManager.AddUpgradeScript(
() => new ContentPathFix(),
new VersionRange(
new Version(4, 10),
new Version(4, 11, 4)));
}
public void OnApplicationStarting(UmbracoApplication httpApplication, ApplicationContext applicationContext)
{
}
public void OnApplicationStarted(UmbracoApplication httpApplication, ApplicationContext applicationContext)
{
}
}
}

View File

@@ -0,0 +1,40 @@
using System;
namespace Umbraco.Web.Install.UpgradeScripts
{
internal class VersionRange
{
private readonly Version _specificVersion;
private readonly Version _startVersion;
private readonly Version _endVersion;
public VersionRange(Version specificVersion)
{
_specificVersion = specificVersion;
}
public VersionRange(Version startVersion, Version endVersion)
{
_startVersion = startVersion;
_endVersion = endVersion;
}
/// <summary>
/// Checks if the versionCheck is in the range (in between) the start and end version
/// </summary>
/// <param name="versionCheck"></param>
/// <returns></returns>
/// <remarks>
/// For example if our version range is 4.10 -> 4.11.4, we want to return true if the version being checked is:
/// greater than or equal to the start version but less than the end version.
/// </remarks>
public bool InRange(Version versionCheck)
{
//if it is a specific version
if (_specificVersion != null)
return versionCheck == _specificVersion;
return versionCheck >= _startVersion && versionCheck < _endVersion;
}
}
}

View File

@@ -30,3 +30,4 @@ using System.Security;
[assembly: InternalsVisibleTo("Umbraco.Tests")]
[assembly: InternalsVisibleTo("umbraco.MacroEngines")]
[assembly: InternalsVisibleTo("umbraco.webservices")]
[assembly: InternalsVisibleTo("Umbraco.Web.UI")]

View File

@@ -252,6 +252,11 @@
<Compile Include="Dynamics\Grouping.cs" />
<Compile Include="Install\InstallPackageController.cs" />
<Compile Include="Install\UmbracoInstallAuthorizeAttribute.cs" />
<Compile Include="Install\UpgradeScripts\ContentPathFix.cs" />
<Compile Include="Install\UpgradeScripts\IUpgradeScript.cs" />
<Compile Include="Install\UpgradeScripts\UpgradeScriptRegistrar.cs" />
<Compile Include="Install\UpgradeScripts\UpgradeScriptManager.cs" />
<Compile Include="Install\UpgradeScripts\VersionRange.cs" />
<Compile Include="Macros\PartialViewMacroController.cs" />
<Compile Include="Macros\PartialViewMacroEngine.cs" />
<Compile Include="Macros\PartialViewMacroPage.cs" />
@@ -329,6 +334,7 @@
<Compile Include="umbraco.presentation\install\Default.aspx.cs">
<SubType>ASPXCodeBehind</SubType>
</Compile>
<Compile Include="umbraco.presentation\install\steps\Definitions\UpgradeScripts.cs" />
<Compile Include="umbraco.presentation\install\steps\Skinning\loadStarterKitDesigns.ascx.cs">
<SubType>ASPXCodeBehind</SubType>
</Compile>
@@ -1894,7 +1900,9 @@
<SubType>ASPXCodeBehind</SubType>
</Content>
<Content Include="umbraco.presentation\umbraco\controls\Tree\TreeControl.ascx" />
<Content Include="umbraco.presentation\install\steps\license.ascx" />
<Content Include="umbraco.presentation\install\steps\license.ascx">
<SubType>ASPXCodeBehind</SubType>
</Content>
<Content Include="umbraco.presentation\umbraco\actions\delete.aspx" />
<Content Include="umbraco.presentation\umbraco\actions\editContent.aspx" />
<Content Include="umbraco.presentation\umbraco\actions\preview.aspx" />

View File

@@ -9,6 +9,7 @@ using Umbraco.Core.Dictionary;
using Umbraco.Core.Dynamics;
using Umbraco.Core.PropertyEditors;
using Umbraco.Web.Dictionary;
using Umbraco.Web.Install.UpgradeScripts;
using Umbraco.Web.Media;
using Umbraco.Web.Media.ThumbnailProviders;
using Umbraco.Web.Models;
@@ -90,6 +91,7 @@ namespace Umbraco.Web
//add the internal types since we don't want to mark these public
ApplicationEventsResolver.Current.AddType<CacheHelperExtensions.CacheHelperApplicationEventListener>();
ApplicationEventsResolver.Current.AddType<LegacyScheduledTasks>();
ApplicationEventsResolver.Current.AddType<UpgradeScriptRegistrar>();
//now we need to call the initialize methods
ApplicationEventsResolver.Current.ApplicationEventHandlers

View File

@@ -9,7 +9,7 @@ using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Collections.Specialized;
using umbraco.IO;
using Umbraco.Core.IO;
using umbraco.cms.businesslogic.installer;
using System.Collections.Generic;
@@ -36,7 +36,7 @@ namespace umbraco.presentation.install
private void loadContent(InstallerStep currentStep)
{
PlaceHolderStep.Controls.Clear();
PlaceHolderStep.Controls.Add(new System.Web.UI.UserControl().LoadControl(IOHelper.ResolveUrl(currentStep.UserControl)));
PlaceHolderStep.Controls.Add(LoadControl(IOHelper.ResolveUrl(currentStep.UserControl)));
step.Value = currentStep.Alias;
currentStepClass = currentStep.Alias;
}
@@ -136,6 +136,7 @@ namespace umbraco.presentation.install
ics.Add(new install.steps.Definitions.Welcome());
ics.Add(new install.steps.Definitions.License());
ics.Add(new install.steps.Definitions.FilePermissions());
ics.Add(new install.steps.Definitions.UpgradeScripts());
ics.Add(new install.steps.Definitions.Database());
ics.Add(new install.steps.Definitions.DefaultUser());
ics.Add(new install.steps.Definitions.Skinning());

View File

@@ -1,9 +1,9 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Umbraco.Core.IO;
using umbraco.cms.businesslogic.installer;
using umbraco.IO;
using umbraco.DataLayer.Utility.Installer;
using umbraco.DataLayer;
@@ -18,7 +18,7 @@ namespace umbraco.presentation.install.steps.Definitions
public override string Name
{
get { return "Database"; }
get { return "Database"; }
}
public override string UserControl
@@ -26,7 +26,7 @@ namespace umbraco.presentation.install.steps.Definitions
get { return SystemDirectories.Install + "/steps/database.ascx"; }
}
public override bool MoveToNextStepAutomaticly
{
get
@@ -38,13 +38,14 @@ namespace umbraco.presentation.install.steps.Definitions
//here we determine if the installer should skip this step...
public override bool Completed()
{
bool retval = false;
bool retval;
try
{
IInstallerUtility m_Installer = BusinessLogic.Application.SqlHelper.Utility.CreateInstaller();
retval = m_Installer.IsLatestVersion;
m_Installer = null;
} catch {
var installer = BusinessLogic.Application.SqlHelper.Utility.CreateInstaller();
retval = installer.IsLatestVersion;
}
catch
{
// this step might fail due to missing connectionstring
return false;
}
@@ -52,6 +53,6 @@ namespace umbraco.presentation.install.steps.Definitions
return retval;
}
}
}

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Umbraco.Core.IO;
using umbraco.cms.businesslogic.installer;
namespace umbraco.presentation.install.steps.Definitions
@@ -20,7 +21,7 @@ namespace umbraco.presentation.install.steps.Definitions
public override string UserControl
{
get { return IO.SystemDirectories.Install + "/steps/validatepermissions.ascx"; }
get { return SystemDirectories.Install + "/steps/validatepermissions.ascx"; }
}
public override bool HideFromNavigation {

View File

@@ -0,0 +1,78 @@
using System;
using Umbraco.Core;
using Umbraco.Core.IO;
using Umbraco.Web.Install.UpgradeScripts;
using umbraco.DataLayer.Utility.Installer;
using umbraco.cms.businesslogic.installer;
namespace umbraco.presentation.install.steps.Definitions
{
internal class UpgradeScripts : InstallerStep
{
public override string Alias
{
get { return "upgradeScripts"; }
}
public override bool HideFromNavigation
{
get { return true; }
}
/// <summary>
/// If there are no scripts for this version the skip
/// </summary>
/// <returns></returns>
public override bool Completed()
{
var canConnect = CanConnectToDb();
//if we cannot connect to the db, then we cannot run the script and most likely the database doesn't exist yet anyways.
if (!canConnect) return true; //skip
//if the version is empty then it's probably a new installation, we cannot run scripts
if (GlobalSettings.CurrentVersion.IsNullOrWhiteSpace()) return true; //skip
var currentUmbVersion = Umbraco.Core.Configuration.GlobalSettings.GetConfigurationVersion();
if (currentUmbVersion == null)
return true; //skip, could not get a version
//check if we have upgrade script to run for this version
var hasScripts = UpgradeScriptManager.HasScriptsForVersion(currentUmbVersion);
return !hasScripts;
}
public override string Name
{
get { return "Upgrade scripts"; }
}
public override string UserControl
{
get { return SystemDirectories.Install + "/steps/UpgradeScripts.ascx"; }
}
public override bool MoveToNextStepAutomaticly
{
get
{
return true;
}
}
private bool CanConnectToDb()
{
try
{
var installer = BusinessLogic.Application.SqlHelper.Utility.CreateInstaller();
var latest = installer.IsLatestVersion;
return true; //if we got this far, we can connect.
}
catch
{
return false;
}
}
}
}

View File

@@ -4,6 +4,7 @@ using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Umbraco.Web.Install.UpgradeScripts;
using umbraco.DataLayer.Utility.Installer;
using umbraco.DataLayer;
@@ -97,6 +98,8 @@ namespace umbraco.presentation.install.utills
Helper.setProgress(100, "Database is up-to-date", "");
return "upgraded";
}
else
{
@@ -136,6 +139,7 @@ namespace umbraco.presentation.install.utills
installer = null;
library.RefreshContent();
return "upgraded";
}
}
@@ -146,5 +150,8 @@ namespace umbraco.presentation.install.utills
return "no connection;";
}
}
}

View File

@@ -261,45 +261,5 @@ namespace umbraco.DataLayer.Utility.Installer
#endregion
}
/// <summary>
/// A triple (Field, Table, Version) meaning:
/// if a <c>SELECT</c> statement of <c>Field FROM Table</c> succeeds,
/// the database version is at least <c>Version</c>.
/// </summary>
/// <remarks>
/// This also supports checking for a value in a table.
/// </remarks>
public struct VersionSpecs
{
/// <summary>The SQL statament to execute in order to test for the specified version</summary>
public readonly string Sql;
/// <summary>An integer identifying the expected row count from the Sql statement</summary>
public readonly int ExpectedRows;
/// <summary>The minimum version number of a database that contains the specified field.</summary>
public readonly DatabaseVersion Version;
/// <summary>
/// Initializes a new instance of the <see cref="VersionSpecs"/> struct.
/// </summary>
/// <param name="sql">The sql statement to execute.</param>
/// <param name="version">The version.</param>
public VersionSpecs(string sql, DatabaseVersion version)
: this(sql, -1, version)
{ }
/// <summary>
/// Initializes a new instance of the <see cref="VersionSpecs"/> struct.
/// </summary>
/// <param name="sql">The sql statement to execute.</param>
/// <param name="expectedRows">The expected row count.</param>
/// <param name="version">The version.</param>
public VersionSpecs(string sql, int expectedRows, DatabaseVersion version)
{
Sql = sql;
ExpectedRows = expectedRows;
Version = version;
}
}
}

View File

@@ -0,0 +1,44 @@
namespace umbraco.DataLayer.Utility.Installer
{
/// <summary>
/// A triple (Field, Table, Version) meaning:
/// if a <c>SELECT</c> statement of <c>Field FROM Table</c> succeeds,
/// the database version is at least <c>Version</c>.
/// </summary>
/// <remarks>
/// This also supports checking for a value in a table.
/// </remarks>
public struct VersionSpecs
{
/// <summary>The SQL statament to execute in order to test for the specified version</summary>
public readonly string Sql;
/// <summary>An integer identifying the expected row count from the Sql statement</summary>
public readonly int ExpectedRows;
/// <summary>The minimum version number of a database that contains the specified field.</summary>
public readonly DatabaseVersion Version;
/// <summary>
/// Initializes a new instance of the <see cref="VersionSpecs"/> struct.
/// </summary>
/// <param name="sql">The sql statement to execute.</param>
/// <param name="version">The version.</param>
public VersionSpecs(string sql, DatabaseVersion version)
: this(sql, -1, version)
{ }
/// <summary>
/// Initializes a new instance of the <see cref="VersionSpecs"/> struct.
/// </summary>
/// <param name="sql">The sql statement to execute.</param>
/// <param name="expectedRows">The expected row count.</param>
/// <param name="version">The version.</param>
public VersionSpecs(string sql, int expectedRows, DatabaseVersion version)
{
Sql = sql;
ExpectedRows = expectedRows;
Version = version;
}
}
}

View File

@@ -117,6 +117,7 @@
<Compile Include="Utility\BaseUtility.cs" />
<Compile Include="Utility\Installer\DatabaseVersion.cs" />
<Compile Include="Utility\Installer\DefaultInstallerUtility.cs" />
<Compile Include="Utility\Installer\VersionSpecs.cs" />
<Compile Include="Utility\Table\DefaultField.cs" />
<Compile Include="Utility\Table\DefaultTable.cs" />
<Compile Include="Utility\Table\FieldProperties.cs" />