Skip to content
This repository has been archived by the owner on Jan 27, 2025. It is now read-only.

Commit

Permalink
Merge pull request #214 from metafacture/135-144-array
Browse files Browse the repository at this point in the history
 Handle $first, $last for find and replace in arrays (#135, #144)
  • Loading branch information
fsteeg authored Apr 28, 2022
2 parents b7c4462 + 1d5f713 commit 1933b59
Show file tree
Hide file tree
Showing 12 changed files with 127 additions and 60 deletions.
105 changes: 59 additions & 46 deletions metafix/src/main/java/org/metafacture/metafix/FixPath.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,10 @@ private FixPath(final String[] path) {
/*package-private*/ Value findIn(final Array array) {

final Value result;
if (path.length > 0) {
if (path.length == 0) {
result = new Value(array);
}
else {
final String currentSegment = path[0];
if (currentSegment.equals(ASTERISK)) {
result = Value.newArray(resultArray -> array.forEach(v -> {
Expand All @@ -79,10 +82,10 @@ private FixPath(final String[] path) {
}
}));
}
else if (Value.isNumber(currentSegment)) {
final int index = Integer.parseInt(currentSegment) - 1; // TODO: 0-based Catmandu vs. 1-based Metafacture
if (index >= 0 && index < array.size()) {
result = findInValue(array.get(index), tail(path));
else if (isReference(currentSegment)) {
final Value referencedValue = getReferencedValue(array, currentSegment);
if (referencedValue != null) {
result = findInValue(referencedValue, tail(path));
}
else {
result = null;
Expand All @@ -93,9 +96,6 @@ else if (Value.isNumber(currentSegment)) {
result = Value.newArray(a -> array.forEach(v -> a.add(findInValue(v, path))));
}
}
else {
result = new Value(array);
}
return result;

}
Expand Down Expand Up @@ -165,7 +165,25 @@ void apply(final Hash hash, final String field, final Value value) {
@Override
void apply(final Array array, final String field, final Value value) {
try {
array.set(Integer.valueOf(field) - 1, value);
final ReservedField reservedField = ReservedField.fromString(field);
if (reservedField != null) {
switch (reservedField) {
case $append:
array.add(value);
break;
case $first:
array.set(0, value);
break;
case $last:
array.set(array.size() - 1, value);
break;
default:
break;
}
}
else {
array.set(Integer.valueOf(field) - 1, value);
}
}
catch (final NumberFormatException e) {
throw new IllegalStateException("Expected Hash, got Array", e);
Expand Down Expand Up @@ -231,28 +249,25 @@ private void removeNestedFrom(final Value value) {
/*package-private*/ private Value insertInto(final Array array, final InsertMode mode, final Value newValue) {
// basic idea: reuse findIn logic here? setIn(findIn(array), newValue)
final String field = path[0];
if (path.length == 1) {
if (field.equals(ASTERISK)) {
if (field.equals(ASTERISK)) {
if (path.length == 1) {
for (int i = 0; i < array.size(); ++i) {
mode.apply(array, "" + (i + 1), newValue);
mode.apply(array, String.valueOf(i + 1), newValue);
}
}
else {
// TODO unify ref usage from below
if ("$append".equals(field)) {
array.add(newValue);
}
else {
mode.apply(array, field, newValue);
}
array.add(Value.newHash(h -> new FixPath(tail(path)).insertInto(h, mode, newValue)));
}
}
else {
final String[] tail = tail(path);
if (isReference(field)) {
return processRef(getReferencedValue(array, field), mode, newValue, field, tail);
if (path.length == 1) {
mode.apply(array, field, newValue);
}
else {
if (isReference(field)) {
return processRef(getReferencedValue(array, field), mode, newValue, field, tail(path));
}
}
array.add(Value.newHash(h -> new FixPath(path).insertInto(h, mode, newValue)));
}
return new Value(array);
}
Expand All @@ -261,12 +276,7 @@ private void removeNestedFrom(final Value value) {
// basic idea: reuse findIn logic here? setIn(findIn(hash), newValue)
final String field = path[0];
if (path.length == 1) {
if (field.equals(ASTERISK)) {
hash.forEach((k, v) -> mode.apply(hash, k, newValue)); //TODO: WDCD? insert into each element?
}
else {
mode.apply(hash, field, newValue);
}
mode.apply(hash, field, newValue);
}
else {
final String[] tail = tail(path);
Expand Down Expand Up @@ -330,24 +340,27 @@ private boolean isReference(final String field) {
// TODO replace switch, extract to method on array?
private Value getReferencedValue(final Array array, final String field) {
Value referencedValue = null;
final ReservedField reservedField = ReservedField.fromString(field);
if (reservedField == null && Value.isNumber(field)) {
return array.get(Integer.valueOf(field) - 1);
if (Value.isNumber(field)) {
final int index = Integer.valueOf(field) - 1;
return 0 <= index && index < array.size() ? array.get(index) : null;
}
switch (reservedField) {
case $first:
referencedValue = array.get(0);
break;
case $last:
referencedValue = array.get(array.size() - 1);
break;
case $append:
referencedValue = Value.newHash(); // TODO: append non-hash?
array.add(referencedValue);
referencedValue.updatePathAppend(String.valueOf(array.size()), "");
break;
default:
break;
final ReservedField reservedField = ReservedField.fromString(field);
if (reservedField != null) {
switch (reservedField) {
case $first:
referencedValue = array.get(0);
break;
case $last:
referencedValue = array.get(array.size() - 1);
break;
case $append:
referencedValue = Value.newHash(); // TODO: append non-hash?
array.add(referencedValue);
referencedValue.updatePathAppend(String.valueOf(array.size()), "");
break;
default:
break;
}
}
return referencedValue;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,9 @@
import nl.jqno.equalsverifier.EqualsVerifier;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

import java.util.Arrays;

@ExtendWith(MetafixToDo.Extension.class)
public class HashValueTest {

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

@Test
@MetafixToDo("Expected String, got Array")
public void shouldFindArrayWildcard() {
shouldFindArray("$last");
}
Expand All @@ -412,7 +409,6 @@ public void shouldFindArrayIndexSubfield() {
}

@Test
@MetafixToDo("Expected String, got Array")
public void shouldFindArrayWildcardSubfield() {
shouldFindArraySubfield("$last");
}
Expand Down
65 changes: 65 additions & 0 deletions metafix/src/test/java/org/metafacture/metafix/MetafixIfTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -1069,4 +1069,69 @@ public void shouldIncludeLocationAndTextInProcessExceptionInBody() {
);
}

@Test
public void ifOnNonExistingIndexInArray() {
MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(
"if exists('animals[].2')",
" copy_field('animals[].2', 'animals2')",
"end"
),
i -> {
i.startRecord("1");
i.startEntity("animals[]");
i.literal("1", "dog");
i.literal("2", "elefant");
i.endEntity();
i.endRecord();
i.startRecord("2");
i.startEntity("animals[]");
i.literal("1", "dog");
i.endEntity();
i.endRecord();
},
o -> {
o.get().startRecord("1");
o.get().startEntity("animals[]");
o.get().literal("1", "dog");
o.get().literal("2", "elefant");
o.get().endEntity();
o.get().literal("animals2", "elefant");
o.get().endRecord();
o.get().startRecord("2");
o.get().startEntity("animals[]");
o.get().literal("1", "dog");
o.get().endEntity();
o.get().endRecord();
}
);
}

@Test
public void ifOnNonExistingIndexInRepeatedField() {
MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(
"if exists('animal.2')",
" copy_field('animal.2', 'animal2')",
"end"
),
i -> {
i.startRecord("1");
i.literal("animal", "dog");
i.literal("animal", "elefant");
i.endRecord();
i.startRecord("2");
i.literal("animal", "dog");
i.endRecord();
},
o -> {
o.get().startRecord("1");
o.get().literal("animal", "dog");
o.get().literal("animal", "elefant");
o.get().literal("animal2", "elefant");
o.get().endRecord();
o.get().startRecord("2");
o.get().literal("animal", "dog");
o.get().endRecord();
}
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2051,7 +2051,6 @@ public void shouldReplaceAllRegexesInArrayByIndex() {
}

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

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

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1 +1 @@
append("animals[].$first.type", " is cool")
append("animals[].$last.type", " is cool")

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1 +1 @@
append("animals[].$last.type", "Big ")
prepend("animals[].$last.type", "Big ")

This file was deleted.

This file was deleted.

0 comments on commit 1933b59

Please sign in to comment.