use jni::objects::{JClass, JString};
use jni::sys::{jint, jlong, jstring};
use jni::EnvUnowned;
use std::ffi::CString;
#[no_mangle]
pub extern "system" fn Java_sz_1orm_1java_SzOrmPool_poolNew<'local>(
mut unowned_env: EnvUnowned<'local>,
_class: JClass<'local>,
dsn: JString<'local>,
max_connections: jint,
) -> jlong {
unowned_env
.with_env(|_env| -> jni::errors::Result<jlong> {
let dsn_str: String = dsn.to_string();
let c_dsn = CString::new(dsn_str).map_err(|_| jni::errors::Error::JavaException)?;
let config = sz_orm_cabi::PoolConfigC {
max_connections: max_connections.max(1) as u32,
min_connections: 1,
connect_timeout_ms: 5000,
idle_timeout_ms: 300000,
};
let handle = unsafe { sz_orm_cabi::sz_orm_pool_new(c_dsn.as_ptr(), &config) };
Ok(handle as jlong)
})
.resolve::<jni::errors::ThrowRuntimeExAndDefault>()
}
#[no_mangle]
pub unsafe extern "system" fn Java_sz_1orm_1java_SzOrmPool_poolFree<'local>(
mut unowned_env: EnvUnowned<'local>,
_class: JClass<'local>,
handle: jlong,
) {
if handle == 0 {
return;
}
let _ = unowned_env.with_env(|_env| -> jni::errors::Result<()> {
unsafe {
sz_orm_cabi::sz_orm_pool_free(handle as sz_orm_cabi::SzOrmPoolHandle);
}
Ok(())
});
}
#[no_mangle]
pub unsafe extern "system" fn Java_sz_1orm_1java_SzOrmPool_ping<'local>(
mut unowned_env: EnvUnowned<'local>,
_class: JClass<'local>,
handle: jlong,
) -> jint {
if handle == 0 {
return 0;
}
unowned_env
.with_env(|_env| -> jni::errors::Result<jint> {
let healthy =
unsafe { sz_orm_cabi::sz_orm_ping(handle as sz_orm_cabi::SzOrmPoolHandle) };
Ok(healthy)
})
.resolve::<jni::errors::ThrowRuntimeExAndDefault>()
}
#[no_mangle]
pub unsafe extern "system" fn Java_sz_1orm_1java_SzOrmPool_query<'local>(
mut unowned_env: EnvUnowned<'local>,
_class: JClass<'local>,
handle: jlong,
sql: JString<'local>,
) -> jstring {
if handle == 0 {
return std::ptr::null_mut();
}
unowned_env
.with_env(|env| -> jni::errors::Result<jstring> {
let sql_str: String = sql.to_string();
let c_sql = CString::new(sql_str).map_err(|_| jni::errors::Error::JavaException)?;
let result = unsafe {
sz_orm_cabi::sz_orm_query(handle as sz_orm_cabi::SzOrmPoolHandle, c_sql.as_ptr())
};
if result.is_null() {
return Ok(std::ptr::null_mut());
}
let result_box = unsafe { Box::from_raw(result) };
let json = if result_box.success != 0 && !result_box.json.is_null() {
unsafe { std::ffi::CStr::from_ptr(result_box.json) }
.to_str()
.map(|s| s.to_string())
.unwrap_or_default()
} else {
String::new()
};
unsafe {
sz_orm_cabi::sz_orm_query_result_free(Box::into_raw(result_box));
}
let jstr = env.new_string(&json)?;
Ok(jstr.into_raw())
})
.resolve::<jni::errors::ThrowRuntimeExAndDefault>()
}
#[no_mangle]
pub unsafe extern "system" fn Java_sz_1orm_1java_SzOrmPool_execute<'local>(
mut unowned_env: EnvUnowned<'local>,
_class: JClass<'local>,
handle: jlong,
sql: JString<'local>,
) -> jlong {
if handle == 0 {
return -1;
}
unowned_env
.with_env(|_env| -> jni::errors::Result<jlong> {
let sql_str: String = sql.to_string();
let c_sql = CString::new(sql_str).map_err(|_| jni::errors::Error::JavaException)?;
let result = unsafe {
sz_orm_cabi::sz_orm_execute(handle as sz_orm_cabi::SzOrmPoolHandle, c_sql.as_ptr())
};
if result.success == 0 {
Ok(-1)
} else {
Ok(result.rows_affected as jlong)
}
})
.resolve::<jni::errors::ThrowRuntimeExAndDefault>()
}
#[no_mangle]
pub extern "system" fn Java_sz_1orm_1java_SzOrmPool_version<'local>(
mut unowned_env: EnvUnowned<'local>,
_class: JClass<'local>,
) -> jint {
unowned_env
.with_env(|_env| -> jni::errors::Result<jint> { Ok(sz_orm_cabi::sz_orm_version() as jint) })
.resolve::<jni::errors::ThrowRuntimeExAndDefault>()
}
#[no_mangle]
pub extern "system" fn Java_sz_1orm_1java_SzOrmPool_beginTransaction<'local>(
mut unowned_env: EnvUnowned<'local>,
_class: JClass<'local>,
pool_handle: jlong,
) -> jlong {
if pool_handle == 0 {
return 0;
}
unowned_env
.with_env(|_env| -> jni::errors::Result<jlong> {
let tx = unsafe {
sz_orm_cabi::sz_orm_transaction_begin(pool_handle as sz_orm_cabi::SzOrmPoolHandle)
};
Ok(tx as jlong)
})
.resolve::<jni::errors::ThrowRuntimeExAndDefault>()
}
#[no_mangle]
pub extern "system" fn Java_sz_1orm_1java_SzOrmPool_commitTransaction<'local>(
mut unowned_env: EnvUnowned<'local>,
_class: JClass<'local>,
tx_handle: jlong,
) -> jint {
if tx_handle == 0 {
return 0;
}
unowned_env
.with_env(|_env| -> jni::errors::Result<jint> {
let r = unsafe {
sz_orm_cabi::sz_orm_transaction_commit(
tx_handle as sz_orm_cabi::SzOrmTransactionHandle,
)
};
Ok(r)
})
.resolve::<jni::errors::ThrowRuntimeExAndDefault>()
}
#[no_mangle]
pub extern "system" fn Java_sz_1orm_1java_SzOrmPool_rollbackTransaction<'local>(
mut unowned_env: EnvUnowned<'local>,
_class: JClass<'local>,
tx_handle: jlong,
) -> jint {
if tx_handle == 0 {
return 0;
}
unowned_env
.with_env(|_env| -> jni::errors::Result<jint> {
let r = unsafe {
sz_orm_cabi::sz_orm_transaction_rollback(
tx_handle as sz_orm_cabi::SzOrmTransactionHandle,
)
};
Ok(r)
})
.resolve::<jni::errors::ThrowRuntimeExAndDefault>()
}
#[no_mangle]
pub unsafe extern "system" fn Java_sz_1orm_1java_SzOrmPool_freeTransaction<'local>(
mut unowned_env: EnvUnowned<'local>,
_class: JClass<'local>,
tx_handle: jlong,
) {
if tx_handle == 0 {
return;
}
let _ = unowned_env.with_env(|_env| -> jni::errors::Result<()> {
unsafe {
sz_orm_cabi::sz_orm_transaction_free(tx_handle as sz_orm_cabi::SzOrmTransactionHandle);
}
Ok(())
});
}
#[no_mangle]
pub extern "system" fn Java_sz_1orm_1java_SzOrmPool_modelInsert<'local>(
mut unowned_env: EnvUnowned<'local>,
_class: JClass<'local>,
pool_handle: jlong,
table: JString<'local>,
fields_json: JString<'local>,
values_json: JString<'local>,
) -> jlong {
if pool_handle == 0 {
return -1;
}
unowned_env
.with_env(|_env| -> jni::errors::Result<jlong> {
let table_s: String = table.to_string();
let fields_s: String = fields_json.to_string();
let values_s: String = values_json.to_string();
let c_table = CString::new(table_s).map_err(|_| jni::errors::Error::JavaException)?;
let c_fields = CString::new(fields_s).map_err(|_| jni::errors::Error::JavaException)?;
let c_values = CString::new(values_s).map_err(|_| jni::errors::Error::JavaException)?;
let r = unsafe {
sz_orm_cabi::sz_orm_model_insert(
pool_handle as sz_orm_cabi::SzOrmPoolHandle,
c_table.as_ptr(),
c_fields.as_ptr(),
c_values.as_ptr(),
)
};
if r.success == 0 {
Ok(-1)
} else {
Ok(r.rows_affected as jlong)
}
})
.resolve::<jni::errors::ThrowRuntimeExAndDefault>()
}
#[no_mangle]
pub extern "system" fn Java_sz_1orm_1java_SzOrmPool_modelUpdate<'local>(
mut unowned_env: EnvUnowned<'local>,
_class: JClass<'local>,
pool_handle: jlong,
table: JString<'local>,
set_json: JString<'local>,
where_clause: JString<'local>,
where_params_json: JString<'local>,
) -> jlong {
if pool_handle == 0 {
return -1;
}
unowned_env
.with_env(|_env| -> jni::errors::Result<jlong> {
let table_s: String = table.to_string();
let set_s: String = set_json.to_string();
let where_s: String = where_clause.to_string();
let where_params_s: String = where_params_json.to_string();
let c_table = CString::new(table_s).map_err(|_| jni::errors::Error::JavaException)?;
let c_set = CString::new(set_s).map_err(|_| jni::errors::Error::JavaException)?;
let c_where = CString::new(where_s).map_err(|_| jni::errors::Error::JavaException)?;
let c_where_params =
CString::new(where_params_s).map_err(|_| jni::errors::Error::JavaException)?;
let r = unsafe {
sz_orm_cabi::sz_orm_model_update(
pool_handle as sz_orm_cabi::SzOrmPoolHandle,
c_table.as_ptr(),
c_set.as_ptr(),
c_where.as_ptr(),
c_where_params.as_ptr(),
)
};
if r.success == 0 {
Ok(-1)
} else {
Ok(r.rows_affected as jlong)
}
})
.resolve::<jni::errors::ThrowRuntimeExAndDefault>()
}
#[no_mangle]
pub extern "system" fn Java_sz_1orm_1java_SzOrmPool_modelDelete<'local>(
mut unowned_env: EnvUnowned<'local>,
_class: JClass<'local>,
pool_handle: jlong,
table: JString<'local>,
where_clause: JString<'local>,
where_params_json: JString<'local>,
) -> jlong {
if pool_handle == 0 {
return -1;
}
unowned_env
.with_env(|_env| -> jni::errors::Result<jlong> {
let table_s: String = table.to_string();
let where_s: String = where_clause.to_string();
let where_params_s: String = where_params_json.to_string();
let c_table = CString::new(table_s).map_err(|_| jni::errors::Error::JavaException)?;
let c_where = CString::new(where_s).map_err(|_| jni::errors::Error::JavaException)?;
let c_where_params =
CString::new(where_params_s).map_err(|_| jni::errors::Error::JavaException)?;
let r = unsafe {
sz_orm_cabi::sz_orm_model_delete(
pool_handle as sz_orm_cabi::SzOrmPoolHandle,
c_table.as_ptr(),
c_where.as_ptr(),
c_where_params.as_ptr(),
)
};
if r.success == 0 {
Ok(-1)
} else {
Ok(r.rows_affected as jlong)
}
})
.resolve::<jni::errors::ThrowRuntimeExAndDefault>()
}
#[no_mangle]
pub extern "system" fn Java_sz_1orm_1java_SzOrmPool_modelFind<'local>(
mut unowned_env: EnvUnowned<'local>,
_class: JClass<'local>,
pool_handle: jlong,
table: JString<'local>,
where_clause: JString<'local>,
where_params_json: JString<'local>,
) -> jstring {
if pool_handle == 0 {
return std::ptr::null_mut();
}
unowned_env
.with_env(|env| -> jni::errors::Result<jstring> {
let table_s: String = table.to_string();
let where_s: String = where_clause.to_string();
let where_params_s: String = where_params_json.to_string();
let c_table = CString::new(table_s).map_err(|_| jni::errors::Error::JavaException)?;
let c_where = CString::new(where_s).map_err(|_| jni::errors::Error::JavaException)?;
let c_where_params =
CString::new(where_params_s).map_err(|_| jni::errors::Error::JavaException)?;
let ptr = unsafe {
sz_orm_cabi::sz_orm_model_find(
pool_handle as sz_orm_cabi::SzOrmPoolHandle,
c_table.as_ptr(),
c_where.as_ptr(),
c_where_params.as_ptr(),
)
};
let json = if ptr.is_null() {
String::new()
} else {
let s = unsafe { std::ffi::CStr::from_ptr(ptr) }
.to_str()
.map(|s| s.to_string())
.unwrap_or_default();
unsafe { sz_orm_cabi::sz_orm_string_free(ptr) };
s
};
let jstr = env.new_string(&json)?;
Ok(jstr.into_raw())
})
.resolve::<jni::errors::ThrowRuntimeExAndDefault>()
}
#[no_mangle]
pub extern "system" fn Java_sz_1orm_1java_SzOrmPool_modelInsertTx<'local>(
mut unowned_env: EnvUnowned<'local>,
_class: JClass<'local>,
tx_handle: jlong,
table: JString<'local>,
fields_json: JString<'local>,
values_json: JString<'local>,
) -> jlong {
if tx_handle == 0 {
return -1;
}
unowned_env
.with_env(|_env| -> jni::errors::Result<jlong> {
let table_s: String = table.to_string();
let fields_s: String = fields_json.to_string();
let values_s: String = values_json.to_string();
let c_table = CString::new(table_s).map_err(|_| jni::errors::Error::JavaException)?;
let c_fields = CString::new(fields_s).map_err(|_| jni::errors::Error::JavaException)?;
let c_values = CString::new(values_s).map_err(|_| jni::errors::Error::JavaException)?;
let r = unsafe {
sz_orm_cabi::sz_orm_model_insert_tx(
tx_handle as sz_orm_cabi::SzOrmTransactionHandle,
c_table.as_ptr(),
c_fields.as_ptr(),
c_values.as_ptr(),
)
};
if r.success == 0 {
Ok(-1)
} else {
Ok(r.rows_affected as jlong)
}
})
.resolve::<jni::errors::ThrowRuntimeExAndDefault>()
}
#[no_mangle]
pub extern "system" fn Java_sz_1orm_1java_SzOrmPool_modelUpdateTx<'local>(
mut unowned_env: EnvUnowned<'local>,
_class: JClass<'local>,
tx_handle: jlong,
table: JString<'local>,
set_json: JString<'local>,
where_clause: JString<'local>,
where_params_json: JString<'local>,
) -> jlong {
if tx_handle == 0 {
return -1;
}
unowned_env
.with_env(|_env| -> jni::errors::Result<jlong> {
let table_s: String = table.to_string();
let set_s: String = set_json.to_string();
let where_s: String = where_clause.to_string();
let where_params_s: String = where_params_json.to_string();
let c_table = CString::new(table_s).map_err(|_| jni::errors::Error::JavaException)?;
let c_set = CString::new(set_s).map_err(|_| jni::errors::Error::JavaException)?;
let c_where = CString::new(where_s).map_err(|_| jni::errors::Error::JavaException)?;
let c_where_params =
CString::new(where_params_s).map_err(|_| jni::errors::Error::JavaException)?;
let r = unsafe {
sz_orm_cabi::sz_orm_model_update_tx(
tx_handle as sz_orm_cabi::SzOrmTransactionHandle,
c_table.as_ptr(),
c_set.as_ptr(),
c_where.as_ptr(),
c_where_params.as_ptr(),
)
};
if r.success == 0 {
Ok(-1)
} else {
Ok(r.rows_affected as jlong)
}
})
.resolve::<jni::errors::ThrowRuntimeExAndDefault>()
}
#[no_mangle]
pub extern "system" fn Java_sz_1orm_1java_SzOrmPool_modelDeleteTx<'local>(
mut unowned_env: EnvUnowned<'local>,
_class: JClass<'local>,
tx_handle: jlong,
table: JString<'local>,
where_clause: JString<'local>,
where_params_json: JString<'local>,
) -> jlong {
if tx_handle == 0 {
return -1;
}
unowned_env
.with_env(|_env| -> jni::errors::Result<jlong> {
let table_s: String = table.to_string();
let where_s: String = where_clause.to_string();
let where_params_s: String = where_params_json.to_string();
let c_table = CString::new(table_s).map_err(|_| jni::errors::Error::JavaException)?;
let c_where = CString::new(where_s).map_err(|_| jni::errors::Error::JavaException)?;
let c_where_params =
CString::new(where_params_s).map_err(|_| jni::errors::Error::JavaException)?;
let r = unsafe {
sz_orm_cabi::sz_orm_model_delete_tx(
tx_handle as sz_orm_cabi::SzOrmTransactionHandle,
c_table.as_ptr(),
c_where.as_ptr(),
c_where_params.as_ptr(),
)
};
if r.success == 0 {
Ok(-1)
} else {
Ok(r.rows_affected as jlong)
}
})
.resolve::<jni::errors::ThrowRuntimeExAndDefault>()
}
#[no_mangle]
pub extern "system" fn Java_sz_1orm_1java_SzOrmPool_modelFindTx<'local>(
mut unowned_env: EnvUnowned<'local>,
_class: JClass<'local>,
tx_handle: jlong,
table: JString<'local>,
where_clause: JString<'local>,
where_params_json: JString<'local>,
) -> jstring {
if tx_handle == 0 {
return std::ptr::null_mut();
}
unowned_env
.with_env(|env| -> jni::errors::Result<jstring> {
let table_s: String = table.to_string();
let where_s: String = where_clause.to_string();
let where_params_s: String = where_params_json.to_string();
let c_table = CString::new(table_s).map_err(|_| jni::errors::Error::JavaException)?;
let c_where = CString::new(where_s).map_err(|_| jni::errors::Error::JavaException)?;
let c_where_params =
CString::new(where_params_s).map_err(|_| jni::errors::Error::JavaException)?;
let ptr = unsafe {
sz_orm_cabi::sz_orm_model_find_tx(
tx_handle as sz_orm_cabi::SzOrmTransactionHandle,
c_table.as_ptr(),
c_where.as_ptr(),
c_where_params.as_ptr(),
)
};
let json = if ptr.is_null() {
String::new()
} else {
let s = unsafe { std::ffi::CStr::from_ptr(ptr) }
.to_str()
.map(|s| s.to_string())
.unwrap_or_default();
unsafe { sz_orm_cabi::sz_orm_string_free(ptr) };
s
};
let jstr = env.new_string(&json)?;
Ok(jstr.into_raw())
})
.resolve::<jni::errors::ThrowRuntimeExAndDefault>()
}
#[cfg(test)]
mod tests {
use std::ffi::CString;
use sz_orm_cabi::{PoolConfigC, SzOrmPoolHandle};
fn test_pool() -> SzOrmPoolHandle {
let dsn = CString::new("sqlite::memory:").unwrap();
let config = PoolConfigC {
max_connections: 1,
min_connections: 1,
connect_timeout_ms: 5000,
idle_timeout_ms: 300000,
};
unsafe { sz_orm_cabi::sz_orm_pool_new(dsn.as_ptr(), &config) }
}
#[test]
fn test_java_binding_pool_create() {
let pool = test_pool();
assert!(!pool.is_null(), "pool should be created via cabi");
unsafe { sz_orm_cabi::sz_orm_pool_free(pool) };
}
#[test]
fn test_java_binding_ping() {
let pool = test_pool();
assert!(!pool.is_null());
let healthy = unsafe { sz_orm_cabi::sz_orm_ping(pool) };
assert_eq!(healthy, 1);
unsafe { sz_orm_cabi::sz_orm_pool_free(pool) };
}
#[test]
fn test_java_binding_version() {
let v = sz_orm_cabi::sz_orm_version();
assert!(v >= 1, "version should be >= 1, got {v}");
}
#[test]
fn test_java_binding_execute_and_query() {
let pool = test_pool();
assert!(!pool.is_null());
let create = CString::new("CREATE TABLE t (id INTEGER PRIMARY KEY, v TEXT)").unwrap();
let r = unsafe { sz_orm_cabi::sz_orm_execute(pool, create.as_ptr()) };
assert_eq!(r.success, 1);
let insert = CString::new("INSERT INTO t (v) VALUES ('x')").unwrap();
let r = unsafe { sz_orm_cabi::sz_orm_execute(pool, insert.as_ptr()) };
assert_eq!(r.success, 1);
assert_eq!(r.rows_affected, 1);
let q = CString::new("SELECT v FROM t").unwrap();
let result_ptr = unsafe { sz_orm_cabi::sz_orm_query(pool, q.as_ptr()) };
assert!(!result_ptr.is_null());
let result_box = unsafe { Box::from_raw(result_ptr) };
assert_eq!(result_box.success, 1);
unsafe { sz_orm_cabi::sz_orm_query_result_free(Box::into_raw(result_box)) };
unsafe { sz_orm_cabi::sz_orm_pool_free(pool) };
}
#[test]
fn test_java_binding_null_dsn_returns_null() {
let pool = unsafe { sz_orm_cabi::sz_orm_pool_new(std::ptr::null(), std::ptr::null()) };
assert!(pool.is_null(), "null dsn should return null pool");
}
#[test]
fn test_java_binding_pool_config_clamped() {
let dsn = CString::new("sqlite::memory:").unwrap();
let config = PoolConfigC {
max_connections: 0,
min_connections: 0,
connect_timeout_ms: 100,
idle_timeout_ms: 100,
};
let pool = unsafe { sz_orm_cabi::sz_orm_pool_new(dsn.as_ptr(), &config) };
if !pool.is_null() {
unsafe { sz_orm_cabi::sz_orm_pool_free(pool) };
}
}
fn model_test_pool() -> SzOrmPoolHandle {
let pool = test_pool();
assert!(!pool.is_null());
let create =
CString::new("CREATE TABLE jm_t (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)")
.unwrap();
let r = unsafe { sz_orm_cabi::sz_orm_execute(pool, create.as_ptr()) };
assert_eq!(r.success, 1, "CREATE should succeed");
pool
}
#[test]
fn test_java_model_insert_find_roundtrip() {
let pool = model_test_pool();
let table = CString::new("jm_t").unwrap();
let fields = CString::new(r#"["name","age"]"#).unwrap();
let values = CString::new(r#"["Alice",30]"#).unwrap();
let r = unsafe {
sz_orm_cabi::sz_orm_model_insert(pool, table.as_ptr(), fields.as_ptr(), values.as_ptr())
};
assert_eq!(
r.success, 1,
"java model_insert should succeed, code={}",
r.error_code
);
assert_eq!(r.rows_affected, 1);
let where_clause = CString::new("name = ?").unwrap();
let where_params = CString::new(r#"["Alice"]"#).unwrap();
let ptr = unsafe {
sz_orm_cabi::sz_orm_model_find(
pool,
table.as_ptr(),
where_clause.as_ptr(),
where_params.as_ptr(),
)
};
assert!(!ptr.is_null());
let json = unsafe { std::ffi::CStr::from_ptr(ptr) }
.to_string_lossy()
.into_owned();
unsafe { sz_orm_cabi::sz_orm_string_free(ptr) };
assert!(
json.contains("Alice"),
"java model_find should contain Alice: {json}"
);
unsafe { sz_orm_cabi::sz_orm_pool_free(pool) };
}
#[test]
fn test_java_model_update_delete_find() {
let pool = model_test_pool();
let table = CString::new("jm_t").unwrap();
let fields = CString::new(r#"["name","age"]"#).unwrap();
let values = CString::new(r#"["Bob",25]"#).unwrap();
unsafe {
sz_orm_cabi::sz_orm_model_insert(pool, table.as_ptr(), fields.as_ptr(), values.as_ptr())
};
let set_json = CString::new(r#"{"age":26}"#).unwrap();
let where_clause = CString::new("name = ?").unwrap();
let where_params = CString::new(r#"["Bob"]"#).unwrap();
let r = unsafe {
sz_orm_cabi::sz_orm_model_update(
pool,
table.as_ptr(),
set_json.as_ptr(),
where_clause.as_ptr(),
where_params.as_ptr(),
)
};
assert_eq!(
r.success, 1,
"java model_update should succeed, code={}",
r.error_code
);
let ptr = unsafe {
sz_orm_cabi::sz_orm_model_find(
pool,
table.as_ptr(),
where_clause.as_ptr(),
where_params.as_ptr(),
)
};
let json = unsafe { std::ffi::CStr::from_ptr(ptr) }
.to_string_lossy()
.into_owned();
unsafe { sz_orm_cabi::sz_orm_string_free(ptr) };
assert!(
json.contains("26"),
"java find after update should contain age 26: {json}"
);
let r = unsafe {
sz_orm_cabi::sz_orm_model_delete(
pool,
table.as_ptr(),
where_clause.as_ptr(),
where_params.as_ptr(),
)
};
assert_eq!(
r.success, 1,
"java model_delete should succeed, code={}",
r.error_code
);
let ptr = unsafe {
sz_orm_cabi::sz_orm_model_find(
pool,
table.as_ptr(),
where_clause.as_ptr(),
where_params.as_ptr(),
)
};
let json = unsafe { std::ffi::CStr::from_ptr(ptr) }
.to_string_lossy()
.into_owned();
unsafe { sz_orm_cabi::sz_orm_string_free(ptr) };
assert!(
json == "[]" || json == "null" || json.is_empty(),
"java find after delete should be empty: {json}"
);
unsafe { sz_orm_cabi::sz_orm_pool_free(pool) };
}
#[test]
fn test_java_model_insert_illegal_table() {
let pool = model_test_pool();
let table = CString::new("jm_t; DROP--").unwrap();
let fields = CString::new(r#"["name"]"#).unwrap();
let values = CString::new(r#"["X"]"#).unwrap();
let r = unsafe {
sz_orm_cabi::sz_orm_model_insert(pool, table.as_ptr(), fields.as_ptr(), values.as_ptr())
};
assert_eq!(r.success, 0, "illegal table should fail");
assert_eq!(
r.error_code,
sz_orm_cabi::SzOrmErrorCode::InvalidArgument.as_i32()
);
unsafe { sz_orm_cabi::sz_orm_pool_free(pool) };
}
#[test]
fn test_java_transaction_model_rollback() {
let pool = model_test_pool();
let tx = unsafe { sz_orm_cabi::sz_orm_transaction_begin(pool) };
assert!(!tx.is_null());
let table = CString::new("jm_t").unwrap();
let fields = CString::new(r#"["name","age"]"#).unwrap();
let values = CString::new(r#"["TxUser",99]"#).unwrap();
let r = unsafe {
sz_orm_cabi::sz_orm_model_insert_tx(
tx,
table.as_ptr(),
fields.as_ptr(),
values.as_ptr(),
)
};
assert_eq!(
r.success, 1,
"java model_insert_tx should succeed, code={}",
r.error_code
);
assert_eq!(unsafe { sz_orm_cabi::sz_orm_transaction_rollback(tx) }, 1);
unsafe { sz_orm_cabi::sz_orm_transaction_free(tx) };
let where_clause = CString::new("name = ?").unwrap();
let where_params = CString::new(r#"["TxUser"]"#).unwrap();
let ptr = unsafe {
sz_orm_cabi::sz_orm_model_find(
pool,
table.as_ptr(),
where_clause.as_ptr(),
where_params.as_ptr(),
)
};
let json = unsafe { std::ffi::CStr::from_ptr(ptr) }
.to_string_lossy()
.into_owned();
unsafe { sz_orm_cabi::sz_orm_string_free(ptr) };
assert!(
json == "[]" || json == "null" || json.is_empty(),
"java find after rollback should be empty: {json}"
);
unsafe { sz_orm_cabi::sz_orm_pool_free(pool) };
}
#[test]
fn test_java_transaction_model_commit() {
let pool = model_test_pool();
let tx = unsafe { sz_orm_cabi::sz_orm_transaction_begin(pool) };
assert!(!tx.is_null());
let table = CString::new("jm_t").unwrap();
let fields = CString::new(r#"["name","age"]"#).unwrap();
let values = CString::new(r#"["CommitUser",50]"#).unwrap();
unsafe {
sz_orm_cabi::sz_orm_model_insert_tx(
tx,
table.as_ptr(),
fields.as_ptr(),
values.as_ptr(),
)
};
assert_eq!(unsafe { sz_orm_cabi::sz_orm_transaction_commit(tx) }, 1);
unsafe { sz_orm_cabi::sz_orm_transaction_free(tx) };
let where_clause = CString::new("name = ?").unwrap();
let where_params = CString::new(r#"["CommitUser"]"#).unwrap();
let ptr = unsafe {
sz_orm_cabi::sz_orm_model_find(
pool,
table.as_ptr(),
where_clause.as_ptr(),
where_params.as_ptr(),
)
};
let json = unsafe { std::ffi::CStr::from_ptr(ptr) }
.to_string_lossy()
.into_owned();
unsafe { sz_orm_cabi::sz_orm_string_free(ptr) };
assert!(
json.contains("CommitUser"),
"java find after commit should contain CommitUser: {json}"
);
unsafe { sz_orm_cabi::sz_orm_pool_free(pool) };
}
}