dk_engine/graph/
depgraph.rs1use dk_core::{Dependency, RepoId, SymbolId};
2use sqlx::postgres::PgPool;
3use uuid::Uuid;
4
5#[derive(sqlx::FromRow)]
7struct DependencyRow {
8 id: Uuid,
9 repo_id: Uuid,
10 package: String,
11 version_req: String,
12}
13
14impl DependencyRow {
15 fn into_dependency(self) -> Dependency {
16 Dependency {
17 id: self.id,
18 repo_id: self.repo_id,
19 package: self.package,
20 version_req: self.version_req,
21 }
22 }
23}
24
25#[derive(Clone)]
27pub struct DependencyStore {
28 pool: PgPool,
29}
30
31impl DependencyStore {
32 pub fn new(pool: PgPool) -> Self {
34 Self { pool }
35 }
36
37 pub async fn upsert_dependency(&self, dep: &Dependency) -> dk_core::Result<()> {
42 sqlx::query(
43 r#"
44 INSERT INTO dependencies (id, repo_id, package, version_req)
45 VALUES ($1, $2, $3, $4)
46 ON CONFLICT (repo_id, package) DO UPDATE SET
47 id = EXCLUDED.id,
48 version_req = EXCLUDED.version_req
49 "#,
50 )
51 .bind(dep.id)
52 .bind(dep.repo_id)
53 .bind(&dep.package)
54 .bind(&dep.version_req)
55 .execute(&self.pool)
56 .await?;
57
58 Ok(())
59 }
60
61 pub async fn find_by_repo(&self, repo_id: RepoId) -> dk_core::Result<Vec<Dependency>> {
63 let rows = sqlx::query_as::<_, DependencyRow>(
64 r#"
65 SELECT id, repo_id, package, version_req
66 FROM dependencies
67 WHERE repo_id = $1
68 ORDER BY package
69 "#,
70 )
71 .bind(repo_id)
72 .fetch_all(&self.pool)
73 .await?;
74
75 Ok(rows.into_iter().map(DependencyRow::into_dependency).collect())
76 }
77
78 pub async fn link_symbol_to_dep(
81 &self,
82 symbol_id: SymbolId,
83 dep_id: Uuid,
84 ) -> dk_core::Result<()> {
85 sqlx::query(
86 r#"
87 INSERT INTO symbol_dependencies (symbol_id, dependency_id)
88 VALUES ($1, $2)
89 ON CONFLICT (symbol_id, dependency_id) DO NOTHING
90 "#,
91 )
92 .bind(symbol_id)
93 .bind(dep_id)
94 .execute(&self.pool)
95 .await?;
96
97 Ok(())
98 }
99
100 pub async fn find_symbols_for_dep(
102 &self,
103 dep_id: Uuid,
104 ) -> dk_core::Result<Vec<SymbolId>> {
105 let rows: Vec<(Uuid,)> = sqlx::query_as(
106 "SELECT symbol_id FROM symbol_dependencies WHERE dependency_id = $1",
107 )
108 .bind(dep_id)
109 .fetch_all(&self.pool)
110 .await?;
111
112 Ok(rows.into_iter().map(|(id,)| id).collect())
113 }
114
115 pub async fn delete_by_repo(&self, repo_id: RepoId) -> dk_core::Result<u64> {
119 let result = sqlx::query("DELETE FROM dependencies WHERE repo_id = $1")
120 .bind(repo_id)
121 .execute(&self.pool)
122 .await?;
123
124 Ok(result.rows_affected())
125 }
126}