2

I need to execute my queries as string instead of lambda expressions because I am having a hard time using mocking frameworks in order to create unit tests for my projects.

In other words, I want to modify my IDatabase interface from:

Interface IDatabase 
{
    IEnumerable<User> Find(Expression<Func<User, bool>> filter);
}

To:

Interface IDatabase 
{
    IEnumerable<User> Find(string query);
}

I already have a lot of my queries written with expressions. As a result, I have created this code to convert an expression to a JSON object:

using MongoDB.Driver;
using System.Linq.Expressions;

class Program
{

    // Example of a collection I store on my DB
    class User
    {
        public string _id { get; set; }

        public string Name { get; set; }

        public DateTime DateCreated { get; set; }
    }

    // Main method
    public static void Main()
    {
        var json = ExpressionToJson<User>(x => x.Name.Contains("Tono") && x.DateCreated < DateTime.UtcNow);

        // outputs:
        // { "Name" : /Tono/s, "DateCreated" : { "$lt" : ISODate("2022-01-21T01:21:27.975Z") } }
        Console.WriteLine(json);

    }

    /// <summary>
    ///     Method that will convert an expression to a string
    /// </summary>
    public static string ExpressionToJson<T>(Expression<Func<T, bool>> filter)
    {
        MongoClient MongoClient = new MongoClient();

        var db1 = MongoClient.GetDatabase("DoesNotMatter");

        var collection = db1.GetCollection<T>("DoesNotMatter");

        var query = collection.Find(filter);

        var json = query.ToString();

        if (string.IsNullOrEmpty(json))
            return "{}";

        // json should look something like this
        // find({ "Name" : /Tono/s, "DateCreated" : { "$lt" : ISODate("2022-01-21T01:11:47.772Z") } })

        // remove the find( at the beginning and last parenthesis
        if (json.StartsWith("find("))
            return json.Substring(5, json.Length - 6);

        throw new NotImplementedException("Did serializer changed?");
    }

}

As you can see this code can convert the expression

x => x.Name.Contains("Tono") && x.DateCreated < DateTime.UtcNow

to JSON

{ "Name" : /Tono/s, "DateCreated" : { "$lt" : ISODate("2022-01-21T01:24:38.628Z") } }

How can I simplify the ExpressionToJson method? It will be cool if I could avoid having to create an instance of MongoClient then an instance of a Database then an instance of IMongoCollection<TDocument> to just serialize the expression as I need it.

1 Answer 1

4

Perhaps, you can write an IMongoCollection extension method and adopt IFindFluent<T, T>.Filter.Render (similar to this question) to generate the filter query in JSON.

public static class IMongoCollectionExtensions
{
    public static string ExpressionToJson<T>(this IMongoCollection<T> collection, Expression<Func<T, bool>> filter)
    {
        var query = collection.Find(filter);

        return query.Filter.Render(
            collection.DocumentSerializer,
            collection.Settings.SerializerRegistry
        ).ToJson();
    }
}
var jsonQuery = collection.ExpressionToJson<User>(x => x.Name.Contains("Tono")
    && x.DateCreated < DateTime.UtcNow);

Output

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.