Skip to content

Commit

Permalink
A bit of cleanup and fix a bug where UseStrictTyping didn't flow thro…
Browse files Browse the repository at this point in the history
…ugh specs (#454)

* A bit of clean up

* Fixes #452
  • Loading branch information
IEvangelist authored Jun 30, 2024
1 parent 3f06c8e commit 167c819
Show file tree
Hide file tree
Showing 36 changed files with 242 additions and 132 deletions.
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

<PropertyGroup>
<CompatibilityTargetFrameworks>netstandard2.0</CompatibilityTargetFrameworks>
<DefaultTargetFrameworks>net7.0;net8.0</DefaultTargetFrameworks>
<DefaultTargetFrameworks>net7.0;net8.0;net9.0;</DefaultTargetFrameworks>
<LangVersion>preview</LangVersion>
</PropertyGroup>

Expand Down
7 changes: 7 additions & 0 deletions Microsoft.Azure.CosmosRepository.sln
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EventSourcingCustomerAccoun
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Azure.CosmosEventSourcingAcceptanceTests", "tests\Microsoft.Azure.CosmosEventSourcingAcceptanceTests\Microsoft.Azure.CosmosEventSourcingAcceptanceTests.csproj", "{99ADC0F0-9433-49AD-86FA-34009CD293BA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BugSandbox", "samples\Microsoft.Azure.CosmosRepository\BugSandbox\BugSandbox.csproj", "{7354577A-699D-4952-B8DF-27CF0FC7F683}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -180,6 +182,10 @@ Global
{99ADC0F0-9433-49AD-86FA-34009CD293BA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{99ADC0F0-9433-49AD-86FA-34009CD293BA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{99ADC0F0-9433-49AD-86FA-34009CD293BA}.Release|Any CPU.Build.0 = Release|Any CPU
{7354577A-699D-4952-B8DF-27CF0FC7F683}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7354577A-699D-4952-B8DF-27CF0FC7F683}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7354577A-699D-4952-B8DF-27CF0FC7F683}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7354577A-699D-4952-B8DF-27CF0FC7F683}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -210,6 +216,7 @@ Global
{D276C752-4DB7-4380-AF76-91492E8F8554} = {8F8738AD-EBC3-4C24-882B-5D9FAC427E80}
{7A2873BC-70A1-489B-9609-E9D7D382C826} = {8F8738AD-EBC3-4C24-882B-5D9FAC427E80}
{99ADC0F0-9433-49AD-86FA-34009CD293BA} = {F8ED6752-5ED3-4EA1-89F0-363C40F8D8E0}
{7354577A-699D-4952-B8DF-27CF0FC7F683} = {2EEE3D0D-6457-46D8-B8E8-FA7364942F1F}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {6AAE7641-B62C-48BA-8FE6-0F819E5B45EF}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace EventSourcingJobsTracker.Core.Aggregates;

public class JobsList : AggregateRoot
{
private readonly List<Job> _jobs = new();
private readonly List<Job> _jobs = [];

public Guid Id { get; private set; }

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\src\Microsoft.Azure.CosmosRepository\Microsoft.Azure.CosmosRepository.csproj" />
</ItemGroup>

</Project>
67 changes: 67 additions & 0 deletions samples/Microsoft.Azure.CosmosRepository/BugSandbox/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Copyright (c) David Pine. All rights reserved.
// Licensed under the MIT License.

using Microsoft.Azure.CosmosRepository;
using Microsoft.Azure.CosmosRepository.Specification;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

// https://learn.microsoft.com/azure/cosmos-db/how-to-develop-emulator?tabs=docker-linux%2Ccsharp&pivots=api-nosql
const string EmulatorConnectionString = """
AccountEndpoint=https://localhost:8081/;AccountKey=C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==;
""";

var builder = Host.CreateApplicationBuilder(args);

ServiceProvider provider = builder.Services.AddCosmosRepository(options =>
{
options.CosmosConnectionString = EmulatorConnectionString;
options.DatabaseId = "bug-sandbox";
options.ContainerBuilder.Configure<ExampleModel>(
static containerOptions => containerOptions
.WithoutStrictTypeChecking()
.WithContainer("Example")
.WithPartitionKey("/id"));
})
.BuildServiceProvider();

IRepository<ExampleModel> repository = provider.GetRequiredService<IRepository<ExampleModel>>();

await SeedAsync();

var queryResult = await repository.QueryAsync(new ExampleSpecification());

if (queryResult is { })
{
// Noice!
}

async Task SeedAsync()
{
IEnumerable<ExampleModel> current = await repository.GetAsync(x => x.Type == nameof(ExampleModel));

if (current.Any())
{
return;
}

await repository.CreateAsync(
[
new() { Category = "Red" },
new() { Category = "Yellow" },
new() { Category = "Blue" },
new() { Category = "Orange" },
new() { Category = "Green" },
]);
}

public class ExampleModel : Item
{
public string Category { get; set; }
}

public class ExampleSpecification : DefaultSpecification<ExampleModel>
{
public ExampleSpecification() =>
Query.Where(q => q.Category == "Red");
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,9 @@

namespace Specification;

public class FullSpecificationSamples
public class FullSpecificationSamples(IRepository<Person> repository)
{
private readonly IRepository<Person> _repository;

public FullSpecificationSamples(IRepository<Person> repository)
{
_repository = repository;
}
private readonly IRepository<Person> _repository = repository;

public async Task FullContinuationTokenSpecificationAsync(int age)
{
Expand Down
10 changes: 10 additions & 0 deletions samples/Microsoft.Azure.CosmosRepository/Specification/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,28 +25,38 @@
SpecificationPagingSamples pagingExamples = new(repository);

Console.WriteLine("Specification paging");

await pagingExamples.BasicPageAsync();

Console.WriteLine("Specification continuation token");

await pagingExamples.BasicScrollingAsync();

SpecificationOrderSamples orderSamples = new(repository);

Console.WriteLine("Simple ordering");

await orderSamples.BasicOrderAsync();

Console.WriteLine("Multiple fields ordering");

//This requires a composite index with name desc then age to work
await orderSamples.MultipleOrderByAsync();

SpecificationFilterSamples filterSamples = new(repository);

Console.WriteLine("Simple filtering");

await filterSamples.FilterSamples();

FullSpecificationSamples fullSpecificationSamples = new(repository);

Console.WriteLine("Continuation Token with query sample");

await fullSpecificationSamples.FullContinuationTokenSpecificationAsync(10);

Console.WriteLine("Offset by page number query sample");

await fullSpecificationSamples.FullPageNumberSpecificationAsync(10);

async Task SeedAsync()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,12 @@

namespace Specification;

public class SpecificationOrderSamples
public class SpecificationOrderSamples(IRepository<Person> repository)
{
private readonly IRepository<Person> _repository;

public SpecificationOrderSamples(IRepository<Person> repository)
{
_repository = repository;
}
public async Task BasicOrderAsync()
{
OrderByNameSpecification specification = new();
IQueryResult<Person> result = await _repository.QueryAsync(specification);
IQueryResult<Person> result = await repository.QueryAsync(specification);

Console.WriteLine($"Simple order first result {result.Items[0].Name}");
Console.WriteLine($"Total Charge {result.Charge} RU's");
Expand All @@ -43,7 +37,7 @@ public async Task BasicOrderAsync()
public async Task MultipleOrderByAsync()
{
OrderByMultipleFieldsSpecification specification = new();
IQueryResult<Person> result = await _repository.QueryAsync(specification);
IQueryResult<Person> result = await repository.QueryAsync(specification);

Console.WriteLine($"Multiple order first result {result.Items[0].Name}");
Console.WriteLine($"Total Charge {result.Charge} RU's");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,8 @@

namespace Specification;

public class SpecificationPagingSamples
public class SpecificationPagingSamples(IRepository<Person> repository)
{
private readonly IRepository<Person> _repository;

public SpecificationPagingSamples(IRepository<Person> repository)
{
_repository = repository;
}
public async Task BasicPageAsync()
{
double totalCharge = 0;
Expand All @@ -28,7 +22,7 @@ public async Task BasicPageAsync()
}
totalCharge += page.Charge;
specification.NextPage();
page = await _repository.QueryAsync(specification);
page = await repository.QueryAsync(specification);
Console.WriteLine($"Get page {page.PageNumber} 25 results cost {page.Charge}");
}
Console.WriteLine($"Total Charge {totalCharge} RU's");
Expand All @@ -40,7 +34,7 @@ public async Task BasicScrollingAsync()
double totalCharge = 0;

ContinuationTokenSpecification<Person> specification = new(null, pageSize: 25);
IPage<Person> page = await _repository.QueryAsync(specification);
IPage<Person> page = await repository.QueryAsync(specification);
specification.UpdateContinuationToken(page.Continuation);
var totalItems = 0;
while (totalItems < page.Total)
Expand All @@ -53,7 +47,7 @@ public async Task BasicScrollingAsync()
totalCharge += page.Charge;
Console.WriteLine($"First 25 results cost {page.Charge}");
specification.UpdateContinuationToken(page.Continuation);
page = await _repository.QueryAsync(specification);
page = await repository.QueryAsync(specification);
}

Console.WriteLine($"Last 50 results cost {page.Charge}");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,19 @@

namespace Specification;

public class SpecificationFilterSamples
public class SpecificationFilterSamples(IRepository<Person> repository)
{
private readonly IRepository<Person> _repository;

public SpecificationFilterSamples(IRepository<Person> repository)
{
_repository = repository;
}

public async Task FilterSamples()
{
AllPersonsWithNameSpecification nameSpecification = new("Tom");
IQueryResult<Person> personsWithNameTom = await _repository.QueryAsync(nameSpecification);
IQueryResult<Person> personsWithNameTom = await repository.QueryAsync(nameSpecification);

Console.WriteLine($"Found {personsWithNameTom.Items.Count} with name Tom");
Console.WriteLine($"Change for query {personsWithNameTom.Charge}");

var age = 25;
AllPersonsOlderThanSpecifciation ageSpecification = new(age);
IQueryResult<Person> peopleOlderThan25 = await _repository.QueryAsync(ageSpecification);
AllPersonsOlderThanSpecification ageSpecification = new(age);
IQueryResult<Person> peopleOlderThan25 = await repository.QueryAsync(ageSpecification);

Console.WriteLine($"Found {peopleOlderThan25.Items.Count} people older than {age}");
Console.WriteLine($"Change for query {peopleOlderThan25.Charge}");
Expand All @@ -39,9 +32,9 @@ public AllPersonsWithNameSpecification(string name)
}
}

private class AllPersonsOlderThanSpecifciation : DefaultSpecification<Person>
private class AllPersonsOlderThanSpecification : DefaultSpecification<Person>
{
public AllPersonsOlderThanSpecifciation(int age)
public AllPersonsOlderThanSpecification(int age)
{
Query.Where(p => p.Age > age);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ public async Task Post_Always_Creates_A_Language()
InitialReleaseDate = new DateTime(2001, 10, 25)
};

List<LanguageDto> languages = new()
{
List<LanguageDto> languages =
[
language
};
];

IRepository<Language> repository = _repositoryFactory.RepositoryOf<Language>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ namespace Microsoft.Azure.CosmosEventSourcing.Aggregates;
/// <inheritdoc />
public abstract class AggregateRoot : IAggregateRoot
{
private List<DomainEvent> _events = new();
private readonly List<DomainEvent> _newEvents = new();
private List<DomainEvent> _events = [];
private readonly List<DomainEvent> _newEvents = [];
private AtomicEvent? _atomicEvent;

/// <inheritdoc />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace Microsoft.Azure.CosmosEventSourcing.Converters;

internal class DomainEventConverter : JsonConverter
{
public static HashSet<Type> ConvertableTypes { get; } = new();
public static HashSet<Type> ConvertableTypes { get; } = [];

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) =>
serializer.Serialize(writer, value, value.GetType());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ private class ParameterReBinder : ExpressionVisitor
private readonly Dictionary<ParameterExpression, ParameterExpression> _map;

private ParameterReBinder(Dictionary<ParameterExpression, ParameterExpression> map) =>
_map = map ?? new();
_map = map ?? [];

internal static Expression ReplaceParameters(
Dictionary<ParameterExpression, ParameterExpression> map, Expression exp) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace Microsoft.Azure.CosmosRepository.Builders;
/// <inheritdoc/>
internal class DefaultItemContainerBuilder : IItemContainerBuilder
{
private readonly List<ContainerOptionsBuilder> _options = new();
private readonly List<ContainerOptionsBuilder> _options = [];

public IReadOnlyList<ContainerOptionsBuilder> Options => _options;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ namespace Microsoft.Azure.CosmosRepository.Builders;

internal class PatchOperationBuilder<TItem> : IPatchOperationBuilder<TItem> where TItem : IItem
{
private readonly List<PatchOperation> _patchOperations = new();
private readonly List<PatchOperation> _patchOperations = [];
private readonly NamingStrategy _namingStrategy;

internal readonly List<InternalPatchOperation> _rawPatchOperations = new();
internal readonly List<InternalPatchOperation> _rawPatchOperations = [];

public IReadOnlyList<PatchOperation> PatchOperations => _patchOperations;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ internal class ParameterRebinder : ExpressionVisitor
readonly Dictionary<ParameterExpression, ParameterExpression> _map;

internal ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map) =>
_map = map ?? new();
_map = map ?? [];

internal static Expression ReplaceParameters(
Dictionary<ParameterExpression, ParameterExpression> map, Expression exp) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,14 @@ public Expression<Func<TItem, bool>> Build<TItem>(Expression<Func<TItem, bool>>
return options.UseStrictTypeChecking ? predicate.Compose(Default<TItem>(), Expression.AndAlso) : predicate;
}

public Expression<Func<TItem, bool>> Default<TItem>() where TItem : IItem =>
item => !item.Type.IsDefined() || item.Type == typeof(TItem).Name;
public Expression<Func<TItem, bool>> Default<TItem>() where TItem : IItem
{
ItemConfiguration options = itemConfigurationProvider.GetItemConfiguration<TItem>();

return options.UseStrictTypeChecking
? item => !item.Type.IsDefined() || item.Type == typeof(TItem).Name
: item => item != null /* If strict typing isn't desired, the default is a simple not null check */;
}

public TItem CheckItem<TItem>(TItem item) where TItem : IItem
{
Expand Down
Loading

0 comments on commit 167c819

Please sign in to comment.