Skip to content

Commit 277f016

Browse files
authored
Create sequential UUID for SQL Server from a specific date (#33)
2 parents b0e06f1 + 74574b5 commit 277f016

17 files changed

Lines changed: 561 additions & 243 deletions

Doc/UUIDNext.xml

Lines changed: 62 additions & 38 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Doc/uuidnext.tools.uuidtoolkit.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,22 @@ Here is the bit layout of the UUID Version 7 created
7171
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
7272
```
7373

74+
### **CreateSequentialUuidForSqlServerFromSpecificDate(DateTimeOffset)**
75+
76+
Create a new sequential UUID Optimised for SQL Server with the given date as timestamp
77+
78+
```csharp
79+
public static Guid CreateSequentialUuidForSqlServerFromSpecificDate(DateTimeOffset date)
80+
```
81+
82+
#### Parameters
83+
84+
`date` [DateTimeOffset](https://docs.microsoft.com/en-us/dotnet/api/system.datetimeoffset)<br>
85+
86+
#### Returns
87+
88+
[Guid](https://docs.microsoft.com/en-us/dotnet/api/system.guid)<br>
89+
7490
### **CreateGuidFromBigEndianBytes(Span&lt;Byte&gt;)**
7591

7692
Create new UUID version 8 with the provided bytes with the variant and version bits set
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
using System;
2+
using NFluent;
3+
using UUIDNext.Tools;
4+
using Xunit;
5+
6+
namespace UUIDNext.Test.Generator;
7+
8+
public abstract class UuidFromSpecificDateGeneratorTestBase : UuidTimestampGeneratorBaseTest
9+
{
10+
[Theory]
11+
[MemberData(nameof(InvalidDates))]
12+
public void CheckThatDateBeforeUnixEpochAreRejected(DateTimeOffset date)
13+
{
14+
var generator = NewGenerator();
15+
Check.ThatCode(() => NewUuid(generator, date)).Throws<ArgumentOutOfRangeException>();
16+
}
17+
18+
public static object[][] InvalidDates
19+
=> [[new DateTimeOffset(new(1900, 1, 1))], [DateTimeOffset.FromUnixTimeMilliseconds(-1)], [DateTimeOffset.MinValue]];
20+
21+
[Fact]
22+
public void EnsureThatUuidsFromTheSameTimestampAreIncreasing()
23+
{
24+
UuidWithTimestampComparer comparer = new();
25+
DateTimeOffset date = new(new(2020, 2, 1));
26+
var generator = NewGenerator();
27+
Guid previousUuid = NewUuid(generator, date.AddMilliseconds(-1));
28+
for (int i = 0; i < 100; i++)
29+
{
30+
var uuid = NewUuid(generator, date);
31+
Check.That(comparer.Compare(previousUuid, uuid)).IsStrictlyLessThan(0);
32+
previousUuid = uuid;
33+
}
34+
}
35+
36+
[Fact]
37+
public void EnsureThatUuidsFromMultipleTimestampAreIncreasing()
38+
{
39+
UuidWithTimestampComparer comparer = new();
40+
41+
DateTimeOffset dateT = new(new(2028, 10, 12));
42+
DateTimeOffset dateA = new(new(2030, 5, 1));
43+
DateTimeOffset dateS = new(new(2037, 11, 24));
44+
45+
var generator = NewGenerator();
46+
47+
Guid previousUuidT = NewUuid(generator, dateT.AddMilliseconds(-1));
48+
Guid previousUuidA = NewUuid(generator, dateA.AddMilliseconds(-1));
49+
Guid previousUuidS = NewUuid(generator, dateS.AddMilliseconds(-1));
50+
51+
for (int i = 0; i < 100; i++)
52+
{
53+
var uuidT = NewUuid(generator, dateT);
54+
var uuidA = NewUuid(generator, dateA);
55+
var uuidS = NewUuid(generator, dateS);
56+
57+
Check.That(comparer.Compare(previousUuidT, uuidT)).IsStrictlyLessThan(0);
58+
Check.That(comparer.Compare(previousUuidA, uuidA)).IsStrictlyLessThan(0);
59+
Check.That(comparer.Compare(previousUuidS, uuidS)).IsStrictlyLessThan(0);
60+
61+
previousUuidT = uuidT;
62+
previousUuidA = uuidA;
63+
previousUuidS = uuidS;
64+
}
65+
}
66+
67+
[Fact]
68+
public void EnsureTimestampAndVersionAreAlwaysCorrect()
69+
{
70+
UuidWithTimestampComparer comparer = new();
71+
DateTime date = new(2020, 2, 1, 0, 0, 0, DateTimeKind.Utc);
72+
var generator = NewGenerator();
73+
74+
int overflowCount = 0;
75+
Guid previousUuid = NewUuid(generator, date.AddMilliseconds(-1));
76+
77+
// we loop 10_000 times to make sure that the sequence of the UUID v7 will overflow at
78+
// least twice since the sequence is stored on 12 bits and its maximum value is thus 4095
79+
int iterationCount = (int)(GetSequenceMaxValue() * 2.5);
80+
for (int i = 0; i < iterationCount; i++)
81+
{
82+
var uuid = NewUuid(generator, date);
83+
Check.That(UuidDecoder.GetVersion(uuid)).Is(Version);
84+
var uuidDate = UuidTestHelper.DecodeDate(uuid);
85+
Check.That(uuidDate).Is(date);
86+
87+
if (comparer.Compare(previousUuid, uuid) > 0)
88+
overflowCount++;
89+
90+
previousUuid = uuid;
91+
}
92+
93+
Check.That(overflowCount).IsGreaterOrEqualThan(2).And.IsLessOrEqualThan(5);
94+
}
95+
}

0 commit comments

Comments
 (0)