Skip to content

Commit

Permalink
v.db.select: Add column names and types to JSON
Browse files Browse the repository at this point in the history
The JSON output now has column names and types under info/columns.

The example in documentation does not include the unclear note about booleans (perhaps a discussion for another place).
A command to reproduce the example output is now included.

Documentation and test of the new functionality are included.
  • Loading branch information
wenzeslaus committed Jul 18, 2023
1 parent 36f4b22 commit 543092a
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 10 deletions.
28 changes: 26 additions & 2 deletions vector/v.db.select/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -337,8 +337,32 @@ int main(int argc, char **argv)
if (format == JSON) {
if (flags.region->answer)
fprintf(stdout, "{\"extent\":\n");
else
fprintf(stdout, "{\"records\":[\n");
else {
fprintf(stdout, "{\"info\":\n{\"columns\":[\n");
for (col = 0; col < ncols; col++) {
column = db_get_table_column(table, col);
if (col)
fprintf(stdout, "},\n");
fprintf(stdout, "{\"name\": \"%s\",",
db_get_column_name(column));
int sql_type = db_get_column_sqltype(column);
fprintf(stdout, "\"sql_type\": \"%s\",",
db_sqltype_name(sql_type));

int c_type = db_sqltype_to_Ctype(sql_type);
fprintf(stdout, "\"is_number\":");
/* Same rules as for quoting, i.e., number only as
* JSON or Python would see it and not numeric which may
* include, e.g., date. */
if (c_type == DB_C_TYPE_INT || c_type == DB_C_TYPE_DOUBLE)
fprintf(stdout, "true");
else
fprintf(stdout, "false");
}

fprintf(stdout, "}\n]},\n");
fprintf(stdout, "\"records\":[\n");
}
}

/* fetch the data */
Expand Down
17 changes: 16 additions & 1 deletion vector/v.db.select/testsuite/test_v_db_select_json_csv.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# MODULE: Test of v.db.select
# AUTHOR(S): Vaclav Petras <wenzeslaus gmail com>
# PURPOSE: Test parsing and structure of CSV and JSON outputs
# COPYRIGHT: (C) 2021 by Vaclav Petras the GRASS Development Team
# COPYRIGHT: (C) 2021-2023 by Vaclav Petras the GRASS Development Team
#
# This program is free software under the GNU General Public
# License (>=v2). Read the file COPYING that comes with GRASS
Expand Down Expand Up @@ -173,6 +173,21 @@ def test_json_loads(self):
"""Load JSON with difficult values"""
text = gs.read_command("v.db.select", map=self.vector_points, format="json")
data = json.loads(text)

column_info = data["info"]["columns"]
self.assertEqual(column_info[0]["name"], "cat")
self.assertEqual(column_info[0]["sql_type"], "INTEGER")
self.assertEqual(column_info[0]["is_number"], True)
self.assertEqual(column_info[1]["name"], "x")
self.assertEqual(column_info[1]["sql_type"], "DOUBLE PRECISION")
self.assertEqual(column_info[1]["is_number"], True)
self.assertEqual(column_info[4]["name"], "owner_id")
self.assertEqual(column_info[4]["sql_type"], "INTEGER")
self.assertEqual(column_info[4]["is_number"], True)
self.assertEqual(column_info[5]["name"], "place_name")
self.assertEqual(column_info[5]["sql_type"], "TEXT")
self.assertEqual(column_info[5]["is_number"], False)

data = data["records"]
self.assertIsNone(data[2]["place_name"])
self.assertEqual(data[3]["place_name"], 'The "Great" Place')
Expand Down
46 changes: 39 additions & 7 deletions vector/v.db.select/v.db.select.html
Original file line number Diff line number Diff line change
Expand Up @@ -105,24 +105,56 @@ <h4>JSON</h4>
the columns were defined in the database.

<p>
Example with added indentation (note that booleans are not directly supported;
here, an attribute is a string with value <tt>no</tt>):
The JSON also contains information about columns stored under key
<code>info</code>. Column names and types are under key <code>columns</code>.
Each colum has SQL data type under <code>sql_type</code> in all caps.
A boolean <code>is_number</code> specifies whether the value is a number, i.e.,
integer or floating point number. The <code>is_number</code> value
is aded for convenience and it is recommended to rely on the types derived
from the JSON representation or the SQL types. The definition of
<code>is_number</code> may change in the future.

<p>
Example with added indentation:

<!--
Generated using:
v.db.select roadsmajor format=json where="cat in (1, 2)" \
columns="ROAD_NAME AS road_name, PROPYEAR + 2001 AS year, SHAPE_LEN as length" \
| jq
-->

<div class="code"><pre>
{
"info": {
"columns": [
{
"name": "road_name",
"sql_type": "CHARACTER",
"is_number": false
},
{
"name": "year",
"sql_type": "INTEGER",
"is_number": true
},
{
"name": "length",
"sql_type": "DOUBLE PRECISION",
"is_number": true
}
]
},
"records": [
{
"cat": 1,
"road_name": "NC-50",
"multilane": "no",
"year": 2001,
"length": 4825.369405
},
{
"cat": 2,
"road_name": "NC-50",
"multilane": "no",
"year": 2002,
"year": 2001,
"length": 14392.589058
}
]
Expand Down

0 comments on commit 543092a

Please sign in to comment.