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