From 9ad9394b9827ce3e2bd7ab290451b7959cfbad50 Mon Sep 17 00:00:00 2001 From: skilion Date: Sat, 24 Dec 2016 14:12:20 +0100 Subject: [PATCH] better handle the case when cTag is null --- src/itemdb.d | 112 +++++++++++++++++++++---------------------------- src/onedrive.d | 4 +- src/sync.d | 46 ++++++++------------ 3 files changed, 67 insertions(+), 95 deletions(-) diff --git a/src/itemdb.d b/src/itemdb.d index 1510a6d2..8db47ee2 100644 --- a/src/itemdb.d +++ b/src/itemdb.d @@ -1,4 +1,4 @@ -import std.datetime, std.path, std.string; +import std.datetime, std.path, std.exception, std.string; import sqlite; enum ItemType @@ -21,6 +21,9 @@ struct Item final class ItemDatabase { + // increment this for every change in the db schema + immutable int itemDatabaseVersion = 1; + Database db; Statement insertItemStmt; Statement updateItemStmt; @@ -35,7 +38,7 @@ final class ItemDatabase name TEXT NOT NULL, type TEXT NOT NULL, eTag TEXT NOT NULL, - cTag TEXT NOT NULL, + cTag TEXT, mtime TEXT NOT NULL, parentId TEXT, crc32 TEXT, @@ -44,6 +47,8 @@ final class ItemDatabase db.exec("CREATE INDEX IF NOT EXISTS name_idx ON item (name)"); db.exec("PRAGMA foreign_keys = ON"); db.exec("PRAGMA recursive_triggers = ON"); + db.setVersion(itemDatabaseVersion); + insertItemStmt = db.prepare("INSERT OR REPLACE INTO item (id, name, type, eTag, cTag, mtime, parentId, crc32) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"); updateItemStmt = db.prepare(" UPDATE item @@ -54,70 +59,28 @@ final class ItemDatabase selectItemByParentIdStmt = db.prepare("SELECT id FROM item WHERE parentId = ?"); } - void insert(const(char)[] id, const(char)[] name, ItemType type, const(char)[] eTag, const(char)[] cTag, const(char)[] mtime, const(char)[] parentId, const(char)[] crc32) + void insert(const ref Item item) { - with (insertItemStmt) { - bind(1, id); - bind(2, name); - string typeStr = void; - final switch (type) { - case ItemType.file: typeStr = "file"; break; - case ItemType.dir: typeStr = "dir"; break; - } - bind(3, typeStr); - bind(4, eTag); - bind(5, cTag); - bind(6, mtime); - bind(7, parentId); - bind(8, crc32); - exec(); - } + bindItem(item, insertItemStmt); + insertItemStmt.exec(); } - void update(const(char)[] id, const(char)[] name, ItemType type, const(char)[] eTag, const(char)[] cTag, const(char)[] mtime, const(char)[] parentId, const(char)[] crc32) + void update(const ref Item item) { - with (updateItemStmt) { - bind(1, id); - bind(2, name); - string typeStr = void; - final switch (type) { - case ItemType.file: typeStr = "file"; break; - case ItemType.dir: typeStr = "dir"; break; - } - bind(3, typeStr); - bind(4, eTag); - bind(5, cTag); - bind(6, mtime); - bind(7, parentId); - bind(8, crc32); - exec(); - } + bindItem(item, updateItemStmt); + updateItemStmt.exec(); } - void upsert(const(char)[] id, const(char)[] name, ItemType type, const(char)[] eTag, const(char)[] cTag, const(char)[] mtime, const(char)[] parentId, const(char)[] crc32) + void upsert(const ref Item item) { auto s = db.prepare("SELECT COUNT(*) FROM item WHERE id = ?"); - s.bind(1, id); + s.bind(1, item.id); auto r = s.exec(); - Statement* p; - if (r.front[0] == "0") p = &insertItemStmt; - else p = &updateItemStmt; - with (p) { - bind(1, id); - bind(2, name); - string typeStr = void; - final switch (type) { - case ItemType.file: typeStr = "file"; break; - case ItemType.dir: typeStr = "dir"; break; - } - bind(3, typeStr); - bind(4, eTag); - bind(5, cTag); - bind(6, mtime); - bind(7, parentId); - bind(8, crc32); - exec(); - } + Statement* stmt; + if (r.front[0] == "0") stmt = &insertItemStmt; + else stmt = &updateItemStmt; + bindItem(item, *stmt); + stmt.exec(); } Item[] selectChildren(const(char)[] id) @@ -218,6 +181,25 @@ final class ItemDatabase return false; } + private void bindItem(const ref Item item, ref Statement stmt) + { + with (stmt) with (item) { + bind(1, id); + bind(2, name); + string typeStr = null; + final switch (type) with (ItemType) { + case file: typeStr = "file"; break; + case dir: typeStr = "dir"; break; + } + bind(3, typeStr); + bind(4, eTag); + bind(5, cTag); + bind(6, mtime.toISOExtString()); + bind(7, parentId); + bind(8, crc32); + } + } + private Item buildItem(Statement.Result result) { assert(!result.empty && result.front.length == 8); @@ -231,25 +213,25 @@ final class ItemDatabase crc32: result.front[7].dup }; switch (result.front[2]) { - case "file": item.type = ItemType.file; break; - case "dir": item.type = ItemType.dir; break; - default: assert(0); + case "file": item.type = ItemType.file; break; + case "dir": item.type = ItemType.dir; break; + default: assert(0); } return item; } + // computes the path of the given item id + // the path is relative to the sync directory ex: "./Music/Turbo Killer.mp3" + // a trailing slash is never added string computePath(const(char)[] id) { - if (!id) return null; string path; auto s = db.prepare("SELECT name, parentId FROM item WHERE id = ?"); while (true) { s.bind(1, id); auto r = s.exec(); - if (r.empty) { - // no results - break; - } else if (r.front[1]) { + enforce(!r.empty, "Unknow item id"); + if (r.front[1]) { if (path) path = r.front[0].idup ~ "/" ~ path; else path = r.front[0].idup; } else { diff --git a/src/onedrive.d b/src/onedrive.d index d07abd1b..8ae6ccae 100644 --- a/src/onedrive.d +++ b/src/onedrive.d @@ -16,7 +16,7 @@ private immutable { class OneDriveException: Exception { int httpStatusCode; - // error details + // https://dev.onedrive.com/misc/errors.htm JSONValue error; @nogc @safe pure nothrow this(string msg, Throwable next, string file = __FILE__, size_t line = __LINE__) @@ -36,7 +36,7 @@ class OneDriveException: Exception { this.httpStatusCode = httpStatusCode; this.error = error; - string msg = format("HTTP request returned status code %d (%s)\n%s", httpStatusCode, reason, toJSON(&error, true)); + string msg = format("HTTP request returned status code %d (%s)\n%s", httpStatusCode, reason, toJSON(error, true)); super(msg, file, line, next); } } diff --git a/src/sync.d b/src/sync.d index 5d76fbf2..cb58566b 100644 --- a/src/sync.d +++ b/src/sync.d @@ -190,17 +190,6 @@ final class SyncEngine return; } - string cTag; - try { - cTag = item["cTag"].str; - } catch (JSONException e) { - // cTag is not returned if the Item is a folder - // https://dev.onedrive.com/resources/item.htm - cTag = ""; - } - - string mtime = item["fileSystemInfo"]["lastModifiedDateTime"].str; - string crc32; if (type == ItemType.file) { try { @@ -215,8 +204,8 @@ final class SyncEngine name: name, type: type, eTag: eTag, - cTag: cTag, - mtime: SysTime.fromISOExtString(mtime), + cTag: "cTag" in item ? item["cTag"].str : null, + mtime: SysTime.fromISOExtString(item["fileSystemInfo"]["lastModifiedDateTime"].str), parentId: parentId, crc32: crc32 }; @@ -229,9 +218,9 @@ final class SyncEngine // save the item in the db if (oldItem.id) { - itemdb.update(id, name, type, eTag, cTag, mtime, parentId, crc32); + itemdb.update(newItem); } else { - itemdb.insert(id, name, type, eTag, cTag, mtime, parentId, crc32); + itemdb.insert(newItem); } } @@ -526,31 +515,32 @@ final class SyncEngine saveItem(res); } - private void saveItem(JSONValue item) + private void saveItem(JSONValue jsonItem) { - string id = item["id"].str; + string id = jsonItem["id"].str; ItemType type; - if (isItemFile(item)) { + if (isItemFile(jsonItem)) { type = ItemType.file; - } else if (isItemFolder(item)) { + } else if (isItemFolder(jsonItem)) { type = ItemType.dir; } else { assert(0); } - string name = item["name"].str; - string eTag = item["eTag"].str; - string cTag = item["cTag"].str; - string mtime = item["fileSystemInfo"]["lastModifiedDateTime"].str; - string parentId = item["parentReference"]["id"].str; - string crc32; + Item item = { + name: jsonItem["name"].str, + eTag: jsonItem["eTag"].str, + cTag: "cTag" in jsonItem ? jsonItem["cTag"].str : null, + mtime: SysTime.fromISOExtString(jsonItem["fileSystemInfo"]["lastModifiedDateTime"].str), + parentId: jsonItem["parentReference"]["id"].str + }; if (type == ItemType.file) { try { - crc32 = item["file"]["hashes"]["crc32Hash"].str; + item.crc32 = jsonItem["file"]["hashes"]["crc32Hash"].str; } catch (JSONException e) { - // swallow exception + log.vlog("The hash is not available"); } } - itemdb.upsert(id, name, type, eTag, cTag, mtime, parentId, crc32); + itemdb.upsert(item); } void uploadMoveItem(string from, string to)