144 QStringList conditions;
147 if ( dimensions.isEmpty() )
157 return QMetaType::Type::UnknownType;
164 auto refFieldCast = [&](
const QString &
fieldName, QMetaType::Type queryType, QMetaType::Type fieldType ) -> QString {
165 const auto fieldRealType { fieldTypeFromName(
fieldName, layer ) };
166 if ( fieldRealType == QMetaType::Type::UnknownType )
173 if ( fieldRealType == QMetaType::Type::QString )
176 if ( fieldType != queryType || fieldType == QMetaType::Type::QDate )
185 else if ( fieldType == queryType || fieldType == QMetaType::Type::QDate )
196 auto quoteValue = [](
const QString &value ) -> QString {
197 if ( value.length() == 10 )
208 auto makeFilter = ["eValue](
const QString &fieldBegin,
const QString &fieldEnd,
const QString &fieldBeginCasted,
const QString &fieldEndCasted,
const QString &queryBegin,
const QString &queryEnd ) -> QString {
212 if ( !queryBegin.isEmpty() && !queryEnd.isEmpty() )
215 if ( !fieldEndCasted.isEmpty() )
217 result = u
"( %1 IS NULL OR %2 <= %6 ) AND ( %4 IS NULL OR %5 >= %3 )"_s
218 .arg( fieldBegin, fieldBeginCasted, quoteValue( queryBegin ), fieldEnd, fieldEndCasted, quoteValue( queryEnd ) );
222 result = u
"( %1 IS NULL OR ( %2 <= %3 AND %3 <= %4 ) )"_s
223 .arg( fieldBegin, quoteValue( queryBegin ), fieldBeginCasted, quoteValue( queryEnd ) );
226 else if ( !queryBegin.isEmpty() )
228 if ( !fieldEndCasted.isEmpty() )
230 result = u
"( %1 IS NULL OR %2 >= %3 )"_s.arg( fieldEnd, fieldEndCasted, quoteValue( queryBegin ) );
234 result = u
"( %1 IS NULL OR %2 >= %3 )"_s.arg( fieldBegin, fieldBeginCasted, quoteValue( queryBegin ) );
239 result = u
"( %1 IS NULL OR %2 <= %3 )"_s.arg( fieldBegin, fieldBeginCasted, quoteValue( queryEnd ) );
245 QString testType { interval };
246 if ( interval.contains(
'/' ) )
248 const QStringList parts { interval.split(
'/' ) };
250 if ( testType.isEmpty() || testType ==
".."_L1 )
257 const bool inputQueryIsDateTime { testType.length() > 10 };
258 const QMetaType::Type queryType { inputQueryIsDateTime ? QMetaType::Type::QDateTime : QMetaType::Type::QDate };
261 if ( interval.contains(
'/' ) )
263 if ( !inputQueryIsDateTime )
267 for (
const auto &dimension : std::as_const( dimensions ) )
270 const QMetaType::Type fieldType { dimension.name.toLower() ==
"time"_L1 ? QMetaType::Type::QDateTime : QMetaType::Type::QDate };
272 const auto fieldBeginCasted { refFieldCast( dimension.fieldName, queryType, fieldType ) };
273 if ( fieldBeginCasted.isEmpty() )
282 const auto fieldEndCasted { refFieldCast( dimension.endFieldName, queryType, fieldType ) };
283 if ( !dateInterval.
begin().isValid() && !dateInterval.
end().isValid() )
289 conditions.push_back( makeFilter( fieldBegin, fieldEnd, fieldBeginCasted, fieldEndCasted, dateInterval.
begin().toString( Qt::DateFormat::ISODate ), dateInterval.
end().toString( Qt::DateFormat::ISODate ) ) );
296 for (
const auto &dimension : std::as_const( dimensions ) )
299 const QMetaType::Type fieldType { dimension.name.toLower() ==
"time"_L1 ? QMetaType::Type::QDateTime : QMetaType::Type::QDate };
301 const auto fieldfBeginCasted { refFieldCast( dimension.fieldName, queryType, fieldType ) };
302 if ( fieldfBeginCasted.isEmpty() )
310 const auto fieldEndCasted { refFieldCast( dimension.endFieldName, queryType, fieldType ) };
311 if ( !dateTimeInterval.
begin().isValid() && !dateTimeInterval.
end().isValid() )
321 if ( fieldType == QMetaType::Type::QDate )
323 beginQuery = dateTimeInterval.
begin().date().toString( Qt::DateFormat::ISODate );
324 endQuery = dateTimeInterval.
end().date().toString( Qt::DateFormat::ISODate );
328 beginQuery = dateTimeInterval.
begin().toString( Qt::DateFormat::ISODate );
329 endQuery = dateTimeInterval.
end().toString( Qt::DateFormat::ISODate );
331 conditions.push_back( makeFilter( fieldBegin, fieldEnd, fieldfBeginCasted, fieldEndCasted, beginQuery, endQuery ) );
338 for (
const auto &dimension : std::as_const( dimensions ) )
341 const bool fieldIsDateTime { dimension.name.toLower() ==
"time"_L1 };
342 const QMetaType::Type fieldType { fieldIsDateTime ? QMetaType::Type::QDateTime : QMetaType::Type::QDate };
344 const auto fieldRefBegin { refFieldCast( dimension.fieldName, queryType, fieldType ) };
345 if ( fieldRefBegin.isEmpty() )
352 const auto fieldRefEnd { refFieldCast( dimension.endFieldName, queryType, fieldType ) };
359 if ( !inputQueryIsDateTime || !fieldIsDateTime )
361 QString castedInterval { interval };
363 if ( inputQueryIsDateTime )
365 castedInterval = QDate::fromString( castedInterval, Qt::DateFormat::ISODate ).toString( Qt::DateFormat::ISODate );
371 QString castedInterval { interval };
373 if ( !inputQueryIsDateTime )
375 castedInterval = QDateTime::fromString( castedInterval, Qt::DateFormat::ISODate ).toString( Qt::DateFormat::ISODate );
380 if ( !fieldRefEnd.isEmpty() )
382 condition = u
"( %1 IS NULL OR %2 <= %3 ) AND ( %5 IS NULL OR %3 <= %4 )"_s.arg( fieldBegin, fieldRefBegin, castedValue, fieldRefEnd, fieldEnd );
386 condition = u
"( %1 IS NULL OR %2 = %3 )"_s
387 .arg( fieldBegin, fieldRefBegin, castedValue );
389 conditions.push_back( condition );
392 if ( !conditions.isEmpty() )
427 QDateTime min { minVal.toDateTime() };
428 QDateTime max { maxVal.toDateTime() };
429 if ( !dimInfo.endFieldName.isEmpty() )
438 QDateTime minEnd { minVal.toDateTime() };
439 QDateTime maxEnd { maxVal.toDateTime() };
440 if ( minEnd.isValid() )
442 min = std::min<QDateTime>( min, minEnd );
444 if ( maxEnd.isValid() )
446 max = std::max<QDateTime>( max, maxEnd );
454 if ( dimensions.isEmpty() )
464 for (
const auto &dimension : dimensions )
469 extent = range( dimension );
474 extent.
extend( range( dimension ) );
477 json ret = json::array();
478 const QString beginVal { extent.
begin().toString( Qt::DateFormat::ISODate ) };
479 const QString endVal { extent.
end().toString( Qt::DateFormat::ISODate ) };
481 if ( beginVal.isEmpty() && endVal.isEmpty() )
483 ret.push_back( {
nullptr,
nullptr } );
485 else if ( beginVal.isEmpty() )
487 ret.push_back( {
nullptr, endVal.toStdString() } );
489 else if ( endVal.isEmpty() )
491 ret.push_back( { beginVal.toStdString(),
nullptr } );
495 ret.push_back( { beginVal.toStdString(), endVal.toStdString() } );
499 catch ( std::exception &ex )
501 const QString errorMessage { u
"Error creating temporal extent: %1"_s.arg( ex.what() ) };