aboutsummaryrefslogtreecommitdiffstats
path: root/py_bindings
diff options
context:
space:
mode:
authorJan Tuomi <jan@jantuomi.fi>2024-10-07 14:44:18 +0300
committerJan Tuomi <jan@jantuomi.fi>2024-10-07 15:16:03 +0300
commit02224c78f33aa183c57d72a0da06d58545b1a350 (patch)
treebf1016fec0b1e29fd2178b3fabc19075ca6a2f0a /py_bindings
parenta4efc83f7f29c6ef8ac9b4c57201c9ecc31266b3 (diff)
Implement some of the py bindings
Diffstat (limited to 'py_bindings')
-rw-r--r--py_bindings/.gitignore72
-rw-r--r--py_bindings/pyproject.toml15
-rw-r--r--py_bindings/src/lib.rs234
3 files changed, 311 insertions, 10 deletions
diff --git a/py_bindings/.gitignore b/py_bindings/.gitignore
new file mode 100644
index 0000000..c8f0442
--- /dev/null
+++ b/py_bindings/.gitignore
@@ -0,0 +1,72 @@
+/target
+
+# Byte-compiled / optimized / DLL files
+__pycache__/
+.pytest_cache/
+*.py[cod]
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+.venv/
+env/
+bin/
+build/
+develop-eggs/
+dist/
+eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+include/
+man/
+venv/
+*.egg-info/
+.installed.cfg
+*.egg
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+pip-selfcheck.json
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.coverage
+.cache
+nosetests.xml
+coverage.xml
+
+# Translations
+*.mo
+
+# Mr Developer
+.mr.developer.cfg
+.project
+.pydevproject
+
+# Rope
+.ropeproject
+
+# Django stuff:
+*.log
+*.pot
+
+.DS_Store
+
+# Sphinx documentation
+docs/_build/
+
+# PyCharm
+.idea/
+
+# VSCode
+.vscode/
+
+# Pyenv
+.python-version
diff --git a/py_bindings/pyproject.toml b/py_bindings/pyproject.toml
new file mode 100644
index 0000000..01bdbce
--- /dev/null
+++ b/py_bindings/pyproject.toml
@@ -0,0 +1,15 @@
+[build-system]
+requires = ["maturin>=1.7,<2.0"]
+build-backend = "maturin"
+
+[project]
+name = "log_db_py"
+requires-python = ">=3.8"
+classifiers = [
+ "Programming Language :: Rust",
+ "Programming Language :: Python :: Implementation :: CPython",
+ "Programming Language :: Python :: Implementation :: PyPy",
+]
+dynamic = ["version"]
+[tool.maturin]
+features = ["pyo3/extension-module"]
diff --git a/py_bindings/src/lib.rs b/py_bindings/src/lib.rs
index abee9f2..fcf9052 100644
--- a/py_bindings/src/lib.rs
+++ b/py_bindings/src/lib.rs
@@ -1,16 +1,230 @@
-use log_db::*;
+use log_db;
+use pyo3::exceptions::PyException;
+use pyo3::prelude::*;
+use pyo3::types::PyTuple;
-pub fn add(left: u64, right: u64) -> u64 {
- left + right
+type Field = String;
+
+#[pyclass]
+#[derive(Clone)]
+struct RecordField {
+ record_field: log_db::RecordField,
+}
+
+#[pymethods]
+impl RecordField {
+ #[staticmethod]
+ fn int() -> Self {
+ RecordField {
+ record_field: log_db::RecordField::int(),
+ }
+ }
+
+ #[staticmethod]
+ fn float() -> Self {
+ RecordField {
+ record_field: log_db::RecordField::float(),
+ }
+ }
+
+ #[staticmethod]
+ fn string() -> Self {
+ RecordField {
+ record_field: log_db::RecordField::string(),
+ }
+ }
+
+ #[staticmethod]
+ fn bytes() -> Self {
+ RecordField {
+ record_field: log_db::RecordField::bytes(),
+ }
+ }
+
+ fn nullable(&self) -> Self {
+ RecordField {
+ record_field: self.record_field.clone().nullable(),
+ }
+ }
}
-#[cfg(test)]
-mod tests {
- use super::*;
+#[pyclass]
+#[derive(Clone)]
+struct MemtableEvictPolicy {
+ memtable_evict_policy: log_db::MemtableEvictPolicy,
+}
+
+#[pyclass]
+#[derive(Clone)]
+struct WriteDurability {
+ write_durability: log_db::WriteDurability,
+}
+
+#[pyclass]
+struct Config {
+ #[pyo3(get, set)]
+ data_dir: Option<String>,
+ #[pyo3(get, set)]
+ segment_size: Option<usize>,
+ #[pyo3(get, set)]
+ memtable_capacity: Option<usize>,
+ #[pyo3(get, set)]
+ fields: Option<Vec<(Field, RecordField)>>,
+ #[pyo3(get, set)]
+ primary_key: Option<Field>,
+ #[pyo3(get, set)]
+ secondary_keys: Option<Vec<Field>>,
+ #[pyo3(get, set)]
+ memtable_evict_policy: Option<MemtableEvictPolicy>,
+ #[pyo3(get, set)]
+ write_durability: Option<WriteDurability>,
+}
+
+#[pymethods]
+impl Config {
+ pub fn initialize(&self) -> PyResult<DB> {
+ let mut config = log_db::DB::configure();
+ if self.data_dir.is_some() {
+ config.data_dir(&self.data_dir.as_ref().unwrap().to_string());
+ }
+ if self.segment_size.is_some() {
+ config.segment_size(self.segment_size.unwrap());
+ }
+ if self.memtable_capacity.is_some() {
+ config.memtable_capacity(self.memtable_capacity.unwrap());
+ }
+ if self.fields.is_some() {
+ let mut fields = Vec::new();
+ for (field, record_field) in self.fields.as_ref().unwrap() {
+ fields.push((field.to_string(), record_field.record_field.clone()));
+ }
+ config.fields(fields);
+ }
+ if self.primary_key.is_some() {
+ config.primary_key(self.primary_key.as_ref().unwrap().to_string());
+ }
+ if self.secondary_keys.is_some() {
+ let tmp = self.secondary_keys.as_ref().unwrap();
+ config.secondary_keys(tmp.clone());
+ }
+ if self.memtable_evict_policy.is_some() {
+ let tmp = self.memtable_evict_policy.as_ref().unwrap();
+ config.memtable_evict_policy(tmp.memtable_evict_policy.clone());
+ }
+ if self.write_durability.is_some() {
+ let tmp = self.write_durability.as_ref().unwrap();
+ config.write_durability(tmp.write_durability.clone());
+ }
- #[test]
- fn it_works() {
- let result = add(2, 2);
- assert_eq!(result, 4);
+ let db = config.initialize().map_err(|e| PyException::new_err(e))?;
+ Ok(DB { db })
}
}
+
+#[pyclass]
+#[derive(Clone)]
+struct RecordValue {
+ record_value: log_db::RecordValue,
+}
+
+#[pymethods]
+impl RecordValue {
+ #[staticmethod]
+ fn int(value: i64) -> Self {
+ RecordValue {
+ record_value: log_db::RecordValue::Int(value),
+ }
+ }
+
+ #[staticmethod]
+ fn float(value: f64) -> Self {
+ RecordValue {
+ record_value: log_db::RecordValue::Float(value),
+ }
+ }
+
+ #[staticmethod]
+ fn string(value: &str) -> Self {
+ RecordValue {
+ record_value: log_db::RecordValue::String(value.to_string()),
+ }
+ }
+
+ #[staticmethod]
+ fn bytes(value: &[u8]) -> Self {
+ RecordValue {
+ record_value: log_db::RecordValue::Bytes(value.to_vec()),
+ }
+ }
+
+ #[staticmethod]
+ fn null() -> Self {
+ RecordValue {
+ record_value: log_db::RecordValue::Null,
+ }
+ }
+}
+
+#[pyclass]
+struct Record {
+ values: Vec<RecordValue>,
+}
+
+#[pymethods]
+impl Record {
+ #[new]
+ #[pyo3(signature = (*py_args))]
+ fn new(py_args: Vec<RecordValue>) -> Self {
+ Record { values: py_args }
+ }
+}
+
+#[pyclass]
+struct DB {
+ db: log_db::DB<Field>,
+}
+
+#[pymethods]
+impl DB {
+ fn upsert(&mut self, record: &Record) -> PyResult<()> {
+ let values = record
+ .values
+ .iter()
+ .map(|v| v.record_value.clone())
+ .collect();
+
+ self.db
+ .upsert(&log_db::Record { values })
+ .map_err(|e| PyException::new_err(e))?;
+ Ok(())
+ }
+
+ #[staticmethod]
+ pub fn configure() -> Config {
+ Config {
+ data_dir: None,
+ segment_size: None,
+ memtable_capacity: None,
+ fields: None,
+ primary_key: None,
+ secondary_keys: None,
+ memtable_evict_policy: None,
+ write_durability: None,
+ }
+ }
+}
+
+// #[pyfunction]
+// fn sum_as_string(a: usize, b: usize) -> PyResult<String> {
+// Ok((a + b).to_string())
+// }
+
+#[pymodule]
+fn log_db_py(m: &Bound<'_, PyModule>) -> PyResult<()> {
+ //m.add_function(wrap_pyfunction!(sum_as_string, m)?)?;
+ m.add_class::<DB>()?;
+ m.add_class::<RecordField>()?;
+ m.add_class::<RecordValue>()?;
+ m.add_class::<Record>()?;
+ Ok(())
+}