Skip to content

Commit

Permalink
Preliminary support for #21 - still fragile & unpolished, some tests …
Browse files Browse the repository at this point in the history
…failing too for MySQL and PostgreSQL [skip ci]
  • Loading branch information
edrdo committed Jun 5, 2017
1 parent 0e5f2ff commit 83290e8
Show file tree
Hide file tree
Showing 7 changed files with 367 additions and 25 deletions.
24 changes: 24 additions & 0 deletions src/main/java/org/jdbdt/DB.java
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,28 @@ void logInsertion(CallInfo callInfo, DataSet data) {
}
}

/**
* Log data set update.
* @param callInfo Call info.
* @param data Data set.
*/
void logUpdate(CallInfo callInfo, DataSet data) {
if (isEnabled(Option.LOG_SETUP)) {
log.write(callInfo, data);
}
}

/**
* Log data set delete.
* @param callInfo Call info.
* @param data Data set.
*/
void logDelete(CallInfo callInfo, DataSet data) {
if (isEnabled(Option.LOG_SETUP)) {
log.write(callInfo, data);
}
}

/**
* Log delta assertion.
* @param callInfo Call info.
Expand Down Expand Up @@ -516,6 +538,8 @@ private void ignoreSQLException(SQLOperationThatMayFail op) {
}
}





}
234 changes: 212 additions & 22 deletions src/main/java/org/jdbdt/DBSetup.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
package org.jdbdt;

import java.sql.PreparedStatement;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
* Utility class with methods for database setup.
Expand Down Expand Up @@ -43,7 +49,7 @@ private static Table asTable(DataSource source) {
}
return (Table) source;
}

/**
* Populate database table with a data set, if associated table
* has changed.
Expand All @@ -70,34 +76,34 @@ private static void doPopulate(CallInfo callInfo, Table table, DataSet data) {
doInsert(callInfo, table, data);
table.setSnapshot(data);
}

/**
* Utility method to perform actual data insertion.
* @param callInfo Call Info.
* @param table Table.
* @param data Data set.
*/
private static void doInsert(CallInfo callInfo, Table table, DataSet data) {
final DB db = table.getDB();
db.access(() -> {
db.logInsertion(callInfo, data);
StringBuilder sql = new StringBuilder("INSERT INTO ");
String[] columnNames = table.getColumns();
sql.append(table.getName())
.append('(')
.append(columnNames[0]);
for (int i=1; i < columnNames.length; i++) {
sql.append(',').append(columnNames[i]);
}
sql.append(") VALUES (?");
for (int i=1; i < columnNames.length; i++) {
sql.append(",?");
}
sql.append(')');
final DB db = table.getDB();
db.logInsertion(callInfo, data);
StringBuilder sql = new StringBuilder("INSERT INTO ");
String[] columnNames = table.getColumns();
sql.append(table.getName())
.append('(')
.append(columnNames[0]);
for (int i=1; i < columnNames.length; i++) {
sql.append(',').append(columnNames[i]);
}
sql.append(") VALUES (?");
for (int i=1; i < columnNames.length; i++) {
sql.append(",?");
}
sql.append(')');

db.access(() -> {
final boolean batchMode = db.useBatchUpdates();
final int maxBatchSize = db.getMaximumBatchUpdateSize();

try(WrappedStatement ws = db.compile(sql.toString())) {
PreparedStatement insertStmt = ws.getStatement();
int batchSize = 0;
Expand Down Expand Up @@ -129,6 +135,189 @@ private static void doInsert(CallInfo callInfo, Table table, DataSet data) {
});
}

/**
* Update rows according to data set.
*
* <p>
* The data set must relate to a table with a defined key (see {@link TableBuilder#key(String...)}.
* </p>
*
* @param callInfo Call Info.
* @param data Data set.
*/
public static void update(CallInfo callInfo, DataSet data) {
Table table = asTable(data.getSource());
List<String> keyColumns = table.getKeyColumns();
if (keyColumns.isEmpty()) {
throw new InvalidOperationException("No key columns defined.");
}

String[] tableColumns = table.getColumns();
List<String> columnsToUpdate = new LinkedList<>();
columnsToUpdate.addAll(Arrays.asList(tableColumns));
columnsToUpdate.removeAll(keyColumns);

if (columnsToUpdate.isEmpty()) {
throw new InvalidOperationException("No columns to update.");
}

DB db = table.getDB();
db.logUpdate(callInfo, data);

// Build SQL statement
StringBuilder sql = new StringBuilder("UPDATE ");
Iterator<String> itr = columnsToUpdate.iterator();
sql.append(table.getName())
.append(" SET ")
.append(itr.next())
.append("=?");
while (itr.hasNext()) {
sql.append(',')
.append(itr.next())
.append("=?");
}
itr = keyColumns.iterator();
sql.append(" WHERE ")
.append(itr.next())
.append("=?");
while (itr.hasNext()) {
sql.append(" AND ")
.append(itr.next())
.append("=?");
}

Map<String,Integer> colToStmtArg = new HashMap<>();
int stmtArgCtr = 1;
for (String c : columnsToUpdate) {
colToStmtArg.put(c.toLowerCase(), stmtArgCtr);
stmtArgCtr++;
}
for (String c : keyColumns) {
colToStmtArg.put(c.toLowerCase(), stmtArgCtr);
stmtArgCtr++;
}
// Perform operation
table.setDirtyStatus(true);
// System.out.println(sql.toString());
db.access(() -> {
final boolean batchMode = db.useBatchUpdates();
final int maxBatchSize = db.getMaximumBatchUpdateSize();

try(WrappedStatement ws = db.compile(sql.toString())) {
PreparedStatement updateStmt = ws.getStatement();
int batchSize = 0;
for (Row r : data.getRows()) {
final int n = r.length();
final Object[] colValues = r.data();
if (n != table.getColumnCount()) {
throw new InvalidOperationException("Invalid number of columns for update.");
}
for (int c = 0; c < n; c++) {
// System.out.printf("%d %s %s\n",
// c,colToStmtArg.get(tableColumns[c].toLowerCase()), colValues[c]);
updateStmt.setObject(colToStmtArg.get(tableColumns[c].toLowerCase()), colValues[c]);
}
if (batchMode) {
updateStmt.addBatch();
batchSize++;
if (batchSize == maxBatchSize) {
updateStmt.executeBatch();
batchSize = 0;
}
} else {
updateStmt.execute();
}
}
if (batchMode && batchSize > 0 ) {
updateStmt.executeBatch();
}
}
return 0;
});
}

/**
* Delete rows from data set.
*
* <p>
* The data set must relate to a table with a defined key (see {@link TableBuilder#key(String...)}.
* </p>
* @param callInfo Call Info.
* @param data Data set.
*/
public static void delete(CallInfo callInfo, DataSet data) {
Table table = asTable(data.getSource());
List<String> keyColumns = table.getKeyColumns();
if (keyColumns.isEmpty()) {
throw new InvalidOperationException("No key columns defined.");
}

DB db = table.getDB();
db.logDelete(callInfo, data);

// Build SQL statement
Iterator<String> itr = keyColumns.iterator();
StringBuilder sql = new StringBuilder();
sql.append("DELETE FROM ")
.append(table.getName())
.append(" WHERE ")
.append(itr.next())
.append("=?");
while (itr.hasNext()) {
sql.append(" AND ")
.append(itr.next())
.append("=?");
}

Map<String,Integer> colToStmtArg = new HashMap<>();
int stmtArgCtr = 1;
for (String c : keyColumns) {
colToStmtArg.put(c.toLowerCase(), stmtArgCtr);
stmtArgCtr++;
}
// Perform operation
table.setDirtyStatus(true);
// System.out.println(sql.toString());
db.access(() -> {
final boolean batchMode = db.useBatchUpdates();
final int maxBatchSize = db.getMaximumBatchUpdateSize();
String[] tableColumns = table.getColumns();
try(WrappedStatement ws = db.compile(sql.toString())) {
PreparedStatement deleteStmt = ws.getStatement();
int batchSize = 0;
for (Row r : data.getRows()) {
final int n = r.length();
final Object[] colValues = r.data();
if (n != table.getColumnCount()) {
throw new InvalidOperationException("Invalid number of columns for update.");
}
for (int c = 0; c < n; c++) {
// System.out.printf("%d %s %s\n",
// c,colToStmtArg.get(tableColumns[c].toLowerCase()), colValues[c]);
int iParam = colToStmtArg.getOrDefault(tableColumns[c].toLowerCase(), 0);
if (iParam != 0) {
deleteStmt.setObject(iParam, colValues[c]);
}
}
if (batchMode) {
deleteStmt.addBatch();
batchSize++;
if (batchSize == maxBatchSize) {
deleteStmt.executeBatch();
batchSize = 0;
}
} else {
deleteStmt.execute();
}
}
if (batchMode && batchSize > 0 ) {
deleteStmt.executeBatch();
}
}
return 0;
});
}

/**
* Delete all data from table.
* @param callInfo Call info.
Expand Down Expand Up @@ -173,7 +362,7 @@ static void truncate(CallInfo callInfo, Table table) {
}
return 0;
});

}

/**
Expand Down Expand Up @@ -222,7 +411,7 @@ public static void drop(CallInfo callInfo, DB db, String tableName) {
return 0;
});
}

/**
* Private constructor to prevent instantiation.
*/
Expand All @@ -231,4 +420,5 @@ private DBSetup() {
}



}
23 changes: 23 additions & 0 deletions src/main/java/org/jdbdt/JDBDT.java
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,29 @@ public static void assertTableDoesNotExist(String message, DB db, String tableNa
public static void insert(DataSet data) {
DBSetup.insert(CallInfo.create(), data);
}


/**
* Update a data set onto database.
*
* @param data Data set for insertion.
*/
public static void update(DataSet data) {
DBSetup.update(CallInfo.create(), data);
}


/**
* Delete data set onto database.
*
*
*
* @param data Data set for insertion.
*/
public static void delete(DataSet data) {
DBSetup.delete(CallInfo.create(), data);
}


/**
* Populate database with given data set.
Expand Down
Loading

0 comments on commit 83290e8

Please sign in to comment.