Skip to content

Commit 3342d8a

Browse files
committed
filter works
1 parent 72552ec commit 3342d8a

9 files changed

+454
-73
lines changed

expected/jsquery.out

+169
Original file line numberDiff line numberDiff line change
@@ -1446,6 +1446,175 @@ select '{"a":[1,2]}' @@ '@# = 1'::jsquery;
14461446
t
14471447
(1 row)
14481448

1449+
--filter
1450+
select '?( not b>0). x'::jsquery;
1451+
jsquery
1452+
------------------------
1453+
?((NOT "b" > 0)) ."x"
1454+
(1 row)
1455+
1456+
select 'a.?(b>0 and x= 0 ) .c'::jsquery;
1457+
jsquery
1458+
-----------------------------------
1459+
"a" ?(("b" > 0 AND "x" = 0)) ."c"
1460+
(1 row)
1461+
1462+
select 'a.$. ?(b>0 and x= 0 ) . c.k'::jsquery;
1463+
jsquery
1464+
-----------------------------------------
1465+
"a".$ ?(("b" > 0 AND "x" = 0)) ."c"."k"
1466+
(1 row)
1467+
1468+
select 'a.$.? (b>0 and x.*= 0 ).c.k'::jsquery;
1469+
jsquery
1470+
-------------------------------------------
1471+
"a".$ ?(("b" > 0 AND "x".* = 0)) ."c"."k"
1472+
(1 row)
1473+
1474+
select '[{"a":1, "b":10}, {"a":2, "b":20}, {"a":3, "b":30}]'::jsonb @@ '#. ?(a < 0) (b=20)';
1475+
?column?
1476+
----------
1477+
f
1478+
(1 row)
1479+
1480+
select '[{"a":1, "b":10}, {"a":2, "b":20}, {"a":3, "b":30}]'::jsonb @@ '#. ?(a > 0) (b=20)';
1481+
?column?
1482+
----------
1483+
t
1484+
(1 row)
1485+
1486+
select '[{"a":1, "b":10}, {"a":2, "b":20}, {"a":3, "b":30}]'::jsonb @@ '#. ?(a > 1) (b=20)';
1487+
?column?
1488+
----------
1489+
t
1490+
(1 row)
1491+
1492+
select '[{"a":1, "b":10}, {"a":2, "b":20}, {"a":3, "b":30}]'::jsonb @@ '#. ?(a > 2) (b=20)';
1493+
?column?
1494+
----------
1495+
f
1496+
(1 row)
1497+
1498+
select '[{"a":1, "b":10}, {"a":2, "b":20}, {"a":3, "b":30}]'::jsonb @@ '#. ?(a > 3) (b=20)';
1499+
?column?
1500+
----------
1501+
f
1502+
(1 row)
1503+
1504+
select '[{"a":1, "b":10}, {"a":2, "b":20}]'::jsonb ~~ '#.a';
1505+
?column?
1506+
----------
1507+
[1, 2]
1508+
(1 row)
1509+
1510+
select '[{"a":1, "b":10}, {"a":2, "b":20}]'::jsonb ~~ '#. ?(a > 1). b';
1511+
?column?
1512+
----------
1513+
[20]
1514+
(1 row)
1515+
1516+
select '[{"a":1, "b":10}, {"a":2, "b":20}, {"a":3, "b":30}]'::jsonb ~~ '# . ?(a > 1)';
1517+
?column?
1518+
----------------------------------------
1519+
[{"a": 2, "b": 20}, {"a": 3, "b": 30}]
1520+
(1 row)
1521+
1522+
select '[{"a":1, "b":10}, {"a":2, "b":20}, {"a":3, "b":30}]'::jsonb ~~ '%';
1523+
?column?
1524+
----------
1525+
1526+
(1 row)
1527+
1528+
select '{"a":1, "b":2, "c":3}'::jsonb ~~ '%';
1529+
?column?
1530+
-----------
1531+
[1, 2, 3]
1532+
(1 row)
1533+
1534+
select '{"a":1, "b":2, "c":3}'::jsonb ~~ '% . ? ( $ > 2 )';
1535+
?column?
1536+
----------
1537+
[3]
1538+
(1 row)
1539+
1540+
select '{"a":1, "b":2, "c":3}'::jsonb ~~ '% . ? ( $ > 2 ).$';
1541+
?column?
1542+
----------
1543+
[3]
1544+
(1 row)
1545+
1546+
select '{"a":1, "b":2, "c":3}'::jsonb ~~ '? ( % > 2 )';
1547+
?column?
1548+
----------------------------
1549+
[{"a": 1, "b": 2, "c": 3}]
1550+
(1 row)
1551+
1552+
select '{"a":1, "b":2, "c":3}'::jsonb ~~ '? ( %: > 0 )';
1553+
?column?
1554+
----------------------------
1555+
[{"a": 1, "b": 2, "c": 3}]
1556+
(1 row)
1557+
1558+
select '{"a":1, "b":2, "c":3}'::jsonb ~~ '? ( %: > 2 )';
1559+
?column?
1560+
----------
1561+
1562+
(1 row)
1563+
1564+
select '[{"a":1, "b":10}, {"a":2, "b":20}, {"a":3, "b":30}]'::jsonb ~~ '#';
1565+
?column?
1566+
-----------------------------------------------------------
1567+
[{"a": 1, "b": 10}, {"a": 2, "b": 20}, {"a": 3, "b": 30}]
1568+
(1 row)
1569+
1570+
select '[1,2,3]'::jsonb ~~ '#';
1571+
?column?
1572+
-----------
1573+
[1, 2, 3]
1574+
(1 row)
1575+
1576+
select '[1,2,3]'::jsonb ~~ '#. ?($ > 2)';
1577+
?column?
1578+
----------
1579+
[3]
1580+
(1 row)
1581+
1582+
select '[1,2,3]'::jsonb ~~ '#. ?($ > 2).$';
1583+
?column?
1584+
----------
1585+
[3]
1586+
(1 row)
1587+
1588+
select '[1,2,3]'::jsonb ~~ ' ?(#.$ > 2).$';
1589+
?column?
1590+
-------------
1591+
[[1, 2, 3]]
1592+
(1 row)
1593+
1594+
select '[1,2,3]'::jsonb ~~ ' ?(#:.$ > 2).$';
1595+
?column?
1596+
----------
1597+
1598+
(1 row)
1599+
1600+
select '[1,2,3]'::jsonb ~~ ' ?(#:.$ > 0).$';
1601+
?column?
1602+
-------------
1603+
[[1, 2, 3]]
1604+
(1 row)
1605+
1606+
select '{"a": {"b": {"c": 1}}}'::jsonb ~~ '*.?(c >0)';
1607+
?column?
1608+
------------
1609+
[{"c": 1}]
1610+
(1 row)
1611+
1612+
select '{"a": {"b": {"c": 1}}}'::jsonb ~~ '?(*.c >0)';
1613+
?column?
1614+
--------------------------
1615+
[{"a": {"b": {"c": 1}}}]
1616+
(1 row)
1617+
14491618
--ALL
14501619
select 'a.*: = 4'::jsquery;
14511620
jsquery

jsquery--1.0.sql

+11
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,17 @@ CREATE OPERATOR @@ (
4848
JOIN = contjoinsel
4949
);
5050

51+
CREATE FUNCTION json_jsquery_filter(jsonb, jsquery)
52+
RETURNS jsonb
53+
AS 'MODULE_PATHNAME'
54+
LANGUAGE C STRICT IMMUTABLE;
55+
56+
CREATE OPERATOR ~~ (
57+
LEFTARG = jsonb,
58+
RIGHTARG = jsquery,
59+
PROCEDURE = json_jsquery_filter
60+
);
61+
5162
CREATE FUNCTION jsquery_join_and(jsquery, jsquery)
5263
RETURNS jsquery
5364
AS 'MODULE_PATHNAME'

jsquery.h

+5-3
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,13 @@ typedef enum JsQueryItemType {
5757
jqiLength,
5858
jqiIn,
5959
jqiIs,
60-
jqiIndexArray
60+
jqiIndexArray,
61+
jqiFilter
6162
} JsQueryItemType;
6263

6364
/*
6465
* JsQueryHint is stored in the same byte as JsQueryItemType so
65-
* JsQueryItemType should not use two high bits
66+
* JsQueryItemType should not use three high bits
6667
*/
6768
typedef enum JsQueryHint {
6869
jsqIndexDefault = 0x00,
@@ -84,7 +85,7 @@ typedef enum JsQueryHint {
8485
typedef struct JsQueryItem {
8586
JsQueryItemType type;
8687
JsQueryHint hint;
87-
int32 nextPos;
88+
uint32 nextPos;
8889
char *base;
8990

9091
union {
@@ -135,6 +136,7 @@ struct JsQueryParseItem {
135136
JsQueryItemType type;
136137
JsQueryHint hint;
137138
JsQueryParseItem *next; /* next in path */
139+
bool filter;
138140

139141
union {
140142
struct {

jsquery_gram.y

+33-24
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
/*-------------------------------------------------------------------------
22
*
33
* jsquery_gram.y
4-
* Grammar definitions for jsquery datatype
4+
* Grammar definitions for jsquery datatype
55
*
66
* Copyright (c) 2014, PostgreSQL Global Development Group
77
* Author: Teodor Sigaev <[email protected]>
88
*
99
* IDENTIFICATION
10-
* contrib/jsquery/jsquery_gram.y
10+
* contrib/jsquery/jsquery_gram.y
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -43,8 +43,8 @@ fprintf_to_ereport(const char *fmt, const char *msg)
4343

4444
/* struct string is shared between scan and gram */
4545
typedef struct string {
46-
char *val;
47-
int len;
46+
char *val;
47+
int len;
4848
int total;
4949
} string;
5050
#include <jsquery_gram.h>
@@ -188,6 +188,9 @@ makeItemList(List *list) {
188188

189189
head = end = (JsQueryParseItem*)linitial(list);
190190

191+
while(end->next)
192+
end = end->next;
193+
191194
foreach(cell, list)
192195
{
193196
JsQueryParseItem *c = (JsQueryParseItem*)lfirst(cell);
@@ -197,6 +200,9 @@ makeItemList(List *list) {
197200

198201
end->next = c;
199202
end = c;
203+
204+
while(end->next)
205+
end = end->next;
200206
}
201207

202208
return head;
@@ -212,7 +218,7 @@ makeItemList(List *list) {
212218
%parse-param {JsQueryParseItem **result}
213219

214220
%union {
215-
string str;
221+
string str;
216222
List *elems; /* list of JsQueryParseItem */
217223

218224
JsQueryParseItem *value;
@@ -225,25 +231,26 @@ makeItemList(List *list) {
225231

226232
%token <str> STRING_P NUMERIC_P INT_P
227233

228-
%type <value> result scalar_value
234+
%type <value> result scalar_value
229235

230236
%type <elems> path value_list
231237

232-
%type <value> key key_any right_expr expr array numeric
238+
%type <value> key key_any right_expr expr array numeric
233239

234240
%token <hint> HINT_P
235241

236-
%left OR_P
237-
%left AND_P
238-
%right NOT_P
239-
%nonassoc IN_P IS_P
242+
%left OR_P
243+
%left AND_P
244+
%right NOT_P
245+
%nonassoc IN_P IS_P
240246
%nonassoc '(' ')'
241247

242248
/* Grammar follows */
243249
%%
244250

245-
result:
246-
expr { *result = $1; }
251+
result:
252+
expr { *result = $1; }
253+
| path { *result = makeItemList($1); }
247254
| /* EMPTY */ { *result = NULL; }
248255
;
249256

@@ -271,8 +278,8 @@ scalar_value:
271278
;
272279

273280
value_list:
274-
scalar_value { $$ = lappend(NIL, $1); }
275-
| value_list ',' scalar_value { $$ = lappend($1, $3); }
281+
scalar_value { $$ = lappend(NIL, $1); }
282+
| value_list ',' scalar_value { $$ = lappend($1, $3); }
276283
;
277284

278285
numeric:
@@ -289,20 +296,20 @@ right_expr:
289296
| '>' numeric { $$ = makeItemUnary(jqiGreater, $2); }
290297
| '<' '=' numeric { $$ = makeItemUnary(jqiLessOrEqual, $3); }
291298
| '>' '=' numeric { $$ = makeItemUnary(jqiGreaterOrEqual, $3); }
292-
| '@' '>' array { $$ = makeItemUnary(jqiContains, $3); }
293-
| '<' '@' array { $$ = makeItemUnary(jqiContained, $3); }
299+
| '@' '>' array { $$ = makeItemUnary(jqiContains, $3); }
300+
| '<' '@' array { $$ = makeItemUnary(jqiContained, $3); }
294301
| '&' '&' array { $$ = makeItemUnary(jqiOverlap, $3); }
295-
| IS_P ARRAY_T { $$ = makeItemIs(jbvArray); }
296-
| IS_P NUMERIC_T { $$ = makeItemIs(jbvNumeric); }
297-
| IS_P OBJECT_T { $$ = makeItemIs(jbvObject); }
298-
| IS_P STRING_T { $$ = makeItemIs(jbvString); }
299-
| IS_P BOOLEAN_T { $$ = makeItemIs(jbvBool); }
302+
| IS_P ARRAY_T { $$ = makeItemIs(jbvArray); }
303+
| IS_P NUMERIC_T { $$ = makeItemIs(jbvNumeric); }
304+
| IS_P OBJECT_T { $$ = makeItemIs(jbvObject); }
305+
| IS_P STRING_T { $$ = makeItemIs(jbvString); }
306+
| IS_P BOOLEAN_T { $$ = makeItemIs(jbvBool); }
300307
;
301308

302309
expr:
303310
path right_expr { $$ = makeItemList(lappend($1, $2)); }
304311
| path HINT_P right_expr { $3->hint = $2; $$ = makeItemList(lappend($1, $3)); }
305-
| NOT_P expr { $$ = makeItemUnary(jqiNot, $2); }
312+
| NOT_P expr { $$ = makeItemUnary(jqiNot, $2); }
306313
/*
307314
* In next two lines NOT_P is a path actually, not a an
308315
* logical expression.
@@ -346,15 +353,17 @@ key:
346353
;
347354

348355
/*
349-
* NOT keyword needs separate processing
356+
* NOT keyword needs separate processing
350357
*/
351358
key_any:
352359
key { $$ = $$; }
360+
| '?' '(' expr ')' { $$ = makeItemUnary(jqiFilter, $3); }
353361
| NOT_P { $$ = makeItemKey(&$1); }
354362
;
355363

356364
path:
357365
key { $$ = lappend(NIL, $1); }
366+
| '?' '(' expr ')' { $$ = lappend(NIL, makeItemUnary(jqiFilter, $3)); }
358367
| path '.' key_any { $$ = lappend($1, $3); }
359368
| NOT_P '.' key_any { $$ = lappend(lappend(NIL, makeItemKey(&$1)), $3); }
360369
;

0 commit comments

Comments
 (0)