commitdb 1.1.2__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-1.1.2/PKG-INFO +106 -0
- commitdb-1.1.2/README.md +84 -0
- commitdb-1.1.2/commitdb/__init__.py +30 -0
- commitdb-1.1.2/commitdb/client.py +244 -0
- commitdb-1.1.2/commitdb.egg-info/PKG-INFO +106 -0
- commitdb-1.1.2/commitdb.egg-info/SOURCES.txt +11 -0
- commitdb-1.1.2/commitdb.egg-info/dependency_links.txt +1 -0
- commitdb-1.1.2/commitdb.egg-info/requires.txt +3 -0
- commitdb-1.1.2/commitdb.egg-info/top_level.txt +3 -0
- commitdb-1.1.2/pyproject.toml +35 -0
- commitdb-1.1.2/setup.cfg +4 -0
- commitdb-1.1.2/tests/__init__.py +0 -0
- commitdb-1.1.2/tests/test_client.py +113 -0
commitdb-1.1.2/PKG-INFO
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: commitdb
|
|
3
|
+
Version: 1.1.2
|
|
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
|
+
|
|
23
|
+
# CommitDB Python Driver
|
|
24
|
+
|
|
25
|
+
Python client for connecting to CommitDB SQL Server.
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pip install -e drivers/python
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Quick Start
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
from commitdb import CommitDB
|
|
37
|
+
|
|
38
|
+
# Connect to server
|
|
39
|
+
db = CommitDB('localhost', 3306)
|
|
40
|
+
db.connect()
|
|
41
|
+
|
|
42
|
+
# Or use context manager
|
|
43
|
+
with CommitDB('localhost', 3306) as db:
|
|
44
|
+
# Create database and table
|
|
45
|
+
db.execute('CREATE DATABASE mydb')
|
|
46
|
+
db.execute('CREATE TABLE mydb.users (id INT PRIMARY KEY, name STRING)')
|
|
47
|
+
|
|
48
|
+
# Insert data
|
|
49
|
+
db.execute("INSERT INTO mydb.users (id, name) VALUES (1, 'Alice')")
|
|
50
|
+
db.execute("INSERT INTO mydb.users (id, name) VALUES (2, 'Bob')")
|
|
51
|
+
|
|
52
|
+
# Query data
|
|
53
|
+
result = db.query('SELECT * FROM mydb.users')
|
|
54
|
+
print(f"Columns: {result.columns}")
|
|
55
|
+
print(f"Rows: {len(result)}")
|
|
56
|
+
|
|
57
|
+
# Iterate over rows as dictionaries
|
|
58
|
+
for row in result:
|
|
59
|
+
print(f" {row['id']}: {row['name']}")
|
|
60
|
+
|
|
61
|
+
# Use convenience methods
|
|
62
|
+
db.insert('mydb', 'users', ['id', 'name'], [3, 'Charlie'])
|
|
63
|
+
tables = db.show_tables('mydb')
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## API Reference
|
|
67
|
+
|
|
68
|
+
### CommitDB
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
CommitDB(host='localhost', port=3306)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**Methods:**
|
|
75
|
+
|
|
76
|
+
- `connect(timeout=10.0)` - Connect to server
|
|
77
|
+
- `close()` - Close connection
|
|
78
|
+
- `execute(sql)` - Execute any SQL query
|
|
79
|
+
- `query(sql)` - Execute SELECT query, returns QueryResult
|
|
80
|
+
- `create_database(name)` - Create a database
|
|
81
|
+
- `drop_database(name)` - Drop a database
|
|
82
|
+
- `create_table(database, table, columns)` - Create a table
|
|
83
|
+
- `insert(database, table, columns, values)` - Insert a row
|
|
84
|
+
- `show_databases()` - List databases
|
|
85
|
+
- `show_tables(database)` - List tables
|
|
86
|
+
|
|
87
|
+
### QueryResult
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
result = db.query('SELECT * FROM mydb.users')
|
|
91
|
+
result.columns # ['id', 'name']
|
|
92
|
+
result.data # [['1', 'Alice'], ['2', 'Bob']]
|
|
93
|
+
len(result) # 2
|
|
94
|
+
result[0] # {'id': '1', 'name': 'Alice'}
|
|
95
|
+
for row in result:
|
|
96
|
+
print(row) # {'id': '1', 'name': 'Alice'}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### CommitResult
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
result = db.execute('INSERT INTO mydb.users ...')
|
|
103
|
+
result.records_written # 1
|
|
104
|
+
result.affected_rows # 1
|
|
105
|
+
result.time_ms # 1.5
|
|
106
|
+
```
|
commitdb-1.1.2/README.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# CommitDB Python Driver
|
|
2
|
+
|
|
3
|
+
Python client for connecting to CommitDB SQL Server.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install -e drivers/python
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
from commitdb import CommitDB
|
|
15
|
+
|
|
16
|
+
# Connect to server
|
|
17
|
+
db = CommitDB('localhost', 3306)
|
|
18
|
+
db.connect()
|
|
19
|
+
|
|
20
|
+
# Or use context manager
|
|
21
|
+
with CommitDB('localhost', 3306) as db:
|
|
22
|
+
# Create database and table
|
|
23
|
+
db.execute('CREATE DATABASE mydb')
|
|
24
|
+
db.execute('CREATE TABLE mydb.users (id INT PRIMARY KEY, name STRING)')
|
|
25
|
+
|
|
26
|
+
# Insert data
|
|
27
|
+
db.execute("INSERT INTO mydb.users (id, name) VALUES (1, 'Alice')")
|
|
28
|
+
db.execute("INSERT INTO mydb.users (id, name) VALUES (2, 'Bob')")
|
|
29
|
+
|
|
30
|
+
# Query data
|
|
31
|
+
result = db.query('SELECT * FROM mydb.users')
|
|
32
|
+
print(f"Columns: {result.columns}")
|
|
33
|
+
print(f"Rows: {len(result)}")
|
|
34
|
+
|
|
35
|
+
# Iterate over rows as dictionaries
|
|
36
|
+
for row in result:
|
|
37
|
+
print(f" {row['id']}: {row['name']}")
|
|
38
|
+
|
|
39
|
+
# Use convenience methods
|
|
40
|
+
db.insert('mydb', 'users', ['id', 'name'], [3, 'Charlie'])
|
|
41
|
+
tables = db.show_tables('mydb')
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## API Reference
|
|
45
|
+
|
|
46
|
+
### CommitDB
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
CommitDB(host='localhost', port=3306)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**Methods:**
|
|
53
|
+
|
|
54
|
+
- `connect(timeout=10.0)` - Connect to server
|
|
55
|
+
- `close()` - Close connection
|
|
56
|
+
- `execute(sql)` - Execute any SQL query
|
|
57
|
+
- `query(sql)` - Execute SELECT query, returns QueryResult
|
|
58
|
+
- `create_database(name)` - Create a database
|
|
59
|
+
- `drop_database(name)` - Drop a database
|
|
60
|
+
- `create_table(database, table, columns)` - Create a table
|
|
61
|
+
- `insert(database, table, columns, values)` - Insert a row
|
|
62
|
+
- `show_databases()` - List databases
|
|
63
|
+
- `show_tables(database)` - List tables
|
|
64
|
+
|
|
65
|
+
### QueryResult
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
result = db.query('SELECT * FROM mydb.users')
|
|
69
|
+
result.columns # ['id', 'name']
|
|
70
|
+
result.data # [['1', 'Alice'], ['2', 'Bob']]
|
|
71
|
+
len(result) # 2
|
|
72
|
+
result[0] # {'id': '1', 'name': 'Alice'}
|
|
73
|
+
for row in result:
|
|
74
|
+
print(row) # {'id': '1', 'name': 'Alice'}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### CommitResult
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
result = db.execute('INSERT INTO mydb.users ...')
|
|
81
|
+
result.records_written # 1
|
|
82
|
+
result.affected_rows # 1
|
|
83
|
+
result.time_ms # 1.5
|
|
84
|
+
```
|
|
@@ -0,0 +1,30 @@
|
|
|
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
|
+
|
|
27
|
+
from .client import CommitDB, QueryResult, CommitResult, CommitDBError
|
|
28
|
+
|
|
29
|
+
__version__ = '0.1.0'
|
|
30
|
+
__all__ = ['CommitDB', 'QueryResult', 'CommitResult', 'CommitDBError']
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CommitDB Client - Python driver for CommitDB SQL Server.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import socket
|
|
7
|
+
from dataclasses import dataclass, field
|
|
8
|
+
from typing import Iterator, Optional
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class CommitDBError(Exception):
|
|
12
|
+
"""Exception raised for CommitDB errors."""
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass
|
|
17
|
+
class QueryResult:
|
|
18
|
+
"""Result from a SELECT query."""
|
|
19
|
+
columns: list[str]
|
|
20
|
+
data: list[list[str]]
|
|
21
|
+
records_read: int
|
|
22
|
+
time_ms: float
|
|
23
|
+
|
|
24
|
+
def __iter__(self) -> Iterator[dict[str, str]]:
|
|
25
|
+
"""Iterate over rows as dictionaries."""
|
|
26
|
+
for row in self.data:
|
|
27
|
+
yield dict(zip(self.columns, row))
|
|
28
|
+
|
|
29
|
+
def __len__(self) -> int:
|
|
30
|
+
return len(self.data)
|
|
31
|
+
|
|
32
|
+
def __getitem__(self, index: int) -> dict[str, str]:
|
|
33
|
+
return dict(zip(self.columns, self.data[index]))
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@dataclass
|
|
37
|
+
class CommitResult:
|
|
38
|
+
"""Result from a mutation operation (INSERT, UPDATE, DELETE, CREATE, DROP)."""
|
|
39
|
+
databases_created: int = 0
|
|
40
|
+
databases_deleted: int = 0
|
|
41
|
+
tables_created: int = 0
|
|
42
|
+
tables_deleted: int = 0
|
|
43
|
+
records_written: int = 0
|
|
44
|
+
records_deleted: int = 0
|
|
45
|
+
time_ms: float = 0.0
|
|
46
|
+
|
|
47
|
+
@property
|
|
48
|
+
def affected_rows(self) -> int:
|
|
49
|
+
"""Total number of affected rows/objects."""
|
|
50
|
+
return (self.databases_created + self.databases_deleted +
|
|
51
|
+
self.tables_created + self.tables_deleted +
|
|
52
|
+
self.records_written + self.records_deleted)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class CommitDB:
|
|
56
|
+
"""
|
|
57
|
+
CommitDB Python client.
|
|
58
|
+
|
|
59
|
+
Example:
|
|
60
|
+
db = CommitDB('localhost', 3306)
|
|
61
|
+
db.connect()
|
|
62
|
+
result = db.query('SELECT * FROM mydb.users')
|
|
63
|
+
db.close()
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
def __init__(self, host: str = 'localhost', port: int = 3306):
|
|
67
|
+
"""
|
|
68
|
+
Initialize CommitDB client.
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
host: Server hostname
|
|
72
|
+
port: Server port (default 3306)
|
|
73
|
+
"""
|
|
74
|
+
self.host = host
|
|
75
|
+
self.port = port
|
|
76
|
+
self._socket: Optional[socket.socket] = None
|
|
77
|
+
self._buffer = b''
|
|
78
|
+
|
|
79
|
+
def connect(self, timeout: float = 10.0) -> 'CommitDB':
|
|
80
|
+
"""
|
|
81
|
+
Connect to the CommitDB server.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
timeout: Connection timeout in seconds
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
self for method chaining
|
|
88
|
+
"""
|
|
89
|
+
self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
90
|
+
self._socket.settimeout(timeout)
|
|
91
|
+
self._socket.connect((self.host, self.port))
|
|
92
|
+
return self
|
|
93
|
+
|
|
94
|
+
def close(self) -> None:
|
|
95
|
+
"""Close the connection."""
|
|
96
|
+
if self._socket:
|
|
97
|
+
try:
|
|
98
|
+
self._socket.send(b'quit\n')
|
|
99
|
+
except Exception:
|
|
100
|
+
pass
|
|
101
|
+
self._socket.close()
|
|
102
|
+
self._socket = None
|
|
103
|
+
|
|
104
|
+
def __enter__(self) -> 'CommitDB':
|
|
105
|
+
return self.connect()
|
|
106
|
+
|
|
107
|
+
def __exit__(self, exc_type, exc_val, exc_tb) -> None:
|
|
108
|
+
self.close()
|
|
109
|
+
|
|
110
|
+
def _send(self, query: str) -> dict:
|
|
111
|
+
"""Send a query and receive the response."""
|
|
112
|
+
if not self._socket:
|
|
113
|
+
raise CommitDBError("Not connected. Call connect() first.")
|
|
114
|
+
|
|
115
|
+
# Send query with newline
|
|
116
|
+
self._socket.send((query + '\n').encode('utf-8'))
|
|
117
|
+
|
|
118
|
+
# Read response until newline
|
|
119
|
+
while b'\n' not in self._buffer:
|
|
120
|
+
chunk = self._socket.recv(4096)
|
|
121
|
+
if not chunk:
|
|
122
|
+
raise CommitDBError("Connection closed by server")
|
|
123
|
+
self._buffer += chunk
|
|
124
|
+
|
|
125
|
+
# Split at first newline
|
|
126
|
+
line, self._buffer = self._buffer.split(b'\n', 1)
|
|
127
|
+
|
|
128
|
+
# Parse JSON response
|
|
129
|
+
try:
|
|
130
|
+
return json.loads(line.decode('utf-8'))
|
|
131
|
+
except json.JSONDecodeError as e:
|
|
132
|
+
raise CommitDBError(f"Invalid response from server: {e}")
|
|
133
|
+
|
|
134
|
+
def execute(self, query: str) -> CommitResult | QueryResult:
|
|
135
|
+
"""
|
|
136
|
+
Execute a SQL query.
|
|
137
|
+
|
|
138
|
+
Args:
|
|
139
|
+
query: SQL query to execute
|
|
140
|
+
|
|
141
|
+
Returns:
|
|
142
|
+
QueryResult for SELECT queries, CommitResult for mutations
|
|
143
|
+
"""
|
|
144
|
+
response = self._send(query)
|
|
145
|
+
|
|
146
|
+
if not response.get('success'):
|
|
147
|
+
raise CommitDBError(response.get('error', 'Unknown error'))
|
|
148
|
+
|
|
149
|
+
result_type = response.get('type')
|
|
150
|
+
result_data = response.get('result', {})
|
|
151
|
+
|
|
152
|
+
if result_type == 'query':
|
|
153
|
+
return QueryResult(
|
|
154
|
+
columns=result_data.get('columns', []),
|
|
155
|
+
data=result_data.get('data', []),
|
|
156
|
+
records_read=result_data.get('records_read', 0),
|
|
157
|
+
time_ms=result_data.get('time_ms', 0.0)
|
|
158
|
+
)
|
|
159
|
+
elif result_type == 'commit':
|
|
160
|
+
return CommitResult(
|
|
161
|
+
databases_created=result_data.get('databases_created', 0),
|
|
162
|
+
databases_deleted=result_data.get('databases_deleted', 0),
|
|
163
|
+
tables_created=result_data.get('tables_created', 0),
|
|
164
|
+
tables_deleted=result_data.get('tables_deleted', 0),
|
|
165
|
+
records_written=result_data.get('records_written', 0),
|
|
166
|
+
records_deleted=result_data.get('records_deleted', 0),
|
|
167
|
+
time_ms=result_data.get('time_ms', 0.0)
|
|
168
|
+
)
|
|
169
|
+
else:
|
|
170
|
+
# Unknown type, return empty commit result
|
|
171
|
+
return CommitResult()
|
|
172
|
+
|
|
173
|
+
def query(self, sql: str) -> QueryResult:
|
|
174
|
+
"""
|
|
175
|
+
Execute a SELECT query and return results.
|
|
176
|
+
|
|
177
|
+
Args:
|
|
178
|
+
sql: SELECT query
|
|
179
|
+
|
|
180
|
+
Returns:
|
|
181
|
+
QueryResult with columns and data
|
|
182
|
+
"""
|
|
183
|
+
result = self.execute(sql)
|
|
184
|
+
if not isinstance(result, QueryResult):
|
|
185
|
+
raise CommitDBError("Expected query result, got commit result")
|
|
186
|
+
return result
|
|
187
|
+
|
|
188
|
+
def create_database(self, name: str) -> CommitResult:
|
|
189
|
+
"""Create a database."""
|
|
190
|
+
result = self.execute(f'CREATE DATABASE {name}')
|
|
191
|
+
if not isinstance(result, CommitResult):
|
|
192
|
+
raise CommitDBError("Expected commit result")
|
|
193
|
+
return result
|
|
194
|
+
|
|
195
|
+
def drop_database(self, name: str) -> CommitResult:
|
|
196
|
+
"""Drop a database."""
|
|
197
|
+
result = self.execute(f'DROP DATABASE {name}')
|
|
198
|
+
if not isinstance(result, CommitResult):
|
|
199
|
+
raise CommitDBError("Expected commit result")
|
|
200
|
+
return result
|
|
201
|
+
|
|
202
|
+
def create_table(self, database: str, table: str, columns: str) -> CommitResult:
|
|
203
|
+
"""
|
|
204
|
+
Create a table.
|
|
205
|
+
|
|
206
|
+
Args:
|
|
207
|
+
database: Database name
|
|
208
|
+
table: Table name
|
|
209
|
+
columns: Column definitions, e.g. "id INT PRIMARY KEY, name STRING"
|
|
210
|
+
"""
|
|
211
|
+
result = self.execute(f'CREATE TABLE {database}.{table} ({columns})')
|
|
212
|
+
if not isinstance(result, CommitResult):
|
|
213
|
+
raise CommitDBError("Expected commit result")
|
|
214
|
+
return result
|
|
215
|
+
|
|
216
|
+
def insert(self, database: str, table: str, columns: list[str], values: list) -> CommitResult:
|
|
217
|
+
"""
|
|
218
|
+
Insert a row.
|
|
219
|
+
|
|
220
|
+
Args:
|
|
221
|
+
database: Database name
|
|
222
|
+
table: Table name
|
|
223
|
+
columns: List of column names
|
|
224
|
+
values: List of values (strings will be quoted)
|
|
225
|
+
"""
|
|
226
|
+
cols = ', '.join(columns)
|
|
227
|
+
vals = ', '.join(
|
|
228
|
+
f"'{v}'" if isinstance(v, str) else str(v)
|
|
229
|
+
for v in values
|
|
230
|
+
)
|
|
231
|
+
result = self.execute(f'INSERT INTO {database}.{table} ({cols}) VALUES ({vals})')
|
|
232
|
+
if not isinstance(result, CommitResult):
|
|
233
|
+
raise CommitDBError("Expected commit result")
|
|
234
|
+
return result
|
|
235
|
+
|
|
236
|
+
def show_databases(self) -> list[str]:
|
|
237
|
+
"""List all databases."""
|
|
238
|
+
result = self.query('SHOW DATABASES')
|
|
239
|
+
return [row[0] for row in result.data] if result.data else []
|
|
240
|
+
|
|
241
|
+
def show_tables(self, database: str) -> list[str]:
|
|
242
|
+
"""List all tables in a database."""
|
|
243
|
+
result = self.query(f'SHOW TABLES IN {database}')
|
|
244
|
+
return [row[0] for row in result.data] if result.data else []
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: commitdb
|
|
3
|
+
Version: 1.1.2
|
|
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
|
+
|
|
23
|
+
# CommitDB Python Driver
|
|
24
|
+
|
|
25
|
+
Python client for connecting to CommitDB SQL Server.
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pip install -e drivers/python
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Quick Start
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
from commitdb import CommitDB
|
|
37
|
+
|
|
38
|
+
# Connect to server
|
|
39
|
+
db = CommitDB('localhost', 3306)
|
|
40
|
+
db.connect()
|
|
41
|
+
|
|
42
|
+
# Or use context manager
|
|
43
|
+
with CommitDB('localhost', 3306) as db:
|
|
44
|
+
# Create database and table
|
|
45
|
+
db.execute('CREATE DATABASE mydb')
|
|
46
|
+
db.execute('CREATE TABLE mydb.users (id INT PRIMARY KEY, name STRING)')
|
|
47
|
+
|
|
48
|
+
# Insert data
|
|
49
|
+
db.execute("INSERT INTO mydb.users (id, name) VALUES (1, 'Alice')")
|
|
50
|
+
db.execute("INSERT INTO mydb.users (id, name) VALUES (2, 'Bob')")
|
|
51
|
+
|
|
52
|
+
# Query data
|
|
53
|
+
result = db.query('SELECT * FROM mydb.users')
|
|
54
|
+
print(f"Columns: {result.columns}")
|
|
55
|
+
print(f"Rows: {len(result)}")
|
|
56
|
+
|
|
57
|
+
# Iterate over rows as dictionaries
|
|
58
|
+
for row in result:
|
|
59
|
+
print(f" {row['id']}: {row['name']}")
|
|
60
|
+
|
|
61
|
+
# Use convenience methods
|
|
62
|
+
db.insert('mydb', 'users', ['id', 'name'], [3, 'Charlie'])
|
|
63
|
+
tables = db.show_tables('mydb')
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## API Reference
|
|
67
|
+
|
|
68
|
+
### CommitDB
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
CommitDB(host='localhost', port=3306)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**Methods:**
|
|
75
|
+
|
|
76
|
+
- `connect(timeout=10.0)` - Connect to server
|
|
77
|
+
- `close()` - Close connection
|
|
78
|
+
- `execute(sql)` - Execute any SQL query
|
|
79
|
+
- `query(sql)` - Execute SELECT query, returns QueryResult
|
|
80
|
+
- `create_database(name)` - Create a database
|
|
81
|
+
- `drop_database(name)` - Drop a database
|
|
82
|
+
- `create_table(database, table, columns)` - Create a table
|
|
83
|
+
- `insert(database, table, columns, values)` - Insert a row
|
|
84
|
+
- `show_databases()` - List databases
|
|
85
|
+
- `show_tables(database)` - List tables
|
|
86
|
+
|
|
87
|
+
### QueryResult
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
result = db.query('SELECT * FROM mydb.users')
|
|
91
|
+
result.columns # ['id', 'name']
|
|
92
|
+
result.data # [['1', 'Alice'], ['2', 'Bob']]
|
|
93
|
+
len(result) # 2
|
|
94
|
+
result[0] # {'id': '1', 'name': 'Alice'}
|
|
95
|
+
for row in result:
|
|
96
|
+
print(row) # {'id': '1', 'name': 'Alice'}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### CommitResult
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
result = db.execute('INSERT INTO mydb.users ...')
|
|
103
|
+
result.records_written # 1
|
|
104
|
+
result.affected_rows # 1
|
|
105
|
+
result.time_ms # 1.5
|
|
106
|
+
```
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
commitdb/__init__.py
|
|
4
|
+
commitdb/client.py
|
|
5
|
+
commitdb.egg-info/PKG-INFO
|
|
6
|
+
commitdb.egg-info/SOURCES.txt
|
|
7
|
+
commitdb.egg-info/dependency_links.txt
|
|
8
|
+
commitdb.egg-info/requires.txt
|
|
9
|
+
commitdb.egg-info/top_level.txt
|
|
10
|
+
tests/__init__.py
|
|
11
|
+
tests/test_client.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "commitdb"
|
|
7
|
+
version = "1.1.2"
|
|
8
|
+
description = "Python driver for CommitDB SQL Server"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = {text = "Apache-2.0"}
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "CommitDB Contributors"}
|
|
14
|
+
]
|
|
15
|
+
keywords = ["database", "sql", "git", "commitdb"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 3 - Alpha",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"License :: OSI Approved :: Apache Software License",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3.10",
|
|
22
|
+
"Programming Language :: Python :: 3.11",
|
|
23
|
+
"Programming Language :: Python :: 3.12",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
[project.urls]
|
|
27
|
+
Homepage = "https://github.com/nickyhof/CommitDB"
|
|
28
|
+
Documentation = "https://github.com/nickyhof/CommitDB#readme"
|
|
29
|
+
Repository = "https://github.com/nickyhof/CommitDB"
|
|
30
|
+
|
|
31
|
+
[tool.setuptools.packages.find]
|
|
32
|
+
where = ["."]
|
|
33
|
+
|
|
34
|
+
[project.optional-dependencies]
|
|
35
|
+
dev = ["pytest>=7.0"]
|
commitdb-1.1.2/setup.cfg
ADDED
|
File without changes
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tests for CommitDB Python driver.
|
|
3
|
+
|
|
4
|
+
To run with a live server:
|
|
5
|
+
1. Start the server: go run ./cmd/server
|
|
6
|
+
2. Run tests: pytest drivers/python/tests/
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import pytest
|
|
10
|
+
from commitdb import CommitDB, QueryResult, CommitResult, CommitDBError
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class TestQueryResult:
|
|
14
|
+
"""Tests for QueryResult class."""
|
|
15
|
+
|
|
16
|
+
def test_iteration(self):
|
|
17
|
+
result = QueryResult(
|
|
18
|
+
columns=['id', 'name'],
|
|
19
|
+
data=[['1', 'Alice'], ['2', 'Bob']],
|
|
20
|
+
records_read=2,
|
|
21
|
+
time_ms=1.0
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
rows = list(result)
|
|
25
|
+
assert rows == [
|
|
26
|
+
{'id': '1', 'name': 'Alice'},
|
|
27
|
+
{'id': '2', 'name': 'Bob'}
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
def test_len(self):
|
|
31
|
+
result = QueryResult(
|
|
32
|
+
columns=['id'],
|
|
33
|
+
data=[['1'], ['2'], ['3']],
|
|
34
|
+
records_read=3,
|
|
35
|
+
time_ms=1.0
|
|
36
|
+
)
|
|
37
|
+
assert len(result) == 3
|
|
38
|
+
|
|
39
|
+
def test_getitem(self):
|
|
40
|
+
result = QueryResult(
|
|
41
|
+
columns=['id', 'name'],
|
|
42
|
+
data=[['1', 'Alice'], ['2', 'Bob']],
|
|
43
|
+
records_read=2,
|
|
44
|
+
time_ms=1.0
|
|
45
|
+
)
|
|
46
|
+
assert result[0] == {'id': '1', 'name': 'Alice'}
|
|
47
|
+
assert result[1] == {'id': '2', 'name': 'Bob'}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class TestCommitResult:
|
|
51
|
+
"""Tests for CommitResult class."""
|
|
52
|
+
|
|
53
|
+
def test_affected_rows(self):
|
|
54
|
+
result = CommitResult(
|
|
55
|
+
databases_created=1,
|
|
56
|
+
tables_created=2,
|
|
57
|
+
records_written=3
|
|
58
|
+
)
|
|
59
|
+
assert result.affected_rows == 6
|
|
60
|
+
|
|
61
|
+
def test_defaults(self):
|
|
62
|
+
result = CommitResult()
|
|
63
|
+
assert result.affected_rows == 0
|
|
64
|
+
assert result.time_ms == 0.0
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class TestCommitDBUnit:
|
|
68
|
+
"""Unit tests for CommitDB client (no server required)."""
|
|
69
|
+
|
|
70
|
+
def test_init(self):
|
|
71
|
+
db = CommitDB('localhost', 3306)
|
|
72
|
+
assert db.host == 'localhost'
|
|
73
|
+
assert db.port == 3306
|
|
74
|
+
|
|
75
|
+
def test_not_connected_error(self):
|
|
76
|
+
db = CommitDB('localhost', 3306)
|
|
77
|
+
with pytest.raises(CommitDBError, match="Not connected"):
|
|
78
|
+
db.execute("SELECT 1")
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
# Integration tests require a running server
|
|
82
|
+
# Uncomment and run with: pytest drivers/python/tests/ -v
|
|
83
|
+
|
|
84
|
+
# class TestCommitDBIntegration:
|
|
85
|
+
# """Integration tests (requires running server)."""
|
|
86
|
+
#
|
|
87
|
+
# @pytest.fixture
|
|
88
|
+
# def db(self):
|
|
89
|
+
# db = CommitDB('localhost', 3306)
|
|
90
|
+
# db.connect()
|
|
91
|
+
# yield db
|
|
92
|
+
# db.close()
|
|
93
|
+
#
|
|
94
|
+
# def test_create_database(self, db):
|
|
95
|
+
# result = db.execute('CREATE DATABASE pytest_test')
|
|
96
|
+
# assert isinstance(result, CommitResult)
|
|
97
|
+
# assert result.databases_created == 1
|
|
98
|
+
#
|
|
99
|
+
# def test_create_table(self, db):
|
|
100
|
+
# db.execute('CREATE DATABASE pytest_test2')
|
|
101
|
+
# result = db.execute('CREATE TABLE pytest_test2.users (id INT PRIMARY KEY, name STRING)')
|
|
102
|
+
# assert isinstance(result, CommitResult)
|
|
103
|
+
# assert result.tables_created == 1
|
|
104
|
+
#
|
|
105
|
+
# def test_insert_and_query(self, db):
|
|
106
|
+
# db.execute('CREATE DATABASE pytest_test3')
|
|
107
|
+
# db.execute('CREATE TABLE pytest_test3.items (id INT PRIMARY KEY, value STRING)')
|
|
108
|
+
# db.execute("INSERT INTO pytest_test3.items (id, value) VALUES (1, 'hello')")
|
|
109
|
+
#
|
|
110
|
+
# result = db.query('SELECT * FROM pytest_test3.items')
|
|
111
|
+
# assert isinstance(result, QueryResult)
|
|
112
|
+
# assert len(result) == 1
|
|
113
|
+
# assert result[0] == {'id': '1', 'value': 'hello'}
|