Skip to content

MLE-28334 Implement Fragment Option#1937

Open
jonmille wants to merge 1 commit into
developfrom
MLE-28334-Fragment-Option
Open

MLE-28334 Implement Fragment Option#1937
jonmille wants to merge 1 commit into
developfrom
MLE-28334-Fragment-Option

Conversation

@jonmille
Copy link
Copy Markdown

Add fragment option to fromSearch() and fromSearchDocs() (MLE-28334)

Summary

Implements the fragment search option introduced in MarkLogic 12.1, which controls which fragment types (DOCUMENT, PROPERTIES, LOCKS, or ANY) are searched and returned by fromSearch() and fromSearchDocs().

Changes

API (PlanSearchOptions)

  • Added Fragment enum with values DOCUMENT, ANY, PROPERTIES, LOCKS
  • Added getFragment() and withFragment(Fragment) to PlanSearchOptions
  • Updated class-level Javadoc to document fragment scope support and MarkLogic 12.1 requirement

Implementation (PlanBuilderBaseImpl, PlanBuilderBase, PlanBuilderSubImpl)

  • Added fragment field and updated all-args constructor in PlanSearchOptionsImpl
  • Implemented getFragment(), withFragment(), and serialization in makeMap() (emits lowercase fragment name as "fragment" key)
  • Added new fromSearchDocs(CtsQueryExpr, String, PlanSearchOptions) overload
  • Bug fix: fromSearchDocs(query, qualifierName) was incorrectly delegating to fromSearchDocs(query, null, null) instead of fromSearchDocs(query, qualifierName, null), silently discarding the qualifier

Tests

  • Added RequiresML12Dot1 JUnit 5 extension to skip tests on MarkLogic versions below 12.1
  • Added FromSearchDocsWithFragmentTest — tests all four fragment types (DOCUMENT, LOCKS, PROPERTIES, ANY) via fromSearchDocs(), plus an explain() smoke test
  • Added FromSearchWithFragmentTest — equivalent coverage for fromSearch(), including a joinDocUri() join for document/any fragment cases; notes that joinDocUri is unsupported for lock and properties fragment IDs on 12.1
  • Both test classes use isolated documents with explicit lock acquisition and property insertion to prove each fragment type is correctly targeted

Notes

  • Fragment scope requires MarkLogic 12.1 or higher; both new test classes are gated by @ExtendWith(RequiresML12Dot1.class)
  • fromSearchDocs() with ANY returns multiple rows per document (one per fragment type), unlike fromSearch() which returns one row per matched fragment ID

Jira Ticket: https://progresssoftware.atlassian.net/browse/MLE-28334

Copilot AI review requested due to automatic review settings May 14, 2026 19:09
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds support for the MarkLogic 12.1 fragment search option to fromSearch() and fromSearchDocs(), allowing callers to scope row-pipeline queries to DOCUMENT, PROPERTIES, LOCKS, or ANY fragment types. Also fixes an existing bug in the two-argument fromSearchDocs overload that silently dropped the qualifier name.

Changes:

  • Extends PlanSearchOptions with a Fragment enum, getFragment()/withFragment(), and corresponding impl/serialization in PlanBuilderBaseImpl (emits "fragment" key with lowercase value).
  • Fixes PlanBuilderSubImpl.fromSearchDocs(query, qualifierName) to forward qualifierName instead of null.
  • Adds JUnit 5 RequiresML12Dot1 extension and two new test classes (FromSearchWithFragmentTest, FromSearchDocsWithFragmentTest) covering all four fragment types and an explain() smoke test.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
marklogic-client-api/src/main/java/com/marklogic/client/type/PlanSearchOptions.java Adds Fragment enum and getFragment/withFragment to the public options interface.
marklogic-client-api/src/main/java/com/marklogic/client/impl/PlanBuilderBaseImpl.java Implements fragment field, constructor, accessors and serialization in PlanSearchOptionsImpl.makeMap().
marklogic-client-api/src/main/java/com/marklogic/client/impl/PlanBuilderSubImpl.java Bug fix: forwards qualifierName in two-arg fromSearchDocs overload.
marklogic-client-api/src/main/java/com/marklogic/client/expression/PlanBuilderBase.java Updates Javadoc for fromSearchDocs/fromSearch overloads to document fragment scope and 12.1 requirement.
marklogic-client-api/src/test/java/com/marklogic/client/test/junit5/RequiresML12Dot1.java New JUnit 5 ExecutionCondition gating tests on MarkLogic ≥ 12.1.
marklogic-client-api/src/test/java/com/marklogic/client/test/rows/FromSearchWithFragmentTest.java Tests fragment option behavior for fromSearch().
marklogic-client-api/src/test/java/com/marklogic/client/test/rows/FromSearchDocsWithFragmentTest.java Tests fragment option behavior for fromSearchDocs().

Comment on lines +58 to +63
* @param options Specifies scoring options and the fragment type to search. Use
* {@link PlanBuilder#searchOptions()} with
* {@link PlanSearchOptions#withFragment(PlanSearchOptions.Fragment)} to control
* the fragment scope.
* @return an AccessPlan object
* @since 8.2.0; requires MarkLogic 12.1 or higher.
Comment on lines +48 to +58
Fragment getFragment();

/**
* Specifies the type of fragment to search and return. Defaults to {@link Fragment#DOCUMENT} when no option
* is specified. Applies to both {@code fromSearch()} and {@code fromSearchDocs()}.
*
* @param fragment the fragment scope to select
* @return a new PlanSearchOptions with the fragment set
* @since 8.2.0; requires MarkLogic 12.1 or higher.
*/
PlanSearchOptions withFragment(Fragment fragment);
Comment on lines +35 to +68
private static final String SETUP_XQUERY =
"xquery version '1.0-ml';" +
"let $jsondoc1 := object-node {'AllDataTypes': array-node {object-node {'word':'dog'}, object-node {'rank':1}, object-node {'score':4}}}" +
"let $jsondoc2 := object-node {'AllDataTypes': array-node {object-node {'word':'cat'}, object-node {'rank':2}, object-node {'score':5}}}" +
"let $jsondoc3 := object-node {'AllDataTypes': array-node {object-node {'word':'duck'}, object-node {'rank':3}, object-node {'score':6}}}" +
"return (" +
"xdmp:document-insert('range-prop-1.json', $jsondoc1, xdmp:default-permissions(), ('elemCol','jsondoc-range','from-search-fragment-test'))," +
"xdmp:document-insert('range-prop-2.json', $jsondoc2, xdmp:default-permissions(), ('elemCol','jsondoc-range','from-search-fragment-test'))," +
"xdmp:document-insert('range-prop-3.json', $jsondoc3, xdmp:default-permissions(), ('elemCol','jsondoc-range','from-search-fragment-test'))," +
"xdmp:document-set-properties('range-prop-1.json', (<my-prop>opticfragmentpropvalue prop1value</my-prop>))," +
"xdmp:document-set-properties('range-prop-2.json', (<my-prop>opticfragmentpropvalue prop2value</my-prop>))," +
"xdmp:document-set-properties('range-prop-3.json', (<my-prop>opticfragmentpropvalue prop3value</my-prop>))," +
"xdmp:lock-acquire('range-prop-1.json', 'exclusive', '0', 'dog rose', xs:unsignedLong(120))," +
"xdmp:lock-acquire('range-prop-2.json', 'exclusive', '0', 'cat tulip', xs:unsignedLong(120))," +
"xdmp:lock-acquire('range-prop-3.json', 'exclusive', '0', 'duck lily', xs:unsignedLong(120))" +
")";

private static final String TEARDOWN_XQUERY =
"xquery version '1.0-ml';" +
"for $uri in ('range-prop-1.json', 'range-prop-2.json', 'range-prop-3.json') return xdmp:document-delete($uri)";

private static final List<String> EXPECTED_URIS = List.of(
"range-prop-1.json", "range-prop-2.json", "range-prop-3.json");

@BeforeEach
void setupTest() {
rowManager.withUpdate(false);
Common.newEvalClient().newServerEval().xquery(SETUP_XQUERY).evalAs(String.class);
}

@AfterEach
void teardownTest() {
Common.newEvalClient().newServerEval().xquery(TEARDOWN_XQUERY).evalAs(String.class);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants