Skip to main content

Type Conversion

Ryx bridges Python and SQL types through a two-way conversion system at the PyO3 boundary.

Python → SQL

fn py_to_sql_value(value: &Bound<'_, PyAny>) -> PyResult<SqlValue>

Maps Python types to SQL-safe variants:

PythonSQL
NoneSqlValue::Null
boolSqlValue::Bool
intSqlValue::Int
floatSqlValue::Float
strSqlValue::Text
bytesSqlValue::Bytes
datetime.dateSqlValue::Date
datetime.timeSqlValue::Time
datetime.datetimeSqlValue::DateTime
dict / listSqlValue::Json

SQL → Python

fn json_to_py(value: JsonValue, py: Python) -> PyResult<PyObject>

Maps decoded SQL values back to Python objects:

SQLPython
NULLNone
BOOLEANbool
INTEGERint
DOUBLEfloat
TEXTstr
BYTEAbytes
DATEdatetime.date
TIMEdatetime.time
TIMESTAMPdatetime.datetime
JSONBdict / list

Row Decoding

The executor decodes AnyRow column-by-column:

fn decode_row(row: &AnyRow) -> HashMap<String, JsonValue> {
let mut map = HashMap::new();
for column in row.columns() {
let name = column.name().to_string();
let value = decode_value(row, &name); // Type-specific decode
map.insert(name, value);
}
map
}

The HashMap<String, JsonValue> is then converted to a PyDict at the PyO3 boundary — a single GIL operation instead of one per column.

Field-Level Conversion

Python fields also perform type conversion:

class DateTimeField(Field):
def to_python(self, value):
"""Convert DB value to Python datetime."""
if value is None:
return None
if isinstance(value, datetime):
return value
return datetime.fromisoformat(str(value))

def to_db(self, value):
"""Convert Python value to DB format."""
if value is None:
return None
return value.isoformat()

Next Steps

Cookbook — Real-world tutorials