From 51446ee420c3dc6aa913f9453e2c3806b2e3faed Mon Sep 17 00:00:00 2001 From: Jens Wille Date: Tue, 11 Jan 2022 21:50:34 +0100 Subject: [PATCH 01/21] Refactor `Value` type extraction. (#103) --- .../org/metafacture/metafix/FixMethod.java | 72 ++++++++++--------- .../java/org/metafacture/metafix/Value.java | 2 +- 2 files changed, 41 insertions(+), 33 deletions(-) diff --git a/metafix/src/main/java/org/metafacture/metafix/FixMethod.java b/metafix/src/main/java/org/metafacture/metafix/FixMethod.java index 2d3504c1..33fa6ab0 100644 --- a/metafix/src/main/java/org/metafacture/metafix/FixMethod.java +++ b/metafix/src/main/java/org/metafacture/metafix/FixMethod.java @@ -199,8 +199,9 @@ public void apply(final Metafix metafix, final Record record, final List final String replace = params.get(2); // TODO: recurse into arrays/values - return v.isHash() ? Value.newHash(h -> - v.asHash().forEach((f, w) -> h.put(f.replaceAll(search, replace), w))) : null; + return v.extractType((m, c) -> m + .ifHash(h -> c.accept(Value.newHash(n -> h.forEach((f, w) -> n.put(f.replaceAll(search, replace), w))))) + ); }); } }, @@ -267,8 +268,10 @@ public void apply(final Metafix metafix, final Record record, final List }, count { public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - record.transformField(params.get(0), v -> - v.isArray() ? new Value(v.asArray().size()) : v.isHash() ? new Value(v.asHash().size()) : null); + record.transformField(params.get(0), v -> v.extractType((m, c) -> m + .ifArray(a -> c.accept(new Value(a.size()))) + .ifHash(h -> c.accept(new Value(h.size()))) + )); } }, downcase { @@ -283,7 +286,9 @@ public void apply(final Metafix metafix, final Record record, final List final boolean invert = getBoolean(options, "invert"); final Predicate predicate = s -> search.matcher(s.asString()).find(); - return v.isArray() ? newArray(v.asArray().stream().filter(invert ? predicate.negate() : predicate)) : null; + return v.extractType((m, c) -> m + .ifArray(a -> c.accept(newArray(a.stream().filter(invert ? predicate.negate() : predicate)))) + ); }); } }, @@ -297,7 +302,9 @@ public void apply(final Metafix metafix, final Record record, final List public void apply(final Metafix metafix, final Record record, final List params, final Map options) { record.transformField(params.get(0), v -> { final String joinChar = params.size() > 1 ? params.get(1) : ""; - return v.isArray() ? new Value(v.asArray().stream().map(Value::toString).collect(Collectors.joining(joinChar))) : null; + return v.extractType((m, c) -> m + .ifArray(a -> c.accept(new Value(a.stream().map(Value::toString).collect(Collectors.joining(joinChar))))) + ); }); } }, @@ -338,23 +345,14 @@ public void apply(final Metafix metafix, final Record record, final List }, reverse { public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - record.transformField(params.get(0), v -> { - final Value result; - - if (v.isString()) { - result = new Value(new StringBuilder(v.asString()).reverse().toString()); - } - else if (v.isArray()) { - final List list = v.asArray().stream().collect(Collectors.toList()); - Collections.reverse(list); - result = new Value(list); - } - else { - result = null; - } - - return result; - }); + record.transformField(params.get(0), v -> v.extractType((m, c) -> m + .ifArray(a -> { + final List list = v.asArray().stream().collect(Collectors.toList()); + Collections.reverse(list); + c.accept(new Value(list)); + }) + .ifString(s -> c.accept(new Value(new StringBuilder(v.asString()).reverse().toString()))) + )); } }, sort_field { @@ -364,13 +362,18 @@ public void apply(final Metafix metafix, final Record record, final List final boolean reverse = getBoolean(options, "reverse"); final boolean uniq = getBoolean(options, "uniq"); - final Stream stream = v.asArray().stream(); final Function function = Value::asString; final Comparator comparator = numeric ? Comparator.comparing(function.andThen(Integer::parseInt)) : Comparator.comparing(function); - return v.isArray() ? new Value((uniq ? unique(stream) : stream) - .sorted(reverse ? comparator.reversed() : comparator).collect(Collectors.toList())) : null; + return v.extractType((m, c) -> m + .ifArray(a -> { + final Stream stream = a.stream(); + c.accept(new Value((uniq ? unique(stream) : stream) + .sorted(reverse ? comparator.reversed() : comparator).collect(Collectors.toList())) + ); + }) + ); }); } }, @@ -383,9 +386,11 @@ public void apply(final Metafix metafix, final Record record, final List final UnaryOperator splitOperator = s -> newArray(Arrays.stream(splitPattern.split(s.asString())).map(Value::new)); - return v.isString() ? splitOperator.apply(v) : v.isArray() ? - newArray(v.asArray().stream().map(splitOperator)) : v.isHash() ? - Value.newHash(h -> v.asHash().forEach((f, s) -> h.put(f, splitOperator.apply(s)))) : null; + return v.extractType((m, c) -> m + .ifArray(a -> c.accept(newArray(a.stream().map(splitOperator)))) + .ifHash(h -> c.accept(Value.newHash(n -> h.forEach((f, w) -> n.put(f, splitOperator.apply(w)))))) + .ifString(s -> c.accept(splitOperator.apply(v))) + ); }); } }, @@ -396,8 +401,9 @@ public void apply(final Metafix metafix, final Record record, final List }, sum { public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - record.transformField(params.get(0), v -> - v.isArray() ? new Value(v.asArray().stream().map(Value::asString).mapToInt(Integer::parseInt).sum()) : null); + record.transformField(params.get(0), v -> v.extractType((m, c) -> m + .ifArray(a -> c.accept(new Value(a.stream().map(Value::asString).mapToInt(Integer::parseInt).sum()))) + )); } }, trim { @@ -407,7 +413,9 @@ public void apply(final Metafix metafix, final Record record, final List }, uniq { public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - record.transformField(params.get(0), v -> v.isArray() ? newArray(unique(v.asArray().stream())) : null); + record.transformField(params.get(0), v -> v.extractType((m, c) -> m + .ifArray(a -> c.accept(newArray(unique(a.stream())))) + )); } }, upcase { diff --git a/metafix/src/main/java/org/metafacture/metafix/Value.java b/metafix/src/main/java/org/metafacture/metafix/Value.java index 8edbed6e..58fdb5a9 100644 --- a/metafix/src/main/java/org/metafacture/metafix/Value.java +++ b/metafix/src/main/java/org/metafacture/metafix/Value.java @@ -210,7 +210,7 @@ public TypeMatcher matchType() { return new TypeMatcher(this); } - private T extractType(final BiConsumer> consumer) { + public T extractType(final BiConsumer> consumer) { final AtomicReference result = new AtomicReference<>(); consumer.accept(matchType(), result::set); return result.get(); From 3270490eb59942b15a9bc838c373ee6cad146bbd Mon Sep 17 00:00:00 2001 From: Jens Wille Date: Tue, 11 Jan 2022 22:22:56 +0100 Subject: [PATCH 02/21] Refactor field transformation. (#103) --- .../org/metafacture/metafix/FixMethod.java | 110 ++++++++---------- .../java/org/metafacture/metafix/Value.java | 6 +- 2 files changed, 51 insertions(+), 65 deletions(-) diff --git a/metafix/src/main/java/org/metafacture/metafix/FixMethod.java b/metafix/src/main/java/org/metafacture/metafix/FixMethod.java index 33fa6ab0..0e9fad37 100644 --- a/metafix/src/main/java/org/metafacture/metafix/FixMethod.java +++ b/metafix/src/main/java/org/metafacture/metafix/FixMethod.java @@ -29,7 +29,6 @@ import java.util.Set; import java.util.function.Function; import java.util.function.Predicate; -import java.util.function.UnaryOperator; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -194,15 +193,13 @@ public void apply(final Metafix metafix, final Record record, final List }, rename { public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - record.transformField(params.get(0), v -> { - final String search = params.get(1); - final String replace = params.get(2); + final String search = params.get(1); + final String replace = params.get(2); - // TODO: recurse into arrays/values - return v.extractType((m, c) -> m - .ifHash(h -> c.accept(Value.newHash(n -> h.forEach((f, w) -> n.put(f.replaceAll(search, replace), w))))) - ); - }); + // TODO: recurse into arrays/values + record.transformField(params.get(0), (m, c) -> m + .ifHash(h -> c.accept(Value.newHash(n -> h.forEach((f, w) -> n.put(f.replaceAll(search, replace), w))))) + ); } }, retain { @@ -268,10 +265,10 @@ public void apply(final Metafix metafix, final Record record, final List }, count { public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - record.transformField(params.get(0), v -> v.extractType((m, c) -> m + record.transformField(params.get(0), (m, c) -> m .ifArray(a -> c.accept(new Value(a.size()))) .ifHash(h -> c.accept(new Value(h.size()))) - )); + ); } }, downcase { @@ -281,15 +278,14 @@ public void apply(final Metafix metafix, final Record record, final List }, filter { public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - record.transformField(params.get(0), v -> { - final Pattern search = Pattern.compile(params.get(1)); - final boolean invert = getBoolean(options, "invert"); + final Pattern search = Pattern.compile(params.get(1)); + final boolean invert = getBoolean(options, "invert"); - final Predicate predicate = s -> search.matcher(s.asString()).find(); - return v.extractType((m, c) -> m - .ifArray(a -> c.accept(newArray(a.stream().filter(invert ? predicate.negate() : predicate)))) - ); - }); + final Predicate predicate = s -> search.matcher(s.asString()).find(); + + record.transformField(params.get(0), (m, c) -> m + .ifArray(a -> c.accept(newArray(a.stream().filter(invert ? predicate.negate() : predicate)))) + ); } }, index { @@ -300,12 +296,10 @@ public void apply(final Metafix metafix, final Record record, final List }, join_field { public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - record.transformField(params.get(0), v -> { - final String joinChar = params.size() > 1 ? params.get(1) : ""; - return v.extractType((m, c) -> m - .ifArray(a -> c.accept(new Value(a.stream().map(Value::toString).collect(Collectors.joining(joinChar))))) - ); - }); + final String joinChar = params.size() > 1 ? params.get(1) : ""; + record.transformField(params.get(0), (m, c) -> m + .ifArray(a -> c.accept(new Value(a.stream().map(Value::toString).collect(Collectors.joining(joinChar))))) + ); } }, lookup { @@ -345,53 +339,45 @@ public void apply(final Metafix metafix, final Record record, final List }, reverse { public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - record.transformField(params.get(0), v -> v.extractType((m, c) -> m + record.transformField(params.get(0), (m, c) -> m .ifArray(a -> { - final List list = v.asArray().stream().collect(Collectors.toList()); + final List list = a.stream().collect(Collectors.toList()); Collections.reverse(list); c.accept(new Value(list)); }) - .ifString(s -> c.accept(new Value(new StringBuilder(v.asString()).reverse().toString()))) - )); + .ifString(s -> c.accept(new Value(new StringBuilder(s).reverse().toString()))) + ); } }, sort_field { public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - record.transformField(params.get(0), v -> { - final boolean numeric = getBoolean(options, "numeric"); - final boolean reverse = getBoolean(options, "reverse"); - final boolean uniq = getBoolean(options, "uniq"); - - final Function function = Value::asString; - final Comparator comparator = numeric ? - Comparator.comparing(function.andThen(Integer::parseInt)) : Comparator.comparing(function); - - return v.extractType((m, c) -> m - .ifArray(a -> { - final Stream stream = a.stream(); - c.accept(new Value((uniq ? unique(stream) : stream) - .sorted(reverse ? comparator.reversed() : comparator).collect(Collectors.toList())) - ); - }) - ); - }); + final boolean numeric = getBoolean(options, "numeric"); + final boolean reverse = getBoolean(options, "reverse"); + final boolean uniq = getBoolean(options, "uniq"); + + final Function function = Value::asString; + final Comparator comparator = numeric ? + Comparator.comparing(function.andThen(Integer::parseInt)) : Comparator.comparing(function); + + record.transformField(params.get(0), (m, c) -> m + .ifArray(a -> c.accept(new Value((uniq ? unique(a.stream()) : a.stream()) + .sorted(reverse ? comparator.reversed() : comparator).collect(Collectors.toList())))) + ); } }, split_field { public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - record.transformField(params.get(0), v -> { - final String splitChar = params.size() > 1 ? params.get(1) : "\\s+"; - final Pattern splitPattern = Pattern.compile(splitChar); + final String splitChar = params.size() > 1 ? params.get(1) : "\\s+"; + final Pattern splitPattern = Pattern.compile(splitChar); - final UnaryOperator splitOperator = s -> - newArray(Arrays.stream(splitPattern.split(s.asString())).map(Value::new)); + final Function splitFunction = s -> + newArray(Arrays.stream(splitPattern.split(s)).map(Value::new)); - return v.extractType((m, c) -> m - .ifArray(a -> c.accept(newArray(a.stream().map(splitOperator)))) - .ifHash(h -> c.accept(Value.newHash(n -> h.forEach((f, w) -> n.put(f, splitOperator.apply(w)))))) - .ifString(s -> c.accept(splitOperator.apply(v))) - ); - }); + record.transformField(params.get(0), (m, c) -> m + .ifArray(a -> c.accept(newArray(a.stream().map(Value::asString).map(splitFunction)))) + .ifHash(h -> c.accept(Value.newHash(n -> h.forEach((f, w) -> n.put(f, splitFunction.apply(w.asString())))))) + .ifString(s -> c.accept(splitFunction.apply(s))) + ); } }, substring { @@ -401,9 +387,9 @@ public void apply(final Metafix metafix, final Record record, final List }, sum { public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - record.transformField(params.get(0), v -> v.extractType((m, c) -> m + record.transformField(params.get(0), (m, c) -> m .ifArray(a -> c.accept(new Value(a.stream().map(Value::asString).mapToInt(Integer::parseInt).sum()))) - )); + ); } }, trim { @@ -413,9 +399,9 @@ public void apply(final Metafix metafix, final Record record, final List }, uniq { public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - record.transformField(params.get(0), v -> v.extractType((m, c) -> m + record.transformField(params.get(0), (m, c) -> m .ifArray(a -> c.accept(newArray(unique(a.stream())))) - )); + ); } }, upcase { diff --git a/metafix/src/main/java/org/metafacture/metafix/Value.java b/metafix/src/main/java/org/metafacture/metafix/Value.java index 58fdb5a9..f0eae12d 100644 --- a/metafix/src/main/java/org/metafacture/metafix/Value.java +++ b/metafix/src/main/java/org/metafacture/metafix/Value.java @@ -210,7 +210,7 @@ public TypeMatcher matchType() { return new TypeMatcher(this); } - public T extractType(final BiConsumer> consumer) { + private T extractType(final BiConsumer> consumer) { final AtomicReference result = new AtomicReference<>(); consumer.accept(matchType(), result::set); return result.get(); @@ -839,11 +839,11 @@ private void appendValue(final String[] newName, final Value v) { } } - public void transformField(final String field, final UnaryOperator operator) { + public void transformField(final String field, final BiConsumer> consumer) { final Value oldValue = find(field); if (oldValue != null) { - final Value newValue = operator.apply(oldValue); + final Value newValue = oldValue.extractType(consumer); if (newValue != null) { insert(InsertMode.REPLACE, split(field), newValue); From e77188be3ec5314ffab5d47d7364141c84a8c0b7 Mon Sep 17 00:00:00 2001 From: Jens Wille Date: Tue, 18 Jan 2022 11:08:22 +0100 Subject: [PATCH 03/21] Add `random` unit tests from functional review. (#103) --- .../metafix/MetafixRecordTest.java | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java b/metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java index d1ce65c4..6dc85412 100644 --- a/metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java +++ b/metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java @@ -1767,6 +1767,93 @@ public void shouldAddRandomNumber() { ); } + @Test + @Disabled("See https://github.com/metafacture/metafacture-fix/issues/100") + public void shouldReplaceExistingValueWithRandomNumber() { + MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( + "random(others, '100')" + ), + i -> { + i.startRecord("1"); + i.literal("others", "human"); + i.endRecord(); + }, + o -> { + o.get().startRecord("1"); + o.get().literal(ArgumentMatchers.eq("others"), ArgumentMatchers.argThat(i -> Integer.parseInt(i) < 100)); + o.get().endRecord(); + } + ); + } + + @Test + public void shouldAddRandomNumberToMarkedArray() { + MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( + "random('animals[].$append', '100')" + ), + i -> { + i.startRecord("1"); + i.startEntity("animals[]"); + i.literal("1", "cat"); + i.literal("2", "dog"); + i.endEntity(); + i.endRecord(); + }, + o -> { + o.get().startRecord("1"); + o.get().startEntity("animals[]"); + o.get().literal("1", "cat"); + o.get().literal("2", "dog"); + o.get().literal(ArgumentMatchers.eq("3"), ArgumentMatchers.argThat(i -> Integer.parseInt(i) < 100)); + o.get().endEntity(); + o.get().endRecord(); + } + ); + } + + @Test + public void shouldAddObjectWithRandomNumberToMarkedArray() { + MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( + "random('bnimals[].$append.number', '100')" + ), + i -> { + i.startRecord("1"); + i.endRecord(); + }, + (o, f) -> { + o.get().startRecord("1"); + o.get().startEntity("bnimals[]"); + o.get().startEntity("1"); + o.get().literal(ArgumentMatchers.eq("number"), ArgumentMatchers.argThat(i -> Integer.parseInt(i) < 100)); + f.apply(2).endEntity(); + o.get().endRecord(); + } + ); + } + + @Test + public void shouldAddRandomNumberToUnmarkedArray() { + MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( + "random('animals.$append', '100')" + ), + i -> { + i.startRecord("1"); + i.literal("animals", "cat"); + i.literal("animals", "dog"); + i.endRecord(); + }, + o -> { + o.get().startRecord("1"); + o.get().startEntity("animals"); + o.get().literal("1", "cat"); + o.get().literal("2", "dog"); + o.get().literal(ArgumentMatchers.eq("3"), ArgumentMatchers.argThat(i -> Integer.parseInt(i) < 100)); + o.get().endEntity(); + o.get().endRecord(); + } + ); + } + @Test public void shouldRenameFieldsInHash() { MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( From 2acb29bee08aba90953e1fc197fd663c30829c65 Mon Sep 17 00:00:00 2001 From: Jens Wille Date: Tue, 18 Jan 2022 11:39:16 +0100 Subject: [PATCH 04/21] Add `rename` unit tests from functional review. (#103) --- .../metafix/MetafixRecordTest.java | 107 ++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java b/metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java index 6dc85412..1f092590 100644 --- a/metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java +++ b/metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java @@ -1876,4 +1876,111 @@ public void shouldRenameFieldsInHash() { ); } + @Test + @Disabled("See https://github.com/metafacture/metafacture-fix/issues/100") + public void shouldRecursivelyRenameFieldsInHash() { + MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( + "rename(others, ani, QR)" + ), + i -> { + i.startRecord("1"); + i.startEntity("others"); + i.literal("animal", "human"); + i.literal("canister", "metall"); + i.startEntity("area"); + i.literal("ani", "test"); + i.endEntity(); + i.endEntity(); + i.endRecord(); + }, + (o, f) -> { + o.get().startRecord("1"); + o.get().startEntity("others"); + o.get().literal("QRmal", "human"); + o.get().literal("cQRster", "metall"); + o.get().startEntity("area"); + o.get().literal("QR", "test"); + f.apply(2).endEntity(); + o.get().endRecord(); + } + ); + } + + @Test + @Disabled("See https://github.com/metafacture/metafacture-fix/issues/100") + public void shouldRecursivelyRenameFieldsInArray() { + MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( + "rename('animals[]', ani, XY)" + ), + i -> { + i.startRecord("1"); + i.startEntity("animals[]"); + i.startEntity("1"); + i.literal("animal", "dog"); + i.endEntity(); + i.startEntity("2"); + i.literal("animal", "cat"); + i.endEntity(); + i.endEntity(); + i.endRecord(); + }, + (o, f) -> { + o.get().startRecord("1"); + o.get().startEntity("animals[]"); + o.get().startEntity("1"); + o.get().literal("XYmal", "dog"); + o.get().endEntity(); + o.get().startEntity("2"); + o.get().literal("XYmal", "cat"); + f.apply(2).endEntity(); + o.get().endRecord(); + } + ); + } + + @Test + @Disabled("java.lang.ArrayIndexOutOfBoundsException: 0; see https://github.com/metafacture/metafacture-fix/issues/100") + public void shouldRenameAllFieldsInHash() { + MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( + "rename('.', ani, XY)" + ), + i -> { + i.startRecord("1"); + i.startEntity("animals"); + i.literal("animal", "dog"); + i.literal("animal", "cat"); + i.endEntity(); + i.startEntity("others"); + i.literal("animal", "human"); + i.literal("canister", "metall"); + i.startEntity("area"); + i.literal("ani", "test"); + i.endEntity(); + i.endEntity(); + i.startEntity("fictional"); + i.literal("animal", "unicorn"); + i.endEntity(); + i.endRecord(); + }, + (o, f) -> { + o.get().startRecord("1"); + o.get().startEntity("XYmals"); + o.get().startEntity("XYmal"); + o.get().literal("1", "dog"); + o.get().literal("2", "cat"); + f.apply(2).endEntity(); + o.get().startEntity("others"); + o.get().literal("XYmal", "human"); + o.get().literal("cXYster", "metall"); + o.get().startEntity("area"); + o.get().literal("XY", "test"); + f.apply(2).endEntity(); + o.get().startEntity("fictional"); + o.get().literal("XYmal", "unicorn"); + o.get().endEntity(); + o.get().endRecord(); + } + ); + } + } From fa0c10e3647dede451dedf2c77f95ffb9e8f2239 Mon Sep 17 00:00:00 2001 From: Jens Wille Date: Tue, 18 Jan 2022 12:06:31 +0100 Subject: [PATCH 05/21] Add `random` unit tests from functional review. (#103) --- .../metafix/MetafixRecordTest.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java b/metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java index 1f092590..727ca1e2 100644 --- a/metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java +++ b/metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java @@ -1854,6 +1854,32 @@ public void shouldAddRandomNumberToUnmarkedArray() { ); } + @Test + @Disabled("See https://github.com/metafacture/metafacture-fix/issues/100") + public void shouldAddRandomNumberToUnmarkedArrayObject() { + MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( + "random('animals.$append', '100')" + ), + i -> { + i.startRecord("1"); + i.startEntity("animals"); + i.literal("1", "cat"); + i.literal("2", "dog"); + i.endEntity(); + i.endRecord(); + }, + o -> { + o.get().startRecord("1"); + o.get().startEntity("animals"); + o.get().literal("1", "cat"); + o.get().literal("2", "dog"); + o.get().literal(ArgumentMatchers.eq("3"), ArgumentMatchers.argThat(i -> Integer.parseInt(i) < 100)); + o.get().endEntity(); + o.get().endRecord(); + } + ); + } + @Test public void shouldRenameFieldsInHash() { MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( From f19b34ada6e4c240f6df3b6ef0ab036a54b47dfc Mon Sep 17 00:00:00 2001 From: Jens Wille Date: Tue, 18 Jan 2022 13:31:25 +0100 Subject: [PATCH 06/21] Add `append` unit tests from functional review. (#103) --- .../metafix/MetafixMethodTest.java | 107 ++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/metafix/src/test/java/org/metafacture/metafix/MetafixMethodTest.java b/metafix/src/test/java/org/metafacture/metafix/MetafixMethodTest.java index d4d1e6b9..ed58afcb 100644 --- a/metafix/src/test/java/org/metafacture/metafix/MetafixMethodTest.java +++ b/metafix/src/test/java/org/metafacture/metafix/MetafixMethodTest.java @@ -21,6 +21,7 @@ import com.google.common.collect.ImmutableMap; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.RegisterExtension; @@ -517,6 +518,112 @@ public void shouldAppendValue() { ); } + @Test + // TODO: Fix order (`animols.name` should stay before `animols.type`) + public void shouldAppendValueInHash() { + MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( + "append(animols.name, ' boss')" + ), + i -> { + i.startRecord("1"); + i.startEntity("animols"); + i.literal("name", "bird"); + i.literal("type", "TEST"); + i.endEntity(); + i.endRecord(); + }, + o -> { + o.get().startRecord("1"); + o.get().startEntity("animols"); + o.get().literal("type", "TEST"); + o.get().literal("name", "bird boss"); + o.get().endEntity(); + o.get().endRecord(); + } + ); + } + + @Test + // TODO: Fix order (`animals[].1` should stay before `animals[].2`) + public void shouldAppendValueInArray() { + MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( + "append('animals[].1', ' is cool')" + ), + i -> { + i.startRecord("1"); + i.startEntity("animals[]"); + i.literal("1", "dog"); + i.literal("2", "cat"); + i.literal("3", "zebra"); + i.endEntity(); + i.endRecord(); + }, + o -> { + o.get().startRecord("1"); + o.get().startEntity("animals[]"); + o.get().literal("2", "cat"); + o.get().literal("3", "zebra"); + o.get().literal("1", "dog is cool"); + o.get().endEntity(); + o.get().endRecord(); + } + ); + } + + @Test + @Disabled("java.lang.ArrayIndexOutOfBoundsException: 0; see https://github.com/metafacture/metafacture-fix/issues/100") + public void shouldAppendValueInEntireArray() { + MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( + "append('animals[].*', ' is cool')" + ), + i -> { + i.startRecord("1"); + i.startEntity("animals[]"); + i.literal("1", "dog"); + i.literal("2", "cat"); + i.literal("3", "zebra"); + i.endEntity(); + i.endRecord(); + }, + o -> { + o.get().startRecord("1"); + o.get().startEntity("animals[]"); + o.get().literal("1", "dog is cool"); + o.get().literal("2", "cat is cool"); + o.get().literal("3", "zebra is cool"); + o.get().endEntity(); + o.get().endRecord(); + } + ); + } + + @Test + @Disabled("See https://github.com/metafacture/metafacture-fix/issues/100") + public void shouldNotAppendValueToArray() { + MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( + "append('animals[]', ' is cool')" + ), + i -> { + i.startRecord("1"); + i.startEntity("animals[]"); + i.literal("1", "dog"); + i.literal("2", "cat"); + i.literal("3", "zebra"); + i.endEntity(); + i.endRecord(); + }, + o -> { + o.get().startRecord("1"); + o.get().startEntity("animals[]"); + o.get().literal("1", "dog"); + o.get().literal("2", "cat"); + o.get().literal("3", "zebra"); + o.get().endEntity(); + o.get().endRecord(); + } + ); + } + @Test public void shouldCountNumberOfValuesInArray() { MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( From 89f56579a09c9618fdc3f565f745500d7ae29e23 Mon Sep 17 00:00:00 2001 From: Jens Wille Date: Tue, 18 Jan 2022 15:54:51 +0100 Subject: [PATCH 07/21] Upgrade xtext dependency to 2.26.0.M2. For Java 17 support; see eclipse/xtext#1982. --- build.gradle | 2 +- .../test/java/org/metafacture/metafix/MetafixBindTest.java | 6 ------ .../test/java/org/metafacture/metafix/MetafixIfTest.java | 6 ------ .../java/org/metafacture/metafix/MetafixLookupTest.java | 6 ------ .../java/org/metafacture/metafix/MetafixMethodTest.java | 6 ------ .../java/org/metafacture/metafix/MetafixRecordTest.java | 6 ------ .../java/org/metafacture/metafix/MetafixSelectorTest.java | 6 ------ 7 files changed, 1 insertion(+), 37 deletions(-) diff --git a/build.gradle b/build.gradle index 109af719..0b9e46ac 100644 --- a/build.gradle +++ b/build.gradle @@ -31,7 +31,7 @@ subprojects { 'mockito': '2.27.0', 'requirejs': '2.3.6', 'slf4j': '1.7.21', - 'xtext': '2.17.0', + 'xtext': '2.26.0.M2', 'guava': '29.0-jre' ] } diff --git a/metafix/src/test/java/org/metafacture/metafix/MetafixBindTest.java b/metafix/src/test/java/org/metafacture/metafix/MetafixBindTest.java index d8bc3e3f..9329a068 100644 --- a/metafix/src/test/java/org/metafacture/metafix/MetafixBindTest.java +++ b/metafix/src/test/java/org/metafacture/metafix/MetafixBindTest.java @@ -21,10 +21,7 @@ import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.junit.jupiter.api.extension.RegisterExtension; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnit; -import org.mockito.junit.MockitoRule; import org.mockito.junit.jupiter.MockitoExtension; import java.util.Arrays; @@ -37,9 +34,6 @@ @ExtendWith(MockitoExtension.class) public class MetafixBindTest { - @RegisterExtension - private MockitoRule mockitoRule = MockitoJUnit.rule(); - @Mock private StreamReceiver streamReceiver; diff --git a/metafix/src/test/java/org/metafacture/metafix/MetafixIfTest.java b/metafix/src/test/java/org/metafacture/metafix/MetafixIfTest.java index d9e71e03..6984f150 100644 --- a/metafix/src/test/java/org/metafacture/metafix/MetafixIfTest.java +++ b/metafix/src/test/java/org/metafacture/metafix/MetafixIfTest.java @@ -21,10 +21,7 @@ import com.google.common.collect.ImmutableMap; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.junit.jupiter.api.extension.RegisterExtension; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnit; -import org.mockito.junit.MockitoRule; import org.mockito.junit.jupiter.MockitoExtension; import java.util.Arrays; @@ -37,9 +34,6 @@ @ExtendWith(MockitoExtension.class) public class MetafixIfTest { - @RegisterExtension - private MockitoRule mockitoRule = MockitoJUnit.rule(); - @Mock private StreamReceiver streamReceiver; diff --git a/metafix/src/test/java/org/metafacture/metafix/MetafixLookupTest.java b/metafix/src/test/java/org/metafacture/metafix/MetafixLookupTest.java index 795e1807..bcebe58b 100644 --- a/metafix/src/test/java/org/metafacture/metafix/MetafixLookupTest.java +++ b/metafix/src/test/java/org/metafacture/metafix/MetafixLookupTest.java @@ -22,10 +22,7 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.junit.jupiter.api.extension.RegisterExtension; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnit; -import org.mockito.junit.MockitoRule; import org.mockito.junit.jupiter.MockitoExtension; import java.util.Arrays; @@ -42,9 +39,6 @@ public class MetafixLookupTest { private static final String CSV_MAP = "src/test/resources/org/metafacture/metafix/maps/test.csv"; private static final String TSV_MAP = "src/test/resources/org/metafacture/metafix/maps/test.tsv"; - @RegisterExtension - private MockitoRule mockitoRule = MockitoJUnit.rule(); - @Mock private StreamReceiver streamReceiver; diff --git a/metafix/src/test/java/org/metafacture/metafix/MetafixMethodTest.java b/metafix/src/test/java/org/metafacture/metafix/MetafixMethodTest.java index 019d89e9..dda5c6c9 100644 --- a/metafix/src/test/java/org/metafacture/metafix/MetafixMethodTest.java +++ b/metafix/src/test/java/org/metafacture/metafix/MetafixMethodTest.java @@ -23,10 +23,7 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.junit.jupiter.api.extension.RegisterExtension; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnit; -import org.mockito.junit.MockitoRule; import org.mockito.junit.jupiter.MockitoExtension; import java.util.Arrays; @@ -40,9 +37,6 @@ @ExtendWith(MockitoExtension.class) public class MetafixMethodTest { - @RegisterExtension - private MockitoRule mockitoRule = MockitoJUnit.rule(); - @Mock private StreamReceiver streamReceiver; diff --git a/metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java b/metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java index bd69dea2..9374be67 100644 --- a/metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java +++ b/metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java @@ -23,10 +23,7 @@ import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.junit.jupiter.api.extension.RegisterExtension; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnit; -import org.mockito.junit.MockitoRule; import org.mockito.junit.jupiter.MockitoExtension; import java.util.Arrays; @@ -40,9 +37,6 @@ @ExtendWith(MockitoExtension.class) public class MetafixRecordTest { - @RegisterExtension - private MockitoRule mockitoRule = MockitoJUnit.rule(); - @Mock private StreamReceiver streamReceiver; diff --git a/metafix/src/test/java/org/metafacture/metafix/MetafixSelectorTest.java b/metafix/src/test/java/org/metafacture/metafix/MetafixSelectorTest.java index 934412ad..0e2a5884 100644 --- a/metafix/src/test/java/org/metafacture/metafix/MetafixSelectorTest.java +++ b/metafix/src/test/java/org/metafacture/metafix/MetafixSelectorTest.java @@ -21,10 +21,7 @@ import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.junit.jupiter.api.extension.RegisterExtension; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnit; -import org.mockito.junit.MockitoRule; import org.mockito.junit.jupiter.MockitoExtension; import java.util.Arrays; @@ -39,9 +36,6 @@ @Disabled("TODO: support Fix-style selectors https://github.com/LibreCat/Catmandu/wiki/Selectors") public final class MetafixSelectorTest { - @RegisterExtension - private MockitoRule mockitoRule = MockitoJUnit.rule(); - @Mock private StreamReceiver streamReceiver; From 6c05a45d09d652e55f687c4e24122b2da15fec24 Mon Sep 17 00:00:00 2001 From: Jens Wille Date: Tue, 18 Jan 2022 17:15:47 +0100 Subject: [PATCH 08/21] Add `filter` unit tests from functional review. (#103) --- .../metafix/MetafixMethodTest.java | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/metafix/src/test/java/org/metafacture/metafix/MetafixMethodTest.java b/metafix/src/test/java/org/metafacture/metafix/MetafixMethodTest.java index ed58afcb..e942ddac 100644 --- a/metafix/src/test/java/org/metafacture/metafix/MetafixMethodTest.java +++ b/metafix/src/test/java/org/metafacture/metafix/MetafixMethodTest.java @@ -714,6 +714,33 @@ public void shouldFilterArrayValuesInverted() { ); } + @Test + @Disabled("See https://github.com/metafacture/metafacture-fix/issues/100") + public void shouldFilterArrayObjectValues() { + MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( + "filter('animals[]', '[Cc]at')" + ), + i -> { + i.startRecord("1"); + i.startEntity("animals[]"); + i.literal("1", "Lion"); + i.literal("2", "Cat"); + i.literal("3", "Tiger"); + i.literal("4", "Bobcat"); + i.endEntity(); + i.endRecord(); + }, + o -> { + o.get().startRecord("1"); + o.get().startEntity("animals[]"); + o.get().literal("1", "Cat"); + o.get().literal("2", "Bobcat"); + o.get().endEntity(); + o.get().endRecord(); + } + ); + } + @Test public void shouldGetIndexOfSubstring() { MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( From a334312d2e8376444825d4d1e90f4443858dbffe Mon Sep 17 00:00:00 2001 From: Jens Wille Date: Tue, 18 Jan 2022 17:26:05 +0100 Subject: [PATCH 09/21] Add `join_field` unit tests from functional review. (#103) --- .../metafix/MetafixMethodTest.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/metafix/src/test/java/org/metafacture/metafix/MetafixMethodTest.java b/metafix/src/test/java/org/metafacture/metafix/MetafixMethodTest.java index e942ddac..663e99ba 100644 --- a/metafix/src/test/java/org/metafacture/metafix/MetafixMethodTest.java +++ b/metafix/src/test/java/org/metafacture/metafix/MetafixMethodTest.java @@ -780,6 +780,29 @@ public void shouldJoinArrayField() { ); } + @Test + @Disabled("See https://github.com/metafacture/metafacture-fix/issues/100") + public void shouldJoinArrayObjectField() { + MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( + "join_field('animals[]', ',')" + ), + i -> { + i.startRecord("1"); + i.startEntity("animals[]"); + i.literal("1", "dog"); + i.literal("2", "cat"); + i.literal("3", "zebra"); + i.endEntity(); + i.endRecord(); + }, + o -> { + o.get().startRecord("1"); + o.get().literal("animals[]", "dog,cat,zebra"); + o.get().endRecord(); + } + ); + } + @Test public void shouldPrependValue() { MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( From bab7bbb7e9bc7548c347ab3a9a10384a82fcaf9f Mon Sep 17 00:00:00 2001 From: Jens Wille Date: Tue, 18 Jan 2022 17:33:01 +0100 Subject: [PATCH 10/21] Add `prepend` unit tests from functional review. (#103) --- .../metafix/MetafixMethodTest.java | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/metafix/src/test/java/org/metafacture/metafix/MetafixMethodTest.java b/metafix/src/test/java/org/metafacture/metafix/MetafixMethodTest.java index 663e99ba..f448064f 100644 --- a/metafix/src/test/java/org/metafacture/metafix/MetafixMethodTest.java +++ b/metafix/src/test/java/org/metafacture/metafix/MetafixMethodTest.java @@ -821,6 +821,112 @@ public void shouldPrependValue() { ); } + @Test + // TODO: Fix order (`animols.name` should stay before `animols.type`) + public void shouldPrependValueInHash() { + MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( + "prepend(animols.name, 'nice ')" + ), + i -> { + i.startRecord("1"); + i.startEntity("animols"); + i.literal("name", "bird"); + i.literal("type", "TEST"); + i.endEntity(); + i.endRecord(); + }, + o -> { + o.get().startRecord("1"); + o.get().startEntity("animols"); + o.get().literal("type", "TEST"); + o.get().literal("name", "nice bird"); + o.get().endEntity(); + o.get().endRecord(); + } + ); + } + + @Test + // TODO: Fix order (`animals[].1` should stay before `animals[].2`) + public void shouldPrependValueInArray() { + MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( + "prepend('animals[].1', 'cool ')" + ), + i -> { + i.startRecord("1"); + i.startEntity("animals[]"); + i.literal("1", "dog"); + i.literal("2", "cat"); + i.literal("3", "zebra"); + i.endEntity(); + i.endRecord(); + }, + o -> { + o.get().startRecord("1"); + o.get().startEntity("animals[]"); + o.get().literal("2", "cat"); + o.get().literal("3", "zebra"); + o.get().literal("1", "cool dog"); + o.get().endEntity(); + o.get().endRecord(); + } + ); + } + + @Test + @Disabled("java.lang.ArrayIndexOutOfBoundsException: 0; see https://github.com/metafacture/metafacture-fix/issues/100") + public void shouldPrependValueInEntireArray() { + MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( + "prepend('animals[].*', 'cool ')" + ), + i -> { + i.startRecord("1"); + i.startEntity("animals[]"); + i.literal("1", "dog"); + i.literal("2", "cat"); + i.literal("3", "zebra"); + i.endEntity(); + i.endRecord(); + }, + o -> { + o.get().startRecord("1"); + o.get().startEntity("animals[]"); + o.get().literal("1", "cool dog"); + o.get().literal("2", "cool cat"); + o.get().literal("3", "cool zebra"); + o.get().endEntity(); + o.get().endRecord(); + } + ); + } + + @Test + @Disabled("See https://github.com/metafacture/metafacture-fix/issues/100") + public void shouldNotPrependValueToArray() { + MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( + "prepend('animals[]', 'cool ')" + ), + i -> { + i.startRecord("1"); + i.startEntity("animals[]"); + i.literal("1", "dog"); + i.literal("2", "cat"); + i.literal("3", "zebra"); + i.endEntity(); + i.endRecord(); + }, + o -> { + o.get().startRecord("1"); + o.get().startEntity("animals[]"); + o.get().literal("1", "dog"); + o.get().literal("2", "cat"); + o.get().literal("3", "zebra"); + o.get().endEntity(); + o.get().endRecord(); + } + ); + } + @Test public void shouldReplaceAllRegexes() { MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( From af12b4f0328b30b1af6b15bc3c0e644f9f13e211 Mon Sep 17 00:00:00 2001 From: Jens Wille Date: Tue, 18 Jan 2022 17:44:57 +0100 Subject: [PATCH 11/21] Add `replace_all` unit tests from functional review. (#103) --- .../metafix/MetafixMethodTest.java | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/metafix/src/test/java/org/metafacture/metafix/MetafixMethodTest.java b/metafix/src/test/java/org/metafacture/metafix/MetafixMethodTest.java index f448064f..4ce81c63 100644 --- a/metafix/src/test/java/org/metafacture/metafix/MetafixMethodTest.java +++ b/metafix/src/test/java/org/metafacture/metafix/MetafixMethodTest.java @@ -945,6 +945,33 @@ public void shouldReplaceAllRegexes() { ); } + @Test + @Disabled("java.lang.ArrayIndexOutOfBoundsException: 0; see https://github.com/metafacture/metafacture-fix/issues/100") + public void shouldReplaceAllRegexesInArray() { + MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( + "replace_all('animals[].*', a, QR)" + ), + i -> { + i.startRecord("1"); + i.startEntity("animals[]"); + i.literal("1", "dog"); + i.literal("2", "cat"); + i.literal("3", "zebra"); + i.endEntity(); + i.endRecord(); + }, + o -> { + o.get().startRecord("1"); + o.get().startEntity("animals[]"); + o.get().literal("1", "dog"); + o.get().literal("2", "cQRt"); + o.get().literal("3", "zebrQR"); + o.get().endEntity(); + o.get().endRecord(); + } + ); + } + @Test public void shouldReverseString() { MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( From 35207445914389ff678fb4fb78e0d532b3661fe0 Mon Sep 17 00:00:00 2001 From: Jens Wille Date: Wed, 19 Jan 2022 11:36:39 +0100 Subject: [PATCH 12/21] Add `index` unit tests from functional review. (#103) --- .../metafacture/metafix/MetafixMethodTest.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/metafix/src/test/java/org/metafacture/metafix/MetafixMethodTest.java b/metafix/src/test/java/org/metafacture/metafix/MetafixMethodTest.java index 4ce81c63..ce0dcff2 100644 --- a/metafix/src/test/java/org/metafacture/metafix/MetafixMethodTest.java +++ b/metafix/src/test/java/org/metafacture/metafix/MetafixMethodTest.java @@ -741,6 +741,24 @@ public void shouldFilterArrayObjectValues() { ); } + @Test + public void shouldGetFirstIndexOfSubstring() { + MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( + "index(animal, 'n')" + ), + i -> { + i.startRecord("1"); + i.literal("animal", "bunny"); + i.endRecord(); + }, + o -> { + o.get().startRecord("1"); + o.get().literal("animal", "2"); + o.get().endRecord(); + } + ); + } + @Test public void shouldGetIndexOfSubstring() { MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( From 131a42550076b97edefec68b9abc7e1ed5c16f2f Mon Sep 17 00:00:00 2001 From: Jens Wille Date: Wed, 19 Jan 2022 11:52:05 +0100 Subject: [PATCH 13/21] Add `split_field` unit tests from functional review. (#103) --- .../metafix/MetafixMethodTest.java | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/metafix/src/test/java/org/metafacture/metafix/MetafixMethodTest.java b/metafix/src/test/java/org/metafacture/metafix/MetafixMethodTest.java index ce0dcff2..266f5b24 100644 --- a/metafix/src/test/java/org/metafacture/metafix/MetafixMethodTest.java +++ b/metafix/src/test/java/org/metafacture/metafix/MetafixMethodTest.java @@ -1261,6 +1261,35 @@ public void shouldSplitHashField() { ); } + @Test + @Disabled("See https://github.com/metafacture/metafacture-fix/issues/100") + public void shouldSplitNestedField() { + MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( + "split_field('others[].*.tools', '--')" + ), + i -> { + i.startRecord("1"); + i.startEntity("others[]"); + i.startEntity("1"); + i.literal("tools", "hammer--saw--bow"); + i.endEntity(); + i.endEntity(); + i.endRecord(); + }, + (o, f) -> { + o.get().startRecord("1"); + o.get().startEntity("others[]"); + o.get().startEntity("1"); + o.get().startEntity("tools"); + o.get().literal("1", "hammer"); + o.get().literal("2", "saw"); + o.get().literal("3", "bow"); + f.apply(3).endEntity(); + o.get().endRecord(); + } + ); + } + @Test public void shouldSumNumbers() { MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( From 1eaf09be110096665ad8b485238ade7fe791acb8 Mon Sep 17 00:00:00 2001 From: Jens Wille Date: Wed, 19 Jan 2022 13:09:55 +0100 Subject: [PATCH 14/21] Switch entities from `Value.Hash` to `Value`. --- .../java/org/metafacture/metafix/Metafix.java | 34 ++++++++++++------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/metafix/src/main/java/org/metafacture/metafix/Metafix.java b/metafix/src/main/java/org/metafacture/metafix/Metafix.java index 4314d0bd..dcff754c 100644 --- a/metafix/src/main/java/org/metafacture/metafix/Metafix.java +++ b/metafix/src/main/java/org/metafacture/metafix/Metafix.java @@ -77,7 +77,7 @@ public class Metafix implements StreamPipe, Maps { // checkstyle private int entityCount; private StreamReceiver outputStreamReceiver; private String recordIdentifier; - private List entities = new ArrayList<>(); + private List entities = new ArrayList<>(); public Metafix() { flattener.setReceiver(new DefaultStreamReceiver() { @@ -170,20 +170,31 @@ private void emit(final String field, final Value value) { }); } + private void addValue(final String name, final Value value) { + final int index = entityCountStack.peek() - 1; + if (index < 0 || entities.size() <= index) { + currentRecord.add(name, value); + } + else { + entities.get(index).matchType() + .ifArray(a -> a.add(value)) + .ifHash(h -> h.add(name, value)) + .orElseThrow(); + } + } + @Override public void startEntity(final String name) { if (name == null) { throw new IllegalArgumentException("Entity name must not be null."); } - ++entityCount; - final Integer currentEntityIndex = entityCountStack.peek() - 1; - final Value.Hash previousEntity = currentEntityIndex < 0 || - entities.size() <= currentEntityIndex ? null : entities.get(currentEntityIndex); - entityCountStack.push(Integer.valueOf(entityCount)); - flattener.startEntity(name); + final Value value = Value.newHash(); - (previousEntity != null ? previousEntity : currentRecord).add(name, value); - entities.add(value.asHash()); + addValue(name, value); + entities.add(value); + + entityCountStack.push(Integer.valueOf(++entityCount)); + flattener.startEntity(name); } @Override @@ -195,10 +206,7 @@ public void endEntity() { @Override public void literal(final String name, final String value) { LOG.debug("Putting '{}': '{}'", name, value); - final Integer currentEntityIndex = entityCountStack.peek() - 1; - final Value.Hash currentEntity = currentEntityIndex < 0 || - entities.size() <= currentEntityIndex ? null : entities.get(currentEntityIndex); - (currentEntity != null ? currentEntity : currentRecord).add(name, new Value(value)); + addValue(name, new Value(value)); // TODO: keep flattener as option? // flattener.literal(name, value); } From a42943d8651c9ef165893be03b1a83140562b0b6 Mon Sep 17 00:00:00 2001 From: Jens Wille Date: Wed, 19 Jan 2022 13:40:58 +0100 Subject: [PATCH 15/21] Produce `Value.Array` for marked array entities. (#109) --- metafix/src/main/java/org/metafacture/metafix/Metafix.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/metafix/src/main/java/org/metafacture/metafix/Metafix.java b/metafix/src/main/java/org/metafacture/metafix/Metafix.java index dcff754c..aeb1dbb5 100644 --- a/metafix/src/main/java/org/metafacture/metafix/Metafix.java +++ b/metafix/src/main/java/org/metafacture/metafix/Metafix.java @@ -189,7 +189,9 @@ public void startEntity(final String name) { throw new IllegalArgumentException("Entity name must not be null."); } - final Value value = Value.newHash(); + final Value value = name.endsWith(ARRAY_MARKER) ? Value.newArray() : Value.newHash(); + // TODO: Remove array marker? => name.substring(0, name.length() - ARRAY_MARKER.length()); + addValue(name, value); entities.add(value); From 7d9b2a44017117469fcc46140048416877da017f Mon Sep 17 00:00:00 2001 From: Jens Wille Date: Wed, 19 Jan 2022 13:47:04 +0100 Subject: [PATCH 16/21] Require explicit array initialization. (#109) --- .../java/org/metafacture/metafix/Value.java | 29 ++----------------- .../metafix/MetafixRecordTest.java | 5 ++++ 2 files changed, 7 insertions(+), 27 deletions(-) diff --git a/metafix/src/main/java/org/metafacture/metafix/Value.java b/metafix/src/main/java/org/metafacture/metafix/Value.java index 496abeda..17dfef5a 100644 --- a/metafix/src/main/java/org/metafacture/metafix/Value.java +++ b/metafix/src/main/java/org/metafacture/metafix/Value.java @@ -305,21 +305,6 @@ void apply(final Hash hash, final String field, final Value value) { void apply(final Hash hash, final String field, final Value value) { hash.add(field, value); } - }, - /* For an indexed representation of arrays as hashes with 1, 2, 3 etc. keys. - * i.e. ["a", "b", "c"] as { "1":"a", "2":"b", "3": "c" } - * This is what is produced by JsonDecoder and Metafix itself for arrays. - * TODO? maybe this would be a good general internal representation, resulting - * in every value being either a hash or a string, no more separate array type.*/ - INDEXED { - @Override - void apply(final Hash hash, final String field, final Value value) { - hash.add(nextIndex(hash), field.equals(ReservedField.$append.name()) ? value : newHash(h -> h.put(field, value))); - } - - private String nextIndex(final Hash hash) { - return "" + (hash.size() + 1) /* TODO? check if keys are actually all ints? */; - } }; abstract void apply(Hash hash, String field, Value value); @@ -697,7 +682,7 @@ private Value insert(final InsertMode mode, final String[] fields, final Value n // TODO: move impl into enum elements, here call only value.insert value.matchType() .ifArray(a -> a.insert(mode, tail, newValue)) - .ifHash(h -> h.insert(insertMode(mode, field, tail), tail, newValue)) + .ifHash(h -> h.insert(mode, tail, newValue)) .orElseThrow(); } } @@ -708,7 +693,7 @@ private Value insert(final InsertMode mode, final String[] fields, final Value n private Value processRef(final InsertMode mode, final Value newValue, final String field, final String[] tail) { final Value referencedValue = getReferencedValue(field); if (referencedValue != null) { - return referencedValue.asHash().insert(insertMode(mode, field, tail), tail, newValue); + return referencedValue.asHash().insert(mode, tail, newValue); } else { throw new IllegalArgumentException("Using ref, but can't find: " + field + " in: " + this); @@ -738,16 +723,6 @@ private Value getReferencedValue(final String field) { return referencedValue; } - private InsertMode insertMode(final InsertMode mode, final String field, final String[] tail) { - // if the field is marked as array, this hash should be smth. like { 1=a, 2=b } - final boolean isIndexedArray = field.endsWith(Metafix.ARRAY_MARKER); - final boolean nextIsRef = tail.length > 0 && ( - tail[0].startsWith(ReservedField.$first.name()) || - tail[0].startsWith(ReservedField.$last.name()) || - isNumber(tail[0])); - return isIndexedArray && !nextIsRef ? InsertMode.INDEXED : mode; - } - /** * Removes the given field/value pair from this hash. * diff --git a/metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java b/metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java index 9374be67..14c3624b 100644 --- a/metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java +++ b/metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java @@ -477,6 +477,7 @@ public void complexAppendWithArrayOfObjects() { @Test public void appendWithWildcard() { MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( + "set_array('stringimals[]')", "copy_field('?nimal', 'stringimals[].$append')" ), i -> { @@ -542,6 +543,7 @@ public void simpleCopyWithWildcard() { @Test public void appendWithMultipleWildcards() { MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( + "set_array('stringimals[]')", "copy_field('?ni??l', 'stringimals[].$append')" ), i -> { @@ -572,6 +574,7 @@ public void appendWithMultipleWildcards() { @Test public void appendWithAsteriksWildcard() { MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( + "set_array('stringimals[]')", "copy_field('*al', 'stringimals[].$append')" ), i -> { @@ -601,6 +604,7 @@ public void appendWithAsteriksWildcard() { @Test public void appendWithBracketWildcard() { MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( + "set_array('stringimals[]')", "copy_field('[ac]nimal', 'stringimals[].$append')" ), i -> { @@ -630,6 +634,7 @@ public void appendWithBracketWildcard() { // See https://github.com/metafacture/metafacture-fix/issues/89 public void appendWithAsteriksWildcardAtTheEnd() { MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( + "set_array('stringimals[]')", "copy_field('ani*', 'stringimals[].$append')" ), i -> { From 0d410df404897de85dafc741a11e72d6a9dff24c Mon Sep 17 00:00:00 2001 From: Jens Wille Date: Wed, 19 Jan 2022 15:10:39 +0100 Subject: [PATCH 17/21] Let `random` replace existing field. (#103) --- .../src/main/java/org/metafacture/metafix/FixMethod.java | 7 ++----- .../java/org/metafacture/metafix/MetafixRecordTest.java | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/metafix/src/main/java/org/metafacture/metafix/FixMethod.java b/metafix/src/main/java/org/metafacture/metafix/FixMethod.java index 0e9fad37..adc7bd8d 100644 --- a/metafix/src/main/java/org/metafacture/metafix/FixMethod.java +++ b/metafix/src/main/java/org/metafacture/metafix/FixMethod.java @@ -178,7 +178,7 @@ public void apply(final Metafix metafix, final Record record, final List final String field = params.get(0); final int max = getInteger(params, 1); - record.append(field, String.valueOf(RANDOM.nextInt(max))); + record.replace(field, String.valueOf(RANDOM.nextInt(max))); } }, reject { @@ -221,10 +221,7 @@ public void apply(final Metafix metafix, final Record record, final List }, set_field { public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - final String field = params.get(0); - - record.remove(field); - record.replace(field, params.get(1)); + record.replace(params.get(0), params.get(1)); } }, set_hash { diff --git a/metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java b/metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java index 727ca1e2..f06e845d 100644 --- a/metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java +++ b/metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java @@ -1768,7 +1768,7 @@ public void shouldAddRandomNumber() { } @Test - @Disabled("See https://github.com/metafacture/metafacture-fix/issues/100") + // See https://github.com/metafacture/metafacture-fix/issues/100 public void shouldReplaceExistingValueWithRandomNumber() { MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( "random(others, '100')" From 2c80ec4069966f9ee27911dc8cde8ffd4913a4d3 Mon Sep 17 00:00:00 2001 From: Jens Wille Date: Thu, 20 Jan 2022 13:31:51 +0100 Subject: [PATCH 18/21] Update unit tests after merging pull request #110. (#103) --- .../metafacture/metafix/MetafixMethodTest.java | 16 +++++++--------- .../metafacture/metafix/MetafixRecordTest.java | 1 + 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/metafix/src/test/java/org/metafacture/metafix/MetafixMethodTest.java b/metafix/src/test/java/org/metafacture/metafix/MetafixMethodTest.java index a1d1a8a8..34251d21 100644 --- a/metafix/src/test/java/org/metafacture/metafix/MetafixMethodTest.java +++ b/metafix/src/test/java/org/metafacture/metafix/MetafixMethodTest.java @@ -538,7 +538,6 @@ public void shouldAppendValueInHash() { } @Test - // TODO: Fix order (`animals[].1` should stay before `animals[].2`) public void shouldAppendValueInArray() { MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( "append('animals[].1', ' is cool')" @@ -555,9 +554,9 @@ public void shouldAppendValueInArray() { o -> { o.get().startRecord("1"); o.get().startEntity("animals[]"); + o.get().literal("1", "dog is cool"); o.get().literal("2", "cat"); o.get().literal("3", "zebra"); - o.get().literal("1", "dog is cool"); o.get().endEntity(); o.get().endRecord(); } @@ -565,7 +564,7 @@ public void shouldAppendValueInArray() { } @Test - @Disabled("java.lang.ArrayIndexOutOfBoundsException: 0; see https://github.com/metafacture/metafacture-fix/issues/100") + // See https://github.com/metafacture/metafacture-fix/issues/100 public void shouldAppendValueInEntireArray() { MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( "append('animals[].*', ' is cool')" @@ -709,7 +708,7 @@ public void shouldFilterArrayValuesInverted() { } @Test - @Disabled("See https://github.com/metafacture/metafacture-fix/issues/100") + // See https://github.com/metafacture/metafacture-fix/issues/100 public void shouldFilterArrayObjectValues() { MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( "filter('animals[]', '[Cc]at')" @@ -793,7 +792,7 @@ public void shouldJoinArrayField() { } @Test - @Disabled("See https://github.com/metafacture/metafacture-fix/issues/100") + // See https://github.com/metafacture/metafacture-fix/issues/100 public void shouldJoinArrayObjectField() { MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( "join_field('animals[]', ',')" @@ -859,7 +858,6 @@ public void shouldPrependValueInHash() { } @Test - // TODO: Fix order (`animals[].1` should stay before `animals[].2`) public void shouldPrependValueInArray() { MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( "prepend('animals[].1', 'cool ')" @@ -876,9 +874,9 @@ public void shouldPrependValueInArray() { o -> { o.get().startRecord("1"); o.get().startEntity("animals[]"); + o.get().literal("1", "cool dog"); o.get().literal("2", "cat"); o.get().literal("3", "zebra"); - o.get().literal("1", "cool dog"); o.get().endEntity(); o.get().endRecord(); } @@ -886,7 +884,7 @@ public void shouldPrependValueInArray() { } @Test - @Disabled("java.lang.ArrayIndexOutOfBoundsException: 0; see https://github.com/metafacture/metafacture-fix/issues/100") + // See https://github.com/metafacture/metafacture-fix/issues/100 public void shouldPrependValueInEntireArray() { MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( "prepend('animals[].*', 'cool ')" @@ -958,7 +956,7 @@ public void shouldReplaceAllRegexes() { } @Test - @Disabled("java.lang.ArrayIndexOutOfBoundsException: 0; see https://github.com/metafacture/metafacture-fix/issues/100") + // See https://github.com/metafacture/metafacture-fix/issues/100 public void shouldReplaceAllRegexesInArray() { MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( "replace_all('animals[].*', a, QR)" diff --git a/metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java b/metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java index f2317ee3..0f8485e9 100644 --- a/metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java +++ b/metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java @@ -1813,6 +1813,7 @@ public void shouldAddRandomNumberToMarkedArray() { @Test public void shouldAddObjectWithRandomNumberToMarkedArray() { MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( + "set_array('bnimals[]')", "random('bnimals[].$append.number', '100')" ), i -> { From 4cee91ebfd924fa6c3d9abb0ac2a763af0c83d9d Mon Sep 17 00:00:00 2001 From: Jens Wille Date: Fri, 21 Jan 2022 12:39:55 +0100 Subject: [PATCH 19/21] Be strict in accepting strings. (#103) Do not just convert any value to string, but throw an exception instead when encountering an unexpected type. --- .../org/metafacture/metafix/FixMethod.java | 8 +++---- .../java/org/metafacture/metafix/Metafix.java | 2 +- .../java/org/metafacture/metafix/Value.java | 7 +++--- .../metafix/MetafixMethodTest.java | 22 +++++++++++++++++++ 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/metafix/src/main/java/org/metafacture/metafix/FixMethod.java b/metafix/src/main/java/org/metafacture/metafix/FixMethod.java index adc7bd8d..9fbd2443 100644 --- a/metafix/src/main/java/org/metafacture/metafix/FixMethod.java +++ b/metafix/src/main/java/org/metafacture/metafix/FixMethod.java @@ -112,7 +112,7 @@ public void apply(final Metafix metafix, final Record record, final List record.getList(field, a -> record.put(field, Value.newHash(h -> { for (int i = 1; i < a.size(); i = i + 2) { - h.put(a.get(i - 1).toString(), a.get(i)); + h.put(a.get(i - 1).asString(), a.get(i)); } }))); } @@ -129,7 +129,7 @@ public void apply(final Metafix metafix, final Record record, final List record.getList(field, a -> a.forEach(v -> { final Pattern p = Pattern.compile(params.get(1)); - final Matcher m = p.matcher(v.toString()); + final Matcher m = p.matcher(v.asString()); if (m.matches()) { record.remove(field); @@ -166,7 +166,7 @@ public void apply(final Metafix metafix, final Record record, final List record.replace(params.get(0), params.subList(1, params.size()).stream() .filter(f -> literalString(f) || record.find(f) != null) .map(f -> literalString(f) ? new Value(f.substring(1)) : record.findList(f, null).asArray().get(0)) - .map(Value::toString).collect(Collectors.joining(joinChar != null ? joinChar : " "))); + .map(Value::asString).collect(Collectors.joining(joinChar != null ? joinChar : " "))); } private boolean literalString(final String s) { @@ -295,7 +295,7 @@ public void apply(final Metafix metafix, final Record record, final List public void apply(final Metafix metafix, final Record record, final List params, final Map options) { final String joinChar = params.size() > 1 ? params.get(1) : ""; record.transformField(params.get(0), (m, c) -> m - .ifArray(a -> c.accept(new Value(a.stream().map(Value::toString).collect(Collectors.joining(joinChar))))) + .ifArray(a -> c.accept(new Value(a.stream().map(Value::asString).collect(Collectors.joining(joinChar))))) ); } }, diff --git a/metafix/src/main/java/org/metafacture/metafix/Metafix.java b/metafix/src/main/java/org/metafacture/metafix/Metafix.java index 6de9ccd2..07c3283f 100644 --- a/metafix/src/main/java/org/metafacture/metafix/Metafix.java +++ b/metafix/src/main/java/org/metafacture/metafix/Metafix.java @@ -132,7 +132,7 @@ public void startRecord(final String identifier) { public void endRecord() { entityCountStack.removeLast(); if (!entityCountStack.isEmpty()) { - throw new IllegalStateException(ENTITIES_NOT_BALANCED); + throw new MetafactureException(new IllegalStateException(ENTITIES_NOT_BALANCED)); } flattener.endRecord(); LOG.debug("End record, walking fix: {}", currentRecord); diff --git a/metafix/src/main/java/org/metafacture/metafix/Value.java b/metafix/src/main/java/org/metafacture/metafix/Value.java index 7dd75f51..11e9bc4b 100644 --- a/metafix/src/main/java/org/metafacture/metafix/Value.java +++ b/metafix/src/main/java/org/metafacture/metafix/Value.java @@ -17,6 +17,7 @@ package org.metafacture.metafix; import org.metafacture.commons.tries.SimpleRegexTrie; +import org.metafacture.framework.MetafactureException; import java.util.ArrayList; import java.util.Arrays; @@ -298,7 +299,7 @@ public void orElse(final Consumer consumer) { public void orElseThrow() { orElse(v -> { final String types = expected.stream().map(Type::name).collect(Collectors.joining(" or ")); - throw new IllegalStateException("expected " + types + ", got " + value.type); + throw new MetafactureException(new IllegalStateException("expected " + types + ", got " + value.type)); }); } @@ -311,7 +312,7 @@ private TypeMatcher match(final Type type, final Consumer consumer, final return this; } else { - throw new IllegalStateException("already expecting " + type); + throw new MetafactureException(new IllegalStateException("already expecting " + type)); } } @@ -848,7 +849,7 @@ private void transformFields(final String[] fields, final UnaryOperator map.remove(f); if (operator != null) { - value.asList(a -> a.forEach(v -> append(f, operator.apply(v.toString())))); + value.asList(a -> a.forEach(v -> append(f, operator.apply(v.asString())))); } } else { diff --git a/metafix/src/test/java/org/metafacture/metafix/MetafixMethodTest.java b/metafix/src/test/java/org/metafacture/metafix/MetafixMethodTest.java index 34251d21..6719292f 100644 --- a/metafix/src/test/java/org/metafacture/metafix/MetafixMethodTest.java +++ b/metafix/src/test/java/org/metafacture/metafix/MetafixMethodTest.java @@ -617,6 +617,28 @@ public void shouldNotAppendValueToArray() { ); } + @Test + // See https://github.com/metafacture/metafacture-fix/issues/100 + public void shouldNotAppendValueToHash() { + assertThrows(IllegalStateException.class, "expected String, got Hash", () -> + MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( + "append('animals', ' is cool')" + ), + i -> { + i.startRecord("1"); + i.startEntity("animals"); + i.literal("1", "dog"); + i.literal("2", "cat"); + i.literal("3", "zebra"); + i.endEntity(); + i.endRecord(); + }, + o -> { + } + ) + ); + } + @Test public void shouldCountNumberOfValuesInArray() { MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( From d8029338bc43b5c1588dde58995459492cc02b23 Mon Sep 17 00:00:00 2001 From: Jens Wille Date: Fri, 21 Jan 2022 14:18:54 +0100 Subject: [PATCH 20/21] Be strict in accepting arrays. (#103) Do not just treat any value as a list, but throw an exception instead when encountering an unexpected type. --- .../java/org/metafacture/metafix/Value.java | 6 +- .../metafix/MetafixLookupTest.java | 40 ++- .../metafix/MetafixMethodTest.java | 321 ++++++++---------- .../metafix/MetafixRecordTest.java | 64 ++-- .../metafix/MetafixTestHelpers.java | 8 + 5 files changed, 211 insertions(+), 228 deletions(-) diff --git a/metafix/src/main/java/org/metafacture/metafix/Value.java b/metafix/src/main/java/org/metafacture/metafix/Value.java index 11e9bc4b..be1d2fad 100644 --- a/metafix/src/main/java/org/metafacture/metafix/Value.java +++ b/metafix/src/main/java/org/metafacture/metafix/Value.java @@ -458,7 +458,7 @@ else if (isNumber(field)) { } } - list.removeIf(v -> v == null); + list.removeIf(v -> Value.isNull(v)); } private void transformFields(final int index, final String[] fields, final UnaryOperator operator) { @@ -849,7 +849,9 @@ private void transformFields(final String[] fields, final UnaryOperator map.remove(f); if (operator != null) { - value.asList(a -> a.forEach(v -> append(f, operator.apply(v.asString())))); + value.matchType() + .ifString(s -> append(f, operator.apply(s))) + .orElseThrow(); } } else { diff --git a/metafix/src/test/java/org/metafacture/metafix/MetafixLookupTest.java b/metafix/src/test/java/org/metafacture/metafix/MetafixLookupTest.java index b96370e7..d901f7f6 100644 --- a/metafix/src/test/java/org/metafacture/metafix/MetafixLookupTest.java +++ b/metafix/src/test/java/org/metafacture/metafix/MetafixLookupTest.java @@ -39,6 +39,8 @@ public class MetafixLookupTest { private static final String CSV_MAP = "src/test/resources/org/metafacture/metafix/maps/test.csv"; private static final String TSV_MAP = "src/test/resources/org/metafacture/metafix/maps/test.tsv"; + private static final String LOOKUP = "lookup('title.*',"; + @Mock private StreamReceiver streamReceiver; @@ -48,14 +50,14 @@ public MetafixLookupTest() { @Test public void inline() { assertMap( - "lookup('title', Aloha: Alohaeha, 'Moin': 'Moin zäme', __default: Tach)" + LOOKUP + " Aloha: Alohaeha, 'Moin': 'Moin zäme', __default: Tach)" ); } @Test public void inlineMultilineIndent() { assertMap( - "lookup('title',", + LOOKUP, " Aloha: Alohaeha,", " Moin: 'Moin zäme',", " __default: Tach)" @@ -65,7 +67,7 @@ public void inlineMultilineIndent() { @Test public void inlineDotNotationNested() { MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( - "lookup('data.title', Aloha: Alohaeha, 'Moin': 'Moin zäme', __default: Tach)" + "lookup('data.title.*', Aloha: Alohaeha, 'Moin': 'Moin zäme', __default: Tach)" ), i -> { i.startRecord("1"); @@ -92,14 +94,14 @@ public void inlineDotNotationNested() { @Test public void csv() { assertMap( - "lookup('title', '" + CSV_MAP + "')" + LOOKUP + " '" + CSV_MAP + "')" ); } @Test public void tsv() { assertMap( - "lookup('title', '" + TSV_MAP + "', sep_char:'\t')" + LOOKUP + " '" + TSV_MAP + "', sep_char:'\t')" ); } @@ -107,7 +109,7 @@ public void tsv() { public void shouldLookupInSeparateInternalMap() { assertMap( "put_map('testMap', Aloha: Alohaeha, 'Moin': 'Moin zäme', __default: Tach)", - "lookup('title', 'testMap')" + LOOKUP + " 'testMap')" ); } @@ -115,7 +117,7 @@ public void shouldLookupInSeparateInternalMap() { public void shouldLookupInSeparateExternalFileMap() { assertMap( "put_filemap('" + CSV_MAP + "')", - "lookup('title', '" + CSV_MAP + "')" + LOOKUP + " '" + CSV_MAP + "')" ); } @@ -123,7 +125,7 @@ public void shouldLookupInSeparateExternalFileMap() { public void shouldLookupInSeparateExternalFileMapWithName() { assertMap( "put_filemap('" + CSV_MAP + "', 'testMap')", - "lookup('title', 'testMap')" + LOOKUP + " 'testMap')" ); } @@ -131,7 +133,7 @@ public void shouldLookupInSeparateExternalFileMapWithName() { public void shouldLookupInSeparateExternalFileMapWithOptions() { assertMap( "put_filemap('" + TSV_MAP + "', sep_char: '\t')", - "lookup('title', '" + TSV_MAP + "')" + LOOKUP + " '" + TSV_MAP + "')" ); } @@ -139,7 +141,7 @@ public void shouldLookupInSeparateExternalFileMapWithOptions() { public void shouldLookupInSeparateExternalFileMapWithNameAndOptions() { assertMap( "put_filemap('" + TSV_MAP + "', 'testMap', sep_char: '\t')", - "lookup('title', 'testMap')" + LOOKUP + " 'testMap')" ); } @@ -148,7 +150,7 @@ public void shouldDefineMultipleSeparateMaps() { assertMap( "put_map('testMap', Aloha: Alohaeha, 'Moin': 'Moin zäme', __default: Tach)", "put_map('testMap2', __default: Hi)", - "lookup('title', 'testMap')" + LOOKUP + " 'testMap')" ); } @@ -157,7 +159,7 @@ public void shouldOverwriteExistingSeparateMap() { assertMap( "put_map('testMap', __default: Hi)", "put_filemap('" + CSV_MAP + "', 'testMap')", - "lookup('title', 'testMap')" + LOOKUP + " 'testMap')" ); } @@ -165,7 +167,7 @@ public void shouldOverwriteExistingSeparateMap() { public void shouldIgnoreOptionsOnLookupInSeparateInternalMap() { assertMap( "put_map('testMap', Aloha: Alohaeha, 'Moin': 'Moin zäme', __default: Tach)", - "lookup('title', 'testMap', __default: Hi)" + LOOKUP + " 'testMap', __default: Hi)" ); } @@ -173,14 +175,14 @@ public void shouldIgnoreOptionsOnLookupInSeparateInternalMap() { public void shouldIgnoreOptionsOnLookupInSeparateExternalFileMap() { assertMap( "put_filemap('" + CSV_MAP + "')", - "lookup('title', '" + CSV_MAP + "', sep_char: '\t')" + LOOKUP + " '" + CSV_MAP + "', sep_char: '\t')" ); } @Test public void shouldNotLookupInExternalFileMapWithWrongOptions() { MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( - "lookup('title', '" + CSV_MAP + "', sep_char: '\t')" + LOOKUP + " '" + CSV_MAP + "', sep_char: '\t')" ), i -> { i.startRecord("1"); @@ -191,6 +193,8 @@ public void shouldNotLookupInExternalFileMapWithWrongOptions() { }, o -> { o.get().startRecord("1"); + o.get().startEntity("title"); + o.get().endEntity(); o.get().endRecord(); } ); @@ -199,8 +203,8 @@ public void shouldNotLookupInExternalFileMapWithWrongOptions() { @Test public void shouldIgnoreOptionsOnSubsequentLookupInExternalFileMap() { MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( - "lookup('title', '" + CSV_MAP + "')", - "lookup('title', '" + CSV_MAP + "', sep_char: '\t')" + LOOKUP + " '" + CSV_MAP + "')", + LOOKUP + " '" + CSV_MAP + "', sep_char: '\t')" ), i -> { i.startRecord("1"); @@ -225,7 +229,7 @@ public void shouldIgnoreOptionsOnSubsequentLookupInExternalFileMap() { public void shouldFailLookupInUnknownNamedMap() { final Throwable exception = Assertions.assertThrows(MorphExecutionException.class, () -> MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( - "lookup('title', 'testMap')" + LOOKUP + " 'testMap')" ), i -> { i.startRecord("1"); diff --git a/metafix/src/test/java/org/metafacture/metafix/MetafixMethodTest.java b/metafix/src/test/java/org/metafacture/metafix/MetafixMethodTest.java index 6719292f..d3b8fed2 100644 --- a/metafix/src/test/java/org/metafacture/metafix/MetafixMethodTest.java +++ b/metafix/src/test/java/org/metafacture/metafix/MetafixMethodTest.java @@ -16,15 +16,12 @@ package org.metafacture.metafix; -import org.metafacture.framework.MetafactureException; import org.metafacture.framework.StreamReceiver; import com.google.common.collect.ImmutableMap; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.junit.jupiter.api.function.Executable; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; @@ -46,212 +43,196 @@ public MetafixMethodTest() { } @Test - public void upcase() { + public void shouldUpcaseString() { MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( - "upcase('title')"), + "upcase('title')" + ), i -> { i.startRecord("1"); - i.endRecord(); - - i.startRecord("2"); i.literal("title", "marc"); - i.literal("title", "json"); - i.endRecord(); - - i.startRecord("3"); i.endRecord(); - }, o -> { + }, + o -> { o.get().startRecord("1"); + o.get().literal("title", "MARC"); o.get().endRecord(); - - o.get().startRecord("2"); - o.get().startEntity("title"); - o.get().literal("1", "MARC"); - o.get().literal("2", "JSON"); - o.get().endEntity(); - o.get().endRecord(); - - o.get().startRecord("3"); - o.get().endRecord(); - }); + } + ); } @Test - public void upcaseDotNotationNested() { + public void shouldUpcaseDotNotationNested() { MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( - "upcase('data.title')"), + "upcase('data.title')" + ), i -> { i.startRecord("1"); i.startEntity("data"); i.literal("title", "marc"); - i.literal("title", "json"); i.endEntity(); i.endRecord(); - }, (o, f) -> { + }, + o -> { o.get().startRecord("1"); o.get().startEntity("data"); - o.get().startEntity("title"); - o.get().literal("1", "MARC"); - o.get().literal("2", "JSON"); - f.apply(2).endEntity(); + o.get().literal("title", "MARC"); + o.get().endEntity(); o.get().endRecord(); - }); + } + ); } @Test - public void downcase() { + public void shouldDowncaseString() { MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( - "downcase('title')"), + "downcase('title')" + ), i -> { i.startRecord("1"); + i.literal("title", "MARC"); i.endRecord(); + }, + o -> { + o.get().startRecord("1"); + o.get().literal("title", "marc"); + o.get().endRecord(); + } + ); + } - i.startRecord("2"); + @Test + public void shouldDowncaseStringsInArray() { + MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( + "downcase('title.*')" + ), + i -> { + i.startRecord("1"); i.literal("title", "MARC"); i.literal("title", "Json"); i.endRecord(); - - i.startRecord("3"); - i.endRecord(); - }, o -> { + }, + o -> { o.get().startRecord("1"); - o.get().endRecord(); - - o.get().startRecord("2"); o.get().startEntity("title"); o.get().literal("1", "marc"); o.get().literal("2", "json"); o.get().endEntity(); o.get().endRecord(); - - o.get().startRecord("3"); - o.get().endRecord(); - }); + } + ); } @Test - public void capitalize() { + public void shouldCapitalizeString() { MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( - "capitalize('title')"), + "capitalize('title')" + ), i -> { i.startRecord("1"); + i.literal("title", "marc"); i.endRecord(); + }, + o -> { + o.get().startRecord("1"); + o.get().literal("title", "Marc"); + o.get().endRecord(); + } + ); + } - i.startRecord("2"); + @Test + public void shouldCapitalizeStringsInArray() { + MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( + "capitalize('title.*')" + ), + i -> { + i.startRecord("1"); i.literal("title", "marc"); i.literal("title", "json"); i.endRecord(); - - i.startRecord("3"); - i.endRecord(); - }, o -> { + }, + o -> { o.get().startRecord("1"); - o.get().endRecord(); - - o.get().startRecord("2"); o.get().startEntity("title"); o.get().literal("1", "Marc"); o.get().literal("2", "Json"); o.get().endEntity(); o.get().endRecord(); + } + ); + } - o.get().startRecord("3"); - o.get().endRecord(); - }); + @Test + public void shouldNotCapitalizeArray() { + MetafixTestHelpers.assertThrows(IllegalStateException.class, "expected String, got Array", () -> + MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( + "capitalize('title')" + ), + i -> { + i.startRecord("1"); + i.literal("title", "marc"); + i.literal("title", "json"); + i.endRecord(); + }, + o -> { + } + ) + ); } @Test - public void substring() { + public void shouldGetSubstringOfString() { MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( - "substring('title', '0', '2')"), + "substring('title', '0', '2')" + ), i -> { i.startRecord("1"); - i.endRecord(); - - i.startRecord("2"); i.literal("title", "marc"); - i.literal("title", "json"); - i.endRecord(); - - i.startRecord("3"); i.endRecord(); - }, o -> { + }, + o -> { o.get().startRecord("1"); + o.get().literal("title", "m"); o.get().endRecord(); - - o.get().startRecord("2"); - o.get().startEntity("title"); - o.get().literal("1", "m"); - o.get().literal("2", "j"); - o.get().endEntity(); - o.get().endRecord(); - - o.get().startRecord("3"); - o.get().endRecord(); - }); + } + ); } @Test - public void substringWithVar() { + public void shouldGetSubstringWithVar() { MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( - "substring('title', '0', '$[end]')"), - ImmutableMap.of("end", "3"), + "substring('title', '0', '$[end]')" + ), + ImmutableMap.of("end", "3"), i -> { i.startRecord("1"); - i.endRecord(); - - i.startRecord("2"); i.literal("title", "marc"); - i.literal("title", "json"); - i.endRecord(); - - i.startRecord("3"); i.endRecord(); - }, o -> { + }, + o -> { o.get().startRecord("1"); + o.get().literal("title", "ma"); o.get().endRecord(); - - o.get().startRecord("2"); - o.get().startEntity("title"); - o.get().literal("1", "ma"); - o.get().literal("2", "js"); - o.get().endEntity(); - o.get().endRecord(); - - o.get().startRecord("3"); - o.get().endRecord(); - }); + } + ); } @Test - public void trim() { + public void shouldTrimString() { MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( - "trim('title')"), + "trim('title')" + ), i -> { i.startRecord("1"); - i.endRecord(); - - i.startRecord("2"); i.literal("title", " marc "); - i.literal("title", " json "); i.endRecord(); - - i.startRecord("3"); - i.endRecord(); - }, o -> { + }, + o -> { o.get().startRecord("1"); + o.get().literal("title", "marc"); o.get().endRecord(); - - o.get().startRecord("2"); - o.get().startEntity("title"); - o.get().literal("1", "marc"); - o.get().literal("2", "json"); - o.get().endEntity(); - o.get().endRecord(); - - o.get().startRecord("3"); - o.get().endRecord(); - }); + } + ); } @Test @@ -353,7 +334,7 @@ public void parseTextMixedGroups() { @Test public void parseTextEscapedGroups() { - assertThrows(IllegalArgumentException.class, "No group with name ", () -> + MetafixTestHelpers.assertThrows(IllegalArgumentException.class, "No group with name ", () -> MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( "parse_text(data, '(?.)(.)\\\\(?.\\\\)')" ), @@ -370,7 +351,7 @@ public void parseTextEscapedGroups() { @Test public void parseTextQuotedGroups() { - assertThrows(IllegalArgumentException.class, "No group with name ", () -> + MetafixTestHelpers.assertThrows(IllegalArgumentException.class, "No group with name ", () -> MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( "parse_text(data, '(?.)(.)\\\\Q(?.)\\\\E')" ), @@ -591,36 +572,31 @@ public void shouldAppendValueInEntireArray() { } @Test - @Disabled("See https://github.com/metafacture/metafacture-fix/issues/100") + // See https://github.com/metafacture/metafacture-fix/issues/100 public void shouldNotAppendValueToArray() { - MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( - "append('animals[]', ' is cool')" - ), - i -> { - i.startRecord("1"); - i.startEntity("animals[]"); - i.literal("1", "dog"); - i.literal("2", "cat"); - i.literal("3", "zebra"); - i.endEntity(); - i.endRecord(); - }, - o -> { - o.get().startRecord("1"); - o.get().startEntity("animals[]"); - o.get().literal("1", "dog"); - o.get().literal("2", "cat"); - o.get().literal("3", "zebra"); - o.get().endEntity(); - o.get().endRecord(); - } + MetafixTestHelpers.assertThrows(IllegalStateException.class, "expected String, got Array", () -> + MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( + "append('animals[]', ' is cool')" + ), + i -> { + i.startRecord("1"); + i.startEntity("animals[]"); + i.literal("1", "dog"); + i.literal("2", "cat"); + i.literal("3", "zebra"); + i.endEntity(); + i.endRecord(); + }, + o -> { + } + ) ); } @Test // See https://github.com/metafacture/metafacture-fix/issues/100 public void shouldNotAppendValueToHash() { - assertThrows(IllegalStateException.class, "expected String, got Hash", () -> + MetafixTestHelpers.assertThrows(IllegalStateException.class, "expected String, got Hash", () -> MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( "append('animals', ' is cool')" ), @@ -933,29 +909,24 @@ public void shouldPrependValueInEntireArray() { } @Test - @Disabled("See https://github.com/metafacture/metafacture-fix/issues/100") + // See https://github.com/metafacture/metafacture-fix/issues/100 public void shouldNotPrependValueToArray() { - MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( - "prepend('animals[]', 'cool ')" - ), - i -> { - i.startRecord("1"); - i.startEntity("animals[]"); - i.literal("1", "dog"); - i.literal("2", "cat"); - i.literal("3", "zebra"); - i.endEntity(); - i.endRecord(); - }, - o -> { - o.get().startRecord("1"); - o.get().startEntity("animals[]"); - o.get().literal("1", "dog"); - o.get().literal("2", "cat"); - o.get().literal("3", "zebra"); - o.get().endEntity(); - o.get().endRecord(); - } + MetafixTestHelpers.assertThrows(IllegalStateException.class, "expected String, got Array", () -> + MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( + "prepend('animals[]', 'cool ')" + ), + i -> { + i.startRecord("1"); + i.startEntity("animals[]"); + i.literal("1", "dog"); + i.literal("2", "cat"); + i.literal("3", "zebra"); + i.endEntity(); + i.endRecord(); + }, + o -> { + } + ) ); } @@ -1098,7 +1069,7 @@ public void shouldSortFieldNumerically() { @Test public void shouldFailToSortNumericallyWithInvalidNumber() { - assertThrows(NumberFormatException.class, "For input string: \"x\"", () -> + MetafixTestHelpers.assertThrows(NumberFormatException.class, "For input string: \"x\"", () -> MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( "sort_field(numbers, numeric: 'true')" ), @@ -1350,10 +1321,4 @@ public void shouldRemoveDuplicates() { ); } - private void assertThrows(final Class expectedClass, final String expectedMessage, final Executable executable) { - final Throwable exception = Assertions.assertThrows(MetafactureException.class, executable).getCause(); - Assertions.assertSame(expectedClass, exception.getClass()); - Assertions.assertEquals(expectedMessage, exception.getMessage()); - } - } diff --git a/metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java b/metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java index 0f8485e9..ac663540 100644 --- a/metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java +++ b/metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java @@ -16,10 +16,8 @@ package org.metafacture.metafix; -import org.metafacture.framework.MetafactureException; import org.metafacture.framework.StreamReceiver; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -896,26 +894,31 @@ public void addFieldToObjectByIndexInIndexedArray() { @Test public void addFieldToFirstObjectMissing() { - assertThrowsOnEmptyRecord("add_field('animals[].$first.kind','nice')"); + assertThrowsOnEmptyRecord("$first"); } @Test public void addFieldToLastObjectMissing() { - assertThrowsOnEmptyRecord("add_field('animals[].$last.kind','nice')"); + assertThrowsOnEmptyRecord("$last"); } @Test public void addFieldToObjectByIndexMissing() { - assertThrowsOnEmptyRecord("add_field('animals[].2.kind','nice')"); + assertThrowsOnEmptyRecord("2"); } - private void assertThrowsOnEmptyRecord(final String fix) { - Assertions.assertThrows(MetafactureException.class, () -> { - MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(fix), + private void assertThrowsOnEmptyRecord(final String index) { + MetafixTestHelpers.assertThrows(IllegalArgumentException.class, "Using ref, but can't find: " + index + " in: {}", () -> { + MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( + "add_field('animals[]." + index + ".kind','nice')" + ), i -> { i.startRecord("1"); i.endRecord(); - }, o -> { }); + }, + o -> { + } + ); }); } @@ -1596,42 +1599,43 @@ public void accessArrayByIndex() { } @Test - public void accessArrayImplicit() { - MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( - "upcase('name')"), - i -> { - i.startRecord("1"); - i.literal("name", "max"); - i.literal("name", "mo"); - i.endRecord(); - }, (o, f) -> { - o.get().startRecord("1"); - o.get().startEntity("name"); - o.get().literal("1", "MAX"); - o.get().literal("2", "MO"); - o.get().endEntity(); - o.get().endRecord(); - }); + public void shouldNotAccessArrayImplicitly() { + MetafixTestHelpers.assertThrows(IllegalStateException.class, "expected String, got Array", () -> + MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( + "upcase('name')" + ), + i -> { + i.startRecord("1"); + i.literal("name", "max"); + i.literal("name", "mo"); + i.endRecord(); + }, + o -> { + } + ) + ); } @Test - // TODO: WDCD? explicit * for array fields? - public void accessArrayByWildcard() { + public void shouldAccessArrayByWildcard() { MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( - "upcase('name.*')"), + "upcase('name.*')" + ), i -> { i.startRecord("1"); i.literal("name", "max"); i.literal("name", "mo"); i.endRecord(); - }, (o, f) -> { + }, + o -> { o.get().startRecord("1"); o.get().startEntity("name"); o.get().literal("1", "MAX"); o.get().literal("2", "MO"); o.get().endEntity(); o.get().endRecord(); - }); + } + ); } @Test diff --git a/metafix/src/test/java/org/metafacture/metafix/MetafixTestHelpers.java b/metafix/src/test/java/org/metafacture/metafix/MetafixTestHelpers.java index cde64818..89b51ca4 100644 --- a/metafix/src/test/java/org/metafacture/metafix/MetafixTestHelpers.java +++ b/metafix/src/test/java/org/metafacture/metafix/MetafixTestHelpers.java @@ -16,9 +16,11 @@ package org.metafacture.metafix; +import org.metafacture.framework.MetafactureException; import org.metafacture.framework.StreamReceiver; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.function.Executable; import org.mockito.InOrder; import org.mockito.Mockito; import org.mockito.exceptions.base.MockitoAssertionError; @@ -43,6 +45,12 @@ public final class MetafixTestHelpers { private MetafixTestHelpers() { } + public static void assertThrows(final Class expectedClass, final String expectedMessage, final Executable executable) { + final Throwable exception = Assertions.assertThrows(MetafactureException.class, executable).getCause(); + Assertions.assertSame(expectedClass, exception.getClass()); + Assertions.assertEquals(expectedMessage, exception.getMessage()); + } + public static void assertFix(final StreamReceiver receiver, final List fixDef, final Consumer in, final Consumer> out) { assertFix(receiver, fixDef, in, (s, f) -> out.accept(s), Metafix.NO_VARS); From 1eebaac79dd177c765e4a4a9f5aea6d118e8d183 Mon Sep 17 00:00:00 2001 From: Jens Wille Date: Fri, 21 Jan 2022 17:37:49 +0100 Subject: [PATCH 21/21] Apply `rename` Fix function recursively. (#103) Catmandu operates on both arrays and hashes. --- .../org/metafacture/metafix/FixMethod.java | 24 +++++++++++++++++-- .../java/org/metafacture/metafix/Value.java | 2 +- .../metafix/MetafixRecordTest.java | 4 ++-- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/metafix/src/main/java/org/metafacture/metafix/FixMethod.java b/metafix/src/main/java/org/metafacture/metafix/FixMethod.java index 9fbd2443..3ad98280 100644 --- a/metafix/src/main/java/org/metafacture/metafix/FixMethod.java +++ b/metafix/src/main/java/org/metafacture/metafix/FixMethod.java @@ -29,6 +29,7 @@ import java.util.Set; import java.util.function.Function; import java.util.function.Predicate; +import java.util.function.UnaryOperator; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -196,9 +197,28 @@ public void apply(final Metafix metafix, final Record record, final List final String search = params.get(1); final String replace = params.get(2); - // TODO: recurse into arrays/values + final UnaryOperator operator = s -> s.replaceAll(search, replace); + record.transformField(params.get(0), (m, c) -> m - .ifHash(h -> c.accept(Value.newHash(n -> h.forEach((f, w) -> n.put(f.replaceAll(search, replace), w))))) + .ifArray(a -> c.accept(renameArray(a, operator))) + .ifHash(h -> c.accept(renameHash(h, operator))) + .orElseThrow() + ); + } + + private Value renameArray(final Value.Array array, final UnaryOperator operator) { + return Value.newArray(a -> array.forEach(v -> a.add(renameValue(v, operator)))); + } + + private Value renameHash(final Value.Hash hash, final UnaryOperator operator) { + return Value.newHash(h -> hash.forEach((f, v) -> h.put(operator.apply(f), renameValue(v, operator)))); + } + + private Value renameValue(final Value value, final UnaryOperator operator) { + return value.extractType((m, c) -> m + .ifArray(a -> c.accept(renameArray(a, operator))) + .ifHash(h -> c.accept(renameHash(h, operator))) + .orElse(c) ); } }, diff --git a/metafix/src/main/java/org/metafacture/metafix/Value.java b/metafix/src/main/java/org/metafacture/metafix/Value.java index be1d2fad..653a2980 100644 --- a/metafix/src/main/java/org/metafacture/metafix/Value.java +++ b/metafix/src/main/java/org/metafacture/metafix/Value.java @@ -211,7 +211,7 @@ public TypeMatcher matchType() { return new TypeMatcher(this); } - private T extractType(final BiConsumer> consumer) { + public T extractType(final BiConsumer> consumer) { final AtomicReference result = new AtomicReference<>(); consumer.accept(matchType(), result::set); return result.get(); diff --git a/metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java b/metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java index ac663540..83a125e8 100644 --- a/metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java +++ b/metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java @@ -1907,7 +1907,7 @@ public void shouldRenameFieldsInHash() { } @Test - @Disabled("See https://github.com/metafacture/metafacture-fix/issues/100") + // See https://github.com/metafacture/metafacture-fix/issues/100 public void shouldRecursivelyRenameFieldsInHash() { MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( "rename(others, ani, QR)" @@ -1937,7 +1937,7 @@ public void shouldRecursivelyRenameFieldsInHash() { } @Test - @Disabled("See https://github.com/metafacture/metafacture-fix/issues/100") + // See https://github.com/metafacture/metafacture-fix/issues/100 public void shouldRecursivelyRenameFieldsInArray() { MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( "rename('animals[]', ani, XY)"