QGIS API Documentation 3.30.0-'s-Hertogenbosch (f186b8efe0)
qgspostgresstringutils.cpp
Go to the documentation of this file.
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
17#include "qgsmessagelog.h"
18
19#include <QRegularExpression>
20
21#include <nlohmann/json.hpp>
22
23using namespace nlohmann;
24
25static void jumpSpace( const QString &txt, int &i )
26{
27 while ( i < txt.length() && txt.at( i ).isSpace() )
28 ++i;
29}
30
31QString QgsPostgresStringUtils::getNextString( const QString &txt, int &i, const QString &sep )
32{
33 jumpSpace( txt, i );
34 QString cur = txt.mid( i );
35 if ( cur.startsWith( '"' ) )
36 {
37 const QRegularExpression stringRe( QRegularExpression::anchoredPattern( "^\"((?:\\\\.|[^\"\\\\])*)\".*" ) );
38 const QRegularExpressionMatch match = stringRe.match( cur );
39 if ( !match.hasMatch() )
40 {
41 QgsMessageLog::logMessage( QObject::tr( "Cannot find end of double quoted string: %1" ).arg( txt ), QObject::tr( "PostgresStringUtils" ) );
42 return QString();
43 }
44 i += match.captured( 1 ).length() + 2;
45 jumpSpace( txt, i );
46 if ( !QStringView{txt}.mid( i ).startsWith( sep ) && i < txt.length() )
47 {
48 QgsMessageLog::logMessage( QObject::tr( "Cannot find separator: %1" ).arg( txt.mid( i ) ), QObject::tr( "PostgresStringUtils" ) );
49 return QString();
50 }
51 i += sep.length();
52 return match.captured( 1 ).replace( QLatin1String( "\\\"" ), QLatin1String( "\"" ) ).replace( QLatin1String( "\\\\" ), QLatin1String( "\\" ) );
53 }
54 else
55 {
56 int sepPos = cur.indexOf( sep );
57 if ( sepPos < 0 )
58 {
59 i += cur.length();
60 return cur.trimmed();
61 }
62 i += sepPos + sep.length();
63 return cur.left( sepPos ).trimmed();
64 }
65}
66
67QVariantList QgsPostgresStringUtils::parseArray( const QString &string )
68{
69 QVariantList variantList;
70
71 //it's a postgres array
72 QString newVal = string.mid( 1, string.length() - 2 );
73
74 if ( newVal.trimmed().startsWith( '{' ) )
75 {
76 //it's a multidimensional array
77 QString subarray = newVal;
78 while ( !subarray.isEmpty() )
79 {
80 bool escaped = false;
81 int openedBrackets = 1;
82 int i = 0;
83 while ( i < subarray.length() && openedBrackets > 0 )
84 {
85 ++i;
86
87 if ( subarray.at( i ) == '}' && !escaped ) openedBrackets--;
88 else if ( subarray.at( i ) == '{' && !escaped ) openedBrackets++;
89
90 escaped = !escaped ? subarray.at( i ) == '\\' : false;
91 }
92
93 variantList.append( subarray.left( ++i ) );
94 i = subarray.indexOf( ',', i );
95 i = i > 0 ? subarray.indexOf( '{', i ) : -1;
96 if ( i == -1 )
97 break;
98
99 subarray = subarray.mid( i );
100 }
101 }
102 else
103 {
104 int i = 0;
105 while ( i < newVal.length() )
106 {
107 const QString value = getNextString( newVal, i, QStringLiteral( "," ) );
108 if ( value.isNull() )
109 {
110 QgsMessageLog::logMessage( QObject::tr( "Error parsing PG like array: %1" ).arg( newVal ), QObject::tr( "PostgresStringUtils" ) );
111 break;
112 }
113 variantList.append( value );
114 }
115 }
116
117 return variantList;
118
119}
120
121QString QgsPostgresStringUtils::buildArray( const QVariantList &list )
122{
123 QStringList sl;
124 for ( const QVariant &v : std::as_const( list ) )
125 {
126 // Convert to proper type
127 switch ( v.type() )
128 {
129 case QVariant::Type::Int:
130 case QVariant::Type::LongLong:
131 sl.push_back( v.toString() );
132 break;
133 default:
134 QString newS = v.toString();
135 if ( newS.startsWith( '{' ) )
136 {
137 sl.push_back( newS );
138 }
139 else
140 {
141 newS.replace( '\\', QLatin1String( R"(\\)" ) );
142 newS.replace( '\"', QLatin1String( R"(\")" ) );
143 sl.push_back( "\"" + newS + "\"" );
144 }
145 break;
146 }
147 }
148 //store as a formatted string because the fields supports only string
149 QString s = sl.join( ',' ).prepend( '{' ).append( '}' );
150
151 return s;
152}
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
static QString buildArray(const QVariantList &list)
Build a postgres array like formatted list in a string from a QVariantList.
static QVariantList parseArray(const QString &string)
Returns a QVariantList created out of a string containing an array in postgres array format {1,...