[#5411] Add support for ResultQuery.fetchSingle(), which returns exactly one record
This commit is contained in:
parent
a6464beb23
commit
c0ca2539b7
@ -58,6 +58,7 @@ import org.jooq.exception.DataAccessException;
|
||||
import org.jooq.exception.DataTypeException;
|
||||
import org.jooq.exception.InvalidResultException;
|
||||
import org.jooq.exception.MappingException;
|
||||
import org.jooq.exception.NoDataFoundException;
|
||||
import org.jooq.exception.TooManyRowsException;
|
||||
import org.jooq.impl.DefaultRecordMapper;
|
||||
|
||||
@ -724,6 +725,276 @@ public interface ResultQuery<R extends Record> extends Query, Iterable<R> {
|
||||
*/
|
||||
<Z extends Record> Z fetchOneInto(Table<Z> table) throws DataAccessException, TooManyRowsException;
|
||||
|
||||
/**
|
||||
* Execute the query and return exactly one resulting value for a field from
|
||||
* the generated result.
|
||||
* <p>
|
||||
* This is the same as calling {@link #fetchSingle()} and then
|
||||
* {@link Record#get(Field)}
|
||||
*
|
||||
* @return The resulting value. This is never <code>null</code>.
|
||||
* @throws DataAccessException if something went wrong executing the query
|
||||
* @thorws NoDataFoundException if the query returned no records
|
||||
* @throws TooManyRowsException if the query returned more than one record
|
||||
*/
|
||||
<T> T fetchSingle(Field<T> field) throws DataAccessException, NoDataFoundException, TooManyRowsException;
|
||||
|
||||
/**
|
||||
* Execute the query and return exactly one resulting value for a
|
||||
* field from the generated result.
|
||||
* <p>
|
||||
* This is the same as calling {@link #fetchSingle()} and then
|
||||
* {@link Record#get(Field, Class)}
|
||||
*
|
||||
* @return The resulting value. This is never <code>null</code>.
|
||||
* @throws DataAccessException if something went wrong executing the query
|
||||
* @thorws NoDataFoundException if the query returned no records
|
||||
* @throws TooManyRowsException if the query returned more than one record
|
||||
*/
|
||||
<T> T fetchSingle(Field<?> field, Class<? extends T> type) throws DataAccessException, NoDataFoundException, TooManyRowsException;
|
||||
|
||||
/**
|
||||
* Execute the query and return exactly one resulting value for a
|
||||
* field from the generated result.
|
||||
* <p>
|
||||
* This is the same as calling {@link #fetchSingle()} and then
|
||||
* {@link Record#get(Field, Converter)}
|
||||
*
|
||||
* @return The resulting value. This is never <code>null</code>.
|
||||
* @throws DataAccessException if something went wrong executing the query
|
||||
* @thorws NoDataFoundException if the query returned no records
|
||||
* @throws TooManyRowsException if the query returned more than one record
|
||||
*/
|
||||
<T, U> U fetchSingle(Field<T> field, Converter<? super T, ? extends U> converter) throws DataAccessException, NoDataFoundException, TooManyRowsException;
|
||||
|
||||
/**
|
||||
* Execute the query and return exactly one resulting value for a
|
||||
* field index from the generated result.
|
||||
* <p>
|
||||
* This is the same as calling {@link #fetchSingle()} and then
|
||||
* {@link Record#get(int)}
|
||||
*
|
||||
* @return The resulting value. This is never <code>null</code>.
|
||||
* @throws DataAccessException if something went wrong executing the query
|
||||
* @thorws NoDataFoundException if the query returned no records
|
||||
* @throws TooManyRowsException if the query returned more than one record
|
||||
*/
|
||||
Object fetchSingle(int fieldIndex) throws DataAccessException, NoDataFoundException, TooManyRowsException;
|
||||
|
||||
/**
|
||||
* Execute the query and return exactly one resulting value for a
|
||||
* field index from the generated result.
|
||||
* <p>
|
||||
* This is the same as calling {@link #fetchSingle()} and then
|
||||
* {@link Record#get(int, Class)}
|
||||
*
|
||||
* @return The resulting value. This is never <code>null</code>.
|
||||
* @throws DataAccessException if something went wrong executing the query
|
||||
* @thorws NoDataFoundException if the query returned no records
|
||||
* @throws TooManyRowsException if the query returned more than one record
|
||||
*/
|
||||
<T> T fetchSingle(int fieldIndex, Class<? extends T> type) throws DataAccessException, NoDataFoundException, TooManyRowsException;
|
||||
|
||||
/**
|
||||
* Execute the query and return exactly one resulting value for a
|
||||
* field index from the generated result.
|
||||
* <p>
|
||||
* This is the same as calling {@link #fetchSingle()} and then
|
||||
* {@link Record#get(int, Converter)}
|
||||
*
|
||||
* @return The resulting value. This is never <code>null</code>.
|
||||
* @throws DataAccessException if something went wrong executing the query
|
||||
* @thorws NoDataFoundException if the query returned no records
|
||||
* @throws TooManyRowsException if the query returned more than one record
|
||||
*/
|
||||
<U> U fetchSingle(int fieldIndex, Converter<?, ? extends U> converter) throws DataAccessException, NoDataFoundException, TooManyRowsException;
|
||||
|
||||
/**
|
||||
* Execute the query and return exactly one resulting value for a
|
||||
* field name from the generated result.
|
||||
* <p>
|
||||
* This is the same as calling {@link #fetchSingle()} and then
|
||||
* {@link Record#get(String)}
|
||||
*
|
||||
* @return The resulting value. This is never <code>null</code>.
|
||||
* @throws DataAccessException if something went wrong executing the query
|
||||
* @thorws NoDataFoundException if the query returned no records
|
||||
* @throws TooManyRowsException if the query returned more than one record
|
||||
*/
|
||||
Object fetchSingle(String fieldName) throws DataAccessException, NoDataFoundException, TooManyRowsException;
|
||||
|
||||
/**
|
||||
* Execute the query and return exactly one resulting value for a
|
||||
* field name from the generated result.
|
||||
* <p>
|
||||
* This is the same as calling {@link #fetchSingle()} and then
|
||||
* {@link Record#get(String, Class)}
|
||||
*
|
||||
* @return The resulting value. This is never <code>null</code>.
|
||||
* @throws DataAccessException if something went wrong executing the query
|
||||
* @thorws NoDataFoundException if the query returned no records
|
||||
* @throws TooManyRowsException if the query returned more than one record
|
||||
*/
|
||||
<T> T fetchSingle(String fieldName, Class<? extends T> type) throws DataAccessException, NoDataFoundException, TooManyRowsException;
|
||||
|
||||
/**
|
||||
* Execute the query and return exactly one resulting value for a
|
||||
* field name from the generated result.
|
||||
* <p>
|
||||
* This is the same as calling {@link #fetchSingle()} and then
|
||||
* {@link Record#get(String, Converter)}
|
||||
*
|
||||
* @return The resulting value. This is never <code>null</code>.
|
||||
* @throws DataAccessException if something went wrong executing the query
|
||||
* @thorws NoDataFoundException if the query returned no records
|
||||
* @throws TooManyRowsException if the query returned more than one record
|
||||
*/
|
||||
<U> U fetchSingle(String fieldName, Converter<?, ? extends U> converter) throws DataAccessException, NoDataFoundException, TooManyRowsException;
|
||||
|
||||
/**
|
||||
* Execute the query and return exactly one resulting value for a
|
||||
* field name from the generated result.
|
||||
* <p>
|
||||
* This is the same as calling {@link #fetchSingle()} and then
|
||||
* {@link Record#get(Name)}
|
||||
*
|
||||
* @return The resulting value. This is never <code>null</code>.
|
||||
* @throws DataAccessException if something went wrong executing the query
|
||||
* @thorws NoDataFoundException if the query returned no records
|
||||
* @throws TooManyRowsException if the query returned more than one record
|
||||
*/
|
||||
Object fetchSingle(Name fieldName) throws DataAccessException, NoDataFoundException, TooManyRowsException;
|
||||
|
||||
/**
|
||||
* Execute the query and return exactly one resulting value for a
|
||||
* field name from the generated result.
|
||||
* <p>
|
||||
* This is the same as calling {@link #fetchSingle()} and then
|
||||
* {@link Record#get(Name, Class)}
|
||||
*
|
||||
* @return The resulting value. This is never <code>null</code>.
|
||||
* @throws DataAccessException if something went wrong executing the query
|
||||
* @thorws NoDataFoundException if the query returned no records
|
||||
* @throws TooManyRowsException if the query returned more than one record
|
||||
*/
|
||||
<T> T fetchSingle(Name fieldName, Class<? extends T> type) throws DataAccessException, NoDataFoundException, TooManyRowsException;
|
||||
|
||||
/**
|
||||
* Execute the query and return exactly one resulting value for a
|
||||
* field name from the generated result.
|
||||
* <p>
|
||||
* This is the same as calling {@link #fetchSingle()} and then
|
||||
* {@link Record#get(Name, Converter)}
|
||||
*
|
||||
* @return The resulting value. This is never <code>null</code>.
|
||||
* @throws DataAccessException if something went wrong executing the query
|
||||
* @thorws NoDataFoundException if the query returned no records
|
||||
* @throws TooManyRowsException if the query returned more than one record
|
||||
*/
|
||||
<U> U fetchSingle(Name fieldName, Converter<?, ? extends U> converter) throws DataAccessException, NoDataFoundException, TooManyRowsException;
|
||||
|
||||
/**
|
||||
* Execute the query and return exactly one resulting record.
|
||||
* <p>
|
||||
* The resulting record is attached to the original {@link Configuration} by
|
||||
* default. Use {@link Settings#isAttachRecords()} to override this
|
||||
* behaviour.
|
||||
*
|
||||
* @return The resulting value. This is never <code>null</code>.
|
||||
* @throws DataAccessException if something went wrong executing the query
|
||||
* @thorws NoDataFoundException if the query returned no records
|
||||
* @throws TooManyRowsException if the query returned more than one record
|
||||
*/
|
||||
R fetchSingle() throws DataAccessException, NoDataFoundException, TooManyRowsException;
|
||||
|
||||
/**
|
||||
* Execute the query and return exactly one resulting value into a
|
||||
* custom mapper callback.
|
||||
*
|
||||
* @return The resulting value. This is never <code>null</code>.
|
||||
* @throws DataAccessException if something went wrong executing the query
|
||||
* @thorws NoDataFoundException if the query returned no records
|
||||
* @throws TooManyRowsException if the query returned more than one record
|
||||
*/
|
||||
<E> E fetchSingle(RecordMapper<? super R, E> mapper) throws DataAccessException, NoDataFoundException, TooManyRowsException;
|
||||
|
||||
/**
|
||||
* Execute the query and return exactly one resulting record as a name/value
|
||||
* map.
|
||||
*
|
||||
* @return The resulting value. This is never <code>null</code>.
|
||||
* @throws DataAccessException if something went wrong executing the query
|
||||
* @thorws NoDataFoundException if the query returned no records
|
||||
* @throws TooManyRowsException if the query returned more than one record
|
||||
* @see Result#intoMaps()
|
||||
* @see Record#intoMap()
|
||||
*/
|
||||
Map<String, Object> fetchSingleMap() throws DataAccessException, NoDataFoundException, TooManyRowsException;
|
||||
|
||||
/**
|
||||
* Execute the query and return exactly one resulting record as an array
|
||||
* <p>
|
||||
* You can access data like this
|
||||
* <code><pre>query.fetchSingleArray()[fieldIndex]</pre></code>
|
||||
*
|
||||
* @return The resulting value. This is never <code>null</code>.
|
||||
* @throws DataAccessException if something went wrong executing the query
|
||||
* @thorws NoDataFoundException if the query returned no records
|
||||
* @throws TooManyRowsException if the query returned more than one record
|
||||
*/
|
||||
Object[] fetchSingleArray() throws DataAccessException, NoDataFoundException, TooManyRowsException;
|
||||
|
||||
/**
|
||||
* Map resulting records onto a custom type.
|
||||
* <p>
|
||||
* This is the same as calling <code><pre>
|
||||
* E result = null;
|
||||
* Record r = q.fetchSingle();
|
||||
*
|
||||
* if (r != null)
|
||||
* result = r.into(type);
|
||||
* </pre></code>. See {@link Record#into(Class)} for more details
|
||||
*
|
||||
* @param <E> The generic entity type.
|
||||
* @param type The entity type.
|
||||
* @return The resulting value. This is never <code>null</code>.
|
||||
* @see Record#into(Class)
|
||||
* @see Result#into(Class)
|
||||
* @throws DataAccessException if something went wrong executing the query
|
||||
* @throws MappingException wrapping any reflection or data type conversion
|
||||
* exception that might have occurred while mapping records
|
||||
* @thorws NoDataFoundException if the query returned no records
|
||||
* @throws TooManyRowsException if the query returned more than one record
|
||||
* @see DefaultRecordMapper
|
||||
*/
|
||||
<E> E fetchSingleInto(Class<? extends E> type) throws DataAccessException, MappingException, NoDataFoundException, TooManyRowsException;
|
||||
|
||||
/**
|
||||
* Map resulting records onto a custom record.
|
||||
* <p>
|
||||
* This is the same as calling <code><pre>
|
||||
* Z result = null;
|
||||
* Record r = q.fetchSingle();
|
||||
*
|
||||
* if (r != null)
|
||||
* result = r.into(table);
|
||||
* </pre></code>. See {@link Record#into(Table)} for more details
|
||||
* <p>
|
||||
* The resulting record is attached to the original {@link Configuration} by
|
||||
* default. Use {@link Settings#isAttachRecords()} to override this
|
||||
* behaviour.
|
||||
*
|
||||
* @param <Z> The generic table record type.
|
||||
* @param table The table type.
|
||||
* @return The resulting value. This is never <code>null</code>.
|
||||
* @see Record#into(Table)
|
||||
* @see Result#into(Table)
|
||||
* @throws DataAccessException if something went wrong executing the query
|
||||
* @thorws NoDataFoundException if the query returned no records
|
||||
* @throws TooManyRowsException if the query returned more than one record
|
||||
*/
|
||||
<Z extends Record> Z fetchSingleInto(Table<Z> table) throws DataAccessException, NoDataFoundException, TooManyRowsException;
|
||||
|
||||
|
||||
/**
|
||||
* Execute the query and return at most one resulting value for a
|
||||
|
||||
@ -559,6 +559,96 @@ abstract class AbstractResultQuery<R extends Record> extends AbstractQuery imple
|
||||
return record == null ? null : record.into(table);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> T fetchSingle(Field<T> field) {
|
||||
return fetchSingle().get(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> T fetchSingle(Field<?> field, Class<? extends T> type) {
|
||||
return Convert.convert(fetchSingle(field), type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T, U> U fetchSingle(Field<T> field, Converter<? super T, ? extends U> converter) {
|
||||
return Convert.convert(fetchSingle(field), converter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Object fetchSingle(int fieldIndex) {
|
||||
return fetchSingle().get(fieldIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> T fetchSingle(int fieldIndex, Class<? extends T> type) {
|
||||
return Convert.convert(fetchSingle(fieldIndex), type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <U> U fetchSingle(int fieldIndex, Converter<?, ? extends U> converter) {
|
||||
return Convert.convert(fetchSingle(fieldIndex), converter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Object fetchSingle(String fieldName) {
|
||||
return fetchSingle().get(fieldName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> T fetchSingle(String fieldName, Class<? extends T> type) {
|
||||
return Convert.convert(fetchSingle(fieldName), type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <U> U fetchSingle(String fieldName, Converter<?, ? extends U> converter) {
|
||||
return Convert.convert(fetchSingle(fieldName), converter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Object fetchSingle(Name fieldName) {
|
||||
return fetchSingle().get(fieldName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> T fetchSingle(Name fieldName, Class<? extends T> type) {
|
||||
return Convert.convert(fetchSingle(fieldName), type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <U> U fetchSingle(Name fieldName, Converter<?, ? extends U> converter) {
|
||||
return Convert.convert(fetchSingle(fieldName), converter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final R fetchSingle() {
|
||||
return Tools.fetchSingle(fetchLazy());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <E> E fetchSingle(RecordMapper<? super R, E> mapper) {
|
||||
return mapper.map(fetchSingle());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Map<String, Object> fetchSingleMap() {
|
||||
return fetchSingle().intoMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Object[] fetchSingleArray() {
|
||||
return fetchSingle().intoArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <E> E fetchSingleInto(Class<? extends E> type) {
|
||||
return fetchSingle().into(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <Z extends Record> Z fetchSingleInto(Table<Z> table) {
|
||||
return fetchSingle().into(table);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final <T> Optional<T> fetchOptional(Field<T> field) {
|
||||
|
||||
@ -124,7 +124,6 @@ import org.jooq.Table;
|
||||
import org.jooq.TableField;
|
||||
import org.jooq.TableLike;
|
||||
import org.jooq.WindowDefinition;
|
||||
import org.jooq.exception.MappingException;
|
||||
|
||||
/**
|
||||
* A wrapper for a {@link SelectQuery}
|
||||
@ -2789,6 +2788,96 @@ final class SelectImpl<R extends Record, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10
|
||||
return getDelegate().fetchOneInto(table);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> T fetchSingle(Field<T> field) {
|
||||
return getDelegate().fetchSingle(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> T fetchSingle(Field<?> field, Class<? extends T> type) {
|
||||
return getDelegate().fetchSingle(field, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T, U> U fetchSingle(Field<T> field, Converter<? super T, ? extends U> converter) {
|
||||
return getDelegate().fetchSingle(field, converter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Object fetchSingle(int fieldIndex) {
|
||||
return getDelegate().fetchSingle(fieldIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> T fetchSingle(int fieldIndex, Class<? extends T> type) {
|
||||
return getDelegate().fetchSingle(fieldIndex, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <U> U fetchSingle(int fieldIndex, Converter<?, ? extends U> converter) {
|
||||
return getDelegate().fetchSingle(fieldIndex, converter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Object fetchSingle(String fieldName) {
|
||||
return getDelegate().fetchSingle(fieldName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> T fetchSingle(String fieldName, Class<? extends T> type) {
|
||||
return getDelegate().fetchSingle(fieldName, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <U> U fetchSingle(String fieldName, Converter<?, ? extends U> converter) {
|
||||
return getDelegate().fetchSingle(fieldName, converter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Object fetchSingle(Name fieldName) {
|
||||
return getDelegate().fetchSingle(fieldName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> T fetchSingle(Name fieldName, Class<? extends T> type) {
|
||||
return getDelegate().fetchSingle(fieldName, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <U> U fetchSingle(Name fieldName, Converter<?, ? extends U> converter) {
|
||||
return getDelegate().fetchSingle(fieldName, converter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final R fetchSingle() {
|
||||
return getDelegate().fetchSingle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <E> E fetchSingle(RecordMapper<? super R, E> mapper) {
|
||||
return getDelegate().fetchSingle(mapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Map<String, Object> fetchSingleMap() {
|
||||
return getDelegate().fetchSingleMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Object[] fetchSingleArray() {
|
||||
return getDelegate().fetchSingleArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <E> E fetchSingleInto(Class<? extends E> type) {
|
||||
return getDelegate().fetchSingleInto(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <Z extends Record> Z fetchSingleInto(Table<Z> table) {
|
||||
return getDelegate().fetchSingleInto(table);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final <T> Optional<T> fetchOptional(Field<T> field) {
|
||||
@ -3362,7 +3451,7 @@ final class SelectImpl<R extends Record, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <K> Map<K, Result<R>> fetchGroups(RecordMapper<? super R, K> keyMapper) throws MappingException {
|
||||
public final <K> Map<K, Result<R>> fetchGroups(RecordMapper<? super R, K> keyMapper) {
|
||||
return getDelegate().fetchGroups(keyMapper);
|
||||
}
|
||||
|
||||
|
||||
@ -217,6 +217,7 @@ import org.jooq.conf.Settings;
|
||||
import org.jooq.conf.ThrowExceptions;
|
||||
import org.jooq.exception.DataAccessException;
|
||||
import org.jooq.exception.MappingException;
|
||||
import org.jooq.exception.NoDataFoundException;
|
||||
import org.jooq.exception.TooManyRowsException;
|
||||
import org.jooq.impl.ResultsImpl.ResultOrRowsImpl;
|
||||
import org.jooq.impl.Tools.Cache.CachedOperation;
|
||||
@ -1624,11 +1625,38 @@ final class Tools {
|
||||
*/
|
||||
static final <R extends Record> R fetchOne(Cursor<R> cursor) throws TooManyRowsException {
|
||||
try {
|
||||
R record = cursor.fetchOne();
|
||||
R record = cursor.fetchNext();
|
||||
|
||||
if (cursor.hasNext()) {
|
||||
if (cursor.hasNext())
|
||||
throw new TooManyRowsException("Cursor returned more than one result");
|
||||
|
||||
return record;
|
||||
}
|
||||
finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the only element from a cursor, or throw an exception.
|
||||
* <p>
|
||||
* [#2373] This method will always close the argument cursor, as it is
|
||||
* supposed to be completely consumed by this method.
|
||||
*
|
||||
* @param cursor The cursor
|
||||
* @return The only element from the cursor
|
||||
* @throws NoDataFoundException Thrown if the cursor did not return any rows
|
||||
* @throws TooManyRowsException Thrown if the cursor returns more than one
|
||||
* element
|
||||
*/
|
||||
static final <R extends Record> R fetchSingle(Cursor<R> cursor) throws NoDataFoundException, TooManyRowsException {
|
||||
try {
|
||||
R record = cursor.fetchNext();
|
||||
|
||||
if (record == null)
|
||||
throw new NoDataFoundException("Cursor returned no rows");
|
||||
if (cursor.hasNext())
|
||||
throw new TooManyRowsException("Cursor returned more than one result");
|
||||
}
|
||||
|
||||
return record;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user