QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
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 QStringList values;
78 QString subarray = newVal;
79 while ( !subarray.isEmpty() )
80 {
81 bool escaped = false;
82 int openedBrackets = 1;
83 int i = 0;
84 while ( i < subarray.length() && openedBrackets > 0 )
85 {
86 ++i;
87
88 if ( subarray.at( i ) == '}' && !escaped ) openedBrackets--;
89 else if ( subarray.at( i ) == '{' && !escaped ) openedBrackets++;
90
91 escaped = !escaped ? subarray.at( i ) == '\\' : false;
92 }
93
94 variantList.append( subarray.left( ++i ) );
95 i = subarray.indexOf( ',', i );
96 i = i > 0 ? subarray.indexOf( '{', i ) : -1;
97 if ( i == -1 )
98 break;
99
100 subarray = subarray.mid( i );
101 }
102 }
103 else
104 {
105 int i = 0;
106 while ( i < newVal.length() )
107 {
108 const QString value = getNextString( newVal, i, QStringLiteral( "," ) );
109 if ( value.isNull() )
110 {
111 QgsMessageLog::logMessage( QObject::tr( "Error parsing PG like array: %1" ).arg( newVal ), QObject::tr( "PostgresStringUtils" ) );
112 break;
113 }
114 variantList.append( value );
115 }
116 }
117
118 return variantList;
119
120}
121
122QString QgsPostgresStringUtils::buildArray( const QVariantList &list )
123{
124 QStringList sl;
125 for ( const QVariant &v : std::as_const( list ) )
126 {
127 // Convert to proper type
128 switch ( v.type() )
129 {
130 case QVariant::Type::Int:
131 case QVariant::Type::LongLong:
132 sl.push_back( v.toString() );
133 break;
134 default:
135 QString newS = v.toString();
136 if ( newS.startsWith( '{' ) )
137 {
138 sl.push_back( newS );
139 }
140 else
141 {
142 newS.replace( '\\', QLatin1String( R"(\\)" ) );
143 newS.replace( '\"', QLatin1String( R"(\")" ) );
144 sl.push_back( "\"" + newS + "\"" );
145 }
146 break;
147 }
148 }
149 //store as a formatted string because the fields supports only string
150 QString s = sl.join( ',' ).prepend( '{' ).append( '}' );
151
152 return s;
153}
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,...