Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
55f7754
PMI-66: Initial statement builder.
redcatbear Sep 18, 2018
3a5ecbf
PMI-66: Added basic FROM clause.
redcatbear Sep 19, 2018
e6fee55
PMI-66: Support basic JOIN
redcatbear Sep 19, 2018
64191cb
PMI-66: Experiment with sub-visitors
redcatbear Sep 20, 2018
f02cf63
PMI-66: Removed duplication in tree handling. Improved renderer for b…
redcatbear Sep 21, 2018
02504d0
PMI-66: Basic boolean expression handling complete.
redcatbear Sep 21, 2018
047e229
PMI-66: Imporved test coverage.
redcatbear Sep 24, 2018
544501c
PMI-66: Raised test coverage to 100%.
redcatbear Sep 24, 2018
556c92a
PMI-86: LIMIT clause now supports both count and offset.
redcatbear Sep 26, 2018
a793f90
PMI-86: Simplified double linking.
redcatbear Sep 26, 2018
ec275e6
PMI-86: Added test coverage for LIMIT.
redcatbear Sep 26, 2018
dd77570
PMI-86: Added lauch configuration for "mvn package"
redcatbear Sep 27, 2018
6b6b54e
PMI-86: Added build configuration for Travis CI.
redcatbear Sep 27, 2018
eca869e
PMI-86: Corrected indentation of "grep" in .travis.yml
redcatbear Sep 27, 2018
2635239
PMI-86: Added Travis CI badge. Outlined milestone plan.
redcatbear Sep 27, 2018
fff45db
Merge pull request #1 from EXASOL/feature/PMI-66_initial_statment_bui…
Oct 1, 2018
e65b759
PMI-86: Added basic comparison features.
redcatbear Oct 1, 2018
26b9d7d
PMI-86: Added tests and implementation for other comparisons than "eq…
redcatbear Oct 1, 2018
4543c78
PMI-86: Added where clause.
redcatbear Oct 1, 2018
9de5b4d
PMI-86: Gave rendering tests a clearer name.
redcatbear Oct 1, 2018
86c0506
PMI-86: Added capability to access FROM after it was created.
redcatbear Oct 2, 2018
2d2233e
PMI-86: Replaced underlying generic tree from SQL fragments by dedica…
redcatbear Oct 5, 2018
0d3eaf2
PMI-86: Test coverage as close to 100% as possible.
redcatbear Oct 5, 2018
ff4e0a3
PMI-86: Added comparison creation from operator enum.
redcatbear Oct 8, 2018
9944ca9
PMI-86: Fixed operator connection and parenthesis for nested comparison.
redcatbear Oct 8, 2018
35cb3e9
PMI-86: Separated visitors and object structure for SELECT and INSERT.
redcatbear Oct 9, 2018
2d3818c
PMI-86: Moved model to more Maven-compliant location.
redcatbear Oct 9, 2018
fb304bb
Merge pull request #2 from EXASOL/feature/PMI-86_add_complex_reads
Oct 9, 2018
334361b
PMI-95: Support basic inserting with values.
redcatbear Oct 9, 2018
5b4eede
PMI-95: Added factory methods for renderers.
redcatbear Oct 9, 2018
d05eccf
PMI-95: Fixed specification trace and added missing unit tests.
redcatbear Oct 10, 2018
86b618f
PMI-95: Added auto-quoting for identifiers.
redcatbear Oct 10, 2018
d8b2d74
PMI-95: Fixed insert value list rendering. Added missing unit tests.
redcatbear Oct 10, 2018
3b02919
PMI-95: Fixed findings from @bobkodex.
redcatbear Oct 15, 2018
76566f9
Merge pull request #4 from EXASOL/feature/PMI-95_Insert_commands
Oct 15, 2018
42eb923
PMI-97: Convert and parse INTERVALS.
redcatbear Oct 16, 2018
fafa12f
Added missing documentation.
redcatbear Oct 16, 2018
aaf4bf6
PMI-97: Improved API documentation.
redcatbear Oct 16, 2018
c06e3b4
PMI-97: Improved API documentation.
redcatbear Oct 16, 2018
19c0fac
PMI-97: Fixed requirement trace.
redcatbear Oct 16, 2018
9eef6c2
PMI-97: Added support for INTERVAL YEAR TO MONTH. Fixed documentation
redcatbear Oct 16, 2018
804a4cf
PMI-97: Fixed requirement trace.
redcatbear Oct 16, 2018
091fa79
PMI-97: Worked in review findings of @bobkodex.
redcatbear Oct 16, 2018
5cb1b0c
Merge pull request #5 from EXASOL/feature/PMI-97_convert_INTERVAL
Oct 17, 2018
9668d88
Fixed error in example.
Oct 17, 2018
da66562
Removed Oracle JDK because automatic download now fails in Travis CI
Oct 17, 2018
de1a121
Updated OpenJDK 10 to 11
Oct 17, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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