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