kodit 0.5.3__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.

Files changed (55) hide show
  1. kodit/_version.py +2 -2
  2. kodit/application/factories/server_factory.py +54 -32
  3. kodit/application/services/code_search_application_service.py +89 -12
  4. kodit/application/services/commit_indexing_application_service.py +314 -195
  5. kodit/application/services/enrichment_query_service.py +274 -43
  6. kodit/application/services/indexing_worker_service.py +1 -1
  7. kodit/application/services/queue_service.py +15 -10
  8. kodit/application/services/sync_scheduler.py +2 -1
  9. kodit/domain/enrichments/architecture/architecture.py +1 -1
  10. kodit/domain/enrichments/architecture/physical/physical.py +1 -1
  11. kodit/domain/enrichments/development/development.py +1 -1
  12. kodit/domain/enrichments/development/snippet/snippet.py +12 -5
  13. kodit/domain/enrichments/enrichment.py +31 -4
  14. kodit/domain/enrichments/usage/api_docs.py +1 -1
  15. kodit/domain/enrichments/usage/usage.py +1 -1
  16. kodit/domain/entities/git.py +30 -25
  17. kodit/domain/factories/git_repo_factory.py +20 -5
  18. kodit/domain/protocols.py +56 -125
  19. kodit/domain/services/embedding_service.py +14 -16
  20. kodit/domain/services/git_repository_service.py +60 -38
  21. kodit/domain/services/git_service.py +18 -11
  22. kodit/domain/tracking/resolution_service.py +6 -16
  23. kodit/domain/value_objects.py +2 -9
  24. kodit/infrastructure/api/v1/dependencies.py +12 -3
  25. kodit/infrastructure/api/v1/query_params.py +27 -0
  26. kodit/infrastructure/api/v1/routers/commits.py +91 -85
  27. kodit/infrastructure/api/v1/routers/repositories.py +53 -37
  28. kodit/infrastructure/api/v1/routers/search.py +1 -1
  29. kodit/infrastructure/api/v1/schemas/enrichment.py +14 -0
  30. kodit/infrastructure/api/v1/schemas/repository.py +1 -1
  31. kodit/infrastructure/providers/litellm_provider.py +23 -1
  32. kodit/infrastructure/slicing/api_doc_extractor.py +0 -2
  33. kodit/infrastructure/sqlalchemy/embedding_repository.py +44 -34
  34. kodit/infrastructure/sqlalchemy/enrichment_association_repository.py +73 -0
  35. kodit/infrastructure/sqlalchemy/enrichment_v2_repository.py +116 -97
  36. kodit/infrastructure/sqlalchemy/entities.py +12 -116
  37. kodit/infrastructure/sqlalchemy/git_branch_repository.py +52 -244
  38. kodit/infrastructure/sqlalchemy/git_commit_repository.py +35 -324
  39. kodit/infrastructure/sqlalchemy/git_file_repository.py +70 -0
  40. kodit/infrastructure/sqlalchemy/git_repository.py +60 -230
  41. kodit/infrastructure/sqlalchemy/git_tag_repository.py +53 -240
  42. kodit/infrastructure/sqlalchemy/query.py +331 -0
  43. kodit/infrastructure/sqlalchemy/repository.py +203 -0
  44. kodit/infrastructure/sqlalchemy/task_repository.py +79 -58
  45. kodit/infrastructure/sqlalchemy/task_status_repository.py +45 -52
  46. kodit/migrations/versions/4b1a3b2c8fa5_refactor_git_tracking.py +190 -0
  47. {kodit-0.5.3.dist-info → kodit-0.5.5.dist-info}/METADATA +1 -1
  48. {kodit-0.5.3.dist-info → kodit-0.5.5.dist-info}/RECORD +51 -49
  49. kodit/infrastructure/mappers/enrichment_mapper.py +0 -83
  50. kodit/infrastructure/mappers/git_mapper.py +0 -193
  51. kodit/infrastructure/mappers/snippet_mapper.py +0 -104
  52. kodit/infrastructure/sqlalchemy/snippet_v2_repository.py +0 -479
  53. {kodit-0.5.3.dist-info → kodit-0.5.5.dist-info}/WHEEL +0 -0
  54. {kodit-0.5.3.dist-info → kodit-0.5.5.dist-info}/entry_points.txt +0 -0
  55. {kodit-0.5.3.dist-info → kodit-0.5.5.dist-info}/licenses/LICENSE +0 -0
@@ -1,12 +1,15 @@
1
1
  """SQLAlchemy implementation of embedding repository."""
2
2
 
3
3
  from collections.abc import Callable
4
+ from typing import Any
4
5
 
5
6
  import numpy as np
6
7
  from sqlalchemy import select
7
8
  from sqlalchemy.ext.asyncio import AsyncSession
8
9
 
9
10
  from kodit.infrastructure.sqlalchemy.entities import Embedding, EmbeddingType
11
+ from kodit.infrastructure.sqlalchemy.query import FilterOperator, QueryBuilder
12
+ from kodit.infrastructure.sqlalchemy.repository import SqlAlchemyRepository
10
13
  from kodit.infrastructure.sqlalchemy.unit_of_work import SqlAlchemyUnitOfWork
11
14
 
12
15
 
@@ -17,68 +20,75 @@ def create_embedding_repository(
17
20
  return SqlAlchemyEmbeddingRepository(session_factory=session_factory)
18
21
 
19
22
 
20
- class SqlAlchemyEmbeddingRepository:
23
+ class SqlAlchemyEmbeddingRepository(SqlAlchemyRepository[Embedding, Embedding]):
21
24
  """SQLAlchemy implementation of embedding repository."""
22
25
 
23
- def __init__(self, session_factory: Callable[[], AsyncSession]) -> None:
24
- """Initialize the SQLAlchemy embedding repository."""
25
- self.session_factory = session_factory
26
+ @property
27
+ def db_entity_type(self) -> type[Embedding]:
28
+ """The SQLAlchemy model type."""
29
+ return Embedding
30
+
31
+ @staticmethod
32
+ def to_domain(db_entity: Embedding) -> Embedding:
33
+ """Map database entity to domain entity."""
34
+ return db_entity
35
+
36
+ @staticmethod
37
+ def to_db(domain_entity: Embedding) -> Embedding:
38
+ """Map domain entity to database entity."""
39
+ return domain_entity
40
+
41
+ def _get_id(self, entity: Embedding) -> Any:
42
+ """Extract ID from domain entity."""
43
+ return entity.id
26
44
 
27
45
  async def create_embedding(self, embedding: Embedding) -> None:
28
46
  """Create a new embedding record in the database."""
29
- async with SqlAlchemyUnitOfWork(self.session_factory) as session:
30
- session.add(embedding)
47
+ await self.save(embedding)
31
48
 
32
49
  async def get_embedding_by_snippet_id_and_type(
33
50
  self, snippet_id: int, embedding_type: EmbeddingType
34
51
  ) -> Embedding | None:
35
52
  """Get an embedding by its snippet ID and type."""
36
- async with SqlAlchemyUnitOfWork(self.session_factory) as session:
37
- query = select(Embedding).where(
38
- Embedding.snippet_id == snippet_id,
39
- Embedding.type == embedding_type,
40
- )
41
- result = await session.execute(query)
42
- return result.scalar_one_or_none()
53
+ query = (
54
+ QueryBuilder()
55
+ .filter("snippet_id", FilterOperator.EQ, snippet_id)
56
+ .filter("type", FilterOperator.EQ, embedding_type)
57
+ )
58
+ results = await self.find(query)
59
+ return results[0] if results else None
43
60
 
44
61
  async def list_embeddings_by_type(
45
62
  self, embedding_type: EmbeddingType
46
63
  ) -> list[Embedding]:
47
64
  """List all embeddings of a given type."""
48
- async with SqlAlchemyUnitOfWork(self.session_factory) as session:
49
- query = select(Embedding).where(Embedding.type == embedding_type)
50
- result = await session.execute(query)
51
- return list(result.scalars())
65
+ query = QueryBuilder().filter("type", FilterOperator.EQ, embedding_type)
66
+ return await self.find(query)
52
67
 
53
68
  async def delete_embeddings_by_snippet_id(self, snippet_id: str) -> None:
54
69
  """Delete all embeddings for a snippet."""
55
- async with SqlAlchemyUnitOfWork(self.session_factory) as session:
56
- query = select(Embedding).where(Embedding.snippet_id == snippet_id)
57
- result = await session.execute(query)
58
- embeddings = result.scalars().all()
59
- for embedding in embeddings:
60
- await session.delete(embedding)
70
+ query = QueryBuilder().filter("snippet_id", FilterOperator.EQ, snippet_id)
71
+ embeddings = await self.find(query)
72
+ for embedding in embeddings:
73
+ await self.delete(embedding)
61
74
 
62
75
  async def list_embeddings_by_snippet_ids_and_type(
63
76
  self, snippet_ids: list[str], embedding_type: EmbeddingType
64
77
  ) -> list[Embedding]:
65
78
  """Get all embeddings for the given snippet IDs."""
66
- async with SqlAlchemyUnitOfWork(self.session_factory) as session:
67
- query = select(Embedding).where(
68
- Embedding.snippet_id.in_(snippet_ids),
69
- Embedding.type == embedding_type,
70
- )
71
- result = await session.execute(query)
72
- return list(result.scalars())
79
+ query = (
80
+ QueryBuilder()
81
+ .filter("snippet_id", FilterOperator.IN, snippet_ids)
82
+ .filter("type", FilterOperator.EQ, embedding_type)
83
+ )
84
+ return await self.find(query)
73
85
 
74
86
  async def get_embeddings_by_snippet_ids(
75
87
  self, snippet_ids: list[str]
76
88
  ) -> list[Embedding]:
77
89
  """Get all embeddings for the given snippet IDs."""
78
- async with SqlAlchemyUnitOfWork(self.session_factory) as session:
79
- query = select(Embedding).where(Embedding.snippet_id.in_(snippet_ids))
80
- result = await session.execute(query)
81
- return list(result.scalars())
90
+ query = QueryBuilder().filter("snippet_id", FilterOperator.IN, snippet_ids)
91
+ return await self.find(query)
82
92
 
83
93
  async def list_semantic_results(
84
94
  self,
@@ -0,0 +1,73 @@
1
+ """Enrichment association repository."""
2
+
3
+ from collections.abc import Callable
4
+
5
+ import structlog
6
+ from sqlalchemy.ext.asyncio import AsyncSession
7
+
8
+ from kodit.domain.enrichments.enrichment import (
9
+ EnrichmentAssociation,
10
+ )
11
+ from kodit.domain.protocols import EnrichmentAssociationRepository
12
+ from kodit.infrastructure.sqlalchemy import entities as db_entities
13
+ from kodit.infrastructure.sqlalchemy.repository import SqlAlchemyRepository
14
+
15
+
16
+ def create_enrichment_association_repository(
17
+ session_factory: Callable[[], AsyncSession],
18
+ ) -> EnrichmentAssociationRepository:
19
+ """Create a enrichment association repository."""
20
+ return SQLAlchemyEnrichmentAssociationRepository(session_factory=session_factory)
21
+
22
+
23
+ class SQLAlchemyEnrichmentAssociationRepository(
24
+ SqlAlchemyRepository[EnrichmentAssociation, db_entities.EnrichmentAssociation],
25
+ EnrichmentAssociationRepository,
26
+ ):
27
+ """Repository for managing enrichment associations."""
28
+
29
+ def __init__(self, session_factory: Callable[[], AsyncSession]) -> None:
30
+ """Initialize the repository."""
31
+ super().__init__(session_factory=session_factory)
32
+ self._log = structlog.get_logger(__name__)
33
+
34
+ def _get_id(self, entity: EnrichmentAssociation) -> int | None:
35
+ """Get the ID of an enrichment association."""
36
+ return entity.id
37
+
38
+ @property
39
+ def db_entity_type(self) -> type[db_entities.EnrichmentAssociation]:
40
+ """The SQLAlchemy model type."""
41
+ return db_entities.EnrichmentAssociation
42
+
43
+ @staticmethod
44
+ def to_domain(
45
+ db_entity: db_entities.EnrichmentAssociation,
46
+ ) -> EnrichmentAssociation:
47
+ """Map database entity to domain entity."""
48
+ return EnrichmentAssociation(
49
+ enrichment_id=db_entity.enrichment_id,
50
+ entity_type=db_entity.entity_type,
51
+ entity_id=db_entity.entity_id,
52
+ id=db_entity.id,
53
+ )
54
+
55
+ @staticmethod
56
+ def to_db(
57
+ domain_entity: EnrichmentAssociation,
58
+ ) -> db_entities.EnrichmentAssociation:
59
+ """Map domain entity to database entity."""
60
+ from datetime import UTC, datetime
61
+
62
+ now = datetime.now(UTC)
63
+ db_entity = db_entities.EnrichmentAssociation(
64
+ enrichment_id=domain_entity.enrichment_id,
65
+ entity_type=domain_entity.entity_type,
66
+ entity_id=domain_entity.entity_id,
67
+ )
68
+ if domain_entity.id is not None:
69
+ db_entity.id = domain_entity.id
70
+ # Always set timestamps since domain entity doesn't track them
71
+ db_entity.created_at = now
72
+ db_entity.updated_at = now
73
+ return db_entity
@@ -1,118 +1,137 @@
1
1
  """EnrichmentV2 repository."""
2
2
 
3
- from collections.abc import Callable, Sequence
3
+ from collections.abc import Callable
4
4
 
5
- import structlog
6
- from sqlalchemy import delete, select
7
5
  from sqlalchemy.ext.asyncio import AsyncSession
8
6
 
7
+ from kodit.domain.enrichments.architecture.architecture import (
8
+ ENRICHMENT_TYPE_ARCHITECTURE,
9
+ )
10
+ from kodit.domain.enrichments.architecture.physical.physical import (
11
+ ENRICHMENT_SUBTYPE_PHYSICAL,
12
+ PhysicalArchitectureEnrichment,
13
+ )
14
+ from kodit.domain.enrichments.development.development import ENRICHMENT_TYPE_DEVELOPMENT
15
+ from kodit.domain.enrichments.development.snippet.snippet import (
16
+ ENRICHMENT_SUBTYPE_SNIPPET,
17
+ ENRICHMENT_SUBTYPE_SNIPPET_SUMMARY,
18
+ SnippetEnrichment,
19
+ SnippetEnrichmentSummary,
20
+ )
9
21
  from kodit.domain.enrichments.enrichment import EnrichmentV2
10
- from kodit.infrastructure.mappers.enrichment_mapper import EnrichmentMapper
22
+ from kodit.domain.enrichments.usage.api_docs import (
23
+ ENRICHMENT_SUBTYPE_API_DOCS,
24
+ APIDocEnrichment,
25
+ )
26
+ from kodit.domain.enrichments.usage.usage import ENRICHMENT_TYPE_USAGE
27
+ from kodit.domain.protocols import EnrichmentV2Repository
11
28
  from kodit.infrastructure.sqlalchemy import entities as db_entities
29
+ from kodit.infrastructure.sqlalchemy.repository import SqlAlchemyRepository
12
30
  from kodit.infrastructure.sqlalchemy.unit_of_work import SqlAlchemyUnitOfWork
13
31
 
14
32
 
15
- class EnrichmentV2Repository:
33
+ def create_enrichment_v2_repository(
34
+ session_factory: Callable[[], AsyncSession],
35
+ ) -> EnrichmentV2Repository:
36
+ """Create a enrichment v2 repository."""
37
+ return SQLAlchemyEnrichmentV2Repository(session_factory=session_factory)
38
+
39
+
40
+ class SQLAlchemyEnrichmentV2Repository(
41
+ SqlAlchemyRepository[EnrichmentV2, db_entities.EnrichmentV2], EnrichmentV2Repository
42
+ ):
16
43
  """Repository for managing enrichments and their associations."""
17
44
 
18
- def __init__(
19
- self,
20
- session_factory: Callable[[], AsyncSession],
21
- ) -> None:
22
- """Initialize the repository."""
23
- self.session_factory = session_factory
24
- self.mapper = EnrichmentMapper()
25
- self.log = structlog.get_logger(__name__)
45
+ def _get_id(self, entity: EnrichmentV2) -> int | None:
46
+ """Extract ID from domain entity."""
47
+ return entity.id
26
48
 
27
- async def enrichments_for_entity_type(
28
- self,
29
- entity_type: str,
30
- entity_ids: list[str],
31
- ) -> list[EnrichmentV2]:
32
- """Get all enrichments for multiple entities of the same type."""
33
- if not entity_ids:
34
- return []
49
+ @property
50
+ def db_entity_type(self) -> type[db_entities.EnrichmentV2]:
51
+ """The SQLAlchemy model type."""
52
+ return db_entities.EnrichmentV2
35
53
 
54
+ async def save(self, entity: EnrichmentV2) -> EnrichmentV2:
55
+ """Save entity (create new or update existing)."""
36
56
  async with SqlAlchemyUnitOfWork(self.session_factory) as session:
37
- stmt = (
38
- select(
39
- db_entities.EnrichmentV2,
40
- db_entities.EnrichmentAssociation.entity_id,
41
- )
42
- .join(db_entities.EnrichmentAssociation)
43
- .where(
44
- db_entities.EnrichmentAssociation.entity_type == entity_type,
45
- db_entities.EnrichmentAssociation.entity_id.in_(entity_ids),
46
- )
57
+ entity_id = self._get_id(entity)
58
+ # Skip session.get if entity_id is None (new entity not yet persisted)
59
+ existing_db_entity = (
60
+ await session.get(self.db_entity_type, entity_id)
61
+ if entity_id is not None
62
+ else None
47
63
  )
48
64
 
49
- result = await session.execute(stmt)
50
- rows = result.all()
51
-
52
- return [
53
- self.mapper.to_domain(db_enrichment, entity_type, entity_id)
54
- for db_enrichment, entity_id in rows
55
- ]
56
-
57
- async def bulk_save_enrichments(
58
- self,
59
- enrichments: Sequence[EnrichmentV2],
60
- ) -> None:
61
- """Bulk save enrichments with their associations."""
62
- if not enrichments:
63
- return
64
-
65
- async with SqlAlchemyUnitOfWork(self.session_factory) as session:
66
- enrichment_records = []
67
- for enrichment in enrichments:
68
- db_enrichment = db_entities.EnrichmentV2(
69
- type=enrichment.type,
70
- subtype=enrichment.subtype,
71
- content=enrichment.content,
72
- )
73
- session.add(db_enrichment)
74
- enrichment_records.append((enrichment, db_enrichment))
65
+ if existing_db_entity:
66
+ # Update existing entity
67
+ new_db_entity = self.to_db(entity)
68
+ self._update_db_entity(existing_db_entity, new_db_entity)
69
+ db_entity = existing_db_entity
70
+ else:
71
+ # Create new entity
72
+ db_entity = self.to_db(entity)
73
+ session.add(db_entity)
75
74
 
76
75
  await session.flush()
77
-
78
- for enrichment, db_enrichment in enrichment_records:
79
- db_association = db_entities.EnrichmentAssociation(
80
- enrichment_id=db_enrichment.id,
81
- entity_type=enrichment.entity_type_key(),
82
- entity_id=enrichment.entity_id,
83
- )
84
- session.add(db_association)
85
-
86
- async def bulk_delete_enrichments(
87
- self,
88
- entity_type: str,
89
- entity_ids: list[str],
90
- ) -> None:
91
- """Bulk delete enrichments for multiple entities of the same type."""
92
- if not entity_ids:
93
- return
94
-
95
- async with SqlAlchemyUnitOfWork(self.session_factory) as session:
96
- stmt = select(db_entities.EnrichmentAssociation.enrichment_id).where(
97
- db_entities.EnrichmentAssociation.entity_type == entity_type,
98
- db_entities.EnrichmentAssociation.entity_id.in_(entity_ids),
76
+ return self.to_domain(db_entity)
77
+
78
+ @staticmethod
79
+ def to_db(domain_entity: EnrichmentV2) -> db_entities.EnrichmentV2:
80
+ """Convert domain enrichment to database entity."""
81
+ enrichment = db_entities.EnrichmentV2(
82
+ type=domain_entity.type,
83
+ subtype=domain_entity.subtype,
84
+ content=domain_entity.content,
85
+ )
86
+ if domain_entity.id is not None:
87
+ enrichment.id = domain_entity.id
88
+ return enrichment
89
+
90
+ @staticmethod
91
+ def to_domain(db_entity: db_entities.EnrichmentV2) -> EnrichmentV2:
92
+ """Convert database enrichment to domain entity."""
93
+ # Use the stored type and subtype to determine the correct domain class
94
+ if (
95
+ db_entity.type == ENRICHMENT_TYPE_DEVELOPMENT
96
+ and db_entity.subtype == ENRICHMENT_SUBTYPE_SNIPPET_SUMMARY
97
+ ):
98
+ return SnippetEnrichmentSummary(
99
+ id=db_entity.id,
100
+ content=db_entity.content,
101
+ created_at=db_entity.created_at,
102
+ updated_at=db_entity.updated_at,
99
103
  )
100
- result = await session.execute(stmt)
101
- enrichment_ids = result.scalars().all()
102
-
103
- if enrichment_ids:
104
- await session.execute(
105
- delete(db_entities.EnrichmentV2).where(
106
- db_entities.EnrichmentV2.id.in_(enrichment_ids)
107
- )
108
- )
109
-
110
- async def delete_enrichment(self, enrichment_id: int) -> bool:
111
- """Delete a specific enrichment by ID."""
112
- async with SqlAlchemyUnitOfWork(self.session_factory) as session:
113
- result = await session.execute(
114
- delete(db_entities.EnrichmentV2).where(
115
- db_entities.EnrichmentV2.id == enrichment_id
116
- )
104
+ if (
105
+ db_entity.type == ENRICHMENT_TYPE_DEVELOPMENT
106
+ and db_entity.subtype == ENRICHMENT_SUBTYPE_SNIPPET
107
+ ):
108
+ return SnippetEnrichment(
109
+ id=db_entity.id,
110
+ content=db_entity.content,
111
+ created_at=db_entity.created_at,
112
+ updated_at=db_entity.updated_at,
113
+ )
114
+ if (
115
+ db_entity.type == ENRICHMENT_TYPE_USAGE
116
+ and db_entity.subtype == ENRICHMENT_SUBTYPE_API_DOCS
117
+ ):
118
+ return APIDocEnrichment(
119
+ id=db_entity.id,
120
+ content=db_entity.content,
121
+ created_at=db_entity.created_at,
122
+ updated_at=db_entity.updated_at,
117
123
  )
118
- return result.rowcount > 0
124
+ if (
125
+ db_entity.type == ENRICHMENT_TYPE_ARCHITECTURE
126
+ and db_entity.subtype == ENRICHMENT_SUBTYPE_PHYSICAL
127
+ ):
128
+ return PhysicalArchitectureEnrichment(
129
+ id=db_entity.id,
130
+ content=db_entity.content,
131
+ created_at=db_entity.created_at,
132
+ updated_at=db_entity.updated_at,
133
+ )
134
+
135
+ raise ValueError(
136
+ f"Unknown enrichment type: {db_entity.type}/{db_entity.subtype}"
137
+ )
@@ -9,7 +9,6 @@ from sqlalchemy import (
9
9
  DateTime,
10
10
  Float,
11
11
  ForeignKey,
12
- ForeignKeyConstraint,
13
12
  Index,
14
13
  Integer,
15
14
  String,
@@ -210,11 +209,15 @@ class GitRepo(Base, CommonMixin):
210
209
  num_commits: Mapped[int] = mapped_column(Integer, default=0)
211
210
  num_branches: Mapped[int] = mapped_column(Integer, default=0)
212
211
  num_tags: Mapped[int] = mapped_column(Integer, default=0)
212
+ tracking_type: Mapped[str] = mapped_column(String(255), index=True)
213
+ tracking_name: Mapped[str] = mapped_column(String(255), index=True)
213
214
 
214
215
  def __init__( # noqa: PLR0913
215
216
  self,
216
217
  sanitized_remote_uri: str,
217
218
  remote_uri: str,
219
+ tracking_type: str,
220
+ tracking_name: str,
218
221
  cloned_path: Path | None,
219
222
  last_scanned_at: datetime | None = None,
220
223
  num_commits: int = 0,
@@ -225,6 +228,8 @@ class GitRepo(Base, CommonMixin):
225
228
  super().__init__()
226
229
  self.sanitized_remote_uri = sanitized_remote_uri
227
230
  self.remote_uri = remote_uri
231
+ self.tracking_type = tracking_type
232
+ self.tracking_name = tracking_name
228
233
  self.cloned_path = cloned_path
229
234
  self.last_scanned_at = last_scanned_at
230
235
  self.num_commits = num_commits
@@ -293,7 +298,12 @@ class GitBranch(Base):
293
298
 
294
299
  __table_args__ = (UniqueConstraint("repo_id", "name", name="uix_repo_branch"),)
295
300
 
296
- def __init__(self, repo_id: int, name: str, head_commit_sha: str) -> None:
301
+ def __init__(
302
+ self,
303
+ repo_id: int,
304
+ name: str,
305
+ head_commit_sha: str,
306
+ ) -> None:
297
307
  """Initialize Git branch."""
298
308
  super().__init__()
299
309
  self.repo_id = repo_id
@@ -301,31 +311,6 @@ class GitBranch(Base):
301
311
  self.head_commit_sha = head_commit_sha
302
312
 
303
313
 
304
- class GitTrackingBranch(Base):
305
- """Git tracking branch model."""
306
-
307
- __tablename__ = "git_tracking_branches"
308
- repo_id: Mapped[int] = mapped_column(
309
- ForeignKey("git_repos.id"), index=True, primary_key=True
310
- )
311
- name: Mapped[str] = mapped_column(String(255), index=True, primary_key=True)
312
- created_at: Mapped[datetime] = mapped_column(
313
- TZDateTime, nullable=False, default=lambda: datetime.now(UTC)
314
- )
315
- updated_at: Mapped[datetime] = mapped_column(
316
- TZDateTime,
317
- nullable=False,
318
- default=lambda: datetime.now(UTC),
319
- onupdate=lambda: datetime.now(UTC),
320
- )
321
-
322
- def __init__(self, repo_id: int, name: str) -> None:
323
- """Initialize Git tracking branch."""
324
- super().__init__()
325
- self.repo_id = repo_id
326
- self.name = name
327
-
328
-
329
314
  class GitTag(Base):
330
315
  """Git tag model."""
331
316
 
@@ -395,95 +380,6 @@ class GitCommitFile(Base):
395
380
  self.extension = extension
396
381
 
397
382
 
398
- class SnippetV2(Base):
399
- """SnippetV2 model for commit-based snippets."""
400
-
401
- __tablename__ = "snippets_v2"
402
-
403
- sha: Mapped[str] = mapped_column(String(64), primary_key=True)
404
- created_at: Mapped[datetime] = mapped_column(
405
- TZDateTime, nullable=False, default=lambda: datetime.now(UTC)
406
- )
407
- updated_at: Mapped[datetime] = mapped_column(
408
- TZDateTime,
409
- nullable=False,
410
- default=lambda: datetime.now(UTC),
411
- onupdate=lambda: datetime.now(UTC),
412
- )
413
- content: Mapped[str] = mapped_column(UnicodeText)
414
- extension: Mapped[str] = mapped_column(String(255), index=True)
415
-
416
- def __init__(
417
- self,
418
- sha: str,
419
- content: str,
420
- extension: str,
421
- ) -> None:
422
- """Initialize snippet."""
423
- super().__init__()
424
- self.sha = sha
425
- self.content = content
426
- self.extension = extension
427
-
428
-
429
- class SnippetV2File(Base):
430
- """Association between snippets and files."""
431
-
432
- __tablename__ = "snippet_v2_files"
433
-
434
- id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
435
- snippet_sha: Mapped[str] = mapped_column(ForeignKey("snippets_v2.sha"), index=True)
436
- blob_sha: Mapped[str] = mapped_column(String(64), index=True)
437
- commit_sha: Mapped[str] = mapped_column(String(64), index=True)
438
- file_path: Mapped[str] = mapped_column(String(1024), index=True)
439
-
440
- __table_args__ = (
441
- ForeignKeyConstraint(
442
- ["commit_sha", "file_path"],
443
- ["git_commit_files.commit_sha", "git_commit_files.path"],
444
- ),
445
- UniqueConstraint(
446
- "snippet_sha",
447
- "blob_sha",
448
- "commit_sha",
449
- "file_path",
450
- name="uix_snippet_file",
451
- ),
452
- )
453
-
454
- def __init__(
455
- self, snippet_sha: str, blob_sha: str, commit_sha: str, file_path: str
456
- ) -> None:
457
- """Initialize snippet file association."""
458
- super().__init__()
459
- self.snippet_sha = snippet_sha
460
- self.blob_sha = blob_sha
461
- self.commit_sha = commit_sha
462
- self.file_path = file_path
463
-
464
-
465
- class CommitSnippetV2(Base):
466
- """Association table for commits and snippets v2."""
467
-
468
- __tablename__ = "commit_snippets_v2"
469
-
470
- id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
471
- commit_sha: Mapped[str] = mapped_column(
472
- ForeignKey("git_commits.commit_sha"), index=True
473
- )
474
- snippet_sha: Mapped[str] = mapped_column(ForeignKey("snippets_v2.sha"), index=True)
475
-
476
- __table_args__ = (
477
- UniqueConstraint("commit_sha", "snippet_sha", name="uix_commit_snippet"),
478
- )
479
-
480
- def __init__(self, commit_sha: str, snippet_sha: str) -> None:
481
- """Initialize commit snippet association."""
482
- super().__init__()
483
- self.commit_sha = commit_sha
484
- self.snippet_sha = snippet_sha
485
-
486
-
487
383
  class CommitIndex(Base):
488
384
  """Commit index model."""
489
385