| 1 | //! Database connection and schema setup via Toasty. |
| 2 | |
| 3 | use std::path::Path; |
| 4 | |
| 5 | use crate::error::Result; |
| 6 | use crate::models::{ |
| 7 | Repository, |
| 8 | Session, |
| 9 | SshKey, |
| 10 | User, |
| 11 | }; |
| 12 | |
| 13 | /// Open (creating if necessary) the SQLite database at `path`, creating the |
| 14 | /// schema on first run. |
| 15 | /// |
| 16 | /// Note: Toasty 0.7's `push_schema` emits plain `CREATE TABLE` (no |
| 17 | /// `IF NOT EXISTS`) for model tables, so it is *not* idempotent — calling it on |
| 18 | /// an existing database errors. We therefore only push the schema when the |
| 19 | /// database file does not yet exist. Skipping it on an existing database issues |
| 20 | /// no DDL, so data is never touched. Schema evolution will move to Toasty's |
| 21 | /// migration system when models start changing. |
| 22 | pub async fn connect(path: impl AsRef<Path>) -> Result<toasty::Db> { |
| 23 | let path = path.as_ref(); |
| 24 | let fresh = !path.exists(); |
| 25 | let url = format!("sqlite:{}", path.display()); |
| 26 | |
| 27 | let db = toasty::Db::builder() |
| 28 | .models(toasty::models!(User, Repository, SshKey, Session)) |
| 29 | .connect(&url) |
| 30 | .await?; |
| 31 | |
| 32 | if fresh { |
| 33 | db.push_schema().await?; |
| 34 | } |
| 35 | Ok(db) |
| 36 | } |