Skip to content
This repository was archived by the owner on Jan 13, 2023. It is now read-only.
Merged
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
4 changes: 3 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ before_script: |
# cargo install wasm-pack
# wasm-pack init
script: |
rustup target add 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
12 changes: 6 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,18 @@ authors = ["Irina Shestak <[email protected]>"]
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 = "0.12.2"
mongodb = "0.3.10"
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"]

[dev-dependencies]
bson = "0.12.1"
mongodb = "0.3.9"
29 changes: 27 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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
Expand Down
58 changes: 51 additions & 7 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -26,28 +34,57 @@ use crate::field_type::FieldType;
mod value_type;
use crate::value_type::ValueType;

// mod error;
// pub use error::{Error, ErrorKind, Result};

extern crate failure;
/// Custom Result type
pub type Result<T> = std::result::Result<T, failure::Error>;

#[wasm_bindgen]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct SchemaParser {
count: i64,
fields: Vec<Field>,
}

// 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)]
#[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<String, JsValue> {
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,
fields: Vec::new(),
}
}

pub fn write(&mut self, json: &str) -> Result<()> {
#[inline]
pub fn write(
&mut self,
json: &str,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let val: Value = serde_json::from_str(json)?;
let bson = Bson::from(val);
// should do a match for NoneError
Expand All @@ -58,15 +95,20 @@ impl SchemaParser {
Ok(())
}

pub fn to_json(&self) -> Result<String> {
#[inline]
pub fn to_json(
&self,
) -> Result<String, Box<dyn std::error::Error + Send + Sync>> {
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 {
Expand All @@ -76,6 +118,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
Expand All @@ -90,6 +133,7 @@ impl SchemaParser {
}
}

#[inline]
fn generate_field(&mut self, doc: Document, path: &Option<String>) {
let count = 0;

Expand Down
110 changes: 56 additions & 54 deletions tests/schema.rs
Original file line number Diff line number Diff line change
@@ -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": "[email protected]"
}"#;

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": "[email protected]"
// }"#;
//
// 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(())
// }
//