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