@@ -331,8 +331,14 @@ const buildWhereClause = ({ schema, query, index }) => {
331
331
if ( opts . indexOf ( 'i' ) >= 0 ) {
332
332
operator = '~*' ;
333
333
}
334
+ if ( opts . indexOf ( 'x' ) >= 0 ) {
335
+ regex = removeWhiteSpace ( regex ) ;
336
+ }
334
337
}
335
- patterns . push ( `$${ index } :name ${ operator } $${ index + 1 } ` ) ;
338
+
339
+ regex = processRegexPattern ( regex ) ;
340
+
341
+ patterns . push ( `$${ index } :name ${ operator } '$${ index + 1 } :raw'` ) ;
336
342
values . push ( fieldName , regex ) ;
337
343
index += 2 ;
338
344
}
@@ -1131,6 +1137,79 @@ function notImplemented() {
1131
1137
return Promise . reject ( new Error ( 'Not implemented yet.' ) ) ;
1132
1138
}
1133
1139
1140
+ function removeWhiteSpace ( regex ) {
1141
+ if ( ! regex . endsWith ( '\n' ) ) {
1142
+ regex += '\n' ;
1143
+ }
1144
+
1145
+ // remove non escaped comments
1146
+ return regex . replace ( / ( [ ^ \\ ] ) # .* \n / gmi, '$1' )
1147
+ // remove lines starting with a comment
1148
+ . replace ( / ^ # .* \n / gmi, '' )
1149
+ // remove non escaped whitespace
1150
+ . replace ( / ( [ ^ \\ ] ) \s + / gmi, '$1' )
1151
+ // remove whitespace at the beginning of a line
1152
+ . replace ( / ^ \s + / , '' )
1153
+ . trim ( ) ;
1154
+ }
1155
+
1156
+ function processRegexPattern ( s ) {
1157
+ if ( s && s . startsWith ( '^' ) ) {
1158
+ // regex for startsWith
1159
+ return '^' + literalizeRegexPart ( s . slice ( 1 ) ) ;
1160
+
1161
+ } else if ( s && s . endsWith ( '$' ) ) {
1162
+ // regex for endsWith
1163
+ return literalizeRegexPart ( s . slice ( 0 , s . length - 1 ) ) + '$' ;
1164
+ }
1165
+
1166
+ // regex for contains
1167
+ return literalizeRegexPart ( s ) ;
1168
+ }
1169
+
1170
+ function createLiteralRegex ( remaining ) {
1171
+ return remaining . split ( '' ) . map ( c => {
1172
+ if ( c . match ( / [ 0 - 9 a - z A - Z ] / ) !== null ) {
1173
+ // don't escape alphanumeric characters
1174
+ return c ;
1175
+ }
1176
+ // escape everything else (single quotes with single quotes, everything else with a backslash)
1177
+ return c === `'` ? `''` : `\\${ c } ` ;
1178
+ } ) . join ( '' ) ;
1179
+ }
1180
+
1181
+ function literalizeRegexPart ( s ) {
1182
+ const matcher1 = / \\ Q ( (? ! \\ E ) .* ) \\ E $ /
1183
+ const result1 = s . match ( matcher1 ) ;
1184
+ if ( result1 && result1 . length > 1 && result1 . index > - 1 ) {
1185
+ // process regex that has a beginning and an end specified for the literal text
1186
+ const prefix = s . substr ( 0 , result1 . index ) ;
1187
+ const remaining = result1 [ 1 ] ;
1188
+
1189
+ return literalizeRegexPart ( prefix ) + createLiteralRegex ( remaining ) ;
1190
+ }
1191
+
1192
+ // process regex that has a beginning specified for the literal text
1193
+ const matcher2 = / \\ Q ( (? ! \\ E ) .* ) $ /
1194
+ const result2 = s . match ( matcher2 ) ;
1195
+ if ( result2 && result2 . length > 1 && result2 . index > - 1 ) {
1196
+ const prefix = s . substr ( 0 , result2 . index ) ;
1197
+ const remaining = result2 [ 1 ] ;
1198
+
1199
+ return literalizeRegexPart ( prefix ) + createLiteralRegex ( remaining ) ;
1200
+ }
1201
+
1202
+ // remove all instances of \Q and \E from the remaining text & escape single quotes
1203
+ return (
1204
+ s . replace ( / ( [ ^ \\ ] ) ( \\ E ) / , '$1' )
1205
+ . replace ( / ( [ ^ \\ ] ) ( \\ Q ) / , '$1' )
1206
+ . replace ( / ^ \\ E / , '' )
1207
+ . replace ( / ^ \\ Q / , '' )
1208
+ . replace ( / ( [ ^ ' ] ) ' / , `$1''` )
1209
+ . replace ( / ^ ' ( [ ^ ' ] ) / , `''$1` )
1210
+ ) ;
1211
+ }
1212
+
1134
1213
// Function to set a key on a nested JSON document
1135
1214
const json_object_set_key = 'CREATE OR REPLACE FUNCTION "json_object_set_key"(\
1136
1215
"json" jsonb,\
0 commit comments