fix: Refactored connection-redis plugin to have non restrictive schemas.

This commit is contained in:
João Correia 2022-01-13 09:46:37 +00:00
parent ee2315d69c
commit f8d9f8e149
5 changed files with 71 additions and 172 deletions

View File

@ -23,47 +23,33 @@ test('All requests are present', () => {
expect(Redis.requests.Redis).toBeDefined();
});
test('valid connection schema, with url', () => {
test('valid connection schema, with string', () => {
const connection = {
url: '/path',
connection: '/path',
};
expect(validate({ schema, data: connection })).toEqual({ valid: true });
});
test('valid connection schema, with socket', () => {
test('valid connection schema, with object', () => {
const connection = {
socket: {
host: 'https://example.com/redis',
port: 6379,
connection: {
socket: {
host: 'https://example.com/redis',
port: 6379,
},
username: 'username',
password: 'password',
database: 5,
},
username: 'username',
password: 'password',
database: 5,
};
expect(validate({ schema, data: connection })).toEqual({ valid: true });
});
test('invalid connection schema, with all properties', () => {
test('invalid connection schema', () => {
const connection = {
url: '/path',
socket: {
host: 'https://example.com/redis',
port: 6379,
},
username: 'username',
password: 'password',
database: 0,
connection: null,
};
expect(() => validate({ schema, data: connection })).toThrow(
'Redis connection should have required property "url" or "socket.host" and "socket.port".'
);
});
test('url is not a string', () => {
const connection = {
url: true,
};
expect(() => validate({ schema, data: connection })).toThrow(
'Redis property "url" should be a string.'
'Redis connection property "connection" should be a string or object.'
);
});

View File

@ -19,23 +19,49 @@ import { createClient } from 'redis';
import schema from './schema.js';
async function Redis({ request, connection }) {
const client = new createClient(connection);
const connectionObject = type.isString(connection.connection)
? { url: connection.connection }
: connection.connection;
const client = new createClient(connectionObject);
client.on('error', (error) => {
throw error;
});
const { command, parameters, modifiers } = request;
try {
const { command, params, modifiers } = request;
await client.connect();
const commandParams = type.isArray(params) ? params : [params];
const commandReturn = await client[command.toUpperCase()](...commandParams, modifiers);
} catch (error) {
throw new Error(`Connection refused.`);
}
if (!type.isFunction(client[command.toUpperCase()])) {
throw new Error(`Invalid redis command "${command}".`);
}
if (!type.isArray(parameters)) {
throw new Error(
`Invalid command, command "${command}" parameters should be an array, received ${JSON.stringify(
parameters
)}.`
);
}
const upperCaseModifiers = Object.entries(modifiers).reduce((acc, [key, value]) => {
acc[key.toUpperCase()] = value;
return acc;
}, {});
try {
const commandReturn = await client[command.toUpperCase()](...parameters, upperCaseModifiers);
await client.quit();
return commandReturn;
} catch (error) {
if (error.code !== 'ECONNREFUSED') {
await client.quit();
}
throw error;
client.quit();
throw new Error(
`Invalid command "${command}" parameters, received ${JSON.stringify(parameters)}.`
);
}
}

View File

@ -21,59 +21,30 @@ const { checkRead, checkWrite } = Redis.meta;
const schema = Redis.schema;
test('valid request schema, with url', () => {
const connection = {
const request = {
command: 'set',
params: ['key', 10],
parameters: ['key', 10],
};
expect(validate({ schema, data: connection })).toEqual({ valid: true });
expect(validate({ schema, data: request })).toEqual({ valid: true });
});
test('command is not a string', () => {
const connection = {
const request = {
command: true,
params: ['key', 'value'],
parameters: ['key', 'value'],
};
expect(() => validate({ schema, data: connection })).toThrow(
expect(() => validate({ schema, data: request })).toThrow(
'Redis request property "command" should be a string.'
);
});
test('command is not valid', () => {
const connection = {
command: 'notValidCommand',
params: ['key', 'value'],
};
expect(() => validate({ schema, data: connection })).toThrow(
'Redis request property "command" is not a valid value.'
);
});
test('params are not valid for command', () => {
const connection = {
command: 'get',
params: ['key', 'value'],
};
expect(() => validate({ schema, data: connection })).toThrow(
'Redis request property "params" should be a string.'
);
});
test('params are not valid for command', () => {
const connection = {
test('parameters is not an array', () => {
const request = {
command: 'set',
params: 'key',
parameters: 'string',
};
expect(() => validate({ schema, data: connection })).toThrow(
'Redis request property "params" should be an array.'
);
});
test('params are not present', () => {
const connection = {
command: 'set',
};
expect(() => validate({ schema, data: connection })).toThrow(
'Redis request property "params" should be present.'
expect(() => validate({ schema, data: request })).toThrow(
'Redis request property "parameters" should be an array.'
);
});

View File

@ -21,11 +21,16 @@ export default {
properties: {
command: {
type: 'string',
enum: ['get', 'set', 'hget', 'hset'],
description: 'Redis command to execute.',
errorMessage: {
type: 'Redis request property "command" should be a string.',
enum: 'Redis request property "command" is not a valid value.',
},
},
parameters: {
type: 'array',
description: 'The parameters to use with the command.',
errorMessage: {
type: 'Redis request property "parameters" should be an array.',
},
},
modifiers: {
@ -38,37 +43,6 @@ export default {
},
},
required: ['command'],
if: {
properties: { command: { enum: ['get'] } },
},
then: {
properties: {
params: {
type: 'string',
errorMessage: {
type: 'Redis request property "params" should be a string.',
},
},
},
required: ['params'],
errorMessage: {
required: 'Redis request property "params" should be present.',
},
},
else: {
properties: {
params: {
type: 'array',
errorMessage: {
type: 'Redis request property "params" should be an array.',
},
},
},
required: ['params'],
errorMessage: {
required: 'Redis request property "params" should be present.',
},
},
errorMessage: {
type: 'Redis request properties should be an object.',
},

View File

@ -19,74 +19,16 @@ export default {
title: 'Lowdefy Connection Schema - Redis',
type: 'object',
properties: {
url: {
type: 'string',
description:
'The redis server url to connect to (redis[s]://[[username][:password]@][host][:port][/db-number])',
connection: {
type: ['string', 'object'],
description: 'Connection object or string to pass to the redis client.',
errorMessage: {
type: 'Redis property "url" should be a string.',
},
},
socket: {
type: 'object',
description: 'Object defining socket connection properties.',
properties: {
host: {
type: 'string',
description: 'Hostname to connect to',
default: 'localhost',
errorMessage: {
type: 'Redis property "socket.host" should be a string.',
},
},
port: {
type: 'number',
description: 'Port to connect to',
default: 6379,
errorMessage: {
type: 'Redis property "socket.port" should be a number.',
},
},
},
required: ['host', 'port'],
errorMessage: {
type: 'Redis property "socket" should be an object.',
},
},
username: {
type: 'string',
description: 'ACL username',
errorMessage: {
type: 'Redis property "username" should be a string.',
},
},
password: {
type: 'string',
description: 'ACL password',
errorMessage: {
type: 'Redis property "password" should be a string.',
},
},
database: {
type: 'number',
description: 'Database number to connect to',
minimum: 0,
errorMessage: {
type: 'Redis property "database" should be a number.',
type: 'Redis connection property "connection" should be a string or object.',
},
},
},
oneOf: [
{
required: ['url'],
},
{
required: ['socket'],
},
],
require: ['connection'],
errorMessage: {
type: 'Redis connection properties should be an object.',
oneOf:
'Redis connection should have required property "url" or "socket.host" and "socket.port".',
},
};