Skip to main content

relay_knowledge/storage/sqlite/
code.rs

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}