Gremlinq / ExRam.Gremlinq

A .NET object-graph-mapper for Apache TinkerPop™ Gremlin enabled databases.
MIT License
184 stars 33 forks source link

Support for Dynamic LINQ in ExRam.Gremlinq #1738

Open nongvantinh opened 1 week ago

nongvantinh commented 1 week ago

I'm moving from Entity Framework Core SQLServer to Cosmos DB for Gremlin. However, I am stuck in the querying process; there is not much information about its usage on the internet. So, I must ask my question here: Is it possible to use dynamic LINQ in Gremlinq, like in the code below?

// GET: api/v{version:apiVersion}/Accounts/?pageIndex=0&pageSize=10&sortColumn=email&sortOrder=asc
[HttpGet]
public async Task<ActionResult<ApiResult<AccountDTO>>> GetAccounts(
    int pageIndex = 0,
    int pageSize = 10,
    string? sortColumn = null,
    string? sortOrder = null,
    string? filterColumn = null,
    string? filterQuery = null)
{
    if (_context.Accounts == null)
    {
        return NotFound();
    }

    Func<IQueryable<Account>, IQueryable<Account>>? queryCallback = null;
    if (!string.IsNullOrEmpty(filterColumn) &&
        !string.IsNullOrEmpty(filterQuery) &&
        ApiResult<Account>.IsValidProperty(filterColumn))
    {
        queryCallback = (query) =>
        {
            query = query.Where(string.Format("{0}.StartsWith(@0)", filterColumn), filterQuery);
            if (!string.IsNullOrEmpty(sortColumn) && ApiResult<Account>.IsValidProperty(sortColumn))
            {
                sortOrder = !string.IsNullOrEmpty(sortOrder) && sortOrder.Equals("ASC", StringComparison.OrdinalIgnoreCase) ? "ASC" : "DESC";
                return query.OrderBy(string.Format("{0} {1}", sortColumn, sortOrder));
            }
            return query;
        };
    }

    IQueryable<Account> source = _context.Accounts.AsNoTracking();
    ApiResult<AccountDTO> apiResult = await ApiResult<AccountDTO>.CreateAsync(
        source,
        pageIndex,
        pageSize,
        projection => new AccountDTO(projection),
        queryCallback
    );

    return Ok(apiResult);
}
danielcweber commented 1 week ago

What exactly do you mean? Can you pinpoint the relevant part of your example to show what you're trying to achieve? Is it the part where you create a query string to execute?

nongvantinh commented 1 week ago

Sorry for the confusion. What I need is to work with dynamic properties for the Where and OrderBy clauses like this:

query = query.Where(string.Format("{0}.StartsWith(@0)", filterColumn), filterQuery);
query.OrderBy(string.Format("{0} {1}", sortColumn, sortOrder));

As I try to achieve this behavior, I see that I can only use strongly-typed methods for the Where and OrderBy clauses, like this:

gremlinQuerySource.V<Account>().Where(account => account.Email == email); // Same goes with all other properties in Account class
gremlinQuerySource.V<Account>().Order(orderBuilder => orderBuilder.By(account => account.FullName));

In my previous database, I used System.Linq.Dynamic to interact with various properties in a class dynamically, depending on user input. For example, the Account table ("vertex") contains columns such as [id, email, phoneNumber, ...], allowing users to sort and filter based on one of these columns. However, as I am new to GremlinQ, I am unsure if it is possible to achieve similar behavior.

danielcweber commented 1 week ago

Would this work for you?