mod prepared;
use drizzle_core::error::{DrizzleError, QueryContext, ResultExt};
use drizzle_core::prepared::prepare_render;
use drizzle_core::traits::ToSQL;
use drizzle_sqlite::values::SQLiteValue;
use rusqlite::{Connection, params_from_iter};
use drizzle_sqlite::{
builder::{self, QueryBuilder},
connection::SQLiteTransactionType,
};
use crate::builder::sqlite::common;
use crate::builder::sqlite::rows::Rows;
use crate::transaction::sqlite::rusqlite::Transaction;
pub type Drizzle<Schema = ()> = common::Drizzle<Connection, Schema>;
pub type DrizzleBuilder<'a, Schema, Builder, State> =
common::DrizzleBuilder<'a, common::Drizzle<Connection, Schema>, Schema, Builder, State>;
crate::drizzle_prepare_impl!();
impl<Schema> common::Drizzle<Connection, Schema> {
pub fn execute<'a, T>(&'a self, query: T) -> rusqlite::Result<usize>
where
T: ToSQL<'a, SQLiteValue<'a>>,
{
#[cfg(feature = "profiling")]
drizzle_core::drizzle_profile_scope!("sqlite.rusqlite", "drizzle.execute");
let query = query.to_sql();
#[cfg(feature = "profiling")]
drizzle_core::drizzle_profile_scope!("sqlite.rusqlite", "drizzle.execute.build");
let (sql_str, params) = query.build();
drizzle_core::drizzle_trace_query!(&sql_str, params.len());
self.conn.execute(&sql_str, params_from_iter(params))
}
pub fn all<'a, T, R, C>(&'a self, query: T) -> drizzle_core::error::Result<C>
where
R: for<'r> TryFrom<&'r ::rusqlite::Row<'r>>,
for<'r> <R as TryFrom<&'r ::rusqlite::Row<'r>>>::Error:
Into<drizzle_core::error::DrizzleError>,
T: ToSQL<'a, SQLiteValue<'a>>,
C: std::iter::FromIterator<R>,
{
self.rows(query)?
.collect::<drizzle_core::error::Result<C>>()
}
pub fn rows<'a, T, R>(&'a self, query: T) -> drizzle_core::error::Result<Rows<R>>
where
R: for<'r> TryFrom<&'r ::rusqlite::Row<'r>>,
for<'r> <R as TryFrom<&'r ::rusqlite::Row<'r>>>::Error:
Into<drizzle_core::error::DrizzleError>,
T: ToSQL<'a, SQLiteValue<'a>>,
{
#[cfg(feature = "profiling")]
drizzle_core::drizzle_profile_scope!("sqlite.rusqlite", "drizzle.all");
let sql = query.to_sql();
#[cfg(feature = "profiling")]
drizzle_core::drizzle_profile_scope!("sqlite.rusqlite", "drizzle.all.build");
let (sql_str, params) = sql.build();
drizzle_core::drizzle_trace_query!(&sql_str, params.len());
let mut stmt = self
.conn
.prepare(&sql_str)
.with_query(|| QueryContext::new(&sql_str, ¶ms))?;
let mut rows = stmt
.query_and_then(params_from_iter(params.iter().copied()), |row| {
R::try_from(row).map_err(Into::into)
})
.with_query(|| QueryContext::new(&sql_str, ¶ms))?;
let (lower, _) = rows.size_hint();
let mut decoded = Vec::with_capacity(lower);
for row in rows {
decoded.push(row?);
}
Ok(Rows::new(decoded))
}
pub fn get<'a, T, R>(&'a self, query: T) -> drizzle_core::error::Result<R>
where
R: for<'r> TryFrom<&'r rusqlite::Row<'r>>,
for<'r> <R as TryFrom<&'r rusqlite::Row<'r>>>::Error:
Into<drizzle_core::error::DrizzleError>,
T: ToSQL<'a, SQLiteValue<'a>>,
{
#[cfg(feature = "profiling")]
drizzle_core::drizzle_profile_scope!("sqlite.rusqlite", "drizzle.get");
let sql = query.to_sql();
#[cfg(feature = "profiling")]
drizzle_core::drizzle_profile_scope!("sqlite.rusqlite", "drizzle.get.build");
let (sql_str, params) = sql.build();
drizzle_core::drizzle_trace_query!(&sql_str, params.len());
let mut stmt = self
.conn
.prepare(&sql_str)
.with_query(|| QueryContext::new(&sql_str, ¶ms))?;
stmt.query_row(params_from_iter(params.iter().copied()), |row| {
Ok(R::try_from(row).map_err(Into::into))
})
.with_query(|| QueryContext::new(&sql_str, ¶ms))?
}
pub fn transaction<F, R>(
&mut self,
tx_type: SQLiteTransactionType,
f: F,
) -> drizzle_core::error::Result<R>
where
Schema: Copy,
F: FnOnce(&Transaction<Schema>) -> drizzle_core::error::Result<R>,
{
drizzle_core::drizzle_trace_tx!("begin", "sqlite.rusqlite");
let tx = self.conn.transaction_with_behavior(tx_type.into())?;
let transaction = Transaction::new(tx, tx_type, self.schema);
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| f(&transaction)));
match result {
Ok(callback_result) => match callback_result {
Ok(value) => {
drizzle_core::drizzle_trace_tx!("commit", "sqlite.rusqlite");
transaction.commit()?;
Ok(value)
}
Err(e) => {
drizzle_core::drizzle_trace_tx!("rollback", "sqlite.rusqlite");
transaction.rollback()?;
Err(e)
}
},
Err(panic_payload) => {
drizzle_core::drizzle_trace_tx!("rollback", "sqlite.rusqlite");
let _ = transaction.rollback();
std::panic::resume_unwind(panic_payload);
}
}
}
}
impl<Schema> common::Drizzle<Connection, Schema>
where
Schema: drizzle_core::traits::SQLSchemaImpl + Default,
{
pub fn create(&self) -> drizzle_core::error::Result<()> {
let schema = Schema::default();
let statements: Vec<_> = schema.create_statements()?.collect();
if !statements.is_empty() {
let batch_sql = statements.join(";");
self.conn.execute_batch(&batch_sql)?;
}
Ok(())
}
}
impl<Schema> common::Drizzle<Connection, Schema> {
pub fn migrate(
&self,
migrations: &[drizzle_migrations::Migration],
tracking: drizzle_migrations::Tracking,
) -> drizzle_core::error::Result<drizzle_migrations::MigrateOutcome> {
let set = drizzle_migrations::Migrations::with_tracking(
migrations.to_vec(),
drizzle_types::Dialect::SQLite,
tracking,
);
ensure_sqlite_migration_table(&self.conn, &set)?;
let mut stmt = self.conn.prepare(&set.applied_names_sql())?;
let rows = stmt.query_map([], |row| row.get::<_, String>(0))?;
let applied_names = rows.filter_map(Result::ok).collect::<Vec<_>>();
let pending: Vec<_> = set.pending(&applied_names).collect();
if pending.is_empty() {
return Ok(drizzle_migrations::MigrateOutcome::UpToDate);
}
self.conn.execute("BEGIN", [])?;
let result = (|| -> drizzle_core::error::Result<Vec<String>> {
let mut applied = Vec::with_capacity(pending.len());
for migration in &pending {
for stmt in migration.statements() {
if !stmt.trim().is_empty() {
self.conn.execute(stmt, [])?;
}
}
self.conn
.execute(&set.record_migration_sql(migration), [])?;
applied.push(migration.tag().to_string());
}
Ok(applied)
})();
match result {
Ok(applied) => {
self.conn.execute("COMMIT", [])?;
Ok(drizzle_migrations::MigrateOutcome::Applied { tags: applied })
}
Err(e) => {
let _ = self.conn.execute("ROLLBACK", []);
Err(e)
}
}
}
}
fn ensure_sqlite_migration_table(
conn: &rusqlite::Connection,
set: &drizzle_migrations::Migrations,
) -> drizzle_core::error::Result<()> {
conn.execute(&set.create_table_sql(), [])?;
let table_name = set.table_name().replace('\'', "''");
let pragma_sql = format!("SELECT name FROM pragma_table_info('{table_name}')");
let mut stmt = conn.prepare(&pragma_sql)?;
let columns = stmt
.query_map([], |row| row.get::<_, String>(0))?
.collect::<Result<Vec<_>, _>>()?;
if columns.iter().any(|column| column == "name") {
return Ok(());
}
let mut stmt = conn.prepare(&format!(
"SELECT id, hash, created_at FROM {} ORDER BY id ASC",
set.table_ident_sql()
))?;
let applied = stmt
.query_map([], |row| {
Ok(drizzle_migrations::AppliedMigrationMetadata {
id: row.get::<_, Option<i64>>(0)?,
hash: row.get::<_, String>(1)?,
created_at: row.get::<_, i64>(2)?,
})
})?
.collect::<Result<Vec<_>, _>>()?;
let matched = drizzle_migrations::match_applied_migration_metadata(set.all(), &applied)
.map_err(|e| drizzle_core::error::DrizzleError::Other(e.to_string().into()))?;
conn.execute("BEGIN", [])?;
let result = (|| -> drizzle_core::error::Result<()> {
conn.execute(
&format!(
"ALTER TABLE {} ADD COLUMN \"name\" text",
set.table_ident_sql()
),
[],
)?;
conn.execute(
&format!(
"ALTER TABLE {} ADD COLUMN \"applied_at\" TEXT",
set.table_ident_sql()
),
[],
)?;
for row in matched {
let escaped_name = row.name.replace('\'', "''");
let where_clause = if let Some(id) = row.id {
format!("\"id\" = {id}")
} else {
format!(
"\"created_at\" = {} AND \"hash\" = '{}'",
row.created_at,
row.hash.replace('\'', "''")
)
};
let update_sql = format!(
"UPDATE {} SET \"name\" = '{}', \"applied_at\" = NULL WHERE {}",
set.table_ident_sql(),
escaped_name,
where_clause
);
conn.execute(&update_sql, [])?;
}
Ok(())
})();
match result {
Ok(()) => {
conn.execute("COMMIT", [])?;
Ok(())
}
Err(err) => {
let _ = conn.execute("ROLLBACK", []);
Err(err)
}
}
}
fn introspect_query_tables(
conn: &rusqlite::Connection,
) -> drizzle_core::error::Result<Vec<(String, Option<String>)>> {
use drizzle_migrations::sqlite::introspect::queries;
let mut tables_stmt = conn.prepare(queries::TABLES_QUERY)?;
let tables: Vec<(String, Option<String>)> = tables_stmt
.query_map([], |row| Ok((row.get(0)?, row.get(1)?)))?
.filter_map(Result::ok)
.collect();
Ok(tables)
}
fn introspect_query_columns(
conn: &rusqlite::Connection,
) -> drizzle_core::error::Result<Vec<drizzle_migrations::sqlite::introspect::RawColumnInfo>> {
use drizzle_migrations::sqlite::introspect::{RawColumnInfo, queries};
let mut columns_stmt = conn.prepare(queries::COLUMNS_QUERY)?;
let raw_columns: Vec<RawColumnInfo> = columns_stmt
.query_map([], |row| {
Ok(RawColumnInfo {
table: row.get(0)?,
cid: row.get(1)?,
name: row.get(2)?,
column_type: row.get(3)?,
not_null: row.get(4)?,
default_value: row.get(5)?,
pk: row.get(6)?,
hidden: row.get(7)?,
sql: row.get(8)?,
})
})?
.filter_map(Result::ok)
.collect();
Ok(raw_columns)
}
fn introspect_query_indexes_and_fks(
conn: &rusqlite::Connection,
tables: &[(String, Option<String>)],
) -> drizzle_core::error::Result<(
Vec<drizzle_migrations::sqlite::introspect::RawIndexInfo>,
Vec<drizzle_migrations::sqlite::introspect::RawIndexColumn>,
Vec<drizzle_migrations::sqlite::introspect::RawForeignKey>,
)> {
use drizzle_migrations::sqlite::introspect::{
RawForeignKey, RawIndexColumn, RawIndexInfo, queries,
};
let mut all_indexes: Vec<RawIndexInfo> = Vec::new();
let mut all_index_columns: Vec<RawIndexColumn> = Vec::new();
let mut all_fks: Vec<RawForeignKey> = Vec::new();
for (table_name, _) in tables {
if let Ok(mut idx_stmt) = conn.prepare(&queries::indexes_query(table_name)) {
let indexes: Vec<RawIndexInfo> = idx_stmt
.query_map([], |row| {
Ok(RawIndexInfo {
table: table_name.clone(),
name: row.get(1)?,
unique: row.get::<_, i32>(2)? != 0,
origin: row.get(3)?,
partial: row.get::<_, i32>(4)? != 0,
})
})?
.filter_map(Result::ok)
.collect();
for idx in &indexes {
if let Ok(mut col_stmt) = conn.prepare(&queries::index_info_query(&idx.name))
&& let Ok(col_iter) = col_stmt.query_map([], |row| {
Ok(RawIndexColumn {
index_name: idx.name.clone(),
seqno: row.get(0)?,
cid: row.get(1)?,
name: row.get(2)?,
desc: row.get::<_, i32>(3)? != 0,
coll: row.get(4)?,
key: row.get::<_, i32>(5)? != 0,
})
})
{
all_index_columns.extend(col_iter.filter_map(Result::ok));
}
}
all_indexes.extend(indexes);
}
if let Ok(mut fk_stmt) = conn.prepare(&queries::foreign_keys_query(table_name))
&& let Ok(fk_iter) = fk_stmt.query_map([], |row| {
Ok(RawForeignKey {
table: table_name.clone(),
id: row.get(0)?,
seq: row.get(1)?,
to_table: row.get(2)?,
from_column: row.get(3)?,
to_column: row.get(4)?,
on_update: row.get(5)?,
on_delete: row.get(6)?,
r#match: row.get(7)?,
})
})
{
all_fks.extend(fk_iter.filter_map(Result::ok));
}
}
Ok((all_indexes, all_index_columns, all_fks))
}
fn introspect_query_views(
conn: &rusqlite::Connection,
) -> Vec<drizzle_migrations::sqlite::introspect::RawViewInfo> {
use drizzle_migrations::sqlite::introspect::{RawViewInfo, queries};
let mut all_views: Vec<RawViewInfo> = Vec::new();
if let Ok(mut views_stmt) = conn.prepare(queries::VIEWS_QUERY)
&& let Ok(view_iter) = views_stmt.query_map([], |row| {
Ok(RawViewInfo {
name: row.get(0)?,
sql: row.get(1)?,
})
})
{
all_views.extend(view_iter.filter_map(Result::ok));
}
all_views
}
fn introspect_build_ddl(
tables: &[(String, Option<String>)],
raw_columns: &[drizzle_migrations::sqlite::introspect::RawColumnInfo],
all_indexes: &[drizzle_migrations::sqlite::introspect::RawIndexInfo],
all_index_columns: &[drizzle_migrations::sqlite::introspect::RawIndexColumn],
all_fks: &[drizzle_migrations::sqlite::introspect::RawForeignKey],
all_views: Vec<drizzle_migrations::sqlite::introspect::RawViewInfo>,
) -> drizzle_migrations::sqlite::SQLiteDDL {
use drizzle_migrations::sqlite::{
SQLiteDDL, Table as SqliteTable, View,
introspect::{
parse_generated_columns_from_table_sql, parse_view_sql, process_columns,
process_foreign_keys, process_indexes, process_unique_constraints_from_indexes,
},
};
use std::collections::{HashMap, HashSet};
let table_sql_map: HashMap<String, String> = tables
.iter()
.filter_map(|(name, sql)| sql.as_ref().map(|s| (name.clone(), s.clone())))
.collect();
let mut generated_columns: HashMap<String, drizzle_migrations::sqlite::ddl::ParsedGenerated> =
HashMap::new();
for (table, sql) in &table_sql_map {
generated_columns.extend(parse_generated_columns_from_table_sql(table, sql));
}
let pk_columns: HashSet<(String, String)> = raw_columns
.iter()
.filter(|c| c.pk > 0)
.map(|c| (c.table.clone(), c.name.clone()))
.collect();
let (columns, primary_keys) = process_columns(raw_columns, &generated_columns, &pk_columns);
let indexes = process_indexes(all_indexes, all_index_columns, &table_sql_map);
let foreign_keys = process_foreign_keys(all_fks);
let uniques = process_unique_constraints_from_indexes(all_indexes, all_index_columns);
let mut ddl = SQLiteDDL::new();
for (table_name, table_sql) in tables {
let mut table = SqliteTable::new(table_name.clone());
if let Some(sql) = table_sql {
let sql_upper = sql.to_uppercase();
table.strict = sql_upper.contains(" STRICT");
table.without_rowid = sql_upper.contains("WITHOUT ROWID");
}
ddl.tables.push(table);
}
for col in columns {
ddl.columns.push(col);
}
for idx in indexes {
ddl.indexes.push(idx);
}
for fk in foreign_keys {
ddl.fks.push(fk);
}
for pk in primary_keys {
ddl.pks.push(pk);
}
for u in uniques {
ddl.uniques.push(u);
}
for v in all_views {
let mut view = View::new(v.name);
if let Some(def) = parse_view_sql(&v.sql) {
view.definition = Some(def.into());
}
ddl.views.push(view);
}
ddl
}
impl<Schema> common::Drizzle<Connection, Schema> {
pub fn introspect(&self) -> drizzle_core::error::Result<drizzle_migrations::schema::Snapshot> {
let tables = introspect_query_tables(&self.conn)?;
let raw_columns = introspect_query_columns(&self.conn)?;
let (all_indexes, all_index_columns, all_fks) =
introspect_query_indexes_and_fks(&self.conn, &tables)?;
let all_views = introspect_query_views(&self.conn);
let ddl = introspect_build_ddl(
&tables,
&raw_columns,
&all_indexes,
&all_index_columns,
&all_fks,
all_views,
);
let mut snapshot = drizzle_migrations::sqlite::SQLiteSnapshot::new();
for entity in ddl.to_entities() {
snapshot.add_entity(entity);
}
Ok(drizzle_migrations::schema::Snapshot::Sqlite(snapshot))
}
pub fn push<S: drizzle_migrations::Schema>(
&self,
schema: &S,
) -> drizzle_core::error::Result<()> {
let live = self.introspect()?;
let desired = schema.to_snapshot();
let generated = drizzle_migrations::diff(&live, &desired)
.map_err(|e| DrizzleError::Other(e.to_string().into()))?;
for stmt in generated.statements {
if !stmt.trim().is_empty() {
self.conn.execute(&stmt, [])?;
}
}
Ok(())
}
}
#[cfg(feature = "query")]
use drizzle_core::query::DeserializeStore as _;
#[cfg(feature = "query")]
use drizzle_core::query::FromJsonObject as _;
#[cfg(feature = "query")]
impl<'a, Schema, T, Rels, Cl>
common::DrizzleQueryBuilder<
'_,
'a,
Connection,
Schema,
T,
Rels,
drizzle_core::query::AllColumns,
Cl,
>
{
pub fn find_many(
self,
) -> drizzle_core::error::Result<
Vec<
drizzle_core::query::QueryRow<
<T as drizzle_core::query::QueryTable>::Select,
<Rels as drizzle_core::query::BuildStore>::Store,
>,
>,
>
where
T: drizzle_core::query::QueryTable,
<T as drizzle_core::query::QueryTable>::Select: for<'r> TryFrom<&'r ::rusqlite::Row<'r>>,
for<'r> <<T as drizzle_core::query::QueryTable>::Select as TryFrom<&'r ::rusqlite::Row<'r>>>::Error:
Into<drizzle_core::error::DrizzleError>,
Rels: drizzle_core::query::BuildStore
+ drizzle_core::query::RenderRelations<'a, SQLiteValue<'a>>,
<Rels as drizzle_core::query::BuildStore>::Store: drizzle_core::query::DeserializeStore,
{
let num_base_cols = T::COLUMN_NAMES.len();
let builder = self.builder;
let mut rendered = Vec::new();
builder.relations.render_into(&mut rendered);
let query_sql = drizzle_core::query::build_query_sql(
T::TABLE_NAME,
T::COLUMN_NAMES,
T::BLOB_COLUMNS,
rendered,
builder.where_sql,
builder.order_by_sql,
builder.limit,
builder.offset,
false,
);
let (sql, bind_params) = query_sql.build();
drizzle_core::drizzle_trace_query!(&sql, bind_params.len());
let mut stmt = self
.runner
.conn
.prepare(&sql)
.with_query(|| QueryContext::new(&sql, &bind_params))?;
let mut raw_rows = stmt
.query(params_from_iter(bind_params.iter().copied()))
.with_query(|| QueryContext::new(&sql, &bind_params))?;
let mut results = Vec::new();
while let Some(row) = raw_rows
.next()
.with_query(|| QueryContext::new(&sql, &bind_params))?
{
let base = <T as drizzle_core::query::QueryTable>::Select::try_from(row)
.map_err(Into::into)?;
let mut rel_col = num_base_cols;
let mut next_rel = || {
let json: Option<String> = row
.get(rel_col)
.map_err(drizzle_core::error::DrizzleError::from)?;
rel_col += 1;
Ok(json)
};
let store =
<Rels as drizzle_core::query::BuildStore>::Store::from_json_columns(&mut next_rel)?;
results.push(drizzle_core::query::QueryRow::new(base, store));
}
Ok(results)
}
}
#[cfg(feature = "query")]
impl<'a, Schema, T, Rels, W, Ord>
common::DrizzleQueryBuilder<
'_,
'a,
Connection,
Schema,
T,
Rels,
drizzle_core::query::AllColumns,
drizzle_core::query::Clauses<W, Ord, drizzle_core::query::NoLimit>,
>
{
pub fn find_first(
self,
) -> drizzle_core::error::Result<
Option<
drizzle_core::query::QueryRow<
<T as drizzle_core::query::QueryTable>::Select,
<Rels as drizzle_core::query::BuildStore>::Store,
>,
>,
>
where
T: drizzle_core::query::QueryTable,
<T as drizzle_core::query::QueryTable>::Select: for<'r> TryFrom<&'r ::rusqlite::Row<'r>>,
for<'r> <<T as drizzle_core::query::QueryTable>::Select as TryFrom<&'r ::rusqlite::Row<'r>>>::Error:
Into<drizzle_core::error::DrizzleError>,
Rels: drizzle_core::query::BuildStore
+ drizzle_core::query::RenderRelations<'a, SQLiteValue<'a>>,
<Rels as drizzle_core::query::BuildStore>::Store: drizzle_core::query::DeserializeStore,
{
Ok(self.limit(1).find_many()?.into_iter().next())
}
}
#[cfg(feature = "query")]
impl<'a, Schema, T, Rels, Cl>
common::DrizzleQueryBuilder<
'_,
'a,
Connection,
Schema,
T,
Rels,
drizzle_core::query::PartialColumns,
Cl,
>
{
pub fn find_many(
self,
) -> drizzle_core::error::Result<
Vec<
drizzle_core::query::QueryRow<
<T as drizzle_core::query::QueryTable>::PartialSelect,
<Rels as drizzle_core::query::BuildStore>::Store,
>,
>,
>
where
T: drizzle_core::query::QueryTable,
<T as drizzle_core::query::QueryTable>::PartialSelect: drizzle_core::query::FromJsonObject,
Rels: drizzle_core::query::BuildStore
+ drizzle_core::query::RenderRelations<'a, SQLiteValue<'a>>,
<Rels as drizzle_core::query::BuildStore>::Store: drizzle_core::query::DeserializeStore,
{
let builder = self.builder;
let column_names = &builder.cols.columns;
let mut rendered = Vec::new();
builder.relations.render_into(&mut rendered);
let col_refs: Vec<&str> = column_names.clone();
let query_sql = drizzle_core::query::build_query_sql(
T::TABLE_NAME,
&col_refs,
T::BLOB_COLUMNS,
rendered,
builder.where_sql,
builder.order_by_sql,
builder.limit,
builder.offset,
true,
);
let (sql, bind_params) = query_sql.build();
drizzle_core::drizzle_trace_query!(&sql, bind_params.len());
let mut stmt = self
.runner
.conn
.prepare(&sql)
.with_query(|| QueryContext::new(&sql, &bind_params))?;
let mut raw_rows = stmt
.query(params_from_iter(bind_params.iter().copied()))
.with_query(|| QueryContext::new(&sql, &bind_params))?;
let mut results = Vec::new();
while let Some(row) = raw_rows
.next()
.with_query(|| QueryContext::new(&sql, &bind_params))?
{
let base_json: String = row.get(0)?;
let base = <T as drizzle_core::query::QueryTable>::PartialSelect::from_json_str(
&base_json, "base",
)?;
let mut rel_col = 1usize;
let mut next_rel = || {
let json: Option<String> = row
.get(rel_col)
.map_err(drizzle_core::error::DrizzleError::from)?;
rel_col += 1;
Ok(json)
};
let store =
<Rels as drizzle_core::query::BuildStore>::Store::from_json_columns(&mut next_rel)?;
results.push(drizzle_core::query::QueryRow::new(base, store));
}
Ok(results)
}
}
#[cfg(feature = "query")]
impl<'a, Schema, T, Rels, W, Ord>
common::DrizzleQueryBuilder<
'_,
'a,
Connection,
Schema,
T,
Rels,
drizzle_core::query::PartialColumns,
drizzle_core::query::Clauses<W, Ord, drizzle_core::query::NoLimit>,
>
{
pub fn find_first(
self,
) -> drizzle_core::error::Result<
Option<
drizzle_core::query::QueryRow<
<T as drizzle_core::query::QueryTable>::PartialSelect,
<Rels as drizzle_core::query::BuildStore>::Store,
>,
>,
>
where
T: drizzle_core::query::QueryTable,
<T as drizzle_core::query::QueryTable>::PartialSelect: drizzle_core::query::FromJsonObject,
Rels: drizzle_core::query::BuildStore
+ drizzle_core::query::RenderRelations<'a, SQLiteValue<'a>>,
<Rels as drizzle_core::query::BuildStore>::Store: drizzle_core::query::DeserializeStore,
{
Ok(self.limit(1).find_many()?.into_iter().next())
}
}
#[cfg(feature = "query")]
impl<'a, T, Rels>
common::DrizzlePreparedQuery<'a, Connection, T, Rels, drizzle_core::query::AllColumns>
{
pub fn find_many<const N: usize>(
&self,
conn: &Connection,
params: [drizzle_core::param::ParamBind<'a, SQLiteValue<'a>>; N],
) -> drizzle_core::error::Result<
Vec<
drizzle_core::query::QueryRow<
<T as drizzle_core::query::QueryTable>::Select,
<Rels as drizzle_core::query::BuildStore>::Store,
>,
>,
>
where
T: drizzle_core::query::QueryTable,
<T as drizzle_core::query::QueryTable>::Select: for<'r> TryFrom<&'r ::rusqlite::Row<'r>>,
for<'r> <<T as drizzle_core::query::QueryTable>::Select as TryFrom<&'r ::rusqlite::Row<'r>>>::Error:
Into<drizzle_core::error::DrizzleError>,
Rels: drizzle_core::query::BuildStore,
<Rels as drizzle_core::query::BuildStore>::Store: drizzle_core::query::DeserializeStore,
{
debug_assert_eq!(
N,
self.inner.external_param_count(),
"parameter count mismatch: expected {} params but got {}",
self.inner.external_param_count(),
N
);
let num_base_cols = T::COLUMN_NAMES.len();
let (sql_str, params) = self.inner.bind(params)?;
let mut stmt = conn.prepare_cached(sql_str)?;
let mut raw_rows = stmt.query(params_from_iter(params))?;
let mut results = Vec::new();
while let Some(row) = raw_rows.next()? {
let base = <T as drizzle_core::query::QueryTable>::Select::try_from(row)
.map_err(Into::into)?;
let mut rel_col = num_base_cols;
let mut next_rel = || {
let json: Option<String> = row.get(rel_col).map_err(DrizzleError::from)?;
rel_col += 1;
Ok(json)
};
let store =
<Rels as drizzle_core::query::BuildStore>::Store::from_json_columns(&mut next_rel)?;
results.push(drizzle_core::query::QueryRow::new(base, store));
}
Ok(results)
}
pub fn find_first<const N: usize>(
&self,
conn: &Connection,
params: [drizzle_core::param::ParamBind<'a, SQLiteValue<'a>>; N],
) -> drizzle_core::error::Result<
Option<
drizzle_core::query::QueryRow<
<T as drizzle_core::query::QueryTable>::Select,
<Rels as drizzle_core::query::BuildStore>::Store,
>,
>,
>
where
T: drizzle_core::query::QueryTable,
<T as drizzle_core::query::QueryTable>::Select: for<'r> TryFrom<&'r ::rusqlite::Row<'r>>,
for<'r> <<T as drizzle_core::query::QueryTable>::Select as TryFrom<&'r ::rusqlite::Row<'r>>>::Error:
Into<drizzle_core::error::DrizzleError>,
Rels: drizzle_core::query::BuildStore,
<Rels as drizzle_core::query::BuildStore>::Store: drizzle_core::query::DeserializeStore,
{
Ok(self.find_many(conn, params)?.into_iter().next())
}
}
#[cfg(feature = "query")]
impl<'a, T, Rels>
common::DrizzlePreparedQuery<'a, Connection, T, Rels, drizzle_core::query::PartialColumns>
{
pub fn find_many<const N: usize>(
&self,
conn: &Connection,
params: [drizzle_core::param::ParamBind<'a, SQLiteValue<'a>>; N],
) -> drizzle_core::error::Result<
Vec<
drizzle_core::query::QueryRow<
<T as drizzle_core::query::QueryTable>::PartialSelect,
<Rels as drizzle_core::query::BuildStore>::Store,
>,
>,
>
where
T: drizzle_core::query::QueryTable,
<T as drizzle_core::query::QueryTable>::PartialSelect: drizzle_core::query::FromJsonObject,
Rels: drizzle_core::query::BuildStore,
<Rels as drizzle_core::query::BuildStore>::Store: drizzle_core::query::DeserializeStore,
{
debug_assert_eq!(
N,
self.inner.external_param_count(),
"parameter count mismatch: expected {} params but got {}",
self.inner.external_param_count(),
N
);
let (sql_str, params) = self.inner.bind(params)?;
let mut stmt = conn.prepare_cached(sql_str)?;
let mut raw_rows = stmt.query(params_from_iter(params))?;
let mut results = Vec::new();
while let Some(row) = raw_rows.next()? {
let base_json: String = row.get(0)?;
let base = <T as drizzle_core::query::QueryTable>::PartialSelect::from_json_str(
&base_json, "base",
)?;
let mut rel_col = 1usize;
let mut next_rel = || {
let json: Option<String> = row.get(rel_col).map_err(DrizzleError::from)?;
rel_col += 1;
Ok(json)
};
let store =
<Rels as drizzle_core::query::BuildStore>::Store::from_json_columns(&mut next_rel)?;
results.push(drizzle_core::query::QueryRow::new(base, store));
}
Ok(results)
}
pub fn find_first<const N: usize>(
&self,
conn: &Connection,
params: [drizzle_core::param::ParamBind<'a, SQLiteValue<'a>>; N],
) -> drizzle_core::error::Result<
Option<
drizzle_core::query::QueryRow<
<T as drizzle_core::query::QueryTable>::PartialSelect,
<Rels as drizzle_core::query::BuildStore>::Store,
>,
>,
>
where
T: drizzle_core::query::QueryTable,
<T as drizzle_core::query::QueryTable>::PartialSelect: drizzle_core::query::FromJsonObject,
Rels: drizzle_core::query::BuildStore,
<Rels as drizzle_core::query::BuildStore>::Store: drizzle_core::query::DeserializeStore,
{
Ok(self.find_many(conn, params)?.into_iter().next())
}
}
impl<S, Schema, State, Table, Mk, Rw, Grouped>
DrizzleBuilder<'_, S, QueryBuilder<'_, Schema, State, Table, Mk, Rw, Grouped>, State>
where
State: builder::ExecutableState,
{
pub fn execute(self) -> drizzle_core::error::Result<usize> {
#[cfg(feature = "profiling")]
drizzle_core::drizzle_profile_scope!("sqlite.rusqlite", "builder.execute");
let (sql_str, params) = self.builder.sql.build();
drizzle_core::drizzle_trace_query!(&sql_str, params.len());
self.runner
.conn
.execute(&sql_str, params_from_iter(params.iter().copied()))
.with_query(|| QueryContext::new(&sql_str, ¶ms))
}
pub fn all<R, Proof, AggProof>(self) -> drizzle_core::error::Result<Vec<R>>
where
for<'r> Mk: drizzle_core::row::DecodeSelectedRef<&'r ::rusqlite::Row<'r>, R>
+ drizzle_core::row::MarkerScopeValidFor<Proof>
+ drizzle_core::row::StrictDecodeMarker
+ drizzle_core::row::MarkerColumnCountValid<::rusqlite::Row<'r>, Rw, R>,
Mk: drizzle_core::row::MarkerAggValidFor<Grouped, AggProof>,
{
#[cfg(feature = "profiling")]
drizzle_core::drizzle_profile_scope!("sqlite.rusqlite", "builder.all");
let (sql_str, params) = self.builder.sql.build();
drizzle_core::drizzle_trace_query!(&sql_str, params.len());
let mut stmt = self
.runner
.conn
.prepare(&sql_str)
.with_query(|| QueryContext::new(&sql_str, ¶ms))?;
let mut raw_rows = stmt
.query(params_from_iter(params.iter().copied()))
.with_query(|| QueryContext::new(&sql_str, ¶ms))?;
let mut decoded = Vec::new();
while let Some(row) = raw_rows
.next()
.with_query(|| QueryContext::new(&sql_str, ¶ms))?
{
decoded.push(<Mk as drizzle_core::row::DecodeSelectedRef<
&::rusqlite::Row<'_>,
R,
>>::decode(row)?);
}
Ok(decoded)
}
pub fn rows(self) -> drizzle_core::error::Result<Rows<Rw>>
where
Rw: for<'r> TryFrom<&'r ::rusqlite::Row<'r>>,
for<'r> <Rw as TryFrom<&'r ::rusqlite::Row<'r>>>::Error:
Into<drizzle_core::error::DrizzleError>,
{
#[cfg(feature = "profiling")]
drizzle_core::drizzle_profile_scope!("sqlite.rusqlite", "builder.rows");
let (sql_str, params) = self.builder.sql.build();
drizzle_core::drizzle_trace_query!(&sql_str, params.len());
let mut stmt = self
.runner
.conn
.prepare(&sql_str)
.with_query(|| QueryContext::new(&sql_str, ¶ms))?;
let mut rows = stmt
.query_and_then(params_from_iter(params.iter().copied()), |row| {
Rw::try_from(row).map_err(Into::into)
})
.with_query(|| QueryContext::new(&sql_str, ¶ms))?;
let (lower, _) = rows.size_hint();
let mut decoded = Vec::with_capacity(lower);
for row in rows {
decoded.push(row?);
}
Ok(Rows::new(decoded))
}
pub fn get<R, Proof, AggProof>(self) -> drizzle_core::error::Result<R>
where
for<'r> Mk: drizzle_core::row::DecodeSelectedRef<&'r ::rusqlite::Row<'r>, R>
+ drizzle_core::row::MarkerScopeValidFor<Proof>
+ drizzle_core::row::StrictDecodeMarker
+ drizzle_core::row::MarkerColumnCountValid<::rusqlite::Row<'r>, Rw, R>,
Mk: drizzle_core::row::MarkerAggValidFor<Grouped, AggProof>,
{
#[cfg(feature = "profiling")]
drizzle_core::drizzle_profile_scope!("sqlite.rusqlite", "builder.get");
let (sql_str, params) = self.builder.sql.build();
drizzle_core::drizzle_trace_query!(&sql_str, params.len());
let mut stmt = self
.runner
.conn
.prepare(&sql_str)
.with_query(|| QueryContext::new(&sql_str, ¶ms))?;
stmt.query_row(params_from_iter(params.iter().copied()), |row| {
Ok(<Mk as drizzle_core::row::DecodeSelectedRef<
&::rusqlite::Row<'_>,
R,
>>::decode(row))
})
.with_query(|| QueryContext::new(&sql_str, ¶ms))?
}
}