Skip to content

feat: Function to mimick Postgres json_extract_path_text #73

@alexanderbianchi

Description

@alexanderbianchi

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?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions