Get example running again with default index locations
This commit is contained in:
parent
78693a7b1e
commit
3055cb96ec
8 changed files with 107 additions and 76 deletions
|
@ -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
|
ghee idx -v -k id ./people ./people:id
|
||||||
|
|
||||||
# Index the dataset by state and 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
|
# Get the name of everybody from California
|
||||||
ghee get -w state=CA -f name ./people
|
ghee get -w state=CA -f name ./people
|
||||||
|
|
||||||
# Get the name of everybody from California, taking advantage of the state index
|
# Get the name of everybody from California, taking advantage of the state index
|
||||||
# This will avoid traversing irrelevant portions of the 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 ..
|
cd ..
|
|
@ -137,7 +137,7 @@ enum Commands {
|
||||||
#[arg(help = "Path to recursively index")]
|
#[arg(help = "Path to recursively index")]
|
||||||
src: PathBuf,
|
src: PathBuf,
|
||||||
#[arg(help = "Path to output the new index to")]
|
#[arg(help = "Path to output the new index to")]
|
||||||
dest: PathBuf,
|
dest: Option<PathBuf>,
|
||||||
#[arg(name = "key", short, long, help = "xattrs to index by")]
|
#[arg(name = "key", short, long, help = "xattrs to index by")]
|
||||||
keys: Vec<Xattr>,
|
keys: Vec<Xattr>,
|
||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
|
|
|
@ -8,16 +8,21 @@ use walkdir::WalkDir;
|
||||||
|
|
||||||
use crate::parser::assignment::Assignment;
|
use crate::parser::assignment::Assignment;
|
||||||
use crate::parser::value::Value;
|
use crate::parser::value::Value;
|
||||||
|
use crate::paths::sub_idx_path;
|
||||||
use crate::XATTR_KEY;
|
use crate::XATTR_KEY;
|
||||||
use crate::{cmd::set, parser::key::Key};
|
use crate::{cmd::set, parser::key::Key};
|
||||||
|
|
||||||
use std::path::PathBuf;
|
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() {
|
if keys.is_empty() {
|
||||||
panic!("No keys were provided to index by");
|
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) {
|
for entry in WalkDir::new(src) {
|
||||||
let entry = entry.unwrap_or_else(|e| panic!("Could not read directory: {}", e));
|
let entry = entry.unwrap_or_else(|e| panic!("Could not read directory: {}", e));
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ extern crate lazy_static;
|
||||||
pub mod cli;
|
pub mod cli;
|
||||||
pub mod cmd;
|
pub mod cmd;
|
||||||
pub mod parser;
|
pub mod parser;
|
||||||
|
pub mod paths;
|
||||||
|
|
||||||
use parser::xattr::{parse_xattr, Xattr};
|
use parser::xattr::{parse_xattr, Xattr};
|
||||||
use xdg::BaseDirectories;
|
use xdg::BaseDirectories;
|
||||||
|
|
|
@ -17,6 +17,35 @@ pub fn array(i: &[u8]) -> IResult<&[u8], Vec<Value>> {
|
||||||
)(i)
|
)(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 assignment;
|
||||||
pub mod index;
|
pub mod index;
|
||||||
pub mod key;
|
pub mod key;
|
||||||
|
|
|
@ -2,61 +2,17 @@ use std::{collections::HashMap, ffi::OsStr};
|
||||||
|
|
||||||
use clap::{builder::TypedValueParser, Arg, Command};
|
use clap::{builder::TypedValueParser, Arg, Command};
|
||||||
use nom::{
|
use nom::{
|
||||||
bytes::complete::take_while,
|
sequence::{pair, terminated},
|
||||||
character::complete::char,
|
|
||||||
character::is_space,
|
|
||||||
multi::separated_list0,
|
|
||||||
sequence::{delimited, pair, terminated},
|
|
||||||
IResult,
|
IResult,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
relation::{parse_relation, Relation},
|
relation::{parse_relation, Relation},
|
||||||
value::{parse_value, Value},
|
space,
|
||||||
|
value::Value,
|
||||||
xattr::{parse_xattr, Xattr},
|
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)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct Predicate {
|
pub struct Predicate {
|
||||||
xattr: Xattr,
|
xattr: Xattr,
|
||||||
|
@ -81,6 +37,28 @@ fn parse_predicate(i: &[u8]) -> IResult<&[u8], Predicate> {
|
||||||
.map(|(i, (xattr, relation))| (i, Predicate { xattr, relation }))
|
.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]
|
#[test]
|
||||||
fn test_parse_predicate() {
|
fn test_parse_predicate() {
|
||||||
assert!(parse_predicate(b"").is_err());
|
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),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use nom::bytes::complete::is_not;
|
||||||
use nom::combinator::map;
|
use nom::combinator::map;
|
||||||
use nom::number::complete::double;
|
use nom::number::complete::double;
|
||||||
|
|
||||||
|
@ -29,7 +30,12 @@ impl Value {
|
||||||
pub fn as_bytes(&self) -> Vec<u8> {
|
pub fn as_bytes(&self) -> Vec<u8> {
|
||||||
match self {
|
match self {
|
||||||
Self::Number(x) => format!("{}", x).into_bytes(),
|
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> {
|
pub fn string(i: &[u8]) -> IResult<&[u8], String> {
|
||||||
alt((
|
alt((
|
||||||
delimited(tag("'"), take_while(is_alphanumeric), tag("'")),
|
delimited(tag("'"), is_not("'"), tag("'")),
|
||||||
delimited(tag("\""), take_while(is_alphanumeric), tag("\"")),
|
delimited(tag("\""), is_not("\""), tag("\"")),
|
||||||
take_while1(is_alphanumeric),
|
take_while1(is_alphanumeric),
|
||||||
))(i)
|
))(i)
|
||||||
.map(|(i, b)| (i, String::from_utf8_lossy(b).to_string()))
|
.map(|(i, b)| (i, String::from_utf8_lossy(b).to_string()))
|
||||||
|
|
34
src/paths.rs
Normal file
34
src/paths.rs
Normal 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)
|
||||||
|
}
|
Loading…
Reference in a new issue