-
Notifications
You must be signed in to change notification settings - Fork 18
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
Commands can contain non-string values, but Redis server supports only strings. Consider enforcing this with the type system. #27
Comments
I've been meaning to come up with a way to enforce this in the type system rather than at runtime such that encoding a command is meaningfully different from encoding an In fact, I'm not actually sure if there's ever a reason for the client to encode arbitrary types by the client (everything I've looked at only uses strings), so maybe we remove support for encoding anything but struct Writer
def encode(values : Enumerable(String))
io << '*' << values.size << CRLF
values.each { |part| encode part }
end
# :nodoc:
def encode(string : String)
io << '$' << string.bytesize << CRLF
io << string << CRLF
end
end I'm a little uncertain of that idea, but in all the things I've been doing I haven't seen anything not use arrays of strings coming from the client. Maybe I should try monkey patching one of my apps to emit metrics if the other |
Hi, It is perfectly legal to store binary data in Redis. It is one of the considerations in the protocol that this shard already uses: The following change will allow you to store --- a/src/commands.cr
+++ b/src/commands.cr
@@ -54,7 +54,7 @@ module Redis
# sleep 1.second
# redis.get("foo") # => nil
# ```
- def set(key : String, value : String, ex : (String | Int)? = nil, px : String | Int | Nil = nil, nx = false, xx = false, keepttl = false)
+ def set(key : String, value : String | Bytes, ex : (String | Int)? = nil, px : String | Int | Nil = nil, nx = false, xx = false, keepttl = false)
command = {"set", key, value}
command += {"ex", ex.to_s} if ex
command += {"px", px.to_s} if px
--- a/src/writer.cr
+++ b/src/writer.cr
@@ -21,6 +21,13 @@ module Redis
io << string << CRLF
end
+ # :nodoc:
+ def encode(bytes : Bytes)
+ io << '$' << bytes.size << CRLF
+ io.write(bytes)
+ io << CRLF
+ end Reading will of course still yield a crystal String, which will likely be (silently) invalid utf8. You can use Or, a "hacky" approach is something like: --- a/src/connection.cr
+++ b/src/connection.cr
@@ -244,7 +244,7 @@ module Redis
append: Int64,
decr: Int64,
decrby: Int64,
- get: String?,
+ get: String | Bytes?,
--- a/src/parser.cr
+++ b/src/parser.cr
@@ -45,7 +45,11 @@ module Redis
if length >= 0
value = @io.read_string length
@io.skip 2 # Skip CRLF
- value
+ if value.valid_encoding?
+ value
+ else
+ value.to_slice
+ end Of course, it would be even better if you could tell the shard you want binary data back, and you can skip the extra processing of |
Indeed, and what I said above about strings being the only data type allowed in commands was misleading, I guess. That's technically Redis strings (this shard only ever emits RESP bulk strings, never simple strings) rather than Crystal's I actually store binary data in Redis with this shard pretty regularly ( I'd love to add first-class support for
I don't know what makes the most sense here. I don't think I want to use the
Letting the caller tell us whether they want the data as a |
I didn't realize you can use msgpack with redis 🤯 I like those names though |
I posted PR #42 to discuss how to get binary data in and out of Redis without using improperly encoded
Yep! I love it. 😄 |
While adding #26 I get this error from running the specs
The text was updated successfully, but these errors were encountered: