Skip to content

Commit 21bc825

Browse files
committed
add string command decr, decrby, getrange, incrbyfloat, mset
1 parent 93a0093 commit 21bc825

File tree

9 files changed

+261
-2
lines changed

9 files changed

+261
-2
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package dev.keva.core.command.impl.string;
2+
3+
import dev.keva.core.command.annotation.CommandImpl;
4+
import dev.keva.core.command.annotation.Execute;
5+
import dev.keva.core.command.annotation.ParamLength;
6+
import dev.keva.core.exception.CommandException;
7+
import dev.keva.ioc.annotation.Autowired;
8+
import dev.keva.ioc.annotation.Component;
9+
import dev.keva.protocol.resp.reply.IntegerReply;
10+
import dev.keva.store.KevaDatabase;
11+
12+
import java.nio.charset.StandardCharsets;
13+
14+
import static dev.keva.core.command.annotation.ParamLength.Type.EXACT;
15+
16+
17+
@Component
18+
@CommandImpl("decr")
19+
@ParamLength(type = EXACT, value = 1)
20+
public class Decr {
21+
private final KevaDatabase database;
22+
23+
@Autowired
24+
public Decr(KevaDatabase database) {
25+
this.database = database;
26+
}
27+
28+
@Execute
29+
public IntegerReply execute(byte[] key) {
30+
byte[] newVal;
31+
try {
32+
newVal = database.decrBy(key, 1L);
33+
} catch (NumberFormatException ex) {
34+
throw new CommandException("value is not an integer or out of range");
35+
}
36+
return new IntegerReply(Long.parseLong(new String(newVal, StandardCharsets.UTF_8)));
37+
}
38+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package dev.keva.core.command.impl.string;
2+
3+
import dev.keva.core.command.annotation.CommandImpl;
4+
import dev.keva.core.command.annotation.Execute;
5+
import dev.keva.core.command.annotation.ParamLength;
6+
import dev.keva.core.exception.CommandException;
7+
import dev.keva.ioc.annotation.Autowired;
8+
import dev.keva.ioc.annotation.Component;
9+
import dev.keva.protocol.resp.reply.IntegerReply;
10+
import dev.keva.store.KevaDatabase;
11+
import lombok.var;
12+
13+
import java.nio.charset.StandardCharsets;
14+
15+
import static dev.keva.core.command.annotation.ParamLength.Type.EXACT;
16+
17+
@Component
18+
@CommandImpl("decrby")
19+
@ParamLength(type = EXACT, value = 2)
20+
public class Decrby {
21+
private final KevaDatabase database;
22+
23+
@Autowired
24+
public Decrby(KevaDatabase database) {
25+
this.database = database;
26+
}
27+
28+
@Execute
29+
public IntegerReply execute(byte[] key, byte[] decrBy) {
30+
var amount = Long.parseLong(new String(decrBy, StandardCharsets.UTF_8));
31+
byte[] newVal;
32+
try {
33+
newVal = database.decrBy(key, amount);
34+
} catch (NumberFormatException ex) {
35+
throw new CommandException("value is not an integer or out of range");
36+
}
37+
return new IntegerReply(Long.parseLong(new String(newVal, StandardCharsets.UTF_8)));
38+
}
39+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package dev.keva.core.command.impl.string;
2+
3+
import dev.keva.core.command.annotation.CommandImpl;
4+
import dev.keva.core.command.annotation.Execute;
5+
import dev.keva.core.command.annotation.ParamLength;
6+
import dev.keva.core.command.impl.key.manager.ExpirationManager;
7+
import dev.keva.ioc.annotation.Autowired;
8+
import dev.keva.ioc.annotation.Component;
9+
import dev.keva.protocol.resp.reply.BulkReply;
10+
import dev.keva.store.KevaDatabase;
11+
12+
import static dev.keva.core.command.annotation.ParamLength.Type.EXACT;
13+
14+
@Component
15+
@CommandImpl("getrange")
16+
@ParamLength(type = EXACT, value = 3)
17+
public class GetRange {
18+
private final KevaDatabase database;
19+
private final ExpirationManager expirationManager;
20+
21+
@Autowired
22+
public GetRange(KevaDatabase database, ExpirationManager expirationManager) {
23+
this.database = database;
24+
this.expirationManager = expirationManager;
25+
}
26+
27+
@Execute
28+
public BulkReply execute(byte[] key, byte[] start, byte[] end) {
29+
return new BulkReply(database.getrange(key, start, end));
30+
}
31+
}

core/src/main/java/dev/keva/core/command/impl/key/Incr.java renamed to core/src/main/java/dev/keva/core/command/impl/string/Incr.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package dev.keva.core.command.impl.key;
1+
package dev.keva.core.command.impl.string;
22

33
import dev.keva.core.command.annotation.CommandImpl;
44
import dev.keva.core.command.annotation.Execute;

core/src/main/java/dev/keva/core/command/impl/key/Incrby.java renamed to core/src/main/java/dev/keva/core/command/impl/string/Incrby.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package dev.keva.core.command.impl.key;
1+
package dev.keva.core.command.impl.string;
22

33
import dev.keva.core.command.annotation.CommandImpl;
44
import dev.keva.core.command.annotation.Execute;

core/src/test/java/dev/keva/core/server/AbstractServerTest.java

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -843,6 +843,38 @@ void dumpAndRestore() {
843843
}
844844
}
845845

846+
@Test
847+
void decr() {
848+
try {
849+
val set1 = jedis.set("mykey", "10");
850+
assertEquals(set1, "OK");
851+
val decr1 = jedis.decr("mykey");
852+
assertEquals(decr1, 9);
853+
val set2 = jedis.set("errKey", "foobar");
854+
assertThrows(JedisDataException.class, () -> jedis.decr("errKey"));
855+
856+
} catch (Exception e) {
857+
fail(e);
858+
}
859+
}
860+
861+
@Test
862+
void decrBy() {
863+
try {
864+
val set1 = jedis.set("mykey", "10");
865+
assertEquals(set1, "OK");
866+
val decrby1 = jedis.decrBy("mykey", 5);
867+
assertEquals(decrby1, 5);
868+
val decrby2 = jedis.decrBy("mykey", 10);
869+
assertEquals(decrby2, -5);
870+
val set2 = jedis.set("mykey2", "abc123");
871+
872+
assertThrows(JedisDataException.class, () -> jedis.decrBy("mykey2", 10));
873+
} catch (Exception e) {
874+
fail(e);
875+
}
876+
}
877+
846878
@Test
847879
void type() {
848880
try {
@@ -860,4 +892,25 @@ void type() {
860892
fail(e);
861893
}
862894
}
895+
896+
@Test
897+
void getRange() {
898+
try {
899+
val set1 = jedis.set("mykey", "This is a string");
900+
val getrange1 = jedis.getrange("mykey", 0, 3);
901+
assertEquals("This", getrange1);
902+
val getrange2 = jedis.getrange("mykey", -3, -1);
903+
assertEquals("ing", getrange2);
904+
val getrange3 = jedis.getrange("mykey", 0, -1);
905+
assertEquals("This is a string", getrange3);
906+
val getrange4 = jedis.getrange("mykey", 10, 100);
907+
assertEquals("string", getrange4);
908+
val getrange5 = jedis.getrange("mykey", 10, 5);
909+
assertEquals("", getrange5);
910+
val getrange6 = jedis.getrange("mykey", -10, 10);
911+
assertEquals("s a s", getrange6);
912+
} catch (Exception e) {
913+
fail(e);
914+
}
915+
}
863916
}

store/src/main/java/dev/keva/store/KevaDatabase.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,8 @@ public interface KevaDatabase {
6969

7070
byte[][] mget(byte[]... keys);
7171

72+
byte[] decrBy(byte[] key, long amount);
73+
74+
byte[] getrange(byte[] key, byte[] start, byte[] end);
75+
7276
}

store/src/main/java/dev/keva/store/impl/OffHeapDatabaseImpl.java

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -716,4 +716,51 @@ public byte[][] mget(byte[]... keys) {
716716
lock.unlock();
717717
}
718718
}
719+
720+
@Override
721+
public byte[] decrBy(byte[] key, long amount) {
722+
lock.lock();
723+
try {
724+
return chronicleMap.compute(key, (k, oldVal) -> {
725+
long curVal = 0L;
726+
if (oldVal != null) {
727+
curVal = Long.parseLong(new String(oldVal, StandardCharsets.UTF_8));
728+
}
729+
curVal = curVal - amount;
730+
return Long.toString(curVal).getBytes(StandardCharsets.UTF_8);
731+
});
732+
} finally {
733+
lock.unlock();
734+
}
735+
}
736+
737+
@Override
738+
public byte[] getrange(byte[] key, byte[] start, byte[] end) {
739+
lock.lock();
740+
try {
741+
val value = chronicleMap.get(key);
742+
int startInt = Integer.parseInt(new String(start, StandardCharsets.UTF_8));
743+
int endInt = Integer.parseInt(new String(end, StandardCharsets.UTF_8));
744+
745+
// convert negative indexes to positive ones
746+
if (startInt < 0 && endInt < 0 && startInt > endInt) {
747+
return null;
748+
}
749+
if (startInt < 0) startInt = value.length + startInt;
750+
if (endInt < 0) endInt = value.length + endInt;
751+
if (startInt < 0) startInt = 0;
752+
if (endInt < 0) endInt = 0;
753+
if (endInt >= value.length) endInt = value.length - 1;
754+
755+
byte[] result;
756+
if (startInt > endInt || value.length == 0) {
757+
result = new String("").getBytes();
758+
} else {
759+
result = Arrays.copyOfRange(value, startInt, endInt + 1);
760+
}
761+
return result;
762+
} finally {
763+
lock.unlock();
764+
}
765+
}
719766
}

store/src/main/java/dev/keva/store/impl/OnHeapDatabaseImpl.java

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -674,4 +674,51 @@ public byte[][] mget(byte[]... keys) {
674674
lock.unlock();
675675
}
676676
}
677+
678+
@Override
679+
public byte[] decrBy(byte[] key, long amount) {
680+
lock.lock();
681+
try {
682+
return map.compute(new BytesKey(key), (k, oldVal) -> {
683+
long curVal = 0L;
684+
if (oldVal != null) {
685+
curVal = Long.parseLong(oldVal.toString());
686+
}
687+
curVal = curVal - amount;
688+
return new BytesValue(Long.toString(curVal).getBytes(StandardCharsets.UTF_8));
689+
}).getBytes();
690+
} finally {
691+
lock.unlock();
692+
}
693+
}
694+
695+
@Override
696+
public byte[] getrange(byte[] key, byte[] start, byte[] end) {
697+
lock.lock ();
698+
try {
699+
val value = map.get (new BytesKey (key)).getBytes ();
700+
int startInt = Integer.parseInt (new String (start, StandardCharsets.UTF_8));
701+
int endInt = Integer.parseInt (new String (end, StandardCharsets.UTF_8));
702+
703+
// convert negative indexes to positive ones
704+
if (startInt < 0 && endInt < 0 && startInt > endInt) {
705+
return null;
706+
}
707+
if (startInt < 0) startInt = value.length + startInt;
708+
if (endInt < 0) endInt = value.length + endInt;
709+
if (startInt < 0) startInt = 0;
710+
if (endInt < 0) endInt = 0;
711+
if (endInt >= value.length) endInt = value.length - 1;
712+
713+
byte[] result;
714+
if (startInt > endInt || value.length == 0) {
715+
result = new String ("").getBytes ();
716+
} else {
717+
result = Arrays.copyOfRange (value, startInt, endInt + 1);
718+
}
719+
return result;
720+
} finally {
721+
lock.unlock ();
722+
}
723+
}
677724
}

0 commit comments

Comments
 (0)