Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] KevaQL #51

Draft
wants to merge 13 commits into
base: develop
Choose a base branch
from
3 changes: 3 additions & 0 deletions server/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ dependencies {
implementation 'com.google.guava:guava:31.0.1-jre'
implementation 'org.reflections:reflections:0.10.1'

implementation 'com.github.jsqlparser:jsqlparser:3.2'
implementation 'org.apache.commons:commons-lang3:3.0'

// Experimental
implementation files('libs/keva-ioc-0.1.0-SNAPSHOT.jar')

Expand Down
98 changes: 98 additions & 0 deletions server/src/main/java/dev/keva/server/command/impl/kql/Kql.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package dev.keva.server.command.impl.kql;

import dev.keva.ioc.annotation.Autowired;
import dev.keva.ioc.annotation.Component;
import dev.keva.protocol.resp.reply.*;
import dev.keva.server.command.annotation.CommandImpl;
import dev.keva.server.command.annotation.Execute;
import dev.keva.server.command.annotation.ParamLength;
import dev.keva.server.command.impl.kql.manager.KqlManager;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.create.table.CreateTable;
import net.sf.jsqlparser.statement.delete.Delete;
import net.sf.jsqlparser.statement.drop.Drop;
import net.sf.jsqlparser.statement.insert.Insert;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.statement.update.Update;

import java.util.List;

@Component
@CommandImpl("kql")
@ParamLength(1)
public class Kql {
private final KqlManager kqlManager;

@Autowired
public Kql(KqlManager kqlManager) {
this.kqlManager = kqlManager;
}

@Execute
public Reply<?> execute(byte[] sqlBytes) {
String sql = new String(sqlBytes);
Statement stmt;
try {
stmt = kqlManager.parse(sql);
} catch (JSQLParserException e) {
return new ErrorReply("ERR " + e.getMessage());
}
if (stmt instanceof CreateTable) {
kqlManager.create(stmt);
Reply<?>[] replies = new Reply[2];
replies[0] = new StatusReply("DONE");
replies[1] = new IntegerReply(0);
return new MultiBulkReply(replies);
} else if (stmt instanceof Drop) {
kqlManager.drop(stmt);
Reply<?>[] replies = new Reply[2];
replies[0] = new StatusReply("DONE");
replies[1] = new IntegerReply(0);
return new MultiBulkReply(replies);
} else if (stmt instanceof Insert) {
kqlManager.insert(stmt);
Reply<?>[] replies = new Reply[2];
replies[0] = new StatusReply("DONE");
replies[1] = new IntegerReply(1);
return new MultiBulkReply(replies);
} else if (stmt instanceof Update) {
int numOfUpdated = kqlManager.update(stmt);
Reply<?>[] replies = new Reply[2];
replies[0] = new StatusReply("DONE");
replies[1] = new IntegerReply(numOfUpdated);
return new MultiBulkReply(replies);
} else if (stmt instanceof Delete) {
int numOfDeleted = kqlManager.delete(stmt);
Reply<?>[] replies = new Reply[2];
replies[0] = new StatusReply("DONE");
replies[1] = new IntegerReply(numOfDeleted);
return new MultiBulkReply(replies);
} else if (stmt instanceof Select) {
List<List<Object>> result = kqlManager.select(stmt);
Reply<?>[] rowReplies = new Reply[result.size()];
for (int i = 0; i < result.size(); i++) {
Reply<?>[] columnReplies = new Reply[result.get(i).size()];
for (int j = 0; j < result.get(i).size(); j++) {
if (result.get(i).get(j) instanceof String) {
columnReplies[j] = new BulkReply((String) result.get(i).get(j));
} else if (result.get(i).get(j) instanceof Integer) {
columnReplies[j] = new IntegerReply((Integer) result.get(i).get(j));
} else if (result.get(i).get(j) instanceof Long) {
columnReplies[j] = new IntegerReply((Long) result.get(i).get(j));
} else if (result.get(i).get(j) instanceof Double) {
columnReplies[j] = new BulkReply(result.get(i).get(j).toString());
} else if (result.get(i).get(j) instanceof Boolean) {
columnReplies[j] = new IntegerReply((Boolean) result.get(i).get(j) ? 1 : 0);
} else if (result.get(i).get(j) == null) {
columnReplies[j] = BulkReply.NIL_REPLY;
}
}
rowReplies[i] = new MultiBulkReply(columnReplies);
}
return new MultiBulkReply(rowReplies);
} else {
return new ErrorReply("ERR unsupported statement");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package dev.keva.server.command.impl.kql.manager;

import lombok.AllArgsConstructor;

import java.io.Serializable;

@AllArgsConstructor
public class KevaColumnDefinition implements Serializable {
public String name;
public String type;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package dev.keva.server.command.impl.kql.manager;

import java.util.List;

public class KevaColumnFinder {
public static int findColumn(String columnName, List<KevaColumnDefinition> kevaColumns) {
for (int i = 0; i < kevaColumns.size(); i++) {
KevaColumnDefinition kevaColumn = kevaColumns.get(i);
if (kevaColumn.name.equals(columnName)) {
return i;
}
}
return -1;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package dev.keva.server.command.impl.kql.manager;

public class KevaSQLConvertUtil {
public static Object convertToRowData(String type, String value) {
value = KevaSQLStringUtil.escape(value);
if (value.equalsIgnoreCase("null")) {
return null;
}
if (type.equals("CHAR") || type.equals("VARCHAR") || type.equals("TEXT")) {
return value;
} else if (type.equals("INT") || type.equals("INTEGER")) {
return Integer.parseInt(value);
} else if (type.equals("BIGINT")) {
return Long.parseLong(value);
} else if (type.equals("DOUBLE")) {
return Double.parseDouble(value);
} else if (type.equals("FLOAT")) {
return Float.parseFloat(value);
} else if (type.equals("BOOL") || type.equals("BOOLEAN")) {
return Boolean.parseBoolean(value);
} else {
throw new KevaSQLException("unknown type: " + type);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package dev.keva.server.command.impl.kql.manager;

public class KevaSQLException extends RuntimeException {
public KevaSQLException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package dev.keva.server.command.impl.kql.manager;

import java.util.Collections;
import java.util.List;

public class KevaSQLResponseUtil {
public static List<List<Object>> singleSelectResponse(Object object) {
return Collections.singletonList(Collections.singletonList(object));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package dev.keva.server.command.impl.kql.manager;

public class KevaSQLStringUtil {
public static String escape(String str) {
if (str.startsWith("'") && str.endsWith("'")) {
return str.replaceAll("^.|.$", "");
}
return str;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package dev.keva.server.command.impl.kql.manager;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

import java.io.Serializable;
import java.util.List;

@RequiredArgsConstructor
public class KevaTable implements Serializable {
@Getter
private final List<KevaColumnDefinition> columns;

@Getter
private long increment = 1;

public void increment() {
increment++;
}
}
Loading