Skip to content

Commit 1933b59

Browse files
authored
Merge pull request #214 from metafacture/135-144-array
Handle $first, $last for find and replace in arrays (#135, #144)
2 parents b7c4462 + 1d5f713 commit 1933b59

File tree

12 files changed

+127
-60
lines changed

12 files changed

+127
-60
lines changed

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

Lines changed: 59 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,10 @@ private FixPath(final String[] path) {
6666
/*package-private*/ Value findIn(final Array array) {
6767

6868
final Value result;
69-
if (path.length > 0) {
69+
if (path.length == 0) {
70+
result = new Value(array);
71+
}
72+
else {
7073
final String currentSegment = path[0];
7174
if (currentSegment.equals(ASTERISK)) {
7275
result = Value.newArray(resultArray -> array.forEach(v -> {
@@ -79,10 +82,10 @@ private FixPath(final String[] path) {
7982
}
8083
}));
8184
}
82-
else if (Value.isNumber(currentSegment)) {
83-
final int index = Integer.parseInt(currentSegment) - 1; // TODO: 0-based Catmandu vs. 1-based Metafacture
84-
if (index >= 0 && index < array.size()) {
85-
result = findInValue(array.get(index), tail(path));
85+
else if (isReference(currentSegment)) {
86+
final Value referencedValue = getReferencedValue(array, currentSegment);
87+
if (referencedValue != null) {
88+
result = findInValue(referencedValue, tail(path));
8689
}
8790
else {
8891
result = null;
@@ -93,9 +96,6 @@ else if (Value.isNumber(currentSegment)) {
9396
result = Value.newArray(a -> array.forEach(v -> a.add(findInValue(v, path))));
9497
}
9598
}
96-
else {
97-
result = new Value(array);
98-
}
9999
return result;
100100

101101
}
@@ -165,7 +165,25 @@ void apply(final Hash hash, final String field, final Value value) {
165165
@Override
166166
void apply(final Array array, final String field, final Value value) {
167167
try {
168-
array.set(Integer.valueOf(field) - 1, value);
168+
final ReservedField reservedField = ReservedField.fromString(field);
169+
if (reservedField != null) {
170+
switch (reservedField) {
171+
case $append:
172+
array.add(value);
173+
break;
174+
case $first:
175+
array.set(0, value);
176+
break;
177+
case $last:
178+
array.set(array.size() - 1, value);
179+
break;
180+
default:
181+
break;
182+
}
183+
}
184+
else {
185+
array.set(Integer.valueOf(field) - 1, value);
186+
}
169187
}
170188
catch (final NumberFormatException e) {
171189
throw new IllegalStateException("Expected Hash, got Array", e);
@@ -231,28 +249,25 @@ private void removeNestedFrom(final Value value) {
231249
/*package-private*/ private Value insertInto(final Array array, final InsertMode mode, final Value newValue) {
232250
// basic idea: reuse findIn logic here? setIn(findIn(array), newValue)
233251
final String field = path[0];
234-
if (path.length == 1) {
235-
if (field.equals(ASTERISK)) {
252+
if (field.equals(ASTERISK)) {
253+
if (path.length == 1) {
236254
for (int i = 0; i < array.size(); ++i) {
237-
mode.apply(array, "" + (i + 1), newValue);
255+
mode.apply(array, String.valueOf(i + 1), newValue);
238256
}
239257
}
240258
else {
241-
// TODO unify ref usage from below
242-
if ("$append".equals(field)) {
243-
array.add(newValue);
244-
}
245-
else {
246-
mode.apply(array, field, newValue);
247-
}
259+
array.add(Value.newHash(h -> new FixPath(tail(path)).insertInto(h, mode, newValue)));
248260
}
249261
}
250262
else {
251-
final String[] tail = tail(path);
252-
if (isReference(field)) {
253-
return processRef(getReferencedValue(array, field), mode, newValue, field, tail);
263+
if (path.length == 1) {
264+
mode.apply(array, field, newValue);
265+
}
266+
else {
267+
if (isReference(field)) {
268+
return processRef(getReferencedValue(array, field), mode, newValue, field, tail(path));
269+
}
254270
}
255-
array.add(Value.newHash(h -> new FixPath(path).insertInto(h, mode, newValue)));
256271
}
257272
return new Value(array);
258273
}
@@ -261,12 +276,7 @@ private void removeNestedFrom(final Value value) {
261276
// basic idea: reuse findIn logic here? setIn(findIn(hash), newValue)
262277
final String field = path[0];
263278
if (path.length == 1) {
264-
if (field.equals(ASTERISK)) {
265-
hash.forEach((k, v) -> mode.apply(hash, k, newValue)); //TODO: WDCD? insert into each element?
266-
}
267-
else {
268-
mode.apply(hash, field, newValue);
269-
}
279+
mode.apply(hash, field, newValue);
270280
}
271281
else {
272282
final String[] tail = tail(path);
@@ -330,24 +340,27 @@ private boolean isReference(final String field) {
330340
// TODO replace switch, extract to method on array?
331341
private Value getReferencedValue(final Array array, final String field) {
332342
Value referencedValue = null;
333-
final ReservedField reservedField = ReservedField.fromString(field);
334-
if (reservedField == null && Value.isNumber(field)) {
335-
return array.get(Integer.valueOf(field) - 1);
343+
if (Value.isNumber(field)) {
344+
final int index = Integer.valueOf(field) - 1;
345+
return 0 <= index && index < array.size() ? array.get(index) : null;
336346
}
337-
switch (reservedField) {
338-
case $first:
339-
referencedValue = array.get(0);
340-
break;
341-
case $last:
342-
referencedValue = array.get(array.size() - 1);
343-
break;
344-
case $append:
345-
referencedValue = Value.newHash(); // TODO: append non-hash?
346-
array.add(referencedValue);
347-
referencedValue.updatePathAppend(String.valueOf(array.size()), "");
348-
break;
349-
default:
350-
break;
347+
final ReservedField reservedField = ReservedField.fromString(field);
348+
if (reservedField != null) {
349+
switch (reservedField) {
350+
case $first:
351+
referencedValue = array.get(0);
352+
break;
353+
case $last:
354+
referencedValue = array.get(array.size() - 1);
355+
break;
356+
case $append:
357+
referencedValue = Value.newHash(); // TODO: append non-hash?
358+
array.add(referencedValue);
359+
referencedValue.updatePathAppend(String.valueOf(array.size()), "");
360+
break;
361+
default:
362+
break;
363+
}
351364
}
352365
return referencedValue;
353366
}

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

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,9 @@
1919
import nl.jqno.equalsverifier.EqualsVerifier;
2020
import org.junit.jupiter.api.Assertions;
2121
import org.junit.jupiter.api.Test;
22-
import org.junit.jupiter.api.extension.ExtendWith;
2322

2423
import java.util.Arrays;
2524

26-
@ExtendWith(MetafixToDo.Extension.class)
2725
public class HashValueTest {
2826

2927
private static final String FIELD = "field";
@@ -394,7 +392,6 @@ public void shouldFindArrayIndex() {
394392
}
395393

396394
@Test
397-
@MetafixToDo("Expected String, got Array")
398395
public void shouldFindArrayWildcard() {
399396
shouldFindArray("$last");
400397
}
@@ -412,7 +409,6 @@ public void shouldFindArrayIndexSubfield() {
412409
}
413410

414411
@Test
415-
@MetafixToDo("Expected String, got Array")
416412
public void shouldFindArrayWildcardSubfield() {
417413
shouldFindArraySubfield("$last");
418414
}

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

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1069,4 +1069,69 @@ public void shouldIncludeLocationAndTextInProcessExceptionInBody() {
10691069
);
10701070
}
10711071

1072+
@Test
1073+
public void ifOnNonExistingIndexInArray() {
1074+
MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(
1075+
"if exists('animals[].2')",
1076+
" copy_field('animals[].2', 'animals2')",
1077+
"end"
1078+
),
1079+
i -> {
1080+
i.startRecord("1");
1081+
i.startEntity("animals[]");
1082+
i.literal("1", "dog");
1083+
i.literal("2", "elefant");
1084+
i.endEntity();
1085+
i.endRecord();
1086+
i.startRecord("2");
1087+
i.startEntity("animals[]");
1088+
i.literal("1", "dog");
1089+
i.endEntity();
1090+
i.endRecord();
1091+
},
1092+
o -> {
1093+
o.get().startRecord("1");
1094+
o.get().startEntity("animals[]");
1095+
o.get().literal("1", "dog");
1096+
o.get().literal("2", "elefant");
1097+
o.get().endEntity();
1098+
o.get().literal("animals2", "elefant");
1099+
o.get().endRecord();
1100+
o.get().startRecord("2");
1101+
o.get().startEntity("animals[]");
1102+
o.get().literal("1", "dog");
1103+
o.get().endEntity();
1104+
o.get().endRecord();
1105+
}
1106+
);
1107+
}
1108+
1109+
@Test
1110+
public void ifOnNonExistingIndexInRepeatedField() {
1111+
MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(
1112+
"if exists('animal.2')",
1113+
" copy_field('animal.2', 'animal2')",
1114+
"end"
1115+
),
1116+
i -> {
1117+
i.startRecord("1");
1118+
i.literal("animal", "dog");
1119+
i.literal("animal", "elefant");
1120+
i.endRecord();
1121+
i.startRecord("2");
1122+
i.literal("animal", "dog");
1123+
i.endRecord();
1124+
},
1125+
o -> {
1126+
o.get().startRecord("1");
1127+
o.get().literal("animal", "dog");
1128+
o.get().literal("animal", "elefant");
1129+
o.get().literal("animal2", "elefant");
1130+
o.get().endRecord();
1131+
o.get().startRecord("2");
1132+
o.get().literal("animal", "dog");
1133+
o.get().endRecord();
1134+
}
1135+
);
1136+
}
10721137
}

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2051,7 +2051,6 @@ public void shouldReplaceAllRegexesInArrayByIndex() {
20512051
}
20522052

20532053
@Test
2054-
@MetafixToDo("See https://github.com/metafacture/metafacture-fix/issues/135")
20552054
public void shouldReplaceAllRegexesInArrayByArrayWildcard() {
20562055
MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(
20572056
"replace_all('names.$last', 'a', 'X')"
@@ -2103,7 +2102,6 @@ public void shouldReplaceAllRegexesInArraySubFieldByIndex() {
21032102
}
21042103

21052104
@Test
2106-
@MetafixToDo("See https://github.com/metafacture/metafacture-fix/issues/135")
21072105
public void shouldReplaceAllRegexesInArraySubFieldByArrayWildcard() {
21082106
MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(
21092107
"replace_all('names[].$last.name', 'a', 'X')"
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
append("animals[].$last.type", " is cool")
1+
append("animals[].$first.type", " is cool")

metafix/src/test/resources/org/metafacture/metafix/integration/method/fromJson/toJson/appendArrayOfObjectsWithFirstArrayWildcard/todo.txt

Lines changed: 0 additions & 1 deletion
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
append("animals[].$first.type", " is cool")
1+
append("animals[].$last.type", " is cool")

metafix/src/test/resources/org/metafacture/metafix/integration/method/fromJson/toJson/appendArrayOfObjectsWithLastArrayWildcard/todo.txt

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

metafix/src/test/resources/org/metafacture/metafix/integration/method/fromJson/toJson/prependArrayOfObjectsWithFirstArrayWildcard/todo.txt

Lines changed: 0 additions & 1 deletion
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
append("animals[].$last.type", "Big ")
1+
prepend("animals[].$last.type", "Big ")

0 commit comments

Comments
 (0)