diff --git a/src/commands/index.js b/src/commands/index.js index 998cf008b..cdf4d025c 100644 --- a/src/commands/index.js +++ b/src/commands/index.js @@ -52,6 +52,7 @@ export * from './llen'; export * from './lpop'; export * from './lpopBuffer'; export * from './lpush'; +export * from './linsert'; export * from './lpushx'; export * from './lrange'; export * from './lrem'; diff --git a/src/commands/linsert.js b/src/commands/linsert.js new file mode 100644 index 000000000..f53361732 --- /dev/null +++ b/src/commands/linsert.js @@ -0,0 +1,25 @@ +export function linsert(key, position, pivot, element) { + if (this.data.has(key) && !(this.data.get(key) instanceof Array)) { + throw new Error(`Key ${key} does not contain a list`); + } + const list = this.data.get(key) || []; + const pivotIndex = list.indexOf(pivot); + if (pivotIndex < 0) return -1; + let elementIndex = pivotIndex; + switch (position) { + case `BEFORE`: + elementIndex = pivotIndex; + break; + case `AFTER`: + elementIndex = pivotIndex + 1; + break; + default: + throw new Error( + `The position of the new element must be BEFORE the pivot or AFTER the pivot` + ); + } + list.splice(elementIndex, 0, element); + const {length} = list; + this.data.set(key, list); + return length; +} diff --git a/test/commands/linsert.js b/test/commands/linsert.js new file mode 100644 index 000000000..df371b9df --- /dev/null +++ b/test/commands/linsert.js @@ -0,0 +1,62 @@ +import MockRedis from '../../src'; + +describe('linsert', () => { + it('should add the value to the list at the correct position', () => { + const redis = new MockRedis({ + data: { + foo: ['1'], + }, + }); + + return redis + .linsert('foo', `BEFORE`, 1, 0) + .then(() => expect(redis.data.get('foo')).toEqual(['0', '1'])) + .then(() => redis.linsert('foo', `AFTER`, 1, 2)) + .then(() => expect(redis.data.get('foo')).toEqual(['0', '1', '2'])); + }); + + it('should return the new length of the list', () => { + let redis = new MockRedis({ + data: {}, + }); + + return redis + .linsert('foo', `BEFORE`, 1, 0) + .then((length) => expect(length).toBe(-1)) + .then(() => { + redis = new MockRedis({ + data: { foo: ['1'] }, + }); + }) + .then(() => redis.linsert('foo', `BEFORE`, 1, 0)) + .then((length) => expect(length).toBe(2)); + }); + + it('should throw an exception if the key contains something other than a list', () => { + const redis = new MockRedis({ + data: { + foo: 'not a list', + }, + }); + + return redis + .linsert('foo', `BEFORE`, 1, 0) + .catch((err) => + expect(err.message).toBe('Key foo does not contain a list') + ); + }); + + it('should throw an exception if the position is not allowed', () => { + const redis = new MockRedis({ + data: {}, + }); + + return redis + .linsert(`foo`, `POSITION_UNKNOWN`, 1, 0) + .catch((err) => + expect(err.message).toBe( + `The position of the new element must be BEFORE the pivot or AFTER the pivot` + ) + ); + }); +});