Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ members = [

[package]
name = "function-runner"
version = "9.2.2"
version = "10.0.0"
edition = "2021"


Expand Down
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,26 @@ Profiling is not available in batch mode.

## Library usage

The `views` module turns run data into output. Each view borrows the data and
builds its text only when you display it:

- `ReadableBytes::from(&container)`: readable text for an input or an output.
It is pretty-printed JSON when the bytes decode to JSON or MessagePack, a hex
dump for the `Raw` codec, or the bytes as lossy UTF-8 when an output does not
decode. `encoding_error` gives the reason, and `raw` keeps the bytes.
- `TextReport::from(&result)`: the report that the CLI prints by default.
- `JsonReport::from(&result)`: the JSON that `--json` prints. It uses the
result's serde serialization, so `serde_json::to_value(&result)` has the same
fields.

```rust
use function_runner::views::{JsonReport, ReadableBytes, TextReport};

println!("{}", TextReport::from(&result));
println!("{}", JsonReport::from(&result));
println!("{}", ReadableBytes::from(&result.output));
```

To compute scale factors for many inputs, use
`bluejay_schema_analyzer::BluejaySchemaAnalyzer::with_analyzer`. It parses the
schema and query once, then calls your closure with an `analyze` function that
Expand All @@ -97,6 +117,24 @@ the schema, so a query with an unknown field still parses. The
`test_with_analyzer_analyzes_many_inputs` test in
`src/bluejay_schema_analyzer.rs` runs this pattern.

### Upgrading to 10.0

10.0 moves display code out of `BytesContainer` and `FunctionRunResult` and
into the `views` module:

| 9.x | 10.0 |
|---|---|
| `container.humanized` | `ReadableBytes::from(&container).to_string()` |
| `result.to_string()` or `format!("{result}")` | `TextReport::from(&result).to_string()` |
| `result.to_json()` | `JsonReport::from(&result).to_string()` |

Other changes:

- `BytesContainer::raw` keeps the bytes of an output that does not decode. In
9.x it was empty.
- `Codec` no longer implements `clap::ValueEnum`.
- The unused `InvalidOutput` type is removed.

## Development

Building requires a rust toolchain of `1.66.0` to `1.67.0`. `cargo install --path . --locked` will build
Expand Down
89 changes: 33 additions & 56 deletions src/container.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,6 @@ pub struct BytesContainer {
/// The JSON represantation of the bytes.
#[serde(flatten)]
pub json_value: Option<serde_json::Value>,
/// The human readable representation of the bytes.
#[serde(skip)]
pub humanized: String,
/// Context for encoding errors.
#[serde(skip)]
pub encoding_error: Option<String>,
Expand All @@ -121,7 +118,6 @@ impl Default for BytesContainer {
fn default() -> Self {
Self {
codec: Codec::Raw,
humanized: "<raw codec>".into(),
json_value: None,
raw: Default::default(),
encoding_error: None,
Expand All @@ -132,20 +128,11 @@ impl Default for BytesContainer {
impl BytesContainer {
pub fn new(ty: BytesContainerType, codec: Codec, raw: Vec<u8>) -> Result<Self> {
match codec {
Codec::Raw => {
let humanized = raw
.iter()
.map(|b| format!("{:02x}", b))
.collect::<Vec<String>>()
.join(" ");

Ok(Self {
raw,
codec,
humanized,
..Default::default()
})
}
Codec::Raw => Ok(Self {
raw,
codec,
..Default::default()
}),
Codec::Json => match ty {
BytesContainerType::Input => {
let json = serde_json::from_slice::<serde_json::Value>(&raw)
Expand All @@ -155,30 +142,25 @@ impl BytesContainer {
Ok(Self {
codec,
raw: minified_buffer,
json_value: Some(json.clone()),
humanized: serde_json::to_string_pretty(&json)?,
json_value: Some(json),
encoding_error: None,
})
}
BytesContainerType::Output => {
let mut this = Self {
codec,
..Default::default()
};

match serde_json::from_slice::<serde_json::Value>(&raw) {
Ok(json) => {
this.json_value = Some(json.clone());
this.humanized = serde_json::to_string_pretty(&json)?;
this.raw = serde_json::to_vec(&json)?;
}
Err(e) => {
this.humanized = String::from_utf8_lossy(&raw).into();
this.encoding_error = Some(e.to_string());
}
};

Ok(this)
Ok(json) => Ok(Self {
codec,
raw: serde_json::to_vec(&json)?,
json_value: Some(json),
encoding_error: None,
}),
Err(e) => Ok(Self {
codec,
raw,
json_value: None,
encoding_error: Some(e.to_string()),
}),
}
}
},
Codec::Messagepack => match ty {
Expand All @@ -191,31 +173,26 @@ impl BytesContainer {
Ok(Self {
raw: bytes,
codec,
json_value: Some(json.clone()),
humanized: serde_json::to_string_pretty(&json)?,
json_value: Some(json),
encoding_error: None,
})
}
BytesContainerType::Output => {
let mut this = Self {
codec,
..Default::default()
};

let value: Result<serde_json::Value, _> = rmp_serde::decode::from_slice(&raw);
match value {
Ok(json) => {
this.json_value = Some(json.clone());
this.humanized = serde_json::to_string_pretty(&json)?;
this.raw = raw;
}
Err(e) => {
this.humanized = String::from_utf8_lossy(&raw).into();
this.encoding_error = Some(e.to_string());
}
};

Ok(this)
Ok(json) => Ok(Self {
codec,
raw,
json_value: Some(json),
encoding_error: None,
}),
Err(e) => Ok(Self {
codec,
raw,
json_value: None,
encoding_error: Some(e.to_string()),
}),
}
}
},
}
Expand Down
13 changes: 5 additions & 8 deletions src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ pub fn run(params: FunctionRunParams) -> Result<FunctionRunResult> {
module,
} = params;

let mut io_handler = IOHandler::new(ValidatedModule::new(module)?, input.clone());
let mut io_handler = IOHandler::new(ValidatedModule::new(module)?, &input);

let mut error_logs: String = String::new();

Expand Down Expand Up @@ -165,11 +165,7 @@ pub fn run(params: FunctionRunParams) -> Result<FunctionRunResult> {
logs.extend_from_slice(error_logs.as_bytes());

let output_codec = input.codec;
let output = BytesContainer::new(
BytesContainerType::Output,
output_codec,
raw_output.to_vec(),
)?;
let output = BytesContainer::new(BytesContainerType::Output, output_codec, raw_output)?;

let name = function_path.file_name().unwrap().to_str().unwrap();
let size = function_path.metadata()?.len() / 1024;
Expand Down Expand Up @@ -439,13 +435,14 @@ mod tests {
profile_opts: None,
})?;

let report = crate::views::TextReport::from(&function_run_result).to_string();
assert!(
function_run_result.to_string().contains(
report.contains(
&"Logs would be truncated in production, length 6000 > 1000 limit"
.red()
.to_string()
),
"Expected logs to be truncated, but were: {function_run_result}"
"Expected logs to be truncated, but were: {report}"
);
Ok(())
}
Expand Down
Loading
Loading