Skip to content

Instantly share code, notes, and snippets.

@jokokko
Last active March 10, 2016 17:26
Show Gist options
  • Save jokokko/fa0edf4673dbd43d5fb1 to your computer and use it in GitHub Desktop.
Save jokokko/fa0edf4673dbd43d5fb1 to your computer and use it in GitHub Desktop.
Marten / Projecting documents
public class ProjectionSource
{
public Guid Id = Guid.NewGuid();
public string Value { get; set; }
public int AnotherValue { get; set; }
public object ThirdValue { get; set; }
}
public class ProjectionTarget
{
public string Value { get; set; }
public object ThirdValue { get; set; }
}
public class project_document_Tests : DocumentSessionFixture<NulloIdentityMap>
{
[Fact]
public void project_a_persisted_document()
{
var projectionSource = new ProjectionSource() {Value = "Value", AnotherValue = int.MaxValue, ThirdValue = DateTime.UtcNow };
theSession.Store(projectionSource);
theSession.SaveChanges();
var projection = ProjectionBuilder<ProjectionSource>.Project().Include(i => i.Value).Include(i => i.ThirdValue).To<ProjectionTarget>();
var projectedValue = theContainer.GetInstance<IDocumentStore>().Project(projectionSource.Id, projection);
Assert.Equal(projectionSource.Value, projectedValue.Value);
Assert.Equal(projectionSource.ThirdValue, projectedValue.ThirdValue);
}
}
public static class QuerySessionExtensions
{
public static TProjection Project<TSource, TProjection>(this IDocumentStore store, object id, Projection<TSource, TProjection> projection) where TSource : class where TProjection : class
{
using (var session = store.QuerySession())
{
var mapping = store.Schema.MappingFor(typeof (TSource));
var jsonSelectors = string.Join(",", projection.PropertiesToInclude.Select(x => $"'{x}',{mapping.TableName}.data->'{x}'"));
var projectionQuery = session.Connection.CreateCommand($"select json_build_object({ jsonSelectors }) from { mapping.TableName } where id = :id").With("id", id);
using (var reader = projectionQuery.ExecuteReader())
{
var found = reader.Read();
return found ? store.Advanced.Options.Serializer().FromJson<TProjection>(reader.GetString(0)) : null;
}
}
}
}
public class Projection<TSource, TProjection>
{
public readonly IEnumerable<string> PropertiesToInclude;
public Projection(IEnumerable<string> propertiesToInclude)
{
PropertiesToInclude = propertiesToInclude;
}
}
public class ProjectionBuilder<TSource>
{
private readonly IEnumerable<string> propertiesToInclude;
private ProjectionBuilder()
{
propertiesToInclude = Enumerable.Empty<string>();
}
public ProjectionBuilder(IEnumerable<string> propertiesToInclude)
{
this.propertiesToInclude = propertiesToInclude;
}
public static ProjectionBuilder<TSource> Project()
{
return new ProjectionBuilder<TSource>();
}
public ProjectionBuilder<TSource> Include(Expression<Func<TSource, object>> field)
{
var expression = (MemberExpression)field.Body;
var name = expression.Member.Name;
return new ProjectionBuilder<TSource>(propertiesToInclude.Concat(new[] { name }));
}
public Projection<TSource, TProjection> To<TProjection>()
{
return new Projection<TSource, TProjection>(propertiesToInclude);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment