Skip to content

Commit

Permalink
feat : add upsert ability for update
Browse files Browse the repository at this point in the history
  • Loading branch information
Hamza SENHAJI RHAZI authored and Hamza SENHAJI RHAZI committed Nov 12, 2024
1 parent a273dcf commit c0d9701
Show file tree
Hide file tree
Showing 9 changed files with 171 additions and 95 deletions.
35 changes: 24 additions & 11 deletions .github/workflows/release-python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ on:
push:
branches:
- main
# tags:
# - "v*.*.*" # Optional: only run on version tags
pull_request:
branches:
- main
tags:
- "v*.*.*" # Optional: only run on version tags
# pull_request:
# branches:
# - main

jobs:
create-dist:
Expand Down Expand Up @@ -46,12 +46,12 @@ jobs:
needs: create-dist
strategy:
matrix:
# os: [ubuntu-latest, macos-14, windows-latest]
os: [macos-14]
# python-version: ["3.9", "3.10"]
python-version: ["3.10"]
# architecture: [x86_64, aarch64] # Explicitly define architectures
architecture: [aarch64] # Explicitly define architectures
os: [ubuntu-latest, macos-14, windows-latest]
# os: [macos-14]
python-version: ["3.9", "3.10"]
# python-version: ["3.10"]
architecture: [x86_64, aarch64] # Explicitly define architectures
# architecture: [aarch64] # Explicitly define architectures
exclude:
- os: windows-latest
architecture: aarch64
Expand Down Expand Up @@ -125,3 +125,16 @@ jobs:
run: |
ls -R artifacts/
twine upload artifacts/**/*.tar.gz artifacts/**/*.whl
release:
name: Release pushed tag
runs-on: ubuntu-22.04
steps:
- name: Create release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ github.ref_name }}
run: |
gh release create "$tag" \
--repo="$GITHUB_REPOSITORY" \
--title="${GITHUB_REPOSITORY#*/} ${tag#v}" \
--generate-notes
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "py-binding-polodb"
version = "0.1.0"
version = "0.1.1"
edition = "2021"

[lib]
Expand Down
22 changes: 11 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,14 @@ python3.9 -m pip install polodb-python

### Current methods supported for collection

* delete_one
* delete_many
* find
* find_one
* insert_many
* insert_one
* len
* name
* update_many
* update_one
* aggregate
- [x] delete_one
- [x] delete_many
- [x] find
- [x] find_one
- [x] insert_many
- [x] insert_one
- [x] len
- [x] name
- [x] update_many (with upsert option)
- [x] update_one (with upsert option)
- [x] aggregate
14 changes: 9 additions & 5 deletions polodb/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,15 @@ def find_one(self, filter: dict):
def find(self, filter: dict):
return self.__rust_collection.find(filter)

def update_many(self, filter: dict, update_doc: dict):
return self.__rust_collection.update_many(filter, update_doc)

def update_one(self, filter: dict, update_doc: dict):
return self.__rust_collection.update_one(filter, update_doc)
def update_many(self, filter: dict, update_doc: dict, upsert=False):
if upsert is False:
return self.__rust_collection.update_many(filter, update_doc)
return self.__rust_collection.upsert_many(filter, update_doc)

def update_one(self, filter: dict, update_doc: dict, upsert=False):
if upsert is False:
return self.__rust_collection.update_one(filter, update_doc)
return self.__rust_collection.upsert(filter, update_doc)

def delete_many(self, filter: dict):
return self.__rust_collection.delete_many(filter)
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "polodb-python"
version = "0.1.10"
version = "0.1.11"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.9"
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use py_database::PyDatabase;
fn rust_polodb(m: &Bound<'_, PyModule>) -> PyResult<()> {
// m.add_function(wrap_pyfunction!(sum_as_string, m)?);
m.add_class::<PyDatabase>()?;

m.add_class::<PyCollection>()?;

Ok(())
Expand Down
186 changes: 122 additions & 64 deletions src/py_database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::helper_type_translator::{
delete_result_to_pydict, document_to_pydict, update_result_to_pydict,
};
use polodb_core::bson::Document;
use polodb_core::options::UpdateOptions;
use polodb_core::{Collection, CollectionT, Database};
use pyo3::exceptions::PyOSError;
use pyo3::exceptions::PyRuntimeError; // Import PyRuntimeError for error handling
Expand All @@ -23,52 +24,6 @@ impl PyCollection {
self.inner.name()
}

pub fn update_one(
&self,
py: Python,
filter: Py<PyDict>,
update: Py<PyDict>,
) -> PyResult<Option<PyObject>> {
// Convert PyDict to BSON Document
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(filter_doc, update_doc) {
Ok(update_result) => {
// Convert BSON Document to Python Dict
let py_result = update_result_to_pydict(py, update_result).unwrap();
Ok(Some(py_result.to_object(py)))
}
Err(err) => Err(PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(format!(
"Update one error: {}",
err
))),
}
}
pub fn update_many(
&self,
py: Python,
filter: Py<PyDict>,
update: Py<PyDict>,
) -> PyResult<Option<PyObject>> {
// Convert PyDict to BSON Document
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_many(filter_doc, update_doc) {
Ok(update_result) => {
// Convert BSON Document to Python Dict
let py_result = update_result_to_pydict(py, update_result).unwrap();
Ok(Some(py_result.to_object(py)))
}
Err(err) => Err(PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(format!(
"Update many error: {}",
err
))),
}
}
pub fn insert_many(&self, doc: Py<PyList>) -> PyResult<PyObject> {
// Acquire the Python GIL (Global Interpreter Lock)
Python::with_gil(|py| {
Expand Down Expand Up @@ -97,24 +52,6 @@ impl PyCollection {
})
}

pub fn count_documents(&self) -> PyResult<PyObject> {
// Acquire the Python GIL (Global Interpreter Lock)
Python::with_gil(|py| {
match self.inner.count_documents() {
Ok(result) => {
Ok(result.into_py(py))
}
Err(e) => {
// Raise a Python exception on error
Err(PyRuntimeError::new_err(format!(
"Count documents error: {}",
e
)))
}
}
})
}

pub fn insert_one(&self, doc: Py<PyDict>) -> PyResult<PyObject> {
// Acquire the Python GIL (Global Interpreter Lock)
Python::with_gil(|py| {
Expand Down Expand Up @@ -142,6 +79,110 @@ impl PyCollection {
})
}

pub fn update_one(
&self,
py: Python,
filter: Py<PyDict>,
update: Py<PyDict>,
) -> PyResult<Option<PyObject>> {
// Convert PyDict to BSON Document
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(filter_doc, update_doc) {
Ok(update_result) => {
// Convert BSON Document to Python Dict
let py_result = update_result_to_pydict(py, update_result).unwrap();
Ok(Some(py_result.to_object(py)))
}
Err(err) => Err(PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(format!(
"Update one error: {}",
err
))),
}
}

pub fn update_many(
&self,
py: Python,
filter: Py<PyDict>,
update: Py<PyDict>,
) -> PyResult<Option<PyObject>> {
// Convert PyDict to BSON Document
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_many(filter_doc, update_doc) {
Ok(update_result) => {
// Convert BSON Document to Python Dict
let py_result = update_result_to_pydict(py, update_result).unwrap();
Ok(Some(py_result.to_object(py)))
}
Err(err) => Err(PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(format!(
"Update many error: {}",
err
))),
}
}

pub fn upsert(
&self,
py: Python,
filter: Py<PyDict>,
update: Py<PyDict>,
) -> PyResult<Option<PyObject>> {
// Convert PyDict to BSON Document
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,
UpdateOptions::builder().upsert(true).build(),
) {
Ok(update_result) => {
// Convert BSON Document to Python Dict
let py_result = update_result_to_pydict(py, update_result).unwrap();
Ok(Some(py_result.to_object(py)))
}
Err(err) => Err(PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(format!(
"Upsert one error: {}",
err
))),
}
}

pub fn upsert_many(
&self,
py: Python,
filter: Py<PyDict>,
update: Py<PyDict>,
) -> PyResult<Option<PyObject>> {
// Convert PyDict to BSON Document
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_many_with_options(
filter_doc,
update_doc,
UpdateOptions::builder().upsert(true).build(),
) {
Ok(update_result) => {
// Convert BSON Document to Python Dict
let py_result = update_result_to_pydict(py, update_result).unwrap();
Ok(Some(py_result.to_object(py)))
}
Err(err) => Err(PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(format!(
"Upsert many error: {}",
err
))),
}
}

pub fn delete_one(&self, filter: Py<PyDict>) -> PyResult<PyObject> {
// Acquire the Python GIL (Global Interpreter Lock)
// let filter_doc = convert_py_obj_to_document(filter.to_object(py).as_any())?;
Expand Down Expand Up @@ -193,6 +234,23 @@ impl PyCollection {
}
})
}

pub fn count_documents(&self) -> PyResult<PyObject> {
// Acquire the Python GIL (Global Interpreter Lock)
Python::with_gil(|py| {
match self.inner.count_documents() {
Ok(result) => Ok(result.into_py(py)),
Err(e) => {
// Raise a Python exception on error
Err(PyRuntimeError::new_err(format!(
"Count documents error: {}",
e
)))
}
}
})
}

pub fn find_one(&self, py: Python, filter: Py<PyDict>) -> PyResult<Option<PyObject>> {
// Convert PyDict to BSON Document
let filter_doc = convert_py_obj_to_document(filter.to_object(py).as_any())?;
Expand Down
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit c0d9701

Please sign in to comment.