1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/java/sql-dk/src/info/globalcode/sql/dk/formatting/AbstractFormatter.java Fri Dec 20 22:01:06 2013 +0100
1.3 @@ -0,0 +1,241 @@
1.4 +/**
1.5 + * SQL-DK
1.6 + * Copyright © 2013 František Kučera (frantovo.cz)
1.7 + *
1.8 + * This program is free software: you can redistribute it and/or modify
1.9 + * it under the terms of the GNU General Public License as published by
1.10 + * the Free Software Foundation, either version 3 of the License, or
1.11 + * (at your option) any later version.
1.12 + *
1.13 + * This program is distributed in the hope that it will be useful,
1.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.16 + * GNU General Public License for more details.
1.17 + *
1.18 + * You should have received a copy of the GNU General Public License
1.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
1.20 + */
1.21 +package info.globalcode.sql.dk.formatting;
1.22 +
1.23 +import info.globalcode.sql.dk.Parameter;
1.24 +import java.io.OutputStream;
1.25 +import java.util.EmptyStackException;
1.26 +import java.util.EnumSet;
1.27 +import java.util.List;
1.28 +import java.util.Stack;
1.29 +
1.30 +/**
1.31 + *
1.32 + * @author Ing. František Kučera (frantovo.cz)
1.33 + */
1.34 +public abstract class AbstractFormatter implements Formatter {
1.35 +
1.36 + private Stack<State> state = new Stack<>();
1.37 + private OutputStream outputStream;
1.38 + private ColumnsHeader currentColumnsHeader;
1.39 + private String currentQuery;
1.40 + private int currentColumnsCount;
1.41 +
1.42 + public AbstractFormatter(OutputStream outputStream) {
1.43 + this.outputStream = outputStream;
1.44 + state.push(State.ROOT);
1.45 + }
1.46 +
1.47 + /*
1.48 + * root
1.49 + * .database
1.50 + * ..resultSet
1.51 + * ...@query
1.52 + * ...@parameters
1.53 + * ...@columnsHeader
1.54 + * ...row
1.55 + * ....@columnValue
1.56 + * ..updatesResult
1.57 + * ...@query
1.58 + * ...@parameters
1.59 + * ...@updatedRowsCount
1.60 + * ...generatedKeys
1.61 + * ....resultSet (see above)
1.62 + */
1.63 + protected enum State {
1.64 +
1.65 + ROOT,
1.66 + DATABASE,
1.67 + RESULT_SET,
1.68 + ROW,
1.69 + UPDATES_RESULT,
1.70 + GENERATED_KEYS
1.71 + }
1.72 +
1.73 + /**
1.74 + * Go down in hierarchy.
1.75 + * Pushes new state and verifies the old one.
1.76 + *
1.77 + * @param current the new state – currently entering
1.78 + * @param expected expected previous states (any of them is valid)
1.79 + * @return previous state
1.80 + * @throws IllegalStateException if previous state was not one from expected
1.81 + */
1.82 + private State pushState(State current, EnumSet expected) {
1.83 + State previous = state.peek();
1.84 +
1.85 + if (expected.contains(previous)) {
1.86 + state.push(current);
1.87 + return previous;
1.88 + } else {
1.89 + throw new IllegalStateException("Formatter was in wrong state: " + previous + " when it should be in one of: " + expected);
1.90 + }
1.91 + }
1.92 +
1.93 + protected State peekState(EnumSet expected) {
1.94 + State current = state.peek();
1.95 +
1.96 + if (expected.contains(current)) {
1.97 + return current;
1.98 + } else {
1.99 + throw new IllegalStateException("Formatter is in wrong state: " + current + " when it should be in one of: " + expected);
1.100 + }
1.101 +
1.102 + }
1.103 +
1.104 + /**
1.105 + * Go up in hierarchy.
1.106 + * Pops the superior state/branch.
1.107 + *
1.108 + * @param expected expected superior state
1.109 + * @return the superior state
1.110 + * @throws IllegalStateException if superior state was not one from expected or if there is no
1.111 + * more superior state (we are at root level)
1.112 + */
1.113 + private State popState(EnumSet expected) {
1.114 + try {
1.115 + State superior = state.pop();
1.116 + if (expected.contains(superior)) {
1.117 + return superior;
1.118 + } else {
1.119 + throw new IllegalStateException("Formatter had wrong superior state: " + superior + " when it should be in one of: " + expected);
1.120 + }
1.121 + } catch (EmptyStackException e) {
1.122 + throw new IllegalStateException("Formatter was already at root level – there is nothing above that.", e);
1.123 + }
1.124 + }
1.125 +
1.126 + @Override
1.127 + public void writeStartDatabase() {
1.128 + pushState(State.DATABASE, EnumSet.of(State.ROOT));
1.129 + }
1.130 +
1.131 + @Override
1.132 + public void writeEndDatabase() {
1.133 + popState(EnumSet.of(State.ROOT));
1.134 + }
1.135 +
1.136 + @Override
1.137 + public void writeStartResultSet() {
1.138 + pushState(State.RESULT_SET, EnumSet.of(State.DATABASE, State.GENERATED_KEYS));
1.139 + }
1.140 +
1.141 + @Override
1.142 + public void writeEndResultSet() {
1.143 + popState(EnumSet.of(State.DATABASE, State.GENERATED_KEYS));
1.144 + currentColumnsHeader = null;
1.145 + }
1.146 +
1.147 + @Override
1.148 + public void writeQuery(String sql) {
1.149 + peekState(EnumSet.of(State.RESULT_SET, State.UPDATES_RESULT));
1.150 +
1.151 + if (currentColumnsHeader == null) {
1.152 + currentQuery = sql;
1.153 + } else {
1.154 + throw new IllegalStateException("Query string '" + sql + "' must be set before columns header – was already set: " + currentColumnsHeader);
1.155 + }
1.156 + }
1.157 +
1.158 + @Override
1.159 + public void writeParameters(List<Parameter> parameters) {
1.160 + peekState(EnumSet.of(State.RESULT_SET, State.UPDATES_RESULT));
1.161 +
1.162 + if (currentColumnsHeader != null) {
1.163 + throw new IllegalStateException("Parameters '" + parameters + "' must be set before columns header – was already set: " + currentColumnsHeader);
1.164 + }
1.165 +
1.166 + if (currentQuery == null) {
1.167 + throw new IllegalStateException("Parameters '" + parameters + "' must be set after query – was not yet set.");
1.168 + }
1.169 + }
1.170 +
1.171 + @Override
1.172 + public void writeColumnsHeader(ColumnsHeader header) {
1.173 + peekState(EnumSet.of(State.RESULT_SET, State.UPDATES_RESULT));
1.174 +
1.175 + if (currentColumnsHeader == null) {
1.176 + currentColumnsHeader = header;
1.177 + } else {
1.178 + throw new IllegalStateException("Columns header can be set only once per result set – was already set: " + currentColumnsHeader);
1.179 + }
1.180 + }
1.181 +
1.182 + @Override
1.183 + public void writeStartRow() {
1.184 + pushState(State.ROW, EnumSet.of(State.RESULT_SET));
1.185 + currentColumnsCount = 0;
1.186 + }
1.187 +
1.188 + @Override
1.189 + public void writeEndRow() {
1.190 + popState(EnumSet.of(State.RESULT_SET));
1.191 + }
1.192 +
1.193 + @Override
1.194 + public void writeColumnValue(Object value) {
1.195 + peekState(EnumSet.of(State.ROW));
1.196 + currentColumnsCount++;
1.197 +
1.198 + int declaredCount = currentColumnsHeader.getColumnCount();
1.199 + if (currentColumnsCount > declaredCount) {
1.200 + throw new IllegalStateException("Current columns count is " + currentColumnsCount + " which is more than declared " + declaredCount + " in header.");
1.201 + }
1.202 + }
1.203 +
1.204 + @Override
1.205 + public void writeStartUpdatesResult() {
1.206 + pushState(State.RESULT_SET, EnumSet.of(State.DATABASE));
1.207 + }
1.208 +
1.209 + @Override
1.210 + public void writeEndUpdatesResult() {
1.211 + popState(EnumSet.of(State.DATABASE));
1.212 + currentColumnsHeader = null;
1.213 + }
1.214 +
1.215 + @Override
1.216 + public void writeUpdatedRowsCount(int updatedRowsCount) {
1.217 + peekState(EnumSet.of(State.UPDATES_RESULT));
1.218 + }
1.219 +
1.220 + @Override
1.221 + public void writeStartGeneratedKeys() {
1.222 + pushState(State.GENERATED_KEYS, EnumSet.of(State.UPDATES_RESULT));
1.223 + }
1.224 +
1.225 + @Override
1.226 + public void writeEndGeneratedKeys() {
1.227 + popState(EnumSet.of(State.UPDATES_RESULT));
1.228 + }
1.229 +
1.230 + protected OutputStream getOutputStream() {
1.231 + return outputStream;
1.232 + }
1.233 +
1.234 + protected ColumnsHeader getCurrentColumnsHeader() {
1.235 + return currentColumnsHeader;
1.236 + }
1.237 +
1.238 + protected int getCurrentColumnsCount() {
1.239 + return currentColumnsCount;
1.240 + }
1.241 + /**
1.242 + * TODO: write SQLWarning
1.243 + */
1.244 +}
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/java/sql-dk/src/info/globalcode/sql/dk/formatting/ColumnsHeader.java Fri Dec 20 22:01:06 2013 +0100
2.3 @@ -0,0 +1,35 @@
2.4 +/**
2.5 + * SQL-DK
2.6 + * Copyright © 2013 František Kučera (frantovo.cz)
2.7 + *
2.8 + * This program is free software: you can redistribute it and/or modify
2.9 + * it under the terms of the GNU General Public License as published by
2.10 + * the Free Software Foundation, either version 3 of the License, or
2.11 + * (at your option) any later version.
2.12 + *
2.13 + * This program is distributed in the hope that it will be useful,
2.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
2.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2.16 + * GNU General Public License for more details.
2.17 + *
2.18 + * You should have received a copy of the GNU General Public License
2.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
2.20 + */
2.21 +package info.globalcode.sql.dk.formatting;
2.22 +
2.23 +/**
2.24 + *
2.25 + * @author Ing. František Kučera (frantovo.cz)
2.26 + */
2.27 +public class ColumnsHeader {
2.28 +
2.29 + public int getColumnCount() {
2.30 + /**
2.31 + * TODO: getColumnCount
2.32 + */
2.33 + throw new RuntimeException("Not yet implemented");
2.34 + }
2.35 + /**
2.36 + * TODO: columns descriptor
2.37 + */
2.38 +}
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/java/sql-dk/src/info/globalcode/sql/dk/formatting/Formatter.java Fri Dec 20 22:01:06 2013 +0100
3.3 @@ -0,0 +1,58 @@
3.4 +/**
3.5 + * SQL-DK
3.6 + * Copyright © 2013 František Kučera (frantovo.cz)
3.7 + *
3.8 + * This program is free software: you can redistribute it and/or modify
3.9 + * it under the terms of the GNU General Public License as published by
3.10 + * the Free Software Foundation, either version 3 of the License, or
3.11 + * (at your option) any later version.
3.12 + *
3.13 + * This program is distributed in the hope that it will be useful,
3.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
3.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3.16 + * GNU General Public License for more details.
3.17 + *
3.18 + * You should have received a copy of the GNU General Public License
3.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
3.20 + */
3.21 +package info.globalcode.sql.dk.formatting;
3.22 +
3.23 +import info.globalcode.sql.dk.Parameter;
3.24 +import java.util.List;
3.25 +
3.26 +/**
3.27 + *
3.28 + * @author Ing. František Kučera (frantovo.cz)
3.29 + */
3.30 +public interface Formatter {
3.31 +
3.32 + void writeStartDatabase();
3.33 +
3.34 + void writeEndDatabase();
3.35 +
3.36 + void writeStartResultSet();
3.37 +
3.38 + void writeEndResultSet();
3.39 +
3.40 + void writeQuery(String sql);
3.41 +
3.42 + void writeParameters(List<Parameter> parameters);
3.43 +
3.44 + void writeColumnsHeader(ColumnsHeader header);
3.45 +
3.46 + void writeStartRow();
3.47 +
3.48 + void writeColumnValue(Object value);
3.49 +
3.50 + void writeEndRow();
3.51 +
3.52 + void writeStartUpdatesResult();
3.53 +
3.54 + void writeUpdatedRowsCount(int updatedRowsCount);
3.55 +
3.56 + void writeStartGeneratedKeys();
3.57 +
3.58 + void writeEndGeneratedKeys();
3.59 +
3.60 + void writeEndUpdatesResult();
3.61 +}