Defining the Application Adapter
The first step in setting up data access is to generate an Application adapter. This establishes a default adapter for the Store to use, which can be supplemented later by additional model-specific adapters.
Let's generate a REST-based Application adapter:
$ auric generate adapter application --target rest
created src/adapters/application.rs
updated src/adapters/mod.rs
==> make
Compiling drr v0.1.0 (/Users/davidr/workspaces/drr)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 2.47s
This will create the following file:
// src/adapters/application.rs
use auric_runtime::{
Config,
async_trait::async_trait,
data::{Adapter, QueryRecordOptions, adapters::RestAdapter},
};
use jsonapi_core::Resource;
#[derive(Default)]
pub struct ApplicationAdapter {
target: RestAdapter,
}
#[async_trait(?Send)]
impl Adapter for ApplicationAdapter {
fn init(&mut self, config: &Config) -> Result<()> {
self.target.init(config)
}
async fn create_record(&self, resource: Resource) -> Result<Resource> {
self.target.create_record(resource).await
}
async fn delete_record(&self, resource: &Resource) -> Result<()> {
self.target.delete_record(resource).await
}
async fn find_record(&self, resource_type: &str, id: &str) -> Result<Resource> {
self.target.find_record(resource_type, id).await
}
async fn query(&self, resource_type: &str, query: serde_json::Value) -> Result<Vec<Resource>> {
self.target.query(resource_type, query).await
}
async fn query_record(
&self,
resource_type: &str,
query: serde_json::Value,
options: QueryRecordOptions,
) -> Result<Option<Resource>> {
self.target
.query_record(resource_type, query, options)
.await
}
async fn update_record(&self, resource: Resource) -> Result<Resource> {
self.target.update_record(resource).await
}
}
#[cfg(test)]
mod tests {
use super::ApplicationAdapter;
use auric_runtime::data::Adapter;
use serde_json::json;
#[test]
fn can_construct() {
let _ = ApplicationAdapter::default();
}
#[test]
fn can_init() {
let mut adapter = ApplicationAdapter::default();
let config = json!({"api_url": "http://localhost:3000"});
adapter
.init(&config)
.expect("Expected to initialize with a valid api url");
}
#[test]
fn cannot_init_with_missing_api_url() {
let mut adapter = ApplicationAdapter::default();
let config = json!({"someStuff": "abc"});
assert!(
adapter.init(&config).is_err(),
"Expected init to fail due to missing api url",
);
}
}
As you can see, the implementation of each Adapter trait function simply delegates to a target RestAdapter, providing a default implementation upfront, while leaving you in a position to make future customizations.