commitdb 2.2.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.
- commitdb-2.2.1/PKG-INFO +277 -0
- commitdb-2.2.1/README.md +252 -0
- commitdb-2.2.1/commitdb/__init__.py +43 -0
- commitdb-2.2.1/commitdb/binding.py +135 -0
- commitdb-2.2.1/commitdb/client.py +521 -0
- commitdb-2.2.1/commitdb/ibis_backend.py +490 -0
- commitdb-2.2.1/commitdb/lib/libcommitdb-linux-amd64.so +0 -0
- commitdb-2.2.1/commitdb.egg-info/PKG-INFO +277 -0
- commitdb-2.2.1/commitdb.egg-info/SOURCES.txt +16 -0
- commitdb-2.2.1/commitdb.egg-info/dependency_links.txt +1 -0
- commitdb-2.2.1/commitdb.egg-info/entry_points.txt +2 -0
- commitdb-2.2.1/commitdb.egg-info/requires.txt +7 -0
- commitdb-2.2.1/commitdb.egg-info/top_level.txt +3 -0
- commitdb-2.2.1/pyproject.toml +42 -0
- commitdb-2.2.1/setup.cfg +4 -0
- commitdb-2.2.1/tests/__init__.py +0 -0
- commitdb-2.2.1/tests/test_client.py +866 -0
- commitdb-2.2.1/tests/test_ibis.py +88 -0
commitdb-2.2.1/PKG-INFO
ADDED
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: commitdb
|
|
3
|
+
Version: 2.2.1
|
|
4
|
+
Summary: Python driver for CommitDB SQL Server
|
|
5
|
+
Author: CommitDB Contributors
|
|
6
|
+
License: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/nickyhof/CommitDB
|
|
8
|
+
Project-URL: Documentation, https://github.com/nickyhof/CommitDB#readme
|
|
9
|
+
Project-URL: Repository, https://github.com/nickyhof/CommitDB
|
|
10
|
+
Keywords: database,sql,git,commitdb
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
Provides-Extra: dev
|
|
21
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
22
|
+
Provides-Extra: ibis
|
|
23
|
+
Requires-Dist: ibis-framework>=9.0; extra == "ibis"
|
|
24
|
+
Requires-Dist: pandas>=2.0; extra == "ibis"
|
|
25
|
+
|
|
26
|
+
# CommitDB Python Driver
|
|
27
|
+
|
|
28
|
+
[](https://badge.fury.io/py/commitdb)
|
|
29
|
+
[](https://www.python.org/downloads/)
|
|
30
|
+
|
|
31
|
+
Python client for CommitDB - a Git-backed SQL database engine.
|
|
32
|
+
|
|
33
|
+
**[📚 Full Documentation](https://nickyhof.github.io/CommitDB/python-driver/)**
|
|
34
|
+
|
|
35
|
+
> ⚠️ **Experimental Project** - This is a hobby project and should not be used in any production environment.
|
|
36
|
+
|
|
37
|
+
## Installation
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
pip install commitdb
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Quick Start
|
|
44
|
+
|
|
45
|
+
### Remote Mode (connect to server)
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
from commitdb import CommitDB
|
|
49
|
+
|
|
50
|
+
with CommitDB('localhost', 3306) as db:
|
|
51
|
+
db.execute('CREATE DATABASE mydb')
|
|
52
|
+
db.execute('CREATE TABLE mydb.users (id INT PRIMARY KEY, name STRING)')
|
|
53
|
+
db.execute("INSERT INTO mydb.users VALUES (1, 'Alice')")
|
|
54
|
+
|
|
55
|
+
result = db.query('SELECT * FROM mydb.users')
|
|
56
|
+
for row in result:
|
|
57
|
+
print(f"{row['id']}: {row['name']}")
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Embedded Mode (no server required)
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
from commitdb import CommitDBLocal
|
|
64
|
+
|
|
65
|
+
with CommitDBLocal() as db: # In-memory
|
|
66
|
+
db.execute('CREATE DATABASE mydb')
|
|
67
|
+
db.execute('CREATE TABLE mydb.users (id INT PRIMARY KEY, name STRING)')
|
|
68
|
+
|
|
69
|
+
with CommitDBLocal('/path/to/data') as db: # File-based (persistent)
|
|
70
|
+
db.execute('CREATE DATABASE mydb')
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Ibis Mode (pandas DataFrame support)
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
pip install commitdb[ibis]
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
import ibis
|
|
81
|
+
|
|
82
|
+
con = ibis.commitdb.connect('localhost', 3306, database='mydb')
|
|
83
|
+
|
|
84
|
+
# Or use URL-based connection:
|
|
85
|
+
con = ibis.connect('commitdb://localhost:3306/mydb')
|
|
86
|
+
|
|
87
|
+
# Query with Ibis expressions
|
|
88
|
+
users = con.table('users')
|
|
89
|
+
result = users.filter(users.age > 30).select('name', 'city').execute() # → pandas DataFrame
|
|
90
|
+
print(result)
|
|
91
|
+
|
|
92
|
+
# Insert from DataFrame
|
|
93
|
+
import pandas as pd
|
|
94
|
+
df = pd.DataFrame({'id': [1, 2], 'name': ['Alice', 'Bob']})
|
|
95
|
+
con.insert('users', df)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## API Reference
|
|
101
|
+
|
|
102
|
+
### CommitDB (Remote)
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
CommitDB(host='localhost', port=3306, use_ssl=False, ssl_verify=True,
|
|
106
|
+
ssl_ca_cert=None, jwt_token=None)
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
| Method | Description |
|
|
110
|
+
|--------|-------------|
|
|
111
|
+
| `connect(timeout=10.0)` | Connect to server |
|
|
112
|
+
| `close()` | Close connection |
|
|
113
|
+
| `execute(sql)` | Execute SQL (INSERT, UPDATE, CREATE, etc.) |
|
|
114
|
+
| `query(sql)` | Execute SELECT, returns QueryResult |
|
|
115
|
+
| `authenticate_jwt(token)` | Authenticate with JWT |
|
|
116
|
+
|
|
117
|
+
### CommitDBLocal (Embedded)
|
|
118
|
+
|
|
119
|
+
```python
|
|
120
|
+
CommitDBLocal(path=None, lib_path=None)
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
- `path` - Directory for persistence (`None` = in-memory)
|
|
124
|
+
- `lib_path` - Path to `libcommitdb` shared library
|
|
125
|
+
|
|
126
|
+
| Method | Description |
|
|
127
|
+
|--------|-------------|
|
|
128
|
+
| `open()` / `close()` | Open/close database |
|
|
129
|
+
| `execute(sql)` | Execute SQL |
|
|
130
|
+
| `query(sql)` | Execute SELECT |
|
|
131
|
+
|
|
132
|
+
### QueryResult
|
|
133
|
+
|
|
134
|
+
```python
|
|
135
|
+
result = db.query('SELECT * FROM mydb.users')
|
|
136
|
+
result.columns # ['id', 'name']
|
|
137
|
+
len(result) # Row count
|
|
138
|
+
result[0] # {'id': '1', 'name': 'Alice'}
|
|
139
|
+
|
|
140
|
+
for row in result:
|
|
141
|
+
print(row)
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Error Handling
|
|
145
|
+
|
|
146
|
+
```python
|
|
147
|
+
from commitdb import CommitDB, CommitDBError
|
|
148
|
+
|
|
149
|
+
try:
|
|
150
|
+
with CommitDB('localhost', 3306) as db:
|
|
151
|
+
db.execute('SELECT * FROM nonexistent.table')
|
|
152
|
+
except CommitDBError as e:
|
|
153
|
+
print(f"Database error: {e}")
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Security
|
|
159
|
+
|
|
160
|
+
### SSL/TLS Encryption
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
# Production (with certificate verification)
|
|
164
|
+
db = CommitDB('localhost', 3306, use_ssl=True, ssl_ca_cert='cert.pem')
|
|
165
|
+
|
|
166
|
+
# Development (skip verification)
|
|
167
|
+
db = CommitDB('localhost', 3306, use_ssl=True, ssl_verify=False)
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### JWT Authentication
|
|
171
|
+
|
|
172
|
+
```python
|
|
173
|
+
# Auto-authenticate on connect
|
|
174
|
+
db = CommitDB('localhost', 3306, jwt_token='eyJhbG...')
|
|
175
|
+
db.connect()
|
|
176
|
+
print(f"Authenticated as: {db.identity}")
|
|
177
|
+
|
|
178
|
+
# Or authenticate after connect
|
|
179
|
+
db.connect()
|
|
180
|
+
db.authenticate_jwt('eyJhbG...')
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## Version Control
|
|
186
|
+
|
|
187
|
+
### Branching & Merging
|
|
188
|
+
|
|
189
|
+
```python
|
|
190
|
+
with CommitDBLocal() as db:
|
|
191
|
+
db.execute('CREATE DATABASE mydb')
|
|
192
|
+
db.execute('CREATE TABLE mydb.users (id INT, name STRING)')
|
|
193
|
+
db.execute("INSERT INTO mydb.users VALUES (1, 'Alice')")
|
|
194
|
+
|
|
195
|
+
# Create and switch to branch
|
|
196
|
+
db.execute('CREATE BRANCH feature')
|
|
197
|
+
db.execute('CHECKOUT feature')
|
|
198
|
+
|
|
199
|
+
# Make changes (isolated to this branch)
|
|
200
|
+
db.execute("INSERT INTO mydb.users VALUES (2, 'Bob')")
|
|
201
|
+
|
|
202
|
+
# Switch back and merge
|
|
203
|
+
db.execute('CHECKOUT master')
|
|
204
|
+
db.execute('MERGE feature')
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
**Branch Commands:**
|
|
208
|
+
|
|
209
|
+
| Command | Description |
|
|
210
|
+
|---------|-------------|
|
|
211
|
+
| `CREATE BRANCH name` | Create new branch |
|
|
212
|
+
| `CHECKOUT name` | Switch to branch |
|
|
213
|
+
| `MERGE name` | Merge branch (auto-resolve) |
|
|
214
|
+
| `MERGE name WITH MANUAL RESOLUTION` | Merge with manual conflict resolution |
|
|
215
|
+
| `SHOW BRANCHES` | List branches |
|
|
216
|
+
| `SHOW MERGE CONFLICTS` | View pending conflicts |
|
|
217
|
+
| `RESOLVE CONFLICT path USING HEAD\|SOURCE` | Resolve conflict |
|
|
218
|
+
| `COMMIT MERGE` / `ABORT MERGE` | Finalize or cancel merge |
|
|
219
|
+
|
|
220
|
+
### Remote Sync (Git)
|
|
221
|
+
|
|
222
|
+
```python
|
|
223
|
+
# Add remote
|
|
224
|
+
db.execute("CREATE REMOTE origin 'https://github.com/user/repo.git'")
|
|
225
|
+
|
|
226
|
+
# Push/Pull with authentication
|
|
227
|
+
db.execute("PUSH WITH TOKEN 'ghp_xxxxxxxxxxxx'")
|
|
228
|
+
db.execute("PUSH WITH SSH KEY '/path/to/id_rsa'")
|
|
229
|
+
db.execute("PULL FROM origin")
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## Bulk Import/Export
|
|
235
|
+
|
|
236
|
+
### Local Files
|
|
237
|
+
|
|
238
|
+
```python
|
|
239
|
+
# Export to CSV
|
|
240
|
+
db.execute("COPY INTO '/path/to/users.csv' FROM mydb.users WITH (HEADER = TRUE)")
|
|
241
|
+
|
|
242
|
+
# Import from CSV
|
|
243
|
+
db.execute("COPY INTO mydb.users FROM '/path/to/users.csv' WITH (HEADER = TRUE)")
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### S3 & HTTPS
|
|
247
|
+
|
|
248
|
+
```python
|
|
249
|
+
# Import from HTTPS
|
|
250
|
+
db.execute("COPY INTO mydb.users FROM 'https://example.com/data.csv'")
|
|
251
|
+
|
|
252
|
+
# Import from S3 (uses AWS env vars)
|
|
253
|
+
db.execute("COPY INTO mydb.users FROM 's3://bucket/users.csv'")
|
|
254
|
+
|
|
255
|
+
# Import from S3 with explicit credentials
|
|
256
|
+
db.execute("""
|
|
257
|
+
COPY INTO mydb.users FROM 's3://bucket/users.csv' WITH (
|
|
258
|
+
AWS_KEY = 'AKIAIOSFODNN7EXAMPLE',
|
|
259
|
+
AWS_SECRET = 'your-secret-key',
|
|
260
|
+
AWS_REGION = 'us-east-1'
|
|
261
|
+
)
|
|
262
|
+
""")
|
|
263
|
+
|
|
264
|
+
# Export to S3
|
|
265
|
+
db.execute("COPY INTO 's3://bucket/export.csv' FROM mydb.users WITH (HEADER = TRUE)")
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
## Building the Shared Library
|
|
271
|
+
|
|
272
|
+
For embedded mode, if the library isn't bundled:
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
# From CommitDB root
|
|
276
|
+
make lib # Creates lib/libcommitdb.dylib (macOS) or .so (Linux)
|
|
277
|
+
```
|
commitdb-2.2.1/README.md
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
# CommitDB Python Driver
|
|
2
|
+
|
|
3
|
+
[](https://badge.fury.io/py/commitdb)
|
|
4
|
+
[](https://www.python.org/downloads/)
|
|
5
|
+
|
|
6
|
+
Python client for CommitDB - a Git-backed SQL database engine.
|
|
7
|
+
|
|
8
|
+
**[📚 Full Documentation](https://nickyhof.github.io/CommitDB/python-driver/)**
|
|
9
|
+
|
|
10
|
+
> ⚠️ **Experimental Project** - This is a hobby project and should not be used in any production environment.
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
pip install commitdb
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Quick Start
|
|
19
|
+
|
|
20
|
+
### Remote Mode (connect to server)
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
from commitdb import CommitDB
|
|
24
|
+
|
|
25
|
+
with CommitDB('localhost', 3306) as db:
|
|
26
|
+
db.execute('CREATE DATABASE mydb')
|
|
27
|
+
db.execute('CREATE TABLE mydb.users (id INT PRIMARY KEY, name STRING)')
|
|
28
|
+
db.execute("INSERT INTO mydb.users VALUES (1, 'Alice')")
|
|
29
|
+
|
|
30
|
+
result = db.query('SELECT * FROM mydb.users')
|
|
31
|
+
for row in result:
|
|
32
|
+
print(f"{row['id']}: {row['name']}")
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Embedded Mode (no server required)
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
from commitdb import CommitDBLocal
|
|
39
|
+
|
|
40
|
+
with CommitDBLocal() as db: # In-memory
|
|
41
|
+
db.execute('CREATE DATABASE mydb')
|
|
42
|
+
db.execute('CREATE TABLE mydb.users (id INT PRIMARY KEY, name STRING)')
|
|
43
|
+
|
|
44
|
+
with CommitDBLocal('/path/to/data') as db: # File-based (persistent)
|
|
45
|
+
db.execute('CREATE DATABASE mydb')
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Ibis Mode (pandas DataFrame support)
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
pip install commitdb[ibis]
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
import ibis
|
|
56
|
+
|
|
57
|
+
con = ibis.commitdb.connect('localhost', 3306, database='mydb')
|
|
58
|
+
|
|
59
|
+
# Or use URL-based connection:
|
|
60
|
+
con = ibis.connect('commitdb://localhost:3306/mydb')
|
|
61
|
+
|
|
62
|
+
# Query with Ibis expressions
|
|
63
|
+
users = con.table('users')
|
|
64
|
+
result = users.filter(users.age > 30).select('name', 'city').execute() # → pandas DataFrame
|
|
65
|
+
print(result)
|
|
66
|
+
|
|
67
|
+
# Insert from DataFrame
|
|
68
|
+
import pandas as pd
|
|
69
|
+
df = pd.DataFrame({'id': [1, 2], 'name': ['Alice', 'Bob']})
|
|
70
|
+
con.insert('users', df)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## API Reference
|
|
76
|
+
|
|
77
|
+
### CommitDB (Remote)
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
CommitDB(host='localhost', port=3306, use_ssl=False, ssl_verify=True,
|
|
81
|
+
ssl_ca_cert=None, jwt_token=None)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
| Method | Description |
|
|
85
|
+
|--------|-------------|
|
|
86
|
+
| `connect(timeout=10.0)` | Connect to server |
|
|
87
|
+
| `close()` | Close connection |
|
|
88
|
+
| `execute(sql)` | Execute SQL (INSERT, UPDATE, CREATE, etc.) |
|
|
89
|
+
| `query(sql)` | Execute SELECT, returns QueryResult |
|
|
90
|
+
| `authenticate_jwt(token)` | Authenticate with JWT |
|
|
91
|
+
|
|
92
|
+
### CommitDBLocal (Embedded)
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
CommitDBLocal(path=None, lib_path=None)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
- `path` - Directory for persistence (`None` = in-memory)
|
|
99
|
+
- `lib_path` - Path to `libcommitdb` shared library
|
|
100
|
+
|
|
101
|
+
| Method | Description |
|
|
102
|
+
|--------|-------------|
|
|
103
|
+
| `open()` / `close()` | Open/close database |
|
|
104
|
+
| `execute(sql)` | Execute SQL |
|
|
105
|
+
| `query(sql)` | Execute SELECT |
|
|
106
|
+
|
|
107
|
+
### QueryResult
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
result = db.query('SELECT * FROM mydb.users')
|
|
111
|
+
result.columns # ['id', 'name']
|
|
112
|
+
len(result) # Row count
|
|
113
|
+
result[0] # {'id': '1', 'name': 'Alice'}
|
|
114
|
+
|
|
115
|
+
for row in result:
|
|
116
|
+
print(row)
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Error Handling
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
from commitdb import CommitDB, CommitDBError
|
|
123
|
+
|
|
124
|
+
try:
|
|
125
|
+
with CommitDB('localhost', 3306) as db:
|
|
126
|
+
db.execute('SELECT * FROM nonexistent.table')
|
|
127
|
+
except CommitDBError as e:
|
|
128
|
+
print(f"Database error: {e}")
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## Security
|
|
134
|
+
|
|
135
|
+
### SSL/TLS Encryption
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
# Production (with certificate verification)
|
|
139
|
+
db = CommitDB('localhost', 3306, use_ssl=True, ssl_ca_cert='cert.pem')
|
|
140
|
+
|
|
141
|
+
# Development (skip verification)
|
|
142
|
+
db = CommitDB('localhost', 3306, use_ssl=True, ssl_verify=False)
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### JWT Authentication
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
# Auto-authenticate on connect
|
|
149
|
+
db = CommitDB('localhost', 3306, jwt_token='eyJhbG...')
|
|
150
|
+
db.connect()
|
|
151
|
+
print(f"Authenticated as: {db.identity}")
|
|
152
|
+
|
|
153
|
+
# Or authenticate after connect
|
|
154
|
+
db.connect()
|
|
155
|
+
db.authenticate_jwt('eyJhbG...')
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## Version Control
|
|
161
|
+
|
|
162
|
+
### Branching & Merging
|
|
163
|
+
|
|
164
|
+
```python
|
|
165
|
+
with CommitDBLocal() as db:
|
|
166
|
+
db.execute('CREATE DATABASE mydb')
|
|
167
|
+
db.execute('CREATE TABLE mydb.users (id INT, name STRING)')
|
|
168
|
+
db.execute("INSERT INTO mydb.users VALUES (1, 'Alice')")
|
|
169
|
+
|
|
170
|
+
# Create and switch to branch
|
|
171
|
+
db.execute('CREATE BRANCH feature')
|
|
172
|
+
db.execute('CHECKOUT feature')
|
|
173
|
+
|
|
174
|
+
# Make changes (isolated to this branch)
|
|
175
|
+
db.execute("INSERT INTO mydb.users VALUES (2, 'Bob')")
|
|
176
|
+
|
|
177
|
+
# Switch back and merge
|
|
178
|
+
db.execute('CHECKOUT master')
|
|
179
|
+
db.execute('MERGE feature')
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
**Branch Commands:**
|
|
183
|
+
|
|
184
|
+
| Command | Description |
|
|
185
|
+
|---------|-------------|
|
|
186
|
+
| `CREATE BRANCH name` | Create new branch |
|
|
187
|
+
| `CHECKOUT name` | Switch to branch |
|
|
188
|
+
| `MERGE name` | Merge branch (auto-resolve) |
|
|
189
|
+
| `MERGE name WITH MANUAL RESOLUTION` | Merge with manual conflict resolution |
|
|
190
|
+
| `SHOW BRANCHES` | List branches |
|
|
191
|
+
| `SHOW MERGE CONFLICTS` | View pending conflicts |
|
|
192
|
+
| `RESOLVE CONFLICT path USING HEAD\|SOURCE` | Resolve conflict |
|
|
193
|
+
| `COMMIT MERGE` / `ABORT MERGE` | Finalize or cancel merge |
|
|
194
|
+
|
|
195
|
+
### Remote Sync (Git)
|
|
196
|
+
|
|
197
|
+
```python
|
|
198
|
+
# Add remote
|
|
199
|
+
db.execute("CREATE REMOTE origin 'https://github.com/user/repo.git'")
|
|
200
|
+
|
|
201
|
+
# Push/Pull with authentication
|
|
202
|
+
db.execute("PUSH WITH TOKEN 'ghp_xxxxxxxxxxxx'")
|
|
203
|
+
db.execute("PUSH WITH SSH KEY '/path/to/id_rsa'")
|
|
204
|
+
db.execute("PULL FROM origin")
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## Bulk Import/Export
|
|
210
|
+
|
|
211
|
+
### Local Files
|
|
212
|
+
|
|
213
|
+
```python
|
|
214
|
+
# Export to CSV
|
|
215
|
+
db.execute("COPY INTO '/path/to/users.csv' FROM mydb.users WITH (HEADER = TRUE)")
|
|
216
|
+
|
|
217
|
+
# Import from CSV
|
|
218
|
+
db.execute("COPY INTO mydb.users FROM '/path/to/users.csv' WITH (HEADER = TRUE)")
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### S3 & HTTPS
|
|
222
|
+
|
|
223
|
+
```python
|
|
224
|
+
# Import from HTTPS
|
|
225
|
+
db.execute("COPY INTO mydb.users FROM 'https://example.com/data.csv'")
|
|
226
|
+
|
|
227
|
+
# Import from S3 (uses AWS env vars)
|
|
228
|
+
db.execute("COPY INTO mydb.users FROM 's3://bucket/users.csv'")
|
|
229
|
+
|
|
230
|
+
# Import from S3 with explicit credentials
|
|
231
|
+
db.execute("""
|
|
232
|
+
COPY INTO mydb.users FROM 's3://bucket/users.csv' WITH (
|
|
233
|
+
AWS_KEY = 'AKIAIOSFODNN7EXAMPLE',
|
|
234
|
+
AWS_SECRET = 'your-secret-key',
|
|
235
|
+
AWS_REGION = 'us-east-1'
|
|
236
|
+
)
|
|
237
|
+
""")
|
|
238
|
+
|
|
239
|
+
# Export to S3
|
|
240
|
+
db.execute("COPY INTO 's3://bucket/export.csv' FROM mydb.users WITH (HEADER = TRUE)")
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
## Building the Shared Library
|
|
246
|
+
|
|
247
|
+
For embedded mode, if the library isn't bundled:
|
|
248
|
+
|
|
249
|
+
```bash
|
|
250
|
+
# From CommitDB root
|
|
251
|
+
make lib # Creates lib/libcommitdb.dylib (macOS) or .so (Linux)
|
|
252
|
+
```
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CommitDB Python Driver
|
|
3
|
+
|
|
4
|
+
A Python client for connecting to CommitDB SQL Server.
|
|
5
|
+
|
|
6
|
+
Usage:
|
|
7
|
+
from commitdb import CommitDB
|
|
8
|
+
|
|
9
|
+
db = CommitDB('localhost', 3306)
|
|
10
|
+
db.connect()
|
|
11
|
+
|
|
12
|
+
# Create database and table
|
|
13
|
+
db.execute('CREATE DATABASE mydb')
|
|
14
|
+
db.execute('CREATE TABLE mydb.users (id INT PRIMARY KEY, name STRING)')
|
|
15
|
+
|
|
16
|
+
# Insert data
|
|
17
|
+
db.execute("INSERT INTO mydb.users (id, name) VALUES (1, 'Alice')")
|
|
18
|
+
|
|
19
|
+
# Query data
|
|
20
|
+
result = db.query('SELECT * FROM mydb.users')
|
|
21
|
+
for row in result:
|
|
22
|
+
print(row)
|
|
23
|
+
|
|
24
|
+
db.close()
|
|
25
|
+
|
|
26
|
+
Embedded mode (requires libcommitdb):
|
|
27
|
+
from commitdb import CommitDBLocal
|
|
28
|
+
|
|
29
|
+
with CommitDBLocal('/path/to/data') as db:
|
|
30
|
+
db.execute('CREATE DATABASE mydb')
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
from importlib.metadata import version, PackageNotFoundError
|
|
34
|
+
|
|
35
|
+
from .client import CommitDB, CommitDBLocal, QueryResult, CommitResult, CommitDBError
|
|
36
|
+
|
|
37
|
+
try:
|
|
38
|
+
__version__ = version("commitdb")
|
|
39
|
+
except PackageNotFoundError:
|
|
40
|
+
__version__ = "0.0.0" # Fallback for development/editable installs
|
|
41
|
+
|
|
42
|
+
__all__ = ['CommitDB', 'CommitDBLocal', 'QueryResult', 'CommitResult', 'CommitDBError', '__version__']
|
|
43
|
+
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Python ctypes bindings for libcommitdb shared library.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import ctypes
|
|
6
|
+
import json
|
|
7
|
+
import os
|
|
8
|
+
import platform
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import Optional
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _find_library() -> Optional[str]:
|
|
14
|
+
"""Find the libcommitdb shared library."""
|
|
15
|
+
system = platform.system()
|
|
16
|
+
|
|
17
|
+
if system == 'Darwin':
|
|
18
|
+
lib_names = ['libcommitdb.dylib', 'libcommitdb-darwin-arm64.dylib', 'libcommitdb-darwin-amd64.dylib']
|
|
19
|
+
elif system == 'Linux':
|
|
20
|
+
lib_names = ['libcommitdb.so', 'libcommitdb-linux-amd64.so', 'libcommitdb-linux-arm64.so']
|
|
21
|
+
elif system == 'Windows':
|
|
22
|
+
lib_names = ['libcommitdb.dll']
|
|
23
|
+
else:
|
|
24
|
+
lib_names = ['libcommitdb.so', 'libcommitdb.dylib']
|
|
25
|
+
|
|
26
|
+
# Search paths
|
|
27
|
+
search_paths = [
|
|
28
|
+
Path(__file__).parent / 'lib', # Package lib directory (for pip installed)
|
|
29
|
+
Path(__file__).parent, # Same directory as this file
|
|
30
|
+
Path(__file__).parent.parent / 'lib', # drivers/python/lib
|
|
31
|
+
Path(__file__).parent.parent.parent.parent / 'lib', # CommitDB/lib
|
|
32
|
+
Path.cwd() / 'lib', # ./lib
|
|
33
|
+
Path.cwd(), # Current directory
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
for path in search_paths:
|
|
37
|
+
for lib_name in lib_names:
|
|
38
|
+
lib_path = path / lib_name
|
|
39
|
+
if lib_path.exists():
|
|
40
|
+
return str(lib_path)
|
|
41
|
+
|
|
42
|
+
return None
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class CommitDBBinding:
|
|
46
|
+
"""Low-level ctypes bindings for libcommitdb."""
|
|
47
|
+
|
|
48
|
+
_lib: Optional[ctypes.CDLL] = None
|
|
49
|
+
_lib_path: Optional[str] = None
|
|
50
|
+
|
|
51
|
+
@classmethod
|
|
52
|
+
def load(cls, lib_path: Optional[str] = None) -> 'CommitDBBinding':
|
|
53
|
+
"""Load the shared library."""
|
|
54
|
+
if lib_path is None:
|
|
55
|
+
lib_path = _find_library()
|
|
56
|
+
|
|
57
|
+
if lib_path is None:
|
|
58
|
+
raise RuntimeError(
|
|
59
|
+
"Could not find libcommitdb shared library. "
|
|
60
|
+
"Build it with: make lib"
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
cls._lib_path = lib_path
|
|
64
|
+
cls._lib = ctypes.CDLL(lib_path)
|
|
65
|
+
|
|
66
|
+
# Define function signatures
|
|
67
|
+
cls._lib.commitdb_open_memory.argtypes = []
|
|
68
|
+
cls._lib.commitdb_open_memory.restype = ctypes.c_int
|
|
69
|
+
|
|
70
|
+
cls._lib.commitdb_open_file.argtypes = [ctypes.c_char_p]
|
|
71
|
+
cls._lib.commitdb_open_file.restype = ctypes.c_int
|
|
72
|
+
|
|
73
|
+
cls._lib.commitdb_close.argtypes = [ctypes.c_int]
|
|
74
|
+
cls._lib.commitdb_close.restype = None
|
|
75
|
+
|
|
76
|
+
# Use c_void_p for the result pointer to avoid automatic conversion
|
|
77
|
+
cls._lib.commitdb_execute.argtypes = [ctypes.c_int, ctypes.c_char_p]
|
|
78
|
+
cls._lib.commitdb_execute.restype = ctypes.c_void_p
|
|
79
|
+
|
|
80
|
+
cls._lib.commitdb_free.argtypes = [ctypes.c_void_p]
|
|
81
|
+
cls._lib.commitdb_free.restype = None
|
|
82
|
+
|
|
83
|
+
return cls()
|
|
84
|
+
|
|
85
|
+
@classmethod
|
|
86
|
+
def is_loaded(cls) -> bool:
|
|
87
|
+
"""Check if the library is loaded."""
|
|
88
|
+
return cls._lib is not None
|
|
89
|
+
|
|
90
|
+
@classmethod
|
|
91
|
+
def open_memory(cls) -> int:
|
|
92
|
+
"""Open an in-memory database."""
|
|
93
|
+
if not cls.is_loaded():
|
|
94
|
+
cls.load()
|
|
95
|
+
handle = cls._lib.commitdb_open_memory()
|
|
96
|
+
if handle < 0:
|
|
97
|
+
raise RuntimeError("Failed to open in-memory database")
|
|
98
|
+
return handle
|
|
99
|
+
|
|
100
|
+
@classmethod
|
|
101
|
+
def open_file(cls, path: str) -> int:
|
|
102
|
+
"""Open a file-based database."""
|
|
103
|
+
if not cls.is_loaded():
|
|
104
|
+
cls.load()
|
|
105
|
+
handle = cls._lib.commitdb_open_file(path.encode('utf-8'))
|
|
106
|
+
if handle < 0:
|
|
107
|
+
raise RuntimeError(f"Failed to open database at {path}")
|
|
108
|
+
return handle
|
|
109
|
+
|
|
110
|
+
@classmethod
|
|
111
|
+
def close(cls, handle: int) -> None:
|
|
112
|
+
"""Close a database handle."""
|
|
113
|
+
if cls.is_loaded():
|
|
114
|
+
cls._lib.commitdb_close(handle)
|
|
115
|
+
|
|
116
|
+
@classmethod
|
|
117
|
+
def execute(cls, handle: int, query: str) -> dict:
|
|
118
|
+
"""Execute a query and return the JSON response."""
|
|
119
|
+
if not cls.is_loaded():
|
|
120
|
+
raise RuntimeError("Library not loaded")
|
|
121
|
+
|
|
122
|
+
result_ptr = cls._lib.commitdb_execute(handle, query.encode('utf-8'))
|
|
123
|
+
if result_ptr is None or result_ptr == 0:
|
|
124
|
+
raise RuntimeError("Query execution failed")
|
|
125
|
+
|
|
126
|
+
try:
|
|
127
|
+
# Cast void pointer to char pointer and read the string
|
|
128
|
+
result_str = ctypes.cast(result_ptr, ctypes.c_char_p).value
|
|
129
|
+
if result_str is None:
|
|
130
|
+
raise RuntimeError("Empty response from query")
|
|
131
|
+
result_json = result_str.decode('utf-8')
|
|
132
|
+
return json.loads(result_json)
|
|
133
|
+
finally:
|
|
134
|
+
# Free the allocated memory using the void pointer
|
|
135
|
+
cls._lib.commitdb_free(result_ptr)
|