On Mon, May 2, 2016 at 4:04 PM, Andrew Dunstan <and...@dunslane.net> wrote:
> > On 05/02/2016 04:56 AM, Shulgin, Oleksandr wrote: > >> On Sun, May 1, 2016 at 3:22 AM, Andrew Dunstan <and...@dunslane.net >> <mailto:and...@dunslane.net>> wrote: >> >> On 04/29/2016 06:11 PM, Merlin Moncure wrote: >> >> This is a simple matter of removing spaces in the occasional C >> string >> literal in the serialization routines and adding a json_pretty >> function. >> >> >> I spent a few hours on this. See >> <https://bitbucket.org/adunstan/pgdevel/commits/branch/jsonformat> >> for WIP - there are three commits. No regression tests yet for the >> two new functions (json_squash and json_pretty), Otherwise fairly >> complete. Removing whitespace generation was pretty simple for >> both json and jsonb. >> >> >> Looks good, thank you! >> >> It would make sense IMO to rename FormatState's `indent' field as >> `pretty': it's being used to add whitespace between the punctuation, not >> only at start of a line. I'd also move the "if (indent)" check out of >> add_indent(): just don't call it if no indent is needed. >> >> I'll try to play with the patch to produce some regression tests for the >> new functions. >> >> > It was done the way it was to be as consistent as possible with how it's > done for jsonb (c.f. jsonb.c:JsonbToCStringWorker and jsonb.c::add_indent). > Ah, I see. Simply taking regression tests for jsonb_pretty() and using them against json_pretty() revealed a bug with extra indent being added before every array/object start. Attached patch fixes that and adds the regression tests. For json_squash() I've taken the same three test values, for lack of a better idea at the moment. At least we are testing key order stability and that no whitespace is spit out. Regards, -- Alex
diff --git a/src/backend/utils/adt/jsonfuncs.c b/src/backend/utils/adt/jsonfuncs.c new file mode 100644 index d82c9c8..77d8325 *** a/src/backend/utils/adt/jsonfuncs.c --- b/src/backend/utils/adt/jsonfuncs.c *************** fmt_object_field_start(void *state, char *** 3394,3402 **** escape_json(_state->strval, fname); ! appendStringInfoCharMacro(_state->strval, ':'); ! if (_state->indent) ! appendStringInfoCharMacro(_state->strval, ' '); _state->last_was_key = true; } --- 3394,3400 ---- escape_json(_state->strval, fname); ! appendBinaryStringInfo(_state->strval, ": ", _state->indent ? 2 : 1); _state->last_was_key = true; } *************** fmt_array_element_start(void *state, boo *** 3409,3417 **** if (!_state->first) appendStringInfoCharMacro(_state->strval, ','); _state->first = false; ! ! add_indent(_state->strval, _state->indent, _state->lex->lex_level); ! } static void --- 3407,3413 ---- if (!_state->first) appendStringInfoCharMacro(_state->strval, ','); _state->first = false; ! _state->last_was_key = false; } static void *************** fmt_scalar(void *state, char *token, Jso *** 3419,3424 **** --- 3415,3424 ---- { FormatState *_state = (FormatState *) state; + if (_state->lex->lex_level > 0) + add_indent(_state->strval, _state->indent && !_state->last_was_key, + _state->lex->lex_level); + if (tokentype == JSON_TOKEN_STRING) escape_json(_state->strval, token); else diff --git a/src/test/regress/expected/json.out b/src/test/regress/expected/json.out new file mode 100644 index 0c45c64..7af4022 *** a/src/test/regress/expected/json.out --- b/src/test/regress/expected/json.out *************** select json_strip_nulls('{"a": {"b": nul *** 1658,1660 **** --- 1658,1736 ---- {"a":{},"d":{}} (1 row) + select json_pretty('{"a": "test", "b": [1, 2, 3], "c": "test3", "d":{"dd": "test4", "dd2":{"ddd": "test5"}}}'); + json_pretty + ---------------------------- + { + + "a": "test", + + "b": [ + + 1, + + 2, + + 3 + + ], + + "c": "test3", + + "d": { + + "dd": "test4", + + "dd2": { + + "ddd": "test5"+ + } + + } + + } + (1 row) + + select json_pretty('[{"f1":1,"f2":null},2,null,[[{"x":true},6,7],8],3]'); + json_pretty + --------------------------- + [ + + { + + "f1": 1, + + "f2": null + + }, + + 2, + + null, + + [ + + [ + + { + + "x": true+ + }, + + 6, + + 7 + + ], + + 8 + + ], + + 3 + + ] + (1 row) + + select json_pretty('{"a":["b", "c"], "d": {"e":"f"}}'); + json_pretty + ------------------ + { + + "a": [ + + "b", + + "c" + + ], + + "d": { + + "e": "f"+ + } + + } + (1 row) + + select json_squash('{"a": "test", "b": [1, 2, 3], "c": "test3", "d":{"dd": "test4", "dd2":{"ddd": "test5"}}}'); + json_squash + ------------------------------------------------------------------------------- + {"a":"test","b":[1,2,3],"c":"test3","d":{"dd":"test4","dd2":{"ddd":"test5"}}} + (1 row) + + select json_squash('[{"f1":1,"f2":null},2,null,[[{"x":true},6,7],8],3]'); + json_squash + ---------------------------------------------------- + [{"f1":1,"f2":null},2,null,[[{"x":true},6,7],8],3] + (1 row) + + select json_squash('{"a":["b", "c"], "d": {"e":"f"}}'); + json_squash + ------------------------------- + {"a":["b","c"],"d":{"e":"f"}} + (1 row) + diff --git a/src/test/regress/sql/json.sql b/src/test/regress/sql/json.sql new file mode 100644 index 603288b..f13e0fa *** a/src/test/regress/sql/json.sql --- b/src/test/regress/sql/json.sql *************** select json_strip_nulls('[1,{"a":1,"b":n *** 545,547 **** --- 545,556 ---- -- an empty object is not null and should not be stripped select json_strip_nulls('{"a": {"b": null, "c": null}, "d": {} }'); + + + select json_pretty('{"a": "test", "b": [1, 2, 3], "c": "test3", "d":{"dd": "test4", "dd2":{"ddd": "test5"}}}'); + select json_pretty('[{"f1":1,"f2":null},2,null,[[{"x":true},6,7],8],3]'); + select json_pretty('{"a":["b", "c"], "d": {"e":"f"}}'); + + select json_squash('{"a": "test", "b": [1, 2, 3], "c": "test3", "d":{"dd": "test4", "dd2":{"ddd": "test5"}}}'); + select json_squash('[{"f1":1,"f2":null},2,null,[[{"x":true},6,7],8],3]'); + select json_squash('{"a":["b", "c"], "d": {"e":"f"}}');
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers