use crate::{Blueprint, Forma, FormaContext, Manifest, Outcome, Query, Row, Source, Value};
use crate::raw::rows_from_outcome;
use crate::view::{derive_columns, derive_filter_layout};
use indexmap::IndexMap;
use serde::Serialize;
use serde_json::Value as JsonValue;
use wasm_bindgen::prelude::*;
#[wasm_bindgen(start)]
pub fn start() {
console_error_panic_hook::set_once();
}
#[wasm_bindgen]
pub fn manifest(blueprint_json: &str, query_json: &str) -> std::result::Result<String, String> {
let blueprint: Blueprint = parse_json(blueprint_json, "blueprint")?;
let query: Query = parse_json(query_json, "query")?;
let manifest = blueprint.manifest(query).map_err(to_string)?;
serde_json::to_string(&manifest).map_err(to_string)
}
#[wasm_bindgen]
pub fn resolve(
blueprint_json: &str,
manifest_json: &str,
source_json: &str,
) -> std::result::Result<String, String> {
let blueprint: Blueprint = parse_json(blueprint_json, "blueprint")?;
let manifest: Manifest = parse_json(manifest_json, "manifest")?;
let source: Source = parse_json(source_json, "source")?;
let result = blueprint.resolve(&manifest, &source).map_err(to_string)?;
serde_json::to_string(&result).map_err(to_string)
}
#[wasm_bindgen]
pub fn resolve_query(
blueprint_json: &str,
query_json: &str,
source_json: &str,
) -> std::result::Result<String, String> {
let blueprint: Blueprint = parse_json(blueprint_json, "blueprint")?;
let query: Query = parse_json(query_json, "query")?;
let source: Source = parse_json(source_json, "source")?;
let (manifest, outcome, rows) = blueprint.resolve_query(query, &source).map_err(to_string)?;
#[derive(Serialize)]
struct Out<'a> {
manifest: &'a Manifest,
result: &'a Outcome,
rows: &'a Vec<Row>,
}
serde_json::to_string(&Out { manifest: &manifest, result: &outcome, rows: &rows })
.map_err(to_string)
}
#[wasm_bindgen]
pub fn rows_array(result_json: &str) -> std::result::Result<String, String> {
let outcome: Outcome = parse_json(result_json, "result")?;
let rows = rows_from_outcome(&outcome);
serde_json::to_string(&rows).map_err(to_string)
}
#[wasm_bindgen]
pub fn is_single(manifest_json: &str, outcome_json: &str) -> std::result::Result<bool, String> {
let manifest: Manifest = parse_json(manifest_json, "manifest")?;
let outcome: Outcome = parse_json(outcome_json, "outcome")?;
Ok(crate::is_single(&manifest, &outcome))
}
#[wasm_bindgen]
pub fn columns(blueprint_json: &str, manifest_json: &str) -> std::result::Result<String, String> {
let blueprint: Blueprint = parse_json(blueprint_json, "blueprint")?;
let manifest: Manifest = parse_json(manifest_json, "manifest")?;
let columns = derive_columns(&blueprint, &manifest).map_err(to_string)?;
serde_json::to_string(&columns).map_err(to_string)
}
#[wasm_bindgen]
pub fn filter_rows(rows_json: &str, filters_json: &str) -> std::result::Result<String, String> {
let rows: Vec<Row> = parse_json(rows_json, "rows")?;
let filters: IndexMap<String, Value> = parse_json(filters_json, "filters")?;
let filtered = crate::filter_rows(&rows, &filters);
serde_json::to_string(&filtered).map_err(to_string)
}
#[wasm_bindgen]
pub fn display_value(
blueprint_json: &str,
outcome_json: &str,
model_name: &str,
field_name: &str,
value_json: &str,
) -> std::result::Result<String, String> {
let blueprint: Blueprint = parse_json(blueprint_json, "blueprint")?;
let outcome: Outcome = parse_json(outcome_json, "outcome")?;
let value: Value = parse_json(value_json, "value")?;
Ok(crate::display_value(
&blueprint, &outcome, model_name, field_name, &value,
))
}
#[wasm_bindgen]
pub fn make_field(
kind: &str,
label: &str,
entity_json: &str,
) -> std::result::Result<String, String> {
let entity: Option<String> = parse_json(entity_json, "entity")?;
let field = crate::make_field(kind, label, entity.as_deref());
serde_json::to_string(&field).map_err(to_string)
}
#[wasm_bindgen]
pub fn filter_layout(
blueprint_json: &str,
manifest_json: &str,
) -> std::result::Result<String, String> {
let blueprint: Blueprint = parse_json(blueprint_json, "blueprint")?;
let manifest: Manifest = parse_json(manifest_json, "manifest")?;
let layout = derive_filter_layout(&blueprint, &manifest).map_err(to_string)?;
serde_json::to_string(&layout).map_err(to_string)
}
#[wasm_bindgen]
pub fn forma_to_query(
forma_json: &str,
table_name: &str,
context_json: &str,
id_json: &str,
) -> std::result::Result<String, String> {
let forma: Forma = parse_json(forma_json, "forma")?;
let context: FormaContext = parse_json(context_json, "context")?;
let id: Option<JsonValue> = {
let v: JsonValue = parse_json(id_json, "id")?;
if v.is_null() { None } else { Some(v) }
};
let query = crate::forma_to_query(&forma, table_name, &context, id.as_ref());
serde_json::to_string(&query).map_err(to_string)
}
#[wasm_bindgen]
pub fn purify_row(
blueprint_json: &str,
model_name: &str,
row_json: &str,
) -> std::result::Result<String, String> {
let blueprint: Blueprint = parse_json(blueprint_json, "blueprint")?;
let row: Row = parse_json(row_json, "row")?;
match crate::purify_row_sync(&blueprint, model_name, &row) {
Ok(()) => Ok("null".to_owned()),
Err(errors) => serde_json::to_string(&errors).map_err(to_string),
}
}
#[wasm_bindgen]
pub fn resolve_and_view(
blueprint_json: &str,
manifest_json: &str,
source_json: &str,
) -> std::result::Result<String, String> {
let blueprint: Blueprint = parse_json(blueprint_json, "blueprint")?;
let manifest: Manifest = parse_json(manifest_json, "manifest")?;
let source: Source = parse_json(source_json, "source")?;
let view = blueprint.resolve_and_view(&manifest, &source).map_err(to_string)?;
serde_json::to_string(&view).map_err(to_string)
}
#[wasm_bindgen]
pub fn apply_view(rows_json: &str, manifest_json: &str) -> std::result::Result<String, String> {
let rows: Vec<Row> = parse_json(rows_json, "rows")?;
let manifest: Manifest = parse_json(manifest_json, "manifest")?;
let result = crate::apply_view(rows, &manifest);
serde_json::to_string(&result).map_err(to_string)
}
fn parse_json<T: serde::de::DeserializeOwned>(
input: &str,
name: &str,
) -> std::result::Result<T, String> {
serde_json::from_str(input).map_err(|err| format!("invalid {name} JSON: {err}"))
}
fn to_string(err: impl std::fmt::Display) -> String {
err.to_string()
}