225 lines
5.1 KiB
JavaScript
225 lines
5.1 KiB
JavaScript
/*
|
|
* memory.js: Simple memory storage engine for nconf configuration(s)
|
|
*
|
|
* (C) 2011, Nodejitsu Inc.
|
|
*
|
|
*/
|
|
|
|
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 || {};
|
|
};
|