Metadata-Version: 2.4
Name: datafusion-functions-json-ffi
Version: 0.54.2
Requires-Dist: datafusion>=54,<55
License-File: LICENSE
License-File: NOTICE
Summary: JSON SQL functions (json_get_str, json_contains, ...) for DataFusion's Python package
License-Expression: Apache-2.0
Requires-Python: >=3.11
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
Project-URL: Repository, https://github.com/RyannDaGreat/datafusion-functions-json-ffi
Project-URL: Upstream, https://github.com/datafusion-contrib/datafusion-functions-json

# datafusion-functions-json-ffi

Adds JSON functions such as `json_get_str` and `json_contains` to SQL in [DataFusion's Python package](https://pypi.org/project/datafusion/). The functions come from the Rust crate [datafusion-functions-json](https://github.com/datafusion-contrib/datafusion-functions-json). This package ships them precompiled, so you don't need Rust.

## Install

```sh
pip install datafusion-functions-json-ffi
```

This also installs `datafusion` 54.x, the only DataFusion version it works with. It needs Python 3.11 or newer. Prebuilt wheels are available for macOS on Apple silicon and for Linux on x86_64 and aarch64. On other platforms pip tries to build from source, which needs Rust and is untested.

## Use

Call `register` on a `SessionContext`. Its SQL can then read values out of JSON stored in string columns:

```python
from datafusion import SessionContext
import datafusion_functions_json_ffi

ctx = SessionContext()
datafusion_functions_json_ffi.register(ctx)

ctx.sql("""
    SELECT json_get_str(doc, 'subjects', 0, 'label') AS first_subject,
           json_get_int(doc, 'n_people') AS n_people
    FROM (VALUES ('{"subjects": [{"label": "dog"}], "n_people": 2}')) AS t(doc)
""").show()
```

```text
DataFrame()
+---------------+----------+
| first_subject | n_people |
+---------------+----------+
| dog           | 2        |
+---------------+----------+
```

After the JSON argument, each function takes a path of keys: a string selects an object field and an integer selects an array element. A single key can come from a column; a path of several keys must be written as literals.

No function raises an error for bad data. If the path is missing, the value has a different type, or the JSON is invalid, `json_contains` returns `false` and every other function returns `NULL`.

## Functions

| Function | Returns |
| --- | --- |
| `json_get_str(json, *keys)` | the string at the path |
| `json_get_int(json, *keys)` | the integer at the path |
| `json_get_float(json, *keys)` | the number at the path, as a float |
| `json_get_bool(json, *keys)` | the boolean at the path |
| `json_get_json(json, *keys)` | the value at the path as raw JSON text |
| `json_get_array(json, *keys)` | the array at the path, as a list of JSON texts: `[1, "b"]` becomes `['1', '"b"']` |
| `json_as_text(json, *keys)` | any value at the path, as text |
| `json_contains(json, *keys)` | whether the path exists |
| `json_length(json, *keys)` | the number of elements or fields at the path |
| `json_object_keys(json, *keys)` | the field names of the object at the path |
| `json_get(json, *keys)` | the value at the path, whatever its type; objects and arrays come back as JSON text |

`register` also adds `json_from_scalar` and `json_union_to_text`, which the upstream crate uses internally.

## Differences from the Rust crate

Only function calls work. The operators `->`, `->>` and `?` are not available, and `json_get(...)::int` is not rewritten to `json_get_int(...)`, so call the typed function directly. Those features plug into DataFusion's query planner, and DataFusion's Python package gives compiled extensions no way to add to it.

## Versions

The package version is the version of the upstream crate inside it: 0.54.2 contains datafusion-functions-json 0.54.2. Each release works with one DataFusion major version, and pip enforces the matching `datafusion` requirement.

