Created
July 21, 2011 22:39
-
-
Save jagregory/1098406 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Index: src/FluentNHibernate.Testing/DatabaseObjects/FluentIndex/FluentIndexBaseTests.cs | |
=================================================================== | |
--- src/FluentNHibernate.Testing/DatabaseObjects/FluentIndex/FluentIndexBaseTests.cs (revision 0) | |
+++ src/FluentNHibernate.Testing/DatabaseObjects/FluentIndex/FluentIndexBaseTests.cs (revision 0) | |
@@ -0,0 +1,64 @@ | |
+using System.Text.RegularExpressions; | |
+using FluentNHibernate.Cfg; | |
+using FluentNHibernate.Cfg.Db; | |
+using FluentNHibernate.DatabaseObjects.FluentIndex; | |
+using FluentNHibernate.Testing.DomainModel; | |
+using NHibernate.Cfg; | |
+using NHibernate.Dialect; | |
+using NHibernate.Engine; | |
+using NUnit.Framework; | |
+using Rhino.Mocks; | |
+ | |
+namespace FluentNHibernate.Testing.DatabaseObjects.FluentIndex | |
+{ | |
+ [TestFixture] | |
+ public class FluentIndexBaseTests : FluentIndexBase | |
+ { | |
+ static readonly Configuration config = Fluently.Configure() | |
+ .Database(SQLiteConfiguration.Standard.InMemory) | |
+ .Mappings(m => | |
+ m.FluentMappings.AddFromAssemblyOf<Record>()) | |
+ .BuildConfiguration(); | |
+ | |
+ private readonly Dialect dialect = MockRepository.GenerateStub<Dialect>(); | |
+ private readonly IMapping mapping = MockRepository.GenerateStub<IMapping>(); | |
+ | |
+ readonly Regex createClustered = new Regex("(CREATE).*?(CLUSTERED).*?(Record)(_)(id).*?(schema).*?(Record).*?(id).*?(ASC)"); | |
+ readonly Regex createUniqueNonclustered = new Regex("(CREATE).*?(UNIQUE)( )(NONCLUSTERED).*?(Record)(_)(Name).*?(schema).*?(Record).*?(Name).*?(ASC)"); | |
+ readonly Regex createNonclustered = new Regex("(CREATE).*?(NONCLUSTERED).*?(SuperRecord)(_)(Type).*?(schema).*?(SuperRecord).*?(Type).*?(ASC)"); | |
+ | |
+ readonly Regex dropClustered = new Regex("(DROP).*?(Record)(_)(id).*?(schema).*?(Record)"); | |
+ readonly Regex dropUniqueNonclustered = new Regex("(DROP).*?(Record)(_)(Name).*?(schema).*?(Record)"); | |
+ readonly Regex dropNonclustered = new Regex("(DROP).*?(SuperRecord)(_)(Type).*?(schema).*?(SuperRecord)"); | |
+ | |
+ public FluentIndexBaseTests() : this(config) { } | |
+ | |
+ public FluentIndexBaseTests(Configuration configuration) | |
+ : base(configuration) | |
+ { | |
+ ClusteredIndex<Record>().OnPrimaryKey(); | |
+ UniqueNonClusteredIndex<Record>().OnProperty(x => x.Name); | |
+ NonClusteredIndex<ChildRecord>().OnDiscriminator(); | |
+ } | |
+ | |
+ [Test] | |
+ public void SqlCreateStringGeneratesExpectedIndexes() | |
+ { | |
+ string indexes = SqlCreateString(dialect, mapping, "catalog", "schema"); | |
+ | |
+ createClustered.Match(indexes).Success.ShouldBeTrue(); | |
+ createUniqueNonclustered.Match(indexes).Success.ShouldBeTrue(); | |
+ createNonclustered.Match(indexes).Success.ShouldBeTrue(); | |
+ } | |
+ | |
+ [Test] | |
+ public void SqlDropStringGeneratesExpectedIndexes() | |
+ { | |
+ string indexes = SqlDropString(dialect, "catalog", "schema"); | |
+ | |
+ dropClustered.Match(indexes).Success.ShouldBeTrue(); | |
+ dropUniqueNonclustered.Match(indexes).Success.ShouldBeTrue(); | |
+ dropNonclustered.Match(indexes).Success.ShouldBeTrue(); | |
+ } | |
+ } | |
+} | |
Index: src/FluentNHibernate.Testing/DatabaseObjects/FluentIndex/IndexTests.cs | |
=================================================================== | |
--- src/FluentNHibernate.Testing/DatabaseObjects/FluentIndex/IndexTests.cs (revision 0) | |
+++ src/FluentNHibernate.Testing/DatabaseObjects/FluentIndex/IndexTests.cs (revision 0) | |
@@ -0,0 +1,91 @@ | |
+using FluentNHibernate.Cfg; | |
+using FluentNHibernate.Cfg.Db; | |
+using FluentNHibernate.DatabaseObjects.FluentIndex; | |
+using FluentNHibernate.Testing.DomainModel; | |
+using NHibernate.Cfg; | |
+using NHibernate.Dialect; | |
+using NUnit.Framework; | |
+using Rhino.Mocks; | |
+ | |
+namespace FluentNHibernate.Testing.DatabaseObjects.FluentIndex | |
+{ | |
+ [TestFixture] | |
+ public class IndexTests | |
+ { | |
+ private Configuration config; | |
+ private readonly Dialect dialect = MockRepository.GenerateStub<Dialect>(); | |
+ | |
+ [TestFixtureSetUp] | |
+ public void SetUpFixture() | |
+ { | |
+ config = Fluently.Configure() | |
+ .Database(SQLiteConfiguration.Standard.InMemory) | |
+ .Mappings(m => | |
+ m.FluentMappings.AddFromAssemblyOf<Record>()) | |
+ .BuildConfiguration(); | |
+ } | |
+ | |
+ [Test] | |
+ public void IndexResolvesCorrectTable() | |
+ { | |
+ var index = new Index<Record>(IndexType.Clustered, config); | |
+ index.OnPrimaryKey(); | |
+ | |
+ index.Table.ShouldContain("Record"); | |
+ } | |
+ | |
+ [Test] | |
+ public void IndexResolvesCorrectShortTable() | |
+ { | |
+ var index = new Index<Record>(IndexType.Clustered, config); | |
+ index.OnPrimaryKey(); | |
+ | |
+ index.ShortTable.ShouldEqual("Record"); | |
+ } | |
+ | |
+ [Test] | |
+ public void OnPrimaryKeyResolvesCorrectColumn() | |
+ { | |
+ var index = new Index<Record>(IndexType.Clustered, config); | |
+ index.OnPrimaryKey(); | |
+ | |
+ index.Column.ShouldEqual("id"); | |
+ } | |
+ | |
+ [Test] | |
+ public void OnPropertyResolvesCorrectColumn() | |
+ { | |
+ var index = new Index<Record>(IndexType.Clustered, config); | |
+ index.OnProperty(x => x.Name); | |
+ | |
+ index.Column.ShouldEqual("Name"); | |
+ } | |
+ | |
+ [Test] | |
+ public void OnDiscriminatorResolvesCorrectColumn() | |
+ { | |
+ var index = new Index<ChildRecord>(IndexType.Clustered, config); | |
+ index.OnDiscriminator(); | |
+ | |
+ index.Column.ShouldEqual("Type"); | |
+ } | |
+ | |
+ [Test] | |
+ public void Ascending() | |
+ { | |
+ var index = new Index<Record>(IndexType.Clustered, config); | |
+ index.OnPrimaryKey().Ascending(); | |
+ | |
+ index.GetCreateString(dialect, "catalog", "schema").ShouldContain("ASC"); | |
+ } | |
+ | |
+ [Test] | |
+ public void Descending() | |
+ { | |
+ var index = new Index<Record>(IndexType.Clustered, config); | |
+ index.OnPrimaryKey().Descending(); | |
+ | |
+ index.GetCreateString(dialect, "catalog", "schema").ShouldContain("DESC"); | |
+ } | |
+ } | |
+} | |
Index: src/FluentNHibernate.Testing/FluentNHibernate.Testing.csproj | |
=================================================================== | |
--- src/FluentNHibernate.Testing/FluentNHibernate.Testing.csproj (revision 423) | |
+++ src/FluentNHibernate.Testing/FluentNHibernate.Testing.csproj (working copy) | |
@@ -3,7 +3,7 @@ | |
<PropertyGroup> | |
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> | |
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> | |
- <ProductVersion>9.0.30729</ProductVersion> | |
+ <ProductVersion>9.0.21022</ProductVersion> | |
<SchemaVersion>2.0</SchemaVersion> | |
<ProjectGuid>{F5DC3221-827E-4CB4-B61C-5F50EB4D32EA}</ProjectGuid> | |
<OutputType>Library</OutputType> | |
@@ -125,6 +125,8 @@ | |
<Compile Include="ConventionsTests\SubclassDiscoveryConventionTester.cs" /> | |
<Compile Include="ConventionsTests\SubclassMappingPartDiscoveryConventionTester.cs" /> | |
<Compile Include="ConventionsTests\VersionDiscoveryConventionTester.cs" /> | |
+ <Compile Include="DatabaseObjects\FluentIndex\FluentIndexBaseTests.cs" /> | |
+ <Compile Include="DatabaseObjects\FluentIndex\IndexTests.cs" /> | |
<Compile Include="DomainModel\Mapping\ClassMapConventionsTester.cs" /> | |
<Compile Include="DomainModel\Mapping\ClassMapDynamicInsertTester.cs" /> | |
<Compile Include="DomainModel\Mapping\ClassMapDynamicUpdateTester.cs" /> | |
Index: src/FluentNHibernate.Testing/FluentNHibernate.Testing.csproj.user | |
=================================================================== | |
--- src/FluentNHibernate.Testing/FluentNHibernate.Testing.csproj.user (revision 423) | |
+++ src/FluentNHibernate.Testing/FluentNHibernate.Testing.csproj.user (working copy) | |
@@ -1,5 +1,5 @@ | |
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |
<PropertyGroup> | |
- <ProjectView>ShowAllFiles</ProjectView> | |
+ <ProjectView>ProjectFiles</ProjectView> | |
</PropertyGroup> | |
</Project> | |
\ No newline at end of file | |
Index: src/FluentNHibernate/DatabaseObjects/FluentIndex/FluentIndexBase.cs | |
=================================================================== | |
--- src/FluentNHibernate/DatabaseObjects/FluentIndex/FluentIndexBase.cs (revision 0) | |
+++ src/FluentNHibernate/DatabaseObjects/FluentIndex/FluentIndexBase.cs (revision 0) | |
@@ -0,0 +1,57 @@ | |
+using System.Collections.Generic; | |
+using System.Text; | |
+using NHibernate.Cfg; | |
+using NHibernate.Dialect; | |
+using NHibernate.Engine; | |
+using NHibernate.Mapping; | |
+ | |
+namespace FluentNHibernate.DatabaseObjects.FluentIndex | |
+{ | |
+ public abstract class FluentIndexBase : AbstractAuxiliaryDatabaseObject | |
+ { | |
+ private readonly IList<IIndex> indexes = new List<IIndex>(); | |
+ private readonly Configuration configuration; | |
+ | |
+ protected FluentIndexBase(Configuration configuration) | |
+ { | |
+ this.configuration = configuration; | |
+ } | |
+ | |
+ protected IIndexIncomplete<T> ClusteredIndex<T>() | |
+ { | |
+ Index<T> index = new Index<T>(IndexType.Clustered, configuration); | |
+ indexes.Add(index); | |
+ return index; | |
+ } | |
+ | |
+ protected IIndexIncomplete<T> NonClusteredIndex<T>() | |
+ { | |
+ Index<T> index = new Index<T>(IndexType.NonClustered, configuration); | |
+ indexes.Add(index); | |
+ return index; | |
+ } | |
+ | |
+ protected IIndexIncomplete<T> UniqueNonClusteredIndex<T>() | |
+ { | |
+ Index<T> index = new Index<T>(IndexType.NonClusteredUnique, configuration); | |
+ indexes.Add(index); | |
+ return index; | |
+ } | |
+ | |
+ public override string SqlCreateString(Dialect d, IMapping p, string defaultCatalog, string defaultSchema) | |
+ { | |
+ StringBuilder sb = new StringBuilder(); | |
+ foreach (var index in indexes) | |
+ { sb.AppendLine(index.GetCreateString(d, defaultCatalog, defaultSchema)); } | |
+ return sb.ToString(); | |
+ } | |
+ | |
+ public override string SqlDropString(Dialect d, string defaultCatalog, string defaultSchema) | |
+ { | |
+ StringBuilder sb = new StringBuilder(); | |
+ foreach (var index in indexes) | |
+ { sb.AppendLine(index.GetDropString(d, defaultCatalog, defaultSchema)); } | |
+ return sb.ToString(); | |
+ } | |
+ } | |
+} | |
\ No newline at end of file | |
Index: src/FluentNHibernate/DatabaseObjects/FluentIndex/Index.cs | |
=================================================================== | |
--- src/FluentNHibernate/DatabaseObjects/FluentIndex/Index.cs (revision 0) | |
+++ src/FluentNHibernate/DatabaseObjects/FluentIndex/Index.cs (revision 0) | |
@@ -0,0 +1,162 @@ | |
+using System; | |
+using System.Linq; | |
+using System.Linq.Expressions; | |
+using System.Reflection; | |
+using FluentNHibernate.Utils; | |
+using NHibernate; | |
+using NHibernate.Cfg; | |
+using NHibernate.Dialect; | |
+using NHibernate.Persister.Entity; | |
+ | |
+namespace FluentNHibernate.DatabaseObjects.FluentIndex | |
+{ | |
+ public interface IIndex | |
+ { | |
+ string GetCreateString(Dialect dialect, string defaultCatalog, string defaultSchema); | |
+ string GetDropString(Dialect dialect, string defaultCatalog, string defaultSchema); | |
+ } | |
+ | |
+ public interface IIndexIncomplete<T> | |
+ { | |
+ IIndexOptional OnDiscriminator(); | |
+ IIndexOptional OnPrimaryKey(); | |
+ IIndexOptional OnProperty(Expression<Func<T, object>> property); | |
+ } | |
+ | |
+ public interface IIndexOptional | |
+ { | |
+ void Ascending(); | |
+ void Descending(); | |
+ } | |
+ | |
+ public enum IndexType | |
+ { | |
+ Clustered, | |
+ NonClustered, | |
+ NonClusteredUnique | |
+ } | |
+ | |
+ public class Index<T> : IIndex, IIndexIncomplete<T>, IIndexOptional | |
+ { | |
+ private static Type IndexedClass { get { return typeof(T); } } | |
+ private readonly IndexType indexType; | |
+ private readonly Configuration configuration; | |
+ | |
+ public Index(IndexType indexType, Configuration configuration) | |
+ { | |
+ this.indexType = indexType; | |
+ this.configuration = configuration; | |
+ } | |
+ | |
+ private bool onDiscriminator; | |
+ public IIndexOptional OnDiscriminator() | |
+ { | |
+ onDiscriminator = true; | |
+ return this; | |
+ } | |
+ | |
+ private bool onPrimaryKey; | |
+ public IIndexOptional OnPrimaryKey() | |
+ { | |
+ onPrimaryKey = true; | |
+ return this; | |
+ } | |
+ | |
+ protected MemberInfo IndexedProperty { get; set; } | |
+ private bool onProperty; | |
+ public IIndexOptional OnProperty(Expression<Func<T, object>> property) | |
+ { | |
+ IndexedProperty = ReflectionHelper.GetProperty(property); | |
+ onProperty = true; | |
+ return this; | |
+ } | |
+ | |
+ private bool isAscending = true; | |
+ public void Ascending() | |
+ { | |
+ isAscending = true; | |
+ } | |
+ | |
+ public void Descending() | |
+ { | |
+ isAscending = false; | |
+ } | |
+ | |
+ protected bool MappingIsResolved { get; set; } | |
+ protected void ResolveMapping() | |
+ { | |
+ ISessionFactory sessionFactory = configuration.BuildSessionFactory(); | |
+ AbstractEntityPersister classMetadata = (AbstractEntityPersister)sessionFactory.GetClassMetadata(IndexedClass); | |
+ | |
+ Table = classMetadata.TableName | |
+ // Remove SQL escape characters | |
+ .Replace("\"", "") | |
+ .Replace("[", "") | |
+ .Replace("]", ""); | |
+ if (onProperty) | |
+ { | |
+ Column = classMetadata.GetPropertyColumnNames(IndexedProperty.Name)[0]; | |
+ } | |
+ else if (onDiscriminator) | |
+ { | |
+ Column = classMetadata.DiscriminatorColumnName; | |
+ } | |
+ else if (onPrimaryKey) | |
+ { | |
+ Column = classMetadata.KeyColumnNames[0]; | |
+ } | |
+ else | |
+ { | |
+ throw new InvalidOperationException("Must provide a column to be indexed."); | |
+ } | |
+ MappingIsResolved = true; | |
+ } | |
+ | |
+ public string ShortTable { get { return Table.Split('.').Last(); } } | |
+ | |
+ private string m_Table; | |
+ public string Table | |
+ { | |
+ get | |
+ { | |
+ if (!MappingIsResolved) ResolveMapping(); | |
+ return m_Table; | |
+ } | |
+ private set { m_Table = value; } | |
+ } | |
+ | |
+ private string m_Column; | |
+ public string Column | |
+ { | |
+ get | |
+ { | |
+ if (!MappingIsResolved) ResolveMapping(); | |
+ return m_Column; | |
+ } | |
+ private set { m_Column = value; } | |
+ } | |
+ | |
+ public string GetCreateString(Dialect dialect, string defaultCatalog, string defaultSchema) | |
+ { | |
+ string sort = isAscending ? "ASC" : "DESC"; | |
+ string createPrefix = GetCreateIndexPrefix(); | |
+ return string.Format(createPrefix + "INDEX [IX_{1}_{2}] ON {0}.[{1}] ([{2}] {3})", defaultSchema, ShortTable, Column, sort); | |
+ } | |
+ | |
+ public string GetDropString(Dialect dialect, string defaultCatalog, string defaultSchema) | |
+ { | |
+ return string.Format("DROP INDEX [IX_{1}_{2}] ON {0}.[{1}]", defaultSchema, ShortTable, Column); | |
+ } | |
+ | |
+ protected string GetCreateIndexPrefix() | |
+ { | |
+ switch (indexType) | |
+ { | |
+ case IndexType.Clustered: return "CREATE CLUSTERED "; | |
+ case IndexType.NonClustered: return "CREATE NONCLUSTERED "; | |
+ case IndexType.NonClusteredUnique: return "CREATE UNIQUE NONCLUSTERED "; | |
+ default: throw new ArgumentException("indexType is unknown"); | |
+ } | |
+ } | |
+ } | |
+} | |
\ No newline at end of file | |
Index: src/FluentNHibernate/FluentNHibernate.csproj | |
=================================================================== | |
--- src/FluentNHibernate/FluentNHibernate.csproj (revision 423) | |
+++ src/FluentNHibernate/FluentNHibernate.csproj (working copy) | |
@@ -3,7 +3,7 @@ | |
<PropertyGroup> | |
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> | |
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> | |
- <ProductVersion>9.0.30729</ProductVersion> | |
+ <ProductVersion>9.0.21022</ProductVersion> | |
<SchemaVersion>2.0</SchemaVersion> | |
<ProjectGuid>{1C988DFB-1EC5-484E-87D9-1D3C775BA435}</ProjectGuid> | |
<OutputType>Library</OutputType> | |
@@ -175,6 +175,8 @@ | |
<Compile Include="Conventions\IJoinedSubclassConvention.cs" /> | |
<Compile Include="Conventions\ISubclassConvention.cs" /> | |
<Compile Include="Conventions\MultipleAttribute.cs" /> | |
+ <Compile Include="DatabaseObjects\FluentIndex\FluentIndexBase.cs" /> | |
+ <Compile Include="DatabaseObjects\FluentIndex\Index.cs" /> | |
<Compile Include="Data\Entity.cs" /> | |
<Compile Include="Data\InMemoryRepository.cs" /> | |
<Compile Include="Data\IRepository.cs" /> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment