From a37ccbfb28d16428247b3ac049f8804020aaf3eb Mon Sep 17 00:00:00 2001 From: Vladislav Date: Wed, 8 Mar 2023 19:51:01 +0300 Subject: [PATCH] fix(core): Auto cast doubles to ints in lua scripts (#922) fix(core): Auto convert double to integers in lua scripts --- src/core/interpreter.cc | 17 ++++++++++++----- src/server/multi_test.cc | 10 ++++++++++ 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/core/interpreter.cc b/src/core/interpreter.cc index 4eae482c4..69cc8c167 100644 --- a/src/core/interpreter.cc +++ b/src/core/interpreter.cc @@ -84,13 +84,20 @@ void RedisTranslator::OnString(std::string_view str) { ArrayPost(); } -// Doubles are not supported by Redis, however we can support them. -// Here is the use-case: -// local foo = redis.call('zscore', 'myzset', 'one') -// assert(type(foo) == "number") void RedisTranslator::OnDouble(double d) { + static constexpr double kConvertEps = std::numeric_limits::epsilon(); + + double fractpart, intpart; + fractpart = modf(d, &intpart); + ArrayPre(); - lua_pushnumber(lua_, d); + + // Convert to integer when possible to allow converting to string without trailing zeros. + if (abs(fractpart) < kConvertEps && intpart < std::numeric_limits::max() && + intpart > std::numeric_limits::min()) + lua_pushinteger(lua_, static_cast(d)); + else + lua_pushnumber(lua_, d); ArrayPost(); } diff --git a/src/server/multi_test.cc b/src/server/multi_test.cc index 1774c3f1b..915ecfdd6 100644 --- a/src/server/multi_test.cc +++ b/src/server/multi_test.cc @@ -381,6 +381,16 @@ TEST_F(MultiTest, Eval) { ASSERT_THAT(resp, ArrLen(3)); const auto& arr = resp.GetVec(); EXPECT_THAT(arr, ElementsAre("a", "b", "c")); + + Run({"zadd", "z1", "123", "a", "12345678912345", "b", "12.5", "c"}); + const char* kGetScore = "return redis.call('ZSCORE', KEYS[1], ARGV[1]) .. '-works'"; + + resp = Run({"eval", kGetScore, "1", "z1", "a"}); + EXPECT_EQ(resp, "123-works"); + resp = Run({"eval", kGetScore, "1", "z1", "b"}); + EXPECT_EQ(resp, "12345678912345-works"); + resp = Run({"eval", kGetScore, "1", "z1", "c"}); + EXPECT_EQ(resp, "12.5-works"); } TEST_F(MultiTest, Watch) {