Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ Add Redis push and pop operations #3127

Merged
merged 8 commits into from
Jul 10, 2022
229 changes: 205 additions & 24 deletions packages/nodes-base/nodes/Redis/Redis.node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export class Redis implements INodeType {
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
options: [
{
name: 'Delete',
Expand All @@ -48,34 +49,43 @@ export class Redis implements INodeType {
value: 'get',
description: 'Get the value of a key from Redis',
},
{
name: 'Info',
value: 'info',
description: 'Returns generic information about the Redis instance',
},
{
name: 'Increment',
value: 'incr',
description: 'Atomically increments a key by 1. Creates the key if it does not exist.',
},
{
name: 'Info',
value: 'info',
description: 'Returns generic information about the Redis instance',
},
{
name: 'Keys',
value: 'keys',
description: 'Returns all the keys matching a pattern',
},
{
name: 'Set',
value: 'set',
description: 'Set the value of a key in redis',
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',
description: 'Set the value of a key in redis',
},
],
default: 'info',
description: 'The operation to perform.',
},

// ----------------------------------
Expand All @@ -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',
Expand Down Expand Up @@ -148,11 +158,6 @@ export class Redis implements INodeType {
value: 'hash',
description: 'Data in key is of type "hash"',
},
{
name: 'String',
value: 'string',
description: 'Data in key is of type "string"',
},
{
name: 'List',
value: 'list',
Expand All @@ -163,6 +168,11 @@ export class Redis implements INodeType {
value: 'sets',
description: 'Data in key is of type "sets"',
},
{
name: 'String',
value: 'string',
description: 'Data in key is of type "string"',
},
],
default: 'automatic',
description: 'The type of the key to get',
Expand Down Expand Up @@ -223,7 +233,7 @@ export class Redis implements INodeType {
},
},
default: false,
description: 'Set a timeout on key?',
description: 'Whether to set a timeout on key?',
},
{
displayName: 'TTL',
Expand Down Expand Up @@ -264,7 +274,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,
RicardoE105 marked this conversation as resolved.
Show resolved Hide resolved
description: 'Whether to get the value of matching keys',
},
// ----------------------------------
// set
// ----------------------------------
Expand Down Expand Up @@ -319,11 +342,6 @@ export class Redis implements INodeType {
value: 'hash',
description: 'Data in key is of type "hash"',
},
{
name: 'String',
value: 'string',
description: 'Data in key is of type "string"',
},
{
name: 'List',
value: 'list',
Expand All @@ -334,6 +352,11 @@ export class Redis implements INodeType {
value: 'sets',
description: 'Data in key is of type "sets"',
},
{
name: 'String',
value: 'string',
description: 'Data in key is of type "string"',
},
],
default: 'automatic',
description: 'The type of the key to set',
Expand All @@ -351,7 +374,7 @@ export class Redis implements INodeType {
},
},
default: false,
description: 'Set a timeout on key ?',
description: 'Whether to set a timeout on key?',
},

{
Expand Down Expand Up @@ -410,6 +433,116 @@ 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',
hint: 'Value or a string of comma separated values',
},
{
displayName: 'Tail',
name: 'tail',
type: 'boolean',
displayOptions: {
show: {
operation: [
'push',
'pop',
],
},
},
default: false,
description: 'Whether to operate on data at the tail of the list',
},
{
displayName: 'Overwrite',
pemontto marked this conversation as resolved.
Show resolved Hide resolved
name: 'overwrite',
type: 'boolean',
displayOptions: {
show: {
operation: [
'pop',
],
},
},
default: false,
description: 'Whether to overwrite item data with returned data',
},
{
displayName: 'Name',
name: 'propertyName',
type: 'string',
displayOptions: {
show: {
operation: [
'pop',
],
overwrite: [
false,
],
},
},
default: 'data',
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',
],
overwrite: [
false,
],
},
},
placeholder: 'Add Option',
default: {},
options: [
{
displayName: 'Dot Notation',
name: 'dotNotation',
type: 'boolean',
default: true,
description: '<p>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} }.<p></p>If that is not intended this can be deactivated, it will then set { "a.b": value } instead.</p>.',
},
],
},
],
};

Expand Down Expand Up @@ -553,7 +686,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[] = [];

Expand Down Expand Up @@ -586,10 +719,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;
} = {};
Expand Down Expand Up @@ -630,6 +769,48 @@ 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;
pemontto marked this conversation as resolved.
Show resolved Hide resolved
const tail = this.getNodeParameter('tail', itemIndex, false) as boolean;

const action = tail ? client.rpushx : client.lpushx;
const clientPush = util.promisify(action).bind(client);

await clientPush(redisList, messageData);
throw Error;
RicardoE105 marked this conversation as resolved.
Show resolved Hide resolved
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 overwrite = this.getNodeParameter('overwrite', itemIndex, false) as boolean;
const propertyName = this.getNodeParameter('propertyName', itemIndex, 'data') as string;

const action = tail ? client.rpop : client.lpop;
const clientPush = util.promisify(action).bind(client);
const value = await clientPush(redisList);

let valueJSON;
try {
valueJSON = JSON.parse(value);
} catch {
valueJSON = undefined;
}
if (overwrite) {
if (valueJSON) {
item = {json: valueJSON};
} else {
item = {json: {data: value}};
}
} else {
const options = this.getNodeParameter('options', itemIndex, {}) as IDataObject;
if (options.dotNotation === false) {
item.json[propertyName] = valueJSON ? valueJSON : value;
} else {
set(item.json, propertyName, valueJSON ? valueJSON : value);
}
}
returnItems.push(item);
}
}

Expand Down