Stabilize output order by replacing HashMap with BTreeMap

This commit is contained in:
Josh Hansen 2023-08-24 16:01:06 -07:00
parent e985456c29
commit 4e6b4471cd
8 changed files with 31 additions and 32 deletions

View file

@ -28,9 +28,9 @@ Linked ./people:id/5 -> ./people/Darrel
./people/:state:id/CA/0 user.name Wulfrum
./people/:state:id/CA/2 user.name Sandeep
+ ghee del -v ./people -w name=Sofia
Removed ./people:id/1
Removed ./people/Sofia
Removed ./people/:state:id/WA/1
Removed ./people/Sofia
Removed ./people:id/1
+ ghee del -v ./people:id 3
Removed ./people:id/3
Removed ./people/Janella

View file

@ -7,7 +7,7 @@ use crate::{
walk_records, xattr_values,
};
use std::{collections::HashMap, fs::remove_file, path::PathBuf};
use std::{collections::BTreeMap, fs::remove_file, path::PathBuf};
#[derive(Error, Debug)]
pub enum DelErr {
@ -28,13 +28,13 @@ pub enum DelErr {
/// Delete all instantiations of a record across tables
/// If `record` is not provided it will be loaded from `record_path`
fn unlink_record(
indices: &HashMap<Key, PathBuf>,
indices: &BTreeMap<Key, PathBuf>,
record_path: &PathBuf,
record: Option<&HashMap<Xattr, Value>>,
record: Option<&BTreeMap<Xattr, Value>>,
verbose: bool,
) -> Result<()> {
// Owned copy of record xattr values if we are loading them
let loaded_xattr_values: Option<HashMap<Xattr, Value>> = if let Some(_) = record {
let loaded_xattr_values: Option<BTreeMap<Xattr, Value>> = if let Some(_) = record {
None
} else {
Some(xattr_values(record_path)?)

View file

@ -6,12 +6,12 @@ use crate::{
xattr_values,
};
use std::{collections::HashMap, io::Write, path::PathBuf};
use std::{collections::BTreeMap, io::Write, path::PathBuf};
#[derive(Serialize)]
struct FileXattrs<'a, 'b> {
path: String,
xattrs: HashMap<&'a Xattr, &'b Value>,
xattrs: BTreeMap<&'a Xattr, &'b Value>,
}
pub fn get(
@ -44,8 +44,7 @@ pub fn get(
fields.clone()
};
if *json {
let mut xattrs: HashMap<&Xattr, &Value> =
HashMap::with_capacity(projected_fields.len());
let mut xattrs: BTreeMap<&Xattr, &Value> = BTreeMap::new();
for field in projected_fields.iter() {
let value = &all_field_values[field];

View file

@ -1,5 +1,5 @@
use std::{
collections::HashMap,
collections::BTreeMap,
fs::{create_dir_all, hard_link, File},
io::{stdin, BufRead, BufReader, Read},
path::PathBuf,
@ -28,9 +28,9 @@ pub enum InsErr {
}
/// Interpret a JSON object as parsed xattr values
fn json_to_record(json: &serde_json::Value) -> Result<HashMap<Xattr, Value>> {
fn json_to_record(json: &serde_json::Value) -> Result<BTreeMap<Xattr, Value>> {
if let serde_json::Value::Object(o) = json {
let mut record: HashMap<Xattr, Value> = HashMap::new();
let mut record: BTreeMap<Xattr, Value> = BTreeMap::new();
for (k, v) in o {
let xattr = Xattr::from(k.as_str());
let value = Value::try_from(v.clone())?;
@ -43,7 +43,7 @@ fn json_to_record(json: &serde_json::Value) -> Result<HashMap<Xattr, Value>> {
}
}
fn write_record_as_xattrs(path: &PathBuf, record: &HashMap<Xattr, Value>) -> Result<()> {
fn write_record_as_xattrs(path: &PathBuf, record: &BTreeMap<Xattr, Value>) -> Result<()> {
for (k, v) in record {
let bytes = v.as_bytes();

View file

@ -9,7 +9,7 @@ pub mod paths;
mod test_support;
use std::{
collections::HashMap,
collections::BTreeMap,
path::{Path, PathBuf},
};
@ -98,13 +98,13 @@ pub fn xattr_values_from_path(
key: &Key,
base_path: &PathBuf,
path: &PathBuf,
) -> Result<HashMap<Xattr, Value>> {
) -> Result<BTreeMap<Xattr, Value>> {
let base_len = base_path.components().count();
// Get just the parts of `path` that go beyond `base_path`
let parts = path.components().skip(base_len).map(|c| c.as_os_str());
let mut values: HashMap<Xattr, Value> = HashMap::new();
let mut values: BTreeMap<Xattr, Value> = BTreeMap::new();
for (i, part) in parts.enumerate() {
let subkey = &key.subkeys[i];
let value = Value::from(part.to_str().ok_or(GheeErr::PathValueNotUtf8)?);
@ -115,13 +115,13 @@ pub fn xattr_values_from_path(
}
pub struct RecordVisit<'a, 'b, 'c> {
all_indices: &'a HashMap<Key, PathBuf>,
all_indices: &'a BTreeMap<Key, PathBuf>,
path: &'b PathBuf,
xattr_values: &'c HashMap<Xattr, Value>,
xattr_values: &'c BTreeMap<Xattr, Value>,
}
/// Return all indices of the table whose path is given
pub fn indices(path: &PathBuf) -> Result<HashMap<Key, PathBuf>> {
pub fn indices(path: &PathBuf) -> Result<BTreeMap<Key, PathBuf>> {
let info = get_index_info(path)?;
let main_key = get_key(path)?.ok_or(GheeErr::KeyNotFound(path.clone()))?;
@ -135,7 +135,7 @@ pub fn indices(path: &PathBuf) -> Result<HashMap<Key, PathBuf>> {
/// The idea is that this will maximally speed up traversal of records, but this may
/// depend on the cardinality / distribution of the subkey values
pub fn best_index<'a>(
indices: &'a HashMap<Key, PathBuf>,
indices: &'a BTreeMap<Key, PathBuf>,
where_: &Vec<Predicate>,
) -> (&'a Key, &'a PathBuf) {
let predicate_xattrs: Vec<Xattr> = where_.iter().map(|pred| pred.xattr.clone()).collect();
@ -158,7 +158,7 @@ pub fn best_index<'a>(
/// Efficiently walk all records in a table that meet the predicate constraints
pub fn walk_records<F: Fn(RecordVisit) -> Result<()>>(
indices: &HashMap<Key, PathBuf>,
indices: &BTreeMap<Key, PathBuf>,
where_: &Vec<Predicate>,
visitor: F,
) -> Result<()> {
@ -254,10 +254,10 @@ pub fn xattr_value<P: AsRef<Path>>(path: P, xattr: &Xattr) -> Result<Value> {
/// Get all xattr values for the given path;
/// like `xattr::list` and `xattr::get` but parsed into our format.
pub fn xattr_values<P: AsRef<Path>>(path: P) -> Result<HashMap<Xattr, Value>> {
pub fn xattr_values<P: AsRef<Path>>(path: P) -> Result<BTreeMap<Xattr, Value>> {
let path = path.as_ref();
let xattrs = list_xattrs(path);
let mut values: HashMap<Xattr, Value> = HashMap::with_capacity(xattrs.len());
let mut values: BTreeMap<Xattr, Value> = BTreeMap::new();
for xattr in xattrs.into_iter() {
let value = xattr_value(path, &xattr)?;

View file

@ -1,4 +1,4 @@
use std::{collections::HashMap, path::PathBuf};
use std::{collections::BTreeMap, path::PathBuf};
use serde::{Deserialize, Serialize};
@ -7,13 +7,13 @@ use crate::parser::key::Key;
#[derive(Serialize, Deserialize)]
pub struct IndexInfo {
/// The indexed key and location of related indices
pub related_indices: HashMap<Key, PathBuf>,
pub related_indices: BTreeMap<Key, PathBuf>,
}
impl Default for IndexInfo {
fn default() -> Self {
IndexInfo {
related_indices: HashMap::new(),
related_indices: BTreeMap::new(),
}
}
}

View file

@ -1,5 +1,5 @@
use std::{
collections::HashMap,
collections::BTreeMap,
ops::{Index, IndexMut},
path::PathBuf,
slice::Iter,
@ -25,7 +25,7 @@ pub enum KeyErr {
RecordNotObject,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[derive(Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
pub struct Key {
pub subkeys: Vec<Xattr>,
}
@ -121,7 +121,7 @@ impl Key {
Ok(values)
}
pub fn value_for_record(&self, record: &HashMap<Xattr, Value>) -> Result<Vec<Value>> {
pub fn value_for_record(&self, record: &BTreeMap<Xattr, Value>) -> Result<Vec<Value>> {
let mut values: Vec<Value> = Vec::with_capacity(self.subkeys.len());
for subkey in self.subkeys.iter() {

View file

@ -1,4 +1,4 @@
use std::{collections::HashMap, ffi::OsStr};
use std::{collections::BTreeMap, ffi::OsStr};
use clap::{builder::TypedValueParser, Arg, Command};
use nom::{
@ -23,7 +23,7 @@ impl Predicate {
pub fn new(xattr: Xattr, relation: Relation) -> Self {
Self { xattr, relation }
}
pub fn satisfied(&self, values: &HashMap<Xattr, Value>) -> bool {
pub fn satisfied(&self, values: &BTreeMap<Xattr, Value>) -> bool {
values
.get(&self.xattr)
.map_or(false, |v| self.relation.satisfied_by(v.clone()))