Skip to content

Commit e64d09d

Browse files
authored
Add is null / is not null filter on parentId (#100)
1 parent 135c7da commit e64d09d

File tree

15 files changed

+1031
-3
lines changed

15 files changed

+1031
-3
lines changed

scheduling-api-graphql/scheduling-api-graphql-beans/scheduling-api-graphql-beans-input/src/main/java/org/ow2/proactive/scheduling/api/graphql/beans/input/JobInput.java

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ public static class Builder {
119119

120120
private String beforeParentId;
121121

122+
private String parentIdNullStatus;
123+
122124
private String afterChildrenCount;
123125

124126
private String beforeChildrenCount;
@@ -232,6 +234,11 @@ public JobInput.Builder afterParentId(String afterParentId) {
232234
return this;
233235
}
234236

237+
public JobInput.Builder parentIdNullStatus(String nullStatus) {
238+
this.parentIdNullStatus = nullStatus;
239+
return this;
240+
}
241+
235242
public JobInput.Builder beforeChildrenCount(String beforeChildrenCount) {
236243
this.beforeChildrenCount = beforeChildrenCount;
237244
return this;
@@ -481,7 +488,10 @@ public JobInput build() {
481488
this.beforeCumulatedCoreTime,
482489
this.afterCumulatedCoreTime);
483490

484-
comparableLongString(InputFields.PARENT_ID.getName(), this.beforeParentId, this.afterParentId);
491+
comparableLongStringWithNullStatus(InputFields.PARENT_ID.getName(),
492+
this.beforeParentId,
493+
this.afterParentId,
494+
this.parentIdNullStatus);
485495

486496
comparableLongString(InputFields.CHILDREN_COUNT.getName(),
487497
this.beforeChildrenCount,
@@ -529,6 +539,26 @@ private void comparableLongString(String longName, String beforeValue, String af
529539
sb.append(" }").append(Constants.RETURN);
530540
}
531541
}
542+
543+
private void comparableLongStringWithNullStatus(String longName, String beforeValue, String afterValue,
544+
String nullStatus) {
545+
if (!Strings.isNullOrEmpty(beforeValue) || !Strings.isNullOrEmpty(afterValue) ||
546+
!Strings.isNullOrEmpty(nullStatus)) {
547+
sb.append(' ');
548+
sb.append(longName);
549+
sb.append(" : {");
550+
if (!Strings.isNullOrEmpty(beforeValue)) {
551+
sb.append(String.format(" %s : ", InputFields.BEFORE.getName())).append(beforeValue);
552+
}
553+
if (!Strings.isNullOrEmpty(afterValue)) {
554+
sb.append(String.format(" %s : ", InputFields.AFTER.getName())).append(afterValue);
555+
}
556+
if (!Strings.isNullOrEmpty(nullStatus)) {
557+
sb.append(String.format(" %s : ", InputFields.NULL_STATUS.getName())).append(nullStatus);
558+
}
559+
sb.append(" }").append(Constants.RETURN);
560+
}
561+
}
532562
}
533563

534564
}

scheduling-api-graphql/scheduling-api-graphql-common/src/main/java/org/ow2/proactive/scheduling/api/graphql/common/Fields.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ public enum Fields {
4141
DESCRIPTION,
4242
EDGES,
4343
END_CURSOR,
44+
NULL_STATUS,
4445
EXECUTION_DURATION,
4546
EXECUTION_HOST_NAME,
4647
FINISHED_TIME,

scheduling-api-graphql/scheduling-api-graphql-common/src/main/java/org/ow2/proactive/scheduling/api/graphql/common/InputFields.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ public enum InputFields {
4444
KEY,
4545
LAST_UPDATED_TIME,
4646
NAME,
47+
NULL_STATUS,
4748
OWNER,
4849
TENANT,
4950
PRIORITY,

scheduling-api-graphql/scheduling-api-graphql-common/src/main/java/org/ow2/proactive/scheduling/api/graphql/common/Inputs.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,21 @@ public static <T> T getValue(Map<String, Object> input, String fieldName, T defa
4646
}
4747
}
4848

49+
public static <T extends Enum> T getEnumValue(Map<String, Object> input, String fieldName, T defaultValue) {
50+
51+
Object fieldValue = input.get(fieldName);
52+
53+
if (fieldValue != null) {
54+
if (fieldValue instanceof String) {
55+
return (T) T.valueOf(defaultValue.getClass(), (String) fieldValue);
56+
} else {
57+
return (T) fieldValue;
58+
}
59+
} else {
60+
return defaultValue;
61+
}
62+
}
63+
4964
public static <T> T getObject(Map<String, Object> input, String fieldName, Function<Map<String, Object>, T> mapper,
5065
T defaultValue) {
5166

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* ProActive Parallel Suite(TM):
3+
* The Open Source library for parallel and distributed
4+
* Workflows & Scheduling, Orchestration, Cloud Automation
5+
* and Big Data Analysis on Enterprise Grids & Clouds.
6+
*
7+
* Copyright (c) 2007 - 2017 ActiveEon
8+
* Contact: contact@activeeon.com
9+
*
10+
* This library is free software: you can redistribute it and/or
11+
* modify it under the terms of the GNU Affero General Public License
12+
* as published by the Free Software Foundation: version 3 of
13+
* the License.
14+
*
15+
* This program is distributed in the hope that it will be useful,
16+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18+
* GNU Affero General Public License for more details.
19+
*
20+
* You should have received a copy of the GNU Affero General Public License
21+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
22+
*
23+
* If needed, contact us to obtain a release under GPL Version 2 or 3
24+
* or a different license than the AGPL.
25+
*/
26+
package org.ow2.proactive.scheduling.api.graphql.common;
27+
28+
public enum NullStatus {
29+
NULL,
30+
NOT_NULL,
31+
ANY
32+
}

scheduling-api-graphql/scheduling-api-graphql-fetchers/src/main/java/org/ow2/proactive/scheduling/api/graphql/fetchers/converter/JobInputConverter.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import org.ow2.proactive.scheduler.core.db.JobDataVariable;
4747
import org.ow2.proactive.scheduling.api.graphql.common.GraphqlContext;
4848
import org.ow2.proactive.scheduling.api.graphql.common.InputFields;
49+
import org.ow2.proactive.scheduling.api.graphql.common.NullStatus;
4950
import org.ow2.proactive.scheduling.api.graphql.common.Types;
5051
import org.ow2.proactive.scheduling.api.graphql.schema.type.User;
5152
import org.ow2.proactive.scheduling.api.graphql.schema.type.inputs.ComparableIntegerInput;
@@ -353,9 +354,11 @@ private void comparableLongPredicated(ComparableLongInput input, String name, Ro
353354
CriteriaBuilder criteriaBuilder, List<Predicate> predicates, boolean filterZeroLess) {
354355
long before = -1;
355356
long after = -1;
357+
NullStatus nullStatus = NullStatus.ANY;
356358
if (input != null) {
357359
before = input.getBefore();
358360
after = input.getAfter();
361+
nullStatus = input.getNullStatus();
359362
}
360363
if (before != -1L) {
361364
predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get(name), before));
@@ -366,22 +369,38 @@ private void comparableLongPredicated(ComparableLongInput input, String name, Ro
366369
if (after != -1L) {
367370
predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get(name), after));
368371
}
372+
if (nullStatus != NullStatus.ANY) {
373+
if (nullStatus.equals(NullStatus.NOT_NULL)) {
374+
predicates.add(criteriaBuilder.isNotNull(root.get(name)));
375+
} else {
376+
predicates.add(criteriaBuilder.isNull(root.get(name)));
377+
}
378+
}
369379
}
370380

371381
private void comparableIntegerPredicated(ComparableIntegerInput input, String name, Root<JobData> root,
372382
CriteriaBuilder criteriaBuilder, List<Predicate> predicates) {
373383
int before = -1;
374384
int after = -1;
385+
NullStatus nullStatus = NullStatus.ANY;
375386
if (input != null) {
376387
before = input.getBefore();
377388
after = input.getAfter();
389+
nullStatus = input.getNullStatus();
378390
}
379391
if (before != -1) {
380392
predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get(name), before));
381393
}
382394
if (after != -1) {
383395
predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get(name), after));
384396
}
397+
if (nullStatus != NullStatus.ANY) {
398+
if (nullStatus.equals(NullStatus.NOT_NULL)) {
399+
predicates.add(criteriaBuilder.isNotNull(root.get(name)));
400+
} else {
401+
predicates.add(criteriaBuilder.isNull(root.get(name)));
402+
}
403+
}
385404
}
386405

387406
@Override

scheduling-api-graphql/scheduling-api-graphql-schema/src/main/java/org/ow2/proactive/scheduling/api/graphql/schema/type/inputs/ComparableInput.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,14 @@
2525
*/
2626
package org.ow2.proactive.scheduling.api.graphql.schema.type.inputs;
2727

28-
import static org.ow2.proactive.scheduling.api.graphql.common.InputFields.AFTER;
29-
import static org.ow2.proactive.scheduling.api.graphql.common.InputFields.BEFORE;
28+
import static org.ow2.proactive.scheduling.api.graphql.common.InputFields.*;
3029

3130
import java.util.Map;
3231

3332
import org.ow2.proactive.scheduling.api.graphql.common.Inputs;
33+
import org.ow2.proactive.scheduling.api.graphql.common.NullStatus;
3434

35+
import graphql.schema.GraphQLEnumType;
3536
import lombok.Data;
3637

3738

@@ -42,17 +43,29 @@
4243
@Data
4344
public class ComparableInput<T> {
4445

46+
public final static GraphQLEnumType NullStatusEnum = GraphQLEnumType.newEnum()
47+
.name(NULL_STATUS.getName())
48+
.description("Check if the value is null or not null")
49+
.value("NULL")
50+
.value("NOT_NULL")
51+
.value("ANY")
52+
.build();
53+
4554
protected final T before;
4655

4756
protected final T after;
4857

58+
protected final NullStatus nullStatus;
59+
4960
public ComparableInput(Map<String, Object> input, T defaultValue) {
5061
if (input != null) {
5162
before = Inputs.getValue(input, BEFORE.getName(), defaultValue);
5263
after = Inputs.getValue(input, AFTER.getName(), defaultValue);
64+
nullStatus = Inputs.getEnumValue(input, NULL_STATUS.getName(), NullStatus.ANY);
5365
} else {
5466
before = defaultValue;
5567
after = defaultValue;
68+
nullStatus = Inputs.getEnumValue(input, NULL_STATUS.getName(), NullStatus.ANY);
5669
}
5770
}
5871
}

scheduling-api-graphql/scheduling-api-graphql-schema/src/main/java/org/ow2/proactive/scheduling/api/graphql/schema/type/inputs/ComparableParentId.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
import static graphql.scalars.java.JavaPrimitives.GraphQLLong;
2929
import static graphql.schema.GraphQLInputObjectField.newInputObjectField;
3030
import static graphql.schema.GraphQLInputObjectType.newInputObject;
31+
import static org.ow2.proactive.scheduling.api.graphql.common.Fields.NULL_STATUS;
32+
import static org.ow2.proactive.scheduling.api.graphql.common.Fields.STATUS;
3133
import static org.ow2.proactive.scheduling.api.graphql.common.InputFields.AFTER;
3234
import static org.ow2.proactive.scheduling.api.graphql.common.InputFields.BEFORE;
3335

@@ -38,6 +40,8 @@
3840

3941
import graphql.schema.DataFetcher;
4042
import graphql.schema.GraphQLInputType;
43+
import graphql.schema.GraphQLList;
44+
import graphql.schema.GraphQLNonNull;
4145
import lombok.Data;
4246

4347

@@ -60,6 +64,10 @@ public GraphQLInputType buildType(DataFetcher... dataFetchers) {
6064
.description("Jobs having parent id greater than this value.")
6165
.type(GraphQLLong)
6266
.build())
67+
.field(newInputObjectField().name(NULL_STATUS.getName())
68+
.description("Is the parent job id present")
69+
.type(NullStatusEnum)
70+
.build())
6371
.build();
6472
}
6573
};

scheduling-api-http/src/integration-test/java/org/ow2/proactive/scheduling/api/GraphqlServiceIntegrationTest.java

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
import org.ow2.proactive.scheduler.core.db.TaskData;
5555
import org.ow2.proactive.scheduling.api.graphql.common.DefaultValues;
5656
import org.ow2.proactive.scheduling.api.graphql.common.GraphqlContext;
57+
import org.ow2.proactive.scheduling.api.graphql.common.NullStatus;
5758
import org.ow2.proactive.scheduling.api.graphql.schema.type.Query;
5859
import org.ow2.proactive.scheduling.api.graphql.service.GraphqlService;
5960
import org.springframework.beans.factory.annotation.Autowired;
@@ -290,6 +291,32 @@ public void testQueryJobsFilterByContainNames() {
290291
assertThat(jobNodes).hasSize(10);
291292
}
292293

294+
@Rollback
295+
@Test
296+
@Transactional
297+
public void testQueryJobsFilterByEmptyParentId() {
298+
addJobData(5);
299+
addJobDataWithParentId(5);
300+
301+
String queryTest = "{\n" + " jobs (filter: {parentId: {nullStatus:%s}}){\n" + " edges {\n" +
302+
" node {\n" + " id\n" + " parentId\n" + " name\n" +
303+
" owner\n" + " submittedTime\n" + " status\n" + " }\n" +
304+
" }\n" + " }\n" + "}";
305+
306+
Map<String, Object> queryResultAny = executeGraphqlQuery(String.format(queryTest, NullStatus.ANY));
307+
List<?> jobNodes = (List<?>) getField(queryResultAny, "data", "jobs", "edges");
308+
assertThat(jobNodes).hasSize(10);
309+
310+
Map<String, Object> queryResultNotNull = executeGraphqlQuery(String.format(queryTest, NullStatus.NOT_NULL));
311+
jobNodes = (List<?>) getField(queryResultNotNull, "data", "jobs", "edges");
312+
assertThat(jobNodes).hasSize(5);
313+
assertThat(jobNodes.stream().allMatch(jobNode -> getField(jobNode, "node", "parentId") != null)).isTrue();
314+
315+
Map<String, Object> queryResultNull = executeGraphqlQuery(String.format(queryTest, NullStatus.NULL));
316+
jobNodes = (List<?>) getField(queryResultNull, "data", "jobs", "edges");
317+
assertThat(jobNodes.stream().allMatch(jobNode -> getField(jobNode, "node", "parentId") == null)).isTrue();
318+
}
319+
293320
@Rollback
294321
@Test
295322
@Transactional
@@ -1181,6 +1208,11 @@ private void addJobData(int nbJobs) {
11811208
jobData.forEach(job -> entityManager.persist(job));
11821209
}
11831210

1211+
private void addJobDataWithParentId(int nbJobs) {
1212+
List<JobData> jobData = createJobDataWithParentId(nbJobs);
1213+
jobData.forEach(job -> entityManager.persist(job));
1214+
}
1215+
11841216
private void addJobDataWithTasks(int nbTasks) {
11851217
JobData jobData = createJobData("job" + UUID.randomUUID().toString(),
11861218
CONTEXT_USER_DATA.getUserName(),
@@ -1204,6 +1236,18 @@ private List<JobData> createJobData(int count) {
12041236
.collect(Collectors.toList());
12051237
}
12061238

1239+
private List<JobData> createJobDataWithParentId(int count) {
1240+
return IntStream.range(1, count + 1)
1241+
.mapToObj(index -> createJobData("job" + index,
1242+
index % 2 == 0 ? CONTEXT_USER_DATA.getUserName()
1243+
: "owner" + index,
1244+
index % 2 == 0 ? JobPriority.IDLE : JobPriority.HIGH,
1245+
"projectName" + index,
1246+
index % 2 == 0 ? JobStatus.CANCELED : JobStatus.KILLED,
1247+
(long) count))
1248+
.collect(Collectors.toList());
1249+
}
1250+
12071251
private JobData createJobData(String name, String owner, JobPriority priority, String projectName,
12081252
JobStatus status) {
12091253
JobData jobData = new JobData();
@@ -1217,6 +1261,20 @@ private JobData createJobData(String name, String owner, JobPriority priority, S
12171261
return jobData;
12181262
}
12191263

1264+
private JobData createJobData(String name, String owner, JobPriority priority, String projectName, JobStatus status,
1265+
Long parentId) {
1266+
JobData jobData = new JobData();
1267+
jobData.setJobName(name);
1268+
jobData.setOwner(owner);
1269+
jobData.setPriority(priority);
1270+
jobData.setProjectName(projectName);
1271+
jobData.setStatus(status);
1272+
jobData.setParentId(parentId);
1273+
jobData.setOnTaskErrorString(OnTaskError.PAUSE_TASK.toString());
1274+
1275+
return jobData;
1276+
}
1277+
12201278
private List<TaskData> createTaskData(JobData jobData, int nbTasks) {
12211279
return IntStream.range(1, nbTasks + 1)
12221280
.mapToObj(index -> createTaskData(jobData, index - 1, "task" + index))

0 commit comments

Comments
 (0)