Skip to content

Commit 019ad48

Browse files
authored
Merge pull request #368 from metafacture/127-arrays
Implicit array creation with `$append`, general `$prepend` support
2 parents 6496352 + fe84442 commit 019ad48

File tree

36 files changed

+232
-70
lines changed

36 files changed

+232
-70
lines changed

metafix/src/main/java/org/metafacture/metafix/FixPath.java

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,9 @@ void apply(final Array array, final String field, final Value value) {
170170
final ReservedField reservedField = ReservedField.fromString(field);
171171
if (reservedField != null) {
172172
switch (reservedField) {
173+
case $prepend:
174+
array.add(0, value);
175+
break;
173176
case $append:
174177
array.add(value);
175178
break;
@@ -275,10 +278,8 @@ else if (isReference(field)) {
275278
mode.apply(hash, field, newValue);
276279
}
277280
else {
278-
if (!hash.containsField(field)) {
279-
hash.put(field, Value.newHash().withPathSet(newValue.getPath()));
280-
}
281-
insertInto(hash.get(field), mode, newValue, field, tail(path));
281+
final String[] tail = tail(path);
282+
insertInto(getContainerValue(hash, field, newValue.getPath(), tail[0]), mode, newValue, field, tail);
282283
}
283284

284285
return new Value(hash);
@@ -298,12 +299,29 @@ private Value insertInto(final Value value, final InsertMode mode, final Value n
298299
}
299300
}
300301

302+
private Value getContainerValue(final Hash hash, final String field, final String newPath, final String nextField) {
303+
Value result = hash.get(field);
304+
final boolean isAddingToArray = nextField.equals(ReservedField.$prepend.name()) || nextField.equals(ReservedField.$append.name());
305+
if (result == null) {
306+
result = (isAddingToArray ? Value.newArray() : Value.newHash()).withPathSet(newPath);
307+
hash.put(field, result);
308+
}
309+
else {
310+
if (isAddingToArray && result.isString()) {
311+
final Value value = result;
312+
result = Value.newArray(a -> a.add(value));
313+
hash.put(field, result);
314+
}
315+
}
316+
return result;
317+
}
318+
301319
private String[] tail(final String[] fields) {
302320
return Arrays.copyOfRange(fields, 1, fields.length);
303321
}
304322

305323
private enum ReservedField {
306-
$append, $first, $last;
324+
$prepend, $append, $first, $last;
307325

308326
private static final Map<String, ReservedField> STRING_TO_ENUM = new HashMap<>();
309327
static {
@@ -343,6 +361,10 @@ private Value getReferencedValue(final Array array, final String field, final St
343361
referencedValue = Value.newHash().withPathSet(p); // TODO: append non-hash?
344362
array.add(referencedValue);
345363
break;
364+
case $prepend:
365+
referencedValue = Value.newHash().withPathSet(p);
366+
array.add(0, referencedValue);
367+
break;
346368
default:
347369
break;
348370
}

metafix/src/main/java/org/metafacture/metafix/Value.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -433,8 +433,24 @@ public void add(final Value value) {
433433
}
434434

435435
/* package-private */ void add(final Value value, final boolean appendToPath) {
436+
add(list.size(), value, appendToPath);
437+
}
438+
439+
/* package-private */ void add(final int index, final Value value) {
440+
add(index, value, true);
441+
}
442+
443+
/* package-private */ void add(final int index, final Value value, final boolean appendToPath) {
436444
if (!isNull(value)) {
437-
list.add(appendToPath ? value.withPathAppend(list.size() + 1) : value);
445+
list.add(index, appendToPath ? value.withPathAppend(index + 1) : value);
446+
updateIndexesInPathsAfter(index);
447+
}
448+
}
449+
450+
private void updateIndexesInPathsAfter(final int start) {
451+
for (int index = start + 1; index < list.size(); index = index + 1) {
452+
final Value value = list.get(index);
453+
value.withPathSet(value.getPath().replaceAll("\\d+$", String.valueOf(index + 1)));
438454
}
439455
}
440456

metafix/src/test/java/org/metafacture/metafix/MetafixLookupTest.java

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -928,14 +928,23 @@ public void shouldLookupInNestedArrays() {
928928
}
929929

930930
@Test
931-
public void shouldLookupInCopiedNestedArrays() {
931+
public void shouldLookupInCopiedNestedArraysCreatedWithAppend() {
932+
shouldLookupInCopiedNestedArraysCreatedWith("$append");
933+
}
934+
935+
@Test
936+
public void shouldLookupInCopiedNestedArraysCreatedWithPrepend() {
937+
shouldLookupInCopiedNestedArraysCreatedWith("$prepend");
938+
}
939+
940+
private void shouldLookupInCopiedNestedArraysCreatedWith(final String reservedField) {
932941
MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(
933942
"put_map('rswk-indicator', s: 'SubjectHeading')",
934943
"set_array('subject[]')",
935-
"set_array('subject[].$append.componentList[]')",
936-
"set_array('subject[].$last.componentList[].$append.type[]')",
944+
"set_array('subject[]." + reservedField + ".componentList[]')",
945+
"set_array('subject[].$last.componentList[]." + reservedField + ".type[]')",
937946
"do list(path: 'D', 'var': '$i')",
938-
" copy_field('$i', 'subject[].$last.componentList[].$last.type[].$append')",
947+
" copy_field('$i', 'subject[].$last.componentList[].$last.type[]." + reservedField + "')",
939948
"end",
940949
"lookup('subject[].*.componentList[].*.type[].*', 'rswk-indicator')",
941950
"retain('subject[]')"

metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java

Lines changed: 139 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,115 @@ public void addWithAppendInNewArray() {
303303
);
304304
}
305305

306+
@Test
307+
public void addWithAppendInImplicitArray() {
308+
MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(
309+
"add_field('my.name.$append','patrick')",
310+
"add_field('my.name.$append','nicolas')"
311+
),
312+
i -> {
313+
i.startRecord("1");
314+
i.endRecord();
315+
316+
i.startRecord("2");
317+
i.startEntity("my");
318+
i.literal("name", "max");
319+
i.endEntity();
320+
i.endRecord();
321+
322+
i.startRecord("3");
323+
i.endRecord();
324+
},
325+
o -> {
326+
o.get().startRecord("1");
327+
o.get().startEntity("my");
328+
o.get().literal("name", "patrick");
329+
o.get().literal("name", "nicolas");
330+
o.get().endEntity();
331+
o.get().endRecord();
332+
333+
o.get().startRecord("2");
334+
o.get().startEntity("my");
335+
o.get().literal("name", "max");
336+
o.get().literal("name", "patrick");
337+
o.get().literal("name", "nicolas");
338+
o.get().endEntity();
339+
o.get().endRecord();
340+
341+
o.get().startRecord("3");
342+
o.get().startEntity("my");
343+
o.get().literal("name", "patrick");
344+
o.get().literal("name", "nicolas");
345+
o.get().endEntity();
346+
o.get().endRecord();
347+
}
348+
);
349+
}
350+
351+
@Test
352+
public void addWithPrependInImplicitArray() {
353+
MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(
354+
"add_field('my.name.$prepend','patrick')",
355+
"add_field('my.name.$prepend','nicolas')"
356+
),
357+
i -> {
358+
i.startRecord("1");
359+
i.endRecord();
360+
361+
i.startRecord("2");
362+
i.startEntity("my");
363+
i.literal("name", "max");
364+
i.endEntity();
365+
i.endRecord();
366+
367+
i.startRecord("3");
368+
i.endRecord();
369+
},
370+
o -> {
371+
o.get().startRecord("1");
372+
o.get().startEntity("my");
373+
o.get().literal("name", "nicolas");
374+
o.get().literal("name", "patrick");
375+
o.get().endEntity();
376+
o.get().endRecord();
377+
378+
o.get().startRecord("2");
379+
o.get().startEntity("my");
380+
o.get().literal("name", "nicolas");
381+
o.get().literal("name", "patrick");
382+
o.get().literal("name", "max");
383+
o.get().endEntity();
384+
o.get().endRecord();
385+
386+
o.get().startRecord("3");
387+
o.get().startEntity("my");
388+
o.get().literal("name", "nicolas");
389+
o.get().literal("name", "patrick");
390+
o.get().endEntity();
391+
o.get().endRecord();
392+
}
393+
);
394+
}
395+
396+
@Test
397+
public void addWithLastInNonArray() {
398+
MetafixTestHelpers.assertExecutionException(IllegalStateException.class, "Expected Array or Hash, got String", () ->
399+
MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(
400+
"add_field('my.name.$last','patrick')"
401+
),
402+
i -> {
403+
i.startRecord("1");
404+
i.startEntity("my");
405+
i.literal("name", "max");
406+
i.endEntity();
407+
i.endRecord();
408+
},
409+
o -> {
410+
}
411+
)
412+
);
413+
}
414+
306415
@Test
307416
public void addWithAppendInArray() {
308417
MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(
@@ -1417,11 +1526,9 @@ public void renameArrayOfHashes() {
14171526
}
14181527

14191528
@Test
1420-
@MetafixToDo("Do we actually need/want implicit $append? WDCD?")
1421-
public void copyIntoArrayOfHashesImplicitAppend() {
1529+
public void copyIntoImplicitArrayAppend() {
14221530
MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(
1423-
"set_array('author[]')",
1424-
"copy_field('your.name','author[].name')",
1531+
"copy_field('your.name','author[].$append.name')",
14251532
"remove_field('your')"),
14261533
i -> {
14271534
i.startRecord("1");
@@ -1446,7 +1553,34 @@ public void copyIntoArrayOfHashesImplicitAppend() {
14461553
}
14471554

14481555
@Test
1449-
public void copyIntoArrayOfHashesExplicitAppend() {
1556+
public void copyIntoImplicitArrayPrepend() {
1557+
MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(
1558+
"copy_field('your.name','author[].$prepend.name')",
1559+
"remove_field('your')"),
1560+
i -> {
1561+
i.startRecord("1");
1562+
i.startEntity("your");
1563+
i.literal("name", "max");
1564+
i.endEntity();
1565+
i.startEntity("your");
1566+
i.literal("name", "mo");
1567+
i.endEntity();
1568+
i.endRecord();
1569+
}, (o, f) -> {
1570+
o.get().startRecord("1");
1571+
o.get().startEntity("author[]");
1572+
o.get().startEntity("1");
1573+
o.get().literal("name", "mo");
1574+
o.get().endEntity();
1575+
o.get().startEntity("2");
1576+
o.get().literal("name", "max");
1577+
f.apply(2).endEntity();
1578+
o.get().endRecord();
1579+
});
1580+
}
1581+
1582+
@Test
1583+
public void copyIntoExplicitArrayAppend() {
14501584
MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(
14511585
"set_array('author[]')",
14521586
"copy_field('your.name','author[].$append.name')",

metafix/src/test/resources/org/metafacture/metafix/integration/record/fromJson/toJson/add_fieldAppendAndCreateArrayOfObjects/todo.txt

Lines changed: 0 additions & 1 deletion
This file was deleted.

metafix/src/test/resources/org/metafacture/metafix/integration/record/fromJson/toJson/add_fieldAppendAndCreateArrayOfObjectsInArrayOfObjects/todo.txt

Lines changed: 0 additions & 1 deletion
This file was deleted.

metafix/src/test/resources/org/metafacture/metafix/integration/record/fromJson/toJson/add_fieldAppendAndCreateArrayOfStrings/todo.txt

Lines changed: 0 additions & 1 deletion
This file was deleted.

metafix/src/test/resources/org/metafacture/metafix/integration/record/fromJson/toJson/add_fieldAppendAndCreateArrayOfStringsInArrayOfObjects/todo.txt

Lines changed: 0 additions & 1 deletion
This file was deleted.

metafix/src/test/resources/org/metafacture/metafix/integration/record/fromJson/toJson/add_fieldAppendAndCreateNestedArrayOfObjects/expected.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"test" : "test",
33
"object" : {
4-
"arrayOfObjects" : [ {
4+
"arrayOfObject" : [ {
55
"key" : "value"
66
}, {
77
"key" : "more_value"

metafix/src/test/resources/org/metafacture/metafix/integration/record/fromJson/toJson/add_fieldAppendAndCreateNestedArrayOfObjects/todo.txt

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)