From 45bb75bef1c3c3b96f4806f998b67b421bd9c852 Mon Sep 17 00:00:00 2001 From: Jens Wille Date: Tue, 31 Oct 2023 12:58:47 +0100 Subject: [PATCH 1/2] Add support for nested paths in `retain()` Fix function. (#145) --- .../java/org/metafacture/metafix/Value.java | 73 ++- .../metafix/MetafixRecordTest.java | 83 +++ .../toJson/retainCertainSubfields/todo.txt | 1 - .../expected.json | 8 + .../retainNestedSubfieldCopyField/input.json | 473 ++++++++++++++++++ .../retainNestedSubfieldCopyField/test.fix | 2 + .../retainNestedSubfieldCopyField/test.flux | 8 + 7 files changed, 644 insertions(+), 4 deletions(-) delete mode 100644 metafix/src/test/resources/org/metafacture/metafix/integration/record/fromJson/toJson/retainCertainSubfields/todo.txt create mode 100644 metafix/src/test/resources/org/metafacture/metafix/integration/record/fromJson/toJson/retainNestedSubfieldCopyField/expected.json create mode 100644 metafix/src/test/resources/org/metafacture/metafix/integration/record/fromJson/toJson/retainNestedSubfieldCopyField/input.json create mode 100644 metafix/src/test/resources/org/metafacture/metafix/integration/record/fromJson/toJson/retainNestedSubfieldCopyField/test.fix create mode 100644 metafix/src/test/resources/org/metafacture/metafix/integration/record/fromJson/toJson/retainNestedSubfieldCopyField/test.flux diff --git a/metafix/src/main/java/org/metafacture/metafix/Value.java b/metafix/src/main/java/org/metafacture/metafix/Value.java index 4c19d280..b6175e34 100644 --- a/metafix/src/main/java/org/metafacture/metafix/Value.java +++ b/metafix/src/main/java/org/metafacture/metafix/Value.java @@ -38,10 +38,12 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.BiConsumer; import java.util.function.Consumer; +import java.util.function.Function; import java.util.function.Predicate; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; +import java.util.stream.IntStream; import java.util.stream.Stream; /** @@ -303,6 +305,13 @@ private Value withPathAppend(final String field) { .orElseThrow()); } + private void retainFields(final Collection fields) { + matchType() + .ifArray(a -> a.retainFields(fields)) + .ifHash(h -> h.retainFields(fields)) + .orElseThrow(); + } + enum Type { Array, Hash, @@ -387,6 +396,23 @@ private abstract static class AbstractValueType implements JsonValue { @Override public abstract void toJson(JsonGenerator jsonGenerator); + protected Map> retainFields(final Collection fields, final Function> function) { + final Map> retainFields = new HashMap<>(); + + fields.forEach(p -> { + final String[] parts = p.split(FIELD_PATH_SEPARATOR, 2); + + function.apply(parts[0]).forEach(f -> { + final Collection retainNested = retainFields.computeIfAbsent(f, k -> new HashSet<>()); + if (parts.length > 1) { + retainNested.add(parts[1]); + } + }); + }); + + return retainFields; + } + } /** @@ -428,10 +454,46 @@ public Stream stream() { return list.stream(); } + private IntStream indexes() { + return IntStream.range(0, size()); + } + private void removeEmptyValues() { list.removeIf(REMOVE_EMPTY_VALUES); } + private void retainFields(final Collection fields) { + final Map> retainFields = retainFields(fields, this::findFields); + + final int max = size() - 1; + indexes().map(i -> max - i).forEach(i -> { + final Collection retainNested = retainFields.get(i); + if (retainNested == null) { + remove(i); + } + else if (!retainNested.isEmpty()) { + get(i).retainFields(retainNested); + } + }); + } + + private Set findFields(final String pattern) { + final Set fieldSet = new LinkedHashSet<>(); + + if ("*".equals(pattern)) { + indexes().forEach(fieldSet::add); + } + else { + final int index = Integer.parseInt(pattern) - 1; // TODO: 0-based Catmandu vs. 1-based Metafacture + + if (index >= 0 && index < size()) { + fieldSet.add(index); + } + } + + return fieldSet; + } + public void forEach(final Consumer consumer) { list.forEach(consumer); } @@ -696,10 +758,15 @@ public void removeField(final String field) { * @param fields the field names */ public void retainFields(final Collection fields) { - final Set retainFields = new HashSet<>(); - fields.forEach(f -> retainFields.addAll(findFields(f))); + final Map> retainFields = retainFields(fields, this::findFields); - map.keySet().retainAll(retainFields); + map.keySet().retainAll(retainFields.keySet()); + + retainFields.forEach((k, v) -> { + if (!v.isEmpty()) { + getField(k).retainFields(v); + } + }); } /** diff --git a/metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java b/metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java index f331bc4a..88c5bab1 100644 --- a/metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java +++ b/metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java @@ -2335,6 +2335,89 @@ public void retain() { }); } + @Test // checkstyle-disable-line JavaNCSS + public void retainNested() { + MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( + "retain('a.b.c','a.[cd].b','b[].2.c','c[].*.a','c[].2.b')" + ), + i -> { + i.startRecord("1"); + i.startEntity("a"); + i.startEntity("a"); + i.literal("b", "1"); + i.literal("c", "2"); + i.endEntity(); + i.startEntity("b"); + i.literal("c", "1"); + i.literal("d", "2"); + i.endEntity(); + i.startEntity("c"); + i.literal("b", "1"); + i.literal("c", "2"); + i.endEntity(); + i.endEntity(); + i.startEntity("b[]"); + i.startEntity("1"); + i.literal("a", "1"); + i.literal("b", "2"); + i.endEntity(); + i.startEntity("2"); + i.literal("a", "1"); + i.literal("b", "2"); + i.literal("c", "3"); + i.endEntity(); + i.startEntity("3"); + i.literal("c", "4"); + i.endEntity(); + i.endEntity(); + i.startEntity("c[]"); + i.startEntity("1"); + i.literal("a", "1"); + i.literal("b", "2"); + i.endEntity(); + i.startEntity("2"); + i.literal("a", "1"); + i.literal("b", "2"); + i.literal("c", "3"); + i.endEntity(); + i.startEntity("3"); + i.literal("c", "4"); + i.endEntity(); + i.endEntity(); + i.startEntity("d"); + i.literal("e", "5"); + i.endEntity(); + i.literal("e", "6"); + i.endRecord(); + }, + (o, f) -> { + o.get().startRecord("1"); + o.get().startEntity("a"); + o.get().startEntity("b"); + o.get().literal("c", "1"); + o.get().endEntity(); + o.get().startEntity("c"); + o.get().literal("b", "1"); + f.apply(2).endEntity(); + o.get().startEntity("b[]"); + o.get().startEntity("1"); + o.get().literal("c", "3"); + f.apply(2).endEntity(); + o.get().startEntity("c[]"); + o.get().startEntity("1"); + o.get().literal("a", "1"); + o.get().endEntity(); + o.get().startEntity("2"); + o.get().literal("a", "1"); + o.get().literal("b", "2"); + o.get().endEntity(); + o.get().startEntity("3"); + f.apply(2).endEntity(); + o.get().endRecord(); + } + ); + } + @Test public void shouldDeleteEmptyArrays() { MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( diff --git a/metafix/src/test/resources/org/metafacture/metafix/integration/record/fromJson/toJson/retainCertainSubfields/todo.txt b/metafix/src/test/resources/org/metafacture/metafix/integration/record/fromJson/toJson/retainCertainSubfields/todo.txt deleted file mode 100644 index d8aeb165..00000000 --- a/metafix/src/test/resources/org/metafacture/metafix/integration/record/fromJson/toJson/retainCertainSubfields/todo.txt +++ /dev/null @@ -1 +0,0 @@ -See issue #145 diff --git a/metafix/src/test/resources/org/metafacture/metafix/integration/record/fromJson/toJson/retainNestedSubfieldCopyField/expected.json b/metafix/src/test/resources/org/metafacture/metafix/integration/record/fromJson/toJson/retainNestedSubfieldCopyField/expected.json new file mode 100644 index 00000000..e27017ae --- /dev/null +++ b/metafix/src/test/resources/org/metafacture/metafix/integration/record/fromJson/toJson/retainNestedSubfieldCopyField/expected.json @@ -0,0 +1,8 @@ +{ + "node" : { + "properties" : { + "ccm:educationallearningresourcetype" : [ "https://w3id.org/kim/hcrt/image" ] + } + }, + "lrt" : [ "https://w3id.org/kim/hcrt/image" ] +} diff --git a/metafix/src/test/resources/org/metafacture/metafix/integration/record/fromJson/toJson/retainNestedSubfieldCopyField/input.json b/metafix/src/test/resources/org/metafacture/metafix/integration/record/fromJson/toJson/retainNestedSubfieldCopyField/input.json new file mode 100644 index 00000000..cd42c97e --- /dev/null +++ b/metafix/src/test/resources/org/metafacture/metafix/integration/record/fromJson/toJson/retainNestedSubfieldCopyField/input.json @@ -0,0 +1,473 @@ +{ + "node": { + "content": { + "url": "https://www.zoerr.de/edu-sharing/components/render/651396b4-db24-44e4-a0f6-76aff3293f90", + "hash": "544246969", + "version": "1.0" + }, + "license": { + "icon": "https://uni-tuebingen.oerbw.de/edu-sharing/ccimages/licenses/cc-by.svg", + "url": "https://creativecommons.org/licenses/by/4.0/deed.en" + }, + "isDirectory": "false", + "commentCount": "0", + "rating": { + "overall": { + "sum": "0.0", + "count": "0", + "rating": "0.0" + }, + "affiliation": { + }, + "user": "0.0" + }, + "usedInCollections": [ + + ], + "ref": { + "repo": "uni-tuebingen.de", + "id": "651396b4-db24-44e4-a0f6-76aff3293f90", + "archived": "false", + "isHomeRepo": "true" + }, + "parent": { + "repo": "uni-tuebingen.de", + "id": "94a86998-e3af-4161-bd37-7e6ad0ca53d7", + "archived": "false", + "isHomeRepo": "true" + }, + "type": "ccm:io", + "aspects": [ + "cclom:lifecycle", + "cclom:technical", + "cm:versionable", + "ccm:iometadata", + "ccm:tracking", + "sys:referenceable", + "cm:metadataset", + "ccm:commonlicenses", + "cclom:rights", + "cm:thumbnailed", + "cm:titled", + "cm:auditable", + "cclom:meta-metadata", + "ccm:educontext", + "ccm:permission_history", + "ccm:eduscope", + "ccm:usageaspect", + "sys:localized", + "cm:thumbnailModification", + "cclom:schema", + "exif:exif", + "ccm:licenses", + "sys:cascadeUpdate", + "ccm:lomreplication", + "cclom:general", + "cm:author" + ], + "name": "IMG_1866.JPG", + "title": "Jubiläumsbrunnen der Universität Tübingen", + "metadataset": "default", + "repositoryType": "ALFRESCO", + "createdAt": "2017-12-06T13:52:35Z", + "createdBy": { + "firstName": "Peter", + "lastName": "Rempis" + }, + "modifiedAt": "2019-07-23T09:26:00Z", + "modifiedBy": { + "firstName": "unknown", + "lastName": "unknown" + }, + "access": [ + "Read", + "ReadAll" + ], + "downloadUrl": "https://uni-tuebingen.oerbw.de/edu-sharing/eduservlet/download?nodeId=651396b4-db24-44e4-a0f6-76aff3293f90", + "properties": { + "ccm:lifecyclecontributer_authorVCARD_ORG": [ + "" + ], + "ccm:ph_modified": [ + "1512568989232" + ], + "cm:created": [ + "1512568355467" + ], + "virtual:commentcount": [ + "0" + ], + "ccm:metadatacontributer_creatorVCARD_ORG": [ + "" + ], + "ccm:university_DISPLAYNAME": [ + "Universität Tübingen" + ], + "sys:node-uuid": [ + "651396b4-db24-44e4-a0f6-76aff3293f90" + ], + "ccm:lifecyclecontributer_authorVCARD_SURNAME": [ + "" + ], + "exif:resolutionUnit": [ + "Inch" + ], + "virtual:licenseurl": [ + "https://creativecommons.org/licenses/by/4.0/deed.de" + ], + "cclom:title": [ + "Jubiläumsbrunnen der Universität Tübingen" + ], + "ccm:lifecyclecontributer_authorVCARD_COUNTRY": [ + "" + ], + "ccm:lifecyclecontributer_instructional_designer": [ + "" + ], + "ccm:ph_modifiedISO8601": [ + "2017-12-06T14:03:09.232Z" + ], + "ccm:lifecyclecontributer_authorVCARD_STREET": [ + "" + ], + "ccm:lifecyclecontributer_authorVCARD_PLZ": [ + "" + ], + "ccm:height": [ + "1200" + ], + "exif:pixelXDimension": [ + "1600" + ], + "ccm:version_comment": [ + "MAIN_FILE_UPLOAD" + ], + "sys:cascadeTx": [ + "191514" + ], + "ccm:create_version": [ + "true" + ], + "ccm:university": [ + "Universität Tübingen" + ], + "ccm:lifecyclecontributer_content_provider": [ + "" + ], + "cm:modifiedISO8601": [ + "2019-07-23T09:26:00.782Z" + ], + "ccm:author_freetext": [ + "Fotograf Peter Rempis" + ], + "ccm:metadatacontributer_creatorVCARD_REGION": [ + "" + ], + "cm:edu_metadataset": [ + "default" + ], + "ccm:metadatacontributer_creatorVCARD_PLZ": [ + "" + ], + "ccm:lifecyclecontributer_unknown": [ + "" + ], + "virtual:permalink": [ + "https://uni-tuebingen.oerbw.de/edu-sharing/components/render/651396b4-db24-44e4-a0f6-76aff3293f90/1.0" + ], + "ccm:metadatacontributer_creatorVCARD_GIVENNAME": [ + "Peter" + ], + "ccm:lifecyclecontributer_authorVCARD_GIVENNAME": [ + "" + ], + "ccm:commonlicense_cc_version": [ + "4.0" + ], + "ccm:width": [ + "1600" + ], + "exif:dateTimeOriginalISO8601": [ + "2009-05-29T08:36:46.000Z" + ], + "ccm:metadatacontributer_creatorVCARD_TEL": [ + "" + ], + "ccm:lifecyclecontributer_authorVCARD_CITY": [ + "" + ], + "exif:pixelYDimension": [ + "1200" + ], + "ccm:ph_action": [ + "PERMISSION_ADD" + ], + "ccm:lifecyclecontributer_terminator": [ + "" + ], + "ccm:lifecyclecontributer_educational_validator": [ + "" + ], + "cclom:general_description": [ + "Der Brunnen wurde zur Feier des 500jährigen-Gründungsjubiläums der Universität Tübingen im Jahr 1977 gestiftet. Er steht heute vor dem Hauptgebäude der Universitätsbibkliothek. " + ], + "cm:modified": [ + "1563873960782" + ], + "ccm:metadatacontributer_creatorVCARD_CITY": [ + "" + ], + "ccm:taxonid": [ + "https://w3id.org/kim/hochschulfaechersystematik/n9" + ], + "cm:modifier": [ + "System" + ], + "ccm:educationallearningresourcetype_DISPLAYNAME": [ + "Abbildung" + ], + "exif:dateTimeOriginal_LONG": [ + "1243586206000" + ], + "exif:orientation": [ + "1" + ], + "cm:autoVersionOnUpdateProps": [ + "false" + ], + "exif:focalLength": [ + "9.28125" + ], + "ccm:metadatacontributer_creatorFN": [ + "Peter Rempis" + ], + "exif:model": [ + "Canon DIGITAL IXUS v2" + ], + "ccm:metadatacontributer_creatorVCARD_TITLE": [ + "" + ], + "cm:automaticUpdate": [ + "true" + ], + "ccm:ph_users": [ + "admin" + ], + "ccm:ph_history": [ + "{\"notifyUser\":\"admin\",\"notifyAction\":\"PERMISSION_ADD\",\"user\":{\"username\":\"admin\",\"fuzzySearchMode\":false,\"authorityName\":\"admin\",\"authorityType\":\"USER\"},\"created\":\"Dec 6, 2017 3:03:09 PM\",\"acl\":{\"inherited\":false,\"aces\":[{\"authority\":\"e395487b9bdd6e53baf174b4fba68f17e2f4c710@uni-tuebingen.de\",\"permission\":\"All\",\"accessStatus\":\"acepted\",\"authorityType\":\"USER\",\"user\":{\"nodeId\":\"d71702e3-270b-41ab-99be-ba248a3024cc\",\"email\":\"peter.rempis@uni-tuebingen.de\",\"givenName\":\"Peter\",\"surname\":\"Rempis\",\"repositoryId\":\"uni-tuebingen.de\",\"username\":\"e395487b9bdd6e53baf174b4fba68f17e2f4c710@uni-tuebingen.de\",\"fuzzySearchMode\":true,\"authorityName\":\"e395487b9bdd6e53baf174b4fba68f17e2f4c710@uni-tuebingen.de\",\"authorityType\":\"USER\"},\"id\":0,\"isInherited\":false,\"isEdited\":false},{\"authority\":\"ROLE_OWNER\",\"permission\":\"All\",\"accessStatus\":\"acepted\",\"authorityType\":\"OWNER\",\"user\":{\"nodeId\":\"f0653dc4-6920-41ea-b101-d40dbeaee503\",\"email\":\"admin@alfresco.com\",\"givenName\":\"Administrator\",\"surname\":\"\",\"repositoryId\":\"uni-tuebingen.de\",\"username\":\"admin\",\"fuzzySearchMode\":true,\"authorityName\":\"admin\",\"authorityType\":\"USER\"},\"id\":0,\"isInherited\":false,\"isEdited\":false},{\"authority\":\"GROUP_EVERYONE\",\"permission\":\"Consumer\",\"accessStatus\":\"acepted\",\"authorityType\":\"EVERYONE\",\"id\":0,\"isInherited\":false,\"isEdited\":false},{\"authority\":\"GROUP_EVERYONE\",\"permission\":\"CCPublish\",\"accessStatus\":\"acepted\",\"authorityType\":\"EVERYONE\",\"id\":0,\"isInherited\":false,\"isEdited\":false}]}}" + ], + "ccm:tracking_downloads": [ + "3" + ], + "cm:initialVersion": [ + "false" + ], + "ccm:lifecyclecontributer_script_writer": [ + "" + ], + "ccm:metadatacontributer_creatorVCARD_SURNAME": [ + "Rempis" + ], + "ccm:commonlicense_key": [ + "CC_BY" + ], + "ccm:lifecyclecontributer_authorVCARD_TITLE": [ + "" + ], + "ccm:original": [ + "651396b4-db24-44e4-a0f6-76aff3293f90" + ], + "cclom:size": [ + "841895" + ], + "cclom:version": [ + "1.0" + ], + "ccm:tracking_views": [ + "85" + ], + "cclom:general_language": [ + "de_DE" + ], + "virtual:licenseicon": [ + "https://uni-tuebingen.oerbw.de/edu-sharing/ccimages/licenses/cc-by.svg" + ], + "virtual:usagecount": [ + "0" + ], + "ccm:lifecyclecontributer_publisher": [ + "" + ], + "ccm:metadatacontributer_provider": [ + "" + ], + "ccm:taxonid_DISPLAYNAME": [ + "Kunst, Kunstwissenschaft" + ], + "ccm:lifecyclecontributer_authorVCARD_URL": [ + "" + ], + "virtual:childobjectcount": [ + "0" + ], + "exif:xResolution": [ + "180.0" + ], + "sys:cascadeCRC": [ + "2490900358" + ], + "ccm:lifecyclecontributer_author": [ + "BEGIN:VCARD\r\nVERSION:3.0\r\nN:;;;;\r\nFN:\r\nEND:VCARD\r\n" + ], + "ccm:lifecyclecontributer_authorVCARD_REGION": [ + "" + ], + "sys:store-protocol": [ + "workspace" + ], + "sys:store-identifier": [ + "SpacesStore" + ], + "cclom:general_language_DISPLAYNAME": [ + "de_DE" + ], + "cclom:format": [ + "image/jpeg" + ], + "ccm:metadatacontributer_creatorVCARD_URL": [ + "" + ], + "ccm:educationallearningresourcetype": [ + "https://w3id.org/kim/hcrt/image" + ], + "exif:exposureTime": [ + "0.0025" + ], + "sys:node-dbid": [ + "1588" + ], + "cclom:otherplatformrequirements": [ + "JPG-Datei. " + ], + "cm:autoVersion": [ + "false" + ], + "ccm:lifecyclecontributer_initiator": [ + "" + ], + "cm:creator": [ + "e395487b9bdd6e53baf174b4fba68f17e2f4c710@uni-tuebingen.de" + ], + "ccm:lifecyclecontributer_subject_matter_expert": [ + "" + ], + "cm:versionLabel": [ + "1.0" + ], + "cm:versionable": [ + "true" + ], + "exif:yResolution": [ + "180.0" + ], + "ccm:metadatacontributer_creatorVCARD_COUNTRY": [ + "" + ], + "cm:created_LONG": [ + "1512568355467" + ], + "ccm:lifecyclecontributer_authorVCARD_TEL": [ + "" + ], + "exif:fNumber": [ + "3.5" + ], + "virtual:primaryparent_nodeid": [ + "94a86998-e3af-4161-bd37-7e6ad0ca53d7" + ], + "cm:lastThumbnailModification": [ + "imgpreview:1512568356868" + ], + "ccm:metadatacontributer_creator": [ + "BEGIN:VCARD\r\nVERSION:3.0\r\nN:Rempis;Peter;;;\r\nFN:Peter Rempis\r\nTITLE:\r\nORG:\r\nURL:\r\nADR;TYPE=INTL,POSTAL,PARCEL,WORK:;;;;;;\r\nTEL;TYPE=WORK,VOICE:\r\nEND:VCARD\r\n" + ], + "ccm:lifecyclecontributer_graphical_designer": [ + "" + ], + "exif:dateTimeOriginal": [ + "1243586206000" + ], + "ccm:metadatacontributer_creatorVCARD_STREET": [ + "" + ], + "cm:createdISO8601": [ + "2017-12-06T13:52:35.467Z" + ], + "cm:edu_forcemetadataset": [ + "false" + ], + "ccm:lifecyclecontributer_editor": [ + "" + ], + "ccm:metadatacontributer_validator": [ + "" + ], + "cclom:location": [ + "ccrep://oerbw.uni-tuebingen.de/651396b4-db24-44e4-a0f6-76aff3293f90" + ], + "ccm:educontextname": [ + "default" + ], + "ccm:lifecyclecontributer_authorFN": [ + "" + ], + "exif:flash": [ + "false" + ], + "ccm:ph_modified_LONG": [ + "1512568989232" + ], + "ccm:lifecyclecontributer_technical_implementer": [ + "" + ], + "cm:modified_LONG": [ + "1563873960782" + ], + "ccm:lifecyclecontributer_validator": [ + "" + ], + "ccm:questionsallowed": [ + "true" + ], + "exif:manufacturer": [ + "Canon" + ], + "cm:name": [ + "IMG_1866.JPG" + ], + "ccm:ph_invited": [ + "ROLE_OWNER", + "GROUP_EVERYONE", + "e395487b9bdd6e53baf174b4fba68f17e2f4c710@uni-tuebingen.de" + ], + "cclom:general_keyword": [ + "Brunnen", + "Universität" + ] + }, + "mimetype": "image/jpeg", + "mediatype": "file-image", + "size": "841895", + "preview": { + "isIcon": "false", + "isGenerated": "true", + "type": "TYPE_GENERATED", + "url": "https://uni-tuebingen.oerbw.de/edu-sharing/preview?nodeId=651396b4-db24-44e4-a0f6-76aff3293f90&storeProtocol=workspace&storeId=SpacesStore&dontcache=1644570252250" + }, + "iconURL": "https://www.zoerr.de/edu-sharing/themes/default/images/common/mime-types/svg/file-image.svg", + "owner": { + "firstName": "Peter", + "lastName": "Rempis" + } + } +} diff --git a/metafix/src/test/resources/org/metafacture/metafix/integration/record/fromJson/toJson/retainNestedSubfieldCopyField/test.fix b/metafix/src/test/resources/org/metafacture/metafix/integration/record/fromJson/toJson/retainNestedSubfieldCopyField/test.fix new file mode 100644 index 00000000..44a296ad --- /dev/null +++ b/metafix/src/test/resources/org/metafacture/metafix/integration/record/fromJson/toJson/retainNestedSubfieldCopyField/test.fix @@ -0,0 +1,2 @@ +copy_field("node.properties.ccm:educationallearningresourcetype[]", "lrt[]") +retain("node.properties.ccm:educationallearningresourcetype[]", "lrt[]") diff --git a/metafix/src/test/resources/org/metafacture/metafix/integration/record/fromJson/toJson/retainNestedSubfieldCopyField/test.flux b/metafix/src/test/resources/org/metafacture/metafix/integration/record/fromJson/toJson/retainNestedSubfieldCopyField/test.flux new file mode 100644 index 00000000..7c3575fa --- /dev/null +++ b/metafix/src/test/resources/org/metafacture/metafix/integration/record/fromJson/toJson/retainNestedSubfieldCopyField/test.flux @@ -0,0 +1,8 @@ +FLUX_DIR + "input.json" +|open-file +|as-records +|decode-json +|fix(FLUX_DIR + "test.fix") +|encode-json(prettyPrinting="true") +|write(FLUX_DIR + "output-metafix.json") +; From 5cc686d81e8bc398d35dd4bd07364e089a1e6271 Mon Sep 17 00:00:00 2001 From: Jens Wille Date: Wed, 8 Nov 2023 11:03:49 +0100 Subject: [PATCH 2/2] Add support for nested `$first`/`$last` in `retain()` Fix function. (#329) --- .../java/org/metafacture/metafix/Value.java | 13 ++++- .../metafix/MetafixRecordTest.java | 52 +++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/metafix/src/main/java/org/metafacture/metafix/Value.java b/metafix/src/main/java/org/metafacture/metafix/Value.java index b6175e34..8aeae637 100644 --- a/metafix/src/main/java/org/metafacture/metafix/Value.java +++ b/metafix/src/main/java/org/metafacture/metafix/Value.java @@ -484,7 +484,18 @@ private Set findFields(final String pattern) { indexes().forEach(fieldSet::add); } else { - final int index = Integer.parseInt(pattern) - 1; // TODO: 0-based Catmandu vs. 1-based Metafacture + final int index; + + switch (pattern) { + case "$first": + index = 0; + break; + case "$last": + index = size() - 1; + break; + default: + index = Integer.parseInt(pattern) - 1; // TODO: 0-based Catmandu vs. 1-based Metafacture + } if (index >= 0 && index < size()) { fieldSet.add(index); diff --git a/metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java b/metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java index 88c5bab1..67e6ea77 100644 --- a/metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java +++ b/metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java @@ -2418,6 +2418,58 @@ public void retainNested() { ); } + @Test + public void retainNestedReservedFields() { + MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList( + "retain('b[].$first.b','c[].$last')" + ), + i -> { + i.startRecord("1"); + i.startEntity("b[]"); + i.startEntity("1"); + i.literal("a", "1"); + i.literal("b", "2"); + i.endEntity(); + i.startEntity("2"); + i.literal("a", "1"); + i.literal("b", "2"); + i.literal("c", "3"); + i.endEntity(); + i.startEntity("3"); + i.literal("c", "4"); + i.endEntity(); + i.endEntity(); + i.startEntity("c[]"); + i.startEntity("1"); + i.literal("a", "1"); + i.literal("b", "2"); + i.endEntity(); + i.startEntity("2"); + i.literal("a", "1"); + i.literal("b", "2"); + i.literal("c", "3"); + i.endEntity(); + i.startEntity("3"); + i.literal("c", "4"); + i.endEntity(); + i.endEntity(); + i.endRecord(); + }, + (o, f) -> { + o.get().startRecord("1"); + o.get().startEntity("b[]"); + o.get().startEntity("1"); + o.get().literal("b", "2"); + f.apply(2).endEntity(); + o.get().startEntity("c[]"); + o.get().startEntity("1"); + o.get().literal("c", "4"); + f.apply(2).endEntity(); + o.get().endRecord(); + } + ); + } + @Test public void shouldDeleteEmptyArrays() { MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(