Skip to content

Commit

Permalink
feat: Add primitive handling to CompiledQuery result writer
Browse files Browse the repository at this point in the history
  • Loading branch information
Blackclaws authored and jeremydmiller committed Jan 26, 2024
1 parent 20c6176 commit f1c62cc
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 5 deletions.
43 changes: 39 additions & 4 deletions src/Http/Wolverine.Http.Marten/CompiledQueryWriterPolicy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using JasperFx.CodeGeneration.Frames;
using JasperFx.CodeGeneration.Model;
using JasperFx.Core.Reflection;
using Marten;
using Marten.Linq;
using Wolverine.Http.Resources;
using QueryableExtensions = Marten.AspNetCore.QueryableExtensions;
Expand Down Expand Up @@ -31,17 +32,51 @@ public bool TryApply(HttpChain chain)
if (compiledQueryClosure is null) return false;

var arguments = compiledQueryClosure.GetGenericArguments();

// If we're dealing with a primitive return type we need to write its string representation directly
if (arguments[1].IsPrimitive)
{
// This call runs the query
var queryCall =
typeof(MartenQueryMethodCall<,>).CloseAndBuildAs<MethodCall>(result, arguments);
chain.Postprocessors.Add(queryCall);

var methodCall = typeof(MartenWriteArrayMethodCall<,>).CloseAndBuildAs<MethodCall>(result, (_responseType, _successStatusCode), arguments);
// This call writes the response directly to the HttpContext as a string
var writeStringCall = MethodCall.For<HttpHandler>(handler => HttpHandler.WriteString(null!, ""));
writeStringCall.Arguments[1] = new Variable(queryCall.ReturnVariable!.VariableType,
$"{queryCall.ReturnVariable.Usage}.ToString()", queryCall);
chain.Postprocessors.Add(writeStringCall);
}
else
{

var writeJsonCall =
typeof(MartenWriteJsonToStreamMethodCall<,>).CloseAndBuildAs<MethodCall>(result,
(_responseType, _successStatusCode), arguments);
chain.Postprocessors.Add(writeJsonCall);
}

chain.Postprocessors.Add(methodCall);
return true;
}
}

public class MartenWriteArrayMethodCall<TDoc, TOut> : MethodCall
public class MartenQueryMethodCall<TDoc, TOut> : MethodCall
{
public MartenQueryMethodCall(Variable resultVariable) : base(typeof(IDocumentSession), FindMethod())
{
Arguments[0] = resultVariable;
}

static MethodInfo FindMethod()
{
return ReflectionHelper.GetMethod<IDocumentSession>(x =>
x.QueryAsync((ICompiledQuery<TDoc, TOut>)null!, default))!;
}
}

public class MartenWriteJsonToStreamMethodCall<TDoc, TOut> : MethodCall
{
public MartenWriteArrayMethodCall(Variable resultVariable, (string responseType, int successStatusCode) options) : base(typeof(QueryableExtensions), FindMethod(resultVariable))
public MartenWriteJsonToStreamMethodCall(Variable resultVariable, (string responseType, int successStatusCode) options) : base(typeof(QueryableExtensions), FindMethod(resultVariable))
{
Arguments[1] = resultVariable;
Arguments[3] = Constant.ForString(options.responseType);
Expand Down
22 changes: 22 additions & 0 deletions src/Http/Wolverine.Http.Tests/Marten/compiled_query_writer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,28 @@ public async Task endpoint_returning_compiled_list_query_should_return_query_res
approvedInvoiceList.ShouldNotBeNull();
approvedInvoiceList.Count.ShouldBe(approvedInvoices);
}

[Fact]
public async Task endpoint_returning_compiled_primitive_query_should_return_query_result()
{
await using var session = Store.LightweightSession();
int invoicesCount = 5;
for (int i = 0; i < invoicesCount; i++)
{
var invoice =
new Invoice()
{
};
session.Store(invoice);
}

await session.SaveChangesAsync();

var approvedInvoiceList = await Host.GetAsText("/invoices/compiled/count");
approvedInvoiceList.ShouldNotBeNull();
int.TryParse(approvedInvoiceList, out var result).ShouldBeTrue();
result.ShouldBe(invoicesCount);
}

[Fact]
public async Task endpoint_returning_compiled_query_should_return_query_result()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// <auto-generated/>
#pragma warning disable
using Microsoft.AspNetCore.Routing;
using System;
using System.Linq;
using Wolverine.Http;
using Wolverine.Marten.Publishing;
using Wolverine.Runtime;

namespace Internal.Generated.WolverineHandlers
{
// START: GET_invoices_compiled_count
public class GET_invoices_compiled_count : Wolverine.Http.HttpHandler
{
private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions;
private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime;
private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory;

public GET_invoices_compiled_count(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions, Wolverine.Runtime.IWolverineRuntime wolverineRuntime, Wolverine.Marten.Publishing.OutboxedSessionFactory outboxedSessionFactory) : base(wolverineHttpOptions)
{
_wolverineHttpOptions = wolverineHttpOptions;
_wolverineRuntime = wolverineRuntime;
_outboxedSessionFactory = outboxedSessionFactory;
}



public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext)
{
var messageContext = new Wolverine.Runtime.MessageContext(_wolverineRuntime);
// Building the Marten session
await using var documentSession = _outboxedSessionFactory.OpenSession(messageContext);

// The actual HTTP request handler execution
var compiledCountQuery = WolverineWebApi.Marten.InvoicesEndpoint.GetCompiledCount();

var result_of_QueryAsync = await documentSession.QueryAsync<WolverineWebApi.Marten.Invoice, int>(compiledCountQuery, httpContext.RequestAborted).ConfigureAwait(false);
await Wolverine.Http.HttpHandler.WriteString(httpContext, result_of_QueryAsync.ToString()).ConfigureAwait(false);
}

}

// END: GET_invoices_compiled_count


}

16 changes: 15 additions & 1 deletion src/Http/WolverineWebApi/Marten/Documents.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ public static ByIdCompiled GetCompiled(Guid id)
{
return new ByIdCompiled(id);
}

[WolverineGet("/invoices/compiled/count")]
public static CompiledCountQuery GetCompiledCount()
{
return new CompiledCountQuery();
}
}

public class Invoice
Expand Down Expand Up @@ -104,4 +110,12 @@ public ByIdCompiled(Guid id)
{
return q => q.FirstOrDefault(x => x.Id == Id);
}
}
}

public class CompiledCountQuery : ICompiledQuery<Invoice, int>
{
public Expression<Func<IMartenQueryable<Invoice>, int>> QueryIs()
{
return q => q.Count();
}
}

0 comments on commit f1c62cc

Please sign in to comment.