Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit07336e5

Browse files
committed
Introduce RowBuilder to support writing basic unit tests
Added RowDescription trait, and let rows to share the same descriptionrather than having a copy in each row (think when there are thousand ofthem in the result).Added RowBuilder to support adding stubs of row data in unit tests.Currently, the library users have no chooice but have to use integrationtests for testing Postgres data access code. With the changes in thiscommit, the `tokio-postgres` lib users can use RowBuilder to createsutbs to verify the deserialization from database result (Rows) tocustom stucts in unit tests.It can also serves as a base for future implementation of certain kindof mocks of the db connection.Related-to#910#950
1 parent0c05614 commit07336e5

File tree

8 files changed

+157
-17
lines changed

8 files changed

+157
-17
lines changed

‎postgres-protocol/src/message/backend.rs‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ impl Message {
164164
DATA_ROW_TAG =>{
165165
let len = buf.read_u16::<BigEndian>()?;
166166
let storage = buf.read_all();
167-
Message::DataRow(DataRowBody{storage, len})
167+
Message::DataRow(DataRowBody::new(storage, len))
168168
}
169169
ERROR_RESPONSE_TAG =>{
170170
let storage = buf.read_all();
@@ -531,6 +531,11 @@ pub struct DataRowBody {
531531
}
532532

533533
implDataRowBody{
534+
/// Constructs a new data row body.
535+
pubfnnew(storage:Bytes,len:u16) ->Self{
536+
Self{ storage, len}
537+
}
538+
534539
#[inline]
535540
pubfnranges(&self) ->DataRowRanges<'_>{
536541
DataRowRanges{

‎postgres-types/src/lib.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -735,6 +735,7 @@ impl<'a> FromSql<'a> for IpAddr {
735735
}
736736

737737
/// An enum representing the nullability of a Postgres value.
738+
#[derive(Debug,Eq,PartialEq)]
738739
pubenumIsNull{
739740
/// The value is NULL.
740741
Yes,

‎postgres/src/test.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::thread;
55
use std::time::Duration;
66
use tokio_postgres::error::SqlState;
77
use tokio_postgres::types::Type;
8-
use tokio_postgres::NoTls;
8+
use tokio_postgres::{NoTls,RowDescription};
99

1010
usesuper::*;
1111
usecrate::binary_copy::{BinaryCopyInWriter,BinaryCopyOutIter};

‎tokio-postgres/src/lib.rs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,11 +130,11 @@ pub use crate::error::Error;
130130
pubusecrate::generic_client::GenericClient;
131131
pubusecrate::portal::Portal;
132132
pubusecrate::query::RowStream;
133-
pubusecrate::row::{Row,SimpleQueryRow};
133+
pubusecrate::row::{Row,RowBuilder,SimpleQueryRow};
134134
pubusecrate::simple_query::SimpleQueryStream;
135135
#[cfg(feature ="runtime")]
136136
pubusecrate::socket::Socket;
137-
pubusecrate::statement::{Column,Statement};
137+
pubusecrate::statement::{Column,RowDescription,Statement};
138138
#[cfg(feature ="runtime")]
139139
usecrate::tls::MakeTlsConnect;
140140
pubusecrate::tls::NoTls;

‎tokio-postgres/src/query.rs‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use postgres_protocol::message::frontend;
1212
use std::fmt;
1313
use std::marker::PhantomPinned;
1414
use std::pin::Pin;
15+
use std::sync::Arc;
1516
use std::task::{Context,Poll};
1617

1718
structBorrowToSqlParamsDebug<'a,T>(&'a[T]);
@@ -50,7 +51,7 @@ where
5051
};
5152
let responses =start(client, buf).await?;
5253
Ok(RowStream{
53-
statement,
54+
statement:Arc::new(statement),
5455
responses,
5556
_p:PhantomPinned,
5657
})
@@ -70,7 +71,7 @@ pub async fn query_portal(
7071
let responses = client.send(RequestMessages::Single(FrontendMessage::Raw(buf)))?;
7172

7273
Ok(RowStream{
73-
statement: portal.statement().clone(),
74+
statement:Arc::new(portal.statement().clone()),
7475
responses,
7576
_p:PhantomPinned,
7677
})
@@ -200,7 +201,7 @@ where
200201
pin_project!{
201202
/// A stream of table rows.
202203
pubstructRowStream{
203-
statement:Statement,
204+
statement:Arc<Statement>,
204205
responses:Responses,
205206
#[pin]
206207
_p:PhantomPinned,

‎tokio-postgres/src/row.rs‎

Lines changed: 124 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22
33
usecrate::row::sealed::{AsName,Sealed};
44
usecrate::simple_query::SimpleColumn;
5-
usecrate::statement::Column;
5+
usecrate::statement::{Column,RowDescription};
66
usecrate::types::{FromSql,Type,WrongType};
7-
usecrate::{Error,Statement};
7+
usecrate::Error;
8+
use bytes::{BufMut,BytesMut};
89
use fallible_iterator::FallibleIterator;
910
use postgres_protocol::message::backend::DataRowBody;
11+
use postgres_types::{IsNull,ToSql};
1012
use std::fmt;
1113
use std::ops::Range;
1214
use std::str;
@@ -96,7 +98,7 @@ where
9698

9799
/// A row of data returned from the database by a query.
98100
pubstructRow{
99-
statement:Statement,
101+
description:Arc<dynRowDescription>,
100102
body:DataRowBody,
101103
ranges:Vec<Option<Range<usize>>>,
102104
}
@@ -110,18 +112,26 @@ impl fmt::Debug for Row {
110112
}
111113

112114
implRow{
113-
pub(crate)fnnew(statement:Statement,body:DataRowBody) ->Result<Row,Error>{
115+
pub(crate)fnnew(
116+
description:Arc<dynRowDescription>,
117+
body:DataRowBody,
118+
) ->Result<Row,Error>{
114119
let ranges = body.ranges().collect().map_err(Error::parse)?;
115120
Ok(Row{
116-
statement,
121+
description,
117122
body,
118123
ranges,
119124
})
120125
}
121126

127+
/// Returns description about the data in the row.
128+
pubfndescription(&self) ->Arc<dynRowDescription>{
129+
self.description.clone()
130+
}
131+
122132
/// Returns information about the columns of data in the row.
123133
pubfncolumns(&self) ->&[Column]{
124-
self.statement.columns()
134+
self.description.columns()
125135
}
126136

127137
/// Determines if the row contains no values.
@@ -270,3 +280,111 @@ impl SimpleQueryRow {
270280
FromSql::from_sql_nullable(&Type::TEXT, buf).map_err(|e|Error::from_sql(e, idx))
271281
}
272282
}
283+
/// Builder for building a [`Row`].
284+
pubstructRowBuilder{
285+
desc:Arc<dynRowDescription>,
286+
buf:BytesMut,
287+
n:usize,
288+
}
289+
290+
implRowBuilder{
291+
/// Creates a new builder using the provided row description.
292+
pubfnnew(desc:Arc<dynRowDescription>) ->Self{
293+
Self{
294+
desc,
295+
buf:BytesMut::new(),
296+
n:0,
297+
}
298+
}
299+
300+
/// Appends a column's value and returns a value indicates if this value should be represented
301+
/// as NULL.
302+
pubfnpush(&mutself,value:Option<implToSql>) ->Result<IsNull,Error>{
303+
let columns =self.desc.columns();
304+
305+
if columns.len() ==self.n{
306+
returnErr(Error::column(
307+
"exceeded expected number of columns".to_string(),
308+
));
309+
}
310+
311+
let db_type = columns[self.n].type_();
312+
let start =self.buf.len();
313+
314+
// Reserve 4 bytes for the length of the binary data to be written
315+
self.buf.put_i32(-1i32);
316+
317+
let is_null = value
318+
.to_sql(db_type,&mutself.buf)
319+
.map_err(|e|Error::to_sql(e,self.n))?;
320+
321+
// Calculate the length of data just written.
322+
if is_null ==IsNull::No{
323+
let len =(self.buf.len() - start -4)asi32;
324+
// Update the length of data
325+
self.buf[start..start +4].copy_from_slice(&len.to_be_bytes());
326+
};
327+
328+
self.n +=1;
329+
Ok(is_null)
330+
}
331+
332+
/// Builds the row.
333+
pubfnbuild(self) ->Result<Row,Error>{
334+
Row::new(
335+
self.desc.clone(),
336+
DataRowBody::new(self.buf.freeze(),self.nasu16),
337+
)
338+
}
339+
}
340+
341+
#[cfg(test)]
342+
mod tests{
343+
use postgres_types::IsNull;
344+
345+
usesuper::*;
346+
use std::net::IpAddr;
347+
348+
structTestRowDescription{
349+
columns:Vec<Column>,
350+
}
351+
352+
implRowDescriptionforTestRowDescription{
353+
fncolumns(&self) ->&[Column]{
354+
&self.columns
355+
}
356+
}
357+
358+
#[test]
359+
fntest_row_builder(){
360+
letmut builder =RowBuilder::new(Arc::new(TestRowDescription{
361+
columns:vec![
362+
Column::new("id".to_string(),Type::INT8),
363+
Column::new("name".to_string(),Type::VARCHAR),
364+
Column::new("ip".to_string(),Type::INET),
365+
],
366+
}));
367+
368+
let expected_id =1234i64;
369+
let is_null = builder.push(Some(expected_id)).unwrap();
370+
assert_eq!(IsNull::No, is_null);
371+
372+
let expected_name ="row builder";
373+
let is_null = builder.push(Some(expected_name)).unwrap();
374+
assert_eq!(IsNull::No, is_null);
375+
376+
let is_null = builder.push(None::<IpAddr>).unwrap();
377+
assert_eq!(IsNull::Yes, is_null);
378+
379+
let row = builder.build().unwrap();
380+
381+
let actual_id:i64 = row.try_get("id").unwrap();
382+
assert_eq!(expected_id, actual_id);
383+
384+
let actual_name:String = row.try_get("name").unwrap();
385+
assert_eq!(expected_name, actual_name);
386+
387+
let actual_dt:Option<IpAddr> = row.try_get("ip").unwrap();
388+
assert_eq!(None, actual_dt);
389+
}
390+
}

‎tokio-postgres/src/statement.rs‎

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ use std::{
88
sync::{Arc,Weak},
99
};
1010

11+
/// Describes the data (columns) in a row.
12+
pubtraitRowDescription:Sync +Send{
13+
/// Returns information about the columns returned when the statement is queried.
14+
fncolumns(&self) ->&[Column];
15+
}
16+
1117
structStatementInner{
1218
client:Weak<InnerClient>,
1319
name:String,
@@ -57,9 +63,16 @@ impl Statement {
5763
pubfnparams(&self) ->&[Type]{
5864
&self.0.params
5965
}
66+
}
6067

61-
/// Returns information about the columns returned when the statement is queried.
62-
pubfncolumns(&self) ->&[Column]{
68+
implRowDescriptionforStatement{
69+
fncolumns(&self) ->&[Column]{
70+
&self.0.columns
71+
}
72+
}
73+
74+
implRowDescriptionforArc<Statement>{
75+
fncolumns(&self) ->&[Column]{
6376
&self.0.columns
6477
}
6578
}
@@ -71,7 +84,8 @@ pub struct Column {
7184
}
7285

7386
implColumn{
74-
pub(crate)fnnew(name:String,type_:Type) ->Column{
87+
/// Constructs a new column.
88+
pubfnnew(name:String,type_:Type) ->Column{
7589
Column{ name, type_}
7690
}
7791

‎tokio-postgres/tests/test/main.rs‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ use tokio_postgres::error::SqlState;
1616
use tokio_postgres::tls::{NoTls,NoTlsStream};
1717
use tokio_postgres::types::{Kind,Type};
1818
use tokio_postgres::{
19-
AsyncMessage,Client,Config,Connection,Error,IsolationLevel,SimpleQueryMessage,
19+
AsyncMessage,Client,Config,Connection,Error,IsolationLevel,RowDescription,
20+
SimpleQueryMessage,
2021
};
2122

2223
mod binary_copy;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp