Skip to content

Commit 635d244

Browse files
committed
MLE-25585 implement optic transitive closure in java client.
Add generated code with minor changes. Add tests for op.transitiveClosure. Add triple data for tests. Some copyright header fixes.
1 parent e609381 commit 635d244

File tree

10 files changed

+663
-4
lines changed

10 files changed

+663
-4
lines changed

marklogic-client-api/src/main/java/com/marklogic/client/expression/PlanBuilder.java

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2010-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
2+
* Copyright (c) 2010-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
33
*/
44

55
package com.marklogic.client.expression;
@@ -2043,6 +2043,36 @@ public interface ModifyPlan extends PreparePlan, PlanBuilderBase.ModifyPlanBase
20432043
* @since 7.2.0; requires MarkLogic 12
20442044
*/
20452045
public abstract ModifyPlan shortestPath(PlanExprCol start, PlanExprCol end, PlanExprCol path, PlanExprCol length, PlanExprCol weight);
2046+
/**
2047+
* This method performs a transitive closure operation over a graph-like structure, identifying all reachable node pairs from a given start node to an end node through one or more intermediate steps. A set of (start, end) node pairs where a path exists between them with a length between minLength and maxLength, inclusive. This models the SPARQL one-or-more (+) operator, enabling recursive or chained relationships to be queried efficiently.
2048+
* @param start The column is the starting node of the traversal. The column can be named with a string or a column function such as op:col, op:view-col, or op:schema-col, or constructed from an expression with the op:as function. See {@link PlanBuilder#col(XsStringVal)}
2049+
* @param end The column is the end node of the traversal. The column can be named with a string or a column function such as op:col, op:view-col, or op:schema-col, or constructed from an expression with the op:as function. See {@link PlanBuilder#col(XsStringVal)}
2050+
* @return a ModifyPlan object
2051+
*/
2052+
public abstract ModifyPlan transitiveClosure(String start, String end);
2053+
/**
2054+
* This method performs a transitive closure operation over a graph-like structure, identifying all reachable node pairs from a given start node to an end node through one or more intermediate steps. A set of (start, end) node pairs where a path exists between them with a length between minLength and maxLength, inclusive. This models the SPARQL one-or-more (+) operator, enabling recursive or chained relationships to be queried efficiently.
2055+
* @param start The column is the starting node of the traversal. The column can be named with a string or a column function such as op:col, op:view-col, or op:schema-col, or constructed from an expression with the op:as function. See {@link PlanBuilder#col(XsStringVal)}
2056+
* @param end The column is the end node of the traversal. The column can be named with a string or a column function such as op:col, op:view-col, or op:schema-col, or constructed from an expression with the op:as function. See {@link PlanBuilder#col(XsStringVal)}
2057+
* @return a ModifyPlan object
2058+
*/
2059+
public abstract ModifyPlan transitiveClosure(PlanExprCol start, PlanExprCol end);
2060+
/**
2061+
* This method performs a transitive closure operation over a graph-like structure, identifying all reachable node pairs from a given start node to an end node through one or more intermediate steps. A set of (start, end) node pairs where a path exists between them with a length between minLength and maxLength, inclusive. This models the SPARQL one-or-more (+) operator, enabling recursive or chained relationships to be queried efficiently.
2062+
* @param start The column is the starting node of the traversal. The column can be named with a string or a column function such as op:col, op:view-col, or op:schema-col, or constructed from an expression with the op:as function. See {@link PlanBuilder#col(XsStringVal)}
2063+
* @param end The column is the end node of the traversal. The column can be named with a string or a column function such as op:col, op:view-col, or op:schema-col, or constructed from an expression with the op:as function. See {@link PlanBuilder#col(XsStringVal)}
2064+
* @param options This is either an array of strings or an object containing keys and values for the options to this operator. Options include: min-length This option is the minimum number of steps (edges) required in the path. It should be a non-negative integer, and the default is 1.max-length This option Maximum number of steps (edges) allowed in the path. It should be a non-negative integer, and the default is unlimited.
2065+
* @return a ModifyPlan object
2066+
*/
2067+
public abstract ModifyPlan transitiveClosure(String start, String end, PlanTransitiveClosureOptions options);
2068+
/**
2069+
* This method performs a transitive closure operation over a graph-like structure, identifying all reachable node pairs from a given start node to an end node through one or more intermediate steps. A set of (start, end) node pairs where a path exists between them with a length between minLength and maxLength, inclusive. This models the SPARQL one-or-more (+) operator, enabling recursive or chained relationships to be queried efficiently.
2070+
* @param start The column is the starting node of the traversal. The column can be named with a string or a column function such as op:col, op:view-col, or op:schema-col, or constructed from an expression with the op:as function. See {@link PlanBuilder#col(XsStringVal)}
2071+
* @param end The column is the end node of the traversal. The column can be named with a string or a column function such as op:col, op:view-col, or op:schema-col, or constructed from an expression with the op:as function. See {@link PlanBuilder#col(XsStringVal)}
2072+
* @param options This is either an array of strings or an object containing keys and values for the options to this operator. Options include: min-length This option is the minimum number of steps (edges) required in the path. It should be a non-negative integer, and the default is 1.max-length This option Maximum number of steps (edges) allowed in the path. It should be a non-negative integer, and the default is unlimited.
2073+
* @return a ModifyPlan object
2074+
*/
2075+
public abstract ModifyPlan transitiveClosure(PlanExprCol start, PlanExprCol end, PlanTransitiveClosureOptions options);
20462076
}
20472077

20482078

marklogic-client-api/src/main/java/com/marklogic/client/expression/PlanBuilderBase.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2010-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
2+
* Copyright (c) 2010-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
33
*/
44
package com.marklogic.client.expression;
55

@@ -356,6 +356,15 @@ public interface PlanBuilderBase {
356356
*/
357357
PlanSparqlOptions sparqlOptions();
358358

359+
/**
360+
* Provides a transitive closure option object to configure the execution of the
361+
* {@link PlanBuilder.ModifyPlan#transitiveClosure(PlanExprCol, PlanExprCol, PlanTransitiveClosureOptions)}
362+
* operator. Use the fluent methods of the transitive closure option object
363+
* to set the configuration.
364+
* @return the configuration object
365+
*/
366+
PlanTransitiveClosureOptions transitiveClosureOptions();
367+
359368
/**
360369
* Specifies a JavaScript or XQuery function installed on the server for use
361370
* in post-processing in a map() or reduce() operation.

marklogic-client-api/src/main/java/com/marklogic/client/impl/PlanBuilderImpl.java

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2010-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
2+
* Copyright (c) 2010-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
33
*/
44

55
package com.marklogic.client.impl;
@@ -1686,6 +1686,20 @@ static class TransformDefCallImpl extends PlanCallImpl implements PlanTransformD
16861686
}
16871687

16881688

1689+
static class TransitiveClosureOptionsSeqListImpl extends PlanSeqListImpl implements PlanTransitiveClosureOptionsSeq {
1690+
TransitiveClosureOptionsSeqListImpl(Object[] items) {
1691+
super(items);
1692+
}
1693+
}
1694+
1695+
1696+
static class TransitiveClosureOptionsSeqCallImpl extends PlanCallImpl implements PlanTransitiveClosureOptionsSeq {
1697+
TransitiveClosureOptionsSeqCallImpl(String fnPrefix, String fnName, Object[] fnArgs) {
1698+
super(fnPrefix, fnName, fnArgs);
1699+
}
1700+
}
1701+
1702+
16891703
static class TriplePatternSeqListImpl extends PlanSeqListImpl implements PlanTriplePatternSeq {
16901704
TriplePatternSeqListImpl(Object[] items) {
16911705
super(items);
@@ -2268,6 +2282,42 @@ public ModifyPlan shortestPath(PlanExprCol start, PlanExprCol end, PlanExprCol p
22682282
}
22692283

22702284

2285+
@Override
2286+
public ModifyPlan transitiveClosure(String start, String end) {
2287+
return transitiveClosure((start == null) ? (PlanExprCol) null : exprCol(start), (end == null) ? (PlanExprCol) null : exprCol(end));
2288+
}
2289+
2290+
2291+
@Override
2292+
public ModifyPlan transitiveClosure(PlanExprCol start, PlanExprCol end) {
2293+
if (start == null) {
2294+
throw new IllegalArgumentException("start parameter for transitiveClosure() cannot be null");
2295+
}
2296+
if (end == null) {
2297+
throw new IllegalArgumentException("end parameter for transitiveClosure() cannot be null");
2298+
}
2299+
return new PlanBuilderSubImpl.ModifyPlanSubImpl(this, "op", "transitive-closure", new Object[]{ start, end });
2300+
}
2301+
2302+
2303+
@Override
2304+
public ModifyPlan transitiveClosure(String start, String end, PlanTransitiveClosureOptions options) {
2305+
return transitiveClosure((start == null) ? (PlanExprCol) null : exprCol(start), (end == null) ? (PlanExprCol) null : exprCol(end), options);
2306+
}
2307+
2308+
2309+
@Override
2310+
public ModifyPlan transitiveClosure(PlanExprCol start, PlanExprCol end, PlanTransitiveClosureOptions options) {
2311+
if (start == null) {
2312+
throw new IllegalArgumentException("start parameter for transitiveClosure() cannot be null");
2313+
}
2314+
if (end == null) {
2315+
throw new IllegalArgumentException("end parameter for transitiveClosure() cannot be null");
2316+
}
2317+
return new PlanBuilderSubImpl.ModifyPlanSubImpl(this, "op", "transitive-closure", new Object[]{ start, end, PlanBuilderSubImpl.asArg(PlanBuilderSubImpl.makeMap(options)) });
2318+
}
2319+
2320+
22712321
@Override
22722322
public ModifyPlan union(ModifyPlan right) {
22732323
if (right == null) {

marklogic-client-api/src/main/java/com/marklogic/client/impl/PlanBuilderSubImpl.java

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2010-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
2+
* Copyright (c) 2010-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
33
*/
44
package com.marklogic.client.impl;
55

@@ -487,6 +487,10 @@ public PlanSampleByOptions withLimit(XsIntVal limit) {
487487
public PlanSparqlOptions sparqlOptions() {
488488
return new PlanSparqlOptionsImpl(this);
489489
}
490+
@Override
491+
public PlanTransitiveClosureOptions transitiveClosureOptions() {
492+
return new PlanTransitiveClosureOptionsImpl(this);
493+
}
490494
static class PlanSparqlOptionsImpl implements PlanSparqlOptions {
491495
private PlanBuilderBaseImpl pb;
492496
private XsBooleanVal deduplicate;
@@ -526,6 +530,45 @@ public PlanSparqlOptions withDeduplicated(XsBooleanVal deduplicate) {
526530
}
527531
}
528532

533+
static class PlanTransitiveClosureOptionsImpl implements PlanTransitiveClosureOptions {
534+
private PlanBuilderBaseImpl pb;
535+
private XsLongVal minLength;
536+
private XsLongVal maxLength;
537+
PlanTransitiveClosureOptionsImpl(PlanBuilderBaseImpl pb) {
538+
this.pb = pb;
539+
}
540+
PlanTransitiveClosureOptionsImpl(PlanBuilderBaseImpl pb, XsLongVal minLength, XsLongVal maxLength) {
541+
this(pb);
542+
this.minLength = minLength;
543+
this.maxLength = maxLength;
544+
}
545+
546+
@Override
547+
public XsLongVal getMinLength() {
548+
return minLength;
549+
}
550+
@Override
551+
public PlanTransitiveClosureOptions withMinLength(long minLength) {
552+
return withMinLength(pb.xs.longVal(minLength));
553+
}
554+
@Override
555+
public PlanTransitiveClosureOptions withMinLength(XsLongVal minLength) {
556+
return new PlanTransitiveClosureOptionsImpl(this.pb, minLength, this.maxLength);
557+
}
558+
@Override
559+
public XsLongVal getMaxLength() {
560+
return maxLength;
561+
}
562+
@Override
563+
public PlanTransitiveClosureOptions withMaxLength(long maxLength) {
564+
return withMaxLength(pb.xs.longVal(maxLength));
565+
}
566+
@Override
567+
public PlanTransitiveClosureOptions withMaxLength(XsLongVal maxLength) {
568+
return new PlanTransitiveClosureOptionsImpl(this.pb, this.minLength, maxLength);
569+
}
570+
}
571+
529572
@Override
530573
public ServerExpression caseExpr(PlanCase... cases) {
531574
int lastPos = cases.length - 1;
@@ -744,6 +787,29 @@ static Map<String,String> makeMap(PlanSparqlOptions options) {
744787

745788
return mapdef;
746789
}
790+
static Map<String,Object> makeMap(PlanTransitiveClosureOptions options) {
791+
if (options == null) {
792+
return null;
793+
}
794+
795+
Map<String,Object> mapdef = null;
796+
797+
XsLongVal minLength = options.getMinLength();
798+
if (minLength != null) {
799+
mapdef = new HashMap<>();
800+
mapdef.put("minLength", minLength.getLong());
801+
}
802+
803+
XsLongVal maxLength = options.getMaxLength();
804+
if (maxLength != null) {
805+
if (mapdef == null) {
806+
mapdef = new HashMap<>();
807+
}
808+
mapdef.put("maxLength", maxLength.getLong());
809+
}
810+
811+
return mapdef;
812+
}
747813
static Map<String,String> makeMap(String key, String value) {
748814
Map<String, String> map = new HashMap<String, String>();
749815
if (key != null) {
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
* Copyright (c) 2010-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
3+
*/
4+
package com.marklogic.client.type;
5+
6+
// IMPORTANT: Do not edit. This file is generated.
7+
8+
/**
9+
* Options for controlling transitive closure operations, including minimum and maximum
10+
* path lengths.
11+
*/
12+
public interface PlanTransitiveClosureOptions {
13+
XsLongVal getMinLength();
14+
PlanTransitiveClosureOptions withMinLength(long minLength);
15+
PlanTransitiveClosureOptions withMinLength(XsLongVal minLength);
16+
XsLongVal getMaxLength();
17+
PlanTransitiveClosureOptions withMaxLength(long maxLength);
18+
PlanTransitiveClosureOptions withMaxLength(XsLongVal maxLength);
19+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/*
2+
* Copyright (c) 2010-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
3+
*/
4+
package com.marklogic.client.type;
5+
6+
// IMPORTANT: Do not edit. This file is generated.
7+
8+
/**
9+
* A sequence of options for transitive closure operations
10+
* in a row pipeline.
11+
*/
12+
public interface PlanTransitiveClosureOptionsSeq {
13+
}

0 commit comments

Comments
 (0)