Skip to content

Commit

Permalink
#124: Split of ColumnMetadataReader.
Browse files Browse the repository at this point in the history
  • Loading branch information
redcatbear committed Mar 28, 2019
1 parent a453c9c commit 30ab0dc
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 9 deletions.
2 changes: 1 addition & 1 deletion jdbc-adapter/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<junit.version>5.4.0</junit.version>
<junit.platform.version>1.3.2</junit.platform.version>
<maven.surefire.version>2.22.1</maven.surefire.version>
<vscommon.version>3.0.0</vscommon.version>
<vscommon.version>4.0.0</vscommon.version>
</properties>
<distributionManagement>
<repository>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,31 +8,73 @@

import com.exasol.adapter.metadata.ColumnMetadata;
import com.exasol.adapter.metadata.DataType;
import com.exasol.adapter.metadata.DataType.ExaCharset;

public class ColumnMetadataReader {
private static final String COLUMN_NAME_COLUMN = "COLUMN_NAME";
public static final int COLUMN_NAME = 4;
public static final int DATA_TYPE = 5;
public static final int COLUMN_SIZE = 7;
private final Connection connection;

public ColumnMetadataReader(final Connection connection) {
this.connection = connection;
}

public List<ColumnMetadata> mapColumns(final String tableName) throws SQLException {
public List<ColumnMetadata> mapColumns(final String tableName) {
final List<ColumnMetadata> columns = new ArrayList<>();
try (final ResultSet remoteColumns = this.connection.getMetaData().getColumns(ANY_CATALOG, ANY_SCHEMA,
tableName, ANY_COLUMN)) {
while (remoteColumns.next()) {
final ColumnMetadata metadata = mapColumn(remoteColumns);
columns.add(metadata);
}
} catch (final SQLException exception) {
throw new RemoteMetadataReaderException("Unable to read table metadata from remote", exception);
}
return columns;
}

private ColumnMetadata mapColumn(final ResultSet remoteColumn) throws SQLException {
return ColumnMetadata.builder() //
.name(remoteColumn.getString(COLUMN_NAME_COLUMN)) //
.type(DataType.createBool()) // FIXME
.name(readColumnName(remoteColumn)) //
.type(mapDatatype(remoteColumn)) //
.build();
}
}

private String readColumnName(final ResultSet remoteColumn) {
try {
return remoteColumn.getString(COLUMN_NAME);
} catch (final SQLException exception) {
throw new RemoteMetadataReaderException("Unable to read remote column name.", exception);
}
}

/**
* Parse the data type from a string
*
* @param string data type name
* @return data type
*/
public DataType mapDatatype(final ResultSet remoteColumn) throws SQLException {
final String datatypeName = readDatatypeName(remoteColumn);
switch (datatypeName) {
case "BOOLEAN":
return DataType.createBool();
case "CHAR":
return DataType.createChar(readColumnSize(remoteColumn), ExaCharset.UTF8);
case "DOUBLE":
return DataType.createDouble();
default:
throw new IllegalArgumentException("Unable to map \"" + datatypeName + "\" into an Exasol data type.");
}

}

private int readColumnSize(final ResultSet remoteColumn) throws SQLException {
return remoteColumn.getInt(COLUMN_SIZE);
}

private String readDatatypeName(final ResultSet remoteColumn) throws SQLException {
return remoteColumn.getString(DATA_TYPE);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public RemoteMetadataReader(final Connection connection) {
this.connection = connection;
}

public SchemaMetadata readRemoteSchemaMetadata() throws RemoteMetadataReaderException {
public SchemaMetadata readRemoteSchemaMetadata() {
try {
final DatabaseMetaData remoteMetadata = this.connection.getMetaData();
final String adapterNotes = null;
Expand Down Expand Up @@ -53,11 +53,15 @@ private void mapTables(final List<TableMetadata> translatedTables, final ResultS
}

private TableMetadata mapTable(final ResultSet remoteTable) throws SQLException {
final String tableName = remoteTable.getString(TABLE_NAME_COLUMN);
final String tableName = readTableName(remoteTable);
LOGGER.info(() -> "Mapping metadata for table \"" + tableName + "\"");
final String adapterNotes = null;
final List<ColumnMetadata> columns = new ColumnMetadataReader(this.connection).mapColumns(tableName);
final String comment = null;
return new TableMetadata(tableName, adapterNotes, columns, comment);
}

private String readTableName(final ResultSet remoteTable) throws SQLException {
return remoteTable.getString(TABLE_NAME_COLUMN);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,15 @@
* This class represents exceptional conditions that occur during attempts to extract schema metadata from a remote data
* source.
*/
public class RemoteMetadataReaderException extends Exception {
public class RemoteMetadataReaderException extends RuntimeException {
private static final long serialVersionUID = -3538574076638223017L;

/**
* Create a new {@link RemoteMetadataReaderException}
*
* @param message error message
* @param cause root cause
*/
public RemoteMetadataReaderException(final String message, final Throwable cause) {
super(message, cause);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package com.exasol.adapter.jdbc;

import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.iterableWithSize;
import static org.junit.Assert.assertThat;
import static org.junit.jupiter.api.Assertions.assertAll;
import static org.mockito.Mockito.when;

import java.sql.*;
import java.util.List;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import com.exasol.adapter.metadata.ColumnMetadata;
import com.exasol.adapter.metadata.DataType;
import com.exasol.adapter.metadata.DataType.ExaCharset;

class ColumnMetadataReaderTest {
@Mock
private Connection connectionMock;
@Mock
private DatabaseMetaData remoteMetadataMock;
@Mock
private ResultSet columnsMock;

@BeforeEach
void beforeEach() throws SQLException {
MockitoAnnotations.initMocks(this);
when(this.connectionMock.getMetaData()).thenReturn(this.remoteMetadataMock);
}

@Test
void testMapColumnsSingleColumn() throws SQLException, RemoteMetadataReaderException {
when(this.columnsMock.next()).thenReturn(true, false);
when(this.columnsMock.getString("COLUMN_NAME")).thenReturn("COLUMN_A");
when(this.columnsMock.getString("DATA_TYPE")).thenReturn("VARCHAR(20)");
when(this.columnsMock.getBoolean("NULLABLE")).thenReturn(false);
final List<ColumnMetadata> columns = mappedMockedColumns(this.columnsMock);
final ColumnMetadata column = columns.get(0);
assertAll(() -> assertThat(columns, iterableWithSize(2)),
() -> assertThat(column.getName(), equalTo("COLUMN_A")),
() -> assertThat(column.getType(), equalTo(DataType.createVarChar(20, ExaCharset.UTF8))));
}

private List<ColumnMetadata> mappedMockedColumns(final ResultSet columnsMock)
throws RemoteMetadataReaderException, SQLException {
when(this.remoteMetadataMock.getColumns(null, null, "THE_TABLE", "%")).thenReturn(columnsMock);
final List<ColumnMetadata> columns = new ColumnMetadataReader(this.connectionMock).mapColumns("THE_TABLE");
return columns;
}

@CsvSource({ //
"BOOLEAN, BOOLEAN", //
"CHAR, CHAR(20) UTF8", //
"DOUBLE, DOUBLE" //
})
@ParameterizedTest
void testParse(final String datatypeAsString, final String expected)
throws SQLException, RemoteMetadataReaderException {
when(this.columnsMock.next()).thenReturn(true, false);
when(this.columnsMock.getString(ColumnMetadataReader.COLUMN_NAME)).thenReturn("COLUMN_A");
when(this.columnsMock.getString(ColumnMetadataReader.DATA_TYPE)).thenReturn(datatypeAsString);
when(this.columnsMock.getInt(ColumnMetadataReader.COLUMN_SIZE)).thenReturn(20);
when(this.remoteMetadataMock.getColumns(null, null, "THE_TABLE", "%")).thenReturn(this.columnsMock);
final List<ColumnMetadata> columns = mappedMockedColumns(this.columnsMock);
final ColumnMetadata column = columns.get(0);
assertThat(column.getType().toString(), equalTo(expected));
}
}

0 comments on commit 30ab0dc

Please sign in to comment.