Skip to main content

relay_knowledge/storage/sqlite/code/
mod.rs

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