Skip to content

Commit

Permalink
Merge pull request #6 from EXASOL/develop
Browse files Browse the repository at this point in the history
0.1.0
  • Loading branch information
redcatbear authored Oct 17, 2018
2 parents d25eea3 + de1a121 commit 46f1dcb
Show file tree
Hide file tree
Showing 90 changed files with 4,554 additions and 1 deletion.
34 changes: 34 additions & 0 deletions .classpath
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?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"/>
</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="var" path="M2_REPO/org/junit/jupiter/junit-jupiter-api/5.3.1/junit-jupiter-api-5.3.1.jar" sourcepath="M2_REPO/org/junit/jupiter/junit-jupiter-api/5.3.1/junit-jupiter-api-5.3.1-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/apiguardian/apiguardian-api/1.0.0/apiguardian-api-1.0.0.jar" sourcepath="M2_REPO/org/apiguardian/apiguardian-api/1.0.0/apiguardian-api-1.0.0-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/opentest4j/opentest4j/1.1.1/opentest4j-1.1.1.jar" sourcepath="M2_REPO/org/opentest4j/opentest4j/1.1.1/opentest4j-1.1.1-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/junit/platform/junit-platform-commons/1.3.1/junit-platform-commons-1.3.1.jar" sourcepath="M2_REPO/org/junit/platform/junit-platform-commons/1.3.1/junit-platform-commons-1.3.1-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/junit/jupiter/junit-jupiter-engine/5.3.1/junit-jupiter-engine-5.3.1.jar" sourcepath="M2_REPO/org/junit/jupiter/junit-jupiter-engine/5.3.1/junit-jupiter-engine-5.3.1-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/junit/platform/junit-platform-engine/1.3.1/junit-platform-engine-1.3.1.jar" sourcepath="M2_REPO/org/junit/platform/junit-platform-engine/1.3.1/junit-platform-engine-1.3.1-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/junit/platform/junit-platform-launcher/1.3.1/junit-platform-launcher-1.3.1.jar" sourcepath="M2_REPO/org/junit/platform/junit-platform-launcher/1.3.1/junit-platform-launcher-1.3.1-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/hamcrest/hamcrest-all/1.3/hamcrest-all-1.3.jar" sourcepath="M2_REPO/org/hamcrest/hamcrest-all/1.3/hamcrest-all-1.3-sources.jar"/>
<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
11 changes: 11 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
language: java

jdk:
- openjdk8
- openjdk11

before_script:
- version=$(grep -oP '(?<=^ <version>)[^<]*' pom.xml)

script:
- mvn clean install
75 changes: 74 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,74 @@
# sql-statement-builder
# sql-statement-builder

[![Build Status](https://travis-ci.com/EXASOL/sql-statement-builder.svg?branch=develop)](https://travis-ci.com/EXASOL/sql-statement-builder)

The Exasol SQL Statement Builder abstracts programmatic creation of SQL statements and is intended to replace ubiquitous string concatenation solutions which make the code hard to read and are prone to error and security risks.

Goals:

1. Foster clean and readable code
1. Allow for thorough validation of dynamic parts
1. Detect as many errors as possible at *compile time*
1. Don't repeat yourself (DRY)
1. Allow extension for different SQL dialects

## Usage

```java
import com.exasol.sql.StatementFactory;
import com.exasol.sql.SqlStatement;
import com.exasol.sql.rendering.SelectRenderer;

SqlStatement statement = StatementFactory.getInstance()
.select().field("firstname", "lastname")
.from().table("person");

String statementText = SqlStatementRenderer.render(statement);
```

## 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 |

### Planned Milestones

The milestones listed below are a rough outline and might be subject to change depending on which constructs are needed more. The plan will be updated accordingly.

#### M1

* Basic support for Data Query Language (DQL) statement constructs (SELECT, FROM, JOIN, WHERE)
* Rendering to string
* Exasol Dialect only

#### M2

* Validation for constructs from M1

(Later milestones will always include validation of the newly learned milestones)

#### M3

* Scalar functions

#### M4

* Sub-Selects including validation

#### Later Milstones (very coarse)

* Data Manipulation Language (DML) statements
* Data Definition Language (DDL) statements
* Support for Standard SQL
* Support for other dialects (help welcome!)
181 changes: 181 additions & 0 deletions doc/design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
# Software Architectural Design -- Exasol SQL Statement Builder

## Building Block View

### Select Statement
`dsn~dql-statement~1`

The Data Query Language (DQL) building block is responsible for managing `SELECT` statements.

## Solution Strategy

### Fluent Programming

#### Statement Construction With Fluent Programming
`dsn~statement-construction-with-fluent-programming~1`

All statement builders use the "fluent programming" model, where the return type of each builder step determines the possible next structural elements that can be added.

Comment:

This is a design principle that cuts across the whole project. Therefore locating it in a single test or implementation part makes no sense.

Covers:

* `req~statement-structure-limited-at-compile-time~1`

## Runtime View

### Building Select Statements

#### Accessing the Clauses That Make Up a SELECT Statement
`dsn~select-statement.out-of-order-clauses~1`

`SELECT` commands allow attaching the following clauses in any order:

* `FROM` clause
* `WHERE` clause
* `LIMIT` clause

Covers:

* `req~statement-structure.step-wise~1`

Needs: impl, utest

Tags: Select Statement Builder

### Building Boolean Expressions

#### Forwarded Requirements

* `dsn --> impl, utest: req~boolean-operators~1`
* `dsn --> impl, utest: req~comparison-operations~1`

#### Constructing Boolean Comparison Operations From Operator Strings
`dsn~boolean-operation.comparison.constructing-from-strings~1`

The Boolean Expression builder allows creating expression objects from a string representing the comparison operator (options listed below) and a list of operands.

* `>`
* `<`
* `=`
* `>=`
* `<=`
* `<>`

Covers:

* `req~boolean-operators~1`

Needs: impl, utest

#### Constructing Boolean Comparison Operations From Operator Enumeration
`dsn~boolean-operation.comparison.constructing-from-enum~1`

The Boolean Expression builder allows creating expression objects from a enumeration of comparison operators.
Covers:

* `req~boolean-operators~1`

Needs: impl, utest

### Building INSERT Statements

#### Forwarded Requirements

* `dsn --> impl, utest: req~insert-statements~1`
* `dsn --> impl, utest: req~values-as-insert-source~1`

### Rendering Statements

#### Forwarded Requirements

* `dsn --> impl, utest: req~rendering.sql.configurable-case~1`
* `dsn --> impl, utest: req~rendering.sql.select~1`
* `dsn --> impl, utest: req~rendering.sql.insert~1`

#### Renderer add Double Quotes for Schema, Table and Column Identifiers
`dsn~rendering.add-double-quotes-for-schema-table-and-column-identifiers~1`

The renderer sets the following identifiers in double quotes if configured:

* Schema identifiers
* Table identifiers
* Column identifiers (except the asterisks)

Comment:

Examples are `"my_schema"."my_table"."my_field"`, `"MY_TABLE"."MyField"` and `"MyTable".*`

Covers:

* `req~rendering.sql.confiugrable-identifier-quoting~1`

Needs: impl, utest

### Exasol Dialect Specific

#### Converting from 64 bit Integers to INTERVAL DAY TO SECOND
`dsn~exasol.converting-int-to-interval-day-to-second~1`

The data converter converts integers to `INTERVAL DAY TO SECOND`.

Covers:

* `req~integer-interval-conversion~1`

Needs: impl, utest

#### Parsing INTERVAL DAY TO SECOND From Strings
`dsn~exasol.parsing-interval-day-to-second-from-strings~1`

The data converter can parse `INTERVAL DAY TO SECOND` from strings in the following format:

interval-d2s = [ days SP ] hours ":" minutes [ ":" seconds [ "." milliseconds ] ]

hours = ( "2" "0" - "3" ) / ( [ "0" / "1" ] DIGIT )

minutes = ( "5" DIGIT ) / ( [ "0" - "4" ] DIGIT )

seconds = ( "5" DIGIT ) / ( [ "0" - "4" ] DIGIT )

milliseconds = 1*3DIGIT

Examples are `12:30`, `12:30.081` or `100 12:30:00.081`.

Covers:

* `req~integer-interval-conversion~1`

Needs: impl, utest

#### Converting from 64 bit Integers to INTERVAL YEAR TO MONTH
`dsn~exasol.converting-int-to-interval-year-to-month~1`

The data converter converts integers to `INTERVAL YEAR TO MONTH`.

Covers:

* `req~integer-interval-conversion~1`

Needs: impl, utest

#### Parsing INTERVAL YEAR TO MONTH From Strings
`dsn~exasol.parsing-interval-year-to-month-from-strings~1`

The data converter can parse `INTERVAL YEAR TO MONTH` from strings in the following format:

interval-y2m = days "-" months

days = 1*9DIGIT

months = ( "1" "0" - "2" ) / DIGIT

Examples are `0-1` and `100-11`.

Covers:

* `req~integer-interval-conversion~1`

Needs: impl, utest
Loading

0 comments on commit 46f1dcb

Please sign in to comment.