Skip to content

Commit

Permalink
fix: set NullHandling to native when sorting (#2999)
Browse files Browse the repository at this point in the history
Without this, I see an exception for all sort requests
```
Caused by: java.lang.UnsupportedOperationException: Applying Null Precedence using Criteria Queries is not yet supported.
	at org.springframework.data.jpa.repository.query.QueryUtils.toJpaOrder(QueryUtils.java:757) ~[spring-data-jpa-3.4.0.jar:3.4.0]
	at org.springframework.data.jpa.repository.query.QueryUtils.toOrders(QueryUtils.java:706) ~[spring-data-jpa-3.4.0.jar:3.4.0]
	at org.springframework.data.jpa.repository.support.SimpleJpaRepository.getQuery(SimpleJpaRepository.java:756) ~[spring-data-jpa-3.4.0.jar:3.4.0]
	at org.springframework.data.jpa.repository.support.SimpleJpaRepository.getQuery(SimpleJpaRepository.java:714) ~[spring-data-jpa-3.4.0.jar:3.4.0]
	at org.springframework.data.jpa.repository.support.SimpleJpaRepository.findAll(SimpleJpaRepository.java:448) ~[spring-data-jpa-3.4.0.jar:3.4.0]
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[na:na]
	at java.base/java.lang.reflect.Method.invoke(Method.java:580) ~[na:na]
	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:359) ~[spring-aop-6.2.0.jar:6.2.0]
	at org.springframework.data.repository.core.support.RepositoryMethodInvoker$RepositoryFragmentMethodInvoker.lambda$new$0(RepositoryMethodInvoker.java:277) ~[spring-data-commons-3.4.0.jar:3.4.0]
	at org.springframework.data.repository.core.support.RepositoryMethodInvoker.doInvoke(RepositoryMethodInvoker.java:170) ~[spring-data-commons-3.4.0.jar:3.4.0]
	at org.springframework.data.repository.core.support.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:158) ~[spring-data-commons-3.4.0.jar:3.4.0]
	at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:515) ~[spring-data-commons-3.4.0.jar:3.4.0]
	at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:284) ~[spring-data-commons-3.4.0.jar:3.4.0]
	at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:752) ~[spring-data-commons-3.4.0.jar:3.4.0]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) ~[spring-aop-6.2.0.jar:6.2.0]
	at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:174) ~[spring-data-commons-3.4.0.jar:3.4.0]
	at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:149) ~[spring-data-commons-3.4.0.jar:3.4.0]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) ~[spring-aop-6.2.0.jar:6.2.0]
	at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:69) ~[spring-data-commons-3.4.0.jar:3.4.0]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) ~[spring-aop-6.2.0.jar:6.2.0]
	at org.springframewo
```

Related to spring-projects/spring-data-jpa#3529
  • Loading branch information
Artur- authored and vaadin-bot committed Dec 16, 2024
1 parent d2e84ca commit 4361d1c
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 17 deletions.
2 changes: 2 additions & 0 deletions packages/ts/react-crud/src/data-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type { CountService, ListService } from './crud';
import type FilterUnion from './types/com/vaadin/hilla/crud/filter/FilterUnion';
import type Sort from './types/com/vaadin/hilla/mappedtypes/Sort';
import Direction from './types/org/springframework/data/domain/Sort/Direction';
import NullHandling from './types/org/springframework/data/domain/Sort/NullHandling';

type MaybeCountService<TItem> = Partial<CountService<TItem>>;
type ListAndMaybeCountService<TItem> = ListService<TItem> & MaybeCountService<TItem>;
Expand Down Expand Up @@ -42,6 +43,7 @@ function createSort<TItem>(params: GridDataProviderParams<TItem>): Sort {
property: order.path,
direction: order.direction === 'asc' ? Direction.ASC : Direction.DESC,
ignoreCase: false,
nullHandling: NullHandling.NATIVE,
})),
};
}
Expand Down
32 changes: 22 additions & 10 deletions packages/ts/react-crud/test/autogrid.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import Matcher from '../src/types/com/vaadin/hilla/crud/filter/PropertyStringFil
import type PropertyStringFilter from '../src/types/com/vaadin/hilla/crud/filter/PropertyStringFilter.js';
import type Sort from '../src/types/com/vaadin/hilla/mappedtypes/Sort.js';
import Direction from '../src/types/org/springframework/data/domain/Sort/Direction.js';
import NullHandling from '../src/types/org/springframework/data/domain/Sort/NullHandling.js';
import type FilterUnion from '../types/com/vaadin/hilla/crud/filter/FilterUnion';
import GridController from './GridController.js';
import SelectController from './SelectController.js';
Expand Down Expand Up @@ -138,7 +139,11 @@ describe('@vaadin/hilla-react-crud', () => {
const service = personService();
const grid = await GridController.init(render(<TestAutoGridNoHeaderFilters service={service} />), user);

const expectedSort: Sort = { orders: [{ property: 'firstName', direction: Direction.ASC, ignoreCase: false }] };
const expectedSort: Sort = {
orders: [
{ property: 'firstName', direction: Direction.ASC, ignoreCase: false, nullHandling: NullHandling.NATIVE },
],
};
expect(service.lastSort).to.deep.equal(expectedSort);
await expect(grid.getSortOrder()).to.eventually.deep.equal([
{ property: 'firstName', direction: Direction.ASC },
Expand Down Expand Up @@ -166,7 +171,9 @@ describe('@vaadin/hilla-react-crud', () => {
await grid.sort('firstName', 'desc');

const expectedSort: Sort = {
orders: [{ property: 'firstName', direction: Direction.DESC, ignoreCase: false }],
orders: [
{ property: 'firstName', direction: Direction.DESC, ignoreCase: false, nullHandling: NullHandling.NATIVE },
],
};
expect(service.lastSort).to.deep.equal(expectedSort);
await expect(grid.getSortOrder()).to.eventually.deep.equal([
Expand Down Expand Up @@ -490,9 +497,12 @@ describe('@vaadin/hilla-react-crud', () => {
});

it('sorts according to first column by default', async () => {
expect(service.lastSort).to.deep.equal({
orders: [{ property: 'firstName', direction: Direction.ASC, ignoreCase: false }],
});
const expectedSort = {
orders: [
{ property: 'firstName', direction: Direction.ASC, ignoreCase: false, nullHandling: NullHandling.NATIVE },
],
};
expect(service.lastSort).to.deep.equal(expectedSort);

await expect(grid.getSortOrder()).to.eventually.deep.equal([
{ property: 'firstName', direction: Direction.ASC },
Expand All @@ -503,8 +513,8 @@ describe('@vaadin/hilla-react-crud', () => {
await grid.sort('lastName', 'asc');
expect(service.lastSort).to.deep.equal({
orders: [
{ property: 'firstName', direction: Direction.ASC, ignoreCase: false },
{ property: 'lastName', direction: Direction.ASC, ignoreCase: false },
{ property: 'firstName', direction: Direction.ASC, ignoreCase: false, nullHandling: NullHandling.NATIVE },
{ property: 'lastName', direction: Direction.ASC, ignoreCase: false, nullHandling: NullHandling.NATIVE },
],
});

Expand All @@ -516,8 +526,8 @@ describe('@vaadin/hilla-react-crud', () => {
await grid.sort('lastName', 'desc');
expect(service.lastSort).to.deep.equal({
orders: [
{ property: 'firstName', direction: Direction.ASC, ignoreCase: false },
{ property: 'lastName', direction: Direction.DESC, ignoreCase: false },
{ property: 'firstName', direction: Direction.ASC, ignoreCase: false, nullHandling: NullHandling.NATIVE },
{ property: 'lastName', direction: Direction.DESC, ignoreCase: false, nullHandling: NullHandling.NATIVE },
],
});

Expand All @@ -528,7 +538,9 @@ describe('@vaadin/hilla-react-crud', () => {

await grid.sort('lastName', null);
expect(service.lastSort).to.deep.equal({
orders: [{ property: 'firstName', direction: Direction.ASC, ignoreCase: false }],
orders: [
{ property: 'firstName', direction: Direction.ASC, ignoreCase: false, nullHandling: NullHandling.NATIVE },
],
});

await expect(grid.getSortOrder()).to.eventually.deep.equal([
Expand Down
27 changes: 20 additions & 7 deletions packages/ts/react-crud/test/dataprovider.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ import type { GridDataProvider, GridSorterDefinition } from '@vaadin/react-compo
import sinon from 'sinon';
import sinonChai from 'sinon-chai';
import type { CountService, ListService } from '../crud.js';
import { DataProvider } from '../src/data-provider.js';
import {
createDataProvider,
DataProvider,
FixedSizeDataProvider,
InfiniteDataProvider,
useDataProvider,
type ItemCounts,
} from '../src/data-provider.js';
import NullHandling from '../src/types/org/springframework/data/domain/Sort/NullHandling.js';
import type AndFilter from '../types/com/vaadin/hilla/crud/filter/AndFilter.js';
import type FilterUnion from '../types/com/vaadin/hilla/crud/filter/FilterUnion.js';
import Matcher from '../types/com/vaadin/hilla/crud/filter/PropertyStringFilter/Matcher.js';
Expand Down Expand Up @@ -203,11 +204,15 @@ describe('@hilla/react-crud', () => {

await grid.requestPage(0, [{ path: 'foo', direction: 'asc' }]);
pageable = listSpy.lastCall.args[0];
expect(pageable.sort).to.eql({ orders: [{ property: 'foo', direction: 'ASC', ignoreCase: false }] });
expect(pageable.sort).to.eql({
orders: [{ property: 'foo', direction: 'ASC', ignoreCase: false, nullHandling: NullHandling.NATIVE }],
});

await grid.requestPage(0, [{ path: 'bar', direction: 'desc' }]);
pageable = listSpy.lastCall.args[0];
expect(pageable.sort).to.eql({ orders: [{ property: 'bar', direction: 'DESC', ignoreCase: false }] });
expect(pageable.sort).to.eql({
orders: [{ property: 'bar', direction: 'DESC', ignoreCase: false, nullHandling: NullHandling.NATIVE }],
});
});

it('utilizes count from listAndCountService and call it only once', async () => {
Expand Down Expand Up @@ -308,11 +313,15 @@ describe('@hilla/react-crud', () => {

await grid.requestPage(0, [{ path: 'foo', direction: 'asc' }]);
pageable = listSpy.lastCall.args[0];
expect(pageable.sort).to.eql({ orders: [{ property: 'foo', direction: 'ASC', ignoreCase: false }] });
expect(pageable.sort).to.eql({
orders: [{ property: 'foo', direction: 'ASC', ignoreCase: false, nullHandling: NullHandling.NATIVE }],
});

await grid.requestPage(0, [{ path: 'bar', direction: 'desc' }]);
pageable = listSpy.lastCall.args[0];
expect(pageable.sort).to.eql({ orders: [{ property: 'bar', direction: 'DESC', ignoreCase: false }] });
expect(pageable.sort).to.eql({
orders: [{ property: 'bar', direction: 'DESC', ignoreCase: false, nullHandling: NullHandling.NATIVE }],
});
});

it('passes filter to service', async () => {
Expand Down Expand Up @@ -438,11 +447,15 @@ describe('@hilla/react-crud', () => {

await grid.requestPage(0, [{ path: 'foo', direction: 'asc' }]);
pageable = listSpy.lastCall.args[0];
expect(pageable.sort).to.eql({ orders: [{ property: 'foo', direction: 'ASC', ignoreCase: false }] });
expect(pageable.sort).to.eql({
orders: [{ property: 'foo', direction: 'ASC', ignoreCase: false, nullHandling: NullHandling.NATIVE }],
});

await grid.requestPage(0, [{ path: 'bar', direction: 'desc' }]);
pageable = listSpy.lastCall.args[0];
expect(pageable.sort).to.eql({ orders: [{ property: 'bar', direction: 'DESC', ignoreCase: false }] });
expect(pageable.sort).to.eql({
orders: [{ property: 'bar', direction: 'DESC', ignoreCase: false, nullHandling: NullHandling.NATIVE }],
});
});

it('passes filter to service', async () => {
Expand Down

0 comments on commit 4361d1c

Please # to comment.