Source: mvc/RestStore.js

const collect = require('collect.js');
const Store = require('./Store.js').Store;

/**
 * This class implements the Store api and transforms it to librest rest calls.
 * @implements Store
 */
class RestStore extends Store {
	constructor(rest, formDataConstructor) {
		super();
		this._rest = rest;
		this._formDataConstructor = formDataConstructor;
	}

	read(cls, params, method) {
		let url = `/rest/${cls}`;

		if (params !== undefined && params.keys().isNotEmpty()) {
			if (params.constructor.name !== 'Collection') {
				throw Error(`Parameters is of unsuported type: ${params.constructor.name}`);
			}

			if (params.has('uid')) {
				url = url.concat('/', params.get('uid'));
				params.forget('uid');
			}
			if (method != null) {
				url = url.concat('/', method);
			}
			if (!params.keys().isEmpty()) {
				let args = this._encodeMap(params);
				url = url.concat('?', args);
			}
		}
		else {
			if (method != null) {
				url = url.concat('/', method);
			}
		}
		return this._rest.get(url);
	}

	delete(cls, uid) {
		if (uid === undefined) {
			throw Error("Must a have an uid");
		}
		return this._rest.delete(`/rest/${cls}/${uid}`);
	}

	update(cls, data, method) {
		let url = `/rest/${cls}`;
		if (data.uid !== undefined) {
			url = url.concat('/', data.uid);
		}
		if (method !== undefined) {
			url = url.concat('/', method);
		}
		let formData = this._formData(data);
		return this._rest.post(url, formData);
	}

	_encodeMap(data) {
		if (data.constructor.name !== 'Collection') {
			throw Error(`Data is of unsuported type: ${data.constructor.name}`);
		}
		let result = '';
		data.each((value, name) => {
			if (result.length > 0) {
				result = result.concat(('&'));
			}
			if (value === undefined || value === null) {
				value = 'null';
			}
			else if (value.constructor.name === 'Object') {
				value = JSON.stringify(value);
			}
			result = result.concat(name,'=',encodeURI(value));
		});
		return result;
	}

	_formData(data) {
		let result = new this._formDataConstructor();
		if (data === undefined || data === null) {
			return result;
		}
		switch(data.constructor.name) {
			case 'Collection':
				data.each((value, key) => this._populate(result, key, value));
				break;
			case 'Object':
				collect(data).each((value, key) => this._populate(result, key, value));
				break;
			case 'FileList':
				for (let i = 0; i < data.length; i++) {
					result.append('files[]', data[i]);
				}
				break;
			default:
				throw Error(`Data is of unsuported type: ${data.constructor.name}`);
		}
		return result;
	}

	_populate(formData, name, value) {
		if (value == null) {
			formData.append(name, value);
		}
		else {
			switch(value.constructor.name) {
				case 'Collection':
					formData.append(name, value.toJson());
					break;
				case 'Object':
					formData.append(name, JSON.stringify(value));
					break;
				case 'File':
					formData.append(name, value);
					break;
				case 'FileList':
					for (let i = 0; i < value.length; i++) {
						formData.append(`${name}[]`, value[i]);
					}
					break;
				default:
					formData.append(name, value);
			}
		}
	}
}
exports.RestStore = RestStore;