You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2020/12/25 07:00:08 UTC
[isis] 02/02: ISIS-2033: encapsulate query-range logic and move to
applib
This is an automated email from the ASF dual-hosted git repository.
ahuber pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/isis.git
commit a828c967ad28f4f85ebb7d989bf0dac47a7c25ff
Author: Andi Huber <ah...@apache.org>
AuthorDate: Fri Dec 25 07:59:51 2020 +0100
ISIS-2033: encapsulate query-range logic and move to applib
---
.../org/apache/isis/applib/query/NamedQuery.java | 3 +-
.../java/org/apache/isis/applib/query/Query.java | 31 +++---
.../org/apache/isis/applib/query/QueryRange.java | 113 +++++++++++++++++++++
.../applib/query/_AllInstancesQueryDefault.java | 21 +---
.../isis/applib/query/_NamedQueryDefault.java | 22 +---
.../apache/isis/applib/query/_QueryAbstract.java | 16 +--
.../isis/applib/query/_QueryRangeDefault.java | 87 ++++++++++++++++
.../NamedQueryTest_withStart_or_withCount.java | 97 +++++++++++++-----
.../repository/RepositoryServiceDefault.java | 5 +-
.../commandlog/impl/jdo/CommandJdoRepository.java | 19 ++--
.../persistence/JdoPersistenceSession5.java | 3 +-
.../persistence/query/PersistenceQuery.java | 3 +-
.../persistence/query/PersistenceQueryFactory.java | 8 +-
.../query/PersistenceQueryFindAllInstances.java | 3 +-
...ersistenceQueryFindUsingApplibQueryDefault.java | 13 +--
.../persistence/query/QueryRangeModel.java | 63 ------------
.../query/_PersistenceQueryAbstract.java | 3 +-
.../metamodel/facets/entity/JdoEntityFacet.java | 13 +--
.../metamodel/JpaEntityFacetFactory.java | 28 +++--
.../persistence/jdo/isis/JdoIsisQueryTest.java | 13 ++-
.../persistence/jdo/spring/JdoSpringQueryTest.java | 13 ++-
.../testdomain/persistence/jpa/JpaQueryTest.java | 13 ++-
22 files changed, 373 insertions(+), 217 deletions(-)
diff --git a/api/applib/src/main/java/org/apache/isis/applib/query/NamedQuery.java b/api/applib/src/main/java/org/apache/isis/applib/query/NamedQuery.java
index 5d4f904..69c328f 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/query/NamedQuery.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/query/NamedQuery.java
@@ -34,8 +34,7 @@ public interface NamedQuery<T> extends Query<T> {
// -- WITHERS
- @Override NamedQuery<T> withStart(long start);
- @Override NamedQuery<T> withCount(long count);
+ @Override NamedQuery<T> withRange(@NonNull QueryRange range);
NamedQuery<T> withParameter(@NonNull String parameterName, @Nullable Object parameterValue);
diff --git a/api/applib/src/main/java/org/apache/isis/applib/query/Query.java b/api/applib/src/main/java/org/apache/isis/applib/query/Query.java
index 3587056..0b60171 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/query/Query.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/query/Query.java
@@ -51,9 +51,6 @@ import lombok.NonNull;
*/
public interface Query<T> extends Serializable {
- public static long UNLIMITED_COUNT = 0L;
-
-
/**
* The {@link Class} of the objects returned by this query.
*/
@@ -65,31 +62,37 @@ public interface Query<T> extends Serializable {
String getDescription();
/**
- * The start index into the set table
- */
- long getStart();
-
- /**
- * The number of items to return, starting at {@link #getStart()}
+ * Returns a model with start index into the set table and maximal number of items to return.
*/
- long getCount();
+ QueryRange getRange();
// -- WITHERS
- Query<T> withStart(long start);
- Query<T> withCount(long count);
+ Query<T> withRange(@NonNull QueryRange range);
+
+ default Query<T> withRange(long ...range) {
+ return withRange(QueryRange.of(range));
+ }
+
+ default Query<T> withStart(long start) {
+ return withRange(start);
+ }
+
+ default Query<T> withLimit(long limit) {
+ return withRange(0L, limit);
+ }
// -- FACTORIES
public static <T> Query<T> allInstances(
final @NonNull Class<T> resultType) {
- return new _AllInstancesQueryDefault<>(resultType, 0, UNLIMITED_COUNT);
+ return new _AllInstancesQueryDefault<>(resultType, QueryRange.unconstrained());
}
public static <T> NamedQuery<T> named(
final @NonNull Class<T> resultType,
final @NonNull String queryName) {
- return new _NamedQueryDefault<>(resultType, queryName, 0, UNLIMITED_COUNT, null);
+ return new _NamedQueryDefault<>(resultType, queryName, QueryRange.unconstrained(), null);
}
}
diff --git a/api/applib/src/main/java/org/apache/isis/applib/query/QueryRange.java b/api/applib/src/main/java/org/apache/isis/applib/query/QueryRange.java
new file mode 100644
index 0000000..52d8b1a
--- /dev/null
+++ b/api/applib/src/main/java/org/apache/isis/applib/query/QueryRange.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.isis.applib.query;
+
+import java.io.Serializable;
+
+/**
+ * @since 2.0 {@index}
+ */
+public interface QueryRange extends Serializable {
+
+ // -- INTERFACE
+
+ boolean isUnconstrained();
+ boolean hasOffset();
+ boolean hasLimit();
+
+ /**
+ * The start index into the set table.
+ * (non-negative)
+ */
+ long getStart();
+
+ /**
+ * The maximum number of items to return, starting at {@link #getStart()}
+ * (non-negative)
+ */
+ long getLimit();
+
+ /**
+ * The end index into the set table. Overflow is ignored.
+ * (non-negative)
+ */
+ long getEnd();
+
+ // -- TO INT
+
+ /**
+ * The start index into the set table (as java int primitive)
+ * @throws ArithmeticException - if {@code start} overflows an int
+ */
+ default int getStartAsInt() {
+ return Math.toIntExact(getStart());
+ }
+
+ /**
+ * The maximum number of items to return (as java int primitive)
+ * if {@code limit} overflows an int, {@link Integer#MAX_VALUE} is returned.
+ */
+ default int getLimitAsInt() {
+ final long limit = getLimit();
+ return limit<=((long)Integer.MAX_VALUE)
+ ? Math.toIntExact(limit)
+ : Integer.MAX_VALUE;
+ }
+
+ /**
+ * The end index into the set table. Overflow is ignored. (as java int primitive)
+ * if {@code end} overflows an int, {@link Integer#MAX_VALUE} is returned.
+ */
+ default int getEndAsInt() {
+ final long end = getEnd();
+ return end<=((long)Integer.MAX_VALUE)
+ ? Math.toIntExact(end)
+ : Integer.MAX_VALUE;
+ }
+
+ // -- FACTORIES
+
+ public static QueryRange unconstrained() {
+ return of(0L, 0L);
+ }
+
+ public static QueryRange start(long start) {
+ return of(start, 0L);
+ }
+
+ public static QueryRange limit(long limit) {
+ return of(0L, limit);
+ }
+
+ public static QueryRange of(long... range) {
+ return new _QueryRangeDefault(range);
+ }
+
+ // -- WITHERS
+
+ public default QueryRange withStart(long start) {
+ return of(start, getLimit());
+ }
+
+ public default QueryRange withLimit(long limit) {
+ return of(getStart(), limit);
+ }
+
+
+}
diff --git a/api/applib/src/main/java/org/apache/isis/applib/query/_AllInstancesQueryDefault.java b/api/applib/src/main/java/org/apache/isis/applib/query/_AllInstancesQueryDefault.java
index 7b041e9..e399740 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/query/_AllInstancesQueryDefault.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/query/_AllInstancesQueryDefault.java
@@ -19,8 +19,6 @@
package org.apache.isis.applib.query;
-import org.apache.isis.commons.internal.exceptions._Exceptions;
-
import lombok.NonNull;
final class _AllInstancesQueryDefault<T>
@@ -31,9 +29,8 @@ implements AllInstancesQuery<T> {
protected _AllInstancesQueryDefault(
final @NonNull Class<T> type,
- final long start,
- final long count) {
- super(type, start, count);
+ final @NonNull QueryRange range) {
+ super(type, range);
}
@Override
@@ -44,19 +41,9 @@ implements AllInstancesQuery<T> {
// -- WITHERS
@Override
- public _AllInstancesQueryDefault<T> withStart(final long start) {
- if(start<0) {
- throw _Exceptions.illegalArgument("require start>=0, got %d", start);
- }
- return new _AllInstancesQueryDefault<>(getResultType(), start, getCount());
+ public _AllInstancesQueryDefault<T> withRange(final @NonNull QueryRange range) {
+ return new _AllInstancesQueryDefault<>(getResultType(), range);
}
- @Override
- public _AllInstancesQueryDefault<T> withCount(final long count) {
- if(count<0) {
- throw _Exceptions.illegalArgument("require count>=0, got %d", count);
- }
- return new _AllInstancesQueryDefault<>(getResultType(), getStart(), count);
- }
}
diff --git a/api/applib/src/main/java/org/apache/isis/applib/query/_NamedQueryDefault.java b/api/applib/src/main/java/org/apache/isis/applib/query/_NamedQueryDefault.java
index 2d1d398..d92a4ae 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/query/_NamedQueryDefault.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/query/_NamedQueryDefault.java
@@ -45,10 +45,9 @@ implements NamedQuery<T> {
protected _NamedQueryDefault(
final @NonNull Class<T> resultType,
final @NonNull String queryName,
- final long start,
- final long count,
+ final @NonNull QueryRange range,
final @Nullable Map<String, Object> parametersByName) {
- super(resultType, start, count);
+ super(resultType, range);
this.name = queryName;
this.parametersByName = parametersByName==null
? Collections.emptyMap()
@@ -63,19 +62,8 @@ implements NamedQuery<T> {
// -- WITHERS
@Override
- public _NamedQueryDefault<T> withStart(final long start) {
- if(start<0) {
- throw _Exceptions.illegalArgument("require start>=0, got %d", start);
- }
- return new _NamedQueryDefault<>(getResultType(), getName(), start, getCount(), getParametersByName());
- }
-
- @Override
- public _NamedQueryDefault<T> withCount(final long count) {
- if(count<0) {
- throw _Exceptions.illegalArgument("require count>=0, got %d", count);
- }
- return new _NamedQueryDefault<>(getResultType(), getName(), getStart(), count, getParametersByName());
+ public _NamedQueryDefault<T> withRange(final @NonNull QueryRange range) {
+ return new _NamedQueryDefault<>(getResultType(), getName(), range, getParametersByName());
}
@Override
@@ -89,7 +77,7 @@ implements NamedQuery<T> {
? new HashMap<String, Object>()
: new HashMap<String, Object>(getParametersByName());
params.put(parameterName, parameterValue);
- return new _NamedQueryDefault<>(getResultType(), getName(), getStart(), getCount(), params);
+ return new _NamedQueryDefault<>(getResultType(), getName(), getRange(), params);
}
}
diff --git a/api/applib/src/main/java/org/apache/isis/applib/query/_QueryAbstract.java b/api/applib/src/main/java/org/apache/isis/applib/query/_QueryAbstract.java
index b71d970..13f03c3 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/query/_QueryAbstract.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/query/_QueryAbstract.java
@@ -20,23 +20,15 @@
package org.apache.isis.applib.query;
import lombok.Getter;
-import lombok.NonNull;
+import lombok.RequiredArgsConstructor;
+@RequiredArgsConstructor
abstract class _QueryAbstract<T> implements Query<T> {
private static final long serialVersionUID = 1L;
- @Getter(onMethod_ = {@Override}) private final long start;
- @Getter(onMethod_ = {@Override}) private final long count;
@Getter(onMethod_ = {@Override}) private final Class<T> resultType;
-
- protected _QueryAbstract(
- final @NonNull Class<T> resultType,
- final long start,
- final long count) {
- this.resultType = resultType;
- this.start = start;
- this.count = count;
- }
+ @Getter(onMethod_ = {@Override}) private final QueryRange range;
+
}
diff --git a/api/applib/src/main/java/org/apache/isis/applib/query/_QueryRangeDefault.java b/api/applib/src/main/java/org/apache/isis/applib/query/_QueryRangeDefault.java
new file mode 100644
index 0000000..d3767e5
--- /dev/null
+++ b/api/applib/src/main/java/org/apache/isis/applib/query/_QueryRangeDefault.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.isis.applib.query;
+
+import org.apache.isis.commons.internal.exceptions._Exceptions;
+
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.ToString;
+
+@EqualsAndHashCode @ToString
+final class _QueryRangeDefault implements QueryRange {
+
+ private static final long serialVersionUID = 1L;
+
+ // -- FACTORY
+
+ static _QueryRangeDefault of(long... range) {
+ return new _QueryRangeDefault(range);
+ }
+
+ @Getter(onMethod_ = {@Override}) private final long start;
+ @Getter(onMethod_ = {@Override}) private final long limit;
+
+ _QueryRangeDefault(
+ final long[] range) {
+ this.start = range.length > 0 ? range[0] : 0L;
+ this.limit = range.length > 1 ? range[1] : 0L;
+ if(start<0L) {
+ throw _Exceptions.illegalArgument("start cannot be a negative number, got %d", start);
+ }
+ if(limit<0L) {
+ throw _Exceptions.illegalArgument("limit cannot be a negative number, got %d", limit);
+ }
+ }
+
+ @Override
+ public long getEnd() {
+ // we limit to Integer.MAX_VALUE because HSQLDB blows up
+ // (with a ClassCastException from Long to Integer)
+ // if we return Long.MAX_VALUE
+ if(!hasLimit()) {
+ return (long) Integer.MAX_VALUE;
+ }
+
+ final long end = getStart() + getLimit();
+ if(end<0 // long addition overflow handling, eg. Long.MAX_VALUE + Long.MAX_VALUE = -2L
+ || end > Integer.MAX_VALUE) {
+ return (long) Integer.MAX_VALUE;
+ }
+
+ return end;
+ }
+
+ @Override
+ public boolean isUnconstrained() {
+ return !(hasOffset()
+ || hasLimit());
+ }
+
+ @Override
+ public boolean hasOffset() {
+ return getStart() != 0;
+ }
+
+ @Override
+ public boolean hasLimit() {
+ return getLimit() != 0;
+ }
+
+}
\ No newline at end of file
diff --git a/api/applib/src/test/java/org/apache/isis/applib/query/NamedQueryTest_withStart_or_withCount.java b/api/applib/src/test/java/org/apache/isis/applib/query/NamedQueryTest_withStart_or_withCount.java
index c8cb655..881ca85 100644
--- a/api/applib/src/test/java/org/apache/isis/applib/query/NamedQueryTest_withStart_or_withCount.java
+++ b/api/applib/src/test/java/org/apache/isis/applib/query/NamedQueryTest_withStart_or_withCount.java
@@ -18,16 +18,21 @@
*/
package org.apache.isis.applib.query;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import lombok.val;
+
class NamedQueryTest_withStart_or_withCount {
private NamedQuery<Customer> namedQuery;
+ private final static long UNLIMITED = 0L;
static class Customer {}
@@ -40,61 +45,105 @@ class NamedQueryTest_withStart_or_withCount {
@Test
public void defaults() throws Exception {
- assertThat(namedQuery.getStart(), is(0L));
- assertThat(namedQuery.getCount(), is(Query.UNLIMITED_COUNT));
+
+ val range = namedQuery.getRange();
+
+ assertThat(range.getStart(), is(0L));
+ assertThat(range.getLimit(), is(UNLIMITED));
+
+ assertTrue(range.isUnconstrained());
+ assertFalse(range.hasOffset());
+ assertFalse(range.hasLimit());
}
@Test
public void typicalHappyCase() throws Exception {
- final Query<Customer> q = namedQuery
- .withStart(10L)
- .withCount(5L);
- assertThat(q.getStart(), is(10L));
- assertThat(q.getCount(), is(5L));
+ val range = namedQuery
+ .withRange(QueryRange.start(10L).withLimit(5L))
+ .getRange();
+
+ assertThat(range.getStart(), is(10L));
+ assertThat(range.getLimit(), is(5L));
+
+ assertFalse(range.isUnconstrained());
+ assertTrue(range.hasOffset());
+ assertTrue(range.hasLimit());
}
@Test
public void happyCase_startOnly() throws Exception {
- final NamedQuery<Customer> q = namedQuery.withStart(10L);
- assertThat(q.getStart(), is(10L));
- assertThat(q.getCount(), is(Query.UNLIMITED_COUNT));
+ val range = namedQuery
+ .withRange(QueryRange.start(10L))
+ .getRange();
+
+ assertThat(range.getStart(), is(10L));
+ assertThat(range.getLimit(), is(UNLIMITED));
+
+ assertFalse(range.isUnconstrained());
+ assertTrue(range.hasOffset());
+ assertFalse(range.hasLimit());
}
@Test
public void happyCase_startZero() throws Exception {
- final NamedQuery<Customer> q = namedQuery.withStart(0);
-
- assertThat(q.getStart(), is(0L));
+
+ val range = namedQuery
+ .withRange(QueryRange.start(0L))
+ .getRange();
+
+ assertThat(range.getStart(), is(0L));
+ assertThat(range.getLimit(), is(UNLIMITED));
+
+ assertTrue(range.isUnconstrained());
+ assertFalse(range.hasOffset());
+ assertFalse(range.hasLimit());
}
@Test
public void startNegative() throws Exception {
assertThrows(IllegalArgumentException.class, ()->{
- namedQuery.withStart(-1);
+ QueryRange.start(-1L);
});
}
@Test
public void happyCase_countOnly() throws Exception {
- final NamedQuery<Customer> q = namedQuery.withCount(20L);
-
- assertThat(q.getStart(), is(0L));
- assertThat(q.getCount(), is(20L));
+
+ val range = namedQuery
+ .withRange(QueryRange.limit(10L))
+ .getRange();
+
+ assertThat(range.getStart(), is(0L));
+ assertThat(range.getLimit(), is(10L));
+
+ assertFalse(range.isUnconstrained());
+ assertFalse(range.hasOffset());
+ assertTrue(range.hasLimit());
}
@Test
public void countNegative() throws Exception {
assertThrows(IllegalArgumentException.class, ()->{
- namedQuery.withCount(-1);
+ QueryRange.limit(-1L);
});
}
@Test
public void countUnlimited() throws Exception {
- final NamedQuery<Customer> q = namedQuery.withCount(Query.UNLIMITED_COUNT);
- assertThat(q.getCount(), is(Query.UNLIMITED_COUNT));
+
+ val range = namedQuery
+ .withRange(QueryRange.limit(UNLIMITED))
+ .getRange();
+
+ assertThat(range.getStart(), is(0L));
+ assertThat(range.getLimit(), is(UNLIMITED));
+
+ assertTrue(range.isUnconstrained());
+ assertFalse(range.hasOffset());
+ assertFalse(range.hasLimit());
+
}
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/repository/RepositoryServiceDefault.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/repository/RepositoryServiceDefault.java
index af32f9c..bb43465 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/repository/RepositoryServiceDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/repository/RepositoryServiceDefault.java
@@ -39,6 +39,7 @@ import org.apache.isis.applib.PersistFailedException;
import org.apache.isis.applib.RepositoryException;
import org.apache.isis.applib.annotation.OrderPrecedence;
import org.apache.isis.applib.query.Query;
+import org.apache.isis.applib.query.QueryRange;
import org.apache.isis.applib.services.factory.FactoryService;
import org.apache.isis.applib.services.repository.EntityState;
import org.apache.isis.applib.services.repository.RepositoryService;
@@ -140,11 +141,9 @@ public class RepositoryServiceDefault implements RepositoryService {
@Override
public <T> List<T> allInstances(final Class<T> type, long start, long count) {
return allMatches(Query.<T>allInstances(type)
- .withStart(start)
- .withCount(count));
+ .withRange(QueryRange.of(start, count)));
}
-
@Override
public <T> List<T> allMatches(Class<T> ofType, Predicate<? super T> predicate) {
return allMatches(ofType, predicate, 0L, Long.MAX_VALUE);
diff --git a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdoRepository.java b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdoRepository.java
index d475448..7f1bd44 100644
--- a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdoRepository.java
+++ b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdoRepository.java
@@ -41,6 +41,7 @@ import org.apache.isis.applib.annotation.OrderPrecedence;
import org.apache.isis.applib.annotation.Programmatic;
import org.apache.isis.applib.jaxb.JavaSqlXMLGregorianCalendarMarshalling;
import org.apache.isis.applib.query.Query;
+import org.apache.isis.applib.query.QueryRange;
import org.apache.isis.applib.services.bookmark.Bookmark;
import org.apache.isis.applib.services.iactn.InteractionContext;
import org.apache.isis.applib.services.repository.RepositoryService;
@@ -246,15 +247,19 @@ public class CommandJdoRepository {
private List<CommandJdo> findSince(
final Timestamp timestamp,
final Integer batchSize) {
- val q = Query.named(CommandJdo.class, "findSince")
- .withParameter("timestamp", timestamp);
-
+
// DN generates incorrect SQL for SQL Server if count set to 1; so we set to 2 and then trim
- if(batchSize != null) {
- q.withCount(batchSize == 1 ? 2 : batchSize);
- }
+ // XXX that's a historic workaround, should rather be fixed upstream
+ val needsTrimFix = batchSize != null && batchSize == 1;
+
+ val q = Query.named(CommandJdo.class, "findSince")
+ .withParameter("timestamp", timestamp)
+ .withRange(QueryRange.limit(
+ needsTrimFix ? 2L : batchSize
+ ));
+
final List<CommandJdo> commandJdos = repositoryService.allMatches(q);
- return batchSize != null && batchSize == 1 && commandJdos.size() > 1
+ return needsTrimFix && commandJdos.size() > 1
? commandJdos.subList(0,1)
: commandJdos;
}
diff --git a/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/JdoPersistenceSession5.java b/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/JdoPersistenceSession5.java
index b4dd9a1..52efb06 100644
--- a/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/JdoPersistenceSession5.java
+++ b/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/JdoPersistenceSession5.java
@@ -29,6 +29,7 @@ import javax.jdo.PersistenceManagerFactory;
import org.datanucleus.enhancement.Persistable;
import org.apache.isis.applib.query.Query;
+import org.apache.isis.applib.query.QueryRange;
import org.apache.isis.applib.services.exceprecog.ExceptionRecognizer;
import org.apache.isis.commons.collections.Can;
import org.apache.isis.core.metamodel.adapter.oid.ObjectNotFoundException;
@@ -165,7 +166,7 @@ implements
@Override
public Optional<ManagedObject> firstMatchingQuery(final Query<?> query) {
- val instances = findInstancesInTransaction(query.withCount(1));
+ val instances = findInstancesInTransaction(query.withRange(QueryRange.limit(1L)));
return instances.getFirst();
}
diff --git a/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/query/PersistenceQuery.java b/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/query/PersistenceQuery.java
index 63f6fb6..e20f267 100644
--- a/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/query/PersistenceQuery.java
+++ b/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/query/PersistenceQuery.java
@@ -20,6 +20,7 @@
package org.apache.isis.persistence.jdo.integration.persistence.query;
import org.apache.isis.applib.query.Query;
+import org.apache.isis.applib.query.QueryRange;
import org.apache.isis.commons.collections.Can;
import org.apache.isis.core.metamodel.spec.ManagedObject;
import org.apache.isis.core.metamodel.spec.ObjectSpecification;
@@ -35,7 +36,7 @@ public interface PersistenceQuery {
*/
ObjectSpecification getSpecification();
- QueryRangeModel getQueryRangeModel() ;
+ QueryRange getQueryRange() ;
Can<ManagedObject> execute(PersistenceQueryContext queryContext);
}
diff --git a/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/query/PersistenceQueryFactory.java b/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/query/PersistenceQueryFactory.java
index f404715..53737cf 100644
--- a/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/query/PersistenceQueryFactory.java
+++ b/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/query/PersistenceQueryFactory.java
@@ -46,7 +46,7 @@ public class PersistenceQueryFactory implements HasMetaModelContext {
/**
* Converts the {@link org.apache.isis.applib.query.Query} applib representation of a query into the
- * {@link PersistenceQuery} internal representation}.
+ * {@link PersistenceQuery} internal representation.
*/
public final PersistenceQuery createPersistenceQueryFor(
final Query<?> query) {
@@ -56,7 +56,7 @@ public class PersistenceQueryFactory implements HasMetaModelContext {
}
val queryResultTypeSpec = specFor(query);
- val range = QueryRangeModel.of(query.getStart(), query.getCount());
+ val range = query.getRange();
if (query instanceof AllInstancesQuery) {
return new PersistenceQueryFindAllInstances(
@@ -81,9 +81,7 @@ public class PersistenceQueryFactory implements HasMetaModelContext {
}
/**
- * Converts a map of param-pojos keyed by param-name to a map of adapters keyed by the
- * same param-name.
- * @implNote we do this to ensure queryParameters have injection points resolved (might be redundant)
+ * Ensure queryParameters have injection points resolved (might be redundant).
*/
private Map<String, Object> injectServicesInto(
final @Nullable Map<String, Object> queryParametersByName) {
diff --git a/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/query/PersistenceQueryFindAllInstances.java b/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/query/PersistenceQueryFindAllInstances.java
index eefeac2..da9d369 100644
--- a/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/query/PersistenceQueryFindAllInstances.java
+++ b/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/query/PersistenceQueryFindAllInstances.java
@@ -20,6 +20,7 @@
package org.apache.isis.persistence.jdo.integration.persistence.query;
import org.apache.isis.applib.query.AllInstancesQuery;
+import org.apache.isis.applib.query.QueryRange;
import org.apache.isis.commons.collections.Can;
import org.apache.isis.core.metamodel.spec.ManagedObject;
import org.apache.isis.core.metamodel.spec.ObjectSpecification;
@@ -35,7 +36,7 @@ public class PersistenceQueryFindAllInstances extends _PersistenceQueryAbstract
public PersistenceQueryFindAllInstances(
final ObjectSpecification specification,
- final QueryRangeModel range) {
+ final QueryRange range) {
super(specification, range);
}
diff --git a/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/query/PersistenceQueryFindUsingApplibQueryDefault.java b/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/query/PersistenceQueryFindUsingApplibQueryDefault.java
index bfa9e69..a1bdfc0 100644
--- a/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/query/PersistenceQueryFindUsingApplibQueryDefault.java
+++ b/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/query/PersistenceQueryFindUsingApplibQueryDefault.java
@@ -24,6 +24,7 @@ import java.util.List;
import java.util.Map;
import org.apache.isis.applib.query.Query;
+import org.apache.isis.applib.query.QueryRange;
import org.apache.isis.commons.collections.Can;
import org.apache.isis.commons.internal.assertions._Assert;
import org.apache.isis.commons.internal.collections._Lists;
@@ -49,7 +50,7 @@ public class PersistenceQueryFindUsingApplibQueryDefault extends _PersistenceQue
final ObjectSpecification specification,
final String queryName,
final Map<String, Object> queryParametersByName,
- final QueryRangeModel range) {
+ final QueryRange range) {
super(specification, range);
this.queryName = queryName;
this.queryParametersByName = queryParametersByName;
@@ -129,10 +130,10 @@ public class PersistenceQueryFindUsingApplibQueryDefault extends _PersistenceQue
val jdoQuery = queryContext.newJdoNamedQuery(cls, queryName);
isisJdoSupport.disableMultivaluedFetch(jdoQuery);
- val queryRangeModel = persistenceQuery.getQueryRangeModel();
+ val range = persistenceQuery.getQueryRange();
- if(queryRangeModel.hasRange()) {
- jdoQuery.setRange(queryRangeModel.getStart(), queryRangeModel.getEnd());
+ if(!range.isUnconstrained()) {
+ jdoQuery.setRange(range.getStart(), range.getEnd());
}
if (log.isDebugEnabled()) {
@@ -146,8 +147,8 @@ public class PersistenceQueryFindUsingApplibQueryDefault extends _PersistenceQue
return Collections.emptyList();
}
- if(queryRangeModel.hasRange()) {
- _Assert.assertTrue(resultList.size()<=queryRangeModel.getCount());
+ if(range.hasLimit()) {
+ _Assert.assertTrue(resultList.size()<=range.getLimit());
}
// puzzler: needs a defensive copy, not sure why
diff --git a/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/query/QueryRangeModel.java b/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/query/QueryRangeModel.java
deleted file mode 100644
index 106427f..0000000
--- a/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/query/QueryRangeModel.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.isis.persistence.jdo.integration.persistence.query;
-
-import lombok.EqualsAndHashCode;
-import lombok.Getter;
-
-@EqualsAndHashCode
-public final class QueryRangeModel {
-
- // -- FACTORY
-
- public static QueryRangeModel of(long... range) {
- return new QueryRangeModel(range);
- }
-
- /**
- * The start index into the set table
- */
- @Getter private final long start;
-
- /**
- * The number of items to return, starting at {@link #getStart()}
- */
- @Getter private final long count;
-
- private QueryRangeModel(
- final long[] range) {
- this.start = range.length > 0 ? range[0]:0;
- this.count = range.length > 1 ? range[1]:0;
- }
-
- public long getEnd() {
- // we default to Integer.MAX_VALUE because HSQLDB blows up
- // (with a ClassCastException from Long to Integer)
- // if we return Long.MAX_VALUE
- return getCount() != 0
- ? getStart() + getCount()
- : Integer.MAX_VALUE;
- }
-
- public boolean hasRange() {
- return getStart() != 0
- || getCount() != 0;
- }
-
-}
diff --git a/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/query/_PersistenceQueryAbstract.java b/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/query/_PersistenceQueryAbstract.java
index 79e7885..66e5ce0 100644
--- a/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/query/_PersistenceQueryAbstract.java
+++ b/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/query/_PersistenceQueryAbstract.java
@@ -25,6 +25,7 @@ import javax.jdo.listener.InstanceLifecycleEvent;
import org.datanucleus.enhancement.Persistable;
+import org.apache.isis.applib.query.QueryRange;
import org.apache.isis.applib.services.registry.ServiceRegistry;
import org.apache.isis.commons.collections.Can;
import org.apache.isis.commons.internal.assertions._Assert;
@@ -48,7 +49,7 @@ abstract class _PersistenceQueryAbstract implements PersistenceQuery {
// -- constructor, fields
protected final @NonNull ObjectSpecification specification;
- protected final @NonNull QueryRangeModel queryRangeModel;
+ protected final @NonNull QueryRange queryRange;
@Override
public String toString() {
diff --git a/persistence/jdo/lightweight/src/main/java/org/apache/isis/persistence/jdo/lightweight/metamodel/facets/entity/JdoEntityFacet.java b/persistence/jdo/lightweight/src/main/java/org/apache/isis/persistence/jdo/lightweight/metamodel/facets/entity/JdoEntityFacet.java
index 4a2ab2f..bb32635 100644
--- a/persistence/jdo/lightweight/src/main/java/org/apache/isis/persistence/jdo/lightweight/metamodel/facets/entity/JdoEntityFacet.java
+++ b/persistence/jdo/lightweight/src/main/java/org/apache/isis/persistence/jdo/lightweight/metamodel/facets/entity/JdoEntityFacet.java
@@ -19,7 +19,6 @@
package org.apache.isis.persistence.jdo.lightweight.metamodel.facets.entity;
import java.lang.reflect.Method;
-import java.math.BigInteger;
import javax.jdo.PersistenceManager;
import javax.jdo.PersistenceManagerFactory;
@@ -34,7 +33,6 @@ import org.apache.isis.commons.internal.base._Lazy;
import org.apache.isis.commons.internal.base._NullSafe;
import org.apache.isis.commons.internal.collections._Maps;
import org.apache.isis.commons.internal.exceptions._Exceptions;
-import org.apache.isis.commons.internal.primitives._Longs;
import org.apache.isis.core.metamodel.context.MetaModelContext;
import org.apache.isis.core.metamodel.facetapi.FacetAbstract;
import org.apache.isis.core.metamodel.facetapi.FacetHolder;
@@ -52,8 +50,6 @@ public class JdoEntityFacet
extends FacetAbstract
implements EntityFacet {
- private final static _Longs.Range NON_NEGATIVE_INTS = _Longs.rangeClosed(0L, Integer.MAX_VALUE);
-
private final Class<?> entityClass;
private final MetaModelContext metaModelContext;
private final JdoFacetContext jdoFacetContext;
@@ -125,13 +121,8 @@ implements EntityFacet {
@Override
public Can<ManagedObject> fetchByQuery(ObjectSpecification spec, Query<?> query) {
- final long rangeLower = query.getStart();
- final long rangeUpper = query.getCount() == Query.UNLIMITED_COUNT
- ? (long) Integer.MAX_VALUE
- : (long) NON_NEGATIVE_INTS.bounded(
- BigInteger.valueOf(query.getStart())
- .add(BigInteger.valueOf(query.getCount()))
- .longValueExact());
+ final long rangeLower = query.getRange().getStart();
+ final long rangeUpper = query.getRange().getEnd();
if(query instanceof AllInstancesQuery) {
diff --git a/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/metamodel/JpaEntityFacetFactory.java b/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/metamodel/JpaEntityFacetFactory.java
index 75a553c..a46338a 100644
--- a/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/metamodel/JpaEntityFacetFactory.java
+++ b/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/metamodel/JpaEntityFacetFactory.java
@@ -42,7 +42,6 @@ import org.apache.isis.commons.internal.base._Strings;
import org.apache.isis.commons.internal.exceptions._Exceptions;
import org.apache.isis.commons.internal.memento._Mementos;
import org.apache.isis.commons.internal.memento._Mementos.SerializingAdapter;
-import org.apache.isis.commons.internal.primitives._Longs;
import org.apache.isis.core.metamodel.facetapi.FacetAbstract;
import org.apache.isis.core.metamodel.facetapi.FacetHolder;
import org.apache.isis.core.metamodel.facetapi.FeatureType;
@@ -86,7 +85,6 @@ public class JpaEntityFacetFactory extends FacetFactoryAbstract {
private final Class<?> entityClass;
private final ServiceRegistry serviceRegistry;
- private final static _Longs.Range NON_NEGATIVE_INTS = _Longs.rangeClosed(0L, Integer.MAX_VALUE);
protected JpaEntityFacet(
final FacetHolder holder,
@@ -150,9 +148,7 @@ public class JpaEntityFacetFactory extends FacetFactoryAbstract {
@Override
public Can<ManagedObject> fetchByQuery(ObjectSpecification spec, Query<?> query) {
- final int start = Math.toIntExact(query.getStart());
- final int count = Math.toIntExact(
- NON_NEGATIVE_INTS.bounded(query.getCount()));
+ val range = query.getRange();
if(query instanceof AllInstancesQuery) {
@@ -172,9 +168,14 @@ public class JpaEntityFacetFactory extends FacetFactoryAbstract {
cr.select(_Casts.uncheckedCast(cr.from(entityClass)));
val typedQuery = entityManager
- .createQuery(cr)
- .setFirstResult(start)
- .setMaxResults(count);
+ .createQuery(cr);
+
+ if(range.hasOffset()) {
+ typedQuery.setFirstResult(range.getStartAsInt());
+ }
+ if(range.hasLimit()) {
+ typedQuery.setMaxResults(range.getLimitAsInt());
+ }
return Can.ofStream(
typedQuery.getResultStream()
@@ -188,9 +189,14 @@ public class JpaEntityFacetFactory extends FacetFactoryAbstract {
val entityManager = getEntityManager();
val namedQuery = entityManager
- .createNamedQuery(applibNamedQuery.getName(), queryResultType)
- .setFirstResult(start)
- .setMaxResults(count);
+ .createNamedQuery(applibNamedQuery.getName(), queryResultType);
+
+ if(range.hasOffset()) {
+ namedQuery.setFirstResult(range.getStartAsInt());
+ }
+ if(range.hasLimit()) {
+ namedQuery.setMaxResults(range.getLimitAsInt());
+ }
applibNamedQuery
.getParametersByName()
diff --git a/regressiontests/stable/src/test/java/org/apache/isis/testdomain/persistence/jdo/isis/JdoIsisQueryTest.java b/regressiontests/stable/src/test/java/org/apache/isis/testdomain/persistence/jdo/isis/JdoIsisQueryTest.java
index 81f0fc7..1b2ad4e 100644
--- a/regressiontests/stable/src/test/java/org/apache/isis/testdomain/persistence/jdo/isis/JdoIsisQueryTest.java
+++ b/regressiontests/stable/src/test/java/org/apache/isis/testdomain/persistence/jdo/isis/JdoIsisQueryTest.java
@@ -18,6 +18,10 @@
*/
package org.apache.isis.testdomain.persistence.jdo.isis;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
import java.sql.SQLException;
import java.util.Collection;
import java.util.SortedSet;
@@ -35,10 +39,6 @@ import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestPropertySource;
import org.springframework.transaction.annotation.Transactional;
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
import org.apache.isis.applib.query.Query;
import org.apache.isis.applib.services.repository.RepositoryService;
import org.apache.isis.commons.internal.primitives._Ints;
@@ -100,7 +100,7 @@ class JdoIsisQueryTest extends IsisIntegrationTestAbstract {
assertInventoryHasBooks(repository
.allMatches(Query.allInstances(JdoBook.class)
- .withCount(2)),
+ .withLimit(2)),
1, 2);
}
@@ -116,8 +116,7 @@ class JdoIsisQueryTest extends IsisIntegrationTestAbstract {
assertInventoryHasBooks(repository
.allMatches(Query.allInstances(JdoBook.class)
- .withStart(1)
- .withCount(1)),
+ .withRange(1, 1)),
2);
}
diff --git a/regressiontests/stable/src/test/java/org/apache/isis/testdomain/persistence/jdo/spring/JdoSpringQueryTest.java b/regressiontests/stable/src/test/java/org/apache/isis/testdomain/persistence/jdo/spring/JdoSpringQueryTest.java
index 8874a64..b0e39f0 100644
--- a/regressiontests/stable/src/test/java/org/apache/isis/testdomain/persistence/jdo/spring/JdoSpringQueryTest.java
+++ b/regressiontests/stable/src/test/java/org/apache/isis/testdomain/persistence/jdo/spring/JdoSpringQueryTest.java
@@ -18,6 +18,10 @@
*/
package org.apache.isis.testdomain.persistence.jdo.spring;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
import java.sql.SQLException;
import java.util.Collection;
import java.util.SortedSet;
@@ -35,10 +39,6 @@ import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestPropertySource;
import org.springframework.transaction.annotation.Transactional;
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
import org.apache.isis.applib.query.Query;
import org.apache.isis.applib.services.repository.RepositoryService;
import org.apache.isis.commons.internal.collections._Maps;
@@ -108,7 +108,7 @@ class JdoSpringQueryTest extends IsisIntegrationTestAbstract {
assertInventoryHasBooks(repository
.allMatches(Query.allInstances(JdoBook.class)
- .withCount(2)),
+ .withLimit(2)),
1, 2);
}
@@ -124,8 +124,7 @@ class JdoSpringQueryTest extends IsisIntegrationTestAbstract {
assertInventoryHasBooks(repository
.allMatches(Query.allInstances(JdoBook.class)
- .withStart(1)
- .withCount(1)),
+ .withRange(1, 1)),
2);
}
diff --git a/regressiontests/stable/src/test/java/org/apache/isis/testdomain/persistence/jpa/JpaQueryTest.java b/regressiontests/stable/src/test/java/org/apache/isis/testdomain/persistence/jpa/JpaQueryTest.java
index ae941dc..5973e5d 100644
--- a/regressiontests/stable/src/test/java/org/apache/isis/testdomain/persistence/jpa/JpaQueryTest.java
+++ b/regressiontests/stable/src/test/java/org/apache/isis/testdomain/persistence/jpa/JpaQueryTest.java
@@ -18,6 +18,10 @@
*/
package org.apache.isis.testdomain.persistence.jpa;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
import java.sql.SQLException;
import java.util.Collection;
import java.util.SortedSet;
@@ -35,10 +39,6 @@ import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestPropertySource;
import org.springframework.transaction.annotation.Transactional;
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
import org.apache.isis.applib.query.Query;
import org.apache.isis.applib.services.repository.RepositoryService;
import org.apache.isis.commons.internal.primitives._Ints;
@@ -102,7 +102,7 @@ class JpaQueryTest extends IsisIntegrationTestAbstract {
assertInventoryHasBooks(repository
.allMatches(Query.allInstances(JpaBook.class)
- .withCount(2)),
+ .withLimit(2)),
1, 2);
}
@@ -118,8 +118,7 @@ class JpaQueryTest extends IsisIntegrationTestAbstract {
assertInventoryHasBooks(repository
.allMatches(Query.allInstances(JpaBook.class)
- .withStart(1)
- .withCount(1)),
+ .withRange(1, 1)),
2);
}