Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit cea7194

Browse files
author
Nikita Glukhov
committed
Add jsonpath .min() and .max() item methods
1 parent 17fe932 commit cea7194

File tree

9 files changed

+161
-1
lines changed

9 files changed

+161
-1
lines changed

src/backend/utils/adt/jsonpath.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,8 @@ flattenJsonPathParseItem(StringInfo buf, JsonPathParseItem *item,
203203
case jpiCeiling:
204204
case jpiDouble:
205205
case jpiKeyValue:
206+
case jpiMin:
207+
case jpiMax:
206208
break;
207209
case jpiSequence:
208210
{
@@ -636,6 +638,12 @@ printJsonPathItem(StringInfo buf, JsonPathItem *v, bool inKey, bool printBracket
636638
printJsonPathItem(buf, &elem, false, false);
637639
appendStringInfoChar(buf, ')');
638640
break;
641+
case jpiMin:
642+
appendBinaryStringInfo(buf, ".min()", 6);
643+
break;
644+
case jpiMax:
645+
appendBinaryStringInfo(buf, ".max()", 6);
646+
break;
639647
default:
640648
elog(ERROR, "Unknown jsonpath item type: %d", v->type);
641649
}
@@ -729,6 +737,8 @@ jspInitByBuffer(JsonPathItem *v, char *base, int32 pos)
729737
case jpiDouble:
730738
case jpiKeyValue:
731739
case jpiLast:
740+
case jpiMin:
741+
case jpiMax:
732742
break;
733743
case jpiKey:
734744
case jpiString:
@@ -868,7 +878,9 @@ jspGetNext(JsonPathItem *v, JsonPathItem *a)
868878
v->type == jpiReduce ||
869879
v->type == jpiFold ||
870880
v->type == jpiFoldl ||
871-
v->type == jpiFoldr
881+
v->type == jpiFoldr ||
882+
v->type == jpiMin ||
883+
v->type == jpiMax
872884
);
873885

874886
if (a)

src/backend/utils/adt/jsonpath_exec.c

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2250,6 +2250,78 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
22502250
res = recursiveExecuteNext(cxt, jsp, NULL, result, found, false);
22512251
}
22522252
break;
2253+
case jpiMin:
2254+
case jpiMax:
2255+
if (JsonbType(jb) != jbvArray)
2256+
{
2257+
if (cxt->lax)
2258+
res = recursiveExecuteNext(cxt, jsp, NULL, jb, found, true);
2259+
else
2260+
res = jperMakeError(ERRCODE_JSON_ARRAY_NOT_FOUND);
2261+
}
2262+
else
2263+
{
2264+
JsonbValue jbvElementBuf;
2265+
JsonbValue *jbvElement;
2266+
JsonbValue *jbvResult = NULL;
2267+
Jsonb *jbResult = NULL;
2268+
JsonbIterator *it = NULL;
2269+
JsonbIteratorToken tok;
2270+
int size = JsonbArraySize(jb);
2271+
int i;
2272+
bool isMax = jsp->type == jpiMax;
2273+
2274+
if (jb->type == jbvBinary)
2275+
{
2276+
jbvElement = &jbvElementBuf;
2277+
it = JsonbIteratorInit(jb->val.binary.data);
2278+
tok = JsonbIteratorNext(&it, &jbvElementBuf, false);
2279+
if (tok != WJB_BEGIN_ARRAY)
2280+
elog(ERROR, "unexpected jsonb token at the array start");
2281+
}
2282+
2283+
for (i = 0; i < size; i++)
2284+
{
2285+
if (it)
2286+
{
2287+
tok = JsonbIteratorNext(&it, jbvElement, true);
2288+
if (tok != WJB_ELEM)
2289+
break;
2290+
}
2291+
else
2292+
jbvElement = &jb->val.array.elems[i];
2293+
2294+
if (!i)
2295+
{
2296+
jbvResult = it ? copyJsonbValue(jbvElement) : jbvElement;
2297+
2298+
if (size > 1)
2299+
jbResult = JsonbValueToJsonb(jbvResult);
2300+
}
2301+
else
2302+
{
2303+
Jsonb *jbElement = JsonbValueToJsonb(jbvElement);
2304+
int cmp = compareJsonbContainers(&jbElement->root,
2305+
&jbResult->root);
2306+
2307+
if (isMax ? cmp > 0 : cmp < 0)
2308+
{
2309+
jbvResult = it ? copyJsonbValue(jbvElement) : jbvElement;
2310+
jbResult = jbElement;
2311+
}
2312+
}
2313+
}
2314+
2315+
if (!jbvResult)
2316+
{
2317+
res = jperNotFound;
2318+
break;
2319+
}
2320+
2321+
res = recursiveExecuteNext(cxt, jsp, NULL, jbvResult, found,
2322+
false);
2323+
}
2324+
break;
22532325
default:
22542326
elog(ERROR,"2Wrong state: %d", jsp->type);
22552327
}

src/backend/utils/adt/jsonpath_gram.y

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,7 @@ makeItemObject(List *fields)
246246
%token <str> STRING_P NUMERIC_P INT_P EXISTS_P STRICT_P LAX_P LAST_P
247247
%token <str> ABS_P SIZE_P TYPE_P FLOOR_P DOUBLE_P CEILING_P DATETIME_P
248248
%token <str> KEYVALUE_P MAP_P REDUCE_P FOLD_P FOLDL_P FOLDR_P
249+
%token <str> MIN_P MAX_P
249250

250251
%token <str> OR_P AND_P NOT_P
251252
%token <str> LESS_P LESSEQUAL_P EQUAL_P NOTEQUAL_P GREATEREQUAL_P GREATER_P
@@ -490,6 +491,8 @@ key_name:
490491
| FOLD_P
491492
| FOLDL_P
492493
| FOLDR_P
494+
| MIN_P
495+
| MAX_P
493496
;
494497

495498
method:
@@ -500,6 +503,8 @@ method:
500503
| DOUBLE_P { $$ = jpiDouble; }
501504
| CEILING_P { $$ = jpiCeiling; }
502505
| KEYVALUE_P { $$ = jpiKeyValue; }
506+
| MIN_P { $$ = jpiMin; }
507+
| MAX_P { $$ = jpiMax; }
503508
;
504509
%%
505510

src/backend/utils/adt/jsonpath_scan.l

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,8 @@ static keyword keywords[] = {
256256
{ 3, false, ABS_P, "abs"},
257257
{ 3, false, LAX_P, "lax"},
258258
{ 3, false, MAP_P, "map"},
259+
{ 3, false, MAX_P, "max"},
260+
{ 3, false, MIN_P, "min"},
259261
{ 4, false, FOLD_P, "fold"},
260262
{ 4, false, LAST_P, "last"},
261263
{ 4, true, NULL_P, "null"},

src/include/utils/jsonpath.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ typedef enum JsonPathItemType {
9292
jpiFold,
9393
jpiFoldl,
9494
jpiFoldr,
95+
jpiMin,
96+
jpiMax,
9597
} JsonPathItemType;
9698

9799

src/test/regress/expected/jsonb_jsonpath.out

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1687,6 +1687,49 @@ select _jsonpath_query(jsonb '[[1, 2], [3, 4, 5], [], [6, 7]]', '$.fold($1 + $2.
16871687
1428
16881688
(1 row)
16891689

1690+
-- extension: min/max item methods
1691+
select _jsonpath_query(jsonb '1', 'strict $.min()');
1692+
ERROR: SQL/JSON array not found
1693+
select _jsonpath_query(jsonb '1', 'lax $.min()');
1694+
_jsonpath_query
1695+
-----------------
1696+
1
1697+
(1 row)
1698+
1699+
select _jsonpath_query(jsonb '[]', '$.min()');
1700+
_jsonpath_query
1701+
-----------------
1702+
(0 rows)
1703+
1704+
select _jsonpath_query(jsonb '[]', '$.max()');
1705+
_jsonpath_query
1706+
-----------------
1707+
(0 rows)
1708+
1709+
select _jsonpath_query(jsonb '[1, 2, 3]', '$.min()');
1710+
_jsonpath_query
1711+
-----------------
1712+
1
1713+
(1 row)
1714+
1715+
select _jsonpath_query(jsonb '[1, 2, 3]', '$.max()');
1716+
_jsonpath_query
1717+
-----------------
1718+
3
1719+
(1 row)
1720+
1721+
select _jsonpath_query(jsonb '[2, 3, 5, 1, 4]', '$.min()');
1722+
_jsonpath_query
1723+
-----------------
1724+
1
1725+
(1 row)
1726+
1727+
select _jsonpath_query(jsonb '[2, 3, 5, 1, 4]', '$.max()');
1728+
_jsonpath_query
1729+
-----------------
1730+
5
1731+
(1 row)
1732+
16901733
-- extension: path sequences
16911734
select _jsonpath_query(jsonb '[1,2,3,4,5]', '10, 20, $[*], 30');
16921735
_jsonpath_query

src/test/regress/expected/jsonpath.out

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,18 @@ select '$.fold($1 + $2 + @[1], 2 + 3)'::jsonpath;
409409
$.fold(($"1" + $"2") + @[1], 2 + 3)
410410
(1 row)
411411

412+
select '$.min().abs() + 5'::jsonpath;
413+
jsonpath
414+
---------------------
415+
($.min().abs() + 5)
416+
(1 row)
417+
418+
select '$.max().floor()'::jsonpath;
419+
jsonpath
420+
-----------------
421+
$.max().floor()
422+
(1 row)
423+
412424
select '$ ? (@ starts with "abc")'::jsonpath;
413425
jsonpath
414426
-------------------------

src/test/regress/sql/jsonb_jsonpath.sql

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,16 @@ select _jsonpath_query(jsonb '[1, 2, 3]', '$.foldl([$1, $2], [])');
395395
select _jsonpath_query(jsonb '[1, 2, 3]', '$.foldr([$2, $1], [])');
396396
select _jsonpath_query(jsonb '[[1, 2], [3, 4, 5], [], [6, 7]]', '$.fold($1 + $2.fold($1 + $2, 100), 1000)');
397397

398+
-- extension: min/max item methods
399+
select _jsonpath_query(jsonb '1', 'strict $.min()');
400+
select _jsonpath_query(jsonb '1', 'lax $.min()');
401+
select _jsonpath_query(jsonb '[]', '$.min()');
402+
select _jsonpath_query(jsonb '[]', '$.max()');
403+
select _jsonpath_query(jsonb '[1, 2, 3]', '$.min()');
404+
select _jsonpath_query(jsonb '[1, 2, 3]', '$.max()');
405+
select _jsonpath_query(jsonb '[2, 3, 5, 1, 4]', '$.min()');
406+
select _jsonpath_query(jsonb '[2, 3, 5, 1, 4]', '$.max()');
407+
398408
-- extension: path sequences
399409
select _jsonpath_query(jsonb '[1,2,3,4,5]', '10, 20, $[*], 30');
400410
select _jsonpath_query(jsonb '[1,2,3,4,5]', 'lax 10, 20, $[*].a, 30');

src/test/regress/sql/jsonpath.sql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ select '$.datetime()'::jsonpath;
7272
select '$.datetime("datetime template")'::jsonpath;
7373
select '$.reduce($1 + $2 + @[1])'::jsonpath;
7474
select '$.fold($1 + $2 + @[1], 2 + 3)'::jsonpath;
75+
select '$.min().abs() + 5'::jsonpath;
76+
select '$.max().floor()'::jsonpath;
7577

7678
select '$ ? (@ starts with "abc")'::jsonpath;
7779
select '$ ? (@ starts with $var)'::jsonpath;

0 commit comments

Comments
 (0)