add get_record()
This commit is contained in:
parent
17e698547b
commit
0614425125
4 changed files with 116 additions and 17 deletions
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::error::Error;
|
||||||
|
|
||||||
use ferrtable::Client;
|
use ferrtable::Client;
|
||||||
use futures::StreamExt as _;
|
use futures::StreamExt as _;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
@ -25,14 +27,14 @@ enum RecordStatus {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() -> Result<(), Box<dyn Error>> {
|
||||||
let settings = Settings::load().unwrap();
|
let settings = Settings::load()?;
|
||||||
let client = Client::new_from_access_token(&settings.access_token).unwrap();
|
let client = Client::new_from_access_token(&settings.access_token)?;
|
||||||
|
|
||||||
println!("Testing Client::list_bases()...");
|
println!("Testing Client::list_bases()...");
|
||||||
let mut bases = client.list_bases().build().unwrap().stream_items();
|
let mut bases = client.list_bases().build()?.stream_items();
|
||||||
while let Some(res) = bases.next().await {
|
while let Some(res) = bases.next().await {
|
||||||
dbg!(res.unwrap());
|
dbg!(res?);
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("Testing Client::create_records()...");
|
println!("Testing Client::create_records()...");
|
||||||
|
|
@ -44,28 +46,46 @@ async fn main() {
|
||||||
}])
|
}])
|
||||||
.with_base_id(settings.base_id.clone())
|
.with_base_id(settings.base_id.clone())
|
||||||
.with_table_id(settings.table_id.clone())
|
.with_table_id(settings.table_id.clone())
|
||||||
.build()
|
.build()?
|
||||||
.unwrap()
|
|
||||||
.execute()
|
.execute()
|
||||||
.await
|
.await?;
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
println!("Testing Client::list_records()...");
|
println!("Testing Client::list_records()...");
|
||||||
let records = client
|
let records = client
|
||||||
.list_records()
|
.list_records()
|
||||||
.with_base_id(settings.base_id.clone())
|
.with_base_id(settings.base_id.clone())
|
||||||
.with_table_id(settings.table_id.clone())
|
.with_table_id(settings.table_id.clone())
|
||||||
.build()
|
.build()?
|
||||||
.unwrap()
|
|
||||||
.stream_items::<TestRecord>()
|
.stream_items::<TestRecord>()
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.await
|
.await
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.collect::<Result<Vec<_>, _>>()
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
.unwrap();
|
for rec in records.iter() {
|
||||||
for rec in records {
|
dbg!(&rec.fields);
|
||||||
dbg!(rec.fields);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let record = client
|
||||||
|
.get_record()
|
||||||
|
.with_base_id(settings.base_id.clone())
|
||||||
|
.with_table_id(settings.table_id.clone())
|
||||||
|
.with_record_id("does_not_exist".to_string())
|
||||||
|
.build()?
|
||||||
|
.fetch_optional::<TestRecord>()
|
||||||
|
.await?;
|
||||||
|
assert!(record.is_none());
|
||||||
|
|
||||||
|
let record = client
|
||||||
|
.get_record()
|
||||||
|
.with_base_id(settings.base_id.clone())
|
||||||
|
.with_table_id(settings.table_id.clone())
|
||||||
|
.with_record_id(records.first().unwrap().id.clone())
|
||||||
|
.build()?
|
||||||
|
.fetch_optional::<TestRecord>()
|
||||||
|
.await?;
|
||||||
|
dbg!(record);
|
||||||
|
|
||||||
println!("All tests succeeded.");
|
println!("All tests succeeded.");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@ use std::fmt::Debug;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
create_records::CreateRecordsQueryBuilder, list_bases::ListBasesQueryBuilder,
|
create_records::CreateRecordsQueryBuilder, get_record::GetRecordQueryBuilder,
|
||||||
list_records::ListRecordsQueryBuilder,
|
list_bases::ListBasesQueryBuilder, list_records::ListRecordsQueryBuilder,
|
||||||
};
|
};
|
||||||
|
|
||||||
const DEFAULT_API_ROOT: &str = "https://api.airtable.com";
|
const DEFAULT_API_ROOT: &str = "https://api.airtable.com";
|
||||||
|
|
@ -68,6 +68,32 @@ impl Client {
|
||||||
.with_records(records.into_iter().collect())
|
.with_records(records.into_iter().collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Retrieve a single record. Any "empty" fields (e.g. "", [], or false) in
|
||||||
|
/// the record will not be returned.
|
||||||
|
///
|
||||||
|
/// Note If we can't locate the record on a given table, the request will
|
||||||
|
/// fallback to a base wide search and will still return the record if the
|
||||||
|
/// Record ID is valid and the record is located within the same base.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ## Basic Usage
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// let result = client
|
||||||
|
/// .get_record()
|
||||||
|
/// .with_base_id("***".to_owned())
|
||||||
|
/// .with_table_id("***".to_owned())
|
||||||
|
/// .with_record_id("***".to_owned())
|
||||||
|
/// .build()?
|
||||||
|
/// .fetch_optional()
|
||||||
|
/// .await?;
|
||||||
|
/// dbg!(result);
|
||||||
|
/// ```
|
||||||
|
pub fn get_record(&self) -> GetRecordQueryBuilder {
|
||||||
|
GetRecordQueryBuilder::default().with_client(self.clone())
|
||||||
|
}
|
||||||
|
|
||||||
/// List the bases the token can access
|
/// List the bases the token can access
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
|
|
|
||||||
52
ferrtable/src/get_record.rs
Normal file
52
ferrtable/src/get_record.rs
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
use derive_builder::Builder;
|
||||||
|
use percent_encoding::{NON_ALPHANUMERIC, utf8_percent_encode};
|
||||||
|
use serde::{Serialize, de::DeserializeOwned};
|
||||||
|
|
||||||
|
use crate::client::Client;
|
||||||
|
use crate::errors::ExecutionError;
|
||||||
|
use crate::types::AirtableRecord;
|
||||||
|
|
||||||
|
#[derive(Builder, Clone, Debug, Serialize)]
|
||||||
|
#[builder(pattern = "owned", setter(prefix = "with"))]
|
||||||
|
pub struct GetRecordQuery {
|
||||||
|
#[serde(skip)]
|
||||||
|
base_id: String,
|
||||||
|
|
||||||
|
#[serde(skip)]
|
||||||
|
#[builder(vis = "pub(crate)")]
|
||||||
|
client: Client,
|
||||||
|
|
||||||
|
#[serde(skip)]
|
||||||
|
record_id: String,
|
||||||
|
|
||||||
|
#[serde(skip)]
|
||||||
|
table_id: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetRecordQuery {
|
||||||
|
pub async fn fetch_optional<T>(self) -> Result<Option<AirtableRecord<T>>, ExecutionError>
|
||||||
|
where
|
||||||
|
T: Clone + Debug + DeserializeOwned,
|
||||||
|
{
|
||||||
|
let base_id = utf8_percent_encode(&self.base_id, NON_ALPHANUMERIC).to_string();
|
||||||
|
let table_id = utf8_percent_encode(&self.table_id, NON_ALPHANUMERIC).to_string();
|
||||||
|
let record_id = utf8_percent_encode(&self.record_id, NON_ALPHANUMERIC).to_string();
|
||||||
|
let http_resp = self
|
||||||
|
.client
|
||||||
|
.get_path(&format!("v0/{base_id}/{table_id}/{record_id}"))
|
||||||
|
.send()
|
||||||
|
.await?;
|
||||||
|
match http_resp.error_for_status() {
|
||||||
|
Ok(http_resp) => Ok(http_resp.json().await?),
|
||||||
|
Err(err) => {
|
||||||
|
if err.status() == Some(reqwest::StatusCode::NOT_FOUND) {
|
||||||
|
Ok(None)
|
||||||
|
} else {
|
||||||
|
Err(err.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -91,6 +91,7 @@ pub mod types;
|
||||||
|
|
||||||
// Each API operation is organized into a dedicated Rust module.
|
// Each API operation is organized into a dedicated Rust module.
|
||||||
pub mod create_records;
|
pub mod create_records;
|
||||||
|
pub mod get_record;
|
||||||
pub mod list_bases;
|
pub mod list_bases;
|
||||||
pub mod list_records;
|
pub mod list_records;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue