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

Add additional jsonpath string methods #12

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 140 additions & 0 deletions doc/src/sgml/func.sgml
Original file line number Diff line number Diff line change
Expand Up @@ -18627,6 +18627,146 @@ ERROR: jsonpath member accessor can only be applied to an object
<returnvalue>[{"id": 0, "key": "x", "value": "20"}, {"id": 0, "key": "y", "value": 32}]</returnvalue>
</para></entry>
</row>

<row>
<entry role="func_table_entry"><para role="func_signature">
<replaceable>string</replaceable> <literal>.</literal> <literal>lower()</literal>
<returnvalue><replaceable>string</replaceable></returnvalue>
</para>
<para>
String converted to all lower case according to the rules of the database's locale.
</para>
<para>
<literal>jsonb_path_query('"TOM"', '$.lower()')</literal>
<returnvalue>"tom"</returnvalue>
</para></entry>
</row>

<row>
<entry role="func_table_entry"><para role="func_signature">
<replaceable>string</replaceable> <literal>.</literal> <literal>upper()</literal>
<returnvalue><replaceable>string</replaceable></returnvalue>
</para>
<para>
String converted to all upper case according to the rules of the database's locale.
</para>
<para>
<literal>jsonb_path_query('"tom"', '$.upper()')</literal>
<returnvalue>"TOM"</returnvalue>
</para></entry>
</row>

<row>
<entry role="func_table_entry"><para role="func_signature">
<replaceable>string</replaceable> <literal>.</literal> <literal>initcap()</literal>
<returnvalue><replaceable>string</replaceable></returnvalue>
</para>
<para>
String with the first letter of each word converted to upper case
according to the rules of the database's locale. Words are sequences
of alphanumeric characters separated by non-alphanumeric characters.
</para>
<para>
<literal>jsonb_path_query('"hi THOMAS"', '$.initcap()')</literal>
<returnvalue>"Hi Thomas"</returnvalue>
</para></entry>
</row>

<row>
<entry role="func_table_entry"><para role="func_signature">
<replaceable>string</replaceable> <literal>.</literal> <literal>replace(<replaceable>from</replaceable>, <replaceable>to</replaceable>)</literal>
<returnvalue><replaceable>string</replaceable></returnvalue>
</para>
<para>
String with all occurrences of substring from replaced with substring to.
</para>
<para>
<literal>jsonb_path_query('"abcdefabcdef"', '$.replace("cd", "XX")')</literal>
<returnvalue>"abXXefabXXef"</returnvalue>
</para></entry>
</row>

<row>
<entry role="func_table_entry"><para role="func_signature">
<replaceable>string</replaceable> <literal>.</literal> <literal>split_part(<replaceable>delimiter</replaceable>, <replaceable>n</replaceable>)</literal>
<returnvalue><replaceable>string</replaceable></returnvalue>
</para>
<para>
String split at occurrences of <replaceable>delimiter</replaceable>
and returns the <replaceable>n</replaceable>'th field (counting from
one) or, when <replaceable>n</replaceable> is negative, returns the
|<replaceable>n</replaceable>|'th-from-last field.
</para>
<para>
<literal>jsonb_path_query('"abc~@~def~@~ghi"', '$.split_part("~@~", 2)')</literal>
<returnvalue>"def"</returnvalue>
</para>
<para>
<literal>jsonb_path_query('"abc,def,ghi,jkl"', '$.split_part(",", 2)')</literal>
<returnvalue>"ghi"</returnvalue>
</para></entry>
</row>

<row>
<entry role="func_table_entry"><para role="func_signature">
<replaceable>string</replaceable> <literal>.</literal> <literal>ltrim(<replaceable>characters</replaceable>)</literal>
<returnvalue><replaceable>string</replaceable></returnvalue>
</para>
<para>
String with the longest string containing only spaces or the
characters in <replaceable>characters</replaceable> removed from the
start of <replaceable>string</replaceable>
</para>
<para>
<literal> jsonb_path_query('" hello"', '$.ltrim()')</literal>
<returnvalue>"hello"</returnvalue>
</para>
<para>
<literal>jsonb_path_query('"zzzytest"', '$.ltrim("xyz")')</literal>
<returnvalue>"test"</returnvalue>
</para></entry>
</row>

<row>
<entry role="func_table_entry"><para role="func_signature">
<replaceable>string</replaceable> <literal>.</literal> <literal>rtrim([ <replaceable>characters</replaceable> ])</literal>
<returnvalue><replaceable>string</replaceable></returnvalue>
</para>
<para>
String with the longest string containing only spaces or the
characters in <replaceable>characters</replaceable> removed from the
end of <replaceable>string</replaceable>
</para>
<para>
<literal>jsonb_path_query('"hello "', '$.rtrim()')</literal>
<returnvalue>"hello"</returnvalue>
</para>
<para>
<literal>jsonb_path_query('"testxxzx"', '$.rtrim("xyz")')</literal>
<returnvalue>"test"</returnvalue>
</para></entry>
</row>

<row>
<entry role="func_table_entry"><para role="func_signature">
<replaceable>string</replaceable> <literal>.</literal> <literal>btrim([ <replaceable>characters</replaceable> ])</literal>
<returnvalue><replaceable>string</replaceable></returnvalue>
</para>
<para>
String with the longest string containing only spaces or the
characters in <replaceable>characters</replaceable> removed from the
start and end of <replaceable>string</replaceable>
</para>
<para>
<literal>jsonb_path_query('" hello "', '$.btrim()')</literal>
<returnvalue>"hello"</returnvalue>
</para>
<para>
<literal>jsonb_path_query('"xyxtrimyyx"', '$.btrim("xyz")')</literal>
<returnvalue>"trim"</returnvalue>
</para></entry>
</row>

</tbody>
</tgroup>
</table>
Expand Down
113 changes: 110 additions & 3 deletions src/backend/utils/adt/jsonpath.c
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,8 @@ flattenJsonPathParseItem(StringInfo buf, int *result, struct Node *escontext,
case jpiMod:
case jpiStartsWith:
case jpiDecimal:
case jpiStrReplace:
case jpiStrSplitPart:
{
/*
* First, reserve place for left/right arg's positions, then
Expand Down Expand Up @@ -362,6 +364,9 @@ flattenJsonPathParseItem(StringInfo buf, int *result, struct Node *escontext,
case jpiTimeTz:
case jpiTimestamp:
case jpiTimestampTz:
case jpiStrLtrim:
case jpiStrRtrim:
case jpiStrBtrim:
{
int32 arg = reserveSpaceForItemPointer(buf);

Expand Down Expand Up @@ -457,6 +462,9 @@ flattenJsonPathParseItem(StringInfo buf, int *result, struct Node *escontext,
case jpiInteger:
case jpiNumber:
case jpiStringFunc:
case jpiStrLower:
case jpiStrUpper:
case jpiStrInitcap:
break;
default:
elog(ERROR, "unrecognized jsonpath item type: %d", item->type);
Expand Down Expand Up @@ -831,6 +839,60 @@ printJsonPathItem(StringInfo buf, JsonPathItem *v, bool inKey,
}
appendStringInfoChar(buf, ')');
break;
case jpiStrReplace:
appendStringInfoString(buf, ".replace(");
jspGetLeftArg(v, &elem);
printJsonPathItem(buf, &elem, false, false);
appendStringInfoChar(buf, ',');
jspGetRightArg(v, &elem);
printJsonPathItem(buf, &elem, false, false);
appendStringInfoChar(buf, ')');
break;
case jpiStrSplitPart:
appendStringInfoString(buf, ".split_part(");
jspGetLeftArg(v, &elem);
printJsonPathItem(buf, &elem, false, false);
appendStringInfoChar(buf, ',');
jspGetRightArg(v, &elem);
printJsonPathItem(buf, &elem, false, false);
appendStringInfoChar(buf, ')');
break;
case jpiStrLower:
appendStringInfoString(buf, ".lower()");
break;
case jpiStrUpper:
appendStringInfoString(buf, ".upper()");
break;
case jpiStrInitcap:
appendStringInfoString(buf, ".initcap()");
break;
case jpiStrLtrim:
appendStringInfoString(buf, ".ltrim(");
if (v->content.arg)
{
jspGetArg(v, &elem);
printJsonPathItem(buf, &elem, false, false);
}
appendStringInfoChar(buf, ')');
break;
case jpiStrRtrim:
appendStringInfoString(buf, ".rtrim(");
if (v->content.arg)
{
jspGetArg(v, &elem);
printJsonPathItem(buf, &elem, false, false);
}
appendStringInfoChar(buf, ')');
break;
case jpiStrBtrim:
appendStringInfoString(buf, ".btrim(");
if (v->content.arg)
{
jspGetArg(v, &elem);
printJsonPathItem(buf, &elem, false, false);
}
appendStringInfoChar(buf, ')');
break;
default:
elog(ERROR, "unrecognized jsonpath item type: %d", v->type);
}
Expand Down Expand Up @@ -906,6 +968,12 @@ jspOperationName(JsonPathItemType type)
return "number";
case jpiStringFunc:
return "string";
case jpiStrReplace:
return "replace";
case jpiStrLower:
return "lower";
case jpiStrUpper:
return "upper";
case jpiTime:
return "time";
case jpiTimeTz:
Expand All @@ -914,6 +982,16 @@ jspOperationName(JsonPathItemType type)
return "timestamp";
case jpiTimestampTz:
return "timestamp_tz";
case jpiStrLtrim:
return "ltrim";
case jpiStrRtrim:
return "rtrim";
case jpiStrBtrim:
return "btrim";
case jpiStrInitcap:
return "initcap";
case jpiStrSplitPart:
return "split_part";
default:
elog(ERROR, "unrecognized jsonpath item type: %d", type);
return NULL;
Expand Down Expand Up @@ -1016,6 +1094,9 @@ jspInitByBuffer(JsonPathItem *v, char *base, int32 pos)
case jpiInteger:
case jpiNumber:
case jpiStringFunc:
case jpiStrLower:
case jpiStrUpper:
case jpiStrInitcap:
break;
case jpiString:
case jpiKey:
Expand All @@ -1041,6 +1122,8 @@ jspInitByBuffer(JsonPathItem *v, char *base, int32 pos)
case jpiMod:
case jpiStartsWith:
case jpiDecimal:
case jpiStrReplace:
case jpiStrSplitPart:
read_int32(v->content.args.left, base, pos);
read_int32(v->content.args.right, base, pos);
break;
Expand All @@ -1055,6 +1138,9 @@ jspInitByBuffer(JsonPathItem *v, char *base, int32 pos)
case jpiTimeTz:
case jpiTimestamp:
case jpiTimestampTz:
case jpiStrLtrim:
case jpiStrRtrim:
case jpiStrBtrim:
read_int32(v->content.arg, base, pos);
break;
case jpiIndexArray:
Expand Down Expand Up @@ -1090,7 +1176,10 @@ jspGetArg(JsonPathItem *v, JsonPathItem *a)
v->type == jpiTime ||
v->type == jpiTimeTz ||
v->type == jpiTimestamp ||
v->type == jpiTimestampTz);
v->type == jpiTimestampTz ||
v->type == jpiStrLtrim ||
v->type == jpiStrRtrim ||
v->type == jpiStrBtrim);

jspInitByBuffer(a, v->base, v->content.arg);
}
Expand Down Expand Up @@ -1149,10 +1238,18 @@ jspGetNext(JsonPathItem *v, JsonPathItem *a)
v->type == jpiInteger ||
v->type == jpiNumber ||
v->type == jpiStringFunc ||
v->type == jpiStrReplace ||
v->type == jpiStrLower ||
v->type == jpiStrUpper ||
v->type == jpiTime ||
v->type == jpiTimeTz ||
v->type == jpiTimestamp ||
v->type == jpiTimestampTz);
v->type == jpiTimestampTz ||
v->type == jpiStrLtrim ||
v->type == jpiStrRtrim ||
v->type == jpiStrBtrim ||
v->type == jpiStrInitcap ||
v->type == jpiStrSplitPart);

if (a)
jspInitByBuffer(a, v->base, v->nextPos);
Expand Down Expand Up @@ -1201,7 +1298,9 @@ jspGetRightArg(JsonPathItem *v, JsonPathItem *a)
v->type == jpiDiv ||
v->type == jpiMod ||
v->type == jpiStartsWith ||
v->type == jpiDecimal);
v->type == jpiDecimal ||
v->type == jpiStrReplace ||
v->type == jpiStrSplitPart);

jspInitByBuffer(a, v->base, v->content.args.right);
}
Expand Down Expand Up @@ -1501,6 +1600,14 @@ jspIsMutableWalker(JsonPathItem *jpi, struct JsonPathMutableContext *cxt)
case jpiInteger:
case jpiNumber:
case jpiStringFunc:
case jpiStrReplace:
case jpiStrLower:
case jpiStrUpper:
case jpiStrLtrim:
case jpiStrRtrim:
case jpiStrBtrim:
case jpiStrInitcap:
case jpiStrSplitPart:
status = jpdsNonDateTime;
break;

Expand Down
Loading