Skip to content

Instantly share code, notes, and snippets.

@ifyoumakeit
Last active January 4, 2018 17:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ifyoumakeit/20e47b4bb413ffd610546b25125fe5ae to your computer and use it in GitHub Desktop.
Save ifyoumakeit/20e47b4bb413ffd610546b25125fe5ae to your computer and use it in GitHub Desktop.
Sortable Data Access Structure
/**
* Sort or set keys
* @param data {object} Keyed data store
* @param keysOrSort {array|function}
* @return {array}
*/
const sortKeys = (data, keysOrSort) => {
return typeof keysOrSort === "undefined"
? Object.keys(data).sort()
: typeof keysOrSort === "function"
? Object.keys(data).sort((keyA, keyB) => {
return keysOrSort(
{ key: keyA, data: data[keyA] },
{ key: keyB, data: data[keyB] }
);
})
: typeof keysOrSort === "object" ? keysOrSort : [keysOrSort];
};
/**
* Remove data that isn't in keys.
* @param data {object} Keyed data store
* @param keys {array} Sorted data keys
*/
const cleanData = (data, keys) => {
return keys.reduce(
(memo, key) => (data[key] ? { ...memo, [key]: data[key] } : memo),
{}
);
};
/**
* Sortable data access object.
* Array/Object methods are remapped to support both.
* @param {object} Keyed data store
* @param {array|function} keysOrSort Sorted array of object keys or sorting function.
* @return {Struct}
* @example const struct1 = Struct({foo: {active: false}, bar: {active: true}}, ["foo", "bar"])
* @example const struct2 = Struct({foo: {active: false}, bar: {active: true}}, (a,b) => a > b ? -1 : 1)
*/
const Struct = function(data = {}, keysOrSort) {
let _keys = sortKeys(data, keysOrSort);
let _data = cleanData(data, _keys);
const values = () => {
return _keys.map(val => _data[val]);
};
const keys = () => {
return _keys;
};
const key = index => {
return _keys[index];
};
const get = keyOrIndex => {
return typeof keyOrIndex === "number"
? data[_keys[keyOrIndex]] || {}
: _data[keyOrIndex] || {};
};
const set = (key, value) => {
return Struct({ ..._data, [key]: _keys.concat(key) });
};
const has = key => {
return typeof _data[key] !== "undefined";
};
const sort = callback => {
return _keys.sort(callback).map(key => _data[key]);
};
const forEach = callback => {
return _keys.forEach((key, index) => {
return callback(_data[key], index, _data);
});
};
const map = callback => {
const data = {};
_keys.forEach((key, index) => {
data[key] = callback(_data[key], index, _data);
});
return Struct(data, _keys);
};
const filter = callback => {
const data = {};
let keys = [];
_keys.forEach((key, index) => {
if (callback(_data[key], index, _data)) {
data[key] = _data[key];
keys = keys.concat(key);
}
});
return Struct(data, keys);
};
const reduce = (callback, initialValue) => {
return _keys.reduce((memo, key, index) => {
return callback(memo, _data[key], index, _data);
}, initialValue);
};
return {
has,
key,
keys,
values,
get,
set,
sort,
forEach,
map,
filter,
reduce
};
};
const cryptids = Struct(
{
kevin: {
name: "Kevin Pruett",
pets: 1
},
dave: {
name: "Dave Garwacke",
pets: 2
},
andy: {
name: "Andy Fritz",
pets: 0
},
molly: {
name: "Molly McGrath",
pets: 0.5
}
},
({ data: a }, { data: b }) => (a.name > b.name ? 1 : -1)
);
console.log({
hasTodd: cryptids.has("todd"),
sortedKeys: cryptids.keys(),
thirdKey: cryptids.key(2),
withCounts: cryptids.map(c => ({ ...c, count: c.pets + 1 })).values(),
cryptids: cryptids.set("tatonka", { name: "Tatonka", pets: 0 }).values(),
petOwners: cryptids.filter(c => c.pets >= 1).values()
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment