Repository: fppt/jedis-mock
Pull request #17 (2019-01-23 07:44:54)

Improve redis operation construction


Patch:
diff --git a/src/main/java/com/github/fppt/jedismock/RedisServer.java b/src/main/java/com/github/fppt/jedismock/RedisServer.java
index b258a8f..59add20 100644
--- a/src/main/java/com/github/fppt/jedismock/RedisServer.java
+++ b/src/main/java/com/github/fppt/jedismock/RedisServer.java
@@ -1,5 +1,8 @@
 package com.github.fppt.jedismock;
 
+import com.github.fppt.jedismock.server.RedisService;
+import com.github.fppt.jedismock.server.ServiceOptions;
+import com.github.fppt.jedismock.storage.RedisBase;
 import com.google.common.base.Preconditions;
 
 import java.io.IOException;
diff --git a/src/main/java/com/github/fppt/jedismock/Utils.java b/src/main/java/com/github/fppt/jedismock/Utils.java
index 95dc0af..0d96e9e 100644
--- a/src/main/java/com/github/fppt/jedismock/Utils.java
+++ b/src/main/java/com/github/fppt/jedismock/Utils.java
@@ -1,6 +1,7 @@
 package com.github.fppt.jedismock;
 
 import com.github.fppt.jedismock.exception.WrongValueTypeException;
+import com.github.fppt.jedismock.server.Slice;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_exec.java b/src/main/java/com/github/fppt/jedismock/commands/RO_exec.java
deleted file mode 100644
index f574942..0000000
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_exec.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.github.fppt.jedismock.commands;
-
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
-import org.slf4j.LoggerFactory;
-
-import java.util.List;
-import java.util.stream.Collectors;
-
-class RO_exec extends AbstractRedisOperation {
-    private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(RO_exec.class);
-    private final List<RedisOperation> transaction;
-
-    RO_exec(RedisBase base, List<RedisOperation> transaction, List<Slice> params) {
-        super(base, params);
-        this.transaction = transaction;
-    }
-
-    Slice response() {
-        try {
-            List<Slice> results = transaction.stream().
-                    map(RedisOperation::execute).
-                    collect(Collectors.toList());
-            transaction.clear();
-            return Response.array(results);
-        } catch (Throwable t){
-            LOG.error("ERROR during committing transaction", t);
-            return Response.NULL;
-        }
-    }
-}
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_quit.java b/src/main/java/com/github/fppt/jedismock/commands/RO_quit.java
deleted file mode 100644
index e7d6d90..0000000
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_quit.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.github.fppt.jedismock.commands;
-
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.RedisClient;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
-
-import java.util.List;
-
-class RO_quit extends AbstractRedisOperation {
-    private final RedisClient client;
-
-    RO_quit(RedisBase base, RedisClient client, List<Slice> params) {
-        super(base, params);
-        this.client = client;
-    }
-
-    Slice response() {
-        client.sendResponse(Response.clientResponse("quit", Response.OK), "quit");
-        client.close();
-
-        return Response.SKIP;
-    }
-}
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_subscribe.java b/src/main/java/com/github/fppt/jedismock/commands/RO_subscribe.java
deleted file mode 100644
index 1053363..0000000
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_subscribe.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.github.fppt.jedismock.commands;
-
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.RedisClient;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
-
-import java.util.List;
-
-class RO_subscribe extends AbstractRedisOperation {
-    private final RedisClient client;
-
-    RO_subscribe(RedisBase base, RedisClient client, List<Slice> params) {
-        super(base, params);
-        this.client = client;
-    }
-
-    Slice response() {
-        params().forEach(channel -> base().addSubscriber(channel, client));
-        List<Slice> numSubscriptions = base().getSubscriptions(client);
-
-        return Response.subscribedToChannel(numSubscriptions);
-    }
-}
diff --git a/src/main/java/com/github/fppt/jedismock/RedisCommand.java b/src/main/java/com/github/fppt/jedismock/commands/RedisCommand.java
similarity index 77%
rename from src/main/java/com/github/fppt/jedismock/RedisCommand.java
rename to src/main/java/com/github/fppt/jedismock/commands/RedisCommand.java
index f2c6d4f..2d4a7ff 100644
--- a/src/main/java/com/github/fppt/jedismock/RedisCommand.java
+++ b/src/main/java/com/github/fppt/jedismock/commands/RedisCommand.java
@@ -1,5 +1,6 @@
-package com.github.fppt.jedismock;
+package com.github.fppt.jedismock.commands;
 
+import com.github.fppt.jedismock.server.Slice;
 import com.google.auto.value.AutoValue;
 import com.google.common.collect.Lists;
 
@@ -11,7 +12,7 @@ public abstract class RedisCommand {
 
     public abstract List<Slice> parameters();
 
-    static RedisCommand create(){
+    public static RedisCommand create(){
         return new AutoValue_RedisCommand(Lists.newArrayList());
     }
 
diff --git a/src/main/java/com/github/fppt/jedismock/RedisCommandParser.java b/src/main/java/com/github/fppt/jedismock/commands/RedisCommandParser.java
similarity index 76%
rename from src/main/java/com/github/fppt/jedismock/RedisCommandParser.java
rename to src/main/java/com/github/fppt/jedismock/commands/RedisCommandParser.java
index e8b26e5..c322312 100644
--- a/src/main/java/com/github/fppt/jedismock/RedisCommandParser.java
+++ b/src/main/java/com/github/fppt/jedismock/commands/RedisCommandParser.java
@@ -1,5 +1,6 @@
-package com.github.fppt.jedismock;
+package com.github.fppt.jedismock.commands;
 
+import com.github.fppt.jedismock.server.SliceParser;
 import com.github.fppt.jedismock.exception.ParseErrorException;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
@@ -13,13 +14,13 @@ import java.io.InputStream;
 public class RedisCommandParser {
 
     @VisibleForTesting
-    static RedisCommand parse(String stringInput) throws ParseErrorException {
+    public static RedisCommand parse(String stringInput) throws ParseErrorException {
         Preconditions.checkNotNull(stringInput);
 
         return parse(new ByteArrayInputStream(stringInput.getBytes()));
     }
 
-    static RedisCommand parse(InputStream messageInput) throws ParseErrorException {
+    public static RedisCommand parse(InputStream messageInput) throws ParseErrorException {
         Preconditions.checkNotNull(messageInput);
 
         long count = SliceParser.consumeCount(messageInput);
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RedisOperationExecutor.java b/src/main/java/com/github/fppt/jedismock/commands/RedisOperationExecutor.java
deleted file mode 100644
index 4b38052..0000000
--- a/src/main/java/com/github/fppt/jedismock/commands/RedisOperationExecutor.java
+++ /dev/null
@@ -1,202 +0,0 @@
-package com.github.fppt.jedismock.commands;
-
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.RedisClient;
-import com.github.fppt.jedismock.RedisCommand;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
-import com.github.fppt.jedismock.exception.WrongValueTypeException;
-import com.google.common.base.Preconditions;
-import org.slf4j.LoggerFactory;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Created by Xiaolu on 2015/4/20.
- */
-public class RedisOperationExecutor {
-    private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(RedisOperationExecutor.class);
-    private final RedisClient owner;
-    private final Map<Integer, RedisBase> redisBases;
-    private boolean transactionModeOn;
-    private List<RedisOperation> transaction;
-    private int selectedRedisBase = 0;
-
-    public RedisOperationExecutor(Map<Integer, RedisBase> redisBases, RedisClient owner) {
-        this.redisBases = redisBases;
-        this.owner = owner;
-        transactionModeOn = false;
-        transaction = new ArrayList<>();
-    }
-
-    private RedisBase getCurrentBase(){
-        return redisBases.computeIfAbsent(selectedRedisBase, key -> new RedisBase());
-    }
-
-    private RedisOperation buildSimpleOperation(String name, List<Slice> params){
-        RedisOperations foundOperation = RedisOperations.valueOf(name);
-
-        switch(foundOperation){
-            case SET:
-                return new RO_set(getCurrentBase(), params);
-            case SETEX:
-                return new RO_setex(getCurrentBase(), params);
-            case PSETEX:
-                return new RO_psetex(getCurrentBase(), params);
-            case SETNX:
-                return new RO_setnx(getCurrentBase(), params);
-            case SETBIT:
-                return new RO_setbit(getCurrentBase(), params);
-            case APPEND:
-                return new RO_append(getCurrentBase(), params);
-            case GET:
-                return new RO_get(getCurrentBase(), params);
-            case GETBIT:
-                return new RO_getbit(getCurrentBase(), params);
-            case TTL:
-                return new RO_ttl(getCurrentBase(), params);
-            case PTTL:
-                return new RO_pttl(getCurrentBase(), params);
-            case EXPIRE:
-                return new RO_expire(getCurrentBase(), params);
-            case PEXPIRE:
-                return new RO_pexpire(getCurrentBase(), params);
-            case INCR:
-                return new RO_incr(getCurrentBase(), params);
-            case INCRBY:
-                return new RO_incrby(getCurrentBase(), params);
-            case DECR:
-                return new RO_decr(getCurrentBase(), params);
-            case DECRBY:
-                return new RO_decrby(getCurrentBase(), params);
-            case PFCOUNT:
-                return new RO_pfcount(getCurrentBase(), params);
-            case PFADD:
-                return new RO_pfadd(getCurrentBase(), params);
-            case PFMERGE:
-                return new RO_pfmerge(getCurrentBase(), params);
-            case MGET:
-                return new RO_mget(getCurrentBase(), params);
-            case MSET:
-                return new RO_mset(getCurrentBase(), params);
-            case GETSET:
-                return new RO_getset(getCurrentBase(), params);
-            case STRLEN:
-                return new RO_strlen(getCurrentBase(), params);
-            case DEL:
-                return new RO_del(getCurrentBase(), params);
-            case EXISTS:
-                return new RO_exists(getCurrentBase(), params);
-            case EXPIREAT:
-                return new RO_expireat(getCurrentBase(), params);
-            case PEXPIREAT:
-                return new RO_pexpireat(getCurrentBase(), params);
-            case LPUSH:
-                return new RO_lpush(getCurrentBase(), params);
-            case RPUSH:
-                return new RO_rpush(getCurrentBase(), params);
-            case LPUSHX:
-                return new RO_lpushx(getCurrentBase(), params);
-            case LRANGE:
-                return new RO_lrange(getCurrentBase(), params);
-            case LLEN:
-                return new RO_llen(getCurrentBase(), params);
-            case LPOP:
-                return new RO_lpop(getCurrentBase(), params);
-            case RPOP:
-                return new RO_rpop(getCurrentBase(), params);
-            case LINDEX:
-                return new RO_lindex(getCurrentBase(), params);
-            case RPOPLPUSH:
-                return new RO_rpoplpush(getCurrentBase(), params);
-            case BRPOPLPUSH:
-                return new RO_brpoplpush(getCurrentBase(), params);
-            case SUBSCRIBE:
-                return new RO_subscribe(getCurrentBase(), owner, params);
-            case UNSUBSCRIBE:
-                return new RO_unsubscribe(getCurrentBase(), owner, params);
-            case PUBLISH:
-                return new RO_publish(getCurrentBase(), params);
-            case FLUSHALL:
-                return new RO_flushall(getCurrentBase(), params);
-            case LREM:
-                return new RO_lrem(getCurrentBase(), params);
-            case QUIT:
-                return new RO_quit(getCurrentBase(), owner, params);
-            case EXEC:
-                transactionModeOn = false;
-                return new RO_exec(getCurrentBase(), transaction, params);
-            case PING:
-                return new RO_ping(getCurrentBase(), params);
-            case KEYS:
-                return new RO_keys(getCurrentBase(), params);
-            case SADD:
-                return new RO_sadd(getCurrentBase(), params);
-            case SMEMBERS:
-                return new RO_smembers(getCurrentBase(), params);
-            case SPOP:
-                return new RO_spop(getCurrentBase(), params);
-            case HGET:
-                return new RO_hget(getCurrentBase(), params);
-            case HSET:
-                return new RO_hset(getCurrentBase(), params);
-            case HDEL:
-                return new RO_hdel(getCurrentBase(), params);
-            case HGETALL:
-                return new RO_hegetall(getCurrentBase(), params);
-            case SINTER:
-                return new RO_sinter(getCurrentBase(), params);
-            case HMGET:
-                return new RO_hmget(getCurrentBase(), params);
-            case HMSET:
-                return new RO_hmset(getCurrentBase(), params);
-            default:
-                throw new UnsupportedOperationException(String.format("Unsupported operation '%s'", name));
-        }
-    }
-
-    public synchronized Slice execCommand(RedisCommand command) {
-        Preconditions.checkArgument(command.parameters().size() > 0);
-        List<Slice> params = command.parameters();
-        List<Slice> commandParams = params.subList(1, params.size());
-        String name = new String(params.get(0).data()).toUpperCase();
-
-        try {
-            //Meta Command handling
-            if(name.equals(RedisOperations.MULTI.name())){
-                newTransaction();
-                return Response.clientResponse(name, Response.OK);
-            }
-
-            if(name.equals(RedisOperations.SELECT.name())){
-                changeActiveRedisBase(commandParams);
-                return Response.clientResponse(name, Response.OK);
-            }
-
-            //Checking if we mutating the transaction or the redisBases
-            RedisOperation redisOperation = buildSimpleOperation(name, commandParams);
-            if(transactionModeOn){
-                transaction.add(redisOperation);
-            } else {
-                return Response.clientResponse(name, redisOperation.execute());
-            }
-
-            return Response.clientResponse(name, Response.OK);
-        } catch(UnsupportedOperationException | WrongValueTypeException | IllegalArgumentException e){
-            LOG.error("Malformed request", e);
-            return Response.error(e.getMessage());
-        }
-    }
-
-    private void changeActiveRedisBase(List<Slice> commandParams) {
-        String data = new String(commandParams.get(0).data());
-        selectedRedisBase = Integer.parseInt(data);
-    }
-
-    private void newTransaction(){
-        if(transactionModeOn) throw new RuntimeException("Redis mock does not support more than one transaction");
-        transactionModeOn = true;
-    }
-}
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RedisOperations.java b/src/main/java/com/github/fppt/jedismock/commands/RedisOperations.java
deleted file mode 100644
index 7ec4273..0000000
--- a/src/main/java/com/github/fppt/jedismock/commands/RedisOperations.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package com.github.fppt.jedismock.commands;
-
-public enum RedisOperations {
-    SET,
-    SETEX,
-    PSETEX,
-    SETNX,
-    SETBIT,
-    APPEND,
-    GET,
-    GETBIT,
-    TTL,
-    PTTL,
-    EXPIRE,
-    PEXPIRE,
-    INCR,
-    INCRBY,
-    DECR,
-    DECRBY,
-    PFCOUNT,
-    PFADD,
-    PFMERGE,
-    MGET,
-    MSET,
-    GETSET,
-    STRLEN,
-    DEL,
-    EXISTS,
-    EXPIREAT,
-    PEXPIREAT,
-    LPUSH,
-    RPUSH,
-    LPUSHX,
-    LRANGE,
-    LLEN,
-    LPOP,
-    RPOP,
-    LINDEX,
-    RPOPLPUSH,
-    BRPOPLPUSH,
-    SUBSCRIBE,
-    UNSUBSCRIBE,
-    PUBLISH,
-    FLUSHALL,
-    LREM,
-    QUIT,
-    EXEC,
-    PING,
-    KEYS,
-    SADD,
-    SPOP,
-    HGET,
-    HSET,
-    HDEL,
-    HGETALL,
-    SINTER,
-    HMGET,
-    HMSET,
-    SMEMBERS,
-    MULTI,
-    SELECT;
-}
diff --git a/src/main/java/com/github/fppt/jedismock/commands/AbstractRedisOperation.java b/src/main/java/com/github/fppt/jedismock/operations/AbstractRedisOperation.java
similarity index 89%
rename from src/main/java/com/github/fppt/jedismock/commands/AbstractRedisOperation.java
rename to src/main/java/com/github/fppt/jedismock/operations/AbstractRedisOperation.java
index d6690b3..667bdf0 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/AbstractRedisOperation.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/AbstractRedisOperation.java
@@ -1,7 +1,7 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
 
 import java.util.List;
 
diff --git a/src/main/java/com/github/fppt/jedismock/operations/OperationFactory.java b/src/main/java/com/github/fppt/jedismock/operations/OperationFactory.java
new file mode 100644
index 0000000..3eb00c0
--- /dev/null
+++ b/src/main/java/com/github/fppt/jedismock/operations/OperationFactory.java
@@ -0,0 +1,98 @@
+package com.github.fppt.jedismock.operations;
+
+import com.github.fppt.jedismock.storage.OperationExecutorState;
+import com.github.fppt.jedismock.storage.RedisBase;
+import com.github.fppt.jedismock.server.Slice;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.BiFunction;
+
+public class OperationFactory {
+    private static final Map<String, BiFunction<RedisBase, List<Slice>, RedisOperation>> TRANSACTIONAL_OPERATIONS = new HashMap<>();
+    static {
+        TRANSACTIONAL_OPERATIONS.put("set", RO_set::new);
+        TRANSACTIONAL_OPERATIONS.put("setex", RO_setex::new);
+        TRANSACTIONAL_OPERATIONS.put("psetex", RO_psetex::new);
+        TRANSACTIONAL_OPERATIONS.put("setnx", RO_setnx::new);
+        TRANSACTIONAL_OPERATIONS.put("setbit", RO_setbit::new);
+        TRANSACTIONAL_OPERATIONS.put("append", RO_append::new);
+        TRANSACTIONAL_OPERATIONS.put("get", RO_get::new);
+        TRANSACTIONAL_OPERATIONS.put("getbit", RO_getbit::new);
+        TRANSACTIONAL_OPERATIONS.put("ttl", RO_ttl::new);
+        TRANSACTIONAL_OPERATIONS.put("pttl", RO_pttl::new);
+        TRANSACTIONAL_OPERATIONS.put("expire", RO_expire::new);
+        TRANSACTIONAL_OPERATIONS.put("pexpire", RO_pexpire::new);
+        TRANSACTIONAL_OPERATIONS.put("incr", RO_incr::new);
+        TRANSACTIONAL_OPERATIONS.put("incrby", RO_incrby::new);
+        TRANSACTIONAL_OPERATIONS.put("decr", RO_decr::new);
+        TRANSACTIONAL_OPERATIONS.put("decrby", RO_decrby::new);
+        TRANSACTIONAL_OPERATIONS.put("pfcount", RO_pfcount::new);
+        TRANSACTIONAL_OPERATIONS.put("pfadd", RO_pfadd::new);
+        TRANSACTIONAL_OPERATIONS.put("pfmerge", RO_pfmerge::new);
+        TRANSACTIONAL_OPERATIONS.put("mget", RO_mget::new);
+        TRANSACTIONAL_OPERATIONS.put("mset", RO_mset::new);
+        TRANSACTIONAL_OPERATIONS.put("getset", RO_getset::new);
+        TRANSACTIONAL_OPERATIONS.put("strlen", RO_strlen::new);
+        TRANSACTIONAL_OPERATIONS.put("del", RO_del::new);
+        TRANSACTIONAL_OPERATIONS.put("exists", RO_exists::new);
+        TRANSACTIONAL_OPERATIONS.put("expireat", RO_expireat::new);
+        TRANSACTIONAL_OPERATIONS.put("pexpireat", RO_pexpireat::new);
+        TRANSACTIONAL_OPERATIONS.put("lpush", RO_lpush::new);
+        TRANSACTIONAL_OPERATIONS.put("rpush", RO_rpush::new);
+        TRANSACTIONAL_OPERATIONS.put("lpushx", RO_lpushx::new);
+        TRANSACTIONAL_OPERATIONS.put("lrange", RO_lrange::new);
+        TRANSACTIONAL_OPERATIONS.put("llen", RO_llen::new);
+        TRANSACTIONAL_OPERATIONS.put("lpop", RO_lpop::new);
+        TRANSACTIONAL_OPERATIONS.put("rpop", RO_rpop::new);
+        TRANSACTIONAL_OPERATIONS.put("lindex", RO_lindex::new);
+        TRANSACTIONAL_OPERATIONS.put("rpoplpush", RO_rpoplpush::new);
+        TRANSACTIONAL_OPERATIONS.put("brpoplpush", RO_brpoplpush::new);
+        TRANSACTIONAL_OPERATIONS.put("publish", RO_publish::new);
+        TRANSACTIONAL_OPERATIONS.put("flushall", RO_flushall::new);
+        TRANSACTIONAL_OPERATIONS.put("lrem", RO_lrem::new);
+        TRANSACTIONAL_OPERATIONS.put("ping", RO_ping::new);
+        TRANSACTIONAL_OPERATIONS.put("keys", RO_keys::new);
+        TRANSACTIONAL_OPERATIONS.put("sadd", RO_sadd::new);
+        TRANSACTIONAL_OPERATIONS.put("spop", RO_spop::new);
+        TRANSACTIONAL_OPERATIONS.put("hget", RO_hget::new);
+        TRANSACTIONAL_OPERATIONS.put("hset", RO_hset::new);
+        TRANSACTIONAL_OPERATIONS.put("hdel", RO_hdel::new);
+        TRANSACTIONAL_OPERATIONS.put("hgetall", RO_hgetall::new);
+        TRANSACTIONAL_OPERATIONS.put("sinter", RO_sinter::new);
+        TRANSACTIONAL_OPERATIONS.put("hmget", RO_hmget::new);
+        TRANSACTIONAL_OPERATIONS.put("hmset", RO_hmset::new);
+        TRANSACTIONAL_OPERATIONS.put("smembers", RO_smembers::new);
+        TRANSACTIONAL_OPERATIONS.put("hsetnx", RO_hsetnx::new);
+    }
+
+
+    public static RedisOperation buildTxOperation(RedisBase base, String name, List<Slice> params){
+        BiFunction<RedisBase, List<Slice>, RedisOperation> builder = OperationFactory.TRANSACTIONAL_OPERATIONS.get(name);
+        if(builder == null) throw new UnsupportedOperationException(String.format("Unsupported operation '%s'", name));
+        return builder.apply(base, params);
+    }
+
+    public static Optional<RedisOperation> buildMetaOperation(String name, OperationExecutorState state, List<Slice> params){
+        switch(name){
+            case "multi":
+                return Optional.of(new RO_multi(state));
+            case "select":
+                return Optional.of(new RO_select(state, params));
+            case "subscribe":
+                return Optional.of(new RO_subscribe(state, params));
+            case "unsubscribe":
+                return Optional.of(new RO_unsubscribe(state, params));
+            case "quit":
+                return Optional.of(new RO_quit(state));
+            case "exec":
+                return Optional.of(new RO_exec(state));
+            default:
+                return Optional.empty();
+        }
+    }
+
+
+}
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_add.java b/src/main/java/com/github/fppt/jedismock/operations/RO_add.java
similarity index 81%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_add.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_add.java
index 95dcf9c..410c091 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_add.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_add.java
@@ -1,8 +1,8 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
 
 import java.util.Collection;
 import java.util.List;
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_append.java b/src/main/java/com/github/fppt/jedismock/operations/RO_append.java
similarity index 80%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_append.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_append.java
index 3e8f659..277a99f 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_append.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_append.java
@@ -1,8 +1,8 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
 
 import java.util.List;
 
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_brpoplpush.java b/src/main/java/com/github/fppt/jedismock/operations/RO_brpoplpush.java
similarity index 83%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_brpoplpush.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_brpoplpush.java
index 8d95821..b1d1931 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_brpoplpush.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_brpoplpush.java
@@ -1,9 +1,9 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
-import com.github.fppt.jedismock.SliceParser;
+import com.github.fppt.jedismock.storage.RedisBase;
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.server.SliceParser;
 
 import java.util.Arrays;
 import java.util.List;
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_decr.java b/src/main/java/com/github/fppt/jedismock/operations/RO_decr.java
similarity index 62%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_decr.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_decr.java
index a3bc387..484198e 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_decr.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_decr.java
@@ -1,7 +1,7 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
+import com.github.fppt.jedismock.server.Slice;
 
 import java.util.List;
 
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_decrby.java b/src/main/java/com/github/fppt/jedismock/operations/RO_decrby.java
similarity index 70%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_decrby.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_decrby.java
index 0386e2d..40d1904 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_decrby.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_decrby.java
@@ -1,7 +1,7 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
+import com.github.fppt.jedismock.server.Slice;
 
 import java.util.List;
 
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_del.java b/src/main/java/com/github/fppt/jedismock/operations/RO_del.java
similarity index 69%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_del.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_del.java
index c4d429a..12b41f0 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_del.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_del.java
@@ -1,8 +1,8 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
 
 import java.util.List;
 
diff --git a/src/main/java/com/github/fppt/jedismock/operations/RO_exec.java b/src/main/java/com/github/fppt/jedismock/operations/RO_exec.java
new file mode 100644
index 0000000..64f50a4
--- /dev/null
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_exec.java
@@ -0,0 +1,33 @@
+package com.github.fppt.jedismock.operations;
+
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.OperationExecutorState;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class RO_exec implements RedisOperation {
+    private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(RO_exec.class);
+    private OperationExecutorState state;
+
+    public RO_exec(OperationExecutorState state) {
+        this.state = state;
+    }
+
+    @Override
+    public Slice execute() {
+        try {
+            state.transactionMode(false);
+            List<Slice> results = state.tx().stream().
+                    map(RedisOperation::execute).
+                    collect(Collectors.toList());
+            state.tx().clear();
+            return Response.array(results);
+        } catch (Throwable t){
+            LOG.error("ERROR during committing transaction", t);
+            return Response.NULL;
+        }
+    }
+}
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_exists.java b/src/main/java/com/github/fppt/jedismock/operations/RO_exists.java
similarity index 63%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_exists.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_exists.java
index 037da82..ebc95e7 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_exists.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_exists.java
@@ -1,8 +1,8 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
 
 import java.util.List;
 
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_expire.java b/src/main/java/com/github/fppt/jedismock/operations/RO_expire.java
similarity index 64%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_expire.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_expire.java
index c309997..eef2ef4 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_expire.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_expire.java
@@ -1,7 +1,7 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
+import com.github.fppt.jedismock.server.Slice;
 
 import java.util.List;
 
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_expireat.java b/src/main/java/com/github/fppt/jedismock/operations/RO_expireat.java
similarity index 68%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_expireat.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_expireat.java
index 925bdd7..33f5207 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_expireat.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_expireat.java
@@ -1,8 +1,8 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
 
 import java.util.List;
 
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_flushall.java b/src/main/java/com/github/fppt/jedismock/operations/RO_flushall.java
similarity index 56%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_flushall.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_flushall.java
index 14ba525..5319a76 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_flushall.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_flushall.java
@@ -1,8 +1,8 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
 
 import java.util.List;
 
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_get.java b/src/main/java/com/github/fppt/jedismock/operations/RO_get.java
similarity index 56%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_get.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_get.java
index a6e025d..cfe75c5 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_get.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_get.java
@@ -1,8 +1,8 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
 
 import java.util.List;
 
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_getbit.java b/src/main/java/com/github/fppt/jedismock/operations/RO_getbit.java
similarity index 78%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_getbit.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_getbit.java
index cd3e99f..f52f791 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_getbit.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_getbit.java
@@ -1,8 +1,8 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
 
 import java.util.List;
 
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_getset.java b/src/main/java/com/github/fppt/jedismock/operations/RO_getset.java
similarity index 64%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_getset.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_getset.java
index 80db148..39b93ce 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_getset.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_getset.java
@@ -1,8 +1,8 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
 
 import java.util.List;
 
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_hdel.java b/src/main/java/com/github/fppt/jedismock/operations/RO_hdel.java
similarity index 71%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_hdel.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_hdel.java
index c2cad89..9718086 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_hdel.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_hdel.java
@@ -1,8 +1,8 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
 
 import java.util.List;
 
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_hget.java b/src/main/java/com/github/fppt/jedismock/operations/RO_hget.java
similarity index 58%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_hget.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_hget.java
index 31bf3c3..271295c 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_hget.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_hget.java
@@ -1,8 +1,8 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
 
 import java.util.List;
 
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_hegetall.java b/src/main/java/com/github/fppt/jedismock/operations/RO_hgetall.java
similarity index 72%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_hegetall.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_hgetall.java
index ab6f2b4..025298e 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_hegetall.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_hgetall.java
@@ -1,15 +1,15 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
 
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 
-public class RO_hegetall extends AbstractRedisOperation {
-    public RO_hegetall(RedisBase base, List<Slice> params) {
+public class RO_hgetall extends AbstractRedisOperation {
+    public RO_hgetall(RedisBase base, List<Slice> params) {
         super(base, params);
     }
 
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_hmget.java b/src/main/java/com/github/fppt/jedismock/operations/RO_hmget.java
similarity index 78%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_hmget.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_hmget.java
index 5e0b78b..116bf67 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_hmget.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_hmget.java
@@ -1,8 +1,8 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_hmset.java b/src/main/java/com/github/fppt/jedismock/operations/RO_hmset.java
similarity index 71%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_hmset.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_hmset.java
index ccef122..eef7708 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_hmset.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_hmset.java
@@ -1,8 +1,8 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
 
 import java.util.List;
 
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_hset.java b/src/main/java/com/github/fppt/jedismock/operations/RO_hset.java
similarity index 73%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_hset.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_hset.java
index e4d80f8..5d8fb8e 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_hset.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_hset.java
@@ -1,8 +1,8 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
 
 import java.util.List;
 
diff --git a/src/main/java/com/github/fppt/jedismock/operations/RO_hsetnx.java b/src/main/java/com/github/fppt/jedismock/operations/RO_hsetnx.java
new file mode 100644
index 0000000..ce5c546
--- /dev/null
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_hsetnx.java
@@ -0,0 +1,21 @@
+package com.github.fppt.jedismock.operations;
+
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
+
+import java.util.List;
+
+class RO_hsetnx extends AbstractRedisOperation {
+    RO_hsetnx(RedisBase base, List<Slice> params) {
+        super(base, params);
+    }
+
+    Slice response(){
+        if (base().getValue(params().get(0)) == null) {
+            base().putValue(params().get(0), params().get(1));
+            return Response.integer(1);
+        }
+        return Response.integer(0);
+    }
+}
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_incr.java b/src/main/java/com/github/fppt/jedismock/operations/RO_incr.java
similarity index 62%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_incr.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_incr.java
index 1fc4c8f..958ac37 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_incr.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_incr.java
@@ -1,7 +1,7 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
+import com.github.fppt.jedismock.server.Slice;
 
 import java.util.List;
 
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_incrOrDecrBy.java b/src/main/java/com/github/fppt/jedismock/operations/RO_incrOrDecrBy.java
similarity index 79%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_incrOrDecrBy.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_incrOrDecrBy.java
index 69b5884..54fb368 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_incrOrDecrBy.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_incrOrDecrBy.java
@@ -1,8 +1,8 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
 
 import java.util.List;
 
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_incrby.java b/src/main/java/com/github/fppt/jedismock/operations/RO_incrby.java
similarity index 70%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_incrby.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_incrby.java
index fc2cab3..8d1bad2 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_incrby.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_incrby.java
@@ -1,7 +1,7 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
+import com.github.fppt.jedismock.server.Slice;
 
 import java.util.List;
 
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_keys.java b/src/main/java/com/github/fppt/jedismock/operations/RO_keys.java
similarity index 87%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_keys.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_keys.java
index 712e654..ae5c912 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_keys.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_keys.java
@@ -1,8 +1,8 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_lindex.java b/src/main/java/com/github/fppt/jedismock/operations/RO_lindex.java
similarity index 81%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_lindex.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_lindex.java
index 2af5435..9b9e643 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_lindex.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_lindex.java
@@ -1,8 +1,8 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
 import com.google.common.collect.Lists;
 
 import java.util.LinkedList;
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_llen.java b/src/main/java/com/github/fppt/jedismock/operations/RO_llen.java
similarity index 68%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_llen.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_llen.java
index 5979a29..4dd3a34 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_llen.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_llen.java
@@ -1,8 +1,8 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
 import com.google.common.collect.Lists;
 
 import java.util.LinkedList;
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_lpop.java b/src/main/java/com/github/fppt/jedismock/operations/RO_lpop.java
similarity index 66%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_lpop.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_lpop.java
index 08cd62f..e78005d 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_lpop.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_lpop.java
@@ -1,7 +1,7 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
+import com.github.fppt.jedismock.server.Slice;
 
 import java.util.LinkedList;
 import java.util.List;
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_lpush.java b/src/main/java/com/github/fppt/jedismock/operations/RO_lpush.java
similarity index 75%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_lpush.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_lpush.java
index 23134ec..147cc9c 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_lpush.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_lpush.java
@@ -1,7 +1,7 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
+import com.github.fppt.jedismock.server.Slice;
 import com.google.common.collect.Lists;
 
 import java.util.LinkedList;
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_lpushx.java b/src/main/java/com/github/fppt/jedismock/operations/RO_lpushx.java
similarity index 65%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_lpushx.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_lpushx.java
index 42f7f98..c9a22a2 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_lpushx.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_lpushx.java
@@ -1,8 +1,8 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
 
 import java.util.List;
 
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_lrange.java b/src/main/java/com/github/fppt/jedismock/operations/RO_lrange.java
similarity index 85%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_lrange.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_lrange.java
index c5aacf4..f90635c 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_lrange.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_lrange.java
@@ -1,8 +1,8 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
 
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_lrem.java b/src/main/java/com/github/fppt/jedismock/operations/RO_lrem.java
similarity index 88%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_lrem.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_lrem.java
index 7b26795..6caefdc 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_lrem.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_lrem.java
@@ -1,8 +1,8 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
 
 import java.util.Iterator;
 import java.util.LinkedList;
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_mget.java b/src/main/java/com/github/fppt/jedismock/operations/RO_mget.java
similarity index 71%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_mget.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_mget.java
index c208c87..8148330 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_mget.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_mget.java
@@ -1,8 +1,8 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
 import com.google.common.collect.ImmutableList;
 
 import java.util.List;
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_mset.java b/src/main/java/com/github/fppt/jedismock/operations/RO_mset.java
similarity index 64%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_mset.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_mset.java
index 562a8d8..4601dca 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_mset.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_mset.java
@@ -1,8 +1,8 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
 
 import java.util.List;
 
diff --git a/src/main/java/com/github/fppt/jedismock/operations/RO_multi.java b/src/main/java/com/github/fppt/jedismock/operations/RO_multi.java
new file mode 100644
index 0000000..1b89ee7
--- /dev/null
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_multi.java
@@ -0,0 +1,19 @@
+package com.github.fppt.jedismock.operations;
+
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.OperationExecutorState;
+
+public class RO_multi implements RedisOperation {
+    private OperationExecutorState state;
+
+    RO_multi(OperationExecutorState state){
+        this.state = state;
+    }
+
+    @Override
+    public Slice execute() {
+        state.newTransaction();
+        return Response.OK;
+    }
+}
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_pexpire.java b/src/main/java/com/github/fppt/jedismock/operations/RO_pexpire.java
similarity index 69%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_pexpire.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_pexpire.java
index 78b506e..773acfe 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_pexpire.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_pexpire.java
@@ -1,8 +1,8 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
 
 import java.util.List;
 
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_pexpireat.java b/src/main/java/com/github/fppt/jedismock/operations/RO_pexpireat.java
similarity index 68%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_pexpireat.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_pexpireat.java
index a30a5f9..8c28b1c 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_pexpireat.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_pexpireat.java
@@ -1,8 +1,8 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
 
 import java.util.List;
 
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_pfadd.java b/src/main/java/com/github/fppt/jedismock/operations/RO_pfadd.java
similarity index 85%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_pfadd.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_pfadd.java
index 9c1e085..13bd42c 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_pfadd.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_pfadd.java
@@ -1,8 +1,8 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
 import com.google.common.collect.Sets;
 
 import java.util.List;
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_pfcount.java b/src/main/java/com/github/fppt/jedismock/operations/RO_pfcount.java
similarity index 77%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_pfcount.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_pfcount.java
index 8537ee3..06ca792 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_pfcount.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_pfcount.java
@@ -1,8 +1,8 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
 import com.google.common.collect.Sets;
 
 import java.util.List;
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_pfmerge.java b/src/main/java/com/github/fppt/jedismock/operations/RO_pfmerge.java
similarity index 85%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_pfmerge.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_pfmerge.java
index d440a5d..96b4cb2 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_pfmerge.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_pfmerge.java
@@ -1,8 +1,8 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
 import com.google.common.collect.Sets;
 
 import java.util.List;
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_ping.java b/src/main/java/com/github/fppt/jedismock/operations/RO_ping.java
similarity index 64%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_ping.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_ping.java
index a8b1c68..6a02266 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_ping.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_ping.java
@@ -1,8 +1,8 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
 
 import java.util.List;
 
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_pop.java b/src/main/java/com/github/fppt/jedismock/operations/RO_pop.java
similarity index 76%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_pop.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_pop.java
index 8d25024..22a23e0 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_pop.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_pop.java
@@ -1,8 +1,8 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
 
 import java.util.Collection;
 import java.util.List;
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_psetex.java b/src/main/java/com/github/fppt/jedismock/operations/RO_psetex.java
similarity index 69%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_psetex.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_psetex.java
index 94ebb34..2a23c38 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_psetex.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_psetex.java
@@ -1,7 +1,7 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
+import com.github.fppt.jedismock.server.Slice;
 
 import java.util.List;
 
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_pttl.java b/src/main/java/com/github/fppt/jedismock/operations/RO_pttl.java
similarity index 53%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_pttl.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_pttl.java
index 95735dd..42d04c1 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_pttl.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_pttl.java
@@ -1,8 +1,8 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
 
 import java.util.List;
 
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_publish.java b/src/main/java/com/github/fppt/jedismock/operations/RO_publish.java
similarity index 71%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_publish.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_publish.java
index 519c6e7..30c13cb 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_publish.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_publish.java
@@ -1,9 +1,9 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.RedisClient;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.server.RedisClient;
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
 
 import java.util.List;
 import java.util.Set;
diff --git a/src/main/java/com/github/fppt/jedismock/operations/RO_quit.java b/src/main/java/com/github/fppt/jedismock/operations/RO_quit.java
new file mode 100644
index 0000000..fa27df1
--- /dev/null
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_quit.java
@@ -0,0 +1,20 @@
+package com.github.fppt.jedismock.operations;
+
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.OperationExecutorState;
+
+public class RO_quit implements RedisOperation {
+    private OperationExecutorState state;
+
+    public RO_quit(OperationExecutorState state) {
+        this.state = state;
+    }
+
+    @Override
+    public Slice execute() {
+        state.owner().sendResponse(Response.clientResponse("quit", Response.OK), "quit");
+        state.owner().close();
+        return Response.SKIP;
+    }
+}
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_rpop.java b/src/main/java/com/github/fppt/jedismock/operations/RO_rpop.java
similarity index 66%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_rpop.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_rpop.java
index ca8d00c..9d5f3f4 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_rpop.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_rpop.java
@@ -1,7 +1,7 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
+import com.github.fppt.jedismock.server.Slice;
 
 import java.util.LinkedList;
 import java.util.List;
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_rpoplpush.java b/src/main/java/com/github/fppt/jedismock/operations/RO_rpoplpush.java
similarity index 76%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_rpoplpush.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_rpoplpush.java
index ce113ed..8d9ca8c 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_rpoplpush.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_rpoplpush.java
@@ -1,8 +1,8 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Slice;
-import com.github.fppt.jedismock.SliceParser;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.server.SliceParser;
+import com.github.fppt.jedismock.storage.RedisBase;
 
 import java.util.Arrays;
 import java.util.Collections;
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_rpush.java b/src/main/java/com/github/fppt/jedismock/operations/RO_rpush.java
similarity index 75%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_rpush.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_rpush.java
index 8483c3e..f29a256 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_rpush.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_rpush.java
@@ -1,7 +1,7 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
+import com.github.fppt.jedismock.server.Slice;
 import com.google.common.collect.Lists;
 
 import java.util.LinkedList;
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_sadd.java b/src/main/java/com/github/fppt/jedismock/operations/RO_sadd.java
similarity index 76%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_sadd.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_sadd.java
index 9b3b370..8aba14f 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_sadd.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_sadd.java
@@ -1,7 +1,7 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
+import com.github.fppt.jedismock.server.Slice;
 
 import java.util.HashSet;
 import java.util.List;
diff --git a/src/main/java/com/github/fppt/jedismock/operations/RO_select.java b/src/main/java/com/github/fppt/jedismock/operations/RO_select.java
new file mode 100644
index 0000000..bcd7572
--- /dev/null
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_select.java
@@ -0,0 +1,24 @@
+package com.github.fppt.jedismock.operations;
+
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.OperationExecutorState;
+
+import java.util.List;
+
+public class RO_select implements RedisOperation {
+    private OperationExecutorState state;
+    private List<Slice> params;
+
+    public RO_select(OperationExecutorState state, List<Slice> params){
+        this.params = params;
+        this.state = state;
+    }
+
+    @Override
+    public Slice execute() {
+        int selectedRedisBase = Integer.parseInt(new String(params.get(0).data()));
+        state.changeActiveRedisBase(selectedRedisBase);
+        return Response.OK;
+    }
+}
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_set.java b/src/main/java/com/github/fppt/jedismock/operations/RO_set.java
similarity index 58%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_set.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_set.java
index 0851248..37dad94 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_set.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_set.java
@@ -1,8 +1,8 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
 
 import java.util.List;
 
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_setbit.java b/src/main/java/com/github/fppt/jedismock/operations/RO_setbit.java
similarity index 89%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_setbit.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_setbit.java
index bd8ac0f..9acb852 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_setbit.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_setbit.java
@@ -1,8 +1,8 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
 
 import java.util.Arrays;
 import java.util.List;
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_setex.java b/src/main/java/com/github/fppt/jedismock/operations/RO_setex.java
similarity index 70%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_setex.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_setex.java
index dd12c1da5..b7ad3f6 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_setex.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_setex.java
@@ -1,8 +1,8 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
 
 import java.util.List;
 
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_setnx.java b/src/main/java/com/github/fppt/jedismock/operations/RO_setnx.java
similarity index 67%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_setnx.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_setnx.java
index 7488a10..2657410 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_setnx.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_setnx.java
@@ -1,8 +1,8 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
 
 import java.util.List;
 
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_sinter.java b/src/main/java/com/github/fppt/jedismock/operations/RO_sinter.java
similarity index 85%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_sinter.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_sinter.java
index 92e4644..8089aa3 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_sinter.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_sinter.java
@@ -1,8 +1,8 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Sets;
 
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_smembers.java b/src/main/java/com/github/fppt/jedismock/operations/RO_smembers.java
similarity index 82%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_smembers.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_smembers.java
index 54c2bce..e607eb9 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_smembers.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_smembers.java
@@ -1,8 +1,8 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
 
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_spop.java b/src/main/java/com/github/fppt/jedismock/operations/RO_spop.java
similarity index 72%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_spop.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_spop.java
index 6e5065a..eedd7c8 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_spop.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_spop.java
@@ -1,7 +1,7 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
+import com.github.fppt.jedismock.server.Slice;
 
 import java.util.Iterator;
 import java.util.List;
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_strlen.java b/src/main/java/com/github/fppt/jedismock/operations/RO_strlen.java
similarity index 65%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_strlen.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_strlen.java
index 0260c0c..af1cd85 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_strlen.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_strlen.java
@@ -1,8 +1,8 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
 
 import java.util.List;
 
diff --git a/src/main/java/com/github/fppt/jedismock/operations/RO_subscribe.java b/src/main/java/com/github/fppt/jedismock/operations/RO_subscribe.java
new file mode 100644
index 0000000..085a657
--- /dev/null
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_subscribe.java
@@ -0,0 +1,23 @@
+package com.github.fppt.jedismock.operations;
+
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.OperationExecutorState;
+
+import java.util.List;
+
+public class RO_subscribe extends AbstractRedisOperation {
+    private OperationExecutorState state;
+
+    public RO_subscribe(OperationExecutorState state, List<Slice> params) {
+        super(state.base(), params);
+        this.state = state;
+    }
+
+    Slice response() {
+        params().forEach(channel -> base().addSubscriber(channel, state.owner()));
+        List<Slice> numSubscriptions = base().getSubscriptions(state.owner());
+
+        return Response.subscribedToChannel(numSubscriptions);
+    }
+}
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_ttl.java b/src/main/java/com/github/fppt/jedismock/operations/RO_ttl.java
similarity index 72%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_ttl.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_ttl.java
index 34fe745..29667f7 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_ttl.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_ttl.java
@@ -1,8 +1,8 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
 
 import java.util.List;
 
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RO_unsubscribe.java b/src/main/java/com/github/fppt/jedismock/operations/RO_unsubscribe.java
similarity index 53%
rename from src/main/java/com/github/fppt/jedismock/commands/RO_unsubscribe.java
rename to src/main/java/com/github/fppt/jedismock/operations/RO_unsubscribe.java
index 8673de5..d36dd47 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RO_unsubscribe.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RO_unsubscribe.java
@@ -1,37 +1,36 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.RedisClient;
-import com.github.fppt.jedismock.Response;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.OperationExecutorState;
 import org.slf4j.LoggerFactory;
 
 import java.util.List;
 
-class RO_unsubscribe extends AbstractRedisOperation {
+public class RO_unsubscribe extends AbstractRedisOperation {
     private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(RO_unsubscribe.class);
-    private final RedisClient client;
+    private OperationExecutorState state;
 
-    RO_unsubscribe(RedisBase base, RedisClient client, List<Slice> params) {
-        super(base, params);
-        this.client = client;
+    public RO_unsubscribe(OperationExecutorState state, List<Slice> params) {
+        super(state.base(), params);
+        this.state = state;
     }
 
     Slice response() {
         List<Slice> channelsToUbsubscribeFrom;
         if(params().isEmpty()){
             LOG.debug("No channels specified therefore unsubscribing from all channels");
-            channelsToUbsubscribeFrom = base().getSubscriptions(client);
+            channelsToUbsubscribeFrom = base().getSubscriptions(state.owner());
         } else {
             channelsToUbsubscribeFrom = params();
         }
 
         for (Slice channel : channelsToUbsubscribeFrom) {
             LOG.debug("Unsubscribing from channel [" + channel + "]");
-            if(base().removeSubscriber(channel, client)) {
-                int numSubscriptions = base().getSubscriptions(client).size();
+            if(base().removeSubscriber(channel, state.owner())) {
+                int numSubscriptions = base().getSubscriptions(state.owner()).size();
                 Slice response = Response.unsubscribe(channel, numSubscriptions);
-                client.sendResponse(Response.clientResponse("unsubscribe", response), "unsubscribe");
+                state.owner().sendResponse(Response.clientResponse("unsubscribe", response), "unsubscribe");
             }
         }
 
diff --git a/src/main/java/com/github/fppt/jedismock/commands/RedisOperation.java b/src/main/java/com/github/fppt/jedismock/operations/RedisOperation.java
similarity index 50%
rename from src/main/java/com/github/fppt/jedismock/commands/RedisOperation.java
rename to src/main/java/com/github/fppt/jedismock/operations/RedisOperation.java
index 5a10325..cd8345e 100644
--- a/src/main/java/com/github/fppt/jedismock/commands/RedisOperation.java
+++ b/src/main/java/com/github/fppt/jedismock/operations/RedisOperation.java
@@ -1,7 +1,7 @@
-package com.github.fppt.jedismock.commands;
+package com.github.fppt.jedismock.operations;
 
-import com.github.fppt.jedismock.RedisBase;
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.storage.RedisBase;
+import com.github.fppt.jedismock.server.Slice;
 
 /**
  * Represents a Redis Operation which can be executed against {@link RedisBase}
diff --git a/src/main/java/com/github/fppt/jedismock/RedisClient.java b/src/main/java/com/github/fppt/jedismock/server/RedisClient.java
similarity index 86%
rename from src/main/java/com/github/fppt/jedismock/RedisClient.java
rename to src/main/java/com/github/fppt/jedismock/server/RedisClient.java
index b01f925..0e32fca 100644
--- a/src/main/java/com/github/fppt/jedismock/RedisClient.java
+++ b/src/main/java/com/github/fppt/jedismock/server/RedisClient.java
@@ -1,6 +1,10 @@
-package com.github.fppt.jedismock;
+package com.github.fppt.jedismock.server;
 
-import com.github.fppt.jedismock.commands.RedisOperationExecutor;
+import com.github.fppt.jedismock.storage.OperationExecutorState;
+import com.github.fppt.jedismock.storage.RedisBase;
+import com.github.fppt.jedismock.commands.RedisCommand;
+import com.github.fppt.jedismock.commands.RedisCommandParser;
+import com.github.fppt.jedismock.Utils;
 import com.github.fppt.jedismock.exception.ParseErrorException;
 import com.google.common.base.Preconditions;
 import org.slf4j.LoggerFactory;
@@ -32,7 +36,8 @@ public class RedisClient implements Runnable {
         Preconditions.checkNotNull(socket);
         Preconditions.checkNotNull(options);
 
-        this.executor = new RedisOperationExecutor(redisBases, this);
+        OperationExecutorState state = new OperationExecutorState(this, redisBases);
+        this.executor = new RedisOperationExecutor(state);
         this.socket = socket;
         this.options = options;
         this.in = socket.getInputStream();
diff --git a/src/main/java/com/github/fppt/jedismock/server/RedisOperationExecutor.java b/src/main/java/com/github/fppt/jedismock/server/RedisOperationExecutor.java
new file mode 100644
index 0000000..203d6a8
--- /dev/null
+++ b/src/main/java/com/github/fppt/jedismock/server/RedisOperationExecutor.java
@@ -0,0 +1,52 @@
+package com.github.fppt.jedismock.server;
+
+import com.github.fppt.jedismock.commands.RedisCommand;
+import com.github.fppt.jedismock.exception.WrongValueTypeException;
+import com.github.fppt.jedismock.operations.OperationFactory;
+import com.github.fppt.jedismock.operations.RedisOperation;
+import com.github.fppt.jedismock.storage.OperationExecutorState;
+import com.google.common.base.Preconditions;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * Created by Xiaolu on 2015/4/20.
+ */
+public class RedisOperationExecutor {
+    private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(RedisOperationExecutor.class);
+    private final OperationExecutorState state;
+
+    public RedisOperationExecutor(OperationExecutorState state) {
+        this.state = state;
+    }
+
+
+    public synchronized Slice execCommand(RedisCommand command) {
+        Preconditions.checkArgument(command.parameters().size() > 0);
+        List<Slice> params = command.parameters();
+        List<Slice> commandParams = params.subList(1, params.size());
+        String name = new String(params.get(0).data()).toLowerCase();
+
+        try {
+            //Checking if we are affecting the server or client state.
+            //This is done outside the context of a transaction which is why it's a separate check
+            Optional<RedisOperation> result = OperationFactory.buildMetaOperation(name, state, commandParams);
+            if(result.isPresent()) return result.get().execute();
+
+            //Checking if we mutating the transaction or the redisBases
+            RedisOperation redisOperation = OperationFactory.buildTxOperation(state.base(), name, commandParams);
+            if(state.isTransactionModeOn()){
+                state.tx().add(redisOperation);
+            } else {
+                return Response.clientResponse(name, redisOperation.execute());
+            }
+
+            return Response.clientResponse(name, Response.OK);
+        } catch(UnsupportedOperationException | WrongValueTypeException | IllegalArgumentException e){
+            LOG.error("Malformed request", e);
+            return Response.error(e.getMessage());
+        }
+    }
+}
diff --git a/src/main/java/com/github/fppt/jedismock/RedisService.java b/src/main/java/com/github/fppt/jedismock/server/RedisService.java
similarity index 91%
rename from src/main/java/com/github/fppt/jedismock/RedisService.java
rename to src/main/java/com/github/fppt/jedismock/server/RedisService.java
index 7e67af4..1e3b30d 100644
--- a/src/main/java/com/github/fppt/jedismock/RedisService.java
+++ b/src/main/java/com/github/fppt/jedismock/server/RedisService.java
@@ -1,5 +1,6 @@
-package com.github.fppt.jedismock;
+package com.github.fppt.jedismock.server;
 
+import com.github.fppt.jedismock.storage.RedisBase;
 import com.google.common.base.Preconditions;
 
 import java.io.IOException;
diff --git a/src/main/java/com/github/fppt/jedismock/Response.java b/src/main/java/com/github/fppt/jedismock/server/Response.java
similarity index 98%
rename from src/main/java/com/github/fppt/jedismock/Response.java
rename to src/main/java/com/github/fppt/jedismock/server/Response.java
index fc23f4b..2a820c4 100644
--- a/src/main/java/com/github/fppt/jedismock/Response.java
+++ b/src/main/java/com/github/fppt/jedismock/server/Response.java
@@ -1,4 +1,4 @@
-package com.github.fppt.jedismock;
+package com.github.fppt.jedismock.server;
 
 import com.google.common.io.ByteArrayDataOutput;
 import com.google.common.io.ByteStreams;
diff --git a/src/main/java/com/github/fppt/jedismock/ServiceOptions.java b/src/main/java/com/github/fppt/jedismock/server/ServiceOptions.java
similarity index 90%
rename from src/main/java/com/github/fppt/jedismock/ServiceOptions.java
rename to src/main/java/com/github/fppt/jedismock/server/ServiceOptions.java
index a8da0ab..67fabd6 100644
--- a/src/main/java/com/github/fppt/jedismock/ServiceOptions.java
+++ b/src/main/java/com/github/fppt/jedismock/server/ServiceOptions.java
@@ -1,4 +1,4 @@
-package com.github.fppt.jedismock;
+package com.github.fppt.jedismock.server;
 
 import com.google.auto.value.AutoValue;
 
diff --git a/src/main/java/com/github/fppt/jedismock/Slice.java b/src/main/java/com/github/fppt/jedismock/server/Slice.java
similarity index 97%
rename from src/main/java/com/github/fppt/jedismock/Slice.java
rename to src/main/java/com/github/fppt/jedismock/server/Slice.java
index 969b527..6161963 100644
--- a/src/main/java/com/github/fppt/jedismock/Slice.java
+++ b/src/main/java/com/github/fppt/jedismock/server/Slice.java
@@ -1,4 +1,4 @@
-package com.github.fppt.jedismock;
+package com.github.fppt.jedismock.server;
 
 import com.google.auto.value.AutoValue;
 
diff --git a/src/main/java/com/github/fppt/jedismock/SliceParser.java b/src/main/java/com/github/fppt/jedismock/server/SliceParser.java
similarity index 98%
rename from src/main/java/com/github/fppt/jedismock/SliceParser.java
rename to src/main/java/com/github/fppt/jedismock/server/SliceParser.java
index fcaa96e..8d6e33f 100644
--- a/src/main/java/com/github/fppt/jedismock/SliceParser.java
+++ b/src/main/java/com/github/fppt/jedismock/server/SliceParser.java
@@ -1,4 +1,4 @@
-package com.github.fppt.jedismock;
+package com.github.fppt.jedismock.server;
 
 import com.github.fppt.jedismock.exception.EOFException;
 import com.github.fppt.jedismock.exception.ParseErrorException;
diff --git a/src/main/java/com/github/fppt/jedismock/storage/ExpiringKeyValueStorage.java b/src/main/java/com/github/fppt/jedismock/storage/ExpiringKeyValueStorage.java
index 44de6d6..12d2fc2 100644
--- a/src/main/java/com/github/fppt/jedismock/storage/ExpiringKeyValueStorage.java
+++ b/src/main/java/com/github/fppt/jedismock/storage/ExpiringKeyValueStorage.java
@@ -1,6 +1,6 @@
 package com.github.fppt.jedismock.storage;
 
-import com.github.fppt.jedismock.Slice;
+import com.github.fppt.jedismock.server.Slice;
 import com.google.auto.value.AutoValue;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.HashBasedTable;
diff --git a/src/main/java/com/github/fppt/jedismock/storage/OperationExecutorState.java b/src/main/java/com/github/fppt/jedismock/storage/OperationExecutorState.java
new file mode 100644
index 0000000..7eb554e
--- /dev/null
+++ b/src/main/java/com/github/fppt/jedismock/storage/OperationExecutorState.java
@@ -0,0 +1,51 @@
+package com.github.fppt.jedismock.storage;
+
+import com.github.fppt.jedismock.operations.RedisOperation;
+import com.github.fppt.jedismock.server.RedisClient;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+public class OperationExecutorState {
+    private final RedisClient owner;
+    private final Map<Integer, RedisBase> redisBases;
+    private AtomicBoolean isTransactionModeOn = new AtomicBoolean(false);
+    private List<RedisOperation> tx = new ArrayList<>();
+    private int selectedRedisBase = 0;
+
+    public OperationExecutorState(RedisClient owner, Map<Integer, RedisBase> redisBases){
+        this.owner = owner;
+        this.redisBases = redisBases;
+    }
+
+    public RedisBase base(){
+        return redisBases.computeIfAbsent(selectedRedisBase, key -> new RedisBase());
+    }
+
+    public RedisClient owner(){
+        return owner;
+    }
+
+    public List<RedisOperation> tx(){
+        return tx;
+    }
+
+    public void changeActiveRedisBase(int selectedRedisBase) {
+        this.selectedRedisBase = selectedRedisBase;
+    }
+
+    public void transactionMode(boolean isTransactionModeOn){
+        this.isTransactionModeOn.set(isTransactionModeOn);
+    }
+
+    public boolean isTransactionModeOn(){
+        return isTransactionModeOn.get();
+    }
+
+    public void newTransaction(){
+        if(isTransactionModeOn.get()) throw new RuntimeException("Redis mock does not support more than one transaction");
+        transactionMode(true);
+    }
+}
diff --git a/src/main/java/com/github/fppt/jedismock/RedisBase.java b/src/main/java/com/github/fppt/jedismock/storage/RedisBase.java
similarity index 91%
rename from src/main/java/com/github/fppt/jedismock/RedisBase.java
rename to src/main/java/com/github/fppt/jedismock/storage/RedisBase.java
index defaefb..ef094ca 100644
--- a/src/main/java/com/github/fppt/jedismock/RedisBase.java
+++ b/src/main/java/com/github/fppt/jedismock/storage/RedisBase.java
@@ -1,6 +1,7 @@
-package com.github.fppt.jedismock;
+package com.github.fppt.jedismock.storage;
 
-import com.github.fppt.jedismock.storage.ExpiringKeyValueStorage;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.server.RedisClient;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -40,13 +41,11 @@ public class RedisBase {
     }
 
     public long setTTL(Slice key, long ttl) {
-        long result = keyValueStorage.setTTL(key, ttl);
-        return result;
+        return keyValueStorage.setTTL(key, ttl);
     }
 
     public long setDeadline(Slice key, long deadline) {
-        long result = keyValueStorage.setDeadline(key, deadline);
-        return result;
+        return keyValueStorage.setDeadline(key, deadline);
     }
 
     public void clear(){


Test patch:
diff --git a/src/test/java/com/github/fppt/jedismock/TestCommandParser.java b/src/test/java/com/github/fppt/jedismock/TestCommandParser.java
index ee96fa9..8ce1fc0 100644
--- a/src/test/java/com/github/fppt/jedismock/TestCommandParser.java
+++ b/src/test/java/com/github/fppt/jedismock/TestCommandParser.java
@@ -1,7 +1,10 @@
 package com.github.fppt.jedismock;
 
+import com.github.fppt.jedismock.commands.RedisCommand;
+import com.github.fppt.jedismock.commands.RedisCommandParser;
 import com.github.fppt.jedismock.exception.EOFException;
 import com.github.fppt.jedismock.exception.ParseErrorException;
+import com.github.fppt.jedismock.server.SliceParser;
 import org.junit.Test;
 
 import java.io.ByteArrayInputStream;
diff --git a/src/test/java/com/github/fppt/jedismock/TestRedisOperationExecutor.java b/src/test/java/com/github/fppt/jedismock/TestRedisOperationExecutor.java
index 2ac2ad8..32b0337 100644
--- a/src/test/java/com/github/fppt/jedismock/TestRedisOperationExecutor.java
+++ b/src/test/java/com/github/fppt/jedismock/TestRedisOperationExecutor.java
@@ -1,8 +1,13 @@
 package com.github.fppt.jedismock;
 
-import com.github.fppt.jedismock.commands.RedisOperationExecutor;
+import com.github.fppt.jedismock.commands.RedisCommandParser;
+import com.github.fppt.jedismock.server.RedisOperationExecutor;
 import com.github.fppt.jedismock.exception.EOFException;
 import com.github.fppt.jedismock.exception.ParseErrorException;
+import com.github.fppt.jedismock.server.Response;
+import com.github.fppt.jedismock.server.Slice;
+import com.github.fppt.jedismock.storage.OperationExecutorState;
+import com.github.fppt.jedismock.storage.RedisBase;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -62,7 +67,8 @@ public class TestRedisOperationExecutor {
         //TODO: Mock out the client here
         Map<Integer, RedisBase> redisBases = new HashMap<>();
         redisBases.put(0, new RedisBase());
-        executor = new RedisOperationExecutor(redisBases, null);
+        OperationExecutorState state = new OperationExecutorState(null, redisBases);
+        executor = new RedisOperationExecutor(state);
     }
 
     @Test
diff --git a/src/test/java/com/github/fppt/jedismock/TestRedisServer.java b/src/test/java/com/github/fppt/jedismock/TestRedisServer.java
index 6b9c7cc..068f4c8 100644
--- a/src/test/java/com/github/fppt/jedismock/TestRedisServer.java
+++ b/src/test/java/com/github/fppt/jedismock/TestRedisServer.java
@@ -1,5 +1,6 @@
 package com.github.fppt.jedismock;
 
+import com.github.fppt.jedismock.server.ServiceOptions;
 import org.junit.Test;
 import redis.clients.jedis.Jedis;
 import redis.clients.jedis.exceptions.JedisConnectionException;
diff --git a/src/test/java/com/github/fppt/jedismock/TestUtils.java b/src/test/java/com/github/fppt/jedismock/TestUtils.java
index 46f9f19..b41bc66 100644
--- a/src/test/java/com/github/fppt/jedismock/TestUtils.java
+++ b/src/test/java/com/github/fppt/jedismock/TestUtils.java
@@ -1,5 +1,6 @@
 package com.github.fppt.jedismock;
 
+import com.github.fppt.jedismock.server.Slice;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;