Represent arbitrary database record

Viewed 56

I'm new to Rust and working on building a testing framework in Rust as a python library with PyO3. The tests are represented as functions that return a bool of whether the logic was passed.

The flow of data is: Snowflake DB -> Python connector -> Rust struct -> rust tests -> bool.

This is fine, except for that I'd have to create a Rust struct for every single table. Since this should be able to test arbitrary tables in the DB, it would be prohibitive to do so.

In python I can do something like

class Result:
def __init__(self, attrs: ta.Dict[str, ta.Any]):
    for k, v in attrs.items():
        setattr(self, k, v)

What would be the right approach here?

Results from the DB are returned as a Python dictionary.

EDIT -- Adding context

The Rust functions are built into a Python library using Maturin.

Here's a sample

use pyo3::prelude::*;

/// Something like this is what I'd like to do.
#[pyfunction]
fn test_amount_not_null(a: Result) -> PyResult<bool> {
    Ok(a.amount > 0)
}

/// A Python module implemented in Rust.
#[pymodule]
fn underling(_py: Python, m: &PyModule) -> PyResult<()> {
    m.add_function(wrap_pyfunction!(test_amount_not_null, m)?)?;
    Ok(())
}

Is it possible to represent something like this in Rust?

1 Answers

You can avoid creating Rust data types by keeping the input as a PyObject:

#[pyfunction]
fn test_amount_not_null(py: Python<'_>, a: PyObject) -> PyResult<bool> {
    let amount: i32 = a.as_ref(py).getattr("amount")?.extract()?;
    Ok(amount > 0)
}

You can even avoid .extract()-ing the value as i32 and do the comparison with .gt() which will use the Python interpreter. However, at that point there's functionally no benefit to using Rust (even detrimental due to the verbosity). Its not clear where you want the line to be drawn between using Python types vs Rust types. Hopefully, the example above is helpful regardless.

Related