Is Spring-GraphQL a good replacement to RSQL? - java

RSQL is a query language for parametrized filtering of entries in RESTful APIs, meaning I can do something like
curl -X GET http://localhost:8081/api/v1/employee?search=lastName==Doe
where the search query param can take multiple filters -
search=lastName==Doe;firstName==John
which translates to select * from employee where firstName = 'John' and lastName = 'Doe'
In GraphQL I need to define a schema in schema.graphqls which only supports a fixed query as -
type Query {
employeeByLastName(lastName: String): Employee
employeeByFirstName(firstName: String): Employee
}
Is it possible to define a single query in GraphQL that can filter on any field without specifying the field explicitly in the schema?
Something like -
type Query {
filter(params: String[]): Employee
}
Note: I am new to GraphQL, I am following this link

Related

How to obtain list of count() results using JpaRepository #Query?

I'm building REST API connected to ORACLE 11G DB. API sends data to Android client using JSON. To get data I'm using JpaRepository, and #Query annotations.
I want to provide data for charts: number of contracts in years.
I have native SQL query:
select aa.ROK, count(aa.NUMER_UMOWY)
from (select distinct NUMER_UMOWY, ROK from AGR_EFEKTY) aa
group by aa.ROK order by aa.ROK
Result of query using SQL Developer look like this:
I tried to get result using native query:
But result is always like this:
or error depending what I try.
Is it possible to obtain list of count() results using #Query?
If not, what should I use?
Thanks in advance :-)
I think What you are trying to use here is spring data projection.
As mentioned in the reference doc:
Spring Data query methods usually return one or multiple instances of
the aggregate root managed by the repository. However, it might
sometimes be desirable to create projections based on certain
attributes of those types. Spring Data allows modeling dedicated
return types, to more selectively retrieve partial views of the
managed aggregates.
and particularly closed projection where all accessor methods match the target attributes. In your case the count is not an attribute of your aggregate.
To perform what you want you can use constructor as follow :
class ContractsDto{
private String rok;
private int count;
public ContractsDto(String rok, int count) {
this.rok=rok;
this.count =count;
}
// getters
}
The query will be:
#Query(value = "select new ContractsDto(aa.rok , /*count */) from fromClause")
List<ContractsDto> getContractsPerYear();

How to apply OR Condition in HQL?

I have an HQL query that takes msisdn and subServiceId on an Entity Unsubscription.
Below is the code for the same:
Query query = session.createSQLQuery(unsubscriptionInfodemo)
.addEntity(Unsubscription.class)
.setParameter("msisdn", msisdn)
.setParameter("subServiceId", subServiceId);
Now,I need to check in this Unsubscription entity whether subServiceId is the subServiceId I have passed or it should be the subServiceId I have hardCoded.
Can I apply like
public void checkUser(String msisdn,String subServiceID){
Query query = session.createSQLQuery(unsubscriptionInfodemo)
.addEntity(Unsubscription.class)
.setParameter("msisdn", msisdn)
.setParameter("subServiceId", subServiceId)
.setParameter("subServiceId", "XYZ");
}
HQL query:
unsubscriptionInfodemo=select * from unsubscription s where s.msisdn=:msisdn and s.subservice_id=:subServiceId
Can anyone guide me how to proceed?
How to apply OR Condition in HQL?
use OR on your query:
select * from unsubscription s where s.msisdn=:msisdn and s.subservice_id=:subServiceId OR
s.subservice_id=:subServiceId2
and name parameters shouldn't be the same:
.setParameter("msisdn", msisdn)
.setParameter("subServiceId", subServiceId)
.setParameter("subServiceId2", "XYZ"); // Make this subServiceId2
The dynamic functionality you want to implement cannot be done with hql without changing the hql string.
I would consider using the criteria api which provides a dynamic functionality.
The easiest way is to either create the hql string based on the value (if subServiceId is existent or not) or use the criteria api, thus you will just have to add one extra equals filter in case of subServiceId presence.
The question should be changed on how to add dynamic conditions to hql based on variable presence.
Also check this answer

Corresponding Spring JPA method name for requesting a random row in SQL

In order to get the a record in an SQL table with a name, I am using the following query:
SELECT * FROM User WHERE User.name = name;
And the corresponding Spring JPA method name is the following:
UserEntity findUserByName(#Param("name") String name);
My question is the following:
How can I request a random record from an SQL table?
I know that my SQL query should be the following:
SELECT * FROM User
ORDER BY RAND()
LIMIT 1;
But, what should be the corresponding Spring JPA method name for that?
UserEntity findUserXXXXXXX (XXXXXXX);
JPA supports functions which are defined in specification. You can use native query option or JPA 2.1 function to call database functions which are not directly supported by the JPA specification. You can use #Query annotation in your spring data jpa repository.
Native Query
#Query(value="SELECT * FROM User ORDER BY RAND() LIMIT 1", nativeQuery = true)
UserEntity findUser();
Function
#Query("SELECT u FROM UserEntity u order by function('RAND')")
List<UserEntity> findUser();
You can use list.get(0) to get the single user.
if you want to random a list you can easily do it by using PagingAndSortingRepository and provide a random page number where (page_number < page_count)
e.g
long page_count = (totalRecords / perPage)
//Use PageRequest for PagingAndSortingRepository Pageable object
PageRequest.of(new Random().nextLong(page_count), perPage)
or you can provide the random page number from front_end side

Spring Data IN clause adds additional brackets

I have a 'Role' table with a 'name' column. I need to get all roles where names are either 'role1' or 'role2'. Role repository method looks like this:
Set<Role> findByNameIsIn(Set<String> roleNames);
My database contains only 'role1'. The request that is generated looks like this:
SELECT ID, NAME FROM ROLE WHERE (NAME IN ((?,?)))
bind => [role1, role2]
Please notice the double brackets around the parameters. Result set is empty. When I try this query manually through the h2 console - no results as well. The following query works:
SELECT ID, NAME FROM ROLE WHERE (NAME IN ('role1', 'role2'))
My set contains two elements exactly. Sets should be supported as a parameter type. See:https://dzone.com/refcardz/core-spring-data
And finally the question: What am I missing?
As Oliver Gierke mentioned - there is a bug opened for this issue in EclipseLink (this is what I'm using as a persistence provider) issue tracker. Since 2011!.. Here is the workaround:
#Query("select r from Role r where r.name in ?1")
Set<Role> findByNameIsIn(Set<String> roleNames);
And here is the valid generated query:
SELECT ID, NAME FROM ROLE WHERE (NAME IN (?,?))
bind => [role1, role2]

Spring Data JPA doesn't specify lower keyword in method names

I need to lowercase all emails when querying my table, but the documentation specifies only method-name-keyowrd for UPPER():
IgnoreCase findByFirstnameIgnoreCase … where UPPER(x.firstame) = UPPER(?1)
How the LOWER() could be used?
I have debug it and can see that PredicateBuilder doesn't seem to be considering it.
Are you aware if that is a limitation? Or could this be achieved in different way?
As per the Spring JPA reference guide, findXXXByIgnoreCase(...) by default uses UPPER(...) to perform case insensitive search.
To force it to use LOWER keyword we can use a custom query with #Query annotation and specifying SELECT .... LOWER(email)= LOWER(?1).
In my case I have used custom query as below to force it to use LOWER keyword for email column:
#Query("SELECT p from Person p where LOWER(email) = LOWER(?1)")
List<Person> findByEmailIgnoreCase(#Param("email") String email);
and this resulted in creating following query:
Hibernate: select person0_.id as id1_0_, person0_.email as email2_0_, person0_.first_name as first_na3_0_, person0_.last_name as last_nam4_0_ from person person0_ where lower(person0_.email)=lower(?)
This should help the query to use the function index i.e., LOWER(email).
The Spring Data JPA docs say this about case sensitivy of properties:
// Enabling ignoring case for an individual property
List<Person> findByLastnameIgnoreCase(String lastname);
// Enabling ignoring case for all suitable properties
List<Person> findByLastnameAndFirstnameAllIgnoreCase(String lastname, String firstname);
Using IgnoreCase in your method name will automatically generate a query which is case insensitiv for one or all specified properties.
Otherwise you always have the possibility to specify a custom query for your method by annotating it like this:
#Query("select u from User u")
Stream<User> findAllByCustomQueryAndStream();
By using the #Query annotation you can use the plain old JPQL to query your database.

Categories

Resources