Skip to main content

relay_knowledge/storage/sqlite/
code.rs

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