pub use sqlmodel_core::connection::{ConnectionConfig, SslMode, Transaction};
pub use sqlmodel_core::{
Budget,
Connection,
Cx,
DumpMode,
DumpOptions,
DumpResult,
Error,
Field,
FieldInfo,
FieldsSet,
Hybrid,
InheritanceInfo,
InheritanceStrategy,
Model,
ModelDump,
Outcome,
RegionId,
Result,
Row,
SqlEnum,
SqlModelDump,
SqlModelValidate,
SqlType,
TaskId,
TrackedModel,
TypeInfo,
ValidateInput,
ValidateOptions,
ValidateResult,
Value,
};
pub use sqlmodel_macros::{Model, SqlEnum, Validate};
pub use sqlmodel_query::{
BinaryOp, Expr, Join, JoinType, Limit, Offset, OrderBy, PolymorphicJoined, PolymorphicJoined2,
PolymorphicJoined3, PolymorphicJoinedSelect, PolymorphicJoinedSelect2,
PolymorphicJoinedSelect3, QueryBuilder, Select, UnaryOp, Where, delete, insert, raw_execute,
raw_query, select, update,
};
pub use sqlmodel_schema::{
CreateTable, Migration, MigrationRunner, MigrationStatus, SchemaBuilder, create_all,
create_table, drop_table,
};
pub use sqlmodel_pool::{
Pool, PoolConfig, PoolStats, PooledConnection, ReplicaPool, ReplicaStrategy,
};
pub use sqlmodel_session::{
GetOptions, ObjectKey, ObjectState, Session, SessionConfig, SessionDebugInfo,
};
#[macro_export]
macro_rules! tracked {
($ty:ident { $($field:ident : $value:expr),* $(,)? }) => {{
let inner = $ty { $($field: $value),* };
$crate::TrackedModel::from_explicit_field_names(inner, &[$(stringify!($field)),*])
}};
($ty:ident { $($field:ident : $value:expr),* , .. $rest:expr $(,)? }) => {{
let inner = $ty { $($field: $value),*, .. $rest };
$crate::TrackedModel::from_explicit_field_names(inner, &[$(stringify!($field)),*])
}};
}
pub mod connection_session;
pub mod session;
pub use connection_session::{ConnectionSession, ConnectionSessionBuilder};
#[cfg(feature = "console")]
pub use connection_session::ConnectionBuilderExt;
#[cfg(feature = "console")]
mod global_console;
#[cfg(feature = "console")]
pub use global_console::{
global_console, has_global_console, init_auto_console, set_global_console,
set_global_shared_console,
};
#[cfg(feature = "console")]
pub use sqlmodel_console::{
ConsoleAware,
OutputMode,
SqlModelConsole,
Theme,
renderables::{ErrorPanel, ErrorSeverity, PoolHealth, PoolStatsProvider, PoolStatusDisplay},
};
#[cfg(test)]
mod generic_model_tests {
use super::*;
use serde::{Deserialize, Serialize};
use std::marker::PhantomData;
#[derive(Model, Debug, Clone, Serialize, Deserialize)]
struct TaggedModel<T: Clone + std::fmt::Debug + Send + Sync + Default> {
#[sqlmodel(primary_key)]
id: i64,
name: String,
#[sqlmodel(skip)]
_marker: PhantomData<T>,
}
#[derive(Model, Debug, Clone, Serialize, Deserialize)]
struct TypedResponse<T: Send + Sync> {
#[sqlmodel(primary_key)]
id: i64,
status_code: i32,
body: String,
#[sqlmodel(skip)]
_type: PhantomData<T>,
}
#[derive(Debug, Clone, Default)]
struct UserData;
#[derive(Debug, Clone, Default)]
struct OrderData;
#[test]
fn test_generic_model_with_phantom_data() {
let model: TaggedModel<UserData> = TaggedModel {
id: 1,
name: "test".to_string(),
_marker: PhantomData,
};
assert_eq!(model.id, 1);
assert_eq!(model.name, "test");
}
#[test]
fn test_generic_model_fields() {
let fields = <TaggedModel<UserData> as Model>::fields();
assert_eq!(fields.len(), 2);
assert!(fields.iter().any(|f| f.name == "id"));
assert!(fields.iter().any(|f| f.name == "name"));
}
#[test]
fn test_generic_model_table_name() {
assert_eq!(
<TaggedModel<UserData> as Model>::TABLE_NAME,
"tagged_models"
);
assert_eq!(
<TypedResponse<UserData> as Model>::TABLE_NAME,
"typed_responses"
);
}
#[test]
fn test_generic_model_primary_key() {
assert_eq!(<TaggedModel<UserData> as Model>::PRIMARY_KEY, &["id"]);
}
#[test]
fn test_generic_model_type_safety() {
let user_response: TypedResponse<UserData> = TypedResponse {
id: 1,
status_code: 200,
body: r#"{"name": "Alice"}"#.to_string(),
_type: PhantomData,
};
let order_response: TypedResponse<OrderData> = TypedResponse {
id: 2,
status_code: 201,
body: r#"{"order_id": 123}"#.to_string(),
_type: PhantomData,
};
assert_eq!(user_response.id, 1);
assert_eq!(order_response.id, 2);
}
#[test]
fn test_generic_model_to_row() {
let model: TaggedModel<UserData> = TaggedModel {
id: 1,
name: "test".to_string(),
_marker: PhantomData,
};
let row = model.to_row();
assert_eq!(row.len(), 2);
assert!(row.iter().any(|(name, _)| *name == "id"));
assert!(row.iter().any(|(name, _)| *name == "name"));
}
#[test]
fn test_generic_model_primary_key_value() {
let model: TaggedModel<UserData> = TaggedModel {
id: 42,
name: "test".to_string(),
_marker: PhantomData,
};
let pk = model.primary_key_value();
assert_eq!(pk.len(), 1);
assert_eq!(pk[0], Value::BigInt(42));
}
#[test]
fn test_generic_model_is_new() {
let new_model: TaggedModel<UserData> = TaggedModel {
id: 0,
name: "new".to_string(),
_marker: PhantomData,
};
let _ = new_model.is_new(); }
}
#[cfg(test)]
mod inheritance_tests {
use super::*;
use serde::{Deserialize, Serialize};
use crate::InheritanceStrategy;
use sqlmodel_core::Value;
#[derive(Model, Debug, Clone, Serialize, Deserialize)]
#[sqlmodel(table, inheritance = "single", discriminator = "type_")]
struct Employee {
#[sqlmodel(primary_key)]
id: i64,
name: String,
type_: String,
}
#[derive(Model, Debug, Clone, Serialize, Deserialize)]
#[sqlmodel(inherits = "Employee", discriminator_value = "manager")]
struct Manager {
#[sqlmodel(primary_key)]
id: i64,
department: String,
}
#[derive(Model, Debug, Clone, Serialize, Deserialize)]
#[sqlmodel(table, inheritance = "joined")]
struct Person {
#[sqlmodel(primary_key)]
id: i64,
name: String,
}
#[derive(Model, Debug, Clone, Serialize, Deserialize)]
#[sqlmodel(table, inherits = "Person")]
struct Student {
#[sqlmodel(parent)]
person: Person,
#[sqlmodel(primary_key)]
id: i64,
grade: String,
}
#[derive(Model, Debug, Clone, Serialize, Deserialize)]
#[sqlmodel(table, inheritance = "concrete")]
struct BaseEntity {
#[sqlmodel(primary_key)]
id: i64,
created_at: i64,
}
#[derive(Model, Debug, Clone, Serialize, Deserialize)]
#[sqlmodel(table)]
struct NormalModel {
#[sqlmodel(primary_key)]
id: i64,
data: String,
}
#[test]
fn test_single_table_inheritance_base() {
let info = <Employee as Model>::inheritance();
assert_eq!(info.strategy, InheritanceStrategy::Single);
assert!(info.parent.is_none());
assert_eq!(info.discriminator_column, Some("type_"));
assert!(info.discriminator_value.is_none());
assert!(info.is_base());
assert!(!info.is_child());
}
#[test]
fn test_single_table_inheritance_child() {
let info = <Manager as Model>::inheritance();
assert_eq!(info.parent, Some(<Employee as Model>::TABLE_NAME));
assert_eq!(info.discriminator_column, Some("type_"));
assert_eq!(info.discriminator_value, Some("manager"));
assert!(info.is_child());
assert!(!info.is_base());
}
#[test]
fn test_single_table_inheritance_child_to_row_includes_discriminator() {
let m = Manager {
id: 1,
department: "ops".to_string(),
};
let row = m.to_row();
assert!(
row.iter()
.any(|(k, v)| *k == "type_" && *v == Value::Text("manager".to_string())),
"STI child to_row() must include discriminator value"
);
}
#[test]
fn test_joined_table_inheritance_base() {
let info = <Person as Model>::inheritance();
assert_eq!(info.strategy, InheritanceStrategy::Joined);
assert!(info.parent.is_none());
assert!(info.is_base());
}
#[test]
fn test_joined_table_inheritance_child() {
let info = <Student as Model>::inheritance();
assert_eq!(info.strategy, InheritanceStrategy::Joined);
assert_eq!(info.parent, Some(<Person as Model>::TABLE_NAME));
assert!(info.is_child());
}
#[test]
fn test_concrete_table_inheritance_base() {
let info = <BaseEntity as Model>::inheritance();
assert_eq!(info.strategy, InheritanceStrategy::Concrete);
assert!(info.parent.is_none());
assert!(info.is_base());
}
#[test]
fn test_no_inheritance() {
let info = <NormalModel as Model>::inheritance();
assert_eq!(info.strategy, InheritanceStrategy::None);
assert!(info.parent.is_none());
assert!(info.discriminator_value.is_none());
assert!(!info.is_base());
assert!(!info.is_child());
}
#[test]
fn test_inheritance_strategy_methods() {
let single = <Employee as Model>::inheritance();
assert!(single.strategy.uses_discriminator());
assert!(!single.strategy.requires_join());
let joined = <Person as Model>::inheritance();
assert!(!joined.strategy.uses_discriminator());
assert!(joined.strategy.requires_join());
let concrete = <BaseEntity as Model>::inheritance();
assert!(!concrete.strategy.uses_discriminator());
assert!(!concrete.strategy.requires_join());
}
}
#[cfg(test)]
mod shard_key_tests {
use super::*;
use serde::{Deserialize, Serialize};
#[derive(Model, Debug, Clone, Serialize, Deserialize)]
#[sqlmodel(table, shard_key = "tenant_id")]
struct TenantData {
#[sqlmodel(primary_key)]
id: i64,
tenant_id: i64,
data: String,
}
#[derive(Model, Debug, Clone, Serialize, Deserialize)]
#[sqlmodel(table, shard_key = "region")]
struct RegionalData {
#[sqlmodel(primary_key)]
id: i64,
region: Option<String>,
value: i32,
}
#[derive(Model, Debug, Clone, Serialize, Deserialize)]
#[sqlmodel(table)]
struct UnshardedData {
#[sqlmodel(primary_key)]
id: i64,
data: String,
}
#[test]
fn test_shard_key_constant() {
assert_eq!(<TenantData as Model>::SHARD_KEY, Some("tenant_id"));
assert_eq!(<RegionalData as Model>::SHARD_KEY, Some("region"));
assert_eq!(<UnshardedData as Model>::SHARD_KEY, None);
}
#[test]
fn test_shard_key_value_non_optional() {
let data = TenantData {
id: 1,
tenant_id: 42,
data: "test".to_string(),
};
let shard_value = data.shard_key_value();
assert!(shard_value.is_some());
assert_eq!(shard_value.unwrap(), Value::BigInt(42));
}
#[test]
fn test_shard_key_value_optional_some() {
let data = RegionalData {
id: 1,
region: Some("us-west".to_string()),
value: 100,
};
let shard_value = data.shard_key_value();
assert!(shard_value.is_some());
assert_eq!(shard_value.unwrap(), Value::Text("us-west".to_string()));
}
#[test]
fn test_shard_key_value_optional_none() {
let data = RegionalData {
id: 1,
region: None,
value: 100,
};
let shard_value = data.shard_key_value();
assert!(shard_value.is_none());
}
#[test]
fn test_shard_key_value_unsharded() {
let data = UnshardedData {
id: 1,
data: "test".to_string(),
};
let shard_value = data.shard_key_value();
assert!(shard_value.is_none());
}
}
pub mod prelude {
pub use crate::{
Budget,
Connection,
ConnectionSession,
ConnectionSessionBuilder,
Cx,
DumpMode,
DumpOptions,
Error,
Expr,
FieldsSet,
GetOptions,
Hybrid,
Join,
JoinType,
Migration,
MigrationRunner,
Model,
ModelDump,
ObjectKey,
ObjectState,
OrderBy,
Outcome,
PolymorphicJoined,
PolymorphicJoined2,
PolymorphicJoined3,
PolymorphicJoinedSelect,
PolymorphicJoinedSelect2,
PolymorphicJoinedSelect3,
Pool,
PoolConfig,
RegionId,
Result,
Row,
Select,
Session,
SessionConfig,
SqlModelDump,
SqlModelValidate,
TaskId,
TrackedModel,
ValidateInput,
ValidateOptions,
ValidateResult,
Value,
create_table,
delete,
insert,
select,
update,
};
pub use sqlmodel_macros::{SqlEnum, Validate};
#[cfg(feature = "console")]
pub use crate::{
ConnectionBuilderExt,
ConsoleAware,
ErrorPanel,
ErrorSeverity,
OutputMode,
PoolHealth,
PoolStatsProvider,
PoolStatusDisplay,
SqlModelConsole,
Theme,
global_console,
has_global_console,
init_auto_console,
set_global_console,
set_global_shared_console,
};
}