Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
- ...

## [1.6.0] - 2025-05-16

### Added
- Supporting SQL dialect of MS Access.

### Fixed
- H2 dialect now correctly supports TO_NUMBER through an inline user defined db function.

## [1.5.0] - 2025-05-12

### Added
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ The example assumes a connection to a MySQL database.
* MySQL
* MariaDb
* PostgreSQL
* MS Access
* H2

### Supported SQL Features
Expand Down Expand Up @@ -151,7 +152,7 @@ Include in a Maven POM file like this:
<dependency>
<groupId>io.github.torand</groupId>
<artifactId>fastersql</artifactId>
<version>1.5.0</version>
<version>1.6.0</version>
</dependency>
</dependencies>
```
Expand Down
16 changes: 15 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

<groupId>io.github.torand</groupId>
<artifactId>fastersql</artifactId>
<version>1.5.1-SNAPSHOT</version>
<version>1.6.0-SNAPSHOT</version>

<packaging>jar</packaging>

Expand Down Expand Up @@ -84,6 +84,8 @@
<mariadb-java-client.version>3.5.3</mariadb-java-client.version>
<postgresql.version>42.7.5</postgresql.version>
<mssql-jdbc.version>12.10.0.jre11</mssql-jdbc.version>
<ucanaccess.version>5.1.3</ucanaccess.version>
<mybatis.version>3.5.19</mybatis.version>
</properties>

<dependencies>
Expand Down Expand Up @@ -206,6 +208,18 @@
<version>${mssql-jdbc.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.github.spannm</groupId>
<artifactId>ucanaccess</artifactId>
<version>${ucanaccess.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/io/github/torand/fastersql/Clause.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
*/
package io.github.torand.fastersql;

/**
* Defines clauses in a statement.
*/
public enum Clause {
PROJECTION, RESTRICTION
}
16 changes: 16 additions & 0 deletions src/main/java/io/github/torand/fastersql/Column.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
import static io.github.torand.fastersql.util.contract.Requires.requireNonBlank;
import static java.util.Objects.requireNonNull;

/**
* A column in a database table.
*/
public class Column implements LeftOperand, Expression, OrderExpression {
private final Table<?> table;
private final String name;
Expand All @@ -45,14 +48,27 @@ private Column(Table<?> table, String name, String alias) {
this.alias = new ColumnAlias(requireNonBlank(alias, "No alias specified"));
}

/**
* Creates a JOIN clause by associating this column with specified column of another table.
* @param other the other column.
* @return the JOIN clause.
*/
public Join on(Column other) {
return new Join(this, other);
}

/**
* Gets the column name.
* @return the column name.
*/
public String name() {
return name;
}

/**
* Gets the table this column belongs to.
* @return the table.
*/
public Table<?> table() {
return table;
}
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/io/github/torand/fastersql/Command.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
*/
package io.github.torand.fastersql;

/**
* Defines available statement commands.
*/
public enum Command {
SELECT, UPDATE, DELETE, INSERT, TRUNCATE
}
45 changes: 45 additions & 0 deletions src/main/java/io/github/torand/fastersql/Context.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,20 @@
import static io.github.torand.fastersql.Command.SELECT;
import static java.util.Collections.emptyList;

/**
* Holds the context of statement SQL builders.
*/
public class Context {
private final Dialect dialect;
private final Command command;
private final Clause clause;
private final List<SelectStatement> outerStatements;

/**
* Creates context with specified SQL dialect.
* @param dialect the SQL dialect.
* @return the context.
*/
public static Context of(Dialect dialect) {
return new Context(dialect, null, null, emptyList());
}
Expand All @@ -42,36 +50,73 @@ private Context(Dialect dialect, Command command, Clause clause, List<SelectStat
this.outerStatements = new ArrayList<>(outerStatements);
}

/**
* Sets the current statement command.
* @param command the statement command.
* @return the modified context.
*/
public Context withCommand(Command command) {
return new Context(this.dialect, command, command == SELECT ? PROJECTION : null, outerStatements);
}

/**
* Sets the current statement clause.
* @param clause the clause.
* @return the modified context.
*/
public Context withClause(Clause clause) {
return new Context(this.dialect, this.command, clause, outerStatements);
}

/**
* Sets the current outer statement.
* @param outerStatement the outer statement.
* @return the modified context.
*/
public Context withOuterStatement(SelectStatement outerStatement) {
List<SelectStatement> newOuterStatements = new ArrayList<>(outerStatements);
newOuterStatements.add(outerStatement);
return new Context(this.dialect, this.command, this.clause, newOuterStatements);
}

/**
* Gets the SQL dialect.
* @return the SQL dialect.
*/
public Dialect getDialect() {
return this.dialect;
}

/**
* Gets the current statement command.
* @return the statement command.
*/
public Command getCommand() {
return command;
}

/**
* Indicates whether the current statement command is a specific command.
* @param command the command.
* @return true if the current command matches; false if not.
*/
public boolean isCommand(Command command) {
return this.command == command;
}

/**
* Indicates whether the current statement clause is a specific clause.
* @param clause the clause.
* @return true if the current clause matches; false if not.
*/
public boolean isClause(Clause clause) {
return this.clause == clause;
}

/**
* Gets the current outer statements, if any.
* @return the outer statements.
*/
public List<SelectStatement> getOuterStatements() {
return outerStatements;
}
Expand Down
20 changes: 20 additions & 0 deletions src/main/java/io/github/torand/fastersql/Join.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@
import static io.github.torand.fastersql.util.contract.Requires.require;
import static java.util.Objects.requireNonNull;

/**
* Implements a JOIN clause.
*/
public class Join implements Sql {
private enum JoinMode {
INNER("inner join"), LEFT_OUTER("left outer join"), RIGHT_OUTER("right outer join");
Expand Down Expand Up @@ -54,14 +57,27 @@ private Join(List<Column> lefts, List<Column> rights, JoinMode mode) {
this.mode = mode;
}

/**
* Specifies that this is a LEFT OUTER JOIN clause.
* @return the modified JOIN clause.
*/
public Join leftOuter() {
return new Join(lefts, rights, JoinMode.LEFT_OUTER);
}

/**
* Specifies that this is a RIGHT OUTER JOIN clause.
* @return the modified JOIN clause.
*/
public Join rightOuter() {
return new Join(lefts, rights, JoinMode.RIGHT_OUTER);
}

/**
* Creates a nested JOIN clause by combining this JOIN clause with the specified JOIN clause.
* @param next the JOIN clause to combine with.
* @return the nested JOIN clause.
*/
public Join and(Join next) {
require(() -> headOf(this.lefts).table().equals(headOf(next.lefts).table()), "Left side of nested joins must belong to the same table");
require(() -> headOf(this.rights).table().equals(headOf(next.rights).table()), "Right side of nested joins must belong to the same table");
Expand All @@ -72,6 +88,10 @@ public Join and(Join next) {
return new Join(concatenatedLefts, concatenatedRights, mode);
}

/**
* Gets the table joined with.
* @return the table joined with.
*/
public Table<?> joined() {
return headOf(rights).table();
}
Expand Down
22 changes: 11 additions & 11 deletions src/main/java/io/github/torand/fastersql/Sql.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,34 +20,34 @@
import java.util.stream.Stream;

/**
* A construct that can be expressed as an SQL fragment.
* Defines a construct that can be expressed as an SQL fragment.
*/
public interface Sql {
/**
* Formats object as an SQL fragment
* @param context the context (incl. dialect)
* @return the formatted SQL fragment
* Formats object as an SQL fragment.
* @param context the context (incl. dialect).
* @return the formatted SQL fragment.
*/
String sql(Context context);

/**
* Returns the statement parameters introduced by this fragment
* @param context the context (incl. dialect)
* @return the statement parameters
* Gets the statement parameters introduced by this fragment.
* @param context the context (incl. dialect).
* @return the statement parameters.
*/
Stream<Object> params(Context context);

/**
* Returns the columns referenced by this fragment.
* Gets the columns referenced by this fragment.
* For validation purposes.
* @return the columns referenced by this fragment
* @return the columns referenced by this fragment.
*/
Stream<Column> columnRefs();

/**
* Returns the column aliases referenced by this fragment.
* Gets the column aliases referenced by this fragment.
* For validation purposes.
* @return the column aliases referenced by this fragment
* @return the column aliases referenced by this fragment.
*/
Stream<ColumnAlias> aliasRefs();
}
13 changes: 13 additions & 0 deletions src/main/java/io/github/torand/fastersql/Table.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@
import static io.github.torand.fastersql.Command.SELECT;
import static io.github.torand.fastersql.util.contract.Requires.requireNonBlank;

/**
* A database table.
* @param <ENTITY> the concrete table class with columns.
*/
public abstract class Table<ENTITY extends Table<?>> implements Relation {
private final String name;
private final TableAlias alias;
Expand All @@ -41,10 +45,19 @@ protected Table(String name, String alias, TableFactory<ENTITY> tableFactory) {
this.tableFactory = tableFactory;
}

/**
* Creates a column of this table.
* @param name the column name.
* @return the column.
*/
public Column column(String name) {
return new Column(this, name);
}

/**
* Gets the table name.
* @return the table name.
*/
public String name() {
return name;
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/io/github/torand/fastersql/alias/Alias.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import io.github.torand.fastersql.Sql;

/**
* Represents an alias (label) for a column or table
* Defines an alias (label) for a column or table
*/
public interface Alias extends Sql {

Expand Down
3 changes: 3 additions & 0 deletions src/main/java/io/github/torand/fastersql/alias/Aliases.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
*/
package io.github.torand.fastersql.alias;

/**
* Provides factory methods for aliases.
*/
public final class Aliases {
private Aliases() {}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,16 @@
* Defines a constant value.
*/
public interface Constant extends Expression {
/**
* Creates a projection of the constant.
* @param column the column to associate projection with.
* @return the projection.
*/
Projection forColumn(Column column);

/**
* Gets the constant value.
* @return the constant value.
*/
Object value();
}
Loading