diff --git a/.github/workflows/release-python.yml b/.github/workflows/release-python.yml index 82a8b1b..ebfed8e 100644 --- a/.github/workflows/release-python.yml +++ b/.github/workflows/release-python.yml @@ -46,7 +46,7 @@ jobs: needs: create-dist strategy: matrix: - os: [ubuntu-latest, macos-14, macos-13, windows-latest] + os: [ubuntu-latest, macos-14, macos-latest, windows-latest] # os: [macos-14] python-version: ["3.9"] # , "3.10" # python-version: ["3.10"] @@ -55,7 +55,7 @@ jobs: exclude: - os: windows-latest architecture: arm64 - - os: macos-13 + - os: macos-latest architecture: arm64 # macOS 13 on GitHub Actions is only x86_64 (Intel) - os: macos-14 architecture: x86_6 diff --git a/Cargo.lock b/Cargo.lock index 2adc273..6042058 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -441,7 +441,7 @@ dependencies = [ [[package]] name = "py-binding-polodb" -version = "0.1.1" +version = "0.1.2" dependencies = [ "polodb_core", "pyo3", @@ -449,9 +449,9 @@ dependencies = [ [[package]] name = "pyo3" -version = "0.22.5" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d922163ba1f79c04bc49073ba7b32fd5a8d3b76a87c955921234b8e77333c51" +checksum = "f54b3d09cbdd1f8c20650b28e7b09e338881482f4aa908a5f61a00c98fba2690" dependencies = [ "cfg-if", "indoc", @@ -467,9 +467,9 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.22.5" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc38c5feeb496c8321091edf3d63e9a6829eab4b863b4a6a65f26f3e9cc6b179" +checksum = "3015cf985888fe66cfb63ce0e321c603706cd541b7aec7ddd35c281390af45d8" dependencies = [ "once_cell", "target-lexicon", @@ -477,9 +477,9 @@ dependencies = [ [[package]] name = "pyo3-ffi" -version = "0.22.5" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94845622d88ae274d2729fcefc850e63d7a3ddff5e3ce11bd88486db9f1d357d" +checksum = "6fca7cd8fd809b5ac4eefb89c1f98f7a7651d3739dfb341ca6980090f554c270" dependencies = [ "libc", "pyo3-build-config", @@ -487,9 +487,9 @@ dependencies = [ [[package]] name = "pyo3-macros" -version = "0.22.5" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e655aad15e09b94ffdb3ce3d217acf652e26bbc37697ef012f5e5e348c716e5e" +checksum = "34e657fa5379a79151b6ff5328d9216a84f55dc93b17b08e7c3609a969b73aa0" dependencies = [ "proc-macro2", "pyo3-macros-backend", @@ -499,9 +499,9 @@ dependencies = [ [[package]] name = "pyo3-macros-backend" -version = "0.22.5" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1e3f09eecd94618f60a455a23def79f79eba4dc561a97324bf9ac8c6df30ce" +checksum = "295548d5ffd95fd1981d2d3cf4458831b21d60af046b729b6fd143b0ba7aee2f" dependencies = [ "heck", "proc-macro2", diff --git a/Cargo.toml b/Cargo.toml index 49f33c4..6ee1f77 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "py-binding-polodb" -version = "0.1.1" +version = "0.1.2" edition = "2021" [lib] @@ -16,7 +16,7 @@ crate-type = ["cdylib", "rlib"] polodb_core = "5.1.3" # polodb_core = { path = "../src/polodb_core", default-features = false } -pyo3 = { version = "0.22.5", features = ["extension-module", "auto-initialize"] } +pyo3 = { version = "0.23.2", features = ["extension-module", "auto-initialize"] } [profile.release] lto = "thin" diff --git a/pyproject.toml b/pyproject.toml index 75f7803..a33fec6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "polodb-python" -version = "0.1.13" +version = "0.1.14" description = "Add your description here" readme = "README.md" requires-python = ">=3.9" diff --git a/src/helper_type_translator.rs b/src/helper_type_translator.rs index 96ad431..748552a 100644 --- a/src/helper_type_translator.rs +++ b/src/helper_type_translator.rs @@ -97,7 +97,7 @@ pub fn delete_result_to_pydict( py: Python, delete_result: results::DeleteResult, ) -> PyResult> { - let py_dict = PyDict::new_bound(py); + let py_dict = PyDict::new(py); // Insert matched_count and modified_count into the PyDict py_dict.set_item("deleted_count", delete_result.deleted_count as i64)?; @@ -109,7 +109,7 @@ pub fn update_result_to_pydict( py: Python, update_result: results::UpdateResult, ) -> PyResult> { - let py_dict = PyDict::new_bound(py); + let py_dict = PyDict::new(py); // Insert matched_count and modified_count into the PyDict py_dict.set_item("matched_count", update_result.matched_count as i64)?; @@ -118,7 +118,7 @@ pub fn update_result_to_pydict( Ok(py_dict.into()) } pub fn document_to_pydict(py: Python, doc: Document) -> PyResult> { - let py_dict = PyDict::new_bound(py); + let py_dict = PyDict::new(py); for (key, value) in doc { let py_value = bson_to_py_obj(py, &value); py_dict.set_item(key, py_value)?; @@ -129,25 +129,25 @@ pub fn document_to_pydict(py: Python, doc: Document) -> PyResult> { pub fn bson_to_py_obj(py: Python, bson: &Bson) -> PyObject { match bson { Bson::Null => py.None(), - Bson::Int32(i) => i.into_py(py), - Bson::Int64(i) => i.into_py(py), - Bson::Double(f) => PyFloat::new_bound(py, *f).into_py(py), - Bson::String(s) => PyString::new_bound(py, s).into_py(py), - Bson::Boolean(b) => PyBool::new_bound(py, *b).into_py(py), + Bson::Int32(i) => i.into_pyobject(py).unwrap().into(), + Bson::Int64(i) => i.into_pyobject(py).unwrap().into(), + Bson::Double(f) => PyFloat::new(py, *f).into_pyobject(py).unwrap().into(), + Bson::String(s) => PyString::new(py, s).into_pyobject(py).unwrap().into(), + Bson::Boolean(b) => PyBool::new(py, *b).into_py(py), Bson::Array(arr) => { // Create an empty PyList without specifying a slice - let py_list = PyList::empty_bound(py); // Use empty method instead of new_bound + let py_list = PyList::empty(py); // Use empty method instead of new for item in arr { py_list.append(bson_to_py_obj(py, item)).unwrap(); } - py_list.into_py(py) + py_list.into_pyobject(py).unwrap().into() } Bson::Document(doc) => { - let py_dict = PyDict::new_bound(py); + let py_dict = PyDict::new(py); for (key, value) in doc.iter() { py_dict.set_item(key, bson_to_py_obj(py, value)).unwrap(); } - py_dict.into_py(py) + py_dict.into_pyobject(py).unwrap().into() } Bson::RegularExpression(regex) => { let re_module = py.import_bound("re").unwrap(); @@ -157,10 +157,10 @@ pub fn bson_to_py_obj(py: Python, bson: &Bson) -> PyObject { .to_object(py) } // Handle JavaScript code - Bson::JavaScriptCode(code) => PyString::new_bound(py, code).into_py(py), - Bson::Timestamp(ts) => (ts.time, ts.increment).into_py(py), - Bson::Binary(bin) => PyBytes::new_bound(py, &bin.bytes).into_py(py), - Bson::ObjectId(oid) => PyString::new_bound(py, &oid.to_hex()).into_py(py), + Bson::JavaScriptCode(code) => PyString::new(py, code).into_pyobject(py).unwrap().into(), + Bson::Timestamp(ts) => (ts.time, ts.increment).into_pyobject(py).unwrap().into(), + Bson::Binary(bin) => PyBytes::new(py, &bin.bytes).into_pyobject(py).unwrap().into(), + Bson::ObjectId(oid) => PyString::new(py, &oid.to_hex()).into_pyobject(py).unwrap().into(), Bson::DateTime(dt) => { let timestamp = dt.timestamp_millis() / 1000; let datetime = py @@ -170,7 +170,7 @@ pub fn bson_to_py_obj(py: Python, bson: &Bson) -> PyObject { .unwrap(); datetime.call1((timestamp,)).unwrap().to_object(py) } - Bson::Symbol(s) => PyString::new_bound(py, s).into_py(py), + Bson::Symbol(s) => PyString::new(py, s).into_pyobject(py).unwrap().into(), // Handle undefined value (deprecated) Bson::Undefined => py.None(), diff --git a/src/py_database.rs b/src/py_database.rs index b5a5845..2788569 100644 --- a/src/py_database.rs +++ b/src/py_database.rs @@ -36,7 +36,7 @@ impl PyCollection { match self.inner.insert_many(bson_vec_docs) { Ok(result) => { // Create a Python object from the Rust result and return it - let dict: Bound<'_, PyDict> = PyDict::new_bound(py); + let dict: Bound<'_, PyDict> = PyDict::new(py); for (key, value) in &result.inserted_ids { dict.set_item(key, bson_to_py_obj(py, value)).unwrap(); @@ -64,7 +64,7 @@ impl PyCollection { Ok(result) => { // Create a Python object from the Rust result and return it let py_inserted_id = bson_to_py_obj(py, &result.inserted_id); - let dict = PyDict::new_bound(py); + let dict = PyDict::new(py); let dict_ref = dict.borrow(); dict_ref.set_item("inserted_id", py_inserted_id)?; Ok(dict.to_object(py)) @@ -137,7 +137,6 @@ impl PyCollection { let filter_doc = convert_py_obj_to_document(filter.to_object(py).as_any())?; let update_doc = convert_py_obj_to_document(update.to_object(py).as_any())?; - // Call the Rust method `find_one` match self.inner.update_one_with_options( filter_doc, update_doc, @@ -155,6 +154,29 @@ impl PyCollection { } } + fn aggregate(&self, pipeline: Py) -> PyResult { + Python::with_gil(|py| { + + let bson_vec_pipeline: Vec = + convert_py_list_to_vec_document(pipeline.to_object(py).as_any()); + match self.inner.aggregate(bson_vec_pipeline).run() { + Ok(result) => { + let vec_result = result.collect::, _>>().unwrap(); + + let py_result: Vec> = vec_result + .into_iter() + .map(|x| document_to_pydict(py, x).unwrap()) + .collect(); + Ok(py_result.to_object(py)) + } + Err(e) => { + // Raise a Python exception on error + Err(PyRuntimeError::new_err(format!("Aggregate error: {}", e))) + } + } + }) + } + pub fn upsert_many( &self, py: Python, @@ -211,7 +233,6 @@ impl PyCollection { pub fn delete_many(&self, filter: Py) -> PyResult { // Acquire the Python GIL (Global Interpreter Lock) - // let filter_doc = convert_py_obj_to_document(filter.to_object(py).as_any())?; Python::with_gil(|py| { let bson_doc: Document = match convert_py_obj_to_document(filter.to_object(py).as_any()) { @@ -239,7 +260,7 @@ impl PyCollection { // Acquire the Python GIL (Global Interpreter Lock) Python::with_gil(|py| { match self.inner.count_documents() { - Ok(result) => Ok(result.into_py(py)), + Ok(result) => Ok(result.into_pyobject(py).unwrap().into()), Err(e) => { // Raise a Python exception on error Err(PyRuntimeError::new_err(format!( diff --git a/uv.lock b/uv.lock index cf088de..0a1da32 100644 --- a/uv.lock +++ b/uv.lock @@ -259,7 +259,7 @@ wheels = [ [[package]] name = "polodb-python" -version = "0.1.12" +version = "0.1.14" source = { editable = "." } dependencies = [ { name = "tomli" },