1use std::ffi::{c_char, CStr, CString};
9
10use sz_orm_cabi::{PoolConfigC, QueryResultC, SzOrmPoolHandle, SzOrmTransactionHandle};
11
12#[no_mangle]
20pub unsafe extern "C" fn sz_orm_cpp_pool_new(
21 dsn: *const c_char,
22 config: *const PoolConfigC,
23) -> SzOrmPoolHandle {
24 unsafe { sz_orm_cabi::sz_orm_pool_new(dsn, config) }
26}
27
28#[no_mangle]
34pub unsafe extern "C" fn sz_orm_cpp_pool_free(handle: SzOrmPoolHandle) {
35 unsafe { sz_orm_cabi::sz_orm_pool_free(handle) }
37}
38
39#[no_mangle]
45pub unsafe extern "C" fn sz_orm_cpp_ping(handle: SzOrmPoolHandle) -> i32 {
46 unsafe { sz_orm_cabi::sz_orm_ping(handle) }
48}
49
50#[no_mangle]
57pub unsafe extern "C" fn sz_orm_cpp_query(
58 handle: SzOrmPoolHandle,
59 sql: *const c_char,
60) -> *mut c_char {
61 if handle.is_null() || sql.is_null() {
62 return std::ptr::null_mut();
63 }
64 let result = unsafe { sz_orm_cabi::sz_orm_query(handle, sql) };
66 if result.is_null() {
67 return std::ptr::null_mut();
68 }
69 let result_box = unsafe { Box::from_raw(result) };
71 let json = if result_box.success != 0 && !result_box.json.is_null() {
72 unsafe { CStr::from_ptr(result_box.json) }
74 .to_str()
75 .map(|s| s.to_string())
76 .unwrap_or_default()
77 } else {
78 unsafe {
80 sz_orm_cabi::sz_orm_query_result_free(Box::into_raw(result_box));
81 }
82 return std::ptr::null_mut();
83 };
84 unsafe {
86 sz_orm_cabi::sz_orm_query_result_free(Box::into_raw(result_box));
87 }
88 match CString::new(json) {
89 Ok(c) => c.into_raw(),
90 Err(_) => std::ptr::null_mut(),
91 }
92}
93
94#[no_mangle]
100pub unsafe extern "C" fn sz_orm_cpp_string_free(ptr: *mut c_char) {
101 if ptr.is_null() {
102 return;
103 }
104 unsafe {
106 drop(CString::from_raw(ptr));
107 }
108}
109
110#[no_mangle]
117pub unsafe extern "C" fn sz_orm_cpp_execute(
118 handle: SzOrmPoolHandle,
119 sql: *const c_char,
120) -> *mut QueryResultC {
121 if handle.is_null() || sql.is_null() {
122 return std::ptr::null_mut();
123 }
124 let result = unsafe { sz_orm_cabi::sz_orm_execute(handle, sql) };
126 Box::into_raw(Box::new(result))
127}
128
129#[no_mangle]
135pub unsafe extern "C" fn sz_orm_cpp_result_free(ptr: *mut QueryResultC) {
136 if ptr.is_null() {
137 return;
138 }
139 unsafe {
141 drop(Box::from_raw(ptr));
142 }
143}
144
145#[no_mangle]
147pub extern "C" fn sz_orm_cpp_version() -> u32 {
148 sz_orm_cabi::sz_orm_version()
149}
150
151#[no_mangle]
161pub unsafe extern "C" fn sz_orm_cpp_transaction_begin(
162 handle: SzOrmPoolHandle,
163) -> SzOrmTransactionHandle {
164 unsafe { sz_orm_cabi::sz_orm_transaction_begin(handle) }
166}
167
168#[no_mangle]
174pub unsafe extern "C" fn sz_orm_cpp_transaction_execute(
175 tx_handle: SzOrmTransactionHandle,
176 sql: *const c_char,
177) -> *mut QueryResultC {
178 if tx_handle.is_null() || sql.is_null() {
179 return std::ptr::null_mut();
180 }
181 let result = unsafe { sz_orm_cabi::sz_orm_transaction_execute(tx_handle, sql) };
183 Box::into_raw(Box::new(result))
184}
185
186#[no_mangle]
192pub unsafe extern "C" fn sz_orm_cpp_transaction_commit(tx_handle: SzOrmTransactionHandle) -> i32 {
193 unsafe { sz_orm_cabi::sz_orm_transaction_commit(tx_handle) }
195}
196
197#[no_mangle]
203pub unsafe extern "C" fn sz_orm_cpp_transaction_rollback(tx_handle: SzOrmTransactionHandle) -> i32 {
204 unsafe { sz_orm_cabi::sz_orm_transaction_rollback(tx_handle) }
206}
207
208#[no_mangle]
214pub unsafe extern "C" fn sz_orm_cpp_transaction_free(tx_handle: SzOrmTransactionHandle) {
215 unsafe { sz_orm_cabi::sz_orm_transaction_free(tx_handle) }
217}
218
219#[no_mangle]
229pub unsafe extern "C" fn sz_orm_cpp_model_insert(
230 handle: SzOrmPoolHandle,
231 table: *const c_char,
232 fields_json: *const c_char,
233 values_json: *const c_char,
234) -> *mut QueryResultC {
235 if handle.is_null() || table.is_null() || fields_json.is_null() || values_json.is_null() {
236 return std::ptr::null_mut();
237 }
238 let result =
240 unsafe { sz_orm_cabi::sz_orm_model_insert(handle, table, fields_json, values_json) };
241 Box::into_raw(Box::new(result))
242}
243
244#[no_mangle]
250pub unsafe extern "C" fn sz_orm_cpp_model_update(
251 handle: SzOrmPoolHandle,
252 table: *const c_char,
253 set_json: *const c_char,
254 where_clause: *const c_char,
255 where_params_json: *const c_char,
256) -> *mut QueryResultC {
257 if handle.is_null() || table.is_null() || set_json.is_null() {
258 return std::ptr::null_mut();
259 }
260 let result = unsafe {
262 sz_orm_cabi::sz_orm_model_update(handle, table, set_json, where_clause, where_params_json)
263 };
264 Box::into_raw(Box::new(result))
265}
266
267#[no_mangle]
273pub unsafe extern "C" fn sz_orm_cpp_model_delete(
274 handle: SzOrmPoolHandle,
275 table: *const c_char,
276 where_clause: *const c_char,
277 where_params_json: *const c_char,
278) -> *mut QueryResultC {
279 if handle.is_null() || table.is_null() {
280 return std::ptr::null_mut();
281 }
282 let result =
284 unsafe { sz_orm_cabi::sz_orm_model_delete(handle, table, where_clause, where_params_json) };
285 Box::into_raw(Box::new(result))
286}
287
288#[no_mangle]
294pub unsafe extern "C" fn sz_orm_cpp_model_find(
295 handle: SzOrmPoolHandle,
296 table: *const c_char,
297 where_clause: *const c_char,
298 where_params_json: *const c_char,
299) -> *mut c_char {
300 if handle.is_null() || table.is_null() {
301 return std::ptr::null_mut();
302 }
303 unsafe { sz_orm_cabi::sz_orm_model_find(handle, table, where_clause, where_params_json) }
305}
306
307#[no_mangle]
313pub unsafe extern "C" fn sz_orm_cpp_model_insert_tx(
314 tx_handle: SzOrmTransactionHandle,
315 table: *const c_char,
316 fields_json: *const c_char,
317 values_json: *const c_char,
318) -> *mut QueryResultC {
319 if tx_handle.is_null() || table.is_null() || fields_json.is_null() || values_json.is_null() {
320 return std::ptr::null_mut();
321 }
322 let result =
324 unsafe { sz_orm_cabi::sz_orm_model_insert_tx(tx_handle, table, fields_json, values_json) };
325 Box::into_raw(Box::new(result))
326}
327
328#[no_mangle]
334pub unsafe extern "C" fn sz_orm_cpp_model_update_tx(
335 tx_handle: SzOrmTransactionHandle,
336 table: *const c_char,
337 set_json: *const c_char,
338 where_clause: *const c_char,
339 where_params_json: *const c_char,
340) -> *mut QueryResultC {
341 if tx_handle.is_null() || table.is_null() || set_json.is_null() {
342 return std::ptr::null_mut();
343 }
344 let result = unsafe {
346 sz_orm_cabi::sz_orm_model_update_tx(
347 tx_handle,
348 table,
349 set_json,
350 where_clause,
351 where_params_json,
352 )
353 };
354 Box::into_raw(Box::new(result))
355}
356
357#[no_mangle]
363pub unsafe extern "C" fn sz_orm_cpp_model_delete_tx(
364 tx_handle: SzOrmTransactionHandle,
365 table: *const c_char,
366 where_clause: *const c_char,
367 where_params_json: *const c_char,
368) -> *mut QueryResultC {
369 if tx_handle.is_null() || table.is_null() {
370 return std::ptr::null_mut();
371 }
372 let result = unsafe {
374 sz_orm_cabi::sz_orm_model_delete_tx(tx_handle, table, where_clause, where_params_json)
375 };
376 Box::into_raw(Box::new(result))
377}
378
379#[no_mangle]
385pub unsafe extern "C" fn sz_orm_cpp_model_find_tx(
386 tx_handle: SzOrmTransactionHandle,
387 table: *const c_char,
388 where_clause: *const c_char,
389 where_params_json: *const c_char,
390) -> *mut c_char {
391 if tx_handle.is_null() || table.is_null() {
392 return std::ptr::null_mut();
393 }
394 unsafe { sz_orm_cabi::sz_orm_model_find_tx(tx_handle, table, where_clause, where_params_json) }
396}
397
398#[cfg(test)]
399mod tests {
400 use super::*;
401
402 fn test_pool() -> SzOrmPoolHandle {
403 let dsn = CString::new("sqlite::memory:").unwrap();
404 unsafe { sz_orm_cpp_pool_new(dsn.as_ptr(), std::ptr::null()) }
406 }
407
408 #[test]
409 fn test_cpp_pool_new_creates_real_pool() {
410 let pool = test_pool();
411 assert!(!pool.is_null(), "pool_new should create a real pool");
412 unsafe { sz_orm_cpp_pool_free(pool) };
414 }
415
416 #[test]
417 fn test_cpp_ping_healthy() {
418 let pool = test_pool();
419 assert!(!pool.is_null());
420 let healthy = unsafe { sz_orm_cpp_ping(pool) };
422 assert_eq!(healthy, 1, "fresh pool should be healthy");
423 unsafe { sz_orm_cpp_pool_free(pool) };
425 }
426
427 #[test]
428 fn test_cpp_execute_and_query_roundtrip() {
429 let pool = test_pool();
430 assert!(!pool.is_null());
431
432 let create =
433 CString::new("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)").unwrap();
434 let rp = unsafe { sz_orm_cpp_execute(pool, create.as_ptr()) };
436 assert!(!rp.is_null(), "CREATE should succeed");
437 let r = unsafe { Box::from_raw(rp) };
439 assert_eq!(
440 r.success, 1,
441 "CREATE should succeed, got code {}",
442 r.error_code
443 );
444 unsafe { sz_orm_cpp_result_free(Box::into_raw(r)) };
446
447 let insert = CString::new("INSERT INTO users (name) VALUES ('Alice'), ('Bob')").unwrap();
448 let rp = unsafe { sz_orm_cpp_execute(pool, insert.as_ptr()) };
450 assert!(!rp.is_null(), "INSERT should succeed");
451 let r = unsafe { Box::from_raw(rp) };
453 assert_eq!(r.success, 1);
454 assert_eq!(r.rows_affected, 2, "two rows inserted");
455 unsafe { sz_orm_cpp_result_free(Box::into_raw(r)) };
457
458 let q = CString::new("SELECT id, name FROM users ORDER BY id").unwrap();
459 let json_ptr = unsafe { sz_orm_cpp_query(pool, q.as_ptr()) };
461 assert!(!json_ptr.is_null(), "query should return JSON");
462 let json = unsafe { CStr::from_ptr(json_ptr) }
464 .to_string_lossy()
465 .into_owned();
466 assert!(
467 json.contains("Alice"),
468 "query rows should contain Alice: {json}"
469 );
470 assert!(
471 json.contains("Bob"),
472 "query rows should contain Bob: {json}"
473 );
474 unsafe { sz_orm_cpp_string_free(json_ptr) };
476
477 unsafe { sz_orm_cpp_pool_free(pool) };
479 }
480
481 #[test]
482 fn test_cpp_query_invalid_sql_returns_null() {
483 let pool = test_pool();
484 assert!(!pool.is_null());
485 let q = CString::new("SELECT * FROM nonexistent").unwrap();
486 let json_ptr = unsafe { sz_orm_cpp_query(pool, q.as_ptr()) };
488 assert!(json_ptr.is_null(), "invalid SQL should return null");
489 unsafe { sz_orm_cpp_pool_free(pool) };
491 }
492
493 #[test]
494 fn test_cpp_null_args() {
495 let pool = unsafe { sz_orm_cpp_pool_new(std::ptr::null(), std::ptr::null()) };
497 assert!(pool.is_null());
498 let r = unsafe { sz_orm_cpp_execute(std::ptr::null_mut(), std::ptr::null()) };
500 assert!(r.is_null());
501 let q = unsafe { sz_orm_cpp_query(std::ptr::null_mut(), std::ptr::null()) };
503 assert!(q.is_null());
504 }
505
506 #[test]
507 fn test_cpp_version() {
508 let v = sz_orm_cpp_version();
509 assert!(v >= 1, "version should be >= 1, got {v}");
510 }
511
512 #[test]
513 fn test_cpp_free_null_safe() {
514 unsafe { sz_orm_cpp_string_free(std::ptr::null_mut()) };
516 unsafe { sz_orm_cpp_result_free(std::ptr::null_mut()) };
518 }
519
520 #[test]
521 fn test_cpp_ping_after_free_returns_zero() {
522 let healthy = unsafe { sz_orm_cpp_ping(std::ptr::null_mut()) };
525 assert_eq!(healthy, 0, "null pool should not be healthy");
526 }
527
528 #[test]
529 fn test_cpp_multiple_pools_independent() {
530 let dsn1 = CString::new("sqlite::memory:").unwrap();
531 let pool1 = unsafe { sz_orm_cpp_pool_new(dsn1.as_ptr(), std::ptr::null()) };
533 let dsn2 = CString::new("sqlite::memory:").unwrap();
534 let pool2 = unsafe { sz_orm_cpp_pool_new(dsn2.as_ptr(), std::ptr::null()) };
536 assert!(!pool1.is_null());
537 assert!(!pool2.is_null());
538 assert_ne!(pool1, pool2, "pools should have distinct handles");
539 unsafe {
541 sz_orm_cpp_pool_free(pool1);
542 sz_orm_cpp_pool_free(pool2);
543 }
544 }
545
546 #[test]
547 fn test_cpp_execute_empty_sql() {
548 let pool = test_pool();
549 assert!(!pool.is_null());
550 let create = CString::new("CREATE TABLE cpp_e (id INTEGER PRIMARY KEY)").unwrap();
551 let r = unsafe { sz_orm_cpp_execute(pool, create.as_ptr()) };
553 unsafe { sz_orm_cpp_result_free(r) };
555 unsafe { sz_orm_cpp_pool_free(pool) };
557 }
558
559 #[test]
560 fn test_cpp_query_empty_table() {
561 let pool = test_pool();
562 assert!(!pool.is_null());
563 let create = CString::new("CREATE TABLE empty_t (id INTEGER PRIMARY KEY)").unwrap();
564 let r = unsafe { sz_orm_cpp_execute(pool, create.as_ptr()) };
566 unsafe { sz_orm_cpp_result_free(r) };
568 let q = CString::new("SELECT id FROM empty_t").unwrap();
569 let json_ptr = unsafe { sz_orm_cpp_query(pool, q.as_ptr()) };
571 assert!(
572 !json_ptr.is_null(),
573 "empty table query should still return JSON"
574 );
575 let json = unsafe { CStr::from_ptr(json_ptr) }
577 .to_string_lossy()
578 .into_owned();
579 assert!(
580 json.contains("[]") || json.is_empty() || json.contains("id"),
581 "empty result should be empty array: {json}"
582 );
583 unsafe { sz_orm_cpp_string_free(json_ptr) };
585 unsafe { sz_orm_cpp_pool_free(pool) };
587 }
588
589 fn model_test_pool() -> SzOrmPoolHandle {
592 let pool = test_pool();
593 assert!(!pool.is_null());
594 let create =
595 CString::new("CREATE TABLE cm_t (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)")
596 .unwrap();
597 let r = unsafe { sz_orm_cpp_execute(pool, create.as_ptr()) };
599 unsafe { sz_orm_cpp_result_free(r) };
601 pool
602 }
603
604 unsafe fn free_cpp_result(ptr: *mut QueryResultC) -> QueryResultC {
605 if ptr.is_null() {
606 return QueryResultC {
607 success: 0,
608 error_code: sz_orm_cabi::SzOrmErrorCode::InvalidArgument.as_i32(),
609 rows_affected: 0,
610 last_insert_id: 0,
611 };
612 }
613 let r = unsafe { Box::from_raw(ptr) };
615 *r
616 }
617
618 unsafe fn free_cpp_str(ptr: *mut c_char) -> String {
619 if ptr.is_null() {
620 return String::new();
621 }
622 let s = unsafe { CStr::from_ptr(ptr) }
624 .to_string_lossy()
625 .into_owned();
626 unsafe { sz_orm_cpp_string_free(ptr) };
628 s
629 }
630
631 #[test]
632 fn test_cpp_model_insert_find_roundtrip() {
633 let pool = model_test_pool();
634 let table = CString::new("cm_t").unwrap();
635 let fields = CString::new(r#"["name","age"]"#).unwrap();
636 let values = CString::new(r#"["Alice",30]"#).unwrap();
637 let r = unsafe {
639 sz_orm_cpp_model_insert(pool, table.as_ptr(), fields.as_ptr(), values.as_ptr())
640 };
641 let r = unsafe { free_cpp_result(r) };
643 assert_eq!(
644 r.success, 1,
645 "cpp model_insert should succeed, code={}",
646 r.error_code
647 );
648 assert_eq!(r.rows_affected, 1);
649
650 let where_clause = CString::new("name = ?").unwrap();
651 let where_params = CString::new(r#"["Alice"]"#).unwrap();
652 let ptr = unsafe {
654 sz_orm_cpp_model_find(
655 pool,
656 table.as_ptr(),
657 where_clause.as_ptr(),
658 where_params.as_ptr(),
659 )
660 };
661 assert!(!ptr.is_null());
662 let json = unsafe { free_cpp_str(ptr) };
664 assert!(
665 json.contains("Alice"),
666 "cpp model_find should contain Alice: {json}"
667 );
668 unsafe { sz_orm_cpp_pool_free(pool) };
670 }
671
672 #[test]
673 fn test_cpp_model_update_delete_find() {
674 let pool = model_test_pool();
675 let table = CString::new("cm_t").unwrap();
676 let fields = CString::new(r#"["name","age"]"#).unwrap();
677 let values = CString::new(r#"["Bob",25]"#).unwrap();
678 let r = unsafe {
680 sz_orm_cpp_model_insert(pool, table.as_ptr(), fields.as_ptr(), values.as_ptr())
681 };
682 unsafe { free_cpp_result(r) };
684
685 let set_json = CString::new(r#"{"age":26}"#).unwrap();
686 let where_clause = CString::new("name = ?").unwrap();
687 let where_params = CString::new(r#"["Bob"]"#).unwrap();
688 let r = unsafe {
690 sz_orm_cpp_model_update(
691 pool,
692 table.as_ptr(),
693 set_json.as_ptr(),
694 where_clause.as_ptr(),
695 where_params.as_ptr(),
696 )
697 };
698 let r = unsafe { free_cpp_result(r) };
700 assert_eq!(
701 r.success, 1,
702 "cpp model_update should succeed, code={}",
703 r.error_code
704 );
705
706 let ptr = unsafe {
708 sz_orm_cpp_model_find(
709 pool,
710 table.as_ptr(),
711 where_clause.as_ptr(),
712 where_params.as_ptr(),
713 )
714 };
715 let json = unsafe { free_cpp_str(ptr) };
717 assert!(
718 json.contains("26"),
719 "cpp find after update should contain age 26: {json}"
720 );
721
722 let r = unsafe {
724 sz_orm_cpp_model_delete(
725 pool,
726 table.as_ptr(),
727 where_clause.as_ptr(),
728 where_params.as_ptr(),
729 )
730 };
731 let r = unsafe { free_cpp_result(r) };
733 assert_eq!(
734 r.success, 1,
735 "cpp model_delete should succeed, code={}",
736 r.error_code
737 );
738
739 let ptr = unsafe {
741 sz_orm_cpp_model_find(
742 pool,
743 table.as_ptr(),
744 where_clause.as_ptr(),
745 where_params.as_ptr(),
746 )
747 };
748 let json = unsafe { free_cpp_str(ptr) };
750 assert!(
751 json == "[]" || json == "null" || json.is_empty(),
752 "cpp find after delete should be empty: {json}"
753 );
754 unsafe { sz_orm_cpp_pool_free(pool) };
756 }
757
758 #[test]
759 fn test_cpp_model_insert_illegal_table() {
760 let pool = model_test_pool();
761 let table = CString::new("cm_t; DROP--").unwrap();
762 let fields = CString::new(r#"["name"]"#).unwrap();
763 let values = CString::new(r#"["X"]"#).unwrap();
764 let r = unsafe {
766 sz_orm_cpp_model_insert(pool, table.as_ptr(), fields.as_ptr(), values.as_ptr())
767 };
768 let r = unsafe { free_cpp_result(r) };
770 assert_eq!(r.success, 0, "illegal table should fail");
771 assert_eq!(
772 r.error_code,
773 sz_orm_cabi::SzOrmErrorCode::InvalidArgument.as_i32()
774 );
775 unsafe { sz_orm_cpp_pool_free(pool) };
777 }
778
779 #[test]
780 fn test_cpp_transaction_model_rollback() {
781 let pool = model_test_pool();
782 let tx = unsafe { sz_orm_cpp_transaction_begin(pool) };
784 assert!(!tx.is_null());
785
786 let table = CString::new("cm_t").unwrap();
787 let fields = CString::new(r#"["name","age"]"#).unwrap();
788 let values = CString::new(r#"["TxUser",99]"#).unwrap();
789 let r = unsafe {
791 sz_orm_cpp_model_insert_tx(tx, table.as_ptr(), fields.as_ptr(), values.as_ptr())
792 };
793 let r = unsafe { free_cpp_result(r) };
795 assert_eq!(
796 r.success, 1,
797 "cpp model_insert_tx should succeed, code={}",
798 r.error_code
799 );
800
801 assert_eq!(unsafe { sz_orm_cpp_transaction_rollback(tx) }, 1);
803 unsafe { sz_orm_cpp_transaction_free(tx) };
805
806 let where_clause = CString::new("name = ?").unwrap();
807 let where_params = CString::new(r#"["TxUser"]"#).unwrap();
808 let ptr = unsafe {
810 sz_orm_cpp_model_find(
811 pool,
812 table.as_ptr(),
813 where_clause.as_ptr(),
814 where_params.as_ptr(),
815 )
816 };
817 let json = unsafe { free_cpp_str(ptr) };
819 assert!(
820 json == "[]" || json == "null" || json.is_empty(),
821 "cpp find after rollback should be empty: {json}"
822 );
823 unsafe { sz_orm_cpp_pool_free(pool) };
825 }
826
827 #[test]
828 fn test_cpp_transaction_model_commit() {
829 let pool = model_test_pool();
830 let tx = unsafe { sz_orm_cpp_transaction_begin(pool) };
832 assert!(!tx.is_null());
833
834 let table = CString::new("cm_t").unwrap();
835 let fields = CString::new(r#"["name","age"]"#).unwrap();
836 let values = CString::new(r#"["CommitUser",50]"#).unwrap();
837 let r = unsafe {
839 sz_orm_cpp_model_insert_tx(tx, table.as_ptr(), fields.as_ptr(), values.as_ptr())
840 };
841 unsafe { free_cpp_result(r) };
843
844 assert_eq!(unsafe { sz_orm_cpp_transaction_commit(tx) }, 1);
846 unsafe { sz_orm_cpp_transaction_free(tx) };
848
849 let where_clause = CString::new("name = ?").unwrap();
850 let where_params = CString::new(r#"["CommitUser"]"#).unwrap();
851 let ptr = unsafe {
853 sz_orm_cpp_model_find(
854 pool,
855 table.as_ptr(),
856 where_clause.as_ptr(),
857 where_params.as_ptr(),
858 )
859 };
860 let json = unsafe { free_cpp_str(ptr) };
862 assert!(
863 json.contains("CommitUser"),
864 "cpp find after commit should contain CommitUser: {json}"
865 );
866 unsafe { sz_orm_cpp_pool_free(pool) };
868 }
869}