Skip to content
This repository was archived by the owner on Sep 16, 2024. It is now read-only.

Commit aba6996

Browse files
committed
LoadSchemas to use tde template batch insert
1 parent dc893de commit aba6996

File tree

6 files changed

+118
-28
lines changed

6 files changed

+118
-28
lines changed

src/main/java/com/marklogic/client/ext/file/GenericFileLoader.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,7 @@ public GenericFileLoader(BatchWriter batchWriter) {
7272
*/
7373
public List<DocumentFile> loadFiles(String... paths) {
7474
batchWriter.initialize();
75-
initializeDocumentFileReader();
76-
77-
List<DocumentFile> documentFiles = documentFileReader.readDocumentFiles(paths);
75+
List<DocumentFile> documentFiles = getDocumentFiles(paths);
7876
if (documentFiles != null && !documentFiles.isEmpty()) {
7977
writeBatchOfDocuments(documentFiles, 0);
8078
if (waitForCompletion) {
@@ -84,6 +82,11 @@ public List<DocumentFile> loadFiles(String... paths) {
8482
return documentFiles;
8583
}
8684

85+
public List<DocumentFile> getDocumentFiles(String... paths) {
86+
initializeDocumentFileReader();
87+
return documentFileReader.readDocumentFiles(paths);
88+
}
89+
8790
/**
8891
* If batchSize is not set, then this method will load all the documents in one call to the BatchWriter. Otherwise,
8992
* this will divide up the list of documentFiles into batches matching the value of batchSize, with the last batch

src/main/java/com/marklogic/client/ext/helper/ClientHelper.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55
import java.util.List;
66

77
import com.marklogic.client.DatabaseClient;
8+
import com.marklogic.client.eval.ServerEvaluationCall;
89
import com.marklogic.client.io.DocumentMetadataHandle;
910
import com.marklogic.client.io.DocumentMetadataHandle.DocumentCollections;
1011
import com.marklogic.client.io.SearchHandle;
12+
import com.marklogic.client.io.StringHandle;
1113
import com.marklogic.client.query.MatchDocumentSummary;
1214
import com.marklogic.client.query.QueryManager;
1315
import com.marklogic.client.query.StringQueryDefinition;
@@ -65,4 +67,15 @@ public List<String> getUrisInCollection(String collectionName, int pageLength) {
6567
public String eval(String expr) {
6668
return getClient().newServerEval().xquery(expr).evalAs(String.class);
6769
}
70+
71+
public int getMLEffectiveVersion() {
72+
int version = -1;
73+
StringBuilder script = new StringBuilder("xdmp.effectiveVersion();");
74+
ServerEvaluationCall call = client.newServerEval().javascript(script.toString());
75+
if (call != null) {
76+
String node = call.eval(new StringHandle()).get();
77+
version = Integer.parseInt(node);
78+
}
79+
return version;
80+
}
6881
}

src/main/java/com/marklogic/client/ext/schemasloader/impl/DefaultSchemasLoader.java

Lines changed: 65 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,31 @@
11
package com.marklogic.client.ext.schemasloader.impl;
22

33
import com.marklogic.client.DatabaseClient;
4+
import com.marklogic.client.eval.ServerEvaluationCall;
45
import com.marklogic.client.ext.batch.BatchWriter;
56
import com.marklogic.client.ext.batch.RestBatchWriter;
67
import com.marklogic.client.ext.file.DocumentFile;
78
import com.marklogic.client.ext.file.GenericFileLoader;
9+
import com.marklogic.client.ext.helper.ClientHelper;
810
import com.marklogic.client.ext.modulesloader.impl.DefaultFileFilter;
911
import com.marklogic.client.ext.schemasloader.SchemasLoader;
12+
import com.marklogic.client.io.DocumentMetadataHandle;
1013

14+
import java.util.ArrayList;
1115
import java.util.List;
16+
import java.util.Set;
1217
import java.util.function.Supplier;
18+
import java.util.stream.Collectors;
1319

1420
public class DefaultSchemasLoader extends GenericFileLoader implements SchemasLoader {
1521

1622
private DatabaseClient schemasDatabaseClient;
1723
private String tdeValidationDatabase;
1824

1925
/**
20-
* Simplest constructor for using this class. Just provide a DatabaseClient, and this will use sensible defaults
21-
* for how documents are read and written. Note that the DatabaseClient will not be released after this class is
22-
* done with it, as this class wasn't the one that created it.
26+
* Simplest constructor for using this class. Just provide a DatabaseClient, and this will use sensible defaults for
27+
* how documents are read and written. Note that the DatabaseClient will not be released after this class is done
28+
* with it, as this class wasn't the one that created it.
2329
*
2430
* @param schemasDatabaseClient
2531
*/
@@ -70,14 +76,21 @@ protected void initializeDefaultSchemasLoader() {
7076
}
7177

7278
/**
73-
* Run the given paths through the DocumentFileReader, and then send the result to the BatchWriter, and then
74-
* return the result.
79+
* Run the given paths through the DocumentFileReader, and then send the result to the BatchWriter, and then return
80+
* the result.
7581
*
7682
* @param paths
7783
* @return a DocumentFile for each file that was loaded as a schema
7884
*/
7985
@Override
8086
public List<DocumentFile> loadSchemas(String... paths) {
87+
ClientHelper helper = new ClientHelper(schemasDatabaseClient);
88+
if (helper.getMLEffectiveVersion() >= 10000900 && tdeValidationDatabase != null && !tdeValidationDatabase.isEmpty()) {
89+
logger.info("Installing tde's using tde.templateBatchInsert");
90+
List<DocumentFile> documentFiles = super.getDocumentFiles(paths);
91+
buildTemplateBatchInsertCall(documentFiles).eval().close();
92+
return documentFiles;
93+
}
8194
return super.loadFiles(paths);
8295
}
8396

@@ -88,4 +101,51 @@ public String getTdeValidationDatabase() {
88101
public void setTdeValidationDatabase(String tdeValidationDatabase) {
89102
this.tdeValidationDatabase = tdeValidationDatabase;
90103
}
104+
105+
protected ServerEvaluationCall buildTemplateBatchInsertCall(List<DocumentFile> documentFiles) {
106+
String tdeTemplate = getTdeBatchInsertQuery(documentFiles);
107+
StringBuilder script = new StringBuilder("declareUpdate(); xdmp.invokeFunction(function() {var tde = require('/MarkLogic/tde.xqy');");
108+
script.append(tdeTemplate);
109+
script.append(format("}, {database: xdmp.database('%s')})", tdeValidationDatabase));
110+
return schemasDatabaseClient.newServerEval().javascript(script.toString());
111+
}
112+
113+
private String getTdeBatchInsertQuery(List<DocumentFile> documentFiles) {
114+
List<String> templateInfoList = new ArrayList<>();
115+
for (DocumentFile doc : documentFiles) {
116+
String uri = doc.getUri();
117+
String content = doc.getContent().toString();
118+
119+
// Permissions
120+
DocumentMetadataHandle.DocumentPermissions documentPermissions = doc.getDocumentMetadata().getPermissions();
121+
List<String> permissionList = new ArrayList<>();
122+
documentPermissions.keySet().forEach(key -> {
123+
Set<DocumentMetadataHandle.Capability> values = documentPermissions.get(key);
124+
values.forEach(value -> permissionList.add(String.format("xdmp.permission('%s', '%s')", key, value)));
125+
});
126+
String permissions = "[".concat(permissionList.stream().collect(Collectors.joining(", "))).concat("]");
127+
128+
// Collections
129+
List<String> collectionsList = new ArrayList<>();
130+
doc.getDocumentMetadata().getCollections().forEach(collection -> collectionsList.add(collection));
131+
String collections = collectionsList.stream().map(coll -> '"' + coll + '"').collect(Collectors.joining(", "));
132+
collections = "[".concat(collections).concat("]");
133+
134+
// Template info
135+
String templateFormat = "";
136+
if (doc.getFormat().toString().equals("XML")) {
137+
templateFormat = String.format("tde.templateInfo('%s', xdmp.unquote(`%s`), %s, %s)", uri, content, permissions, collections);
138+
} else if (doc.getFormat().toString().equals("JSON")) {
139+
templateFormat = String.format("tde.templateInfo('%s', xdmp.toJSON(%s), %s, %s)", uri, content, permissions, collections);
140+
} else {
141+
templateFormat = String.format("tde.templateInfo('%s',%s, %s, %s)", uri, content, permissions, collections);
142+
}
143+
templateInfoList.add(templateFormat);
144+
}
145+
146+
String templateString = "tde.templateBatchInsert(["
147+
.concat(templateInfoList.stream().collect(Collectors.joining(",")))
148+
.concat("]);");
149+
return templateString;
150+
}
91151
}

src/main/java/com/marklogic/client/ext/schemasloader/impl/TdeDocumentFileProcessor.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import com.marklogic.client.eval.ServerEvaluationCall;
66
import com.marklogic.client.ext.file.DocumentFile;
77
import com.marklogic.client.ext.file.DocumentFileProcessor;
8+
import com.marklogic.client.ext.helper.ClientHelper;
89
import com.marklogic.client.ext.helper.LoggingObject;
910
import com.marklogic.client.io.Format;
1011
import com.marklogic.client.io.JacksonHandle;
@@ -37,6 +38,7 @@ public TdeDocumentFileProcessor(DatabaseClient databaseClient, String tdeValidat
3738

3839
@Override
3940
public DocumentFile processDocumentFile(DocumentFile documentFile) {
41+
ClientHelper helper = new ClientHelper(databaseClient);
4042
String uri = documentFile.getUri();
4143
String extension = documentFile.getFileExtension();
4244
if (extension != null) {
@@ -54,8 +56,16 @@ public DocumentFile processDocumentFile(DocumentFile documentFile) {
5456
documentFile.setFormat(Format.XML);
5557
}
5658

59+
if(isTdeTemplate) {
60+
return documentFile;
61+
}
62+
5763
if (isTdeTemplate) {
58-
validateTdeTemplate(documentFile);
64+
if(helper.getMLEffectiveVersion() >= 10000900 && tdeValidationDatabase != null && !tdeValidationDatabase.isEmpty()) {
65+
return documentFile;
66+
} else {
67+
validateTdeTemplate(documentFile);
68+
}
5969
}
6070

6171
return documentFile;

src/test/java/com/marklogic/client/ext/schemasloader/impl/LoadSchemasTest.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,17 @@ public void test() {
3030
assertTrue(uris.contains("/parent.tdex"));
3131
assertTrue(uris.contains("/tde/ruleset.txt"));
3232
}
33+
34+
@Test
35+
public void testTemplateBatchInsert() {
36+
DefaultSchemasLoader loader = new DefaultSchemasLoader(client, "Documents");
37+
List<DocumentFile> files = loader.loadSchemas(Paths.get("src", "test", "resources", "good-schemas", "originals").toString());
38+
assertEquals(2, files.size());
39+
40+
ClientHelper helper = new ClientHelper(client);
41+
List<String> uris = helper.getUrisInCollection("http://marklogic.com/xdmp/tde");
42+
assertEquals(2, uris.size());
43+
assertTrue(uris.contains("/tde/good-schema.json"));
44+
assertTrue(uris.contains("/tde/good-schema.xml"));
45+
}
3346
}

src/test/java/com/marklogic/client/ext/schemasloader/impl/ValidateTdeTemplatesTest.java

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.marklogic.client.ext.schemasloader.impl;
22

3+
import com.marklogic.client.FailedRequestException;
34
import com.marklogic.client.ext.file.DocumentFile;
45
import org.junit.jupiter.api.BeforeEach;
56
import org.junit.jupiter.api.Test;
@@ -26,14 +27,9 @@ public void setup() {
2627

2728
@Test
2829
public void badJsonFile() {
29-
try {
30-
loader.loadSchemas(Paths.get("src", "test", "resources", "bad-schemas", "bad-json").toString());
31-
fail("The bad-template.json file should have failed processing because it has a duplicate column in it");
32-
} catch (RuntimeException ex) {
33-
String message = ex.getCause().getMessage();
34-
assertTrue(message.startsWith("TDE template failed validation"));
35-
assertTrue(message.contains("TDE-REPEATEDCOLUMN"));
36-
}
30+
FailedRequestException ex = assertThrows(FailedRequestException.class, () ->
31+
loader.loadSchemas(Paths.get("src", "test", "resources", "bad-schemas", "bad-json").toString()));
32+
logger.info(ex.getMessage());
3733
}
3834

3935
@Test
@@ -50,21 +46,16 @@ public void goodTemplateThatsThenUpdatedViaJavascript() {
5046

5147
@Test
5248
public void badXmlFile() {
53-
try {
54-
loader.loadSchemas(Paths.get("src", "test", "resources", "bad-schemas", "bad-xml").toString());
55-
fail("The bad-template.xml file should have failed processing because it has a duplicate column in it");
56-
} catch (RuntimeException ex) {
57-
String message = ex.getCause().getMessage();
58-
assertTrue(message.startsWith("TDE template failed validation"));
59-
assertTrue(message.contains("TDE-REPEATEDCOLUMN"));
60-
}
49+
FailedRequestException ex = assertThrows(FailedRequestException.class, () ->
50+
loader.loadSchemas(Paths.get("src", "test", "resources", "bad-schemas", "bad-xml").toString()));
51+
logger.info(ex.getMessage());
6152
}
6253

6354
@Test
6455
public void badJsonFileInNonTdeDirectory() {
65-
List<DocumentFile> files = loader.loadSchemas(Paths.get("src", "test", "resources", "bad-schemas", "otherpath").toString());
66-
assertEquals(1, files.size(), "The file in the otherpath directory is a TDE template, but it's not under /tde/, so it's not " +
67-
"validated as a TDE template");
56+
FailedRequestException ex = assertThrows(FailedRequestException.class, () ->
57+
loader.loadSchemas(Paths.get("src", "test", "resources", "bad-schemas", "otherpath").toString()));
58+
logger.info(ex.getMessage());
6859
}
6960

7061
@Test

0 commit comments

Comments
 (0)