Skip to content

Commit

Permalink
feat: 🎸 Support sea_orm::ColumnTrait with fully-qualification
Browse files Browse the repository at this point in the history
  • Loading branch information
mpyw committed Aug 25, 2024
1 parent eb42083 commit b0d1a53
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 13 deletions.
41 changes: 32 additions & 9 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,18 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
sea-query: ["0.30", "0.31"]
sqlx: ["0.7", "0.8"]
sea:
- { sea-orm: "1.0", sea-query: "0.31" }
use-sea-orm:
- true
- false
sqlx:
- "0.7"
- "0.8"
exclude:
- sea: { sea-orm: "1.0", sea-query: "0.31" }
use-sea-orm: true
sqlx: "0.8"
steps:
- uses: actions/checkout@v4
- name: Setup Rust stable toolchain
Expand All @@ -18,17 +28,30 @@ jobs:
components: rustfmt
- name: Update dependencies
run: |
cargo add sea-query@${{ matrix.sea-query }}
cargo add --dev sqlx@${{ matrix.sqlx }}
cargo add --dev sqlx-postgres@${{ matrix.sqlx }}
cargo remove sea-orm sea-query
cargo remove --dev sea-orm sea-query sqlx sqlx-postgres
cargo add sea-query@${{ matrix.sea.sea-query }}
if [ "${{ matrix.use-sea-orm }}" == "true" ]; then
cargo add sea-orm@${{ matrix.sea.sea-orm }} --features macros
fi
cargo add --dev sqlx@${{ matrix.sqlx }} sqlx-postgres@${{ matrix.sqlx }}
cat Cargo.toml
- name: Generate feature flags
id: generate-flags
run: |
if [ "${{ matrix.use-sea-orm }}" == "true" ]; then
echo "feature_flags=--all-features" >> $GITHUB_OUTPUT
else
echo "feature_flags=" >> $GITHUB_OUTPUT
fi
- name: Restore cache
uses: Swatinem/rust-cache@v2
- name: Check code (dependencies only)
run: cargo +nightly check
run: cargo +nightly check ${{ steps.generate-flags.outputs.feature_flags }}
- name: Check code (with dev-dependencies)
run: cargo +nightly check --all-targets
run: cargo +nightly check --all-targets ${{ steps.generate-flags.outputs.feature_flags }}
- name: Check test
run: cargo +nightly test
run: cargo +nightly test ${{ steps.generate-flags.outputs.feature_flags }}

rust-lint:
timeout-minutes: 10
Expand All @@ -48,6 +71,6 @@ jobs:
- name: Check format
run: cargo +nightly fmt --all -- --check
- name: Check clippy
run: cargo clippy -- -D warnings
run: cargo clippy --all-features -- -D warnings
- name: Check sort
run: cargo sort -w -c
14 changes: 10 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,23 +1,29 @@
[package]
name = "sea-query-common-like"
version = "0.1.4"
version = "1.0.0"
authors = ["mpyw <[email protected]>"]
edition = "2021"
rust-version = "1.80.0"
description = "A Rust crate for enhancing sea_query with typical LIKE search support, including escape sequences for patterns (%fuzzy%, prefix%, %suffix) and multi-column fuzzy search."
repository = "https://github.com/yumemi-inc/sea-query-common-like"
license = "MIT"
include = ["/src", "LICENSE"]
keywords = ["sea_query", "sql", "database", "LIKE", "search"]
keywords = ["sea-orm", "sea-query", "sql", "LIKE", "search"]
categories = ["database", "web-programming"]

[dependencies]
fancy-regex = { version = "0.13", default-features = false }
regex = { version = "1", default-features = false, features = ["unicode-gencat"] }
sea-query = { version = ">=0.30, <0.32", default-features = false }
sea-orm = { version = ">=1.0, <1.1", default-features = false, optional = true }
sea-query = { version = ">=0.31, <0.32", default-features = false }

[dev-dependencies]
sea-query = ">=0.30, <0.32"
sea-orm = { version = ">=1.0, <1.1", features = ["macros"] }
sea-query = ">=0.31, <0.32"
sqlformat = "0.2.4"
sqlx = ">=0.7, <0.9"
sqlx-postgres = ">=0.7, <0.9"

[features]
default = []
with-sea-orm = ["dep:sea-orm"]
134 changes: 134 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ use regex::Regex;
use sea_query::{Cond, Condition, Expr, IntoColumnRef, IntoLikeExpr, LikeExpr};
use std::sync::LazyLock;

#[cfg(feature = "with-sea-orm")]
use sea_orm::ColumnTrait;

/// Represents a keyword used for `LIKE` search with different matching types.
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Keyword {
Expand Down Expand Up @@ -99,6 +102,10 @@ static SEPARATOR_REGEX: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"\p{Zs}++
/// ),
/// );
/// ```
///
/// # Examples (`with-sea-orm`)
///
/// See [`fuzzy_separated`] examples.
pub fn prefix<T: Into<String>>(text: T) -> Keyword {
Keyword {
ty: KeywordType::Prefix,
Expand Down Expand Up @@ -163,6 +170,10 @@ pub fn prefix<T: Into<String>>(text: T) -> Keyword {
/// ),
/// );
/// ```
///
/// # Examples (`with-sea-orm`)
///
/// See [`fuzzy_separated`] examples.
pub fn suffix<T: Into<String>>(text: T) -> Keyword {
Keyword {
ty: KeywordType::Suffix,
Expand Down Expand Up @@ -229,6 +240,10 @@ pub fn suffix<T: Into<String>>(text: T) -> Keyword {
/// ),
/// );
/// ```
///
/// # Examples (`with-sea-orm`)
///
/// See [`fuzzy_separated`] examples.
pub fn fuzzy<T: Into<String>>(text: T) -> Keyword {
Keyword {
ty: KeywordType::Fuzzy,
Expand Down Expand Up @@ -306,6 +321,83 @@ pub fn fuzzy<T: Into<String>>(text: T) -> Keyword {
/// ),
/// );
/// ```
///
/// # Examples (`with-sea-orm`)
///
/// ```
/// use sea_query::all;
/// use sea_query_common_like::fuzzy_separated;
/// use sqlformat::{format, FormatOptions, QueryParams};
///
/// #[cfg(feature = "with-sea-orm")]
/// use sea_orm::{ColumnTrait, DbBackend, EntityTrait, QueryFilter, QueryTrait};
///
/// #[cfg(feature = "with-sea-orm")]
/// mod book {
/// use sea_orm::entity::prelude::*;
///
/// #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
/// #[sea_orm(schema_name = "book", table_name = "books")]
/// pub struct Model {
/// #[sea_orm(primary_key, auto_increment = false)]
/// pub id: Uuid,
/// #[sea_orm(column_type = "Text")]
/// pub title: String,
/// #[sea_orm(column_type = "Text")]
/// pub author: String,
/// pub deleted_at: Option<DateTimeWithTimeZone>,
/// }
///
/// #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
/// pub enum Relation {
/// }
///
/// impl ActiveModelBehavior for ActiveModel {}
/// }
///
/// #[cfg(feature = "with-sea-orm")]
/// assert_eq!(
/// format(
/// book::Entity::find()
/// .filter(all![
/// fuzzy_separated("1% 99% Edison").into_condition_for_orm_columns([book::Column::Title, book::Column::Author]),
/// book::Column::DeletedAt.is_null(),
/// ])
/// .build(DbBackend::Postgres)
/// .to_string()
/// .as_str(),
/// &QueryParams::default(),
/// FormatOptions::default(),
/// ),
/// format(
/// r#"
/// SELECT
/// "books"."id",
/// "books"."title",
/// "books"."author",
/// "books"."deleted_at"
/// FROM
/// "book"."books"
/// WHERE
/// (
/// "books"."title" LIKE '%1!%%' ESCAPE '!'
/// OR "books"."author" LIKE '%1!%%' ESCAPE '!'
/// )
/// AND (
/// "books"."title" LIKE '%99!%%' ESCAPE '!'
/// OR "books"."author" LIKE '%99!%%' ESCAPE '!'
/// )
/// AND (
/// "books"."title" LIKE '%Edison%' ESCAPE '!'
/// OR "books"."author" LIKE '%Edison%' ESCAPE '!'
/// )
/// AND "books"."deleted_at" IS NULL
/// "#,
/// &QueryParams::default(),
/// FormatOptions::default(),
/// ),
/// );
/// ```
pub fn fuzzy_separated<T: Into<String>>(text: T) -> Keywords {
keywords(
SEPARATOR_REGEX
Expand Down Expand Up @@ -382,6 +474,10 @@ pub fn fuzzy_separated<T: Into<String>>(text: T) -> Keywords {
/// ),
/// );
/// ```
///
/// # Examples (`with-sea-orm`)
///
/// See [`fuzzy_separated`] examples.
pub fn keywords<T: Into<Keyword>, Iter: IntoIterator<Item = T>>(texts: Iter) -> Keywords {
Keywords(texts.into_iter().map(Into::into).collect())
}
Expand Down Expand Up @@ -436,6 +532,25 @@ impl Keyword {
.map(|col| Expr::col(col).like(self.clone()))
.fold(Cond::all(), Cond::add)
}

/// Generate a [`Condition`] for a single column with the `LIKE` pattern using a fully-qualified column name with `sea-orm`.
#[cfg(feature = "with-sea-orm")]
pub fn into_condition_for_orm_column<C>(self, column: C) -> Condition
where
C: ColumnTrait,
{
self.into_condition_for_orm_columns([column])
}

/// Generate a [`Condition`] for multiple columns with the `LIKE` pattern using fully-qualified column names with `sea-orm`.
#[cfg(feature = "with-sea-orm")]
pub fn into_condition_for_orm_columns<C, Iter>(self, columns: Iter) -> Condition
where
C: ColumnTrait,
Iter: IntoIterator<Item = C>,
{
self.into_condition_for_columns(columns.into_iter().map(|col| col.as_column_ref()))
}
}

/// Methods for converting [`Keywords`] into [`sea_query::Condition`] for a single or multiple columns.
Expand All @@ -461,4 +576,23 @@ impl Keywords {
})
.fold(Cond::all(), Cond::add)
}

/// Generate a [`Condition`] for a single column with multiple `LIKE` patterns using a fully-qualified column name with `sea-orm`.
#[cfg(feature = "with-sea-orm")]
pub fn into_condition_for_orm_column<C>(self, column: C) -> Condition
where
C: ColumnTrait,
{
self.into_condition_for_orm_columns([column])
}

/// Generate a [`Condition`] for multiple columns with multiple `LIKE` patterns using fully-qualified column names with `sea-orm`.
#[cfg(feature = "with-sea-orm")]
pub fn into_condition_for_orm_columns<C, Iter>(self, columns: Iter) -> Condition
where
C: ColumnTrait,
Iter: IntoIterator<Item = C>,
{
self.into_condition_for_columns(columns.into_iter().map(|col| col.as_column_ref()))
}
}

0 comments on commit b0d1a53

Please sign in to comment.