You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Connected.Framework.Service.../Connected.ServiceModel.Clie.../TableStorageProvider.cs

115 lines
3.2 KiB

using System.Linq.Expressions;
using System.Reflection;
using Connected.Annotations;
using Connected.Data;
using Connected.Data.Storage;
using Connected.Entities;
using Connected.Entities.Storage;
using Connected.Expressions;
using Connected.Expressions.Evaluation;
using Connected.Expressions.Query;
using Connected.Expressions.Translation;
using Connected.Interop;
using Connected.ServiceModel.Data;
namespace Connected.ServiceModel.Client.Data;
[Priority(2)]
internal class TableStorageProvider : QueryProvider, IStorageExecutor, IStorageMiddleware
{
public TableStorageProvider(IStorageProvider storage)
{
Storage = storage;
}
private IStorageProvider Storage { get; }
protected override object? OnExecute(Expression expression)
{
return CreateExecutionPlan(expression).Compile()(this);
}
private static Expression<Func<IStorageExecutor, object>> CreateExecutionPlan(Expression expression)
{
var lambda = expression as LambdaExpression;
if (lambda is not null)
expression = lambda.Body;
var context = new ExpressionCompilationContext(new CqlLanguage());
var translator = new Translator(context);
var translation = translator.Translate(expression);
var parameters = lambda?.Parameters;
var provider = Resolve(expression, parameters, typeof(IStorage<>));
if (provider is null)
{
var rootQueryable = Resolve(expression, parameters, typeof(IQueryable));
provider = Expression.Property(rootQueryable, typeof(IQueryable).GetTypeInfo().GetDeclaredProperty(nameof(IQueryable.Provider)));
}
return ExecutionBuilder.Build(context, new CqlLinguist(context, CqlLanguage.Default, translator), translation, provider);
}
/// <summary>
/// Find the expression of the specified type, either in the specified expression or parameters.
/// </summary>
private static Expression Resolve(Expression expression, IList<ParameterExpression> parameters, Type type)
{
if (parameters is not null)
{
var found = parameters.FirstOrDefault(p => type.IsAssignableFrom(p.Type));
if (found is not null)
return found;
}
return SubtreeResolver.Resolve(expression, type);
}
public IEnumerable<TResult?> Execute<TResult>(IStorageOperation operation)
where TResult : IEntity
{
var result = Storage.Open<TResult>().Query(new StorageContextArgs(operation));
if (result.IsCompleted)
return result.Result;
var r = result.GetAwaiter().GetResult();
return r;
}
public bool SupportsEntity(Type entityType)
{
return entityType.ImplementsInterface(typeof(ITableEntity<>));
}
public IStorageOperation CreateOperation<TEntity>(TEntity entity)
where TEntity : IEntity
{
var builder = new AggregatedCommandBuilder<TEntity?>();
if (builder.Build(entity) is not StorageOperation operation)
throw new NullReferenceException(nameof(StorageOperation));
return operation;
}
public IStorageReader<TEntity> OpenReader<TEntity>(IStorageOperation operation, IStorageConnection connection)
{
return new TableReader<TEntity>(operation, connection);
}
public IStorageWriter OpenWriter(IStorageOperation operation, IStorageConnection connection)
{
return new TableWriter(operation, connection);
}
public async Task Initialize()
{
await Task.CompletedTask;
}
}