cinchdb 0.1.3__py3-none-any.whl → 0.1.5__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.
cinchdb/managers/table.py CHANGED
@@ -95,13 +95,13 @@ class TableManager:
95
95
  for column in columns:
96
96
  if column.foreign_key:
97
97
  fk = column.foreign_key
98
-
98
+
99
99
  # Validate referenced table exists
100
100
  if not self._table_exists(fk.table):
101
101
  raise ValueError(
102
102
  f"Foreign key reference to non-existent table: '{fk.table}'"
103
103
  )
104
-
104
+
105
105
  # Validate referenced column exists
106
106
  ref_table = self.get_table(fk.table)
107
107
  ref_col_names = [col.name for col in ref_table.columns]
@@ -109,9 +109,11 @@ class TableManager:
109
109
  raise ValueError(
110
110
  f"Foreign key reference to non-existent column: '{fk.table}.{fk.column}'"
111
111
  )
112
-
112
+
113
113
  # Build foreign key constraint
114
- fk_constraint = f"FOREIGN KEY ({column.name}) REFERENCES {fk.table}({fk.column})"
114
+ fk_constraint = (
115
+ f"FOREIGN KEY ({column.name}) REFERENCES {fk.table}({fk.column})"
116
+ )
115
117
  if fk.on_delete != "RESTRICT":
116
118
  fk_constraint += f" ON DELETE {fk.on_delete}"
117
119
  if fk.on_update != "RESTRICT":
@@ -143,7 +145,7 @@ class TableManager:
143
145
  col_def += " UNIQUE"
144
146
 
145
147
  sql_parts.append(col_def)
146
-
148
+
147
149
  # Add foreign key constraints
148
150
  sql_parts.extend(foreign_key_constraints)
149
151
 
@@ -201,16 +203,17 @@ class TableManager:
201
203
  to_col = fk_row["to"]
202
204
  on_update = fk_row["on_update"]
203
205
  on_delete = fk_row["on_delete"]
204
-
206
+
205
207
  # Create ForeignKeyRef
206
208
  from cinchdb.models import ForeignKeyRef
209
+
207
210
  foreign_keys[from_col] = ForeignKeyRef(
208
211
  table=to_table,
209
212
  column=to_col,
210
213
  on_update=on_update,
211
- on_delete=on_delete
214
+ on_delete=on_delete,
212
215
  )
213
-
216
+
214
217
  # Get column information
215
218
  cursor = conn.execute(f"PRAGMA table_info({table_name})")
216
219
 
@@ -241,7 +244,7 @@ class TableManager:
241
244
  nullable=(row["notnull"] == 0),
242
245
  default=row["dflt_value"],
243
246
  primary_key=(row["pk"] == 1),
244
- foreign_key=foreign_key
247
+ foreign_key=foreign_key,
245
248
  )
246
249
  columns.append(column)
247
250
 
@@ -70,7 +70,7 @@ class TenantManager:
70
70
  """
71
71
  # Validate tenant name
72
72
  validate_name(tenant_name, "tenant")
73
-
73
+
74
74
  # Check maintenance mode
75
75
  check_maintenance_mode(self.project_root, self.database, self.branch)
76
76
 
@@ -168,7 +168,7 @@ class TenantManager:
168
168
  """
169
169
  # Validate target tenant name
170
170
  validate_name(target_tenant, "tenant")
171
-
171
+
172
172
  # Check maintenance mode
173
173
  check_maintenance_mode(self.project_root, self.database, self.branch)
174
174
 
@@ -213,7 +213,7 @@ class TenantManager:
213
213
  """
214
214
  # Validate new tenant name
215
215
  validate_name(new_name, "tenant")
216
-
216
+
217
217
  # Can't rename main tenant
218
218
  if old_name == "main":
219
219
  raise ValueError("Cannot rename the main tenant")
cinchdb/models/branch.py CHANGED
@@ -22,7 +22,7 @@ class Branch(CinchDBBaseModel):
22
22
  )
23
23
  is_main: bool = Field(default=False, description="Whether this is the main branch")
24
24
 
25
- @field_validator('name')
25
+ @field_validator("name")
26
26
  @classmethod
27
27
  def validate_name_field(cls, v: str) -> str:
28
28
  """Validate branch name meets naming requirements."""
@@ -16,7 +16,7 @@ class Database(CinchDBBaseModel):
16
16
  active_branch: str = Field(default="main", description="Currently active branch")
17
17
  description: Optional[str] = Field(default=None, description="Database description")
18
18
 
19
- @field_validator('name')
19
+ @field_validator("name")
20
20
  @classmethod
21
21
  def validate_name_field(cls, v: str) -> str:
22
22
  """Validate database name meets naming requirements."""
cinchdb/models/table.py CHANGED
@@ -14,18 +14,16 @@ ForeignKeyAction = Literal["CASCADE", "SET NULL", "RESTRICT", "NO ACTION"]
14
14
 
15
15
  class ForeignKeyRef(BaseModel):
16
16
  """Foreign key reference specification."""
17
-
17
+
18
18
  model_config = ConfigDict(extra="forbid")
19
-
19
+
20
20
  table: str = Field(description="Referenced table name")
21
21
  column: str = Field(default="id", description="Referenced column name")
22
22
  on_delete: ForeignKeyAction = Field(
23
- default="RESTRICT",
24
- description="Action on delete of referenced row"
23
+ default="RESTRICT", description="Action on delete of referenced row"
25
24
  )
26
25
  on_update: ForeignKeyAction = Field(
27
- default="RESTRICT",
28
- description="Action on update of referenced row"
26
+ default="RESTRICT", description="Action on update of referenced row"
29
27
  )
30
28
 
31
29
 
@@ -47,8 +45,7 @@ class Column(BaseModel):
47
45
  )
48
46
  unique: bool = Field(default=False, description="Whether values must be unique")
49
47
  foreign_key: Optional[ForeignKeyRef] = Field(
50
- default=None,
51
- description="Foreign key constraint specification"
48
+ default=None, description="Foreign key constraint specification"
52
49
  )
53
50
 
54
51
 
cinchdb/models/tenant.py CHANGED
@@ -15,7 +15,7 @@ class Tenant(CinchDBBaseModel):
15
15
  description: Optional[str] = Field(default=None, description="Tenant description")
16
16
  is_main: bool = Field(default=False, description="Whether this is the main tenant")
17
17
 
18
- @field_validator('name')
18
+ @field_validator("name")
19
19
  @classmethod
20
20
  def validate_name_field(cls, v: str) -> str:
21
21
  """Validate tenant name meets naming requirements."""
cinchdb/utils/__init__.py CHANGED
@@ -4,13 +4,13 @@ from cinchdb.utils.sql_validator import (
4
4
  validate_sql_query,
5
5
  validate_query_safe,
6
6
  SQLValidationError,
7
- SQLOperation
7
+ SQLOperation,
8
8
  )
9
9
  from cinchdb.utils.name_validator import (
10
10
  validate_name,
11
11
  clean_name,
12
12
  is_valid_name,
13
- InvalidNameError
13
+ InvalidNameError,
14
14
  )
15
15
 
16
16
  __all__ = [
@@ -19,7 +19,7 @@ __all__ = [
19
19
  "SQLValidationError",
20
20
  "SQLOperation",
21
21
  "validate_name",
22
- "clean_name",
22
+ "clean_name",
23
23
  "is_valid_name",
24
- "InvalidNameError"
25
- ]
24
+ "InvalidNameError",
25
+ ]
@@ -5,55 +5,76 @@ and follow consistent naming conventions.
5
5
  """
6
6
 
7
7
  import re
8
- from typing import Optional
9
8
 
10
9
 
11
10
  # Regex pattern for valid names: lowercase letters, numbers, dash, underscore, period
12
- VALID_NAME_PATTERN = re.compile(r'^[a-z0-9][a-z0-9\-_\.]*[a-z0-9]$|^[a-z0-9]$')
11
+ VALID_NAME_PATTERN = re.compile(r"^[a-z0-9][a-z0-9\-_\.]*[a-z0-9]$|^[a-z0-9]$")
13
12
 
14
13
  # Reserved names that cannot be used
15
- RESERVED_NAMES = {'con', 'prn', 'aux', 'nul', 'com1', 'com2', 'com3', 'com4',
16
- 'com5', 'com6', 'com7', 'com8', 'com9', 'lpt1', 'lpt2',
17
- 'lpt3', 'lpt4', 'lpt5', 'lpt6', 'lpt7', 'lpt8', 'lpt9'}
14
+ RESERVED_NAMES = {
15
+ "con",
16
+ "prn",
17
+ "aux",
18
+ "nul",
19
+ "com1",
20
+ "com2",
21
+ "com3",
22
+ "com4",
23
+ "com5",
24
+ "com6",
25
+ "com7",
26
+ "com8",
27
+ "com9",
28
+ "lpt1",
29
+ "lpt2",
30
+ "lpt3",
31
+ "lpt4",
32
+ "lpt5",
33
+ "lpt6",
34
+ "lpt7",
35
+ "lpt8",
36
+ "lpt9",
37
+ }
18
38
 
19
39
 
20
40
  class InvalidNameError(ValueError):
21
41
  """Raised when a name doesn't meet validation requirements."""
42
+
22
43
  pass
23
44
 
24
45
 
25
46
  def validate_name(name: str, entity_type: str = "entity") -> None:
26
47
  """Validate that a name meets CinchDB naming requirements.
27
-
48
+
28
49
  Valid names must:
29
50
  - Contain only lowercase letters (a-z), numbers (0-9), dash (-), and underscore (_)
30
51
  - Start and end with alphanumeric characters
31
52
  - Be at least 1 character long
32
53
  - Not exceed 255 characters (filesystem limit)
33
54
  - Not be a reserved name
34
-
55
+
35
56
  Args:
36
57
  name: The name to validate
37
58
  entity_type: Type of entity (branch, database, tenant) for error messages
38
-
59
+
39
60
  Raises:
40
61
  InvalidNameError: If the name is invalid
41
62
  """
42
63
  if not name:
43
64
  raise InvalidNameError(f"{entity_type.capitalize()} name cannot be empty")
44
-
65
+
45
66
  if len(name) > 255:
46
67
  raise InvalidNameError(
47
68
  f"{entity_type.capitalize()} name cannot exceed 255 characters"
48
69
  )
49
-
70
+
50
71
  # Check for lowercase requirement
51
72
  if name != name.lower():
52
73
  raise InvalidNameError(
53
74
  f"{entity_type.capitalize()} name must be lowercase. "
54
75
  f"Use '{name.lower()}' instead of '{name}'"
55
76
  )
56
-
77
+
57
78
  # Check pattern
58
79
  if not VALID_NAME_PATTERN.match(name):
59
80
  raise InvalidNameError(
@@ -62,14 +83,24 @@ def validate_name(name: str, entity_type: str = "entity") -> None:
62
83
  f"dash (-), underscore (_), and period (.). "
63
84
  f"Names must start and end with alphanumeric characters."
64
85
  )
65
-
86
+
66
87
  # Check for consecutive special characters
67
- if '--' in name or '__' in name or '-_' in name or '_-' in name or '..' in name or '.-' in name or '-.' in name or '._' in name or '_.' in name:
88
+ if (
89
+ "--" in name
90
+ or "__" in name
91
+ or "-_" in name
92
+ or "_-" in name
93
+ or ".." in name
94
+ or ".-" in name
95
+ or "-." in name
96
+ or "._" in name
97
+ or "_." in name
98
+ ):
68
99
  raise InvalidNameError(
69
100
  f"Invalid {entity_type} name '{name}'. "
70
101
  f"Names cannot contain consecutive special characters."
71
102
  )
72
-
103
+
73
104
  # Check reserved names
74
105
  if name.lower() in RESERVED_NAMES:
75
106
  raise InvalidNameError(
@@ -79,46 +110,46 @@ def validate_name(name: str, entity_type: str = "entity") -> None:
79
110
 
80
111
  def clean_name(name: str) -> str:
81
112
  """Clean a name to make it valid if possible.
82
-
113
+
83
114
  This performs basic cleaning:
84
115
  - Convert to lowercase
85
116
  - Replace spaces with dashes
86
117
  - Remove invalid characters
87
-
118
+
88
119
  Args:
89
120
  name: The name to clean
90
-
121
+
91
122
  Returns:
92
123
  Cleaned name
93
-
124
+
94
125
  Note:
95
126
  This is a best-effort cleaning. The result should still be validated
96
127
  with validate_name() before use.
97
128
  """
98
129
  # Convert to lowercase
99
130
  cleaned = name.lower()
100
-
131
+
101
132
  # Replace spaces with dashes
102
- cleaned = cleaned.replace(' ', '-')
103
-
133
+ cleaned = cleaned.replace(" ", "-")
134
+
104
135
  # Remove invalid characters
105
- cleaned = re.sub(r'[^a-z0-9\-_\.]', '', cleaned)
106
-
136
+ cleaned = re.sub(r"[^a-z0-9\-_\.]", "", cleaned)
137
+
107
138
  # Remove consecutive special characters
108
- cleaned = re.sub(r'[-_\.]{2,}', '-', cleaned)
109
-
139
+ cleaned = re.sub(r"[-_\.]{2,}", "-", cleaned)
140
+
110
141
  # Remove leading/trailing special characters
111
- cleaned = cleaned.strip('-_.')
112
-
142
+ cleaned = cleaned.strip("-_.")
143
+
113
144
  return cleaned
114
145
 
115
146
 
116
147
  def is_valid_name(name: str) -> bool:
117
148
  """Check if a name is valid without raising an exception.
118
-
149
+
119
150
  Args:
120
151
  name: The name to check
121
-
152
+
122
153
  Returns:
123
154
  True if valid, False otherwise
124
155
  """
@@ -126,4 +157,4 @@ def is_valid_name(name: str) -> bool:
126
157
  validate_name(name)
127
158
  return True
128
159
  except InvalidNameError:
129
- return False
160
+ return False
@@ -11,6 +11,7 @@ from enum import Enum
11
11
 
12
12
  class SQLOperation(Enum):
13
13
  """Allowed SQL operations."""
14
+
14
15
  SELECT = "SELECT"
15
16
  INSERT = "INSERT"
16
17
  UPDATE = "UPDATE"
@@ -19,37 +20,63 @@ class SQLOperation(Enum):
19
20
 
20
21
  # List of restricted DDL operations and keywords
21
22
  RESTRICTED_OPERATIONS = {
22
- 'CREATE', 'ALTER', 'DROP', 'TRUNCATE', 'RENAME',
23
- 'GRANT', 'REVOKE', 'ANALYZE', 'VACUUM', 'ATTACH',
24
- 'DETACH', 'PRAGMA', 'REINDEX', 'SAVEPOINT', 'RELEASE'
23
+ "CREATE",
24
+ "ALTER",
25
+ "DROP",
26
+ "TRUNCATE",
27
+ "RENAME",
28
+ "GRANT",
29
+ "REVOKE",
30
+ "ANALYZE",
31
+ "VACUUM",
32
+ "ATTACH",
33
+ "DETACH",
34
+ "PRAGMA",
35
+ "REINDEX",
36
+ "SAVEPOINT",
37
+ "RELEASE",
25
38
  }
26
39
 
27
40
  # Additional restricted keywords that could modify schema
28
41
  RESTRICTED_KEYWORDS = {
29
- 'ADD COLUMN', 'DROP COLUMN', 'MODIFY COLUMN',
30
- 'ADD CONSTRAINT', 'DROP CONSTRAINT', 'ADD INDEX',
31
- 'DROP INDEX', 'CREATE INDEX', 'CREATE UNIQUE',
32
- 'CREATE VIEW', 'DROP VIEW', 'CREATE TRIGGER',
33
- 'DROP TRIGGER', 'CREATE PROCEDURE', 'DROP PROCEDURE',
34
- 'CREATE FUNCTION', 'DROP FUNCTION'
42
+ "ADD COLUMN",
43
+ "DROP COLUMN",
44
+ "MODIFY COLUMN",
45
+ "ADD CONSTRAINT",
46
+ "DROP CONSTRAINT",
47
+ "ADD INDEX",
48
+ "DROP INDEX",
49
+ "CREATE INDEX",
50
+ "CREATE UNIQUE",
51
+ "CREATE VIEW",
52
+ "DROP VIEW",
53
+ "CREATE TRIGGER",
54
+ "DROP TRIGGER",
55
+ "CREATE PROCEDURE",
56
+ "DROP PROCEDURE",
57
+ "CREATE FUNCTION",
58
+ "DROP FUNCTION",
35
59
  }
36
60
 
37
61
 
38
62
  class SQLValidationError(Exception):
39
63
  """Raised when SQL query validation fails."""
64
+
40
65
  pass
41
66
 
42
67
 
43
- def validate_sql_query(query: str, allow_multiple_statements: bool = False) -> Tuple[bool, Optional[str], Optional[SQLOperation]]:
68
+ def validate_sql_query(
69
+ query: str, allow_multiple_statements: bool = False
70
+ ) -> Tuple[bool, Optional[str], Optional[SQLOperation]]:
44
71
  """Validate a SQL query to ensure it only contains allowed operations.
45
-
72
+
46
73
  Allowed operations: SELECT, INSERT, UPDATE, DELETE
47
74
  Blocked operations: All DDL operations (CREATE, ALTER, DROP, etc.)
48
-
75
+
49
76
  Args:
50
77
  query: The SQL query to validate
51
78
  allow_multiple_statements: Whether to allow multiple SQL statements (default: False)
52
-
79
+
53
80
  Returns:
54
81
  Tuple of (is_valid, error_message, operation)
55
82
  - is_valid: True if query is valid
@@ -58,80 +85,103 @@ def validate_sql_query(query: str, allow_multiple_statements: bool = False) -> T
58
85
  """
59
86
  if not query or not query.strip():
60
87
  return False, "Query cannot be empty", None
61
-
88
+
62
89
  # Normalize the query - remove comments and extra whitespace
63
90
  normalized_query = query
64
91
  # Remove single-line comments
65
- normalized_query = re.sub(r'--.*$', '', normalized_query, flags=re.MULTILINE)
92
+ normalized_query = re.sub(r"--.*$", "", normalized_query, flags=re.MULTILINE)
66
93
  # Remove multi-line comments
67
- normalized_query = re.sub(r'/\*[\s\S]*?\*/', '', normalized_query)
94
+ normalized_query = re.sub(r"/\*[\s\S]*?\*/", "", normalized_query)
68
95
  # Replace multiple spaces with single space
69
- normalized_query = re.sub(r'\s+', ' ', normalized_query)
96
+ normalized_query = re.sub(r"\s+", " ", normalized_query)
70
97
  normalized_query = normalized_query.strip().upper()
71
-
98
+
72
99
  if not normalized_query:
73
100
  return False, "Query cannot be empty after removing comments", None
74
-
101
+
75
102
  # Check for multiple statements (security risk)
76
103
  if not allow_multiple_statements:
77
104
  # Count semicolons that are not at the end
78
- semicolon_pos = normalized_query.find(';')
105
+ semicolon_pos = normalized_query.find(";")
79
106
  if semicolon_pos != -1 and semicolon_pos < len(normalized_query) - 1:
80
107
  # Check if there's non-whitespace after the semicolon
81
- remaining = normalized_query[semicolon_pos + 1:].strip()
108
+ remaining = normalized_query[semicolon_pos + 1 :].strip()
82
109
  if remaining:
83
- return False, "Multiple statements are not allowed. Please execute one query at a time.", None
84
-
110
+ return (
111
+ False,
112
+ "Multiple statements are not allowed. Please execute one query at a time.",
113
+ None,
114
+ )
115
+
85
116
  # Extract the first word (operation)
86
- first_word = normalized_query.split()[0].rstrip(';')
87
-
117
+ first_word = normalized_query.split()[0].rstrip(";")
118
+
88
119
  # Check if it's an allowed operation
89
120
  try:
90
121
  operation = SQLOperation(first_word)
91
-
122
+
92
123
  # Additional validation for UPDATE and DELETE
93
124
  if operation in (SQLOperation.UPDATE, SQLOperation.DELETE):
94
125
  # Warning if no WHERE clause (we don't block it, just log)
95
- if 'WHERE' not in normalized_query:
126
+ if "WHERE" not in normalized_query:
96
127
  import logging
97
- logging.warning(f"{operation.value} statement without WHERE clause detected")
98
-
128
+
129
+ logging.warning(
130
+ f"{operation.value} statement without WHERE clause detected"
131
+ )
132
+
99
133
  return True, None, operation
100
134
  except ValueError:
101
135
  # Not a recognized allowed operation
102
136
  pass
103
-
137
+
104
138
  # Check for restricted operations
105
139
  for restricted in RESTRICTED_OPERATIONS:
106
140
  if normalized_query.startswith(restricted):
107
- return False, f"{restricted} operations are not allowed. Only SELECT, INSERT, UPDATE, and DELETE queries are permitted.", None
108
-
141
+ return (
142
+ False,
143
+ f"{restricted} operations are not allowed. Only SELECT, INSERT, UPDATE, and DELETE queries are permitted.",
144
+ None,
145
+ )
146
+
109
147
  # Check for restricted keywords anywhere in the query
110
148
  for keyword in RESTRICTED_KEYWORDS:
111
149
  if keyword in normalized_query:
112
- return False, f"Query contains restricted operation: {keyword}. Only SELECT, INSERT, UPDATE, and DELETE queries are permitted.", None
113
-
150
+ return (
151
+ False,
152
+ f"Query contains restricted operation: {keyword}. Only SELECT, INSERT, UPDATE, and DELETE queries are permitted.",
153
+ None,
154
+ )
155
+
114
156
  # Check for WITH statements that might contain DDL
115
- if normalized_query.startswith('WITH'):
157
+ if normalized_query.startswith("WITH"):
116
158
  # Check if the CTE contains any DDL operations
117
159
  for restricted in RESTRICTED_OPERATIONS:
118
160
  if restricted in normalized_query:
119
- return False, f"CTE (WITH clause) containing {restricted} operations is not allowed.", None
120
-
161
+ return (
162
+ False,
163
+ f"CTE (WITH clause) containing {restricted} operations is not allowed.",
164
+ None,
165
+ )
166
+
121
167
  # If we get here, it's an unrecognized operation
122
- return False, "Unrecognized or restricted SQL operation. Only SELECT, INSERT, UPDATE, and DELETE queries are permitted.", None
168
+ return (
169
+ False,
170
+ "Unrecognized or restricted SQL operation. Only SELECT, INSERT, UPDATE, and DELETE queries are permitted.",
171
+ None,
172
+ )
123
173
 
124
174
 
125
175
  def validate_query_safe(query: str, allow_multiple_statements: bool = False) -> None:
126
176
  """Validate a SQL query and raise an exception if invalid.
127
-
177
+
128
178
  Args:
129
179
  query: The SQL query to validate
130
180
  allow_multiple_statements: Whether to allow multiple SQL statements
131
-
181
+
132
182
  Raises:
133
183
  SQLValidationError: If the query is invalid
134
184
  """
135
185
  is_valid, error_message, _ = validate_sql_query(query, allow_multiple_statements)
136
186
  if not is_valid:
137
- raise SQLValidationError(error_message)
187
+ raise SQLValidationError(error_message)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cinchdb
3
- Version: 0.1.3
3
+ Version: 0.1.5
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
@@ -31,7 +31,7 @@ Description-Content-Type: text/markdown
31
31
 
32
32
  NOTE: CinchDB is in early alpha. This is project to test out an idea. Do not use this in production.
33
33
 
34
- CinchDB is for projects that need fast queries, data isolated data per-tenant [or even per-user](https://turso.tech/blog/give-each-of-your-users-their-own-sqlite-database-b74445f4), and a branchable database.
34
+ CinchDB is for projects that need fast queries, data isolated data per-tenant [or even per-user](https://turso.tech/blog/give-each-of-your-users-their-own-sqlite-database-b74445f4), and a branchable database that makes it easy to merge changes between branches.
35
35
 
36
36
  On a meta level, I made this because I wanted a database structure that I felt comfortable letting AI agents take full control over, safely, and I didn't want to run my own Postgres instance somewhere or pay for it on e.g. Neon - I don't need hyperscaling, I just need super fast queries.
37
37
 
@@ -0,0 +1,54 @@
1
+ cinchdb/__init__.py,sha256=NZdSzfhRguSBTjJ2dcESOQYy53OZEuBndlB7U08GMY0,179
2
+ cinchdb/__main__.py,sha256=OpkDqn9zkTZhhYgvv_grswWLAHKbmxs4M-8C6Z5HfWY,85
3
+ cinchdb/config.py,sha256=gocjMnYKLWhgvnteo6zprgwtK6Oevoxq547J_v-C9Ns,5265
4
+ cinchdb/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ cinchdb/cli/main.py,sha256=Icr_uhe_zXPAuhM9NB7evR5b1ZP7f_N40HQcC1JFhQ0,4706
6
+ cinchdb/cli/utils.py,sha256=NREFxN9k53FnPbDoPt4SXmdZzlzw9zUMv5ICQwTT8gk,5679
7
+ cinchdb/cli/commands/__init__.py,sha256=gQ6tnU0Rvm0-ESWFUBU-KDl5dpNOpUTG509hXOQQjwY,27
8
+ cinchdb/cli/commands/branch.py,sha256=Nz8YQYJ7lizSXEAv0usTx85TDOC-N5Ul9KIxN8JQtKc,17973
9
+ cinchdb/cli/commands/codegen.py,sha256=WsRWmXNTDuaLPyECW5psXM9zOQnKHpUiv8BJnBAjMII,6189
10
+ cinchdb/cli/commands/column.py,sha256=ISHRmcoLf1fAbPqC2MaAYH7Fc6xZWtzCMSRh7_9o-lY,11757
11
+ cinchdb/cli/commands/database.py,sha256=-UCOnn3VatdNog-fX5pguJ2GKdSSXQN99-LSVwkvinY,6857
12
+ cinchdb/cli/commands/query.py,sha256=XW_YL6M5IYHHHMpVB5p-M01kawFxwDOK5B5hGIy_BA8,5044
13
+ cinchdb/cli/commands/remote.py,sha256=i07hfiAxgrROB9lVJVaKK_nWxT1SGiSbtFb4jvEwxEo,4445
14
+ cinchdb/cli/commands/table.py,sha256=NxfOTCd9beaujffiAPiW0Vko0--HS1JVeCwBMp_khx4,10518
15
+ cinchdb/cli/commands/tenant.py,sha256=cOWs9Gf13ZE4KTKJZ_AvDwFDdXBUn5i-Av4MoUsc8Go,6199
16
+ cinchdb/cli/commands/view.py,sha256=ZmS1IW7idzzHAXmgVyY3C4IQRo7toHb6fHNFY_tQJjI,6385
17
+ cinchdb/cli/handlers/__init__.py,sha256=f2f-Cc96rSBLbVsiIbf-b4pZCKZoHfmhNEvnZ0OurRs,131
18
+ cinchdb/cli/handlers/codegen_handler.py,sha256=i5we_AbiUW3zfO6pIKWxvtO8OvOqz3H__4xPmTLEuQM,6524
19
+ cinchdb/core/__init__.py,sha256=iNlT0iO9cM0HLoYwzBavUBoXRh1Tcnz1l_vfbwVxK_Q,246
20
+ cinchdb/core/connection.py,sha256=SlKyEfIpeaDws8M6SfEbvCEVnt26zBY1RYwHtTXj0kY,5110
21
+ cinchdb/core/database.py,sha256=g-QH8NOWvegajAwplNHcooPPpvZEr7L7NfrTIqlqJN8,18591
22
+ cinchdb/core/initializer.py,sha256=CjnJSMuR1NrHobyFfwL44tUeH8VE62q02bijEtVH3p4,6922
23
+ cinchdb/core/maintenance.py,sha256=PAgrSL7Cj9p3rKHV0h_L7gupN6nLD0-5eQpJZNiqyEs,2097
24
+ cinchdb/core/path_utils.py,sha256=J2UEu1X_NFOqDamcsrPrC7ZitGTg9Y-HFjmx4sHf5j8,3806
25
+ cinchdb/managers/__init__.py,sha256=ic61ZUdsg-muq0ETYO6fuZRQWF4j7l920PthTkt2QrE,808
26
+ cinchdb/managers/branch.py,sha256=FkF2i5vZ8ifldGm9tLcgPNymifFdBbpCrfLorIBYCiE,5330
27
+ cinchdb/managers/change_applier.py,sha256=cHPhPgbJ9jeyrb6lkfRyumS8IHat0HiWfwZh-n7ButA,14310
28
+ cinchdb/managers/change_comparator.py,sha256=08pwybpSt36cFwhZRSIkHynvFMUaLKEVwa8Ajn_R9yQ,6862
29
+ cinchdb/managers/change_tracker.py,sha256=U93BPnuGv8xSaO5qr_y5Q8ppKrVXygozdp5zUvLUqwg,5054
30
+ cinchdb/managers/codegen.py,sha256=1CfIwjgHnNDdjrq4SzQ9VE7DFgnWfk7RtpupBFUTqxk,21804
31
+ cinchdb/managers/column.py,sha256=YhYq-hnH0o2BqZkyihnsY5KIWEztzs-_iLJNZMdVUkk,20807
32
+ cinchdb/managers/data.py,sha256=zS1HkMGf436m6f8VdFAqQbQFgo4sL5yKJRcRf4A6lIc,16253
33
+ cinchdb/managers/merge_manager.py,sha256=R8S2hLkLJg4hLDpeJTzjVkduZgqPOjXtYgOSJhTXXrE,15690
34
+ cinchdb/managers/query.py,sha256=pBlbqoovnFsZ36pB7nv8NtzcTFwtT26hp8IlwjIx29Q,7301
35
+ cinchdb/managers/table.py,sha256=KWSAfZCJafKZPx-dRG7KwQUGVqVQ56ARMVBllb3VBig,13114
36
+ cinchdb/managers/tenant.py,sha256=QONC5R8tW5CJoGUxECJmQyiSP12mz3rZBmRqxCsKjmM,8726
37
+ cinchdb/managers/view.py,sha256=v9gYtRufZyxywPKLGvIjvlUXcxYh9CLRArefu9QX6zk,7809
38
+ cinchdb/models/__init__.py,sha256=382OuS0BaKPA71GjqNW5lfVhtUYqmcMlLRin7HPi6XI,602
39
+ cinchdb/models/base.py,sha256=7j4rlFTP5K9ZuF8vxwC7lMFEaL7O90NJ47Ig5i7ubcw,1320
40
+ cinchdb/models/branch.py,sha256=gRgLpRFkMC3fxf9ZigVOkS6wdkBERWqlLk0_gOYjqNk,1180
41
+ cinchdb/models/change.py,sha256=YpBWdI6yMT3uucd8duET9s75xr5JUWJqurkkyTlXPlk,1449
42
+ cinchdb/models/database.py,sha256=QrWd_SkE1G8TMWflO4sXRUbSdbqcrfGOt2e-PS7OW7A,971
43
+ cinchdb/models/project.py,sha256=6GMXUZUsEIebqQJgRXIthWzpWKuNNmJ3drgI1vFDrMo,644
44
+ cinchdb/models/table.py,sha256=k2_nnyW1E6-UM2Zw49K5njP_fxySW3HVWymcR_a0e_0,2759
45
+ cinchdb/models/tenant.py,sha256=UKYTKM4mQH3IqEjI_tOU5CszwBWH4cXa3lI0mpMFF_4,967
46
+ cinchdb/models/view.py,sha256=q6j-jYzFJuhRJO87rKt6Uv8hOizHQx8xwoPKoH6XnNY,530
47
+ cinchdb/utils/__init__.py,sha256=yQQhEjndDiB2SUJybUmp9dvEOQKiR-GySe-WiCius5E,490
48
+ cinchdb/utils/name_validator.py,sha256=dyGX5bjlTFRA9EGrWRQKp6kR__HSV04hLV5VueJs4IQ,4027
49
+ cinchdb/utils/sql_validator.py,sha256=aWOGlPX0gBkuR6R1EBP2stbP4PHZuI6FUBi2Ljx7JUI,5815
50
+ cinchdb-0.1.5.dist-info/METADATA,sha256=pnIHIDE116wBD3rp7oNJ_45l9NVxV0Qg7V0QyarGZvo,5855
51
+ cinchdb-0.1.5.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
52
+ cinchdb-0.1.5.dist-info/entry_points.txt,sha256=VBOIzvnGbkKudMCCmNORS3885QSyjZUVKJQ-Syqa62w,47
53
+ cinchdb-0.1.5.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
54
+ cinchdb-0.1.5.dist-info/RECORD,,