All Downloads are FREE. Search and download functionalities are using the official Maven repository.

impl.H2DatabaseConnection Maven / Gradle / Ivy

package impl;

import api.Column;
import api.Table;
import api.sql.SQLDatabaseConnection;
import api.sql.SQLSchema;
import api.sql.SQLTable;
import api.sql.constraint.Constraint;
import api.sql.constraint.NotNull;
import api.sql.constraint.PrimaryKey;

import java.sql.*;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public abstract class H2DatabaseConnection implements SQLDatabaseConnection {
    protected abstract String buildDatabaseUrl();

    /**
     * Initializes the database according to the given schema. Tables which are mentioned in the
     * schema will be dropped if they already exist. All other tables will not be touched by this
     * commmand.
     * @param schema The schema that the database have to fulfill
     * @param moreSchemas (Optional) More schemas the database have to fulfill
     */
    @Override
    public void init(SQLSchema schema, SQLSchema... moreSchemas) {
        try(Connection connection = DriverManager.getConnection(buildDatabaseUrl())) {
            initDatabase(schema, connection);
            for (SQLSchema moreSchema : moreSchemas) {
                initDatabase(moreSchema, connection);
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    private void initDatabase(SQLSchema schema, Connection connection) {
        schema.getTables().forEach(table -> {
            try(Statement statement = connection.createStatement()){
                statement.execute(String.format("DROP TABLE IF EXISTS %s CASCADE", table.getName()));
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }

            List columns = new ArrayList<>(table.getColumns());
            StringBuilder columnDefinition = new StringBuilder();
            for (int i = 0; i < columns.size(); i++){
                if (i > 0){
                    columnDefinition.append(",");
                }
                columnDefinition.append(String.format("%s %s", columns.get(i).getName(), columns.get(i).getDatatype()));
                appendConstraints(table, columnDefinition, columns.get(i));
            }
            try(Statement statement = connection.createStatement()){
                String queryString = String.format("CREATE TABLE %s (%s)", table.getName(), columnDefinition);
                statement.execute(queryString);
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        });
    }

    @Override
    public void insert(Table table, Row row) {
        try(Connection connection = DriverManager.getConnection(buildDatabaseUrl())){
            StringBuilder columnNames = new StringBuilder();
            StringBuilder valuesHolder = new StringBuilder();
            List values = new ArrayList<>(row.getColumns().size());
            final boolean[] isFirstRow = {true};
            row.getColumns().forEach(column -> {
                if (!isFirstRow[0]){
                    columnNames.append(",");
                    valuesHolder.append(",");
                }
                columnNames.append(column.getName());
                valuesHolder.append("?");
                Optional value = row.get(column);
                assert value.isPresent();
                values.add(value.get());
                isFirstRow[0] = false;
            });
            String query = String.format("INSERT INTO %s (%s) VALUES (%s)", table.getName(), columnNames, valuesHolder);
            try(PreparedStatement statement = connection.prepareStatement(query)){
                for (int i = 0; i < values.size(); i++){
                    statement.setString(i+1, values.get(i).get());
                }
                statement.execute();
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public Stream readTable(Table table) {
        try(Connection connection = DriverManager.getConnection(buildDatabaseUrl())){
            try(Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE)){
                StringBuilder columns = new StringBuilder();
                final boolean[] isFirstRow = {true};
                table.getColumns().forEach(column -> {
                    if (!isFirstRow[0]){
                        columns.append(",");
                    }
                    columns.append(String.format("%s", column.getName()));
                    isFirstRow[0] = false;
                });
                String query = String.format("SELECT %s FROM %s GROUP BY %s", columns, table.getName(), columns);
                ResultSet queryResult = statement.executeQuery(query);
                if (!queryResult.last()){
                    return Stream.empty();
                }
                int rowCount = queryResult.getRow();
                queryResult.beforeFirst();
                List rows = new ArrayList<>(rowCount);
                while(queryResult.next()){
                    Map columnValues = new HashMap<>();
                    table.getColumns().forEach(column -> {
                        try {
                            String value = queryResult.getString(column.getName());
                            if (value == null){
                                value = "";
                            }
                            columnValues.put(column, new Value(value));
                        } catch (SQLException e) {
                            throw new RuntimeException(e);
                        }
                    });
                    Row row = new Row(columnValues);
                    rows.add(row);
                }
                return rows.parallelStream();
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Appends the constraint string to the given column definition string
     * @param table The table containing the constraints
     * @param columnDefinition The column definition string the constraints shall be appended to
     * @param column The column the constraints refer to
     */
    private void appendConstraints(SQLTable table, StringBuilder columnDefinition, Column column) {
        Set constraints = table.getConstraints().stream().filter(
                constraint -> Objects.equals(constraint.getConstrainedColumn(), column)
        ).collect(Collectors.toSet());
        constraints.forEach(constraint -> {
            if (constraint instanceof PrimaryKey){
                columnDefinition.append(" PRIMARY KEY");
            }
            if (constraint instanceof NotNull){
                columnDefinition.append(" NOT NULL");
            }
        });
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy