cinchdb 0.1.7__tar.gz → 0.1.8__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.
- {cinchdb-0.1.7 → cinchdb-0.1.8}/PKG-INFO +1 -1
- {cinchdb-0.1.7 → cinchdb-0.1.8}/pyproject.toml +1 -1
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/core/database.py +8 -4
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/managers/index.py +17 -13
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/managers/table.py +21 -3
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/managers/tenant.py +4 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/models/__init__.py +2 -1
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/models/table.py +10 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/.gitignore +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/LICENSE +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/README.md +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/__init__.py +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/__main__.py +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/cli/__init__.py +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/cli/commands/__init__.py +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/cli/commands/branch.py +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/cli/commands/codegen.py +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/cli/commands/column.py +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/cli/commands/database.py +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/cli/commands/index.py +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/cli/commands/query.py +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/cli/commands/remote.py +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/cli/commands/table.py +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/cli/commands/tenant.py +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/cli/commands/view.py +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/cli/handlers/__init__.py +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/cli/handlers/codegen_handler.py +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/cli/main.py +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/cli/utils.py +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/config.py +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/core/__init__.py +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/core/connection.py +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/core/initializer.py +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/core/maintenance.py +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/core/path_utils.py +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/managers/__init__.py +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/managers/branch.py +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/managers/change_applier.py +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/managers/change_comparator.py +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/managers/change_tracker.py +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/managers/codegen.py +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/managers/column.py +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/managers/data.py +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/managers/merge_manager.py +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/managers/query.py +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/managers/view.py +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/models/base.py +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/models/branch.py +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/models/change.py +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/models/database.py +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/models/project.py +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/models/tenant.py +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/models/view.py +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/utils/__init__.py +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/utils/name_validator.py +0 -0
- {cinchdb-0.1.7 → cinchdb-0.1.8}/src/cinchdb/utils/sql_validator.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: cinchdb
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.8
|
4
4
|
Summary: A Git-like SQLite database management system with branching and multi-tenancy
|
5
5
|
Project-URL: Homepage, https://github.com/russellromney/cinchdb
|
6
6
|
Project-URL: Documentation, https://russellromney.github.io/cinchdb
|
@@ -507,8 +507,12 @@ class CinchDB:
|
|
507
507
|
# Named index
|
508
508
|
db.create_index("products", ["category", "price"], name="idx_category_price")
|
509
509
|
"""
|
510
|
+
# Convert parameters to Index model for validation
|
511
|
+
from cinchdb.models import Index
|
512
|
+
index = Index(columns=columns, name=name, unique=unique)
|
513
|
+
|
510
514
|
if self.is_local:
|
511
|
-
return self.indexes.create_index(table, columns, name, unique)
|
515
|
+
return self.indexes.create_index(table, index.columns, index.name, index.unique)
|
512
516
|
else:
|
513
517
|
# Remote index creation
|
514
518
|
result = self._make_request(
|
@@ -516,9 +520,9 @@ class CinchDB:
|
|
516
520
|
"/indexes",
|
517
521
|
json={
|
518
522
|
"table": table,
|
519
|
-
"columns": columns,
|
520
|
-
"name": name,
|
521
|
-
"unique": unique,
|
523
|
+
"columns": index.columns,
|
524
|
+
"name": index.name,
|
525
|
+
"unique": index.unique,
|
522
526
|
},
|
523
527
|
)
|
524
528
|
return result.get("name")
|
@@ -52,14 +52,18 @@ class IndexManager:
|
|
52
52
|
Raises:
|
53
53
|
ValueError: If table doesn't exist or columns are invalid
|
54
54
|
"""
|
55
|
-
|
55
|
+
# Convert parameters to Index model for validation
|
56
|
+
from cinchdb.models import Index
|
57
|
+
index = Index(columns=columns, name=name, unique=unique)
|
58
|
+
|
59
|
+
if not index.columns:
|
56
60
|
raise ValueError("At least one column must be specified for the index")
|
57
61
|
|
58
62
|
# Generate index name if not provided
|
59
|
-
if not name:
|
60
|
-
column_str = "_".join(columns)
|
61
|
-
unique_prefix = "uniq_" if unique else "idx_"
|
62
|
-
name = f"{unique_prefix}{table}_{column_str}"
|
63
|
+
if not index.name:
|
64
|
+
column_str = "_".join(index.columns)
|
65
|
+
unique_prefix = "uniq_" if index.unique else "idx_"
|
66
|
+
index.name = f"{unique_prefix}{table}_{column_str}"
|
63
67
|
|
64
68
|
# Get connection to main tenant database (indexes are branch-level)
|
65
69
|
db_path = get_tenant_db_path(
|
@@ -79,18 +83,18 @@ class IndexManager:
|
|
79
83
|
result = conn.execute(f"PRAGMA table_info({table})")
|
80
84
|
existing_columns = {row[1] for row in result.fetchall()}
|
81
85
|
|
82
|
-
invalid_columns = set(columns) - existing_columns
|
86
|
+
invalid_columns = set(index.columns) - existing_columns
|
83
87
|
if invalid_columns:
|
84
88
|
raise ValueError(
|
85
89
|
f"Columns {invalid_columns} do not exist in table '{table}'"
|
86
90
|
)
|
87
91
|
|
88
92
|
# Build and execute CREATE INDEX statement
|
89
|
-
unique_clause = "UNIQUE " if unique else ""
|
93
|
+
unique_clause = "UNIQUE " if index.unique else ""
|
90
94
|
if_not_exists_clause = "IF NOT EXISTS " if if_not_exists else ""
|
91
|
-
column_list = ", ".join(columns)
|
95
|
+
column_list = ", ".join(index.columns)
|
92
96
|
|
93
|
-
sql = f"CREATE {unique_clause}INDEX {if_not_exists_clause}{name} ON {table} ({column_list})"
|
97
|
+
sql = f"CREATE {unique_clause}INDEX {if_not_exists_clause}{index.name} ON {table} ({column_list})"
|
94
98
|
|
95
99
|
try:
|
96
100
|
result = conn.execute(sql)
|
@@ -98,18 +102,18 @@ class IndexManager:
|
|
98
102
|
except sqlite3.Error as e:
|
99
103
|
if "already exists" in str(e):
|
100
104
|
if not if_not_exists:
|
101
|
-
raise ValueError(f"Index '{name}' already exists")
|
105
|
+
raise ValueError(f"Index '{index.name}' already exists")
|
102
106
|
else:
|
103
107
|
raise
|
104
108
|
|
105
109
|
# Track the change
|
106
110
|
self._track_change(
|
107
111
|
ChangeType.CREATE_INDEX,
|
108
|
-
name,
|
109
|
-
{"table": table, "columns": columns, "unique": unique}
|
112
|
+
index.name,
|
113
|
+
{"table": table, "columns": index.columns, "unique": index.unique}
|
110
114
|
)
|
111
115
|
|
112
|
-
return name
|
116
|
+
return index.name
|
113
117
|
|
114
118
|
def drop_index(self, name: str, if_exists: bool = True) -> None:
|
115
119
|
"""Drop an index.
|
@@ -1,9 +1,12 @@
|
|
1
1
|
"""Table management for CinchDB."""
|
2
2
|
|
3
3
|
from pathlib import Path
|
4
|
-
from typing import List
|
4
|
+
from typing import List, Optional, TYPE_CHECKING
|
5
5
|
|
6
6
|
from cinchdb.models import Table, Column, Change, ChangeType
|
7
|
+
|
8
|
+
if TYPE_CHECKING:
|
9
|
+
from cinchdb.models import Index
|
7
10
|
from cinchdb.core.connection import DatabaseConnection
|
8
11
|
from cinchdb.core.path_utils import get_tenant_db_path
|
9
12
|
from cinchdb.core.maintenance import check_maintenance_mode
|
@@ -61,12 +64,13 @@ class TableManager:
|
|
61
64
|
|
62
65
|
return tables
|
63
66
|
|
64
|
-
def create_table(self, table_name: str, columns: List[Column]) -> Table:
|
65
|
-
"""Create a new table with optional foreign key constraints.
|
67
|
+
def create_table(self, table_name: str, columns: List[Column], indexes: Optional[List["Index"]] = None) -> Table:
|
68
|
+
"""Create a new table with optional foreign key constraints and indexes.
|
66
69
|
|
67
70
|
Args:
|
68
71
|
table_name: Name of the table
|
69
72
|
columns: List of Column objects defining the schema
|
73
|
+
indexes: Optional list of Index objects to create on the table
|
70
74
|
|
71
75
|
Returns:
|
72
76
|
Created Table object
|
@@ -168,6 +172,20 @@ class TableManager:
|
|
168
172
|
applier = ChangeApplier(self.project_root, self.database, self.branch)
|
169
173
|
applier.apply_change(change.id)
|
170
174
|
|
175
|
+
# Create indexes if specified
|
176
|
+
if indexes:
|
177
|
+
from cinchdb.managers.index import IndexManager
|
178
|
+
index_manager = IndexManager(self.project_root, self.database, self.branch)
|
179
|
+
|
180
|
+
for index in indexes:
|
181
|
+
index_manager.create_index(
|
182
|
+
table=table_name,
|
183
|
+
columns=index.columns,
|
184
|
+
name=index.name,
|
185
|
+
unique=index.unique,
|
186
|
+
if_not_exists=True
|
187
|
+
)
|
188
|
+
|
171
189
|
# Return the created table
|
172
190
|
return Table(
|
173
191
|
name=table_name,
|
@@ -104,6 +104,10 @@ class TenantManager:
|
|
104
104
|
conn.execute(f"DELETE FROM {table}")
|
105
105
|
|
106
106
|
conn.commit()
|
107
|
+
|
108
|
+
# Open a new connection to vacuum the database
|
109
|
+
with DatabaseConnection(new_db_path) as conn:
|
110
|
+
conn.execute("VACUUM")
|
107
111
|
|
108
112
|
return Tenant(
|
109
113
|
name=tenant_name,
|
@@ -5,7 +5,7 @@ from .project import Project
|
|
5
5
|
from .database import Database
|
6
6
|
from .branch import Branch
|
7
7
|
from .tenant import Tenant
|
8
|
-
from .table import Table, Column, ColumnType, ForeignKeyRef, ForeignKeyAction
|
8
|
+
from .table import Table, Column, ColumnType, ForeignKeyRef, ForeignKeyAction, Index
|
9
9
|
from .view import View
|
10
10
|
from .change import Change, ChangeType
|
11
11
|
|
@@ -21,6 +21,7 @@ __all__ = [
|
|
21
21
|
"ColumnType",
|
22
22
|
"ForeignKeyRef",
|
23
23
|
"ForeignKeyAction",
|
24
|
+
"Index",
|
24
25
|
"View",
|
25
26
|
"Change",
|
26
27
|
"ChangeType",
|
@@ -27,6 +27,16 @@ class ForeignKeyRef(BaseModel):
|
|
27
27
|
)
|
28
28
|
|
29
29
|
|
30
|
+
class Index(BaseModel):
|
31
|
+
"""Index specification for table columns."""
|
32
|
+
|
33
|
+
model_config = ConfigDict(extra="forbid")
|
34
|
+
|
35
|
+
columns: List[str] = Field(description="Column names to index")
|
36
|
+
name: Optional[str] = Field(default=None, description="Index name")
|
37
|
+
unique: bool = Field(default=False, description="Create unique index")
|
38
|
+
|
39
|
+
|
30
40
|
class Column(BaseModel):
|
31
41
|
"""Represents a column in a table."""
|
32
42
|
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|