diff --git a/src/TableStorage/AttributedDocumentRepository`1.cs b/src/TableStorage/AttributedDocumentRepository`1.cs
index 59b8f32..c27c013 100644
--- a/src/TableStorage/AttributedDocumentRepository`1.cs
+++ b/src/TableStorage/AttributedDocumentRepository`1.cs
@@ -5,7 +5,7 @@
namespace Devlooped
{
///
- /// A implementation which relies on the entity type
+ /// An implementation which relies on the entity type
/// being annotated with and , and
/// optionally (defaults to type name).
///
@@ -13,7 +13,7 @@ namespace Devlooped
/// When attributed entities are used, this is a convenient generic implementation for use with
/// a dependency injection container, such as in ASP.NET Core:
///
- /// services.AddScoped(typeof(ITableRepository<>), typeof(AttributedDocumentRepository<>));
+ /// services.AddScoped(typeof(IDocumentRepository<>), typeof(AttributedDocumentRepository<>));
///
///
partial class AttributedDocumentRepository : DocumentRepository where T : class
diff --git a/src/TableStorage/AttributedTableRepository`1.cs b/src/TableStorage/AttributedTableRepository`1.cs
index 7af3b46..d32b840 100644
--- a/src/TableStorage/AttributedTableRepository`1.cs
+++ b/src/TableStorage/AttributedTableRepository`1.cs
@@ -5,7 +5,7 @@
namespace Devlooped
{
///
- /// A implementation which relies on the entity type
+ /// An implementation which relies on the entity type
/// being annotated with and , and
/// optionally (defaults to type name).
///
diff --git a/src/TableStorage/DocumentPartition.cs b/src/TableStorage/DocumentPartition.cs
index 287d932..f417e72 100644
--- a/src/TableStorage/DocumentPartition.cs
+++ b/src/TableStorage/DocumentPartition.cs
@@ -8,7 +8,7 @@
namespace Devlooped
{
///
- /// Factory methods to create instances
+ /// Factory methods to create instances
/// that store entities as a serialized document.
///
static partial class DocumentPartition
@@ -22,14 +22,14 @@ static partial class DocumentPartition
public const string DefaultTableName = "Documents";
///
- /// Creates an for the given entity type
+ /// Creates an for the given entity type
/// , using as the table name and the
/// Name as the partition key.
///
/// The type of entity that the repository will manage.
/// The storage account to use.
/// Function to retrieve the row key for a given entity.
- /// The new .
+ /// The new .
public static IDocumentPartition Create(
CloudStorageAccount storageAccount,
Func rowKey,
@@ -37,7 +37,7 @@ public static IDocumentPartition Create(
=> Create(storageAccount, DefaultTableName, typeof(T).Name, rowKey);
///
- /// Creates an for the given entity type
+ /// Creates an for the given entity type
/// , using the given table name and the
/// Name as the partition key.
///
@@ -45,7 +45,7 @@ public static IDocumentPartition Create(
/// The storage account to use.
/// Table name to use.
/// Function to retrieve the row key for a given entity.
- /// The new .
+ /// The new .
public static IDocumentPartition Create(
CloudStorageAccount storageAccount,
string tableName,
@@ -54,7 +54,7 @@ public static IDocumentPartition Create(
=> Create(storageAccount, tableName, default, rowKey);
///
- /// Creates an for the given entity type
+ /// Creates an for the given entity type
/// .
///
/// The type of entity that the repository will manage.
@@ -65,7 +65,7 @@ public static IDocumentPartition Create(
/// If not provided, the Name will be used.
/// Optional function to retrieve the row key for a given entity.
/// If not provided, the class will need a property annotated with .
- /// The new .
+ /// The new .
public static IDocumentPartition Create(
CloudStorageAccount storageAccount,
string? tableName = default,
diff --git a/src/TableStorage/DocumentPartition`1.cs b/src/TableStorage/DocumentPartition`1.cs
index eb674fe..67ac368 100644
--- a/src/TableStorage/DocumentPartition`1.cs
+++ b/src/TableStorage/DocumentPartition`1.cs
@@ -2,6 +2,7 @@
#nullable enable
using System;
using System.Collections.Generic;
+using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Azure.Cosmos.Table;
@@ -11,7 +12,7 @@ namespace Devlooped
///
partial class DocumentPartition : IDocumentPartition where T : class
{
- readonly IDocumentRepository repository;
+ readonly DocumentRepository repository;
///
/// Initializes the repository with the given storage account and optional table name.
@@ -50,6 +51,10 @@ public Task DeleteAsync(string rowKey, CancellationToken cancellation = default)
public IAsyncEnumerable EnumerateAsync(CancellationToken cancellation = default)
=> repository.EnumerateAsync(PartitionKey, cancellation);
+ ///
+ public IAsyncEnumerable EnumerateAsync(Expression> predicate, CancellationToken cancellation = default)
+ => repository.EnumerateAsync(e => e.PartitionKey == PartitionKey, cancellation);
+
///
public Task GetAsync(string rowKey, CancellationToken cancellation = default)
=> repository.GetAsync(PartitionKey, rowKey, cancellation);
diff --git a/src/TableStorage/DocumentRepository.cs b/src/TableStorage/DocumentRepository.cs
index ac719c1..26cc631 100644
--- a/src/TableStorage/DocumentRepository.cs
+++ b/src/TableStorage/DocumentRepository.cs
@@ -6,13 +6,13 @@
namespace Devlooped
{
///
- /// Factory methods to create instances
+ /// Factory methods to create instances
/// that store entities as a serialized document.
///
static partial class DocumentRepository
{
///
- /// Creates an for the given entity type
+ /// Creates an for the given entity type
/// .
///
/// The type of entity that the repository will manage.
@@ -23,7 +23,7 @@ static partial class DocumentRepository
/// If not provided, the class will need a property annotated with .
/// Optional function to retrieve the row key for a given entity.
/// If not provided, the class will need a property annotated with .
- /// The new .
+ /// The new .
public static IDocumentRepository Create(
CloudStorageAccount storageAccount,
string? tableName = default,
diff --git a/src/TableStorage/DocumentRepository`1.cs b/src/TableStorage/DocumentRepository`1.cs
index 5b79949..6a4cdc5 100644
--- a/src/TableStorage/DocumentRepository`1.cs
+++ b/src/TableStorage/DocumentRepository`1.cs
@@ -2,6 +2,8 @@
#nullable enable
using System;
using System.Collections.Generic;
+using System.Linq;
+using System.Linq.Expressions;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
@@ -12,7 +14,9 @@ namespace Devlooped
///
partial class DocumentRepository : IDocumentRepository where T : class
{
- static readonly string documentVersion = (typeof(T).Assembly.GetName().Version ?? new Version(1, 0)).ToString(2);
+ static readonly string documentVersion;
+ static readonly int documentMajorVersion;
+ static readonly int documentMinorVersion;
readonly CloudStorageAccount storageAccount;
@@ -23,10 +27,18 @@ partial class DocumentRepository : IDocumentRepository where T : class
readonly Func rowKey;
readonly Task table;
- readonly Func> enumerate;
+ readonly Func>?, CancellationToken, IAsyncEnumerable> enumerate;
readonly Func> get;
readonly Func> put;
+ static DocumentRepository()
+ {
+ var version = (typeof(T).Assembly.GetName().Version ?? new Version(1, 0));
+ documentVersion = version.ToString(2);
+ documentMajorVersion = version.Major;
+ documentMinorVersion = version.Minor;
+ }
+
///
/// Initializes the table repository.
///
@@ -91,8 +103,12 @@ await table.ExecuteAsync(TableOperation.Delete(
}
///
- public IAsyncEnumerable EnumerateAsync(string? partitionKey = default, CancellationToken cancellation = default)
- => enumerate(partitionKey, cancellation);
+ public IAsyncEnumerable EnumerateAsync(string? partitionKey = default, CancellationToken cancellation = default)
+ => enumerate(partitionKey == null ? null : e => e.PartitionKey == partitionKey, cancellation);
+
+ ///
+ public IAsyncEnumerable EnumerateAsync(Expression> predicate, CancellationToken cancellation = default)
+ => enumerate(predicate, cancellation);
///
public Task GetAsync(string partitionKey, string rowKey, CancellationToken cancellation = default)
@@ -104,12 +120,16 @@ public Task PutAsync(T entity, CancellationToken cancellation = default)
#region Binary
- async IAsyncEnumerable EnumerateBinaryAsync(string? partitionKey = default, [EnumeratorCancellation] CancellationToken cancellation = default)
+ async IAsyncEnumerable EnumerateBinaryAsync(Expression>? predicate, [EnumeratorCancellation] CancellationToken cancellation = default)
{
var table = await this.table.ConfigureAwait(false);
- var query = new TableQuery();
- if (partitionKey != null)
- query = query.Where(TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, partitionKey));
+ var query = table.CreateQuery();
+
+ if (predicate != null)
+ {
+ var expression = Expression.Lambda>(predicate.Body, Expression.Parameter(typeof(BinaryDocumentEntity)));
+ query = (TableQuery)((IQueryable)query).Where(expression);
+ }
TableContinuationToken? continuation = null;
do
@@ -158,8 +178,10 @@ async Task PutBinaryAsync(T entity, CancellationToken cancellation = default)
{
ETag = "*",
Document = binarySerializer!.Serialize(entity),
- DocumentType = typeof(T).FullName,
- DocumentVersion = documentVersion,
+ Type = typeof(T).FullName,
+ Version = documentVersion,
+ MajorVersion = documentMajorVersion,
+ MinorVersion = documentMinorVersion,
}), cancellation)
.ConfigureAwait(false);
@@ -174,12 +196,16 @@ async Task PutBinaryAsync(T entity, CancellationToken cancellation = default)
#region String
- async IAsyncEnumerable EnumerateStringAsync(string? partitionKey = default, [EnumeratorCancellation] CancellationToken cancellation = default)
+ async IAsyncEnumerable EnumerateStringAsync(Expression>? predicate, [EnumeratorCancellation] CancellationToken cancellation = default)
{
var table = await this.table.ConfigureAwait(false);
- var query = new TableQuery();
- if (partitionKey != null)
- query = query.Where(TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, partitionKey));
+ var query = table.CreateQuery();
+
+ if (predicate != null)
+ {
+ var expression = Expression.Lambda>(predicate.Body, Expression.Parameter(typeof(DocumentEntity)));
+ query = (TableQuery)((IQueryable)query).Where(expression);
+ }
TableContinuationToken? continuation = null;
do
@@ -228,8 +254,10 @@ async Task PutStringAsync(T entity, CancellationToken cancellation = default)
{
ETag = "*",
Document = stringSerializer!.Serialize(entity),
- DocumentType = typeof(T).FullName,
- DocumentVersion = documentVersion,
+ Type = typeof(T).FullName,
+ Version = documentVersion,
+ MajorVersion = documentMajorVersion,
+ MinorVersion = documentMinorVersion,
}), cancellation)
.ConfigureAwait(false);
@@ -250,22 +278,26 @@ async Task GetTableAsync(string tableName)
return table;
}
- class BinaryDocumentEntity : TableEntity
+ class BinaryDocumentEntity : TableEntity, IDocumentEntity
{
public BinaryDocumentEntity() { }
public BinaryDocumentEntity(string partitionKey, string rowKey) : base(partitionKey, rowKey) { }
public byte[]? Document { get; set; }
- public string? DocumentType { get; set; }
- public string? DocumentVersion { get; set; }
+ public string? Type { get; set; }
+ public string? Version { get; set; }
+ public int? MajorVersion { get; set; }
+ public int? MinorVersion { get; set; }
}
- class DocumentEntity : TableEntity
+ class DocumentEntity : TableEntity, IDocumentEntity
{
public DocumentEntity() { }
public DocumentEntity(string partitionKey, string rowKey) : base(partitionKey, rowKey) { }
public string? Document { get; set; }
- public string? DocumentType { get; set; }
- public string? DocumentVersion { get; set; }
+ public string? Type { get; set; }
+ public string? Version { get; set; }
+ public int? MajorVersion { get; set; }
+ public int? MinorVersion { get; set; }
}
}
}
\ No newline at end of file
diff --git a/src/TableStorage/IDocumentEntity.cs b/src/TableStorage/IDocumentEntity.cs
new file mode 100644
index 0000000..1e56962
--- /dev/null
+++ b/src/TableStorage/IDocumentEntity.cs
@@ -0,0 +1,32 @@
+//
+#nullable enable
+using Microsoft.Azure.Cosmos.Table;
+
+namespace Devlooped
+{
+ ///
+ /// Document metadata for querying purposes.
+ ///
+ partial interface IDocumentEntity : ITableEntity
+ {
+ ///
+ /// The type of the document, its .
+ ///
+ string? Type { get; }
+
+ ///
+ /// The major.minor version of the assembly the document type belongs to.
+ ///
+ string? Version { get; }
+
+ ///
+ /// The major component of the .
+ ///
+ int? MajorVersion { get; }
+
+ ///
+ /// The minor component of the .
+ ///
+ int? MinorVersion { get; }
+ }
+}
diff --git a/src/TableStorage/IDocumentPartition`1.cs b/src/TableStorage/IDocumentPartition`1.cs
new file mode 100644
index 0000000..5d7eef0
--- /dev/null
+++ b/src/TableStorage/IDocumentPartition`1.cs
@@ -0,0 +1,31 @@
+//
+#nullable enable
+using System;
+using System.Collections.Generic;
+using System.Linq.Expressions;
+using System.Threading;
+
+namespace Devlooped
+{
+ ///
+ /// A specific partition within an .
+ ///
+ /// The type of entity being persisted.
+ partial interface IDocumentPartition : ITableStoragePartition where T : class
+ {
+ ///
+ /// Queries the document repository for items that match the given .
+ ///
+ ///
+ /// var books = DocumentPartition.Create<Book>();
+ /// await foreach (var book in books.EnumerateAsync(x =>
+ /// x.PartitionKey == "Rick Riordan" &&
+ /// x.RowKey.CompareTo("Percy Jackson") >= 0 &&
+ /// x.Version == "1.0"))
+ /// {
+ /// Console.WriteLine(book.ISBN);
+ /// }
+ ///
+ public IAsyncEnumerable EnumerateAsync(Expression> predicate, CancellationToken cancellation = default);
+ }
+}
diff --git a/src/TableStorage/IDocumentRepository`1.cs b/src/TableStorage/IDocumentRepository`1.cs
new file mode 100644
index 0000000..1fa25e6
--- /dev/null
+++ b/src/TableStorage/IDocumentRepository`1.cs
@@ -0,0 +1,29 @@
+//
+#nullable enable
+using System;
+using System.Collections.Generic;
+using System.Linq.Expressions;
+using System.Threading;
+
+namespace Devlooped
+{
+ ///
+ /// A generic repository that stores entities in table storage as serialized
+ /// documents.
+ ///
+ /// The type of entity being persisted.
+ partial interface IDocumentRepository : ITableStorage where T : class
+ {
+ ///
+ /// Queries the document repository for items that match the given .
+ ///
+ ///
+ /// var books = DocumentRepository.Create<Book>();
+ /// await foreach (var book in books.EnumerateAsync(x => x.PartitionKey == "Rick Riordan" && x.DocumentType ))
+ /// {
+ /// Console.WriteLine(book.ISBN);
+ /// }
+ ///
+ public IAsyncEnumerable EnumerateAsync(Expression> predicate, CancellationToken cancellation = default);
+ }
+}
\ No newline at end of file
diff --git a/src/TableStorage/ITablePartition`1.cs b/src/TableStorage/ITablePartition`1.cs
index b0f5b1b..b8f5cc6 100644
--- a/src/TableStorage/ITablePartition`1.cs
+++ b/src/TableStorage/ITablePartition`1.cs
@@ -9,7 +9,7 @@ namespace Devlooped
/// by the entity properties, since they are stored in individual columns.
///
/// The type of entity being persisted.
- partial interface ITablePartition : IDocumentPartition where T : class
+ partial interface ITablePartition : ITableStoragePartition where T : class
{
///
/// Creates a query for use with LINQ expressions. See
diff --git a/src/TableStorage/ITableRepository`1.cs b/src/TableStorage/ITableRepository`1.cs
index 994b934..264a0af 100644
--- a/src/TableStorage/ITableRepository`1.cs
+++ b/src/TableStorage/ITableRepository`1.cs
@@ -5,12 +5,12 @@
namespace Devlooped
{
///
- /// A specialized which allows querying
+ /// A specialized which allows querying
/// the repository by the entity properties, since they are stored in individual
/// columns.
///
/// The type of entity being persisted.
- partial interface ITableRepository : IDocumentRepository where T : class
+ partial interface ITableRepository : ITableStorage where T : class
{
///
/// Creates a query for use with LINQ expressions. See
diff --git a/src/TableStorage/IDocumentPartition.cs b/src/TableStorage/ITableStoragePartition`1.cs
similarity index 94%
rename from src/TableStorage/IDocumentPartition.cs
rename to src/TableStorage/ITableStoragePartition`1.cs
index 338b10d..1ba4195 100644
--- a/src/TableStorage/IDocumentPartition.cs
+++ b/src/TableStorage/ITableStoragePartition`1.cs
@@ -7,10 +7,10 @@
namespace Devlooped
{
///
- /// A specific partition within a .
+ /// A specific partition within an .
///
/// The type of entity being persisted.
- partial interface IDocumentPartition where T : class
+ partial interface ITableStoragePartition where T : class
{
///
/// Gets the table name being used.
diff --git a/src/TableStorage/IDocumentRepository.cs b/src/TableStorage/ITableStorage`1.cs
similarity index 97%
rename from src/TableStorage/IDocumentRepository.cs
rename to src/TableStorage/ITableStorage`1.cs
index d0b17a6..2fae258 100644
--- a/src/TableStorage/IDocumentRepository.cs
+++ b/src/TableStorage/ITableStorage`1.cs
@@ -10,7 +10,7 @@ namespace Devlooped
/// A generic repository that stores entities in table storage.
///
/// The type of entity being persisted.
- partial interface IDocumentRepository where T : class
+ partial interface ITableStorage where T : class
{
///
/// Gets the table name being used.
diff --git a/src/TableStorage/TableEntityPartition.cs b/src/TableStorage/TableEntityPartition.cs
index 7019f57..7080829 100644
--- a/src/TableStorage/TableEntityPartition.cs
+++ b/src/TableStorage/TableEntityPartition.cs
@@ -2,6 +2,7 @@
#nullable enable
using System;
using System.Collections.Generic;
+using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Azure.Cosmos.Table;
@@ -9,9 +10,9 @@
namespace Devlooped
{
///
- partial class TableEntityPartition : IDocumentPartition
+ partial class TableEntityPartition : ITablePartition
{
- readonly IDocumentRepository repository;
+ readonly TableEntityRepository repository;
///
/// Initializes the repository with the given storage account and optional table name.
@@ -32,6 +33,9 @@ protected internal TableEntityPartition(CloudStorageAccount storageAccount, stri
///
public string PartitionKey { get; }
+ ///
+ public IQueryable CreateQuery() => repository.CreateQuery().Where(x => x.PartitionKey == PartitionKey);
+
///
public async Task DeleteAsync(TableEntity entity, CancellationToken cancellation = default)
{
diff --git a/src/TableStorage/TableEntityRepository.cs b/src/TableStorage/TableEntityRepository.cs
index e730eb4..bb6f039 100644
--- a/src/TableStorage/TableEntityRepository.cs
+++ b/src/TableStorage/TableEntityRepository.cs
@@ -1,6 +1,7 @@
//
#nullable enable
using System.Collections.Generic;
+using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
@@ -9,7 +10,7 @@
namespace Devlooped
{
///
- partial class TableEntityRepository : IDocumentRepository
+ partial class TableEntityRepository : ITableRepository
{
readonly CloudStorageAccount storageAccount;
readonly Task table;
@@ -29,6 +30,10 @@ protected internal TableEntityRepository(CloudStorageAccount storageAccount, str
///
public string TableName { get; }
+ ///
+ public IQueryable CreateQuery()
+ => storageAccount.CreateCloudTableClient().GetTableReference(TableName).CreateQuery();
+
///
public async Task DeleteAsync(string partitionKey, string rowKey, CancellationToken cancellation = default)
{
diff --git a/src/TableStorage/TablePartition.cs b/src/TableStorage/TablePartition.cs
index fd9dd0e..6fd741b 100644
--- a/src/TableStorage/TablePartition.cs
+++ b/src/TableStorage/TablePartition.cs
@@ -9,7 +9,7 @@
namespace Devlooped
{
///
- /// Factory methods to create instances
+ /// Factory methods to create instances
/// that store entities using individual columns for entity properties.
///
static partial class TablePartition
@@ -23,13 +23,13 @@ static partial class TablePartition
public const string DefaultTableName = "Entities";
///
- /// Creates an , using
+ /// Creates an , using
/// as the table name and the
/// Name as the partition key.
///
/// The storage account to use.
- /// The new .
- public static IDocumentPartition Create(CloudStorageAccount storageAccount, string tableName, string partitionKey)
+ /// The new .
+ public static ITablePartition Create(CloudStorageAccount storageAccount, string tableName, string partitionKey)
=> new TableEntityPartition(storageAccount, tableName, partitionKey);
///
@@ -40,7 +40,7 @@ public static IDocumentPartition Create(CloudStorageAccount storage
/// The type of entity that the repository will manage.
/// The storage account to use.
/// Function to retrieve the row key for a given entity.
- /// The new .
+ /// The new .
public static ITablePartition Create(
CloudStorageAccount storageAccount,
Expression> rowKey) where T : class
@@ -74,7 +74,7 @@ public static ITablePartition Create(
/// If not provided, the Name will be used.
/// Optional function to retrieve the row key for a given entity.
/// If not provided, the class will need a property annotated with .
- /// The new .
+ /// The new .
public static ITablePartition Create(
CloudStorageAccount storageAccount,
string? tableName = default,
diff --git a/src/TableStorage/TableRepository.cs b/src/TableStorage/TableRepository.cs
index d8be781..e53246b 100644
--- a/src/TableStorage/TableRepository.cs
+++ b/src/TableStorage/TableRepository.cs
@@ -9,7 +9,7 @@
namespace Devlooped
{
///
- /// Factory methods to create instances
+ /// Factory methods to create instances
/// that store entities using individual columns for entity properties.
///
static partial class TableRepository
@@ -17,18 +17,18 @@ static partial class TableRepository
static readonly ConcurrentDictionary defaultTableNames = new();
///
- /// Creates an repository.
+ /// Creates an repository.
///
/// The storage account to use.
/// Table name to use.
- /// The new .
- public static IDocumentRepository Create(
+ /// The new .
+ public static ITableRepository Create(
CloudStorageAccount storageAccount,
string tableName)
=> new TableEntityRepository(storageAccount, tableName);
///
- /// Creates an for the given entity type
+ /// Creates an for the given entity type
/// , using the Name as
/// the table name.
///
@@ -36,7 +36,7 @@ public static IDocumentRepository Create(
/// The storage account to use.
/// Function to retrieve the partition key for a given entity.
/// Function to retrieve the row key for a given entity.
- /// The new .
+ /// The new .
public static ITableRepository Create(
CloudStorageAccount storageAccount,
Expression> partitionKey,
@@ -44,7 +44,7 @@ public static ITableRepository Create(
=> Create(storageAccount, typeof(T).Name, partitionKey, rowKey);
///
- /// Creates an for the given entity type
+ /// Creates an for the given entity type
/// .
///
/// The type of entity that the repository will manage.
@@ -55,7 +55,7 @@ public static ITableRepository Create(
/// If not provided, the class will need a property annotated with .
/// Optional function to retrieve the row key for a given entity.
/// If not provided, the class will need a property annotated with .
- /// The new .
+ /// The new .
public static ITableRepository Create(
CloudStorageAccount storageAccount,
string? tableName = default,
diff --git a/src/TableStorage/Visibility.cs b/src/TableStorage/Visibility.cs
index b7ec6fd..ba4b264 100644
--- a/src/TableStorage/Visibility.cs
+++ b/src/TableStorage/Visibility.cs
@@ -2,13 +2,17 @@
namespace Devlooped
{
// Sets default visibility when using compiled version, where everything is public
- public partial interface IDocumentRepository { }
+ public partial interface ITableStorage { }
+ public partial interface ITableStoragePartition { }
+ public partial interface ITableRepository { }
public partial interface ITableRepository { }
- public partial interface IDocumentPartition { }
public partial interface ITablePartition { }
+ public partial interface IDocumentRepository { }
+ public partial interface IDocumentPartition { }
public partial interface IDocumentSerializer { }
public partial interface IBinaryDocumentSerializer { }
public partial interface IStringDocumentSerializer { }
+ public partial interface IDocumentEntity { }
public partial class TableRepository { }
public partial class TableRepository { }
diff --git a/src/Tests/DocumentRepositoryTests.cs b/src/Tests/DocumentRepositoryTests.cs
index 1139e0f..a95b24a 100644
--- a/src/Tests/DocumentRepositoryTests.cs
+++ b/src/Tests/DocumentRepositoryTests.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.ComponentModel;
using System.Threading.Tasks;
using MessagePack;
using Microsoft.Azure.Cosmos.Table;
@@ -125,6 +126,51 @@ public async Task DocumentPartitionEndToEnd(IDocumentSerializer serializer)
}
}
+ [Theory]
+ [MemberData(nameof(Serializers))]
+ public async Task CanQueryDocument(IDocumentSerializer serializer)
+ {
+ var table = CloudStorageAccount.DevelopmentStorageAccount.CreateCloudTableClient()
+ .GetTableReference(nameof(CanQueryDocument) + serializer.GetType().Name);
+ await table.DeleteIfExistsAsync();
+ await table.CreateAsync();
+
+ try
+ {
+ var repo = DocumentRepository.Create(CloudStorageAccount.DevelopmentStorageAccount,
+ table.Name, serializer: serializer);
+
+ var partitionKey = "P" + Guid.NewGuid().ToString("N");
+
+ await repo.PutAsync(new DocumentEntity
+ {
+ PartitionKey = partitionKey,
+ RowKey = "Bar",
+ Title = "Bar",
+ });
+
+ await repo.PutAsync(new DocumentEntity
+ {
+ PartitionKey = partitionKey,
+ RowKey = "Foo",
+ Title = "Foo",
+ });
+
+ var entities = await repo.EnumerateAsync(e =>
+ e.PartitionKey == partitionKey &&
+ e.RowKey.CompareTo("Foo") >= 0 && e.RowKey.CompareTo("Fop") < 0 &&
+ e.Version != "1.0" &&
+ e.Type == typeof(DocumentEntity).FullName)
+ .ToListAsync();
+
+ Assert.Single(entities);
+ }
+ finally
+ {
+ await table.DeleteIfExistsAsync();
+ }
+ }
+
[ProtoContract]
[MessagePackObject]
public class DocumentEntity
diff --git a/src/Tests/QueryTests.cs b/src/Tests/QueryTests.cs
index bb59422..0e2b2f1 100644
--- a/src/Tests/QueryTests.cs
+++ b/src/Tests/QueryTests.cs
@@ -127,6 +127,29 @@ public async Task CanFilterByColumn()
Assert.Single(result);
}
+ [Fact]
+ public async Task CanFilterDocuments()
+ {
+ var account = CloudStorageAccount.DevelopmentStorageAccount;
+ await LoadBooksAsync(DocumentRepository.Create(
+ account, nameof(CanFilterDocuments), x => x.Author, x => x.ISBN));
+
+ var repo = DocumentPartition.Create(account, nameof(CanFilterDocuments), "Rick Riordan", x => x.ISBN);
+
+ //// Get specific set of books from one particular publisher/country combination
+ //// in this case, 978-[English-speaking country, 1][Disney Editions, 4231]
+ //// See https://en.wikipedia.org/wiki/List_of_group-1_ISBN_publisher_codes
+ //var query = from book in repo.CreateQuery()
+ // where
+ // book.ISBN.CompareTo("97814231") >= 0 &&
+ // book.ISBN.CompareTo("97814232") < 0
+ // select new { book.ISBN, book.Title };
+
+ //var result = await query.AsAsyncEnumerable().ToListAsync();
+
+ //Assert.Equal(4, result.Count);
+ }
+
[Fact]
public async Task EnumFailsInTableClient()
{
@@ -142,7 +165,7 @@ public async Task EnumFailsInTableClient()
.ToList());
}
- async Task LoadBooksAsync(ITableRepository books)
+ async Task LoadBooksAsync(ITableStorage books)
{
foreach (var book in File.ReadAllLines("Books.csv").Skip(1)
.Select(line => line.Split(','))