[#2280] Improve supported formats for MockFileDatabase
This commit is contained in:
parent
82fa44d98f
commit
e648132697
@ -1590,6 +1590,82 @@ public class Executor implements Configuration {
|
||||
return fetchLazy(rs, Utils.getDataTypes(types));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch all data from a formatted string.
|
||||
* <p>
|
||||
* The supplied string is supposed to be formatted in the following,
|
||||
* human-readable way: <code><pre>
|
||||
* COL1 COL2 COL3 containing whitespace
|
||||
* ----- ---- --------------------------
|
||||
* val1 1 some text
|
||||
* val2 2 more text
|
||||
* </pre></code> This method will decode the above formatted string
|
||||
* according to the following rules:
|
||||
* <ul>
|
||||
* <li>The number of columns is defined by the number of dash groups in the
|
||||
* second line</li>
|
||||
* <li>The column types are <code>VARCHAR(N)</code> where
|
||||
* <code>N = number of dashes per dash group</code></li>
|
||||
* <li>The column names are defined by the trimmed text contained in the
|
||||
* first row</li>
|
||||
* <li>The data is defined by the trimmed text contained in the subsequent
|
||||
* rows</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* This is the same as calling {@link #fetchFromTXT(String, String)} with
|
||||
* <code>"{null}"</code> as <code>nullLiteral</code>
|
||||
* <p>
|
||||
* A future version of jOOQ will also support the inverse operation of
|
||||
* {@link Result#format()} through this method
|
||||
*
|
||||
* @param string The formatted string
|
||||
* @return The transformed result
|
||||
* @see #fetchFromTXT(String, String)
|
||||
* @throws DataAccessException If the supplied string does not adhere to the
|
||||
* above format rules.
|
||||
*/
|
||||
@Support
|
||||
public final Result<Record> fetchFromTXT(String string) throws DataAccessException {
|
||||
return fetchFromTXT(string, "{null}");
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch all data from a formatted string.
|
||||
* <p>
|
||||
* The supplied string is supposed to be formatted in the following,
|
||||
* human-readable way: <code><pre>
|
||||
* COL1 COL2 COL3 containing whitespace
|
||||
* ----- ---- --------------------------
|
||||
* val1 1 some text
|
||||
* val2 2 more text
|
||||
* </pre></code> This method will decode the above formatted string
|
||||
* according to the following rules:
|
||||
* <ul>
|
||||
* <li>The number of columns is defined by the number of dash groups in the
|
||||
* second line</li>
|
||||
* <li>The column types are <code>VARCHAR(N)</code> where
|
||||
* <code>N = number of dashes per dash group</code></li>
|
||||
* <li>The column names are defined by the trimmed text contained in the
|
||||
* first row</li>
|
||||
* <li>The data is defined by the trimmed text contained in the subsequent
|
||||
* rows</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* A future version of jOOQ will also support the inverse operation of
|
||||
* {@link Result#format()} through this method
|
||||
*
|
||||
* @param string The formatted string
|
||||
* @param nullLiteral The string literal to be used as <code>null</code>
|
||||
* value.
|
||||
* @return The transformed result
|
||||
* @throws DataAccessException If the supplied string does not adhere to the
|
||||
* above format rules.
|
||||
*/
|
||||
@Support
|
||||
public final Result<Record> fetchFromTXT(String string, String nullLiteral) throws DataAccessException {
|
||||
return fetchFromStringData(Utils.parseTXT(string, nullLiteral));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch all data from a CSV string.
|
||||
* <p>
|
||||
|
||||
@ -75,6 +75,7 @@ import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.persistence.Column;
|
||||
@ -130,7 +131,7 @@ import org.jooq.util.postgres.PostgresUtils;
|
||||
*/
|
||||
final class Utils {
|
||||
|
||||
static final JooqLogger log = JooqLogger.getLogger(Utils.class);
|
||||
static final JooqLogger log = JooqLogger.getLogger(Utils.class);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Some constants for use with Configuration.setData()
|
||||
@ -141,7 +142,7 @@ final class Utils {
|
||||
* clause in {@link Executor#batchStore(UpdatableRecord...)} calls for
|
||||
* {@link SQLDialect#POSTGRES}
|
||||
*/
|
||||
static final String DATA_OMIT_RETURNING_CLAUSE = "org.jooq.configuration.omit-returning-clause";
|
||||
static final String DATA_OMIT_RETURNING_CLAUSE = "org.jooq.configuration.omit-returning-clause";
|
||||
|
||||
/**
|
||||
* [#1905] This constant is used internally by jOOQ to indicate to
|
||||
@ -161,7 +162,7 @@ final class Utils {
|
||||
* The default escape character for <code>[a] LIKE [b] ESCAPE [...]</code>
|
||||
* clauses.
|
||||
*/
|
||||
static final char ESCAPE = '!';
|
||||
static final char ESCAPE = '!';
|
||||
|
||||
/**
|
||||
* Indicating whether JPA (<code>javax.persistence</code>) is on the
|
||||
@ -169,10 +170,15 @@ final class Utils {
|
||||
*/
|
||||
private static Boolean isJPAAvailable;
|
||||
|
||||
/**
|
||||
* A pattern for the dash line syntax
|
||||
*/
|
||||
private static final Pattern DASH_PATTERN = Pattern.compile("(-+)"); ;
|
||||
|
||||
/**
|
||||
* A pattern for the JDBC escape syntax
|
||||
*/
|
||||
private static final Pattern JDBC_ESCAPE_PATTERN = Pattern.compile("\\{(fn|d|t|ts)\\b.*");
|
||||
private static final Pattern JDBC_ESCAPE_PATTERN = Pattern.compile("\\{(fn|d|t|ts)\\b.*");
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// XXX: Record constructors and related methods
|
||||
@ -2396,4 +2402,54 @@ final class Utils {
|
||||
private static final <T> void pgSetValue(UDTRecord<?> record, Field<T> field, String value) throws SQLException {
|
||||
record.setValue(field, pgFromString(field.getType(), value));
|
||||
}
|
||||
|
||||
static List<String[]> parseTXT(String string, String nullLiteral) {
|
||||
String[] strings = string.split("[\\r\\n]+");
|
||||
|
||||
if (strings.length < 2) {
|
||||
throw new DataAccessException("String must contain at least two lines");
|
||||
}
|
||||
|
||||
// Find the set of positions defined by the dashed line number two:
|
||||
// ----- ------- ----
|
||||
// results in
|
||||
// [{0,5} {7,14} {15,19}]
|
||||
List<int[]> positions = new ArrayList<int[]>();
|
||||
Matcher m = DASH_PATTERN.matcher(strings[1]);
|
||||
|
||||
while (m.find()) {
|
||||
positions.add(new int[] { m.start(1), m.end(1) });
|
||||
}
|
||||
|
||||
// Parse header line and data lines into string arrays
|
||||
List<String[]> result = new ArrayList<String[]>();
|
||||
parseTXTLine(positions, result, strings[0], nullLiteral);
|
||||
|
||||
for (int j = 2; j < strings.length; j++) {
|
||||
parseTXTLine(positions, result, strings[j], nullLiteral);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void parseTXTLine(List<int[]> positions, List<String[]> result, String string, String nullLiteral) {
|
||||
String[] fields = new String[positions.size()];
|
||||
result.add(fields);
|
||||
int length = string.length();
|
||||
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
int[] position = positions.get(i);
|
||||
|
||||
if (position[0] < length) {
|
||||
fields[i] = string.substring(position[0], Math.min(position[1], length)).trim();
|
||||
}
|
||||
else {
|
||||
fields[i] = null;
|
||||
}
|
||||
|
||||
if (StringUtils.equals(fields[i], nullLiteral)) {
|
||||
fields[i] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -128,12 +128,8 @@ public class MockFileDatabase implements MockDataProvider {
|
||||
|
||||
// A line of result data
|
||||
else if (line.startsWith(">")) {
|
||||
|
||||
// But ignore visual delimiter
|
||||
if (!line.startsWith("> -")) {
|
||||
currentResult.append(line.substring(2));
|
||||
currentResult.append("\n");
|
||||
}
|
||||
currentResult.append(line.substring(2));
|
||||
currentResult.append("\n");
|
||||
}
|
||||
|
||||
// A result data termination literal
|
||||
@ -219,7 +215,7 @@ public class MockFileDatabase implements MockDataProvider {
|
||||
rows = Integer.parseInt(rowString.substring(7).trim());
|
||||
}
|
||||
|
||||
return new MockResult(rows, create.fetchFromCSV(currentResult.toString(), ' '));
|
||||
return new MockResult(rows, create.fetchFromTXT(currentResult.toString()));
|
||||
}
|
||||
|
||||
private String readLine() throws IOException {
|
||||
|
||||
@ -333,5 +333,53 @@ public class MockTest extends AbstractTest {
|
||||
@Test
|
||||
public void testFileDatabase_SELECT_ID1_NAME1_FROM_TABLE1() throws Exception {
|
||||
Result<Record2<Integer, String>> r = MOCK.select(FIELD_ID1, FIELD_NAME1).from(TABLE1).fetch();
|
||||
|
||||
assertEquals(2, r.size());
|
||||
assertEquals("ID1", r.field(0).getName());
|
||||
assertEquals("NAME1", r.field(1).getName());
|
||||
assertEquals(asList(1, 2), r.getValues(0));
|
||||
assertEquals(asList("X", "Y"), r.getValues(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFileDatabase_SELECT_COMPLEX_DATA() throws Exception {
|
||||
List<Result<Record>> results = MOCK.fetchMany("select complex_data");
|
||||
assertEquals(2, results.size());
|
||||
|
||||
Result<Record> r1 = results.get(0);
|
||||
Result<Record> r2 = results.get(1);
|
||||
|
||||
// Result 1
|
||||
// --------
|
||||
assertEquals(2, r1.size());
|
||||
|
||||
// Header
|
||||
assertEquals(3, r1.fields().length);
|
||||
assertEquals("F1", r1.field(0).getName());
|
||||
assertEquals("F2", r1.field(1).getName());
|
||||
assertEquals("F3 is a bit more complex", r1.field(2).getName());
|
||||
|
||||
// Data
|
||||
assertEquals("1", r1.getValue(0, 0));
|
||||
assertEquals("2", r1.getValue(0, 1));
|
||||
assertEquals("and a string containing data", r1.getValue(0, 2));
|
||||
assertEquals("1.1", r1.getValue(1, 0));
|
||||
assertEquals("x", r1.getValue(1, 1));
|
||||
assertEquals("another string", r1.getValue(1, 2));
|
||||
|
||||
// Result 1
|
||||
// --------
|
||||
assertEquals(1, r2.size());
|
||||
|
||||
// Header
|
||||
assertEquals(3, r2.fields().length);
|
||||
assertEquals("A", r2.field(0).getName());
|
||||
assertEquals("B", r2.field(1).getName());
|
||||
assertEquals("\"C D\"", r2.field(2).getName());
|
||||
|
||||
// Data
|
||||
assertEquals("x", r2.getValue(0, 0));
|
||||
assertEquals("y", r2.getValue(0, 1));
|
||||
assertEquals("z", r2.getValue(0, 2));
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,6 +15,19 @@ select 'A', 'B' from dual;
|
||||
select "TABLE1"."ID1", "TABLE1"."NAME1" from "TABLE1";
|
||||
> ID1 NAME1
|
||||
> --- -----
|
||||
> 1 X
|
||||
> 2 Y
|
||||
@ rows: 2
|
||||
> 1 X
|
||||
> 2 Y
|
||||
@ rows: 2
|
||||
|
||||
# [#2280] Check if "advanced" CSV content can be handled, too
|
||||
select complex_data;
|
||||
> F1 F2 F3 is a bit more complex
|
||||
> --- -- ----------------------------
|
||||
> 1 2 and a string containing data
|
||||
> 1.1 x another string
|
||||
@ rows: 2
|
||||
|
||||
> A B "C D"
|
||||
> - - -----
|
||||
> x y z
|
||||
@ rows: 1
|
||||
Loading…
Reference in New Issue
Block a user