[#3322] Add UpdatableRecord.store(Field<?>...), insert(Field<?>...), update(Field<?>...)

This commit is contained in:
Lukas Eder 2014-06-06 11:09:29 +02:00
parent 8e8e44a43e
commit d50e283ba9
6 changed files with 168 additions and 21 deletions

View File

@ -500,6 +500,71 @@ extends BaseTest<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, UU, I, IPK, T7
.fetchOne(0));
}
public void testUpdatablesPartialUpdates() throws Exception {
jOOQAbstractTest.reset = false;
A author1 = create().fetchOne(TAuthor(), TAuthor_ID().eq(1));
// Store only FIRST_NAME, keep a changed value for LAST_NAME in the updatable record
author1.setValue(TAuthor_FIRST_NAME(), "A1");
author1.setValue(TAuthor_LAST_NAME(), "B1");
assertEquals(1, author1.store(TAuthor_FIRST_NAME()));
assertTrue(author1.changed());
assertFalse(author1.changed(TAuthor_ID()));
assertFalse(author1.changed(TAuthor_FIRST_NAME()));
assertTrue(author1.changed(TAuthor_LAST_NAME()));
// Store the LAST_NAME value as well
assertEquals(1, author1.store());
assertFalse(author1.changed());
assertFalse(author1.changed(TAuthor_ID()));
assertFalse(author1.changed(TAuthor_FIRST_NAME()));
assertFalse(author1.changed(TAuthor_LAST_NAME()));
// Repeat, but this time, don't store LAST_NAME at all
author1.setValue(TAuthor_FIRST_NAME(), "A2");
author1.setValue(TAuthor_LAST_NAME(), "B2");
assertEquals(1, author1.store(TAuthor_FIRST_NAME()));
assertTrue(author1.changed());
assertFalse(author1.changed(TAuthor_ID()));
assertFalse(author1.changed(TAuthor_FIRST_NAME()));
assertTrue(author1.changed(TAuthor_LAST_NAME()));
author1.refresh();
assertEquals(1, (int) author1.getValue(TAuthor_ID()));
assertEquals("A2", author1.getValue(TAuthor_FIRST_NAME()));
assertEquals("B1", author1.getValue(TAuthor_LAST_NAME()));
// Can't store only FIRST_NAME, because of a missing primary key value
A author2 = newAuthor(3);
author2.setValue(TAuthor_FIRST_NAME(), "A3");
author2.setValue(TAuthor_LAST_NAME(), "B3");
try {
author2.store(TAuthor_FIRST_NAME());
fail();
}
catch (DataAccessException expected) {
assertTrue(author2.changed());
assertTrue(author2.changed(TAuthor_ID()));
assertTrue(author2.changed(TAuthor_FIRST_NAME()));
assertTrue(author2.changed(TAuthor_LAST_NAME()));
assertNull(create().fetchOne(TAuthor(), TAuthor_ID().eq(3)));
}
// Now insert ID and LAST_NAME
assertEquals(1, author2.store(TAuthor_ID(), TAuthor_LAST_NAME()));
assertTrue(author2.changed());
assertFalse(author2.changed(TAuthor_ID()));
assertTrue(author2.changed(TAuthor_FIRST_NAME()));
assertFalse(author2.changed(TAuthor_LAST_NAME()));
author2.refresh();
assertEquals(3, (int) author2.getValue(TAuthor_ID()));
assertNull(author2.getValue(TAuthor_FIRST_NAME()));
assertEquals("B3", author2.getValue(TAuthor_LAST_NAME()));
}
public void testUpdatablesPKChangePK() throws Exception {
jOOQAbstractTest.reset = false;

View File

@ -2072,6 +2072,11 @@ public abstract class jOOQAbstractTest<
new CRUDTests(this).testUpdatablesPK();
}
@Test
public void testUpdatablesPartialUpdates() throws Exception {
new CRUDTests(this).testUpdatablesPartialUpdates();
}
@Test
public void testUpdatablesPKChangePK() throws Exception {
new CRUDTests(this).testUpdatablesPKChangePK();

View File

@ -76,6 +76,17 @@ public interface TableRecord<R extends TableRecord<R>> extends Record {
*/
int insert() throws DataAccessException;
/**
* Store parts of this record to the database using an <code>INSERT</code>
* statement.
*
* @return <code>1</code> if the record was stored to the database. <code>0
* </code> if storing was not necessary.
* @throws DataAccessException if something went wrong executing the query
* @see #insert()
*/
int insert(Field<?>... fields) throws DataAccessException;
/**
* Fetch a parent record of this record, given a foreign key
* <p>

View File

@ -211,6 +211,8 @@ public interface UpdatableRecord<R extends UpdatableRecord<R>> extends TableReco
* this record were changed, you can explicitly set the changed flags for
* all values with {@link #changed(boolean)} or for single values with
* {@link #changed(Field, boolean)}, prior to storing.
* <p>
* This is the same as calling <code>record.store(record.fields())</code>
*
* @return <code>1</code> if the record was stored to the database. <code>0
* </code> if storing was not necessary.
@ -222,6 +224,20 @@ public interface UpdatableRecord<R extends UpdatableRecord<R>> extends TableReco
*/
int store() throws DataAccessException, DataChangedException;
/**
* Store parts of this record to the database.
*
* @return <code>1</code> if the record was stored to the database. <code>0
* </code> if storing was not necessary.
* @throws DataAccessException if something went wrong executing the query
* @throws DataChangedException If optimistic locking is enabled and the
* record has already been changed/deleted in the database
* @see #store()
* @see #insert(Field...)
* @see #update(Field...)
*/
int store(Field<?>... fields) throws DataAccessException, DataChangedException;
/**
* Store this record back to the database using an <code>INSERT</code>
* statement.
@ -233,6 +249,8 @@ public interface UpdatableRecord<R extends UpdatableRecord<R>> extends TableReco
* this record were changed, you can explicitly set the changed flags for
* all values with {@link #changed(boolean)} or for single values with
* {@link #changed(Field, boolean)}, prior to insertion.
* <p>
* This is the same as calling <code>record.insert(record.fields())</code>
*
* @return <code>1</code> if the record was stored to the database. <code>0
* </code> if storing was not necessary.
@ -242,6 +260,18 @@ public interface UpdatableRecord<R extends UpdatableRecord<R>> extends TableReco
@Override
int insert() throws DataAccessException;
/**
* Store parts of this record to the database using an <code>INSERT</code>
* statement.
*
* @return <code>1</code> if the record was stored to the database. <code>0
* </code> if storing was not necessary.
* @throws DataAccessException if something went wrong executing the query
* @see #insert()
*/
@Override
int insert(Field<?>... fields) throws DataAccessException;
/**
* Store this record back to the database using an <code>UPDATE</code>
* statement.
@ -253,6 +283,8 @@ public interface UpdatableRecord<R extends UpdatableRecord<R>> extends TableReco
* this record were changed, you can explicitly set the changed flags for
* all values with {@link #changed(boolean)} or for single values with
* {@link #changed(Field, boolean)}, prior to updating.
* <p>
* This is the same as calling <code>record.update(record.fields())</code>
*
* @return <code>1</code> if the record was stored to the database. <code>0
* </code> if storing was not necessary.
@ -263,6 +295,19 @@ public interface UpdatableRecord<R extends UpdatableRecord<R>> extends TableReco
*/
int update() throws DataAccessException, DataChangedException;
/**
* Store parts of this record to the database using an <code>UPDATE</code>
* statement.
*
* @return <code>1</code> if the record was stored to the database. <code>0
* </code> if storing was not necessary.
* @throws DataAccessException if something went wrong executing the query
* @throws DataChangedException If optimistic locking is enabled and the
* record has already been changed/deleted in the database
* @see #update()
*/
int update(Field<?>... fields) throws DataAccessException, DataChangedException;
/**
* Deletes this record from the database, based on the value of the primary
* key or main unique key.

View File

@ -120,10 +120,15 @@ public class TableRecordImpl<R extends TableRecord<R>> extends AbstractRecord im
@Override
public final int insert() {
return storeInsert();
return insert(fields.fields.fields);
}
final int storeInsert() {
@Override
public final int insert(Field<?>... storeFields) {
return storeInsert(storeFields);
}
final int storeInsert(final Field<?>[] storeFields) {
final int[] result = new int[1];
delegate(configuration(), (Record) this, INSERT)
@ -131,7 +136,7 @@ public class TableRecordImpl<R extends TableRecord<R>> extends AbstractRecord im
@Override
public Record operate(Record record) throws RuntimeException {
result[0] = storeInsert0();
result[0] = storeInsert0(storeFields);
return record;
}
});
@ -139,10 +144,10 @@ public class TableRecordImpl<R extends TableRecord<R>> extends AbstractRecord im
return result[0];
}
final int storeInsert0() {
final int storeInsert0(Field<?>[] storeFields) {
DSLContext create = create();
InsertQuery<R> insert = create.insertQuery(getTable());
addChangedValues(insert);
addChangedValues(storeFields, insert);
// Don't store records if no value was set by client code
if (!insert.isExecutable()) return 0;
@ -180,7 +185,9 @@ public class TableRecordImpl<R extends TableRecord<R>> extends AbstractRecord im
}
}
changed(false);
for (Field<?> storeField : storeFields)
changed(storeField, false);
fetched = true;
}
@ -215,9 +222,11 @@ public class TableRecordImpl<R extends TableRecord<R>> extends AbstractRecord im
/**
* Set all changed values of this record to a store query
*/
final void addChangedValues(StoreQuery<R> query) {
final void addChangedValues(Field<?>[] storeFields, StoreQuery<R> query) {
Fields<Record> f = new Fields<Record>(storeFields);
for (Field<?> field : fields.fields.fields) {
if (changed(field)) {
if (changed(field) && f.field(field) != null) {
addValue(query, field);
}
}

View File

@ -69,6 +69,7 @@ import org.jooq.TableRecord;
import org.jooq.UniqueKey;
import org.jooq.UpdatableRecord;
import org.jooq.UpdateQuery;
import org.jooq.exception.DataAccessException;
import org.jooq.exception.DataChangedException;
import org.jooq.exception.InvalidResultException;
import org.jooq.tools.StringUtils;
@ -117,6 +118,11 @@ public class UpdatableRecordImpl<R extends UpdatableRecord<R>> extends TableReco
@Override
public final int store() {
return store(fields.fields.fields);
}
@Override
public final int store(final Field<?>... storeFields) throws DataAccessException, DataChangedException {
final int[] result = new int[1];
delegate(configuration(), (Record) this, STORE)
@ -124,7 +130,7 @@ public class UpdatableRecordImpl<R extends UpdatableRecord<R>> extends TableReco
@Override
public Record operate(Record record) throws RuntimeException {
result[0] = store0();
result[0] = store0(storeFields);
return record;
}
});
@ -134,10 +140,15 @@ public class UpdatableRecordImpl<R extends UpdatableRecord<R>> extends TableReco
@Override
public final int update() {
return storeUpdate(getPrimaryKey().getFieldsArray());
return update(fields.fields.fields);
}
private final int store0() {
@Override
public int update(Field<?>... storeFields) throws DataAccessException, DataChangedException {
return storeUpdate(storeFields, getPrimaryKey().getFieldsArray());
}
private final int store0(Field<?>[] storeFields) {
TableField<R, ?>[] keys = getPrimaryKey().getFieldsArray();
boolean executeUpdate = false;
@ -166,16 +177,16 @@ public class UpdatableRecordImpl<R extends UpdatableRecord<R>> extends TableReco
int result = 0;
if (executeUpdate) {
result = storeUpdate(keys);
result = storeUpdate(storeFields, keys);
}
else {
result = storeInsert();
result = storeInsert(storeFields);
}
return result;
}
private final int storeUpdate(final TableField<R, ?>[] keys) {
private final int storeUpdate(final Field<?>[] storeFields, final TableField<R, ?>[] keys) {
final int[] result = new int[1];
delegate(configuration(), (Record) this, UPDATE)
@ -183,7 +194,7 @@ public class UpdatableRecordImpl<R extends UpdatableRecord<R>> extends TableReco
@Override
public Record operate(Record record) throws RuntimeException {
result[0] = storeUpdate0(keys);
result[0] = storeUpdate0(storeFields, keys);
return record;
}
});
@ -192,9 +203,9 @@ public class UpdatableRecordImpl<R extends UpdatableRecord<R>> extends TableReco
}
private final int storeUpdate0(TableField<R, ?>[] keys) {
private final int storeUpdate0(Field<?>[] storeFields, TableField<R, ?>[] keys) {
UpdateQuery<R> update = create().updateQuery(getTable());
addChangedValues(update);
addChangedValues(storeFields, update);
Utils.addConditions(update, this, keys);
// Don't store records if no value was set by client code
@ -223,7 +234,8 @@ public class UpdatableRecordImpl<R extends UpdatableRecord<R>> extends TableReco
checkIfChanged(result, version, timestamp);
if (result > 0) {
changed(false);
for (Field<?> storeField : storeFields)
changed(storeField, false);
}
return result;
@ -285,9 +297,9 @@ public class UpdatableRecordImpl<R extends UpdatableRecord<R>> extends TableReco
}
@Override
public final void refresh(final Field<?>... f) {
public final void refresh(final Field<?>... refreshFields) {
SelectQuery<Record> select = create().selectQuery();
select.addSelect(f);
select.addSelect(refreshFields);
select.addFrom(getTable());
Utils.addConditions(select, this, getPrimaryKey().getFieldsArray());
@ -298,7 +310,7 @@ public class UpdatableRecordImpl<R extends UpdatableRecord<R>> extends TableReco
.operate(new RecordOperation<Record, RuntimeException>() {
@Override
public Record operate(Record record) throws RuntimeException {
setValues(f, source);
setValues(refreshFields, source);
return record;
}
});