1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
#![deny(
clippy::cargo,
clippy::nursery,
clippy::pedantic,
clippy::restriction,
rustdoc::missing_crate_level_docs,
rustdoc::private_doc_tests,
rustdoc::invalid_html_tags,
warnings,
absolute_paths_not_starting_with_crate,
elided_lifetimes_in_paths,
explicit_outlives_requirements,
keyword_idents,
macro_use_extern_crate,
meta_variable_misuse,
missing_abi,
missing_copy_implementations,
missing_debug_implementations,
missing_docs,
non_ascii_idents,
noop_method_call,
pointer_structural_match,
rust_2021_incompatible_closure_captures,
rust_2021_incompatible_or_patterns,
rust_2021_prefixes_incompatible_syntax,
rust_2021_prelude_collisions,
single_use_lifetimes,
trivial_casts,
trivial_numeric_casts,
unsafe_code,
unsafe_op_in_unsafe_fn,
unstable_features,
unused_crate_dependencies,
unused_extern_crates,
unused_import_braces,
unused_lifetimes,
unused_macro_rules,
unused_qualifications,
variant_size_differences,
// Unstable lints:
// unreachable_pub,
// Nightly lints:
// rustdoc::missing_doc_code_examples,
// fuzzy_provenance_casts,
// lossy_provenance_casts,
// must_not_suspend,
// non_exhaustive_omitted_patterns,
)]
#![allow(
clippy::blanket_clippy_restriction_lints,
clippy::exhaustive_structs,
clippy::missing_inline_in_public_items,
clippy::implicit_return,
clippy::unwrap_used,
clippy::multiple_inherent_impl,
clippy::pattern_type_mismatch,
clippy::wildcard_enum_match_arm,
clippy::exhaustive_enums,
clippy::self_named_module_files,
clippy::pub_use,
clippy::else_if_without_else,
clippy::std_instead_of_alloc
)]
#![doc = include_str!("../README.md")]
use sqlx::{query, PgPool};
/// Implementing [`sparkle_cache::Backend`] on [`Cache`]
mod backend;
/// Implementing [`sparkle_cache::Cache`] on [`Cache`]
mod cache;
/// Models for SQL select queries and their conversion to `sparkle_cache` models
pub(crate) mod model;
/// Tests for this crate
#[cfg(test)]
mod tests;
/// The Discord cache
///
/// This is a wrapper over [`PgPool`], you can use [`Cache::pg`] to get the
/// inner [`PgPool`], see its documentation for more info
///
///
/// # Indexing
///
/// Most ID and name columns are indexed, you can inspect the database to see
/// which columns are indexed, you can also create your own indexes using the
/// inner [`PgPool`], if you think there's a missing index, please create an
/// issue
///
/// [`PgPool`]: https://docs.rs/sqlx/latest/sqlx/type.PgPool.html
#[derive(Debug)]
pub struct Cache(PgPool);
impl Cache {
/// Create a new cache using the given URL
///
/// Refer to [`sqlx::postgres::PgConnectOptions`] for the URL format
///
/// This only clears the tables about Sparkle Cache, meaning any other
/// custom tables are persistent
///
/// # Errors
///
/// Returns the error `SQLx` returns when the database connection failed or
/// the `init.sql` script failed to run
pub async fn new(url: &str) -> Result<Self, sqlx::Error> {
let cache = PgPool::connect(url).await?;
let init_sql = include_str!("../sql/init.sql");
for statement in init_sql.split(';') {
query(statement.trim()).execute(&cache).await?;
}
Ok(Self(cache))
}
/// Return a reference to the inner `PgPool` for the cache, so that you can
/// use it in custom queries
///
/// Make sure the names of tables or indexes you create don't collide with
/// the ones created by this crate
///
/// # Example
///
/// ```rust
/// use sparkle_cache_postgres::Cache;
/// use sqlx::query;
/// # #[tokio::main]
/// # async fn main() -> Result<(), anyhow::Error> {
/// # let cache = Cache::new("postgresql://localhost:5432/sparkle").await?;
/// query!("CREATE TABLE IF NOT EXISTS members_ext (id bigint, age smallint)")
/// .execute(cache.pg())
/// .await?;
/// # Ok(())
/// # }
/// ```
#[must_use]
pub const fn pg(&self) -> &PgPool {
&self.0
}
}