Skip to content

Commit 10f9db7

Browse files
authored
Merge pull request #1555 from marklogic/feature/394-columnInfo
DEVEXP-394 columnInfo now supports DSL and serialized queries
2 parents 168ced8 + acdce1c commit 10f9db7

File tree

6 files changed

+606
-6
lines changed

6 files changed

+606
-6
lines changed

marklogic-client-api/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ dependencies {
5353
testImplementation 'org.apache.httpcomponents:httpclient:4.5.14'
5454
testImplementation 'com.opencsv:opencsv:4.6'
5555
testImplementation 'org.geonames:geonames:1.0'
56+
testImplementation 'org.skyscreamer:jsonassert:1.5.0'
5657
}
5758

5859
// Ensure that mlHost and mlPassword can override the defaults of localhost/admin if they've been modified

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,7 @@ public <T> T generateViewAs(PlanBuilder.PreparePlan plan, String schema, String
331331
}
332332

333333
@Override
334-
public <T extends JSONReadHandle> T columnInfo(PlanBuilder.PreparePlan plan, T resultsHandle) {
334+
public <T extends JSONReadHandle> T columnInfo(PlanBuilder.Plan plan, T resultsHandle) {
335335
if (resultsHandle == null) {
336336
throw new IllegalArgumentException("Must specify a handle to generate a view for the plan");
337337
}
@@ -345,7 +345,7 @@ public <T extends JSONReadHandle> T columnInfo(PlanBuilder.PreparePlan plan, T r
345345
return services.postResource(requestLogger, "rows", null, params, astHandle, resultsHandle);
346346
}
347347
@Override
348-
public <T> T columnInfoAs(PlanBuilder.PreparePlan plan, Class<T> as) {
348+
public <T> T columnInfoAs(PlanBuilder.Plan plan, Class<T> as) {
349349
ContentHandle<T> handle = handleFor(as);
350350
if (!(handle instanceof JSONReadHandle))
351351
throw new IllegalArgumentException("The handle is not an instance of JSONReadHandle.");

marklogic-client-api/src/main/java/com/marklogic/client/row/RowManager.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -344,10 +344,12 @@ public enum RowStructure{ARRAY, OBJECT}
344344
* @param <T> the type of the handle for the column information
345345
* @return the handle with the content of the column information for the plan
346346
*/
347-
<T extends JSONReadHandle> T columnInfo(PlanBuilder.PreparePlan plan, T handle);
348-
/**This function can be used to inspect the state of a plan before execution. It returns the information about each
347+
<T extends JSONReadHandle> T columnInfo(PlanBuilder.Plan plan, T handle);
348+
349+
/**
350+
* This function can be used to inspect the state of a plan before execution. It returns the information about each
349351
* column in the plan, including schema name, view name, column name, data type and nullability. It also returns the
350-
* information about system columns.Generates generates a view that encapsulates a plan.
352+
* information about system columns.
351353
*
352354
* The IO class must have been registered before creating the database client.
353355
* By default, the provided handles that implement
@@ -360,7 +362,7 @@ public enum RowStructure{ARRAY, OBJECT}
360362
* @param <T> the type of the IO object for reading the column information
361363
* @return an object of the IO class with the content of the column information for the plan
362364
*/
363-
<T> T columnInfoAs(PlanBuilder.PreparePlan plan, Class<T> as);
365+
<T> T columnInfoAs(PlanBuilder.Plan plan, Class<T> as);
364366

365367
/**
366368
* Executes a GraphQL query against the database and returns the results as a JSON object.
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package com.marklogic.client.test.rows;
2+
3+
import com.fasterxml.jackson.databind.JsonNode;
4+
import com.fasterxml.jackson.databind.ObjectMapper;
5+
import com.marklogic.client.expression.PlanBuilder;
6+
import com.marklogic.client.io.StringHandle;
7+
import com.marklogic.client.row.RawPlanDefinition;
8+
import com.marklogic.client.row.RawQueryDSLPlan;
9+
import com.marklogic.client.row.RowManager;
10+
import com.marklogic.client.test.Common;
11+
import org.junit.jupiter.api.BeforeEach;
12+
import org.junit.jupiter.api.Test;
13+
import org.skyscreamer.jsonassert.JSONAssert;
14+
import org.springframework.core.io.ClassPathResource;
15+
16+
import static org.junit.jupiter.api.Assertions.assertEquals;
17+
import static org.junit.jupiter.api.Assertions.assertTrue;
18+
19+
public class ColumnInfoTest {
20+
21+
private RowManager rowManager;
22+
23+
@BeforeEach
24+
void beforeEach() {
25+
rowManager = Common.newClient().newRowManager();
26+
}
27+
28+
@Test
29+
void allTypesWithDSLPlan() {
30+
String query = "op.fromView('javaClient', 'allTypes')";
31+
RawQueryDSLPlan plan = rowManager.newRawQueryDSLPlan(new StringHandle(query));
32+
verifyColumnInfo(plan);
33+
}
34+
35+
@Test
36+
void allTypesWithSerializedPlan() {
37+
String serializedQuery = "{\n" +
38+
" \"$optic\": {\n" +
39+
" \"ns\": \"op\",\n" +
40+
" \"fn\": \"operators\",\n" +
41+
" \"args\": [\n" +
42+
" {\n" +
43+
" \"ns\": \"op\",\n" +
44+
" \"fn\": \"from-view\",\n" +
45+
" \"args\": [\n" +
46+
" \"javaClient\",\n" +
47+
" \"allTypes\"\n" +
48+
" ]\n" +
49+
" }\n" +
50+
" ]\n" +
51+
" }\n" +
52+
"}";
53+
54+
RawPlanDefinition plan = rowManager.newRawPlanDefinition(new StringHandle(serializedQuery));
55+
verifyColumnInfo(plan);
56+
}
57+
58+
/**
59+
* The expected JSON for all the column infos is based on the results from the 20230417 build. See the internal
60+
* DBQ-296 ticket for an explanation on why some of the columns have an expected type of "none".
61+
*
62+
* @param plan
63+
*/
64+
private void verifyColumnInfo(PlanBuilder.Plan plan) {
65+
StringHandle output = Common.client.newRowManager().columnInfo(plan, new StringHandle());
66+
67+
assertTrue(output.getServerTimestamp() > 0, "The server timestamp should be present so that a client, such as " +
68+
"the Spark connector, can both get column info and identify a timestamp for future point-in-time queries.");
69+
70+
String[] columnInfos = output.get().split("\n");
71+
assertEquals(36, columnInfos.length, "There are 35 column definitions in the allTypes TDE, and then a 36th " +
72+
"column info is added for the rowid column.");
73+
74+
ObjectMapper mapper = new ObjectMapper();
75+
try {
76+
JsonNode actualColumnInfo = mapper.readTree("[" + String.join(",", columnInfos) + "]");
77+
JsonNode expectedColumnInfo = mapper.readTree(new ClassPathResource("allTypes-columnInfo.json").getInputStream());
78+
JSONAssert.assertEquals(expectedColumnInfo.toString(), actualColumnInfo.toString(), true);
79+
} catch (Exception ex) {
80+
throw new RuntimeException(ex);
81+
}
82+
}
83+
}

0 commit comments

Comments
 (0)