From 704a2b4607c142ef4e0ec0d8ea40b38eb14af740 Mon Sep 17 00:00:00 2001 From: saket0187 Date: Wed, 10 Jun 2026 18:32:00 +0530 Subject: [PATCH 1/3] Add format options --- temporal/t.vect.db.select/t.vect.db.select.md | 30 ++++ temporal/t.vect.db.select/t.vect.db.select.py | 131 ++++++++++++------ 2 files changed, 121 insertions(+), 40 deletions(-) diff --git a/temporal/t.vect.db.select/t.vect.db.select.md b/temporal/t.vect.db.select/t.vect.db.select.md index 27779833ff8..8a03bae75b4 100644 --- a/temporal/t.vect.db.select/t.vect.db.select.md +++ b/temporal/t.vect.db.select/t.vect.db.select.md @@ -40,6 +40,36 @@ start_time|end_time|DATE|SOURCE 1849|1873|01/01/1873|Coastal Carolina University ``` +You can output the data in three formats: plain (the default), csv, and json. + +```sh +t.vect.db.select input=schools_stds columns="cat,CORECAPACI" format=json +``` + +```json +[ + { + "start_time": "2024-01-01 00:00:00", + "end_time": "2025-01-01 00:00:00", + "cat": 1, + "CORECAPACI": 448 + }, + { + "start_time": "2024-01-01 00:00:00", + "end_time": "2025-01-01 00:00:00", + "cat": 2, + "CORECAPACI": 540 + }, + { + "start_time": "2024-01-01 00:00:00", + "end_time": "2025-01-01 00:00:00", + "cat": 3, + "CORECAPACI": 523 + }, + ... +] +``` + ## SEE ALSO *[t.create](t.create.md), [t.info](t.info.md)* diff --git a/temporal/t.vect.db.select/t.vect.db.select.py b/temporal/t.vect.db.select/t.vect.db.select.py index a8f2490749e..53faab6f02c 100755 --- a/temporal/t.vect.db.select/t.vect.db.select.py +++ b/temporal/t.vect.db.select/t.vect.db.select.py @@ -36,8 +36,16 @@ # %option G_OPT_DB_COLUMNS # %end +# %option G_OPT_F_FORMAT +# % options: plain,csv,json +# % descriptions: plain;Plain text output;csv;CSV (Comma Separated Values);json;JSON (JavaScript Object Notation) +# % answer: plain +# % guisection: Formatting +# %end + # %option G_OPT_F_SEP # % label: Field separator character between the output columns +# % answer: # %end # %option G_OPT_V_FIELD @@ -50,14 +58,15 @@ # % key: t_where # %end +import json + import grass.script as gs +from grass.tools import ToolError, Tools ############################################################################ def main(): - # lazy imports - import grass.temporal as tgis # Get the options input = options["input"] @@ -66,6 +75,7 @@ def main(): tempwhere = options["t_where"] layer = options["layer"] separator = gs.separator(options["separator"]) + output_format = options.get("format", "plain") if where in {"", " ", "\n"}: where = None @@ -73,6 +83,24 @@ def main(): if columns in {"", " ", "\n"}: columns = None + if output_format == "csv": + if not separator: + separator = "," + elif len(separator) > 1: + gs.fatal( + _("A standard CSV separator (delimiter) is only one character long") + ) + + elif output_format == "json": + if separator: + gs.fatal(_("Separator option is not allowed with JSON format")) + + elif not separator: # output_format == "plain" + separator = "|" + + # lazy imports + import grass.temporal as tgis + # Make sure the temporal database exists tgis.init() @@ -82,6 +110,8 @@ def main(): "name,layer,mapset,start_time,end_time", tempwhere, "start_time", None ) + tools = Tools() + json_output = [] col_names = "" if rows: for row in rows: @@ -91,52 +121,73 @@ def main(): if row["layer"]: layer = row["layer"] - select = gs.read_command( - "v.db.select", - map=vector_name, - layer=layer, - columns=columns, - separator="%s" % (separator), - where=where, - ) - - if not select: + try: + res = tools.v_db_select( + map=vector_name, + layer=layer, + columns=columns, + separator=separator, + where=where, + format=output_format, + ) + select = res.text + except ToolError: gs.fatal( _("Unable to run v.db.select for vector map <%s> with layer %s") % (vector_name, layer) ) - # The first line are the column names - list = select.split("\n") - count = 0 - for entry in list: - if entry.strip() != "": - # print the column names in case they change - if count == 0: - col_names_new = "start_time%send_time%s%s" % ( - separator, - separator, - entry, - ) - if col_names != col_names_new: - col_names = col_names_new - print(col_names) - elif row["end_time"]: - print( - "%s%s%s%s%s" - % ( - row["start_time"], + if output_format == "json": + try: + map_json = json.loads(select) + records = map_json.get("records", []) + for record in records: + new_record = { + "start_time": row["start_time"], + "end_time": row["end_time"], + } + new_record.update(record) + json_output.append(new_record) + except json.JSONDecodeError: + gs.fatal( + _("Unable to parse JSON output for vector map <%s>") + % vector_name + ) + else: + # The first line are the column names + list = select.split("\n") + count = 0 + for entry in list: + if entry.strip() != "": + # print the column names in case they change + if count == 0: + col_names_new = "start_time%send_time%s%s" % ( separator, - row["end_time"], separator, entry, ) - ) - else: - print( - "%s%s%s%s" - % (row["start_time"], separator, separator, entry) - ) - count += 1 + if col_names != col_names_new: + col_names = col_names_new + print(col_names) + elif row["end_time"]: + print( + "%s%s%s%s%s" + % ( + row["start_time"], + separator, + row["end_time"], + separator, + entry, + ) + ) + else: + print( + "%s%s%s%s" + % (row["start_time"], separator, separator, entry) + ) + count += 1 + + if output_format == "json": + print(json.dumps(json_output, indent=4, default=str)) if __name__ == "__main__": From 55d14ffad39731de28302e9b6b52fc9a7628b5ef Mon Sep 17 00:00:00 2001 From: saket0187 Date: Wed, 17 Jun 2026 19:27:58 +0530 Subject: [PATCH 2/3] Add improvements --- temporal/t.vect.db.select/t.vect.db.select.py | 56 ++++++++----------- 1 file changed, 23 insertions(+), 33 deletions(-) diff --git a/temporal/t.vect.db.select/t.vect.db.select.py b/temporal/t.vect.db.select/t.vect.db.select.py index 53faab6f02c..be4e8986f3c 100755 --- a/temporal/t.vect.db.select/t.vect.db.select.py +++ b/temporal/t.vect.db.select/t.vect.db.select.py @@ -61,7 +61,7 @@ import json import grass.script as gs -from grass.tools import ToolError, Tools +from grass.tools import Tools ############################################################################ @@ -113,6 +113,7 @@ def main(): tools = Tools() json_output = [] col_names = "" + if rows: for row in rows: vector_name = "%s@%s" % (row["name"], row["mapset"]) @@ -121,38 +122,27 @@ def main(): if row["layer"]: layer = row["layer"] - try: - res = tools.v_db_select( - map=vector_name, - layer=layer, - columns=columns, - separator=separator, - where=where, - format=output_format, - ) - select = res.text - except ToolError: - gs.fatal( - _("Unable to run v.db.select for vector map <%s> with layer %s") - % (vector_name, layer) - ) + res = tools.v_db_select( + map=vector_name, + layer=layer, + columns=columns, + separator=separator, + where=where, + format=output_format, + ) + if output_format == "json": - try: - map_json = json.loads(select) - records = map_json.get("records", []) - for record in records: - new_record = { - "start_time": row["start_time"], - "end_time": row["end_time"], - } - new_record.update(record) - json_output.append(new_record) - except json.JSONDecodeError: - gs.fatal( - _("Unable to parse JSON output for vector map <%s>") - % vector_name - ) + records = res["records"] + for record in records: + new_record = { + "start_time": row["start_time"], + "end_time": row["end_time"], + } + new_record.update(record) + json_output.append(new_record) + else: + select = res.text # The first line are the column names list = select.split("\n") count = 0 @@ -186,8 +176,8 @@ def main(): ) count += 1 - if output_format == "json": - print(json.dumps(json_output, indent=4, default=str)) + if output_format == "json": + print(json.dumps(json_output, indent=4, default=str)) if __name__ == "__main__": From 017ce625b49bc6e16f9780b6b1f4ad6684b554d2 Mon Sep 17 00:00:00 2001 From: Anna Petrasova Date: Thu, 18 Jun 2026 09:41:00 -0400 Subject: [PATCH 3/3] Apply suggestion from @petrasovaa --- temporal/t.vect.db.select/t.vect.db.select.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/temporal/t.vect.db.select/t.vect.db.select.md b/temporal/t.vect.db.select/t.vect.db.select.md index 8a03bae75b4..07142afc83a 100644 --- a/temporal/t.vect.db.select/t.vect.db.select.md +++ b/temporal/t.vect.db.select/t.vect.db.select.md @@ -40,7 +40,7 @@ start_time|end_time|DATE|SOURCE 1849|1873|01/01/1873|Coastal Carolina University ``` -You can output the data in three formats: plain (the default), csv, and json. +You can output the data in three formats: plain (the default), CSV, and JSON. ```sh t.vect.db.select input=schools_stds columns="cat,CORECAPACI" format=json