mirror of
https://github.com/rzmk/czv.git
synced 2025-12-19 08:09:24 +00:00
feat: add czv, czv-wasm, and czv-python (init release)
This commit is contained in:
commit
9799ab694b
40 changed files with 70383 additions and 0 deletions
17
czv-wasm/Cargo.toml
Normal file
17
czv-wasm/Cargo.toml
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
[package]
|
||||
name = "czv-wasm"
|
||||
version = "0.0.0"
|
||||
authors = ["Mueez Khan"]
|
||||
description = "WASM library for performing CSV-related functions for data engineering and analysis."
|
||||
repository = "https://github.com/rzmk/czv"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.86"
|
||||
csv = "1.3.0"
|
||||
thiserror = "1.0.61"
|
||||
wasm-bindgen = { version = "0.2" }
|
||||
wasm-bindgen-test = { version = "0.3.42" }
|
||||
47
czv-wasm/README.md
Normal file
47
czv-wasm/README.md
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
# czv-wasm
|
||||
|
||||
WebAssembly (JavaScript and TypeScript) library for [czv](https://github.com/rzmk/czv). czv is a library of utility functions for CSV-related data engineering and analysis tasks.
|
||||
|
||||
## Installation and example
|
||||
|
||||
```bash
|
||||
bun install czv
|
||||
```
|
||||
|
||||
Or use `npm`, `pnpm`, or `yarn` instead of `bun`.
|
||||
|
||||
```js
|
||||
import init, * as czv from "czv";
|
||||
// Must run `await init()` or `initSync()` first for web use
|
||||
await init();
|
||||
|
||||
const data = `fruits,price
|
||||
apple,2.50
|
||||
banana,3.00
|
||||
strawberry,1.50`;
|
||||
|
||||
const output = czv.rowCount(data);
|
||||
console.log(output);
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
You must have [wasm-pack](https://rustwasm.github.io/wasm-pack/installer/) installed. If you have Cargo installed you may run:
|
||||
|
||||
```bash
|
||||
cargo install wasm-pack
|
||||
```
|
||||
|
||||
### Build WASM for web
|
||||
|
||||
```bash
|
||||
wasm-pack build --release --target web
|
||||
```
|
||||
|
||||
### Test WASM for browser
|
||||
|
||||
```bash
|
||||
wasm-pack test --firefox --release
|
||||
```
|
||||
|
||||
You may replace `--firefox` with another browser such as `--chrome` and `--safari`.
|
||||
69
czv-wasm/examples/basic-demo/index.html
Normal file
69
czv-wasm/examples/basic-demo/index.html
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
<!DOCTYPE html>
|
||||
<html id="html" lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="pico.min.css" />
|
||||
<title>czv demo</title>
|
||||
</head>
|
||||
|
||||
<body style="padding:1rem">
|
||||
<div style="display: flex; gap: 2rem; justify-content: space-between;">
|
||||
<h1>czv playground</h1>
|
||||
<button class="outline secondary" style="height: fit-content; padding: 0.25rem;" onclick="const html = document.getElementById('html');
|
||||
if (html.getAttribute('data-theme') === 'light')
|
||||
html.setAttribute('data-theme', 'dark')
|
||||
else
|
||||
html.setAttribute('data-theme', 'light')">Switch
|
||||
page theme</button>
|
||||
</div>
|
||||
<p>Import a CSV file and get statistical data from running <a href="https://github.com/rzmk/czv">czv</a> in your
|
||||
browser using WASM.</p>
|
||||
<input type="file" id="upload" accept=".csv" class="hidden" />
|
||||
<label for="upload" style="display: none;" id="progress">Loading...</label>
|
||||
<table style="width: 100%;" class="striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 10rem">Output type</th>
|
||||
<th>Output</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Row count</td>
|
||||
<td id="row-count"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Column count</td>
|
||||
<td id="column-count"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<script type="module">
|
||||
const input = document.getElementById("upload")
|
||||
const progress = document.getElementById("progress")
|
||||
|
||||
import init, * as czv from "../../pkg/czv.js";
|
||||
// Must run `await init()` or `initSync()` first for web use
|
||||
await init();
|
||||
|
||||
const fileReader = new FileReader()
|
||||
|
||||
fileReader.onloadstart = () => {
|
||||
progress.style.display = "block";
|
||||
}
|
||||
|
||||
fileReader.onloadend = () => {
|
||||
document.getElementById("column-count").innerText = czv.columnCount(fileReader.result)
|
||||
document.getElementById("row-count").innerText = czv.rowCount(fileReader.result)
|
||||
progress.style.display = "none";
|
||||
}
|
||||
|
||||
input.addEventListener("change", () => {
|
||||
fileReader.readAsText(input.files[0])
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
4
czv-wasm/examples/basic-demo/pico.min.css
vendored
Normal file
4
czv-wasm/examples/basic-demo/pico.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
32
czv-wasm/src/count.rs
Normal file
32
czv-wasm/src/count.rs
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
use crate::Result;
|
||||
use csv::ReaderBuilder;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
/// Returns a count of the total number of rows.
|
||||
///
|
||||
/// @param {string} `file_data` CSV file data.
|
||||
/// @param {boolean | undefined} `include_header_row` Specify whether to include the header row (first row) in the row count. Default is false.
|
||||
/// @returns {number}
|
||||
#[wasm_bindgen(skip_jsdoc, js_name = rowCount)]
|
||||
pub fn row_count(file_data: String, include_header_row: Option<bool>) -> Result<usize> {
|
||||
let mut rdr = ReaderBuilder::new();
|
||||
|
||||
rdr.has_headers(!include_header_row.unwrap_or(false));
|
||||
return Ok(rdr.from_reader(file_data.as_bytes()).records().count());
|
||||
}
|
||||
|
||||
/// Returns a count of the total number of columns (fields).
|
||||
///
|
||||
/// ## Arguments
|
||||
///
|
||||
/// @param {string} `file_data` CSV file data.
|
||||
#[wasm_bindgen(skip_jsdoc, js_name = columnCount)]
|
||||
pub fn column_count(file_data: Option<String>) -> Result<usize> {
|
||||
let rdr = ReaderBuilder::new();
|
||||
|
||||
if let Some(file_data) = file_data {
|
||||
return Ok(rdr.from_reader(file_data.as_bytes()).headers()?.len());
|
||||
} else {
|
||||
bail!("Could not determine a file path or file data for column_count_builder.");
|
||||
}
|
||||
}
|
||||
30
czv-wasm/src/lib.rs
Normal file
30
czv-wasm/src/lib.rs
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
use wasm_bindgen::JsValue;
|
||||
|
||||
// Error-handling helpers
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
#[error("{0}")]
|
||||
pub struct CzvError(anyhow::Error);
|
||||
|
||||
impl From<csv::Error> for CzvError {
|
||||
fn from(value: csv::Error) -> Self {
|
||||
value.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<JsValue> for CzvError {
|
||||
fn into(self) -> JsValue {
|
||||
JsValue::from_str(self.to_string().as_str())
|
||||
}
|
||||
}
|
||||
|
||||
pub type Result<T> = anyhow::Result<T, CzvError>;
|
||||
|
||||
#[allow(unused_macros)]
|
||||
macro_rules! bail {
|
||||
($err:expr $(,)?) => {
|
||||
return Err(crate::CzvError(anyhow::anyhow!($err)))
|
||||
};
|
||||
}
|
||||
|
||||
// Command imports
|
||||
pub mod count;
|
||||
19
czv-wasm/tests/count.rs
Normal file
19
czv-wasm/tests/count.rs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
use czv_wasm;
|
||||
use czv_wasm::Result;
|
||||
use wasm_bindgen_test::*;
|
||||
wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
|
||||
|
||||
#[test]
|
||||
#[wasm_bindgen_test]
|
||||
fn basic() -> Result<()> {
|
||||
let result = czv_wasm::count::row_count(
|
||||
"fruit,price
|
||||
apple,2.00
|
||||
banana,1.50
|
||||
strawberry,3.00"
|
||||
.to_string(),
|
||||
Some(false),
|
||||
)?;
|
||||
assert_eq!(result, 3);
|
||||
Ok(())
|
||||
}
|
||||
1
czv-wasm/tests/tests.rs
Normal file
1
czv-wasm/tests/tests.rs
Normal file
|
|
@ -0,0 +1 @@
|
|||
mod count;
|
||||
Loading…
Add table
Add a link
Reference in a new issue