I am building a mini SQL parser that reads and converts SELECT, INSERT, UPDATE and DELETE statements into an AST. My current design is as follows:
Statement.java:
public interface Statement {
String getOperation();
String getTable();
Map<String, Object> getColumns();
String getConditions();
}
Select.java, Insert.java, Update.java and Delete.java are all POJO's that implement this interface, with varying attributes (for example, different toString()
implementations). I have a separate utility class that defines a method called parse(String query)
as follows:
public Statement parse(String query) {
String operation = getOperation(query);
if (operation.equals("insert")) {
String table = getTable();
Map<String, Object> keyValues = getColumns();
return new InsertStatement(table, keyValues);
} else if ...
}
I'm wondering if it makes sense to have a separate utility class for defining the parse
method or if it may be a better idea to change Statement
to an abstract
class and move the parse
method inside it. That way, someone could call Statement.parse("INSERT INTO ...")
and get an InsertStatement
object back:
public abstract class Statement {
String getOperation();
String getTable();
Map<String, Object> getColumns();
String getConditions();
public Statement parse(String query) {
String operation = getOperation(query);
if (operation.equals("insert")) {
return parseInsert(query);
} else if ...
}
private InsertStatement parseInsert(String query) {
// parse and return InsertStatement instance
}
}
Is there a general good practice recommended here?
-
2It'd be better to model your hierarchy akin to some EBNF of the language you're looking to parse.Telastyn– Telastyn2020年03月22日 23:48:39 +00:00Commented Mar 22, 2020 at 23:48
-
1I would use interface to transfer any data from inside to outside world, however this has nothing to do with parsing, this is how I write code and I believe how it should be written.greenoldman– greenoldman2020年03月23日 06:05:30 +00:00Commented Mar 23, 2020 at 6:05
2 Answers 2
Foreword: I hope you are not serious. If you really want to create an AST for a complex language, get a good grip on some tool (e.g. ANTLR) and use this tool. Don't do it manually, don't go in this direction. Now, assuming that you do it just for fun, the rest of the answer:
Your utility class right now is basically a factory, which creates different things (statements) which have something in common (being types of statements) according to some business object passed from the outside (the sql string).
So the question boils down to: should I have my factory in a common abstract base class?
There are pros and cons here. For some real big factory-code (which your parser will be in the end) I'd go for a separate parser class/package. If you like, you can still add a method in your abstract base class, which utilizes that parser internally.
Why not this? http://www.sqlparser.com/sql-parser-java.php
You are embarking on a very complex undertaking that has already been well-done, many times, for many programming languages There is no point in doing it again.
Actum Ne Agas: Do Not Do A Thing Already Done.TM