Skip to content

Commit 57dd969

Browse files
authored
Merge pull request #218 from metafacture/dollar-in-var-path
Fix issue with dollars in var paths when handled as regex
2 parents 39c1bca + 03bb744 commit 57dd969

File tree

3 files changed

+176
-2
lines changed

3 files changed

+176
-2
lines changed

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
import java.util.Arrays;
2323
import java.util.HashMap;
2424
import java.util.Map;
25+
import java.util.regex.Pattern;
26+
import java.util.stream.Collectors;
2527

2628
/**
2729
* Our goal here is something like https://metacpan.org/pod/Catmandu::Path::simple
@@ -33,6 +35,8 @@
3335
*/
3436
/*package-private*/ class FixPath {
3537

38+
/*package-private*/ static final Pattern RESERVED_FIELD_PATTERN = Pattern.compile(String.format("(?:%s)",
39+
Arrays.stream(ReservedField.values()).map(f -> Pattern.quote(f.name())).collect(Collectors.joining("|"))));
3640
private static final String ASTERISK = "*";
3741
private String[] path;
3842

@@ -248,13 +252,14 @@ private void removeNestedFrom(final Value value) {
248252

249253
/*package-private*/ private Value insertInto(final Array array, final InsertMode mode, final Value newValue) {
250254
// basic idea: reuse findIn logic here? setIn(findIn(array), newValue)
255+
251256
final String field = path[0];
252257
if (path.length == 1) {
253258
mode.apply(array, field, newValue);
254259
}
255260
else {
256261
if (ASTERISK.equals(field)) {
257-
array.forEach(value -> insertInto(value, mode, newValue, field, tail(path)));
262+
array.forEach(value -> insertInto(value, mode, newValue.copy(), field, tail(path)));
258263
}
259264
else if (isReference(field)) {
260265
insertInto(getReferencedValue(array, field), mode, newValue, field, tail(path));

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ public Value asList(final Consumer<Array> consumer) {
208208

209209
/*package-private*/ Value updatePathRename(final String newName) {
210210
if (path != null) {
211-
path = newName.replaceAll("\\$[^.]+", split(path)[0]);
211+
path = FixPath.RESERVED_FIELD_PATTERN.matcher(newName).replaceAll(Matcher.quoteReplacement(split(path)[0]));
212212
}
213213
return this;
214214
}
@@ -289,6 +289,14 @@ public String getPath() {
289289
this.path = path;
290290
}
291291

292+
/*package-private*/ Value copy() {
293+
return extractType((m, c) -> m
294+
.ifArray(oldArray -> c.accept(Value.newArray(newArray -> oldArray.forEach(v -> newArray.add(v)))))
295+
.ifHash(oldHash -> c.accept(Value.newHash(newHash -> oldHash.forEach((k, v) -> newHash.put(k, v)))))
296+
.ifString(s -> c.accept(new Value(s)))
297+
.orElseThrow());
298+
}
299+
292300
enum Type {
293301
Array,
294302
Hash,

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

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2060,6 +2060,167 @@ public void shouldReplaceAllRegexesInListCopiedArraySubField() {
20602060
);
20612061
}
20622062

2063+
@Test
2064+
public void shouldCopyBindVarWithDollarAfterLookup() {
2065+
MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(
2066+
"set_array('@coll[]')",
2067+
"do list(path: 'a', 'var': '$i')",
2068+
" lookup('$i.name')",
2069+
" copy_field('$i.name', '@coll[].$append')",
2070+
"end",
2071+
"remove_field('a')"
2072+
),
2073+
i -> {
2074+
i.startRecord("1");
2075+
i.startEntity("a");
2076+
i.literal("name", "Dog");
2077+
i.endEntity();
2078+
i.endRecord();
2079+
},
2080+
(o, f) -> {
2081+
o.get().startRecord("1");
2082+
o.get().startEntity("@coll[]");
2083+
o.get().literal("1", "Dog");
2084+
f.apply(1).endEntity();
2085+
o.get().endRecord();
2086+
}
2087+
);
2088+
}
2089+
2090+
@Test
2091+
public void shouldCopyToFieldWithIndexAndReservedFieldName() {
2092+
MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(
2093+
"set_array('a[].*.test[]', 'test')",
2094+
"copy_field('some', 'a[].1.test[].$append')",
2095+
"remove_field('some')"
2096+
),
2097+
i -> {
2098+
i.startRecord("1");
2099+
i.literal("some", "thing");
2100+
i.startEntity("a[]");
2101+
i.startEntity("1");
2102+
i.literal("name", "Dog");
2103+
i.endEntity();
2104+
i.startEntity("2");
2105+
i.literal("name", "Cat");
2106+
i.endEntity();
2107+
i.endEntity();
2108+
i.endRecord();
2109+
},
2110+
(o, f) -> {
2111+
o.get().startRecord("1");
2112+
o.get().startEntity("a[]");
2113+
o.get().startEntity("1");
2114+
o.get().literal("name", "Dog");
2115+
o.get().startEntity("test[]");
2116+
o.get().literal("1", "test");
2117+
o.get().literal("2", "thing");
2118+
f.apply(2).endEntity();
2119+
o.get().startEntity("2");
2120+
o.get().literal("name", "Cat");
2121+
o.get().startEntity("test[]");
2122+
o.get().literal("1", "test");
2123+
f.apply(3).endEntity();
2124+
o.get().endRecord();
2125+
}
2126+
);
2127+
}
2128+
2129+
@Test
2130+
public void shouldCopyToFieldWithTwoReservedFieldNames() {
2131+
MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(
2132+
"set_array('a[].*.test[]', 'test')",
2133+
"copy_field('some', 'a[].$first.test[].$append')",
2134+
"remove_field('some')"
2135+
),
2136+
i -> {
2137+
i.startRecord("1");
2138+
i.literal("some", "thing");
2139+
i.startEntity("a[]");
2140+
i.startEntity("1");
2141+
i.literal("name", "Dog");
2142+
i.endEntity();
2143+
i.startEntity("2");
2144+
i.literal("name", "Cat");
2145+
i.endEntity();
2146+
i.endEntity();
2147+
i.endRecord();
2148+
},
2149+
(o, f) -> {
2150+
o.get().startRecord("1");
2151+
o.get().startEntity("a[]");
2152+
o.get().startEntity("1");
2153+
o.get().literal("name", "Dog");
2154+
o.get().startEntity("test[]");
2155+
o.get().literal("1", "test");
2156+
o.get().literal("2", "thing");
2157+
f.apply(2).endEntity();
2158+
o.get().startEntity("2");
2159+
o.get().literal("name", "Cat");
2160+
o.get().startEntity("test[]");
2161+
o.get().literal("1", "test");
2162+
f.apply(3).endEntity();
2163+
o.get().endRecord();
2164+
}
2165+
);
2166+
}
2167+
2168+
@Test
2169+
@MetafixToDo("Existing value has no path ('[[a]]'), resulting in wrong path for new value")
2170+
public void shouldMoveFieldToPathWithIndexAndReservedField() {
2171+
MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(
2172+
"move_field('b', 'names[].1.$append')"
2173+
),
2174+
i -> {
2175+
i.startRecord("1");
2176+
i.literal("b", "b");
2177+
i.startEntity("names[]");
2178+
i.startEntity("1[]");
2179+
i.literal("1", "a");
2180+
i.endEntity();
2181+
i.endEntity();
2182+
i.endRecord();
2183+
},
2184+
(o, f) -> {
2185+
o.get().startRecord("1");
2186+
o.get().startEntity("names[]");
2187+
o.get().startEntity("1[]");
2188+
o.get().literal("1", "a");
2189+
o.get().literal("2", "b");
2190+
f.apply(2).endEntity();
2191+
o.get().endRecord();
2192+
}
2193+
);
2194+
}
2195+
2196+
@Test
2197+
@MetafixToDo("Existing value has no path ('[[a]]'), resulting in wrong path for new value")
2198+
public void shouldMoveFieldToPathWithTwoReservedFields() {
2199+
MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(
2200+
"move_field('b', 'names[].$first.$append')"
2201+
),
2202+
i -> {
2203+
i.startRecord("1");
2204+
i.literal("b", "b");
2205+
i.startEntity("names[]");
2206+
i.startEntity("1[]");
2207+
i.literal("1", "a");
2208+
i.endEntity();
2209+
i.endEntity();
2210+
i.endRecord();
2211+
},
2212+
(o, f) -> {
2213+
o.get().startRecord("1");
2214+
o.get().startEntity("names[]");
2215+
o.get().startEntity("1[]");
2216+
o.get().literal("1", "a");
2217+
o.get().literal("2", "b");
2218+
f.apply(2).endEntity();
2219+
o.get().endRecord();
2220+
}
2221+
);
2222+
}
2223+
20632224
@Test
20642225
// See https://github.com/metafacture/metafacture-fix/issues/121
20652226
public void shouldReplaceAllRegexesInNestedArray() {

0 commit comments

Comments
 (0)