Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Function to mimick Postgres json_extract_path_text #73

Open
alexanderbianchi opened this issue Feb 7, 2025 · 0 comments
Open

Comments

@alexanderbianchi
Copy link

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?

@alexanderbianchi alexanderbianchi changed the title Function to mimick Postgres json_extract_path_text feat: Function to mimick Postgres json_extract_path_text Feb 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant