@@ -239,7 +239,7 @@ rocksdb::Status String::Set(engine::Context &ctx, const std::string &user_key, c
239239}
240240
241241rocksdb::Status String::Set (engine::Context &ctx, const std::string &user_key, const std::string &value,
242- StringSetArgs args, std::optional<std::string> &ret) {
242+ const StringSetArgs & args, std::optional<std::string> &ret) {
243243 uint64_t expire = 0 ;
244244 std::string ns_key = AppendNamespacePrefix (user_key);
245245
@@ -249,6 +249,21 @@ rocksdb::Status String::Set(engine::Context &ctx, const std::string &user_key, c
249249 uint64_t old_expire = 0 ;
250250 auto s = getValueAndExpire (ctx, ns_key, &old_value, &old_expire);
251251 if (!s.ok () && !s.IsNotFound () && !s.IsInvalidArgument ()) return s;
252+ // If the existing key is not a string type, enforce expected behaviors:
253+ if (s.IsInvalidArgument ()) {
254+ // For conditional comparisons (IFEQ/IFNE/IFDEQ/IFDNE), reading the old value is required,
255+ // so return the underlying WRONGTYPE (InvalidArgument) error.
256+ if (args.type == StringSetType::IFEQ || args.type == StringSetType::IFNE || args.type == StringSetType::IFDEQ ||
257+ args.type == StringSetType::IFDNE ) {
258+ return s;
259+ }
260+ // For NX option, treat a wrong type as "key exists" so the condition is not met.
261+ if (args.type == StringSetType::NX ) {
262+ if (!args.get ) ret = std::nullopt ;
263+ return rocksdb::Status::OK ();
264+ }
265+ // For other options, continue (e.g., XX may still proceed since key exists).
266+ }
252267 // GET option
253268 if (args.get ) {
254269 if (s.IsInvalidArgument ()) {
@@ -271,6 +286,38 @@ rocksdb::Status String::Set(engine::Context &ctx, const std::string &user_key, c
271286 // if XX option given, the key didn't exist before: return nil
272287 if (!args.get ) ret = std::nullopt ;
273288 return rocksdb::Status::OK ();
289+ } else if (args.type == StringSetType::IFEQ ) {
290+ // condition met only when key exists AND value matches
291+ bool matched = s.ok () && (old_value == args.cmp_value );
292+ if (!matched) {
293+ if (!args.get ) ret = std::nullopt ;
294+ return rocksdb::Status::OK ();
295+ }
296+ if (!args.get ) ret = " " ;
297+ } else if (args.type == StringSetType::IFNE ) {
298+ // condition not met when key exists AND value matches; key-not-found counts as met
299+ bool not_matched = s.ok () && (old_value == args.cmp_value );
300+ if (not_matched) {
301+ if (!args.get ) ret = std::nullopt ;
302+ return rocksdb::Status::OK ();
303+ }
304+ if (!args.get ) ret = " " ;
305+ } else if (args.type == StringSetType::IFDEQ ) {
306+ // condition met only when key exists AND digest matches
307+ bool matched = s.ok () && (util::StringDigest (old_value) == args.cmp_value );
308+ if (!matched) {
309+ if (!args.get ) ret = std::nullopt ;
310+ return rocksdb::Status::OK ();
311+ }
312+ if (!args.get ) ret = " " ;
313+ } else if (args.type == StringSetType::IFDNE ) {
314+ // condition not met when key exists AND digest matches; key-not-found counts as met
315+ bool not_matched = s.ok () && (util::StringDigest (old_value) == args.cmp_value );
316+ if (not_matched) {
317+ if (!args.get ) ret = std::nullopt ;
318+ return rocksdb::Status::OK ();
319+ }
320+ if (!args.get ) ret = " " ;
274321 } else {
275322 // if GET option not given, make ret not nil
276323 if (!args.get ) ret = " " ;
0 commit comments