-
Notifications
You must be signed in to change notification settings - Fork 64
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
Implement strings API in test executor #511
Conversation
Looks really great! Would be good to have some tests for the new operations to make sure they are working as specified. |
@mvelimir Please resolve the conflicts. |
bdf7aa0
to
7a47331
Compare
@mvelimir Is this still work in progress? If not, please convert it to a pull request :) |
There's still the BITFIELD command left to be implemented, but I could make a separate PR for that. |
@mvelimir I agree, let's have it in a separate PR. Please rebase this one, and I'll review it immediately. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First pass done.
Try(start.getOrElse("0").toInt).toOption.fold[RespValue](Replies.Error) { start => | ||
Try(end.getOrElse(string.length.toString).toInt).toOption.fold[RespValue](Replies.Error) { end => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's unnest this a bit, e.g.
val resp =
for {
bit <- Option.when(bit == "0" || bit == "1") // you'll need a helper since this is 2.13 function
start <- start.map(start => Try(start.toInt).toOption).orElse(Some(0))
end <- end.map(end => Try(end.toInt).toOption).orElse(Some(string.length))
// the rest of calculation
} yield value
resp.getOrElse(Replies.Error)
Consider creating a helper for int conversion if there isn't one already. Once you have it, replace the other parsing occurrences.
|
||
val index = string.zipWithIndex | ||
.slice(newStart, newEnd) | ||
.map(tuple => f"${tuple._1.asInstanceOf[Int].toBinaryString}%8s".replace(' ', '0') -> tuple._2) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's get rid of asInstanceOf
.
Try(stringOption.getOrElse("0").toLong).toOption.fold(STM.succeed(Replies.Error: RespValue)) { num => | ||
if (decr >= 0 && num >= Long.MinValue + decr || decr < 0 && num <= Long.MaxValue + decr) { | ||
val result = num - decr | ||
|
||
putString(key, result.toString).as(RespValue.Integer(result)) | ||
} else STM.succeed(Replies.Error) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Simplify as suggested above.
Try(stringOption.getOrElse("0").toLong).toOption.fold(STM.succeed(Replies.Error: RespValue)) { num => | ||
if (num > Long.MinValue) { | ||
val result = num - 1 | ||
|
||
putString(key, result.toString).as(RespValue.Integer(result)) | ||
} else STM.succeed(Replies.Error) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Simplify as suggested above.
strings.getOrElse(key, "").map { string => | ||
Try(offset.toInt).toOption.filter(_ >= 0).fold[RespValue](Replies.Error) { offset => | ||
RespValue | ||
.Integer(string.getBytes.lift(offset / 8).fold(0L)(byte => (byte >> (7 - offset % 8) & 1).toLong)) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto.
strings.getOrElse(key, "").map { string => | ||
Try(start.toInt).toOption | ||
.flatMap(a => Try(end.toInt).toOption.map(b => (a, b))) | ||
.fold[RespValue](Replies.Error) { range => | ||
val newStart = if (range._1 < 0) string.length + range._1 else range._1 | ||
val newEnd = (if (range._2 < 0) string.length + range._2 else range._2) + 1 | ||
|
||
RespValue.bulkString(string.slice(newStart, newEnd)) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto
if (num < Long.MaxValue) { | ||
val result = num + 1 | ||
|
||
putString(key, result.toString).as(RespValue.Integer(result)) | ||
} else STM.succeed(Replies.Error) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use ZSTM.cond
strings.getOrElse(key, "0").flatMap { string => | ||
Try(string.toLong).toOption.fold(STM.succeed(Replies.Error: RespValue)) { num => | ||
Try(incr.toLong).toOption.fold(STM.succeed(Replies.Error: RespValue)) { incr => | ||
if (incr >= 0 && num <= Long.MaxValue - incr || incr < 0 && num >= Long.MinValue - incr) { | ||
val result = num + incr | ||
|
||
putString(key, result.toString).as(RespValue.Integer(result)) | ||
} else STM.succeed(Replies.Error) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Simplify as suggested above.
Try(string.toDouble).toOption.fold(STM.succeed(Replies.Error: RespValue)) { num => | ||
Try(incr.toDouble).toOption.fold(STM.succeed(Replies.Error: RespValue)) { incr => | ||
if (incr >= 0 && num <= Double.MaxValue - incr || incr < 0 && num >= Double.MinValue - incr) { | ||
val result = (num + incr).toString | ||
|
||
putString(key, result).as(RespValue.bulkString(result)) | ||
} else STM.succeed(Replies.Error) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Simplify as suggested above.
Try(offset.toInt).toOption.filter(_ >= 0).fold[USTM[RespValue]](STM.succeed(Replies.Error)) { offset => | ||
Try(value.toInt).toOption | ||
.filter(num => num == 0 || num == 1) | ||
.fold[USTM[RespValue]](STM.succeed(Replies.Error)) { value => | ||
val newString = string + "\u0000" * (offset / 8 + 1 - string.length) | ||
|
||
newString.lift(offset / 8).fold(STM.succeed(Replies.Error: RespValue)) { char => | ||
val resp = (char >> (7 - offset % 8) & 1).toLong | ||
val updatedChar = (if (value == 1) char | (1 << (7 - offset % 8)) | ||
else char & ~(1 << (7 - offset % 8))).toChar | ||
|
||
putString(key, newString.updated(offset / 8, updatedChar)).as(RespValue.Integer(resp)) | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Simplify as suggested above.
@mvelimir Would love to get this in! Do you have a chance to push it through? |
7a47331
to
937cc2b
Compare
Sorry for the wait. |
Resolves #198
BITFIELD not yet implemented