datafusion-contrib / datafusion-contrib/datafusion-functions-json

feat: Function to mimick Postgres `json_extract_path_text`

Open
#73 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
62
Forks
33
Avg merge
1d 12h
Merged PRs (30d)
9

Description

In Postgres, json_extract_path_text will return a string value without the surrounding double quotes, and any other values as casted strings. Paths not found become NULL's.

https://www.postgresql.org/docs/9.3/functions-json.html

I tried using json_as_text but it fails on cases where the path is not found.

Locally I have vendored the JsonPath and created this function which is giving me the expected behavior.

If there is no way of getting this desired behavior with the existing tools, I could publish my UDF. It's marginally redundant behavior, so I wonder if theres an easier way to factor things.


/// This function mimics the behavior of PostgreSQL's `json_extract_path_text`,
/// which returns the value at a given JSON path as text or NULL if not found.
/// Non-string values are returned as their JSON representation.
fn jiter_json_extract_path_text(
    opt_json: Option<&str>,
    path: &[JsonPath],
) -> Result<Option<String>, jiter::JiterError> {
    if let Some((mut jiter, peek)) = jiter_json_find(opt_json, path) {
        match peek {
            Peek::Null => {
                jiter.known_null()?;
                // The value is JSON null; Postgres returns SQL NULL in this case
                Ok(None)
            }
            Peek::String => {
                let s = jiter.known_str()?;
                Ok(Some(s.to_owned()))
            }
            _ => {
                // For other types (number, bool, object, array), we return their textual representation.
                let start = jiter.current_index();
                jiter.known_skip(peek)?;
                let slice = jiter.slice_to_current(start);
                match String::from_utf8(slice.to_vec()) {
                    Ok(val_str) => Ok(Some(val_str)),
                    Err(_) => Ok(None),
                }
            }
        }
    } else {
        // Path not found; return NULL
        Ok(None)
    }
}

Side note: Could JsonPath be published with the crate in a common package?

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by examining the existing json_as_text behavior and the locally described jiter_json_find and JsonPath usage. Compare the desired PostgreSQL semantics for missing paths, JSON nulls, strings, and other values with the available tools. Done means a supported function returns text or NULL consistently with the stated behavior, with relevant tests added if the project has an established test location.

Written by the indexing model from the issue text.

Assessment

Tech stack
postgresql, rust
Domain
databases
Issue type
Feature
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.