Skip to content

Commit d613dba

Browse files
committed
add example for plugin and more documentation for --help
1 parent a5391f6 commit d613dba

File tree

2 files changed

+108
-4
lines changed

2 files changed

+108
-4
lines changed
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/// Example of kafka-json-processor-generator plugin, in Rust.
2+
///
3+
/// This plugin has the same purpose as ./kjp-generator-generators/static_field.sh.
4+
/// The following code will generate a processor that adds a static field to the output JSON.
5+
/// See the test at the end of this file for an example of generated code.
6+
///
7+
/// This executable needs to be run with the following arguments:
8+
/// `./static_field $function_name field $field_name value $static_value`
9+
/// Example:
10+
/// `./static_field static_field_function field '$.hello' value 'Greetings, folks!'`
11+
///
12+
/// It will be activated by placing a compiled executable in the generators directory
13+
/// (default: ./generators, can be set with --generators-path <GENERATORS_PATH> when using kjp_generator).
14+
15+
use kjp_generator_plugin::{GeneratorError, json_path_to_object_key, JsonFieldName, ProcessorParams, return_generated};
16+
use kjp_generator_plugin::GeneratorError::RequiredConfigNotFound;
17+
18+
fn main() {
19+
return_generated(static_field);
20+
}
21+
22+
/// Generates a processor that adds a static field to JSON
23+
///
24+
/// This generates a function that adds a static field to a JSON from topic.
25+
/// Available config options:
26+
/// - "field" - static field name
27+
/// - "value" - a string to put in this field
28+
pub fn static_field(params: ProcessorParams) -> Result<String, GeneratorError> {
29+
let function_name = params.function_name;
30+
let config = params.config;
31+
32+
let target_field = json_path_to_object_key(
33+
config.get("field")
34+
.ok_or_else(|| RequiredConfigNotFound {
35+
function_name: function_name.to_string(),
36+
field_name: "field".to_string(),
37+
description: None,
38+
})?
39+
);
40+
41+
let value = config.get("value")
42+
.ok_or_else(|| RequiredConfigNotFound {
43+
function_name: function_name.to_string(),
44+
field_name: "value".to_string(),
45+
description: None,
46+
})?
47+
.escape_for_json();
48+
49+
Ok(FUNCTION_TEMPLATE
50+
.replace(FUNCTION_NAME, &function_name)
51+
.replace(TARGET_FIELD, &target_field)
52+
.replace(VALUE, &value)
53+
)
54+
}
55+
56+
const FUNCTION_TEMPLATE: &str = r##"
57+
fn %%FUNCTION_NAME%%(_input: &Value, message: &mut OutputMessage) -> Result<(), ProcessingError> {
58+
message.insert_val(%%TARGET_FIELD%%, Value::String("%%VALUE%%".to_string()))?;
59+
Ok(())
60+
}
61+
"##;
62+
63+
const FUNCTION_NAME: &str = "%%FUNCTION_NAME%%";
64+
const TARGET_FIELD: &str = "%%TARGET_FIELD%%";
65+
const VALUE: &str = "%%VALUE%%";
66+
67+
#[cfg(test)]
68+
mod test {
69+
use std::collections::HashMap;
70+
use kjp_generator_plugin::ProcessorParams;
71+
use crate::static_field;
72+
73+
#[test]
74+
fn should_generate_static_field() {
75+
let mut config = HashMap::new();
76+
config.insert("field".to_string(), "$.example[0]".to_string());
77+
config.insert("value".to_string(), "abcdef".to_string());
78+
let result = static_field(ProcessorParams {
79+
function_name: "abc1".to_string(),
80+
config,
81+
});
82+
assert_eq!(Ok(r##"
83+
fn abc1(_input: &Value, message: &mut OutputMessage) -> Result<(), ProcessingError> {
84+
message.insert_val(&[Key("example".to_string()), Index(0)], Value::String("abcdef".to_string()))?;
85+
Ok(())
86+
}
87+
"##.to_string()), result);
88+
}
89+
}

kjp-generator/src/main.rs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,34 @@ fn main() {
2121
#[derive(Parser, Debug)]
2222
#[command(author, version, about, long_about = None)]
2323
struct Args {
24-
/// Path to template file (YAML)
24+
/// Path to template file (YAML).
25+
///
26+
/// A template file is a configuration file that will be used to generate the final project.
27+
/// 'The final project' - Rust project with generated code to process messages from selected Kafka topics.
2528
#[arg(short, long)]
2629
template: String,
2730

28-
/// Output directory of generated project
31+
/// Output directory of generated project.
32+
///
33+
/// This will be the directory where the project with message processors will be generated.
34+
/// This project will contain generated code to process messages basing on the supplied template.
35+
/// The code will need to be compiled afterwards.
2936
#[arg(short, long)]
3037
output: String,
3138

32-
/// Custom path to kafka_json_processor_core
39+
/// Custom path to kafka_json_processor_core.
40+
///
41+
/// kafka_json_processor_code is a dependency that contains code that will prevent boilerplate in the generated project.
42+
/// By default, it will use hardcoded version from `crates.io`.
43+
/// If it doesn't work (or you want to use custom core), supply a path to the source code of kafka_json_processor_code.
3344
#[arg(short, long)]
3445
core_path: Option<String>,
3546

36-
/// Custom path to processor generators
47+
/// Custom path to processor generators.
48+
///
49+
/// Put all processor generators in this directory.
50+
/// This directory will be scanned for available files and those files will
51+
/// be used as executable plugins to generate any code requested by `generator` option in your `template.yaml`.
3752
#[arg(short, long, default_value_t = String::from("./generators"))]
3853
generators_path: String,
3954
}

0 commit comments

Comments
 (0)