Filter by mime

This commit is contained in:
2026-03-15 10:20:15 -07:00
parent 8041fc7531
commit 979fbb9b0d
30 changed files with 258 additions and 93 deletions

View File

@@ -1,3 +1,13 @@
#[derive(Debug, Clone)]
pub struct ExtractState {
/// If true, extract all fields from all items.
/// Do not pre-filter using mime type.
///
/// This may detect additional fields, but
/// makes extraction take much longer
pub ignore_mime: bool,
}
/// An attachment that extracts metadata from an [Item].
///
/// Metadata is exposed as an immutable map of {label: value},
@@ -15,6 +25,7 @@ pub trait ObjectExtractor: Send + Sync {
/// this fn should return `Ok(Some(None))`.
async fn field(
&self,
state: &ExtractState,
name: &pile_config::Label,
args: Option<&str>,
) -> Result<Option<crate::value::PileValue>, std::io::Error>;
@@ -25,15 +36,15 @@ pub trait ObjectExtractor: Send + Sync {
async fn fields(&self) -> Result<Vec<pile_config::Label>, std::io::Error>;
/// Convert this to a JSON value.
async fn to_json(&self) -> Result<serde_json::Value, std::io::Error> {
async fn to_json(&self, state: &ExtractState) -> Result<serde_json::Value, std::io::Error> {
let keys = self.fields().await?;
let mut map = serde_json::Map::new();
for k in &keys {
let v = match self.field(k, None).await? {
let v = match self.field(state, k, None).await? {
Some(x) => x,
None => continue,
};
map.insert(k.to_string(), Box::pin(v.to_json()).await?);
map.insert(k.to_string(), Box::pin(v.to_json(state)).await?);
}
Ok(serde_json::Value::Object(map))
@@ -49,25 +60,25 @@ pub trait ListExtractor: Send + Sync {
/// Indices start at zero, and must be consecutive.
/// - returns `None` if `idx` is out of range
/// - returns `Some(Null)` if `None` is at `idx`
async fn get(&self, idx: usize) -> Result<Option<crate::value::PileValue>, std::io::Error>;
async fn get(
&self,
state: &ExtractState,
idx: usize,
) -> Result<Option<crate::value::PileValue>, std::io::Error>;
async fn len(&self) -> Result<usize, std::io::Error>;
async fn is_empty(&self) -> Result<bool, std::io::Error> {
Ok(self.len().await? == 0)
}
async fn len(&self, state: &ExtractState) -> Result<usize, std::io::Error>;
/// Convert this list to a JSON value.
async fn to_json(&self) -> Result<serde_json::Value, std::io::Error> {
let len = self.len().await?;
async fn to_json(&self, state: &ExtractState) -> Result<serde_json::Value, std::io::Error> {
let len = self.len(state).await?;
let mut list = Vec::with_capacity(len);
for i in 0..len {
#[expect(clippy::expect_used)]
let v = self
.get(i)
.get(state, i)
.await?
.expect("value must be present according to length");
list.push(Box::pin(v.to_json()).await?);
list.push(Box::pin(v.to_json(state)).await?);
}
Ok(serde_json::Value::Array(list))