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
@@ -44,7 +44,9 @@ class GitRepositoryScanner:
44
44
  self._log = structlog.getLogger(__name__)
45
45
  self.git_adapter = git_adapter
46
46
 
47
- async def scan_repository(self, cloned_path: Path) -> RepositoryScanResult:
47
+ async def scan_repository(
48
+ self, cloned_path: Path, repo_id: int
49
+ ) -> RepositoryScanResult:
48
50
  """Scan repository and return immutable result data."""
49
51
  self._log.info(f"Starting repository scan at: {cloned_path}")
50
52
 
@@ -58,13 +60,16 @@ class GitRepositoryScanner:
58
60
 
59
61
  # Process branches efficiently using bulk commit data
60
62
  branches, commit_cache = await self._process_branches_bulk(
61
- cloned_path, branch_data, all_commits_data
63
+ cloned_path, branch_data, all_commits_data, repo_id
62
64
  )
63
65
  self._log.info(f"Found {len(branches)} branches")
64
- tags = await self._process_tags(cloned_path, commit_cache)
66
+ tags = await self._process_tags(cloned_path, commit_cache, repo_id)
65
67
  self._log.info(f"Found {len(tags)} tags")
66
68
 
67
- return self._create_scan_result(branches, commit_cache, tags)
69
+ all_files = await self._process_files(cloned_path, commit_cache)
70
+ self._log.info(f"Found {len(all_files)} files")
71
+
72
+ return self._create_scan_result(branches, commit_cache, tags, all_files)
68
73
 
69
74
  async def _process_commits_concurrently(
70
75
  self,
@@ -86,7 +91,7 @@ class GitRepositoryScanner:
86
91
  semaphore = asyncio.Semaphore(50) # Limit concurrent operations
87
92
 
88
93
  async def bounded_process(
89
- item: tuple[str, dict[str, Any]]
94
+ item: tuple[str, dict[str, Any]],
90
95
  ) -> tuple[str, GitCommit | None]:
91
96
  async with semaphore:
92
97
  return await process_single_commit(item[0], item[1])
@@ -112,6 +117,7 @@ class GitRepositoryScanner:
112
117
  cloned_path: Path,
113
118
  branch_data: list[dict],
114
119
  all_commits_data: dict[str, dict[str, Any]],
120
+ repo_id: int,
115
121
  ) -> tuple[list[GitBranch], dict[str, GitCommit]]:
116
122
  """Process branches efficiently using bulk commit data."""
117
123
  branches = []
@@ -124,7 +130,9 @@ class GitRepositoryScanner:
124
130
  self._log.info(f"Processing {len(all_commits_data)} commits (metadata only)")
125
131
 
126
132
  for commit_sha, commit_data in all_commits_data.items():
127
- git_commit = self._create_lightweight_git_commit(commit_data, current_time)
133
+ git_commit = self._create_lightweight_git_commit(
134
+ commit_data, current_time, repo_id
135
+ )
128
136
  if git_commit:
129
137
  commit_cache[commit_sha] = git_commit
130
138
 
@@ -139,9 +147,10 @@ class GitRepositoryScanner:
139
147
  if commit_shas and commit_shas[0] in commit_cache:
140
148
  head_commit = commit_cache[commit_shas[0]]
141
149
  branch = GitBranch(
150
+ repo_id=repo_id,
142
151
  created_at=current_time,
143
152
  name=branch_info["name"],
144
- head_commit=head_commit,
153
+ head_commit_sha=head_commit.commit_sha,
145
154
  )
146
155
  branches.append(branch)
147
156
  self._log.debug(f"Processed branch: {branch_info['name']}")
@@ -159,14 +168,14 @@ class GitRepositoryScanner:
159
168
  return branches, commit_cache
160
169
 
161
170
  async def _create_git_commit_from_data(
162
- self, cloned_path: Path, commit_data: dict[str, Any]
171
+ self, cloned_path: Path, commit_data: dict[str, Any], repo_id: int | None = None
163
172
  ) -> GitCommit | None:
164
173
  """Create GitCommit from pre-fetched commit data."""
165
174
  commit_sha = commit_data["sha"]
166
175
 
167
176
  # Get files for this commit
168
177
  files_data = await self.git_adapter.get_commit_files(cloned_path, commit_sha)
169
- files = self._create_git_files(cloned_path, files_data)
178
+ self._create_git_files(cloned_path, files_data, commit_sha)
170
179
  author = self._format_author_from_data(commit_data)
171
180
 
172
181
  # Cache datetime creation
@@ -175,10 +184,10 @@ class GitRepositoryScanner:
175
184
  return GitCommit(
176
185
  created_at=created_at,
177
186
  commit_sha=commit_sha,
187
+ repo_id=repo_id or 0, # Use 0 as default if not provided
178
188
  date=commit_data["date"],
179
189
  message=commit_data["message"],
180
190
  parent_commit_sha=commit_data["parent_sha"],
181
- files=files,
182
191
  author=author,
183
192
  )
184
193
 
@@ -191,7 +200,7 @@ class GitRepositoryScanner:
191
200
  return author_name or "Unknown"
192
201
 
193
202
  def _create_lightweight_git_commit(
194
- self, commit_data: dict[str, Any], created_at: datetime
203
+ self, commit_data: dict[str, Any], created_at: datetime, repo_id: int | None
195
204
  ) -> GitCommit | None:
196
205
  """Create a GitCommit without expensive file data fetching."""
197
206
  try:
@@ -203,10 +212,10 @@ class GitRepositoryScanner:
203
212
  return GitCommit(
204
213
  created_at=created_at,
205
214
  commit_sha=commit_sha,
215
+ repo_id=repo_id or 0, # Use 0 as default if not provided
206
216
  date=commit_data["date"],
207
217
  message=commit_data["message"],
208
218
  parent_commit_sha=commit_data["parent_sha"],
209
- files=[], # Empty for performance - load on demand
210
219
  author=author,
211
220
  )
212
221
  except Exception as e: # noqa: BLE001
@@ -214,7 +223,7 @@ class GitRepositoryScanner:
214
223
  return None
215
224
 
216
225
  async def _process_branches(
217
- self, cloned_path: Path, branch_data: list[dict]
226
+ self, cloned_path: Path, branch_data: list[dict], repo_id: int
218
227
  ) -> tuple[list[GitBranch], dict[str, GitCommit]]:
219
228
  """Process branches and return branches with commit cache."""
220
229
  branches = []
@@ -222,7 +231,7 @@ class GitRepositoryScanner:
222
231
 
223
232
  for branch_info in branch_data:
224
233
  branch = await self._process_single_branch(
225
- cloned_path, branch_info, commit_cache
234
+ cloned_path, branch_info, commit_cache, repo_id
226
235
  )
227
236
  if branch:
228
237
  branches.append(branch)
@@ -234,6 +243,7 @@ class GitRepositoryScanner:
234
243
  cloned_path: Path,
235
244
  branch_info: dict,
236
245
  commit_cache: dict[str, GitCommit],
246
+ repo_id: int,
237
247
  ) -> GitBranch | None:
238
248
  """Process a single branch and return GitBranch or None."""
239
249
  self._log.info(f"Processing branch: {branch_info['name']}")
@@ -246,21 +256,19 @@ class GitRepositoryScanner:
246
256
  self._log.warning(f"No commits found for branch {branch_info['name']}")
247
257
  return None
248
258
 
249
- head_commit = await self._process_branch_commits(
250
- cloned_path, commits_data, commit_cache
251
- )
259
+ head_commit = await self._process_branch_commits(commits_data, commit_cache)
252
260
 
253
261
  if head_commit:
254
262
  return GitBranch(
263
+ repo_id=repo_id,
255
264
  created_at=datetime.now(UTC),
256
265
  name=branch_info["name"],
257
- head_commit=head_commit,
266
+ head_commit_sha=head_commit.commit_sha,
258
267
  )
259
268
  return None
260
269
 
261
270
  async def _process_branch_commits(
262
271
  self,
263
- cloned_path: Path,
264
272
  commits_data: list[dict],
265
273
  commit_cache: dict[str, GitCommit],
266
274
  ) -> GitCommit | None:
@@ -276,7 +284,7 @@ class GitRepositoryScanner:
276
284
  head_commit = commit_cache[commit_sha]
277
285
  continue
278
286
 
279
- git_commit = await self._create_git_commit(cloned_path, commit_data)
287
+ git_commit = await self._create_git_commit(commit_data)
280
288
  if git_commit:
281
289
  commit_cache[commit_sha] = git_commit
282
290
  if head_commit is None:
@@ -285,27 +293,25 @@ class GitRepositoryScanner:
285
293
  return head_commit
286
294
 
287
295
  async def _create_git_commit(
288
- self, cloned_path: Path, commit_data: dict
296
+ self, commit_data: dict, repo_id: int | None = None
289
297
  ) -> GitCommit | None:
290
298
  """Create GitCommit from commit data."""
291
299
  commit_sha = commit_data["sha"]
292
300
 
293
- files_data = await self.git_adapter.get_commit_files(cloned_path, commit_sha)
294
- files = self._create_git_files(cloned_path, files_data)
295
301
  author = self._format_author(commit_data)
296
302
 
297
303
  return GitCommit(
298
304
  created_at=datetime.now(UTC),
299
305
  commit_sha=commit_sha,
306
+ repo_id=repo_id or 0, # Use 0 as default if not provided
300
307
  date=commit_data["date"],
301
308
  message=commit_data["message"],
302
309
  parent_commit_sha=commit_data["parent_sha"],
303
- files=files,
304
310
  author=author,
305
311
  )
306
312
 
307
313
  def _create_git_files(
308
- self, cloned_path: Path, files_data: list[dict]
314
+ self, cloned_path: Path, files_data: list[dict], commit_sha: str
309
315
  ) -> list[GitFile]:
310
316
  """Create GitFile entities from files data."""
311
317
  # Cache expensive path operations
@@ -318,14 +324,17 @@ class GitRepositoryScanner:
318
324
  file_path = f["path"]
319
325
  full_path = f"{cloned_path_str}/{file_path}"
320
326
 
321
- result.append(GitFile(
322
- blob_sha=f["blob_sha"],
323
- path=full_path,
324
- mime_type=f.get("mime_type", "application/octet-stream"),
325
- size=f["size"],
326
- extension=GitFile.extension_from_path(file_path),
327
- created_at=f.get("created_at", current_time),
328
- ))
327
+ result.append(
328
+ GitFile(
329
+ blob_sha=f["blob_sha"],
330
+ commit_sha=commit_sha,
331
+ path=full_path,
332
+ mime_type=f.get("mime_type", "application/octet-stream"),
333
+ size=f["size"],
334
+ extension=GitFile.extension_from_path(file_path),
335
+ created_at=f.get("created_at", current_time),
336
+ )
337
+ )
329
338
  return result
330
339
 
331
340
  def _format_author(self, commit_data: dict) -> str:
@@ -337,7 +346,7 @@ class GitRepositoryScanner:
337
346
  return author_name or "Unknown"
338
347
 
339
348
  async def _process_tags(
340
- self, cloned_path: Path, commit_cache: dict[str, GitCommit]
349
+ self, cloned_path: Path, commit_cache: dict[str, GitCommit], repo_id: int
341
350
  ) -> list[GitTag]:
342
351
  """Process repository tags."""
343
352
  tag_data = await self.git_adapter.get_all_tags(cloned_path)
@@ -346,8 +355,9 @@ class GitRepositoryScanner:
346
355
  try:
347
356
  target_commit = commit_cache[tag_info["target_commit_sha"]]
348
357
  git_tag = GitTag(
358
+ repo_id=repo_id,
349
359
  name=tag_info["name"],
350
- target_commit=target_commit,
360
+ target_commit_sha=target_commit.commit_sha,
351
361
  created_at=target_commit.created_at or datetime.now(UTC),
352
362
  updated_at=target_commit.updated_at or datetime.now(UTC),
353
363
  )
@@ -366,17 +376,17 @@ class GitRepositoryScanner:
366
376
  branches: list[GitBranch],
367
377
  commit_cache: dict[str, GitCommit],
368
378
  tags: list[GitTag],
379
+ all_files: list[GitFile],
369
380
  ) -> RepositoryScanResult:
370
381
  """Create final scan result."""
371
382
  # Files are loaded on-demand for performance, so total_files is 0 during scan
372
- total_files = 0
373
-
374
383
  scan_result = RepositoryScanResult(
375
384
  branches=branches,
376
385
  all_commits=list(commit_cache.values()),
377
386
  scan_timestamp=datetime.now(UTC),
378
- total_files_across_commits=total_files,
387
+ total_files_across_commits=len(all_files),
379
388
  all_tags=tags,
389
+ all_files=all_files,
380
390
  )
381
391
 
382
392
  self._log.info(
@@ -385,6 +395,18 @@ class GitRepositoryScanner:
385
395
  )
386
396
  return scan_result
387
397
 
398
+ async def _process_files(
399
+ self, cloned_path: Path, commit_cache: dict[str, GitCommit]
400
+ ) -> list[GitFile]:
401
+ """Process files for a commit."""
402
+ files = []
403
+ for commit_sha in commit_cache:
404
+ files_data = await self.git_adapter.get_commit_files(
405
+ cloned_path, commit_sha
406
+ )
407
+ files.extend(self._create_git_files(cloned_path, files_data, commit_sha))
408
+ return files
409
+
388
410
 
389
411
  class RepositoryCloner:
390
412
  """Pure service for cloning repositories."""
@@ -120,22 +120,22 @@ class GitService:
120
120
  # Get current branch as tracking branch
121
121
  try:
122
122
  current_branch = repo.active_branch
123
- tracking_branch = next(
124
- (b for b in branches if b.name == current_branch.name),
125
- branches[0] if branches else None,
123
+ tracking_branch_name = next(
124
+ (b.name for b in branches if b.name == current_branch.name),
125
+ branches[0].name if branches else None,
126
126
  )
127
127
  except (AttributeError, TypeError):
128
128
  # Handle detached HEAD state or other branch access issues
129
- tracking_branch = branches[0] if branches else None
129
+ tracking_branch_name = branches[0].name if branches else None
130
130
 
131
- if tracking_branch is None:
131
+ if tracking_branch_name is None:
132
132
  raise ValueError("No branches found in repository")
133
133
 
134
134
  return GitRepoFactory.create_from_path_scan(
135
135
  remote_uri=remote_uri,
136
136
  sanitized_remote_uri=sanitized_remote_uri,
137
137
  repo_path=repo_path,
138
- tracking_branch=tracking_branch,
138
+ tracking_branch_name=tracking_branch_name,
139
139
  last_scanned_at=datetime.now(UTC),
140
140
  num_commits=num_commits,
141
141
  num_branches=len(branches),
@@ -182,7 +182,13 @@ class GitService:
182
182
  try:
183
183
  # Get head commit for this branch
184
184
  head_commit = self._convert_commit(repo, branch.commit)
185
- branches.append(GitBranch(name=branch.name, head_commit=head_commit))
185
+ branches.append(
186
+ GitBranch(
187
+ name=branch.name,
188
+ head_commit_sha=head_commit.commit_sha,
189
+ repo_id=0, # No repo context yet, use placeholder
190
+ )
191
+ )
186
192
  except Exception: # noqa: BLE001, S112
187
193
  # Skip branches that can't be accessed
188
194
  continue
@@ -210,7 +216,7 @@ class GitService:
210
216
  def _get_all_tags(self, repo: Repo) -> list[GitTag]:
211
217
  """Get all tags in the repository."""
212
218
  all_commits = self._get_all_commits(repo)
213
- all_commits_map = {commit.commit_sha: commit for commit in all_commits}
219
+ {commit.commit_sha: commit for commit in all_commits}
214
220
  tags = []
215
221
  try:
216
222
  for tag_ref in repo.tags:
@@ -221,7 +227,7 @@ class GitService:
221
227
  tag = GitTag(
222
228
  created_at=datetime.now(UTC),
223
229
  name=tag_ref.name,
224
- target_commit=all_commits_map[target_commit.hexsha],
230
+ target_commit_sha=target_commit.hexsha,
225
231
  )
226
232
  tags.append(tag)
227
233
  except Exception: # noqa: BLE001, S112
@@ -242,7 +248,7 @@ class GitService:
242
248
  parent_sha = commit.parents[0].hexsha if commit.parents else ""
243
249
 
244
250
  # Get files changed in this commit
245
- files = self._get_commit_files(repo, commit)
251
+ self._get_commit_files(repo, commit)
246
252
 
247
253
  # Format author string from name and email
248
254
  author_name = str(commit.author.name) if commit.author.name else ""
@@ -254,10 +260,10 @@ class GitService:
254
260
 
255
261
  return GitCommit(
256
262
  commit_sha=commit.hexsha,
263
+ repo_id=0, # GitService doesn't have repo context, use placeholder
257
264
  date=commit_date,
258
265
  message=str(commit.message).strip(),
259
266
  parent_commit_sha=parent_sha,
260
- files=files,
261
267
  author=author,
262
268
  )
263
269
 
@@ -283,6 +289,7 @@ class GitService:
283
289
  file_entity = GitFile(
284
290
  created_at=datetime.now(UTC),
285
291
  blob_sha=blob.hexsha,
292
+ commit_sha=commit.hexsha,
286
293
  path=str(Path(repo.working_dir) / file_path),
287
294
  mime_type="application/octet-stream", # Default
288
295
  size=blob.size,
@@ -43,30 +43,20 @@ class TrackableResolutionService:
43
43
  # COMMIT_SHA
44
44
  return [trackable.identifier]
45
45
 
46
- async def _resolve_branch(
47
- self, trackable: Trackable, limit: int
48
- ) -> list[str]:
46
+ async def _resolve_branch(self, trackable: Trackable, limit: int) -> list[str]:
49
47
  """Get commits from branch HEAD backwards through history."""
50
48
  branch = await self.branch_repo.get_by_name(
51
49
  trackable.identifier, trackable.repo_id
52
50
  )
53
51
  # Walk commit history from head_commit backwards
54
- return await self._walk_commit_history(
55
- branch.head_commit.commit_sha, limit
56
- )
52
+ return await self._walk_commit_history(branch.head_commit_sha, limit)
57
53
 
58
54
  async def _resolve_tag(self, trackable: Trackable, limit: int) -> list[str]:
59
55
  """Get commits from tag target backwards through history."""
60
- tag = await self.tag_repo.get_by_name(
61
- trackable.identifier, trackable.repo_id
62
- )
63
- return await self._walk_commit_history(
64
- tag.target_commit.commit_sha, limit
65
- )
56
+ tag = await self.tag_repo.get_by_name(trackable.identifier, trackable.repo_id)
57
+ return await self._walk_commit_history(tag.target_commit_sha, limit)
66
58
 
67
- async def _walk_commit_history(
68
- self, start_sha: str, limit: int
69
- ) -> list[str]:
59
+ async def _walk_commit_history(self, start_sha: str, limit: int) -> list[str]:
70
60
  """Walk commit history backwards from start_sha."""
71
61
  result = []
72
62
  current_sha: str | None = start_sha
@@ -75,7 +65,7 @@ class TrackableResolutionService:
75
65
  if not current_sha:
76
66
  break
77
67
  result.append(current_sha)
78
- commit = await self.commit_repo.get_by_sha(current_sha)
68
+ commit = await self.commit_repo.get(current_sha)
79
69
  current_sha = commit.parent_commit_sha or None
80
70
 
81
71
  return result
@@ -25,18 +25,11 @@ class SnippetContentType(StrEnum):
25
25
  SUMMARY = "summary"
26
26
 
27
27
 
28
- class EnrichmentType(StrEnum):
29
- """Type of enrichment."""
30
-
31
- UNKNOWN = "unknown"
32
- SUMMARIZATION = "summarization"
33
-
34
-
35
28
  @dataclass(frozen=True)
36
29
  class Enrichment:
37
30
  """Enrichment domain value object."""
38
31
 
39
- type: EnrichmentType
32
+ type: str
40
33
  content: str
41
34
 
42
35
 
@@ -163,7 +156,7 @@ class DocumentSearchResult:
163
156
  score: float
164
157
 
165
158
 
166
- @dataclass
159
+ @dataclass(frozen=True)
167
160
  class SearchResult:
168
161
  """Generic search result model."""
169
162
 
@@ -21,6 +21,7 @@ from kodit.config import AppContext
21
21
  from kodit.domain.protocols import (
22
22
  GitBranchRepository,
23
23
  GitCommitRepository,
24
+ GitFileRepository,
24
25
  GitRepoRepository,
25
26
  GitTagRepository,
26
27
  )
@@ -131,9 +132,7 @@ async def get_git_tag_repository(
131
132
  return server_factory.git_tag_repository()
132
133
 
133
134
 
134
- GitTagRepositoryDep = Annotated[
135
- GitTagRepository, Depends(get_git_tag_repository)
136
- ]
135
+ GitTagRepositoryDep = Annotated[GitTagRepository, Depends(get_git_tag_repository)]
137
136
 
138
137
 
139
138
  async def get_commit_indexing_app_service(
@@ -170,3 +169,13 @@ async def get_enrichment_query_service(
170
169
  EnrichmentQueryServiceDep = Annotated[
171
170
  EnrichmentQueryService, Depends(get_enrichment_query_service)
172
171
  ]
172
+
173
+
174
+ async def get_git_file_repository(
175
+ server_factory: ServerFactoryDep,
176
+ ) -> GitFileRepository:
177
+ """Get git file repository dependency."""
178
+ return server_factory.git_file_repository()
179
+
180
+
181
+ GitFileRepositoryDep = Annotated[GitFileRepository, Depends(get_git_file_repository)]
@@ -0,0 +1,27 @@
1
+ """Query parameters for the API."""
2
+
3
+ from typing import Annotated
4
+
5
+ from fastapi import Depends, Query
6
+
7
+
8
+ class PaginationParams:
9
+ """Pagination parameters for the API."""
10
+
11
+ def __init__(
12
+ self,
13
+ page: Annotated[
14
+ int, Query(ge=1, description="Page number, starting from 1")
15
+ ] = 1,
16
+ page_size: Annotated[
17
+ int, Query(ge=1, le=100, description="Items per page")
18
+ ] = 20,
19
+ ) -> None:
20
+ """Initialize pagination parameters."""
21
+ self.page = page
22
+ self.page_size = page_size
23
+ self.offset = (page - 1) * page_size
24
+ self.limit = page_size
25
+
26
+
27
+ PaginationParamsDep = Annotated[PaginationParams, Depends()]