Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgspostgresstringutils.cpp 3 : : --------------------- 4 : : begin : July 2019 5 : : copyright : (C) 2019 by David Signer 6 : : email : david at opengis dot ch 7 : : *************************************************************************** 8 : : * * 9 : : * This program is free software; you can redistribute it and/or modify * 10 : : * it under the terms of the GNU General Public License as published by * 11 : : * the Free Software Foundation; either version 2 of the License, or * 12 : : * (at your option) any later version. * 13 : : * * 14 : : ***************************************************************************/ 15 : : 16 : : #include "qgspostgresstringutils.h" 17 : : #include "qgsmessagelog.h" 18 : : #include <QDebug> 19 : : #include <nlohmann/json.hpp> 20 : : 21 : : using namespace nlohmann; 22 : : 23 : 0 : static void jumpSpace( const QString &txt, int &i ) 24 : : { 25 : 0 : while ( i < txt.length() && txt.at( i ).isSpace() ) 26 : 0 : ++i; 27 : 0 : } 28 : : 29 : 0 : QString QgsPostgresStringUtils::getNextString( const QString &txt, int &i, const QString &sep ) 30 : : { 31 : 0 : jumpSpace( txt, i ); 32 : 0 : QString cur = txt.mid( i ); 33 : 0 : if ( cur.startsWith( '"' ) ) 34 : : { 35 : 0 : QRegExp stringRe( "^\"((?:\\\\.|[^\"\\\\])*)\".*" ); 36 : 0 : if ( !stringRe.exactMatch( cur ) ) 37 : : { 38 : 0 : QgsMessageLog::logMessage( QObject::tr( "Cannot find end of double quoted string: %1" ).arg( txt ), QObject::tr( "PostgresStringUtils" ) ); 39 : 0 : return QString(); 40 : : } 41 : 0 : i += stringRe.cap( 1 ).length() + 2; 42 : 0 : jumpSpace( txt, i ); 43 : 0 : if ( !QStringView{txt}.mid( i ).startsWith( sep ) && i < txt.length() ) 44 : : { 45 : 0 : QgsMessageLog::logMessage( QObject::tr( "Cannot find separator: %1" ).arg( txt.mid( i ) ), QObject::tr( "PostgresStringUtils" ) ); 46 : 0 : return QString(); 47 : : } 48 : 0 : i += sep.length(); 49 : 0 : return stringRe.cap( 1 ).replace( QLatin1String( "\\\"" ), QLatin1String( "\"" ) ).replace( QLatin1String( "\\\\" ), QLatin1String( "\\" ) ); 50 : 0 : } 51 : : else 52 : : { 53 : 0 : int sepPos = cur.indexOf( sep ); 54 : 0 : if ( sepPos < 0 ) 55 : : { 56 : 0 : i += cur.length(); 57 : 0 : return cur.trimmed(); 58 : : } 59 : 0 : i += sepPos + sep.length(); 60 : 0 : return cur.left( sepPos ).trimmed(); 61 : : } 62 : 0 : } 63 : : 64 : 0 : QVariantList QgsPostgresStringUtils::parseArray( const QString &string ) 65 : : { 66 : 0 : QVariantList variantList; 67 : : 68 : : //it's a postgres array 69 : 0 : QString newVal = string.mid( 1, string.length() - 2 ); 70 : : 71 : 0 : if ( newVal.trimmed().startsWith( '{' ) ) 72 : : { 73 : : //it's a multidimensional array 74 : 0 : QStringList values; 75 : 0 : QString subarray = newVal; 76 : 0 : while ( !subarray.isEmpty() ) 77 : : { 78 : 0 : bool escaped = false; 79 : 0 : int openedBrackets = 1; 80 : 0 : int i = 0; 81 : 0 : while ( i < subarray.length() && openedBrackets > 0 ) 82 : : { 83 : 0 : ++i; 84 : : 85 : 0 : if ( subarray.at( i ) == '}' && !escaped ) openedBrackets--; 86 : 0 : else if ( subarray.at( i ) == '{' && !escaped ) openedBrackets++; 87 : : 88 : 0 : escaped = !escaped ? subarray.at( i ) == '\\' : false; 89 : : } 90 : : 91 : 0 : variantList.append( subarray.left( ++i ) ); 92 : 0 : i = subarray.indexOf( ',', i ); 93 : 0 : i = i > 0 ? subarray.indexOf( '{', i ) : -1; 94 : 0 : if ( i == -1 ) 95 : 0 : break; 96 : : 97 : 0 : subarray = subarray.mid( i ); 98 : : } 99 : 0 : } 100 : : else 101 : : { 102 : 0 : int i = 0; 103 : 0 : while ( i < newVal.length() ) 104 : : { 105 : 0 : const QString value = getNextString( newVal, i, QStringLiteral( "," ) ); 106 : 0 : if ( value.isNull() ) 107 : : { 108 : 0 : QgsMessageLog::logMessage( QObject::tr( "Error parsing PG like array: %1" ).arg( newVal ), QObject::tr( "PostgresStringUtils" ) ); 109 : 0 : break; 110 : : } 111 : 0 : variantList.append( value ); 112 : 0 : } 113 : : } 114 : : 115 : 0 : return variantList; 116 : : 117 : 0 : } 118 : : 119 : 0 : QString QgsPostgresStringUtils::buildArray( const QVariantList &list ) 120 : : { 121 : 0 : QStringList sl; 122 : 0 : for ( const QVariant &v : std::as_const( list ) ) 123 : : { 124 : : // Convert to proper type 125 : 0 : switch ( v.type() ) 126 : : { 127 : : case QVariant::Type::Int: 128 : : case QVariant::Type::LongLong: 129 : 0 : sl.push_back( v.toString() ); 130 : 0 : break; 131 : : default: 132 : 0 : QString newS = v.toString(); 133 : 0 : if ( newS.startsWith( '{' ) ) 134 : : { 135 : 0 : sl.push_back( newS ); 136 : 0 : } 137 : : else 138 : : { 139 : 0 : newS.replace( '\\', QLatin1String( R"(\\)" ) ); 140 : 0 : newS.replace( '\"', QLatin1String( R"(\")" ) ); 141 : 0 : sl.push_back( "\"" + newS + "\"" ); 142 : : } 143 : : break; 144 : 0 : } 145 : : } 146 : : //store as a formatted string because the fields supports only string 147 : 0 : QString s = sl.join( ',' ).prepend( '{' ).append( '}' ); 148 : : 149 : 0 : return s; 150 : 0 : }