Add Geary.Account::list_local_email_async

Add new method and implementation to support breaking search folder
impl out of the ImapDb package.
This commit is contained in:
Michael Gratton 2019-12-10 13:36:36 +11:00 committed by Michael James Gratton
parent cb16bdc59d
commit b3488f6cf9
5 changed files with 144 additions and 6 deletions

View file

@ -425,6 +425,22 @@ public abstract class Geary.Account : BaseObject, Logging.Source {
public abstract async Geary.Email local_fetch_email_async(Geary.EmailIdentifier email_id,
Geary.Email.Field required_fields, Cancellable? cancellable = null) throws Error;
/**
* Return a collection of email with the given identifiers.
*
* The returned collection will be in the same order as the
* natural ordering of the given identifiers.
*
* Throws {@link EngineError.NOT_FOUND} if any email is not found
* and {@link EngineError.INCOMPLETE_MESSAGE} if the fields aren't
* available.
*/
public abstract async Gee.List<Email> list_local_email_async(
Gee.Collection<EmailIdentifier> ids,
Email.Field required_fields,
GLib.Cancellable? cancellable = null
) throws GLib.Error;
/**
* Create a new {@link SearchQuery} for this {@link Account}.
*

View file

@ -804,6 +804,48 @@ private class Geary.ImapDB.Account : BaseObject {
return search_matches;
}
public async Gee.List<Email>? list_email(Gee.Collection<EmailIdentifier> ids,
Email.Field required_fields,
GLib.Cancellable? cancellable = null)
throws GLib.Error {
check_open();
var results = new Gee.ArrayList<Email>();
yield db.exec_transaction_async(Db.TransactionType.RO, (cx) => {
foreach (var id in ids) {
// TODO: once we have a way of deleting messages, we won't be able
// to assume that a row id will point to the same email outside of
// transactions, because SQLite will reuse row ids.
Geary.Email.Field db_fields;
MessageRow row = Geary.ImapDB.Folder.do_fetch_message_row(
cx, id.message_id, required_fields, out db_fields, cancellable
);
if (!row.fields.fulfills(required_fields)) {
throw new EngineError.INCOMPLETE_MESSAGE(
"Message %s only fulfills %Xh fields (required: %Xh)",
id.to_string(), row.fields, required_fields
);
}
Email email = row.to_email(id);
Attachment.add_attachments(
cx,
this.db.attachments_path,
email,
id.message_id,
cancellable
);
results.add(email);
}
return Db.TransactionOutcome.DONE;
},
cancellable
);
return results;
}
public async Geary.Email fetch_email_async(ImapDB.EmailIdentifier email_id,
Geary.Email.Field required_fields, Cancellable? cancellable = null) throws Error {
check_open();

View file

@ -512,6 +512,16 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account {
return (Gee.Collection<ImapDB.EmailIdentifier>) ids;
}
/** {@inheritDoc} */
public override async SearchQuery new_search_query(string query,
SearchQuery.Strategy strategy,
GLib.Cancellable? cancellable)
throws GLib.Error {
return yield new ImapDB.SearchQuery(
this, local, query, strategy, cancellable
);
}
public override async Gee.MultiMap<Geary.Email, Geary.FolderPath?>? local_search_message_id_async(
Geary.RFC822.MessageID message_id, Geary.Email.Field requested_fields, bool partial_ok,
Gee.Collection<Geary.FolderPath?>? folder_blacklist, Geary.EmailFlags? flag_blacklist,
@ -526,12 +536,13 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account {
}
/** {@inheritDoc} */
public override async SearchQuery new_search_query(string query,
SearchQuery.Strategy strategy,
GLib.Cancellable? cancellable)
throws GLib.Error {
return yield new ImapDB.SearchQuery(
this, local, query, strategy, cancellable
public override async Gee.List<Email> list_local_email_async(
Gee.Collection<EmailIdentifier> ids,
Email.Field required_fields,
GLib.Cancellable? cancellable = null
) throws GLib.Error {
return yield local.list_email(
check_ids(ids), required_fields, cancellable
);
}

View file

@ -204,6 +204,18 @@ public class Geary.MockAccount : Account, MockObject {
);
}
public override async Gee.List<Email> list_local_email_async(
Gee.Collection<EmailIdentifier> ids,
Email.Field required_fields,
GLib.Cancellable? cancellable = null
) throws GLib.Error {
return object_or_throw_call<Gee.List<Email>>(
"list_local_email_async",
{ids, box_arg(required_fields), cancellable},
new EngineError.NOT_FOUND("Mock call")
);
}
public override async Email local_fetch_email_async(EmailIdentifier email_id,
Email.Field required_fields,
Cancellable? cancellable = null)

View file

@ -26,6 +26,7 @@ class Geary.ImapDB.AccountTest : TestCase {
add_test("fetch_base_folder", fetch_base_folder);
add_test("fetch_child_folder", fetch_child_folder);
add_test("fetch_nonexistent_folder", fetch_nonexistent_folder);
add_test("list_local_email", list_local_email);
}
public override void set_up() throws GLib.Error {
@ -310,4 +311,60 @@ class Geary.ImapDB.AccountTest : TestCase {
}
}
public void list_local_email() throws GLib.Error {
Email.Field fixture_fields = Email.Field.RECEIVERS;
string fixture_to = "test1@example.com";
this.account.db.exec(
"INSERT INTO MessageTable (id, fields, to_field) " +
"VALUES (1, %d, '%s');".printf(fixture_fields, fixture_to)
);
this.account.db.exec(
"INSERT INTO MessageTable (id, fields, to_field) " +
"VALUES (2, %d, '%s');".printf(fixture_fields, fixture_to)
);
this.account.list_email.begin(
iterate_array<Geary.ImapDB.EmailIdentifier>({
new EmailIdentifier(1, null),
new EmailIdentifier(2, null)
}).to_linked_list(),
Email.Field.RECEIVERS,
null,
(obj, ret) => { async_complete(ret); }
);
Gee.List<Email> result = this.account.list_email.end(
async_result()
);
assert_int(2, result.size, "Not enough email listed");
assert_true(new EmailIdentifier(1, null).equal_to(result[0].id));
assert_true(new EmailIdentifier(2, null).equal_to(result[1].id));
this.account.list_email.begin(
Collection.single(new EmailIdentifier(3, null)),
Email.Field.RECEIVERS,
null,
(obj, ret) => { async_complete(ret); }
);
try {
this.account.list_email.end(async_result());
assert_not_reached();
} catch (EngineError.NOT_FOUND error) {
// All good
}
this.account.list_email.begin(
Collection.single(new EmailIdentifier(1, null)),
Email.Field.BODY,
null,
(obj, ret) => { async_complete(ret); }
);
try {
this.account.list_email.end(async_result());
assert_not_reached();
} catch (EngineError.INCOMPLETE_MESSAGE error) {
// All good
}
}
}