HHH-17375 Shorthand bracket syntax for array slicing
This commit is contained in:
parent
67d04577be
commit
b74992198c
|
@ -1458,14 +1458,26 @@ include::{array-example-dir-hql}/ArrayRemoveIndexTest.java[tags=hql-array-remove
|
|||
[[hql-array-slice-functions]]
|
||||
===== `array_slice()`
|
||||
|
||||
Returns the sub-array as specified by the given start and end index. Returns `null` if any of the arguments is `null`
|
||||
Returns the sub-array as specified by the given 1-based inclusive start and end index. Returns `null` if any of the arguments is `null`
|
||||
and also if the index is out of bounds.
|
||||
|
||||
[[hql-array-remove-index-example]]
|
||||
[[hql-array-slice-example]]
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{array-example-dir-hql}/ArrayRemoveIndexTest.java[tags=hql-array-remove-index-example]
|
||||
include::{array-example-dir-hql}/ArraySliceTest.java[tags=hql-array-slice-example]
|
||||
----
|
||||
====
|
||||
|
||||
Alternatively, it's also possible to slice an array by specifying the lower and upper bound,
|
||||
separated by a colon, as index in the bracket array index syntax `array[lowerIndex:upperIndex]`.
|
||||
This is syntax sugar that translates to the `array_slice` function.
|
||||
|
||||
[[hql-array-slice-hql-example]]
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{array-example-dir-hql}/ArraySliceTest.java[tags=hql-array-slice-hql-example]
|
||||
----
|
||||
====
|
||||
|
||||
|
|
|
@ -438,9 +438,11 @@ syntacticDomainPath
|
|||
| collectionValueNavigablePath
|
||||
| mapKeyNavigablePath
|
||||
| simplePath indexedPathAccessFragment
|
||||
| simplePath slicedPathAccessFragment
|
||||
| toOneFkReference
|
||||
| function pathContinuation
|
||||
| function indexedPathAccessFragment pathContinuation?
|
||||
| function slicedPathAccessFragment
|
||||
;
|
||||
|
||||
/**
|
||||
|
@ -463,6 +465,13 @@ indexedPathAccessFragment
|
|||
: LEFT_BRACKET expression RIGHT_BRACKET (DOT generalPathFragment)?
|
||||
;
|
||||
|
||||
/**
|
||||
* The slice operator to obtain elements between the lower and upper bound.
|
||||
*/
|
||||
slicedPathAccessFragment
|
||||
: LEFT_BRACKET expression COLON expression RIGHT_BRACKET
|
||||
;
|
||||
|
||||
/**
|
||||
* A 'treat()' function that "breaks" a path expression
|
||||
*/
|
||||
|
|
|
@ -5205,17 +5205,44 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
return visitToOneFkReference( ctx.toOneFkReference() );
|
||||
}
|
||||
else if ( ctx.function() != null ) {
|
||||
return visitPathContinuation(
|
||||
visitIndexedPathAccessFragment(
|
||||
(SemanticPathPart) visitFunction( ctx.function() ),
|
||||
ctx.indexedPathAccessFragment()
|
||||
),
|
||||
ctx.pathContinuation()
|
||||
);
|
||||
final HqlParser.SlicedPathAccessFragmentContext slicedFragmentsCtx = ctx.slicedPathAccessFragment();
|
||||
if ( slicedFragmentsCtx != null ) {
|
||||
final List<HqlParser.ExpressionContext> slicedFragments = slicedFragmentsCtx.expression();
|
||||
return getFunctionDescriptor( "array_slice" ).generateSqmExpression(
|
||||
List.of(
|
||||
(SqmTypedNode<?>) visitFunction( ctx.function() ),
|
||||
(SqmTypedNode<?>) slicedFragments.get( 0 ).accept( this ),
|
||||
(SqmTypedNode<?>) slicedFragments.get( 1 ).accept( this )
|
||||
),
|
||||
null,
|
||||
creationContext.getQueryEngine()
|
||||
);
|
||||
}
|
||||
else {
|
||||
return visitPathContinuation(
|
||||
visitIndexedPathAccessFragment(
|
||||
(SemanticPathPart) visitFunction( ctx.function() ),
|
||||
ctx.indexedPathAccessFragment()
|
||||
),
|
||||
ctx.pathContinuation()
|
||||
);
|
||||
}
|
||||
}
|
||||
else if ( ctx.simplePath() != null && ctx.indexedPathAccessFragment() != null ) {
|
||||
return visitIndexedPathAccessFragment( visitSimplePath( ctx.simplePath() ), ctx.indexedPathAccessFragment() );
|
||||
}
|
||||
else if ( ctx.simplePath() != null && ctx.slicedPathAccessFragment() != null ) {
|
||||
final List<HqlParser.ExpressionContext> slicedFragments = ctx.slicedPathAccessFragment().expression();
|
||||
return getFunctionDescriptor( "array_slice" ).generateSqmExpression(
|
||||
List.of(
|
||||
(SqmTypedNode<?>) visitSimplePath( ctx.simplePath() ),
|
||||
(SqmTypedNode<?>) slicedFragments.get( 0 ).accept( this ),
|
||||
(SqmTypedNode<?>) slicedFragments.get( 1 ).accept( this )
|
||||
),
|
||||
null,
|
||||
creationContext.getQueryEngine()
|
||||
);
|
||||
}
|
||||
else {
|
||||
throw new ParsingException( "Illegal domain path '" + ctx.getText() + "'" );
|
||||
}
|
||||
|
|
|
@ -139,4 +139,21 @@ public class ArraySliceTest {
|
|||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSliceSyntax(SessionFactoryScope scope) {
|
||||
scope.inSession( em -> {
|
||||
//tag::hql-array-slice-hql-example[]
|
||||
List<Tuple> results = em.createQuery( "select e.id, e.theArray[1:1] from EntityWithArrays e order by e.id", Tuple.class )
|
||||
.getResultList();
|
||||
//end::hql-array-slice-hql-example[]
|
||||
assertEquals( 3, results.size() );
|
||||
assertEquals( 1L, results.get( 0 ).get( 0 ) );
|
||||
assertArrayEquals( new String[0], results.get( 0 ).get( 1, String[].class ) );
|
||||
assertEquals( 2L, results.get( 1 ).get( 0 ) );
|
||||
assertArrayEquals( new String[] { "abc" }, results.get( 1 ).get( 1, String[].class ) );
|
||||
assertEquals( 3L, results.get( 2 ).get( 0 ) );
|
||||
assertNull( results.get( 2 ).get( 1, String[].class ) );
|
||||
} );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue