pub struct Connection { /* private fields */ }Expand description
A handle to a SQLRite database. Opens a file or an in-memory DB;
drop it to close. Every mutating statement auto-saves (except inside
an explicit BEGIN/COMMIT block — see Transactions).
§Transactions
let mut conn = Connection::open("foo.sqlrite")?;
conn.execute("BEGIN")?;
conn.execute("INSERT INTO users (name) VALUES ('alice')")?;
conn.execute("INSERT INTO users (name) VALUES ('bob')")?;
conn.execute("COMMIT")?;Connection is Send but not Sync — clone it (it’s currently
unclonable) or share via a Mutex<Connection> if you need
multi-threaded access.
Implementations§
Source§impl Connection
impl Connection
Sourcepub fn open<P: AsRef<Path>>(path: P) -> Result<Self>
pub fn open<P: AsRef<Path>>(path: P) -> Result<Self>
Opens (or creates) a database file for read-write access.
If the file doesn’t exist, an empty one is materialized with the
current format version. Takes an exclusive advisory lock on the
file and its -wal sidecar; returns Err if either is already
locked by another process.
Sourcepub fn open_read_only<P: AsRef<Path>>(path: P) -> Result<Self>
pub fn open_read_only<P: AsRef<Path>>(path: P) -> Result<Self>
Opens an existing database file for read-only access. Takes a
shared advisory lock, so multiple read-only connections can
coexist on the same file; any open writer excludes them.
Mutating statements return cannot execute: database is opened read-only.
Sourcepub fn open_in_memory() -> Result<Self>
pub fn open_in_memory() -> Result<Self>
Opens a transient in-memory database. No file is touched and no
locks are taken; state lives for the lifetime of the
Connection and is discarded on drop.
Examples found in repository?
14fn main() -> Result<()> {
15 let mut conn = Connection::open_in_memory()?;
16
17 conn.execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER);")?;
18 conn.execute("INSERT INTO users (name, age) VALUES ('alice', 30);")?;
19 conn.execute("INSERT INTO users (name, age) VALUES ('bob', 25);")?;
20 conn.execute("INSERT INTO users (name, age) VALUES ('charlie', 40);")?;
21
22 println!("All users:");
23 let stmt = conn.prepare("SELECT id, name, age FROM users;")?;
24 let mut rows = stmt.query()?;
25 while let Some(row) = rows.next()? {
26 let id: i64 = row.get_by_name("id")?;
27 let name: String = row.get_by_name("name")?;
28 // `Option<i64>` wraps NULL cleanly — `age` is declared
29 // nullable so the typed accessor surfaces None when absent.
30 let age: Option<i64> = row.get_by_name("age")?;
31 println!(
32 " {} — {} ({})",
33 id,
34 name,
35 age.map(|a| a.to_string())
36 .unwrap_or_else(|| "NULL".to_string())
37 );
38 }
39
40 // Transactions: BEGIN + INSERT + ROLLBACK leaves the table untouched.
41 conn.execute("BEGIN;")?;
42 conn.execute("INSERT INTO users (name, age) VALUES ('will_vanish', 99);")?;
43 println!("\nMid-transaction row count: {}", count_users(&mut conn)?);
44 conn.execute("ROLLBACK;")?;
45 println!(
46 "Post-rollback row count: {} (unchanged)",
47 count_users(&mut conn)?
48 );
49
50 Ok(())
51}More examples
52fn main() -> Result<()> {
53 let mut conn = Connection::open_in_memory()?;
54 conn.execute(
55 "CREATE TABLE docs (id INTEGER PRIMARY KEY, name TEXT, body TEXT, embedding VECTOR(4));",
56 )?;
57 for (name, body, vec) in CORPUS {
58 conn.execute(&format!(
59 "INSERT INTO docs (name, body, embedding) VALUES \
60 ('{name}', '{body}', [{}, {}, {}, {}]);",
61 vec[0], vec[1], vec[2], vec[3]
62 ))?;
63 }
64 conn.execute("CREATE INDEX docs_fts ON docs USING fts (body);")?;
65
66 // Same query, three rankings — see README for what each shape sees.
67 let body_query = "small embedded database";
68 let vector_query = [0.0, 0.0, 0.9, 0.2]; // semantic intent: "database, lightly web-ish"
69 let q_str = vec_lit(&vector_query);
70
71 println!("Corpus:");
72 for (name, body, vec) in CORPUS {
73 println!(" {name}: \"{body}\" embedding={vec:?}");
74 }
75 println!("\nQuery body: '{body_query}'");
76 println!("Query vector: {vector_query:?}\n");
77
78 println!("=== 1. Pure BM25 (lexical) ===");
79 println!(
80 "WHERE fts_match(body, '{body_query}')\n\
81 ORDER BY bm25_score(body, '{body_query}') DESC LIMIT 3"
82 );
83 print_top(
84 &mut conn,
85 &format!(
86 "SELECT name, body FROM docs \
87 WHERE fts_match(body, '{body_query}') \
88 ORDER BY bm25_score(body, '{body_query}') DESC LIMIT 3;"
89 ),
90 )?;
91
92 println!("=== 2. Pure vector (semantic) ===");
93 println!("ORDER BY vec_distance_cosine(embedding, {q_str}) ASC LIMIT 3");
94 print_top(
95 &mut conn,
96 &format!(
97 "SELECT name, body FROM docs \
98 ORDER BY vec_distance_cosine(embedding, {q_str}) ASC LIMIT 3;"
99 ),
100 )?;
101
102 println!("=== 3. Hybrid (50% BM25 + 50% inverted cosine) ===");
103 println!(
104 "WHERE fts_match(body, '{body_query}')\n\
105 ORDER BY 0.5*bm25_score(...) + 0.5*(1.0 - vec_distance_cosine(...)) DESC LIMIT 3"
106 );
107 print_top(
108 &mut conn,
109 &format!(
110 "SELECT name, body FROM docs \
111 WHERE fts_match(body, '{body_query}') \
112 ORDER BY 0.5 * bm25_score(body, '{body_query}') \
113 + 0.5 * (1.0 - vec_distance_cosine(embedding, {q_str})) DESC \
114 LIMIT 3;"
115 ),
116 )?;
117 Ok(())
118}Sourcepub fn execute(&mut self, sql: &str) -> Result<String>
pub fn execute(&mut self, sql: &str) -> Result<String>
Parses and executes one SQL statement. For DDL (CREATE TABLE,
CREATE INDEX), DML (INSERT, UPDATE, DELETE) and
transaction control (BEGIN, COMMIT, ROLLBACK). Returns
the status message the engine produced (e.g.
"INSERT Statement executed.").
For SELECT, execute works but discards the row data and
just returns the rendered status — use Connection::prepare
and Statement::query to iterate typed rows.
Examples found in repository?
14fn main() -> Result<()> {
15 let mut conn = Connection::open_in_memory()?;
16
17 conn.execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER);")?;
18 conn.execute("INSERT INTO users (name, age) VALUES ('alice', 30);")?;
19 conn.execute("INSERT INTO users (name, age) VALUES ('bob', 25);")?;
20 conn.execute("INSERT INTO users (name, age) VALUES ('charlie', 40);")?;
21
22 println!("All users:");
23 let stmt = conn.prepare("SELECT id, name, age FROM users;")?;
24 let mut rows = stmt.query()?;
25 while let Some(row) = rows.next()? {
26 let id: i64 = row.get_by_name("id")?;
27 let name: String = row.get_by_name("name")?;
28 // `Option<i64>` wraps NULL cleanly — `age` is declared
29 // nullable so the typed accessor surfaces None when absent.
30 let age: Option<i64> = row.get_by_name("age")?;
31 println!(
32 " {} — {} ({})",
33 id,
34 name,
35 age.map(|a| a.to_string())
36 .unwrap_or_else(|| "NULL".to_string())
37 );
38 }
39
40 // Transactions: BEGIN + INSERT + ROLLBACK leaves the table untouched.
41 conn.execute("BEGIN;")?;
42 conn.execute("INSERT INTO users (name, age) VALUES ('will_vanish', 99);")?;
43 println!("\nMid-transaction row count: {}", count_users(&mut conn)?);
44 conn.execute("ROLLBACK;")?;
45 println!(
46 "Post-rollback row count: {} (unchanged)",
47 count_users(&mut conn)?
48 );
49
50 Ok(())
51}More examples
52fn main() -> Result<()> {
53 let mut conn = Connection::open_in_memory()?;
54 conn.execute(
55 "CREATE TABLE docs (id INTEGER PRIMARY KEY, name TEXT, body TEXT, embedding VECTOR(4));",
56 )?;
57 for (name, body, vec) in CORPUS {
58 conn.execute(&format!(
59 "INSERT INTO docs (name, body, embedding) VALUES \
60 ('{name}', '{body}', [{}, {}, {}, {}]);",
61 vec[0], vec[1], vec[2], vec[3]
62 ))?;
63 }
64 conn.execute("CREATE INDEX docs_fts ON docs USING fts (body);")?;
65
66 // Same query, three rankings — see README for what each shape sees.
67 let body_query = "small embedded database";
68 let vector_query = [0.0, 0.0, 0.9, 0.2]; // semantic intent: "database, lightly web-ish"
69 let q_str = vec_lit(&vector_query);
70
71 println!("Corpus:");
72 for (name, body, vec) in CORPUS {
73 println!(" {name}: \"{body}\" embedding={vec:?}");
74 }
75 println!("\nQuery body: '{body_query}'");
76 println!("Query vector: {vector_query:?}\n");
77
78 println!("=== 1. Pure BM25 (lexical) ===");
79 println!(
80 "WHERE fts_match(body, '{body_query}')\n\
81 ORDER BY bm25_score(body, '{body_query}') DESC LIMIT 3"
82 );
83 print_top(
84 &mut conn,
85 &format!(
86 "SELECT name, body FROM docs \
87 WHERE fts_match(body, '{body_query}') \
88 ORDER BY bm25_score(body, '{body_query}') DESC LIMIT 3;"
89 ),
90 )?;
91
92 println!("=== 2. Pure vector (semantic) ===");
93 println!("ORDER BY vec_distance_cosine(embedding, {q_str}) ASC LIMIT 3");
94 print_top(
95 &mut conn,
96 &format!(
97 "SELECT name, body FROM docs \
98 ORDER BY vec_distance_cosine(embedding, {q_str}) ASC LIMIT 3;"
99 ),
100 )?;
101
102 println!("=== 3. Hybrid (50% BM25 + 50% inverted cosine) ===");
103 println!(
104 "WHERE fts_match(body, '{body_query}')\n\
105 ORDER BY 0.5*bm25_score(...) + 0.5*(1.0 - vec_distance_cosine(...)) DESC LIMIT 3"
106 );
107 print_top(
108 &mut conn,
109 &format!(
110 "SELECT name, body FROM docs \
111 WHERE fts_match(body, '{body_query}') \
112 ORDER BY 0.5 * bm25_score(body, '{body_query}') \
113 + 0.5 * (1.0 - vec_distance_cosine(embedding, {q_str})) DESC \
114 LIMIT 3;"
115 ),
116 )?;
117 Ok(())
118}Sourcepub fn prepare<'c>(&'c mut self, sql: &str) -> Result<Statement<'c>>
pub fn prepare<'c>(&'c mut self, sql: &str) -> Result<Statement<'c>>
Prepares a statement for repeated execution or row iteration.
The SQL is parsed once and validated; the resulting
Statement can be executed multiple times. Today this is
primarily useful for SELECT (to reach the typed-row API);
parameter binding and prepared-plan caching are future work.
Examples found in repository?
125fn print_top(conn: &mut Connection, sql: &str) -> Result<()> {
126 let stmt = conn.prepare(sql)?;
127 let mut rows = stmt.query()?;
128 let mut rank = 1;
129 while let Some(row) = rows.next()? {
130 let name: String = row.get_by_name("name")?;
131 let body: String = row.get_by_name("body")?;
132 println!(" {rank}. {name} \"{body}\"");
133 rank += 1;
134 }
135 println!();
136 Ok(())
137}More examples
14fn main() -> Result<()> {
15 let mut conn = Connection::open_in_memory()?;
16
17 conn.execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER);")?;
18 conn.execute("INSERT INTO users (name, age) VALUES ('alice', 30);")?;
19 conn.execute("INSERT INTO users (name, age) VALUES ('bob', 25);")?;
20 conn.execute("INSERT INTO users (name, age) VALUES ('charlie', 40);")?;
21
22 println!("All users:");
23 let stmt = conn.prepare("SELECT id, name, age FROM users;")?;
24 let mut rows = stmt.query()?;
25 while let Some(row) = rows.next()? {
26 let id: i64 = row.get_by_name("id")?;
27 let name: String = row.get_by_name("name")?;
28 // `Option<i64>` wraps NULL cleanly — `age` is declared
29 // nullable so the typed accessor surfaces None when absent.
30 let age: Option<i64> = row.get_by_name("age")?;
31 println!(
32 " {} — {} ({})",
33 id,
34 name,
35 age.map(|a| a.to_string())
36 .unwrap_or_else(|| "NULL".to_string())
37 );
38 }
39
40 // Transactions: BEGIN + INSERT + ROLLBACK leaves the table untouched.
41 conn.execute("BEGIN;")?;
42 conn.execute("INSERT INTO users (name, age) VALUES ('will_vanish', 99);")?;
43 println!("\nMid-transaction row count: {}", count_users(&mut conn)?);
44 conn.execute("ROLLBACK;")?;
45 println!(
46 "Post-rollback row count: {} (unchanged)",
47 count_users(&mut conn)?
48 );
49
50 Ok(())
51}
52
53fn count_users(conn: &mut Connection) -> Result<usize> {
54 let stmt = conn.prepare("SELECT id FROM users;")?;
55 let rows = stmt.query()?.collect_all()?;
56 Ok(rows.len())
57}Sourcepub fn in_transaction(&self) -> bool
pub fn in_transaction(&self) -> bool
Returns true while a BEGIN … COMMIT/ROLLBACK block is open
against this connection.
Sourcepub fn is_read_only(&self) -> bool
pub fn is_read_only(&self) -> bool
Returns true if the connection was opened read-only. Mutating
statements on a read-only connection return a typed error.
Trait Implementations§
Source§impl ConnectionAskExt for Connection
Available on crate feature ask only.
impl ConnectionAskExt for Connection
ask only.