Skip to content

Commit

Permalink
Tests!
Browse files Browse the repository at this point in the history
  • Loading branch information
Chris Skardon committed Oct 2, 2020
1 parent e98ffae commit 8b581a5
Show file tree
Hide file tree
Showing 7 changed files with 688 additions and 81 deletions.
102 changes: 57 additions & 45 deletions Neo4j.Driver.Extensions/AsyncSessionExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,67 +1,79 @@
namespace Neo4j.Driver.Extensions
{
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using EnsureThat;

/// <summary>
/// Extension methods for the <see cref="IAsyncSession" />
/// </summary>
public static class AsyncSessionExtensions
{
public static async Task<T> RunReadTransactionForNodeResults<T>(this IAsyncSession session, string query, object parameters, string identifier)
/// <summary>
/// Executes a <see cref="IAsyncSession.ReadTransactionAsync{T}(System.Func{IAsyncTransaction,Task{T}})" /> transaction
/// returning the <typeparamref name="T" /> specified.
/// </summary>
/// <remarks>
/// This should be used with queries returning <see cref="INode" /> values, for example: <c>MATCH (n) RETURN n</c>
/// </remarks>
/// <typeparam name="T">The type to attempt to cast to. This should be a class.</typeparam>
/// <param name="session">The <see cref="IAsyncSession" /> to run the transaction on.</param>
/// <param name="query">The query to execute.</param>
/// <param name="parameters">The parameters to the query.</param>
/// <param name="identifier">
/// The identifier to cast into <typeparamref name="T" />. e.g. if the query is
/// <c>MATCH (n) RETURN n</c> the identifier is <c>n</c>.
/// </param>
/// <returns>The results of the query.</returns>
public static async Task<IEnumerable<T>> RunReadTransactionForObjects<T>(this IAsyncSession session, string query, object parameters, string identifier)
where T : new()
{
var results = await session.ReadTransactionAsync(async work =>
{
var cursor = await work.RunAsync(query, parameters);
var fetched = await cursor.FetchAsync();

while (fetched)
{
var node = cursor.Current[identifier].As<INode>();
return node.ToObject<T>();
}

return default;
});
Ensure.That(session).IsNotNull();
Ensure.That(query).IsNotNullOrWhiteSpace();
Ensure.That(identifier).IsNotNullOrWhiteSpace();

return results;
return await session.ReadTransactionAsync(tx => ReadTransactionAsList(tx, query, parameters, cursor => cursor.Current.ToObject<T>(identifier)));
}

public static async Task<T> RunReadTransaction<T>(this IAsyncSession session, string query, object parameters, string identifier)
where T : new()
/// <summary>
/// Executes a <see cref="IAsyncSession.ReadTransactionAsync{T}(System.Func{IAsyncTransaction,Task{T}})" /> transaction
/// returning the <typeparamref name="T" /> specified.
/// </summary>
/// <remarks>
/// This should be used with queries not returning <see cref="INode" /> values, for example:
/// <c>MATCH (n) RETURN n.title AS title</c>
/// </remarks>
/// <typeparam name="T">The type to attempt to cast to. This should be a class.</typeparam>
/// <param name="session">The <see cref="IAsyncSession" /> to run the transaction on.</param>
/// <param name="query">The query to execute.</param>
/// <param name="parameters">The parameters to the query.</param>
/// <param name="identifier">
/// The identifier to cast into <typeparamref name="T" />. e.g. if the query is
/// <c>MATCH (n) RETURN n.title AS title</c> the identifier is <c>title</c>.
/// </param>
/// <returns>The results of the query.</returns>
public static async Task<IEnumerable<T>> RunReadTransaction<T>(this IAsyncSession session, string query, object parameters, string identifier)
{
var results = await session.ReadTransactionAsync(async work =>
{
var cursor = await work.RunAsync(query, parameters);
var fetched = await cursor.FetchAsync();
Ensure.That(session).IsNotNull();
Ensure.That(query).IsNotNullOrWhiteSpace();
Ensure.That(identifier).IsNotNullOrWhiteSpace();

while (fetched)
{
return cursor.Current[identifier].As<T>();
}

return default;
});

return results;
return await session.ReadTransactionAsync(tx => ReadTransactionAsList(tx, query, parameters, cursor => cursor.GetValue<T>(identifier)));
}

public static async Task<IEnumerable<T>> RunReadTransactionEnumerable<T>(this IAsyncSession session, string query, object parameters, string identifier)
where T : new()
internal static async Task<List<T>> ReadTransactionAsList<T>(this IAsyncTransaction tx, string query, object parameters, Func<IResultCursor, T> conversionFunction)
{
var results = await session.ReadTransactionAsync(async work =>
var cursor = await tx.RunAsync(query, parameters);
var fetched = await cursor.FetchAsync();
var output = new List<T>();
while (fetched)
{
var cursor = await work.RunAsync(query, parameters);
var fetched = await cursor.FetchAsync();
var output = new List<T>();
while (fetched)
{
output.Add(cursor.Current[identifier].As<T>());
fetched = await cursor.FetchAsync();
}

return output;
});
output.Add(conversionFunction(cursor));
fetched = await cursor.FetchAsync();
}

return results;
return output;
}
}
}
105 changes: 105 additions & 0 deletions Neo4j.Driver.Extensions/Neo4j.Driver.Extensions.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 23 additions & 0 deletions Neo4j.Driver.Extensions/RecordExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
using System.Linq;
using EnsureThat;

/// <summary>
/// Extension methods for the <see cref="IRecord"/>
/// </summary>
public static class RecordExtensions
{
/// <summary>
Expand Down Expand Up @@ -34,6 +37,7 @@ public static class RecordExtensions

return obj;
}

/// <summary>
/// Gets a value from an <see cref="IRecord" /> instance.
/// </summary>
Expand All @@ -55,6 +59,25 @@ public static T GetValue<T>(this IRecord record, string identifier)
: default;
}

/// <summary>
/// Gets a value from an <see cref="IRecord" /> instance. Throwing a <see cref="KeyNotFoundException"/> if the property isn't there.
/// </summary>
/// <typeparam name="T">The <see cref="Type" /> to attempt to get the property as.</typeparam>
/// <param name="record">The <see cref="IRecord" /> instance to pull the property from.</param>
/// <param name="identifier">The name of the identifier to get.</param>
/// <returns>The converted <typeparamref name="T" /> or <c>default</c></returns>
/// <exception cref="KeyNotFoundException">Thrown if the property doesn't exist</exception>
public static T GetValueStrict<T>(this IRecord record, string identifier)
{
Ensure.That(record).IsNotNull();
Ensure.That(identifier).IsNotEmptyOrWhiteSpace();

if(record.Keys.Contains(identifier))
return record.Values[identifier].As<T>();

throw new KeyNotFoundException($"'{identifier}' doesn't exist on the Record.");
}

/// <summary>
/// Gets a value from an <see cref="IRecord"/> instance, by executing
/// the <see cref="GetValue{T}" /> method via reflection.
Expand Down
Loading

0 comments on commit 8b581a5

Please sign in to comment.