Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace Nevermore.IntegrationTests.Model
{
class CustomPrefixIdKeyHandler : StringCustomIdTypeIdKeyHandler<CustomPrefixId>
{
public const string CustomPrefix = "CustomPrefix";

public CustomPrefixIdKeyHandler():base(CustomPrefix)
{
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace Nevermore.IntegrationTests.Model
{
public class DocumentWithCustomPrefix
{
public CustomPrefixId Id { get; set; }
public string Name { get; set; }
}

public class CustomPrefixId : StringCustomIdType
{
internal CustomPrefixId(string value) : base(value)
{
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Nevermore.IntegrationTests.Model
{
public class DocumentWithCustomPrefixAndStringId
{
public string Id { get; set; }
public string Name { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using Nevermore.Mapping;

namespace Nevermore.IntegrationTests.Model
{
public class DocumentWithCustomPrefixAndStringIdMap : DocumentMap<DocumentWithCustomPrefixAndStringId>
{
public const string CustomPrefix = "CustomPrefix";

public DocumentWithCustomPrefixAndStringIdMap()
{
Id().KeyHandler(new StringPrimaryKeyHandler(_ => CustomPrefix));
Column(m => m.Name);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using Nevermore.Mapping;

namespace Nevermore.IntegrationTests.Model
{
public class DocumentWithCustomPrefixMap : DocumentMap<DocumentWithCustomPrefix>
{
public DocumentWithCustomPrefixMap()
{
Id();
Column(m => m.Name);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,17 @@

namespace Nevermore.IntegrationTests.Model
{
class StringCustomIdTypeIdKeyHandler<T> : IStringBasedPrimitivePrimaryKeyHandler
class StringCustomIdTypeIdKeyHandler<T> : IPrimaryKeyHandler
where T : StringCustomIdType
{
readonly string? customPrefix;
public Type Type => typeof(T);

public StringCustomIdTypeIdKeyHandler(string? customPrefix = null)
{
this.customPrefix = customPrefix;
}

public object? ConvertToPrimitiveValue(object? id)
{
if (!(id is StringCustomIdType stringCustomType))
Expand All @@ -19,22 +25,7 @@ class StringCustomIdTypeIdKeyHandler<T> : IStringBasedPrimitivePrimaryKeyHandler
public object GetNextKey(IKeyAllocator keyAllocator, string tableName)
{
var key = keyAllocator.NextId(tableName);
return CustomIdType<string>.Create<T>($"{GetPrefix(tableName)}-{key}")!;
}

public void SetPrefix(Func<string, string> idPrefix)
{
throw new NotImplementedException();
}

public string GetPrefix(string tableName)
{
return $"{tableName}s";
}

public void SetFormat(Func<(string idPrefix, int key), string> format)
{
throw new NotImplementedException();
return CustomIdType<string>.Create<T>($"{customPrefix ?? tableName}s-{key}")!;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -452,5 +452,37 @@ public void LoadManyByWrongIdType_ShouldThrowArgumentException()
target.ShouldThrow<ArgumentException>().Which.Message.Should().Be("Provided Id of type 'System.String' does not match configured type of 'System.Guid'.");
}
}

[Test]
public void StoreAndLoadWithCustomIdAndCustomPrefix()
{
using (var trn = Store.BeginTransaction())
{
var document = new DocumentWithCustomPrefix()
{
Name = "test"
};

trn.Insert(document);

document.Id.Value.Should().StartWith(CustomPrefixIdKeyHandler.CustomPrefix);
}
}

[Test]
public void StoreAndLoadWithCustomPrefix()
{
using (var trn = Store.BeginTransaction())
{
var document = new DocumentWithCustomPrefixAndStringId()
{
Name = "test"
};

trn.Insert(document);

document.Id.Should().StartWith(DocumentWithCustomPrefixAndStringIdMap.CustomPrefix);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ protected FixtureWithRelationalStore()
new MessageWithGuidIdMap(),
new DocumentWithRowVersionMap(),
new DocumentWithIdentityIdMap(),
new DocumentWithIdentityIdAndRowVersionMap()
new DocumentWithIdentityIdAndRowVersionMap(),
new DocumentWithCustomPrefixMap(),
new DocumentWithCustomPrefixAndStringIdMap()
};

var config = new RelationalStoreConfiguration(ConnectionString)
Expand All @@ -43,6 +45,7 @@ protected FixtureWithRelationalStore()
config.TypeHandlers.Register(new StringCustomIdTypeHandler<CustomerId>());

config.PrimaryKeyHandlers.Register(new StringCustomIdTypeIdKeyHandler<CustomerId>());
config.PrimaryKeyHandlers.Register(new CustomPrefixIdKeyHandler());

config.InstanceTypeResolvers.Register(new ProductTypeResolver());
config.InstanceTypeResolvers.Register(new BrandTypeResolver());
Expand Down
12 changes: 0 additions & 12 deletions source/Nevermore/Mapping/IIdColumnMappingBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,6 @@ public interface IIdColumnMappingBuilder : IColumnMappingBuilder
/// <returns></returns>
IIdColumnMappingBuilder KeyHandler(IPrimaryKeyHandler primaryKeyHandler);

/// <summary>
/// Set a function that when given the TableName will return key prefix string.
/// </summary>
/// <param name="idPrefix">The function to call back to get the prefix.</param>
IIdColumnMappingBuilder Prefix(Func<string, string> idPrefix);

/// <summary>
/// Set a function that format a key value, given a prefix and a key number.
/// </summary>
/// <param name="format">The function to call back to format the id.</param>
IIdColumnMappingBuilder Format(Func<(string idPrefix, int key), string> format);

/// <summary>
/// Builds the IdColumnMapping.
/// </summary>
Expand Down
26 changes: 0 additions & 26 deletions source/Nevermore/Mapping/IStringBasedPrimitivePrimaryKeyHandler.cs

This file was deleted.

59 changes: 5 additions & 54 deletions source/Nevermore/Mapping/IdColumnMapping.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,73 +44,24 @@ public IIdColumnMappingBuilder Identity()
{
ValidateForIdentityUse();

if (!(PrimaryKeyHandler is null))
throw new InvalidOperationException($"{nameof(KeyHandler)} has already been set to a non-identity handler.");

IsIdentity = true;

return this;
}

void ValidateForIdentityUse()
{
if (!ValidIdentityTypes.Contains(Type))
throw new InvalidOperationException($"The type {Type.Name} is not supported for Identity columns. Identity columns must be one of 'short', 'int' or 'long'.");

if (hasCustomPropertyHandler)
throw new InvalidOperationException("Unable to configure an Identity Id column with a custom PropertyHandler");
}

public IIdColumnMappingBuilder KeyHandler(IPrimaryKeyHandler primaryKeyHandler)
{
if (!(PrimaryKeyHandler is null) && Direction == ColumnDirection.FromDatabase)
throw new InvalidOperationException($"{nameof(KeyHandler)} can only be called with an IIdentityPrimaryKeyHandler, once {nameof(Identity)} has been called.");

PrimaryKeyHandler = primaryKeyHandler;

return this;
}

/// <summary>
/// Set a function that when given the TableName will return key prefix string.
/// </summary>
/// <param name="idPrefix">The function to call back to get the prefix.</param>
public IIdColumnMappingBuilder Prefix(Func<string, string> idPrefix)
{
if (Direction == ColumnDirection.FromDatabase)
throw new InvalidOperationException($"{nameof(Prefix)} cannot be set when an identity key handler has been configured.");

if (PrimaryKeyHandler == null)
return KeyHandler(new StringPrimaryKeyHandler(idPrefix));

if (PrimaryKeyHandler is IStringBasedPrimitivePrimaryKeyHandler stringIdHandler)
{
stringIdHandler.SetPrefix(idPrefix);
return this;
}

throw new InvalidOperationException($"Cannot set the Id prefix when the PrimaryKeyHandler is of type {PrimaryKeyHandler.GetType().Name}");
}

/// <summary>
/// Set a function that format a key value, given a prefix and a key number.
/// </summary>
/// <param name="format">The function to call back to format the id.</param>
public IIdColumnMappingBuilder Format(Func<(string idPrefix, int key), string> format)
void ValidateForIdentityUse()
{
if (!(PrimaryKeyHandler is null) && Direction == ColumnDirection.FromDatabase)
throw new InvalidOperationException($"{nameof(Format)} cannot be set when an identity key handler has been configured.");

if (PrimaryKeyHandler == null)
return KeyHandler(new StringPrimaryKeyHandler(format: format));

if (PrimaryKeyHandler is IStringBasedPrimitivePrimaryKeyHandler stringIdHandler)
{
stringIdHandler.SetFormat(format);
return this;
}
if (!ValidIdentityTypes.Contains(Type))
throw new InvalidOperationException($"The type {Type.Name} is not supported for Identity columns. Identity columns must be one of 'short', 'int' or 'long'.");

throw new InvalidOperationException($"Cannot set the key format when the PrimaryKeyHandler is of type {PrimaryKeyHandler.GetType().Name}");
if (hasCustomPropertyHandler)
throw new InvalidOperationException("Unable to configure an Identity Id column with a custom PropertyHandler");
}

protected override void SetCustomPropertyHandler(IPropertyHandler propertyHandler)
Expand Down
36 changes: 7 additions & 29 deletions source/Nevermore/Mapping/StringPrimaryKeyHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,43 +3,21 @@

namespace Nevermore.Mapping
{
class StringPrimaryKeyHandler : PrimaryKeyHandler<string>, IStringBasedPrimitivePrimaryKeyHandler
class StringPrimaryKeyHandler : PrimaryKeyHandler<string>
{
Func<string, string> idPrefixFunc;
Func<(string idPrefix, int key), string> formatFunc;
readonly Func<string, string> idPrefix;
readonly Func<(string idPrefix, int key), string> format;

public StringPrimaryKeyHandler(Func<string, string>? idPrefix = null, Func<(string idPrefix, int key), string>? format = null)
{
idPrefixFunc = idPrefix ?? (x => $"{x}s");
formatFunc = format ?? (x => $"{x.idPrefix}-{x.key}");
}

/// <summary>
/// Set a function that when given the TableName will return key prefix string.
/// </summary>
/// <param name="idPrefix">The function to call back to get the prefix.</param>
public void SetPrefix(Func<string, string> idPrefix)
{
idPrefixFunc = idPrefix;
}

public string GetPrefix(string tableName)
{
return idPrefixFunc(tableName);
}

/// <summary>
/// Set a function that format a key value, given a prefix and a key number.
/// </summary>
/// <param name="format">The function to call back to format the id.</param>
public void SetFormat(Func<(string idPrefix, int key), string> format)
{
formatFunc = format;
this.idPrefix = idPrefix ?? (tableName => $"{tableName}s");
this.format = format ?? (x => $"{x.idPrefix}-{x.key}");
}

public override object GetNextKey(IKeyAllocator keyAllocator, string tableName)
{
var nextKey = keyAllocator.NextId(tableName);
return formatFunc((GetPrefix(tableName), nextKey));
return format((idPrefix(tableName), nextKey));
}
}
}