[jOOQ/jOOQ#11798] Add a VALUES() overload taking T... or Field<T>... arguments

This includes:

- [jOOQ/jOOQ#11799] Refactor some internals to re-use a new functional mapping method
This commit is contained in:
Lukas Eder 2021-04-23 16:29:23 +02:00
parent 70dadcb9f2
commit c3a9877bea
21 changed files with 265 additions and 325 deletions

View File

@ -44,6 +44,7 @@ package org.jooq;
// ...
// ...
// ...
// ...
import static org.jooq.SQLDialect.CUBRID;
// ...
import static org.jooq.SQLDialect.DERBY;

View File

@ -635,8 +635,8 @@ abstract class AbstractField<T> extends AbstractTypedNamed<T> implements Field<T
* [#11200] Nest these constants to prevent initialisation deadlocks.
*/
private static class BooleanValues {
static final List<Field<String>> TRUE_VALUES = Tools.inline(Convert.TRUE_VALUES.toArray(EMPTY_STRING));
static final List<Field<String>> FALSE_VALUES = Tools.inline(Convert.FALSE_VALUES.toArray(EMPTY_STRING));
static final List<Field<String>> TRUE_VALUES = Tools.mapToList(Convert.TRUE_VALUES, v -> DSL.inline(v));
static final List<Field<String>> FALSE_VALUES = Tools.mapToList(Convert.FALSE_VALUES, v -> DSL.inline(v));
}
@SuppressWarnings({ "unchecked" })

View File

@ -996,7 +996,7 @@ abstract class AbstractTable<R extends Record> extends AbstractNamed implements
@Override
public final Table<R> as(Table<?> otherTable, Field<?>... otherFields) {
return as(otherTable.getUnqualifiedName(), Tools.fieldNames(otherFields));
return as(otherTable.getUnqualifiedName(), Tools.map(otherFields, Field::getUnqualifiedName, Name[]::new));
}
@Override

View File

@ -79,6 +79,7 @@ import static org.jooq.impl.DSL.select;
import static org.jooq.impl.Keywords.K_AS;
import static org.jooq.impl.QueryPartListView.wrap;
import static org.jooq.impl.Tools.fieldNames;
import static org.jooq.impl.Tools.mapToList;
import static org.jooq.impl.Tools.visitSubquery;
import static org.jooq.impl.Tools.BooleanDataKey.DATA_AS_REQUIRED;
import static org.jooq.impl.Tools.BooleanDataKey.DATA_UNALIAS_ALIASED_EXPRESSIONS;
@ -88,6 +89,7 @@ import static org.jooq.impl.Values.NO_SUPPORT_VALUES;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
import org.jooq.Clause;
import org.jooq.Context;
@ -120,13 +122,13 @@ final class Alias<Q extends QueryPart> extends AbstractQueryPart {
final Q wrapping;
final Name alias;
final Name[] fieldAliases;
final boolean wrapInParentheses;
final Predicate<Context<?>> wrapInParentheses;
Alias(Q wrapped, Q wrapping, Name alias) {
this(wrapped, wrapping, alias, null, false);
this(wrapped, wrapping, alias, null, c -> false);
}
Alias(Q wrapped, Q wrapping, Name alias, Name[] fieldAliases, boolean wrapInParentheses) {
Alias(Q wrapped, Q wrapping, Name alias, Name[] fieldAliases, Predicate<Context<?>> wrapInParentheses) {
this.wrapped = wrapped;
this.wrapping = wrapping;
this.alias = alias;
@ -230,7 +232,7 @@ final class Alias<Q extends QueryPart> extends AbstractQueryPart {
// [#9486] H2 cannot handle duplicate column names in derived tables, despite derived column lists
// See: https://github.com/h2database/h2database/issues/2532
if (SUPPORT_DERIVED_COLUMN_NAMES_SPECIAL3.contains(dialect)) {
List<Name> names = fieldNames(select);
List<Name> names = mapToList(select, Field::getUnqualifiedName);
if (names.size() > 0 && names.size() == new HashSet<>(names).size()) {
toSQLWrapped(context);
@ -346,9 +348,11 @@ final class Alias<Q extends QueryPart> extends AbstractQueryPart {
}
private final void toSQLWrapped(Context<?> ctx) {
ctx.sql(wrapInParentheses ? "(" : "")
boolean wrap = wrapInParentheses.test(ctx);
ctx.sql(wrap ? "(" : "")
.visit(wrapped)
.sql(wrapInParentheses ? ")" : "");
.sql(wrap ? ")" : "");
}
private final void toSQLDerivedColumnList(Context<?> ctx) {

View File

@ -90,12 +90,12 @@ final class AliasedSelect<R extends Record> extends AbstractTable<R> {
if (q != null && (!q.getOrderBy().isEmpty() || Tools.hasEmbeddedFields(q.getSelect())))
return query.asTable(alias, aliases);
else
return new TableAlias<>(this, alias, true);
return new TableAlias<>(this, alias, c -> true);
}
@Override
public final Table<R> as(Name alias, Name... fieldAliases) {
return new TableAlias<>(this, alias, fieldAliases, true);
return new TableAlias<>(this, alias, fieldAliases, c -> true);
}
@Override

View File

@ -76,6 +76,7 @@ import static org.jooq.impl.DSL.asterisk;
import static org.jooq.impl.DSL.commentOnTable;
import static org.jooq.impl.DSL.createIndex;
import static org.jooq.impl.DSL.field;
import static org.jooq.impl.DSL.inline;
import static org.jooq.impl.DSL.insertInto;
import static org.jooq.impl.DSL.name;
import static org.jooq.impl.DSL.select;
@ -99,10 +100,9 @@ import static org.jooq.impl.Keywords.K_WITH_NO_DATA;
import static org.jooq.impl.SQLDataType.INTEGER;
import static org.jooq.impl.Tools.EMPTY_FIELD;
import static org.jooq.impl.Tools.begin;
import static org.jooq.impl.Tools.beginExecuteImmediate;
import static org.jooq.impl.Tools.endExecuteImmediate;
import static org.jooq.impl.Tools.enumLiterals;
import static org.jooq.impl.Tools.enums;
import static org.jooq.impl.Tools.executeImmediate;
import static org.jooq.impl.Tools.mapToList;
import static org.jooq.impl.Tools.storedEnumType;
import static org.jooq.impl.Tools.tryCatch;
import static org.jooq.impl.Tools.BooleanDataKey.DATA_SELECT_NO_DATA;
@ -138,7 +138,6 @@ import org.jooq.Select;
import org.jooq.Table;
import org.jooq.TableOptions.OnCommit;
import org.jetbrains.annotations.NotNull;
/**
* @author Lukas Eder
@ -549,11 +548,12 @@ final class CreateTableImpl extends AbstractDDLQuery implements
if (EMULATE_STORED_ENUM_TYPES_AS_CHECK.contains(ctx.dialect()) || !storedEnumType(enumType)) {
Field<?> field = columnFields.get(i);
List<Field<String>> literals = mapToList(enums(enumType.getType()), e -> inline(e.getLiteral()));
ctx.sql(',')
.formatSeparator()
.visit(DSL.constraint(table.getName() + "_" + field.getName() + "_chk")
.check(((Field) field).in(Tools.inline(enumLiterals(enumType.getType())))));
.check(((Field) field).in(literals)));
}
}
}

View File

@ -85,7 +85,7 @@ final class CreateTypeImpl extends AbstractDDLQuery implements
@Override
public final CreateTypeFinalStep asEnum(String... v) {
return asEnum(Tools.inline(v));
return asEnum(Tools.mapToList(v, s -> DSL.inline(s)));
}
@SafeVarargs

View File

@ -68,6 +68,7 @@ import static org.jooq.impl.Keywords.K_REPLACE;
import static org.jooq.impl.Keywords.K_VIEW;
import static org.jooq.impl.QueryPartListView.wrap;
import static org.jooq.impl.Tools.EMPTY_FIELD;
import static org.jooq.impl.Tools.map;
import static org.jooq.impl.Tools.tryCatch;
import java.util.List;
@ -81,6 +82,7 @@ import org.jooq.CreateViewAsStep;
import org.jooq.CreateViewFinalStep;
import org.jooq.DSLContext;
import org.jooq.Field;
import org.jooq.Name;
import org.jooq.QueryPart;
import org.jooq.Record;
import org.jooq.ResultQuery;
@ -88,7 +90,6 @@ import org.jooq.SQL;
import org.jooq.SQLDialect;
import org.jooq.Select;
import org.jooq.Table;
import org.jooq.conf.ParamType;
/**
* @author Lukas Eder
@ -265,7 +266,7 @@ final class CreateViewImpl<R extends Record> extends AbstractDDLQuery implements
// [#4806] CREATE VIEW doesn't accept parameters in most databases
.visit(
rename && !renameSupported
? selectFrom(parsed().asTable(name("t"), Tools.fieldNames(f)))
? selectFrom(parsed().asTable(name("t"), map(f, Field::getUnqualifiedName, Name[]::new)))
: select,
INLINED
)

View File

@ -47,6 +47,7 @@ import static org.jooq.Operator.OR;
// ...
// ...
// ...
// ...
import static org.jooq.SQLDialect.CUBRID;
// ...
// ...
@ -351,6 +352,7 @@ import org.jooq.Row8;
import org.jooq.Row9;
import org.jooq.RowCountQuery;
import org.jooq.RowN;
import org.jooq.Rows;
import org.jooq.SQL;
import org.jooq.SQLDialect;
import org.jooq.Schema;
@ -19294,7 +19296,7 @@ public class DSL {
@NotNull
@Support({ H2, MARIADB, MYSQL, POSTGRES })
public static JSONObjectNullStep<JSON> jsonObject(Field<?>... entries) {
return new JSONObject<>(SQLDataType.JSON, Tools.jsonEntries(entries));
return new JSONObject<>(SQLDataType.JSON, Tools.mapToList(entries, f -> jsonEntry(f)));
}
/**
@ -19321,7 +19323,7 @@ public class DSL {
@NotNull
@Support({ H2, MARIADB, MYSQL, POSTGRES })
public static JSONObjectNullStep<JSONB> jsonbObject(Field<?>... entries) {
return new JSONObject<>(SQLDataType.JSONB, Tools.jsonEntries(entries));
return new JSONObject<>(SQLDataType.JSONB, Tools.mapToList(entries, f -> jsonEntry(f)));
}
/**
@ -27529,6 +27531,72 @@ public class DSL {
return new Values<Record>(rows).as("v", columns);
}
/**
* Create a <code>VALUES()</code> expression of degree <code>1</code>.
* <p>
* The <code>VALUES()</code> constructor is a tool supported by some
* databases to allow for constructing tables from constant values.
* <p>
* If a database doesn't support the <code>VALUES()</code> constructor, it
* can be emulated using <code>SELECT .. UNION ALL ..</code>. The following
* expressions are equivalent:
* <p>
* <pre><code>
* -- Using VALUES() constructor
* VALUES(val1_1),
* (val2_1),
* (val3_1)
* AS "v"("c1" )
*
* -- Using UNION ALL
* SELECT val1_1 AS "c1") UNION ALL
* SELECT val1_1 AS "c1") UNION ALL
* SELECT val1_1 AS "c1")
* </code></pre>
* <p>
* Use {@link Table#as(String, String...)} to rename the resulting table and
* its columns.
*/
@SafeVarargs
@NotNull
@Support
public static <T> Table<Record1<T>> values(T... values) {
return values(Tools.map(values, t -> row(t), Row1[]::new));
}
/**
* Create a <code>VALUES()</code> expression of degree <code>1</code>.
* <p>
* The <code>VALUES()</code> constructor is a tool supported by some
* databases to allow for constructing tables from constant values.
* <p>
* If a database doesn't support the <code>VALUES()</code> constructor, it
* can be emulated using <code>SELECT .. UNION ALL ..</code>. The following
* expressions are equivalent:
* <p>
* <pre><code>
* -- Using VALUES() constructor
* VALUES(val1_1),
* (val2_1),
* (val3_1)
* AS "v"("c1" )
*
* -- Using UNION ALL
* SELECT val1_1 AS "c1") UNION ALL
* SELECT val1_1 AS "c1") UNION ALL
* SELECT val1_1 AS "c1")
* </code></pre>
* <p>
* Use {@link Table#as(String, String...)} to rename the resulting table and
* its columns.
*/
@SafeVarargs
@NotNull
@Support
public static <T> Table<Record1<T>> values(Field<T>... values) {
return values(Tools.map(values, f -> row(f), Row1[]::new));
}
/**

View File

@ -70,12 +70,12 @@ class DerivedTable<R extends Record> extends AbstractTable<R> {
@Override
public final Table<R> as(Name alias) {
return new TableAlias<>(this, alias, true);
return new TableAlias<>(this, alias, c -> true);
}
@Override
public final Table<R> as(Name alias, Name... fieldAliases) {
return new TableAlias<>(this, alias, fieldAliases, true);
return new TableAlias<>(this, alias, fieldAliases, c -> true);
}
@Override

View File

@ -818,7 +818,7 @@ final class InsertQueryImpl<R extends Record> extends AbstractStoreQuery<R> impl
// [#6375] INSERT .. VALUES and INSERT .. SELECT distinction also in MERGE
Table<?> t;
if (s != null) {
t = s.asTable("t", fieldNameStrings(insertMaps.fields().toArray(EMPTY_FIELD)));
t = s.asTable("t", Tools.map(insertMaps.fields(), Field::getName, String[]::new));
if (NO_SUPPORT_DERIVED_COLUMN_LIST_IN_MERGE_USING.contains(configuration.dialect()))
t = selectFrom(t).asTable("t");

View File

@ -52,6 +52,7 @@ import static org.jooq.impl.SQLDataType.BIGINT;
import static org.jooq.impl.Tools.EMPTY_FIELD;
import static org.jooq.impl.Tools.dataTypes;
import static org.jooq.impl.Tools.intersect;
import static org.jooq.impl.Tools.mapToList;
import static org.jooq.impl.Tools.normaliseNameCase;
import static org.jooq.impl.Tools.reverseIterable;
import static org.jooq.tools.StringUtils.defaultIfNull;
@ -59,6 +60,7 @@ import static org.jooq.tools.StringUtils.defaultIfNull;
import java.util.AbstractList;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
@ -807,7 +809,7 @@ final class Interpreter {
List<DataType<?>> columnTypes = query.$select() != null
? dataTypes(query.$select())
: asList(dataTypes(query.$fields()));
: mapToList(query.$fields(), f -> f.getDataType());
newTable(table, schema, asList(query.$fields()), columnTypes, query.$select(), null, TableOptions.view(query.$select()));
}
@ -957,7 +959,7 @@ final class Interpreter {
throw notExists(table);
MutableIndex existing = find(mt.indexes, index);
List<MutableSortField> mtf = mt.sortFields(Tools.sortFields(query.$on()));
List<MutableSortField> mtf = mt.sortFields(query.$on());
if (existing != null) {
if (!query.$createIndexIfNotExists())
@ -1711,7 +1713,7 @@ final class Interpreter {
return result;
}
final List<MutableSortField> sortFields(List<? extends OrderField<?>> ofs) {
final List<MutableSortField> sortFields(Collection<? extends OrderField<?>> ofs) {
List<MutableSortField> result = new ArrayList<>();
for (OrderField<?> of : ofs) {

View File

@ -535,12 +535,12 @@ implements
@Override
public final Table<Record> as(Name alias) {
return new TableAlias<>(this, alias, true);
return new TableAlias<>(this, alias, c -> true);
}
@Override
public final Table<Record> as(Name alias, Name... fieldAliases) {
return new TableAlias<>(this, alias, fieldAliases, true);
return new TableAlias<>(this, alias, fieldAliases, c -> true);
}
@Override

View File

@ -41,6 +41,7 @@ import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static org.jooq.impl.Tools.EMPTY_PARAM;
import static org.jooq.impl.Tools.dataTypes;
import static org.jooq.impl.Tools.mapToList;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
@ -132,7 +133,7 @@ final class ParsingConnection extends DefaultConnection {
return new CacheValue(configuration, sql, bindValues);
},
CacheType.CACHE_PARSING_CONNECTION,
() -> Cache.key(sql, asList(dataTypes(nonNull(bindValues))))
() -> Cache.key(sql, mapToList(nonNull(bindValues), f -> f.getDataType()))
).rendered(bindValues);
log.debug("Translating to", result.sql);

View File

@ -349,5 +349,6 @@ package org.jooq.impl;

View File

@ -419,7 +419,7 @@ final class R2DBC {
&& !q2.nativeSupportReturning(configuration.dsl()))
stmt.returnGeneratedValues(fieldNameStrings(q2.returningResolvedAsterisks.toArray(EMPTY_FIELD)));
stmt.returnGeneratedValues(Tools.map(q2.returningResolvedAsterisks, Field::getName, String[]::new));
stmt.execute().subscribe(resultSubscriber.apply(query, downstream));
}

View File

@ -39,6 +39,7 @@ package org.jooq.impl;
import static java.lang.Boolean.TRUE;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static java.util.function.Function.identity;
import static org.jooq.Clause.SELECT;
import static org.jooq.Clause.SELECT_CONNECT_BY;
@ -183,6 +184,7 @@ import static org.jooq.impl.Tools.fieldArray;
import static org.jooq.impl.Tools.hasAmbiguousNames;
import static org.jooq.impl.Tools.isNotEmpty;
import static org.jooq.impl.Tools.isWindow;
import static org.jooq.impl.Tools.mapToList;
import static org.jooq.impl.Tools.qualify;
import static org.jooq.impl.Tools.recordType;
import static org.jooq.impl.Tools.search;
@ -1392,7 +1394,7 @@ final class SelectQueryImpl<R extends Record> extends AbstractResultQuery<R> imp
DSL.select(qualify(table(name("t")), select))
.from(copy.asTable("t"))
.where(rn.eq(one()))
.orderBy(unqualified(orderBy.toArray(EMPTY_SORTFIELD)));
.orderBy(mapToList(orderBy, o -> unqualified(o)));
if (limit.numberOfRows != null) {
SelectLimitPercentStep<?> s2 = s1.limit((Param) limit.numberOfRows);
@ -3211,7 +3213,7 @@ final class SelectQueryImpl<R extends Record> extends AbstractResultQuery<R> imp
// [#7222] Workaround for https://issues.apache.org/jira/browse/DERBY-6983
if (ctx.family() == DERBY)
ctx.visit(new SelectFieldList<>(Tools.unqualified(fields)));
ctx.visit(new SelectFieldList<>(mapToList(fields, Tools::unqualified)));
else
ctx.sql('*');
@ -3711,6 +3713,8 @@ final class SelectQueryImpl<R extends Record> extends AbstractResultQuery<R> imp
return f;
}

View File

@ -40,6 +40,7 @@ package org.jooq.impl;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import org.jooq.Clause;
import org.jooq.Context;
@ -63,18 +64,18 @@ final class TableAlias<R extends Record> extends AbstractTable<R> {
final FieldsImpl<R> aliasedFields;
TableAlias(Table<R> table, Name alias) {
this(table, alias, null, false);
this(table, alias, null, c -> false);
}
TableAlias(Table<R> table, Name alias, boolean wrapInParentheses) {
TableAlias(Table<R> table, Name alias, Predicate<Context<?>> wrapInParentheses) {
this(table, alias, null, wrapInParentheses);
}
TableAlias(Table<R> table, Name alias, Name[] fieldAliases) {
this(table, alias, fieldAliases, false);
this(table, alias, fieldAliases, c -> false);
}
TableAlias(Table<R> table, Name alias, Name[] fieldAliases, boolean wrapInParentheses) {
TableAlias(Table<R> table, Name alias, Name[] fieldAliases, Predicate<Context<?>> wrapInParentheses) {
super(table.getOptions(), alias, table.getSchema());
this.alias = new Alias<>(table, this, alias, fieldAliases, wrapInParentheses);

View File

@ -103,7 +103,6 @@ import static org.jooq.impl.DSL.asterisk;
import static org.jooq.impl.DSL.concat;
import static org.jooq.impl.DSL.escape;
import static org.jooq.impl.DSL.getDataType;
import static org.jooq.impl.DSL.jsonEntry;
import static org.jooq.impl.DSL.keyword;
import static org.jooq.impl.DSL.name;
import static org.jooq.impl.DSL.noCondition;
@ -218,6 +217,8 @@ import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinPool.ManagedBlocker;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.regex.Matcher;
@ -280,7 +281,6 @@ import org.jooq.Table;
import org.jooq.TableField;
import org.jooq.TableRecord;
import org.jooq.UDT;
import org.jooq.UDTRecord;
import org.jooq.UpdatableRecord;
import org.jooq.XML;
import org.jooq.conf.BackslashEscaping;
@ -1212,30 +1212,7 @@ final class Tools {
// ------------------------------------------------------------------------
static final DataType<?>[] dataTypes(Class<?>[] types) {
if (types == null)
return null;
DataType<?>[] result = new DataType<?>[types.length];
for (int i = 0; i < types.length; i++)
if (types[i] != null)
result[i] = getDataType(types[i]);
else
result[i] = getDataType(Object.class);
return result;
}
static final DataType<?>[] dataTypes(Field<?>[] fields) {
if (fields == null)
return null;
DataType<?>[] result = new DataType<?>[fields.length];
for (int i = 0; i < fields.length; i++)
result[i] = fields[i].getDataType();
return result;
return map(types, t -> t != null ? getDataType(t) : getDataType(Object.class), DataType[]::new);
}
// ------------------------------------------------------------------------
@ -1252,29 +1229,14 @@ final class Tools {
}
static final SortField<?>[] sortFields(OrderField<?>[] fields) {
if (fields == null)
return null;
if (fields instanceof SortField<?>[])
return (SortField<?>[]) fields;
SortField<?>[] result = new SortField[fields.length];
for (int i = 0; i < fields.length; i++)
result[i] = sortField(fields[i]);
return result;
else
return map(fields, o -> sortField(o), SortField[]::new);
}
static final List<SortField<?>> sortFields(Collection<? extends OrderField<?>> fields) {
if (fields == null)
return null;
int size = fields.size();
List<SortField<?>> result = new ArrayList<>(size);
for (OrderField<?> field : fields)
result.add(sortField(field));
return result;
return mapToList(fields, o -> sortField(o));
}
static final String fieldNameString(int index) {
@ -1303,42 +1265,6 @@ final class Tools {
return result;
}
static final Name[] fieldNames(Field<?>[] fields) {
if (fields == null)
return null;
Name[] result = new Name[fields.length];
for (int i = 0; i < fields.length; i++)
result[i] = fields[i].getUnqualifiedName();
return result;
}
static final List<Name> fieldNames(Collection<? extends Field<?>> fields) {
if (fields == null)
return null;
List<Name> result = new ArrayList<>(fields.size());
for (Field<?> field : fields)
result.add(field.getUnqualifiedName());
return result;
}
static final String[] fieldNameStrings(Field<?>[] fields) {
if (fields == null)
return null;
String[] result = new String[fields.length];
for (int i = 0; i < fields.length; i++)
result[i] = fields[i].getName();
return result;
}
static final Field<?>[] fields(int length) {
return fields(length, SQLDataType.OTHER);
}
@ -1353,30 +1279,6 @@ final class Tools {
return result;
}
static final Field<?>[] unqualified(Field<?>[] fields) {
if (fields == null)
return null;
Field<?>[] result = new Field[fields.length];
for (int i = 0; i < fields.length; i++)
result[i] = unqualified(fields[i]);
return result;
}
static final List<Field<?>> unqualified(Collection<? extends Field<?>> fields) {
if (fields == null)
return null;
List<Field<?>> result = new ArrayList<>(fields.size());
for (Field<?> field : fields)
result.add(unqualified(field));
return result;
}
static final <T> Field<T> unqualified(Field<T> field) {
return DSL.field(field.getUnqualifiedName(), field.getDataType());
}
@ -1386,28 +1288,8 @@ final class Tools {
return i.transform(unqualified(i.getField()));
}
static final SortField<?>[] unqualified(SortField<?>[] fields) {
if (fields == null)
return null;
SortField<?>[] result = new SortField[fields.length];
for (int i = 0; i < result.length; i++)
result[i] = unqualified(fields[i]);
return result;
}
static final List<Field<?>> unaliasedFields(Collection<? extends Field<?>> fields) {
if (fields == null)
return null;
List<Field<?>> result = new ArrayList<>(fields.size());
int i = 0;
for (Field<?> field : fields)
result.add(DSL.field(fieldName(i++), field.getDataType()).as(field));
return result;
return mapToList(fields, (f, i) -> DSL.field(fieldName(i), f.getDataType()).as(f));
}
static final <R extends Record, O extends Record> ReferenceImpl<R, O> aliasedKey(ForeignKey<R, O> key, Table<R> child, Table<O> parent) {
@ -1426,19 +1308,7 @@ final class Tools {
}
static final List<Field<?>> aliasedFields(Collection<? extends Field<?>> fields) {
return aliasedFields(0, fields);
}
static final List<Field<?>> aliasedFields(int offset, Collection<? extends Field<?>> fields) {
if (fields == null)
return null;
List<Field<?>> result = new ArrayList<>(fields.size());
int i = offset;
for (Field<?> field : fields)
result.add(field.as(fieldName(i++)));
return result;
return mapToList(fields, (f, i) -> f.as(fieldName(i)));
}
static final Field<?>[] fieldsByName(String[] fieldNames) {
@ -1460,87 +1330,36 @@ final class Tools {
@SuppressWarnings("unchecked")
static final <R extends Record> TableField<R, ?>[] fieldsByName(Table<R> tableName, Field<?>[] fieldNames) {
if (fieldNames == null)
return null;
TableField<R, ?>[] result = new TableField[fieldNames.length];
if (tableName == null)
for (int i = 0; i < fieldNames.length; i++)
result[i] = (TableField<R, ?>) DSL.field(fieldNames[i].getUnqualifiedName(), fieldNames[i].getDataType());
return map(fieldNames, n -> (TableField<R, ?>) DSL.field(n.getUnqualifiedName(), n.getDataType()), TableField[]::new);
else
for (int i = 0; i < fieldNames.length; i++)
result[i] = (TableField<R, ?>) DSL.field(tableName.getQualifiedName().append(fieldNames[i].getUnqualifiedName()), fieldNames[i].getDataType());
return result;
return map(fieldNames, n -> (TableField<R, ?>) DSL.field(tableName.getQualifiedName().append(n.getUnqualifiedName()), n.getDataType()), TableField[]::new);
}
static final Field<?>[] fieldsByName(Name tableName, Name[] fieldNames) {
if (fieldNames == null)
return null;
Field<?>[] result = new Field[fieldNames.length];
if (tableName == null)
for (int i = 0; i < fieldNames.length; i++)
result[i] = DSL.field(fieldNames[i]);
return map(fieldNames, n -> DSL.field(n), Field[]::new);
else
for (int i = 0; i < fieldNames.length; i++)
result[i] = DSL.field(name(tableName, fieldNames[i]));
return result;
return map(fieldNames, n -> DSL.field(name(tableName, n)), Field[]::new);
}
static final Field<?>[] fieldsByName(String tableName, String[] fieldNames) {
if (fieldNames == null)
return null;
Field<?>[] result = new Field[fieldNames.length];
if (StringUtils.isEmpty(tableName))
for (int i = 0; i < fieldNames.length; i++)
result[i] = DSL.field(name(fieldNames[i]));
return map(fieldNames, n -> DSL.field(name(n)), Field[]::new);
else
for (int i = 0; i < fieldNames.length; i++)
result[i] = DSL.field(name(tableName, fieldNames[i]));
return result;
return map(fieldNames, n -> DSL.field(name(tableName, n)), Field[]::new);
}
static final Field<?>[] fieldsByName(Name[] names) {
if (names == null)
return null;
Field<?>[] result = new Field[names.length];
for (int i = 0; i < names.length; i++)
result[i] = DSL.field(names[i]);
return result;
return map(names, n -> DSL.field(n), Field[]::new);
}
static final Name[] names(String[] names) {
if (names == null)
return null;
Name[] result = new Name[names.length];
for (int i = 0; i < names.length; i++)
result[i] = DSL.name(names[i]);
return result;
return map(names, n -> DSL.name(n), Name[]::new);
}
static final List<Name> names(Collection<?> names) {
if (names == null)
return null;
List<Name> result = new ArrayList<>(names.size());
for (Object o : names)
result.add(o instanceof Name ? (Name) o : DSL.name(String.valueOf(o)));
return result;
return mapToList(names, n -> n instanceof Name ? (Name) n : DSL.name(String.valueOf(n)));
}
private static final IllegalArgumentException fieldExpected(Object value) {
@ -1833,25 +1652,14 @@ final class Tools {
@SuppressWarnings("unchecked")
static final <T> Field<T>[] fieldsArray(T[] values) {
if (values == null)
return (Field<T>[]) EMPTY_FIELD;
Field<T>[] result = new Field[values.length];
for (int i = 0; i < values.length; i++)
result[i] = field(values[i]);
return result;
return map(values, v -> field(v), Field[]::new);
}
static final <T> List<Field<T>> fields(Object[] values, Field<T> field) {
if (values == null || field == null)
if (field == null)
return new ArrayList<>();
List<Field<T>> result = new ArrayList<>(values.length);
for (int i = 0; i < values.length; i++)
result.add(field(values[i], field));
return result;
else
return mapToList(values, v -> field(v, field));
}
static final List<Field<?>> fields(Object[] values, Field<?>[] fields) {
@ -1859,16 +1667,7 @@ final class Tools {
}
static final Field<?>[] fieldsArray(Object[] values, Field<?>[] fields) {
if (values == null || fields == null)
return EMPTY_FIELD;
int length = Math.min(values.length, fields.length);
Field<?>[] result = new Field[length];
for (int i = 0; i < length; i++)
result[i] = field(values[i], fields[i]);
return result;
return map(values, (v, i) -> field(v, fields[i]), Field[]::new);
}
static final <T> List<Field<T>> fields(Object[] values, DataType<T> type) {
@ -1876,26 +1675,12 @@ final class Tools {
}
static final <T> List<Field<T>> fields(Collection<?> values, DataType<T> type) {
if (values == null || type == null)
return new ArrayList<>();
List<Field<T>> result = new ArrayList<>(values.size());
for (Object value : values)
result.add(field(value, type));
return result;
return mapToList(values, v -> field(v, type));
}
@SuppressWarnings("unchecked")
static final <T> Field<T>[] fieldsArray(Object[] values, DataType<T> type) {
if (values == null)
return (Field<T>[]) EMPTY_FIELD;
Field<T>[] result = new Field[values.length];
for (int i = 0; i < result.length; i++)
result[i] = field(values[i], type);
return result;
return map(values, v -> field(v, type), Field[]::new);
}
static final List<Field<?>> fields(Object[] values, DataType<?>[] types) {
@ -1903,27 +1688,11 @@ final class Tools {
}
static final Field<?>[] fieldsArray(Object[] values, DataType<?>[] types) {
if (values == null || types == null)
return EMPTY_FIELD;
int length = Math.min(values.length, types.length);
Field<?>[] result = new Field[length];
for (int i = 0; i < length; i++)
result[i] = field(values[i], types[i]);
return result;
return map(values, (v, i) -> field(v, types[i]), Field[]::new);
}
static final <T> List<Field<T>> inline(T[] values) {
if (values == null)
return new ArrayList<>();
List<Field<T>> result = new ArrayList<>(values.length);
for (int i = 0; i < values.length; i++)
result.add(DSL.inline(values[i]));
return result;
return mapToList(values, v -> DSL.inline(v));
}
@SuppressWarnings("unchecked")
@ -2016,26 +1785,112 @@ final class Tools {
return result;
}
static final List<JSONEntry<?>> jsonEntries(Field<?>... fields) {
if (fields == null)
return null;
/**
* Like <code>Stream.of(array).map(mapper).toArray(constructor)</code> but
* without the entire stream pipeline.
*/
static final <T, U> U[] map(T[] array, Function<? super T, ? extends U> mapper, IntFunction<U[]> constructor) {
if (array == null)
return constructor.apply(0);
List<JSONEntry<?>> result = new ArrayList<>(fields.length);
for (Field<?> field : fields)
result.add(jsonEntry(field));
U[] result = constructor.apply(array.length);
for (int i = 0; i < array.length; i++)
result[i] = mapper.apply(array[i]);
return result;
}
static final <T> T last(Collection<T> collection) {
if (collection.isEmpty())
return null;
else if (collection instanceof List)
return ((List<T>) collection).get(collection.size() - 1);
/**
* Like <code>Stream.of(array).map(mapper).toArray(constructor)</code> but
* without the entire stream pipeline.
*/
static final <T, U> U[] map(Collection<? extends T> collection, Function<? super T, ? extends U> mapper, IntFunction<U[]> constructor) {
if (collection == null)
return constructor.apply(0);
T last = null;
for (Iterator<T> it = collection.iterator(); it.hasNext(); last = it.next());
return last;
U[] result = constructor.apply(collection.size());
int i = 0;
for (T t : collection)
result[i++] = mapper.apply(t);
return result;
}
/**
* Like
* <code>Stream.of(array).zipWithIndex().map(mapper).toArray(constructor)</code>
* but without the entire stream pipeline.
*/
static final <T, U> U[] map(T[] array, ObjIntFunction<? super T, ? extends U> mapper, IntFunction<U[]> constructor) {
if (array == null)
return constructor.apply(0);
U[] result = constructor.apply(array.length);
for (int i = 0; i < array.length; i++)
result[i] = mapper.apply(array[i], i);
return result;
}
/**
* Like <code>Stream.of(array).map(mapper).toList()</code> but
* without the entire stream pipeline.
*/
static final <T, U> List<U> mapToList(T[] array, Function<? super T, ? extends U> mapper) {
if (array == null)
return emptyList();
List<U> result = new ArrayList<>(array.length);
for (T t : array)
result.add(mapper.apply(t));
return result;
}
/**
* Like <code>Stream.of(array).map(mapper).toList()</code> but
* without the entire stream pipeline.
*/
static final <T, U> List<U> mapToList(Collection<? extends T> collection, Function<? super T, ? extends U> mapper) {
if (collection == null)
return emptyList();
List<U> result = new ArrayList<>(collection.size());
for (T t : collection)
result.add(mapper.apply(t));
return result;
}
/**
* Like <code>Stream.of(array).zipWithIndex().map(mapper).toList()</code>
* but without the entire stream pipeline.
*/
static final <T, U> List<U> mapToList(T[] array, ObjIntFunction<? super T, ? extends U> mapper) {
if (array == null)
return emptyList();
List<U> result = new ArrayList<>(array.length);
for (int i = 0; i < array.length; i++)
result.add(mapper.apply(array[i], i));
return result;
}
/**
* Like <code>Stream.of(array).map(mapper).toList()</code> but
* without the entire stream pipeline.
*/
static final <T, U> List<U> mapToList(Collection<? extends T> collection, ObjIntFunction<? super T, ? extends U> mapper) {
if (collection == null)
return emptyList();
List<U> result = new ArrayList<>(collection.size());
int i = 0;
for (T t : collection)
result.add(mapper.apply(t, i++));
return result;
}
/**
@ -2140,6 +1995,17 @@ final class Tools {
return null;
}
static final <T> T last(Collection<T> collection) {
if (collection.isEmpty())
return null;
else if (collection instanceof List)
return ((List<T>) collection).get(collection.size() - 1);
T last = null;
for (Iterator<T> it = collection.iterator(); it.hasNext(); last = it.next());
return last;
}
/**
* Sets the statement's fetch size to the given value or
* {@link org.jooq.conf.Settings#getFetchSize()} if {@code 0}.
@ -5267,16 +5133,6 @@ final class Tools {
};
}
static final String[] enumLiterals(Class<? extends EnumType> type) {
EnumType[] values = enums(type);
String[] result = new String[values.length];
for (int i = 0; i < values.length; i++)
result[i] = values[i].getLiteral();
return result;
}
static final <E extends EnumType> E[] enums(Class<? extends E> type) {
// Java implementation

View File

@ -93,9 +93,10 @@ final class Values<R extends Record> extends AbstractTable<R> {
/**
* Generated UID
*/
private static final long serialVersionUID = -637982217747670311L;
static final Set<SQLDialect> NO_SUPPORT_VALUES = SQLDialect.supportedUntil(FIREBIRD, MARIADB);
static final Set<SQLDialect> REQUIRE_ROWTYPE_CAST = SQLDialect.supportedBy(FIREBIRD);
private static final long serialVersionUID = -637982217747670311L;
static final Set<SQLDialect> NO_SUPPORT_VALUES = SQLDialect.supportedUntil(FIREBIRD, MARIADB);
static final Set<SQLDialect> REQUIRE_ROWTYPE_CAST = SQLDialect.supportedBy(FIREBIRD);
static final Set<SQLDialect> NO_SUPPORT_PARENTHESES = SQLDialect.supportedBy();
private final Row[] rows;
private transient DataType<?>[] types;
@ -157,12 +158,12 @@ final class Values<R extends Record> extends AbstractTable<R> {
@Override
public final Table<R> as(Name alias) {
return new TableAlias<>(this, alias, true);
return new TableAlias<>(this, alias, c -> !NO_SUPPORT_PARENTHESES.contains(c.dialect()));
}
@Override
public final Table<R> as(Name alias, Name... fieldAliases) {
return new TableAlias<>(this, alias, fieldAliases, true);
return new TableAlias<>(this, alias, fieldAliases, c -> !NO_SUPPORT_PARENTHESES.contains(c.dialect()));
}
@Override

View File

@ -299,12 +299,12 @@ implements
@Override
public final WithImpl with(String a, String... f) {
return with(DSL.name(a), Tools.names(f));
return with(DSL.name(a), Tools.map(f, s -> DSL.name(s), Name[]::new));
}
@Override
public final WithImpl with(String a, Collection<String> f) {
return with(DSL.name(a), Tools.names(f));
return with(DSL.name(a), Tools.map(f, s -> DSL.name(s), Name[]::new));
}
@Override