Skip to content

Commit edf6ab6

Browse files
kulshekharflovilmart
authored andcommitted
Enable query related tests for Postgres (#2969)
1 parent 142b3be commit edf6ab6

File tree

2 files changed

+90
-7
lines changed

2 files changed

+90
-7
lines changed

spec/ParseQuery.spec.js

+10-6
Original file line numberDiff line numberDiff line change
@@ -1233,7 +1233,7 @@ describe('Parse.Query testing', () => {
12331233
query.find(expectError(Parse.Error.INVALID_QUERY, done));
12341234
});
12351235

1236-
it_exclude_dbs(['postgres'])("Use a regex that requires all modifiers", function(done) {
1236+
it("Use a regex that requires all modifiers", function(done) {
12371237
var thing = new TestObject();
12381238
thing.set("myString", "PArSe\nCom");
12391239
Parse.Object.saveAll([thing], function() {
@@ -1248,6 +1248,10 @@ describe('Parse.Query testing', () => {
12481248
success: function(results) {
12491249
equal(results.length, 1);
12501250
done();
1251+
},
1252+
error: function(err) {
1253+
jfail(err);
1254+
done();
12511255
}
12521256
});
12531257
});
@@ -1271,7 +1275,7 @@ describe('Parse.Query testing', () => {
12711275
var someAscii = "\\E' !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTU" +
12721276
"VWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~'";
12731277

1274-
it_exclude_dbs(['postgres'])("contains", function(done) {
1278+
it("contains", function(done) {
12751279
Parse.Object.saveAll([new TestObject({myString: "zax" + someAscii + "qub"}),
12761280
new TestObject({myString: "start" + someAscii}),
12771281
new TestObject({myString: someAscii + "end"}),
@@ -1287,7 +1291,7 @@ describe('Parse.Query testing', () => {
12871291
});
12881292
});
12891293

1290-
it_exclude_dbs(['postgres'])("startsWith", function(done) {
1294+
it("startsWith", function(done) {
12911295
Parse.Object.saveAll([new TestObject({myString: "zax" + someAscii + "qub"}),
12921296
new TestObject({myString: "start" + someAscii}),
12931297
new TestObject({myString: someAscii + "end"}),
@@ -1303,7 +1307,7 @@ describe('Parse.Query testing', () => {
13031307
});
13041308
});
13051309

1306-
it_exclude_dbs(['postgres'])("endsWith", function(done) {
1310+
it("endsWith", function(done) {
13071311
Parse.Object.saveAll([new TestObject({myString: "zax" + someAscii + "qub"}),
13081312
new TestObject({myString: "start" + someAscii}),
13091313
new TestObject({myString: someAscii + "end"}),
@@ -1634,7 +1638,7 @@ describe('Parse.Query testing', () => {
16341638
})
16351639
});
16361640

1637-
it_exclude_dbs(['postgres'])('properly nested array of mixed objects with bad ids', (done) => {
1641+
it('properly nested array of mixed objects with bad ids', (done) => {
16381642
let objects = [];
16391643
let total = 0;
16401644
while(objects.length != 5) {
@@ -1744,7 +1748,7 @@ describe('Parse.Query testing', () => {
17441748
});
17451749
});
17461750

1747-
it_exclude_dbs(['postgres'])("matches query", function(done) {
1751+
it("matches query", function(done) {
17481752
var ParentObject = Parse.Object.extend("ParentObject");
17491753
var ChildObject = Parse.Object.extend("ChildObject");
17501754
var objects = [];

src/Adapters/Storage/Postgres/PostgresStorageAdapter.js

+80-1
Original file line numberDiff line numberDiff line change
@@ -331,8 +331,14 @@ const buildWhereClause = ({ schema, query, index }) => {
331331
if (opts.indexOf('i') >= 0) {
332332
operator = '~*';
333333
}
334+
if (opts.indexOf('x') >= 0) {
335+
regex = removeWhiteSpace(regex);
336+
}
334337
}
335-
patterns.push(`$${index}:name ${operator} $${index+1}`);
338+
339+
regex = processRegexPattern(regex);
340+
341+
patterns.push(`$${index}:name ${operator} '$${index+1}:raw'`);
336342
values.push(fieldName, regex);
337343
index += 2;
338344
}
@@ -1131,6 +1137,79 @@ function notImplemented() {
11311137
return Promise.reject(new Error('Not implemented yet.'));
11321138
}
11331139

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-9a-zA-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+
11341213
// Function to set a key on a nested JSON document
11351214
const json_object_set_key = 'CREATE OR REPLACE FUNCTION "json_object_set_key"(\
11361215
"json" jsonb,\

0 commit comments

Comments
 (0)