mod prepared;
use drizzle_core::error::{DrizzleError, QueryContext, ResultExt};
use drizzle_core::prepared::prepare_render;
use drizzle_core::traits::ToSQL;
use turso::{Connection, IntoValue, Row};
#[cfg(feature = "sqlite")]
use drizzle_sqlite::{
builder::{self, QueryBuilder},
connection::SQLiteTransactionType,
values::SQLiteValue,
};
crate::drizzle_prepare_impl!();
use crate::builder::sqlite::common;
use crate::builder::sqlite::rows::TursoRows as Rows;
use crate::transaction::sqlite::turso::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>;
async fn turso_execute_cached(
conn: &Connection,
sql: &str,
params: Vec<turso::Value>,
) -> turso::Result<u64> {
let mut stmt = conn.prepare_cached(sql).await?;
stmt.execute(params).await
}
async fn turso_query_cached(
conn: &Connection,
sql: &str,
params: Vec<turso::Value>,
) -> turso::Result<turso::Rows> {
let mut stmt = conn.prepare_cached(sql).await?;
stmt.query(params).await
}
impl<Schema> common::Drizzle<Connection, Schema> {
pub async fn execute<'a, T>(
&'a self,
query: T,
) -> Result<u64, drizzle_core::error::DrizzleError>
where
T: ToSQL<'a, SQLiteValue<'a>>,
{
let query = query.to_sql();
let (sql_str, params) = query.build();
let driver_params: Vec<turso::Value> = params
.iter()
.copied()
.map(|p| {
p.into_value()
.map_err(drizzle_core::error::DrizzleError::from)
})
.collect::<Result<Vec<_>, _>>()
.with_query(|| QueryContext::new(&sql_str, ¶ms))?;
turso_execute_cached(&self.conn, &sql_str, driver_params)
.await
.map_err(drizzle_core::error::DrizzleError::from)
.with_query(|| QueryContext::new(&sql_str, ¶ms))
}
pub async fn all<'a, T, R, C>(&'a self, query: T) -> drizzle_core::error::Result<C>
where
R: for<'r> TryFrom<&'r Row>,
for<'r> <R as TryFrom<&'r Row>>::Error: Into<DrizzleError>,
T: ToSQL<'a, SQLiteValue<'a>>,
C: Default + Extend<R>,
{
let sql = query.to_sql();
let (sql_str, params) = sql.build();
let driver_params: Vec<turso::Value> = params
.iter()
.copied()
.map(|p| p.into_value().map_err(DrizzleError::from))
.collect::<Result<Vec<_>, _>>()
.with_query(|| QueryContext::new(&sql_str, ¶ms))?;
let mut rows = turso_query_cached(&self.conn, &sql_str, driver_params)
.await
.map_err(DrizzleError::from)
.with_query(|| QueryContext::new(&sql_str, ¶ms))?;
let mut out = C::default();
while let Some(row) = rows
.next()
.await
.map_err(DrizzleError::from)
.with_query(|| QueryContext::new(&sql_str, ¶ms))?
{
out.extend(core::iter::once(R::try_from(&row).map_err(Into::into)?));
}
Ok(out)
}
pub async fn rows<'a, T, R>(&'a self, query: T) -> drizzle_core::error::Result<Rows<R>>
where
R: for<'r> TryFrom<&'r Row>,
for<'r> <R as TryFrom<&'r Row>>::Error: Into<DrizzleError>,
T: ToSQL<'a, SQLiteValue<'a>>,
{
let sql = query.to_sql();
let (sql_str, params) = sql.build();
let driver_params: Vec<turso::Value> = params
.iter()
.copied()
.map(|p| p.into_value().map_err(DrizzleError::from))
.collect::<Result<Vec<_>, _>>()
.with_query(|| QueryContext::new(&sql_str, ¶ms))?;
let rows = self
.conn
.query(&sql_str, driver_params)
.await
.map_err(DrizzleError::from)
.with_query(|| QueryContext::new(&sql_str, ¶ms))?;
Ok(Rows::new(rows))
}
pub async fn get<'a, T, R>(&'a self, query: T) -> drizzle_core::error::Result<R>
where
R: for<'r> TryFrom<&'r Row>,
for<'r> <R as TryFrom<&'r Row>>::Error: Into<DrizzleError>,
T: ToSQL<'a, SQLiteValue<'a>>,
{
let sql = query.to_sql();
let (sql_str, params) = sql.build();
let driver_params: Vec<turso::Value> = params
.iter()
.copied()
.map(|p| p.into_value().map_err(DrizzleError::from))
.collect::<Result<Vec<_>, _>>()
.with_query(|| QueryContext::new(&sql_str, ¶ms))?;
let mut rows = turso_query_cached(&self.conn, &sql_str, driver_params)
.await
.map_err(DrizzleError::from)
.with_query(|| QueryContext::new(&sql_str, ¶ms))?;
rows.next()
.await
.map_err(DrizzleError::from)
.with_query(|| QueryContext::new(&sql_str, ¶ms))?
.map_or_else(
|| Err(DrizzleError::NotFound),
|row| R::try_from(&row).map_err(Into::into),
)
}
pub async fn transaction<F, R>(
&mut self,
tx_type: SQLiteTransactionType,
f: F,
) -> drizzle_core::error::Result<R>
where
Schema: Copy,
F: AsyncFnOnce(&Transaction<Schema>) -> drizzle_core::error::Result<R>,
{
let tx = self.conn.transaction_with_behavior(tx_type.into()).await?;
let transaction = Transaction::new(tx, tx_type, self.schema);
match f(&transaction).await {
Ok(result) => {
transaction.commit().await?;
Ok(result)
}
Err(e) => {
let _ = transaction.rollback().await;
Err(e)
}
}
}
}
impl<Schema> Drizzle<Schema>
where
Schema: drizzle_core::traits::SQLSchemaImpl + Default,
{
pub async fn create(&self) -> drizzle_core::error::Result<()> {
let schema = Schema::default();
let statements = schema.create_statements()?;
for sql in statements {
self.conn.execute(&sql, ()).await?;
}
Ok(())
}
}
impl<Schema> common::Drizzle<Connection, Schema> {
pub async fn migrate(
&mut 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(&mut self.conn, &set).await?;
let mut rows = self
.conn
.query(&set.applied_names_sql(), ())
.await
.map_err(DrizzleError::from)?;
let mut applied_names: Vec<String> = Vec::new();
while let Some(row) = rows.next().await.map_err(DrizzleError::from)? {
if let Ok(name) = row.get::<String>(0) {
applied_names.push(name);
}
}
let pending: Vec<_> = set.pending(&applied_names).collect();
if pending.is_empty() {
return Ok(drizzle_migrations::MigrateOutcome::UpToDate);
}
let tx = self.conn.transaction().await.map_err(DrizzleError::from)?;
let mut applied = Vec::with_capacity(pending.len());
for migration in &pending {
for stmt in migration.statements() {
if !stmt.trim().is_empty() {
tx.execute(stmt, ()).await.map_err(DrizzleError::from)?;
}
}
tx.execute(&set.record_migration_sql(migration), ())
.await
.map_err(DrizzleError::from)?;
applied.push(migration.tag().to_string());
}
tx.commit().await.map_err(DrizzleError::from)?;
Ok(drizzle_migrations::MigrateOutcome::Applied { tags: applied })
}
}
async fn migration_table_has_name_column(
conn: &turso::Connection,
set: &drizzle_migrations::Migrations,
) -> drizzle_core::error::Result<bool> {
let table_name = set.table_name().replace('\'', "''");
let pragma_sql = format!("SELECT name FROM pragma_table_info('{table_name}')");
let mut rows = conn
.query(&pragma_sql, ())
.await
.map_err(DrizzleError::from)?;
while let Some(row) = rows.next().await.map_err(DrizzleError::from)? {
if let Ok(name) = row.get::<String>(0)
&& name == "name"
{
return Ok(true);
}
}
Ok(false)
}
async fn load_legacy_applied_migrations(
conn: &turso::Connection,
set: &drizzle_migrations::Migrations,
) -> drizzle_core::error::Result<Vec<drizzle_migrations::AppliedMigrationMetadata>> {
let mut rows = conn
.query(
&format!(
"SELECT id, hash, created_at FROM {} ORDER BY id ASC",
set.table_ident_sql()
),
(),
)
.await
.map_err(DrizzleError::from)?;
let mut applied = Vec::new();
while let Some(row) = rows.next().await.map_err(DrizzleError::from)? {
applied.push(drizzle_migrations::AppliedMigrationMetadata {
id: row.get::<Option<i64>>(0).ok().flatten(),
hash: row.get::<String>(1).map_err(DrizzleError::from)?,
created_at: row.get::<i64>(2).map_err(DrizzleError::from)?,
});
}
Ok(applied)
}
async fn backfill_migration_name_column(
conn: &mut turso::Connection,
set: &drizzle_migrations::Migrations,
matched: Vec<drizzle_migrations::MatchedMigrationMetadata>,
) -> drizzle_core::error::Result<()> {
let tx = conn.transaction().await.map_err(DrizzleError::from)?;
tx.execute(
&format!(
"ALTER TABLE {} ADD COLUMN \"name\" text",
set.table_ident_sql()
),
(),
)
.await
.map_err(DrizzleError::from)?;
tx.execute(
&format!(
"ALTER TABLE {} ADD COLUMN \"applied_at\" TEXT",
set.table_ident_sql()
),
(),
)
.await
.map_err(DrizzleError::from)?;
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('\'', "''")
)
};
tx.execute(
&format!(
"UPDATE {} SET \"name\" = '{}', \"applied_at\" = NULL WHERE {}",
set.table_ident_sql(),
escaped_name,
where_clause
),
(),
)
.await
.map_err(DrizzleError::from)?;
}
tx.commit().await.map_err(DrizzleError::from)?;
Ok(())
}
async fn ensure_sqlite_migration_table(
conn: &mut turso::Connection,
set: &drizzle_migrations::Migrations,
) -> drizzle_core::error::Result<()> {
conn.execute(&set.create_table_sql(), ())
.await
.map_err(DrizzleError::from)?;
if migration_table_has_name_column(conn, set).await? {
return Ok(());
}
let applied = load_legacy_applied_migrations(conn, set).await?;
let matched = drizzle_migrations::match_applied_migration_metadata(set.all(), &applied)
.map_err(|e| DrizzleError::Other(e.to_string().into()))?;
backfill_migration_name_column(conn, set, matched).await
}
async fn turso_introspect_query_tables(
conn: &turso::Connection,
) -> drizzle_core::error::Result<Vec<(String, Option<String>)>> {
use drizzle_migrations::sqlite::introspect::queries;
let err = DrizzleError::from;
let mut tables_rows = conn.query(queries::TABLES_QUERY, ()).await.map_err(err)?;
let mut tables: Vec<(String, Option<String>)> = Vec::new();
while let Some(row) = tables_rows.next().await.map_err(err)? {
let name: String = row.get(0).unwrap_or_default();
let sql: Option<String> = row.get(1).ok();
tables.push((name, sql));
}
Ok(tables)
}
async fn turso_introspect_query_columns(
conn: &turso::Connection,
) -> drizzle_core::error::Result<Vec<drizzle_migrations::sqlite::introspect::RawColumnInfo>> {
use drizzle_migrations::sqlite::introspect::{RawColumnInfo, queries};
let err = DrizzleError::from;
let mut columns_rows = conn.query(queries::COLUMNS_QUERY, ()).await.map_err(err)?;
let mut raw_columns: Vec<RawColumnInfo> = Vec::new();
while let Some(row) = columns_rows.next().await.map_err(err)? {
raw_columns.push(RawColumnInfo {
table: row.get(0).unwrap_or_default(),
cid: row.get(1).unwrap_or(0),
name: row.get(2).unwrap_or_default(),
column_type: row.get(3).unwrap_or_default(),
not_null: row.get::<i32>(4).unwrap_or(0) != 0,
default_value: row.get(5).ok(),
pk: row.get(6).unwrap_or(0),
hidden: row.get(7).unwrap_or(0),
sql: row.get(8).ok(),
});
}
Ok(raw_columns)
}
async fn turso_introspect_query_indexes_and_fks(
conn: &turso::Connection,
tables: &[(String, Option<String>)],
) -> (
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_rows) = conn.query(&queries::indexes_query(table_name), ()).await {
while let Ok(Some(row)) = idx_rows.next().await {
let idx = RawIndexInfo {
table: table_name.clone(),
name: row.get(1).unwrap_or_default(),
unique: row.get::<i32>(2).unwrap_or(0) != 0,
origin: row.get(3).unwrap_or_default(),
partial: row.get::<i32>(4).unwrap_or(0) != 0,
};
if let Ok(mut col_rows) =
conn.query(&queries::index_info_query(&idx.name), ()).await
{
while let Ok(Some(col_row)) = col_rows.next().await {
all_index_columns.push(RawIndexColumn {
index_name: idx.name.clone(),
seqno: col_row.get(0).unwrap_or(0),
cid: col_row.get(1).unwrap_or(0),
name: col_row.get(2).ok(),
desc: col_row.get::<i32>(3).unwrap_or(0) != 0,
coll: col_row.get(4).unwrap_or_default(),
key: col_row.get::<i32>(5).unwrap_or(0) != 0,
});
}
}
all_indexes.push(idx);
}
}
if let Ok(mut fk_rows) = conn
.query(&queries::foreign_keys_query(table_name), ())
.await
{
while let Ok(Some(row)) = fk_rows.next().await {
all_fks.push(RawForeignKey {
table: table_name.clone(),
id: row.get(0).unwrap_or(0),
seq: row.get(1).unwrap_or(0),
to_table: row.get(2).unwrap_or_default(),
from_column: row.get(3).unwrap_or_default(),
to_column: row.get(4).unwrap_or_default(),
on_update: row.get(5).unwrap_or_default(),
on_delete: row.get(6).unwrap_or_default(),
r#match: row.get(7).unwrap_or_default(),
});
}
}
}
(all_indexes, all_index_columns, all_fks)
}
async fn turso_introspect_query_views(
conn: &turso::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_rows) = conn.query(queries::VIEWS_QUERY, ()).await {
while let Ok(Some(row)) = views_rows.next().await {
let name: String = row.get(0).unwrap_or_default();
let sql: String = row.get(1).unwrap_or_default();
all_views.push(RawViewInfo { name, sql });
}
}
all_views
}
fn turso_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 async fn introspect(
&self,
) -> drizzle_core::error::Result<drizzle_migrations::schema::Snapshot> {
let tables = turso_introspect_query_tables(&self.conn).await?;
let raw_columns = turso_introspect_query_columns(&self.conn).await?;
let (all_indexes, all_index_columns, all_fks) =
turso_introspect_query_indexes_and_fks(&self.conn, &tables).await;
let all_views = turso_introspect_query_views(&self.conn).await;
let ddl = turso_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 async fn push<S: drizzle_migrations::Schema>(
&self,
schema: &S,
) -> drizzle_core::error::Result<()> {
let live = self.introspect().await?;
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, ())
.await
.map_err(DrizzleError::from)?;
}
}
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 async 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 ::turso::Row>,
for<'r> <<T as drizzle_core::query::QueryTable>::Select as TryFrom<&'r ::turso::Row>>::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();
let params: Vec<turso::Value> = bind_params
.iter()
.copied()
.map(std::convert::Into::into)
.collect();
let mut raw_rows = turso_query_cached(&self.runner.conn, &sql, params)
.await
.map_err(drizzle_core::error::DrizzleError::from)
.with_query(|| QueryContext::new(&sql, &bind_params))?;
let mut results = Vec::new();
while let Some(row) = raw_rows
.next()
.await
.map_err(drizzle_core::error::DrizzleError::from)
.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 = row
.get::<Option<String>>(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 async 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 ::turso::Row>,
for<'r> <<T as drizzle_core::query::QueryTable>::Select as TryFrom<&'r ::turso::Row>>::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().await?.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 async 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();
let params: Vec<turso::Value> = bind_params
.iter()
.copied()
.map(std::convert::Into::into)
.collect();
let mut raw_rows = turso_query_cached(&self.runner.conn, &sql, params)
.await
.map_err(drizzle_core::error::DrizzleError::from)
.with_query(|| QueryContext::new(&sql, &bind_params))?;
let mut results = Vec::new();
while let Some(row) = raw_rows
.next()
.await
.map_err(drizzle_core::error::DrizzleError::from)
.with_query(|| QueryContext::new(&sql, &bind_params))?
{
let base_json: String = row
.get::<String>(0)
.map_err(drizzle_core::error::DrizzleError::from)?;
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 = row.get::<String>(rel_col).ok();
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 async 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().await?.into_iter().next())
}
}
#[cfg(feature = "query")]
impl<'a, T, Rels>
common::DrizzlePreparedQuery<'a, Connection, T, Rels, drizzle_core::query::AllColumns>
{
pub async fn find_many<const N: usize>(
&self,
conn: &impl prepared::TursoExecutor,
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 ::turso::Row>,
for<'r> <<T as drizzle_core::query::QueryTable>::Select as TryFrom<&'r ::turso::Row>>::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 driver_params = Vec::with_capacity(self.inner.params.len());
driver_params.extend(params.map(Into::into));
let mut raw_rows = conn.fetch(sql_str, driver_params).await?;
let mut results = Vec::new();
while let Some(row) = raw_rows.next().await? {
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 = row
.get::<Option<String>>(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)
}
pub async fn find_first<const N: usize>(
&self,
conn: &impl prepared::TursoExecutor,
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 ::turso::Row>,
for<'r> <<T as drizzle_core::query::QueryTable>::Select as TryFrom<&'r ::turso::Row>>::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).await?.into_iter().next())
}
}
#[cfg(feature = "query")]
impl<'a, T, Rels>
common::DrizzlePreparedQuery<'a, Connection, T, Rels, drizzle_core::query::PartialColumns>
{
pub async fn find_many<const N: usize>(
&self,
conn: &impl prepared::TursoExecutor,
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 driver_params = Vec::with_capacity(self.inner.params.len());
driver_params.extend(params.map(Into::into));
let mut raw_rows = conn.fetch(sql_str, driver_params).await?;
let mut results = Vec::new();
while let Some(row) = raw_rows.next().await? {
let base_json: String = row
.get::<String>(0)
.map_err(drizzle_core::error::DrizzleError::from)?;
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 = row
.get::<Option<String>>(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)
}
pub async fn find_first<const N: usize>(
&self,
conn: &impl prepared::TursoExecutor,
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).await?.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 async fn execute(self) -> drizzle_core::error::Result<u64> {
let (sql_str, params) = self.builder.sql.build();
let driver_params: Vec<turso::Value> = params
.iter()
.copied()
.map(std::convert::Into::into)
.collect();
turso_execute_cached(&self.runner.conn, &sql_str, driver_params)
.await
.map_err(drizzle_core::error::DrizzleError::from)
.with_query(|| QueryContext::new(&sql_str, ¶ms))
}
pub async fn all<R, Proof, AggProof>(self) -> drizzle_core::error::Result<Vec<R>>
where
for<'r> Mk: drizzle_core::row::DecodeSelectedRef<&'r ::turso::Row, R>
+ drizzle_core::row::MarkerScopeValidFor<Proof>
+ drizzle_core::row::StrictDecodeMarker
+ drizzle_core::row::MarkerColumnCountValid<::turso::Row, Rw, R>,
Mk: drizzle_core::row::MarkerAggValidFor<Grouped, AggProof>,
{
let (sql_str, params) = self.builder.sql.build();
let driver_params: Vec<turso::Value> = params
.iter()
.copied()
.map(std::convert::Into::into)
.collect();
let mut rows = turso_query_cached(&self.runner.conn, &sql_str, driver_params)
.await
.map_err(drizzle_core::error::DrizzleError::from)
.with_query(|| QueryContext::new(&sql_str, ¶ms))?;
let mut decoded = Vec::new();
while let Some(row) = rows
.next()
.await
.map_err(drizzle_core::error::DrizzleError::from)
.with_query(|| QueryContext::new(&sql_str, ¶ms))?
{
decoded.push(<Mk as drizzle_core::row::DecodeSelectedRef<
&::turso::Row,
R,
>>::decode(&row)?);
}
Ok(decoded)
}
pub async fn rows(self) -> drizzle_core::error::Result<Rows<Rw>>
where
Rw: for<'r> TryFrom<&'r turso::Row>,
for<'r> <Rw as TryFrom<&'r turso::Row>>::Error: Into<drizzle_core::error::DrizzleError>,
{
let (sql_str, params) = self.builder.sql.build();
let driver_params: Vec<turso::Value> = params
.iter()
.copied()
.map(std::convert::Into::into)
.collect();
let rows = self
.runner
.conn
.query(&sql_str, driver_params)
.await
.map_err(drizzle_core::error::DrizzleError::from)
.with_query(|| QueryContext::new(&sql_str, ¶ms))?;
Ok(Rows::with_sql(rows, sql_str))
}
pub async fn get<R, Proof, AggProof>(self) -> drizzle_core::error::Result<R>
where
for<'r> Mk: drizzle_core::row::DecodeSelectedRef<&'r ::turso::Row, R>
+ drizzle_core::row::MarkerScopeValidFor<Proof>
+ drizzle_core::row::StrictDecodeMarker
+ drizzle_core::row::MarkerColumnCountValid<::turso::Row, Rw, R>,
Mk: drizzle_core::row::MarkerAggValidFor<Grouped, AggProof>,
{
let (sql_str, params) = self.builder.sql.build();
let driver_params: Vec<turso::Value> = params
.iter()
.copied()
.map(std::convert::Into::into)
.collect();
let mut rows = turso_query_cached(&self.runner.conn, &sql_str, driver_params)
.await
.map_err(drizzle_core::error::DrizzleError::from)
.with_query(|| QueryContext::new(&sql_str, ¶ms))?;
rows.next()
.await
.map_err(drizzle_core::error::DrizzleError::from)
.with_query(|| QueryContext::new(&sql_str, ¶ms))?
.map_or_else(
|| Err(drizzle_core::error::DrizzleError::NotFound),
|row| <Mk as drizzle_core::row::DecodeSelectedRef<&::turso::Row, R>>::decode(&row),
)
}
}