UNPKG

copious-transitions

Version:
655 lines (584 loc) 26.1 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>JSDoc: Source: lib/general_db.js</title> <script src="scripts/prettify/prettify.js"> </script> <script src="scripts/prettify/lang-css.js"> </script> <!--[if lt IE 9]> <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> <![endif]--> <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css"> <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css"> </head> <body> <div id="main"> <h1 class="page-title">Source: lib/general_db.js</h1> <section> <article> <pre class="prettyprint source linenums"><code>const AppLifeCycle = require("./general_lifecyle") const DEFAULT_STATIC_SYNC_INTERVAL = (1000*60*30) /** * This class provides a central point of reckonning for database interfaces. * All modules that preform actions on behalf of the contractual modules have access to the application database interface. * This class provides interfaes for different type of databases. * * * the idea of the different types of DBs * 1) The key value DB is an LRU in memory cache which has disk backup. Different kinds of data structures can be put there * -- if a value is out of cache, it can be retrieved from disk. Used in song-search db. Stores files as the value. * -- Also, it retrieves files from disk at startup and stores them into the in memory table. (A shim for something like * -- Redis might be used.) * 2) The session_key_value_db -- this is for taking in and validating sessions in particular. It might be useful for other * -- data collection purposes. This is in-memory records, specifically within an LRU. There is no disk backup. But, * -- there is redundancy on secondary machines which will hold sessions for longer periods of time and age them out * -- gracefully unless they are accessed. * 3) the pdb - a persistence database is a database that promises to maintain a record with some permanence. It is fronted by * -- a key value db with ephemeral properties. But, it can be assumed that the records will be written early in the life of * -- a data object. Aging out of the LRU quickly can be expected. And, the data location can be expected to be on a seconday * -- machine. (User records -- for customer stats, etc. may be stored here) * 4) the sdb - a static data base. The static db is expected to be fairly similar to a persistence DB, except that it offers the * -- guarantee that the data items are stored on a disk local to the process which accesses the code. (This is mostly used to * -- create a set of static assets for serving to web sessions. Ideally, the sort of caching available to nginx or other * -- web servers might be served by this sort of store.) It is expected that the store will be loaded when the database service * -- starts for the general case. (The general case handles as much logic a it can. Dashboard and profile assets can be loaded. * -- these are sitewide pages or page frameworks which might be loaded with user specific data.) * * Note: both the persistence DB and the static DB will default to using the DB provided by `default_persistent_db` if these are not * configured or passed into the constructor. * * NOTE: all the base classes in /lib return the class and do not return an instance. Explore the applications and * the reader will find that the descendant modules export instances. The classes provided by copious-transitions must * be extended by an application. * * @memberof base */ class DBClass extends AppLifeCycle { // constructor(keyValueDB,sessionKeyValueDB,persistentDB,staticDB) { // super() // this.hasher = (typeof config.global_hasher === 'function') ? config.global_hasher : (key) => { return key } // // EPHEMERAL (in memory will be erased when the application turns off.. BUT -- may be replicated on nodes with checkpoint writes) this.key_value_db = keyValueDB // MEMORY BASED (SHARED MEM) but with with likely backup (size less determined) this.session_key_value_db = !(sessionKeyValueDB) ? keyValueDB : sessionKeyValueDB // MEMORY BASED (SHARED MEM) size fixed (all back up is elastic and ephemeral) // // CACHEABLE (WILL WRITE TO DISK SOMEWHERE) if ( !(persistentDB) ) { // DISK within LOCAL and PEER NODES this.pdb = require('../custom_storage/default_persistent_db') } else { this.pdb = persistentDB } // if ( !(staticDB) ) { // LOCAL ON DISK (LOCAL CACHE AND STARTUP CACHE) this.sdb = require('../custom_storage/default_static_db') } else { this.sdb = staticDB } if ( this.sdb &amp;&amp; (typeof this.sdb.setPersistence === 'function ') ) { this.sdb.setPersistence(this.pdb) } if ( this.key_value_db &amp;&amp; (typeof this.key_value_db.setPersistence === 'function ') ) { this.key_value_db.setPersistence(this.pdb) } } /** * Calls the initialization methods for all the connection based databases interfaces. * This includes the `key_value_db`, the persistent db (pdb), and the static db (sdb). * The `static_sync` interval is read from the configuration. * * @param {object} conf */ initialize(conf) { this.key_value_db.initialize(conf) if ( this.session_key_value_db !== this.key_value_db ) { this.session_key_value_db.initialize(conf) } this.pdb.initialize(conf) // initialize persitence...relative to the database this.sdb.initialize(conf) this.static_sync_interval = conf.static_sync ? conf.static_sync : DEFAULT_STATIC_SYNC_INTERVAL } /** * The method `last_step_initalization` exists in order to give make a call available to the initialization process * in the `user_service_class` module. This method is called at the start of `run`.s */ last_step_initalization() { } // /** * If the hasher is not set during construction, * then the application may use this method to set the has function for use by the db. * @param {*} hashfn */ set_hasher(hashfn) { this.hasher = hashfn } // KEY VALUE cache like DB in memory. e.g. an interface to shm-lru-cache /** * Insert or update in the key value DB * @param {string} key * @param {object} value - */ async set_key_value(key,value) { // notice this is set (the actual value is stored) await this.key_value_db.set(key,value) } // /** * delete from the key value DB * @param {string} token */ async del_key_value(token) { await this.key_value_db.delete(token) } // /** * return the value mapped by the key in the DB. * retun null if the value is not present. * * @param {string} key - key mapping to the object * @returns {any} */ async get_key_value(key) { try { let value = await this.key_value_db.get(key) return value } catch (e) { console.log(e) return null } } // --- SESSION --- /** * The session storage. * Most likely the session storage will be implemented as a shared hash table. * Some implementations may user share memory storage. And, some may use DHT (distributed hash tables). * * @param {string} key * @param {object} value * @returns {string} - the hash key for the value. */ async set_session_key_value(key,value) { // notice this is a hash set (a speedy check) return await this.session_key_value_db.hash_set(key,value) } // /** * Remove the key from the hash table and free up space. * * @param {string} key */ async del_session_key_value(key) { await this.session_key_value_db.delete(key) } // /** * Get the value from the hash table. * The value mapped by the key is often a JSON object. If so, it should be parsed before it is returned. * * @param {string} key * @returns {any} The value mapped by the key */ async get_session_key_value(key) { try { let value = await this.session_key_value_db.get(key) return value } catch (e) { console.log(e) return null } } // ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- // /** * This method is for fecthing the description of fields that may occur in client forms. * This method is called by the method used to configure the validator. * * @param {string} fields_key * @returns {object} */ async fetch_fields(fields_key) { // let fields = {} if ( fields_key ) { let fields = await this.fetch(fields_key) if ( (typeof fields) === 'string' ) { fields = JSON.parse(fields) } } return(fields) } // /** * This may be an implementation of get for one of the DB types. But, it may have other properties. * This is left as an abstract entry point for an application to define. * * @param {string} key * @returns {object} */ fetch(key) { // should be written by descendant let data = "" return(data) } // // ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- /** * Get an object from static store * @param {string} asset * @returns {object} -- the stored object */ async static_store(asset) { // for small size objects depending on the initialization parameters of the cache DB let data = "" if ( asset ) { try { data = await this.sdb.get_key_value(asset) if ( data ) { return(JSON.parse(data)) } } catch(e) { } } return(data) } /** * put the object in the static db, which attempts to keep a copy of the asset close to the processor on its own local disks... * * wrap the object in a carrier, in which the object is serialized with its mime-type for future transport.. * * * @param {string} whokey * @param {string} text * @param {string} mime_type * @param {string} extension * @returns {boolean} */ async put_static_store(whokey,text,mime_type,extension) { if ( (typeof text) !== 'string' ) { text = JSON.stringify(text) } if ( this.sdb === undefined ) return let data = { 'string' : text, 'mime_type' : mime_type } if ( extension &amp;&amp; ( typeof extension === 'object' ) ) { // don't overwrite the fields this storage is about. if ( extension.string !== undefined ) delete extension.string if ( extension.mime_type !== undefined ) delete extension.mime_type data = Object.assign(data,extension) } await this.sdb.set_key_value(whokey,data) } /** * * @param {string} whokey */ async del_static_store(whokey) { if ( this.sdb === undefined ) return await this.sdb.del_key_value(whokey) } /** * * @param {Function} sync_function */ static_synchronizer(sync_function) { if ( this.sdb === undefined ) return if ( this.sdb.schedule === undefined ) return this.sdb.schedule(sync_function,this.static_sync_interval) } // CACHE // ---- ---- ---- ---- ---- ---- ---- ---- ---- // May use a backref /** * * @param {string} key * @param {object} data * @param {string} back_ref */ async store_cache(key,data,back_ref) { // make use of the application chosen key-value implementation... // let ref = back_ref ? data[back_ref] : false; if ( ref ) { let ehash = this.hasher(key) await this.set_key_value(ref,ehash) await this.set_key_value(ehash,data) } else { // await this.set_key_value(key,data) // } } /** * * @param {string} key * @param {object} body * @returns {object} */ async cache_stored(key,body) { let ehash = this.hasher(key) try { let data = await this.get_key_value(ehash) if ( data ) { if ( (typeof data) === 'string' ) { return JSON.parse(data) } return data } else return body } catch(e) { return body } } /** * * @param {string} key * @param {object} data * @param {string} back_ref */ async update_cache(key,data,back_ref) { if ( typeof data !== 'string' ) { data = JSON.stringify(data) } let ref = back_ref ? data[back_ref] : false; if ( ref ) { let ehash = this.get_key_value(ref) if ( ehash !== false ) { await this.set_key_value(ehash,data) } } else { // await this.set_key_value(key,JSON.stringify(data)) // } } // ---- ---- ---- ---- ---- ---- ---- ---- ---- // // in subclass // /** * A wrapper for putting data into a table * * @param {object} collection - A table that will eventually contain the item * @param {object} data - any data that might be used by a method for inserting an entry or the data to be stored */ store(collection,data) {} // /** * * A method for checling the existence of some object in a DB table. * * @param {object} collection - A table that will containing the item to be found * @param {object} data - any data that might be used by a method for searching for an entry * @returns {boolean} */ exists(collection,query_components) { return(false) } // /** * * @param {object} collection - A table that will containing the item to be removed * @param {object} data - any data that might be used by a method removing an entry */ remove(collection,data) {} /** * * This is a method for wrapping `drop` usually associated with a DB for dropping a table. * The collection is some object (perhaps a string) identifying the object to be dropped. * * @param {object} collection - A table that will be dropped * @param {object} data - any data that might be used by a method dropping a DB table. */ drop(collection,data) {} // drop the database connection // /** * This method is made available for applications that will clean up database connections on shutdown * or at various other times. * * @returns {boolean} - the extending class must implement this method */ disconnect() { console.log("implement in instance") return(false) } } /** * * USER METHODS default implementations * * This class adds methods that deal directly with possible user storage and lookup tables. * The methods defined in the class are used by the class GeneralAuth found in `general_auth.js` in particular. * * The default behavior is for the user to be stored in the persistence DB, which is most likely to be * implemented by a connection to a DB service. Except there is one method `fetch_user_from_key_value_store` * that is used to get user information from the key-value DB, which is expected to be faster (in local memory). * * Some applcations may want to override this class in order to change the kind of user table storage arrangement from * what is provided here. Even without the override, the constuctor expects that objects linking to external databases to be parameters. * * Within the user methods, the user object, `u_data` (often) is expected to have an identity field, `_id`. * */ class GeneralUserDBWrapperImpl extends GeneralDBWrapperImpl { constructor(keyValueDB,sessionKeyValueDB,persistentDB,staticDB) { super(keyValueDB,sessionKeyValueDB,persistentDB,staticDB) } /** * * Some applications may elect to store user in the KV store. * That is not the default behavior. The default behavior is to store the user in the persistence DB. * * @param {string} key * @returns {object|boolean} - returns false on failing to find an object */ async fetch_user_from_key_value_store(key) { if ( key == undefined ) return(false); try { let ehash = await this.get_key_value(key) if ( ehash === null || ehash === false ) { return(false) } if ( isHex(ehash) ) { // or other format try { let u_data = await this.get_key_value(ehash) if ( u_data ) { if ( (typeof data) === 'string' ) { return JSON.parse(data) } return data } return false } catch (e) { return false } } else { try { let data = ehash // user data if ( (typeof data) === 'string' ) { return JSON.parse(data) } return data } catch (e) { return false } } } catch(e) { return false } } /** * This is supplied to provide the parenthetical to the method `fetch_user_from_key_value_store` * @param {string} key * @param {object} u_data * @returns {boolean} - false on error */ async put_user_into_key_value_store(key,u_data,ehash) { if ( key == undefined ) return(false); try { if ( ehash !== undefined ) { await this.set_key_value(key,ehash) if ( typeof u_data !== 'string' ) { u_data = JSON.stringify(u_data) } await this.set_key_value(ehash,u_data) return true } else { if ( typeof u_data !== 'string' ) { u_data = JSON.stringify(u_data) } await this.set_key_value(ehash,u_data) return true } } catch(e) { return false } } /** * * @param {string} user_txt * @returns {string} an unique id for a stored object */ id_hashing(user_txt) { let id = this.hasher(user_txt) // or this.oracular_storage() return id } // store_user // // just work with the presistent DB /** * * @param {object} u_data * @param {string} key * @param {Function} cb * @returns {string} an unique id for a stored object */ async store_user(u_data,key,cb) { // up to the application...(?) let id = '' if ( key ) { id = u_data[key] } else { id = u_data._id if ( id === undefined ) { let user_txt if ( (typeof data) !== 'string' ) { user_txt = JSON.stringify(u_data) } else { user_txt = data } id = await this.id_hashing(user_txt) // or this.oracular_storage() } } u_data._id = id u_data._tx_directory_ensurance = true // for the endpoint -- might not need it // m_path is user let dont_remote = false let result = await this.pdb.update(u_data,dont_remote,'create') // the end point will write information into files and create directories... // a response service will react sending new information to subscribers... if ( cb !== undefined ) cb(result) return(id) } // /** * * @param {string} id * @param {Function} cb * @returns {object} - the user object stored in the DB */ async fetch_user(id,cb) { // up to the application...(?) // just work with the presistent DB return(await this.pdb.findOne(id,cb)) } // /** * * @param {object} u_data * @param {string} id_key * @param {Function} cb */ async update_user(u_data,id_key,cb) { // just work with the presistent DB let id = '' if ( key ) { id = u_data[id_key] } else { id = u_data._id } if ( u_data._id == undefined ) { u_data._id = id } u_data._tx_directory_ensurance = true // m_path is user let dont_remote = false let result = await this.pdb.update(u_data,dont_remote,'update') // the end point will write information into files and create directories... if ( cb !== undefined ) cb(result) } } module.exports = DBClass </code></pre> </article> </section> </div> <nav> <h2><a href="index.html">Home</a></h2><h3>Namespaces</h3><ul><li><a href="Contractual.html">Contractual</a></li><li><a href="CopiousTransitions.html">CopiousTransitions</a></li><li><a href="DefaultDB.html">DefaultDB</a></li><li><a href="base.html">base</a></li><li><a href="field_validators.html">field_validators</a></li></ul><h3>Classes</h3><ul><li><a href="Contractual.LocalTObjectCache.html">LocalTObjectCache</a></li><li><a href="Contractual.MimeHandling.html">MimeHandling</a></li><li><a href="Contractual.TransitionHandling.html">TransitionHandling</a></li><li><a href="Contractual.UserHandling.html">UserHandling</a></li><li><a href="CopiousTransitions.CopiousTransitions.html">CopiousTransitions</a></li><li><a href="DefaultDB.CustomizationMethodsByApplication.html">CustomizationMethodsByApplication</a></li><li><a href="DefaultDB.FauxInMemStore.html">FauxInMemStore</a></li><li><a href="DefaultDB.FileMapper.html">FileMapper</a></li><li><a href="DefaultDB.FilesAndRelays.html">FilesAndRelays</a></li><li><a href="DefaultDB.FilesAndRelays_base.html">FilesAndRelays_base</a></li><li><a href="DefaultDB.LocalStaticDB.html">LocalStaticDB</a></li><li><a href="DefaultDB.LocalStorageLifeCycle.html">LocalStorageLifeCycle</a></li><li><a href="DefaultDB.LocalStorageSerialization.html">LocalStorageSerialization</a></li><li><a href="DefaultDB.PageableMemStoreElement.html">PageableMemStoreElement</a></li><li><a href="DefaultDB.PersistenceContracts.html">PersistenceContracts</a></li><li><a href="DefaultDB.RemoteMessaging.html">RemoteMessaging</a></li><li><a href="DefaultDB.StaticDBDefault.html">StaticDBDefault</a></li><li><a href="GeneralUserDBWrapperImpl.html">GeneralUserDBWrapperImpl</a></li><li><a href="SessionTokenManager.html">SessionTokenManager</a></li><li><a href="base.DBClass.html">DBClass</a></li><li><a href="base.EndpointManager.html">EndpointManager</a></li><li><a href="base.GeneralAppLifeCycle.html">GeneralAppLifeCycle</a></li><li><a href="base.GeneralAuth.html">GeneralAuth</a></li><li><a href="base.GeneralBusiness.html">GeneralBusiness</a></li><li><a href="base.GeneralDynamic.html">GeneralDynamic</a></li><li><a href="base.GeneralMiddleWare.html">GeneralMiddleWare</a></li><li><a href="base.GeneralStatic.html">GeneralStatic</a></li><li><a href="base.GeneralTransitionEngImpl.html">GeneralTransitionEngImpl</a></li><li><a href="base.SessionManager.html">SessionManager</a></li><li><a href="base.SessionManager_Lite.html">SessionManager_Lite</a></li><li><a href="base.TaggedTransition.html">TaggedTransition</a></li><li><a href="base.TokenTables.html">TokenTables</a></li><li><a href="base.UserMessageEndpoint.html">UserMessageEndpoint</a></li><li><a href="base.WebSocketManager.html">WebSocketManager</a></li><li><a href="field_validators.DataLookupField.html">DataLookupField</a></li><li><a href="field_validators.EmailField.html">EmailField</a></li><li><a href="field_validators.EmailVerifyField.html">EmailVerifyField</a></li><li><a href="field_validators.FieldTest.html">FieldTest</a></li><li><a href="field_validators.FieldValidatorTools.html">FieldValidatorTools</a></li><li><a href="field_validators.ForeignAuth.html">ForeignAuth</a></li><li><a href="field_validators.GeneralValidator.html">GeneralValidator</a></li><li><a href="field_validators.LengthyAlphabetField.html">LengthyAlphabetField</a></li><li><a href="field_validators.LengthyDigitalField.html">LengthyDigitalField</a></li><li><a href="field_validators.LengthyField.html">LengthyField</a></li><li><a href="field_validators.LengthyStringField.html">LengthyStringField</a></li><li><a href="field_validators.PasswordField.html">PasswordField</a></li><li><a href="field_validators.PasswordVerifyField.html">PasswordVerifyField</a></li><li><a href="field_validators.TypeCheckField.html">TypeCheckField</a></li></ul><h3>Global</h3><ul><li><a href="global.html#generate_password_block">generate_password_block</a></li><li><a href="global.html#load_configuration">load_configuration</a></li><li><a href="global.html#load_parameters">load_parameters</a></li><li><a href="global.html#module_top">module_top</a></li></ul> </nav> <br class="clear"> <footer> Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a> on Tue Oct 31 2023 17:32:59 GMT-0700 (Pacific Daylight Time) </footer> <script> prettyPrint(); </script> <script src="scripts/linenumber.js"> </script> </body> </html>