diff --git a/.classpath b/.classpath
new file mode 100644
index 00000000..962da8d7
--- /dev/null
+++ b/.classpath
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..357db2cf
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,7 @@
+/bin/
+/target/
+**/*.md.html
+**/*.bak
+**/*.swp
+**/*.log
+**/*.out
\ No newline at end of file
diff --git a/.project b/.project
new file mode 100644
index 00000000..547c8446
--- /dev/null
+++ b/.project
@@ -0,0 +1,18 @@
+
+
+ sql-statement-builder
+ This module provides a Builder for SQL statements that helps creating the correct structure and validates variable parts of the statements. NO_M2ECLIPSE_SUPPORT: Project files created with the maven-eclipse-plugin are not supported in M2Eclipse.
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+ org.eclipse.m2e.core.maven2Builder
+
+
+
+ org.eclipse.jdt.core.javanature
+ org.eclipse.m2e.core.maven2Nature
+
+
\ No newline at end of file
diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 00000000..f9fe3459
--- /dev/null
+++ b/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,4 @@
+eclipse.preferences.version=1
+encoding//src/main/java=UTF-8
+encoding//src/test/java=UTF-8
+encoding/=UTF-8
diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000..b8947ec6
--- /dev/null
+++ b/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,6 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.release=disabled
+org.eclipse.jdt.core.compiler.source=1.8
diff --git a/README.md b/README.md
index 3ae35b3a..aa1b2e0c 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,32 @@
-# sql-statement-builder
\ No newline at end of file
+# sql-statement-builder
+
+## Usage
+
+```java
+SqlStatement statement = StatementFactory.getInstance().select().all().from("foo.bar");
+
+SqlStatement statement = StatementFactory.getInstance()
+ .select()
+ .field("name")
+ .from("bar")
+ .join("zoo").on("zoo.bar_id").eq("bar.id")
+
+
+
+```
+
+## Development
+
+The following sub-sections provide information about building and extending the project.
+
+### Build Time Dependencies
+
+The list below show all build time dependencies in alphabetical order. Note that except the Maven build tool all required modules are downloaded automatically by Maven.
+
+| Dependency | Purpose | License |
+------------------------------------------------------------|--------------------------------------------------------|--------------------------------
+| [Apache Maven](https://maven.apache.org/) | Build tool | Apache License 2.0 |
+| [Equals Verifier](https://github.com/jqno/equalsverifier) | Automatic contract checker for `equals()` and `hash()` | Apache License 2.0 |
+| [Hamcrest](http://hamcrest.org/) | Advanced matchers for JUnit | GNU BSD-3-Clause |
+| [JUnit 5](https://junit.org/junit5/) | Unit testing framework | Eclipse Public License 1.0 |
+| [Mockito](http://site.mockito.org/) | Mocking framework | MIT License |
\ No newline at end of file
diff --git a/doc/system_requirements.md b/doc/system_requirements.md
new file mode 100644
index 00000000..ae4b6d15
--- /dev/null
+++ b/doc/system_requirements.md
@@ -0,0 +1,2 @@
+* Upper case / lower case
+* One line / pretty
\ No newline at end of file
diff --git a/launch/sql-statment-builder all tests.launch b/launch/sql-statment-builder all tests.launch
new file mode 100644
index 00000000..c0bc8ef8
--- /dev/null
+++ b/launch/sql-statment-builder all tests.launch
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/model/diagrams/cl_fragments.plantuml b/model/diagrams/cl_fragments.plantuml
new file mode 100644
index 00000000..40121cca
--- /dev/null
+++ b/model/diagrams/cl_fragments.plantuml
@@ -0,0 +1,17 @@
+@startuml
+hide empty methods
+hide empty attributes
+skinparam style strictuml
+!pragma horizontalLineBetweenDifferentPackageAllowed
+
+interface Fragment <>
+interface FieldDefinition <>
+class Select
+class Field
+
+FieldDefinition -u-> Fragment
+Field "1..*" -l-> Select : parent
+
+Field -u-> FieldDefinition
+Select -u-> Fragment
+@enduml
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 00000000..ae43a0e6
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,53 @@
+
+ 4.0.0
+ sql-statement-builder
+ sql-statement-builder
+ 0.1.0
+ Exasol SQL Statement Builder
+ This module provides a Builder for SQL statements that helps creating the correct structure and validates variable parts of the statements.
+
+ UTF-8
+ 1.8
+ 5.3.1
+ 1.3.1
+
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ ${junit.version}
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ ${junit.version}
+ test
+
+
+ org.hamcrest
+ hamcrest-core
+ 1.3
+ test
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.8.0
+
+ ${java.version}
+ ${java.version}
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 2.22.0
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/com/exasol/sql/AbstractFragement.java b/src/main/java/com/exasol/sql/AbstractFragement.java
new file mode 100644
index 00000000..d6b368ae
--- /dev/null
+++ b/src/main/java/com/exasol/sql/AbstractFragement.java
@@ -0,0 +1,63 @@
+package com.exasol.sql;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class provides an abstract base for SQL statement fragments. It also
+ * keeps track of the relationships to other fragments.
+ *
+ * @param the type of the concrete class implementing the missing parts.
+ */
+public abstract class AbstractFragement implements Fragment {
+ private final Fragment root;
+ protected final Fragment parent;
+ protected final List children = new ArrayList<>();
+
+ protected AbstractFragement(final Fragment parent) {
+ if (parent == null) {
+ this.root = this;
+ } else {
+ this.root = parent.getRoot();
+ }
+ this.parent = parent;
+ }
+
+ @Override
+ public Fragment getRoot() {
+ return this.root;
+ }
+
+ @Override
+ public Fragment getParent() {
+ return this.parent;
+ }
+
+ protected void addChild(final Fragment child) {
+ this.children.add(child);
+ }
+
+ protected List getChildren() {
+ return this.children;
+ }
+
+ @Override
+ public Fragment getChild(final int index) {
+ return this.children.get(index);
+ }
+
+ @Override
+ public boolean isFirstSibling() {
+ return (this.parent != null) && (this.getParent().getChild(0) == this);
+ }
+
+ @Override
+ public void accept(final FragmentVisitor visitor) {
+ acceptConcrete(visitor);
+ for (final Fragment child : getChildren()) {
+ child.accept(visitor);
+ }
+ }
+
+ protected abstract void acceptConcrete(final FragmentVisitor visitor);
+}
\ No newline at end of file
diff --git a/src/main/java/com/exasol/sql/Fragment.java b/src/main/java/com/exasol/sql/Fragment.java
new file mode 100644
index 00000000..77544c93
--- /dev/null
+++ b/src/main/java/com/exasol/sql/Fragment.java
@@ -0,0 +1,24 @@
+package com.exasol.sql;
+
+public interface Fragment {
+ @Override
+ public String toString();
+
+ public Fragment getParent();
+
+ public void accept(FragmentVisitor visitor);
+
+ public Fragment getRoot();
+
+ public boolean isFirstSibling();
+
+ /**
+ * Get child at index position
+ *
+ * @param index position of the child
+ * @return child at index
+ * @throws IndexOutOfBoundsException if the index is out of range (index < 0 ||
+ * index >= size())
+ */
+ public Fragment getChild(int index) throws IndexOutOfBoundsException;
+}
diff --git a/src/main/java/com/exasol/sql/FragmentVisitor.java b/src/main/java/com/exasol/sql/FragmentVisitor.java
new file mode 100644
index 00000000..f73b140e
--- /dev/null
+++ b/src/main/java/com/exasol/sql/FragmentVisitor.java
@@ -0,0 +1,14 @@
+package com.exasol.sql;
+
+import com.exasol.sql.dql.*;
+
+/**
+ * This interface represents a visitor for SQL statement fragments.
+ */
+public interface FragmentVisitor {
+ public void visit(final Select select);
+
+ public void visit(final Field field);
+
+ public void visit(final TableExpression tableExpression);
+}
\ No newline at end of file
diff --git a/src/main/java/com/exasol/sql/SqlStatement.java b/src/main/java/com/exasol/sql/SqlStatement.java
new file mode 100644
index 00000000..bdbceaf6
--- /dev/null
+++ b/src/main/java/com/exasol/sql/SqlStatement.java
@@ -0,0 +1,8 @@
+package com.exasol.sql;
+
+/**
+ * This interface represents an SQL statement.
+ */
+public interface SqlStatement extends Fragment {
+
+}
diff --git a/src/main/java/com/exasol/sql/dql/Field.java b/src/main/java/com/exasol/sql/dql/Field.java
new file mode 100644
index 00000000..b10ac338
--- /dev/null
+++ b/src/main/java/com/exasol/sql/dql/Field.java
@@ -0,0 +1,25 @@
+package com.exasol.sql.dql;
+
+import com.exasol.sql.*;
+
+public class Field extends AbstractFragement implements FieldDefinition {
+ private final String name;
+
+ protected Field(final Fragment parent, final String name) {
+ super(parent);
+ this.name = name;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public static Field all(final Fragment parent) {
+ return new Field(parent, "*");
+ }
+
+ @Override
+ protected void acceptConcrete(final FragmentVisitor visitor) {
+ visitor.visit(this);
+ }
+}
diff --git a/src/main/java/com/exasol/sql/dql/FieldDefinition.java b/src/main/java/com/exasol/sql/dql/FieldDefinition.java
new file mode 100644
index 00000000..be560c0a
--- /dev/null
+++ b/src/main/java/com/exasol/sql/dql/FieldDefinition.java
@@ -0,0 +1,7 @@
+package com.exasol.sql.dql;
+
+import com.exasol.sql.Fragment;
+
+public interface FieldDefinition extends Fragment {
+
+}
diff --git a/src/main/java/com/exasol/sql/dql/Select.java b/src/main/java/com/exasol/sql/dql/Select.java
new file mode 100644
index 00000000..f901ceee
--- /dev/null
+++ b/src/main/java/com/exasol/sql/dql/Select.java
@@ -0,0 +1,39 @@
+package com.exasol.sql.dql;
+
+import com.exasol.sql.*;
+
+/**
+ * This class implements an SQL {@link Select} statement
+ */
+public class Select extends AbstractFragement implements SqlStatement {
+ public Select(final Fragment parent) {
+ super(parent);
+ }
+
+ @Override
+ public String toString() {
+ return "SELECT";
+ }
+
+ /**
+ * Create a wildcard field for all involved fields.
+ *
+ * @return this instance for fluent programming
+ */
+ public Select all() {
+ addChild(Field.all(this));
+ return this;
+ }
+
+ public Select field(final String... names) {
+ for (final String name : names) {
+ addChild(new Field(this, name));
+ }
+ return this;
+ }
+
+ @Override
+ public void acceptConcrete(final FragmentVisitor visitor) {
+ visitor.visit(this);
+ }
+}
diff --git a/src/main/java/com/exasol/sql/dql/StatementFactory.java b/src/main/java/com/exasol/sql/dql/StatementFactory.java
new file mode 100644
index 00000000..23491300
--- /dev/null
+++ b/src/main/java/com/exasol/sql/dql/StatementFactory.java
@@ -0,0 +1,33 @@
+package com.exasol.sql.dql;
+
+/**
+ * The {@link StatementFactory} implements an factory for SQL statements.
+ */
+public final class StatementFactory {
+ private static StatementFactory instance;
+
+ /**
+ * Get an instance of a {@link StatementFactory}
+ *
+ * @return the existing instance otherwise creates one.
+ */
+ public static synchronized StatementFactory getInstance() {
+ if (instance == null) {
+ instance = new StatementFactory();
+ }
+ return instance;
+ }
+
+ private StatementFactory() {
+ // prevent instantiation outside singleton
+ }
+
+ /**
+ * Create a {@link Select} statement
+ *
+ * @return a new instance of a {@link Select} statement
+ */
+ public Select select() {
+ return new Select(null);
+ }
+}
diff --git a/src/main/java/com/exasol/sql/dql/StringRendererConfig.java b/src/main/java/com/exasol/sql/dql/StringRendererConfig.java
new file mode 100644
index 00000000..b3591c79
--- /dev/null
+++ b/src/main/java/com/exasol/sql/dql/StringRendererConfig.java
@@ -0,0 +1,48 @@
+package com.exasol.sql.dql;
+
+/**
+ * This class implements a parameter object containing the configuration options
+ * for the {@link StatementFactory}.
+ */
+public class StringRendererConfig {
+ private final boolean lowerCase;
+
+ private StringRendererConfig(final boolean lowerCase) {
+ this.lowerCase = lowerCase;
+ }
+
+ /**
+ * Get whether the statements should be produced in lower case.
+ *
+ * @return true
if statements are produced in lower case
+ */
+ public boolean produceLowerCase() {
+ return this.lowerCase;
+ }
+
+ /**
+ * Builder for {@link StringRendererConfig}
+ */
+ public static class Builder {
+ private boolean lowerCase = false;
+
+ /**
+ * Create a new instance of a {@link StringRendererConfig}
+ *
+ * @return new instance
+ */
+ public StringRendererConfig build() {
+ return new StringRendererConfig(this.lowerCase);
+ }
+
+ /**
+ * Define whether the statement should be produced in lower case
+ *
+ * @param lowerCase set to true
if the statement should be produced
+ * in lower case
+ */
+ public void lowerCase(final boolean lowerCase) {
+ this.lowerCase = lowerCase;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/exasol/sql/dql/TableExpression.java b/src/main/java/com/exasol/sql/dql/TableExpression.java
new file mode 100644
index 00000000..f54b43a5
--- /dev/null
+++ b/src/main/java/com/exasol/sql/dql/TableExpression.java
@@ -0,0 +1,15 @@
+package com.exasol.sql.dql;
+
+import com.exasol.sql.*;
+
+public class TableExpression extends AbstractFragement {
+
+ public TableExpression(final Fragment parent) {
+ super(parent);
+ }
+
+ @Override
+ protected void acceptConcrete(final FragmentVisitor visitor) {
+ visitor.visit(this);
+ }
+}
diff --git a/src/main/java/com/exasol/sql/rendering/StringRenderer.java b/src/main/java/com/exasol/sql/rendering/StringRenderer.java
new file mode 100644
index 00000000..42d8fff3
--- /dev/null
+++ b/src/main/java/com/exasol/sql/rendering/StringRenderer.java
@@ -0,0 +1,56 @@
+package com.exasol.sql.rendering;
+
+import com.exasol.sql.FragmentVisitor;
+import com.exasol.sql.dql.*;
+
+/**
+ * The {@link StringRenderer} turns SQL statement structures in to SQL strings.
+ */
+public class StringRenderer implements FragmentVisitor {
+ private final StringBuilder builder = new StringBuilder();
+ private final StringRendererConfig config;
+
+ /**
+ * Create a new {@link StringRenderer} using the default
+ * {@link StringRendererConfig}.
+ */
+ public StringRenderer() {
+ this.config = new StringRendererConfig.Builder().build();
+ }
+
+ /**
+ * Create a new {@link StringRenderer} with custom render settings.
+ *
+ * @param config render configuration settings
+ */
+ public StringRenderer(final StringRendererConfig config) {
+ this.config = config;
+ }
+
+ @Override
+ public void visit(final Select select) {
+ this.builder.append(this.config.produceLowerCase() ? "select" : "SELECT");
+ }
+
+ @Override
+ public void visit(final Field field) {
+ if (!field.isFirstSibling()) {
+ this.builder.append(",");
+ }
+ this.builder.append(" ");
+ this.builder.append(field.getName());
+ }
+
+ @Override
+ public void visit(final TableExpression tableExpression) {
+ }
+
+ /**
+ * Render an SQL statement to a string.
+ *
+ * @return rendered string
+ */
+ public String render() {
+ return this.builder.toString();
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/exasol/dql/TestSelect.java b/src/test/java/com/exasol/dql/TestSelect.java
new file mode 100644
index 00000000..669b86df
--- /dev/null
+++ b/src/test/java/com/exasol/dql/TestSelect.java
@@ -0,0 +1,59 @@
+package com.exasol.dql;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.nullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import com.exasol.sql.Fragment;
+import com.exasol.sql.dql.StatementFactory;
+import com.exasol.sql.dql.StringRendererConfig;
+import com.exasol.sql.rendering.StringRenderer;
+
+class TestSelect {
+ private StringRenderer renderer;
+
+ @BeforeEach
+ void beforeEach() {
+ this.renderer = new StringRenderer();
+ }
+
+ @Test
+ void testGetParentReturnsNull() {
+ assertThat(StatementFactory.getInstance().select().getParent(), nullValue());
+ }
+
+ @Test
+ void testEmptySelect() {
+ final Fragment fragment = StatementFactory.getInstance().select();
+ assertFragmentRenderedTo(fragment, "SELECT");
+ }
+
+ private void assertFragmentRenderedTo(final Fragment fragment, final String expected) {
+ fragment.getRoot().accept(this.renderer);
+ assertThat(this.renderer.render(), equalTo(expected));
+ }
+
+ @Test
+ void testEmptySelectLowerCase() {
+ final StringRendererConfig.Builder builder = new StringRendererConfig.Builder();
+ builder.lowerCase(true);
+ this.renderer = new StringRenderer(builder.build());
+ final Fragment fragment = StatementFactory.getInstance().select();
+ assertFragmentRenderedTo(fragment, "select");
+ }
+
+ @Test
+ void testSelectAll() {
+ final Fragment fragment = StatementFactory.getInstance().select().all();
+ assertFragmentRenderedTo(fragment, "SELECT *");
+ }
+
+ @Test
+ void testSelectFieldNames() {
+ final Fragment fragment = StatementFactory.getInstance().select().field("a", "b");
+ assertFragmentRenderedTo(fragment, "SELECT a, b");
+ }
+}
\ No newline at end of file