diff --git a/README.md b/README.md index 7444c830d..b62a19c7a 100644 --- a/README.md +++ b/README.md @@ -247,7 +247,7 @@ Options: include(""[, ...]) ``` -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+include+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/script/Include.java) ##### `log` @@ -265,7 +265,7 @@ Options: log(""[, level: ""]) ``` -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+log+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/script/Log.java) ##### `nothing` @@ -277,7 +277,7 @@ nothing() [Example in Playground](https://metafacture.org/playground/?example=nothing) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+nothing+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/script/Nothing.java) ##### `put_filemap` @@ -306,7 +306,7 @@ Options: - `key_column`: Defines the column to be used for keys. Uses zero index. (Default: `0`) - `value_column`: Defines the column to be used for values. Uses zero index. (Default: `1`) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+put_filemap+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/script/PutFileMap.java) ##### `put_map` @@ -322,7 +322,7 @@ put_map("", [Example in Playground](https://metafacture.org/playground/?example=put_map) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+put_map+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/script/PutMap.java) ##### `put_rdfmap` @@ -337,7 +337,7 @@ put_rdfmap("", "", target: "", select_lang [Example in Playground](https://metafacture.org/playground/?example=put_rdfmap) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+put_rdfmap+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/script/PutRdfMap.java) ##### `put_var` @@ -349,7 +349,7 @@ put_var("", "") [Example in Playground](https://metafacture.org/playground/?example=put_var) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+put_var+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/script/PutVar.java) ##### `put_vars` @@ -364,7 +364,7 @@ put_vars( [Example in Playground](https://metafacture.org/playground/?example=put_vars) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+put_vars+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/script/PutVars.java) ##### `to_var` @@ -380,7 +380,7 @@ Options: [Example in Playground](https://metafacture.org/playground/?example=to_var) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+to_var+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/script/ToVar.java) #### Record-level functions @@ -395,7 +395,7 @@ add_array("", ""[, ...]) [Example in Playground](https://metafacture.org/playground/?example=add_array) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+add_array+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/record/AddArray.java) ##### `add_field` @@ -407,7 +407,7 @@ add_field("", "") [Example in Playground](https://metafacture.org/playground/?example=add_field) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+add_field+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/record/AddField.java) ##### `add_hash` @@ -420,7 +420,7 @@ add_hash("", "subfieldName": ""[, ...]) [Example in Playground](https://metafacture.org/playground/?example=add_hash) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+add_hash+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/record/AddHash.java) ##### `array` @@ -439,7 +439,7 @@ array("foo") [Example in Playground](https://metafacture.org/playground/?example=array) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+array+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/record/Array.java) ##### `call_macro` @@ -462,7 +462,7 @@ call_macro(""[, ...]) [Example in Playground](https://metafacture.org/playground/?example=call_macro) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+call_macro+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/record/CallMacro.java) ##### `copy_field` @@ -474,7 +474,7 @@ copy_field("", "") [Example in Playground](https://metafacture.org/playground/?example=copy_field) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+copy_field+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/record/CopyField.java) ##### `format` @@ -486,7 +486,7 @@ Replaces the value with a formatted (`sprintf`-like) version. format("", "") ``` -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+format+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/record/Format.java) ##### `hash` @@ -504,7 +504,7 @@ hash("foo") [Example in Playground](https://metafacture.org/playground/?example=hash) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+hash+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/record/Hash.java) ##### `move_field` @@ -516,7 +516,7 @@ move_field("", "") [Example in Playground](https://metafacture.org/playground/?example=move_field) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+move_field+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/record/MoveField.java) ##### `parse_text` @@ -530,7 +530,7 @@ parse_text("", "") [Example in Playground](https://metafacture.org/playground/?example=parse_text) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+parse_text+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/record/ParseText.java) ##### `paste` @@ -555,7 +555,7 @@ paste("my.string", "~Hi", "a", "~how are you?") [Example in Playground](https://metafacture.org/playground/?example=paste) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+paste+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/record/Paste.java) ##### `print_record` @@ -590,7 +590,7 @@ print_record(destination: "record-%2$s.json", id: "001", pretty: "true") print_record(destination: "record-%03d.json.gz", header: "After transformation: ") ``` -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+print_record+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/record/PrintRecord.java) ##### `random` @@ -602,7 +602,7 @@ random("", "") [Example in Playground](https://metafacture.org/playground/?example=random) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+random+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/record/Random.java) ##### `remove_field` @@ -614,7 +614,7 @@ remove_field("") [Example in Playground](https://metafacture.org/playground/?example=remove_field) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+remove_field+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/record/RemoveField.java) ##### `rename` @@ -626,7 +626,7 @@ rename("", "", "") [Example in Playground](https://metafacture.org/playground/?example=rename) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+rename+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/record/Rename.java) ##### `retain` @@ -638,7 +638,7 @@ retain(""[, ...]) [Example in Playground](https://metafacture.org/playground/?example=retain) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+retain+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/record/Retain.java) ##### `set_array` @@ -651,7 +651,7 @@ set_array("", ""[, ...]) [Example in Playground](https://metafacture.org/playground/?example=set_array) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+set_array+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/record/SetArray.java) ##### `set_field` @@ -663,7 +663,7 @@ set_field("", "") [Example in Playground](https://metafacture.org/playground/?example=set_field) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+set_field+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/record/SetField.java) ##### `set_hash` @@ -676,7 +676,7 @@ set_hash("", "subfieldName": ""[, ...]) [Example in Playground](https://metafacture.org/playground/?example=set_hash) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+set_hash+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/record/SetHash.java) ##### `timestamp` @@ -694,7 +694,7 @@ timestamp(""[, format: ""][, timezone: "", "") [Example in Playground](https://metafacture.org/playground/?example=append) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+append+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/field/Append.java) ##### `capitalize` @@ -732,7 +732,7 @@ capitalize("") [Example in Playground](https://metafacture.org/playground/?example=capitalize) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+capitalize+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/field/Capitalize.java) ##### `count` @@ -744,7 +744,7 @@ count("") [Example in Playground](https://metafacture.org/playground/?example=count) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+count+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/field/Count.java) ##### `downcase` @@ -756,7 +756,7 @@ downcase("") [Example in Playground](https://metafacture.org/playground/?example=downcase) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+downcase+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/field/Downcase.java) ##### `filter` @@ -768,7 +768,7 @@ filter("", "") [Example in Playground](https://metafacture.org/playground/?example=filter) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+filter+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/field/Filter.java) ##### `flatten` @@ -780,7 +780,7 @@ flatten("") [Example in Playground](https://metafacture.org/playground/?example=flatten) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+flatten+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/field/Flatten.java) ##### `from_json` @@ -794,7 +794,7 @@ Options: from_json(""[, error_string: ""]) ``` -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+from_json+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/field/FromJson.java) ##### `index` @@ -806,7 +806,7 @@ index("", "") [Example in Playground](https://metafacture.org/playground/?example=index) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+index+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/field/Index.java) ##### `isbn` @@ -824,7 +824,7 @@ isbn(""[, to: ""][, verify_check_digit: ""][, [Example in Playground](https://metafacture.org/playground/?example=isbn) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+isbn+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/field/Isbn.java) ##### `join_field` @@ -836,7 +836,7 @@ join_field("", "") [Example in Playground](https://metafacture.org/playground/?example=join_field) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+join_field+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/field/JoinField.java) ##### `lookup` @@ -897,7 +897,7 @@ lookup("path.to.field", "map-name", "default": "NA") lookup("path.to.field", "map-name", print_unknown: "true", destination: "unknown.txt") ``` -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+lookup+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/field/Lookup.java) ##### `prepend` @@ -909,7 +909,7 @@ prepend("", "") [Example in Playground](https://metafacture.org/playground/?example=prepend) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+prepend+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/field/Prepend.java) ##### `replace_all` @@ -921,7 +921,7 @@ replace_all("", "", "") [Example in Playground](https://metafacture.org/playground/?example=replace_all) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+replace_all+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/field/ReplaceAll.java) ##### `reverse` @@ -933,7 +933,7 @@ reverse("") [Example in Playground](https://metafacture.org/playground/?example=reverse) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+reverse+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/field/Reverse.java) ##### `sort_field` @@ -947,7 +947,7 @@ sort_field("", numeric: "true") [Example in Playground](https://metafacture.org/playground/?example=sort_field) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+sort_field+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/field/SortField.java) ##### `split_field` @@ -959,7 +959,7 @@ split_field("", "") [Example in Playground](https://metafacture.org/playground/?example=split_field) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+split_field+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/field/SplitField.java) ##### `substring` @@ -971,7 +971,7 @@ substring("", "", "") [Example in Playground](https://metafacture.org/playground/?example=substring) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+substring+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/field/Substring.java) ##### `sum` @@ -983,40 +983,40 @@ sum("") [Example in Playground](https://metafacture.org/playground/?example=sum) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+sum+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/field/Sum.java) -##### `to_json` +##### `to_base64` -Replaces the value with its JSON serialization. +Replaces the value with its Base64 encoding. Options: -- `error_string`: Error message as a placeholder if the JSON couldn't be generated. (Default: `null`) -- `pretty`: Whether to use pretty printing. (Default: `false`) +-`url_safe`: Perform URL-safe encoding (uses Base64URL format). (Default: `false`) ```perl -to_json(""[, pretty: ""][, error_string: ""]) +to_base64(""[, url_safe: ""]) ``` -[Example in Playground](https://metafacture.org/playground/?example=to_json) +[Example in Playground](https://metafacture.org/playground/?example=to_base64) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+to_json+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/field/ToBase64.java) -##### `to_base64` +##### `to_json` -Replaces the value with its Base64 encoding. +Replaces the value with its JSON serialization. Options: --`url_safe`: Perform URL-safe encoding (uses Base64URL format). (Default: `false`) +- `error_string`: Error message as a placeholder if the JSON couldn't be generated. (Default: `null`) +- `pretty`: Whether to use pretty printing. (Default: `false`) ```perl -to_base64(""[, url_safe: ""]) +to_json(""[, pretty: ""][, error_string: ""]) ``` -[Example in Playground](https://metafacture.org/playground/?example=to_base64) +[Example in Playground](https://metafacture.org/playground/?example=to_json) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+to_base64+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/field/ToJson.java) ##### `trim` @@ -1028,7 +1028,7 @@ trim("") [Example in Playground](https://metafacture.org/playground/?example=trim) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+trim+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/field/Trim.java) ##### `uniq` @@ -1040,7 +1040,7 @@ uniq("") [Example in Playground](https://metafacture.org/playground/?example=uniq) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+uniq+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/field/Uniq.java) ##### `upcase` @@ -1052,7 +1052,7 @@ upcase("") [Example in Playground](https://metafacture.org/playground/?example=upcase) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+upcase+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/field/Upcase.java) ##### `uri_encode` @@ -1075,7 +1075,7 @@ uri_encode("path.to.field", plus_for_space:"false", safe_chars:"") [Example in Playground](https://metafacture.org/playground/?example=uri_encode) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+uri_encode+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/field/UriEncode.java) ### Selectors @@ -1091,7 +1091,7 @@ end [Example in Playground](https://metafacture.org/playground/?example=reject) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixMethod.java+"+reject+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/method/record/Reject.java) ### Binds @@ -1099,7 +1099,7 @@ end Iterates over each element of an array. In contrast to Catmandu, it can also iterate over a single object or string. -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixBind.java+"+list+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/bind/List.java) ```perl do list(path: "") @@ -1127,7 +1127,7 @@ Iterates over each _named_ element of an array (like [`do list`](#do-list) with [Example in Playground](https://metafacture.org/playground/?example=do+list_as) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixBind.java+"+list_as+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/bind/ListAs.java) ```perl do list_as(element_1: ""[, ...]) @@ -1160,7 +1160,7 @@ end [Example in Playground](https://metafacture.org/playground/?example=do_once) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixBind.java+"+once+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/bind/Once.java) In order to execute multiple blocks only once, tag them with unique identifiers: @@ -1200,7 +1200,7 @@ call_macro(""[, ...]) [Example in Playground](https://metafacture.org/playground/?example=do_put_macro) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixBind.java+"+put_macro+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/bind/PutMacro.java) ### Conditionals @@ -1240,7 +1240,7 @@ Executes the functions if/unless the field contains the value. If it is an array [Example in Playground](https://metafacture.org/playground/?example=all_contain) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixConditional.java+"+all_contain+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/conditional/AllContain.java) ##### `any_contain` @@ -1248,7 +1248,7 @@ Executes the functions if/unless the field contains the value. If it is an array [Example in Playground](https://metafacture.org/playground/?example=any_contain) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixConditional.java+"+any_contain+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/conditional/AnyContain.java) ##### `none_contain` @@ -1256,7 +1256,7 @@ Executes the functions if/unless the field does not contain the value. If it is [Example in Playground](https://metafacture.org/playground/?example=none_contain) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixConditional.java+"+none_contain+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/conditional/NoneContain.java) ##### `str_contain` @@ -1264,7 +1264,7 @@ Executes the functions if/unless the first string contains the second string. [Example in Playground](https://metafacture.org/playground/?example=str_contain) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixConditional.java+"+str_contain+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/conditional/StrContain.java) #### `equal` @@ -1274,7 +1274,7 @@ Executes the functions if/unless the field value equals the string. If it is an [Example in Playground](https://metafacture.org/playground/?example=all_equal) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixConditional.java+"+all_equal+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/conditional/AllEqual.java) ##### `any_equal` @@ -1282,7 +1282,7 @@ Executes the functions if/unless the field value equals the string. If it is an [Example in Playground](https://metafacture.org/playground/?example=any_equal) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixConditional.java+"+any_equal+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/conditional/AnyEqual.java) ##### `none_equal` @@ -1290,7 +1290,7 @@ Executes the functions if/unless the field value does not equal the string. If i [Example in Playground](https://metafacture.org/playground/?example=none_equal) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixConditional.java+"+none_equal+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/conditional/NoneEqual.java) ##### `str_equal` @@ -1298,7 +1298,7 @@ Executes the functions if/unless the first string equals the second string. [Example in Playground](https://metafacture.org/playground/?example=str_equal) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixConditional.java+"+str_equal+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/conditional/StrEqual.java) #### `exists` @@ -1310,7 +1310,7 @@ if exists("") [Example in Playground](https://metafacture.org/playground/?example=exists) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixConditional.java+"+exists+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/conditional/Exists.java) #### `greater_than` @@ -1318,7 +1318,7 @@ Executes the functions if/unless the field value is greater than the given value [Example in Playground](https://metafacture.org/playground/?example=greater_than) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixConditional.java+"+greater_than+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/conditional/GreaterThan.java) #### `in` @@ -1328,19 +1328,21 @@ _Also aliased as [`is_contained_in`](#is_contained_in)._ [Example in Playground](https://metafacture.org/playground/?example=in) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixConditional.java+"+in+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/conditional/In.java) #### `is_contained_in` _Alias for [`in`](#in)._ +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/conditional/IsContainedIn.java) + #### `is_array` Executes the functions if/unless the field value is an array. [Example in Playground](https://metafacture.org/playground/?example=is_array) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixConditional.java+"+is_array+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/conditional/IsArray.java) #### `is_empty` @@ -1348,7 +1350,7 @@ Executes the functions if/unless the field value is empty. [Example in Playground](https://metafacture.org/playground/?example=is_empty) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixConditional.java+"+is_empty+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/conditional/IsEmpty.java) #### `is_false` @@ -1356,7 +1358,7 @@ Executes the functions if/unless the field value equals `false` or `0`. [Example in Playground](https://metafacture.org/playground/?example=is_false) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixConditional.java+"+is_false+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/conditional/IsFalse.java) #### `is_hash` @@ -1364,7 +1366,7 @@ _Alias for [`is_object`](#is_object)._ [Example in Playground](https://metafacture.org/playground/?example=is_hash) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixConditional.java+"+is_hash+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/conditional/IsHash.java) #### `is_number` @@ -1372,7 +1374,7 @@ Executes the functions if/unless the field value is a number. [Example in Playground](https://metafacture.org/playground/?example=is_number) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixConditional.java+"+is_number+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/conditional/IsNumber.java) #### `is_object` @@ -1380,13 +1382,15 @@ Executes the functions if/unless the field value is a hash (object). _Also aliased as [`is_hash`](#is_hash)._ +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/conditional/IsObject.java) + #### `is_string` Executes the functions if/unless the field value is a string (and not a number). [Example in Playground](https://metafacture.org/playground/?example=is_string) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixConditional.java+"+is_string+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/conditional/IsString.java) #### `is_true` @@ -1394,7 +1398,7 @@ Executes the functions if/unless the field value equals `true` or `1`. [Example in Playground](https://metafacture.org/playground/?example=is_true) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixConditional.java+"+is_true+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/conditional/IsTrue.java) #### `less_than` @@ -1402,7 +1406,7 @@ Executes the functions if/unless the field value is less than the given value. [Example in Playground](https://metafacture.org/playground/?example=less_than) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixConditional.java+"+less_than+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/conditional/LessThan.java) #### `match` @@ -1412,7 +1416,7 @@ Executes the functions if/unless the field value matches the regular expression [Example in Playground](https://metafacture.org/playground/?example=all_match) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixConditional.java+"+all_match+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/conditional/AllMatch.java) ##### `any_match` @@ -1420,7 +1424,7 @@ Executes the functions if/unless the field value matches the regular expression [Example in Playground](https://metafacture.org/playground/?example=any_match) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixConditional.java+"+any_match+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/conditional/AnyMatch.java) ##### `none_match` @@ -1428,7 +1432,7 @@ Executes the functions if/unless the field value does not match the regular expr [Example in Playground](https://metafacture.org/playground/?example=none_match) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixConditional.java+"+none_match+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/conditional/NoneMatch.java) ##### `str_match` @@ -1436,7 +1440,7 @@ Executes the functions if/unless the string matches the regular expression patte [Example in Playground](https://metafacture.org/playground/?example=str_match) -[Java Code](https://github.com/search?type=code&q=repo:metafacture/metafacture-core+path:FixConditional.java+"+str_match+{") +[Java Code](https://github.com/metafacture/metafacture-core/blob/master/metafix/src/main/java/org/metafacture/metafix/conditional/StrMatch.java) ## Xtext diff --git a/metafix/src/main/java/org/metafacture/metafix/FixBind.java b/metafix/src/main/java/org/metafacture/metafix/FixBind.java index 69ddd77bc..b629f5fee 100644 --- a/metafix/src/main/java/org/metafacture/metafix/FixBind.java +++ b/metafix/src/main/java/org/metafacture/metafix/FixBind.java @@ -17,93 +17,39 @@ package org.metafacture.metafix; import org.metafacture.metafix.api.FixContext; +import org.metafacture.metafix.bind.*; // checkstyle-disable-line AvoidStarImport -import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Set; +@Deprecated(since = "7.1.0", forRemoval = true) public enum FixBind implements FixContext { list { @Override public void execute(final Metafix metafix, final Record record, final List params, final Map options, final RecordTransformer recordTransformer) { - final String scopeVariable = options.get("var"); - Value.asList(record.get(options.get("path")), a -> { - for (int i = 0; i < a.size(); ++i) { - final Value value = a.get(i); - - // with var -> keep full record in scope, add the var: - if (scopeVariable != null) { - record.put(scopeVariable, value, false); - recordTransformer.transform(record); - record.remove(scopeVariable); - } - // w/o var -> use the currently bound value as the record: - else { - final int index = i; - - value.matchType() - .ifHash(h -> { - final Record scopeRecord = new Record(); - scopeRecord.addAll(h); - - recordTransformer.transform(scopeRecord); - a.set(index, new Value(scopeRecord)); - }) - // TODO: bind to arrays (if that makes sense) and strings (access with '.') - .orElseThrow(); - } - } - }); + new org.metafacture.metafix.bind.List().execute(metafix, record, params, options, recordTransformer); } }, list_as { @Override public void execute(final Metafix metafix, final Record record, final List params, final Map options, final RecordTransformer recordTransformer) { - final Map lists = new HashMap<>(); - options.forEach((k, v) -> Value.asList(record.get(v), a -> lists.put(k, a))); - - final int size = lists.values().stream().mapToInt(a -> a.size()).max().orElse(0); - for (int i = 0; i < size; ++i) { - final int index = i; - - lists.forEach((k, v) -> { - final Value value = index < v.size() ? v.get(index) : null; - - if (value != null) { - record.put(k, value); - } - else { - record.remove(k); - } - }); - - recordTransformer.transform(record); - } - - lists.keySet().forEach(record::remove); + new ListAs().execute(metafix, record, params, options, recordTransformer); } }, once { - private final Map> executed = new HashMap<>(); - @Override public void execute(final Metafix metafix, final Record record, final List params, final Map options, final RecordTransformer recordTransformer) { - if (executed.computeIfAbsent(metafix, k -> new HashSet<>()).add(params.isEmpty() ? null : params.get(0))) { - recordTransformer.transform(record); - } + new Once().execute(metafix, record, params, options, recordTransformer); } }, put_macro { @Override public void execute(final Metafix metafix, final Record record, final List params, final Map options, final RecordTransformer recordTransformer) { - recordTransformer.setVars(options); - metafix.putMacro(params.get(0), recordTransformer); + new PutMacro().execute(metafix, record, params, options, recordTransformer); } } diff --git a/metafix/src/main/java/org/metafacture/metafix/FixCommand.java b/metafix/src/main/java/org/metafacture/metafix/FixCommand.java new file mode 100644 index 000000000..2e3a99941 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/FixCommand.java @@ -0,0 +1,37 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface FixCommand { + + /** + * Returns the Fix command name. + * + * @return Fix command name + */ + String value(); + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/FixConditional.java b/metafix/src/main/java/org/metafacture/metafix/FixConditional.java index 176a91410..0321af97d 100644 --- a/metafix/src/main/java/org/metafacture/metafix/FixConditional.java +++ b/metafix/src/main/java/org/metafacture/metafix/FixConditional.java @@ -17,183 +17,168 @@ package org.metafacture.metafix; import org.metafacture.metafix.api.FixPredicate; +import org.metafacture.metafix.conditional.*; // checkstyle-disable-line AvoidStarImport import java.util.List; import java.util.Map; +@Deprecated(since = "7.1.0", forRemoval = true) // checkstyle-disable-line ClassDataAbstractionCoupling|ClassFanOutComplexity public enum FixConditional implements FixPredicate { all_contain { @Override public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { - return testConditional(record, params, ALL, CONTAINS); + return new AllContain().test(metafix, record, params, options); } }, any_contain { @Override public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { - return testConditional(record, params, ANY, CONTAINS); + return new AnyContain().test(metafix, record, params, options); } }, none_contain { @Override public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { - return !any_contain.test(metafix, record, params, options); + return new NoneContain().test(metafix, record, params, options); } }, str_contain { @Override public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { - return testConditional(params, CONTAINS); + return new StrContain().test(metafix, record, params, options); } }, all_equal { @Override public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { - return testConditional(record, params, ALL, EQUALS); + return new AllEqual().test(metafix, record, params, options); } }, any_equal { @Override public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { - return testConditional(record, params, ANY, EQUALS); + return new AnyEqual().test(metafix, record, params, options); } }, none_equal { @Override public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { - return !any_equal.test(metafix, record, params, options); + return new NoneEqual().test(metafix, record, params, options); } }, str_equal { @Override public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { - return testConditional(params, EQUALS); + return new StrEqual().test(metafix, record, params, options); } }, exists { @Override public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { - return record.containsPath(params.get(0)); + return new Exists().test(metafix, record, params, options); } }, in { @Override public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { - final Value value1 = record.get(params.get(0)); - final Value value2 = record.get(params.get(1)); - - return value1 != null && value2 != null && value1.extractType((m, c) -> m - .ifArray(a1 -> value2.matchType() - .ifArray(a2 -> c.accept(a1.equals(a2))) - .orElse(v -> c.accept(false)) - ) - .ifHash(h1 -> value2.matchType() - .ifHash(h2 -> c.accept(h1.equals(h2))) - .orElse(v -> c.accept(false)) - ) - .ifString(s1 -> value2.matchType() - .ifArray(a2 -> c.accept(a2.stream().anyMatch(value1::equals))) - .ifHash(h2 -> c.accept(h2.containsField(s1))) - .ifString(s2 -> c.accept(s1.equals(s2))) - ) - ); + return new In().test(metafix, record, params, options); } }, is_contained_in { @Override public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { - return in.test(metafix, record, params, options); + return new IsContainedIn().test(metafix, record, params, options); } }, is_array { @Override public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { - return testConditional(record, params, Value::isArray); + return new IsArray().test(metafix, record, params, options); } }, is_empty { @Override public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { - return testConditional(record, params, IS_EMPTY); + return new IsEmpty().test(metafix, record, params, options); } }, is_false { @Override public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { - return testStringConditional(record, params, IS_FALSE); // TODO: strict=false + return new IsFalse().test(metafix, record, params, options); } }, is_hash { @Override public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { - return is_object.test(metafix, record, params, options); + return new IsHash().test(metafix, record, params, options); } }, is_number { @Override public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { - return testStringConditional(record, params, IS_NUMBER); + return new IsNumber().test(metafix, record, params, options); } }, is_object { @Override public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { - return testConditional(record, params, Value::isHash); + return new IsObject().test(metafix, record, params, options); } }, is_string { @Override public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { - return testConditional(record, params, Value::isString) && !is_number.test(metafix, record, params, options); + return new IsString().test(metafix, record, params, options); } }, is_true { @Override public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { - return testStringConditional(record, params, IS_TRUE); // TODO: strict=false + return new IsTrue().test(metafix, record, params, options); } }, all_match { @Override public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { - return testConditional(record, params, ALL, MATCHES); + return new AllMatch().test(metafix, record, params, options); } }, any_match { @Override public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { - return testConditional(record, params, ANY, MATCHES); + return new AnyMatch().test(metafix, record, params, options); } }, none_match { @Override public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { - return !any_match.test(metafix, record, params, options); + return new NoneMatch().test(metafix, record, params, options); } }, str_match { @Override public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { - return testConditional(params, MATCHES); + return new StrMatch().test(metafix, record, params, options); } }, greater_than { @Override public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { - return testConditional(record, params, ALL, GREATER_THAN); + return new GreaterThan().test(metafix, record, params, options); } }, less_than { @Override public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { - return testConditional(record, params, ALL, LESS_THAN); + return new LessThan().test(metafix, record, params, options); } } diff --git a/metafix/src/main/java/org/metafacture/metafix/FixMethod.java b/metafix/src/main/java/org/metafacture/metafix/FixMethod.java index c7132e37d..ad0211177 100644 --- a/metafix/src/main/java/org/metafacture/metafix/FixMethod.java +++ b/metafix/src/main/java/org/metafacture/metafix/FixMethod.java @@ -17,148 +17,70 @@ package org.metafacture.metafix; import org.metafacture.metafix.api.FixFunction; -import org.metafacture.metafix.maps.RdfMap; -import org.metafacture.metamorph.api.Maps; -import org.metafacture.metamorph.functions.ISBN; -import org.metafacture.metamorph.functions.Timestamp; -import org.metafacture.metamorph.functions.URLEncode; -import org.metafacture.metamorph.maps.FileMap; +import org.metafacture.metafix.method.field.*; // checkstyle-disable-line AvoidStarImport +import org.metafacture.metafix.method.record.*; // checkstyle-disable-line AvoidStarImport +import org.metafacture.metafix.method.script.*; // checkstyle-disable-line AvoidStarImport -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.File; -import java.io.IOException; -import java.util.Arrays; -import java.util.Base64; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Random; -import java.util.concurrent.atomic.LongAdder; -import java.util.function.Consumer; -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; -public enum FixMethod implements FixFunction { // checkstyle-disable-line ClassDataAbstractionCoupling|ClassFanOutComplexity +@Deprecated(since = "7.1.0", forRemoval = true) // checkstyle-disable-line ClassDataAbstractionCoupling|ClassFanOutComplexity +public enum FixMethod implements FixFunction { // SCRIPT-LEVEL METHODS: include { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - final String includeFile = params.get(0); - - if (!Metafix.isFixFile(includeFile)) { - throw new IllegalArgumentException("Not a Fix file: " + includeFile); - } - - // TODO: Catmandu load path - final String includePath = metafix.resolvePath(includeFile); - - metafix.getRecordTransformer(includePath).transform(record, options); + new Include().apply(metafix, record, params, options); } }, log { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - // does not support Catmandu log level option FATAL - - final String level = options.getOrDefault("level", "INFO"); - final Consumer consumer; - - switch (level) { - case "DEBUG": - consumer = LOG::debug; - break; - case "ERROR": - consumer = LOG::error; - break; - case "INFO": - consumer = LOG::info; - break; - case "WARN": - consumer = LOG::warn; - break; - default: - throw new IllegalArgumentException("Unsupported log level: " + level); - } - - consumer.accept(params.get(0)); + new Log().apply(metafix, record, params, options); } }, nothing { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - // do nothing + new Nothing().apply(metafix, record, params, options); } }, put_filemap { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - final String fileName = params.get(0); - final FileMap fileMap = new FileMap(); - - fileMap.setSeparator(options.getOrDefault(FILEMAP_SEPARATOR_OPTION, FILEMAP_DEFAULT_SEPARATOR)); - fileMap.setFile(metafix.resolvePath(fileName)); - - withOption(options, "allow_empty_values", fileMap::setAllowEmptyValues, this::getBoolean); - withOption(options, "compression", fileMap::setCompression); - withOption(options, "decompress_concatenated", fileMap::setDecompressConcatenated, this::getBoolean); - withOption(options, "encoding", fileMap::setEncoding); - withOption(options, "expected_columns", fileMap::setExpectedColumns, this::getInteger); - withOption(options, "ignore_pattern", fileMap::setIgnorePattern); - withOption(options, "key_column", fileMap::setKeyColumn, this::getInteger); - withOption(options, "value_column", fileMap::setValueColumn, this::getInteger); - - metafix.putMap(params.size() > 1 ? params.get(1) : fileName, fileMap); + new PutFileMap().apply(metafix, record, params, options); } }, put_map { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - metafix.putMap(params.get(0), options); + new PutMap().apply(metafix, record, params, options); } }, put_rdfmap { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - final String fileName = params.get(0); - final RdfMap rdfMap = new RdfMap(); - - rdfMap.setResource(fileName, metafix::resolvePath); - - withOption(options, RdfMap.TARGET, rdfMap::setTarget); - withOption(options, RdfMap.TARGET_LANGUAGE, rdfMap::setTargetLanguage); - withOption(options, RdfMap.SELECT, rdfMap::setSelect); - withOption(options, Maps.DEFAULT_MAP_KEY, rdfMap::setDefault); - - metafix.putMap(params.size() > 1 ? params.get(1) : fileName, rdfMap); + new PutRdfMap().apply(metafix, record, params, options); } }, put_var { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - metafix.getVars().put(params.get(0), params.get(1)); + new PutVar().apply(metafix, record, params, options); } }, put_vars { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - metafix.getVars().putAll(options); + new PutVars().apply(metafix, record, params, options); } }, to_var { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - final Value value = record.get(params.get(0)); - metafix.getVars().put(params.get(1), Value.isNull(value) ? options.getOrDefault(DEFAULT_OPTION, "") : value.asString()); + new ToVar().apply(metafix, record, params, options); } }, @@ -167,285 +89,133 @@ public void apply(final Metafix metafix, final Record record, final List add_array { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - final String field = params.get(0); - final Value newValue = newArray(params.subList(1, params.size()).stream().map(Value::new)); - record.set(field, newValue); - newValue.asArray().forEach(value -> value.withPathSet(newValue.getPath() + Value.FIELD_PATH_SEPARATOR + value.getPath())); + new AddArray().apply(metafix, record, params, options); } }, add_field { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - record.set(params.get(0), new Value(params.get(1))); + new AddField().apply(metafix, record, params, options); } }, add_hash { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - final String field = params.get(0); - final Value newValue = Value.newHash(h -> options.forEach((f, v) -> h.put(f, new Value(v)))); - record.set(field, newValue); + new AddHash().apply(metafix, record, params, options); } }, array { // array-from-hash @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - final String field = params.get(0); - - record.getList(field, a -> a.forEach(v -> v.matchType().ifHash(h -> { - record.remove(field); - - h.forEach((subField, value) -> { - record.addNested(field, new Value(subField)); - record.addNested(field, value.withPathSet(null)); - }); - }))); + new Array().apply(metafix, record, params, options); } }, call_macro { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - final String macroName = params.get(0); - final RecordTransformer recordTransformer = metafix.getMacro(macroName); - - if (recordTransformer != null) { - recordTransformer.transform(record, options); - } - else { - throw new IllegalArgumentException("Macro '" + macroName + "' undefined!"); - } + new CallMacro().apply(metafix, record, params, options); } }, copy_field { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - final String oldName = params.get(0); - final String newName = params.get(1); - - final Value oldValue = record.get(oldName); - if (!Value.isNull(oldValue)) { - oldValue.matchType() - .ifArray(a -> { - record.remove(newName); - a.forEach(v -> record.addNested(newName, v.withPathSet(null))); - }) - .orElse(v -> record.set(newName, v.withPathSet(null))); - } + new CopyField().apply(metafix, record, params, options); } }, format { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - final String field = params.get(0); - - record.getList(field, oldValues -> { - final String newValue = String.format(params.get(1), oldValues.stream().toArray()); - record.replace(field, new Value(Arrays.asList(new Value(newValue)))); - }); + new Format().apply(metafix, record, params, options); } }, hash { // hash-from-array @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - final String field = params.get(0); - - 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).asString(), a.get(i)); - } - }))); + new Hash().apply(metafix, record, params, options); } }, move_field { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - FixMethod.copy_field.apply(metafix, record, params, options); - record.remove(params.get(0)); + new MoveField().apply(metafix, record, params, options); } }, parse_text { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - final String field = params.get(0); - - record.getList(field, a -> a.forEach(v -> { - final Pattern p = Pattern.compile(params.get(1)); - final Matcher m = p.matcher(v.asString()); - if (m.matches()) { - record.remove(field); - - /** - * {@code Pattern.namedGroups()} not available as API, - * see https://stackoverflow.com/a/65012527. - * - * Assumptions: 1. Named groups are not escaped/quoted; - * 2. Named groups are not mixed with unnamed groups. - */ - final Matcher groupMatcher = NAMED_GROUP_PATTERN.matcher(p.pattern()); - final Value value = Value.newHash(h -> { - while (groupMatcher.find()) { - final String group = groupMatcher.group(1); - h.put(group, new Value(m.group(group))); - } - }); - - if (!value.asHash().isEmpty()) { - record.addNested(field, value); - } - else { - for (int i = 1; i <= m.groupCount(); i = i + 1) { - record.addNested(field, new Value(m.group(i))); - } - } - } - })); + new ParseText().apply(metafix, record, params, options); } }, paste { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - final String joinChar = options.get("join_char"); - final Value newValue = new Value(params.subList(1, params.size()).stream() - .filter(f -> literalString(f) || record.get(f) != null) - .map(f -> literalString(f) ? new Value(f.substring(1)) : Value.asList(record.get(f), null).asArray().get(0)) - .map(Value::asString).collect(Collectors.joining(joinChar != null ? joinChar : " "))); - record.set(params.get(0), newValue); - } - - private boolean literalString(final String s) { - return s.startsWith("~"); + new Paste().apply(metafix, record, params, options); } }, print_record { - private final Map scopedCounter = new HashMap<>(); - @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - final boolean internal = getBoolean(options, "internal"); - final boolean pretty = getBoolean(options, "pretty"); - - if (!params.isEmpty()) { - options.put("prefix", params.get(0)); - } - - withWriter(metafix, record, options, scopedCounter, c -> { - if (internal) { - if (pretty) { - record.forEach((f, v) -> c.accept(f + "=" + v)); - } - else { - c.accept(record.toString()); - } - } - else { - try { - c.accept(record.toJson(pretty)); - } - catch (final IOException e) { - // Log a warning? Print string representation instead? - } - } - }); + new PrintRecord().apply(metafix, record, params, options); } }, random { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - final String field = params.get(0); - final int max = getInteger(params, 1); - record.set(field, new Value(String.valueOf(RANDOM.nextInt(max)))); + new Random().apply(metafix, record, params, options); } }, reject { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - record.setReject(true); + new Reject().apply(metafix, record, params, options); } }, remove_field { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - params.forEach(p -> record.remove(p)); + new RemoveField().apply(metafix, record, params, options); } }, rename { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - final String search = params.get(1); - final String replace = params.get(2); - - final UnaryOperator operator = s -> s.replaceAll(search, replace); - - record.transform(params.get(0), (m, c) -> m - .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) - ); + new Rename().apply(metafix, record, params, options); } }, retain { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - record.retainFields(params); + new Retain().apply(metafix, record, params, options); } }, set_array { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - if (parentFieldExists(record, params.get(0))) { - add_array.apply(metafix, record, params, options); - } + new SetArray().apply(metafix, record, params, options); } }, set_field { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - if (parentFieldExists(record, params.get(0))) { - add_field.apply(metafix, record, params, options); - } + new SetField().apply(metafix, record, params, options); } }, set_hash { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - if (parentFieldExists(record, params.get(0))) { - add_hash.apply(metafix, record, params, options); - } + new SetHash().apply(metafix, record, params, options); } }, timestamp { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - final String field = params.get(0); - final Timestamp timestamp = new Timestamp(); - - withOption(options, "format", timestamp::setFormat); - withOption(options, "language", timestamp::setLanguage); - withOption(options, "timezone", timestamp::setTimezone); - - record.set(field, new Value(timestamp.process(null))); + new Timestamp().apply(metafix, record, params, options); } }, vacuum { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - record.removeEmptyValues(); + new Vacuum().apply(metafix, record, params, options); } }, @@ -456,301 +226,146 @@ public void apply(final Metafix metafix, final Record record, final List append { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - final String value = params.get(1); - record.transform(params.get(0), s -> s + value); + new Append().apply(metafix, record, params, options); } }, capitalize { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - record.transform(params.get(0), s -> s.substring(0, 1).toUpperCase() + s.substring(1)); + new Capitalize().apply(metafix, record, params, options); } }, count { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - record.transform(params.get(0), (m, c) -> m - .ifArray(a -> c.accept(new Value(a.size()))) - .ifHash(h -> c.accept(new Value(h.size()))) - ); + new Count().apply(metafix, record, params, options); } }, downcase { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - record.transform(params.get(0), s -> s.toLowerCase()); + new Downcase().apply(metafix, record, params, options); } }, filter { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - final Pattern search = Pattern.compile(params.get(1)); - final boolean invert = getBoolean(options, "invert"); - - final Predicate predicate = s -> search.matcher(s.asString()).find(); - - record.transform(params.get(0), (m, c) -> m - .ifArray(a -> c.accept(newArray(a.stream().filter(invert ? predicate.negate() : predicate)))) - ); + new Filter().apply(metafix, record, params, options); } }, flatten { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - record.transform(params.get(0), (m, c) -> m - .ifArray(a -> c.accept(newArray(flatten(a.stream())))) - ); + new Flatten().apply(metafix, record, params, options); } }, from_json { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - final String errorString = options.get(ERROR_STRING_OPTION); - final JsonValue.Parser parser = new JsonValue.Parser(); - - record.transform(params.get(0), (m, c) -> m - .ifString(s -> { - try { - c.accept(parser.parse(s)); - } - catch (final IOException e) { - c.accept(errorString != null ? new Value(errorString) : null); - } - }) - ); + new FromJson().apply(metafix, record, params, options); } }, index { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - final String search = params.get(1); - record.transform(params.get(0), s -> String.valueOf(s.indexOf(search))); // TODO: multiple + new Index().apply(metafix, record, params, options); } }, isbn { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - final ISBN isbn = new ISBN(); - - withOption(options, ERROR_STRING_OPTION, isbn::setErrorString); - withOption(options, "to", isbn::setTo); - withOption(options, "verify_check_digit", isbn::setVerifyCheckDigit); - - record.transform(params.get(0), isbn::process); + new Isbn().apply(metafix, record, params, options); } }, join_field { @Override 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.transform(params.get(0), (m, c) -> m - .ifArray(a -> c.accept(new Value(a.stream().map(Value::asString).collect(Collectors.joining(joinChar))))) - ); + new JoinField().apply(metafix, record, params, options); } }, lookup { - private final Map scopedCounter = new HashMap<>(); - @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - final Map map; - - if (params.size() <= 1) { - map = options; - } - else { - final String mapName = params.get(1); - - if (!metafix.getMapNames().contains(mapName)) { - if (mapName.contains(".") || mapName.contains(File.separator)) { - put_filemap.apply(metafix, record, Arrays.asList(mapName), options); - } - else { - // Probably an unknown internal map? Log a warning? - } - } - - map = metafix.getMap(mapName); - } - - final String defaultValue = options.getOrDefault("default", map.get(Maps.DEFAULT_MAP_KEY)); - final boolean delete = getBoolean(options, "delete"); - final boolean printUnknown = getBoolean(options, "print_unknown"); - - final Consumer> consumer = c -> record.transform(params.get(0), oldValue -> { - final String newValue = map.get(oldValue); - if (newValue != null) { - return newValue; - } - else { - if (c != null) { - c.accept(oldValue); - } - - return defaultValue != null ? defaultValue : delete ? null : oldValue; - } - }); - - if (printUnknown) { - options.putIfAbsent("append", "true"); - withWriter(metafix, record, options, scopedCounter, consumer); - } - else { - consumer.accept(null); - } + new Lookup().apply(metafix, record, params, options); } }, prepend { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - final String value = params.get(1); - record.transform(params.get(0), s -> value + s); + new Prepend().apply(metafix, record, params, options); } }, replace_all { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - final String search = params.get(1); - final String replace = params.get(2); - - record.transform(params.get(0), s -> s.replaceAll(search, replace)); + new ReplaceAll().apply(metafix, record, params, options); } }, reverse { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - record.transform(params.get(0), (m, c) -> m - .ifArray(a -> { - final List list = a.stream().collect(Collectors.toList()); - Collections.reverse(list); - c.accept(new Value(list)); - }) - .ifString(s -> c.accept(new Value(new StringBuilder(s).reverse().toString()))) - ); + new Reverse().apply(metafix, record, params, options); } }, sort_field { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - 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.transform(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())))) - ); + new SortField().apply(metafix, record, params, options); } }, split_field { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - final String splitChar = params.size() > 1 ? params.get(1) : "\\s+"; - final Pattern splitPattern = Pattern.compile(splitChar); - - final Function splitFunction = s -> - newArray(Arrays.stream(splitPattern.split(s)).map(Value::new)); - - record.transform(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))) - ); + new SplitField().apply(metafix, record, params, options); } }, substring { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - final int offset = getInteger(params, 1); - final Integer end = params.size() > 2 ? offset + getInteger(params, 2) : null; - // TODO: final String replacement = params.size() > 3 ? params.get(3) : null; - - record.transform(params.get(0), s -> { - final int length = s.length(); - return offset > length ? s : end == null || end > length ? s.substring(offset) : s.substring(offset, end); - }); + new Substring().apply(metafix, record, params, options); } }, sum { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - record.transform(params.get(0), (m, c) -> m - .ifArray(a -> c.accept(new Value(a.stream().map(Value::asString).mapToInt(Integer::parseInt).sum()))) - ); + new Sum().apply(metafix, record, params, options); } }, to_base64 { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - final boolean urlSafe = getBoolean(options, "url_safe"); - final Base64.Encoder encoder = urlSafe ? Base64.getUrlEncoder() : Base64.getEncoder(); - - record.transform(params.get(0), s -> encoder.encodeToString(s.getBytes())); + new ToBase64().apply(metafix, record, params, options); } }, to_json { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - final String errorString = options.get(ERROR_STRING_OPTION); - final boolean pretty = getBoolean(options, "pretty"); - - record.transform(params.get(0), (m, c) -> m - .orElse(v -> { - try { - c.accept(new Value(v.toJson(pretty))); - } - catch (final IOException e) { - c.accept(errorString != null ? new Value(errorString) : null); - } - }) - ); + new ToJson().apply(metafix, record, params, options); } }, trim { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - record.transform(params.get(0), String::trim); + new Trim().apply(metafix, record, params, options); } }, uniq { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - record.transform(params.get(0), (m, c) -> m - .ifArray(a -> c.accept(newArray(unique(a.stream())))) - ); + new Uniq().apply(metafix, record, params, options); } }, upcase { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - record.transform(params.get(0), s -> s.toUpperCase()); + new Upcase().apply(metafix, record, params, options); } }, uri_encode { @Override public void apply(final Metafix metafix, final Record record, final List params, final Map options) { - final URLEncode urlEncoder = new URLEncode(); - withOption(options, "safe_chars", urlEncoder::setSafeChars); - withOption(options, "plus_for_space", urlEncoder::setPlusForSpace, this::getBoolean); - - record.transform(params.get(0), urlEncoder::process); + new UriEncode().apply(metafix, record, params, options); } - }; - - private static final Pattern NAMED_GROUP_PATTERN = Pattern.compile("\\(\\?<(.+?)>"); - - private static final String FILEMAP_SEPARATOR_OPTION = "sep_char"; - private static final String FILEMAP_DEFAULT_SEPARATOR = ","; - - private static final String DEFAULT_OPTION = "default"; - private static final String ERROR_STRING_OPTION = "error_string"; - - private static final Random RANDOM = new Random(); - - private static final Logger LOG = LoggerFactory.getLogger(FixMethod.class); + } } diff --git a/metafix/src/main/java/org/metafacture/metafix/Metafix.java b/metafix/src/main/java/org/metafacture/metafix/Metafix.java index ba5f5c142..0dd0562e1 100644 --- a/metafix/src/main/java/org/metafacture/metafix/Metafix.java +++ b/metafix/src/main/java/org/metafacture/metafix/Metafix.java @@ -28,6 +28,7 @@ import org.metafacture.framework.annotations.Out; import org.metafacture.framework.helpers.DefaultStreamReceiver; import org.metafacture.mangling.StreamFlattener; +import org.metafacture.metafix.api.FixRegistry; import org.metafacture.metafix.fix.Expression; import org.metafacture.metamorph.api.Maps; @@ -52,6 +53,7 @@ import java.util.List; import java.util.Map; import java.util.function.BiConsumer; +import java.util.function.Function; /** * Transforms a data stream sent via the {@link StreamReceiver} interface. Uses @@ -83,6 +85,7 @@ public class Metafix implements StreamPipe, Maps { private static final String ENTITIES_NOT_BALANCED = "Entity starts and ends are not balanced"; private final Deque entityCountStack = new LinkedList<>(); + private final FixRegistry registry = new FixRegistry(); private final List resources = new ArrayList<>(); private final List expressions = new ArrayList<>(); private final Map> maps = new HashMap<>(); @@ -117,7 +120,17 @@ public Metafix() { * @param vars the Fix variables as a Map */ public Metafix(final Map vars) { - init(vars); + this(m -> vars); + } + + /** + * Creates an instance of {@link Metafix}. + * + * @param function an optional function that accepts the Metafix instance + * and returns the Fix variables as a Map, or {@code null} + */ + public Metafix(final Function> function) { + init(function); recordTransformer = null; } @@ -141,7 +154,20 @@ public Metafix(final String fixDef) throws IOException { * @throws IOException if an I/O error occurs */ public Metafix(final String fixDef, final Map vars) throws IOException { - init(vars); + this(fixDef, m -> vars); + } + + /** + * Creates an instance of {@link Metafix}. + * + * @param fixDef the Fix definition + * @param function an optional function that accepts the Metafix instance + * and returns the Fix variables as a Map, or {@code null} + * + * @throws IOException if an I/O error occurs + */ + public Metafix(final String fixDef, final Function> function) throws IOException { + init(function); if (isFixFile(fixDef)) { fixFile = fixDef; @@ -170,11 +196,22 @@ public Metafix(final Reader fixDef) { * @param vars the Fix variables as a Map */ public Metafix(final Reader fixDef, final Map vars) { - init(vars); + this(fixDef, m -> vars); + } + + /** + * Creates an instance of {@link Metafix}. + * + * @param fixDef the Fix definition + * @param function an optional function that accepts the Metafix instance + * and returns the Fix variables as a Map, or {@code null} + */ + public Metafix(final Reader fixDef, final Function> function) { + init(function); recordTransformer = getRecordTransformer(fixDef); } - private void init(final Map newVars) { + private void init(final Function> function) { flattener.setReceiver(new DefaultStreamReceiver() { @Override @@ -187,10 +224,22 @@ public void literal(final String name, final String value) { }); - vars.putAll(newVars); + if (function != null) { + final Map newVars = function.apply(this); + if (newVars != null) { + vars.putAll(newVars); + } + } } - /*package-private*/ static boolean isFixFile(final String fixDef) { + /** + * Checks whether the given Fix definition indicates a Fix file. + * + * @param fixDef the Fix definition + * + * @return true if the given Fix definition indicates a Fix file + */ + public static boolean isFixFile(final String fixDef) { return fixDef.endsWith(FIX_EXTENSION); } @@ -301,6 +350,15 @@ public List getExpressions() { return expressions; } + /** + * Returns the Fix registry. + * + * @return the Fix registry + */ + public FixRegistry getRegistry() { + return registry; + } + @Override public void startRecord(final String identifier) { currentRecord = new Record(); diff --git a/metafix/src/main/java/org/metafacture/metafix/RecordTransformer.java b/metafix/src/main/java/org/metafacture/metafix/RecordTransformer.java index 4809cd490..61b696f67 100644 --- a/metafix/src/main/java/org/metafacture/metafix/RecordTransformer.java +++ b/metafix/src/main/java/org/metafacture/metafix/RecordTransformer.java @@ -22,6 +22,7 @@ import org.metafacture.metafix.api.FixContext; import org.metafacture.metafix.api.FixFunction; import org.metafacture.metafix.api.FixPredicate; +import org.metafacture.metafix.api.FixRegistry; import org.metafacture.metafix.fix.Do; import org.metafacture.metafix.fix.ElsIf; import org.metafacture.metafix.fix.Else; @@ -62,6 +63,7 @@ public class RecordTransformer { // checkstyle-disable-line ClassFanOutComplexit private static final Logger LOG = LoggerFactory.getLogger(RecordTransformer.class); + private final FixRegistry registry; private final List> consumers = new LinkedList<>(); private final List> vars = new ArrayList<>(Collections.nCopies(Vars.values().length, null)); private final Metafix metafix; @@ -82,6 +84,7 @@ private enum Vars { private RecordTransformer(final Metafix metafix, final List expressions, final RecordTransformer parent) { this.metafix = metafix; this.parent = parent; + this.registry = metafix.getRegistry(); expressions.forEach(e -> { final Params params = new Params(e.getParams(), this); @@ -143,7 +146,7 @@ public void transform(final Record record) { private void processDo(final Do expression, final Params params, final Options options) { processFix(() -> executionExceptionMessage(expression), () -> { - final FixContext context = getInstance(expression.getName(), FixContext.class, FixBind::valueOf); + final FixContext context = getInstance(expression.getName(), FixContext.class, registry::getBind); final RecordTransformer recordTransformer = childTransformer(expression.getElements()); return record -> context.execute(metafix, record, params.resolve(), options.resolve(), recordTransformer); @@ -158,10 +161,10 @@ private void processIf(final If ifExpression, final Params ifParams, final Optio final Supplier elseMessageSupplier = () -> executionExceptionMessage(elseExpression, elseExpression.eResource()); processFix(() -> executionExceptionMessage(ifExpression, ifExpression.eResource()), () -> { - final FixPredicate ifPredicate = getInstance(ifExpression.getName(), FixPredicate.class, FixConditional::valueOf); + final FixPredicate ifPredicate = getInstance(ifExpression.getName(), FixPredicate.class, registry::getConditional); final RecordTransformer ifTransformer = childTransformer(ifExpression.getElements()); - final List elseIfPredicates = mapList(elseIfExpressions, e -> getInstance(e.getName(), FixPredicate.class, FixConditional::valueOf)); + final List elseIfPredicates = mapList(elseIfExpressions, e -> getInstance(e.getName(), FixPredicate.class, registry::getConditional)); final List elseIfParamsList = mapList(elseIfExpressions, e -> new Params(e.getParams(), this)); final List elseIfOptionsList = mapList(elseIfExpressions, e -> new Options(e.getOptions(), this)); final List elseIfTransformers = mapList(elseIfExpressions, e -> childTransformer(e.getElements())); @@ -200,7 +203,7 @@ private void processIf(final If ifExpression, final Params ifParams, final Optio private void processUnless(final Unless expression, final Params params, final Options options) { processFix(() -> executionExceptionMessage(expression, expression.eResource()), () -> { - final FixPredicate predicate = getInstance(expression.getName(), FixPredicate.class, FixConditional::valueOf); + final FixPredicate predicate = getInstance(expression.getName(), FixPredicate.class, registry::getConditional); final RecordTransformer recordTransformer = childTransformer(expression.getElements()); return record -> { @@ -213,7 +216,7 @@ private void processUnless(final Unless expression, final Params params, final O private void processFunction(final MethodCall expression, final Params params, final Options options) { processFix(() -> executionExceptionMessage(expression), () -> { - final FixFunction function = getInstance(expression.getName(), FixFunction.class, FixMethod::valueOf); + final FixFunction function = getInstance(expression.getName(), FixFunction.class, registry::getMethod); return record -> function.apply(metafix, record, params.resolve(), options.resolve()); }); } @@ -299,7 +302,12 @@ private String executionExceptionMessage(final EObject object, final Resource re resource.getURI(), node.getStartLine(), NodeModelUtils.getTokenText(node)); } - /*package-private*/ void setVars(final Map staticVars) { + /** + * Sets static variables. + * + * @param staticVars the static variables + */ + public void setVars(final Map staticVars) { setVars(Vars.STATIC, staticVars); } diff --git a/metafix/src/main/java/org/metafacture/metafix/Value.java b/metafix/src/main/java/org/metafacture/metafix/Value.java index 5cca2c488..52b03ec67 100644 --- a/metafix/src/main/java/org/metafacture/metafix/Value.java +++ b/metafix/src/main/java/org/metafacture/metafix/Value.java @@ -422,7 +422,14 @@ public String getPath() { return path; } - /*package-private*/ Value withPathSet(final String p) { + /** + * Sets the value's path. + * + * @param p the path + * + * @return the Value + */ + public Value withPathSet(final String p) { this.path = p; return this; } @@ -782,7 +789,14 @@ public void remove(final int index) { list.remove(index); } - /*package-private*/ void set(final int index, final Value value) { + /** + * Sets the Array element at the given index to the given Value and + * appends the index number to its path. + * + * @param index the index + * @param value the Value + */ + public void set(final int index, final Value value) { list.set(index, value.withPathAppend(index + 1)); } @@ -893,7 +907,14 @@ public void put(final String field, final Value value) { put(field, value, true); } - /*package-private*/ void put(final String field, final Value value, final boolean appendToPath) { + /** + * Adds a field/value pair to this hash, provided it's not {@link #isNull(Value) null}. + * + * @param field the field name + * @param value the metadata value + * @param appendToPath whether to append the field name to the Value's path + */ + public void put(final String field, final Value value, final boolean appendToPath) { if (!isNull(value)) { map.put(field, appendToPath ? value.withPathAppend(field) : value); } diff --git a/metafix/src/main/java/org/metafacture/metafix/api/FixFunction.java b/metafix/src/main/java/org/metafacture/metafix/api/FixFunction.java index f3033513f..95411b388 100644 --- a/metafix/src/main/java/org/metafacture/metafix/api/FixFunction.java +++ b/metafix/src/main/java/org/metafacture/metafix/api/FixFunction.java @@ -36,6 +36,9 @@ @FunctionalInterface public interface FixFunction { + String DEFAULT_OPTION = "default"; + String ERROR_STRING_OPTION = "error_string"; + /** * Applies the Fix function. * diff --git a/metafix/src/main/java/org/metafacture/metafix/api/FixRegistry.java b/metafix/src/main/java/org/metafacture/metafix/api/FixRegistry.java new file mode 100644 index 000000000..3a23e1ac0 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/api/FixRegistry.java @@ -0,0 +1,418 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.api; + +import org.metafacture.commons.ResourceUtil; +import org.metafacture.commons.reflection.ReflectionUtil; +import org.metafacture.framework.MetafactureException; +import org.metafacture.metafix.FixCommand; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.JarURLConnection; +import java.net.URL; +import java.net.URLConnection; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.stream.Stream; + +public class FixRegistry { + + private static final String FILE_SEPARATOR = "/"; + private static final String PACKAGE_SEPARATOR = "."; + + private static final String CLASS_FILE_EXTENSION = ".class"; + + private static final String PROPERTIES_LOCATION = "fix-commands.properties"; + + private static final Map>> CACHE = new ConcurrentHashMap<>(); + + private final Registry binds = new Registry<>(FixContext.class, "bind"); + private final Registry methods = new Registry<>(FixFunction.class, "method"); + private final Registry conditionals = new Registry<>(FixPredicate.class, "conditional"); + + private final Set> registries = Set.of(methods, conditionals, binds); + + private final ClassLoader loader = ReflectionUtil.getContextClassLoader(); + + /** + * Creates an instance of {@link FixRegistry}. {@link #registerProperties(String) Registers} + * all Fix commands found in any {@value PROPERTIES_LOCATION} files. + */ + public FixRegistry() { + registerProperties(PROPERTIES_LOCATION); + } + + private void registerCommands(final String key, final Function>> function) { + loadCommands(key, function).forEach(this::registerCommand); + } + + private Map> loadCommands(final String key, final Function>> function) { + return CACHE.computeIfAbsent(key, function); + } + + private void getResources(final String name, final Consumer consumer) { + try { + loader.getResources(name).asIterator().forEachRemaining(consumer); + } + catch (final IOException e) { + throw new MetafactureException("Unable to load resources: " + name, e); + } + } + + /** + * Registers Fix commands from the given properties file. If the property + * value is empty, {@link #registerPackage(String) registers} the package + * given in the property key, otherwise registers the class given in the + * property value under the Fix command name given in the property key. + * + * @param propertiesName the properties file + */ + public void registerProperties(final String propertiesName) { + registerCommands(propertiesName, this::loadProperties); + } + + private Map> loadProperties(final String propertiesName) { + final Map> map = new HashMap<>(); + + getResources(propertiesName, u -> { + try { + ResourceUtil.loadProperties(u).forEach((k, v) -> { + final String key = k.toString(); + final String value = v.toString(); + + if (value.isEmpty()) { + map.putAll(loadCommands(key, this::loadPackage)); + } + else { + try { + map.put(key, loader.loadClass(value)); + } + catch (final ClassNotFoundException e) { + throw new MetafactureException("Class not found: " + value, e); + } + } + }); + } + catch (final IOException e) { + throw new MetafactureException("Unable to load properties: " + u, e); + } + }); + + return map; + } + + /** + * Registers Fix commands from the given package name. Only classes + * annotated with the {@link FixCommand} annotation are considered. + * + * @param packageName the package name + */ + public void registerPackage(final String packageName) { + registerCommands(packageName, this::loadPackage); + } + + private Map> loadPackage(final String packageName) { + final Map> map = new HashMap<>(); + + final String directoryName = packageName.replace(PACKAGE_SEPARATOR, FILE_SEPARATOR); + + getResources(directoryName, u -> { + try { + final URLConnection connection = u.openConnection(); + + if (connection instanceof JarURLConnection) { + final JarURLConnection jarConnection = (JarURLConnection) connection; + + try (JarFile jarFile = jarConnection.getJarFile()) { + loadPackage(map, jarFile.stream().map(JarEntry::getName) + .filter(f -> { + final int index = f.lastIndexOf(FILE_SEPARATOR); + return index > 0 && directoryName.equals(f.substring(0, index)); + }) + .map(f -> f.replace(FILE_SEPARATOR, PACKAGE_SEPARATOR))); + } + } + else { + try ( + InputStream stream = connection.getInputStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(stream)) + ) { + loadPackage(map, reader.lines().map(l -> packageName + PACKAGE_SEPARATOR + l)); + } + } + } + catch (final IOException e) { + throw new MetafactureException("Unable to load package: " + u, e); + } + }); + + return map; + } + + private void loadPackage(final Map> map, final Stream stream) { + stream.filter(f -> f.endsWith(CLASS_FILE_EXTENSION)).forEach(f -> { + final String className = f.substring(0, f.lastIndexOf(CLASS_FILE_EXTENSION)); + + try { + final Class clazz = loader.loadClass(className); + final String name = getCommandName(clazz); + + if (name != null) { + map.put(name, clazz); + } + } + catch (final ClassNotFoundException e) { + throw new MetafactureException("Class not found: " + className, e); + } + }); + } + + private String getCommandName(final Class clazz) { + final FixCommand annotation = clazz.getAnnotation(FixCommand.class); + return annotation != null ? Objects.requireNonNull(annotation.value()) : null; + } + + /** + * Registers the given class as Fix command under the Fix command name given + * by the {@link FixCommand} annotation. + * + * @param clazz the class + * + * @return the Fix command name + * + * @throws IllegalArgumentException if the class is not annotated with the + * {@link FixCommand} annotation + */ + public String registerCommand(final Class clazz) { + final String name = getCommandName(clazz); + + if (name != null) { + return registerCommand(name, clazz) ? name : null; + } + else { + throw new IllegalArgumentException("Fix command annotation missing: " + clazz); + } + } + + /** + * Registers the given class as Fix command under the given Fix command name. + * + * @param the Fix command type + * @param name the Fix command name + * @param clazz the class + * + * @return false if the class has already been registered under the name + * + * @throws IllegalArgumentException if a different class has already been + * registered under the name + * + * @throws IllegalArgumentException if the Fix command type is not supported + */ + public boolean registerCommand(final String name, final Class clazz) { + Objects.requireNonNull(name); + Objects.requireNonNull(clazz); + + for (final Registry registry : registries) { + final Class currentClass = registry.get(name); + if (currentClass != null) { + if (currentClass.equals(clazz)) { + return false; + } + + throw new IllegalArgumentException("Fix " + registry.getTypeName() + " already registered: " + name); + } + } + + for (final Registry registry : registries) { + if (registry.getTypeClass().isAssignableFrom(clazz)) { + @SuppressWarnings("unchecked") // protected by isAssignableFrom check + final Registry castedRegistry = (Registry) registry; + + castedRegistry.put(name, clazz); + return true; + } + } + + throw new IllegalArgumentException("Unsupported Fix command type: " + clazz); + } + + /** + * Checks whether a Fix command is registered under the given name. + * + * @param name the Fix command name + * + * @return true if a Fix command is registered under the given name + */ + public boolean isRegisteredCommand(final String name) { + return registries.stream().anyMatch(r -> r.containsKey(name)); + } + + private T getCommand(final Registry registry, final String name) { + final Class clazz = registry.get(name); + if (clazz == null) { + throw new IllegalArgumentException("Unsupported Fix " + registry.getTypeName() + ": " + name); + } + + try { + return clazz.getDeclaredConstructor().newInstance(); + } + catch (final ReflectiveOperationException e) { + throw new MetafactureException(e); + } + } + + /** + * Returns the Fix bind registered under the given name. + * + * @param name the Fix command name + * + * @return the Fix bind + * + * @throws IllegalArgumentException if the Fix command name is not a + * registered bind + */ + public FixContext getBind(final String name) { + return getCommand(binds, name); + } + + /** + * Returns the Fix conditional registered under the given name. + * + * @param name the Fix command name + * + * @return the Fix conditional + * + * @throws IllegalArgumentException if the Fix command name is not a + * registered conditional + */ + public FixPredicate getConditional(final String name) { + return getCommand(conditionals, name); + } + + /** + * Returns the Fix method registered under the given name. + * + * @param name the Fix command name + * + * @return the Fix method + * + * @throws IllegalArgumentException if the Fix command name is not a + * registered method + */ + public FixFunction getMethod(final String name) { + return getCommand(methods, name); + } + + private Class unregisterCommand(final Registry registry, final String name) { + final Class clazz = registry.remove(name); + if (clazz == null) { + throw new IllegalArgumentException("Fix " + registry.getTypeName() + " not registered: " + name); + } + + return clazz; + } + + /** + * Unregisters the Fix bind registered under the given name. + * + * @param name the Fix command name + * + * @return the previously registered Fix bind + * + * @throws IllegalArgumentException if the Fix command name is not a + * registered bind + */ + public Class unregisterBind(final String name) { + return unregisterCommand(binds, name); + } + + /** + * Unregisters the Fix conditional registered under the given name. + * + * @param name the Fix command name + * + * @return the previously registered Fix conditional + * + * @throws IllegalArgumentException if the Fix command name is not a + * registered conditional + */ + public Class unregisterConditional(final String name) { + return unregisterCommand(conditionals, name); + } + + /** + * Unregisters the Fix method registered under the given name. + * + * @param name the Fix command name + * + * @return the previously registered Fix method + * + * @throws IllegalArgumentException if the Fix command name is not a + * registered method + */ + public Class unregisterMethod(final String name) { + return unregisterCommand(methods, name); + } + + private static class Registry { + + private final Map> registry = new HashMap<>(); + private final Class typeClass; + private final String typeName; + + private Registry(final Class typeClass, final String typeName) { + this.typeClass = typeClass; + this.typeName = typeName; + } + + private Class getTypeClass() { + return typeClass; + } + + private String getTypeName() { + return typeName; + } + + private void put(final String name, final Class clazz) { + registry.put(name, clazz); + } + + private boolean containsKey(final String name) { + return registry.containsKey(name); + } + + private Class get(final String name) { + return registry.get(name); + } + + private Class remove(final String name) { + return registry.remove(name); + } + + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/bind/List.java b/metafix/src/main/java/org/metafacture/metafix/bind/List.java new file mode 100644 index 000000000..e7eecbf8e --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/bind/List.java @@ -0,0 +1,69 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.bind; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.RecordTransformer; +import org.metafacture.metafix.Value; +import org.metafacture.metafix.api.FixContext; + +import java.util.Map; + +@FixCommand("list") +public class List implements FixContext { + + /** + * Creates an instance of {@link List}. + */ + public List() { + } + + @Override + public void execute(final Metafix metafix, final Record record, final java.util.List params, final Map options, final RecordTransformer recordTransformer) { + final String scopeVariable = options.get("var"); + Value.asList(record.get(options.get("path")), a -> { + for (int i = 0; i < a.size(); ++i) { + final Value value = a.get(i); + + // with var -> keep full record in scope, add the var: + if (scopeVariable != null) { + record.put(scopeVariable, value, false); + recordTransformer.transform(record); + record.remove(scopeVariable); + } + // w/o var -> use the currently bound value as the record: + else { + final int index = i; + + value.matchType() + .ifHash(h -> { + final Record scopeRecord = new Record(); + scopeRecord.addAll(h); + + recordTransformer.transform(scopeRecord); + a.set(index, new Value(scopeRecord)); + }) + // TODO: bind to arrays (if that makes sense) and strings (access with '.') + .orElseThrow(); + } + } + }); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/bind/ListAs.java b/metafix/src/main/java/org/metafacture/metafix/bind/ListAs.java new file mode 100644 index 000000000..6a005f1e7 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/bind/ListAs.java @@ -0,0 +1,65 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.bind; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.RecordTransformer; +import org.metafacture.metafix.Value; +import org.metafacture.metafix.api.FixContext; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@FixCommand("list_as") +public class ListAs implements FixContext { + + /** + * Creates an instance of {@link ListAs}. + */ + public ListAs() { + } + + @Override + public void execute(final Metafix metafix, final Record record, final List params, final Map options, final RecordTransformer recordTransformer) { + final Map lists = new HashMap<>(); + options.forEach((k, v) -> Value.asList(record.get(v), a -> lists.put(k, a))); + + final int size = lists.values().stream().mapToInt(a -> a.size()).max().orElse(0); + for (int i = 0; i < size; ++i) { + final int index = i; + + lists.forEach((k, v) -> { + final Value value = index < v.size() ? v.get(index) : null; + + if (value != null) { + record.put(k, value); + } + else { + record.remove(k); + } + }); + + recordTransformer.transform(record); + } + + lists.keySet().forEach(record::remove); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/bind/Once.java b/metafix/src/main/java/org/metafacture/metafix/bind/Once.java new file mode 100644 index 000000000..9315ac808 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/bind/Once.java @@ -0,0 +1,49 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.bind; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.RecordTransformer; +import org.metafacture.metafix.api.FixContext; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +@FixCommand("once") +public class Once implements FixContext { + + private static final Map> EXECUTED = new HashMap<>(); + + /** + * Creates an instance of {@link Once}. + */ + public Once() { + } + + @Override + public void execute(final Metafix metafix, final Record record, final List params, final Map options, final RecordTransformer recordTransformer) { + if (EXECUTED.computeIfAbsent(metafix, k -> new HashSet<>()).add(params.isEmpty() ? null : params.get(0))) { + recordTransformer.transform(record); + } + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/bind/PutMacro.java b/metafix/src/main/java/org/metafacture/metafix/bind/PutMacro.java new file mode 100644 index 000000000..5e4c701a5 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/bind/PutMacro.java @@ -0,0 +1,43 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.bind; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.RecordTransformer; +import org.metafacture.metafix.api.FixContext; + +import java.util.List; +import java.util.Map; + +@FixCommand("put_macro") +public class PutMacro implements FixContext { + + /** + * Creates an instance of {@link PutMacro}. + */ + public PutMacro() { + } + + @Override + public void execute(final Metafix metafix, final Record record, final List params, final Map options, final RecordTransformer recordTransformer) { + recordTransformer.setVars(options); + metafix.putMacro(params.get(0), recordTransformer); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/conditional/AllContain.java b/metafix/src/main/java/org/metafacture/metafix/conditional/AllContain.java new file mode 100644 index 000000000..8d226ac71 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/conditional/AllContain.java @@ -0,0 +1,41 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.conditional; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixPredicate; + +import java.util.List; +import java.util.Map; + +@FixCommand("all_contain") +public class AllContain implements FixPredicate { + + /** + * Creates an instance of {@link AllContain}. + */ + public AllContain() { + } + + @Override + public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { + return testConditional(record, params, ALL, CONTAINS); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/conditional/AllEqual.java b/metafix/src/main/java/org/metafacture/metafix/conditional/AllEqual.java new file mode 100644 index 000000000..dc5434389 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/conditional/AllEqual.java @@ -0,0 +1,41 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.conditional; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixPredicate; + +import java.util.List; +import java.util.Map; + +@FixCommand("all_equal") +public class AllEqual implements FixPredicate { + + /** + * Creates an instance of {@link AllEqual}. + */ + public AllEqual() { + } + + @Override + public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { + return testConditional(record, params, ALL, EQUALS); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/conditional/AllMatch.java b/metafix/src/main/java/org/metafacture/metafix/conditional/AllMatch.java new file mode 100644 index 000000000..0093feb75 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/conditional/AllMatch.java @@ -0,0 +1,41 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.conditional; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixPredicate; + +import java.util.List; +import java.util.Map; + +@FixCommand("all_match") +public class AllMatch implements FixPredicate { + + /** + * Creates an instance of {@link AllMatch}. + */ + public AllMatch() { + } + + @Override + public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { + return testConditional(record, params, ALL, MATCHES); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/conditional/AnyContain.java b/metafix/src/main/java/org/metafacture/metafix/conditional/AnyContain.java new file mode 100644 index 000000000..850bae7e9 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/conditional/AnyContain.java @@ -0,0 +1,41 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.conditional; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixPredicate; + +import java.util.List; +import java.util.Map; + +@FixCommand("any_contain") +public class AnyContain implements FixPredicate { + + /** + * Creates an instance of {@link AnyContain}. + */ + public AnyContain() { + } + + @Override + public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { + return testConditional(record, params, ANY, CONTAINS); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/conditional/AnyEqual.java b/metafix/src/main/java/org/metafacture/metafix/conditional/AnyEqual.java new file mode 100644 index 000000000..a463898ec --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/conditional/AnyEqual.java @@ -0,0 +1,41 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.conditional; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixPredicate; + +import java.util.List; +import java.util.Map; + +@FixCommand("any_equal") +public class AnyEqual implements FixPredicate { + + /** + * Creates an instance of {@link AnyEqual}. + */ + public AnyEqual() { + } + + @Override + public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { + return testConditional(record, params, ANY, EQUALS); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/conditional/AnyMatch.java b/metafix/src/main/java/org/metafacture/metafix/conditional/AnyMatch.java new file mode 100644 index 000000000..e91337d99 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/conditional/AnyMatch.java @@ -0,0 +1,41 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.conditional; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixPredicate; + +import java.util.List; +import java.util.Map; + +@FixCommand("any_match") +public class AnyMatch implements FixPredicate { + + /** + * Creates an instance of {@link AnyMatch}. + */ + public AnyMatch() { + } + + @Override + public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { + return testConditional(record, params, ANY, MATCHES); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/conditional/Exists.java b/metafix/src/main/java/org/metafacture/metafix/conditional/Exists.java new file mode 100644 index 000000000..db3209d2e --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/conditional/Exists.java @@ -0,0 +1,41 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.conditional; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixPredicate; + +import java.util.List; +import java.util.Map; + +@FixCommand("exists") +public class Exists implements FixPredicate { + + /** + * Creates an instance of {@link Exists}. + */ + public Exists() { + } + + @Override + public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { + return record.containsPath(params.get(0)); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/conditional/GreaterThan.java b/metafix/src/main/java/org/metafacture/metafix/conditional/GreaterThan.java new file mode 100644 index 000000000..c313224a9 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/conditional/GreaterThan.java @@ -0,0 +1,41 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.conditional; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixPredicate; + +import java.util.List; +import java.util.Map; + +@FixCommand("greater_than") +public class GreaterThan implements FixPredicate { + + /** + * Creates an instance of {@link GreaterThan}. + */ + public GreaterThan() { + } + + @Override + public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { + return testConditional(record, params, ALL, GREATER_THAN); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/conditional/In.java b/metafix/src/main/java/org/metafacture/metafix/conditional/In.java new file mode 100644 index 000000000..16b3bc1f6 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/conditional/In.java @@ -0,0 +1,59 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.conditional; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.Value; +import org.metafacture.metafix.api.FixPredicate; + +import java.util.List; +import java.util.Map; + +@FixCommand("in") +public class In implements FixPredicate { + + /** + * Creates an instance of {@link In}. + */ + public In() { + } + + @Override + public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { + final Value value1 = record.get(params.get(0)); + final Value value2 = record.get(params.get(1)); + + return value1 != null && value2 != null && value1.extractType((m, c) -> m + .ifArray(a1 -> value2.matchType() + .ifArray(a2 -> c.accept(a1.equals(a2))) + .orElse(v -> c.accept(false)) + ) + .ifHash(h1 -> value2.matchType() + .ifHash(h2 -> c.accept(h1.equals(h2))) + .orElse(v -> c.accept(false)) + ) + .ifString(s1 -> value2.matchType() + .ifArray(a2 -> c.accept(a2.stream().anyMatch(value1::equals))) + .ifHash(h2 -> c.accept(h2.containsField(s1))) + .ifString(s2 -> c.accept(s1.equals(s2))) + ) + ); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/conditional/IsArray.java b/metafix/src/main/java/org/metafacture/metafix/conditional/IsArray.java new file mode 100644 index 000000000..89892139a --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/conditional/IsArray.java @@ -0,0 +1,42 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.conditional; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.Value; +import org.metafacture.metafix.api.FixPredicate; + +import java.util.List; +import java.util.Map; + +@FixCommand("is_array") +public class IsArray implements FixPredicate { + + /** + * Creates an instance of {@link IsArray}. + */ + public IsArray() { + } + + @Override + public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { + return testConditional(record, params, Value::isArray); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/conditional/IsContainedIn.java b/metafix/src/main/java/org/metafacture/metafix/conditional/IsContainedIn.java new file mode 100644 index 000000000..a7de1d64e --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/conditional/IsContainedIn.java @@ -0,0 +1,41 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.conditional; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixPredicate; + +import java.util.List; +import java.util.Map; + +@FixCommand("is_contained_in") +public class IsContainedIn implements FixPredicate { + + /** + * Creates an instance of {@link IsContainedIn}. + */ + public IsContainedIn() { + } + + @Override + public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { + return new In().test(metafix, record, params, options); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/conditional/IsEmpty.java b/metafix/src/main/java/org/metafacture/metafix/conditional/IsEmpty.java new file mode 100644 index 000000000..d03dc748d --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/conditional/IsEmpty.java @@ -0,0 +1,41 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.conditional; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixPredicate; + +import java.util.List; +import java.util.Map; + +@FixCommand("is_empty") +public class IsEmpty implements FixPredicate { + + /** + * Creates an instance of {@link IsEmpty}. + */ + public IsEmpty() { + } + + @Override + public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { + return testConditional(record, params, IS_EMPTY); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/conditional/IsFalse.java b/metafix/src/main/java/org/metafacture/metafix/conditional/IsFalse.java new file mode 100644 index 000000000..05e0fd56c --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/conditional/IsFalse.java @@ -0,0 +1,41 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.conditional; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixPredicate; + +import java.util.List; +import java.util.Map; + +@FixCommand("is_false") +public class IsFalse implements FixPredicate { + + /** + * Creates an instance of {@link IsFalse}. + */ + public IsFalse() { + } + + @Override + public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { + return testStringConditional(record, params, IS_FALSE); // TODO: strict=false + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/conditional/IsHash.java b/metafix/src/main/java/org/metafacture/metafix/conditional/IsHash.java new file mode 100644 index 000000000..ba72230e3 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/conditional/IsHash.java @@ -0,0 +1,41 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.conditional; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixPredicate; + +import java.util.List; +import java.util.Map; + +@FixCommand("is_hash") +public class IsHash implements FixPredicate { + + /** + * Creates an instance of {@link IsHash}. + */ + public IsHash() { + } + + @Override + public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { + return new IsObject().test(metafix, record, params, options); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/conditional/IsNumber.java b/metafix/src/main/java/org/metafacture/metafix/conditional/IsNumber.java new file mode 100644 index 000000000..a20fd1f35 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/conditional/IsNumber.java @@ -0,0 +1,41 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.conditional; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixPredicate; + +import java.util.List; +import java.util.Map; + +@FixCommand("is_number") +public class IsNumber implements FixPredicate { + + /** + * Creates an instance of {@link IsNumber}. + */ + public IsNumber() { + } + + @Override + public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { + return testStringConditional(record, params, IS_NUMBER); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/conditional/IsObject.java b/metafix/src/main/java/org/metafacture/metafix/conditional/IsObject.java new file mode 100644 index 000000000..e1df9ebe3 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/conditional/IsObject.java @@ -0,0 +1,42 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.conditional; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.Value; +import org.metafacture.metafix.api.FixPredicate; + +import java.util.List; +import java.util.Map; + +@FixCommand("is_object") +public class IsObject implements FixPredicate { + + /** + * Creates an instance of {@link IsObject}. + */ + public IsObject() { + } + + @Override + public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { + return testConditional(record, params, Value::isHash); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/conditional/IsString.java b/metafix/src/main/java/org/metafacture/metafix/conditional/IsString.java new file mode 100644 index 000000000..946235e27 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/conditional/IsString.java @@ -0,0 +1,42 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.conditional; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.Value; +import org.metafacture.metafix.api.FixPredicate; + +import java.util.List; +import java.util.Map; + +@FixCommand("is_string") +public class IsString implements FixPredicate { + + /** + * Creates an instance of {@link IsString}. + */ + public IsString() { + } + + @Override + public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { + return testConditional(record, params, Value::isString) && !new IsNumber().test(metafix, record, params, options); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/conditional/IsTrue.java b/metafix/src/main/java/org/metafacture/metafix/conditional/IsTrue.java new file mode 100644 index 000000000..205834e36 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/conditional/IsTrue.java @@ -0,0 +1,41 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.conditional; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixPredicate; + +import java.util.List; +import java.util.Map; + +@FixCommand("is_true") +public class IsTrue implements FixPredicate { + + /** + * Creates an instance of {@link IsTrue}. + */ + public IsTrue() { + } + + @Override + public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { + return testStringConditional(record, params, IS_TRUE); // TODO: strict=false + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/conditional/LessThan.java b/metafix/src/main/java/org/metafacture/metafix/conditional/LessThan.java new file mode 100644 index 000000000..6c7650c59 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/conditional/LessThan.java @@ -0,0 +1,41 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.conditional; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixPredicate; + +import java.util.List; +import java.util.Map; + +@FixCommand("less_than") +public class LessThan implements FixPredicate { + + /** + * Creates an instance of {@link LessThan}. + */ + public LessThan() { + } + + @Override + public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { + return testConditional(record, params, ALL, LESS_THAN); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/conditional/NoneContain.java b/metafix/src/main/java/org/metafacture/metafix/conditional/NoneContain.java new file mode 100644 index 000000000..8b2ae2eb2 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/conditional/NoneContain.java @@ -0,0 +1,41 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.conditional; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixPredicate; + +import java.util.List; +import java.util.Map; + +@FixCommand("none_contain") +public class NoneContain implements FixPredicate { + + /** + * Creates an instance of {@link NoneContain}. + */ + public NoneContain() { + } + + @Override + public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { + return !new AnyContain().test(metafix, record, params, options); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/conditional/NoneEqual.java b/metafix/src/main/java/org/metafacture/metafix/conditional/NoneEqual.java new file mode 100644 index 000000000..f4e68700e --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/conditional/NoneEqual.java @@ -0,0 +1,41 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.conditional; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixPredicate; + +import java.util.List; +import java.util.Map; + +@FixCommand("none_equal") +public class NoneEqual implements FixPredicate { + + /** + * Creates an instance of {@link NoneEqual}. + */ + public NoneEqual() { + } + + @Override + public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { + return !new AnyEqual().test(metafix, record, params, options); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/conditional/NoneMatch.java b/metafix/src/main/java/org/metafacture/metafix/conditional/NoneMatch.java new file mode 100644 index 000000000..52807eb6c --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/conditional/NoneMatch.java @@ -0,0 +1,41 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.conditional; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixPredicate; + +import java.util.List; +import java.util.Map; + +@FixCommand("none_match") +public class NoneMatch implements FixPredicate { + + /** + * Creates an instance of {@link NoneMatch}. + */ + public NoneMatch() { + } + + @Override + public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { + return !new AnyMatch().test(metafix, record, params, options); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/conditional/StrContain.java b/metafix/src/main/java/org/metafacture/metafix/conditional/StrContain.java new file mode 100644 index 000000000..f2e0007dc --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/conditional/StrContain.java @@ -0,0 +1,41 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.conditional; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixPredicate; + +import java.util.List; +import java.util.Map; + +@FixCommand("str_contain") +public class StrContain implements FixPredicate { + + /** + * Creates an instance of {@link StrContain}. + */ + public StrContain() { + } + + @Override + public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { + return testConditional(params, CONTAINS); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/conditional/StrEqual.java b/metafix/src/main/java/org/metafacture/metafix/conditional/StrEqual.java new file mode 100644 index 000000000..d32288aa3 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/conditional/StrEqual.java @@ -0,0 +1,41 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.conditional; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixPredicate; + +import java.util.List; +import java.util.Map; + +@FixCommand("str_equal") +public class StrEqual implements FixPredicate { + + /** + * Creates an instance of {@link StrEqual}. + */ + public StrEqual() { + } + + @Override + public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { + return testConditional(params, EQUALS); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/conditional/StrMatch.java b/metafix/src/main/java/org/metafacture/metafix/conditional/StrMatch.java new file mode 100644 index 000000000..4e704d86e --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/conditional/StrMatch.java @@ -0,0 +1,41 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.conditional; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixPredicate; + +import java.util.List; +import java.util.Map; + +@FixCommand("str_match") +public class StrMatch implements FixPredicate { + + /** + * Creates an instance of {@link StrMatch}. + */ + public StrMatch() { + } + + @Override + public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { + return testConditional(params, MATCHES); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/field/Append.java b/metafix/src/main/java/org/metafacture/metafix/method/field/Append.java new file mode 100644 index 000000000..fec4512d9 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/field/Append.java @@ -0,0 +1,42 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.field; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixFunction; + +import java.util.List; +import java.util.Map; + +@FixCommand("append") +public class Append implements FixFunction { + + /** + * Creates an instance of {@link Append}. + */ + public Append() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + final String value = params.get(1); + record.transform(params.get(0), s -> s + value); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/field/Capitalize.java b/metafix/src/main/java/org/metafacture/metafix/method/field/Capitalize.java new file mode 100644 index 000000000..184d6cc9b --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/field/Capitalize.java @@ -0,0 +1,41 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.field; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixFunction; + +import java.util.List; +import java.util.Map; + +@FixCommand("capitalize") +public class Capitalize implements FixFunction { + + /** + * Creates an instance of {@link Capitalize}. + */ + public Capitalize() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + record.transform(params.get(0), s -> s.substring(0, 1).toUpperCase() + s.substring(1)); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/field/Count.java b/metafix/src/main/java/org/metafacture/metafix/method/field/Count.java new file mode 100644 index 000000000..feef32a88 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/field/Count.java @@ -0,0 +1,45 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.field; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.Value; +import org.metafacture.metafix.api.FixFunction; + +import java.util.List; +import java.util.Map; + +@FixCommand("count") +public class Count implements FixFunction { + + /** + * Creates an instance of {@link Count}. + */ + public Count() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + record.transform(params.get(0), (m, c) -> m + .ifArray(a -> c.accept(new Value(a.size()))) + .ifHash(h -> c.accept(new Value(h.size()))) + ); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/field/Downcase.java b/metafix/src/main/java/org/metafacture/metafix/method/field/Downcase.java new file mode 100644 index 000000000..286cb5931 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/field/Downcase.java @@ -0,0 +1,41 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.field; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixFunction; + +import java.util.List; +import java.util.Map; + +@FixCommand("downcase") +public class Downcase implements FixFunction { + + /** + * Creates an instance of {@link Downcase}. + */ + public Downcase() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + record.transform(params.get(0), s -> s.toLowerCase()); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/field/Filter.java b/metafix/src/main/java/org/metafacture/metafix/method/field/Filter.java new file mode 100644 index 000000000..5e83e9107 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/field/Filter.java @@ -0,0 +1,51 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.field; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.Value; +import org.metafacture.metafix.api.FixFunction; + +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; +import java.util.regex.Pattern; + +@FixCommand("filter") +public class Filter implements FixFunction { + + /** + * Creates an instance of {@link Filter}. + */ + public Filter() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + final Pattern search = Pattern.compile(params.get(1)); + final boolean invert = getBoolean(options, "invert"); + + final Predicate predicate = s -> search.matcher(s.asString()).find(); + + record.transform(params.get(0), (m, c) -> m + .ifArray(a -> c.accept(newArray(a.stream().filter(invert ? predicate.negate() : predicate)))) + ); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/field/Flatten.java b/metafix/src/main/java/org/metafacture/metafix/method/field/Flatten.java new file mode 100644 index 000000000..53a6db975 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/field/Flatten.java @@ -0,0 +1,43 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.field; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixFunction; + +import java.util.List; +import java.util.Map; + +@FixCommand("flatten") +public class Flatten implements FixFunction { + + /** + * Creates an instance of {@link Flatten}. + */ + public Flatten() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + record.transform(params.get(0), (m, c) -> m + .ifArray(a -> c.accept(newArray(flatten(a.stream())))) + ); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/field/FromJson.java b/metafix/src/main/java/org/metafacture/metafix/method/field/FromJson.java new file mode 100644 index 000000000..1515f2d1e --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/field/FromJson.java @@ -0,0 +1,56 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.field; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.JsonValue; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.Value; +import org.metafacture.metafix.api.FixFunction; + +import java.io.IOException; +import java.util.List; +import java.util.Map; + +@FixCommand("from_json") +public class FromJson implements FixFunction { + + /** + * Creates an instance of {@link FromJson}. + */ + public FromJson() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + final String errorString = options.get(ERROR_STRING_OPTION); + final JsonValue.Parser parser = new JsonValue.Parser(); + + record.transform(params.get(0), (m, c) -> m + .ifString(s -> { + try { + c.accept(parser.parse(s)); + } + catch (final IOException e) { + c.accept(errorString != null ? new Value(errorString) : null); + } + }) + ); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/field/Index.java b/metafix/src/main/java/org/metafacture/metafix/method/field/Index.java new file mode 100644 index 000000000..6dc4bad35 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/field/Index.java @@ -0,0 +1,42 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.field; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixFunction; + +import java.util.List; +import java.util.Map; + +@FixCommand("index") +public class Index implements FixFunction { + + /** + * Creates an instance of {@link Index}. + */ + public Index() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + final String search = params.get(1); + record.transform(params.get(0), s -> String.valueOf(s.indexOf(search))); // TODO: multiple + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/field/Isbn.java b/metafix/src/main/java/org/metafacture/metafix/method/field/Isbn.java new file mode 100644 index 000000000..f4c28dc5b --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/field/Isbn.java @@ -0,0 +1,48 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.field; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixFunction; +import org.metafacture.metamorph.functions.ISBN; + +import java.util.List; +import java.util.Map; + +@FixCommand("isbn") +public class Isbn implements FixFunction { + + /** + * Creates an instance of {@link Isbn}. + */ + public Isbn() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + final ISBN isbn = new ISBN(); + + withOption(options, ERROR_STRING_OPTION, isbn::setErrorString); + withOption(options, "to", isbn::setTo); + withOption(options, "verify_check_digit", isbn::setVerifyCheckDigit); + + record.transform(params.get(0), isbn::process); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/field/JoinField.java b/metafix/src/main/java/org/metafacture/metafix/method/field/JoinField.java new file mode 100644 index 000000000..5553629ea --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/field/JoinField.java @@ -0,0 +1,46 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.field; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.Value; +import org.metafacture.metafix.api.FixFunction; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@FixCommand("join_field") +public class JoinField implements FixFunction { + + /** + * Creates an instance of {@link JoinField}. + */ + public JoinField() { + } + + @Override + 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.transform(params.get(0), (m, c) -> m + .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/method/field/Lookup.java b/metafix/src/main/java/org/metafacture/metafix/method/field/Lookup.java new file mode 100644 index 000000000..80f9d599c --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/field/Lookup.java @@ -0,0 +1,94 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.field; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixFunction; +import org.metafacture.metafix.method.script.PutFileMap; +import org.metafacture.metamorph.api.Maps; + +import java.io.File; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.LongAdder; +import java.util.function.Consumer; + +@FixCommand("lookup") +public class Lookup implements FixFunction { + + private static final Map SCOPED_COUNTER = new HashMap<>(); + + /** + * Creates an instance of {@link Lookup}. + */ + public Lookup() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + final Map map; + + if (params.size() <= 1) { + map = options; + } + else { + final String mapName = params.get(1); + + if (!metafix.getMapNames().contains(mapName)) { + if (mapName.contains(".") || mapName.contains(File.separator)) { + new PutFileMap().apply(metafix, record, Arrays.asList(mapName), options); + } + else { + // Probably an unknown internal map? Log a warning? + } + } + + map = metafix.getMap(mapName); + } + + final String defaultValue = options.getOrDefault("default", map.get(Maps.DEFAULT_MAP_KEY)); + final boolean delete = getBoolean(options, "delete"); + final boolean printUnknown = getBoolean(options, "print_unknown"); + + final Consumer> consumer = c -> record.transform(params.get(0), oldValue -> { + final String newValue = map.get(oldValue); + if (newValue != null) { + return newValue; + } + else { + if (c != null) { + c.accept(oldValue); + } + + return defaultValue != null ? defaultValue : delete ? null : oldValue; + } + }); + + if (printUnknown) { + options.putIfAbsent("append", "true"); + withWriter(metafix, record, options, SCOPED_COUNTER, consumer); + } + else { + consumer.accept(null); + } + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/field/Prepend.java b/metafix/src/main/java/org/metafacture/metafix/method/field/Prepend.java new file mode 100644 index 000000000..99fc4f931 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/field/Prepend.java @@ -0,0 +1,42 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.field; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixFunction; + +import java.util.List; +import java.util.Map; + +@FixCommand("prepend") +public class Prepend implements FixFunction { + + /** + * Creates an instance of {@link Prepend}. + */ + public Prepend() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + final String value = params.get(1); + record.transform(params.get(0), s -> value + s); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/field/ReplaceAll.java b/metafix/src/main/java/org/metafacture/metafix/method/field/ReplaceAll.java new file mode 100644 index 000000000..14dd1bb92 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/field/ReplaceAll.java @@ -0,0 +1,44 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.field; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixFunction; + +import java.util.List; +import java.util.Map; + +@FixCommand("replace_all") +public class ReplaceAll implements FixFunction { + + /** + * Creates an instance of {@link ReplaceAll}. + */ + public ReplaceAll() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + final String search = params.get(1); + final String replace = params.get(2); + + record.transform(params.get(0), s -> s.replaceAll(search, replace)); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/field/Reverse.java b/metafix/src/main/java/org/metafacture/metafix/method/field/Reverse.java new file mode 100644 index 000000000..abcfdeb61 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/field/Reverse.java @@ -0,0 +1,51 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.field; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.Value; +import org.metafacture.metafix.api.FixFunction; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@FixCommand("reverse") +public class Reverse implements FixFunction { + + /** + * Creates an instance of {@link Reverse}. + */ + public Reverse() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + record.transform(params.get(0), (m, c) -> m + .ifArray(a -> { + final List list = a.stream().collect(Collectors.toList()); + Collections.reverse(list); + c.accept(new Value(list)); + }) + .ifString(s -> c.accept(new Value(new StringBuilder(s).reverse().toString()))) + ); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/field/SortField.java b/metafix/src/main/java/org/metafacture/metafix/method/field/SortField.java new file mode 100644 index 000000000..8cbe14524 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/field/SortField.java @@ -0,0 +1,56 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.field; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.Value; +import org.metafacture.metafix.api.FixFunction; + +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +@FixCommand("sort_field") +public class SortField implements FixFunction { + + /** + * Creates an instance of {@link SortField}. + */ + public SortField() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + 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.transform(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())))) + ); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/field/SplitField.java b/metafix/src/main/java/org/metafacture/metafix/method/field/SplitField.java new file mode 100644 index 000000000..81b4bf33e --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/field/SplitField.java @@ -0,0 +1,55 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.field; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.Value; +import org.metafacture.metafix.api.FixFunction; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.regex.Pattern; + +@FixCommand("split_field") +public class SplitField implements FixFunction { + + /** + * Creates an instance of {@link SplitField}. + */ + public SplitField() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + final String splitChar = params.size() > 1 ? params.get(1) : "\\s+"; + final Pattern splitPattern = Pattern.compile(splitChar); + + final Function splitFunction = s -> + newArray(Arrays.stream(splitPattern.split(s)).map(Value::new)); + + record.transform(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))) + ); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/field/Substring.java b/metafix/src/main/java/org/metafacture/metafix/method/field/Substring.java new file mode 100644 index 000000000..cc41dd1ab --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/field/Substring.java @@ -0,0 +1,48 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.field; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixFunction; + +import java.util.List; +import java.util.Map; + +@FixCommand("substring") +public class Substring implements FixFunction { + + /** + * Creates an instance of {@link Substring}. + */ + public Substring() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + final int offset = getInteger(params, 1); + final Integer end = params.size() > 2 ? offset + getInteger(params, 2) : null; + // TODO: final String replacement = params.size() > 3 ? params.get(3) : null; + + record.transform(params.get(0), s -> { + final int length = s.length(); + return offset > length ? s : end == null || end > length ? s.substring(offset) : s.substring(offset, end); + }); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/field/Sum.java b/metafix/src/main/java/org/metafacture/metafix/method/field/Sum.java new file mode 100644 index 000000000..33e6c2fae --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/field/Sum.java @@ -0,0 +1,44 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.field; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.Value; +import org.metafacture.metafix.api.FixFunction; + +import java.util.List; +import java.util.Map; + +@FixCommand("sum") +public class Sum implements FixFunction { + + /** + * Creates an instance of {@link Sum}. + */ + public Sum() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + record.transform(params.get(0), (m, c) -> m + .ifArray(a -> c.accept(new Value(a.stream().map(Value::asString).mapToInt(Integer::parseInt).sum()))) + ); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/field/ToBase64.java b/metafix/src/main/java/org/metafacture/metafix/method/field/ToBase64.java new file mode 100644 index 000000000..cb43e273f --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/field/ToBase64.java @@ -0,0 +1,45 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.field; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixFunction; + +import java.util.Base64; +import java.util.List; +import java.util.Map; + +@FixCommand("to_base64") +public class ToBase64 implements FixFunction { + + /** + * Creates an instance of {@link ToBase64}. + */ + public ToBase64() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + final boolean urlSafe = getBoolean(options, "url_safe"); + final Base64.Encoder encoder = urlSafe ? Base64.getUrlEncoder() : Base64.getEncoder(); + + record.transform(params.get(0), s -> encoder.encodeToString(s.getBytes())); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/field/ToJson.java b/metafix/src/main/java/org/metafacture/metafix/method/field/ToJson.java new file mode 100644 index 000000000..14eb044e1 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/field/ToJson.java @@ -0,0 +1,55 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.field; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.Value; +import org.metafacture.metafix.api.FixFunction; + +import java.io.IOException; +import java.util.List; +import java.util.Map; + +@FixCommand("to_json") +public class ToJson implements FixFunction { + + /** + * Creates an instance of {@link ToJson}. + */ + public ToJson() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + final String errorString = options.get(ERROR_STRING_OPTION); + final boolean pretty = getBoolean(options, "pretty"); + + record.transform(params.get(0), (m, c) -> m + .orElse(v -> { + try { + c.accept(new Value(v.toJson(pretty))); + } + catch (final IOException e) { + c.accept(errorString != null ? new Value(errorString) : null); + } + }) + ); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/field/Trim.java b/metafix/src/main/java/org/metafacture/metafix/method/field/Trim.java new file mode 100644 index 000000000..c11a7f8aa --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/field/Trim.java @@ -0,0 +1,41 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.field; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixFunction; + +import java.util.List; +import java.util.Map; + +@FixCommand("trim") +public class Trim implements FixFunction { + + /** + * Creates an instance of {@link Trim}. + */ + public Trim() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + record.transform(params.get(0), String::trim); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/field/Uniq.java b/metafix/src/main/java/org/metafacture/metafix/method/field/Uniq.java new file mode 100644 index 000000000..591febcb9 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/field/Uniq.java @@ -0,0 +1,43 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.field; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixFunction; + +import java.util.List; +import java.util.Map; + +@FixCommand("uniq") +public class Uniq implements FixFunction { + + /** + * Creates an instance of {@link Uniq}. + */ + public Uniq() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + record.transform(params.get(0), (m, c) -> m + .ifArray(a -> c.accept(newArray(unique(a.stream())))) + ); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/field/Upcase.java b/metafix/src/main/java/org/metafacture/metafix/method/field/Upcase.java new file mode 100644 index 000000000..0f6675160 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/field/Upcase.java @@ -0,0 +1,41 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.field; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixFunction; + +import java.util.List; +import java.util.Map; + +@FixCommand("upcase") +public class Upcase implements FixFunction { + + /** + * Creates an instance of {@link Upcase}. + */ + public Upcase() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + record.transform(params.get(0), s -> s.toUpperCase()); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/field/UriEncode.java b/metafix/src/main/java/org/metafacture/metafix/method/field/UriEncode.java new file mode 100644 index 000000000..507afdf71 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/field/UriEncode.java @@ -0,0 +1,46 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.field; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixFunction; +import org.metafacture.metamorph.functions.URLEncode; + +import java.util.List; +import java.util.Map; + +@FixCommand("uri_encode") +public class UriEncode implements FixFunction { + + /** + * Creates an instance of {@link UriEncode}. + */ + public UriEncode() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + final URLEncode urlEncoder = new URLEncode(); + withOption(options, "safe_chars", urlEncoder::setSafeChars); + withOption(options, "plus_for_space", urlEncoder::setPlusForSpace, this::getBoolean); + + record.transform(params.get(0), urlEncoder::process); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/record/AddArray.java b/metafix/src/main/java/org/metafacture/metafix/method/record/AddArray.java new file mode 100644 index 000000000..41621b633 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/record/AddArray.java @@ -0,0 +1,45 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.record; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.Value; +import org.metafacture.metafix.api.FixFunction; + +import java.util.List; +import java.util.Map; + +@FixCommand("add_array") +public class AddArray implements FixFunction { + + /** + * Creates an instance of {@link AddArray}. + */ + public AddArray() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + final String field = params.get(0); + final Value newValue = newArray(params.subList(1, params.size()).stream().map(Value::new)); + record.set(field, newValue); + newValue.asArray().forEach(value -> value.withPathSet(newValue.getPath() + Value.FIELD_PATH_SEPARATOR + value.getPath())); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/record/AddField.java b/metafix/src/main/java/org/metafacture/metafix/method/record/AddField.java new file mode 100644 index 000000000..89e5dbffb --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/record/AddField.java @@ -0,0 +1,42 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.record; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.Value; +import org.metafacture.metafix.api.FixFunction; + +import java.util.List; +import java.util.Map; + +@FixCommand("add_field") +public class AddField implements FixFunction { + + /** + * Creates an instance of {@link AddField}. + */ + public AddField() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + record.set(params.get(0), new Value(params.get(1))); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/record/AddHash.java b/metafix/src/main/java/org/metafacture/metafix/method/record/AddHash.java new file mode 100644 index 000000000..d8f048338 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/record/AddHash.java @@ -0,0 +1,44 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.record; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.Value; +import org.metafacture.metafix.api.FixFunction; + +import java.util.List; +import java.util.Map; + +@FixCommand("add_hash") +public class AddHash implements FixFunction { + + /** + * Creates an instance of {@link AddHash}. + */ + public AddHash() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + final String field = params.get(0); + final Value newValue = Value.newHash(h -> options.forEach((f, v) -> h.put(f, new Value(v)))); + record.set(field, newValue); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/record/Array.java b/metafix/src/main/java/org/metafacture/metafix/method/record/Array.java new file mode 100644 index 000000000..e878c7558 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/record/Array.java @@ -0,0 +1,51 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.record; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.Value; +import org.metafacture.metafix.api.FixFunction; + +import java.util.List; +import java.util.Map; + +@FixCommand("array") +public class Array implements FixFunction { + + /** + * Creates an instance of {@link Array}. + */ + public Array() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + final String field = params.get(0); + + record.getList(field, a -> a.forEach(v -> v.matchType().ifHash(h -> { + record.remove(field); + + h.forEach((subField, value) -> { + record.addNested(field, new Value(subField)); + record.addNested(field, value.withPathSet(null)); + }); + }))); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/record/CallMacro.java b/metafix/src/main/java/org/metafacture/metafix/method/record/CallMacro.java new file mode 100644 index 000000000..01c019e46 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/record/CallMacro.java @@ -0,0 +1,50 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.record; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.RecordTransformer; +import org.metafacture.metafix.api.FixFunction; + +import java.util.List; +import java.util.Map; + +@FixCommand("call_macro") +public class CallMacro implements FixFunction { + + /** + * Creates an instance of {@link CallMacro}. + */ + public CallMacro() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + final String macroName = params.get(0); + final RecordTransformer recordTransformer = metafix.getMacro(macroName); + + if (recordTransformer != null) { + recordTransformer.transform(record, options); + } + else { + throw new IllegalArgumentException("Macro '" + macroName + "' undefined!"); + } + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/record/CopyField.java b/metafix/src/main/java/org/metafacture/metafix/method/record/CopyField.java new file mode 100644 index 000000000..e775c22af --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/record/CopyField.java @@ -0,0 +1,53 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.record; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.Value; +import org.metafacture.metafix.api.FixFunction; + +import java.util.List; +import java.util.Map; + +@FixCommand("copy_field") +public class CopyField implements FixFunction { + + /** + * Creates an instance of {@link CopyField}. + */ + public CopyField() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + final String oldName = params.get(0); + final String newName = params.get(1); + + final Value oldValue = record.get(oldName); + if (!Value.isNull(oldValue)) { + oldValue.matchType() + .ifArray(a -> { + record.remove(newName); + a.forEach(v -> record.addNested(newName, v.withPathSet(null))); + }) + .orElse(v -> record.set(newName, v.withPathSet(null))); + } + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/record/Format.java b/metafix/src/main/java/org/metafacture/metafix/method/record/Format.java new file mode 100644 index 000000000..58e318418 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/record/Format.java @@ -0,0 +1,48 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.record; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.Value; +import org.metafacture.metafix.api.FixFunction; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +@FixCommand("format") +public class Format implements FixFunction { + + /** + * Creates an instance of {@link Format}. + */ + public Format() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + final String field = params.get(0); + + record.getList(field, oldValues -> { + final String newValue = String.format(params.get(1), oldValues.stream().toArray()); + record.replace(field, new Value(Arrays.asList(new Value(newValue)))); + }); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/record/Hash.java b/metafix/src/main/java/org/metafacture/metafix/method/record/Hash.java new file mode 100644 index 000000000..993958738 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/record/Hash.java @@ -0,0 +1,48 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.record; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.Value; +import org.metafacture.metafix.api.FixFunction; + +import java.util.List; +import java.util.Map; + +@FixCommand("hash") +public class Hash implements FixFunction { + + /** + * Creates an instance of {@link Hash}. + */ + public Hash() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + final String field = params.get(0); + + 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).asString(), a.get(i)); + } + }))); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/record/MoveField.java b/metafix/src/main/java/org/metafacture/metafix/method/record/MoveField.java new file mode 100644 index 000000000..c06db814a --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/record/MoveField.java @@ -0,0 +1,42 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.record; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixFunction; + +import java.util.List; +import java.util.Map; + +@FixCommand("move_field") +public class MoveField implements FixFunction { + + /** + * Creates an instance of {@link MoveField}. + */ + public MoveField() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + new CopyField().apply(metafix, record, params, options); + record.remove(params.get(0)); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/record/ParseText.java b/metafix/src/main/java/org/metafacture/metafix/method/record/ParseText.java new file mode 100644 index 000000000..e8a13b32f --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/record/ParseText.java @@ -0,0 +1,78 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.record; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.Value; +import org.metafacture.metafix.api.FixFunction; + +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +@FixCommand("parse_text") +public class ParseText implements FixFunction { + + private static final Pattern NAMED_GROUP_PATTERN = Pattern.compile("\\(\\?<(.+?)>"); + + /** + * Creates an instance of {@link ParseText}. + */ + public ParseText() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + final String field = params.get(0); + + record.getList(field, a -> a.forEach(v -> { + final Pattern p = Pattern.compile(params.get(1)); + final Matcher m = p.matcher(v.asString()); + if (m.matches()) { + record.remove(field); + + /** + * {@code Pattern.namedGroups()} not available as API, + * see https://stackoverflow.com/a/65012527. + * + * Assumptions: 1. Named groups are not escaped/quoted; + * 2. Named groups are not mixed with unnamed groups. + */ + final Matcher groupMatcher = NAMED_GROUP_PATTERN.matcher(p.pattern()); + final Value value = Value.newHash(h -> { + while (groupMatcher.find()) { + final String group = groupMatcher.group(1); + h.put(group, new Value(m.group(group))); + } + }); + + if (!value.asHash().isEmpty()) { + record.addNested(field, value); + } + else { + for (int i = 1; i <= m.groupCount(); i = i + 1) { + record.addNested(field, new Value(m.group(i))); + } + } + } + })); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/record/Paste.java b/metafix/src/main/java/org/metafacture/metafix/method/record/Paste.java new file mode 100644 index 000000000..455e7f59f --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/record/Paste.java @@ -0,0 +1,52 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.record; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.Value; +import org.metafacture.metafix.api.FixFunction; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@FixCommand("paste") +public class Paste implements FixFunction { + + /** + * Creates an instance of {@link Paste}. + */ + public Paste() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + final String joinChar = options.get("join_char"); + final Value newValue = new Value(params.subList(1, params.size()).stream() + .filter(f -> literalString(f) || record.get(f) != null) + .map(f -> literalString(f) ? new Value(f.substring(1)) : Value.asList(record.get(f), null).asArray().get(0)) + .map(Value::asString).collect(Collectors.joining(joinChar != null ? joinChar : " "))); + record.set(params.get(0), newValue); + } + + private boolean literalString(final String s) { + return s.startsWith("~"); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/record/PrintRecord.java b/metafix/src/main/java/org/metafacture/metafix/method/record/PrintRecord.java new file mode 100644 index 000000000..8a5fda7da --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/record/PrintRecord.java @@ -0,0 +1,70 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.record; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixFunction; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.LongAdder; + +@FixCommand("print_record") +public class PrintRecord implements FixFunction { + + private static final Map SCOPED_COUNTER = new HashMap<>(); + + /** + * Creates an instance of {@link PrintRecord}. + */ + public PrintRecord() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + final boolean internal = getBoolean(options, "internal"); + final boolean pretty = getBoolean(options, "pretty"); + + if (!params.isEmpty()) { + options.put("prefix", params.get(0)); + } + + withWriter(metafix, record, options, SCOPED_COUNTER, c -> { + if (internal) { + if (pretty) { + record.forEach((f, v) -> c.accept(f + "=" + v)); + } + else { + c.accept(record.toString()); + } + } + else { + try { + c.accept(record.toJson(pretty)); + } + catch (final IOException e) { + // Log a warning? Print string representation instead? + } + } + }); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/record/Random.java b/metafix/src/main/java/org/metafacture/metafix/method/record/Random.java new file mode 100644 index 000000000..2a4af41c3 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/record/Random.java @@ -0,0 +1,46 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.record; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.Value; +import org.metafacture.metafix.api.FixFunction; + +import java.util.List; +import java.util.Map; + +@FixCommand("random") +public class Random implements FixFunction { + + private static final java.util.Random RANDOM = new java.util.Random(); + + /** + * Creates an instance of {@link Random}. + */ + public Random() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + final String field = params.get(0); + final int max = getInteger(params, 1); + record.set(field, new Value(String.valueOf(RANDOM.nextInt(max)))); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/record/Reject.java b/metafix/src/main/java/org/metafacture/metafix/method/record/Reject.java new file mode 100644 index 000000000..e11b48809 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/record/Reject.java @@ -0,0 +1,41 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.record; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixFunction; + +import java.util.List; +import java.util.Map; + +@FixCommand("reject") +public class Reject implements FixFunction { + + /** + * Creates an instance of {@link Reject}. + */ + public Reject() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + record.setReject(true); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/record/RemoveField.java b/metafix/src/main/java/org/metafacture/metafix/method/record/RemoveField.java new file mode 100644 index 000000000..c0e08717d --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/record/RemoveField.java @@ -0,0 +1,41 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.record; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixFunction; + +import java.util.List; +import java.util.Map; + +@FixCommand("remove_field") +public class RemoveField implements FixFunction { + + /** + * Creates an instance of {@link RemoveField}. + */ + public RemoveField() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + params.forEach(p -> record.remove(p)); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/record/Rename.java b/metafix/src/main/java/org/metafacture/metafix/method/record/Rename.java new file mode 100644 index 000000000..e0851e2c5 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/record/Rename.java @@ -0,0 +1,68 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.record; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.Value; +import org.metafacture.metafix.api.FixFunction; + +import java.util.List; +import java.util.Map; +import java.util.function.UnaryOperator; + +@FixCommand("rename") +public class Rename implements FixFunction { + + /** + * Creates an instance of {@link Rename}. + */ + public Rename() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + final String search = params.get(1); + final String replace = params.get(2); + + final UnaryOperator operator = s -> s.replaceAll(search, replace); + + record.transform(params.get(0), (m, c) -> m + .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/method/record/Retain.java b/metafix/src/main/java/org/metafacture/metafix/method/record/Retain.java new file mode 100644 index 000000000..c1424f1e3 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/record/Retain.java @@ -0,0 +1,41 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.record; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixFunction; + +import java.util.List; +import java.util.Map; + +@FixCommand("retain") +public class Retain implements FixFunction { + + /** + * Creates an instance of {@link Retain}. + */ + public Retain() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + record.retainFields(params); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/record/SetArray.java b/metafix/src/main/java/org/metafacture/metafix/method/record/SetArray.java new file mode 100644 index 000000000..cc77c17b7 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/record/SetArray.java @@ -0,0 +1,43 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.record; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixFunction; + +import java.util.List; +import java.util.Map; + +@FixCommand("set_array") +public class SetArray implements FixFunction { + + /** + * Creates an instance of {@link SetArray}. + */ + public SetArray() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + if (parentFieldExists(record, params.get(0))) { + new AddArray().apply(metafix, record, params, options); + } + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/record/SetField.java b/metafix/src/main/java/org/metafacture/metafix/method/record/SetField.java new file mode 100644 index 000000000..934dec181 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/record/SetField.java @@ -0,0 +1,43 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.record; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixFunction; + +import java.util.List; +import java.util.Map; + +@FixCommand("set_field") +public class SetField implements FixFunction { + + /** + * Creates an instance of {@link SetField}. + */ + public SetField() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + if (parentFieldExists(record, params.get(0))) { + new AddField().apply(metafix, record, params, options); + } + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/record/SetHash.java b/metafix/src/main/java/org/metafacture/metafix/method/record/SetHash.java new file mode 100644 index 000000000..cef39e8f8 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/record/SetHash.java @@ -0,0 +1,43 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.record; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixFunction; + +import java.util.List; +import java.util.Map; + +@FixCommand("set_hash") +public class SetHash implements FixFunction { + + /** + * Creates an instance of {@link SetHash}. + */ + public SetHash() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + if (parentFieldExists(record, params.get(0))) { + new AddHash().apply(metafix, record, params, options); + } + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/record/Timestamp.java b/metafix/src/main/java/org/metafacture/metafix/method/record/Timestamp.java new file mode 100644 index 000000000..9e1a02331 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/record/Timestamp.java @@ -0,0 +1,49 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.record; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.Value; +import org.metafacture.metafix.api.FixFunction; + +import java.util.List; +import java.util.Map; + +@FixCommand("timestamp") +public class Timestamp implements FixFunction { + + /** + * Creates an instance of {@link Timestamp}. + */ + public Timestamp() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + final String field = params.get(0); + final org.metafacture.metamorph.functions.Timestamp timestamp = new org.metafacture.metamorph.functions.Timestamp(); + + withOption(options, "format", timestamp::setFormat); + withOption(options, "language", timestamp::setLanguage); + withOption(options, "timezone", timestamp::setTimezone); + + record.set(field, new Value(timestamp.process(null))); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/record/Vacuum.java b/metafix/src/main/java/org/metafacture/metafix/method/record/Vacuum.java new file mode 100644 index 000000000..e6253c516 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/record/Vacuum.java @@ -0,0 +1,41 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.record; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixFunction; + +import java.util.List; +import java.util.Map; + +@FixCommand("vacuum") +public class Vacuum implements FixFunction { + + /** + * Creates an instance of {@link Vacuum}. + */ + public Vacuum() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + record.removeEmptyValues(); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/script/Include.java b/metafix/src/main/java/org/metafacture/metafix/method/script/Include.java new file mode 100644 index 000000000..a9c1177c3 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/script/Include.java @@ -0,0 +1,50 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.script; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixFunction; + +import java.util.List; +import java.util.Map; + +@FixCommand("include") +public class Include implements FixFunction { + + /** + * Creates an instance of {@link Include}. + */ + public Include() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + final String includeFile = params.get(0); + + if (!Metafix.isFixFile(includeFile)) { + throw new IllegalArgumentException("Not a Fix file: " + includeFile); + } + + // TODO: Catmandu load path + final String includePath = metafix.resolvePath(includeFile); + + metafix.getRecordTransformer(includePath).transform(record, options); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/script/Log.java b/metafix/src/main/java/org/metafacture/metafix/method/script/Log.java new file mode 100644 index 000000000..ce4afcc17 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/script/Log.java @@ -0,0 +1,69 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.script; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixFunction; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; + +@FixCommand("log") +public class Log implements FixFunction { + + private static final Logger LOG = LoggerFactory.getLogger(Log.class); + + /** + * Creates an instance of {@link Log}. + */ + public Log() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + // does not support Catmandu log level option FATAL + + final String level = options.getOrDefault("level", "INFO"); + final Consumer consumer; + + switch (level) { + case "DEBUG": + consumer = LOG::debug; + break; + case "ERROR": + consumer = LOG::error; + break; + case "INFO": + consumer = LOG::info; + break; + case "WARN": + consumer = LOG::warn; + break; + default: + throw new IllegalArgumentException("Unsupported log level: " + level); + } + + consumer.accept(params.get(0)); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/script/Nothing.java b/metafix/src/main/java/org/metafacture/metafix/method/script/Nothing.java new file mode 100644 index 000000000..fc87eecf8 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/script/Nothing.java @@ -0,0 +1,41 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.script; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixFunction; + +import java.util.List; +import java.util.Map; + +@FixCommand("nothing") +public class Nothing implements FixFunction { + + /** + * Creates an instance of {@link Nothing}. + */ + public Nothing() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + // do nothing + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/script/PutFileMap.java b/metafix/src/main/java/org/metafacture/metafix/method/script/PutFileMap.java new file mode 100644 index 000000000..6b3ed1dc2 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/script/PutFileMap.java @@ -0,0 +1,60 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.script; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixFunction; +import org.metafacture.metamorph.maps.FileMap; + +import java.util.List; +import java.util.Map; + +@FixCommand("put_filemap") +public class PutFileMap implements FixFunction { + + private static final String FILEMAP_SEPARATOR_OPTION = "sep_char"; + private static final String FILEMAP_DEFAULT_SEPARATOR = ","; + + /** + * Creates an instance of {@link PutFileMap}. + */ + public PutFileMap() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + final String fileName = params.get(0); + final FileMap fileMap = new FileMap(); + + fileMap.setSeparator(options.getOrDefault(FILEMAP_SEPARATOR_OPTION, FILEMAP_DEFAULT_SEPARATOR)); + fileMap.setFile(metafix.resolvePath(fileName)); + + withOption(options, "allow_empty_values", fileMap::setAllowEmptyValues, this::getBoolean); + withOption(options, "compression", fileMap::setCompression); + withOption(options, "decompress_concatenated", fileMap::setDecompressConcatenated, this::getBoolean); + withOption(options, "encoding", fileMap::setEncoding); + withOption(options, "expected_columns", fileMap::setExpectedColumns, this::getInteger); + withOption(options, "ignore_pattern", fileMap::setIgnorePattern); + withOption(options, "key_column", fileMap::setKeyColumn, this::getInteger); + withOption(options, "value_column", fileMap::setValueColumn, this::getInteger); + + metafix.putMap(params.size() > 1 ? params.get(1) : fileName, fileMap); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/script/PutMap.java b/metafix/src/main/java/org/metafacture/metafix/method/script/PutMap.java new file mode 100644 index 000000000..5e2a3f183 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/script/PutMap.java @@ -0,0 +1,41 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.script; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixFunction; + +import java.util.List; +import java.util.Map; + +@FixCommand("put_map") +public class PutMap implements FixFunction { + + /** + * Creates an instance of {@link PutMap}. + */ + public PutMap() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + metafix.putMap(params.get(0), options); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/script/PutRdfMap.java b/metafix/src/main/java/org/metafacture/metafix/method/script/PutRdfMap.java new file mode 100644 index 000000000..2b6dfda1c --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/script/PutRdfMap.java @@ -0,0 +1,53 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.script; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixFunction; +import org.metafacture.metafix.maps.RdfMap; +import org.metafacture.metamorph.api.Maps; + +import java.util.List; +import java.util.Map; + +@FixCommand("put_rdfmap") +public class PutRdfMap implements FixFunction { + + /** + * Creates an instance of {@link PutRdfMap}. + */ + public PutRdfMap() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + final String fileName = params.get(0); + final RdfMap rdfMap = new RdfMap(); + + rdfMap.setResource(fileName, metafix::resolvePath); + + withOption(options, RdfMap.TARGET, rdfMap::setTarget); + withOption(options, RdfMap.TARGET_LANGUAGE, rdfMap::setTargetLanguage); + withOption(options, RdfMap.SELECT, rdfMap::setSelect); + withOption(options, Maps.DEFAULT_MAP_KEY, rdfMap::setDefault); + + metafix.putMap(params.size() > 1 ? params.get(1) : fileName, rdfMap); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/script/PutVar.java b/metafix/src/main/java/org/metafacture/metafix/method/script/PutVar.java new file mode 100644 index 000000000..40a05e7e4 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/script/PutVar.java @@ -0,0 +1,41 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.script; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixFunction; + +import java.util.List; +import java.util.Map; + +@FixCommand("put_var") +public class PutVar implements FixFunction { + + /** + * Creates an instance of {@link PutVar}. + */ + public PutVar() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + metafix.getVars().put(params.get(0), params.get(1)); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/script/PutVars.java b/metafix/src/main/java/org/metafacture/metafix/method/script/PutVars.java new file mode 100644 index 000000000..5ceea19d9 --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/script/PutVars.java @@ -0,0 +1,41 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.script; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.api.FixFunction; + +import java.util.List; +import java.util.Map; + +@FixCommand("put_vars") +public class PutVars implements FixFunction { + + /** + * Creates an instance of {@link PutVars}. + */ + public PutVars() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + metafix.getVars().putAll(options); + } + +} diff --git a/metafix/src/main/java/org/metafacture/metafix/method/script/ToVar.java b/metafix/src/main/java/org/metafacture/metafix/method/script/ToVar.java new file mode 100644 index 000000000..ed6d01c5c --- /dev/null +++ b/metafix/src/main/java/org/metafacture/metafix/method/script/ToVar.java @@ -0,0 +1,43 @@ +/* + * Copyright 2025 hbz NRW + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.metafacture.metafix.method.script; + +import org.metafacture.metafix.FixCommand; +import org.metafacture.metafix.Metafix; +import org.metafacture.metafix.Record; +import org.metafacture.metafix.Value; +import org.metafacture.metafix.api.FixFunction; + +import java.util.List; +import java.util.Map; + +@FixCommand("to_var") +public class ToVar implements FixFunction { + + /** + * Creates an instance of {@link ToVar}. + */ + public ToVar() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + final Value value = record.get(params.get(0)); + metafix.getVars().put(params.get(1), Value.isNull(value) ? options.getOrDefault(DEFAULT_OPTION, "") : value.asString()); + } + +} diff --git a/metafix/src/main/resources/fix-commands.properties b/metafix/src/main/resources/fix-commands.properties new file mode 100644 index 000000000..f468a2797 --- /dev/null +++ b/metafix/src/main/resources/fix-commands.properties @@ -0,0 +1,5 @@ +org.metafacture.metafix.bind +org.metafacture.metafix.conditional +org.metafacture.metafix.method.field +org.metafacture.metafix.method.record +org.metafacture.metafix.method.script diff --git a/metafix/src/test/java/org/metafacture/metafix/MetafixScriptTest.java b/metafix/src/test/java/org/metafacture/metafix/MetafixScriptTest.java index 2141ed055..9600019e3 100644 --- a/metafix/src/test/java/org/metafacture/metafix/MetafixScriptTest.java +++ b/metafix/src/test/java/org/metafacture/metafix/MetafixScriptTest.java @@ -46,7 +46,7 @@ public class MetafixScriptTest { 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"; - @Mock(name = "org.metafacture.metafix.FixMethod") + @Mock(name = "org.metafacture.metafix.method.script.Log") private Logger fixMethodLogger; @Mock @@ -554,7 +554,7 @@ public void shouldAbortProcessOnExecutionException() { @Test public void shouldAbortProcessOnProcessException() { - MetafixTestHelpers.assertProcessException(IllegalArgumentException.class, "No enum constant org.metafacture.metafix.FixMethod.foo", () -> + MetafixTestHelpers.assertProcessException(IllegalArgumentException.class, "Unsupported Fix method: foo", () -> assertStrictness(Metafix.Strictness.EXPRESSION, "foo()", false, null, o -> { }) ); diff --git a/metafix/src/test/java/org/metafacture/metafix/MetafixTest.java b/metafix/src/test/java/org/metafacture/metafix/MetafixTest.java index d1ad8c466..79e9ed39a 100644 --- a/metafix/src/test/java/org/metafacture/metafix/MetafixTest.java +++ b/metafix/src/test/java/org/metafacture/metafix/MetafixTest.java @@ -16,6 +16,10 @@ package org.metafacture.metafix; +import org.metafacture.metafix.api.FixFunction; +import org.metafacture.metafix.api.FixRegistry; +import org.metafacture.metafix.bind.ListAs; +import org.metafacture.metafix.bind.Once; import org.metafacture.metamorph.api.Maps; import org.junit.jupiter.api.Assertions; @@ -25,6 +29,7 @@ import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; /** @@ -177,4 +182,175 @@ public void shouldMatchTwoDigitIndexInPath() { Assertions.assertEquals(concretePath, result.toString()); } + @Test + public void shouldRegisterNamedCommand() { + final FixRegistry registry = new Metafix().getRegistry(); + final String name = "bla"; + final Class clazz = Once.class; + + Assertions.assertFalse(registry.isRegisteredCommand(name)); + Assertions.assertTrue(registry.registerCommand(name, clazz)); + Assertions.assertTrue(registry.isRegisteredCommand(name)); + } + + @Test + public void shouldRegisterAnnotatedCommand() { + final FixRegistry registry = new Metafix().getRegistry(); + final String name = "test_command"; + final Class clazz = TestCommand1.class; + + Assertions.assertFalse(registry.isRegisteredCommand(name)); + Assertions.assertEquals(name, registry.registerCommand(clazz)); + Assertions.assertTrue(registry.isRegisteredCommand(name)); + } + + @Test + public void shouldNotRegisterSameAnnotatedCommandRepeatedly() { + final FixRegistry registry = new Metafix().getRegistry(); + final String name = "test_command"; + final Class clazz = TestCommand1.class; + + Assertions.assertEquals(name, registry.registerCommand(clazz)); + Assertions.assertNull(registry.registerCommand(clazz)); + } + + @Test + public void shouldNotRegisterUnannotatedCommand() { + final FixRegistry registry = new Metafix().getRegistry(); + final Class clazz = TestCommand2.class; + + Assertions.assertThrows(IllegalArgumentException.class, () -> registry.registerCommand(clazz)); + } + + @Test + public void shouldNotRegisterCommandThatIsNoCommand() { + final FixRegistry registry = new Metafix().getRegistry(); + final String name = "bla"; + final Class clazz = MetafixTest.class; + + Assertions.assertThrows(IllegalArgumentException.class, () -> registry.registerCommand(name, clazz)); + } + + @Test + public void shouldNotRegisterSameCommandRepeatedly() { + final FixRegistry registry = new Metafix().getRegistry(); + final String name = "bla"; + final Class clazz = Once.class; + + Assertions.assertTrue(registry.registerCommand(name, clazz)); + Assertions.assertFalse(registry.registerCommand(name, clazz)); + } + + @Test + public void shouldRegisterSameCommandInDifferentRegistry() { + final FixRegistry registry1 = new Metafix().getRegistry(); + final FixRegistry registry2 = new Metafix().getRegistry(); + final String name = "bla"; + final Class clazz = Once.class; + + Assertions.assertTrue(registry1.registerCommand(name, clazz)); + Assertions.assertTrue(registry2.registerCommand(name, clazz)); + } + + @Test + public void shouldRegisterSameCommandRepeatedlyAfterUnregistering() { + final FixRegistry registry = new Metafix().getRegistry(); + final String name = "bla"; + final Class clazz = Once.class; + + Assertions.assertTrue(registry.registerCommand(name, clazz)); + Assertions.assertEquals(clazz, registry.unregisterBind(name)); + Assertions.assertTrue(registry.registerCommand(name, clazz)); + } + + @Test + public void shouldRegisterSameCommandUnderDifferentName() { + final FixRegistry registry = new Metafix().getRegistry(); + final String name1 = "bla"; + final String name2 = "blub"; + final Class clazz = Once.class; + + Assertions.assertTrue(registry.registerCommand(name1, clazz)); + Assertions.assertTrue(registry.registerCommand(name2, clazz)); + } + + @Test + public void shouldNotRegisterDifferentCommandUnderSameName() { + final FixRegistry registry = new Metafix().getRegistry(); + final String name = "bla"; + final Class clazz1 = Once.class; + final Class clazz2 = ListAs.class; + + Assertions.assertTrue(registry.registerCommand(name, clazz1)); + Assertions.assertThrows(IllegalArgumentException.class, () -> registry.registerCommand(name, clazz2)); + } + + @Test + public void shouldRegisterDifferentCommandUnderSameNameInDifferentRegistry() { + final FixRegistry registry1 = new Metafix().getRegistry(); + final FixRegistry registry2 = new Metafix().getRegistry(); + final String name = "bla"; + final Class clazz1 = Once.class; + final Class clazz2 = ListAs.class; + + Assertions.assertTrue(registry1.registerCommand(name, clazz1)); + Assertions.assertTrue(registry2.registerCommand(name, clazz2)); + } + + @Test + public void shouldNotRegisterCommandWithoutName() { + final FixRegistry registry = new Metafix().getRegistry(); + final String name = null; + final Class clazz = Once.class; + + Assertions.assertThrows(NullPointerException.class, () -> registry.registerCommand(name, clazz)); + } + + @Test + public void shouldNotRegisterCommandWithoutClass() { + final FixRegistry registry = new Metafix().getRegistry(); + final String name = "bla"; + final Class clazz = null; + + Assertions.assertThrows(NullPointerException.class, () -> registry.registerCommand(name, clazz)); + } + + @Test + public void shouldRegisterCommandInConstructor() { + final String name = "bla"; + final Class clazz = Once.class; + + final Metafix metafix = new Metafix(m -> { + final FixRegistry registry = m.getRegistry(); + + Assertions.assertFalse(registry.isRegisteredCommand(name)); + Assertions.assertTrue(registry.registerCommand(name, clazz)); + + return null; + }); + + final FixRegistry registry = metafix.getRegistry(); + Assertions.assertTrue(registry.isRegisteredCommand(name)); + } + + @FixCommand("test_command") + private static class TestCommand1 implements FixFunction { + + private TestCommand1() { + } + + @Override + public void apply(final Metafix metafix, final Record record, final List params, final Map options) { + // nothing to do + } + + } + + private static class TestCommand2 extends TestCommand1 { + + private TestCommand2() { + } + + } + } diff --git a/metafix/src/test/java/org/metafacture/metafix/util/TestFunction.java b/metafix/src/test/java/org/metafacture/metafix/util/TestFunction.java index 5db0d7f17..5cef9e7f0 100644 --- a/metafix/src/test/java/org/metafacture/metafix/util/TestFunction.java +++ b/metafix/src/test/java/org/metafacture/metafix/util/TestFunction.java @@ -16,11 +16,11 @@ package org.metafacture.metafix.util; -import org.metafacture.metafix.FixMethod; import org.metafacture.metafix.Metafix; import org.metafacture.metafix.Record; import org.metafacture.metafix.Value; import org.metafacture.metafix.api.FixFunction; +import org.metafacture.metafix.method.record.AddField; import java.util.List; import java.util.Map; @@ -34,7 +34,7 @@ public TestFunction() { public void apply(final Metafix metafix, final Record record, final List params, final Map options) { params.add(params.get(0).toUpperCase()); params.set(0, "test"); - FixMethod.add_field.apply(metafix, record, params, options); + new AddField().apply(metafix, record, params, options); options.forEach((k, v) -> record.set(k, new Value(v))); } diff --git a/metafix/src/test/java/org/metafacture/metafix/util/TestPredicate.java b/metafix/src/test/java/org/metafacture/metafix/util/TestPredicate.java index 94d179aaa..78c6c4d0e 100644 --- a/metafix/src/test/java/org/metafacture/metafix/util/TestPredicate.java +++ b/metafix/src/test/java/org/metafacture/metafix/util/TestPredicate.java @@ -16,10 +16,11 @@ package org.metafacture.metafix.util; -import org.metafacture.metafix.FixConditional; import org.metafacture.metafix.Metafix; import org.metafacture.metafix.Record; import org.metafacture.metafix.api.FixPredicate; +import org.metafacture.metafix.conditional.AnyEqual; +import org.metafacture.metafix.conditional.Exists; import java.util.List; import java.util.Map; @@ -31,8 +32,8 @@ public TestPredicate() { @Override public boolean test(final Metafix metafix, final Record record, final List params, final Map options) { - return !FixConditional.exists.test(metafix, record, params, options) || - FixConditional.any_equal.test(metafix, record, params, options); + return !new Exists().test(metafix, record, params, options) || + new AnyEqual().test(metafix, record, params, options); } } diff --git a/metafix/src/test/resources/org/metafacture/metafix/integration/script/fromJson/toJson/strictnessAbortProcessOnProcessException/expected.err b/metafix/src/test/resources/org/metafacture/metafix/integration/script/fromJson/toJson/strictnessAbortProcessOnProcessException/expected.err index 0ce27caa1..382c42b57 100644 --- a/metafix/src/test/resources/org/metafacture/metafix/integration/script/fromJson/toJson/strictnessAbortProcessOnProcessException/expected.err +++ b/metafix/src/test/resources/org/metafacture/metafix/integration/script/fromJson/toJson/strictnessAbortProcessOnProcessException/expected.err @@ -1,3 +1,3 @@ ^Exception in thread "main" org\.metafacture\.commons\.reflection\.ReflectionException: class could not be instantiated: class org\.metafacture\.metafix\.Metafix$ ^Caused by: org\.metafacture\.metafix\.FixProcessException: Error while executing Fix expression \(at file:.*/metafix/src/test/resources/org/metafacture/metafix/integration/script/fromJson/toJson/strictnessAbortProcessOnProcessException/test\.fix, line 2\): foo\(\)$ -^Caused by: java\.lang\.IllegalArgumentException: No enum constant org\.metafacture\.metafix\.FixMethod.foo$ +^Caused by: java\.lang\.IllegalArgumentException: Unsupported Fix method: foo$