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

Add support for named parameters in string queries #2183

Closed
diamondT opened this issue Jun 5, 2022 · 6 comments
Closed

Add support for named parameters in string queries #2183

diamondT opened this issue Jun 5, 2022 · 6 comments
Labels
type: enhancement A general enhancement

Comments

@diamondT
Copy link
Contributor

diamondT commented Jun 5, 2022

hi,

it would be nice to have support for named parameters in @Query queries, similarly to e.g. spring-data-jpa:

@Query("{\"match\": {\"name\": {\"query\": \":name\"}}}")
Page<Book> findByName(String name,Pageable pageable);

instead of

@Query("{\"match\": {\"name\": {\"query\": \"?0\"}}}")
Page<Book> findByName(String name,Pageable pageable);

looking for patterns with : would be tricky because of the ES query syntax so we could make that behavior explicit instead; let the user define if a query is using positional or named parameters with a new flag.

created a WIP here: diamondT@cd3d2cc
if this is something worth pursuing i can polish a bit more and send a PR.

thanks,

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Jun 5, 2022
@sothawo
Copy link
Collaborator

sothawo commented Jun 14, 2022

ping @mp911de: do we have parameter resolution by name in other Spring Data modules? Do we have the names of the parameters at parameter resolving time?

@mp911de
Copy link
Member

mp911de commented Jun 15, 2022

Yes, there's access to named parameters via o.s.d.r.q.Parameter.getName() (isNamedParameter) and Parameters. We generally reference named parameters via :<the name>. In several modules we resolve the parameter by looking it up via name and then using the parameter index to access the actual value from ParameterAccessor.getBindableValue(int).

@sothawo sothawo added type: enhancement A general enhancement and removed status: waiting-for-triage An issue we've not yet triaged labels Jun 15, 2022
@sothawo
Copy link
Collaborator

sothawo commented Feb 28, 2024

With the implementation of #2083 it is now possible to use a named query like this:

@Query("""
        {
            "match": {
            "text": {
                "query": "#{#foo}"
                }
            }
        }
        """)
SearchHits<Foo>searchByFoo(String foo);

@sothawo sothawo closed this as completed Feb 28, 2024
@mp911de
Copy link
Member

mp911de commented Feb 29, 2024

The implementation from the PR is a little complicated. SpelQueryContext is capable of finding and replacing query parameters (or its successor spring-projects/spring-data-commons#3050). Over time, we introduced a JSON parser to MongoDB to resolve query expressions eagerly. Also, "\"" + targetElement + "\"" asks for injection troubles.

@sothawo
Copy link
Collaborator

sothawo commented Feb 29, 2024

Will have a look at the injection issue.

As for the SpEL stuff: It's hard to know what's available in spring-data-commons without following every PR/change, I didn't find anything about the ValueExpression or SpelQueryContext in the docs (https://docs.spring.io/spring-data/data-commons/docs/current/reference/html/) is there some other source?

Looking at that merge(spring-projects/spring-data-commons#3050), if I understand it correctly, ValueExpression converts the query to replace the spel parts by binding parameters that need to be supported by the store? This is something Elasticsearch does not have, we need to replace the spel parts in the query with the verbatim values from the parameters.

@puppylpg
Copy link
Contributor

I looked into the SpelQueryContext today, found it may not be suitable for elasticsearch query. (Or maybe I misunderstood something in SpelQueryContext?)

With SpelQueryContext the json query should be written as:

@Query("""
        {
            "match": {
            "text": {
                "query": :#{#foo}
                }
            }
        }
        """)
SearchHits<Foo>searchByFoo(String foo);

Indeed the :#{#foo} or ?#{#foo} part in elasticsearch query should be quoted with ", thus the actual value for #foo should be escaped. When it comes to collection, things get more complicated(prepend/append with [/] and consider the escape too). That's the reason SpEL expression evaluation looks like this.

If I'm wrong, please correct me, thanks in advanced.

PLUS: the official docs for spring-data-commons are indeed imperfect, and when searching on the web, most of the information is about the subprojects of spring-data-commons, which makes learning spring-data-commons difficult too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

5 participants