overdrive-db 1.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- overdrive_db-1.0.1/MANIFEST.in +3 -0
- overdrive_db-1.0.1/PKG-INFO +114 -0
- overdrive_db-1.0.1/README.md +82 -0
- overdrive_db-1.0.1/overdrive/__init__.py +348 -0
- overdrive_db-1.0.1/overdrive/download.py +74 -0
- overdrive_db-1.0.1/overdrive_db.egg-info/PKG-INFO +114 -0
- overdrive_db-1.0.1/overdrive_db.egg-info/SOURCES.txt +9 -0
- overdrive_db-1.0.1/overdrive_db.egg-info/dependency_links.txt +1 -0
- overdrive_db-1.0.1/overdrive_db.egg-info/top_level.txt +1 -0
- overdrive_db-1.0.1/pyproject.toml +47 -0
- overdrive_db-1.0.1/setup.cfg +4 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: overdrive-db
|
|
3
|
+
Version: 1.0.1
|
|
4
|
+
Summary: Embeddable document database — like SQLite for JSON
|
|
5
|
+
Author-email: ALL FOR ONE TECH <admin@afot.in>
|
|
6
|
+
License: MIT OR Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/ALL-FOR-ONE-TECH/OverDrive-DB_SDK
|
|
8
|
+
Project-URL: Documentation, https://github.com/ALL-FOR-ONE-TECH/OverDrive-DB_SDK/blob/main/docs/python-guide.md
|
|
9
|
+
Project-URL: Repository, https://github.com/ALL-FOR-ONE-TECH/OverDrive-DB_SDK
|
|
10
|
+
Project-URL: Bug Tracker, https://github.com/ALL-FOR-ONE-TECH/OverDrive-DB_SDK/issues
|
|
11
|
+
Project-URL: Downloads, https://github.com/ALL-FOR-ONE-TECH/OverDrive-DB_SDK/releases
|
|
12
|
+
Keywords: database,document,json,sql,embedded,nosql,sqlite
|
|
13
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
17
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
18
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
19
|
+
Classifier: Operating System :: MacOS :: MacOS X
|
|
20
|
+
Classifier: Programming Language :: Python :: 3
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
26
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
27
|
+
Classifier: Topic :: Database
|
|
28
|
+
Classifier: Topic :: Database :: Database Engines/Servers
|
|
29
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
30
|
+
Requires-Python: >=3.8
|
|
31
|
+
Description-Content-Type: text/markdown
|
|
32
|
+
|
|
33
|
+
# OverDrive InCode SDK — Python
|
|
34
|
+
|
|
35
|
+
**Embeddable document database — like SQLite for JSON.**
|
|
36
|
+
|
|
37
|
+
Import the package. Open a file. Query your data. *No server needed.*
|
|
38
|
+
|
|
39
|
+
## Install
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pip install overdrive-db
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
After installing, download the native library for your platform from
|
|
46
|
+
[GitHub Releases](https://github.com/ALL-FOR-ONE-TECH/OverDrive-DB_SDK/releases/latest)
|
|
47
|
+
and place it in your project directory or on your system PATH.
|
|
48
|
+
|
|
49
|
+
| Platform | File |
|
|
50
|
+
|---|---|
|
|
51
|
+
| Windows x64 | `overdrive-windows-x64.dll` → rename to `overdrive.dll` |
|
|
52
|
+
| Linux x64 | `liboverdrive-linux-x64.so` → rename to `liboverdrive.so` |
|
|
53
|
+
| macOS ARM64 | `liboverdrive-macos-arm64.dylib` → rename to `liboverdrive.dylib` |
|
|
54
|
+
|
|
55
|
+
## Quick Start
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
from overdrive import OverDrive
|
|
59
|
+
|
|
60
|
+
# Context manager for automatic cleanup
|
|
61
|
+
with OverDrive("myapp.odb") as db:
|
|
62
|
+
db.create_table("users")
|
|
63
|
+
|
|
64
|
+
# Insert
|
|
65
|
+
user_id = db.insert("users", {
|
|
66
|
+
"name": "Alice",
|
|
67
|
+
"email": "alice@example.com",
|
|
68
|
+
"age": 30
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
# SQL Query
|
|
72
|
+
results = db.query("SELECT * FROM users WHERE age > 25")
|
|
73
|
+
for row in results:
|
|
74
|
+
print(f" {row['name']} — {row['email']}")
|
|
75
|
+
|
|
76
|
+
# Full-text search
|
|
77
|
+
matches = db.search("users", "alice")
|
|
78
|
+
|
|
79
|
+
# Batch insert
|
|
80
|
+
db.insert_many("users", [
|
|
81
|
+
{"name": "Bob", "age": 25},
|
|
82
|
+
{"name": "Charlie", "age": 35},
|
|
83
|
+
])
|
|
84
|
+
|
|
85
|
+
print(f"Total users: {db.count('users')}")
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## API
|
|
89
|
+
|
|
90
|
+
| Method | Description |
|
|
91
|
+
|---|---|
|
|
92
|
+
| `OverDrive(path)` | Open or create a database |
|
|
93
|
+
| `db.close()` | Close the database |
|
|
94
|
+
| `db.create_table(name)` | Create a table |
|
|
95
|
+
| `db.drop_table(name)` | Drop a table |
|
|
96
|
+
| `db.list_tables()` | List all tables |
|
|
97
|
+
| `db.insert(table, doc)` | Insert a document, returns `_id` |
|
|
98
|
+
| `db.insert_many(table, docs)` | Batch insert |
|
|
99
|
+
| `db.get(table, id)` | Get by `_id` |
|
|
100
|
+
| `db.update(table, id, updates)` | Update fields |
|
|
101
|
+
| `db.delete(table, id)` | Delete by `_id` |
|
|
102
|
+
| `db.count(table)` | Count documents |
|
|
103
|
+
| `db.query(sql)` | Execute SQL query |
|
|
104
|
+
| `db.search(table, text)` | Full-text search |
|
|
105
|
+
|
|
106
|
+
## Links
|
|
107
|
+
|
|
108
|
+
- [Full Documentation](https://github.com/ALL-FOR-ONE-TECH/OverDrive-DB_SDK/blob/main/docs/python-guide.md)
|
|
109
|
+
- [GitHub](https://github.com/ALL-FOR-ONE-TECH/OverDrive-DB_SDK)
|
|
110
|
+
- [Releases](https://github.com/ALL-FOR-ONE-TECH/OverDrive-DB_SDK/releases)
|
|
111
|
+
|
|
112
|
+
## License
|
|
113
|
+
|
|
114
|
+
MIT / Apache-2.0
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# OverDrive InCode SDK — Python
|
|
2
|
+
|
|
3
|
+
**Embeddable document database — like SQLite for JSON.**
|
|
4
|
+
|
|
5
|
+
Import the package. Open a file. Query your data. *No server needed.*
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install overdrive-db
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
After installing, download the native library for your platform from
|
|
14
|
+
[GitHub Releases](https://github.com/ALL-FOR-ONE-TECH/OverDrive-DB_SDK/releases/latest)
|
|
15
|
+
and place it in your project directory or on your system PATH.
|
|
16
|
+
|
|
17
|
+
| Platform | File |
|
|
18
|
+
|---|---|
|
|
19
|
+
| Windows x64 | `overdrive-windows-x64.dll` → rename to `overdrive.dll` |
|
|
20
|
+
| Linux x64 | `liboverdrive-linux-x64.so` → rename to `liboverdrive.so` |
|
|
21
|
+
| macOS ARM64 | `liboverdrive-macos-arm64.dylib` → rename to `liboverdrive.dylib` |
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
```python
|
|
26
|
+
from overdrive import OverDrive
|
|
27
|
+
|
|
28
|
+
# Context manager for automatic cleanup
|
|
29
|
+
with OverDrive("myapp.odb") as db:
|
|
30
|
+
db.create_table("users")
|
|
31
|
+
|
|
32
|
+
# Insert
|
|
33
|
+
user_id = db.insert("users", {
|
|
34
|
+
"name": "Alice",
|
|
35
|
+
"email": "alice@example.com",
|
|
36
|
+
"age": 30
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
# SQL Query
|
|
40
|
+
results = db.query("SELECT * FROM users WHERE age > 25")
|
|
41
|
+
for row in results:
|
|
42
|
+
print(f" {row['name']} — {row['email']}")
|
|
43
|
+
|
|
44
|
+
# Full-text search
|
|
45
|
+
matches = db.search("users", "alice")
|
|
46
|
+
|
|
47
|
+
# Batch insert
|
|
48
|
+
db.insert_many("users", [
|
|
49
|
+
{"name": "Bob", "age": 25},
|
|
50
|
+
{"name": "Charlie", "age": 35},
|
|
51
|
+
])
|
|
52
|
+
|
|
53
|
+
print(f"Total users: {db.count('users')}")
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## API
|
|
57
|
+
|
|
58
|
+
| Method | Description |
|
|
59
|
+
|---|---|
|
|
60
|
+
| `OverDrive(path)` | Open or create a database |
|
|
61
|
+
| `db.close()` | Close the database |
|
|
62
|
+
| `db.create_table(name)` | Create a table |
|
|
63
|
+
| `db.drop_table(name)` | Drop a table |
|
|
64
|
+
| `db.list_tables()` | List all tables |
|
|
65
|
+
| `db.insert(table, doc)` | Insert a document, returns `_id` |
|
|
66
|
+
| `db.insert_many(table, docs)` | Batch insert |
|
|
67
|
+
| `db.get(table, id)` | Get by `_id` |
|
|
68
|
+
| `db.update(table, id, updates)` | Update fields |
|
|
69
|
+
| `db.delete(table, id)` | Delete by `_id` |
|
|
70
|
+
| `db.count(table)` | Count documents |
|
|
71
|
+
| `db.query(sql)` | Execute SQL query |
|
|
72
|
+
| `db.search(table, text)` | Full-text search |
|
|
73
|
+
|
|
74
|
+
## Links
|
|
75
|
+
|
|
76
|
+
- [Full Documentation](https://github.com/ALL-FOR-ONE-TECH/OverDrive-DB_SDK/blob/main/docs/python-guide.md)
|
|
77
|
+
- [GitHub](https://github.com/ALL-FOR-ONE-TECH/OverDrive-DB_SDK)
|
|
78
|
+
- [Releases](https://github.com/ALL-FOR-ONE-TECH/OverDrive-DB_SDK/releases)
|
|
79
|
+
|
|
80
|
+
## License
|
|
81
|
+
|
|
82
|
+
MIT / Apache-2.0
|
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
"""
|
|
2
|
+
OverDrive InCode SDK — Python Wrapper
|
|
3
|
+
Embeddable document database. Like SQLite for JSON.
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
from overdrive import OverDrive
|
|
7
|
+
|
|
8
|
+
db = OverDrive("myapp.odb")
|
|
9
|
+
db.create_table("users")
|
|
10
|
+
db.insert("users", {"name": "Alice", "age": 30})
|
|
11
|
+
results = db.query("SELECT * FROM users WHERE age > 25")
|
|
12
|
+
db.close()
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import ctypes
|
|
16
|
+
import json
|
|
17
|
+
import os
|
|
18
|
+
import platform
|
|
19
|
+
import sys
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
from typing import Any, Dict, List, Optional, Union
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _find_library() -> str:
|
|
25
|
+
"""Find the overdrive shared library."""
|
|
26
|
+
system = platform.system()
|
|
27
|
+
if system == "Windows":
|
|
28
|
+
lib_name = "overdrive.dll"
|
|
29
|
+
elif system == "Darwin":
|
|
30
|
+
lib_name = "liboverdrive.dylib"
|
|
31
|
+
else:
|
|
32
|
+
lib_name = "liboverdrive.so"
|
|
33
|
+
|
|
34
|
+
# Search paths
|
|
35
|
+
search_paths = [
|
|
36
|
+
Path(__file__).parent / lib_name,
|
|
37
|
+
Path(__file__).parent / "lib" / lib_name,
|
|
38
|
+
Path(__file__).parent.parent / "target" / "release" / lib_name,
|
|
39
|
+
Path(__file__).parent.parent.parent / "target" / "release" / lib_name,
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
for path in search_paths:
|
|
43
|
+
if path.exists():
|
|
44
|
+
return str(path)
|
|
45
|
+
|
|
46
|
+
# Try system path
|
|
47
|
+
return lib_name
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class _Native:
|
|
51
|
+
"""Low-level ctypes bindings to liboverdrive."""
|
|
52
|
+
|
|
53
|
+
def __init__(self):
|
|
54
|
+
lib_path = _find_library()
|
|
55
|
+
self.lib = ctypes.cdll.LoadLibrary(lib_path)
|
|
56
|
+
|
|
57
|
+
# Lifecycle
|
|
58
|
+
self.lib.overdrive_open.argtypes = [ctypes.c_char_p]
|
|
59
|
+
self.lib.overdrive_open.restype = ctypes.c_void_p
|
|
60
|
+
|
|
61
|
+
self.lib.overdrive_close.argtypes = [ctypes.c_void_p]
|
|
62
|
+
self.lib.overdrive_close.restype = None
|
|
63
|
+
|
|
64
|
+
self.lib.overdrive_sync.argtypes = [ctypes.c_void_p]
|
|
65
|
+
self.lib.overdrive_sync.restype = None
|
|
66
|
+
|
|
67
|
+
# Tables
|
|
68
|
+
self.lib.overdrive_create_table.argtypes = [ctypes.c_void_p, ctypes.c_char_p]
|
|
69
|
+
self.lib.overdrive_create_table.restype = ctypes.c_int
|
|
70
|
+
|
|
71
|
+
self.lib.overdrive_drop_table.argtypes = [ctypes.c_void_p, ctypes.c_char_p]
|
|
72
|
+
self.lib.overdrive_drop_table.restype = ctypes.c_int
|
|
73
|
+
|
|
74
|
+
self.lib.overdrive_list_tables.argtypes = [ctypes.c_void_p]
|
|
75
|
+
self.lib.overdrive_list_tables.restype = ctypes.c_void_p
|
|
76
|
+
|
|
77
|
+
self.lib.overdrive_table_exists.argtypes = [ctypes.c_void_p, ctypes.c_char_p]
|
|
78
|
+
self.lib.overdrive_table_exists.restype = ctypes.c_int
|
|
79
|
+
|
|
80
|
+
# CRUD
|
|
81
|
+
self.lib.overdrive_insert.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_char_p]
|
|
82
|
+
self.lib.overdrive_insert.restype = ctypes.c_void_p
|
|
83
|
+
|
|
84
|
+
self.lib.overdrive_get.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_char_p]
|
|
85
|
+
self.lib.overdrive_get.restype = ctypes.c_void_p
|
|
86
|
+
|
|
87
|
+
self.lib.overdrive_update.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p]
|
|
88
|
+
self.lib.overdrive_update.restype = ctypes.c_int
|
|
89
|
+
|
|
90
|
+
self.lib.overdrive_delete.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_char_p]
|
|
91
|
+
self.lib.overdrive_delete.restype = ctypes.c_int
|
|
92
|
+
|
|
93
|
+
self.lib.overdrive_count.argtypes = [ctypes.c_void_p, ctypes.c_char_p]
|
|
94
|
+
self.lib.overdrive_count.restype = ctypes.c_int
|
|
95
|
+
|
|
96
|
+
# Query
|
|
97
|
+
self.lib.overdrive_query.argtypes = [ctypes.c_void_p, ctypes.c_char_p]
|
|
98
|
+
self.lib.overdrive_query.restype = ctypes.c_void_p
|
|
99
|
+
|
|
100
|
+
self.lib.overdrive_search.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_char_p]
|
|
101
|
+
self.lib.overdrive_search.restype = ctypes.c_void_p
|
|
102
|
+
|
|
103
|
+
# Utility
|
|
104
|
+
self.lib.overdrive_last_error.argtypes = []
|
|
105
|
+
self.lib.overdrive_last_error.restype = ctypes.c_char_p
|
|
106
|
+
|
|
107
|
+
self.lib.overdrive_free_string.argtypes = [ctypes.c_void_p]
|
|
108
|
+
self.lib.overdrive_free_string.restype = None
|
|
109
|
+
|
|
110
|
+
self.lib.overdrive_version.argtypes = []
|
|
111
|
+
self.lib.overdrive_version.restype = ctypes.c_char_p
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
_native = None
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def _get_native() -> _Native:
|
|
118
|
+
global _native
|
|
119
|
+
if _native is None:
|
|
120
|
+
_native = _Native()
|
|
121
|
+
return _native
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def _check_error(native: _Native):
|
|
125
|
+
"""Check for and raise the last error."""
|
|
126
|
+
err = native.lib.overdrive_last_error()
|
|
127
|
+
if err:
|
|
128
|
+
raise OverDriveError(err.decode("utf-8"))
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def _read_and_free(native: _Native, ptr) -> Optional[str]:
|
|
132
|
+
"""Read a C string and free it."""
|
|
133
|
+
if not ptr:
|
|
134
|
+
return None
|
|
135
|
+
try:
|
|
136
|
+
s = ctypes.cast(ptr, ctypes.c_char_p).value
|
|
137
|
+
return s.decode("utf-8") if s else None
|
|
138
|
+
finally:
|
|
139
|
+
native.lib.overdrive_free_string(ptr)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
class OverDriveError(Exception):
|
|
143
|
+
"""Exception raised by OverDrive operations."""
|
|
144
|
+
pass
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
class OverDrive:
|
|
148
|
+
"""
|
|
149
|
+
OverDrive InCode SDK — Embeddable Document Database
|
|
150
|
+
|
|
151
|
+
Usage:
|
|
152
|
+
db = OverDrive("myapp.odb")
|
|
153
|
+
db.create_table("users")
|
|
154
|
+
db.insert("users", {"name": "Alice", "age": 30})
|
|
155
|
+
results = db.query("SELECT * FROM users WHERE age > 25")
|
|
156
|
+
db.close()
|
|
157
|
+
|
|
158
|
+
Context manager:
|
|
159
|
+
with OverDrive("myapp.odb") as db:
|
|
160
|
+
db.insert("logs", {"event": "startup"})
|
|
161
|
+
"""
|
|
162
|
+
|
|
163
|
+
def __init__(self, path: str):
|
|
164
|
+
self._native = _get_native()
|
|
165
|
+
self._handle = self._native.lib.overdrive_open(path.encode("utf-8"))
|
|
166
|
+
if not self._handle:
|
|
167
|
+
_check_error(self._native)
|
|
168
|
+
raise OverDriveError(f"Failed to open database: {path}")
|
|
169
|
+
self._path = path
|
|
170
|
+
|
|
171
|
+
def __enter__(self):
|
|
172
|
+
return self
|
|
173
|
+
|
|
174
|
+
def __exit__(self, *args):
|
|
175
|
+
self.close()
|
|
176
|
+
|
|
177
|
+
def __del__(self):
|
|
178
|
+
try:
|
|
179
|
+
self.close()
|
|
180
|
+
except Exception:
|
|
181
|
+
pass
|
|
182
|
+
|
|
183
|
+
# ── Lifecycle ───────────────────────────────
|
|
184
|
+
|
|
185
|
+
def close(self):
|
|
186
|
+
"""Close the database and release resources."""
|
|
187
|
+
if self._handle:
|
|
188
|
+
self._native.lib.overdrive_close(self._handle)
|
|
189
|
+
self._handle = None
|
|
190
|
+
|
|
191
|
+
def sync(self):
|
|
192
|
+
"""Force sync data to disk."""
|
|
193
|
+
self._ensure_open()
|
|
194
|
+
self._native.lib.overdrive_sync(self._handle)
|
|
195
|
+
|
|
196
|
+
@property
|
|
197
|
+
def path(self) -> str:
|
|
198
|
+
return self._path
|
|
199
|
+
|
|
200
|
+
@staticmethod
|
|
201
|
+
def version() -> str:
|
|
202
|
+
native = _get_native()
|
|
203
|
+
v = native.lib.overdrive_version()
|
|
204
|
+
return v.decode("utf-8") if v else "unknown"
|
|
205
|
+
|
|
206
|
+
# ── Tables ──────────────────────────────────
|
|
207
|
+
|
|
208
|
+
def create_table(self, name: str):
|
|
209
|
+
"""Create a new table."""
|
|
210
|
+
self._ensure_open()
|
|
211
|
+
result = self._native.lib.overdrive_create_table(self._handle, name.encode("utf-8"))
|
|
212
|
+
if result != 0:
|
|
213
|
+
_check_error(self._native)
|
|
214
|
+
|
|
215
|
+
def drop_table(self, name: str):
|
|
216
|
+
"""Drop a table."""
|
|
217
|
+
self._ensure_open()
|
|
218
|
+
result = self._native.lib.overdrive_drop_table(self._handle, name.encode("utf-8"))
|
|
219
|
+
if result != 0:
|
|
220
|
+
_check_error(self._native)
|
|
221
|
+
|
|
222
|
+
def list_tables(self) -> List[str]:
|
|
223
|
+
"""List all tables."""
|
|
224
|
+
self._ensure_open()
|
|
225
|
+
ptr = self._native.lib.overdrive_list_tables(self._handle)
|
|
226
|
+
if not ptr:
|
|
227
|
+
_check_error(self._native)
|
|
228
|
+
return []
|
|
229
|
+
result = _read_and_free(self._native, ptr)
|
|
230
|
+
return json.loads(result) if result else []
|
|
231
|
+
|
|
232
|
+
def table_exists(self, name: str) -> bool:
|
|
233
|
+
"""Check if a table exists."""
|
|
234
|
+
self._ensure_open()
|
|
235
|
+
result = self._native.lib.overdrive_table_exists(self._handle, name.encode("utf-8"))
|
|
236
|
+
return result == 1
|
|
237
|
+
|
|
238
|
+
# ── CRUD ────────────────────────────────────
|
|
239
|
+
|
|
240
|
+
def insert(self, table: str, doc: Dict[str, Any]) -> str:
|
|
241
|
+
"""Insert a document. Returns the _id."""
|
|
242
|
+
self._ensure_open()
|
|
243
|
+
json_str = json.dumps(doc)
|
|
244
|
+
ptr = self._native.lib.overdrive_insert(
|
|
245
|
+
self._handle,
|
|
246
|
+
table.encode("utf-8"),
|
|
247
|
+
json_str.encode("utf-8"),
|
|
248
|
+
)
|
|
249
|
+
if not ptr:
|
|
250
|
+
_check_error(self._native)
|
|
251
|
+
raise OverDriveError("Insert failed")
|
|
252
|
+
result = _read_and_free(self._native, ptr)
|
|
253
|
+
return result or ""
|
|
254
|
+
|
|
255
|
+
def insert_many(self, table: str, docs: List[Dict[str, Any]]) -> List[str]:
|
|
256
|
+
"""Insert multiple documents. Returns list of _ids."""
|
|
257
|
+
return [self.insert(table, doc) for doc in docs]
|
|
258
|
+
|
|
259
|
+
def get(self, table: str, id: str) -> Optional[Dict[str, Any]]:
|
|
260
|
+
"""Get a document by _id."""
|
|
261
|
+
self._ensure_open()
|
|
262
|
+
ptr = self._native.lib.overdrive_get(
|
|
263
|
+
self._handle,
|
|
264
|
+
table.encode("utf-8"),
|
|
265
|
+
id.encode("utf-8"),
|
|
266
|
+
)
|
|
267
|
+
if not ptr:
|
|
268
|
+
return None
|
|
269
|
+
result = _read_and_free(self._native, ptr)
|
|
270
|
+
return json.loads(result) if result else None
|
|
271
|
+
|
|
272
|
+
def update(self, table: str, id: str, updates: Dict[str, Any]) -> bool:
|
|
273
|
+
"""Update a document by _id."""
|
|
274
|
+
self._ensure_open()
|
|
275
|
+
json_str = json.dumps(updates)
|
|
276
|
+
result = self._native.lib.overdrive_update(
|
|
277
|
+
self._handle,
|
|
278
|
+
table.encode("utf-8"),
|
|
279
|
+
id.encode("utf-8"),
|
|
280
|
+
json_str.encode("utf-8"),
|
|
281
|
+
)
|
|
282
|
+
if result == -1:
|
|
283
|
+
_check_error(self._native)
|
|
284
|
+
return result == 1
|
|
285
|
+
|
|
286
|
+
def delete(self, table: str, id: str) -> bool:
|
|
287
|
+
"""Delete a document by _id."""
|
|
288
|
+
self._ensure_open()
|
|
289
|
+
result = self._native.lib.overdrive_delete(
|
|
290
|
+
self._handle,
|
|
291
|
+
table.encode("utf-8"),
|
|
292
|
+
id.encode("utf-8"),
|
|
293
|
+
)
|
|
294
|
+
if result == -1:
|
|
295
|
+
_check_error(self._native)
|
|
296
|
+
return result == 1
|
|
297
|
+
|
|
298
|
+
def count(self, table: str) -> int:
|
|
299
|
+
"""Count documents in a table."""
|
|
300
|
+
self._ensure_open()
|
|
301
|
+
result = self._native.lib.overdrive_count(self._handle, table.encode("utf-8"))
|
|
302
|
+
if result == -1:
|
|
303
|
+
_check_error(self._native)
|
|
304
|
+
return max(0, result)
|
|
305
|
+
|
|
306
|
+
# ── Query ───────────────────────────────────
|
|
307
|
+
|
|
308
|
+
def query(self, sql: str) -> List[Dict[str, Any]]:
|
|
309
|
+
"""Execute SQL query. Returns list of result rows."""
|
|
310
|
+
self._ensure_open()
|
|
311
|
+
ptr = self._native.lib.overdrive_query(self._handle, sql.encode("utf-8"))
|
|
312
|
+
if not ptr:
|
|
313
|
+
_check_error(self._native)
|
|
314
|
+
return []
|
|
315
|
+
result = _read_and_free(self._native, ptr)
|
|
316
|
+
if not result:
|
|
317
|
+
return []
|
|
318
|
+
parsed = json.loads(result)
|
|
319
|
+
return parsed.get("rows", [])
|
|
320
|
+
|
|
321
|
+
def query_full(self, sql: str) -> Dict[str, Any]:
|
|
322
|
+
"""Execute SQL query. Returns full result with metadata."""
|
|
323
|
+
self._ensure_open()
|
|
324
|
+
ptr = self._native.lib.overdrive_query(self._handle, sql.encode("utf-8"))
|
|
325
|
+
if not ptr:
|
|
326
|
+
_check_error(self._native)
|
|
327
|
+
return {"rows": [], "columns": [], "rows_affected": 0}
|
|
328
|
+
result = _read_and_free(self._native, ptr)
|
|
329
|
+
return json.loads(result) if result else {}
|
|
330
|
+
|
|
331
|
+
def search(self, table: str, text: str) -> List[Dict[str, Any]]:
|
|
332
|
+
"""Full-text search."""
|
|
333
|
+
self._ensure_open()
|
|
334
|
+
ptr = self._native.lib.overdrive_search(
|
|
335
|
+
self._handle,
|
|
336
|
+
table.encode("utf-8"),
|
|
337
|
+
text.encode("utf-8"),
|
|
338
|
+
)
|
|
339
|
+
if not ptr:
|
|
340
|
+
return []
|
|
341
|
+
result = _read_and_free(self._native, ptr)
|
|
342
|
+
return json.loads(result) if result else []
|
|
343
|
+
|
|
344
|
+
# ── Internal ────────────────────────────────
|
|
345
|
+
|
|
346
|
+
def _ensure_open(self):
|
|
347
|
+
if not self._handle:
|
|
348
|
+
raise OverDriveError("Database is closed")
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Helper to download the OverDrive native binary from GitHub Releases.
|
|
3
|
+
|
|
4
|
+
Usage:
|
|
5
|
+
python -m overdrive.download
|
|
6
|
+
|
|
7
|
+
Or in code:
|
|
8
|
+
from overdrive.download import ensure_binary
|
|
9
|
+
ensure_binary()
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import os
|
|
13
|
+
import platform
|
|
14
|
+
import sys
|
|
15
|
+
import urllib.request
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
REPO = "ALL-FOR-ONE-TECH/OverDrive-DB_SDK"
|
|
19
|
+
VERSION = "v1.0.1"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def get_binary_info():
|
|
23
|
+
"""Get the correct binary name for the current platform."""
|
|
24
|
+
system = platform.system()
|
|
25
|
+
if system == "Windows":
|
|
26
|
+
return "overdrive-windows-x64.dll", "overdrive.dll"
|
|
27
|
+
elif system == "Darwin":
|
|
28
|
+
return "liboverdrive-macos-arm64.dylib", "liboverdrive.dylib"
|
|
29
|
+
else:
|
|
30
|
+
return "liboverdrive-linux-x64.so", "liboverdrive.so"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def ensure_binary(target_dir: str = None) -> str:
|
|
34
|
+
"""
|
|
35
|
+
Download the native binary if not already present.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
target_dir: Directory to place the binary. Defaults to package directory.
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
Path to the binary.
|
|
42
|
+
"""
|
|
43
|
+
remote_name, local_name = get_binary_info()
|
|
44
|
+
|
|
45
|
+
if target_dir is None:
|
|
46
|
+
target_dir = str(Path(__file__).parent)
|
|
47
|
+
|
|
48
|
+
dest = os.path.join(target_dir, local_name)
|
|
49
|
+
|
|
50
|
+
if os.path.exists(dest):
|
|
51
|
+
print(f"✓ overdrive: Binary already present ({local_name})")
|
|
52
|
+
return dest
|
|
53
|
+
|
|
54
|
+
url = f"https://github.com/{REPO}/releases/download/{VERSION}/{remote_name}"
|
|
55
|
+
print(f"⬇ overdrive: Downloading {remote_name}...")
|
|
56
|
+
|
|
57
|
+
try:
|
|
58
|
+
urllib.request.urlretrieve(url, dest)
|
|
59
|
+
size_mb = os.path.getsize(dest) / (1024 * 1024)
|
|
60
|
+
print(f"✓ overdrive: Downloaded {local_name} ({size_mb:.1f} MB)")
|
|
61
|
+
return dest
|
|
62
|
+
except Exception as e:
|
|
63
|
+
print(f"⚠ overdrive: Download failed: {e}")
|
|
64
|
+
print(f" Download manually from: https://github.com/{REPO}/releases/tag/{VERSION}")
|
|
65
|
+
print(f" Place the binary in: {target_dir}/")
|
|
66
|
+
return ""
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
if __name__ == "__main__":
|
|
70
|
+
path = ensure_binary()
|
|
71
|
+
if path:
|
|
72
|
+
print(f"\nBinary ready at: {path}")
|
|
73
|
+
else:
|
|
74
|
+
sys.exit(1)
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: overdrive-db
|
|
3
|
+
Version: 1.0.1
|
|
4
|
+
Summary: Embeddable document database — like SQLite for JSON
|
|
5
|
+
Author-email: ALL FOR ONE TECH <admin@afot.in>
|
|
6
|
+
License: MIT OR Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/ALL-FOR-ONE-TECH/OverDrive-DB_SDK
|
|
8
|
+
Project-URL: Documentation, https://github.com/ALL-FOR-ONE-TECH/OverDrive-DB_SDK/blob/main/docs/python-guide.md
|
|
9
|
+
Project-URL: Repository, https://github.com/ALL-FOR-ONE-TECH/OverDrive-DB_SDK
|
|
10
|
+
Project-URL: Bug Tracker, https://github.com/ALL-FOR-ONE-TECH/OverDrive-DB_SDK/issues
|
|
11
|
+
Project-URL: Downloads, https://github.com/ALL-FOR-ONE-TECH/OverDrive-DB_SDK/releases
|
|
12
|
+
Keywords: database,document,json,sql,embedded,nosql,sqlite
|
|
13
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
17
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
18
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
19
|
+
Classifier: Operating System :: MacOS :: MacOS X
|
|
20
|
+
Classifier: Programming Language :: Python :: 3
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
26
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
27
|
+
Classifier: Topic :: Database
|
|
28
|
+
Classifier: Topic :: Database :: Database Engines/Servers
|
|
29
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
30
|
+
Requires-Python: >=3.8
|
|
31
|
+
Description-Content-Type: text/markdown
|
|
32
|
+
|
|
33
|
+
# OverDrive InCode SDK — Python
|
|
34
|
+
|
|
35
|
+
**Embeddable document database — like SQLite for JSON.**
|
|
36
|
+
|
|
37
|
+
Import the package. Open a file. Query your data. *No server needed.*
|
|
38
|
+
|
|
39
|
+
## Install
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pip install overdrive-db
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
After installing, download the native library for your platform from
|
|
46
|
+
[GitHub Releases](https://github.com/ALL-FOR-ONE-TECH/OverDrive-DB_SDK/releases/latest)
|
|
47
|
+
and place it in your project directory or on your system PATH.
|
|
48
|
+
|
|
49
|
+
| Platform | File |
|
|
50
|
+
|---|---|
|
|
51
|
+
| Windows x64 | `overdrive-windows-x64.dll` → rename to `overdrive.dll` |
|
|
52
|
+
| Linux x64 | `liboverdrive-linux-x64.so` → rename to `liboverdrive.so` |
|
|
53
|
+
| macOS ARM64 | `liboverdrive-macos-arm64.dylib` → rename to `liboverdrive.dylib` |
|
|
54
|
+
|
|
55
|
+
## Quick Start
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
from overdrive import OverDrive
|
|
59
|
+
|
|
60
|
+
# Context manager for automatic cleanup
|
|
61
|
+
with OverDrive("myapp.odb") as db:
|
|
62
|
+
db.create_table("users")
|
|
63
|
+
|
|
64
|
+
# Insert
|
|
65
|
+
user_id = db.insert("users", {
|
|
66
|
+
"name": "Alice",
|
|
67
|
+
"email": "alice@example.com",
|
|
68
|
+
"age": 30
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
# SQL Query
|
|
72
|
+
results = db.query("SELECT * FROM users WHERE age > 25")
|
|
73
|
+
for row in results:
|
|
74
|
+
print(f" {row['name']} — {row['email']}")
|
|
75
|
+
|
|
76
|
+
# Full-text search
|
|
77
|
+
matches = db.search("users", "alice")
|
|
78
|
+
|
|
79
|
+
# Batch insert
|
|
80
|
+
db.insert_many("users", [
|
|
81
|
+
{"name": "Bob", "age": 25},
|
|
82
|
+
{"name": "Charlie", "age": 35},
|
|
83
|
+
])
|
|
84
|
+
|
|
85
|
+
print(f"Total users: {db.count('users')}")
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## API
|
|
89
|
+
|
|
90
|
+
| Method | Description |
|
|
91
|
+
|---|---|
|
|
92
|
+
| `OverDrive(path)` | Open or create a database |
|
|
93
|
+
| `db.close()` | Close the database |
|
|
94
|
+
| `db.create_table(name)` | Create a table |
|
|
95
|
+
| `db.drop_table(name)` | Drop a table |
|
|
96
|
+
| `db.list_tables()` | List all tables |
|
|
97
|
+
| `db.insert(table, doc)` | Insert a document, returns `_id` |
|
|
98
|
+
| `db.insert_many(table, docs)` | Batch insert |
|
|
99
|
+
| `db.get(table, id)` | Get by `_id` |
|
|
100
|
+
| `db.update(table, id, updates)` | Update fields |
|
|
101
|
+
| `db.delete(table, id)` | Delete by `_id` |
|
|
102
|
+
| `db.count(table)` | Count documents |
|
|
103
|
+
| `db.query(sql)` | Execute SQL query |
|
|
104
|
+
| `db.search(table, text)` | Full-text search |
|
|
105
|
+
|
|
106
|
+
## Links
|
|
107
|
+
|
|
108
|
+
- [Full Documentation](https://github.com/ALL-FOR-ONE-TECH/OverDrive-DB_SDK/blob/main/docs/python-guide.md)
|
|
109
|
+
- [GitHub](https://github.com/ALL-FOR-ONE-TECH/OverDrive-DB_SDK)
|
|
110
|
+
- [Releases](https://github.com/ALL-FOR-ONE-TECH/OverDrive-DB_SDK/releases)
|
|
111
|
+
|
|
112
|
+
## License
|
|
113
|
+
|
|
114
|
+
MIT / Apache-2.0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
overdrive
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "overdrive-db"
|
|
7
|
+
version = "1.0.1"
|
|
8
|
+
description = "Embeddable document database — like SQLite for JSON"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = {text = "MIT OR Apache-2.0"}
|
|
11
|
+
requires-python = ">=3.8"
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "ALL FOR ONE TECH", email = "admin@afot.in"}
|
|
14
|
+
]
|
|
15
|
+
keywords = ["database", "document", "json", "sql", "embedded", "nosql", "sqlite"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 5 - Production/Stable",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"License :: OSI Approved :: Apache Software License",
|
|
21
|
+
"Operating System :: Microsoft :: Windows",
|
|
22
|
+
"Operating System :: POSIX :: Linux",
|
|
23
|
+
"Operating System :: MacOS :: MacOS X",
|
|
24
|
+
"Programming Language :: Python :: 3",
|
|
25
|
+
"Programming Language :: Python :: 3.8",
|
|
26
|
+
"Programming Language :: Python :: 3.9",
|
|
27
|
+
"Programming Language :: Python :: 3.10",
|
|
28
|
+
"Programming Language :: Python :: 3.11",
|
|
29
|
+
"Programming Language :: Python :: 3.12",
|
|
30
|
+
"Programming Language :: Python :: 3.13",
|
|
31
|
+
"Topic :: Database",
|
|
32
|
+
"Topic :: Database :: Database Engines/Servers",
|
|
33
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
[project.urls]
|
|
37
|
+
Homepage = "https://github.com/ALL-FOR-ONE-TECH/OverDrive-DB_SDK"
|
|
38
|
+
Documentation = "https://github.com/ALL-FOR-ONE-TECH/OverDrive-DB_SDK/blob/main/docs/python-guide.md"
|
|
39
|
+
Repository = "https://github.com/ALL-FOR-ONE-TECH/OverDrive-DB_SDK"
|
|
40
|
+
"Bug Tracker" = "https://github.com/ALL-FOR-ONE-TECH/OverDrive-DB_SDK/issues"
|
|
41
|
+
Downloads = "https://github.com/ALL-FOR-ONE-TECH/OverDrive-DB_SDK/releases"
|
|
42
|
+
|
|
43
|
+
[tool.setuptools.packages.find]
|
|
44
|
+
include = ["overdrive*"]
|
|
45
|
+
|
|
46
|
+
[tool.setuptools.package-data]
|
|
47
|
+
overdrive = ["*.dll", "*.so", "*.dylib"]
|