Skip to content

Commit ed3e72d

Browse files
authored
Merge pull request #1654 from marklogic/feature/optic-patch-prototype
MLE-13685 Added support for patch builder methods
2 parents c3679e9 + a61fcac commit ed3e72d

File tree

6 files changed

+616
-20
lines changed

6 files changed

+616
-20
lines changed

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

Lines changed: 81 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2023 MarkLogic Corporation
2+
* Copyright (c) 2024 MarkLogic Corporation
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -227,6 +227,58 @@ protected PlanBuilder(
227227
*/
228228
public abstract ServerExpression subtract(ServerExpression left, ServerExpression right);
229229
/**
230+
* Add an error-handler to the Optic Pipeline to catch Optic Update runtime errors. The runtime errors are added in the errors column. If no error occurred the value of the error column is null. When added, the error-handler should be the last operator before op:result.
231+
* @param action The Optic Plan. You can either use the XQuery => chaining operator or specify the variable that captures the return value from the previous operation.
232+
* @return a ModifyPlan object
233+
*/
234+
public abstract ModifyPlan onError(String action);
235+
/**
236+
* Add an error-handler to the Optic Pipeline to catch Optic Update runtime errors. The runtime errors are added in the errors column. If no error occurred the value of the error column is null. When added, the error-handler should be the last operator before op:result.
237+
* @param action The Optic Plan. You can either use the XQuery => chaining operator or specify the variable that captures the return value from the previous operation.
238+
* @return a ModifyPlan object
239+
*/
240+
public abstract ModifyPlan onError(XsStringVal action);
241+
/**
242+
* Add an error-handler to the Optic Pipeline to catch Optic Update runtime errors. The runtime errors are added in the errors column. If no error occurred the value of the error column is null. When added, the error-handler should be the last operator before op:result.
243+
* @param action The Optic Plan. You can either use the XQuery => chaining operator or specify the variable that captures the return value from the previous operation.
244+
* @param errorColumn Valid options are: "fail" - stop procesisng and "continue" - add an error to the error column and continue processing. See {@link PlanBuilder#col(XsStringVal)}
245+
* @return a ModifyPlan object
246+
*/
247+
public abstract ModifyPlan onError(String action, String errorColumn);
248+
/**
249+
* Add an error-handler to the Optic Pipeline to catch Optic Update runtime errors. The runtime errors are added in the errors column. If no error occurred the value of the error column is null. When added, the error-handler should be the last operator before op:result.
250+
* @param action The Optic Plan. You can either use the XQuery => chaining operator or specify the variable that captures the return value from the previous operation.
251+
* @param errorColumn Valid options are: "fail" - stop procesisng and "continue" - add an error to the error column and continue processing. See {@link PlanBuilder#col(XsStringVal)}
252+
* @return a ModifyPlan object
253+
*/
254+
public abstract ModifyPlan onError(XsStringVal action, PlanExprCol errorColumn);
255+
/**
256+
* Create a patch builder which can be used to chain patch operations.
257+
* @param contextPath The context path to patch.
258+
* @return a PatchBuilder object
259+
*/
260+
public abstract PatchBuilder patchBuilder(String contextPath);
261+
/**
262+
* Create a patch builder which can be used to chain patch operations.
263+
* @param contextPath The context path to patch.
264+
* @return a PatchBuilder object
265+
*/
266+
public abstract PatchBuilder patchBuilder(XsStringVal contextPath);
267+
/**
268+
* Create a patch builder which can be used to chain patch operations.
269+
* @param contextPath The context path to patch.
270+
* @param namespaces Namespaces prefix (key) and uri (value).
271+
* @return a PatchBuilder object
272+
*/
273+
public abstract PatchBuilder patchBuilder(String contextPath, Map<String,String> namespaces);
274+
/**
275+
* Create a patch builder which can be used to chain patch operations.
276+
* @param contextPath The context path to patch.
277+
* @param namespaces Namespaces prefix (key) and uri (value).
278+
* @return a PatchBuilder object
279+
*/
280+
public abstract PatchBuilder patchBuilder(XsStringVal contextPath, Map<String,String> namespaces);
281+
/**
230282
* This function creates a placeholder for a literal value in an expression or as the offset or max for a limit. The op:result function throws in an error if the binding parameter does not specify a literal value for the parameter.
231283
* <p>
232284
* Provides a client interface to the <a href="http://docs.marklogic.com/op:param" target="mlserverdoc">op:param</a> server function.
@@ -1573,20 +1625,6 @@ public interface ModifyPlan extends PreparePlan, PlanBuilderBase.ModifyPlanBase
15731625
* @return a ModifyPlan object
15741626
*/
15751627
public abstract ModifyPlan joinDoc(PlanColumn docCol, PlanColumn sourceCol);
1576-
/**
1577-
* This method adds a uri column to rows based on an existing fragment id column to identify the source document for each row. The fragmentIdCol must be an op:fragment-id-col specifying a fragment id column. If the fragment id column is null in the row, the row is dropped from the rowset.
1578-
* @param uriCol The document uri. This is the output from op:col('uri') that specifies a document uri column. See {@link PlanBuilder#col(XsStringVal)}
1579-
* @param fragmentIdCol The document fragment id value. This is the output from op:fragment-id-col specifying a fragment id column. See {@link PlanBuilder#col(XsStringVal)}
1580-
* @return a ModifyPlan object
1581-
*/
1582-
public abstract ModifyPlan joinDocUri(String uriCol, String fragmentIdCol);
1583-
/**
1584-
* This method adds a uri column to rows based on an existing fragment id column to identify the source document for each row. The fragmentIdCol must be an op:fragment-id-col specifying a fragment id column. If the fragment id column is null in the row, the row is dropped from the rowset.
1585-
* @param uriCol The document uri. This is the output from op:col('uri') that specifies a document uri column. See {@link PlanBuilder#col(XsStringVal)}
1586-
* @param fragmentIdCol The document fragment id value. This is the output from op:fragment-id-col specifying a fragment id column. See {@link PlanBuilder#col(XsStringVal)}
1587-
* @return a ModifyPlan object
1588-
*/
1589-
public abstract ModifyPlan joinDocUri(PlanColumn uriCol, PlanColumn fragmentIdCol);
15901628
/**
15911629
* This method adds an uri column and a document column to rows based on an existing source column having a value of a document uri (which can be used to read other documents) or a fragment id (which can be used to read the source documents for rows). If the fragment id column is null in the row, the row is dropped from the rowset.
15921630
* @param docCol The document column to add to the rows. This can be a string or a column, op:col, op:view-col or op:schema-col, specifying the name of the new column that should have the document as its value. See {@link PlanBuilder#col(XsStringVal)}
@@ -1603,6 +1641,20 @@ public interface ModifyPlan extends PreparePlan, PlanBuilderBase.ModifyPlanBase
16031641
* @return a ModifyPlan object
16041642
*/
16051643
public abstract ModifyPlan joinDocAndUri(PlanColumn docCol, PlanColumn uriCol, PlanColumn sourceCol);
1644+
/**
1645+
* This method adds a uri column to rows based on an existing fragment id column to identify the source document for each row. The fragmentIdCol must be an op:fragment-id-col specifying a fragment id column. If the fragment id column is null in the row, the row is dropped from the rowset.
1646+
* @param uriCol The document uri. This is the output from op:col('uri') that specifies a document uri column. See {@link PlanBuilder#col(XsStringVal)}
1647+
* @param fragmentIdCol The document fragment id value. This is the output from op:fragment-id-col specifying a fragment id column. See {@link PlanBuilder#col(XsStringVal)}
1648+
* @return a ModifyPlan object
1649+
*/
1650+
public abstract ModifyPlan joinDocUri(String uriCol, String fragmentIdCol);
1651+
/**
1652+
* This method adds a uri column to rows based on an existing fragment id column to identify the source document for each row. The fragmentIdCol must be an op:fragment-id-col specifying a fragment id column. If the fragment id column is null in the row, the row is dropped from the rowset.
1653+
* @param uriCol The document uri. This is the output from op:col('uri') that specifies a document uri column. See {@link PlanBuilder#col(XsStringVal)}
1654+
* @param fragmentIdCol The document fragment id value. This is the output from op:fragment-id-col specifying a fragment id column. See {@link PlanBuilder#col(XsStringVal)}
1655+
* @return a ModifyPlan object
1656+
*/
1657+
public abstract ModifyPlan joinDocUri(PlanColumn uriCol, PlanColumn fragmentIdCol);
16061658
/**
16071659
* This method returns all rows from multiple tables where the join condition is met. In the output row set, each row concatenates one left row and one right row for each match between the keys in the left and right row sets.
16081660
* @param right The row set from the right view.
@@ -1753,6 +1805,20 @@ public interface ModifyPlan extends PreparePlan, PlanBuilderBase.ModifyPlanBase
17531805
* @return a ModifyPlan object
17541806
*/
17551807
public abstract ModifyPlan orderBy(PlanSortKeySeq keys);
1808+
/**
1809+
* Builds a patch operation including a sequence of inserts, replaces, replace-inserts and deletes.
1810+
* @param docColumn The document column which need to be patched. See {@link PlanBuilder#col(XsStringVal)}
1811+
* @param patchDef The patch definition as op:patch-builder
1812+
* @return a ModifyPlan object
1813+
*/
1814+
public abstract ModifyPlan patch(String docColumn, PatchBuilder patchDef);
1815+
/**
1816+
* Builds a patch operation including a sequence of inserts, replaces, replace-inserts and deletes.
1817+
* @param docColumn The document column which need to be patched. See {@link PlanBuilder#col(XsStringVal)}
1818+
* @param patchDef The patch definition as op:patch-builder
1819+
* @return a ModifyPlan object
1820+
*/
1821+
public abstract ModifyPlan patch(PlanExprCol docColumn, PatchBuilder patchDef);
17561822
/**
17571823
* This method prepares the specified plan for execution as an optional final step before execution.
17581824
* @param optimize The optimization level, which can be 0, 1, or 2 (1 is mostly used).
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
package com.marklogic.client.impl;
2+
3+
import com.marklogic.client.type.PatchBuilder;
4+
import com.marklogic.client.type.ServerExpression;
5+
import com.marklogic.client.type.XsStringVal;
6+
7+
import java.util.ArrayList;
8+
import java.util.Arrays;
9+
import java.util.List;
10+
import java.util.Map;
11+
12+
class PatchBuilderImpl extends BaseTypeImpl.BaseCallImpl implements PatchBuilder, BaseTypeImpl.BaseArgImpl {
13+
14+
PatchBuilderImpl(XsStringVal contextPath) {
15+
super("op", "suboperators",
16+
new BaseTypeImpl.BaseArgImpl[]{
17+
new BaseTypeImpl.BaseCallImpl("op", "patchBuilder",
18+
new BaseTypeImpl.BaseArgImpl[]{(BaseTypeImpl.BaseArgImpl) contextPath})
19+
});
20+
}
21+
22+
PatchBuilderImpl(XsStringVal contextPath, Map<String, String> namespaces) {
23+
super("op", "suboperators",
24+
new BaseTypeImpl.BaseArgImpl[]{
25+
new BaseTypeImpl.BaseCallImpl("op", "patchBuilder",
26+
new BaseTypeImpl.BaseArgImpl[]{(BaseTypeImpl.BaseArgImpl) contextPath, new BaseTypeImpl.BaseMapImpl(namespaces)})
27+
});
28+
}
29+
30+
private PatchBuilderImpl(List<BaseTypeImpl.BaseArgImpl> args) {
31+
super("op", "suboperators", args.toArray(new BaseTypeImpl.BaseArgImpl[]{}));
32+
}
33+
34+
@Override
35+
public PatchBuilder insertAfter(String path, ServerExpression node) {
36+
return addArg("insertAfter", path, node);
37+
}
38+
39+
@Override
40+
public PatchBuilder insertAfter(XsStringVal path, ServerExpression node) {
41+
return addArg("insertAfter", path, node);
42+
}
43+
44+
@Override
45+
public PatchBuilder insertBefore(String path, ServerExpression node) {
46+
return addArg("insertBefore", path, node);
47+
}
48+
49+
@Override
50+
public PatchBuilder insertBefore(XsStringVal path, ServerExpression node) {
51+
return addArg("insertBefore", path, node);
52+
}
53+
54+
@Override
55+
public PatchBuilder insertChild(String path, ServerExpression node) {
56+
return addArg("insertChild", path, node);
57+
}
58+
59+
@Override
60+
public PatchBuilder insertChild(XsStringVal path, ServerExpression node) {
61+
return addArg("insertChild", path, node);
62+
}
63+
64+
@Override
65+
public PatchBuilder insertNamedChild(String path, String key, ServerExpression node) {
66+
return addArg("insertNamedChild", new XsValueImpl.StringValImpl(path), new XsValueImpl.StringValImpl(key), node);
67+
}
68+
69+
@Override
70+
public PatchBuilder insertNamedChild(XsStringVal path, XsStringVal key, ServerExpression node) {
71+
return addArg("insertNamedChild", path, key, node);
72+
}
73+
74+
@Override
75+
public PatchBuilder remove(String path) {
76+
return addArg("remove", new XsValueImpl.StringValImpl(path));
77+
}
78+
79+
@Override
80+
public PatchBuilder remove(XsStringVal path) {
81+
return addArg("remove", path);
82+
}
83+
84+
@Override
85+
public PatchBuilder replace(String path, ServerExpression node) {
86+
return addArg("replace", path, node);
87+
}
88+
89+
@Override
90+
public PatchBuilder replace(XsStringVal path, ServerExpression node) {
91+
return addArg("replace", path, node);
92+
}
93+
94+
@Override
95+
public PatchBuilder replaceInsertChild(String parentPath, String pathToReplace) {
96+
return addArg("replaceInsertChild", new XsValueImpl.StringValImpl(parentPath), new XsValueImpl.StringValImpl(pathToReplace));
97+
}
98+
99+
@Override
100+
public PatchBuilder replaceInsertChild(XsStringVal parentPath, XsStringVal pathToReplace) {
101+
return addArg("replaceInsertChild", parentPath, pathToReplace);
102+
}
103+
104+
@Override
105+
public PatchBuilder replaceInsertChild(String parentPath, String pathToReplace, ServerExpression node) {
106+
return addArg("replaceInsertChild", new XsValueImpl.StringValImpl(parentPath), new XsValueImpl.StringValImpl(pathToReplace), node);
107+
}
108+
109+
@Override
110+
public PatchBuilder replaceInsertChild(XsStringVal parentPath, XsStringVal pathToReplace, ServerExpression node) {
111+
return addArg("replaceInsertChild", parentPath, pathToReplace, node);
112+
}
113+
114+
@Override
115+
public PatchBuilder replaceValue(String path, ServerExpression value) {
116+
return addArg("replaceValue", path, value);
117+
}
118+
119+
@Override
120+
public PatchBuilder replaceValue(XsStringVal path, ServerExpression value) {
121+
return addArg("replaceValue", path, value);
122+
}
123+
124+
private PatchBuilder addArg(String functionName, String path, ServerExpression value) {
125+
return addArg(functionName, new XsValueImpl.StringValImpl(path), value);
126+
}
127+
128+
private PatchBuilder addArg(String functionName, ServerExpression... expressions) {
129+
BaseTypeImpl.BaseArgImpl newArg = new BaseTypeImpl.BaseCallImpl(
130+
"op", functionName, makeArgs(expressions)
131+
);
132+
List<BaseTypeImpl.BaseArgImpl> newArgs = new ArrayList<>();
133+
newArgs.addAll(Arrays.asList(getArgsImpl()));
134+
newArgs.add(newArg);
135+
return new PatchBuilderImpl(newArgs);
136+
}
137+
138+
private BaseTypeImpl.BaseArgImpl[] makeArgs(ServerExpression... expressions) {
139+
List<BaseTypeImpl.BaseArgImpl> args = new ArrayList<>();
140+
for (ServerExpression expression : expressions) {
141+
args.add((BaseTypeImpl.BaseArgImpl) expression);
142+
}
143+
return args.toArray(new BaseTypeImpl.BaseArgImpl[]{});
144+
}
145+
}

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

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2023 MarkLogic Corporation
2+
* Copyright (c) 2024 MarkLogic Corporation
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -856,6 +856,36 @@ public PlanJoinKey on(PlanExprCol left, PlanExprCol right) {
856856
}
857857

858858

859+
@Override
860+
public ModifyPlan onError(String action) {
861+
return onError((action == null) ? (XsStringVal) null : xs.string(action));
862+
}
863+
864+
865+
@Override
866+
public ModifyPlan onError(XsStringVal action) {
867+
if (action == null) {
868+
throw new IllegalArgumentException("action parameter for onError() cannot be null");
869+
}
870+
return new PlanBuilderSubImpl.ModifyPlanSubImpl("op", "on-error", new Object[]{ action });
871+
}
872+
873+
874+
@Override
875+
public ModifyPlan onError(String action, String errorColumn) {
876+
return onError((action == null) ? (XsStringVal) null : xs.string(action), (errorColumn == null) ? (PlanExprCol) null : exprCol(errorColumn));
877+
}
878+
879+
880+
@Override
881+
public ModifyPlan onError(XsStringVal action, PlanExprCol errorColumn) {
882+
if (action == null) {
883+
throw new IllegalArgumentException("action parameter for onError() cannot be null");
884+
}
885+
return new PlanBuilderSubImpl.ModifyPlanSubImpl("op", "on-error", new Object[]{ action, errorColumn });
886+
}
887+
888+
859889
@Override
860890
public ServerExpression or(ServerExpression... left) {
861891
if (left == null) {

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

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,27 @@ public PlanBuilderSubImpl() {
3434
super();
3535
}
3636

37-
@Override
37+
@Override
38+
public PatchBuilder patchBuilder(String contextPath) {
39+
return new PatchBuilderImpl(new XsValueImpl.StringValImpl(contextPath));
40+
}
41+
42+
@Override
43+
public PatchBuilder patchBuilder(XsStringVal contextPath) {
44+
return new PatchBuilderImpl(contextPath);
45+
}
46+
47+
@Override
48+
public PatchBuilder patchBuilder(String contextPath, Map<String, String> namespaces) {
49+
return new PatchBuilderImpl(new XsValueImpl.StringValImpl(contextPath), namespaces);
50+
}
51+
52+
@Override
53+
public PatchBuilder patchBuilder(XsStringVal contextPath, Map<String, String> namespaces) {
54+
return new PatchBuilderImpl(contextPath, namespaces);
55+
}
56+
57+
@Override
3858
public PlanBuilder.AccessPlan fromSearchDocs(CtsQueryExpr query) {
3959
return fromSearchDocs(query, null);
4060
}
@@ -282,7 +302,7 @@ public PlanRowColTypes colType(String column, String type, Boolean nullable) {
282302
return new PlanRowColTypesImpl(column, type, nullable);
283303
}
284304

285-
305+
286306
@Override
287307
public TransformDef transformDef(String path) {
288308
return new TransformDefImpl(path);
@@ -972,7 +992,17 @@ static class ModifyPlanSubImpl
972992
super(prior, fnPrefix, fnName, fnArgs);
973993
}
974994

975-
@Override
995+
@Override
996+
public ModifyPlan patch(String docColumn, PatchBuilder patchDef) {
997+
return new PlanBuilderSubImpl.ModifyPlanSubImpl(this, "op", "patch", new Object[]{ this.col(docColumn), patchDef });
998+
}
999+
1000+
@Override
1001+
public ModifyPlan patch(PlanExprCol docColumn, PatchBuilder patchDef) {
1002+
return new PlanBuilderSubImpl.ModifyPlanSubImpl(this, "op", "patch", new Object[]{ docColumn, patchDef });
1003+
}
1004+
1005+
@Override
9761006
public PlanBuilder.ModifyPlan groupByUnion(PlanGroupSeq keys) {
9771007
return groupByUnion(keys, null);
9781008
}
@@ -1022,7 +1052,7 @@ public ModifyPlan limit(XsLongVal length) {
10221052
public ModifyPlan limit(PlanParamExpr length) {
10231053
return new ModifyPlanSubImpl(this, "op", "limit", new Object[]{ length });
10241054
}
1025-
1055+
10261056
@Override
10271057
public ModifyPlan lockForUpdate() {
10281058
return new ModifyPlanSubImpl(this, "op", "lockForUpdate", new Object[]{});
@@ -1345,4 +1375,5 @@ public SemIriVal iri(String suffix) {
13451375
return sem.iri(prefix+suffix);
13461376
}
13471377
}
1378+
13481379
}

0 commit comments

Comments
 (0)