141 QStringList conditions;
144 if ( dimensions.isEmpty() )
154 return QMetaType::Type::UnknownType;
161 auto refFieldCast = [&](
const QString &
fieldName, QMetaType::Type queryType, QMetaType::Type fieldType ) -> QString {
162 const auto fieldRealType { fieldTypeFromName(
fieldName, layer ) };
163 if ( fieldRealType == QMetaType::Type::UnknownType )
170 if ( fieldRealType == QMetaType::Type::QString )
173 if ( fieldType != queryType || fieldType == QMetaType::Type::QDate )
179 return QStringLiteral(
"%2( %1 )" ).arg(
QgsExpression::quotedColumnRef(
fieldName ) ).arg( queryType == QMetaType::Type::QDate ? QStringLiteral(
"to_date" ) : QStringLiteral(
"to_datetime" ) );
182 else if ( fieldType == queryType || fieldType == QMetaType::Type::QDate )
188 return QStringLiteral(
"%2( %1 )" ).arg(
QgsExpression::quotedColumnRef(
fieldName ) ).arg( queryType == QMetaType::Type::QDate ? QStringLiteral(
"to_date" ) : QStringLiteral(
"to_datetime" ) );
193 auto quoteValue = [](
const QString &value ) -> QString {
194 if ( value.length() == 10 )
205 auto makeFilter = ["eValue](
const QString &fieldBegin,
const QString &fieldEnd,
const QString &fieldBeginCasted,
const QString &fieldEndCasted,
const QString &queryBegin,
const QString &queryEnd ) -> QString {
209 if ( !queryBegin.isEmpty() && !queryEnd.isEmpty() )
212 if ( !fieldEndCasted.isEmpty() )
214 result = QStringLiteral(
"( %1 IS NULL OR %2 <= %6 ) AND ( %4 IS NULL OR %5 >= %3 )" )
215 .arg( fieldBegin, fieldBeginCasted, quoteValue( queryBegin ), fieldEnd, fieldEndCasted, quoteValue( queryEnd ) );
219 result = QStringLiteral(
"( %1 IS NULL OR ( %2 <= %3 AND %3 <= %4 ) )" )
220 .arg( fieldBegin, quoteValue( queryBegin ), fieldBeginCasted, quoteValue( queryEnd ) );
223 else if ( !queryBegin.isEmpty() )
225 if ( !fieldEndCasted.isEmpty() )
227 result = QStringLiteral(
"( %1 IS NULL OR %2 >= %3 )" ).arg( fieldEnd, fieldEndCasted, quoteValue( queryBegin ) );
231 result = QStringLiteral(
"( %1 IS NULL OR %2 >= %3 )" ).arg( fieldBegin, fieldBeginCasted, quoteValue( queryBegin ) );
236 result = QStringLiteral(
"( %1 IS NULL OR %2 <= %3 )" ).arg( fieldBegin, fieldBeginCasted, quoteValue( queryEnd ) );
242 QString testType { interval };
243 if ( interval.contains(
'/' ) )
245 const QStringList parts { interval.split(
'/' ) };
247 if ( testType.isEmpty() || testType == QLatin1String(
".." ) )
254 const bool inputQueryIsDateTime { testType.length() > 10 };
255 const QMetaType::Type queryType { inputQueryIsDateTime ? QMetaType::Type::QDateTime : QMetaType::Type::QDate };
258 if ( interval.contains(
'/' ) )
260 if ( !inputQueryIsDateTime )
264 for (
const auto &dimension : std::as_const( dimensions ) )
267 const QMetaType::Type fieldType { dimension.name.toLower() == QLatin1String(
"time" ) ? QMetaType::Type::QDateTime : QMetaType::Type::QDate };
269 const auto fieldBeginCasted { refFieldCast( dimension.fieldName, queryType, fieldType ) };
270 if ( fieldBeginCasted.isEmpty() )
279 const auto fieldEndCasted { refFieldCast( dimension.endFieldName, queryType, fieldType ) };
280 if ( !dateInterval.
begin().isValid() && !dateInterval.
end().isValid() )
286 conditions.push_back( makeFilter( fieldBegin, fieldEnd, fieldBeginCasted, fieldEndCasted, dateInterval.
begin().toString( Qt::DateFormat::ISODate ), dateInterval.
end().toString( Qt::DateFormat::ISODate ) ) );
293 for (
const auto &dimension : std::as_const( dimensions ) )
296 const QMetaType::Type fieldType { dimension.name.toLower() == QLatin1String(
"time" ) ? QMetaType::Type::QDateTime : QMetaType::Type::QDate };
298 const auto fieldfBeginCasted { refFieldCast( dimension.fieldName, queryType, fieldType ) };
299 if ( fieldfBeginCasted.isEmpty() )
307 const auto fieldEndCasted { refFieldCast( dimension.endFieldName, queryType, fieldType ) };
308 if ( !dateTimeInterval.
begin().isValid() && !dateTimeInterval.
end().isValid() )
318 if ( fieldType == QMetaType::Type::QDate )
320 beginQuery = dateTimeInterval.
begin().date().toString( Qt::DateFormat::ISODate );
321 endQuery = dateTimeInterval.
end().date().toString( Qt::DateFormat::ISODate );
325 beginQuery = dateTimeInterval.
begin().toString( Qt::DateFormat::ISODate );
326 endQuery = dateTimeInterval.
end().toString( Qt::DateFormat::ISODate );
328 conditions.push_back( makeFilter( fieldBegin, fieldEnd, fieldfBeginCasted, fieldEndCasted, beginQuery, endQuery ) );
335 for (
const auto &dimension : std::as_const( dimensions ) )
338 const bool fieldIsDateTime { dimension.name.toLower() == QLatin1String(
"time" ) };
339 const QMetaType::Type fieldType { fieldIsDateTime ? QMetaType::Type::QDateTime : QMetaType::Type::QDate };
341 const auto fieldRefBegin { refFieldCast( dimension.fieldName, queryType, fieldType ) };
342 if ( fieldRefBegin.isEmpty() )
349 const auto fieldRefEnd { refFieldCast( dimension.endFieldName, queryType, fieldType ) };
356 if ( !inputQueryIsDateTime || !fieldIsDateTime )
358 QString castedInterval { interval };
360 if ( inputQueryIsDateTime )
362 castedInterval = QDate::fromString( castedInterval, Qt::DateFormat::ISODate ).toString( Qt::DateFormat::ISODate );
368 QString castedInterval { interval };
370 if ( !inputQueryIsDateTime )
372 castedInterval = QDateTime::fromString( castedInterval, Qt::DateFormat::ISODate ).toString( Qt::DateFormat::ISODate );
377 if ( !fieldRefEnd.isEmpty() )
379 condition = QStringLiteral(
"( %1 IS NULL OR %2 <= %3 ) AND ( %5 IS NULL OR %3 <= %4 )" ).arg( fieldBegin, fieldRefBegin, castedValue, fieldRefEnd, fieldEnd );
383 condition = QStringLiteral(
"( %1 IS NULL OR %2 = %3 )" )
384 .arg( fieldBegin, fieldRefBegin, castedValue );
386 conditions.push_back( condition );
389 if ( !conditions.isEmpty() )
391 expression.
setExpression( conditions.join( QLatin1String(
" AND " ) ) );
424 QDateTime min { minVal.toDateTime() };
425 QDateTime max { maxVal.toDateTime() };
426 if ( !dimInfo.endFieldName.isEmpty() )
435 QDateTime minEnd { minVal.toDateTime() };
436 QDateTime maxEnd { maxVal.toDateTime() };
437 if ( minEnd.isValid() )
439 min = std::min<QDateTime>( min, minEnd );
441 if ( maxEnd.isValid() )
443 max = std::max<QDateTime>( max, maxEnd );
451 if ( dimensions.isEmpty() )
461 for (
const auto &dimension : dimensions )
466 extent = range( dimension );
471 extent.
extend( range( dimension ) );
474 json ret = json::array();
475 const QString beginVal { extent.
begin().toString( Qt::DateFormat::ISODate ) };
476 const QString endVal { extent.
end().toString( Qt::DateFormat::ISODate ) };
478 if ( beginVal.isEmpty() && endVal.isEmpty() )
480 ret.push_back( {
nullptr,
nullptr } );
482 else if ( beginVal.isEmpty() )
484 ret.push_back( {
nullptr, endVal.toStdString() } );
486 else if ( endVal.isEmpty() )
488 ret.push_back( { beginVal.toStdString(),
nullptr } );
492 ret.push_back( { beginVal.toStdString(), endVal.toStdString() } );
496 catch ( std::exception &ex )
498 const QString errorMessage { QStringLiteral(
"Error creating temporal extent: %1" ).arg( ex.what() ) };