Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(core): Update filter updates #170

Merged
merged 2 commits into from
Jan 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 6 additions & 117 deletions geekorm-core/src/backends/libsql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
//!
//! ```no_run
//! # #[cfg(feature = "libsql")] {
//! use std::sync::{Arc, RwLock};
//! use std::sync::Arc;
//! use geekorm::prelude::*;
//!
//! #[derive(Table, Clone, Default, serde::Serialize, serde::Deserialize)]
Expand All @@ -22,7 +22,7 @@
//! #[tokio::main]
//! async fn main() -> anyhow::Result<()> {
//! let database = libsql::Builder::new_local(":memory:").build().await?;
//! let connection = Arc::new(RwLock::new(database.connect().unwrap()));
//! let connection = Arc::new(tokio::sync::Mutex::new(database.connect().unwrap()));
//!
//! Users::create_table(&connection).await?;
//!
Expand All @@ -40,16 +40,15 @@ use libsql::{de, params::IntoValue};
#[cfg(feature = "log")]
use log::{debug, error};
use serde::{de::DeserializeOwned, Serialize};
#[cfg(not(feature = "backends-tokio"))]
use std::sync::Mutex;
use std::{collections::HashMap, sync::Arc};
#[cfg(feature = "backends-tokio")]
use tokio::sync::Mutex;
use std::collections::HashMap;

use crate::{
builder::models::QueryType, GeekConnection, QueryBuilderTrait, TableBuilder, Value, Values,
};

#[cfg(feature = "backends-tokio")]
mod mutex;

impl GeekConnection for libsql::Connection {
type Connection = libsql::Connection;

Expand Down Expand Up @@ -382,116 +381,6 @@ impl GeekConnection for libsql::Connection {
}
}

const TIMEOUT: std::time::Duration = std::time::Duration::from_secs(5);

impl<C> GeekConnection for Arc<tokio::sync::Mutex<C>>
where
Self: Sync + Send + 'static,
C: GeekConnection<Connection = libsql::Connection>,
{
type Connection = Arc<Mutex<libsql::Connection>>;

async fn create_table<T>(connection: &Self::Connection) -> Result<(), crate::Error>
where
T: TableBuilder + QueryBuilderTrait + Sized + Serialize + DeserializeOwned,
{
let start = std::time::Instant::now();
while start.elapsed() < TIMEOUT {
match connection.try_lock() {
Ok(conn) => return C::create_table::<T>(&conn).await,
Err(_) => {
std::thread::sleep(std::time::Duration::from_millis(10));
}
}
}
Err(crate::Error::LibSQLError(
"Error getting write lock on connection".to_string(),
))
}

async fn row_count(
connection: &Self::Connection,
query: crate::Query,
) -> Result<i64, crate::Error> {
let start = std::time::Instant::now();
while start.elapsed() < TIMEOUT {
match connection.try_lock() {
Ok(conn) => return C::row_count(&conn, query).await,
Err(_) => {
std::thread::sleep(std::time::Duration::from_millis(10));
}
}
}
Err(crate::Error::LibSQLError(
"Error getting write lock on connection in row_count".to_string(),
))
}

async fn query<T>(
connection: &Self::Connection,
query: crate::Query,
) -> Result<Vec<T>, crate::Error>
where
T: serde::de::DeserializeOwned,
{
let start = std::time::Instant::now();
while start.elapsed() < TIMEOUT {
match connection.try_lock() {
Ok(conn) => return C::query::<T>(&conn, query).await,
Err(_) => {
std::thread::sleep(std::time::Duration::from_millis(10));
}
}
}

Err(crate::Error::LibSQLError(
"Error getting write lock on connection".to_string(),
))
}

async fn query_first<T>(
connection: &Self::Connection,
query: crate::Query,
) -> Result<T, crate::Error>
where
T: serde::de::DeserializeOwned,
{
let start = std::time::Instant::now();
while start.elapsed() < TIMEOUT {
match connection.try_lock() {
Ok(conn) => return C::query_first::<T>(&conn, query).await,
Err(_) => {
std::thread::sleep(std::time::Duration::from_millis(10));
}
}
}
Err(crate::Error::LibSQLError(
"Error getting write lock on connection".to_string(),
))
}

async fn execute<T>(
connection: &Self::Connection,
query: crate::Query,
) -> Result<(), crate::Error>
where
T: serde::de::DeserializeOwned,
{
let start = std::time::Instant::now();
while start.elapsed() < TIMEOUT {
match connection.try_lock() {
Ok(conn) => return C::execute::<T>(&conn, query).await,
Err(_) => {
std::thread::sleep(std::time::Duration::from_millis(10));
}
}
}
Err(crate::Error::LibSQLError(
"Error getting write lock on connection in execute".to_string(),
))
}
}

fn convert_values(query: &crate::Query) -> Result<Vec<libsql::Value>, crate::Error> {
let mut parameters: Vec<libsql::Value> = Vec::new();

Expand Down
119 changes: 119 additions & 0 deletions geekorm-core/src/backends/libsql/mutex.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
use serde::{de::DeserializeOwned, Serialize};
use std::sync::Arc;

#[cfg(not(feature = "backends-tokio"))]
use std::sync::Mutex;
#[cfg(feature = "backends-tokio")]
use tokio::sync::Mutex;

use crate::{GeekConnection, QueryBuilderTrait, TableBuilder};

const TIMEOUT: std::time::Duration = std::time::Duration::from_secs(5);

impl<C> GeekConnection for Arc<Mutex<C>>
where
Self: Sync + Send + 'static,
C: GeekConnection<Connection = libsql::Connection>,
{
type Connection = Arc<Mutex<libsql::Connection>>;

async fn create_table<T>(connection: &Self::Connection) -> Result<(), crate::Error>
where
T: TableBuilder + QueryBuilderTrait + Sized + Serialize + DeserializeOwned,
{
let start = std::time::Instant::now();
while start.elapsed() < TIMEOUT {
match connection.try_lock() {
Ok(conn) => return C::create_table::<T>(&conn).await,
Err(_) => {
std::thread::sleep(std::time::Duration::from_millis(10));
}
}
}
Err(crate::Error::LibSQLError(
"Error getting write lock on connection".to_string(),
))
}

async fn row_count(
connection: &Self::Connection,
query: crate::Query,
) -> Result<i64, crate::Error> {
let start = std::time::Instant::now();
while start.elapsed() < TIMEOUT {
match connection.try_lock() {
Ok(conn) => return C::row_count(&conn, query).await,
Err(_) => {
std::thread::sleep(std::time::Duration::from_millis(10));
}
}
}
Err(crate::Error::LibSQLError(
"Error getting write lock on connection in row_count".to_string(),
))
}

async fn query<T>(
connection: &Self::Connection,
query: crate::Query,
) -> Result<Vec<T>, crate::Error>
where
T: serde::de::DeserializeOwned,
{
let start = std::time::Instant::now();
while start.elapsed() < TIMEOUT {
match connection.try_lock() {
Ok(conn) => return C::query::<T>(&conn, query).await,
Err(_) => {
std::thread::sleep(std::time::Duration::from_millis(10));
}
}
}

Err(crate::Error::LibSQLError(
"Error getting write lock on connection".to_string(),
))
}

async fn query_first<T>(
connection: &Self::Connection,
query: crate::Query,
) -> Result<T, crate::Error>
where
T: serde::de::DeserializeOwned,
{
let start = std::time::Instant::now();
while start.elapsed() < TIMEOUT {
match connection.try_lock() {
Ok(conn) => return C::query_first::<T>(&conn, query).await,
Err(_) => {
std::thread::sleep(std::time::Duration::from_millis(10));
}
}
}
Err(crate::Error::LibSQLError(
"Error getting write lock on connection".to_string(),
))
}

async fn execute<T>(
connection: &Self::Connection,
query: crate::Query,
) -> Result<(), crate::Error>
where
T: serde::de::DeserializeOwned,
{
let start = std::time::Instant::now();
while start.elapsed() < TIMEOUT {
match connection.try_lock() {
Ok(conn) => return C::execute::<T>(&conn, query).await,
Err(_) => {
std::thread::sleep(std::time::Duration::from_millis(10));
}
}
}
Err(crate::Error::LibSQLError(
"Error getting write lock on connection in execute".to_string(),
))
}
}
43 changes: 26 additions & 17 deletions geekorm-core/src/backends/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,24 +186,33 @@ where
connection: &'a C,
fields: Vec<(&str, impl Into<Value>)>,
) -> Result<Vec<Self>, crate::Error> {
let mut query = Self::query_select().table(Self::table());
Self::query(
connection,
Self::query_select()
.table(Self::table())
.filter(fields)
.build()?,
)
.await
}

for (field, value) in fields {
if field.starts_with("=") {
let field = &field[1..];
query = query.where_eq(field, value.into());
} else if field.starts_with("~") {
let field = &field[1..];
query = query.where_like(field, value.into());
} else if field.starts_with("!") {
let field = &field[1..];
query = query.where_ne(field, value.into());
} else {
// Default to WHERE field = value with an OR operator
query = query.where_eq(field, value.into()).or();
}
}
Self::query(connection, query.build()?).await
/// Filter with Pagination
#[cfg(feature = "pagination")]
#[allow(async_fn_in_trait, unused_variables)]
async fn filter_page(
connection: &'a C,
fields: Vec<(&str, impl Into<Value>)>,
page: &crate::Page,
) -> Result<Vec<Self>, crate::Error> {
Self::query(
connection,
Self::query_select()
.table(Self::table())
.filter(fields)
.page(page)
.build()?,
)
.await
}

/// Fetch all rows from the database
Expand Down
20 changes: 20 additions & 0 deletions geekorm-core/src/queries/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,26 @@ impl QueryBuilder {
self
}

/// Filter the query by multiple fields
pub fn filter(mut self, fields: Vec<(&str, impl Into<Value>)>) -> Self {
for (field, value) in fields {
if field.starts_with("=") {
let field = &field[1..];
self = self.where_eq(field, value.into());
} else if field.starts_with("~") {
let field = &field[1..];
self = self.where_like(field, value.into());
} else if field.starts_with("!") {
let field = &field[1..];
self = self.where_ne(field, value.into());
} else {
// Default to WHERE field = value with an OR operator
self = self.where_eq(field, value.into()).or();
}
}
self
}

/// Order the query by a particular column
pub fn order_by(mut self, column: &str, order: QueryOrder) -> Self {
if self.table.is_valid_column(column) {
Expand Down
4 changes: 4 additions & 0 deletions geekorm-core/src/queries/pages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ impl Page {
(self.total as f64 / self.limit as f64).ceil() as u32
}
}
/// Get total number of rows
pub fn total(&self) -> u32 {
self.total
}
/// Set the total number of rows
pub fn set_total(&mut self, total: u32) {
self.total = total;
Expand Down
21 changes: 13 additions & 8 deletions geekorm-core/src/queries/pagination.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,21 @@ use crate::{GeekConnection, QueryBuilderTrait, TableBuilder};
///
/// pub type UserPage = Pagination<Users>;
///
/// # fn main() {
/// // Create a new Page instance
/// let mut page = UserPage::new();
/// #[tokio::main]
/// async fn main() -> anyhow::Result<()> {
/// let database = libsql::Builder::new_local(":memory:").build().await?;
/// let connection = database.connect().unwrap();
///
/// // Create a new Page instance
/// let mut page = UserPage::new();
///
/// // Update the page to the next page
/// let results = page.next();
/// # assert_eq!(page.limit(), 100);
/// # assert_eq!(page.page(), 0);
/// // Update the page to the next page
/// let results = page.next(&connection).await?;
/// # assert_eq!(page.limit(), 100);
/// # assert_eq!(page.page(), 0);
///
/// # }
/// # Ok(())
/// }
/// # }
/// ```
pub struct Pagination<T>
Expand Down
Loading