Skip to content

Commit 47ef7e8

Browse files
committed
Handle whitespace and escaped quotes in CQL values
See openlayers#743.
1 parent 8d0da09 commit 47ef7e8

File tree

2 files changed

+68
-4
lines changed

2 files changed

+68
-4
lines changed

lib/OpenLayers/Format/CQL.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ OpenLayers.Format.CQL = (function() {
3030
COMPARISON: /^(=|<>|<=|<|>=|>|LIKE)/i,
3131
COMMA: /^,/,
3232
LOGICAL: /^(AND|OR)/i,
33-
VALUE: /^('\w+'|\d+(\.\d*)?|\.\d+)/,
33+
VALUE: /^('([^']|'')*'|\d+(\.\d*)?|\.\d+)/,
3434
LPAREN: /^\(/,
3535
RPAREN: /^\)/,
3636
SPATIAL: /^(BBOX|INTERSECTS|DWITHIN|WITHIN|CONTAINS)/i,
@@ -258,8 +258,9 @@ OpenLayers.Format.CQL = (function() {
258258
type: operators[tok.text.toUpperCase()]
259259
});
260260
case "VALUE":
261-
if ((/^'.*'$/).test(tok.text)) {
262-
return tok.text.substr(1, tok.text.length - 2);
261+
var match = tok.text.match(/^'(.*)'$/);
262+
if (match) {
263+
return match[1].replace(/''/g, "'");
263264
} else {
264265
return Number(tok.text);
265266
}
@@ -425,7 +426,7 @@ OpenLayers.Format.CQL = (function() {
425426
}
426427
case undefined:
427428
if (typeof filter === "string") {
428-
return "'" + filter + "'";
429+
return "'" + filter.replace(/'/g, "''") + "'";
429430
} else if (typeof filter === "number") {
430431
return String(filter);
431432
}

tests/Format/CQL.html

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,69 @@
3535
t.eq(format.write(filter), test_cql, "write returned test cql");
3636
}
3737

38+
function test_read_whitespace(t) {
39+
t.plan(4);
40+
var cql = "TYPEDESC = 'BOE Numbered Plans'";
41+
var format = new OpenLayers.Format.CQL();
42+
var filter = format.read(cql);
43+
t.ok(filter instanceof OpenLayers.Filter.Comparison, "filter parsed correctly with whitespace in string");
44+
t.eq(filter.property, 'TYPEDESC', "filter property parsed correctly");
45+
t.eq(filter.value, 'BOE Numbered Plans', "value parsed correctly");
46+
t.eq(filter.type, '==', 'filter type parsed correctly');
47+
}
48+
49+
function test_read_escaped_quotes(t) {
50+
t.plan(14);
51+
var cql = "PROP = 'don''t worry' or PROP = 'value''s value' or PROP = 'foo'";
52+
var format = new OpenLayers.Format.CQL();
53+
54+
var filter = format.read(cql);
55+
t.ok(filter instanceof OpenLayers.Filter.Logical, "filter type");
56+
t.eq(filter.filters.length, 2, "filter children");
57+
58+
var f0 = filter.filters[0];
59+
t.ok(f0 instanceof OpenLayers.Filter.Logical, "f0 type");
60+
t.eq(f0.filters.length, 2, "f0 children");
61+
62+
var f00 = f0.filters[0];
63+
t.eq(f00.property, "PROP", "f000 property");
64+
t.eq(f00.type, "==", "f000 type");
65+
t.eq(f00.value, "don't worry", "f000 value");
66+
67+
var f01 = f0.filters[1];
68+
t.eq(f01.property, "PROP", "f001 property");
69+
t.eq(f01.type, "==", "f001 type");
70+
t.eq(f01.value, "value's value", "f001 value");
71+
72+
var f1 = filter.filters[1];
73+
t.ok(f1 instanceof OpenLayers.Filter.Comparison, "f1 type");
74+
t.eq(f1.property, "PROP", "f1 property");
75+
t.eq(f1.type, "==", "f1 type");
76+
t.eq(f1.value, "foo", "f1 value");
77+
}
78+
79+
function test_write_escaped_quotes(t) {
80+
t.plan(1);
81+
var filter = new OpenLayers.Filter.Logical({
82+
type: OpenLayers.Filter.Logical.OR,
83+
filters: [
84+
new OpenLayers.Filter.Comparison({
85+
type: OpenLayers.Filter.Comparison.EQUAL_TO,
86+
property: "PROP",
87+
value: "quot'd string"
88+
}),
89+
new OpenLayers.Filter.Comparison({
90+
type: OpenLayers.Filter.Comparison.EQUAL_TO,
91+
property: "PROP",
92+
value: "don't quote's"
93+
})
94+
]
95+
});
96+
var format = new OpenLayers.Format.CQL();
97+
var cql = format.write(filter);
98+
t.eq(cql, "(PROP = 'quot''d string') OR (PROP = 'don''t quote''s')", "escaped");
99+
}
100+
38101
function test_Comparison_number(t) {
39102
t.plan(5);
40103
var test_cql, format, filter;

0 commit comments

Comments
 (0)