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