nconf-lite/lib/nconf/stores/memory.js

226 lines
5.1 KiB
JavaScript

/*
* memory.js: Simple memory storage engine for nconf configuration(s)
*
* (C) 2011, Charlie Robbins and the Contributors.
*
*/
var common = require('../common');
//
// ### function Memory (options)
// #### @options {Object} Options for this instance
// Constructor function for the Memory nconf store which maintains
// a nested json structure based on key delimiters `:`.
//
// e.g. `my:nested:key` ==> `{ my: { nested: { key: } } }`
//
var Memory = exports.Memory = function (options) {
options = options || {};
this.type = 'memory';
this.store = {};
this.mtimes = {};
this.readOnly = false;
this.loadFrom = options.loadFrom || null;
this.logicalSeparator = options.logicalSeparator || ':';
if (this.loadFrom) {
this.store = common.loadFilesSync(this.loadFrom);
}
};
//
// ### function get (key)
// #### @key {string} Key to retrieve for this instance.
// Retrieves the value for the specified key (if any).
//
Memory.prototype.get = function (key) {
var target = this.store,
path = common.path(key, this.logicalSeparator);
//
// Scope into the object to get the appropriate nested context
//
while (path.length > 0) {
key = path.shift();
if (target && target.hasOwnProperty(key)) {
target = target[key];
continue;
}
return undefined;
}
return target;
};
//
// ### function set (key, value)
// #### @key {string} Key to set in this instance
// #### @value {literal|Object} Value for the specified key
// Sets the `value` for the specified `key` in this instance.
//
Memory.prototype.set = function (key, value) {
if (this.readOnly) {
return false;
}
var target = this.store,
path = common.path(key, this.logicalSeparator);
if (path.length === 0) {
//
// Root must be an object
//
if (!value || typeof value !== 'object') {
return false;
}
else {
this.reset();
this.store = value;
return true;
}
}
//
// Update the `mtime` (modified time) of the key
//
this.mtimes[key] = Date.now();
//
// Scope into the object to get the appropriate nested context
//
while (path.length > 1) {
key = path.shift();
if (!target[key] || typeof target[key] !== 'object') {
target[key] = {};
}
target = target[key];
}
// Set the specified value in the nested JSON structure
key = path.shift();
target[key] = value;
return true;
};
//
// ### function clear (key)
// #### @key {string} Key to remove from this instance
// Removes the value for the specified `key` from this instance.
//
Memory.prototype.clear = function (key) {
if (this.readOnly) {
return false;
}
var target = this.store,
value = target,
path = common.path(key, this.logicalSeparator);
//
// Remove the key from the set of `mtimes` (modified times)
//
delete this.mtimes[key];
//
// Scope into the object to get the appropriate nested context
//
for (var i = 0; i < path.length - 1; i++) {
key = path[i];
value = target[key];
if (typeof value !== 'function' && typeof value !== 'object') {
return false;
}
target = value;
}
// Delete the key from the nested JSON structure
key = path[i];
delete target[key];
return true;
};
//
// ### function merge (key, value)
// #### @key {string} Key to merge the value into
// #### @value {literal|Object} Value to merge into the key
// Merges the properties in `value` into the existing object value
// at `key`. If the existing value `key` is not an Object, it will be
// completely overwritten.
//
Memory.prototype.merge = function (key, value) {
if (this.readOnly) {
return false;
}
//
// If the key is not an `Object` or is an `Array`,
// then simply set it. Merging is for Objects.
//
if (typeof value !== 'object' || Array.isArray(value) || value === null) {
return this.set(key, value);
}
var self = this,
target = this.store,
path = common.path(key, this.logicalSeparator),
fullKey = key;
//
// Update the `mtime` (modified time) of the key
//
this.mtimes[key] = Date.now();
//
// Scope into the object to get the appropriate nested context
//
while (path.length > 1) {
key = path.shift();
if (!target[key]) {
target[key] = {};
}
target = target[key];
}
// Set the specified value in the nested JSON structure
key = path.shift();
//
// If the current value at the key target is not an `Object`,
// or is an `Array` then simply override it because the new value
// is an Object.
//
if (typeof target[key] !== 'object' || Array.isArray(target[key])) {
target[key] = value;
return true;
}
return Object.keys(value).every(function (nested) {
return self.merge(common.keyed(self.logicalSeparator, fullKey, nested), value[nested]);
});
};
//
// ### function reset (callback)
// Clears all keys associated with this instance.
//
Memory.prototype.reset = function () {
if (this.readOnly) {
return false;
}
this.mtimes = {};
this.store = {};
return true;
};
//
// ### function loadSync
// Returns the store managed by this instance
//
Memory.prototype.loadSync = function () {
return this.store || {};
};