From 337773664804a2be57bb5aed8471da72b0b6ae9e Mon Sep 17 00:00:00 2001 From: takegue Date: Sun, 21 Jan 2024 11:33:29 +0900 Subject: [PATCH] Allow multi line pretty print for long column --- .../v0/@routines/ztable_stringify/ddl.sql | 111 ++++++++++++++---- 1 file changed, 91 insertions(+), 20 deletions(-) diff --git a/bigquery/@default/v0/@routines/ztable_stringify/ddl.sql b/bigquery/@default/v0/@routines/ztable_stringify/ddl.sql index 3903cd2..dc2fec0 100644 --- a/bigquery/@default/v0/@routines/ztable_stringify/ddl.sql +++ b/bigquery/@default/v0/@routines/ztable_stringify/ddl.sql @@ -60,6 +60,19 @@ const prettyPrintTable = (data) => { } const defaultFormetter = (val) => val ? val.toString() : "null" + // If long string is included, set allowMultiline to true + const allowMultiline = (() => { + for (const row of data) { + for (const key in row) { + const val = JSON.stringify(row[key]) + if (val && val.length > 30) { + return true + } + } + } + return false + })(); + const formatter = { 'INTEGER': defaultFormetter, 'FLOAT': defaultFormetter, @@ -69,11 +82,10 @@ const prettyPrintTable = (data) => { 'TIME': defaultFormetter, 'DATETIME': defaultFormetter, 'TIMESTAMP': defaultFormetter, - 'ARRAY': (val) => JSON.stringify(val), - 'RECORD_OR_JSON': (val) => JSON.stringify(val), + 'ARRAY': (val) => JSON.stringify(val, null, allowMultiline ? 2 : null), + 'RECORD_OR_JSON': (val) => JSON.stringify(val, null, allowMultiline ? 2 : null), }; - const estimatedTypes = (() => { const agg = data.reduce((acc, cur) => { for (const key in cur) { @@ -90,11 +102,16 @@ const prettyPrintTable = (data) => { return Object.entries(agg).reduce((acc, [key, examples]) => { const type = estimateTypeFromExamples(examples) const typeLength = Math.max( - key.length + 2, + key.length + 3, ...examples.map((e) => { const f = formatter[type] ; const s = (f ? f : defaultFormetter)(e) - return s && s.length ? s.length + 2: null; + // Calculate max line length of string by delimited by new line + const len = (s.split("\n")).reduce((acc, cur) => { + const _new = cur && cur.length ? cur.length + 2: null + return acc < _new ? _new : acc ; + }, 0); + return len; })); acc[key] = { type, @@ -119,18 +136,36 @@ const prettyPrintTable = (data) => { const f = formatter[estimated.type]; const formated = (f ? f : defaultFormetter)(value); - return `${formated} `.padStart(length, ' ') + return `${formated}` } + const formatRow = (row) => { - return Object.entries(row).map(formatField).join(sep) + const formatedFields = Object.entries(row).map(formatField) + const fields = formatedFields.map(s => s.split('\n')) + // transpose fields aligned with longet elements of arary + // argmax of elemtens length + const longest = fields.reduce((acc, cur) => { + return acc.length < cur.length ? cur : acc ; + }) + + const transposedFields = longest.map((_, colIndex) => fields.map(row => row[colIndex] ?? "")) + return transposedFields.map((columns) => { + c = columns.map( + (c, colIndex) => { + const estimated = estimatedTypes[Object.keys(row)[colIndex]] + const length = estimated.typeLength + return ` ${c}`.padEnd(length, ' ') + }).join(sep) + return `|${c}|` + }).join('\n') } const table = [ `/*${headerSepRow.join(sepGrid).substring(1)}+`, `|${headerRow.join(sep)}|`, `+${headerSepRow.join(sepGrid)}+`, - ...data.map((row) => { - return `|${formatRow(row)}|` - }), + data.map((row) => { + return `${formatRow(row)}` + }).join(`\n`), `+${headerSepRow.join(sepGrid).substring(0)}*/` ].join('\n') return table @@ -141,24 +176,60 @@ const prettyPrintTable = (data) => { const _test = () => { const data = [ + // long record + {"int":1,"str":"hoge","float":3.2,"boolean":null,"ts":null,"dt":null,"d":null,"json":{"int":null,"str":null,"float":null,"boolean":null,"ts":"2023-01-01T00:00:00Z","dt":"2023-01-01T00:00:00","d":"2023-01-01","json":null,"arr":[1,2],"record":{"int":1}},"arr":null,"record":null}, + // short {"int":1,"str":"hoge","float":3.2,"boolean":null,"ts":null,"dt":null,"d":null,"json":null,"arr":null,"record":null}, - {"int":null,"str":null,"float":null,"boolean":null,"ts":"2023-01-01T00:00:00Z","dt":"2023-01-01T00:00:00","d":"2023-01-01","json":null,"arr":[1,2],"record":{"int":1}} + {"int":null,"str":null,"float":null,"boolean":null,"ts":"2023-01-01T00:00:00Z","dt":"2023-01-01T00:00:00","d":"2023-01-01","json":null,"arr":[1,2],"record":{"int":1}}, ] - const ret = prettyPrintTable(data) - return ret === ` -/*-----+--------+-------+---------+----------------------+---------------------+------------+------+-------+-----------+ -| int | str | float | boolean | ts | dt | d | json | arr | record | -+------+--------+-------+---------+----------------------+---------------------+------------+------+-------+-----------+ -| 1 | "hoge" | 3.2 | null | null | null | null | null | null | null | -| null | null | null | null | 2023-01-01T00:00:00Z | 2023-01-01T00:00:00 | 2023-01-01 | null | [1,2] | {"int":1} | -+------+--------+-------+---------+----------------------+---------------------+------------+------+-------+-----------*/ -`.trim() + const ret1 = prettyPrintTable(data.slice(1,)) + console.log({ret1, assert: ret1 === ` +/*-----+--------+--------+----------+----------------------+---------------------+------------+-------+-------+-----------+ +| int | str | float | boolean | ts | dt | d | json | arr | record | ++------+--------+--------+----------+----------------------+---------------------+------------+-------+-------+-----------+ +| 1 | "hoge" | 3.2 | null | null | null | null | null | null | null | +| null | null | null | null | 2023-01-01T00:00:00Z | 2023-01-01T00:00:00 | 2023-01-01 | null | [1,2] | {"int":1} | ++------+--------+--------+----------+----------------------+---------------------+------------+-------+-------+-----------*/ +`.trim()}) + const ret2 = prettyPrintTable(data, true) + console.log({ret2, assert: ret2 === ` +/*-----+--------+--------+----------+----------------------+---------------------+------------+---------------------------------+------+------------+ +| int | str | float | boolean | ts | dt | d | json | arr | record | ++------+--------+--------+----------+----------------------+---------------------+------------+---------------------------------+------+------------+ +| 1 | "hoge" | 3.2 | null | null | null | null | { | null | null | +| | | | | | | | "int": null, | | | +| | | | | | | | "str": null, | | | +| | | | | | | | "float": null, | | | +| | | | | | | | "boolean": null, | | | +| | | | | | | | "ts": "2023-01-01T00:00:00Z", | | | +| | | | | | | | "dt": "2023-01-01T00:00:00", | | | +| | | | | | | | "d": "2023-01-01", | | | +| | | | | | | | "json": null, | | | +| | | | | | | | "arr": [ | | | +| | | | | | | | 1, | | | +| | | | | | | | 2 | | | +| | | | | | | | ], | | | +| | | | | | | | "record": { | | | +| | | | | | | | "int": 1 | | | +| | | | | | | | } | | | +| | | | | | | | } | | | +| 1 | "hoge" | 3.2 | null | null | null | null | null | null | null | +| null | null | null | null | 2023-01-01T00:00:00Z | 2023-01-01T00:00:00 | 2023-01-01 | null | [ | { | +| | | | | | | | | 1, | "int": 1 | +| | | | | | | | | 2 | } | +| | | | | | | | | ] | | ++------+--------+--------+----------+----------------------+---------------------+------------+---------------------------------+------+------------*/ +`.trim()}) } + +// _test() + try { return prettyPrintTable(JSON.parse(json_like_string)) } catch { return null; } + """;