feature/library-patch-endpoint #94
@@ -80,16 +80,21 @@ impl Library {
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse a comma-separated excluded_dirs column into a Vec, dropping
|
||||
/// empty entries (mirrors `AppState::parse_excluded_dirs` for the env
|
||||
/// var). NULL → empty Vec. Duplicates are preserved — `PathExcluder`
|
||||
/// accepts repeats, and the storage-side normaliser is where dedup
|
||||
/// happens.
|
||||
/// Parse an excluded_dirs string into a Vec, dropping empty entries.
|
||||
/// NULL → empty Vec. Duplicates are preserved — `PathExcluder` accepts
|
||||
/// repeats, and the storage-side normaliser is where dedup happens.
|
||||
///
|
||||
/// Accepts both `,` and newline (`\n` / `\r\n`) as separators so the
|
||||
/// UI's textarea can submit one-entry-per-line input without forcing
|
||||
/// the operator to remember commas. The DB stores the canonical
|
||||
/// comma-joined form (see `normalize_excluded_dirs_input`); the
|
||||
/// newline path matters mostly for the frontend submit, but mirroring
|
||||
/// it here keeps the parse direction round-trip safe.
|
||||
pub fn parse_excluded_dirs_column(raw: Option<&str>) -> Vec<String> {
|
||||
match raw {
|
||||
None => Vec::new(),
|
||||
Some(s) => s
|
||||
.split(',')
|
||||
.split(|c: char| matches!(c, ',' | '\n' | '\r'))
|
||||
.map(str::trim)
|
||||
.filter(|s| !s.is_empty())
|
||||
.map(String::from)
|
||||
@@ -739,6 +744,40 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_excluded_dirs_column_splits_on_newlines_too() {
|
||||
// Newline-separated input from a textarea submit. One-per-line
|
||||
// is the recommended UX because "I forgot the comma" was a
|
||||
// recurring footgun (.thumbnails .thumbnails2 silently
|
||||
// becomes a single never-matching pattern).
|
||||
assert_eq!(
|
||||
parse_excluded_dirs_column(Some("@eaDir\n.thumbnails\n/private")),
|
||||
vec![
|
||||
"@eaDir".to_string(),
|
||||
".thumbnails".to_string(),
|
||||
"/private".to_string()
|
||||
]
|
||||
);
|
||||
// Windows line endings (CRLF) — the carriage return is its own
|
||||
// separator so the trailing empty token between \r and \n gets
|
||||
// trimmed + dropped.
|
||||
assert_eq!(
|
||||
parse_excluded_dirs_column(Some("a\r\nb\r\nc")),
|
||||
vec!["a".to_string(), "b".to_string(), "c".to_string()]
|
||||
);
|
||||
// Mixed comma + newline — the user pastes from one source,
|
||||
// adds a few entries inline. Both work, in any combination.
|
||||
assert_eq!(
|
||||
parse_excluded_dirs_column(Some("a, b\nc,d")),
|
||||
vec![
|
||||
"a".to_string(),
|
||||
"b".to_string(),
|
||||
"c".to_string(),
|
||||
"d".to_string()
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn effective_excluded_dirs_unions_global_and_per_library() {
|
||||
let lib_no_extras = Library {
|
||||
|
||||
Reference in New Issue
Block a user