You've already forked seamantic
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
0a585c09e5
|
|||
|
5d9f14d8b3
|
|||
|
3bfebe424a
|
|||
|
9b868c98de
|
|||
|
9cf1f1f0c5
|
|||
|
302612281f
|
|||
|
96f260d02d
|
|||
|
2bd654249d
|
|||
|
fcd437d608
|
|||
|
792abdadfe
|
Vendored
-9
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"recommendations": [
|
|
||||||
"vadimcn.vscode-lldb",
|
|
||||||
"barbosshack.crates-io",
|
|
||||||
"usernamehw.errorlens",
|
|
||||||
"tamasfe.even-better-toml",
|
|
||||||
"rust-lang.rust-analyzer",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
Vendored
-33
@@ -1,33 +0,0 @@
|
|||||||
{
|
|
||||||
// VSCode
|
|
||||||
"editor.detectIndentation": false,
|
|
||||||
"editor.insertSpaces": false,
|
|
||||||
"editor.tabSize": 4,
|
|
||||||
"files.exclude": {
|
|
||||||
"**/target": true,
|
|
||||||
"**/Cargo.lock": true,
|
|
||||||
},
|
|
||||||
"files.insertFinalNewline": true,
|
|
||||||
"files.trimFinalNewlines": true,
|
|
||||||
"files.trimTrailingWhitespace": true,
|
|
||||||
"files.watcherExclude": {
|
|
||||||
"**/.git/**": true,
|
|
||||||
"**/target/**": true,
|
|
||||||
},
|
|
||||||
// Extensions
|
|
||||||
"crates.listPreReleases": true,
|
|
||||||
"evenBetterToml.formatter.alignComments": true,
|
|
||||||
"evenBetterToml.formatter.alignEntries": false,
|
|
||||||
"evenBetterToml.formatter.allowedBlankLines": 1,
|
|
||||||
"evenBetterToml.formatter.arrayAutoExpand": true,
|
|
||||||
"evenBetterToml.formatter.arrayTrailingComma": true,
|
|
||||||
"evenBetterToml.formatter.columnWidth": 80,
|
|
||||||
"evenBetterToml.formatter.reorderKeys": true,
|
|
||||||
"evenBetterToml.formatter.trailingNewline": true,
|
|
||||||
"rust-analyzer.imports.granularity.enforce": true,
|
|
||||||
"rust-analyzer.imports.granularity.group": "module",
|
|
||||||
"rust-analyzer.imports.group.enable": true,
|
|
||||||
"rust-analyzer.imports.merge.glob": false,
|
|
||||||
"rust-analyzer.imports.preferNoStd": true,
|
|
||||||
"rust-analyzer.showUnlinkedFileNotification": false,
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"project_name": null,
|
||||||
|
|
||||||
|
"auto_install_extensions": {
|
||||||
|
"tombi": true,
|
||||||
|
"cargo-appraiser": true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"languages": {
|
||||||
|
"TOML": {
|
||||||
|
"format_on_save": "on",
|
||||||
|
"formatter": { "language_server": { "name": "tombi" } },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"lsp": {
|
||||||
|
"rust-analyzer": {
|
||||||
|
"initialization_options": {
|
||||||
|
"imports": {
|
||||||
|
"granularity": { "enforce": true, "group": "module" },
|
||||||
|
"group": { "enable": true },
|
||||||
|
"merge": { "glob": false },
|
||||||
|
"preferNoStd": true,
|
||||||
|
},
|
||||||
|
"server": {
|
||||||
|
"extraEnv": {
|
||||||
|
"RUSTUP_TOOLCHAIN": "stable",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
Generated
+1330
-373
File diff suppressed because it is too large
Load Diff
+24
-49
@@ -1,23 +1,21 @@
|
|||||||
[package]
|
[workspace]
|
||||||
name = "seamantic"
|
|
||||||
version = "0.0.3"
|
|
||||||
|
|
||||||
categories = []
|
|
||||||
description = "A library to enhance SeaORM"
|
|
||||||
repository = "https://github.com/QuantumShade/seamantic"
|
|
||||||
|
|
||||||
authors = []
|
|
||||||
edition = "2024"
|
|
||||||
license-file = "LICENSE.md"
|
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
members = ["seamantic"]
|
||||||
|
|
||||||
|
[workspace.package]
|
||||||
|
edition = "2024"
|
||||||
rust-version = "1.85.0"
|
rust-version = "1.85.0"
|
||||||
|
license-file = "LICENSE.md"
|
||||||
|
|
||||||
[lints.rust]
|
[workspace.dependencies]
|
||||||
arithmetic_overflow = "forbid"
|
sea-orm = { version = "2.0.0-rc.27", default-features = false }
|
||||||
missing_docs = "forbid"
|
sea-orm-migration = { version = "2.0.0-rc.27", default-features = false }
|
||||||
unsafe_code = "forbid"
|
seamantic = { path = "seamantic", version = "=0.0.12", default-features = false }
|
||||||
|
serde = { version = "^1", default-features = false }
|
||||||
|
serde_test = { version = "^1", default-features = false }
|
||||||
|
tokio = { version = "^1", default-features = false }
|
||||||
|
|
||||||
[lints.clippy]
|
[workspace.lints.clippy]
|
||||||
arithmetic_side_effects = "forbid"
|
arithmetic_side_effects = "forbid"
|
||||||
as_conversions = "forbid"
|
as_conversions = "forbid"
|
||||||
checked_conversions = "forbid"
|
checked_conversions = "forbid"
|
||||||
@@ -27,41 +25,18 @@ indexing_slicing = "forbid"
|
|||||||
integer_division = "forbid"
|
integer_division = "forbid"
|
||||||
integer_division_remainder_used = "forbid"
|
integer_division_remainder_used = "forbid"
|
||||||
transmute_undefined_repr = "forbid"
|
transmute_undefined_repr = "forbid"
|
||||||
unchecked_duration_subtraction = "forbid"
|
unchecked_time_subtraction = "forbid"
|
||||||
unwrap_used = "forbid"
|
unwrap_used = "forbid"
|
||||||
|
|
||||||
|
[workspace.lints.rust]
|
||||||
|
arithmetic_overflow = "forbid"
|
||||||
|
missing_docs = "forbid"
|
||||||
|
unsafe_code = "forbid"
|
||||||
|
unused_doc_comments = "forbid"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
codegen-units = 1
|
|
||||||
lto = "fat"
|
|
||||||
opt-level = 3
|
opt-level = 3
|
||||||
overflow-checks = true
|
|
||||||
strip = "debuginfo"
|
strip = "debuginfo"
|
||||||
|
overflow-checks = true
|
||||||
[[example]]
|
lto = "fat"
|
||||||
name = "migrations"
|
codegen-units = 1
|
||||||
path = "examples/migrations/main.rs"
|
|
||||||
required-features = ["sqlite"]
|
|
||||||
|
|
||||||
[features]
|
|
||||||
default = []
|
|
||||||
serde = ["dep:serde"]
|
|
||||||
sqlite = ["sea-orm-migration/sqlx-sqlite"]
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
sea-orm = { version = "^1", default-features = false }
|
|
||||||
sea-orm-migration = { version = "^1", default-features = false }
|
|
||||||
|
|
||||||
serde = { version = "^1", default-features = false, features = [
|
|
||||||
"derive",
|
|
||||||
"std",
|
|
||||||
], optional = true }
|
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
sea-orm-migration = { version = "^1", default-features = false, features = [
|
|
||||||
"runtime-tokio-rustls",
|
|
||||||
] }
|
|
||||||
serde_test = { version = "^1", default-features = false }
|
|
||||||
tokio = { version = "^1", default-features = false, features = [
|
|
||||||
"rt",
|
|
||||||
"macros",
|
|
||||||
] }
|
|
||||||
|
|||||||
@@ -9,7 +9,9 @@ A library to enhance SeaORM
|
|||||||
- build: `cargo hack --feature-powerset build`
|
- build: `cargo hack --feature-powerset build`
|
||||||
- clippy: `cargo hack --feature-powerset clippy -- -D warnings`
|
- clippy: `cargo hack --feature-powerset clippy -- -D warnings`
|
||||||
- test: `cargo hack --feature-powerset test`
|
- test: `cargo hack --feature-powerset test`
|
||||||
|
- test old: `cargo +1.85 hack --feature-powerset test`
|
||||||
- example: `cargo run --example=migrations --features=sqlite`
|
- example: `cargo run --example=migrations --features=sqlite`
|
||||||
- fmt: `cargo fmt --check`
|
- fmt: `cargo fmt --check`
|
||||||
- docs: `RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --all-features`
|
- docs: `RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --all-features`
|
||||||
- publish: `cargo publish --dry-run`
|
- semver: `cargo semver-checks --all-features`
|
||||||
|
- publish: `cargo publish --dry-run -p seamantic`
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
[package]
|
||||||
|
name = "seamantic"
|
||||||
|
version = "0.0.12"
|
||||||
|
edition.workspace = true
|
||||||
|
rust-version.workspace = true
|
||||||
|
description = "A library to enhance SeaORM"
|
||||||
|
repository = "https://github.com/QuantumShade/seamantic"
|
||||||
|
license-file.workspace = true
|
||||||
|
categories = []
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
all-features = true
|
||||||
|
rustdoc-args = ["--cfg", "docsrs"]
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "migrations"
|
||||||
|
path = "examples/migrations/main.rs"
|
||||||
|
required-features = ["sqlite"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
sea-orm = { workspace = true }
|
||||||
|
sea-orm-migration = { workspace = true }
|
||||||
|
serde = { workspace = true, features = ["derive", "std"], optional = true }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
sea-orm = { workspace = true, features = ["entity-registry", "schema-sync"] }
|
||||||
|
sea-orm-migration = { workspace = true, features = ["runtime-tokio-rustls"] }
|
||||||
|
serde_test = { workspace = true }
|
||||||
|
tokio = { workspace = true, features = ["macros", "rt"] }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = []
|
||||||
|
serde = ["dep:serde"]
|
||||||
|
sqlite = ["sea-orm-migration/sqlx-sqlite"]
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# Seamantic
|
||||||
|
|
||||||
|
[](https://crates.io/crates/seamantic)
|
||||||
|
|
||||||
|
A library to enhance SeaORM
|
||||||
@@ -1,9 +1,12 @@
|
|||||||
//! A library for enhacing SeaORM
|
//! A library for enhacing SeaORM
|
||||||
|
|
||||||
|
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||||
|
|
||||||
pub use sea_orm;
|
pub use sea_orm;
|
||||||
pub use sea_orm_migration;
|
pub use sea_orm_migration;
|
||||||
|
|
||||||
pub mod model;
|
pub mod model;
|
||||||
|
pub mod orm;
|
||||||
pub mod schema;
|
pub mod schema;
|
||||||
|
|
||||||
/// A macro for defining a Migrator with a custom migration table while
|
/// A macro for defining a Migrator with a custom migration table while
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
use core::time::Duration;
|
use core::time::Duration;
|
||||||
|
|
||||||
use sea_orm::sea_query::{ArrayType, Nullable, ValueType, ValueTypeErr};
|
use sea_orm::sea_query::{ArrayType, Nullable, ValueType, ValueTypeErr};
|
||||||
use sea_orm::{ColIdx, ColumnType, QueryResult, TryGetError, TryGetable, Value};
|
use sea_orm::{ColIdx, ColumnType, DbErr, QueryResult, TryFromU64, TryGetError, TryGetable, Value};
|
||||||
|
|
||||||
// "u64 unsupported by sqlx-sqlite", so use i64 as the bit representation
|
// "u64 unsupported by sqlx-sqlite", so use i64 as the bit representation
|
||||||
type SeaOrmRepr = i64;
|
type SeaOrmRepr = i64;
|
||||||
@@ -13,7 +13,7 @@ type DurationRepr = u64;
|
|||||||
///
|
///
|
||||||
/// ### Warning:
|
/// ### Warning:
|
||||||
/// Sub-second precision will be lost
|
/// Sub-second precision will be lost
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
#[cfg_attr(feature = "serde", serde(transparent))]
|
#[cfg_attr(feature = "serde", serde(transparent))]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
@@ -40,7 +40,7 @@ impl ValueType for Seconds {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn type_name() -> String {
|
fn type_name() -> String {
|
||||||
core::any::type_name::<Duration>().to_string()
|
core::any::type_name::<Self>().to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn array_type() -> ArrayType {
|
fn array_type() -> ArrayType {
|
||||||
@@ -67,6 +67,15 @@ impl TryGetable for Seconds {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TryFromU64 for Seconds {
|
||||||
|
fn try_from_u64(n: u64) -> Result<Self, DbErr> {
|
||||||
|
SeaOrmRepr::try_from_u64(n)
|
||||||
|
.map(|i| DurationRepr::from_ne_bytes(i.to_ne_bytes()))
|
||||||
|
.map(Duration::from_secs)
|
||||||
|
.map(Self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Nullable for Seconds {
|
impl Nullable for Seconds {
|
||||||
fn null() -> Value {
|
fn null() -> Value {
|
||||||
SeaOrmRepr::null()
|
SeaOrmRepr::null()
|
||||||
@@ -76,23 +85,26 @@ impl Nullable for Seconds {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use sea_orm::{
|
use sea_orm::{
|
||||||
ActiveModelBehavior, DeriveEntityModel, DerivePrimaryKey, DeriveRelation, EnumIter,
|
ActiveModelBehavior, DeriveEntityModel, DerivePrimaryKey, DeriveRelation, EntityTrait,
|
||||||
PrimaryKeyTrait,
|
EnumIter, PrimaryKeyTrait,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::Seconds;
|
use super::Seconds;
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, DeriveEntityModel)]
|
#[derive(Debug, Clone, PartialEq, Eq, DeriveEntityModel)]
|
||||||
#[sea_orm(table_name = "seconds")]
|
#[sea_orm(table_name = "seconds")]
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
#[sea_orm(primary_key, auto_increment = false)]
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
id: u8,
|
id: u8,
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
seconds: Seconds,
|
seconds: Seconds,
|
||||||
nullable: Option<Seconds>,
|
nullable: Option<Seconds>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ActiveModelBehavior for ActiveModel {}
|
impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
#[derive(Debug, EnumIter, DeriveRelation)]
|
#[derive(Debug, EnumIter, DeriveRelation)]
|
||||||
pub enum Relation {}
|
pub enum Relation {}
|
||||||
}
|
}
|
||||||
@@ -12,6 +12,8 @@ use sea_orm::{ColIdx, ColumnType, DbErr, QueryResult, TryFromU64, TryGetError, T
|
|||||||
pub type SeaOrmRepr = i64;
|
pub type SeaOrmRepr = i64;
|
||||||
|
|
||||||
/// An opaque type representing a row ID
|
/// An opaque type representing a row ID
|
||||||
|
///
|
||||||
|
/// IDs should be tagged with `#[sea_orm(primary_key, auto_increment = false)]`
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
#[cfg_attr(feature = "serde", serde(transparent))]
|
#[cfg_attr(feature = "serde", serde(transparent))]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
@@ -78,7 +80,7 @@ impl<T> Id<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T> fmt::Debug for Id<T> {
|
impl<T> fmt::Debug for Id<T> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
f.debug_struct("Id")
|
f.debug_struct("Id")
|
||||||
.field("T", &core::any::type_name::<T>())
|
.field("T", &core::any::type_name::<T>())
|
||||||
.field("id", &self.id)
|
.field("id", &self.id)
|
||||||
@@ -140,12 +142,13 @@ impl<T> Nullable for Id<T> {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use sea_orm::{
|
use sea_orm::{
|
||||||
ActiveModelBehavior, DeriveEntityModel, DerivePrimaryKey, DeriveRelation, EnumIter,
|
ActiveModelBehavior, DeriveEntityModel, DerivePrimaryKey, DeriveRelation, EntityTrait,
|
||||||
PrimaryKeyTrait,
|
EnumIter, PrimaryKeyTrait,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::Id;
|
use super::Id;
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, DeriveEntityModel)]
|
#[derive(Debug, Clone, PartialEq, Eq, DeriveEntityModel)]
|
||||||
#[sea_orm(table_name = "ids")]
|
#[sea_orm(table_name = "ids")]
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
@@ -156,6 +159,7 @@ mod tests {
|
|||||||
|
|
||||||
impl ActiveModelBehavior for ActiveModel {}
|
impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
#[derive(Debug, EnumIter, DeriveRelation)]
|
#[derive(Debug, EnumIter, DeriveRelation)]
|
||||||
pub enum Relation {}
|
pub enum Relation {}
|
||||||
|
|
||||||
@@ -0,0 +1,179 @@
|
|||||||
|
//! [IpAddr], [Ipv4Addr], and [Ipv6Addr] utilities
|
||||||
|
|
||||||
|
use core::net::{IpAddr, Ipv4Addr, Ipv6Addr};
|
||||||
|
|
||||||
|
use sea_orm::sea_query::{ArrayType, Nullable, ValueType, ValueTypeErr};
|
||||||
|
use sea_orm::{ColIdx, ColumnType, DbErr, QueryResult, TryFromU64, TryGetError, TryGetable, Value};
|
||||||
|
|
||||||
|
type SeaOrmRepr = String;
|
||||||
|
|
||||||
|
/// Wrapper around [IpAddr]
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "serde", serde(transparent))]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct IpAddress(pub IpAddr);
|
||||||
|
|
||||||
|
/// Wrapper around [IpAddr]
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "serde", serde(transparent))]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct Ipv4Address(pub Ipv4Addr);
|
||||||
|
|
||||||
|
/// Wrapper around [IpAddr]
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "serde", serde(transparent))]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct Ipv6Address(pub Ipv6Addr);
|
||||||
|
|
||||||
|
macro_rules! impl_addr {
|
||||||
|
($t:ty, $inner:ty, $repr:ty) => {
|
||||||
|
impl From<$inner> for $t {
|
||||||
|
fn from(value: $inner) -> Self {
|
||||||
|
Self(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<$t> for $inner {
|
||||||
|
fn from(value: $t) -> Self {
|
||||||
|
value.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ValueType for $t {
|
||||||
|
fn try_from(v: Value) -> Result<Self, ValueTypeErr> {
|
||||||
|
<SeaOrmRepr as ValueType>::try_from(v)
|
||||||
|
.and_then(|s| s.parse().map_err(|_| ValueTypeErr))
|
||||||
|
.map(Self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn type_name() -> String {
|
||||||
|
core::any::type_name::<Self>().to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn array_type() -> ArrayType {
|
||||||
|
SeaOrmRepr::array_type()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn column_type() -> ColumnType {
|
||||||
|
SeaOrmRepr::column_type()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<$t> for Value {
|
||||||
|
fn from(value: $t) -> Self {
|
||||||
|
value.0.to_string().into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryGetable for $t {
|
||||||
|
fn try_get_by<I: ColIdx>(res: &QueryResult, index: I) -> Result<Self, TryGetError> {
|
||||||
|
SeaOrmRepr::try_get_by(res, index)
|
||||||
|
.and_then(|s| s.parse().map_err(|_| TryGetError::Null(Self::type_name())))
|
||||||
|
.map(Self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFromU64 for $t {
|
||||||
|
fn try_from_u64(n: u64) -> Result<Self, DbErr> {
|
||||||
|
SeaOrmRepr::try_from_u64(n)
|
||||||
|
.and_then(|s| {
|
||||||
|
s.parse()
|
||||||
|
.map_err(|_| DbErr::ConvertFromU64(core::any::type_name::<Self>()))
|
||||||
|
})
|
||||||
|
.map(Self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Nullable for $t {
|
||||||
|
fn null() -> Value {
|
||||||
|
SeaOrmRepr::null()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_addr!(IpAddress, IpAddr, SeaOrmRepr);
|
||||||
|
impl_addr!(Ipv4Address, Ipv4Addr, SeaOrmRepr);
|
||||||
|
impl_addr!(Ipv6Address, Ipv6Addr, SeaOrmRepr);
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
mod ipaddress {
|
||||||
|
use sea_orm::{
|
||||||
|
ActiveModelBehavior, DeriveEntityModel, DerivePrimaryKey, DeriveRelation, EntityTrait,
|
||||||
|
EnumIter, PrimaryKeyTrait,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::super::IpAddress;
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, DeriveEntityModel)]
|
||||||
|
#[sea_orm(table_name = "ipaddress")]
|
||||||
|
pub struct Model {
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
id: u8,
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
addr: IpAddress,
|
||||||
|
nullable: Option<IpAddress>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Debug, EnumIter, DeriveRelation)]
|
||||||
|
pub enum Relation {}
|
||||||
|
}
|
||||||
|
mod ipv4address {
|
||||||
|
use sea_orm::{
|
||||||
|
ActiveModelBehavior, DeriveEntityModel, DerivePrimaryKey, DeriveRelation, EntityTrait,
|
||||||
|
EnumIter, PrimaryKeyTrait,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::super::Ipv4Address;
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, DeriveEntityModel)]
|
||||||
|
#[sea_orm(table_name = "ipv4address")]
|
||||||
|
pub struct Model {
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
id: u8,
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
addr: Ipv4Address,
|
||||||
|
nullable: Option<Ipv4Address>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Debug, EnumIter, DeriveRelation)]
|
||||||
|
pub enum Relation {}
|
||||||
|
}
|
||||||
|
mod ipv6address {
|
||||||
|
use sea_orm::{
|
||||||
|
ActiveModelBehavior, DeriveEntityModel, DerivePrimaryKey, DeriveRelation, EntityTrait,
|
||||||
|
EnumIter, PrimaryKeyTrait,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::super::Ipv6Address;
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, DeriveEntityModel)]
|
||||||
|
#[sea_orm(table_name = "ipv6address")]
|
||||||
|
pub struct Model {
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
id: u8,
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
addr: Ipv6Address,
|
||||||
|
nullable: Option<Ipv6Address>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Debug, EnumIter, DeriveRelation)]
|
||||||
|
pub enum Relation {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,4 +2,5 @@
|
|||||||
|
|
||||||
pub mod duration;
|
pub mod duration;
|
||||||
pub mod id;
|
pub mod id;
|
||||||
|
pub mod ip;
|
||||||
pub mod path;
|
pub mod path;
|
||||||
@@ -9,7 +9,7 @@ use std::os::unix::ffi::OsStringExt as _;
|
|||||||
compile_error!("PathBytes is not supported on Windows");
|
compile_error!("PathBytes is not supported on Windows");
|
||||||
|
|
||||||
use sea_orm::sea_query::{ArrayType, Nullable, ValueType, ValueTypeErr};
|
use sea_orm::sea_query::{ArrayType, Nullable, ValueType, ValueTypeErr};
|
||||||
use sea_orm::{ColIdx, ColumnType, QueryResult, TryGetError, TryGetable, Value};
|
use sea_orm::{ColIdx, ColumnType, DbErr, QueryResult, TryFromU64, TryGetError, TryGetable, Value};
|
||||||
|
|
||||||
type SeaOrmRepr = Vec<u8>;
|
type SeaOrmRepr = Vec<u8>;
|
||||||
|
|
||||||
@@ -47,7 +47,7 @@ impl ValueType for PathBytes {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn type_name() -> String {
|
fn type_name() -> String {
|
||||||
core::any::type_name::<PathBuf>().to_string()
|
core::any::type_name::<Self>().to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn array_type() -> ArrayType {
|
fn array_type() -> ArrayType {
|
||||||
@@ -74,6 +74,15 @@ impl TryGetable for PathBytes {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TryFromU64 for PathBytes {
|
||||||
|
fn try_from_u64(n: u64) -> Result<Self, DbErr> {
|
||||||
|
SeaOrmRepr::try_from_u64(n)
|
||||||
|
.map(OsString::from_vec)
|
||||||
|
.map(PathBuf::from)
|
||||||
|
.map(Self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Nullable for PathBytes {
|
impl Nullable for PathBytes {
|
||||||
fn null() -> Value {
|
fn null() -> Value {
|
||||||
SeaOrmRepr::null()
|
SeaOrmRepr::null()
|
||||||
@@ -83,23 +92,26 @@ impl Nullable for PathBytes {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use sea_orm::{
|
use sea_orm::{
|
||||||
ActiveModelBehavior, DeriveEntityModel, DerivePrimaryKey, DeriveRelation, EnumIter,
|
ActiveModelBehavior, DeriveEntityModel, DerivePrimaryKey, DeriveRelation, EntityTrait,
|
||||||
PrimaryKeyTrait,
|
EnumIter, PrimaryKeyTrait,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::PathBytes;
|
use super::PathBytes;
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, DeriveEntityModel)]
|
#[derive(Debug, Clone, PartialEq, Eq, DeriveEntityModel)]
|
||||||
#[sea_orm(table_name = "paths")]
|
#[sea_orm(table_name = "paths")]
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
#[sea_orm(primary_key, auto_increment = false)]
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
id: u8,
|
id: u8,
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
path: PathBytes,
|
path: PathBytes,
|
||||||
nullable: Option<PathBytes>,
|
nullable: Option<PathBytes>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ActiveModelBehavior for ActiveModel {}
|
impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
#[derive(Debug, EnumIter, DeriveRelation)]
|
#[derive(Debug, EnumIter, DeriveRelation)]
|
||||||
pub enum Relation {}
|
pub enum Relation {}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
//! Helpers for working with SeaORM
|
||||||
|
|
||||||
|
mod upsert;
|
||||||
|
pub use upsert::UpsertTrait;
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
use sea_orm::sea_query::{IntoColumnRef, OnConflict};
|
||||||
|
use sea_orm::{ActiveModelTrait, EntityTrait, Insert, Iterable};
|
||||||
|
|
||||||
|
/// This trait add a method on [Insert] to allow for upsert behavior
|
||||||
|
pub trait UpsertTrait: private::Sealed {
|
||||||
|
/// Set ON CONFLICT on primary key to update all other columns
|
||||||
|
fn on_conflict_upsert(self) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn primary_key_iter<A: ActiveModelTrait>()
|
||||||
|
-> impl Iterator<Item = <A::Entity as EntityTrait>::PrimaryKey> {
|
||||||
|
<A::Entity as EntityTrait>::PrimaryKey::iter()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn column_iter<A: ActiveModelTrait>() -> impl Iterator<Item = <A::Entity as EntityTrait>::Column> {
|
||||||
|
<<A as ActiveModelTrait>::Entity as EntityTrait>::Column::iter()
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: ActiveModelTrait> UpsertTrait for Insert<A> {
|
||||||
|
fn on_conflict_upsert(self) -> Self {
|
||||||
|
self.on_conflict(
|
||||||
|
OnConflict::columns(primary_key_iter::<A>())
|
||||||
|
.update_columns(column_iter::<A>().filter(|col| {
|
||||||
|
!primary_key_iter::<A>().any(|pk| pk.into_column_ref() == col.into_column_ref())
|
||||||
|
}))
|
||||||
|
.to_owned(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod private {
|
||||||
|
pub trait Sealed {}
|
||||||
|
impl<A: ::sea_orm::ActiveModelTrait> Sealed for ::sea_orm::Insert<A> {}
|
||||||
|
}
|
||||||
@@ -3,4 +3,5 @@
|
|||||||
#[cfg(feature = "sqlite")]
|
#[cfg(feature = "sqlite")]
|
||||||
mod sqlite;
|
mod sqlite;
|
||||||
#[cfg(feature = "sqlite")]
|
#[cfg(feature = "sqlite")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "sqlite")))]
|
||||||
pub use sqlite::*;
|
pub use sqlite::*;
|
||||||
@@ -11,34 +11,221 @@ use sea_orm_migration::sea_query::{ColumnDef, IntoIden};
|
|||||||
/// and should be tagged with:
|
/// and should be tagged with:
|
||||||
///
|
///
|
||||||
/// `#[sea_orm(primary_key, auto_increment = false)]`
|
/// `#[sea_orm(primary_key, auto_increment = false)]`
|
||||||
|
///
|
||||||
|
/// When using the new entity format:
|
||||||
|
///
|
||||||
|
/// use sea_orm::entity::prelude::*;
|
||||||
|
/// use seamantic::model::id::Id;
|
||||||
|
///
|
||||||
|
/// #[sea_orm::model]
|
||||||
|
/// #[derive(Debug, Clone, DeriveEntityModel)]
|
||||||
|
/// #[sea_orm(table_name = "rowid_test")]
|
||||||
|
/// pub struct Model {
|
||||||
|
/// #[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
/// id: Id<Model>,
|
||||||
|
/// }
|
||||||
|
/// impl ActiveModelBehavior for ActiveModel {}
|
||||||
pub fn sqlite_rowid_alias<T: IntoIden>(name: T) -> ColumnDef {
|
pub fn sqlite_rowid_alias<T: IntoIden>(name: T) -> ColumnDef {
|
||||||
integer_null(name).primary_key().take()
|
integer_null(name).primary_key().take()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the column to be a case insensitive string
|
/// Set the column to be a case insensitive string
|
||||||
|
///
|
||||||
|
/// When using the new entity format:
|
||||||
|
///
|
||||||
|
/// use sea_orm::entity::prelude::*;
|
||||||
|
/// use seamantic::model::id::Id;
|
||||||
|
///
|
||||||
|
/// #[sea_orm::model]
|
||||||
|
/// #[derive(Debug, Clone, DeriveEntityModel)]
|
||||||
|
/// #[sea_orm(table_name = "nocase_test")]
|
||||||
|
/// pub struct Model {
|
||||||
|
/// #[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
/// id: i64,
|
||||||
|
/// #[sea_orm(extra = "COLLATE NOCASE")]
|
||||||
|
/// nocase: String,
|
||||||
|
/// }
|
||||||
|
/// impl ActiveModelBehavior for ActiveModel {}
|
||||||
pub fn sqlite_case_insensitive_string<T: IntoIden>(name: T) -> ColumnDef {
|
pub fn sqlite_case_insensitive_string<T: IntoIden>(name: T) -> ColumnDef {
|
||||||
string(name).extra("COLLATE NOCASE").take()
|
string(name).extra("COLLATE NOCASE").take()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod entity_tests {
|
||||||
use sea_orm_migration::async_trait::async_trait;
|
use sea_orm::{ConnectOptions, Database, DatabaseConnection};
|
||||||
use sea_orm_migration::sea_orm::QueryFilter;
|
|
||||||
use sea_orm_migration::sea_orm::{
|
pub async fn new_initialized_memory_db() -> DatabaseConnection {
|
||||||
ActiveModelBehavior, ActiveModelTrait, ActiveValue::NotSet, ActiveValue::Set, ColumnTrait,
|
let options = ConnectOptions::new("sqlite::memory:");
|
||||||
ConnectOptions, Database, DatabaseConnection, DbErr, DeriveEntityModel,
|
|
||||||
DeriveMigrationName, DerivePrimaryKey, EntityTrait, EnumIter, PrimaryKeyTrait, RelationDef,
|
let db = Database::connect(options)
|
||||||
RelationTrait,
|
.await
|
||||||
|
.expect("Database::connect()");
|
||||||
|
db.get_schema_registry("seamantic::schema::sqlite::*")
|
||||||
|
.sync(&db)
|
||||||
|
.await
|
||||||
|
.expect("db.get_schema_registry().sync()");
|
||||||
|
db
|
||||||
|
}
|
||||||
|
|
||||||
|
mod rowid_test {
|
||||||
|
use sea_orm::ActiveValue::{NotSet, Set};
|
||||||
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
|
use crate::model::id::{Id, SeaOrmRepr};
|
||||||
|
|
||||||
|
#[sea_orm::model]
|
||||||
|
#[derive(Debug, Clone, DeriveEntityModel)]
|
||||||
|
#[sea_orm(table_name = "rowid_test")]
|
||||||
|
pub struct Model {
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
id: Id<Model>,
|
||||||
|
}
|
||||||
|
impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_sqlite_rowid_alias() {
|
||||||
|
let db = super::new_initialized_memory_db().await;
|
||||||
|
|
||||||
|
// Starts at 1 and increments
|
||||||
|
for i in 1..=3 {
|
||||||
|
let model = ActiveModel { id: NotSet };
|
||||||
|
let model = model.insert(&db).await.expect("insert");
|
||||||
|
assert_eq!(model.id.into_raw(), i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the top number and re-add
|
||||||
|
for i in 3..=3 {
|
||||||
|
let model = ActiveModel {
|
||||||
|
id: Set(Id::from_raw(i)),
|
||||||
};
|
};
|
||||||
use sea_orm_migration::sea_query::{self, Iden, Table};
|
model.delete(&db).await.expect("delete");
|
||||||
use sea_orm_migration::{MigrationTrait, MigratorTrait, SchemaManager};
|
let model = ActiveModel { id: NotSet };
|
||||||
|
let model = model.insert(&db).await.expect("insert");
|
||||||
|
assert_eq!(model.id.into_raw(), i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Jump to 100 and increment
|
||||||
|
for i in 100..=103 {
|
||||||
|
let model = ActiveModel {
|
||||||
|
id: Set(Id::from_raw(i)),
|
||||||
|
};
|
||||||
|
let model = model.insert(&db).await.expect("insert");
|
||||||
|
assert_eq!(model.id.into_raw(), i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Continue to increment
|
||||||
|
for i in 104..=104 {
|
||||||
|
let model = ActiveModel { id: NotSet };
|
||||||
|
let model = model.insert(&db).await.expect("insert");
|
||||||
|
assert_eq!(model.id.into_raw(), i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Jump to SeaOrmRepr::MAX and increment
|
||||||
|
for i in SeaOrmRepr::MAX..=SeaOrmRepr::MAX {
|
||||||
|
let model = ActiveModel {
|
||||||
|
id: Set(Id::from_raw(i)),
|
||||||
|
};
|
||||||
|
let model = model.insert(&db).await.expect("insert");
|
||||||
|
assert_eq!(model.id.into_raw(), i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next ones are random around the center
|
||||||
|
for _ in 0..3 {
|
||||||
|
let model = ActiveModel { id: NotSet };
|
||||||
|
let model = model.insert(&db).await.expect("insert");
|
||||||
|
assert!(model.id.into_raw() > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zero ID is valid
|
||||||
|
for i in 0..=0 {
|
||||||
|
let model = ActiveModel {
|
||||||
|
id: Set(Id::from_raw(i)),
|
||||||
|
};
|
||||||
|
let model = model.insert(&db).await.expect("insert");
|
||||||
|
assert_eq!(model.id.into_raw(), i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Negative ID is valid
|
||||||
|
for i in SeaOrmRepr::MIN..=(SeaOrmRepr::MIN + 3) {
|
||||||
|
let model = ActiveModel {
|
||||||
|
id: Set(Id::from_raw(i)),
|
||||||
|
};
|
||||||
|
let model = model.insert(&db).await.expect("insert");
|
||||||
|
assert_eq!(model.id.into_raw(), i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod nocase_test {
|
||||||
|
use sea_orm::ActiveValue::Set;
|
||||||
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
|
#[sea_orm::model]
|
||||||
|
#[derive(Debug, Clone, DeriveEntityModel)]
|
||||||
|
#[sea_orm(table_name = "nocase_test")]
|
||||||
|
pub struct Model {
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
id: i64,
|
||||||
|
case: String,
|
||||||
|
#[sea_orm(extra = "COLLATE NOCASE")]
|
||||||
|
nocase: String,
|
||||||
|
}
|
||||||
|
impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_sqlite_case_insensitive_string() {
|
||||||
|
let db = super::new_initialized_memory_db().await;
|
||||||
|
|
||||||
|
let i = 50;
|
||||||
|
|
||||||
|
// Insert a lowercase string
|
||||||
|
{
|
||||||
|
let model = ActiveModel {
|
||||||
|
id: Set(i),
|
||||||
|
case: Set("abcd".to_owned()),
|
||||||
|
nocase: Set("abcd".to_owned()),
|
||||||
|
};
|
||||||
|
model.insert(&db).await.expect("insert");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query by uppercase string
|
||||||
|
{
|
||||||
|
Entity::find()
|
||||||
|
.filter(Column::Case.eq("ABCD"))
|
||||||
|
.one(&db)
|
||||||
|
.await
|
||||||
|
.expect("find by case insensitive string")
|
||||||
|
.ok_or(())
|
||||||
|
.expect_err("find by case insensitive string");
|
||||||
|
|
||||||
|
let model = Entity::find()
|
||||||
|
.filter(Column::Nocase.eq("ABCD"))
|
||||||
|
.one(&db)
|
||||||
|
.await
|
||||||
|
.expect("find by case insensitive string")
|
||||||
|
.expect("find by case insensitive string");
|
||||||
|
assert_eq!(model.id, i);
|
||||||
|
// The string should be read back as-is
|
||||||
|
assert_eq!(model.nocase, "abcd");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use sea_orm::ActiveValue::{NotSet, Set};
|
||||||
|
use sea_orm::entity::prelude::*;
|
||||||
|
use sea_orm::{ConnectOptions, Database, DatabaseConnection};
|
||||||
|
use sea_orm_migration::async_trait::async_trait;
|
||||||
|
use sea_orm_migration::prelude::*;
|
||||||
|
|
||||||
use crate::model::id::{Id, SeaOrmRepr};
|
use crate::model::id::{Id, SeaOrmRepr};
|
||||||
|
|
||||||
use super::{sqlite_case_insensitive_string, sqlite_rowid_alias};
|
use super::{sqlite_case_insensitive_string, sqlite_rowid_alias};
|
||||||
|
|
||||||
async fn new_memory_db() -> DatabaseConnection {
|
async fn new_memory_db() -> DatabaseConnection {
|
||||||
let options = ConnectOptions::new("sqlite:/tmp/db?mode=memory");
|
let options = ConnectOptions::new("sqlite::memory:");
|
||||||
Database::connect(options).await.expect("Database::connect")
|
Database::connect(options).await.expect("Database::connect")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,7 +415,7 @@ mod tests {
|
|||||||
// Query by uppercase string
|
// Query by uppercase string
|
||||||
{
|
{
|
||||||
let model = Entity::find()
|
let model = Entity::find()
|
||||||
.filter(Column::CiStr.contains("ABCD"))
|
.filter(Column::CiStr.eq("ABCD"))
|
||||||
.one(&db)
|
.one(&db)
|
||||||
.await
|
.await
|
||||||
.expect("find by case insensitive string")
|
.expect("find by case insensitive string")
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
toml-version = "v1.0.0"
|
||||||
|
|
||||||
|
[format.rules]
|
||||||
|
indent-style = "tab"
|
||||||
|
indent-width = 4
|
||||||
Reference in New Issue
Block a user