Skip to content
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
6 changes: 3 additions & 3 deletions Cargo.lock

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

4 changes: 2 additions & 2 deletions cli/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "atomic-cli"
version = "0.12.1"
version = "0.13.0"
authors = ["Joep Meindertsma <joep@argu.co>"]
edition = "2018"
license = "MIT"
Expand All @@ -14,6 +14,6 @@ repository = "https://github.com/joepio/atomic"
promptly = "0.3.0"
clap = "2.33.1"
colored = "1.9.3"
atomic_lib = { version = "0.12.1", path = "../lib", features = ["db", "rdf"] }
atomic_lib = { version = "0.13.0", path = "../lib", features = ["db", "rdf"] }
dirs = "3.0.1"
regex = "1.3.9"
2 changes: 1 addition & 1 deletion cli/src/delta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ pub fn subcommand_to_url(context: &Context, subcommand: &str) -> AtomicResult<St
let subcommand_matches = context.matches.subcommand_matches("delta").unwrap();
let user_arg = subcommand_matches.value_of(subcommand).unwrap();
let id_url: String = context
.mapping
.mapping.lock().unwrap()
.try_mapping_or_url(&String::from(user_arg))
.ok_or(&*format!("No url found for {}", user_arg))?;
Ok(id_url)
Expand Down
12 changes: 6 additions & 6 deletions cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use atomic_lib::mapping::Mapping;
use clap::{App, AppSettings, Arg, ArgMatches, SubCommand, crate_version};
use colored::*;
use dirs::home_dir;
use std::path::PathBuf;
use std::{path::PathBuf, sync::Mutex};

mod delta;
mod new;
Expand All @@ -14,7 +14,7 @@ mod path;
pub struct Context<'a> {
base_url: String,
store: atomic_lib::Store,
mapping: Mapping,
mapping: Mutex<Mapping>,
matches: ArgMatches<'a>,
config_folder: PathBuf,
user_mapping_path: PathBuf,
Expand Down Expand Up @@ -136,7 +136,7 @@ fn main() -> AtomicResult<()> {
let mut context = Context {
// TODO: This should be configurable
base_url: "http://localhost/".into(),
mapping,
mapping: Mutex::new(mapping),
store,
matches,
config_folder,
Expand Down Expand Up @@ -179,7 +179,7 @@ fn exec_command(context: &mut Context) -> AtomicResult<()>{
/// List all bookmarks
fn list(context: &mut Context) {
let mut string = String::new();
for (shortname, url) in context.mapping.clone().into_iter() {
for (shortname, url) in context.mapping.lock().unwrap().clone().into_iter() {
string.push_str(&*format!(
"{0: <15}{1: <10} \n",
shortname.blue().bold(),
Expand Down Expand Up @@ -239,7 +239,7 @@ fn populate(context: &mut Context) -> AtomicResult<()> {

/// Validates the store
fn validate(context: &mut Context) -> AtomicResult<()> {
context.store.validate_store()?;
println!("Store is valid!");
let reportstring = context.store.validate().to_string();
println!("{}", reportstring);
Ok(())
}
25 changes: 12 additions & 13 deletions cli/src/new.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pub fn new(context: &mut Context) -> AtomicResult<()> {
.unwrap()
.value_of("class")
.expect("Add a class value");
let class_url = context.mapping.try_mapping_or_url(class_input).unwrap();
let class_url = context.mapping.lock().unwrap().try_mapping_or_url(class_input).unwrap();
let class = context.store.get_class(&class_url)?;
println!("Enter a new {}: {}", class.shortname, class.description);
let (resource, _bookmark) = prompt_instance(context, &class, None)?;
Expand All @@ -36,11 +36,11 @@ pub fn new(context: &mut Context) -> AtomicResult<()> {
/// Lets the user enter an instance of an Atomic Class through multiple prompts
/// Adds the instance to the store, and writes to disk.
/// Returns the Resource, its URL and its Bookmark.
fn prompt_instance(
context: &mut Context,
fn prompt_instance<'a>(
context: &'a Context,
class: &Class,
preffered_shortname: Option<String>,
) -> AtomicResult<(Resource, Option<String>)> {
) -> AtomicResult<(Resource<'a>, Option<String>)> {
// Not sure about the best way t
// The Path is the thing at the end of the URL, from the domain
// Here I set some (kind of) random numbers.
Expand All @@ -52,7 +52,7 @@ fn prompt_instance(
subject = format!("{}/{}-{}", context.base_url, path, preffered_shortname.clone().unwrap());
}

let mut new_resource: Resource = Resource::new(subject.clone());
let mut new_resource: Resource = Resource::new(subject.clone(), &context.store);

new_resource.insert(
"https://atomicdata.dev/properties/isA".into(),
Expand All @@ -64,7 +64,6 @@ fn prompt_instance(
new_resource.insert_string(
field.subject.clone(),
&preffered_shortname.clone().unwrap(),
&mut context.store,
)?;
println!(
"Shortname set to {}",
Expand All @@ -78,7 +77,7 @@ fn prompt_instance(
let mut input = prompt_field(&field, false, context)?;
loop {
if let Some(i) = input {
new_resource.insert_string(field.subject.clone(), &i, &mut context.store)?;
new_resource.insert_string(field.subject.clone(), &i)?;
break;
} else {
println!("Required field, please enter a value.");
Expand All @@ -91,20 +90,20 @@ fn prompt_instance(
println!("{}: {}", field.shortname.bold().blue(), field.description);
let input = prompt_field(&field, true, context)?;
if let Some(i) = input {
new_resource.insert_string(field.subject.clone(), &i, &mut context.store)?;
new_resource.insert_string(field.subject.clone(), &i)?;
}
}

println!("{} created with URL: {}", &class.shortname, &subject);

let map = prompt_bookmark(&mut context.mapping, &subject);
let map = prompt_bookmark(&mut context.mapping.lock().unwrap(), &subject);

// Add created_instance to store
context
.store
.add_resource_string(new_resource.subject().clone(), &new_resource.to_plain())?;
context
.mapping
.mapping.lock().unwrap()
.write_mapping_to_disk(&context.user_mapping_path);
Ok((new_resource, map))
}
Expand All @@ -113,7 +112,7 @@ fn prompt_instance(
fn prompt_field(
property: &Property,
optional: bool,
context: &mut Context,
context: &Context,
) -> AtomicResult<Option<String>> {
let mut input: Option<String> = None;
let msg_appendix;
Expand Down Expand Up @@ -182,7 +181,7 @@ fn prompt_field(
}
if let Some(u) = url {
// TODO: Check if string or if map
input = context.mapping.try_mapping_or_url(&u);
input = context.mapping.lock().unwrap().try_mapping_or_url(&u);
match input {
Some(url) => return Ok(Some(url)),
None => {
Expand All @@ -204,7 +203,7 @@ fn prompt_field(
let mut urls: Vec<String> = Vec::new();
let length = string_items.clone().count();
for item in string_items.into_iter() {
match context.mapping.try_mapping_or_url(item) {
match context.mapping.lock().unwrap().try_mapping_or_url(item) {
Some(url) => {
urls.push(url);
}
Expand Down
2 changes: 1 addition & 1 deletion cli/src/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ pub fn get_path(context: &mut Context) -> AtomicResult<()> {
};

// Returns a URL or Value
let result = context.store.get_path(path_string, Some(&context.mapping));
let result = context.store.get_path(path_string, Some(&context.mapping.lock().unwrap()));
let store = &mut context.store;
match result {
Ok(res) => match res {
Expand Down
2 changes: 1 addition & 1 deletion cli/wapm.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "atomic"
version = "0.12.0"
version = "0.13.0"
description = "Create, share, fetch and model linked Atomic Data!"
license = "MIT"
repository = "https://github.com/joepio/atomic"
Expand Down
2 changes: 1 addition & 1 deletion lib/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "atomic_lib"
version = "0.12.1"
version = "0.13.0"
authors = ["Joep Meindertsma <joep@argu.co>"]
edition = "2018"
license = "MIT"
Expand Down
4 changes: 2 additions & 2 deletions lib/examples/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ fn main() {
// Import the `Storelike` trait to get access to most functions
use atomic_lib::Storelike;
// Start with initializing our store
let mut store = atomic_lib::Store::init();
let store = atomic_lib::Store::init();
// Load the default Atomic Data Atoms
store.populate().unwrap();
// Let's parse this AD3 string. It looks awkward because of the escaped quotes.
Expand All @@ -21,7 +21,7 @@ fn main() {
.unwrap();
assert!(my_value.to_string() == "Test");
// We can also use the shortname of description
let my_value_from_shortname = my_resource.get_shortname("description", &mut store).unwrap();
let my_value_from_shortname = my_resource.get_shortname("description").unwrap();
assert!(my_value_from_shortname.to_string() == "Test");
// We can find any Atoms matching some value using Triple Pattern Fragments:
let found_atoms = store.tpf(None, None, Some("Test")).unwrap();
Expand Down
5 changes: 2 additions & 3 deletions lib/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ pub fn fetch_resource(subject: &str) -> AtomicResult<ResourceString> {
}

/// Posts a delta to an endpoint
pub fn post_delta(endpoint: &str, delta: Delta) -> AtomicResult<()> {
let resp = ureq::post(&endpoint)
pub fn post_delta(endpoint: &str, _delta: Delta) -> AtomicResult<()> {
let _resp = ureq::post(&endpoint)
.set("Accept", crate::parse::AD3_MIME)
.timeout_read(500)
.call();
Expand All @@ -42,5 +42,4 @@ pub fn post_delta(endpoint: &str, delta: Delta) -> AtomicResult<()> {
// Another one is to create nested Resources for every deltaline.
// I think having JSON compatibility should be top priority.
todo!();
Ok(())
}
2 changes: 1 addition & 1 deletion lib/src/collections.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ mod test {

#[test]
fn create_collection() {
let mut store = crate::Store::init();
let store = crate::Store::init();
store.populate().unwrap();
let tpf = TPFQuery {
subject: None,
Expand Down
61 changes: 33 additions & 28 deletions lib/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,32 +51,28 @@ impl Db {
}

impl Storelike for Db {
fn add_atoms(&mut self, atoms: Vec<Atom>) -> AtomicResult<()> {
fn add_atoms(&self, atoms: Vec<Atom>) -> AtomicResult<()> {
for atom in atoms {
self.add_atom(atom)?;
}
self.db.flush()?;
Ok(())
}

fn add_resource(&mut self, resource: &Resource) -> AtomicResult<()> {
fn add_resource(&self, resource: &Resource) -> AtomicResult<()> {
self.add_resource_string(resource.subject().clone(), &resource.to_plain())?;
Ok(())
}

fn add_resource_string(
&mut self,
subject: String,
resource: &ResourceString,
) -> AtomicResult<()> {
fn add_resource_string(&self, subject: String, resource: &ResourceString) -> AtomicResult<()> {
let res_bin = bincode::serialize(resource)?;
let sub_bin = bincode::serialize(&subject)?;
self.resources.insert(sub_bin, res_bin)?;
// Note that this does not do anything with indexes, so it might have to be replaced!
Ok(())
}

fn get_resource_string(&mut self, resource_url: &str) -> AtomicResult<ResourceString> {
fn get_resource_string(&self, resource_url: &str) -> AtomicResult<ResourceString> {
match self
.resources
// Todo: return some custom error types here
Expand All @@ -90,46 +86,52 @@ impl Storelike for Db {
}
None => {
if resource_url.starts_with(&self.base_url) {
return Err(format!("Failed to retrieve {}, does not exist locally", resource_url).into())
return Err(format!(
"Failed to retrieve {}, does not exist locally",
resource_url
)
.into());
}

match self.fetch_resource(resource_url) {
Ok(got) => Ok(got),
Err(e) => {
Err(format!("Failed to retrieve {} from the web: {}", resource_url, e).into())
Ok(got) => Ok(got),
Err(e) => Err(format!(
"Failed to retrieve {} from the web: {}",
resource_url, e
)
.into()),
}
}},
}
}
}

fn all_resources(&self) -> AtomicResult<ResourceCollection> {
fn all_resources(&self) -> ResourceCollection {
let mut resources: ResourceCollection = Vec::new();
for item in self.resources.into_iter() {
let (subject_bin, resource_bin) = item?;
let subby: String = bincode::deserialize(&subject_bin)?;
let resource: ResourceString = bincode::deserialize(&resource_bin)?;
resources.push((subby, resource));
let (subject_bin, resource_bin) = item.unwrap();
let subject: String = bincode::deserialize(&subject_bin).unwrap();
let resource: ResourceString = bincode::deserialize(&resource_bin).unwrap();
resources.push((subject, resource));
}
Ok(resources)
resources
}
}

#[cfg(test)]
mod test {
use super::*;
use crate::{parse::parse_ad3, Storelike};

// Same as examples/basic.rs
#[test]
fn basic() {
let string =
String::from("[\"_:test\",\"https://atomicdata.dev/properties/shortname\",\"hi\"]");
let mut store = Db::init("tmp/db", "localhost".into()).unwrap();
// Import the `Storelike` trait to get access to most functions
use crate::Storelike;
// Start with initializing our store
let store = Db::init("tmp/db", "localhost".into()).unwrap();
// Load the default Atomic Data Atoms
store.populate().unwrap();
let atoms = parse_ad3(&string).unwrap();
store.add_atoms(atoms).unwrap();
// Let's parse this AD3 string. It looks awkward because of the escaped quotes.
let string = "[\"_:test\",\"https://atomicdata.dev/properties/description\",\"Test\"]";
let string = r#"["_:test","https://atomicdata.dev/properties/description","Test"]"#;
// The parser returns a Vector of Atoms
let atoms = crate::parse::parse_ad3(&string).unwrap();
// Add the Atoms to the Store
Expand All @@ -142,7 +144,10 @@ mod test {
.unwrap();
assert!(my_value.to_string() == "Test");
// We can also use the shortname of description
let my_value_from_shortname = my_resource.get_shortname("description", &mut store).unwrap();
assert!(my_value_from_shortname.to_string() == "Test")
let my_value_from_shortname = my_resource.get_shortname("description").unwrap();
assert!(my_value_from_shortname.to_string() == "Test");
// We can find any Atoms matching some value using Triple Pattern Fragments:
let found_atoms = store.tpf(None, None, Some("Test")).unwrap();
assert!(found_atoms.len() == 1);
}
}
Loading