138 QStringList conditions;
141 if ( dimensions.isEmpty() )
151 return QMetaType::Type::UnknownType;
158 auto refFieldCast = [&](
const QString &
fieldName, QMetaType::Type queryType, QMetaType::Type fieldType ) -> QString {
159 const auto fieldRealType { fieldTypeFromName(
fieldName, layer ) };
160 if ( fieldRealType == QMetaType::Type::UnknownType )
167 if ( fieldRealType == QMetaType::Type::QString )
170 if ( fieldType != queryType || fieldType == QMetaType::Type::QDate )
176 return QStringLiteral(
"%2( %1 )" ).arg(
QgsExpression::quotedColumnRef(
fieldName ) ).arg( queryType == QMetaType::Type::QDate ? QStringLiteral(
"to_date" ) : QStringLiteral(
"to_datetime" ) );
179 else if ( fieldType == queryType || fieldType == QMetaType::Type::QDate )
185 return QStringLiteral(
"%2( %1 )" ).arg(
QgsExpression::quotedColumnRef(
fieldName ) ).arg( queryType == QMetaType::Type::QDate ? QStringLiteral(
"to_date" ) : QStringLiteral(
"to_datetime" ) );
190 auto quoteValue = [](
const QString &value ) -> QString {
191 if ( value.length() == 10 )
202 auto makeFilter = ["eValue](
const QString &fieldBegin,
const QString &fieldEnd,
const QString &fieldBeginCasted,
const QString &fieldEndCasted,
const QString &queryBegin,
const QString &queryEnd ) -> QString {
206 if ( !queryBegin.isEmpty() && !queryEnd.isEmpty() )
209 if ( !fieldEndCasted.isEmpty() )
211 result = QStringLiteral(
"( %1 IS NULL OR %2 <= %6 ) AND ( %4 IS NULL OR %5 >= %3 )" )
212 .arg( fieldBegin, fieldBeginCasted, quoteValue( queryBegin ), fieldEnd, fieldEndCasted, quoteValue( queryEnd ) );
216 result = QStringLiteral(
"( %1 IS NULL OR ( %2 <= %3 AND %3 <= %4 ) )" )
217 .arg( fieldBegin, quoteValue( queryBegin ), fieldBeginCasted, quoteValue( queryEnd ) );
220 else if ( !queryBegin.isEmpty() )
222 if ( !fieldEndCasted.isEmpty() )
224 result = QStringLiteral(
"( %1 IS NULL OR %2 >= %3 )" ).arg( fieldEnd, fieldEndCasted, quoteValue( queryBegin ) );
228 result = QStringLiteral(
"( %1 IS NULL OR %2 >= %3 )" ).arg( fieldBegin, fieldBeginCasted, quoteValue( queryBegin ) );
233 result = QStringLiteral(
"( %1 IS NULL OR %2 <= %3 )" ).arg( fieldBegin, fieldBeginCasted, quoteValue( queryEnd ) );
239 QString testType { interval };
240 if ( interval.contains(
'/' ) )
242 const QStringList parts { interval.split(
'/' ) };
244 if ( testType.isEmpty() || testType == QLatin1String(
".." ) )
251 const bool inputQueryIsDateTime { testType.length() > 10 };
252 const QMetaType::Type queryType { inputQueryIsDateTime ? QMetaType::Type::QDateTime : QMetaType::Type::QDate };
255 if ( interval.contains(
'/' ) )
257 if ( !inputQueryIsDateTime )
261 for (
const auto &dimension : std::as_const( dimensions ) )
264 const QMetaType::Type fieldType { dimension.name.toLower() == QLatin1String(
"time" ) ? QMetaType::Type::QDateTime : QMetaType::Type::QDate };
266 const auto fieldBeginCasted { refFieldCast( dimension.fieldName, queryType, fieldType ) };
267 if ( fieldBeginCasted.isEmpty() )
276 const auto fieldEndCasted { refFieldCast( dimension.endFieldName, queryType, fieldType ) };
277 if ( !dateInterval.begin().isValid() && !dateInterval.end().isValid() )
283 conditions.push_back( makeFilter( fieldBegin, fieldEnd, fieldBeginCasted, fieldEndCasted, dateInterval.begin().toString( Qt::DateFormat::ISODate ), dateInterval.end().toString( Qt::DateFormat::ISODate ) ) );
290 for (
const auto &dimension : std::as_const( dimensions ) )
293 const QMetaType::Type fieldType { dimension.name.toLower() == QLatin1String(
"time" ) ? QMetaType::Type::QDateTime : QMetaType::Type::QDate };
295 const auto fieldfBeginCasted { refFieldCast( dimension.fieldName, queryType, fieldType ) };
296 if ( fieldfBeginCasted.isEmpty() )
304 const auto fieldEndCasted { refFieldCast( dimension.endFieldName, queryType, fieldType ) };
305 if ( !dateTimeInterval.begin().isValid() && !dateTimeInterval.end().isValid() )
315 if ( fieldType == QMetaType::Type::QDate )
317 beginQuery = dateTimeInterval.begin().date().toString( Qt::DateFormat::ISODate );
318 endQuery = dateTimeInterval.end().date().toString( Qt::DateFormat::ISODate );
322 beginQuery = dateTimeInterval.begin().toString( Qt::DateFormat::ISODate );
323 endQuery = dateTimeInterval.end().toString( Qt::DateFormat::ISODate );
325 conditions.push_back( makeFilter( fieldBegin, fieldEnd, fieldfBeginCasted, fieldEndCasted, beginQuery, endQuery ) );
332 for (
const auto &dimension : std::as_const( dimensions ) )
335 const bool fieldIsDateTime { dimension.name.toLower() == QLatin1String(
"time" ) };
336 const QMetaType::Type fieldType { fieldIsDateTime ? QMetaType::Type::QDateTime : QMetaType::Type::QDate };
338 const auto fieldRefBegin { refFieldCast( dimension.fieldName, queryType, fieldType ) };
339 if ( fieldRefBegin.isEmpty() )
346 const auto fieldRefEnd { refFieldCast( dimension.endFieldName, queryType, fieldType ) };
353 if ( !inputQueryIsDateTime || !fieldIsDateTime )
355 QString castedInterval { interval };
357 if ( inputQueryIsDateTime )
359 castedInterval = QDate::fromString( castedInterval, Qt::DateFormat::ISODate ).toString( Qt::DateFormat::ISODate );
365 QString castedInterval { interval };
367 if ( !inputQueryIsDateTime )
369 castedInterval = QDateTime::fromString( castedInterval, Qt::DateFormat::ISODate ).toString( Qt::DateFormat::ISODate );
374 if ( !fieldRefEnd.isEmpty() )
376 condition = QStringLiteral(
"( %1 IS NULL OR %2 <= %3 ) AND ( %5 IS NULL OR %3 <= %4 )" ).arg( fieldBegin, fieldRefBegin, castedValue, fieldRefEnd, fieldEnd );
380 condition = QStringLiteral(
"( %1 IS NULL OR %2 = %3 )" )
381 .arg( fieldBegin, fieldRefBegin, castedValue );
383 conditions.push_back( condition );
386 if ( !conditions.isEmpty() )
388 expression.
setExpression( conditions.join( QLatin1String(
" AND " ) ) );
421 QDateTime min { minVal.toDateTime() };
422 QDateTime max { maxVal.toDateTime() };
423 if ( !dimInfo.endFieldName.isEmpty() )
432 QDateTime minEnd { minVal.toDateTime() };
433 QDateTime maxEnd { maxVal.toDateTime() };
434 if ( minEnd.isValid() )
436 min = std::min<QDateTime>( min, minEnd );
438 if ( maxEnd.isValid() )
440 max = std::max<QDateTime>( max, maxEnd );
448 if ( dimensions.isEmpty() )
458 for (
const auto &dimension : dimensions )
463 extent = range( dimension );
468 extent.
extend( range( dimension ) );
471 json ret = json::array();
472 const QString beginVal { extent.
begin().toString( Qt::DateFormat::ISODate ) };
473 const QString endVal { extent.
end().toString( Qt::DateFormat::ISODate ) };
475 if ( beginVal.isEmpty() && endVal.isEmpty() )
477 ret.push_back( {
nullptr,
nullptr } );
479 else if ( beginVal.isEmpty() )
481 ret.push_back( {
nullptr, endVal.toStdString() } );
483 else if ( endVal.isEmpty() )
485 ret.push_back( { beginVal.toStdString(),
nullptr } );
489 ret.push_back( { beginVal.toStdString(), endVal.toStdString() } );
493 catch ( std::exception &ex )
495 const QString errorMessage { QStringLiteral(
"Error creating temporal extent: %1" ).arg( ex.what() ) };
The QgsServerApiContext class encapsulates the resources for a particular client request: the request...