From fbce2dd1cca8170be0193709cc4997b585a6e041 Mon Sep 17 00:00:00 2001 From: lrlna Date: Mon, 7 Jan 2019 14:09:48 +0100 Subject: [PATCH 1/4] point bson package to a fork with wasm support --- .travis.yml | 2 ++ Cargo.toml | 9 ++------- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9f2ad35..3ebb2b3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,8 @@ before_script: | # cargo install wasm-pack # wasm-pack init script: | + rustup target add wasm32-unknown-unknown + cargo check --target wasm32-unknown-unknown cargo fmt --all -- --check && cargo clippy -- -D all && cargo build --verbose && diff --git a/Cargo.toml b/Cargo.toml index d7f381e..e68d6c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,13 +14,8 @@ failure = "0.1.2" serde = "1.0" serde_json = "1.0" serde_derive = "1.0" -bson = "0.12.2" -mongodb = "0.3.10" +bson = { git = "https://github.com/lrlna/bson-rs", branch = "wasm-suport" } [dependencies.wasm-bindgen] version = "^0.2" -features = ["serde-serialize"] - -[dev-dependencies] -bson = "0.12.1" -mongodb = "0.3.9" +features = ["serde-serialize"] \ No newline at end of file From 7e3cec2f914b7b92a28e16e41595d03f4fbee6ed Mon Sep 17 00:00:00 2001 From: lrlna Date: Tue, 8 Jan 2019 15:22:50 +0100 Subject: [PATCH 2/4] wrap wasm-bindgen export functions to be able to return an error string as JsValue in Result<> --- Cargo.toml | 7 ++- src/lib.rs | 55 +++++++++++++++++++++--- tests/schema.rs | 110 ++++++++++++++++++++++++------------------------ 3 files changed, 111 insertions(+), 61 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e68d6c0..995e872 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,13 +9,18 @@ authors = ["Irina Shestak "] readme = "README.md" edition = "2018" +[lib] +crate-type = ["cdylib"] + [dependencies] failure = "0.1.2" serde = "1.0" serde_json = "1.0" serde_derive = "1.0" bson = { git = "https://github.com/lrlna/bson-rs", branch = "wasm-suport" } +wee_alloc = "0.4.2" +console_error_panic_hook = "0.1.5" [dependencies.wasm-bindgen] version = "^0.2" -features = ["serde-serialize"] \ No newline at end of file +features = ["serde-serialize"] diff --git a/src/lib.rs b/src/lib.rs index da0b39e..bc59ba7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,6 +14,14 @@ extern crate serde; extern crate serde_json; use serde_json::Value; +use wasm_bindgen::prelude::*; + +// using custom allocator which is built specifically for wasm; makes it smaller +// + faster +extern crate wee_alloc; +#[global_allocator] +static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; + use std::mem; use std::string::String; @@ -26,20 +34,44 @@ use crate::field_type::FieldType; mod value_type; use crate::value_type::ValueType; -// mod error; -// pub use error::{Error, ErrorKind, Result}; +// i have a method that returns a result with boxed error which i can't add the wasm-bindgen tag to them. intead i am wrapping my methods extern crate failure; -/// Custom Result type -pub type Result = std::result::Result; +#[wasm_bindgen] #[derive(Serialize, Deserialize, Debug, Clone)] pub struct SchemaParser { count: i64, fields: Vec, } +#[wasm_bindgen] +impl SchemaParser { + #[wasm_bindgen(constructor)] + #[wasm_bindgen(js_name = "new")] + pub fn wasm_new() -> Self { + Self::new() + } + + #[wasm_bindgen(js_name = "write")] + pub fn wasm_write(&mut self, json: &str) -> Result<(), JsValue> { + match self.write(json) { + Err(e) => Err(JsValue::from_str(&format!("{}", e))), + _ => Ok(()), + } + } + + #[wasm_bindgen(js_name = "toJson")] + pub fn wasm_to_json(&mut self) -> Result { + match self.to_json() { + Err(e) => Err(JsValue::from_str(&format!("{}", e))), + Ok(val) => Ok(val), + } + } +} + impl SchemaParser { + #[inline] pub fn new() -> Self { SchemaParser { count: 0, @@ -47,7 +79,11 @@ impl SchemaParser { } } - pub fn write(&mut self, json: &str) -> Result<()> { + #[inline] + pub fn write( + &mut self, + json: &str, + ) -> Result<(), Box> { let val: Value = serde_json::from_str(json)?; let bson = Bson::from(val); // should do a match for NoneError @@ -58,15 +94,20 @@ impl SchemaParser { Ok(()) } - pub fn to_json(&self) -> Result { + #[inline] + pub fn to_json( + &self, + ) -> Result> { Ok(serde_json::to_string(&self)?) } + #[inline] fn add_to_fields(&mut self, field: Field) { self.fields.push(field) } // why do i have to explicitly return true instead of just returning field.name == key + #[inline] fn does_field_name_exist(&mut self, key: &str) -> bool { for field in &mut self.fields { if field.name == key { @@ -76,6 +117,7 @@ impl SchemaParser { false } + #[inline] fn update_field(&mut self, key: &str, value: &Bson) { // need to set count here as well // maybe store the names in a hash map so then it's easier to look up the key @@ -90,6 +132,7 @@ impl SchemaParser { } } + #[inline] fn generate_field(&mut self, doc: Document, path: &Option) { let count = 0; diff --git a/tests/schema.rs b/tests/schema.rs index 2f0214b..7bb8b7d 100644 --- a/tests/schema.rs +++ b/tests/schema.rs @@ -1,54 +1,56 @@ -use failure::Error; -use mongodb_schema_parser::SchemaParser; -use std::fs; - -#[test] -fn simple_schema_gen() -> Result<(), Error> { - let doc = r#"{ - "_id": { - "$oid": "50319491fe4dce143835c552" - }, - "membership_status": "ACTIVE", - "name": "Ellie J Clarke", - "gender": "male", - "age": 36, - "phone_no": "+19786213180", - "last_login": { - "$date": "2014-01-31T22:26:33.000Z" - }, - "address": { - "city": "El Paso, Texas", - "street": "133 Aloha Ave", - "postal_code": 50017, - "country": "USA", - "location": { - "type": "Point", - "coordinates":[-73.4446279457308,40.89674015263909] - } - }, - "favorite_feature": "Auth", - "email": "corefinder88@hotmail.com" - }"#; - - let mut schema_parser = SchemaParser::new(); - schema_parser.write(doc)?; - - let schema = schema_parser.to_json(); - println!("{:?}", schema); - Ok(()) -} - -#[test] -fn json_file_gen() -> Result<(), Error> { - // TODO: check timing on running this test - let file = fs::read_to_string("examples/fanclub.json")?; - let vec: Vec<&str> = file.trim().split('\n').collect(); - let mut schema_parser = SchemaParser::new(); - for json in vec { - // this panics i think ? - schema_parser.write(&json)?; - } - let schema = schema_parser.to_json(); - println!("{:?}", schema); - Ok(()) -} +// these set of tests cannot run with cdylib in cargo.toml +// use failure::Error; +// use mongodb_schema_parser::SchemaParser; +// use std::fs; +// +// #[test] +// fn simple_schema_gen() -> Result<(), Error> { +// let doc = r#"{ +// "_id": { +// "$oid": "50319491fe4dce143835c552" +// }, +// "membership_status": "ACTIVE", +// "name": "Ellie J Clarke", +// "gender": "male", +// "age": 36, +// "phone_no": "+19786213180", +// "last_login": { +// "$date": "2014-01-31T22:26:33.000Z" +// }, +// "address": { +// "city": "El Paso, Texas", +// "street": "133 Aloha Ave", +// "postal_code": 50017, +// "country": "USA", +// "location": { +// "type": "Point", +// "coordinates":[-73.4446279457308,40.89674015263909] +// } +// }, +// "favorite_feature": "Auth", +// "email": "corefinder88@hotmail.com" +// }"#; +// +// let mut schema_parser = SchemaParser::new(); +// schema_parser.write(doc)?; +// +// let schema = schema_parser.to_json(); +// println!("{:?}", schema); +// Ok(()) +// } +// +// #[test] +// fn json_file_gen() -> Result<(), Error> { +// // TODO: check timing on running this test +// let file = fs::read_to_string("examples/fanclub.json")?; +// let vec: Vec<&str> = file.trim().split('\n').collect(); +// let mut schema_parser = SchemaParser::new(); +// for json in vec { +// // this panics i think ? +// schema_parser.write(&json)?; +// } +// let schema = schema_parser.to_json(); +// println!("{:?}", schema); +// Ok(()) +// } +// From cfdca876814b908a6f175067e154e5d9c5c1bd06 Mon Sep 17 00:00:00 2001 From: lrlna Date: Wed, 9 Jan 2019 18:43:15 +0100 Subject: [PATCH 3/4] add js usage to readme --- README.md | 29 +++++++++++++++++++++++++++-- src/lib.rs | 5 +++-- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index f646da1..5884811 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,13 @@ [![crates.io version][1]][2] [![build status][3]][4] [![downloads][5]][6] [![docs.rs docs][7]][8] -MongoDB Schema Parser. +MongoDB Schema Parser. This library is meant to be used in Rust or as Web +Assembly module in JavaScript. - [Documentation][8] - [Crates.io][2] -## Usage +## Usage: in Rust ```rust use SchemaParser @@ -22,6 +23,30 @@ pub fn main () { } ``` +## Usage: in JavaScript +Make sure your environment is setup for Web Assembly usage. +```js +import { SchemaParser } from "mongodb-schema-parser"; + +const schemaParser = new SchemaParser() + +// get the json file +fetch('./fanclub.json') + .then(response => response.text()) + .then(data => { + var json = data.split("\n") + for (var i = 0; i < json.length; i++) { + if (json[i] !== '') { + // feed the parser json line by line + schemaParser.write(json[i]) + } + } + // get the result as a json string + var result = schemaParser.toJson() + console.log(result) + }) +``` + ## Installation ```sh $ cargo add mongodb-schema-parser diff --git a/src/lib.rs b/src/lib.rs index bc59ba7..4e31673 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,8 +34,6 @@ use crate::field_type::FieldType; mod value_type; use crate::value_type::ValueType; -// i have a method that returns a result with boxed error which i can't add the wasm-bindgen tag to them. intead i am wrapping my methods - extern crate failure; #[wasm_bindgen] @@ -45,6 +43,9 @@ pub struct SchemaParser { fields: Vec, } +// Need to wrap schema parser impl for wasm suppport. +// Here we are wrapping the exported to JS land methods and mathing on Result to +// turn the error message to JsValue. #[wasm_bindgen] impl SchemaParser { #[wasm_bindgen(constructor)] From 468bb707a0e064b7b52c2acfdc41bfe4cfc3485a Mon Sep 17 00:00:00 2001 From: lrlna Date: Fri, 11 Jan 2019 09:41:44 +0100 Subject: [PATCH 4/4] fix && in travis.yml scripts --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3ebb2b3..5157016 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,9 +10,9 @@ before_script: | # wasm-pack init script: | rustup target add wasm32-unknown-unknown - cargo check --target wasm32-unknown-unknown cargo fmt --all -- --check && cargo clippy -- -D all && cargo build --verbose && - cargo test --verbose + cargo test --verbose && + cargo check --target wasm32-unknown-unknown cache: cargo