cinchdb 0.1.0__py3-none-any.whl

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.
Files changed (68) hide show
  1. cinchdb/__init__.py +7 -0
  2. cinchdb/__main__.py +6 -0
  3. cinchdb/api/__init__.py +5 -0
  4. cinchdb/api/app.py +76 -0
  5. cinchdb/api/auth.py +290 -0
  6. cinchdb/api/main.py +137 -0
  7. cinchdb/api/routers/__init__.py +25 -0
  8. cinchdb/api/routers/auth.py +135 -0
  9. cinchdb/api/routers/branches.py +368 -0
  10. cinchdb/api/routers/codegen.py +164 -0
  11. cinchdb/api/routers/columns.py +290 -0
  12. cinchdb/api/routers/data.py +479 -0
  13. cinchdb/api/routers/databases.py +177 -0
  14. cinchdb/api/routers/projects.py +133 -0
  15. cinchdb/api/routers/query.py +156 -0
  16. cinchdb/api/routers/tables.py +349 -0
  17. cinchdb/api/routers/tenants.py +216 -0
  18. cinchdb/api/routers/views.py +219 -0
  19. cinchdb/cli/__init__.py +0 -0
  20. cinchdb/cli/commands/__init__.py +1 -0
  21. cinchdb/cli/commands/branch.py +479 -0
  22. cinchdb/cli/commands/codegen.py +176 -0
  23. cinchdb/cli/commands/column.py +308 -0
  24. cinchdb/cli/commands/database.py +212 -0
  25. cinchdb/cli/commands/query.py +136 -0
  26. cinchdb/cli/commands/remote.py +144 -0
  27. cinchdb/cli/commands/table.py +289 -0
  28. cinchdb/cli/commands/tenant.py +173 -0
  29. cinchdb/cli/commands/view.py +189 -0
  30. cinchdb/cli/handlers/__init__.py +5 -0
  31. cinchdb/cli/handlers/codegen_handler.py +189 -0
  32. cinchdb/cli/main.py +137 -0
  33. cinchdb/cli/utils.py +182 -0
  34. cinchdb/config.py +177 -0
  35. cinchdb/core/__init__.py +5 -0
  36. cinchdb/core/connection.py +175 -0
  37. cinchdb/core/database.py +537 -0
  38. cinchdb/core/maintenance.py +73 -0
  39. cinchdb/core/path_utils.py +153 -0
  40. cinchdb/managers/__init__.py +26 -0
  41. cinchdb/managers/branch.py +167 -0
  42. cinchdb/managers/change_applier.py +414 -0
  43. cinchdb/managers/change_comparator.py +194 -0
  44. cinchdb/managers/change_tracker.py +182 -0
  45. cinchdb/managers/codegen.py +523 -0
  46. cinchdb/managers/column.py +579 -0
  47. cinchdb/managers/data.py +455 -0
  48. cinchdb/managers/merge_manager.py +429 -0
  49. cinchdb/managers/query.py +214 -0
  50. cinchdb/managers/table.py +383 -0
  51. cinchdb/managers/tenant.py +258 -0
  52. cinchdb/managers/view.py +252 -0
  53. cinchdb/models/__init__.py +27 -0
  54. cinchdb/models/base.py +44 -0
  55. cinchdb/models/branch.py +26 -0
  56. cinchdb/models/change.py +47 -0
  57. cinchdb/models/database.py +20 -0
  58. cinchdb/models/project.py +20 -0
  59. cinchdb/models/table.py +86 -0
  60. cinchdb/models/tenant.py +19 -0
  61. cinchdb/models/view.py +15 -0
  62. cinchdb/utils/__init__.py +15 -0
  63. cinchdb/utils/sql_validator.py +137 -0
  64. cinchdb-0.1.0.dist-info/METADATA +195 -0
  65. cinchdb-0.1.0.dist-info/RECORD +68 -0
  66. cinchdb-0.1.0.dist-info/WHEEL +4 -0
  67. cinchdb-0.1.0.dist-info/entry_points.txt +3 -0
  68. cinchdb-0.1.0.dist-info/licenses/LICENSE +201 -0
@@ -0,0 +1,153 @@
1
+ """Path utilities for CinchDB."""
2
+
3
+ from pathlib import Path
4
+ from typing import List
5
+
6
+
7
+ def get_project_root(start_path: Path) -> Path:
8
+ """Find the project root by looking for .cinchdb directory.
9
+
10
+ Args:
11
+ start_path: Path to start searching from
12
+
13
+ Returns:
14
+ Path to project root
15
+
16
+ Raises:
17
+ FileNotFoundError: If no project root found
18
+ """
19
+ current = Path(start_path).resolve()
20
+
21
+ while current != current.parent:
22
+ if (current / ".cinchdb").exists():
23
+ return current
24
+ current = current.parent
25
+
26
+ raise FileNotFoundError(f"No CinchDB project found from {start_path}")
27
+
28
+
29
+ def get_database_path(project_root: Path, database: str) -> Path:
30
+ """Get path to a database directory.
31
+
32
+ Args:
33
+ project_root: Project root directory
34
+ database: Database name
35
+
36
+ Returns:
37
+ Path to database directory
38
+ """
39
+ return project_root / ".cinchdb" / "databases" / database
40
+
41
+
42
+ def get_branch_path(project_root: Path, database: str, branch: str) -> Path:
43
+ """Get path to a branch directory.
44
+
45
+ Args:
46
+ project_root: Project root directory
47
+ database: Database name
48
+ branch: Branch name
49
+
50
+ Returns:
51
+ Path to branch directory
52
+ """
53
+ return get_database_path(project_root, database) / "branches" / branch
54
+
55
+
56
+ def get_tenant_path(
57
+ project_root: Path, database: str, branch: str, tenant: str
58
+ ) -> Path:
59
+ """Get path to tenant directory.
60
+
61
+ Args:
62
+ project_root: Project root directory
63
+ database: Database name
64
+ branch: Branch name
65
+ tenant: Tenant name
66
+
67
+ Returns:
68
+ Path to tenant directory
69
+ """
70
+ return get_branch_path(project_root, database, branch) / "tenants"
71
+
72
+
73
+ def get_tenant_db_path(
74
+ project_root: Path, database: str, branch: str, tenant: str
75
+ ) -> Path:
76
+ """Get path to tenant database file.
77
+
78
+ Args:
79
+ project_root: Project root directory
80
+ database: Database name
81
+ branch: Branch name
82
+ tenant: Tenant name
83
+
84
+ Returns:
85
+ Path to tenant database file
86
+ """
87
+ return get_tenant_path(project_root, database, branch, tenant) / f"{tenant}.db"
88
+
89
+
90
+ def ensure_directory(path: Path) -> None:
91
+ """Ensure a directory exists, creating it if necessary.
92
+
93
+ Args:
94
+ path: Directory path to ensure exists
95
+ """
96
+ path.mkdir(parents=True, exist_ok=True)
97
+
98
+
99
+ def list_databases(project_root: Path) -> List[str]:
100
+ """List all databases in a project.
101
+
102
+ Args:
103
+ project_root: Project root directory
104
+
105
+ Returns:
106
+ List of database names
107
+ """
108
+ db_dir = project_root / ".cinchdb" / "databases"
109
+ if not db_dir.exists():
110
+ return []
111
+
112
+ return sorted([d.name for d in db_dir.iterdir() if d.is_dir()])
113
+
114
+
115
+ def list_branches(project_root: Path, database: str) -> List[str]:
116
+ """List all branches in a database.
117
+
118
+ Args:
119
+ project_root: Project root directory
120
+ database: Database name
121
+
122
+ Returns:
123
+ List of branch names
124
+ """
125
+ branches_dir = get_database_path(project_root, database) / "branches"
126
+ if not branches_dir.exists():
127
+ return []
128
+
129
+ return sorted([b.name for b in branches_dir.iterdir() if b.is_dir()])
130
+
131
+
132
+ def list_tenants(project_root: Path, database: str, branch: str) -> List[str]:
133
+ """List all tenants in a branch.
134
+
135
+ Args:
136
+ project_root: Project root directory
137
+ database: Database name
138
+ branch: Branch name
139
+
140
+ Returns:
141
+ List of tenant names
142
+ """
143
+ tenants_dir = get_branch_path(project_root, database, branch) / "tenants"
144
+ if not tenants_dir.exists():
145
+ return []
146
+
147
+ # Only list .db files, not WAL or SHM files
148
+ tenants = []
149
+ for f in tenants_dir.iterdir():
150
+ if f.is_file() and f.suffix == ".db":
151
+ tenants.append(f.stem)
152
+
153
+ return sorted(tenants)
@@ -0,0 +1,26 @@
1
+ """CinchDB managers."""
2
+
3
+ from cinchdb.managers.branch import BranchManager
4
+ from cinchdb.managers.tenant import TenantManager
5
+ from cinchdb.managers.change_tracker import ChangeTracker
6
+ from cinchdb.managers.change_applier import ChangeApplier
7
+ from cinchdb.managers.change_comparator import ChangeComparator
8
+ from cinchdb.managers.merge_manager import MergeManager, MergeError
9
+ from cinchdb.managers.table import TableManager
10
+ from cinchdb.managers.column import ColumnManager
11
+ from cinchdb.managers.view import ViewModel
12
+ from cinchdb.managers.codegen import CodegenManager
13
+
14
+ __all__ = [
15
+ "BranchManager",
16
+ "TenantManager",
17
+ "ChangeTracker",
18
+ "ChangeApplier",
19
+ "ChangeComparator",
20
+ "MergeManager",
21
+ "MergeError",
22
+ "TableManager",
23
+ "ColumnManager",
24
+ "ViewModel",
25
+ "CodegenManager",
26
+ ]
@@ -0,0 +1,167 @@
1
+ """Branch management for CinchDB."""
2
+
3
+ import json
4
+ import shutil
5
+ from pathlib import Path
6
+ from typing import List, Dict, Any
7
+ from datetime import datetime, timezone
8
+
9
+ from cinchdb.config import Config
10
+ from cinchdb.models import Branch
11
+ from cinchdb.core.path_utils import (
12
+ get_database_path,
13
+ get_branch_path,
14
+ list_branches,
15
+ )
16
+
17
+
18
+ class BranchManager:
19
+ """Manages branches within a database."""
20
+
21
+ def __init__(self, project_root: Path, database: str):
22
+ """Initialize branch manager.
23
+
24
+ Args:
25
+ project_root: Path to project root
26
+ database: Database name
27
+ """
28
+ self.project_root = Path(project_root)
29
+ self.database = database
30
+ self.db_path = get_database_path(self.project_root, database)
31
+
32
+ def list_branches(self) -> List[Branch]:
33
+ """List all branches in the database.
34
+
35
+ Returns:
36
+ List of Branch objects
37
+ """
38
+ branch_names = list_branches(self.project_root, self.database)
39
+ branches = []
40
+
41
+ for name in branch_names:
42
+ metadata = self.get_branch_metadata(name)
43
+ branch = Branch(
44
+ name=name,
45
+ database=self.database,
46
+ parent_branch=metadata.get("parent_branch"),
47
+ is_main=(name == "main"),
48
+ metadata=metadata,
49
+ )
50
+ branches.append(branch)
51
+
52
+ return branches
53
+
54
+ def create_branch(self, source_branch: str, new_branch_name: str) -> Branch:
55
+ """Create a new branch from an existing branch.
56
+
57
+ Args:
58
+ source_branch: Name of branch to copy from
59
+ new_branch_name: Name for the new branch
60
+
61
+ Returns:
62
+ Created Branch object
63
+
64
+ Raises:
65
+ ValueError: If source doesn't exist or new branch already exists
66
+ """
67
+ # Validate source branch exists
68
+ if source_branch not in list_branches(self.project_root, self.database):
69
+ raise ValueError(f"Source branch '{source_branch}' does not exist")
70
+
71
+ # Validate new branch doesn't exist
72
+ if new_branch_name in list_branches(self.project_root, self.database):
73
+ raise ValueError(f"Branch '{new_branch_name}' already exists")
74
+
75
+ # Get paths
76
+ source_path = get_branch_path(self.project_root, self.database, source_branch)
77
+ new_path = get_branch_path(self.project_root, self.database, new_branch_name)
78
+
79
+ # Copy entire branch directory
80
+ shutil.copytree(source_path, new_path)
81
+
82
+ # Update metadata for new branch
83
+ metadata = self.get_branch_metadata(new_branch_name)
84
+ metadata["parent_branch"] = source_branch
85
+ metadata["created_at"] = datetime.now(timezone.utc).isoformat()
86
+ self.update_branch_metadata(new_branch_name, metadata)
87
+
88
+ # New branch inherits all changes from source branch
89
+ # (changes.json is already copied by copytree, so nothing to do here)
90
+
91
+ return Branch(
92
+ name=new_branch_name,
93
+ database=self.database,
94
+ parent_branch=source_branch,
95
+ is_main=False,
96
+ metadata=metadata,
97
+ )
98
+
99
+ def delete_branch(self, branch_name: str) -> None:
100
+ """Delete a branch.
101
+
102
+ Args:
103
+ branch_name: Name of branch to delete
104
+
105
+ Raises:
106
+ ValueError: If branch doesn't exist or is main branch
107
+ """
108
+ # Can't delete main branch
109
+ if branch_name == "main":
110
+ raise ValueError("Cannot delete the main branch")
111
+
112
+ # Validate branch exists
113
+ if branch_name not in list_branches(self.project_root, self.database):
114
+ raise ValueError(f"Branch '{branch_name}' does not exist")
115
+
116
+ # Delete branch directory
117
+ branch_path = get_branch_path(self.project_root, self.database, branch_name)
118
+ shutil.rmtree(branch_path)
119
+
120
+
121
+ def get_branch_metadata(self, branch_name: str) -> Dict[str, Any]:
122
+ """Get metadata for a branch.
123
+
124
+ Args:
125
+ branch_name: Branch name
126
+
127
+ Returns:
128
+ Metadata dictionary
129
+ """
130
+ metadata_path = (
131
+ get_branch_path(self.project_root, self.database, branch_name)
132
+ / "metadata.json"
133
+ )
134
+
135
+ if metadata_path.exists():
136
+ with open(metadata_path, "r") as f:
137
+ return json.load(f)
138
+
139
+ return {}
140
+
141
+ def update_branch_metadata(
142
+ self, branch_name: str, metadata: Dict[str, Any]
143
+ ) -> None:
144
+ """Update metadata for a branch.
145
+
146
+ Args:
147
+ branch_name: Branch name
148
+ metadata: Metadata dictionary to save
149
+ """
150
+ metadata_path = (
151
+ get_branch_path(self.project_root, self.database, branch_name)
152
+ / "metadata.json"
153
+ )
154
+
155
+ with open(metadata_path, "w") as f:
156
+ json.dump(metadata, f, indent=2)
157
+
158
+ def branch_exists(self, branch_name: str) -> bool:
159
+ """Check if a branch exists.
160
+
161
+ Args:
162
+ branch_name: Branch name to check
163
+
164
+ Returns:
165
+ True if branch exists, False otherwise
166
+ """
167
+ return branch_name in list_branches(self.project_root, self.database)