From 32c68eb126f8411d1a3261dc8a900c109b99da6f Mon Sep 17 00:00:00 2001 From: pemontto <939704+pemontto@users.noreply.github.com> Date: Sun, 10 Jul 2022 07:12:18 +0100 Subject: [PATCH] feat(Redis Node): Add push and pop operations (#3127) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ✨ Add push and pop operations * :zap: linter fixes * :zap: linter fixes * 🐛 Fix errors and remove overwrite * 🐛 Remove errant hint * :zap: Small change Co-authored-by: Michael Kret Co-authored-by: ricardo --- packages/nodes-base/nodes/Redis/Redis.node.ts | 156 +++++++++++++++++- 1 file changed, 153 insertions(+), 3 deletions(-) diff --git a/packages/nodes-base/nodes/Redis/Redis.node.ts b/packages/nodes-base/nodes/Redis/Redis.node.ts index 2d08f7e77a..5c3f474cf3 100644 --- a/packages/nodes-base/nodes/Redis/Redis.node.ts +++ b/packages/nodes-base/nodes/Redis/Redis.node.ts @@ -64,11 +64,21 @@ export class Redis implements INodeType { value: 'keys', description: 'Returns all the keys matching a pattern', }, + { + name: 'Pop', + value: 'pop', + description: 'Pop data from a redis list', + }, { name: 'Publish', value: 'publish', description: 'Publish message to redis channel', }, + { + name: 'Push', + value: 'push', + description: 'Push data to a redis list', + }, { name: 'Set', value: 'set', @@ -94,7 +104,7 @@ export class Redis implements INodeType { }, default: 'propertyName', required: true, - description: 'Name of the property to write received data to. Supports dot-notation. Example: "data.person[0].name"', + description: 'Name of the property to write received data to. Supports dot-notation. Example: "data.person[0].name".', }, { displayName: 'Key', @@ -265,7 +275,20 @@ export class Redis implements INodeType { required: true, description: 'The key pattern for the keys to return', }, - + { + displayName: 'Get Values', + name: 'getValues', + type: 'boolean', + displayOptions: { + show: { + operation: [ + 'keys', + ], + }, + }, + default: true, + description: 'Whether to get the value of matching keys', + }, // ---------------------------------- // set // ---------------------------------- @@ -411,6 +434,96 @@ export class Redis implements INodeType { required: true, description: 'Data to publish', }, + // ---------------------------------- + // push/pop + // ---------------------------------- + { + displayName: 'List', + name: 'list', + type: 'string', + displayOptions: { + show: { + operation: [ + 'push', + 'pop', + ], + }, + }, + default: '', + required: true, + description: 'Name of the list in Redis', + }, + { + displayName: 'Data', + name: 'messageData', + type: 'string', + displayOptions: { + show: { + operation: [ + 'push', + ], + }, + }, + typeOptions: { + alwaysOpenEditWindow: true, + }, + default: '', + required: true, + description: 'Data to push', + }, + { + displayName: 'Tail', + name: 'tail', + type: 'boolean', + displayOptions: { + show: { + operation: [ + 'push', + 'pop', + ], + }, + }, + default: false, + description: 'Whether to push or pop data from the end of the list', + }, + { + displayName: 'Name', + name: 'propertyName', + type: 'string', + displayOptions: { + show: { + operation: [ + 'pop', + ], + }, + }, + default: 'propertyName', + description: 'Optional name of the property to write received data to. Supports dot-notation. Example: "data.person[0].name".', + }, + { + displayName: 'Options', + name: 'options', + type: 'collection', + displayOptions: { + show: { + operation: [ + 'pop', + ], + }, + }, + placeholder: 'Add Option', + default: {}, + options: [ + { + displayName: 'Dot Notation', + name: 'dotNotation', + type: 'boolean', + default: true, + // eslint-disable-next-line n8n-nodes-base/node-param-description-boolean-without-whether + description: '

By default, dot-notation is used in property names. This means that "a.b" will set the property "b" underneath "a" so { "a": { "b": value} }.

If that is not intended this can be deactivated, it will then set { "a.b": value } instead.

.', + }, + ], + }, ], }; @@ -554,7 +667,7 @@ export class Redis implements INodeType { resolve(this.prepareOutputData([{ json: convertInfoToObject(result as unknown as string) }])); client.quit(); - } else if (['delete', 'get', 'keys', 'set', 'incr', 'publish'].includes(operation)) { + } else if (['delete', 'get', 'keys', 'set', 'incr', 'publish', 'push', 'pop'].includes(operation)) { const items = this.getInputData(); const returnItems: INodeExecutionData[] = []; @@ -587,10 +700,16 @@ export class Redis implements INodeType { returnItems.push(item); } else if (operation === 'keys') { const keyPattern = this.getNodeParameter('keyPattern', itemIndex) as string; + const getValues = this.getNodeParameter('getValues', itemIndex, true) as boolean; const clientKeys = util.promisify(client.keys).bind(client); const keys = await clientKeys(keyPattern); + if (!getValues) { + returnItems.push({json: {'keys': keys}}); + continue; + } + const promises: { [key: string]: GenericValue; } = {}; @@ -631,6 +750,37 @@ export class Redis implements INodeType { const clientPublish = util.promisify(client.publish).bind(client); await clientPublish(channel, messageData); returnItems.push(items[itemIndex]); + } else if (operation === 'push'){ + const redisList = this.getNodeParameter('list', itemIndex) as string; + const messageData = this.getNodeParameter('messageData', itemIndex) as string; + const tail = this.getNodeParameter('tail', itemIndex, false) as boolean; + const action = tail ? client.RPUSH : client.LPUSH; + const clientPush = util.promisify(action).bind(client); + // @ts-ignore: typescript not understanding generic function signatures + await clientPush(redisList, messageData); + returnItems.push(items[itemIndex]); + } else if (operation === 'pop'){ + const redisList = this.getNodeParameter('list', itemIndex) as string; + const tail = this.getNodeParameter('tail', itemIndex, false) as boolean; + const propertyName = this.getNodeParameter('propertyName', itemIndex, 'propertyName') as string; + + const action = tail ? client.rpop : client.lpop; + const clientPop = util.promisify(action).bind(client); + const value = await clientPop(redisList); + + let outputValue; + try { + outputValue = JSON.parse(value); + } catch { + outputValue = value; + } + const options = this.getNodeParameter('options', itemIndex, {}) as IDataObject; + if (options.dotNotation === false) { + item.json[propertyName] = outputValue; + } else { + set(item.json, propertyName, outputValue); + } + returnItems.push(item); } }