Skip to content

Commit

Permalink
🎨 Split client into core, async and sync crates.
Browse files Browse the repository at this point in the history
  • Loading branch information
LouisGariepy committed Jul 30, 2022
1 parent 5312849 commit e400630
Show file tree
Hide file tree
Showing 25 changed files with 261 additions and 946 deletions.
40 changes: 28 additions & 12 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[workspace]
members = [
"examples/*",
"cornucopia_client",
"clients/*",
"integration",
"codegen_test",
"bench",
Expand Down
6 changes: 4 additions & 2 deletions bench/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@ criterion = "0.3.6"
postgres = "0.19.3"
tokio-postgres = "0.7.6"
postgres-types = "0.2.3"
cornucopia = { path = "../cornucopia" }
cornucopia_client = { path = "../cornucopia_client", features = ["sync"] }
diesel = { version = "2.0.0-rc.0", features = ["postgres"] }

cornucopia = { path = "../cornucopia" }
cornucopia_client_sync = { path = "../clients/cornucopia_client_sync" }
cornucopia_client_async = { path = "../clients/cornucopia_client_async" }

[[bench]]
name = "usage"
harness = false
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[package]
name = "cornucopia_client"
name = "cornucopia_client_async"
version = "0.2.2"
edition = "2021"
license = "MIT/Apache-2.0"
Expand All @@ -12,17 +12,13 @@ keywords = ["postgresql", "query", "generator", "sql", "tokio-postgres"]

[features]
default = ["deadpool"]
async = ["dep:tokio-postgres", "dep:async-trait"]
deadpool = ["async", "dep:deadpool-postgres"]
sync = ["dep:postgres"]
deadpool = ["dep:deadpool-postgres"]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
tokio-postgres = { version = "0.7.6", optional = true }
postgres = { version = "0.19.3", optional = true }
async-trait = { version = "0.1.56", optional = true }
tokio-postgres = { version = "0.7.6" }
async-trait = { version = "0.1.56" }
deadpool-postgres = { version = "0.10.2", optional = true }
fallible-iterator = "0.2"
postgres-protocol = "0.6.4"
postgres-types = { version = "0.2.3" }

cornucopia_client_core = { path = "../cornucopia_client_core" }
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use tokio_postgres::{
Transaction as PgTransaction,
};

use crate::async_::GenericClient;
use crate::generic_client::GenericClient;

#[async_trait]
impl GenericClient for DeadpoolClient {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,37 +169,3 @@ impl GenericClient for Client {
Client::query_raw(self, statement, params).await
}
}

/// Cached statement
pub struct Stmt {
query: &'static str,
cached: Option<Statement>,
}

impl Stmt {
#[must_use]
pub fn new(query: &'static str) -> Self {
Self {
query,
cached: None,
}
}

pub async fn prepare<'a, C: GenericClient>(
&'a mut self,
client: &C,
) -> Result<&'a Statement, Error> {
if self.cached.is_none() {
let stmt = client.prepare(self.query).await?;
self.cached = Some(stmt);
}
// the statement is always prepared at this point
Ok(unsafe { self.cached.as_ref().unwrap_unchecked() })
}
}

/// This trait allows you to bind parameters to a query using a single
/// struct, rather than passing each bind parameter as a function parameter.
pub trait Params<'a, P, O, C> {
fn params(&'a mut self, client: &'a C, params: &'a P) -> O;
}
15 changes: 15 additions & 0 deletions clients/cornucopia_client_async/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#[doc(hidden)]
pub mod private;

pub use crate::generic_client::GenericClient;
pub use cornucopia_client_core::ArrayIterator;

#[cfg(feature = "deadpool")]
mod deadpool;
mod generic_client;

/// This trait allows you to bind parameters to a query using a single
/// struct, rather than passing each bind parameter as a function parameter.
pub trait Params<'a, P, O, C> {
fn params(&'a mut self, client: &'a C, params: &'a P) -> O;
}
32 changes: 32 additions & 0 deletions clients/cornucopia_client_async/src/private.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
pub use cornucopia_client_core::{slice_iter, Domain, DomainArray};

use crate::generic_client::GenericClient;
use tokio_postgres::{Error, Statement};

/// Cached statement
pub struct Stmt {
query: &'static str,
cached: Option<Statement>,
}

impl Stmt {
#[must_use]
pub fn new(query: &'static str) -> Self {
Self {
query,
cached: None,
}
}

pub async fn prepare<'a, C: GenericClient>(
&'a mut self,
client: &C,
) -> Result<&'a Statement, Error> {
if self.cached.is_none() {
let stmt = client.prepare(self.query).await?;
self.cached = Some(stmt);
}
// the statement is always prepared at this point
Ok(unsafe { self.cached.as_ref().unwrap_unchecked() })
}
}
18 changes: 18 additions & 0 deletions clients/cornucopia_client_core/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[package]
name = "cornucopia_client_core"
version = "0.2.2"
edition = "2021"
license = "MIT/Apache-2.0"
description = "Generic client trait for Cornucopia users"
homepage = "https://github.com/cornucopia-rs/cornucopia"
repository = "https://github.com/cornucopia-rs/cornucopia"
readme = "README.md"
categories = ["database"]
keywords = ["postgresql", "query", "generator", "sql", "tokio-postgres"]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
postgres-protocol = "0.6.4"
postgres-types = { version = "0.2.3" }
fallible-iterator = "0.2"
47 changes: 47 additions & 0 deletions clients/cornucopia_client_core/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<div align="center"> <img src="https://raw.githubusercontent.com/cornucopia-rs/cornucopia/main/assets/logo.svg" width=200 /> </div>
<h1 align="center">Cornucopia</h1>
<div align="center">
<strong>
Generate type checked Rust from your SQL
</strong>
</div>

<br />

<div align="center">
<!-- Github Actions -->
<img src="https://img.shields.io/github/workflow/status/cornucopia-rs/cornucopia/ci" alt="actions status" />
<!-- Version -->
<a href="https://crates.io/crates/cornucopia">
<img src="https://img.shields.io/crates/v/cornucopia.svg?style=flat-square"
alt="Crates.io version" />
</a>
<!-- Downloads -->
<a href="https://crates.io/crates/cornucopia">
<img src="https://img.shields.io/crates/d/cornucopia.svg?style=flat-square"
alt="Download" />
</a>
</div>

<div align="center">
<h4>
<a href="#install">
Install
</a>
<span> | </span>
<a href="/examples/basic_async/README.md">
Example
</a>
</h4>
</div>

---

This crate is a small library exposing Cornucopia's `GenericClient`. You probably need this if you're a Cornucopia user.

The `GenericClient` is an abstraction over four types of connections (`deadpool_postgres::Client`, `deadpool_postgres::Transaction`, `tokio_postgres::Client`, `tokio_postgres::Transaction`). Its meant to allow you to mix-and-match these connection types in Cornucopia Queries.

| | non-pooled | pooled |
| ---------------- | ----------------------------- | -------------------------------- |
| single-statement | `tokio_postgres::Client` | `deadpool_postgres::Client` |
| multi-statement | `tokio_postgres::Transaction` | `deadpool_postgres::Transaction` |
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use fallible_iterator::FallibleIterator;
use postgres_protocol::types::{array_from_sql, ArrayValues};
use postgres_types::{FromSql, Kind, Type};
use std::{fmt::Debug, marker::PhantomData};
use std::fmt::Debug;
use std::marker::PhantomData;

use crate::private::escape_domain;
use crate::utils::escape_domain;

/// Iterator over the items in a PostgreSQL array. You only need this if you are
/// working with custom zero-cost type mapping of rows containing PostgreSQL arrays.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ use std::{
fmt::{Debug, Formatter},
};

use crate::utils::escape_domain;

pub struct Domain<T: ToSql>(pub T);

impl<T: ToSql + Debug> Debug for Domain<T> {
Expand Down Expand Up @@ -37,7 +39,6 @@ impl<T: ToSql> ToSql for Domain<T> {
}
}

/// Wrapper for slice `ToSql` which ignore
pub struct DomainArray<'a, T: ToSql>(pub &'a [T]);

impl<'a, T: ToSql> Debug for DomainArray<'a, T> {
Expand Down Expand Up @@ -87,23 +88,10 @@ impl<'a, T: ToSql + 'a> ToSql for DomainArray<'a, T> {
}
}

pub fn slice_iter<'a>(
s: &'a [&'a (dyn ToSql + Sync)],
) -> impl ExactSizeIterator<Item = &'a dyn ToSql> + 'a {
s.iter().map(|s| *s as _)
}

fn downcast(len: usize) -> Result<i32, Box<dyn Error + Sync + Send>> {
if len > i32::max_value() as usize {
Err("value too large to transmit".into())
} else {
Ok(len as i32)
}
}

pub fn escape_domain(ty: &Type) -> &Type {
match ty.kind() {
Kind::Domain(ty) => ty,
_ => ty,
}
}
7 changes: 7 additions & 0 deletions clients/cornucopia_client_core/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
mod array_iterator;
mod domain;
mod utils;

pub use array_iterator::ArrayIterator;
pub use domain::{Domain, DomainArray};
pub use utils::slice_iter;
14 changes: 14 additions & 0 deletions clients/cornucopia_client_core/src/utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
use postgres_types::{Kind, ToSql, Type};

pub fn escape_domain(ty: &Type) -> &Type {
match ty.kind() {
Kind::Domain(ty) => ty,
_ => ty,
}
}

pub fn slice_iter<'a>(
s: &'a [&'a (dyn ToSql + Sync)],
) -> impl ExactSizeIterator<Item = &'a dyn ToSql> + 'a {
s.iter().map(|s| *s as _)
}
Loading

0 comments on commit e400630

Please sign in to comment.