use super::{map_row_to_raw_call, RawCall};
use rusqlite::Connection;
pub fn insert_raw_call(conn: &Connection, r: &RawCall) -> rusqlite::Result<()> {
let mut stmt = conn.prepare_cached(
"INSERT INTO raw_calls (
caller_nid, callee_name, callee_simple, callee_scope,
call_kind, receiver_expr, receiver_type, package_or_namespace, import_hint,
relationship_kind, reverse_edge, target_qualified_hint, resolution_hint, line, column
) SELECT nid, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15 FROM nodes WHERE id = ?1",
)?;
stmt.execute((
&r.caller_id,
&r.callee_name,
&r.callee_simple,
&r.callee_scope,
&r.call_kind,
&r.receiver_expr,
&r.receiver_type,
&r.package_or_namespace,
&r.import_hint,
&r.relationship_kind,
i64::from(r.reverse_edge),
&r.target_qualified_hint,
r.resolution_hint,
r.line,
r.column,
))?;
Ok(())
}
pub fn get_raw_call_source_ids_by_callee_simple(
conn: &Connection,
callee_simple: &str,
) -> rusqlite::Result<Vec<String>> {
let mut stmt = conn.prepare(
"SELECT DISTINCT n.id FROM raw_calls r
JOIN nodes n ON n.nid = r.caller_nid
WHERE r.callee_simple = ?",
)?;
let rows = stmt.query_map([callee_simple], |row| row.get(0))?;
rows.collect()
}
pub fn get_raw_calls_for_source_id(
conn: &Connection,
source_id: &str,
) -> rusqlite::Result<Vec<RawCall>> {
let mut stmt = conn.prepare(
"SELECT n.id, r.callee_name, r.callee_simple, r.callee_scope,
r.call_kind, r.receiver_expr, r.receiver_type, r.package_or_namespace, r.import_hint,
r.relationship_kind, r.reverse_edge, r.target_qualified_hint, r.resolution_hint,
r.line, r.column
FROM raw_calls r
JOIN nodes n ON n.nid = r.caller_nid
WHERE n.id = ?",
)?;
let rows = stmt.query_map([source_id], map_row_to_raw_call)?;
rows.collect()
}
pub fn get_all_raw_calls(conn: &Connection) -> rusqlite::Result<Vec<RawCall>> {
let mut stmt = conn.prepare(
"SELECT n.id, r.callee_name, r.callee_simple, r.callee_scope,
r.call_kind, r.receiver_expr, r.receiver_type, r.package_or_namespace, r.import_hint,
r.relationship_kind, r.reverse_edge, r.target_qualified_hint, r.resolution_hint,
r.line, r.column
FROM raw_calls r
JOIN nodes n ON n.nid = r.caller_nid",
)?;
let rows = stmt.query_map([], map_row_to_raw_call)?;
let mut calls = Vec::new();
for r in rows {
calls.push(r?);
}
Ok(calls)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::db::{init_schema, upsert_node, Node};
fn node(id: &str, name: &str) -> Node {
Node {
id: id.to_string(),
name: name.to_string(),
kind: "class".to_string(),
qualified_name: Some(name.to_string()),
file_path: "App.java".to_string(),
start_line: 1,
end_line: 1,
start_column: 0,
end_column: 1,
signature: None,
doc_comment: None,
is_test: false,
resolution_kind: None,
confidence: None,
}
}
#[test]
fn relationship_metadata_survives_raw_call_round_trip() {
let conn = Connection::open_in_memory().unwrap();
init_schema(&conn).unwrap();
upsert_node(&conn, &node("App.java::Consumer", "Consumer")).unwrap();
let mut relation = RawCall::new(
"App.java::Consumer".to_string(),
"Dependency".to_string(),
4,
2,
);
relation.relationship_kind = "injected_into".to_string();
relation.reverse_edge = true;
relation.target_qualified_hint = Some("pkg::Dependency".to_string());
relation.resolution_hint = Some(6);
insert_raw_call(&conn, &relation).unwrap();
assert_eq!(get_all_raw_calls(&conn).unwrap(), vec![relation]);
}
}