Skip to content

Commit 993ea4b

Browse files
geokolliasSameera Salameh
andauthored
Return higher-level structure for txn v2 results (#76)
* Return higher-level structures for txn v2 results * no need for show.results(multipart) Co-authored-by: Sameera Salameh <sameera@sameeras-mbp.relational.ai.beta.tailscale.net>
1 parent 783caed commit 993ea4b

File tree

4 files changed

+22
-35
lines changed

4 files changed

+22
-35
lines changed

examples/get_transaction_results.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def run(id: str, profile: str):
2525
ctx = api.Context(**cfg)
2626
rsp = api.get_transaction_results(ctx, id)
2727
print("Results:")
28-
show.results(rsp, "multipart")
28+
print(json.dumps(rsp, indent=2))
2929

3030
rsp = api.get_transaction_problems(ctx, id)
3131
print("\nProblems:")

examples/run_query_async.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License
1414

15+
import json
1516
from argparse import ArgumentParser
1617
from urllib.request import HTTPError
1718
from railib import api, config, show
@@ -21,7 +22,7 @@ def run(database: str, engine: str, command: str, readonly: bool, profile: str):
2122
cfg = config.read(profile=profile)
2223
ctx = api.Context(**cfg)
2324
rsp = api.query_async(ctx, database, engine, command, readonly=readonly)
24-
show.results(rsp)
25+
print(json.dumps(rsp, indent=2))
2526

2627

2728
if __name__ == "__main__":

railib/api.py

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import io
1818
import json
19+
import pyarrow as pa
1920
from enum import Enum, unique
2021
from typing import List, Union
2122
from . import rest
@@ -172,17 +173,31 @@ def _get_collection(ctx, path: str, key=None, **kwargs):
172173
# Parses "multipart/form-data" responses. It returns the parts in a list.
173174
def _parse_multipart(content_type: str, content: bytes) -> list:
174175
result = []
176+
content_type_json = b'application/json'
177+
content_type_arrow = b'application/vnd.apache.arrow.stream'
175178
boundary = _extract_multipart_boundary(content_type)
179+
176180
parts = content.split(b'\r\n' + boundary)
177181
for i, part in enumerate(parts):
178182
# fix the first part, it may contain the boundary
179183
if i == 0:
180184
part = part.split(boundary)[-1]
181-
# skip the part which contains the following
185+
# Skip "--\r\n"
182186
if b'--\r\n' in part:
183187
continue
184-
# append the part
185-
result.append(part)
188+
# Part body and headers are separated with CRLFCRLF. Get the body.
189+
part_value = part.split(b'\r\n\r\n')[-1]
190+
if content_type_json in part:
191+
result.append(json.loads(part_value))
192+
# if the part has arrow stream, then decode the arrow stream
193+
# the results are in a form of a tuple/table
194+
elif content_type_arrow in part:
195+
with pa.ipc.open_stream(part_value) as reader:
196+
schema = reader.schema
197+
batches = [batch for batch in reader]
198+
table = pa.Table.from_batches(batches=batches, schema=schema)
199+
result.append(table.to_pydict())
200+
186201
return result
187202

188203

railib/show.py

Lines changed: 1 addition & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -76,31 +76,6 @@ def _show_rel(rsp: dict) -> None:
7676
print(rsp["status"])
7777

7878

79-
def _show_multipart(parts: list):
80-
result = []
81-
content_type_json = b'application/json'
82-
content_type_arrow_stream = b'application/vnd.apache.arrow.stream'
83-
for part in parts:
84-
# split the part
85-
# part body and headers are separated with CRLFCRLF
86-
strings = part.split(b'\r\n\r\n')
87-
# last part is the content/body
88-
part_value = strings[len(strings) - 1]
89-
# content is json, decode the part content as json
90-
if content_type_json in part:
91-
result.append(json.loads(part_value))
92-
# if the part has arrow stream, then decode the arrow stream
93-
# the results are in a form of a tuple/table
94-
elif content_type_arrow_stream in part:
95-
with pa.ipc.open_stream(part_value) as reader:
96-
schema = reader.schema
97-
batches = [batch for batch in reader]
98-
table = pa.Table.from_batches(batches=batches, schema=schema)
99-
result.append(table.to_pydict())
100-
101-
json.dump(result, sys.stdout, indent=2)
102-
103-
10479
# Print the problems in the given response dict.
10580
def problems(rsp: dict) -> None:
10681
if rsp is None:
@@ -122,17 +97,13 @@ def problems(rsp: dict) -> None:
12297

12398

12499
# Print the results contained in the given response dict.
125-
def results(rsp: Union[dict, list], format=None) -> None:
100+
def results(rsp: Union[dict, list], format="physical") -> None:
126101
if rsp is None:
127102
return
128-
if format is None:
129-
format = "multipart" if isinstance(rsp, list) else "wire"
130103
if format == "wire":
131104
json.dump(rsp, sys.stdout, indent=2)
132105
elif format == "physical":
133106
_show_rel(rsp)
134107
problems(rsp)
135-
elif format == "multipart":
136-
_show_multipart(rsp)
137108
else:
138109
raise Exception(f"unknown format: '{format}'")

0 commit comments

Comments
 (0)