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) {