Skip to content

Commit

Permalink
Merge pull request #149 from OctopusDeploy/sl/primarykeyhandlers
Browse files Browse the repository at this point in the history
Added the concept of Primary Key Handlers
  • Loading branch information
slewis74 committed Jul 6, 2021
2 parents fd85926 + 459f6eb commit f3c566f
Show file tree
Hide file tree
Showing 48 changed files with 1,149 additions and 410 deletions.
6 changes: 3 additions & 3 deletions source/Nevermore.IntegrationTests/Advanced/HooksFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,16 @@ public void ShouldCallHooks()

using var transaction = Store.BeginTransaction();

var customer = new Customer {Id = "C131", FirstName = "Fred", LastName = "Freddy"};
var customer = new Customer {Id = "C131".ToCustomerId(), FirstName = "Fred", LastName = "Freddy"};
transaction.Insert(customer);
AssertLogged(log, "BeforeInsert", "AfterInsert");

customer = transaction.Load<Customer>("C131");
customer = transaction.Load<Customer, CustomerId>("C131".ToCustomerId());

transaction.Update(customer);
AssertLogged(log, "BeforeUpdate", "AfterUpdate");

transaction.Delete(customer);
transaction.Delete<Customer, CustomerId>(customer);
AssertLogged(log, "BeforeDelete", "AfterDelete");

transaction.Commit();
Expand Down
16 changes: 8 additions & 8 deletions source/Nevermore.IntegrationTests/Advanced/MappingFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class User

// Test accessibility
public string Prop1 { get; set; }
public string Prop2 { get; } = "Hello";
public string Prop2 { get; } = "Hello";
public string Prop3 { get; private set; }
public string Prop4 { get; protected set; }
public string Prop5 { get; private set; }
Expand All @@ -31,13 +31,13 @@ public void SetOtherProps(string prop3, string prop4, string prop5)
Prop5 = prop5;
}
}

enum Education { School, HighSchool, College }

public override void OneTimeSetUp()
{
base.OneTimeSetUp();

NoMonkeyBusiness();
KeepDataBetweenTests();

Expand Down Expand Up @@ -86,7 +86,7 @@ public void ShouldFailIfReadOnlyNotMapped()
[Test, Order(2)]
public void ShouldWorkIfProp2IsSaveOnly()
{
var map = ((IDocumentMap)new UserMap()).Build();
var map = ((IDocumentMap)new UserMap()).Build(Configuration.PrimaryKeyHandlers);
// Pretend the user edited their document map to set it to SaveOnly
((IColumnMappingBuilder) map.Columns.Single(c => c.ColumnName == "Prop2")).SaveOnly();
Configuration.DocumentMaps.Register(map);
Expand All @@ -105,9 +105,9 @@ public void ShouldInsert()
Prop1 = "Prop1",
FirstName = "Fred"
};

user.SetOtherProps("Prop3", "Prop4", "Prop5");

transaction.Insert(user);
transaction.Update(user);
transaction.Commit();
Expand All @@ -117,7 +117,7 @@ public void ShouldInsert()
public void ShouldLoad()
{
using var transaction = Store.BeginTransaction();

var user = transaction.Load<User>("users-123");
user.Should().NotBeNull();
user.Age.Should().Be(18);
Expand All @@ -132,7 +132,7 @@ public void ShouldLoad()
public void ShouldDelete()
{
using var transaction = Store.BeginTransaction();

transaction.Delete<User>("users-123");
var user = transaction.Load<User>("users-123");
user.Should().BeNull();
Expand Down
23 changes: 10 additions & 13 deletions source/Nevermore.IntegrationTests/Advanced/NoJsonFixture.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
using System.Collections.Generic;
using System.Data;
using FluentAssertions;
using Microsoft.Data.SqlClient.Server;
using Nevermore.IntegrationTests.SetUp;
using Nevermore.Mapping;
using NUnit.Framework;
Expand All @@ -14,9 +11,9 @@ public override void OneTimeSetUp()
{
base.OneTimeSetUp();
NoMonkeyBusiness();

ExecuteSql("create table TestSchema.Car([Id] nvarchar(50), [Name] nvarchar(100))");

Store.Configuration.DocumentMaps.Register(new CarMap());
}

Expand All @@ -25,23 +22,23 @@ class Car
public string Id { get; set; }
public string Name { get; set; }
}
class CarMap : DocumentMap<Car>

class CarMap : DocumentMap<Car>
{
public CarMap()
{
Column(m => m.Name);

JsonStorageFormat = JsonStorageFormat.NoJson;
}
}

[Test]
public void ShouldMapWithoutJson()
{
using var transaction = Store.BeginTransaction();
transaction.Insert(new Car { Name = "Volvo" });

var car = transaction.Load<Car>("Cars-1");
car.Should().NotBeNull();
car.Name.Should().Be("Volvo");
Expand All @@ -54,9 +51,9 @@ public void ShouldMapWithoutJson()
car.Name.Should().Be("Bertie");

transaction.Query<Car>().Count().Should().Be(1);
transaction.Delete(car);

transaction.Delete<Car, string>(car);

transaction.Query<Car>().Count().Should().Be(0);

car = transaction.Load<Car>("Cars-1");
Expand Down
26 changes: 13 additions & 13 deletions source/Nevermore.IntegrationTests/KeyAllocatorFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public void ShouldAllocateKeysInChunks()
var allocatorA = new KeyAllocator(Store, 10);
var allocatorB = new KeyAllocator(Store, 10);

// A gets 1-10
// A gets 1-10
AssertNext(allocatorA, "Todos", 1);
AssertNext(allocatorA, "Todos", 2);
AssertNext(allocatorA, "Todos", 3);
Expand Down Expand Up @@ -76,7 +76,7 @@ public void ShouldAllocateInParallel()
const int allocationCount = 20;
const int threadCount = 10;

var projectIds = new ConcurrentBag<string>();
var customerIds = new ConcurrentBag<CustomerId>();
var deploymentIds = new ConcurrentBag<string>();
var random = new Random(1);

Expand All @@ -90,21 +90,21 @@ public void ShouldAllocateInParallel()
var sequence = random.Next(3);
if (sequence == 0)
{
var id = transaction.AllocateId(typeof (Customer));
projectIds.Add(id);
var id = transaction.AllocateId<Customer, CustomerId>();
customerIds.Add(id);
transaction.Commit();
}
else if (sequence == 1)
{
// Abandon some transactions (just projects to make it easier)
var id = transaction.AllocateId(typeof(Customer));
var id = transaction.AllocateId<Customer, CustomerId>();
// Abandoned Ids are not returned to the pool
projectIds.Add(id);
customerIds.Add(id);
transaction.Dispose();
}
else if (sequence == 2)
{
var id = transaction.AllocateId(typeof(Order));
var id = transaction.AllocateId<Order, string>();
deploymentIds.Add(id);
transaction.Commit();
}
Expand All @@ -115,21 +115,21 @@ public void ShouldAllocateInParallel()
Task.WaitAll(tasks);
Func<string, int> removePrefix = x => int.Parse(x.Split('-')[1]);

var projectIdsAfter = projectIds.Select(removePrefix).OrderBy(x => x).ToArray();
var customerIdsAfter = customerIds.Select(x => removePrefix(x.Value)).OrderBy(x => x).ToArray();
var deploymentIdsAfter = deploymentIds.Select(removePrefix).OrderBy(x => x).ToArray();

projectIdsAfter.Distinct().Count().Should().Be(projectIdsAfter.Length);
customerIdsAfter.Distinct().Count().Should().Be(customerIdsAfter.Length);
deploymentIdsAfter.Distinct().Count().Should().Be(deploymentIdsAfter.Length);

// Check that there are no gaps in sequence

var firstProjectId = projectIdsAfter.First();
var lastProjectId = projectIdsAfter.Last();
var firstProjectId = customerIdsAfter.First();
var lastProjectId = customerIdsAfter.Last();

var expectedProjectIds = Enumerable.Range(firstProjectId, lastProjectId - firstProjectId + 1)
.ToList();

projectIdsAfter.Should().BeEquivalentTo(expectedProjectIds);
customerIdsAfter.Should().BeEquivalentTo(expectedProjectIds);
}

static void AssertNext(KeyAllocator allocator, string collection, int expected)
Expand Down
54 changes: 54 additions & 0 deletions source/Nevermore.IntegrationTests/Model/CustomIdType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#nullable enable
using System;
using System.Globalization;
using System.Reflection;

namespace Nevermore.IntegrationTests.Model
{
public class CustomIdType<T>
{
internal CustomIdType(T value)
{
Value = value;
}

public T Value { get; }

public override string? ToString()
{
return Value?.ToString();
}

public override bool Equals(object? obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != GetType()) return false;
return !(Value is null) && Value.Equals(((CustomIdType<T>) obj).Value);
}

public override int GetHashCode()
{
return (Value != null ? Value.GetHashCode() : 0);
}

public static CustomIdType<T>? Create(Type customType, T value)
{
const BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
var instance = Activator.CreateInstance(customType, bindingFlags, null, new object[] { value! }, CultureInfo.CurrentCulture);
return instance as CustomIdType<T>;
}

public static TCustomIdType? Create<TCustomIdType>(T value) where TCustomIdType : CustomIdType<T>
{
return (TCustomIdType?) Create(typeof(TCustomIdType), value);
}
}

public class StringCustomIdType : CustomIdType<string>
{
internal StringCustomIdType(string value) : base(value)
{
}
}
}
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)
{
}
}
}
19 changes: 18 additions & 1 deletion source/Nevermore.IntegrationTests/Model/Customer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public Customer()
Roles = new ReferenceCollection();
}

public string Id { get; set; }
public CustomerId Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public ReferenceCollection Roles { get; }
Expand All @@ -18,4 +18,21 @@ public Customer()
public string ApiKey { get; set; }
public string[] Passphrases { get; set; }
}

public class CustomerId : StringCustomIdType
{
internal CustomerId(string value) : base(value)
{
}
}

#nullable enable

public static class CustomerIdExtensionMethods
{
public static CustomerId? ToCustomerId(this string? value)
{
return string.IsNullOrWhiteSpace(value) ? null : new CustomerId(value);
}
}
}
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);
}
}
}
Loading

0 comments on commit f3c566f

Please sign in to comment.