[#2265] Added prototype implementation for Record.delete()
This commit is contained in:
parent
9946b236e7
commit
b729a58a07
@ -53,7 +53,9 @@ import java.util.Collections;
|
||||
|
||||
import org.jooq.Cursor;
|
||||
import org.jooq.DSLContext;
|
||||
import org.jooq.Delete;
|
||||
import org.jooq.ExecuteContext;
|
||||
import org.jooq.Query;
|
||||
import org.jooq.Record;
|
||||
import org.jooq.Record1;
|
||||
import org.jooq.Record2;
|
||||
@ -100,21 +102,31 @@ extends BaseTest<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, UU, I, IPK, T7
|
||||
* This listener is used to check if a <code>SELECT</code> statement is
|
||||
* issued after a call to {@link Record#refresh()}.
|
||||
*/
|
||||
private static class NoSelectAfterRefreshListener extends DefaultExecuteListener {
|
||||
private static class NoStatementAfterCRUDListener extends DefaultExecuteListener {
|
||||
|
||||
/**
|
||||
* Default UID
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final Class<? extends Query> type;
|
||||
private final String crudMethod;
|
||||
|
||||
NoStatementAfterCRUDListener(Class<? extends Query> type, String crudMethod) {
|
||||
this.type = type;
|
||||
this.crudMethod = crudMethod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(ExecuteContext ctx) {
|
||||
super.start(ctx);
|
||||
|
||||
if (ctx.query() instanceof Select) {
|
||||
for (StackTraceElement e : Thread.currentThread().getStackTrace()) {
|
||||
if (e.getMethodName().equals("refresh")) {
|
||||
fail("Record.refresh() should not execute any queries");
|
||||
if (ctx.query() != null) {
|
||||
if (type.isAssignableFrom(ctx.query().getClass())) {
|
||||
for (StackTraceElement e : Thread.currentThread().getStackTrace()) {
|
||||
if (e.getMethodName().equals(crudMethod)) {
|
||||
fail("Record." + crudMethod + "() should not execute any " + type.getName() + " queries");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -140,7 +152,7 @@ extends BaseTest<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, UU, I, IPK, T7
|
||||
|
||||
@Test
|
||||
public void testKeepRSWithCloseAfterFetch() throws Exception {
|
||||
DSLContext create = create(new NoSelectAfterRefreshListener());
|
||||
DSLContext create = create(new NoStatementAfterCRUDListener(Select.class, "refresh"));
|
||||
|
||||
Result<B> b1 = create.selectFrom(TBook()).fetch();
|
||||
assertNull(b1.resultSet());
|
||||
@ -194,7 +206,7 @@ extends BaseTest<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, UU, I, IPK, T7
|
||||
return;
|
||||
}
|
||||
|
||||
DSLContext create = create(new NoSelectAfterRefreshListener());
|
||||
DSLContext create = create(new NoStatementAfterCRUDListener(Select.class, "refresh"));
|
||||
Result<B> b2 = create.selectFrom(TBook()).keepResultSet(KEEP_AFTER_FETCH).fetch();
|
||||
B r = b2.get(0);
|
||||
assertNotNull(b2.resultSet());
|
||||
@ -259,7 +271,7 @@ extends BaseTest<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, UU, I, IPK, T7
|
||||
}
|
||||
|
||||
jOOQAbstractTest.reset = false;
|
||||
DSLContext create = create(new NoSelectAfterRefreshListener());
|
||||
DSLContext create = create(new NoStatementAfterCRUDListener(Select.class, "refresh"));
|
||||
|
||||
// Use plain SQL to prevent fetching of UpdatableRecord
|
||||
Result<B> books =
|
||||
@ -297,7 +309,7 @@ extends BaseTest<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, UU, I, IPK, T7
|
||||
}
|
||||
|
||||
jOOQAbstractTest.reset = false;
|
||||
DSLContext create = create(new NoSelectAfterRefreshListener());
|
||||
DSLContext create = create(new NoStatementAfterCRUDListener(Select.class, "refresh"));
|
||||
|
||||
Cursor<B> books =
|
||||
create.selectFrom(TBook())
|
||||
@ -337,7 +349,7 @@ extends BaseTest<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, UU, I, IPK, T7
|
||||
|
||||
jOOQAbstractTest.reset = false;
|
||||
|
||||
DSLContext create = create(new NoSelectAfterRefreshListener());
|
||||
DSLContext create = create(new NoStatementAfterCRUDListener(Select.class, "refresh"));
|
||||
Record book =
|
||||
create.select()
|
||||
.from(TBook().getName())
|
||||
@ -374,7 +386,7 @@ extends BaseTest<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, UU, I, IPK, T7
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testKeepRSWithUpdateOnChangeRemove() throws Exception {
|
||||
public void testKeepRSWithUpdateOnChangeDelete() throws Exception {
|
||||
switch (dialect()) {
|
||||
case SQLITE:
|
||||
log.info("SKIPPING", "KeepResultSet tests");
|
||||
@ -382,6 +394,24 @@ extends BaseTest<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, UU, I, IPK, T7
|
||||
}
|
||||
|
||||
jOOQAbstractTest.reset = false;
|
||||
|
||||
DSLContext create = create(new NoStatementAfterCRUDListener(Delete.class, "delete"));
|
||||
Result<B> books =
|
||||
create.selectFrom(TBook())
|
||||
.orderBy(TBook_ID())
|
||||
.keepResultSet(UPDATE_ON_CHANGE)
|
||||
.fetch();
|
||||
|
||||
B b2 = books.get(1);
|
||||
assertEquals(1, b2.delete());
|
||||
ResultSet rs = b2.resultSet();
|
||||
rs.beforeFirst();
|
||||
assertTrue(rs.next());
|
||||
assertTrue(rs.next());
|
||||
assertTrue(rs.next());
|
||||
assertFalse(rs.next());
|
||||
|
||||
System.out.println(books);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@ -2241,8 +2241,8 @@ public abstract class jOOQAbstractTest<
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testKeepRSWithUpdateOnChangeRemove() throws Exception {
|
||||
new KeepResultSetTests(this).testKeepRSWithUpdateOnChangeRemove();
|
||||
public void testKeepRSWithUpdateOnChangeDelete() throws Exception {
|
||||
new KeepResultSetTests(this).testKeepRSWithUpdateOnChangeDelete();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@ -1042,6 +1042,8 @@ public interface Record extends Attachable, Comparable<Record> {
|
||||
// Methods related to the underlying ResultSet (if applicable)
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
int delete() throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Refresh this record from the database.
|
||||
* <p>
|
||||
|
||||
@ -298,6 +298,7 @@ public interface UpdatableRecord<R extends UpdatableRecord<R>> extends TableReco
|
||||
* @throws DataChangedException If optimistic locking is enabled and the
|
||||
* record has already been changed/deleted in the database
|
||||
*/
|
||||
@Override
|
||||
int delete() throws DataAccessException, DataChangedException;
|
||||
|
||||
/**
|
||||
|
||||
@ -66,6 +66,7 @@ import org.jooq.UniqueKey;
|
||||
import org.jooq.exception.DataAccessException;
|
||||
import org.jooq.exception.InvalidResultException;
|
||||
import org.jooq.exception.MappingException;
|
||||
import org.jooq.impl.CursorImpl.CursorResultSet;
|
||||
import org.jooq.tools.Convert;
|
||||
import org.jooq.tools.JooqLogger;
|
||||
|
||||
@ -86,7 +87,7 @@ abstract class AbstractRecord extends AbstractStore implements Record {
|
||||
final RowImpl fields;
|
||||
final Value<?>[] values;
|
||||
transient KeepResultSetMode keepResultSetMode;
|
||||
transient ResultSet rs;
|
||||
transient CursorResultSet rs;
|
||||
transient int rsIndex;
|
||||
|
||||
AbstractRecord(Collection<? extends Field<?>> fields) {
|
||||
@ -699,6 +700,28 @@ abstract class AbstractRecord extends AbstractStore implements Record {
|
||||
// XXX: Methods related to the underlying ResultSet (if applicable)
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p>
|
||||
* Subclasses may override this
|
||||
*/
|
||||
@Override
|
||||
public int delete() {
|
||||
checkRsAvailable("Cannot delete record. No ResultSet available");
|
||||
|
||||
try {
|
||||
|
||||
// [#2265] TODO: This code is prototypical.
|
||||
rs.absolute(rsIndex - 1);
|
||||
rs.deleteRow();
|
||||
|
||||
return 1;
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw translate("Cannot delete record", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void refresh() {
|
||||
refresh(fields.fields.fields);
|
||||
@ -710,22 +733,25 @@ abstract class AbstractRecord extends AbstractStore implements Record {
|
||||
* Subclasses may override this
|
||||
*/
|
||||
@Override
|
||||
public void refresh(Field<?>... f) throws DataAccessException {
|
||||
if (rs != null) {
|
||||
try {
|
||||
public void refresh(Field<?>... f) {
|
||||
checkRsAvailable("Cannot refresh record. No ResultSet available");
|
||||
|
||||
// [#2265] TODO: This code is prototypical. fetchLazy() is not
|
||||
// the best way to fetch a record
|
||||
rs.absolute(rsIndex - 1);
|
||||
AbstractRecord record = (AbstractRecord) create().fetchLazy(rs).fetchOne();
|
||||
setValues(f, record);
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw translate("Cannot refresh record", e);
|
||||
}
|
||||
try {
|
||||
|
||||
// [#2265] TODO: This code is prototypical. fetchLazy() is not
|
||||
// the best way to fetch a record
|
||||
rs.absolute(rsIndex - 1);
|
||||
AbstractRecord record = (AbstractRecord) create().fetchLazy(rs).fetchOne();
|
||||
setValues(f, record);
|
||||
}
|
||||
else {
|
||||
throw new DataAccessException("Cannot refresh record. No ResultSet available");
|
||||
catch (SQLException e) {
|
||||
throw translate("Cannot refresh record", e);
|
||||
}
|
||||
}
|
||||
|
||||
private final void checkRsAvailable(String message) {
|
||||
if (rs == null) {
|
||||
throw new DataAccessException(message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -302,35 +302,40 @@ public class UpdatableRecordImpl<R extends UpdatableRecord<R>> extends TableReco
|
||||
|
||||
@Override
|
||||
public final int delete() {
|
||||
TableField<R, ?>[] keys = getPrimaryKey().getFieldsArray();
|
||||
if (rs != null) {
|
||||
return super.delete();
|
||||
}
|
||||
else {
|
||||
TableField<R, ?>[] keys = getPrimaryKey().getFieldsArray();
|
||||
|
||||
try {
|
||||
DeleteQuery<R> delete1 = create().deleteQuery(getTable());
|
||||
Utils.addConditions(delete1, this, keys);
|
||||
try {
|
||||
DeleteQuery<R> delete1 = create().deleteQuery(getTable());
|
||||
Utils.addConditions(delete1, this, keys);
|
||||
|
||||
if (isExecuteWithOptimisticLocking()) {
|
||||
if (isExecuteWithOptimisticLocking()) {
|
||||
|
||||
// [#1596] Add additional conditions for version and/or timestamp columns
|
||||
if (isTimestampOrVersionAvailable()) {
|
||||
addConditionForVersionAndTimestamp(delete1);
|
||||
// [#1596] Add additional conditions for version and/or timestamp columns
|
||||
if (isTimestampOrVersionAvailable()) {
|
||||
addConditionForVersionAndTimestamp(delete1);
|
||||
}
|
||||
|
||||
// [#1547] Try fetching the Record again first, and compare this
|
||||
// Record's original values with the ones in the database
|
||||
else {
|
||||
checkIfChanged(keys);
|
||||
}
|
||||
}
|
||||
|
||||
// [#1547] Try fetching the Record again first, and compare this
|
||||
// Record's original values with the ones in the database
|
||||
else {
|
||||
checkIfChanged(keys);
|
||||
}
|
||||
int result = delete1.execute();
|
||||
checkIfChanged(result, null, null);
|
||||
return result;
|
||||
}
|
||||
|
||||
int result = delete1.execute();
|
||||
checkIfChanged(result, null, null);
|
||||
return result;
|
||||
}
|
||||
|
||||
// [#673] If store() is called after delete(), a new INSERT should
|
||||
// be executed and the record should be recreated
|
||||
finally {
|
||||
changed(true);
|
||||
// [#673] If store() is called after delete(), a new INSERT should
|
||||
// be executed and the record should be recreated
|
||||
finally {
|
||||
changed(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user