Skip to content

Commit 57d7c20

Browse files
authored
Merge pull request #2 from jeme/main
Add an actual test and switch to datetime2
2 parents fa0bd56 + 905fa89 commit 57d7c20

File tree

9 files changed

+148
-135
lines changed

9 files changed

+148
-135
lines changed

src/DotJEM.Json.Storage2.Test/DotJEM.Json.Storage2.Test.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
1111
<PackageReference Include="NUnit" Version="3.13.3" />
1212
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
13+
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
1314
</ItemGroup>
1415

1516
<ItemGroup>

src/DotJEM.Json.Storage2.Test/SqlServerStorageAreaFactoryTest.cs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
using System.Data.SqlClient;
2-
using DotJEM.Json.Storage2.SqlServer;
1+
using DotJEM.Json.Storage2.SqlServer;
32
using Newtonsoft.Json.Linq;
43
using NUnit.Framework;
54

@@ -13,6 +12,9 @@ public async Task EnsureLogTable_NoTableExists_ShouldCreateTable()
1312
SqlServerStorageContext context = await SqlServerStorageContext.Create(TestSqlConnectionFactory.ConnectionString);
1413
IStorageArea area = await context.AreaAsync("test");
1514
await area.InsertAsync("na", new JObject());
15+
16+
17+
1618
}
1719

1820
[Test]
@@ -48,12 +50,23 @@ public async Task GetAsync_NoTableExists_ShouldCreateTables()
4850
await area.InsertAsync("na", JObject.FromObject(new { track="T-01"}));
4951
await area.InsertAsync("na", JObject.FromObject(new { track= "T-02" }));
5052
await area.InsertAsync("na", JObject.FromObject(new { track= "T-03" }));
51-
52-
5353
await foreach (StorageObject obj in area.GetAsync())
5454
{
5555
Console.WriteLine(obj);
5656
}
5757
}
5858

59+
[Test]
60+
public async Task InsertAsync_Record_ShouldAddToTable()
61+
{
62+
SqlServerStorageContext context = await SqlServerStorageContext.Create(TestSqlConnectionFactory.ConnectionString, "fox");
63+
IStorageArea area = await context.AreaAsync("test");
64+
65+
StorageObject obj = await area.InsertAsync("na", JObject.FromObject(new { track = "T-01" }));
66+
StorageObject? obj2 = await area.GetAsync(obj.Id);
67+
68+
Assert.That(obj2, Is.Not.Null & Has.Property(nameof(StorageObject.UpdatedBy)).EqualTo(obj.UpdatedBy));
69+
70+
}
71+
5972
}

src/DotJEM.Json.Storage2/IsExternalInit.cs

Lines changed: 0 additions & 22 deletions
This file was deleted.
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
using System.Data;
2+
using System.Data.SqlClient;
3+
4+
namespace DotJEM.Json.Storage2.SqlServer.Initialization;
5+
6+
public interface ISqlServerSchemaStateManager
7+
{
8+
string Schema { get; }
9+
10+
Task Ensure();
11+
}
12+
13+
public class SqlServerSchemaStateManager : ISqlServerSchemaStateManager
14+
{
15+
private bool created;
16+
private readonly SqlServerConnectionFactory connectionFactory;
17+
private readonly SemaphoreSlim padlock = new(1, 1);
18+
19+
public string Schema { get; }
20+
21+
public SqlServerSchemaStateManager(SqlServerConnectionFactory connectionFactory, string schema, bool created)
22+
{
23+
this.connectionFactory = connectionFactory;
24+
this.Schema = schema;
25+
this.created = created;
26+
}
27+
28+
public async Task Ensure()
29+
{
30+
if (created)
31+
return;
32+
33+
using IDisposable locked = await padlock.ObtainLockAsync();
34+
if (created)
35+
return;
36+
37+
string commandText = SqlTemplates.CreateSchema(Schema);
38+
39+
await using SqlConnection connection = connectionFactory.Create();
40+
await using SqlCommand command = new SqlCommand(commandText, connection);
41+
await connection.OpenAsync().ConfigureAwait(false);
42+
43+
await using SqlTransaction transaction = connection.BeginTransaction(IsolationLevel.ReadUncommitted);
44+
command.Connection = connection;
45+
command.Transaction = transaction;
46+
await command.ExecuteNonQueryAsync().ConfigureAwait(false);
47+
await transaction.CommitAsync().ConfigureAwait(false);
48+
49+
created = true;
50+
}
51+
}
52+
53+
public static class SemaphoreSlimExt
54+
{
55+
public static async Task<IDisposable> ObtainLockAsync(this SemaphoreSlim semaphore)
56+
{
57+
await semaphore.WaitAsync();
58+
return new ObtainedLock(semaphore);
59+
}
60+
61+
private class ObtainedLock(SemaphoreSlim semaphore) : IDisposable
62+
{
63+
public void Dispose() => semaphore.Release();
64+
}
65+
}
66+
67+
public class SqlServerAreaStateManager : ISqlServerSchemaStateManager
68+
{
69+
private bool created;
70+
private readonly ISqlServerConnectionFactory connectionFactory;
71+
private readonly SemaphoreSlim padlock = new(1, 1);
72+
73+
public string AreaName { get; }
74+
public bool Exists => created;
75+
public string Schema { get; }
76+
77+
public SqlServerAreaStateManager(ISqlServerConnectionFactory connectionFactory, string schema, string area, bool created)
78+
{
79+
this.connectionFactory = connectionFactory;
80+
this.Schema = schema;
81+
this.AreaName = area;
82+
this.created = created;
83+
}
84+
85+
86+
public async Task Ensure()
87+
{
88+
if (created)
89+
return;
90+
91+
using IDisposable locked = await padlock.ObtainLockAsync();
92+
if (created)
93+
return;
94+
95+
string dataTableCommandText = SqlTemplates.CreateDataTable(Schema, AreaName);// SqlServerStatements.Load("CreateDataTable", map);
96+
string logTableCommandText = SqlTemplates.CreateLogTable(Schema, AreaName); // SqlServerStatements.Load("CreateLogTable", map);
97+
string schemaTableCommandText = SqlTemplates.CreateSchemasTable(Schema, AreaName); // SqlServerStatements.Load("CreateSchemasTable", map);
98+
99+
//await using SqlConnection connection = connectionFactory.Create();
100+
await using SqlConnection connection = connectionFactory.Create();
101+
await connection.OpenAsync().ConfigureAwait(false);
102+
103+
//await using SqlTransaction transaction = connection.BeginTransaction(IsolationLevel.ReadUncommitted);
104+
await using SqlTransaction transaction = connection.BeginTransaction(IsolationLevel.ReadUncommitted);
105+
await Execute(dataTableCommandText, connection, transaction);
106+
await Execute(logTableCommandText, connection, transaction);
107+
await Execute(schemaTableCommandText, connection, transaction);
108+
//await transaction.CommitAsync().ConfigureAwait(false);
109+
transaction.Commit();
110+
111+
created = true;
112+
}
113+
114+
private async Task Execute(string commandText, SqlConnection connection, SqlTransaction transaction)
115+
{
116+
//await using SqlCommand command = new(commandText);
117+
await using SqlCommand command = new(commandText);
118+
command.Connection = connection;
119+
command.Transaction = transaction;
120+
await command.ExecuteNonQueryAsync().ConfigureAwait(false);
121+
}
122+
123+
}

src/DotJEM.Json.Storage2/SqlServer/Initialization/Temp.cs

Lines changed: 1 addition & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
namespace DotJEM.Json.Storage2.SqlServer.Initialization;
1010

11+
//NOTE: Temp holds "in development" items, these should go into meaningful services under interfaces so they can be substituded e.g. for testing purposes.
1112
public static class Temp
1213
{
1314
public static async Task<SqlServerStorageAreaFactory> Create(string schema, SqlServerConnectionFactory connectionFactory)
@@ -52,106 +53,3 @@ public static async Task<SqlServerStorageAreaFactory> Create(string schema, SqlS
5253

5354
}
5455

55-
public interface ISqlServerSchemaStateManager
56-
{
57-
string SchemaName { get; }
58-
59-
Task Ensure();
60-
}
61-
62-
public class SqlServerSchemaStateManager : ISqlServerSchemaStateManager
63-
{
64-
private bool created;
65-
private readonly SqlServerConnectionFactory connectionFactory;
66-
private readonly SemaphoreSlim padlock = new(1, 1);
67-
public string SchemaName { get; }
68-
69-
public SqlServerSchemaStateManager(SqlServerConnectionFactory connectionFactory, string schema, bool created)
70-
{
71-
this.connectionFactory = connectionFactory;
72-
this.SchemaName = schema;
73-
this.created = created;
74-
}
75-
76-
public async Task Ensure()
77-
{
78-
if (created)
79-
return;
80-
81-
await padlock.WaitAsync();
82-
83-
string commandText = SqlTemplates.CreateSchema(SchemaName);
84-
85-
await using SqlConnection connection = connectionFactory.Create();
86-
await using SqlCommand command = new SqlCommand(commandText, connection);
87-
await connection.OpenAsync().ConfigureAwait(false);
88-
89-
await using SqlTransaction transaction = connection.BeginTransaction(IsolationLevel.ReadUncommitted);
90-
command.Connection = connection;
91-
command.Transaction = transaction;
92-
await command.ExecuteNonQueryAsync().ConfigureAwait(false);
93-
await transaction.CommitAsync().ConfigureAwait(false);
94-
95-
created = true;
96-
padlock.Release();
97-
}
98-
}
99-
100-
101-
public class SqlServerAreaStateManager
102-
{
103-
private bool created;
104-
private readonly ISqlServerConnectionFactory connectionFactory;
105-
private readonly SemaphoreSlim padlock = new(1, 1);
106-
107-
public string Schema { get; }
108-
public string AreaName { get; }
109-
public bool Exists => created;
110-
111-
public SqlServerAreaStateManager(ISqlServerConnectionFactory connectionFactory, string schema, string area, bool created)
112-
{
113-
this.connectionFactory = connectionFactory;
114-
this.Schema = schema;
115-
this.AreaName = area;
116-
this.created = created;
117-
}
118-
119-
public async Task Ensure()
120-
{
121-
if (created)
122-
return;
123-
124-
await padlock.WaitAsync();
125-
if (created)
126-
return;
127-
128-
string dataTableCommandText = SqlTemplates.CreateDataTable(Schema, AreaName);// SqlServerStatements.Load("CreateDataTable", map);
129-
string logTableCommandText = SqlTemplates.CreateLogTable(Schema, AreaName); // SqlServerStatements.Load("CreateLogTable", map);
130-
string schemaTableCommandText = SqlTemplates.CreateSchemasTable(Schema, AreaName); // SqlServerStatements.Load("CreateSchemasTable", map);
131-
132-
//await using SqlConnection connection = connectionFactory.Create();
133-
using SqlConnection connection = connectionFactory.Create();
134-
await connection.OpenAsync().ConfigureAwait(false);
135-
136-
//await using SqlTransaction transaction = connection.BeginTransaction(IsolationLevel.ReadUncommitted);
137-
using SqlTransaction transaction = connection.BeginTransaction(IsolationLevel.ReadUncommitted);
138-
await Execute(dataTableCommandText, connection, transaction);
139-
await Execute(logTableCommandText, connection, transaction);
140-
await Execute(schemaTableCommandText, connection, transaction);
141-
//await transaction.CommitAsync().ConfigureAwait(false);
142-
transaction.Commit();
143-
144-
created = true;
145-
padlock.Release();
146-
}
147-
148-
private async Task Execute(string commandText, SqlConnection connection, SqlTransaction transaction)
149-
{
150-
//await using SqlCommand command = new(commandText);
151-
using SqlCommand command = new(commandText);
152-
command.Connection = connection;
153-
command.Transaction = transaction;
154-
await command.ExecuteNonQueryAsync().ConfigureAwait(false);
155-
}
156-
157-
}

src/DotJEM.Json.Storage2/SqlServer/SqlServerStorageAreaFactory.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public async Task<SqlServerStorageArea> Create(string name, SqlServerStorageCont
4545
return new(context, areaInfo.State);
4646

4747
await padlock.WaitAsync().ConfigureAwait(false);
48-
AreaInfo area = new(name, new(context.ConnectionFactory, schema.SchemaName, name, false));
48+
AreaInfo area = new(name, new(context.ConnectionFactory, schema.Schema, name, false));
4949
areas.Add(name, area);
5050
return new(context, area.State);
5151
}

src/DotJEM.Json.Storage2/SqlServer/Statements/CreateDataTable.sql

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
[Id] [uniqueidentifier] NOT NULL,
33
[Version] [int] NOT NULL,
44
[ContentType] [varchar](64) NOT NULL,
5-
[Created] [datetime] NOT NULL,
6-
[Updated] [datetime] NOT NULL,
5+
[Created] [datetime2] NOT NULL,
6+
[Updated] [datetime2] NOT NULL,
77
[CreatedBy] [nvarchar](256) NULL,
88
[UpdatedBy] [nvarchar](256) NULL,
99
[Data] [nvarchar](max) NOT NULL,

src/DotJEM.Json.Storage2/SqlServer/Statements/CreateLogTable.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
[Revision] [bigint] IDENTITY(1,1) NOT NULL,
33
[Id] [uniqueidentifier] NOT NULL,
44
[Event] [varchar](1) NOT NULL,
5-
[Time] [datetime] NOT NULL,
5+
[Time] [datetime2] NOT NULL,
66
[User] [nvarchar](256) NULL,
77
[Version] [bigint] NOT NULL,
88
[Data] [nvarchar](max) NOT NULL,

src/DotJEM.Json.Storage2/SqlServer/Statements/CreateSchemasTable.sql

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
[Id] [uniqueidentifier] NOT NULL,
33
[Version] [int] NOT NULL,
44
[ContentType] [varchar](64) NOT NULL,
5-
[Created] [datetime] NOT NULL,
6-
[Updated] [datetime] NOT NULL,
5+
[Created] [datetime2] NOT NULL,
6+
[Updated] [datetime2] NOT NULL,
77
[Data] [nvarchar](max) NOT NULL,
88
[RV] [rowversion] NOT NULL,
99
CONSTRAINT [PK_@{area_name}.schemas] PRIMARY KEY CLUSTERED ( [Id] ASC )

0 commit comments

Comments
 (0)