removed redundant key parentDriveId

This commit is contained in:
skilion 2018-01-02 15:05:32 +01:00
parent 4ebc4a8544
commit d7f6674f60
2 changed files with 44 additions and 51 deletions

View file

@ -4,15 +4,13 @@ import std.path;
import std.string;
import sqlite;
enum ItemType
{
enum ItemType {
file,
dir,
remote
}
struct Item
{
struct Item {
string driveId;
string id;
string name;
@ -20,7 +18,6 @@ struct Item
string eTag;
string cTag;
SysTime mtime;
string parentDriveId;
string parentId;
string crc32Hash;
string sha1Hash;
@ -53,7 +50,6 @@ final class ItemDatabase
eTag TEXT,
cTag TEXT,
mtime TEXT NOT NULL,
parentDriveId TEXT,
parentId TEXT,
crc32Hash TEXT,
sha1Hash TEXT,
@ -62,7 +58,7 @@ final class ItemDatabase
remoteId TEXT,
deltaLink TEXT,
PRIMARY KEY (driveId, id),
FOREIGN KEY (parentDriveId, parentId)
FOREIGN KEY (driveId, parentId)
REFERENCES item (driveId, id)
ON DELETE CASCADE
ON UPDATE RESTRICT
@ -76,12 +72,12 @@ final class ItemDatabase
db.exec("PRAGMA foreign_keys = ON");
db.exec("PRAGMA recursive_triggers = ON");
insertItemStmt = db.prepare("
INSERT OR REPLACE INTO item (driveId, id, name, type, eTag, cTag, mtime, parentDriveId, parentId, crc32Hash, sha1Hash, quickXorHash, remoteDriveId, remoteId)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
INSERT OR REPLACE INTO item (driveId, id, name, type, eTag, cTag, mtime, parentId, crc32Hash, sha1Hash, quickXorHash, remoteDriveId, remoteId)
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13)
");
updateItemStmt = db.prepare("
UPDATE item
SET name = ?3, type = ?4, eTag = ?5, cTag = ?6, mtime = ?7, parentDriveId = ?8, parentId = ?9, crc32Hash = ?10, sha1Hash = ?11, quickXorHash = ?12, remoteDriveId = ?13, remoteId = ?14
SET name = ?3, type = ?4, eTag = ?5, cTag = ?6, mtime = ?7, parentId = ?8, crc32Hash = ?9, sha1Hash = ?10, quickXorHash = ?11, remoteDriveId = ?12, remoteId = ?13
WHERE driveId = ?1 AND id = ?2
");
selectItemByIdStmt = db.prepare("
@ -89,7 +85,7 @@ final class ItemDatabase
FROM item
WHERE driveId = ?1 AND id = ?2
");
selectItemByParentIdStmt = db.prepare("SELECT * FROM item WHERE parentDriveId = ? AND parentId = ?");
selectItemByParentIdStmt = db.prepare("SELECT * FROM item WHERE driveId = ? AND parentId = ?");
deleteItemByIdStmt = db.prepare("DELETE FROM item WHERE driveId = ? AND id = ?");
}
@ -145,11 +141,11 @@ final class ItemDatabase
// returns the item with the given path
// the path is relative to the sync directory ex: "./Music/Turbo Killer.mp3"
bool selectByPath(const(char)[] path, out Item item)
bool selectByPath(const(char)[] path, string rootDriveId, out Item item)
{
Item currItem;
Item currItem = { driveId: rootDriveId };
path = "root/" ~ path.chompPrefix(".");
auto s = db.prepare("SELECT * FROM item WHERE name IS ?1 AND parentDriveId IS ?2 AND parentId IS ?3");
auto s = db.prepare("SELECT * FROM item WHERE name = ?1 AND driveId IS ?2 AND parentId IS ?3");
foreach (name; pathSplitter(path)) {
s.bind(1, name);
s.bind(2, currItem.driveId);
@ -171,11 +167,11 @@ final class ItemDatabase
}
// same as selectByPath() but it does not traverse remote folders
bool selectByPathNoRemote(const(char)[] path, out Item item)
bool selectByPathNoRemote(const(char)[] path, string rootDriveId, out Item item)
{
Item currItem;
Item currItem = { driveId: rootDriveId };
path = "root/" ~ path.chompPrefix(".");
auto s = db.prepare("SELECT * FROM item WHERE name IS ?1 AND parentDriveId IS ?2 AND parentId IS ?3");
auto s = db.prepare("SELECT * FROM item WHERE name IS ?1 AND driveId IS ?2 AND parentId IS ?3");
foreach (name; pathSplitter(path)) {
s.bind(1, name);
s.bind(2, currItem.driveId);
@ -211,20 +207,19 @@ final class ItemDatabase
bind(5, eTag);
bind(6, cTag);
bind(7, mtime.toISOExtString());
bind(8, parentDriveId);
bind(9, parentId);
bind(10, crc32Hash);
bind(11, sha1Hash);
bind(12, quickXorHash);
bind(13, remoteDriveId);
bind(14, remoteId);
bind(8, parentId);
bind(9, crc32Hash);
bind(10, sha1Hash);
bind(11, quickXorHash);
bind(12, remoteDriveId);
bind(13, remoteId);
}
}
private Item buildItem(Statement.Result result)
{
assert(!result.empty, "The result must not be empty");
assert(result.front.length == 15, "The result must have 15 columns");
assert(result.front.length == 14, "The result must have 14 columns");
Item item = {
driveId: result.front[0].dup,
id: result.front[1].dup,
@ -232,13 +227,12 @@ final class ItemDatabase
eTag: result.front[4].dup,
cTag: result.front[5].dup,
mtime: SysTime.fromISOExtString(result.front[6]),
parentDriveId: result.front[7].dup,
parentId: result.front[8].dup,
crc32Hash: result.front[9].dup,
sha1Hash: result.front[10].dup,
quickXorHash: result.front[11].dup,
remoteDriveId: result.front[12].dup,
remoteId: result.front[13].dup
parentId: result.front[7].dup,
crc32Hash: result.front[8].dup,
sha1Hash: result.front[9].dup,
quickXorHash: result.front[10].dup,
remoteDriveId: result.front[11].dup,
remoteId: result.front[12].dup
};
switch (result.front[3]) {
case "file": item.type = ItemType.file; break;
@ -273,7 +267,6 @@ final class ItemDatabase
if (path) path = item.name ~ "/" ~ path;
else path = item.name;
}
driveId = item.parentDriveId;
id = item.parentId;
} else {
if (id == null) {

View file

@ -60,7 +60,6 @@ private Item makeItem(const ref JSONValue driveItem)
// root and remote items do not have parentReference
if (!isItemRoot(driveItem) && ("parentReference" in driveItem) != null) {
item.driveId = driveItem["parentReference"]["driveId"].str,
item.parentDriveId = item.driveId; // TODO: parentDriveId is redundant
item.parentId = driveItem["parentReference"]["id"].str;
}
@ -116,6 +115,8 @@ final class SyncEngine
private string[] skippedItems;
// list of items to delete after the changes has been downloaded
private string[2][] idsToDelete;
// default drive id
private string defaultDriveId;
this(Config cfg, OneDriveApi onedrive, ItemDatabase itemdb, SelectiveSync selectiveSync)
{
@ -141,7 +142,7 @@ final class SyncEngine
void applyDifferences()
{
// root folder
string driveId = onedrive.getDefaultDrive()["id"].str;
string driveId = defaultDriveId = onedrive.getDefaultDrive()["id"].str;
string rootId = onedrive.getDefaultRoot["id"].str;
applyDifferences(driveId, rootId);
@ -193,7 +194,7 @@ final class SyncEngine
Item item = makeItem(driveItem);
log.vlog("Processing ", item.id, " ", item.name);
if (isItemRoot(driveItem) || !item.parentDriveId) {
if (isItemRoot(driveItem) || !item.parentId) {
log.vlog("Root");
item.driveId = driveId; // HACK: makeItem() cannot set the driveId propery of the root
itemdb.upsert(item);
@ -222,7 +223,7 @@ final class SyncEngine
// check for selective sync
string path;
if (!unwanted) {
path = itemdb.computePath(item.parentDriveId, item.parentId) ~ "/" ~ item.name;
path = itemdb.computePath(item.driveId, item.parentId) ~ "/" ~ item.name;
path = buildNormalizedPath(path);
unwanted = selectiveSync.isPathExcluded(path);
}
@ -431,7 +432,7 @@ final class SyncEngine
{
log.vlog("Uploading differences of ", path);
Item item;
if (itemdb.selectByPath(path, item)) {
if (itemdb.selectByPath(path, defaultDriveId, item)) {
uploadDifferences(item);
}
log.vlog("Uploading new items of ", path);
@ -533,7 +534,7 @@ final class SyncEngine
writeln(" done.");
} else {
writeln("");
response = session.upload(path, item.parentDriveId, item.parentId, baseName(path), eTag);
response = session.upload(path, item.driveId, item.parentId, baseName(path), eTag);
}
// saveItem(response); redundant
// use the cTag instead of the eTag because Onedrive may update the metadata of files AFTER they have been uploaded
@ -573,7 +574,7 @@ final class SyncEngine
if (isDir(path)) {
Item item;
if (!itemdb.selectByPath(path, item)) {
if (!itemdb.selectByPath(path, defaultDriveId, item)) {
uploadCreateDir(path);
}
// recursively traverse children
@ -583,7 +584,7 @@ final class SyncEngine
}
} else {
Item item;
if (!itemdb.selectByPath(path, item)) {
if (!itemdb.selectByPath(path, defaultDriveId, item)) {
uploadNewFile(path);
}
}
@ -591,23 +592,22 @@ final class SyncEngine
private void uploadCreateDir(const(char)[] path)
{
log.log("Creating folder ", path, "...");
log.log("Creating folder ", path);
Item parent;
enforce(itemdb.selectByPath(dirName(path), parent), "The parent item is not in the database");
enforce(itemdb.selectByPath(dirName(path), defaultDriveId, parent), "The parent item is not in the database");
JSONValue driveItem = [
"name": JSONValue(baseName(path)),
"folder": parseJSON("{}")
];
auto res = onedrive.createById(parent.driveId, parent.id, driveItem);
saveItem(res);
writeln(" done.");
}
private void uploadNewFile(string path)
{
write("Uploading file ", path, "...");
Item parent;
enforce(itemdb.selectByPath(dirName(path), parent), "The parent item is not in the database");
enforce(itemdb.selectByPath(dirName(path), defaultDriveId, parent), "The parent item is not in the database");
JSONValue response;
if (getSize(path) <= thresholdFileSize) {
response = onedrive.simpleUpload(path, parent.driveId, parent.id, baseName(path));
@ -660,18 +660,18 @@ final class SyncEngine
{
log.log("Moving ", from, " to ", to);
Item fromItem, toItem, parentItem;
if (!itemdb.selectByPath(from, fromItem)) {
if (!itemdb.selectByPath(from, defaultDriveId, fromItem)) {
throw new SyncException("Can't move an unsynced item");
}
if (fromItem.parentId == null) {
// the item is a remote folder, need to do the operation on the parent
enforce(itemdb.selectByPathNoRemote(from, fromItem));
enforce(itemdb.selectByPathNoRemote(from, defaultDriveId, fromItem));
}
if (itemdb.selectByPath(to, toItem)) {
if (itemdb.selectByPath(to, defaultDriveId, toItem)) {
// the destination has been overwritten
uploadDeleteItem(toItem, to);
}
if (!itemdb.selectByPath(dirName(to), parentItem)) {
if (!itemdb.selectByPath(dirName(to), defaultDriveId, parentItem)) {
throw new SyncException("Can't move an item to an unsynced directory");
}
if (fromItem.driveId != parentItem.driveId) {
@ -698,12 +698,12 @@ final class SyncEngine
void deleteByPath(const(char)[] path)
{
Item item;
if (!itemdb.selectByPath(path, item)) {
if (!itemdb.selectByPath(path, defaultDriveId, item)) {
throw new SyncException("Can't delete an unsynced item");
}
if (item.parentId == null) {
// the item is a remote folder, need to do the operation on the parent
enforce(itemdb.selectByPathNoRemote(path, item));
enforce(itemdb.selectByPathNoRemote(path, defaultDriveId, item));
}
try {
uploadDeleteItem(item, path);