[jOOQ/jOOQ#8755] Add Loader[CSV|JSON|Rows]Step#fieldsFromSource()
This new `fieldsFromSource()` method can be used when all or a subset of the input field names exactly match the target table column names. The load operation can then be executed without having to specify the fields and will create rows with all matching fields (other fields are ignored). Since the fields are mapped by name this requires the input to specify the field names. For CSV this means that there must be a header row, otherwise using `fieldsFromSource()` will result in a runtime exception.
This commit is contained in:
parent
93bfffea5c
commit
11a5422efc
@ -40,6 +40,7 @@ package org.jooq;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.jooq.LoaderFieldMapper.LoaderFieldContext;
|
||||
import org.jooq.exception.LoaderConfigurationException;
|
||||
|
||||
/**
|
||||
* The <code>Loader</code> API is used for configuring data loads.
|
||||
@ -102,4 +103,16 @@ public interface LoaderCSVStep<R extends Record> {
|
||||
*/
|
||||
@Support
|
||||
LoaderCSVOptionsStep<R> fields(LoaderFieldMapper mapper);
|
||||
|
||||
/**
|
||||
* Indicate that all input fields which have a corresponding field in the
|
||||
* target table (with the same name) should be loaded.
|
||||
* <p>
|
||||
* When {@link LoaderLoadStep#execute() executing the loader} input fields
|
||||
* for which there is no match in the target table will be logged and if no
|
||||
* field names can be derived for the input data a
|
||||
* {@link LoaderConfigurationException} will be reported.
|
||||
*/
|
||||
@Support
|
||||
LoaderCSVOptionsStep<R> fieldsFromSource();
|
||||
}
|
||||
|
||||
@ -40,6 +40,7 @@ package org.jooq;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.jooq.LoaderFieldMapper.LoaderFieldContext;
|
||||
import org.jooq.exception.LoaderConfigurationException;
|
||||
|
||||
/**
|
||||
* The <code>Loader</code> API is used for configuring data loads.
|
||||
@ -53,7 +54,7 @@ import org.jooq.LoaderFieldMapper.LoaderFieldContext;
|
||||
public interface LoaderJSONStep<R extends Record> {
|
||||
|
||||
/**
|
||||
* Specify the the fields to be loaded into the table in the correct order.
|
||||
* Specify the fields to be loaded into the table in the correct order.
|
||||
* <p>
|
||||
* The JSON column at index <code>i</code> is inserted into the table field
|
||||
* at index <code>i</code>. If <code>fields[i] == null</code> or
|
||||
@ -64,7 +65,7 @@ public interface LoaderJSONStep<R extends Record> {
|
||||
LoaderJSONOptionsStep<R> fields(Field<?>... fields);
|
||||
|
||||
/**
|
||||
* Specify the the fields to be loaded into the table in the correct order.
|
||||
* Specify the fields to be loaded into the table in the correct order.
|
||||
* <p>
|
||||
* The JSON column at index <code>i</code> is inserted into the table field
|
||||
* at index <code>i</code>. If
|
||||
@ -86,4 +87,16 @@ public interface LoaderJSONStep<R extends Record> {
|
||||
*/
|
||||
@Support
|
||||
LoaderJSONOptionsStep<R> fields(LoaderFieldMapper mapper);
|
||||
|
||||
/**
|
||||
* Indicate that all input fields which have a corresponding field in the
|
||||
* target table (with the same name) should be loaded.
|
||||
* <p>
|
||||
* When {@link LoaderLoadStep#execute() executing the loader} input fields
|
||||
* for which there is no match in the target table will be logged and if no
|
||||
* field names can be derived for the input data a
|
||||
* {@link LoaderConfigurationException} will be reported.
|
||||
*/
|
||||
@Support
|
||||
LoaderJSONOptionsStep<R> fieldsFromSource();
|
||||
}
|
||||
|
||||
@ -40,6 +40,7 @@ package org.jooq;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.jooq.LoaderFieldMapper.LoaderFieldContext;
|
||||
import org.jooq.exception.LoaderConfigurationException;
|
||||
|
||||
/**
|
||||
* The <code>Loader</code> API is used for configuring data loads.
|
||||
@ -103,4 +104,15 @@ public interface LoaderRowsStep<R extends Record> {
|
||||
@Support
|
||||
LoaderListenerStep<R> fields(LoaderFieldMapper mapper);
|
||||
|
||||
/**
|
||||
* Indicate that all input fields which have a corresponding field in the
|
||||
* target table (with the same name) should be loaded.
|
||||
* <p>
|
||||
* When {@link LoaderLoadStep#execute() executing the loader} input fields
|
||||
* for which there is no match in the target table will be logged and if no
|
||||
* field names can be derived for the input data a
|
||||
* {@link LoaderConfigurationException} will be reported.
|
||||
*/
|
||||
@Support
|
||||
LoaderListenerStep<R> fieldsFromSource();
|
||||
}
|
||||
|
||||
@ -82,6 +82,7 @@ import org.jooq.Source;
|
||||
import org.jooq.Table;
|
||||
import org.jooq.exception.DataAccessException;
|
||||
import org.jooq.exception.LoaderConfigurationException;
|
||||
import org.jooq.tools.JooqLogger;
|
||||
import org.jooq.tools.StringUtils;
|
||||
import org.jooq.tools.csv.CSVParser;
|
||||
import org.jooq.tools.csv.CSVReader;
|
||||
@ -104,6 +105,8 @@ final class LoaderImpl<R extends Record> implements
|
||||
LoaderJSONOptionsStep<R>,
|
||||
Loader<R> {
|
||||
|
||||
private static final JooqLogger log = JooqLogger.getLogger(LoaderImpl.class);
|
||||
|
||||
// Configuration constants
|
||||
// -----------------------
|
||||
private static final int ON_DUPLICATE_KEY_ERROR = 0;
|
||||
@ -156,6 +159,7 @@ final class LoaderImpl<R extends Record> implements
|
||||
private Field<?>[] source;
|
||||
private Field<?>[] fields;
|
||||
private LoaderFieldMapper fieldMapper;
|
||||
private boolean fieldsFromSource;
|
||||
private boolean[] primaryKey;
|
||||
|
||||
// Result data
|
||||
@ -547,29 +551,46 @@ final class LoaderImpl<R extends Record> implements
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoaderImpl<R> fieldsFromSource() {
|
||||
fieldsFromSource = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
private final void fields0(Object[] row) {
|
||||
Field<?>[] f = new Field[row.length];
|
||||
|
||||
// [#5145] When loading arrays, or when CSV headers are ignored,
|
||||
// the source is still null at this stage.
|
||||
if (source == null)
|
||||
source = Tools.fields(row.length);
|
||||
if (fieldsFromSource)
|
||||
throw new LoaderConfigurationException("Using fieldsFromSource() requires field names to be available in source.");
|
||||
else
|
||||
source = Tools.fields(row.length);
|
||||
|
||||
for (int i = 0; i < row.length; i++) {
|
||||
final int index = i;
|
||||
if (fieldMapper != null)
|
||||
for (int i = 0; i < row.length; i++) {
|
||||
final int index = i;
|
||||
|
||||
f[i] = fieldMapper.map(new LoaderFieldContext() {
|
||||
@Override
|
||||
public int index() {
|
||||
return index;
|
||||
}
|
||||
f[i] = fieldMapper.map(new LoaderFieldContext() {
|
||||
@Override
|
||||
public int index() {
|
||||
return index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Field<?> field() {
|
||||
return source[index];
|
||||
}
|
||||
});
|
||||
}
|
||||
@Override
|
||||
public Field<?> field() {
|
||||
return source[index];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
else if (fieldsFromSource)
|
||||
for (int i = 0; i < row.length; i++) {
|
||||
f[i] = table.field(source[i]);
|
||||
if (f[i] == null)
|
||||
log.info("No column in target table " + table + " found for input field " + source[i]);
|
||||
}
|
||||
|
||||
fields(f);
|
||||
}
|
||||
@ -721,8 +742,8 @@ final class LoaderImpl<R extends Record> implements
|
||||
if (row.getClass() != Object[].class)
|
||||
row = Arrays.copyOf(row, row.length, Object[].class);
|
||||
|
||||
// [#5145] Lazy initialisation of fields off the first row
|
||||
// in case LoaderFieldMapper was used.
|
||||
// [#5145][#8755] Lazy initialisation of fields from the first row
|
||||
// in case fields(LoaderFieldMapper) or fieldsFromSource() was used
|
||||
if (fields == null)
|
||||
fields0(row);
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user