38
38
import com .redhat .lightblue .query .QueryExpression ;
39
39
import com .redhat .lightblue .query .NaryLogicalOperator ;
40
40
41
+ import com .redhat .lightblue .assoc .BindQuery ;
42
+
43
+ import com .redhat .lightblue .eval .QueryEvaluator ;
44
+
41
45
/**
42
46
* There are two sides to an Assemble step: Assemble gets results from the
43
47
* source, and for each of those documents, it runs the associated queries on
@@ -182,7 +186,7 @@ public void commit() {
182
186
}
183
187
List <ResultDocument > destResults = dest .getResultList (combinedQuery , ctx );
184
188
for (DocAndQ parentDocAndQ : docs ) {
185
- Searches . associateDocs (parentDocAndQ .doc , destResults , aq );
189
+ associateDocs (parentDocAndQ .doc , destResults , aq );
186
190
}
187
191
}
188
192
docs = new ArrayList <>();
@@ -208,6 +212,70 @@ private JsonNode toJson(Step.ToJsonCb<Step> scb,Step.ToJsonCb<ExecutionBlock> bc
208
212
return o ;
209
213
}
210
214
215
+ /**
216
+ * Associates child documents obtained from 'aq' to all the slots in the
217
+ * parent document
218
+ */
219
+ public static void associateDocs (ResultDocument parentDoc ,
220
+ List <ResultDocument > childDocs ,
221
+ AssociationQuery aq ) {
222
+ List <ChildSlot > slots = parentDoc .getSlots ().get (aq .getReference ());
223
+ for (ChildSlot slot : slots ) {
224
+ associateDocs (parentDoc , slot , childDocs , aq );
225
+ }
226
+ }
227
+
228
+ /**
229
+ * Associate child documents with their parents. The association query is
230
+ * for the association from the child to the parent, so caller must flip it
231
+ * before sending it in if necessary. The caller also make sure parentDocs
232
+ * is a unique stream.
233
+ *
234
+ * @param parentDoc The parent document
235
+ * @param parentSlot The slot in parent docuemnt to which the results will
236
+ * be attached
237
+ * @param childDocs The child documents
238
+ * @param aq The association query from parent to child. This may not be the
239
+ * same association query between the blocks. If the child block is before
240
+ * the parent block, a new aq must be constructed for the association from
241
+ * the parent to the child
242
+ */
243
+ public static void associateDocs (ResultDocument parentDoc ,
244
+ ChildSlot parentSlot ,
245
+ List <ResultDocument > childDocs ,
246
+ AssociationQuery aq ) {
247
+ if (!childDocs .isEmpty ()) {
248
+ LOGGER .debug ("Associating docs" );
249
+ ExecutionBlock childBlock = childDocs .get (0 ).getBlock ();
250
+ ArrayNode destNode = (ArrayNode ) parentDoc .getDoc ().get (parentSlot .getSlotFieldName ());
251
+ BindQuery binders = parentDoc .getBindersForSlot (parentSlot , aq );
252
+ // No binders means all child docs will be added to the parent
253
+ if (binders .getBindings ().isEmpty ()) {
254
+ if (destNode == null ) {
255
+ destNode = JsonNodeFactory .instance .arrayNode ();
256
+ parentDoc .getDoc ().modify (parentSlot .getSlotFieldName (), destNode , true );
257
+ }
258
+ for (ResultDocument d : childDocs ) {
259
+ destNode .add (d .getDoc ().getRoot ());
260
+ }
261
+ } else {
262
+ QueryExpression boundQuery = binders .iterate (aq .getQuery ());
263
+ LOGGER .debug ("Association query:{}" , boundQuery );
264
+ QueryEvaluator qeval = QueryEvaluator .getInstance (boundQuery , childBlock .getMetadata ());
265
+ for (ResultDocument childDoc : childDocs ) {
266
+ if (qeval .evaluate (childDoc .getDoc ()).getResult ()) {
267
+ if (destNode == null ) {
268
+ destNode = JsonNodeFactory .instance .arrayNode ();
269
+ parentDoc .getDoc ().modify (parentSlot .getSlotFieldName (), destNode , true );
270
+ }
271
+ destNode .add (childDoc .getDoc ().getRoot ());
272
+ }
273
+ }
274
+ }
275
+ }
276
+ }
277
+
278
+
211
279
@ Override
212
280
public JsonNode toJson () {
213
281
return toJson (Step ::toJson ,ExecutionBlock ::toJson );
0 commit comments