From dde7f6828b7e2fc479d2285754e4a150be7958a5 Mon Sep 17 00:00:00 2001 From: Chris Jaekl Date: Sun, 12 Jun 2016 22:01:06 +0900 Subject: [PATCH] select queries now work, and print tabular output. There is support in the output code for CSV formatting as well, but I still need to add a UI feature to enable it. --- src/main/java/net/jaekl/squelch/Squelch.java | 2 + src/main/java/net/jaekl/squelch/sql/Row.java | 1 + .../java/net/jaekl/squelch/stmt/Select.java | 3 +- .../java/net/jaekl/squelch/stmt/Tabular.java | 12 +- .../jaekl/squelch/stmt/TabularResultSet.java | 21 +++- .../net/jaekl/squelch/stmt/TabularMock.java | 41 +++++++ .../net/jaekl/squelch/stmt/TabularTest.java | 107 ++++++++++++++---- 7 files changed, 156 insertions(+), 31 deletions(-) create mode 100644 src/test/java/net/jaekl/squelch/stmt/TabularMock.java diff --git a/src/main/java/net/jaekl/squelch/Squelch.java b/src/main/java/net/jaekl/squelch/Squelch.java index 383b541..88515e0 100644 --- a/src/main/java/net/jaekl/squelch/Squelch.java +++ b/src/main/java/net/jaekl/squelch/Squelch.java @@ -116,7 +116,9 @@ public class Squelch { break; } // Unrecognized command + // TODO: add a string table, and a natural-language error message. pw.println("??? \"" + line + "\""); + pw.flush(); } } } diff --git a/src/main/java/net/jaekl/squelch/sql/Row.java b/src/main/java/net/jaekl/squelch/sql/Row.java index 0496d23..fd47301 100644 --- a/src/main/java/net/jaekl/squelch/sql/Row.java +++ b/src/main/java/net/jaekl/squelch/sql/Row.java @@ -7,6 +7,7 @@ public class Row { m_args = new Object[numCols]; } + // 1-based index, like JDBC public void setValue(int idx, Object value) { m_args[idx - 1] = value; } diff --git a/src/main/java/net/jaekl/squelch/stmt/Select.java b/src/main/java/net/jaekl/squelch/stmt/Select.java index afad262..f34b8c9 100644 --- a/src/main/java/net/jaekl/squelch/stmt/Select.java +++ b/src/main/java/net/jaekl/squelch/stmt/Select.java @@ -29,8 +29,7 @@ public class Select extends Query { { try (ResultSet rs = ps.executeQuery()) { - rowCount = printFormatted(pw, rs); - + rowCount = printFormatted(pw, rs); } } return rowCount; diff --git a/src/main/java/net/jaekl/squelch/stmt/Tabular.java b/src/main/java/net/jaekl/squelch/stmt/Tabular.java index 03c403e..af3d5da 100644 --- a/src/main/java/net/jaekl/squelch/stmt/Tabular.java +++ b/src/main/java/net/jaekl/squelch/stmt/Tabular.java @@ -38,7 +38,7 @@ abstract public class Tabular { } abstract Column[] getCols() throws SQLException; - abstract Row getNext(); + abstract Row getNext() throws SQLException; // Returns the number of (data) rows that were output public int printTable(PrintWriter pw) throws SQLException { @@ -66,6 +66,10 @@ abstract public class Tabular { rowCount += pending; } + if (rowCount > 0) { + writeDivider(pw, colWidths); + } + // TODO: Implement a String table for i18n pw.println("" + rowCount + " row(s) returned."); pw.flush(); @@ -119,7 +123,7 @@ abstract public class Tabular { // Examine and buffer up to rowBuf.length rows. // Returns the number of actual rows that were buffered (zero if no more rows are available). - RowBuffer bufferRows(int[] colWidths) + RowBuffer bufferRows(int[] colWidths) throws SQLException { RowBuffer rowBuf = new RowBuffer(); @@ -222,7 +226,7 @@ abstract public class Tabular { void writeHeader(PrintWriter pw, Column[] cols, int[] colWidths) { writeDivider(pw, colWidths); - for (int idx = 1; idx <= cols.length; ++idx) { + for (int idx = 0; idx < cols.length; ++idx) { Column col = cols[idx]; pw.print("|" + centrePad(col.getLabel(), colWidths[idx])); } @@ -236,7 +240,7 @@ abstract public class Tabular { for (int rowIdx = 0; rowIdx < rowBuf.getPending(); ++rowIdx) { Row row = rowBuf.getRow(rowIdx); for (int colIdx = 0; colIdx < colWidths.length; ++colIdx) { - String value = "" + row.getValue(colIdx); + String value = "" + row.getValue(colIdx + 1); String padding = repChar(' ', colWidths[colIdx] - value.length()); pw.print("|" + value + padding); } diff --git a/src/main/java/net/jaekl/squelch/stmt/TabularResultSet.java b/src/main/java/net/jaekl/squelch/stmt/TabularResultSet.java index 92da23d..f8e233c 100644 --- a/src/main/java/net/jaekl/squelch/stmt/TabularResultSet.java +++ b/src/main/java/net/jaekl/squelch/stmt/TabularResultSet.java @@ -9,9 +9,11 @@ import net.jaekl.squelch.sql.Row; public class TabularResultSet extends Tabular { private ResultSet m_resultSet; + private Column[] m_cols; public TabularResultSet(ResultSet resultSet) { m_resultSet = resultSet; + m_cols = null; } @Override @@ -26,13 +28,24 @@ public class TabularResultSet extends Tabular { int width = metaData.getColumnDisplaySize(idx); cols[idx - 1] = new Column(label, clazz, width); } - + m_cols = cols; return cols; } @Override - Row getNext() { - // TODO Auto-generated method stub - return null; + Row getNext() throws SQLException { + if (null == m_cols) { + m_cols = getCols(); + } + if (! m_resultSet.next()) { + return null; + } + + Row row = new Row(m_cols.length); + for (int idx = 0; idx < m_cols.length; ++idx) { + row.setValue(idx + 1, m_resultSet.getObject(idx + 1)); + } + + return row; } } diff --git a/src/test/java/net/jaekl/squelch/stmt/TabularMock.java b/src/test/java/net/jaekl/squelch/stmt/TabularMock.java new file mode 100644 index 0000000..b19a946 --- /dev/null +++ b/src/test/java/net/jaekl/squelch/stmt/TabularMock.java @@ -0,0 +1,41 @@ +package net.jaekl.squelch.stmt; + +import java.sql.SQLException; +import java.util.ArrayList; + +import net.jaekl.squelch.sql.Column; +import net.jaekl.squelch.sql.Row; + +public class TabularMock extends Tabular { + private Column[] m_cols; + private ArrayList m_rows; + private int m_rowIdx; + + public TabularMock() { + m_cols = new Column[0]; + m_rows = new ArrayList(); + m_rowIdx = (-1); + } + + @Override + Column[] getCols() throws SQLException { + return m_cols.clone(); + } + + @Override + Row getNext() { + if (m_rowIdx >= (m_rows.size() - 1)) { + return null; + } + m_rowIdx++; + return m_rows.get(m_rowIdx); + } + + public void mock_setCols(Column[] cols) { + m_cols = cols.clone(); + } + + public void mock_addRow(Row row) { + m_rows.add(row); + } +} diff --git a/src/test/java/net/jaekl/squelch/stmt/TabularTest.java b/src/test/java/net/jaekl/squelch/stmt/TabularTest.java index 6b5462d..f6749f2 100644 --- a/src/test/java/net/jaekl/squelch/stmt/TabularTest.java +++ b/src/test/java/net/jaekl/squelch/stmt/TabularTest.java @@ -1,7 +1,12 @@ package net.jaekl.squelch.stmt; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.nio.charset.StandardCharsets; import java.sql.SQLException; import java.sql.Types; @@ -11,18 +16,17 @@ import net.jaekl.squelch.sql.Row; import org.junit.Test; public class TabularTest { - private static class TabularMock extends Tabular { - @Override - Column[] getCols() throws SQLException { - return null; - } - - @Override - Row getNext() { - return null; - } + @Test + public void test_centrePad() { + Tabular tabular = new TabularMock(); + + assertEquals("Vestibule", tabular.centrePad("Vestibule", 2)); + assertEquals(" Fred ", tabular.centrePad("Fred", 8)); + assertEquals("NULL", tabular.centrePad(null, 0)); + assertEquals(" NULL ", tabular.centrePad(null, 8)); + assertEquals(" Wilma ", tabular.centrePad("Wilma", 12)); } - + @Test public void test_classForSqlType() { Object[][] data = { @@ -70,7 +74,53 @@ public class TabularTest { assertEquals(expected, actual); } } + + @Test + public void test_printCsv_empTable() throws IOException, SQLException + { + TabularMock tabular = createEmpTable(); + + try ( + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintWriter pw = new PrintWriter(new OutputStreamWriter(baos, StandardCharsets.UTF_8)); + ) + { + tabular.printCsv(pw); + pw.close(); + baos.close(); + String actual = baos.toString(); + assertEquals( "EmpId,FirstName,LastName\n" + + "12345,Fred,Flintstone\n" + + "7654321,Barney,Rubble\n", + actual); + } + } + @Test + public void test_printTable_empTable() throws IOException, SQLException + { + TabularMock tabular = createEmpTable(); + + try ( + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintWriter pw = new PrintWriter(new OutputStreamWriter(baos, StandardCharsets.UTF_8)); + ) + { + tabular.printTable(pw); + pw.close(); + baos.close(); + String actual = baos.toString(); + assertEquals( "+-------+---------+----------+\n" + + "| EmpId |FirstName| LastName |\n" + + "+-------+---------+----------+\n" + + "|12345 |Fred |Flintstone|\n" + + "|7654321|Barney |Rubble |\n" + + "+-------+---------+----------+\n" + + "2 row(s) returned.\n", + actual); + } + } + @Test public void test_repChar() { Tabular tabular = new TabularMock(); @@ -80,15 +130,30 @@ public class TabularTest { assertEquals("###", tabular.repChar('#', 3)); assertEquals("------", tabular.repChar('-', 6)); } - - @Test - public void test_centrePad() { - Tabular tabular = new TabularMock(); + + private TabularMock createEmpTable() + { + TabularMock tabular = new TabularMock(); - assertEquals("Vestibule", tabular.centrePad("Vestibule", 2)); - assertEquals(" Fred ", tabular.centrePad("Fred", 8)); - assertEquals("NULL", tabular.centrePad(null, 0)); - assertEquals(" NULL ", tabular.centrePad(null, 8)); - assertEquals(" Wilma ", tabular.centrePad("Wilma", 12)); + Column[] cols = { + new Column("EmpId", Long.class, 10), + new Column("FirstName", String.class, 14), + new Column("LastName", String.class, 14) + }; + tabular.mock_setCols(cols); + + Row row = new Row(cols.length); + row.setValue(1, Long.valueOf(12345)); + row.setValue(2, "Fred"); + row.setValue(3, "Flintstone"); + tabular.mock_addRow(row); + + row = new Row(cols.length); + row.setValue(1, Long.valueOf(7654321)); + row.setValue(2, "Barney"); + row.setValue(3, "Rubble"); + tabular.mock_addRow(row); + + return tabular; } } -- 2.39.2