Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 27 additions & 8 deletions marimo/_runtime/_wasm/_duckdb/sources.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,17 +130,17 @@ def _read_function_source(
if not args:
return None
source_expr = args[0]
if isinstance(source_expr, exp.Literal) and source_expr.is_string:
return str(source_expr.this)
source = _string_literal_value(source_expr)
if source is not None:
return source

if isinstance(source_expr, exp.Array) and source_expr.expressions:
urls: list[str] = []
for item_expr in source_expr.expressions:
if not (
isinstance(item_expr, exp.Literal) and item_expr.is_string
):
item = _string_literal_value(item_expr)
if item is None:
return None
urls.append(str(item_expr.this))
urls.append(item)
return tuple(urls)

return None
Expand Down Expand Up @@ -191,10 +191,29 @@ def _literal_value(value_expr: exp.Expression) -> Any:
"""Convert sqlglot literals while preserving falsy values via _MISSING."""
import sqlglot.expressions as exp

value = _string_literal_value(value_expr)
if value is not None:
return value
if isinstance(value_expr, exp.Boolean):
return value_expr.this
if isinstance(value_expr, exp.Literal):
if value_expr.is_string:
return value_expr.this
return value_expr.to_py()
return _MISSING


def _string_literal_value(value_expr: exp.Expression) -> str | None:
"""Return SQL string literals, including DuckDB double-quoted strings."""
import sqlglot.expressions as exp

if isinstance(value_expr, exp.Literal) and value_expr.is_string:
return str(value_expr.this)
if isinstance(value_expr, exp.Identifier):
return str(value_expr.this) if value_expr.args.get("quoted") else None
if isinstance(value_expr, exp.Column) and all(
value_expr.args.get(part) is None
for part in ("table", "db", "catalog")
):
identifier = value_expr.this
if isinstance(identifier, exp.Identifier):
return _string_literal_value(identifier)
return None
34 changes: 34 additions & 0 deletions tests/_runtime/test_duckdb_wasm.py
Original file line number Diff line number Diff line change
Expand Up @@ -969,6 +969,40 @@ def test_wrapped_sql_rewrites_remote_literal_with_explicit_connection() -> (
"https://datasets.marimo.app/cars.csv"
)

@staticmethod
def test_wrapped_sql_rewrites_double_quoted_reader_url() -> None:
import duckdb

from marimo._sql.utils import wrapped_sql

connection = duckdb.connect(":memory:")
try:
with (
mock_pyodide(),
patch(
"marimo._runtime._wasm._fetch.fetch_url_bytes",
return_value=b"make,mpg\nford,25\ntoyota,18\n",
) as fetch_url_bytes,
):
relation = wrapped_sql(
"""
SELECT make
FROM read_csv(
"https://datasets.marimo.app/cars.csv"
)
WHERE mpg > 20
""",
connection,
)
rows = relation.fetchall()
finally:
connection.close()

assert rows == [("ford",)]
fetch_url_bytes.assert_called_once_with(
"https://datasets.marimo.app/cars.csv"
)

@staticmethod
def test_execute_duckdb_sql_rewrites_remote_literal_with_explicit_connection() -> (
None
Expand Down
Loading