[#2265] Add Result.store(), delete(), refresh(), to allow for

batch-synchronisation of Records contained in a Result - Prototype
implementation
This commit is contained in:
Lukas Eder 2013-05-11 10:11:47 +02:00
parent 342c769309
commit 712a0f2f62
5 changed files with 102 additions and 7 deletions

View File

@ -52,6 +52,7 @@ import java.sql.SQLException;
import java.util.Collections;
import org.jooq.Cursor;
import org.jooq.Record;
import org.jooq.Record1;
import org.jooq.Record2;
import org.jooq.Record3;
@ -134,23 +135,32 @@ extends BaseTest<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, UU, I, IPK, T7
return;
}
Result<B> b2 = create().selectFrom(TBook()).keepResultSet(KEEP_AFTER_FETCH).fetch();
Result<Record> b2 = create().select().from(TBook().getName()).keepResultSet(KEEP_AFTER_FETCH).fetch();
Record r = b2.get(0);
assertNotNull(b2.resultSet());
assertNotNull(r.resultSet());
testFailUpdateRow(b2.resultSet());
// Changing a TITLE has no effect
b2.get(0).setValue(TBook_TITLE(), "XX");
assertTrue(b2.get(0).changed());
assertFalse(b2.get(0).original().equals(b2.get(0)));
r.setValue(TBook_TITLE(), "XX");
assertEquals("XX", r.getValue(TBook_TITLE()));
assertTrue(r.changed());
assertFalse(r.original().equals(r));
assertEquals(BOOK_TITLES.get(0), getBook(1).getValue(TBook_TITLE()));
// Refresh the record
r.refresh();
assertEquals("1984", r.getValue(TBook_TITLE()));
assertFalse(r.changed());
assertEquals(r.original(), r);
b2.close();
assertNull(b2.resultSet());
Cursor<B> c1 = create().selectFrom(TBook()).keepResultSet(KEEP_AFTER_FETCH).fetchLazy();
Cursor<Record> c1 = create().select().from(TBook().getName()).keepResultSet(KEEP_AFTER_FETCH).fetchLazy();
assertFalse(c1.closesAfterFetch());
while (c1.hasNext()) {
Result<B> result = c1.fetch(1);
Result<Record> result = c1.fetch(1);
assertNotNull(result.get(0).resultSet());
assertNotNull(result.resultSet());
assertNotNull(c1.resultSet());
@ -304,5 +314,6 @@ extends BaseTest<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, UU, I, IPK, T7
* - Implement all data types from ResultSet.updateXXX() (e.g. updateInt(), etc)
* - Implement UPDATE_ON_STORE
* - refresh() should not execute a new query if a ResultSet is available
* - TYPE_SCROLL_SENSITIVE should be active for KEEP_AFTER_FETCH (for refresh())
*/
}

View File

@ -1042,6 +1042,57 @@ public interface Record extends Attachable, Comparable<Record> {
// Methods related to the underlying ResultSet (if applicable)
// -------------------------------------------------------------------------
/**
* Refresh this record from the database.
* <p>
* A successful refresh results in the following:
* <ul>
* <li>{@link #valuesRow()} will have been restored to the respective values
* from the database</li>
* <li>{@link #original()} will match this record</li>
* <li>{@link #changed()} will be <code>false</code></li>
* </ul>
* <p>
* Refreshing can trigger any of the following actions:
* <ul>
* <li>Re-reading the underlying {@link #resultSet()}, if that
* <code>ResultSet</code> is available.</li>
* <li>Executing a new <code>SELECT</code> statement, if this is an
* {@link UpdatableRecord}.</li>
* <li>Failing, otherwise</li>
* </ul>
* <p>
* This is the same as calling <code>record.refresh(record.fields())</code>
*
* @throws DataAccessException This exception is thrown if
* <ul>
* <li>something went wrong executing the query</li> <li>the
* {@link #resultSet()} is not available, or is in
* {@link ResultSet#TYPE_FORWARD_ONLY} mode, such that
* refreshing is not possible.</li><li>the record does not exist
* anymore in the database</li>
* </ul>
* @see UpdatableRecord#refresh()
* @see ResultQuery#keepResultSet(KeepResultSetMode)
*/
void refresh() throws DataAccessException;
// /**
// * Refresh this record from the database, based on the value of the primary
// * key or main unique key.
// * <p>
// * The executed statement is <code><pre>
// * SELECT [fields] FROM [table]
// * WHERE [primary key fields = primary key values]</pre></code>
// *
// * @throws DataAccessException This exception is thrown if
// * <ul>
// * <li>something went wrong executing the query</li> <li>the
// * record does not exist anymore in the database</li>
// * </ul>
// */
// void refresh(Field<?>... fields) throws DataAccessException;
/**
* Close the underlying JDBC {@link ResultSet}, if applicable.
* <p>

View File

@ -317,6 +317,7 @@ public interface UpdatableRecord<R extends UpdatableRecord<R>> extends TableReco
* record does not exist anymore in the database</li>
* </ul>
*/
@Override
void refresh() throws DataAccessException;
/**

View File

@ -63,6 +63,7 @@ import org.jooq.RecordMapper;
import org.jooq.Result;
import org.jooq.Table;
import org.jooq.UniqueKey;
import org.jooq.exception.DataAccessException;
import org.jooq.exception.InvalidResultException;
import org.jooq.exception.MappingException;
import org.jooq.tools.Convert;
@ -692,6 +693,29 @@ abstract class AbstractRecord extends AbstractStore implements Record {
// XXX: Methods related to the underlying ResultSet (if applicable)
// -------------------------------------------------------------------------
@Override
public void refresh() {
if (rs != null) {
try {
// [#2265] TODO: This code is prototypical. fetchLazy() is not
// the best way to fetch a record
rs.absolute(rsIndex - 1);
Record record = create().fetchLazy(rs).fetchOne();
for (int i = 0; i < record.size(); i++) {
setValue(i, new Value<Object>(record.getValue(i)));
}
}
catch (SQLException e) {
throw translate("Cannot refresh record", e);
}
}
else {
throw new DataAccessException("Cannot refresh record. No ResultSet available");
}
}
@Override
public final void close() {
try {

View File

@ -35,11 +35,13 @@
*/
package org.jooq.impl;
import static java.sql.ResultSet.CONCUR_READ_ONLY;
import static java.sql.ResultSet.CONCUR_UPDATABLE;
import static java.sql.ResultSet.TYPE_SCROLL_SENSITIVE;
import static java.util.Arrays.asList;
import static java.util.concurrent.Executors.newSingleThreadExecutor;
import static org.jooq.KeepResultSetMode.CLOSE_AFTER_FETCH;
import static org.jooq.KeepResultSetMode.KEEP_AFTER_FETCH;
import static org.jooq.KeepResultSetMode.UPDATE_ON_CHANGE;
import static org.jooq.KeepResultSetMode.UPDATE_ON_STORE;
import static org.jooq.SQLDialect.ASE;
@ -224,7 +226,12 @@ abstract class AbstractResultQuery<R extends Record> extends AbstractQuery imple
}
}
// [#1846] When updatable Results are fetched
// [#1846] When scrollable Results are fetched
else if (keepResultSetMode == KEEP_AFTER_FETCH) {
ctx.statement(ctx.connection().prepareStatement(ctx.sql(), TYPE_SCROLL_SENSITIVE, CONCUR_READ_ONLY));
}
// [#1846] When scrollable and updatable Results are fetched
else if (keepResultSetMode == UPDATE_ON_CHANGE ||
keepResultSetMode == UPDATE_ON_STORE) {
ctx.statement(ctx.connection().prepareStatement(ctx.sql(), TYPE_SCROLL_SENSITIVE, CONCUR_UPDATABLE));
@ -350,6 +357,7 @@ abstract class AbstractResultQuery<R extends Record> extends AbstractQuery imple
@Override
protected final boolean keepResultSet() {
return lazy
|| keepResultSetMode == KEEP_AFTER_FETCH
|| keepResultSetMode == UPDATE_ON_CHANGE
|| keepResultSetMode == UPDATE_ON_STORE;
}