tildefriends/packages/cory/db/db.js

269 lines
7.5 KiB
JavaScript

//! {"category": "libraries"}
class DatabaseList {
constructor(name) {
this._name = name;
}
_getList() {
let self = this;
return database.get(this._name).then(function(node) {
return JSON.parse(node);
}).catch(function(error) {
return self._emptyNode();
});
}
_randomKey() {
let kAlphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
let kBytes = 32;
let result = "";
for (let i = 0; i < kBytes; i++) {
result += kAlphabet.charAt(Math.floor(Math.random() * kAlphabet.length));
}
return this._name + "_" + result;
}
_emptyNode() {
return {next: null, previous: null};
}
_getNode() {
var self = this;
var key = self._randomKey();
return database.get(key).then(function(found) {
if (!found) {
return key;
} else {
return self._getNode();
}
});
}
_getRelative(node, next, count) {
}
_insertEnd(item, after) {
let self = this;
return this._getList().then(function(listNode) {
let readPromises = [self._getNode()];
readPromises.push(listNode.previous ? database.get(listNode.previous).then(JSON.parse) : null);
readPromises.push(listNode.next ? database.get(listNode.next).then(JSON.parse) : null);
return Promise.all(readPromises).then(function(results) {
let newNodeName = results[0];
let previousNode = results[1];
let nextNode = results[2];
let newNode = self._emptyNode();
let oldPrevious = listNode.previous;
let oldNext = listNode.next;
newNode.value = item;
newNode.previous = listNode.previous || newNodeName;
newNode.next = listNode.next || newNodeName;
if (after) {
listNode.previous = newNodeName;
listNode.next = listNode.next || newNodeName;
} else {
listNode.next = newNodeName;
listNode.previous = listNode.previous || newNodeName;
}
let writePromises = [
database.set(self._name, JSON.stringify(listNode)),
database.set(newNodeName, JSON.stringify(newNode)),
];
if (oldPrevious && oldPrevious == oldNext) {
previousNode.next = newNodeName;
previousNode.previous = newNodeName;
writePromises.push(database.set(oldPrevious, JSON.stringify(previousNode)));
} else {
if (previousNode) {
previousNode.next = newNodeName;
writePromises.push(database.set(oldPrevious, JSON.stringify(previousNode)));
}
if (nextNode) {
nextNode.previous = newNodeName;
writePromises.push(database.set(oldNext, JSON.stringify(nextNode)));
}
}
return Promise.all(writePromises);
});
});
}
_removeEnd(after) {
let self = this;
return this._getList().then(function(listNode) {
if (listNode.next) {
if (listNode.next == listNode.previous) {
return database.get(listNode.next).then(JSON.parse).then(function(removedNode) {
let removedName = listNode.next;
listNode.next = null;
listNode.previous = null;
return Promise.all([
database.remove(removedName),
database.set(self._name, JSON.stringify(listNode)),
]).then(function() {
return removedNode.value;
});
});
} else {
let name1 = listNode.previous;
let name2 = listNode.next;
return Promise.all([
database.get(listNode.previous),
database.get(listNode.next),
]).then(function(nodes) {
var node1 = JSON.parse(nodes[0]);
var node2 = JSON.parse(nodes[1]);
if (after) {
let name0 = node1.previous;
return database.get(name0).then(JSON.parse).then(function(node0) {
node0.next = name2;
node2.previous = name0;
listNode.previous = name0;
return Promise.all([
database.set(name0, JSON.stringify(node0)),
database.remove(name1),
database.set(name2, JSON.stringify(node2)),
database.set(self._name, JSON.stringify(listNode)),
])
}).then(function() {
return node1.value;
});
} else {
let name3 = node2.next;
return database.get(name3).then(JSON.parse).then(function(node3) {
node1.next = name3;
node3.previous = name1;
listNode.next = name3;
terminal.print(name1, " ", name2, " ", name3, " ", self._name);
terminal.print(JSON.stringify(listNode));
return Promise.all([
database.set(name1, JSON.stringify(node1)),
database.remove(name2),
database.set(name3, JSON.stringify(node3)),
database.set(self._name, JSON.stringify(listNode)),
])
}).then(function() {
return node2.value;
});
}
});
}
}
});
}
push(item) {
return this._insertEnd(item, true);
}
pop() {
return this._removeEnd(true);
}
shift() {
return this._removeEnd(false);
}
unshift(item) {
return this._insertEnd(item, false);
}
_sliceInternal(head, count, next, end, result) {
let self = this;
if (head[next] == end && count > 0) {
result.push(head.value);
return new Promise(function(resolve, reject) { resolve(result); });
} else {
if (count > 0) {
return database.get(head[next]).then(JSON.parse).then(function(retrieved) {
return self._sliceInternal(retrieved, count - 1, next, end, result).then(function(result) {
result.push(head.value);
return result;
});
});
} else {
return new Promise(function(resolve, reject) { resolve(result); });
}
}
}
get(count) {
let self = this;
return self._getList().then(function(listNode) {
if (listNode.next) {
return database.get(count > 0 ? listNode.next : listNode.previous).then(JSON.parse).then(function(head) {
if (head) {
return self._sliceInternal(
head,
Math.abs(count),
count > 0 ? "next" : "previous",
count > 0 ? listNode.next : listNode.previous,
[]).then(function(result) {
result.reverse();
return result;
});
} else {
return null;
}
});
}
});
}
}
function wipeDatabase() {
let promises = [];
return database.getAll().then(function(list) {
for (let i = 0; i < list.length; i++) {
promises.push(database.remove(list[i]));
}
});
return Promise.all(promises);
}
function dumpDatabase() {
return database.getAll().then(function(list) {
let promises = [];
for (let i = 0; i < list.length; i++) {
promises.push(database.get(list[i]));
}
return Promise.all(promises).then(function(values) {
for (let i = 0; i < list.length; i++) {
terminal.print(list[i], " ", values[i]);
}
});
}).catch(function(error) {
terminal.print(error);
});
}
if (imports.terminal) {
x = new DatabaseList("list");
core.register("onInput", function(input) {
if (input == "clear") {
wipeDatabase().then(function() {
terminal.print("Database is now empty.");
});
} else if (input.substring(0, "push ".length) == "push ") {
x.push(input.substring("push ".length)).then(dumpDatabase).catch(terminal.print);
} else if (input.substring(0, "unshift ".length) == "unshift ") {
x.unshift(input.substring("unshift ".length)).then(dumpDatabase).catch(terminal.print);
} else if (input == "pop") {
x.pop().then(function(out) {
terminal.print("POPPED: ", out);
}).then(dumpDatabase).catch(terminal.print);
} else if (input == "shift") {
x.shift().then(function(out) {
terminal.print("SHIFTED: ", out);
}).then(dumpDatabase).catch(terminal.print);
} else if (input.substring(0, "get ".length) == "get ") {
let parts = input.split(" ");
x.get(parseInt(parts[1])).then(function(result) {
terminal.print(JSON.stringify(result))
}).catch(terminal.print);
} else {
dumpDatabase();
}
});
}