geary/src/engine/sqlite/api/sqlite-account.vala
Jim Nelson 0533bc9700 Further work on detecting message removal when folder first selected: #3805
Needed to rethink storage strategies as I researched this and realized that a true scarce database -- where the database is sparsely populated both in columns and rows -- is not feasible due to IMAP's UID rules.  The strategy now means that the database rows are contiguous from the highest (newest) message to the oldest *requested by the user*.  This is a better situation than having to download the UID for the entire folder.
2011-07-15 13:39:02 -07:00

148 lines
6 KiB
Vala

/* Copyright 2011 Yorba Foundation
*
* This software is licensed under the GNU Lesser General Public License
* (version 2.1 or later). See the COPYING file in this distribution.
*/
public class Geary.Sqlite.Account : Geary.AbstractAccount, Geary.LocalAccount {
private ImapDatabase db;
private FolderTable folder_table;
private ImapFolderPropertiesTable folder_properties_table;
private MessageTable message_table;
public Account(Geary.Credentials cred) {
base ("SQLite account for %s".printf(cred.to_string()));
try {
db = new ImapDatabase(cred.user);
} catch (Error err) {
error("Unable to open database: %s", err.message);
}
folder_table = db.get_folder_table();
folder_properties_table = db.get_imap_folder_properties_table();
message_table = db.get_message_table();
}
public override Geary.Email.Field get_required_fields_for_writing() {
return Geary.Email.Field.NONE;
}
private async int64 fetch_id_async(Geary.FolderPath path, Cancellable? cancellable = null)
throws Error {
FolderRow? row = yield folder_table.fetch_descend_async(path.as_list(), cancellable);
if (row == null)
throw new EngineError.NOT_FOUND("Cannot find local path to %s", path.to_string());
return row.id;
}
private async int64 fetch_parent_id_async(Geary.FolderPath path, Cancellable? cancellable = null)
throws Error {
return path.is_root() ? Row.INVALID_ID : yield fetch_id_async(path.get_parent(), cancellable);
}
public async void clone_folder_async(Geary.Folder folder, Cancellable? cancellable = null)
throws Error {
Geary.Imap.Folder imap_folder = (Geary.Imap.Folder) folder;
Geary.Imap.FolderProperties? imap_folder_properties = (Geary.Imap.FolderProperties?)
imap_folder.get_properties();
// properties *must* be available to perform a clone
assert(imap_folder_properties != null);
int64 parent_id = yield fetch_parent_id_async(folder.get_path(), cancellable);
int64 folder_id = yield folder_table.create_async(new FolderRow(folder_table,
imap_folder.get_path().basename, parent_id), cancellable);
yield folder_properties_table.create_async(
new ImapFolderPropertiesRow.from_imap_properties(folder_properties_table, folder_id,
imap_folder_properties));
}
public async void update_folder_async(Geary.Folder folder, Cancellable? cancellable = null)
throws Error {
Geary.Imap.Folder imap_folder = (Geary.Imap.Folder) folder;
Geary.Imap.FolderProperties? imap_folder_properties = (Geary.Imap.FolderProperties?)
imap_folder.get_properties();
// properties *must* be available
assert(imap_folder_properties != null);
int64 parent_id = yield fetch_parent_id_async(folder.get_path(), cancellable);
FolderRow? row = yield folder_table.fetch_async(parent_id, folder.get_path().basename,
cancellable);
if (row == null)
throw new EngineError.NOT_FOUND("Can't find in local store %s", folder.get_path().to_string());
yield folder_properties_table.update_async(row.id,
new ImapFolderPropertiesRow.from_imap_properties(folder_properties_table, row.id,
imap_folder_properties));
}
public override async Gee.Collection<Geary.Folder> list_folders_async(Geary.FolderPath? parent,
Cancellable? cancellable = null) throws Error {
int64 parent_id = (parent != null)
? yield fetch_id_async(parent, cancellable)
: Row.INVALID_ID;
if (parent != null)
assert(parent_id != Row.INVALID_ID);
Gee.List<FolderRow> rows = yield folder_table.list_async(parent_id, cancellable);
if (rows.size == 0) {
throw new EngineError.NOT_FOUND("No local folders in %s",
(parent != null) ? parent.get_fullpath() : "root");
}
Gee.Collection<Geary.Folder> folders = new Gee.ArrayList<Geary.Sqlite.Folder>();
foreach (FolderRow row in rows) {
ImapFolderPropertiesRow? properties = yield folder_properties_table.fetch_async(row.id,
cancellable);
Geary.FolderPath path = (parent != null)
? parent.get_child(row.name)
: new Geary.FolderRoot(row.name, "/", Geary.Imap.Folder.CASE_SENSITIVE);
folders.add(new Geary.Sqlite.Folder(db, row, properties, path));
}
return folders;
}
public override async bool folder_exists_async(Geary.FolderPath path,
Cancellable? cancellable = null) throws Error {
try {
int64 id = yield fetch_id_async(path, cancellable);
return (id != Row.INVALID_ID);
} catch (EngineError err) {
if (err is EngineError.NOT_FOUND)
return false;
else
throw err;
}
}
public override async Geary.Folder fetch_folder_async(Geary.FolderPath path,
Cancellable? cancellable = null) throws Error {
FolderRow? row = yield folder_table.fetch_descend_async(path.as_list(), cancellable);
if (row == null)
throw new EngineError.NOT_FOUND("%s not found in local database", path.to_string());
ImapFolderPropertiesRow? properties = yield folder_properties_table.fetch_async(row.id,
cancellable);
return new Geary.Sqlite.Folder(db, row, properties, path);
}
public async bool has_message_id_async(Geary.RFC822.MessageID message_id, out int count,
Cancellable? cancellable = null) throws Error {
count = yield message_table.search_message_id_count_async(message_id);
return (count > 0);
}
}