Get example running again with default index locations

This commit is contained in:
Josh Hansen 2023-08-16 14:28:00 -07:00
parent 78693a7b1e
commit 3055cb96ec
8 changed files with 107 additions and 76 deletions

View file

@ -22,13 +22,13 @@ ghee set -s name=Wulfrum -s id=0 -s state=CA ./people/Wulfrum
ghee idx -v -k id ./people ./people:id
# Index the dataset by state and ID
ghee idx -v -k state -k id ./people ./people:state:id
ghee idx -v -k state -k id ./people
# Get the name of everybody from California
ghee get -w state=CA -f name ./people
# Get the name of everybody from California, taking advantage of the state index
# This will avoid traversing irrelevant portions of the index
ghee get -w state=CA -f name ./people:state:id
ghee get -w state=CA -f name ./people/:state:id
cd ..

View file

@ -137,7 +137,7 @@ enum Commands {
#[arg(help = "Path to recursively index")]
src: PathBuf,
#[arg(help = "Path to output the new index to")]
dest: PathBuf,
dest: Option<PathBuf>,
#[arg(name = "key", short, long, help = "xattrs to index by")]
keys: Vec<Xattr>,
#[arg(short, long)]

View file

@ -8,16 +8,21 @@ use walkdir::WalkDir;
use crate::parser::assignment::Assignment;
use crate::parser::value::Value;
use crate::paths::sub_idx_path;
use crate::XATTR_KEY;
use crate::{cmd::set, parser::key::Key};
use std::path::PathBuf;
pub fn idx(src: &PathBuf, dest: &PathBuf, keys: &Key, verbose: &bool) {
pub fn idx(src: &PathBuf, dest: &Option<PathBuf>, keys: &Key, verbose: &bool) {
if keys.is_empty() {
panic!("No keys were provided to index by");
}
let dest = dest.clone().unwrap_or_else(|| {
sub_idx_path(src, keys).unwrap_or_else(|e| panic!("Could not get sub-index path: {}", e))
});
for entry in WalkDir::new(src) {
let entry = entry.unwrap_or_else(|e| panic!("Could not read directory: {}", e));

View file

@ -4,6 +4,7 @@ extern crate lazy_static;
pub mod cli;
pub mod cmd;
pub mod parser;
pub mod paths;
use parser::xattr::{parse_xattr, Xattr};
use xdg::BaseDirectories;

View file

@ -17,6 +17,35 @@ pub fn array(i: &[u8]) -> IResult<&[u8], Vec<Value>> {
)(i)
}
#[test]
fn test_array() {
assert_eq!(
array(b"[1,2,3,4]".as_slice()),
Ok((
b"".as_slice(),
vec![1f64, 2f64, 3f64, 4f64]
.into_iter()
.map(Value::from)
.collect()
))
);
assert_eq!(
array(b"[ 1 ,2 , 3, A, \"B\" ,\"C\",Defg]"),
Ok((
b"".as_slice(),
vec![
Value::from(1f64),
Value::from(2f64),
Value::from(3f64),
Value::from("A"),
Value::from("B"),
Value::from("C"),
Value::from("Defg")
]
))
);
}
pub mod assignment;
pub mod index;
pub mod key;

View file

@ -2,61 +2,17 @@ use std::{collections::HashMap, ffi::OsStr};
use clap::{builder::TypedValueParser, Arg, Command};
use nom::{
bytes::complete::take_while,
character::complete::char,
character::is_space,
multi::separated_list0,
sequence::{delimited, pair, terminated},
sequence::{pair, terminated},
IResult,
};
use super::{
relation::{parse_relation, Relation},
value::{parse_value, Value},
space,
value::Value,
xattr::{parse_xattr, Xattr},
};
fn space(i: &[u8]) -> IResult<&[u8], &[u8]> {
take_while(move |x| is_space(x))(i)
}
fn array(i: &[u8]) -> IResult<&[u8], Vec<Value>> {
delimited(
char('['),
separated_list0(char(','), delimited(space, parse_value, space)),
char(']'),
)(i)
}
#[test]
fn test_array() {
assert_eq!(
array(b"[1,2,3,4]".as_slice()),
Ok((
b"".as_slice(),
vec![1f64, 2f64, 3f64, 4f64]
.into_iter()
.map(Value::from)
.collect()
))
);
assert_eq!(
array(b"[ 1 ,2 , 3, A, \"B\" ,\"C\",Defg]"),
Ok((
b"".as_slice(),
vec![
Value::from(1f64),
Value::from(2f64),
Value::from(3f64),
Value::from("A"),
Value::from("B"),
Value::from("C"),
Value::from("Defg")
]
))
);
}
#[derive(Clone, Debug, PartialEq)]
pub struct Predicate {
xattr: Xattr,
@ -81,6 +37,28 @@ fn parse_predicate(i: &[u8]) -> IResult<&[u8], Predicate> {
.map(|(i, (xattr, relation))| (i, Predicate { xattr, relation }))
}
#[derive(Clone)]
pub struct PredicateParser;
impl TypedValueParser for PredicateParser {
type Value = Predicate;
fn parse_ref(
&self,
_cmd: &Command,
_arg: Option<&Arg>,
value: &OsStr,
) -> Result<Self::Value, clap::error::Error<clap::error::RichFormatter>> {
parse_predicate(value.to_string_lossy().as_bytes())
.map(|(_remainder, predicate)| predicate)
.map_err(|e| {
clap::error::Error::raw(
clap::error::ErrorKind::InvalidValue,
format!("Malformed WHERE clause: {}\n", e),
)
})
}
}
#[test]
fn test_parse_predicate() {
assert!(parse_predicate(b"").is_err());
@ -131,25 +109,3 @@ fn test_parse_predicate() {
))
);
}
#[derive(Clone)]
pub struct PredicateParser;
impl TypedValueParser for PredicateParser {
type Value = Predicate;
fn parse_ref(
&self,
_cmd: &Command,
_arg: Option<&Arg>,
value: &OsStr,
) -> Result<Self::Value, clap::error::Error<clap::error::RichFormatter>> {
parse_predicate(value.to_string_lossy().as_bytes())
.map(|(_remainder, predicate)| predicate)
.map_err(|e| {
clap::error::Error::raw(
clap::error::ErrorKind::InvalidValue,
format!("Malformed WHERE clause: {}\n", e),
)
})
}
}

View file

@ -1,3 +1,4 @@
use nom::bytes::complete::is_not;
use nom::combinator::map;
use nom::number::complete::double;
@ -29,7 +30,12 @@ impl Value {
pub fn as_bytes(&self) -> Vec<u8> {
match self {
Self::Number(x) => format!("{}", x).into_bytes(),
Self::String(s) => s.clone().into_bytes(),
Self::String(s) => {
let mut bytes = s.clone().into_bytes();
bytes.insert(0, b'"');
bytes.push(b'"');
bytes
}
}
}
}
@ -95,8 +101,8 @@ impl Into<serde_json::Value> for Value {
pub fn string(i: &[u8]) -> IResult<&[u8], String> {
alt((
delimited(tag("'"), take_while(is_alphanumeric), tag("'")),
delimited(tag("\""), take_while(is_alphanumeric), tag("\"")),
delimited(tag("'"), is_not("'"), tag("'")),
delimited(tag("\""), is_not("\""), tag("\"")),
take_while1(is_alphanumeric),
))(i)
.map(|(i, b)| (i, String::from_utf8_lossy(b).to_string()))

34
src/paths.rs Normal file
View file

@ -0,0 +1,34 @@
use std::{ffi::OsString, os::unix::prelude::OsStringExt, path::PathBuf};
use thiserror::Error;
use crate::parser::key::Key;
#[derive(Error, Debug)]
pub enum SubIdxPathErr {
#[error("The provided key was empty")]
EmptyKey,
}
/// The path of a sub-index: an index nested inside another (primary) index
pub fn sub_idx_path(view_of: &PathBuf, key: &Key) -> Result<PathBuf, SubIdxPathErr> {
if key.is_empty() {
return Err(SubIdxPathErr::EmptyKey);
}
let mut sub_idx_dirname = OsString::new();
for k in key {
sub_idx_dirname.push(":");
if k.namespace == b"user" {
sub_idx_dirname.push(OsString::from_vec(k.attr.clone()));
} else {
sub_idx_dirname.push(k.to_osstring());
}
}
let mut sub_idx_path = view_of.clone();
sub_idx_path.push(sub_idx_dirname);
Ok(sub_idx_path)
}