Add id based database load and save functions

Add functions to save and load a Map of objects indexed by the id
property in the objects.
This commit is contained in:
Hornwitser committed 2019-11-21 22:25:15 +01:00
1 parent fcae3ef0c1
commit 65f75d86e6
6 files changed
+163 -4

No files matched your search

+76 -3
View File
@@ -31,9 +31,10 @@ function mapToObject(map) {
}
/**
* Load JSON file as a Map
* Load JSON object file as a Map
*
* Loads the JSON file specified by path an converts it into a JavaScript Map.
* Loads the JSON file specified by path containing an object with
* properties as key value pairs and converts it into a JavaScript Map.
* Returns an empty Map if the file does not exist.
*
* @param {string} filePath - The path to the JSON file to load.
@@ -71,7 +72,7 @@ async function loadJsonAsMap(filePath) {
}
/**
* Save a Map as a JSON file
* Save a Map as a JSON object file
*
* Save the content of a key-value Map with only string keys as a JSON file.
* If the directory the file is to be saved into doesn't exist it will be
@@ -87,6 +88,76 @@ async function saveMapAsJson(filePath, map) {
await fs.outputFile(filePath, JSON.stringify(obj, null, 4));
}
/**
* Load JSON array file as a Map
*
* Loads the JSON file specified by path containing an array of objects that
* each have an id property into a Map from the id to the object.
*
* @param {string} filePath - The path to the JSON file to load.
* @throws {Error} If JSON file did not contain an array.
* @throws {Error} If there are objects in the array without an id property.
* @throws {Error} If an error occured reading the file.
*/
async function loadJsonArrayAsMap(filePath) {
try {
let content = await fs.readFile(filePath);
let parsed = JSON.parse(content);
if (parsed === null) {
throw new Error(`Expected array but got null`);
}
if (typeof parsed !== "object") {
throw new Error(`Expected array but got ${typeof parsed}`);
}
if (!(parsed instanceof Array)) {
throw new Error(`Expected array but got object`);
}
let map = new Map();
for (let element of parsed) {
if (element === null || element instanceof Array || typeof element !== "object") {
throw new Error(`Expected all elements to be objects`);
}
if (element.id === undefined) {
throw new Error(`Expected all elements to have an id property`);
}
map.set(element.id, element);
}
return map;
} catch (err) {
if (err.code == "ENOENT") {
// File does not exist, return empty map
return new Map();
} else {
throw err;
}
}
}
/**
* Save a Map as a JSON array file
*
* Save the values of a Map with objects containing an id property that is
* equal to the key the objects are stored at into a JSON file.
*
* @param {string} filePath - The path to the JSON file that will be saved.
* @param {Map} map -
* Map with objects containing an id property equal to the key they are
* stored under.
* @throws {Error} if an error occured writing to the file.
*/
async function saveMapAsJsonArray(filePath, map) {
await fs.outputFile(filePath, JSON.stringify([...map.values()], null, 4));
}
function checkName(name) {
if (typeof name !== "string") {
@@ -227,5 +298,7 @@ module.exports = {
mapToObject,
loadJsonAsMap,
saveMapAsJson,
loadJsonArrayAsMap,
saveMapAsJsonArray,
ItemDatabase,
}
+1
View File
@@ -0,0 +1 @@
[null]
+1
View File
@@ -0,0 +1 @@
[{}]
+1
View File
@@ -0,0 +1 @@
[{"id":"a"},{"id":"b"}]
+10
View File
@@ -0,0 +1,10 @@
[
[
"c",
{}
],
[
"d",
"foo"
]
]
+74 -1
View File
@@ -60,7 +60,7 @@ describe("lib/database", function() {
describe("saveMapAsJson()", function() {
it("should save a mapping as JSON", async function() {
let testFile = 'test/json/save_map.json';
let testFile = 'test/temp/save_map.json';
async function deleteTestFile() {
try {
await fs.unlink(testFile);
@@ -81,7 +81,80 @@ describe("lib/database", function() {
await fs.readFile(testFile, {encoding: 'utf-8'}),
'{\n "c": {},\n "d": "foo"\n}'
);
});
});
describe("loadJsonArrayAsMap()", function() {
let badTypes = ['null', 'object', 'number', 'string', 'boolean'];
for (let type of badTypes) {
it(`should reject on ${type} JSON`, async function() {
await assert.rejects(
database.loadJsonArrayAsMap(`test/json/${type}.json`),
new Error(`Expected array but got ${type}`)
);
});
}
it("should reject on null element", async function() {
await assert.rejects(
database.loadJsonArrayAsMap('test/json/array_null.json'),
new Error("Expected all elements to be objects")
);
});
it("should reject on element missing id", async function() {
await assert.rejects(
database.loadJsonArrayAsMap('test/json/array_object.json'),
new Error("Expected all elements to have an id property")
);
});
it("should work on empty array JSON", async function() {
assert.deepEqual(
await database.loadJsonArrayAsMap('test/json/array.json'),
new Map()
);
});
it("should work on array JSON", async function() {
assert.deepEqual(
await database.loadJsonArrayAsMap('test/json/load_array_map.json'),
new Map([['a', {id: 'a'}], ['b', {id: 'b'}]])
);
});
it("should give an empty Map for non-existant file", async function() {
assert.deepEqual(
await database.loadJsonArrayAsMap('test/json/does-not-exist'),
new Map()
);
});
});
describe("saveMapAsJsonArray()", function() {
it("should save a mapping as JSON", async function() {
let testFile = 'test/temp/save_array_map.json';
async function deleteTestFile() {
try {
await fs.unlink(testFile);
} catch (err) {
/* istanbul ignore if */
if (err.code !== 'ENOENT') {
throw err;
}
}
}
await deleteTestFile();
await database.saveMapAsJsonArray(
testFile, new Map([['c', {id: 'c'}], ['d', {id: 'd'}]])
);
assert.equal(
await fs.readFile(testFile, {encoding: 'utf-8'}),
'[\n {\n "id": "c"\n },\n {\n "id": "d"\n }\n]'
);
});
});