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