Skip to content

Commit 1294ccb

Browse files
authored
Merge pull request #1475 from marklogic/feature/272-unnest
JAVA-272: Added tests for unnest
2 parents ee32c39 + 17599a4 commit 1294ccb

File tree

2 files changed

+135
-0
lines changed

2 files changed

+135
-0
lines changed
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
package com.marklogic.client.test.rows;
2+
3+
import com.fasterxml.jackson.databind.node.ArrayNode;
4+
import com.fasterxml.jackson.databind.node.ObjectNode;
5+
import com.marklogic.client.expression.PlanBuilder;
6+
import com.marklogic.client.row.RowRecord;
7+
import org.junit.Before;
8+
import org.junit.Test;
9+
import org.springframework.util.StringUtils;
10+
11+
import java.util.List;
12+
import java.util.stream.Stream;
13+
14+
import static org.junit.Assert.assertEquals;
15+
import static org.junit.Assert.assertNull;
16+
17+
/**
18+
* Test demonstrates the primary use case for unnest, which is, for a given row, to create N rows based on a column in
19+
* that row containing an array with N values.
20+
*/
21+
public class UnnestTest extends AbstractOpticUpdateTest {
22+
23+
private final static String SINGLE_NAME_COLUMN = "teamMemberName";
24+
25+
/**
26+
* Inserts a test document for testing with the unnestSchema/unnestView view.
27+
*/
28+
@Before
29+
public void insertTestDocument() {
30+
ObjectNode doc = mapper.createObjectNode();
31+
ArrayNode office = doc.putArray("office");
32+
Stream.of("Engineering:Cindy,Alice", "Sales:Bob", "Marketing: ").forEach(value -> {
33+
String[] tokens = value.split(":");
34+
ObjectNode obj = office.addObject();
35+
obj.put("department", tokens[0]);
36+
obj.put("teamMembers", StringUtils.hasText(tokens[1]) ? tokens[1] : null);
37+
});
38+
39+
resultRows(op.fromDocDescriptors(op.docDescriptor(newWriteOp("/acme/office1.json", doc))).write());
40+
}
41+
42+
@Test
43+
public void unnestInner() {
44+
PlanBuilder.ModifyPlan plan = op.fromView("unnestSchema", "unnestView")
45+
.bind(op.as("teamMemberNameArray", op.fn.tokenize(op.col("teamMembers"), op.xs.string(","))))
46+
.unnestInner("teamMemberNameArray", SINGLE_NAME_COLUMN)
47+
.orderBy(op.col(SINGLE_NAME_COLUMN));
48+
49+
List<RowRecord> rows = resultRows(plan);
50+
assertEquals(3, rows.size());
51+
assertEquals("Alice", rows.get(0).getString(SINGLE_NAME_COLUMN));
52+
assertEquals("Bob", rows.get(1).getString(SINGLE_NAME_COLUMN));
53+
assertEquals("Cindy", rows.get(2).getString(SINGLE_NAME_COLUMN));
54+
}
55+
56+
@Test
57+
public void unnestInnerWithOrdinality() {
58+
PlanBuilder.ModifyPlan plan = op.fromView("unnestSchema", "unnestView")
59+
.bind(op.as("teamMemberNameArray", op.fn.tokenize(op.col("teamMembers"), op.xs.string(","))))
60+
.unnestInner("teamMemberNameArray", SINGLE_NAME_COLUMN, "index")
61+
.orderBy(op.col(SINGLE_NAME_COLUMN));
62+
63+
List<RowRecord> rows = resultRows(plan);
64+
assertEquals(3, rows.size());
65+
assertEquals("Alice", rows.get(0).getString(SINGLE_NAME_COLUMN));
66+
assertEquals(
67+
"The ordinality column is expected to capture the index of the value in the array that it came from, " +
68+
"where the index is 1-based, not 0-based", 2, rows.get(0).getInt("index"));
69+
assertEquals("Bob", rows.get(1).getString(SINGLE_NAME_COLUMN));
70+
assertEquals(1, rows.get(1).getInt("index"));
71+
assertEquals("Cindy", rows.get(2).getString(SINGLE_NAME_COLUMN));
72+
assertEquals(1, rows.get(2).getInt("index"));
73+
}
74+
75+
@Test
76+
public void unnestLeftOuter() {
77+
PlanBuilder.ModifyPlan plan = op.fromView("unnestSchema", "unnestView")
78+
.bind(op.as("teamMemberNameArray", op.fn.tokenize(op.col("teamMembers"), op.xs.string(","))))
79+
.unnestLeftOuter("teamMemberNameArray", SINGLE_NAME_COLUMN)
80+
.orderBy(op.col(SINGLE_NAME_COLUMN));
81+
82+
List<RowRecord> rows = resultRows(plan);
83+
assertEquals(4, rows.size());
84+
assertEquals("Alice", rows.get(0).getString(SINGLE_NAME_COLUMN));
85+
assertEquals("Bob", rows.get(1).getString(SINGLE_NAME_COLUMN));
86+
assertEquals("Cindy", rows.get(2).getString(SINGLE_NAME_COLUMN));
87+
assertNull(rows.get(3).get(SINGLE_NAME_COLUMN));
88+
}
89+
90+
@Test
91+
public void unnestLeftOuterWithOrdinality() {
92+
PlanBuilder.ModifyPlan plan = op.fromView("unnestSchema", "unnestView")
93+
.bind(op.as("teamMemberNameArray", op.fn.tokenize(op.col("teamMembers"), op.xs.string(","))))
94+
.unnestLeftOuter("teamMemberNameArray", SINGLE_NAME_COLUMN, "myIndex")
95+
.orderBy(op.col(SINGLE_NAME_COLUMN));
96+
97+
List<RowRecord> rows = resultRows(plan);
98+
assertEquals(4, rows.size());
99+
assertEquals("Alice", rows.get(0).getString(SINGLE_NAME_COLUMN));
100+
assertEquals(2, rows.get(0).getInt("myIndex"));
101+
assertEquals("Bob", rows.get(1).getString(SINGLE_NAME_COLUMN));
102+
assertEquals(1, rows.get(1).getInt("myIndex"));
103+
assertEquals("Cindy", rows.get(2).getString(SINGLE_NAME_COLUMN));
104+
assertEquals(1, rows.get(2).getInt("myIndex"));
105+
assertNull(rows.get(3).get(SINGLE_NAME_COLUMN));
106+
assertNull(rows.get(3).get("myIndex"));
107+
}
108+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"template": {
3+
"context": "office",
4+
"rows": [
5+
{
6+
"schemaName": "unnestSchema",
7+
"viewName": "unnestView",
8+
"columns": [
9+
{
10+
"name": "department",
11+
"scalarType": "string",
12+
"val": "department",
13+
"nullable": true,
14+
"invalidValues": "ignore"
15+
},
16+
{
17+
"name": "teamMembers",
18+
"scalarType": "string",
19+
"val": "teamMembers",
20+
"nullable": true,
21+
"invalidValues": "ignore"
22+
}
23+
]
24+
}
25+
]
26+
}
27+
}

0 commit comments

Comments
 (0)