kodit 0.5.4__py3-none-any.whl → 0.5.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.
Potentially problematic release.
This version of kodit might be problematic. Click here for more details.
- kodit/_version.py +2 -2
- kodit/application/factories/server_factory.py +54 -32
- kodit/application/services/code_search_application_service.py +89 -12
- kodit/application/services/commit_indexing_application_service.py +314 -195
- kodit/application/services/enrichment_query_service.py +274 -43
- kodit/application/services/indexing_worker_service.py +1 -1
- kodit/application/services/queue_service.py +15 -10
- kodit/application/services/sync_scheduler.py +2 -1
- kodit/domain/enrichments/architecture/architecture.py +1 -1
- kodit/domain/enrichments/architecture/physical/physical.py +1 -1
- kodit/domain/enrichments/development/development.py +1 -1
- kodit/domain/enrichments/development/snippet/snippet.py +12 -5
- kodit/domain/enrichments/enrichment.py +31 -4
- kodit/domain/enrichments/usage/api_docs.py +1 -1
- kodit/domain/enrichments/usage/usage.py +1 -1
- kodit/domain/entities/git.py +30 -25
- kodit/domain/factories/git_repo_factory.py +20 -5
- kodit/domain/protocols.py +56 -125
- kodit/domain/services/embedding_service.py +14 -16
- kodit/domain/services/git_repository_service.py +60 -38
- kodit/domain/services/git_service.py +18 -11
- kodit/domain/tracking/resolution_service.py +6 -16
- kodit/domain/value_objects.py +2 -9
- kodit/infrastructure/api/v1/dependencies.py +12 -3
- kodit/infrastructure/api/v1/query_params.py +27 -0
- kodit/infrastructure/api/v1/routers/commits.py +91 -85
- kodit/infrastructure/api/v1/routers/repositories.py +53 -37
- kodit/infrastructure/api/v1/routers/search.py +1 -1
- kodit/infrastructure/api/v1/schemas/enrichment.py +14 -0
- kodit/infrastructure/api/v1/schemas/repository.py +1 -1
- kodit/infrastructure/slicing/api_doc_extractor.py +0 -2
- kodit/infrastructure/sqlalchemy/embedding_repository.py +44 -34
- kodit/infrastructure/sqlalchemy/enrichment_association_repository.py +73 -0
- kodit/infrastructure/sqlalchemy/enrichment_v2_repository.py +116 -97
- kodit/infrastructure/sqlalchemy/entities.py +12 -116
- kodit/infrastructure/sqlalchemy/git_branch_repository.py +52 -244
- kodit/infrastructure/sqlalchemy/git_commit_repository.py +35 -324
- kodit/infrastructure/sqlalchemy/git_file_repository.py +70 -0
- kodit/infrastructure/sqlalchemy/git_repository.py +60 -230
- kodit/infrastructure/sqlalchemy/git_tag_repository.py +53 -240
- kodit/infrastructure/sqlalchemy/query.py +331 -0
- kodit/infrastructure/sqlalchemy/repository.py +203 -0
- kodit/infrastructure/sqlalchemy/task_repository.py +79 -58
- kodit/infrastructure/sqlalchemy/task_status_repository.py +45 -52
- kodit/migrations/versions/4b1a3b2c8fa5_refactor_git_tracking.py +190 -0
- {kodit-0.5.4.dist-info → kodit-0.5.5.dist-info}/METADATA +1 -1
- {kodit-0.5.4.dist-info → kodit-0.5.5.dist-info}/RECORD +50 -48
- kodit/infrastructure/mappers/enrichment_mapper.py +0 -83
- kodit/infrastructure/mappers/git_mapper.py +0 -193
- kodit/infrastructure/mappers/snippet_mapper.py +0 -104
- kodit/infrastructure/sqlalchemy/snippet_v2_repository.py +0 -479
- {kodit-0.5.4.dist-info → kodit-0.5.5.dist-info}/WHEEL +0 -0
- {kodit-0.5.4.dist-info → kodit-0.5.5.dist-info}/entry_points.txt +0 -0
- {kodit-0.5.4.dist-info → kodit-0.5.5.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
"""Task repository for the task queue."""
|
|
2
2
|
|
|
3
3
|
from collections.abc import Callable
|
|
4
|
+
from typing import Any
|
|
4
5
|
|
|
5
6
|
import structlog
|
|
6
7
|
from sqlalchemy import select
|
|
7
8
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
import kodit.domain.entities as domain_entities
|
|
10
11
|
from kodit.domain.protocols import TaskRepository
|
|
11
|
-
from kodit.domain.value_objects import TaskOperation
|
|
12
12
|
from kodit.infrastructure.mappers.task_mapper import TaskMapper
|
|
13
13
|
from kodit.infrastructure.sqlalchemy import entities as db_entities
|
|
14
|
+
from kodit.infrastructure.sqlalchemy.repository import SqlAlchemyRepository
|
|
14
15
|
from kodit.infrastructure.sqlalchemy.unit_of_work import SqlAlchemyUnitOfWork
|
|
15
16
|
|
|
16
17
|
|
|
@@ -21,7 +22,12 @@ def create_task_repository(
|
|
|
21
22
|
return SqlAlchemyTaskRepository(session_factory=session_factory)
|
|
22
23
|
|
|
23
24
|
|
|
24
|
-
|
|
25
|
+
# TODO(Phil): Stop using dedup_key as the primary key. Add some DDD to this instead.
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class SqlAlchemyTaskRepository(
|
|
29
|
+
SqlAlchemyRepository[domain_entities.Task, db_entities.Task], TaskRepository
|
|
30
|
+
):
|
|
25
31
|
"""Repository for task persistence using the existing Task entity."""
|
|
26
32
|
|
|
27
33
|
def __init__(self, session_factory: Callable[[], AsyncSession]) -> None:
|
|
@@ -29,25 +35,81 @@ class SqlAlchemyTaskRepository(TaskRepository):
|
|
|
29
35
|
self.session_factory = session_factory
|
|
30
36
|
self.log = structlog.get_logger(__name__)
|
|
31
37
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
38
|
+
@property
|
|
39
|
+
def db_entity_type(self) -> type[db_entities.Task]:
|
|
40
|
+
"""The SQLAlchemy model type."""
|
|
41
|
+
return db_entities.Task
|
|
42
|
+
|
|
43
|
+
def _get_id(self, entity: domain_entities.Task) -> Any:
|
|
44
|
+
"""Extract ID from domain entity."""
|
|
45
|
+
return entity.id
|
|
46
|
+
|
|
47
|
+
@staticmethod
|
|
48
|
+
def to_domain(db_entity: db_entities.Task) -> domain_entities.Task:
|
|
49
|
+
"""Map database entity to domain entity."""
|
|
50
|
+
return TaskMapper.to_domain_task(db_entity)
|
|
51
|
+
|
|
52
|
+
@staticmethod
|
|
53
|
+
def to_db(domain_entity: domain_entities.Task) -> db_entities.Task:
|
|
54
|
+
"""Map domain entity to database entity."""
|
|
55
|
+
return TaskMapper.from_domain_task(domain_entity)
|
|
56
|
+
|
|
57
|
+
async def get(self, entity_id: Any) -> domain_entities.Task:
|
|
58
|
+
"""Get entity by dedup_key."""
|
|
37
59
|
async with SqlAlchemyUnitOfWork(self.session_factory) as session:
|
|
38
|
-
|
|
60
|
+
stmt = select(db_entities.Task).where(
|
|
61
|
+
db_entities.Task.dedup_key == entity_id
|
|
62
|
+
)
|
|
63
|
+
result = await session.execute(stmt)
|
|
64
|
+
db_entity = result.scalar_one_or_none()
|
|
65
|
+
if not db_entity:
|
|
66
|
+
raise ValueError(f"Entity with id {entity_id} not found")
|
|
67
|
+
return self.to_domain(db_entity)
|
|
39
68
|
|
|
40
|
-
async def
|
|
41
|
-
"""
|
|
69
|
+
async def exists(self, entity_id: Any) -> bool:
|
|
70
|
+
"""Check if entity exists by dedup_key."""
|
|
42
71
|
async with SqlAlchemyUnitOfWork(self.session_factory) as session:
|
|
43
|
-
stmt = select(db_entities.Task).where(
|
|
72
|
+
stmt = select(db_entities.Task).where(
|
|
73
|
+
db_entities.Task.dedup_key == entity_id
|
|
74
|
+
)
|
|
44
75
|
result = await session.execute(stmt)
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
76
|
+
return result.scalar_one_or_none() is not None
|
|
77
|
+
|
|
78
|
+
async def save(self, entity: domain_entities.Task) -> domain_entities.Task:
|
|
79
|
+
"""Save entity (create new or update existing)."""
|
|
80
|
+
async with SqlAlchemyUnitOfWork(self.session_factory) as session:
|
|
81
|
+
# Query by dedup_key instead of primary key
|
|
82
|
+
stmt = select(db_entities.Task).where(
|
|
83
|
+
db_entities.Task.dedup_key == entity.id
|
|
84
|
+
)
|
|
85
|
+
result = await session.execute(stmt)
|
|
86
|
+
existing_db_entity = result.scalar_one_or_none()
|
|
87
|
+
|
|
88
|
+
if existing_db_entity:
|
|
89
|
+
# Update existing entity
|
|
90
|
+
new_db_entity = self.to_db(entity)
|
|
91
|
+
self._update_db_entity(existing_db_entity, new_db_entity)
|
|
92
|
+
db_entity = existing_db_entity
|
|
93
|
+
else:
|
|
94
|
+
# Create new entity
|
|
95
|
+
db_entity = self.to_db(entity)
|
|
96
|
+
session.add(db_entity)
|
|
97
|
+
|
|
98
|
+
await session.flush()
|
|
99
|
+
return self.to_domain(db_entity)
|
|
100
|
+
|
|
101
|
+
async def delete(self, entity: domain_entities.Task) -> None:
|
|
102
|
+
"""Remove entity by dedup_key."""
|
|
103
|
+
async with SqlAlchemyUnitOfWork(self.session_factory) as session:
|
|
104
|
+
stmt = select(db_entities.Task).where(
|
|
105
|
+
db_entities.Task.dedup_key == entity.id
|
|
106
|
+
)
|
|
107
|
+
result = await session.execute(stmt)
|
|
108
|
+
db_entity = result.scalar_one_or_none()
|
|
109
|
+
if db_entity:
|
|
110
|
+
await session.delete(db_entity)
|
|
49
111
|
|
|
50
|
-
async def next(self) -> Task | None:
|
|
112
|
+
async def next(self) -> domain_entities.Task | None:
|
|
51
113
|
"""Take a task for processing and remove it from the database."""
|
|
52
114
|
async with SqlAlchemyUnitOfWork(self.session_factory) as session:
|
|
53
115
|
stmt = (
|
|
@@ -60,44 +122,3 @@ class SqlAlchemyTaskRepository(TaskRepository):
|
|
|
60
122
|
if not db_task:
|
|
61
123
|
return None
|
|
62
124
|
return TaskMapper.to_domain_task(db_task)
|
|
63
|
-
|
|
64
|
-
async def remove(self, task: Task) -> None:
|
|
65
|
-
"""Remove a task from the database."""
|
|
66
|
-
async with SqlAlchemyUnitOfWork(self.session_factory) as session:
|
|
67
|
-
db_task = await session.scalar(
|
|
68
|
-
select(db_entities.Task).where(db_entities.Task.dedup_key == task.id)
|
|
69
|
-
)
|
|
70
|
-
if not db_task:
|
|
71
|
-
raise ValueError(f"Task not found: {task.id}")
|
|
72
|
-
await session.delete(db_task)
|
|
73
|
-
|
|
74
|
-
async def update(self, task: Task) -> None:
|
|
75
|
-
"""Update a task in the database."""
|
|
76
|
-
async with SqlAlchemyUnitOfWork(self.session_factory) as session:
|
|
77
|
-
stmt = select(db_entities.Task).where(db_entities.Task.dedup_key == task.id)
|
|
78
|
-
result = await session.execute(stmt)
|
|
79
|
-
db_task = result.scalar_one_or_none()
|
|
80
|
-
|
|
81
|
-
if not db_task:
|
|
82
|
-
raise ValueError(f"Task not found: {task.id}")
|
|
83
|
-
|
|
84
|
-
db_task.priority = task.priority
|
|
85
|
-
db_task.payload = task.payload
|
|
86
|
-
|
|
87
|
-
async def list(self, task_operation: TaskOperation | None = None) -> list[Task]:
|
|
88
|
-
"""List tasks with optional status filter."""
|
|
89
|
-
async with SqlAlchemyUnitOfWork(self.session_factory) as session:
|
|
90
|
-
stmt = select(db_entities.Task)
|
|
91
|
-
|
|
92
|
-
if task_operation:
|
|
93
|
-
stmt = stmt.where(db_entities.Task.type == task_operation.value)
|
|
94
|
-
|
|
95
|
-
stmt = stmt.order_by(
|
|
96
|
-
db_entities.Task.priority.desc(), db_entities.Task.created_at
|
|
97
|
-
)
|
|
98
|
-
|
|
99
|
-
result = await session.execute(stmt)
|
|
100
|
-
records = result.scalars().all()
|
|
101
|
-
|
|
102
|
-
# Convert to domain entities
|
|
103
|
-
return [TaskMapper.to_domain_task(record) for record in records]
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
"""Task repository for the task queue."""
|
|
2
2
|
|
|
3
3
|
from collections.abc import Callable
|
|
4
|
+
from typing import Any, override
|
|
4
5
|
|
|
5
|
-
import
|
|
6
|
-
from sqlalchemy import delete, select
|
|
6
|
+
from sqlalchemy import select
|
|
7
7
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
8
8
|
|
|
9
9
|
from kodit.domain import entities as domain_entities
|
|
10
10
|
from kodit.domain.protocols import TaskStatusRepository
|
|
11
11
|
from kodit.infrastructure.mappers.task_status_mapper import TaskStatusMapper
|
|
12
12
|
from kodit.infrastructure.sqlalchemy import entities as db_entities
|
|
13
|
+
from kodit.infrastructure.sqlalchemy.repository import SqlAlchemyRepository
|
|
13
14
|
from kodit.infrastructure.sqlalchemy.unit_of_work import SqlAlchemyUnitOfWork
|
|
14
15
|
|
|
15
16
|
|
|
@@ -20,52 +21,52 @@ def create_task_status_repository(
|
|
|
20
21
|
return SqlAlchemyTaskStatusRepository(session_factory=session_factory)
|
|
21
22
|
|
|
22
23
|
|
|
23
|
-
class SqlAlchemyTaskStatusRepository(
|
|
24
|
+
class SqlAlchemyTaskStatusRepository(
|
|
25
|
+
SqlAlchemyRepository[domain_entities.TaskStatus, db_entities.TaskStatus],
|
|
26
|
+
TaskStatusRepository,
|
|
27
|
+
):
|
|
24
28
|
"""Repository for persisting TaskStatus entities."""
|
|
25
29
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
self.log = structlog.get_logger(__name__)
|
|
30
|
+
@property
|
|
31
|
+
def db_entity_type(self) -> type[db_entities.TaskStatus]:
|
|
32
|
+
"""The SQLAlchemy model type."""
|
|
33
|
+
return db_entities.TaskStatus
|
|
31
34
|
|
|
32
|
-
|
|
35
|
+
def _get_id(self, entity: domain_entities.TaskStatus) -> Any:
|
|
36
|
+
"""Extract ID from domain entity."""
|
|
37
|
+
return entity.id
|
|
38
|
+
|
|
39
|
+
@staticmethod
|
|
40
|
+
def to_domain(
|
|
41
|
+
db_entity: db_entities.TaskStatus,
|
|
42
|
+
) -> domain_entities.TaskStatus:
|
|
43
|
+
"""Map database entity to domain entity."""
|
|
44
|
+
return TaskStatusMapper.to_domain_task_status(db_entity)
|
|
45
|
+
|
|
46
|
+
@staticmethod
|
|
47
|
+
def to_db(
|
|
48
|
+
domain_entity: domain_entities.TaskStatus,
|
|
49
|
+
) -> db_entities.TaskStatus:
|
|
50
|
+
"""Map domain entity to database entity."""
|
|
51
|
+
return TaskStatusMapper.from_domain_task_status(domain_entity)
|
|
52
|
+
|
|
53
|
+
@override
|
|
54
|
+
async def save(
|
|
55
|
+
self, entity: domain_entities.TaskStatus
|
|
56
|
+
) -> domain_entities.TaskStatus:
|
|
33
57
|
"""Save a TaskStatus to database."""
|
|
34
|
-
#
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
parent_result = await session.execute(parent_stmt)
|
|
41
|
-
existing_parent = parent_result.scalar_one_or_none()
|
|
42
|
-
|
|
43
|
-
if not existing_parent:
|
|
44
|
-
# Recursively save the parent first
|
|
45
|
-
await self.save(status.parent)
|
|
58
|
+
# Recursively convert parents to a list of domain entities, parents first
|
|
59
|
+
parents: list[domain_entities.TaskStatus] = []
|
|
60
|
+
current = entity
|
|
61
|
+
while current.parent is not None:
|
|
62
|
+
parents.insert(0, current.parent)
|
|
63
|
+
current = current.parent
|
|
46
64
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
)
|
|
53
|
-
result = await session.execute(stmt)
|
|
54
|
-
existing = result.scalar_one_or_none()
|
|
55
|
-
|
|
56
|
-
if not existing:
|
|
57
|
-
session.add(db_status)
|
|
58
|
-
else:
|
|
59
|
-
# Update existing record with new values
|
|
60
|
-
existing.operation = db_status.operation
|
|
61
|
-
existing.state = db_status.state
|
|
62
|
-
existing.error = db_status.error
|
|
63
|
-
existing.total = db_status.total
|
|
64
|
-
existing.current = db_status.current
|
|
65
|
-
existing.updated_at = db_status.updated_at
|
|
66
|
-
existing.parent = db_status.parent
|
|
67
|
-
existing.trackable_id = db_status.trackable_id
|
|
68
|
-
existing.trackable_type = db_status.trackable_type
|
|
65
|
+
# Add current entity to the end of the list
|
|
66
|
+
parents.append(entity)
|
|
67
|
+
|
|
68
|
+
await self.save_bulk(parents)
|
|
69
|
+
return entity
|
|
69
70
|
|
|
70
71
|
async def load_with_hierarchy(
|
|
71
72
|
self, trackable_type: str, trackable_id: int
|
|
@@ -80,12 +81,4 @@ class SqlAlchemyTaskStatusRepository(TaskStatusRepository):
|
|
|
80
81
|
db_statuses = list(result.scalars().all())
|
|
81
82
|
|
|
82
83
|
# Use mapper to convert and reconstruct hierarchy
|
|
83
|
-
return
|
|
84
|
-
|
|
85
|
-
async def delete(self, status: domain_entities.TaskStatus) -> None:
|
|
86
|
-
"""Delete a TaskStatus."""
|
|
87
|
-
async with SqlAlchemyUnitOfWork(self.session_factory) as session:
|
|
88
|
-
stmt = delete(db_entities.TaskStatus).where(
|
|
89
|
-
db_entities.TaskStatus.id == status.id,
|
|
90
|
-
)
|
|
91
|
-
await session.execute(stmt)
|
|
84
|
+
return TaskStatusMapper.to_domain_task_status_with_hierarchy(db_statuses)
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# ruff: noqa
|
|
2
|
+
"""refactorings
|
|
3
|
+
|
|
4
|
+
Revision ID: 4b1a3b2c8fa5
|
|
5
|
+
Revises: 19f8c7faf8b9
|
|
6
|
+
Create Date: 2025-10-29 13:38:10.737704
|
|
7
|
+
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from typing import Sequence, Union
|
|
11
|
+
|
|
12
|
+
from alembic import op
|
|
13
|
+
import sqlalchemy as sa
|
|
14
|
+
|
|
15
|
+
from kodit.domain.tracking.trackable import TrackableReferenceType
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
# revision identifiers, used by Alembic.
|
|
19
|
+
revision: str = "4b1a3b2c8fa5"
|
|
20
|
+
down_revision: Union[str, None] = "19f8c7faf8b9"
|
|
21
|
+
branch_labels: Union[str, Sequence[str], None] = None
|
|
22
|
+
depends_on: Union[str, Sequence[str], None] = None
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def upgrade() -> None:
|
|
26
|
+
"""Upgrade schema."""
|
|
27
|
+
op.drop_index("ix_commit_snippets_v2_commit_sha", table_name="commit_snippets_v2")
|
|
28
|
+
op.drop_index("ix_commit_snippets_v2_snippet_sha", table_name="commit_snippets_v2")
|
|
29
|
+
op.drop_table("commit_snippets_v2")
|
|
30
|
+
op.drop_index("ix_snippet_v2_files_blob_sha", table_name="snippet_v2_files")
|
|
31
|
+
op.drop_index("ix_snippet_v2_files_commit_sha", table_name="snippet_v2_files")
|
|
32
|
+
op.drop_index("ix_snippet_v2_files_file_path", table_name="snippet_v2_files")
|
|
33
|
+
op.drop_index("ix_snippet_v2_files_snippet_sha", table_name="snippet_v2_files")
|
|
34
|
+
op.drop_table("snippet_v2_files")
|
|
35
|
+
op.drop_index("ix_snippets_v2_extension", table_name="snippets_v2")
|
|
36
|
+
op.drop_table("snippets_v2")
|
|
37
|
+
op.drop_index("ix_git_tracking_branches_name", table_name="git_tracking_branches")
|
|
38
|
+
op.drop_index(
|
|
39
|
+
"ix_git_tracking_branches_repo_id", table_name="git_tracking_branches"
|
|
40
|
+
)
|
|
41
|
+
op.drop_table("git_tracking_branches")
|
|
42
|
+
|
|
43
|
+
# Use batch_alter_table for SQLite compatibility
|
|
44
|
+
with op.batch_alter_table("git_repos", schema=None) as batch_op:
|
|
45
|
+
# Add columns as nullable first
|
|
46
|
+
batch_op.add_column(
|
|
47
|
+
sa.Column("tracking_type", sa.String(length=255), nullable=True)
|
|
48
|
+
)
|
|
49
|
+
batch_op.add_column(
|
|
50
|
+
sa.Column("tracking_name", sa.String(length=255), nullable=True)
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
# Set default values for existing rows
|
|
54
|
+
op.execute(
|
|
55
|
+
f"UPDATE git_repos SET tracking_type = '{TrackableReferenceType.BRANCH}' WHERE tracking_type IS NULL"
|
|
56
|
+
)
|
|
57
|
+
op.execute(
|
|
58
|
+
f"UPDATE git_repos SET tracking_name = 'main' WHERE tracking_name IS NULL"
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
# Make columns non-nullable using batch_alter_table for SQLite compatibility
|
|
62
|
+
with op.batch_alter_table("git_repos", schema=None) as batch_op:
|
|
63
|
+
batch_op.alter_column("tracking_type", nullable=False)
|
|
64
|
+
batch_op.alter_column("tracking_name", nullable=False)
|
|
65
|
+
batch_op.create_index(
|
|
66
|
+
op.f("ix_git_repos_tracking_name"),
|
|
67
|
+
["tracking_name"],
|
|
68
|
+
unique=False,
|
|
69
|
+
)
|
|
70
|
+
batch_op.create_index(
|
|
71
|
+
op.f("ix_git_repos_tracking_type"),
|
|
72
|
+
["tracking_type"],
|
|
73
|
+
unique=False,
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def downgrade() -> None:
|
|
78
|
+
"""Downgrade schema."""
|
|
79
|
+
op.create_table(
|
|
80
|
+
"snippets_v2",
|
|
81
|
+
sa.Column("sha", sa.VARCHAR(length=64), nullable=False),
|
|
82
|
+
sa.Column("created_at", sa.DATETIME(), nullable=False),
|
|
83
|
+
sa.Column("updated_at", sa.DATETIME(), nullable=False),
|
|
84
|
+
sa.Column("content", sa.TEXT(), nullable=False),
|
|
85
|
+
sa.Column("extension", sa.VARCHAR(length=255), nullable=False),
|
|
86
|
+
sa.PrimaryKeyConstraint("sha"),
|
|
87
|
+
)
|
|
88
|
+
op.create_index(
|
|
89
|
+
"ix_snippets_v2_extension", "snippets_v2", ["extension"], unique=False
|
|
90
|
+
)
|
|
91
|
+
op.create_table(
|
|
92
|
+
"snippet_v2_files",
|
|
93
|
+
sa.Column("id", sa.INTEGER(), nullable=False),
|
|
94
|
+
sa.Column("snippet_sha", sa.VARCHAR(length=64), nullable=False),
|
|
95
|
+
sa.Column("blob_sha", sa.VARCHAR(length=64), nullable=False),
|
|
96
|
+
sa.Column("commit_sha", sa.VARCHAR(length=64), nullable=False),
|
|
97
|
+
sa.Column("file_path", sa.VARCHAR(length=1024), nullable=False),
|
|
98
|
+
sa.ForeignKeyConstraint(
|
|
99
|
+
["commit_sha", "file_path"],
|
|
100
|
+
["git_commit_files.commit_sha", "git_commit_files.path"],
|
|
101
|
+
),
|
|
102
|
+
sa.ForeignKeyConstraint(
|
|
103
|
+
["snippet_sha"],
|
|
104
|
+
["snippets_v2.sha"],
|
|
105
|
+
),
|
|
106
|
+
sa.PrimaryKeyConstraint("id"),
|
|
107
|
+
sa.UniqueConstraint(
|
|
108
|
+
"snippet_sha",
|
|
109
|
+
"blob_sha",
|
|
110
|
+
"commit_sha",
|
|
111
|
+
"file_path",
|
|
112
|
+
name="uix_snippet_file",
|
|
113
|
+
),
|
|
114
|
+
)
|
|
115
|
+
op.create_index(
|
|
116
|
+
"ix_snippet_v2_files_snippet_sha",
|
|
117
|
+
"snippet_v2_files",
|
|
118
|
+
["snippet_sha"],
|
|
119
|
+
unique=False,
|
|
120
|
+
)
|
|
121
|
+
op.create_index(
|
|
122
|
+
"ix_snippet_v2_files_file_path", "snippet_v2_files", ["file_path"], unique=False
|
|
123
|
+
)
|
|
124
|
+
op.create_index(
|
|
125
|
+
"ix_snippet_v2_files_commit_sha",
|
|
126
|
+
"snippet_v2_files",
|
|
127
|
+
["commit_sha"],
|
|
128
|
+
unique=False,
|
|
129
|
+
)
|
|
130
|
+
op.create_index(
|
|
131
|
+
"ix_snippet_v2_files_blob_sha", "snippet_v2_files", ["blob_sha"], unique=False
|
|
132
|
+
)
|
|
133
|
+
op.create_table(
|
|
134
|
+
"commit_snippets_v2",
|
|
135
|
+
sa.Column("id", sa.INTEGER(), nullable=False),
|
|
136
|
+
sa.Column("commit_sha", sa.VARCHAR(length=64), nullable=False),
|
|
137
|
+
sa.Column("snippet_sha", sa.VARCHAR(length=64), nullable=False),
|
|
138
|
+
sa.ForeignKeyConstraint(
|
|
139
|
+
["commit_sha"],
|
|
140
|
+
["git_commits.commit_sha"],
|
|
141
|
+
),
|
|
142
|
+
sa.ForeignKeyConstraint(
|
|
143
|
+
["snippet_sha"],
|
|
144
|
+
["snippets_v2.sha"],
|
|
145
|
+
),
|
|
146
|
+
sa.PrimaryKeyConstraint("id"),
|
|
147
|
+
sa.UniqueConstraint("commit_sha", "snippet_sha", name="uix_commit_snippet"),
|
|
148
|
+
)
|
|
149
|
+
op.create_index(
|
|
150
|
+
"ix_commit_snippets_v2_snippet_sha",
|
|
151
|
+
"commit_snippets_v2",
|
|
152
|
+
["snippet_sha"],
|
|
153
|
+
unique=False,
|
|
154
|
+
)
|
|
155
|
+
op.create_index(
|
|
156
|
+
"ix_commit_snippets_v2_commit_sha",
|
|
157
|
+
"commit_snippets_v2",
|
|
158
|
+
["commit_sha"],
|
|
159
|
+
unique=False,
|
|
160
|
+
)
|
|
161
|
+
# Use batch_alter_table for SQLite compatibility
|
|
162
|
+
with op.batch_alter_table("git_repos", schema=None) as batch_op:
|
|
163
|
+
batch_op.drop_index(op.f("ix_git_repos_tracking_type"))
|
|
164
|
+
batch_op.drop_index(op.f("ix_git_repos_tracking_name"))
|
|
165
|
+
batch_op.drop_column("tracking_name")
|
|
166
|
+
batch_op.drop_column("tracking_type")
|
|
167
|
+
|
|
168
|
+
op.create_table(
|
|
169
|
+
"git_tracking_branches",
|
|
170
|
+
sa.Column("repo_id", sa.INTEGER(), nullable=False),
|
|
171
|
+
sa.Column("name", sa.VARCHAR(length=255), nullable=False),
|
|
172
|
+
sa.Column("created_at", sa.DATETIME(), nullable=False),
|
|
173
|
+
sa.Column("updated_at", sa.DATETIME(), nullable=False),
|
|
174
|
+
sa.ForeignKeyConstraint(
|
|
175
|
+
["repo_id"], ["git_repos.id"], name="fk_tracking_branch_repo"
|
|
176
|
+
),
|
|
177
|
+
sa.PrimaryKeyConstraint("repo_id", "name", name="pk_git_tracking_branches"),
|
|
178
|
+
)
|
|
179
|
+
op.create_index(
|
|
180
|
+
"ix_git_tracking_branches_repo_id",
|
|
181
|
+
"git_tracking_branches",
|
|
182
|
+
["repo_id"],
|
|
183
|
+
unique=False,
|
|
184
|
+
)
|
|
185
|
+
op.create_index(
|
|
186
|
+
"ix_git_tracking_branches_name",
|
|
187
|
+
"git_tracking_branches",
|
|
188
|
+
["name"],
|
|
189
|
+
unique=False,
|
|
190
|
+
)
|