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.
- 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/providers/litellm_provider.py +23 -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.3.dist-info → kodit-0.5.5.dist-info}/METADATA +1 -1
- {kodit-0.5.3.dist-info → kodit-0.5.5.dist-info}/RECORD +51 -49
- 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.3.dist-info → kodit-0.5.5.dist-info}/WHEEL +0 -0
- {kodit-0.5.3.dist-info → kodit-0.5.5.dist-info}/entry_points.txt +0 -0
- {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
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
|
|
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
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
-
|
|
49
|
-
|
|
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
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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
|
-
|
|
79
|
-
|
|
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
|
|
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.
|
|
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
|
-
|
|
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
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
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
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
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
|
-
|
|
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__(
|
|
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
|
|