You've already forked node-redis
mirror of
https://github.com/redis/node-redis.git
synced 2025-08-11 22:42:42 +03:00
feat: accept Map and Set and flatten arguments
This commit is contained in:
142
lib/writeCommands.js
Normal file
142
lib/writeCommands.js
Normal file
@@ -0,0 +1,142 @@
|
||||
'use strict'
|
||||
|
||||
const Commands = require('redis-commands')
|
||||
const utils = require('./utils')
|
||||
const debug = require('./debug')
|
||||
// const isUint8Array = (() => {
|
||||
// try {
|
||||
// return process.binding('util').isUint8Array
|
||||
// } catch (e) {
|
||||
// // Fallback
|
||||
// return (val) => {
|
||||
// return Buffer.isBuffer(val) || ArrayBuffer.isView(val)
|
||||
// }
|
||||
// }
|
||||
// })()
|
||||
const copy = []
|
||||
|
||||
var bufferCount = 0
|
||||
var errors = null
|
||||
|
||||
function writeBuffers (client) {
|
||||
client.fireStrings = false
|
||||
|
||||
while (copy.length) {
|
||||
const arg = copy.shift()
|
||||
// TODO: Consider to convert the strings to buffers
|
||||
// This might actually improve the performance at
|
||||
// least in more modern Node versions
|
||||
if (typeof arg === 'string') {
|
||||
client.write(`$${Buffer.byteLength(arg)}\r\n${arg}\r\n`)
|
||||
} else { // buffer
|
||||
client.write(`$${arg.length}\r\n`)
|
||||
client.write(arg)
|
||||
client.write('\r\n')
|
||||
}
|
||||
debug('sendCommand: buffer send %s bytes', arg.length)
|
||||
}
|
||||
}
|
||||
|
||||
function toString (arg) {
|
||||
if (typeof arg === 'string') {
|
||||
copy.push(arg)
|
||||
} else if (typeof arg === 'number') {
|
||||
copy.push('' + arg)
|
||||
} else if (arg instanceof Array) {
|
||||
for (var i = 0; i < arg.length; i += 1) {
|
||||
toString(arg[i])
|
||||
}
|
||||
} else if (arg && arg.constructor.name === 'Buffer') {
|
||||
copy.push(arg)
|
||||
bufferCount++
|
||||
} else if (typeof arg === 'boolean') { // TODO: Remove this support and use hooks instead
|
||||
copy.push('' + arg)
|
||||
} else if (arg && arg.constructor.name === 'Object') { // Check if this is actually a good check or not
|
||||
// TODO: As soon as we add support for JSON
|
||||
// We could simple stringify this right here.
|
||||
// This might interfere with nested Objects though.
|
||||
// So we should only do this for the first level.
|
||||
const keys = Object.keys(arg)
|
||||
for (var j = 0; j < keys.length; j++) {
|
||||
copy.push(keys[j])
|
||||
toString(arg[keys[j]])
|
||||
}
|
||||
} else if (arg instanceof Map) {
|
||||
arg.forEach((val, key) => {
|
||||
toString(key)
|
||||
toString(val)
|
||||
})
|
||||
} else if (arg instanceof Set) {
|
||||
arg.forEach((val) => toString(val))
|
||||
} else if (arg && arg.constructor.name === 'Date') { // Check if this is actually a good check or not
|
||||
copy.push(arg.toString())
|
||||
} else {
|
||||
if (errors === null) {
|
||||
errors = []
|
||||
}
|
||||
errors.push(arg)
|
||||
}
|
||||
}
|
||||
|
||||
function returnErr (client, command) {
|
||||
const err = new TypeError('NodeRedis can not handle the provided arguments (see "error.issues" property).\n\nFurther information https://github.com/asd')
|
||||
err.command = command.name.toUpperCase()
|
||||
err.args = command.args
|
||||
err.issues = errors
|
||||
errors = null
|
||||
utils.replyInOrder(client, command.callback, err, undefined, client.commandQueue)
|
||||
}
|
||||
|
||||
// Always use 'Multi bulk commands', but if passed any Buffer args, then do multiple writes, one for each arg.
|
||||
// This means that using Buffers in commands is going to be slower, so use Strings if you don't already have a Buffer.
|
||||
|
||||
// TODO: It is faster to move this part somewhere else
|
||||
// We could move this to the function creation as well
|
||||
// if we use hooks for our individual commands!
|
||||
function normalizeAndWrite (client, command) {
|
||||
const args = command.args
|
||||
const origName = command.command
|
||||
const renameCommands = client.renameCommands
|
||||
const name = renameCommands[origName] !== undefined
|
||||
? renameCommands[origName]
|
||||
: origName
|
||||
|
||||
bufferCount = 0
|
||||
for (var i = 0; i < args.length; i++) {
|
||||
toString(args[i])
|
||||
}
|
||||
|
||||
if (errors) {
|
||||
return returnErr(client, command)
|
||||
}
|
||||
|
||||
if (typeof client.options.prefix === 'string') {
|
||||
const prefixKeys = Commands.getKeyIndexes(origName, copy)
|
||||
prefixKeys.forEach((i) => {
|
||||
// Attention it would be to expensive to detect if the input is non utf8 Buffer
|
||||
// In that case the prefix *might* destroys user information
|
||||
copy[i] = client.options.prefix + copy[i]
|
||||
})
|
||||
}
|
||||
|
||||
const bufferArgs = bufferCount !== 0
|
||||
const len = copy.length
|
||||
var commandStr = `*${len + 1}\r\n$${name.length}\r\n${name}\r\n`
|
||||
|
||||
command.bufferArgs = bufferArgs
|
||||
command.argsLength = len
|
||||
|
||||
if (bufferArgs === false) {
|
||||
while (copy.length) {
|
||||
const arg = copy.shift()
|
||||
commandStr += `$${Buffer.byteLength(arg)}\r\n${arg}\r\n`
|
||||
}
|
||||
debug('Send %s id %s: %s', client.address, client.connectionId, commandStr)
|
||||
client.write(commandStr)
|
||||
} else {
|
||||
client.write(commandStr)
|
||||
writeBuffers(client)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = normalizeAndWrite
|
Reference in New Issue
Block a user