Skip to content

Commit

Permalink
Expose row columns for MySQL
Browse files Browse the repository at this point in the history
This is my attempt to fix #181 .

I am not sure if you have the same implementation in mind so let me know if I am
on the right track.

I was not sure how to verify the column type in tests as I couldn't construct
`MySqlTypeInfo` due to `TypeId` being crate-private.
  • Loading branch information
zaynetro committed Apr 30, 2020
1 parent c285e28 commit 08cca83
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 4 deletions.
21 changes: 20 additions & 1 deletion sqlx-core/src/mysql/row.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use std::collections::HashMap;
use std::sync::Arc;
use std::vec::Vec;

use crate::mysql::protocol;
use crate::mysql::{MySql, MySqlValue};
use crate::row::{ColumnIndex, Row};
use crate::row::{Column, ColumnIndex, Row};

pub struct MySqlRow<'c> {
pub(super) row: protocol::Row<'c>,
Expand Down Expand Up @@ -35,6 +36,24 @@ impl<'c> Row<'c> for MySqlRow<'c> {

Ok(value)
}

fn columns(&self) -> Box<[Column<Self::Database>]> {
let mut columns = Vec::with_capacity(self.row.columns.len());
for (index, column_type) in self.row.columns.iter().enumerate() {
let name = self
.names
.iter()
.find(|(_name, name_index)| (**name_index as usize) == index)
.map(|(name, _)| name.as_ref());

columns.push(Column {
name,
type_info: Some(column_type),
});
}

columns.into_boxed_slice()
}
}

impl<'c> ColumnIndex<'c, MySqlRow<'c>> for usize {
Expand Down
6 changes: 5 additions & 1 deletion sqlx-core/src/postgres/row.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::postgres::protocol::{DataRow, TypeFormat};
use crate::postgres::type_info::SharedStr;
use crate::postgres::value::PgValue;
use crate::postgres::{PgTypeInfo, Postgres};
use crate::row::{ColumnIndex, Row};
use crate::row::{self, ColumnIndex, Row};

// A statement has 0 or more columns being returned from the database
// For Postgres, each column has an OID and a format (binary or text)
Expand Down Expand Up @@ -68,6 +68,10 @@ impl<'c> Row<'c> for PgRow<'c> {

Ok(value)
}

fn columns(&self) -> Box<[row::Column<Self::Database>]> {
todo!()
}
}

impl<'c> ColumnIndex<'c, PgRow<'c>> for usize {
Expand Down
8 changes: 8 additions & 0 deletions sqlx-core/src/row.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,9 @@ where
) -> crate::Result<<Self::Database as HasRawValue<'c>>::RawValue>
where
I: ColumnIndex<'c, Self>;

/// Get all columns.
fn columns(&self) -> Box<[Column<Self::Database>]>;
}

// Prevent users from implementing the `Row` trait.
Expand Down Expand Up @@ -235,6 +238,11 @@ where
fn from_row(row: &R) -> crate::Result<Self>;
}

pub struct Column<'r, DB: Database> {
pub name: Option<&'r str>,
pub type_info: Option<&'r DB::TypeInfo>,
}

// Macros to help unify the internal implementations as a good chunk
// is very similar

Expand Down
6 changes: 5 additions & 1 deletion sqlx-core/src/sqlite/row.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::row::{ColumnIndex, Row};
use crate::row::{Column, ColumnIndex, Row};
use crate::sqlite::statement::Statement;
use crate::sqlite::value::SqliteValue;
use crate::sqlite::{Sqlite, SqliteConnection};
Expand Down Expand Up @@ -43,6 +43,10 @@ impl<'c> Row<'c> for SqliteRow<'c> {
index: index.index(self)? as i32,
})
}

fn columns(&self) -> Box<[Column<Self::Database>]> {
todo!()
}
}

impl<'c> ColumnIndex<'c, SqliteRow<'c>> for usize {
Expand Down
36 changes: 35 additions & 1 deletion tests/mysql.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use futures::TryStreamExt;
use sqlx::{mysql::MySqlQueryAs, Connection, Executor, MySql, MySqlPool};
use sqlx::{mysql::MySqlQueryAs, Connection, Cursor, Executor, MySql, MySqlPool, Row};
use sqlx_test::new;
use std::time::Duration;

Expand Down Expand Up @@ -232,3 +232,37 @@ async fn test_fetch_one_and_ping() -> anyhow::Result<()> {

Ok(())
}

#[cfg_attr(feature = "runtime-async-std", async_std::test)]
#[cfg_attr(feature = "runtime-tokio", tokio::test)]
async fn test_row_columns() -> anyhow::Result<()> {
let mut conn = new::<MySql>().await?;

let _ = conn
.execute(
r#"
CREATE TEMPORARY TABLE row_columns_test (
id int primary key auto_increment,
name text not null,
age int
);
INSERT INTO row_columns_test (name, age) VALUES ('James', 12);
"#,
)
.await?;

let mut cursor = conn.fetch("SELECT * FROM row_columns_test");
let row = cursor.next().await?.unwrap();
let columns = row.columns();

assert_eq!(columns.len(), 3);
assert_eq!(columns[0].name, Some("id"));
assert_eq!(columns[0].type_info.is_some(), true);
assert_eq!(columns[1].name, Some("name"));
assert_eq!(columns[1].type_info.is_some(), true);
assert_eq!(columns[2].name, Some("age"));
assert_eq!(columns[2].type_info.is_some(), true);

Ok(())
}

0 comments on commit 08cca83

Please sign in to comment.