Skip to content
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

[Question] How to pass a string array parameter to a custom function? #1003

Closed
AndriiLesiuk opened this issue Jul 31, 2023 · 8 comments
Closed
Assignees

Comments

@AndriiLesiuk
Copy link

Hi
I am currently working on creating a custom $filter function:
[(https://github.com//issues/1000)]
I want to pass a string array to it as a parameter:
/odata/MyTable?$filter=Custom.in(Name, ['Bob', 'Eric', 'John'])

This is my code in which I add my custom function and its signature:

        public static ODataOptions AddODataModel(this ODataOptions? options)
        {
            AddCustomUriFunctions();

            options ??= new ODataOptions();
            options.EnableQueryFeatures(3000);
            options.AddRouteComponents(routePrefix: "odata", model: CreateEdmModel(), services =>
            {
                services.AddSingleton<IFilterBinder, CustomFilterBinder>();
                services.AddSingleton<ISearchBinder, SearchBinder>();
                services.AddSingleton<ODataBatchHandler>(GetBatchHandler());
            });
            options.RouteOptions.EnableNonParenthesisForEmptyParameterFunction = true;
            options.EnableAttributeRouting = true;

            return options;
        }

        private static void AddCustomUriFunctions()
        {
            IEdmTypeReference stringType = EdmCoreModel.Instance.GetString(true);
            
            FunctionSignatureWithReturnType signatureString;
            signatureString = new FunctionSignatureWithReturnType(
                EdmCoreModel.Instance.GetBoolean(false),
                EdmCoreModel.Instance.GetString(true),
                EdmCoreModel.GetCollection(stringType));

            CustomUriFunctions.AddCustomUriFunction("Custom.in", signatureString);   
        }

But when I submit my request, I get this error:
image

My question is what exactly am I doing wrong and how do I implement passing an array of strings as a parameter?
How to configure custom function signature?
Thanks.

@julealgon
Copy link
Contributor

Can you elaborate on what type of function you are trying to create there? I know this doesn't answer the original question, but I'm just curious about what type of logic you want.

@xuzhg
Copy link
Member

xuzhg commented Aug 1, 2023

@AndriiLesiuk In OData lib parser, it starts to parse the parameter value, then uses the function name and parsed value to match the defined functions. Since there's no parameter type information at the beginning when parsing the parameter value, ODL parses the 'collection value' as a single string value. As a result, it can't match the second parameter type since you define the second parameter type as a collection of string.

ODL should fix it by converting the single string value into a collection of string. Or parse the "string literal" into a collection if it's a "collection literal". Would you please help to file an issue at odata.net repo?

of course, as a workaround, you can just define the second parameter type as Edm.String, then in your customized filter binder, process the single string value into a collection or others. For example:

image

@AndriiLesiuk
Copy link
Author

Can you elaborate on what type of function you are trying to create there? I know this doesn't answer the original question, but I'm just curious about what type of logic you want.

I want to create a custom function that will filter one property againts multiple values:
/odata/MyTable?$filter=Custom.in(Name, ['Bob', 'Eric', 'John'])

@AndriiLesiuk
Copy link
Author

ODL should fix it by converting the single string value into a collection of string. Or parse the "string literal" into a collection if it's a "collection literal". Would you please help to file an issue at odata.net repo?

I did not understand what problem you mean.
Please clarify.

As for passing a simple string and then parsing it into a collection - yes, this option works well, thanks.

@AndriiLesiuk
Copy link
Author

AndriiLesiuk commented Aug 1, 2023

Can you elaborate on what type of function you are trying to create there? I know this doesn't answer the original question, but I'm just curious about what type of logic you want.

@julealgon @xuzhg
I know that there is already existing functionality that fully meets my requirements:

/odata/MyTable?$filter=propertyName in ('Bob', 'Rob')

But the requirements do not always fall under a logical understanding (in my case).
So I'm wondering if it's possible to call my function, but under the hood to repeat or call the "in" functionality that's already implemented in your library?
Cheers

@xuzhg
Copy link
Member

xuzhg commented Aug 1, 2023

ODL should fix it by converting the single string value into a collection of string. Or parse the "string literal" into a collection if it's a "collection literal". Would you please help to file an issue at odata.net repo?

I did not understand what problem you mean. Please clarify.

As for passing a simple string and then parsing it into a collection - yes, this option works well, thanks.

Forget it. I filed an issue here: OData/odata.net#2712

@xuzhg
Copy link
Member

xuzhg commented Aug 1, 2023

Can you elaborate on what type of function you are trying to create there? I know this doesn't answer the original question, but I'm just curious about what type of logic you want.

@julealgon @xuzhg I know that there is already existing functionality that fully meets my requirements:

/odata/MyTable?$filter=propertyName in ('Bob', 'Rob')

But the requirements do not always fall under a logical understanding (in my case). So I'm wondering if it's possible to call my function, but under the hood to repeat or call the "in" functionality that's already implemented in your library? Cheers

  1. In your own FilterBinder, you can replace the 'SingleValueFunctionCallNode' into an 'InNode', and let it go
  2. Or, at early of request pipeline, change your $filter query into a 'in' operator by yourself.

@xuzhg xuzhg self-assigned this Aug 1, 2023
@AndriiLesiuk
Copy link
Author

@xuzhg
Thanks)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants