-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement QueryProvider for converting from IQueryable to Json string #20 #23
Conversation
@piotrczyz I is now ready for review and I think it is time to test it against an real api endpoint, not just the mockup API. |
Nice work, In regards to the toString function, you say you removed it within the expression, so just wonder how you can debug or log the expressions nicely without it? |
I did not know that
@u12206050 would that be fine with you? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be nice to discuss the implementation as I found it more complex than the solution created in Core API. Interesting to hear from you which part of Core API was not flexible enough.
/// <param name="path"></param> | ||
/// <typeparam name="T"></typeparam> | ||
/// <returns></returns> | ||
public static IQueryable<T> GetAsQueryable<T>(this IApiClient apiClient, string path) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The example in Core.Api suits better as it creates a client as a transient scope.
services.AddHttpClient();
services.AddTransient<ICoreApiClient>(x =>
{
var clientFactory = x.GetRequiredService<IHttpClientFactory>();
return new CoreApiClient(options, clientFactory);
});
services.AddTransient(x => x.GetRequiredService<ICoreApiClient>().Persons );
services.AddTransient(x => x.GetRequiredService<ICoreApiClient>().Countries );
services.AddTransient(x => x.GetRequiredService<ICoreApiClient>().Relations );
services.AddTransient(x => x.GetRequiredService<ICoreApiClient>().Affiliations );
services.AddTransient(x => x.GetRequiredService<ICoreApiClient>().Consents );
services.AddTransient(x => x.GetRequiredService<ICoreApiClient>().Orgs );
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. I see we need something like DbSet<T>
for the API...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please check out my new version of the sample ApiClientMockup class.
I renamed now the extension method from GetAsQueryable
to GetQueryable
to have the same naming as the Core API. But the generic type parameter and the path
parameter are still required.
I am not anymore sure if we should keep the extension method. It would be possible that the ApiClient holds a instance of ApiQueryProvider
as well. The static typed properties could instanciate a ApiQueryable
instance on calling. I did not spend so much time on how the queryable logic should be integrated with the API client... maybe someone has better ideas
Yes, we can arrange a meeting for that. Lets talk on discord about it. Just some lines to explain myself here: The comment IQueryable<T> persons = api.Persons;
Dictionary<string, bool> euCountries = new Dictionary<string, bool>
{
{"NO", false}.
{"PL", true},
{"DE", true}
};
// sorry for running simplified linq here ...
var query = from p in persons
join euCountry in euCountries on euCountry.Key equals p.Country
where euCountry.Value == true
select p; would never be possible. Now it should be possible (even tho I did not implement it yet). This is made possible because we visit the expression tree and replaces the parts in place which the API can handle. The other parts just remain in the expression tree and are client evaluated. (This might end up in may API calls ... but that is something we need to bring up somewhere else I think. I think w should not limit the developer functions but rather the number of allowed API calls when it gets too heavy). It had some other dangerous stuff as well, e.g. when you run IQueryable<T> persons = api.Persons;
var firstPerson = api.Persons.FirstOrDefault(); the Core API logic would just download all the persons (27k?) and then return a single entity. Now this is processed by the Let us discuss it further in a meeting :-) |
…o match the CoreAPI method naming
Closes #20
I decided to do a redesign of the original version. The reason for this was that I found the implementation at some parts not so flexible / at some parts even dangerous to use.
Here a list of changes I did against the version from the Core API:
High level changes
IApiClient
which implements synchronous and asynchronous commands. The API requests are should implement theIApiRequest
interface.IQueryable<T>
class can be retrieved via the extension methodGetAsQueryable
(I am not 100% happy with this name)ExpressionVisitor
class capacity, allowing more flexibility in queries (=> client side executioning of not implemented Linq functions is possible). We could disable this or make it optional if wanted.ToString
insinde an expression has been removed. (I could not find a meaningful example but when there is, I am happy to add it back again.)Low-level changes
ApiQueryBuilder
class has been copied and slightly modifiedApiPagedEnumerable
is now performing the actual API requests holding theApiQueryBuilder
instanceApiQueryProvider
class is now only required for creating theApiPagedEnumerable
instance and parsing the expression tree.ApiQueryRewriter
has bee implemented intoApiQueryProvider
and is droppedIQueryabe<T>
only supports enumerable requests. Single row calls are not supported anymore. (I am not sure if they where used in the Core API)Implementation matrix
When it is not implemented, the default behavior applies --> meaning: the query is performed on client side, possibly running heavy API loads against the API.