Skip to content

Commit

Permalink
Refactor
Browse files Browse the repository at this point in the history
Preparations for implementing IQueryable<TModel> with SetContexts
  • Loading branch information
YuriyDurov committed Jan 7, 2024
1 parent 6c97598 commit 18195e9
Show file tree
Hide file tree
Showing 77 changed files with 463 additions and 232 deletions.
2 changes: 1 addition & 1 deletion src/BitzArt.Flux.Json/BitzArt.Flux.Json.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/BitzArt/Flux</RepositoryUrl>
<PackageProjectUrl>https://github.com/BitzArt/Flux</PackageProjectUrl>
<PackageProjectUrl>https://bitzart.github.io/Flux</PackageProjectUrl>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageIcon>flux-logo-128.png</PackageIcon>
</PropertyGroup>
Expand Down
7 changes: 7 additions & 0 deletions src/BitzArt.Flux.Json/Exceptions/FluxItemNotFoundException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace BitzArt.Flux;

internal class FluxItemNotFoundException<TModel> : Exception
{
public FluxItemNotFoundException(object? id) : base($"{typeof(TModel).Name} with key {id} was not found")
{ }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace BitzArt.Flux;

internal class FluxJsonMissingDataException : Exception
{
public FluxJsonMissingDataException() : base("Missing set data. Consider populating the set with json data when configuring Flux.")
{ }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace BitzArt.Flux;

internal class FluxKeyPropertyExpressionMissingException<TModel> : Exception
{
public FluxKeyPropertyExpressionMissingException() : base($"KeyPropertyExpression is required for {typeof(TModel).Name}. Consider using .WithKey() when configuring a Set.")
{
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace BitzArt.Flux;

public interface IFluxJsonSetBuilder<TModel> : IFluxModelBuilder, IFluxJsonServiceBuilder
public interface IFluxJsonSetBuilder<TModel> : IFluxJsonServiceBuilder
where TModel : class
{
public FluxJsonSetOptions<TModel> SetOptions { get; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,15 +125,3 @@ public IFluxSetContext<TModel, TKey> CreateSetContext<TModel, TKey>(IServiceProv
return new FluxJsonSetContext<TModel, TKey>(_serviceOptions, logger, options);
}
}

internal class SetConfigurationNotFoundException : Exception
{
public SetConfigurationNotFoundException() : base("Requested Set Configuration was not found.")
{ }
}

internal class SetAlreadyRegisteredException : Exception
{
public SetAlreadyRegisteredException(string name) : base($"An unnamed Flux Set for a model '{name}' was already registered previously. Consider giving specific names to different sets for this model.")
{ }
}
42 changes: 42 additions & 0 deletions src/BitzArt.Flux.Json/Models/FluxJsonSetContext{TModel,TKey}.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using Microsoft.Extensions.Logging;

namespace BitzArt.Flux;

internal class FluxJsonSetContext<TModel, TKey> : FluxJsonSetContext<TModel>, IFluxSetContext<TModel, TKey>
where TModel : class
{
// ================ Flux internal wiring ================

internal new FluxJsonSetOptions<TModel, TKey> SetOptions
{
get => (FluxJsonSetOptions<TModel, TKey>)_setOptions;
set => _setOptions = value;
}

// ==================== Constructor ====================

public FluxJsonSetContext(FluxJsonServiceOptions serviceOptions, ILogger logger, FluxJsonSetOptions<TModel, TKey> setOptions)
: base(serviceOptions, logger, setOptions)
{
SetOptions = setOptions;
}

// ============== Methods implementation ==============

public override Task<TModel> GetAsync(object? id, params object[]? parameters) => GetAsync((TKey?)id, parameters);

public Task<TModel> GetAsync(TKey? id, params object[]? parameters)
{
_logger.LogInformation("Get {type}[{id}]", typeof(TModel).Name, id is not null ? id.ToString() : "_");

var existingItem = SetOptions.Items!.FirstOrDefault(item =>
{
if (SetOptions.KeyPropertyExpression is null) throw new FluxKeyPropertyExpressionMissingException<TModel>();

var itemId = SetOptions.KeyPropertyExpression.Compile().Invoke(item);
return Equals(itemId, id);
}) ?? throw new FluxItemNotFoundException<TModel>(id);

return Task.FromResult(existingItem);
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
using BitzArt.Pagination;
using Microsoft.Extensions.Logging;
using System.Collections;
using System.Linq.Expressions;

namespace BitzArt.Flux;

internal class FluxJsonSetContext<TModel> : IFluxSetContext<TModel>
internal class FluxJsonSetContext<TModel> : IFluxSetContext<TModel>
where TModel : class
{
// ================ Flux internal wiring ================

internal readonly FluxJsonServiceOptions ServiceOptions;
internal readonly ILogger _logger;

Expand All @@ -16,13 +20,35 @@ internal virtual FluxJsonSetOptions<TModel> SetOptions
set => _setOptions = value;
}

// ==================== Constructor ====================

public FluxJsonSetContext(FluxJsonServiceOptions serviceOptions, ILogger logger, FluxJsonSetOptions<TModel> setOptions)
{
ServiceOptions = serviceOptions;
_logger = logger;
_setOptions = setOptions;
}


// ================ Linking parsed data ================

public ICollection<TModel> Items => SetOptions.Items ?? throw new FluxJsonMissingDataException();
private IQueryable<TModel> Query => Items.AsQueryable();

// ============== IEnumerable implementation ==============

public IEnumerator<TModel> GetEnumerator() => Items.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();

// ============== IQueryable implementation ==============

public Type ElementType => typeof(TModel);

public Expression Expression => Query.Expression;

public IQueryProvider Provider => Query.Provider;

// ============== Data methods implementation ==============

public virtual Task<IEnumerable<TModel>> GetAllAsync(params object[]? parameters)
{
_logger.LogInformation("GetAll {type}", typeof(TModel).Name);
Expand Down Expand Up @@ -57,49 +83,3 @@ public virtual Task<TModel> GetAsync(object? id, params object[]? parameters)
return Task.FromResult(existingItem);
}
}

internal class FluxJsonSetContext<TModel, TKey> : FluxJsonSetContext<TModel>, IFluxSetContext<TModel, TKey>
where TModel : class
{
internal new FluxJsonSetOptions<TModel, TKey> SetOptions
{
get => (FluxJsonSetOptions<TModel, TKey>)_setOptions;
set => _setOptions = value;
}

public FluxJsonSetContext(FluxJsonServiceOptions serviceOptions, ILogger logger, FluxJsonSetOptions<TModel, TKey> setOptions)
: base(serviceOptions, logger, setOptions)
{
SetOptions = setOptions;
}

public override Task<TModel> GetAsync(object? id, params object[]? parameters) => GetAsync((TKey?)id, parameters);

public Task<TModel> GetAsync(TKey? id, params object[]? parameters)
{
_logger.LogInformation("Get {type}[{id}]", typeof(TModel).Name, id is not null ? id.ToString() : "_");

var existingItem = SetOptions.Items!.FirstOrDefault(item =>
{
if (SetOptions.KeyPropertyExpression is null) throw new FluxKeyPropertyExpressionMissingException<TModel>();

var itemId = SetOptions.KeyPropertyExpression.Compile().Invoke(item);
return Equals(itemId, id);
}) ?? throw new FluxItemNotFoundException<TModel>(id);

return Task.FromResult(existingItem);
}
}

internal class FluxItemNotFoundException<TModel> : Exception
{
public FluxItemNotFoundException(object? id) : base($"{typeof(TModel).Name} with key {id} was not found")
{ }
}

internal class FluxKeyPropertyExpressionMissingException<TModel> : Exception
{
public FluxKeyPropertyExpressionMissingException() : base($"KeyPropertyExpression is required for {typeof(TModel).Name}. Consider using .WithKey() when configuring a Set.")
{
}
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,7 @@
using System.Linq.Expressions;
using System.Linq.Expressions;

namespace BitzArt.Flux;

public class FluxJsonSetOptions<TModel>
where TModel : class
{
public ICollection<TModel>? Items { get; set; }
protected Expression<Func<TModel, object>>? _keyPropertyExpression;

public Expression<Func<TModel, object>>? KeyPropertyExpression
{
get => _keyPropertyExpression;
set => _keyPropertyExpression = value;
}
}

public class FluxJsonSetOptions<TModel, TKey> : FluxJsonSetOptions<TModel>
where TModel : class
{
Expand Down
17 changes: 17 additions & 0 deletions src/BitzArt.Flux.Json/Options/FluxJsonSetOptions{TModel}.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System.Linq.Expressions;

namespace BitzArt.Flux;

public class FluxJsonSetOptions<TModel>
where TModel : class
{
public ICollection<TModel>? Items { get; set; }

protected Expression<Func<TModel, object>>? _keyPropertyExpression;

public Expression<Func<TModel, object>>? KeyPropertyExpression
{
get => _keyPropertyExpression;
set => _keyPropertyExpression = value;
}
}
2 changes: 1 addition & 1 deletion src/BitzArt.Flux.REST/BitzArt.Flux.REST.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/BitzArt/Flux</RepositoryUrl>
<PackageProjectUrl>https://github.com/BitzArt/Flux</PackageProjectUrl>
<PackageProjectUrl>https://bitzart.github.io/Flux</PackageProjectUrl>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageIcon>flux-logo-128.png</PackageIcon>
</PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace BitzArt.Flux;

internal class FluxRestKeyNotFoundException<TModel> : Exception
{
private static readonly string Msg = $"Unable to find TKey for type '{typeof(TModel).Name}'. Consider specifying a key when registering the set.";
public FluxRestKeyNotFoundException() : base(Msg) { }
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace BitzArt.Flux;

public interface IFluxRestSetBuilder<TModel> : IFluxModelBuilder, IFluxRestServiceBuilder
public interface IFluxRestSetBuilder<TModel> : IFluxRestServiceBuilder
where TModel : class
{
public FluxRestSetOptions<TModel> SetOptions { get; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,15 +127,3 @@ public IFluxSetContext<TModel, TKey> CreateSetContext<TModel, TKey>(IServiceProv
return new FluxRestSetContext<TModel, TKey>(httpClient, _serviceOptions, logger, options);
}
}

internal class SetConfigurationNotFoundException : Exception
{
public SetConfigurationNotFoundException() : base("Requested Set Configuration was not found.")
{ }
}

internal class SetAlreadyRegisteredException : Exception
{
public SetAlreadyRegisteredException(string name) : base($"An unnamed Flux Set for a model '{name}' was already registered previously. Consider giving specific names to different sets for this model.")
{ }
}
14 changes: 14 additions & 0 deletions src/BitzArt.Flux.REST/Models/FluxRestSetBuilder{TModel, TKey}.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using Microsoft.Extensions.DependencyInjection;

namespace BitzArt.Flux;

internal class FluxRestSetBuilder<TModel, TKey> : FluxRestSetBuilder<TModel>, IFluxRestSetBuilder<TModel, TKey>
where TModel : class
{
public new FluxRestSetOptions<TModel, TKey> SetOptions { get; set; }

public FluxRestSetBuilder(IFluxRestServiceBuilder serviceBuilder) : base(serviceBuilder)
{
SetOptions = new();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,3 @@ public FluxRestSetBuilder(IFluxRestServiceBuilder serviceBuilder)
SetOptions = new();
}
}

internal class FluxRestSetBuilder<TModel, TKey> : FluxRestSetBuilder<TModel>, IFluxRestSetBuilder<TModel, TKey>
where TModel : class
{
public new FluxRestSetOptions<TModel, TKey> SetOptions { get; set; }

public FluxRestSetBuilder(IFluxRestServiceBuilder serviceBuilder) : base(serviceBuilder)
{
SetOptions = new();
}
}
51 changes: 51 additions & 0 deletions src/BitzArt.Flux.REST/Models/FluxRestSetContext{TModel,TKey}.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using Microsoft.Extensions.Logging;

namespace BitzArt.Flux;

internal class FluxRestSetContext<TModel, TKey> : FluxRestSetContext<TModel>, IFluxSetContext<TModel, TKey>
where TModel : class
{
// ================ Flux internal wiring ================

internal new FluxRestSetOptions<TModel, TKey> SetOptions
{
get => (FluxRestSetOptions<TModel, TKey>)_setOptions;
set => _setOptions = value;
}

// ==================== Constructor ====================

public FluxRestSetContext(HttpClient httpClient, FluxRestServiceOptions serviceOptions, ILogger logger, FluxRestSetOptions<TModel, TKey> setOptions)
: base(httpClient, serviceOptions, logger, setOptions)
{
SetOptions = setOptions;
}

// ============== Data methods implementation ==============

public override Task<TModel> GetAsync(object? id, params object[]? parameters) => GetAsync((TKey?)id, parameters);

public async Task<TModel> GetAsync(TKey? id, params object[]? parameters)
{
string idEndpoint;

bool handleParameters = false;
if (SetOptions.GetIdEndpointAction is not null)
{
idEndpoint = SetOptions.GetIdEndpointAction(id, parameters);
}
else
{
idEndpoint = SetOptions.Endpoint is not null ? Path.Combine(SetOptions.Endpoint, id!.ToString()!) : id!.ToString()!;
handleParameters = true;
}
var parse = GetFullPath(idEndpoint, handleParameters, parameters);

_logger.LogInformation("Get {type}[{id}]: {route}{parsingLog}", typeof(TModel).Name, id!.ToString(), parse.Result, parse.Log);

var message = new HttpRequestMessage(HttpMethod.Get, parse.Result);
var result = await HandleRequestAsync<TModel>(message);

return result;
}
}
Loading

0 comments on commit 18195e9

Please sign in to comment.