forked from teslamotors/informed
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
added lodash implimentation of object map
- Loading branch information
Showing
7 changed files
with
308 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import ldset from 'lodash/setWith'; | ||
import ldunset from 'lodash/unset'; | ||
import ldtoPath from 'lodash/toPath'; | ||
import ldget from 'lodash/get'; | ||
import ldvalues from 'lodash/values'; | ||
|
||
class ObjectMap { | ||
constructor(object = {}, opts ={}) { | ||
this.name = opts.name; | ||
this.object = JSON.parse(JSON.stringify(object)); | ||
} | ||
|
||
empty() { | ||
return ldvalues(this.object).length === 0; | ||
} | ||
|
||
rebuild(object = {}) { | ||
this.object = JSON.parse(JSON.stringify(object)); | ||
} | ||
|
||
get(path) { | ||
return ldget(this.object, path); | ||
} | ||
|
||
set(path, value) { | ||
//console.log(`${this.name} obj: ${JSON.stringify(this.object)}`); | ||
//console.log(`${this.name} setting ${path} to ${value}`); | ||
if( value == null ){ | ||
this.delete(path); | ||
} else { | ||
ldset(this.object, path, value); | ||
} | ||
//console.log(`${this.name} obj: ${JSON.stringify(this.object)}`); | ||
} | ||
|
||
delete(path) { | ||
ldunset(this.object, path); | ||
let pathArray = ldtoPath(path); | ||
pathArray = pathArray.slice(0, pathArray.length - 1); | ||
cleanup(this.object, pathArray); | ||
} | ||
} | ||
|
||
function cleanup( obj, path ) { | ||
// Base case no path left | ||
if( path.length === 0 ){ | ||
return; | ||
} | ||
// Delete object if its empty | ||
const object = ldget(obj, path); | ||
if( Array.isArray(object) ? object.every(e=> e == null) : JSON.stringify( object ) === '{}' ){ | ||
ldunset(obj, path); | ||
} | ||
// Recur | ||
cleanup( obj, path.slice(0, path.length - 1) ); | ||
} | ||
|
||
export default ObjectMap; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,237 @@ | ||
import ObjectMap from '../src/ObjectMap/LodashMap'; | ||
import { expect } from 'chai'; | ||
|
||
describe('LodashMap', () => { | ||
describe('constructor', () => { | ||
it('create a map and an object', () => { | ||
const expectedObj = { foo: 'bar' }; | ||
const objectMap = new ObjectMap({ foo: 'bar' }); | ||
const actualObj = objectMap.object; | ||
expect(actualObj).to.deep.equal(expectedObj); | ||
}); | ||
|
||
it('create a nested map and an object', () => { | ||
const expectedObj = { foo: { bar: { baz: 3 } } }; | ||
const objectMap = new ObjectMap({ foo: { bar: { baz: 3 } } }); | ||
const actualObj = objectMap.object; | ||
expect(actualObj).to.deep.equal(expectedObj); | ||
}); | ||
}); | ||
|
||
describe('get', () => { | ||
it('should get value from very nested object', () => { | ||
const expected = 2; | ||
const object = { | ||
foo: { | ||
bar: { | ||
baz: [ | ||
{ | ||
taz: { | ||
bar: [ | ||
null, | ||
null, | ||
null, | ||
null, | ||
null, | ||
null, | ||
null, | ||
null, | ||
null, | ||
null, | ||
[ | ||
null, | ||
null, | ||
null, | ||
{ | ||
bar: { | ||
'0': { | ||
'5': 2 | ||
} | ||
} | ||
} | ||
] | ||
] | ||
} | ||
}, | ||
{} | ||
] | ||
} | ||
} | ||
}; | ||
const objectMap = new ObjectMap(object); | ||
const actual = objectMap.get( | ||
'foo[\'bar\'].baz[0].taz.bar[10][3].bar[\'0\'].5' | ||
); | ||
expect(actual).to.equal(expected); | ||
}); | ||
|
||
it('should return undefined when get is called with field that does not exist', () => { | ||
const map = undefined; | ||
const expected = undefined; | ||
const objectMap = new ObjectMap(); | ||
const actual = objectMap.get('foo.bar'); | ||
expect(actual).to.equal(expected); | ||
}); | ||
}); | ||
|
||
describe('set', () => { | ||
it('should set a value', () => { | ||
const expected = 3; | ||
const objectMap = new ObjectMap(); | ||
objectMap.set('foo', 3); | ||
const actual = objectMap.get('foo'); | ||
expect(actual).to.equal(expected); | ||
}); | ||
|
||
describe('object', () => { | ||
it('should set a nested value and initialize objects along the way', () => { | ||
const expected = { foo: { bar: { baz: 3 } } }; | ||
const objectMap = new ObjectMap(); | ||
objectMap.set('foo.bar.baz', 3); | ||
const actual = objectMap.object; | ||
expect(actual).to.deep.equal(expected); | ||
}); | ||
|
||
it('should set a nested value and initialize arrays along the way', () => { | ||
const expected = { foo: [, [, 3]] }; | ||
const objectMap = new ObjectMap(); | ||
objectMap.set('foo[1][1]', 3); | ||
const actual = objectMap.object; | ||
expect(actual).to.deep.equal(expected); | ||
}); | ||
|
||
it('should set a nested value and initialize objects along the way with array object syntax', () => { | ||
const expected = { foo: { bar: { baz: 3 } } }; | ||
const objectMap = new ObjectMap(); | ||
objectMap.set('foo[\'bar\'].baz', 3); | ||
const actual = objectMap.object; | ||
expect(actual).to.deep.equal(expected); | ||
}); | ||
|
||
it('should set a nested value and initialize arrays and objects along the way', () => { | ||
const expected = { foo: [, { bar: [, 3] }] }; | ||
const objectMap = new ObjectMap(); | ||
objectMap.set('foo[1].bar[1]', 3); | ||
const actual = objectMap.object; | ||
expect(actual).to.deep.equal(expected); | ||
}); | ||
|
||
it('should remove objects when they are empty after setting null', () => { | ||
const expected = {}; | ||
const objectMap = new ObjectMap({ foo: { bar: { baz: 3 } } }); | ||
objectMap.set('foo.bar.baz', null); | ||
const actual = objectMap.object; | ||
expect(actual).to.deep.equal(expected); | ||
}); | ||
|
||
it('should NOT remove objects when they are NOT empty after setting null', () => { | ||
const expected = { foo: { bar: { boo: 4 } } }; | ||
const objectMap = new ObjectMap({ foo: { bar: { baz: 3, boo: 4 } } }); | ||
objectMap.set('foo.bar.baz', null); | ||
const actual = objectMap.object; | ||
expect(actual).to.deep.equal(expected); | ||
}); | ||
|
||
it('should remove array when they are empty after setting null', () => { | ||
const expected = {}; | ||
const objectMap = new ObjectMap({ foo: [, [, 3]] }); | ||
objectMap.set('foo[1][1]', null); | ||
const actual = objectMap.object; | ||
expect(actual).to.deep.equal(expected); | ||
}); | ||
|
||
it('should NOT remove array when they are NOT empty after setting null', () => { | ||
const expected = { foo: [null, [null, , 4]] }; | ||
const objectMap = new ObjectMap({ foo: [, [, 3, 4]] }); | ||
objectMap.set('foo[1][1]', null); | ||
const actual = objectMap.object; | ||
expect(actual).to.deep.equal(expected); | ||
}); | ||
|
||
it('should remove arrays and objects when they are empty after setting null', () => { | ||
const expected = {}; | ||
const objectMap = new ObjectMap({ foo: [, { bar: [, 3] }] }); | ||
objectMap.set('foo[1].bar[1]', null); | ||
const actual = objectMap.object; | ||
expect(actual).to.deep.equal(expected); | ||
}); | ||
|
||
it('should NOT remove arrays and objects when they are NOT empty after setting null', () => { | ||
const expected = { foo: [null, { bar: [null, , 4] }] }; | ||
const objectMap = new ObjectMap({ foo: [, { bar: [, 3, 4] }] }); | ||
objectMap.set('foo[1].bar[1]', null); | ||
const actual = objectMap.object; | ||
expect(actual).to.deep.equal(expected); | ||
}); | ||
}); | ||
|
||
describe('delete', () => { | ||
it('should delete value', () => { | ||
const objectMap = new ObjectMap({ foo: { bar: { baz: 3 } } }); | ||
objectMap.delete('foo.bar.baz'); | ||
expect(objectMap.object).to.deep.equal({}); | ||
}); | ||
|
||
it('should delete value from array', () => { | ||
const objectMap = new ObjectMap({ foo: { bar: { baz: [1, 2, 3] } } }); | ||
objectMap.delete('foo.bar.baz[1]'); | ||
expect(objectMap.object).to.deep.equal({ | ||
foo: { bar: { baz: [1,,3] } } | ||
}); | ||
}); | ||
|
||
it('should remove array and objects when all values are deleted', () => { | ||
const objectMap = new ObjectMap({ foo: { bar: { baz: [1, 2, 3] } } }); | ||
objectMap.delete('foo.bar.baz[0]'); | ||
objectMap.delete('foo.bar.baz[1]'); | ||
objectMap.delete('foo.bar.baz[2]'); | ||
expect(objectMap.object).to.deep.equal({}); | ||
}); | ||
}); | ||
|
||
it('should set value in very nested obejct', () => { | ||
const expected = 3; | ||
const object = { | ||
foo: { | ||
bar: { | ||
baz: [ | ||
{ | ||
taz: { | ||
bar: [ | ||
null, | ||
null, | ||
null, | ||
null, | ||
null, | ||
null, | ||
null, | ||
null, | ||
null, | ||
null, | ||
[ | ||
null, | ||
null, | ||
null, | ||
{ | ||
bar: { | ||
'0': { | ||
'5': 2 | ||
} | ||
} | ||
} | ||
] | ||
] | ||
} | ||
}, | ||
{} | ||
] | ||
} | ||
} | ||
}; | ||
const objectMap = new ObjectMap(object); | ||
objectMap.set('foo.bar.baz[0].taz.bar[10][3].bar.0.5', 3); | ||
const actual = objectMap.get('foo.bar.baz[0].taz.bar[10][3].bar.0.5'); | ||
expect(actual).to.equal(expected); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters