Skip to content

Commit

Permalink
Implementing collections support
Browse files Browse the repository at this point in the history
Fixes #22
  • Loading branch information
sebastienros committed Sep 22, 2016
2 parents 190eefb + 3cdb976 commit 30cfca4
Show file tree
Hide file tree
Showing 23 changed files with 592 additions and 58 deletions.
111 changes: 111 additions & 0 deletions src/YesSql.Core/Collections/Collection.cs
@@ -0,0 +1,111 @@
using System;
using System.Text;

namespace YesSql.Core.Collections
{
public abstract class Collection : IDisposable
{
IDisposable _scope;

public Collection()
{
_scope = CollectionHelper.EnterScope(this);
}

public abstract string GetSafeName();
public static string CreateSafeName(string name)
{
if (name == null)
{
throw new ArgumentNullException(nameof(name));
}

var builder = new StringBuilder();
bool first = true;
foreach (var c in name)
{
if (Char.IsLetter(c) || (!first && Char.IsDigit(c)))
{
builder.Append(c);
}

first = false;
}

return builder.ToString();
}

public void Dispose()
{
_scope.Dispose();
}
}

public static class CollectionExtensions
{
public static string GetPrefixedName(this Collection collection, string table)
{
var name = collection.GetSafeName();

if (String.IsNullOrEmpty(name))
{
return table;
}

return String.Concat(name, "_", table);
}
}

public class DefaultCollection : Collection
{
public DefaultCollection()
{

}

public override string GetSafeName()
{
return "";
}
}

public class TypeCollection<T> : Collection
{
private readonly string _safeName;

public TypeCollection()
{
_safeName = CreateSafeName(typeof(T).Name);

if(String.IsNullOrEmpty(_safeName))
{
throw new ArgumentException("Invalid collection name: " + _safeName);
}
}

public override string GetSafeName()
{
return _safeName;
}
}

public class NamedCollection : Collection
{
private readonly string _safeName;

public NamedCollection(string name)
{
_safeName = CreateSafeName(name);

if (String.IsNullOrEmpty(_safeName))
{
throw new ArgumentException("Invalid collection name: " + _safeName);
}
}

public override string GetSafeName()
{
return _safeName;
}
}
}
90 changes: 90 additions & 0 deletions src/YesSql.Core/Collections/CollectionHelper.cs
@@ -0,0 +1,90 @@
using System;
#if NETSTANDARD1_5
using System.Threading;
#else
using System.Runtime.Remoting;
using System.Runtime.Remoting.Messaging;
#endif

namespace YesSql.Core.Collections
{
public class CollectionHelper
{

#if NETSTANDARD1_5
private static readonly AsyncLocal<CollectionStack> _scopes = new AsyncLocal<CollectionStack>();

internal static CollectionStack Scopes
{
get { return _scopes.Value; }
set { _scopes.Value = value; }
}
#else
private static readonly string CollectionDataName = "Collection.Scopes" + AppDomain.CurrentDomain.Id;

internal static CollectionStack Scopes
{
get
{
var handle = CallContext.LogicalGetData(CollectionDataName) as ObjectHandle;

if (handle == null)
{
return null;
}

return handle.Unwrap() as CollectionStack;
}
set
{
CallContext.LogicalSetData(CollectionDataName, new ObjectHandle(value));
}
}
#endif
public static Collection Current
{
get
{
var scopes = GetOrCreateScopes();
return scopes.Peek();
}
}

internal static IDisposable EnterScope(Collection collection)
{
var scopes = GetOrCreateScopes();

var scopeLease = new ScopeLease(scopes);
Scopes = scopes.Push(collection);

return scopeLease;
}

private static CollectionStack GetOrCreateScopes()
{
var scopes = Scopes;
if (scopes == null)
{
scopes = CollectionStack.Empty;
Scopes = scopes;
}

return scopes;
}

private sealed class ScopeLease : IDisposable
{
readonly CollectionStack _collectionStack;

public ScopeLease(CollectionStack collectionStack)
{
_collectionStack = collectionStack;
}

public void Dispose()
{
Scopes = _collectionStack;
}
}
}
}
38 changes: 38 additions & 0 deletions src/YesSql.Core/Collections/CollectionStack.cs
@@ -0,0 +1,38 @@
using System;

namespace YesSql.Core.Collections
{
internal class CollectionStack
{
private readonly CollectionStack _previous;
private readonly Collection _collection;

private CollectionStack()
{

}

private CollectionStack(CollectionStack previous, Collection collection)
{
if (previous == null)
{
throw new ArgumentNullException(nameof(previous));
}

_previous = previous;
_collection = collection;
}

public static readonly CollectionStack Empty = new CollectionStack();

public CollectionStack Push(Collection c)
{
return new CollectionStack(this, c);
}

public Collection Peek()
{
return _collection ?? new DefaultCollection();
}
}
}
5 changes: 4 additions & 1 deletion src/YesSql.Core/Commands/CreateDocumentCommand.cs
@@ -1,7 +1,9 @@
using System.Data.Common;
using System.Threading.Tasks;
using Dapper;
using YesSql.Core.Collections;
using YesSql.Core.Indexes;
using YesSql.Core.Services;
using YesSql.Core.Sql;

namespace YesSql.Core.Commands
Expand All @@ -20,7 +22,8 @@ public CreateDocumentCommand(Document document, string tablePrefix) : base(docum
public override Task ExecuteAsync(DbConnection connection, DbTransaction transaction)
{
var dialect = SqlDialectFactory.For(connection);
var insertCmd = $"insert into [{_tablePrefix}Document] ([Id], [Type]) values (@Id, @Type);";
var documentTable = CollectionHelper.Current.GetPrefixedName(Store.DocumentTable);
var insertCmd = $"insert into [{_tablePrefix}{documentTable}] ([Id], [Type]) values (@Id, @Type);";
return connection.ExecuteScalarAsync<int>(insertCmd, Document, transaction);
}
}
Expand Down
5 changes: 4 additions & 1 deletion src/YesSql.Core/Commands/CreateIndexCommand.cs
Expand Up @@ -5,6 +5,8 @@
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Data.Common;
using YesSql.Core.Collections;
using YesSql.Core.Services;

namespace YesSql.Core.Commands
{
Expand All @@ -26,6 +28,7 @@ public override async Task ExecuteAsync(DbConnection connection, DbTransaction t
{
var dialect = SqlDialectFactory.For(connection);
var type = Index.GetType();
var documentTable = CollectionHelper.Current.GetPrefixedName(Store.DocumentTable);

if (Index is MapIndex)
{
Expand All @@ -40,7 +43,7 @@ public override async Task ExecuteAsync(DbConnection connection, DbTransaction t
var sql = Inserts(type) + $"; {dialect.IdentitySelectString} id";
Index.Id = await connection.ExecuteScalarAsync<int>(sql, Index, transaction);

var bridgeTableName = type.Name + "_Document";
var bridgeTableName = type.Name + "_" + documentTable;
var columnList = $"[{type.Name}Id], [DocumentId]";
var parameterList = $"@Id, @DocumentId";
var bridgeSql = $"insert into [{_tablePrefix}{bridgeTableName}] ({columnList}) values ({parameterList});";
Expand Down
5 changes: 4 additions & 1 deletion src/YesSql.Core/Commands/DeleteDocumentCommand.cs
@@ -1,7 +1,9 @@
using System.Data.Common;
using System.Threading.Tasks;
using Dapper;
using YesSql.Core.Collections;
using YesSql.Core.Indexes;
using YesSql.Core.Services;
using YesSql.Core.Sql;

namespace YesSql.Core.Commands
Expand All @@ -20,7 +22,8 @@ public DeleteDocumentCommand(Document document, string tablePrefix) : base(docum
public override Task ExecuteAsync(DbConnection connection, DbTransaction transaction)
{
var dialect = SqlDialectFactory.For(connection);
var deleteCmd = $"delete from [{_tablePrefix}Document] where [Id] = @Id;";
var documentTable = CollectionHelper.Current.GetPrefixedName(Store.DocumentTable);
var deleteCmd = $"delete from [{_tablePrefix}{documentTable}] where [Id] = @Id;";
return connection.ExecuteAsync(deleteCmd, Document, transaction);
}
}
Expand Down
5 changes: 4 additions & 1 deletion src/YesSql.Core/Commands/DeleteReduceIndexCommand.cs
Expand Up @@ -2,6 +2,8 @@
using System.Data.Common;
using System.Threading.Tasks;
using YesSql.Core.Indexes;
using YesSql.Core.Collections;
using YesSql.Core.Services;

namespace YesSql.Core.Commands
{
Expand All @@ -17,7 +19,8 @@ public override async Task ExecuteAsync(DbConnection connection, DbTransaction t
{
var name = Index.GetType().Name;

var bridgeTableName = name + "_Document";
var documentTable = CollectionHelper.Current.GetPrefixedName(Store.DocumentTable);
var bridgeTableName = name + "_" + documentTable;
var bridgeSql = $"delete from [{_tablePrefix}{bridgeTableName}] where {name}Id = @Id";

await connection.ExecuteAsync(bridgeSql, new { Id = Index.Id }, transaction);
Expand Down
5 changes: 4 additions & 1 deletion src/YesSql.Core/Commands/UpdateIndexCommand.cs
Expand Up @@ -5,6 +5,8 @@
using System.Threading.Tasks;
using YesSql.Core.Indexes;
using YesSql.Core.Sql;
using YesSql.Core.Collections;
using YesSql.Core.Services;

namespace YesSql.Core.Commands
{
Expand Down Expand Up @@ -37,7 +39,8 @@ public override async Task ExecuteAsync(DbConnection connection, DbTransaction t
var reduceIndex = Index as ReduceIndex;
if (reduceIndex != null)
{
var bridgeTableName = type.Name + "_Document";
var documentTable = CollectionHelper.Current.GetPrefixedName(Store.DocumentTable);
var bridgeTableName = type.Name + "_" + documentTable;
var columnList = $"[{type.Name}Id], [DocumentId]";
var parameterList = $"@Id, @DocumentId";
var bridgeSqlAdd = $"insert into [{_tablePrefix}{bridgeTableName}] ({columnList}) values ({parameterList});";
Expand Down
3 changes: 3 additions & 0 deletions src/YesSql.Core/Indexes/IIndexProvider.cs
Expand Up @@ -6,6 +6,7 @@ public interface IIndexProvider
{
void Describe(IDescriptor context);
Type ForType();
string CollectionName { get; set; }
}

public abstract class IndexProvider<T> : IIndexProvider
Expand All @@ -17,6 +18,8 @@ void IIndexProvider.Describe(IDescriptor context)
Describe((DescribeContext<T>)context);
}

public string CollectionName { get; set; }

public Type ForType()
{
return typeof(T);
Expand Down

0 comments on commit 30cfca4

Please sign in to comment.