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]]
|
[[hql-array-slice-functions]]
|
||||||
===== `array_slice()`
|
===== `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.
|
and also if the index is out of bounds.
|
||||||
|
|
||||||
[[hql-array-remove-index-example]]
|
[[hql-array-slice-example]]
|
||||||
====
|
====
|
||||||
[source, JAVA, indent=0]
|
[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
|
| collectionValueNavigablePath
|
||||||
| mapKeyNavigablePath
|
| mapKeyNavigablePath
|
||||||
| simplePath indexedPathAccessFragment
|
| simplePath indexedPathAccessFragment
|
||||||
|
| simplePath slicedPathAccessFragment
|
||||||
| toOneFkReference
|
| toOneFkReference
|
||||||
| function pathContinuation
|
| function pathContinuation
|
||||||
| function indexedPathAccessFragment pathContinuation?
|
| function indexedPathAccessFragment pathContinuation?
|
||||||
|
| function slicedPathAccessFragment
|
||||||
;
|
;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -463,6 +465,13 @@ indexedPathAccessFragment
|
||||||
: LEFT_BRACKET expression RIGHT_BRACKET (DOT generalPathFragment)?
|
: 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
|
* A 'treat()' function that "breaks" a path expression
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -5205,6 +5205,20 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
||||||
return visitToOneFkReference( ctx.toOneFkReference() );
|
return visitToOneFkReference( ctx.toOneFkReference() );
|
||||||
}
|
}
|
||||||
else if ( ctx.function() != null ) {
|
else if ( ctx.function() != null ) {
|
||||||
|
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(
|
return visitPathContinuation(
|
||||||
visitIndexedPathAccessFragment(
|
visitIndexedPathAccessFragment(
|
||||||
(SemanticPathPart) visitFunction( ctx.function() ),
|
(SemanticPathPart) visitFunction( ctx.function() ),
|
||||||
|
@ -5213,9 +5227,22 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
||||||
ctx.pathContinuation()
|
ctx.pathContinuation()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else if ( ctx.simplePath() != null && ctx.indexedPathAccessFragment() != null ) {
|
else if ( ctx.simplePath() != null && ctx.indexedPathAccessFragment() != null ) {
|
||||||
return visitIndexedPathAccessFragment( visitSimplePath( ctx.simplePath() ), ctx.indexedPathAccessFragment() );
|
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 {
|
else {
|
||||||
throw new ParsingException( "Illegal domain path '" + ctx.getText() + "'" );
|
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