Skip to content

Commit 6adcd8f

Browse files
feat : add upsert ability for update
1 parent a273dcf commit 6adcd8f

File tree

9 files changed

+171
-95
lines changed

9 files changed

+171
-95
lines changed

.github/workflows/release-python.yml

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ on:
44
push:
55
branches:
66
- main
7-
# tags:
8-
# - "v*.*.*" # Optional: only run on version tags
9-
pull_request:
10-
branches:
11-
- main
7+
tags:
8+
- "v*.*.*" # Optional: only run on version tags
9+
# pull_request:
10+
# branches:
11+
# - main
1212

1313
jobs:
1414
create-dist:
@@ -46,12 +46,12 @@ jobs:
4646
needs: create-dist
4747
strategy:
4848
matrix:
49-
# os: [ubuntu-latest, macos-14, windows-latest]
50-
os: [macos-14]
51-
# python-version: ["3.9", "3.10"]
52-
python-version: ["3.10"]
53-
# architecture: [x86_64, aarch64] # Explicitly define architectures
54-
architecture: [aarch64] # Explicitly define architectures
49+
os: [ubuntu-latest, macos-14, windows-latest]
50+
# os: [macos-14]
51+
python-version: ["3.9", "3.10"]
52+
# python-version: ["3.10"]
53+
architecture: [x86_64, aarch64] # Explicitly define architectures
54+
# architecture: [aarch64] # Explicitly define architectures
5555
exclude:
5656
- os: windows-latest
5757
architecture: aarch64
@@ -125,3 +125,16 @@ jobs:
125125
run: |
126126
ls -R artifacts/
127127
twine upload artifacts/**/*.tar.gz artifacts/**/*.whl
128+
release:
129+
name: Release pushed tag
130+
runs-on: ubuntu-22.04
131+
steps:
132+
- name: Create release
133+
env:
134+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
135+
tag: ${{ github.ref_name }}
136+
run: |
137+
gh release create "$tag" \
138+
--repo="$GITHUB_REPOSITORY" \
139+
--title="${GITHUB_REPOSITORY#*/} ${tag#v}" \
140+
--generate-notes

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "py-binding-polodb"
3-
version = "0.1.0"
3+
version = "0.1.1"
44
edition = "2021"
55

66
[lib]

README.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,14 @@ python3.9 -m pip install polodb-python
2828

2929
### Current methods supported for collection
3030

31-
* delete_one
32-
* delete_many
33-
* find
34-
* find_one
35-
* insert_many
36-
* insert_one
37-
* len
38-
* name
39-
* update_many
40-
* update_one
41-
* aggregate
31+
- [x] delete_one
32+
- [x] delete_many
33+
- [x] find
34+
- [x] find_one
35+
- [x] insert_many
36+
- [x] insert_one
37+
- [x] len
38+
- [x] name
39+
- [x] update_many (with upsert option)
40+
- [x] update_one (with upsert option)
41+
- [x] aggregate

polodb/core.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,15 @@ def find_one(self, filter: dict):
4949
def find(self, filter: dict):
5050
return self.__rust_collection.find(filter)
5151

52-
def update_many(self, filter: dict, update_doc: dict):
53-
return self.__rust_collection.update_many(filter, update_doc)
54-
55-
def update_one(self, filter: dict, update_doc: dict):
56-
return self.__rust_collection.update_one(filter, update_doc)
52+
def update_many(self, filter: dict, update_doc: dict, upsert=False):
53+
if upsert is False:
54+
return self.__rust_collection.update_many(filter, update_doc)
55+
return self.__rust_collection.upsert_many(filter, update_doc)
56+
57+
def update_one(self, filter: dict, update_doc: dict, upsert=False):
58+
if upsert is False:
59+
return self.__rust_collection.update_one(filter, update_doc)
60+
return self.__rust_collection.upsert(filter, update_doc)
5761

5862
def delete_many(self, filter: dict):
5963
return self.__rust_collection.delete_many(filter)

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "polodb-python"
3-
version = "0.1.10"
3+
version = "0.1.12"
44
description = "Add your description here"
55
readme = "README.md"
66
requires-python = ">=3.9"

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use py_database::PyDatabase;
1010
fn rust_polodb(m: &Bound<'_, PyModule>) -> PyResult<()> {
1111
// m.add_function(wrap_pyfunction!(sum_as_string, m)?);
1212
m.add_class::<PyDatabase>()?;
13+
1314
m.add_class::<PyCollection>()?;
1415

1516
Ok(())

src/py_database.rs

Lines changed: 122 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use crate::helper_type_translator::{
33
delete_result_to_pydict, document_to_pydict, update_result_to_pydict,
44
};
55
use polodb_core::bson::Document;
6+
use polodb_core::options::UpdateOptions;
67
use polodb_core::{Collection, CollectionT, Database};
78
use pyo3::exceptions::PyOSError;
89
use pyo3::exceptions::PyRuntimeError; // Import PyRuntimeError for error handling
@@ -23,52 +24,6 @@ impl PyCollection {
2324
self.inner.name()
2425
}
2526

26-
pub fn update_one(
27-
&self,
28-
py: Python,
29-
filter: Py<PyDict>,
30-
update: Py<PyDict>,
31-
) -> PyResult<Option<PyObject>> {
32-
// Convert PyDict to BSON Document
33-
let filter_doc = convert_py_obj_to_document(filter.to_object(py).as_any())?;
34-
let update_doc = convert_py_obj_to_document(update.to_object(py).as_any())?;
35-
36-
// Call the Rust method `find_one`
37-
match self.inner.update_one(filter_doc, update_doc) {
38-
Ok(update_result) => {
39-
// Convert BSON Document to Python Dict
40-
let py_result = update_result_to_pydict(py, update_result).unwrap();
41-
Ok(Some(py_result.to_object(py)))
42-
}
43-
Err(err) => Err(PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(format!(
44-
"Update one error: {}",
45-
err
46-
))),
47-
}
48-
}
49-
pub fn update_many(
50-
&self,
51-
py: Python,
52-
filter: Py<PyDict>,
53-
update: Py<PyDict>,
54-
) -> PyResult<Option<PyObject>> {
55-
// Convert PyDict to BSON Document
56-
let filter_doc = convert_py_obj_to_document(filter.to_object(py).as_any())?;
57-
let update_doc = convert_py_obj_to_document(update.to_object(py).as_any())?;
58-
59-
// Call the Rust method `find_one`
60-
match self.inner.update_many(filter_doc, update_doc) {
61-
Ok(update_result) => {
62-
// Convert BSON Document to Python Dict
63-
let py_result = update_result_to_pydict(py, update_result).unwrap();
64-
Ok(Some(py_result.to_object(py)))
65-
}
66-
Err(err) => Err(PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(format!(
67-
"Update many error: {}",
68-
err
69-
))),
70-
}
71-
}
7227
pub fn insert_many(&self, doc: Py<PyList>) -> PyResult<PyObject> {
7328
// Acquire the Python GIL (Global Interpreter Lock)
7429
Python::with_gil(|py| {
@@ -97,24 +52,6 @@ impl PyCollection {
9752
})
9853
}
9954

100-
pub fn count_documents(&self) -> PyResult<PyObject> {
101-
// Acquire the Python GIL (Global Interpreter Lock)
102-
Python::with_gil(|py| {
103-
match self.inner.count_documents() {
104-
Ok(result) => {
105-
Ok(result.into_py(py))
106-
}
107-
Err(e) => {
108-
// Raise a Python exception on error
109-
Err(PyRuntimeError::new_err(format!(
110-
"Count documents error: {}",
111-
e
112-
)))
113-
}
114-
}
115-
})
116-
}
117-
11855
pub fn insert_one(&self, doc: Py<PyDict>) -> PyResult<PyObject> {
11956
// Acquire the Python GIL (Global Interpreter Lock)
12057
Python::with_gil(|py| {
@@ -142,6 +79,110 @@ impl PyCollection {
14279
})
14380
}
14481

82+
pub fn update_one(
83+
&self,
84+
py: Python,
85+
filter: Py<PyDict>,
86+
update: Py<PyDict>,
87+
) -> PyResult<Option<PyObject>> {
88+
// Convert PyDict to BSON Document
89+
let filter_doc = convert_py_obj_to_document(filter.to_object(py).as_any())?;
90+
let update_doc = convert_py_obj_to_document(update.to_object(py).as_any())?;
91+
92+
// Call the Rust method `find_one`
93+
match self.inner.update_one(filter_doc, update_doc) {
94+
Ok(update_result) => {
95+
// Convert BSON Document to Python Dict
96+
let py_result = update_result_to_pydict(py, update_result).unwrap();
97+
Ok(Some(py_result.to_object(py)))
98+
}
99+
Err(err) => Err(PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(format!(
100+
"Update one error: {}",
101+
err
102+
))),
103+
}
104+
}
105+
106+
pub fn update_many(
107+
&self,
108+
py: Python,
109+
filter: Py<PyDict>,
110+
update: Py<PyDict>,
111+
) -> PyResult<Option<PyObject>> {
112+
// Convert PyDict to BSON Document
113+
let filter_doc = convert_py_obj_to_document(filter.to_object(py).as_any())?;
114+
let update_doc = convert_py_obj_to_document(update.to_object(py).as_any())?;
115+
116+
// Call the Rust method `find_one`
117+
match self.inner.update_many(filter_doc, update_doc) {
118+
Ok(update_result) => {
119+
// Convert BSON Document to Python Dict
120+
let py_result = update_result_to_pydict(py, update_result).unwrap();
121+
Ok(Some(py_result.to_object(py)))
122+
}
123+
Err(err) => Err(PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(format!(
124+
"Update many error: {}",
125+
err
126+
))),
127+
}
128+
}
129+
130+
pub fn upsert(
131+
&self,
132+
py: Python,
133+
filter: Py<PyDict>,
134+
update: Py<PyDict>,
135+
) -> PyResult<Option<PyObject>> {
136+
// Convert PyDict to BSON Document
137+
let filter_doc = convert_py_obj_to_document(filter.to_object(py).as_any())?;
138+
let update_doc = convert_py_obj_to_document(update.to_object(py).as_any())?;
139+
140+
// Call the Rust method `find_one`
141+
match self.inner.update_one_with_options(
142+
filter_doc,
143+
update_doc,
144+
UpdateOptions::builder().upsert(true).build(),
145+
) {
146+
Ok(update_result) => {
147+
// Convert BSON Document to Python Dict
148+
let py_result = update_result_to_pydict(py, update_result).unwrap();
149+
Ok(Some(py_result.to_object(py)))
150+
}
151+
Err(err) => Err(PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(format!(
152+
"Upsert one error: {}",
153+
err
154+
))),
155+
}
156+
}
157+
158+
pub fn upsert_many(
159+
&self,
160+
py: Python,
161+
filter: Py<PyDict>,
162+
update: Py<PyDict>,
163+
) -> PyResult<Option<PyObject>> {
164+
// Convert PyDict to BSON Document
165+
let filter_doc = convert_py_obj_to_document(filter.to_object(py).as_any())?;
166+
let update_doc = convert_py_obj_to_document(update.to_object(py).as_any())?;
167+
168+
// Call the Rust method `find_one`
169+
match self.inner.update_many_with_options(
170+
filter_doc,
171+
update_doc,
172+
UpdateOptions::builder().upsert(true).build(),
173+
) {
174+
Ok(update_result) => {
175+
// Convert BSON Document to Python Dict
176+
let py_result = update_result_to_pydict(py, update_result).unwrap();
177+
Ok(Some(py_result.to_object(py)))
178+
}
179+
Err(err) => Err(PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(format!(
180+
"Upsert many error: {}",
181+
err
182+
))),
183+
}
184+
}
185+
145186
pub fn delete_one(&self, filter: Py<PyDict>) -> PyResult<PyObject> {
146187
// Acquire the Python GIL (Global Interpreter Lock)
147188
// let filter_doc = convert_py_obj_to_document(filter.to_object(py).as_any())?;
@@ -193,6 +234,23 @@ impl PyCollection {
193234
}
194235
})
195236
}
237+
238+
pub fn count_documents(&self) -> PyResult<PyObject> {
239+
// Acquire the Python GIL (Global Interpreter Lock)
240+
Python::with_gil(|py| {
241+
match self.inner.count_documents() {
242+
Ok(result) => Ok(result.into_py(py)),
243+
Err(e) => {
244+
// Raise a Python exception on error
245+
Err(PyRuntimeError::new_err(format!(
246+
"Count documents error: {}",
247+
e
248+
)))
249+
}
250+
}
251+
})
252+
}
253+
196254
pub fn find_one(&self, py: Python, filter: Py<PyDict>) -> PyResult<Option<PyObject>> {
197255
// Convert PyDict to BSON Document
198256
let filter_doc = convert_py_obj_to_document(filter.to_object(py).as_any())?;

uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)