[#3322] Add UpdatableRecord.store(Field<?>...), insert(Field<?>...), update(Field<?>...)
This commit is contained in:
parent
8e8e44a43e
commit
d50e283ba9
@ -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;
|
||||
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
});
|
||||
|
||||
Loading…
Reference in New Issue
Block a user