Source: resolvers/jsonResolver.js

const fs = require('fs').promises;

import Resolver from './base';

// Maybe this should just be done with arguments passed to Resolver
/** Read and write objects and collections to a JSON file */
class JsonResolver extends Resolver {
	constructor(file, appRoot) {
		super(appRoot);
		this._saveLocation = file;
	}

	async load() {
		let j;
		try {
			if(this._saving) {
				await this._saving;
			}
			const json = await fs.readFile(this._saveLocation, 'utf8');
			j = [this._saveLocation, json];
			const { collections, objects } = require(this._saveLocation);
			this._storageHandlers._collections = collections;
			this._storageHandlers._objects = objects;
		} catch(e) {
			console.log('Could not parse json', j);
			switch(e.code) {
				case 'MODULE_NOT_FOUND':
				case 'ENOENT':
					this._storageHandlers._collections = {};
					this._storageHandlers._objects = {};
					break;
				default:
					throw e;
			}
		}
	}

	async save(){
		if(this._saving) {
			await this._saving;
		}

		this._saving = fs.writeFile(this._saveLocation, JSON.stringify({ collections: this._storageHandlers._collections, objects: this._storageHandlers._objects }));
		await this._saving;
		this._saving = null;
	}

	async write(fn){
		await this.load();
		const r = await fn();
		console.log('Write');
		await this.save();
		console.log('End write');
		return r;
	}

	/**
	 * Store the object and assign it an ID
	 * @param {Object} object Created object
	 */
	async createObject(object){
		return this.write(() => super.createObject(object));
	}

	/**
	 * Fetch and return an object by its ID
	 * @param {string} id Object ID
	 */
	async getObject(id) {
		await this.load();

		return super.getObject(id);
	}

	/**
	 * Update an object and store it
	 * @param {Object} object Object
	 */
	async updateObject(object){
		// Save the object
		return this.write(() => super.updateObject(object));
	}

	/**
	 * Delete an object
	 * @param {Object|string} objectOrId The object or ID to delete
	 */
	async deleteObject(objectOrId){
		return this.write(() => super.deleteObject(objectOrId));
	}

	/**
	 * Return items for a collection
	 * @param {Collection} collection The collection to load for
	 */
	async collectionLoad(collection) {
		await this.load();

		console.log(this._)

		return super.collectionLoad(collection);
	}

	/**
	 * Add an object to a collection and store it
	 * @param {Collection} collection The collection to add to
	 * @param {Object} object The object to add
	 */
	async collectionAdd(collection, object) {
		return this.write(() => super.collectionAdd(collection, object));
	}

	/**
	 * Remove an object from a collection & persist
	 * @param {Collection} collection Target collection
	 * @param {Object|string} objectOrId Item to remove from collection
	 */
	async collectionRemove(collection, objectOrId) {
		return this.write(() => super.collectionRemove(collection, objectOrId));
	}
}

export default JsonResolver;