1use rusqlite::Connection;
2
3#[path = "code_query.rs"]
4mod code_query;
5
6#[path = "code_query_prepare.rs"]
7mod code_query_prepare;
8
9#[path = "code_query_hits.rs"]
10mod code_query_hits;
11
12#[path = "code_feature_flags.rs"]
13mod code_feature_flags;
14
15#[path = "code_query_scope.rs"]
16mod code_query_scope;
17
18#[path = "code_impact.rs"]
19mod code_impact;
20
21#[path = "code_report.rs"]
22pub(super) mod code_report;
23
24#[path = "code_schema.rs"]
25mod code_schema;
26
27#[path = "code_status.rs"]
28mod code_status;
29
30#[path = "code_batch.rs"]
31mod code_batch;
32
33#[path = "code_cleanup.rs"]
34mod code_cleanup;
35
36#[path = "code_tasks.rs"]
37mod code_tasks;
38
39#[path = "code_search.rs"]
40mod code_search;
41
42#[path = "code_snapshot.rs"]
43mod code_snapshot;
44
45#[path = "code_set.rs"]
46mod code_set;
47
48#[path = "code_set_tasks.rs"]
49mod code_set_tasks;
50
51#[path = "software.rs"]
52mod software;
53
54#[cfg(test)]
55#[path = "code_tests.rs"]
56mod code_tests;
57
58#[cfg(test)]
59#[path = "code_snapshot_candidate_paths_tests.rs"]
60mod code_snapshot_candidate_paths_tests;
61
62#[cfg(test)]
63#[path = "code_incremental_search_tests.rs"]
64mod code_incremental_search_tests;
65
66#[cfg(test)]
67#[path = "code_batch_finalize_tests.rs"]
68mod code_batch_finalize_tests;
69
70#[cfg(test)]
71#[path = "code_batch_finalize_typescript_tests.rs"]
72mod code_batch_finalize_typescript_tests;
73
74#[cfg(test)]
75#[path = "code_cross_language_call_tests.rs"]
76mod code_cross_language_call_tests;
77
78#[cfg(test)]
79#[path = "code_batch_search_tests.rs"]
80mod code_batch_search_tests;
81
82#[cfg(test)]
83#[path = "code_snapshot_progress_tests.rs"]
84mod code_snapshot_progress_tests;
85
86#[cfg(test)]
87#[path = "code_query_accuracy_tests.rs"]
88mod code_query_accuracy_tests;
89
90#[cfg(test)]
91#[path = "code_query_import_target_tests.rs"]
92mod code_query_import_target_tests;
93
94#[cfg(test)]
95#[path = "code_query_import_ranking_tests.rs"]
96mod code_query_import_ranking_tests;
97
98#[cfg(test)]
99#[path = "code_query_sbom_tests.rs"]
100mod code_query_sbom_tests;
101
102#[cfg(test)]
103#[path = "code_query_line_context_tests.rs"]
104mod code_query_line_context_tests;
105
106#[cfg(test)]
107#[path = "code_metadata_tests.rs"]
108mod code_metadata_tests;
109
110#[cfg(test)]
111#[path = "code_tasks_tests.rs"]
112mod code_tasks_tests;
113
114#[cfg(test)]
115#[path = "code_set_tasks_tests.rs"]
116mod code_set_tasks_tests;
117
118#[cfg(test)]
119#[path = "code_set_tests.rs"]
120mod code_set_tests;
121
122use crate::{
123 domain::{
124 CodeFeatureFlagGraph, CodeFeatureFlagRequest, CodeFileFingerprint, CodeImpactRequest,
125 CodeIndexBatch, CodeIndexCheckpoint, CodeIndexSession, CodeIndexSnapshot, CodeIndexSummary,
126 CodeRepositoryRegistration, CodeRepositoryReport, CodeRepositoryStatus,
127 CodeRepositoryTotals, CodeRetrievalHit, CodeRetrievalRequest, SoftwareGlobalProjection,
128 SoftwareGlobalRequest,
129 },
130 storage::{CodeImpactChanges, CodeRepositoryStore, StorageError, StorageFuture},
131};
132
133use super::SqliteGraphStore;
134pub(super) use code_search::SearchDocumentInserter;
135
136const MAX_SYMBOL_SIGNATURE_LOOKUP_IDS_PER_STATEMENT: usize = 500;
137
138pub(super) fn initialize_code_schema(connection: &Connection) -> Result<(), StorageError> {
139 code_schema::initialize_code_schema(connection)?;
140 software::initialize_schema(connection)
141}
142
143impl CodeRepositoryStore for SqliteGraphStore {
144 fn upsert_code_repository(
145 &self,
146 registration: CodeRepositoryRegistration,
147 ) -> StorageFuture<'_, CodeRepositoryStatus> {
148 self.run(move |connection| code_status::upsert_repository(connection, registration))
149 }
150
151 fn code_repository_status(
152 &self,
153 repository: String,
154 ) -> StorageFuture<'_, Option<CodeRepositoryStatus>> {
155 self.run_read(move |connection| code_status::repository_status(connection, &repository))
156 }
157
158 fn code_repository_scope_status(
159 &self,
160 repository: String,
161 resolved_commit_sha: String,
162 path_filters: Vec<String>,
163 language_filters: Vec<String>,
164 ) -> StorageFuture<'_, Option<CodeRepositoryStatus>> {
165 self.run_read(move |connection| {
166 code_status::repository_scope_status(
167 connection,
168 &repository,
169 &resolved_commit_sha,
170 &path_filters,
171 &language_filters,
172 )
173 })
174 }
175
176 fn latest_code_repository_scope_status(
177 &self,
178 repository: String,
179 path_filters: Vec<String>,
180 language_filters: Vec<String>,
181 ) -> StorageFuture<'_, Option<CodeRepositoryStatus>> {
182 self.run_read(move |connection| {
183 code_status::latest_repository_scope_status(
184 connection,
185 &repository,
186 &path_filters,
187 &language_filters,
188 )
189 })
190 }
191
192 fn queue_code_index_task(
193 &self,
194 task: crate::storage::CodeIndexTaskSeed,
195 ) -> StorageFuture<'_, crate::domain::CodeIndexTaskRecord> {
196 self.run(move |connection| code_tasks::queue_task(connection, task))
197 }
198
199 fn claim_code_index_task(
200 &self,
201 request: crate::storage::CodeIndexTaskClaimRequest,
202 ) -> StorageFuture<'_, Option<crate::domain::CodeIndexTaskRecord>> {
203 self.run(move |connection| code_tasks::claim_task(connection, request))
204 }
205
206 fn recover_code_index_task_leases(
207 &self,
208 now_ms: u64,
209 max_attempts: u32,
210 ) -> StorageFuture<'_, ()> {
211 self.run(move |connection| {
212 code_tasks::recover_expired_task_leases(connection, now_ms, max_attempts)
213 })
214 }
215
216 fn running_code_index_task_leases(
217 &self,
218 ) -> StorageFuture<'_, Vec<crate::storage::CodeIndexTaskLeaseRecord>> {
219 self.run_read(code_tasks::running_task_leases)
220 }
221
222 fn recover_code_index_task_leases_by_task(
223 &self,
224 request: crate::storage::CodeIndexTaskLeaseRecovery,
225 ) -> StorageFuture<'_, usize> {
226 self.run(move |connection| code_tasks::recover_task_leases_by_task(connection, request))
227 }
228
229 fn renew_code_index_task_lease(
230 &self,
231 request: crate::storage::CodeIndexTaskLeaseRenewal,
232 ) -> StorageFuture<'_, crate::domain::CodeIndexTaskRecord> {
233 self.run(move |connection| code_tasks::renew_task_lease(connection, request))
234 }
235
236 fn complete_code_index_task(
237 &self,
238 request: crate::storage::CodeIndexTaskCompletion,
239 ) -> StorageFuture<'_, crate::domain::CodeIndexTaskRecord> {
240 self.run(move |connection| code_tasks::complete_task(connection, request))
241 }
242
243 fn fail_code_index_task(
244 &self,
245 request: crate::storage::CodeIndexTaskFailure,
246 ) -> StorageFuture<'_, crate::domain::CodeIndexTaskRecord> {
247 self.run(move |connection| code_tasks::fail_task(connection, request))
248 }
249
250 fn code_index_task(
251 &self,
252 task_id: String,
253 ) -> StorageFuture<'_, Option<crate::domain::CodeIndexTaskRecord>> {
254 self.run_read(move |connection| code_tasks::task_by_id(connection, &task_id))
255 }
256
257 fn active_code_index_task(
258 &self,
259 repository_id: String,
260 ) -> StorageFuture<'_, Option<crate::domain::CodeIndexTaskRecord>> {
261 self.run_read(move |connection| code_tasks::active_task(connection, &repository_id))
262 }
263
264 fn code_index_checkpoint(
265 &self,
266 source_scope: String,
267 ) -> StorageFuture<'_, Option<crate::domain::CodeIndexCheckpoint>> {
268 self.run_read(move |connection| code_tasks::checkpoint(connection, &source_scope))
269 }
270
271 fn latest_code_index_checkpoint(
272 &self,
273 repository_id: String,
274 ) -> StorageFuture<'_, Option<crate::domain::CodeIndexCheckpoint>> {
275 self.run_read(move |connection| {
276 code_tasks::latest_checkpoint_for_repository(connection, &repository_id)
277 })
278 }
279
280 fn code_scope_retention(
281 &self,
282 repository_id: String,
283 ) -> StorageFuture<'_, crate::domain::CodeScopeRetentionSummary> {
284 self.run_read(move |connection| code_tasks::retention_status(connection, &repository_id))
285 }
286
287 fn prune_code_repository_scopes(
288 &self,
289 request: crate::storage::CodeScopeRetentionRequest,
290 ) -> StorageFuture<'_, crate::domain::CodeScopeRetentionSummary> {
291 self.run(move |connection| code_tasks::prune_scopes(connection, request))
292 }
293
294 fn code_file_fingerprints(
295 &self,
296 repository_id: String,
297 ) -> StorageFuture<'_, Vec<CodeFileFingerprint>> {
298 self.run_read(move |connection| {
299 code_snapshot::file_fingerprints(connection, &repository_id)
300 })
301 }
302
303 fn code_file_fingerprints_for_scope(
304 &self,
305 source_scope: String,
306 ) -> StorageFuture<'_, Vec<CodeFileFingerprint>> {
307 self.run_read(move |connection| {
308 code_snapshot::file_fingerprints_for_scope(connection, &source_scope)
309 })
310 }
311
312 fn code_file_candidate_paths_for_scope(
313 &self,
314 source_scope: String,
315 path_filters: Vec<String>,
316 language_filters: Vec<String>,
317 limit: usize,
318 ) -> StorageFuture<'_, Vec<String>> {
319 self.run_read(move |connection| {
320 code_snapshot::file_candidate_paths_for_scope(
321 connection,
322 &source_scope,
323 &path_filters,
324 &language_filters,
325 limit,
326 )
327 })
328 }
329
330 fn code_file_candidate_paths_for_query_scope(
331 &self,
332 source_scope: String,
333 query: String,
334 path_filters: Vec<String>,
335 language_filters: Vec<String>,
336 limit: usize,
337 ) -> StorageFuture<'_, Vec<String>> {
338 self.run_read(move |connection| {
339 code_snapshot::file_candidate_paths_for_query_scope(
340 connection,
341 &source_scope,
342 &query,
343 &path_filters,
344 &language_filters,
345 limit,
346 )
347 })
348 }
349
350 fn apply_code_index_snapshot(
351 &self,
352 snapshot: CodeIndexSnapshot,
353 ) -> StorageFuture<'_, CodeIndexSummary> {
354 self.run(move |connection| code_snapshot::apply_snapshot(connection, snapshot))
355 }
356
357 fn begin_code_index_session(
358 &self,
359 session: CodeIndexSession,
360 ) -> StorageFuture<'_, CodeIndexCheckpoint> {
361 self.run(move |connection| code_batch::begin_session(connection, session))
362 }
363
364 fn apply_code_index_batch(
365 &self,
366 batch: CodeIndexBatch,
367 ) -> StorageFuture<'_, CodeIndexCheckpoint> {
368 self.run(move |connection| code_batch::apply_batch(connection, batch))
369 }
370
371 fn finalize_code_index_session(
372 &self,
373 session: CodeIndexSession,
374 ) -> StorageFuture<'_, CodeIndexSummary> {
375 self.run(move |connection| code_batch::finalize_session(connection, session))
376 }
377
378 fn search_code(
379 &self,
380 request: CodeRetrievalRequest,
381 ) -> StorageFuture<'_, Vec<CodeRetrievalHit>> {
382 self.run_read(move |connection| code_query::search_code(connection, request))
383 }
384
385 fn search_code_feature_flags(
386 &self,
387 request: CodeFeatureFlagRequest,
388 ) -> StorageFuture<'_, Vec<CodeFeatureFlagGraph>> {
389 self.run_read(move |connection| code_feature_flags::search(connection, request))
390 }
391
392 fn search_code_feature_flags_scope(
393 &self,
394 source_scope: String,
395 request: CodeFeatureFlagRequest,
396 ) -> StorageFuture<'_, Vec<CodeFeatureFlagGraph>> {
397 self.run_read(move |connection| {
398 code_feature_flags::search_scope(connection, &source_scope, request)
399 })
400 }
401
402 fn search_code_scope(
403 &self,
404 source_scope: String,
405 request: CodeRetrievalRequest,
406 ) -> StorageFuture<'_, Vec<CodeRetrievalHit>> {
407 self.run_read(move |connection| {
408 code_query::search_code_scope(connection, &source_scope, request)
409 })
410 }
411
412 fn analyze_code_impact(
413 &self,
414 request: CodeImpactRequest,
415 changes: CodeImpactChanges,
416 ) -> StorageFuture<'_, Vec<CodeRetrievalHit>> {
417 self.run_read(move |connection| code_impact::analyze_impact(connection, request, changes))
418 }
419
420 fn code_repository_totals(&self) -> StorageFuture<'_, CodeRepositoryTotals> {
421 self.run_read(code_report::repository_totals)
422 }
423
424 fn code_repository_report(
425 &self,
426 repository: String,
427 ) -> StorageFuture<'_, CodeRepositoryReport> {
428 self.run_read(move |connection| code_report::repository_report(connection, &repository))
429 }
430
431 fn refresh_software_global_projection(
432 &self,
433 source_scope: String,
434 ) -> StorageFuture<'_, SoftwareGlobalProjection> {
435 self.run(move |connection| software::refresh_projection(connection, &source_scope))
436 }
437
438 fn software_global_projection(
439 &self,
440 request: SoftwareGlobalRequest,
441 ) -> StorageFuture<'_, SoftwareGlobalProjection> {
442 self.run_read(move |connection| software::projection(connection, request))
443 }
444
445 fn software_global_projection_for_scope(
446 &self,
447 source_scope: String,
448 request: SoftwareGlobalRequest,
449 ) -> StorageFuture<'_, SoftwareGlobalProjection> {
450 self.run_read(move |connection| {
451 software::projection_for_scope(connection, &source_scope, request)
452 })
453 }
454
455 fn create_code_repository_set(
456 &self,
457 seed: crate::storage::CodeRepositorySetSeed,
458 ) -> StorageFuture<'_, crate::domain::CodeRepositorySet> {
459 self.run(move |connection| code_set::create_set(connection, seed))
460 }
461
462 fn add_code_repository_set_member(
463 &self,
464 seed: crate::storage::CodeRepositorySetMemberSeed,
465 ) -> StorageFuture<'_, crate::domain::CodeRepositorySetMember> {
466 self.run(move |connection| code_set::add_member(connection, seed))
467 }
468
469 fn remove_code_repository_set_member(
470 &self,
471 set_alias: String,
472 repository_alias: String,
473 ) -> StorageFuture<'_, crate::domain::CodeRepositorySetMember> {
474 self.run(move |connection| {
475 code_set::remove_member(connection, &set_alias, &repository_alias)
476 })
477 }
478
479 fn code_repository_set(
480 &self,
481 set_alias: String,
482 ) -> StorageFuture<'_, Option<crate::domain::CodeRepositorySet>> {
483 self.run_read(move |connection| code_set::set_by_alias(connection, &set_alias))
484 }
485
486 fn code_repository_set_status(
487 &self,
488 set_alias: String,
489 ) -> StorageFuture<'_, Option<crate::domain::CodeRepositorySetStatus>> {
490 self.run_read(move |connection| code_set::set_status(connection, &set_alias))
491 }
492
493 fn refresh_code_repository_set_overlay(
494 &self,
495 set_alias: String,
496 now_ms: u64,
497 ) -> StorageFuture<'_, crate::domain::CodeRepositorySetRefreshSummary> {
498 self.run(move |connection| code_set::refresh_overlay(connection, &set_alias, now_ms))
499 }
500
501 fn code_repository_set_cross_edges(
502 &self,
503 set_id: String,
504 ) -> StorageFuture<'_, Vec<crate::domain::CodeRepositoryCrossEdge>> {
505 self.run_read(move |connection| code_set::cross_edges_for_set(connection, &set_id))
506 }
507
508 fn queue_code_repository_set_refresh_task(
509 &self,
510 task: crate::storage::CodeRepositorySetRefreshTaskSeed,
511 ) -> StorageFuture<'_, crate::domain::CodeRepositorySetRefreshTaskRecord> {
512 self.run(move |connection| code_set_tasks::queue_refresh_task(connection, task))
513 }
514
515 fn claim_code_repository_set_refresh_task(
516 &self,
517 request: crate::storage::CodeRepositorySetRefreshTaskClaimRequest,
518 ) -> StorageFuture<'_, Option<crate::domain::CodeRepositorySetRefreshTaskRecord>> {
519 self.run(move |connection| code_set_tasks::claim_refresh_task(connection, request))
520 }
521
522 fn complete_code_repository_set_refresh_task(
523 &self,
524 request: crate::storage::CodeRepositorySetRefreshTaskCompletion,
525 ) -> StorageFuture<'_, crate::domain::CodeRepositorySetRefreshTaskRecord> {
526 self.run(move |connection| code_set_tasks::complete_refresh_task(connection, request))
527 }
528
529 fn fail_code_repository_set_refresh_task(
530 &self,
531 request: crate::storage::CodeRepositorySetRefreshTaskFailure,
532 ) -> StorageFuture<'_, crate::domain::CodeRepositorySetRefreshTaskRecord> {
533 self.run(move |connection| code_set_tasks::fail_refresh_task(connection, request))
534 }
535}