Skip to content

Commit 167a601

Browse files
committed
feat(duckdb): add to_json() to Table and duckdb backend
Fixes #10413
1 parent a720e68 commit 167a601

File tree

4 files changed

+104
-0
lines changed

4 files changed

+104
-0
lines changed

ibis/backends/__init__.py

+26
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,32 @@ def to_delta(
586586
with expr.to_pyarrow_batches(params=params) as batch_reader:
587587
write_deltalake(path, batch_reader, **kwargs)
588588

589+
@util.experimental
590+
def to_json(
591+
self,
592+
expr: ir.Table,
593+
path: str | Path,
594+
**kwargs: Any,
595+
) -> None:
596+
"""Write the results of `expr` to a json file of [{column -> value}, ...] objects.
597+
598+
This method is eager and will execute the associated expression
599+
immediately.
600+
601+
Parameters
602+
----------
603+
expr
604+
The ibis expression to execute and persist to Delta Lake table.
605+
path
606+
The data source. A string or Path to the Delta Lake table.
607+
kwargs
608+
Additional, backend-specifc keyword arguments.
609+
"""
610+
backend = expr._find_backend(use_default=True)
611+
raise NotImplementedError(
612+
f"{backend.__class__.__name__} does not support writing to JSON."
613+
)
614+
589615

590616
class CanListCatalog(abc.ABC):
591617
@abc.abstractmethod

ibis/backends/duckdb/__init__.py

+25
Original file line numberDiff line numberDiff line change
@@ -1566,6 +1566,31 @@ def to_geo(
15661566
with self._safe_raw_sql(copy_cmd):
15671567
pass
15681568

1569+
@util.experimental
1570+
def to_json(
1571+
self,
1572+
expr: ir.Table,
1573+
path: str | Path,
1574+
**kwargs: Any,
1575+
) -> None:
1576+
"""Write the results of `expr` to a json file of [{column -> value}, ...] objects.
1577+
1578+
This method is eager and will execute the associated expression
1579+
immediately.
1580+
1581+
Parameters
1582+
----------
1583+
expr
1584+
The ibis expression to execute and persist to Delta Lake table.
1585+
path
1586+
URLs such as S3 buckets are supported.
1587+
kwargs
1588+
Additional, backend-specifc keyword arguments.
1589+
"""
1590+
self.raw_sql(
1591+
f"COPY ({self.compile(expr)}) TO '{path!s}' (FORMAT JSON, ARRAY true);"
1592+
)
1593+
15691594
def _get_schema_using_query(self, query: str) -> sch.Schema:
15701595
with self._safe_raw_sql(f"DESCRIBE {query}") as cur:
15711596
rows = cur.fetch_arrow_table()

ibis/backends/tests/test_export.py

+31
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,37 @@ def test_table_to_csv(tmp_path, backend, awards_players):
347347
backend.assert_frame_equal(awards_players.to_pandas(), df)
348348

349349

350+
@pytest.mark.notimpl(
351+
[
352+
"athena",
353+
"bigquery",
354+
"clickhouse",
355+
"databricks",
356+
"datafusion",
357+
"druid",
358+
"exasol",
359+
"flink",
360+
"impala",
361+
"mssql",
362+
"mysql",
363+
"oracle",
364+
"polars",
365+
"postgres",
366+
"pyspark",
367+
"risingwave",
368+
"snowflake",
369+
"sqlite",
370+
],
371+
reason="haven't gotten to them yet. Might be easy!",
372+
raises=NotImplementedError,
373+
)
374+
def test_to_json(backend, tmp_path, awards_players):
375+
out_path = tmp_path / "out.json"
376+
awards_players.to_json(out_path)
377+
df = pd.read_json(out_path, orient="records")
378+
backend.assert_frame_equal(awards_players.to_pandas(), df)
379+
380+
350381
@pytest.mark.notimpl(
351382
["duckdb"],
352383
reason="cannot inline WriteOptions objects",

ibis/expr/types/core.py

+22
Original file line numberDiff line numberDiff line change
@@ -771,6 +771,28 @@ def to_delta(
771771
"""
772772
self._find_backend(use_default=True).to_delta(self, path, **kwargs)
773773

774+
@experimental
775+
def to_json(
776+
self,
777+
path: str | Path,
778+
**kwargs: Any,
779+
) -> None:
780+
"""Write the results of `expr` to a json file of [{column -> value}, ...] objects.
781+
782+
This method is eager and will execute the associated expression
783+
immediately.
784+
785+
Parameters
786+
----------
787+
expr
788+
The ibis expression to execute and persist to Delta Lake table.
789+
path
790+
The data source. A string or Path to the Delta Lake table.
791+
kwargs
792+
Additional, backend-specifc keyword arguments.
793+
"""
794+
self._find_backend(use_default=True).to_json(self, path, **kwargs)
795+
774796
@experimental
775797
def to_torch(
776798
self,

0 commit comments

Comments
 (0)