UNPKG

@aegis-framework/artemis

Version:

Aegis Framework Javascript Library

225 lines (210 loc) 6.4 kB
/** * ============================== * Remote Storage Adapter * ============================== */ import { Request } from './../Request'; /** * The Remote Storage Adapter provides the Space Class the ability to interact * with a server in order to handle data persistance. The server's implementation * is up to the developer but it will need to respond to this adapter's request * formatting. This adapter uses the Request class to perfom its tasks. * * @class */ export class RemoteStorage { /** * Create a new Remote Storage. This adapter requires an endpoint url where * it will make the requests. If a store is defined, the request will be made * using the store as an URL, for example, let's assume the following endpoint: * * https://example.com/api/v1/ * * If no store is defined, then the requests will be made to that simple route, * with a store definition, requests will be made to: * * https://example.com/api/v1/{myStore}/ * * The key of each item in this store represents another part of the request * * https://example.com/api/v1/{key}/ * * Or: * * https://example.com/api/v1/{myStore}/{key}/ * * This adapter just as the IndexedDB, works with JSON objects instead of string or * numeric values. * * @constructor * @param {object} [configuration={name = '', version = '', store = '', endpoint = '', props = {}] - Configuration Object for the Adapter * @param {string} configuration.name - Name of the Space * @param {string} configuration.version - Version of the Space in Semantic versioning syntax * @param {string} configuration.store - Name of the Object Store to use * @param {string} configuration.endpoint - Endpoint URL where the requests will be made * @param {string} configuration.props - Properties object to use for the fetch requests */ constructor ({name = '', version = '', store = '', endpoint = '', props = {}}) { this.name = name; this.version = version; this.store = store; this.endpoint = `${endpoint}${store}/`; this.props = props; } /** * Open the Storage Object * * @return {Promise<RemoteStorage>} */ open () { if (typeof this.storage === 'undefined') { this.storage = Request; } return Promise.resolve (this); } /** * Store a key-value pair. This function sends a POST request to the server * * @param {string} key - Key with which this value will be saved * @param {Object} value - Value to save * @return {Promise<Response>} */ set (key, value) { return this.open ().then (() => { return this.storage.post (this.endpoint + key, value, this.props) .then ((response) => response.json ()) .then ((value) => { return Promise.resolve ({ key, value }); }); }); } /** * Update a key-value pair. In difference with the set () method, the update * method will use an Object.assign () in the case of objects so no value is * lost. This function sends a PUT request to the server. * * @param {string} key - Key with which this value will be saved * @param {Object} value - Value to save * @return {Promise<Object>} */ update (key, value) { return this.get (key).then ((currentValue) => { return this.storage.put (this.endpoint + key, Object.assign ({}, currentValue, value), this.props) .then ((response) => response.json ()) .then ((value) => { return Promise.resolve ({ key, value }); }); }); } /** * Retrieves a value from storage given it's key * * @param {string} - Key with which the value was saved * @return {Promise<Object>} - Resolves to the retreived value or its rejected * if it doesn't exist */ get (key) { return this.open ().then (() => { return this.storage.json (this.endpoint + key, {}, this.props); }); } /** * Retrieves all the values in the space in a key-value JSON object * * @return {Promise<Object>} - Resolves to the retreived values */ getAll () { return this.open ().then (() => { return this.storage.json (this.endpoint, {}, this.props); }); } /** * Check if a space contains a given key. * * @param {string} key - Key to look for. * @return {Promise} Promise gets resolved if it exists and rejected if it * doesn't */ contains (key) { return this.keys ().then ((keys) => { if (keys.includes (key)) { Promise.resolve (); } else { return Promise.reject (); } }); } /** * Upgrading the Storage must be done on the server side, therefore this function * always gets rejected. * * @returns {Promise} */ upgrade () { return Promise.reject (); } /** * Renaming the Storage must be done on the server side, therefore this function * always gets rejected. * * @returns {Promise} */ rename () { return Promise.reject (); } /** * Getting a key by its index is not possible in this adapter, therefore this * function always gets rejected. * * @return {Promise} - Promise Rejection */ key () { return Promise.reject (); } /** * Return all keys stored in the space. This makes a GET request to the full * endpoint (the URL of the endpoint and store name) with a keys query * parameter: * * https://example.com/api/v1/?keys=true * * Or: * * https://example.com/api/v1/{myStore}/?keys=true * * @return {Promise<string[]>} - Array of keys */ keys () { return this.open ().then (() => { return this.storage.json (this.endpoint, {keys: true}, this.props); }); } /** * Delete a value from the space given it's key. This function sends a DELETE * request to the server. * * @param {string} key - Key of the item to delete * @return {Promise<key, value>} - Resolves to the key and value of the deleted object */ remove (key) { return this.open ().then (() => { return this.storage.delete (this.endpoint + key, {}, this.props) .then ((response) => response.json ()) .then ((value) => { return Promise.resolve (key,value); }); }); } /** * Clear the entire space. This function sends a DELETE request to the server. * The difference between a clear () and remove () operation is that the clear * operation does not uses a key in the URL where the request is made. * * @return {Promise} - Result of the clear operation */ clear () { return this.open ().then (() => { return this.storage.delete (this.endpoint, {}, this.props); }); } }