Skip to content

Commit

Permalink
subject database hooks changes to update redis entries (#276)
Browse files Browse the repository at this point in the history
* subject database hooks changes to update redis entries

* aspect database hook changes to update redis

* lint error fix

* added a comment to cleanSample and cleanAspect function

* fixed a typo

* updated the comments section of redisOps.js again

* fixed a few more typos
  • Loading branch information
shriramshankar authored and pallavi2209 committed Mar 8, 2017
1 parent 8a2c590 commit 9a3d25f
Show file tree
Hide file tree
Showing 12 changed files with 1,030 additions and 11 deletions.
261 changes: 261 additions & 0 deletions cache/redisOps.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,261 @@
/**
* Copyright (c) 2017, salesforce.com, inc.
* All rights reserved.
* Licensed under the BSD 3-Clause license.
* For full license text, see LICENSE.txt file in the repo root or
* https://opensource.org/licenses/BSD-3-Clause
*/

/**
* cache/redisOps.js
*/
'use strict'; // eslint-disable-line strict

const redisStore = require('./sampleStore');
const redisClient = require('./redisCache').client.sampleStore;
const subjectType = redisStore.constants.objectType.subject;
const aspectType = redisStore.constants.objectType.aspect;
const sampleType = redisStore.constants.objectType.sample;

/**
* Capitalize the first letter of the string and returns the modified string.
*
* @param {String} str - String that has to have its first letter capitalized
* @returns {String} str - String with the first letter capitalized
*/
function capitalizeFirstLetter(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
} // capitalizeFirstLetter

/**
* Creates or updates the hash specified by the name argument, with values
* specified by the value argument.
* @param {String} objectName - Name of the object.
* @param {String} name - Name used to identify the hash
* @param {Object} value - The value object's key/value are set as the
* key/value of the hash that is created or updated.
* @returns {Promise} - which resolves to true
*/
function hmSet(objectName, name, value) {
const cleanobj =
redisStore['clean' + capitalizeFirstLetter(objectName)](value);
const nameKey = redisStore.toKey(objectName, name);
return redisClient.hmsetAsync(nameKey, cleanobj)
.then((ok) => Promise.resolve(ok))
.catch((err) => Promise.reject(err));
} // hmSet

/**
* Adds an entry identified by name to the master list of indices identified
* by "type"
* @param {String} type - The type of the master list on which the
* set operations are to be performed
* @param {String} name - Name of the key to be added
* @returns {Promise} - which resolves to the values returned by the redis
* command
*/
function addKey(type, name) {
const indexName = redisStore.constants.indexKey[type];
const nameKey = redisStore.toKey(type, name);
return redisClient.saddAsync(indexName, nameKey)
.then((ok) => Promise.resolve(ok))
.catch((err) => Promise.reject(err));
} // addKey

/**
* Deletes an entry from the master list of indices identified by "type" and
* and the corresponding set identified by "name". Use this to delete a single
* key from the subjectStore, aspectStore or SampleStore.
* @param {String} type - The type of the master list on which the
* set operations are to be performed
* @param {String} name - Name of the key to be added
* @returns {Promise} - which resolves to the values returned by the redis
* batch command
*/
function deleteKey(type, name) {
const indexName = redisStore.constants.indexKey[type];
const key = redisStore.toKey(type, name);
const cmds = [];

// remove the entry from the master index of type
cmds.push(['srem', indexName, key]);

// delete the set
cmds.push(['del', key]);
return redisClient.batch(cmds).execAsync()
.then((ret) => Promise.resolve(ret))
.catch((err) => Promise.reject(err));
} // deleteKey

/**
* Deletes entries from the sampleStore that matches the "subject name" part
* or the "aspect name" part of the entry. The hash identified by the
* deleted entry is also deleted. Use this only to delete multiple keys in the
* sampleStore and its related hashes.
* @param {String} type - The type of the master list on which the
* set operations are to be performed
* @param {String} objectName - The object name (like Subject, Aspect, Sample)
* @param {String} name - Name of the key to be deleted
* @returns {Promise} - which resolves to the values returned by the redis batch
* command
*/
function deleteKeys(type, objectName, name) {
if (type !== sampleType) {
return Promise.reject(false);
}

const nameKey = redisStore.toKey(type, name);
const indexName = redisStore.constants.indexKey[type];
const cmds = [];
return redisClient.smembersAsync(indexName)
.then((keys) => {
const keyArr = [];

/*
* Go through the members in the SampleStore. Split the name parts. If
* the object type is subject and the "subjectNamepart" matches the nameKey
* remove it from the SampleStore. There is also a hash with the same name
* as this, delete that hash too. If the object type is aspect and the
* and aspect name matches the name, remove it from the sampleStore and
* delete the hash.
*/
keys.forEach((key) => {
const nameParts = key.split('|');
const subjectKey = nameParts[0];
const aspect = nameParts[1];
if ((objectName.toLowerCase() === subjectType && nameKey === subjectKey)
|| (objectName.toLowerCase() === aspectType && name === aspect)) {
keyArr.push(key);
}
});

// remove the entry from the master list of index
cmds.push(['srem', indexName, Array.from(keyArr)]);

// delete the set too
cmds.push(['del', Array.from(keyArr)]);
return redisClient.batch(cmds).execAsync();
})
.then((ret) => Promise.resolve(ret))
.catch((err) => Promise.reject(err));
} // deleteKeys

/**
* Renames the entry in subject or aspect master list and the corresponding
* hash identified by the entry. Use this to handle the subject store and aspect
* store entries and its corresponding hashes.
* @param {String} type - The type of the master list on which the
* set operations are to be performed
* @param {String} oldName - The old key name
* @param {String} newName - The new key name
* @returns {Promise} - which resolves to the values returned by the redis batch
* command
*/
function renameKey(type, oldName, newName) {
const newKey = redisStore.toKey(type, newName);
const oldKey = redisStore.toKey(type, oldName);
const indexName = redisStore.constants.indexKey[type];
const cmds = [];

// remove the old key from the master list of index
cmds.push(['srem', indexName, oldKey]);

// add the new key to the master list of index
cmds.push(['sadd', indexName, newKey]);

// rename the set with the new name
cmds.push(['rename', oldKey, newKey]);
return redisClient.batch(cmds).execAsync()
.then((ret) => Promise.resolve(ret))
.catch((err) => Promise.reject(err));
} // renameKey

/**
* Renames the entries in the sample master list and the corresponding hashes
* identified by the entries.
* @param {String} type - The type of the master list on which the
* set operations are to be performed
* @param {String} objectName - The object name (like Subject, Aspect, Sample)
* @param {String} oldName - The old key name
* @param {String} newName - The new key name
* @returns {Promise} - which resolves to the values returned by the redis batch
* command
*/
function renameKeys(type, objectName, oldName, newName) {
if (type !== sampleType) {
return Promise.reject(false);
}

const indexName = redisStore.constants.indexKey[type];
const oldKey = redisStore.toKey(type, oldName);
const newKey = redisStore.toKey(type, newName);
const cmds = [];
return redisClient.smembersAsync(indexName)
.then((keys) => {
const finalNewKeyArr = [];
const finalOldKeyArr = [];

/*
* For each key in the sampleStore, split the key into subjectKey and aspect
* (calling it subjectKey because the subject has redis namespace prefixed
* to it ). If the subjectKey matches the oldKey and the objectName is
* subject, add the key to finalOldKeyArr to be removed later and
* add create a finalNewKey(sample key) using the newKey and the aspect name
* obtained after spliting the key. Add the finalNewKey to
* a finalNewKeyArr to be aded to the sampleStore later. Also, rename the
* set that corresponds to the key to finalNewKey. The same is done when
* the oldName matches the aspect name obtained from splitting the key and
* the objectName is aspect, expect the finaNewKey is created using the
* subjectKey from spiliting the key and the newName.
*/
keys.forEach((key) => {
const nameParts = key.split('|');
const subjectKey = nameParts[0];
const aspect = nameParts[1];
let finalNewKey;
if (oldKey === subjectKey &&
objectName.toLowerCase() === redisStore.constants.objectType.subject) {
finalNewKey = newKey + '|' + aspect;
finalNewKeyArr.push(finalNewKey);
finalOldKeyArr.push(key);
cmds.push(['rename', key, finalNewKey]);
} else if (oldName === aspect &&
objectName.toLowerCase() === redisStore.constants.objectType.aspect) {
finalNewKey = subjectKey + '|' + newName;
finalNewKeyArr.push(finalNewKey);
finalOldKeyArr.push(key);
cmds.push(['rename', key, finalNewKey]);
}
});

// remove the old key from the master list of index
cmds.push(['srem', indexName, Array.from(finalOldKeyArr)]);

// add the new key to the master list of index
cmds.push(['sadd', indexName, Array.from(finalNewKeyArr)]);

return redisClient.batch(cmds).execAsync();
})
.then((ret) => Promise.resolve(ret))
.catch((err) => Promise.reject(err));
} // renameKeys

module.exports = {
renameKey,

renameKeys,

deleteKey,

deleteKeys,

addKey,

hmSet,

subjectType,

aspectType,

sampleType,
}; // export
10 changes: 6 additions & 4 deletions cache/sampleStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,12 @@ function removeNullsAndStringifyArrays(obj, arrayFields) {
/**
* Remove nulls and stringify arrays.
*
* @param {Object} a - The aspect to clean.
* @param {Object} a - The aspect to clean. This can be either be a sequelize
* object instance or just a regular object.
* @returns {Object} cleaned up and ready to store in redis.
*/
function cleanAspect(a) {
let retval = a.get();
let retval = a.get ? a.get() : a;
retval = removeNullsAndStringifyArrays(retval,
constants.fieldsToStringify.aspect);
return retval;
Expand All @@ -111,11 +112,12 @@ function cleanAspect(a) {
/**
* Remove the aspect field, remove nulls and stringify arrays.
*
* @param {Object} s - The sample to clean.
* @param {Object} s - The sample to clean. This can be either be a sequelize
* object instance or just a regular object.
* @returns {Object} cleaned up and ready to store in redis.
*/
function cleanSample(s) {
let retval = s.get();
let retval = s.get ? s.get() : s;
delete retval.aspect;
retval = removeNullsAndStringifyArrays(retval,
constants.fieldsToStringify.sample);
Expand Down
Loading

0 comments on commit 9a3d25f

Please sign in to comment.