Skip to content

Commit

Permalink
PMI-66: Initial statement builder.
Browse files Browse the repository at this point in the history
  • Loading branch information
redcatbear committed Sep 18, 2018
1 parent d25eea3 commit 55f7754
Show file tree
Hide file tree
Showing 22 changed files with 583 additions and 1 deletion.
27 changes: 27 additions & 0 deletions .classpath
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/classes" path="src/main/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/bin/
/target/
**/*.md.html
**/*.bak
**/*.swp
**/*.log
**/*.out
18 changes: 18 additions & 0 deletions .project
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>sql-statement-builder</name>
<comment>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.</comment>
<projects/>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
</natures>
</projectDescription>
4 changes: 4 additions & 0 deletions .settings/org.eclipse.core.resources.prefs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
eclipse.preferences.version=1
encoding//src/main/java=UTF-8
encoding//src/test/java=UTF-8
encoding/<project>=UTF-8
6 changes: 6 additions & 0 deletions .settings/org.eclipse.jdt.core.prefs
Original file line number Diff line number Diff line change
@@ -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
33 changes: 32 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,32 @@
# sql-statement-builder
# 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 |
2 changes: 2 additions & 0 deletions doc/system_requirements.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
* Upper case / lower case
* One line / pretty
26 changes: 26 additions & 0 deletions launch/sql-statment-builder all tests.launch
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
<listEntry value="/sql-statement-builder"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="4"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
<listEntry value="org.eclipse.eclemma.ui.launchGroup.coverage"/>
<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
</listAttribute>
<listAttribute key="org.eclipse.eclemma.core.SCOPE_IDS">
<listEntry value="=sql-statement-builder/src\/main\/java"/>
</listAttribute>
<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value="=sql-statement-builder"/>
<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit5"/>
<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="org.eclipse.m2e.launchconfig.classpathProvider"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value=""/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="sql-statement-builder"/>
<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.m2e.launchconfig.sourcepathProvider"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-ea"/>
</launchConfiguration>
17 changes: 17 additions & 0 deletions model/diagrams/cl_fragments.plantuml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
@startuml
hide empty methods
hide empty attributes
skinparam style strictuml
!pragma horizontalLineBetweenDifferentPackageAllowed

interface Fragment <<interface>>
interface FieldDefinition <<interface>>
class Select
class Field

FieldDefinition -u-> Fragment
Field "1..*" -l-> Select : parent

Field -u-> FieldDefinition
Select -u-> Fragment
@enduml
53 changes: 53 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>sql-statement-builder</groupId>
<artifactId>sql-statement-builder</artifactId>
<version>0.1.0</version>
<name>Exasol SQL Statement Builder</name>
<description>This module provides a Builder for SQL statements that helps creating the correct structure and validates variable parts of the statements.</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<junit.version>5.3.1</junit.version>
<junit.platform.version>1.3.1</junit.platform.version>
</properties>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.0</version>
</plugin>
</plugins>
</build>
</project>
63 changes: 63 additions & 0 deletions src/main/java/com/exasol/sql/AbstractFragement.java
Original file line number Diff line number Diff line change
@@ -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 <T> 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<Fragment> 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<Fragment> 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);
}
24 changes: 24 additions & 0 deletions src/main/java/com/exasol/sql/Fragment.java
Original file line number Diff line number Diff line change
@@ -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;
}
14 changes: 14 additions & 0 deletions src/main/java/com/exasol/sql/FragmentVisitor.java
Original file line number Diff line number Diff line change
@@ -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);
}
8 changes: 8 additions & 0 deletions src/main/java/com/exasol/sql/SqlStatement.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.exasol.sql;

/**
* This interface represents an SQL statement.
*/
public interface SqlStatement extends Fragment {

}
25 changes: 25 additions & 0 deletions src/main/java/com/exasol/sql/dql/Field.java
Original file line number Diff line number Diff line change
@@ -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);
}
}
7 changes: 7 additions & 0 deletions src/main/java/com/exasol/sql/dql/FieldDefinition.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.exasol.sql.dql;

import com.exasol.sql.Fragment;

public interface FieldDefinition extends Fragment {

}
39 changes: 39 additions & 0 deletions src/main/java/com/exasol/sql/dql/Select.java
Original file line number Diff line number Diff line change
@@ -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);
}
}
Loading

0 comments on commit 55f7754

Please sign in to comment.