Fix find & replace for notes without 'field_name'

Distinguish between no 'field_name' passed and 'field_name' not on note.
This commit is contained in:
RumovZ 2021-07-13 16:21:13 +02:00
parent 9c354f5e6b
commit b148b7b5e0

View file

@ -20,6 +20,12 @@ pub struct FindReplaceContext {
field_name: Option<String>, field_name: Option<String>,
} }
enum FieldForNotetype {
Any,
Index(usize),
None,
}
impl FindReplaceContext { impl FindReplaceContext {
pub fn new( pub fn new(
nids: Vec<NoteId>, nids: Vec<NoteId>,
@ -62,17 +68,22 @@ impl Collection {
fn find_and_replace_inner(&mut self, ctx: FindReplaceContext) -> Result<usize> { fn find_and_replace_inner(&mut self, ctx: FindReplaceContext) -> Result<usize> {
let mut last_ntid = None; let mut last_ntid = None;
let mut field_ord = None; let mut field_for_notetype = FieldForNotetype::None;
self.transform_notes(&ctx.nids, |note, nt| { self.transform_notes(&ctx.nids, |note, nt| {
if last_ntid != Some(nt.id) { if last_ntid != Some(nt.id) {
field_ord = ctx.field_name.as_ref().and_then(|n| nt.get_field_ord(n)); field_for_notetype = match ctx.field_name.as_ref() {
None => FieldForNotetype::Any,
Some(name) => match nt.get_field_ord(name) {
None => FieldForNotetype::None,
Some(ord) => FieldForNotetype::Index(ord),
},
};
last_ntid = Some(nt.id); last_ntid = Some(nt.id);
} }
let mut changed = false; let mut changed = false;
match field_ord { match field_for_notetype {
None => { FieldForNotetype::Any => {
// all fields
for txt in note.fields_mut() { for txt in note.fields_mut() {
if let Cow::Owned(otxt) = ctx.replace_text(txt) { if let Cow::Owned(otxt) = ctx.replace_text(txt) {
changed = true; changed = true;
@ -80,8 +91,7 @@ impl Collection {
} }
} }
} }
Some(ord) => { FieldForNotetype::Index(ord) => {
// single field
if let Some(txt) = note.fields_mut().get_mut(ord) { if let Some(txt) = note.fields_mut().get_mut(ord) {
if let Cow::Owned(otxt) = ctx.replace_text(txt) { if let Cow::Owned(otxt) = ctx.replace_text(txt) {
changed = true; changed = true;
@ -89,6 +99,7 @@ impl Collection {
} }
} }
} }
FieldForNotetype::None => (),
} }
Ok(TransformNoteOutput { Ok(TransformNoteOutput {
@ -142,12 +153,11 @@ mod test {
] ]
); );
let out = col.find_and_replace(nids, "BBB", "ccc", Some("Front".into()))?; let out = col.find_and_replace(nids, "BBB", "ccc", Some("Front".into()))?;
// still 2, as the caller is expected to provide only note ids that have // 1, because notes without the specified field should be skipped
// that field, and if we can't find the field we fall back on all fields assert_eq!(out.output, 1);
assert_eq!(out.output, 2);
let note = col.storage.get_note(note.id)?.unwrap(); let note = col.storage.get_note(note.id)?.unwrap();
// but the update should be limited to the specified field when it was available // the update should be limited to the specified field when it was available
assert_eq!(&note.fields()[..], &["one ccc", "two BBB"]); assert_eq!(&note.fields()[..], &["one ccc", "two BBB"]);
Ok(()) Ok(())