1pub use sqlmodel_core::connection::{ConnectionConfig, SslMode, Transaction};
99pub use sqlmodel_core::{
100 Budget,
102 Connection,
104 Cx,
105 DumpMode,
106 DumpOptions,
107 DumpResult,
108 Error,
109 Field,
110 FieldInfo,
111 FieldsSet,
112 Hybrid,
113 InheritanceInfo,
115 InheritanceStrategy,
116 Model,
117 ModelDump,
118 Outcome,
119 RegionId,
120 Result,
121 Row,
122 SqlEnum,
123 SqlModelDump,
124 SqlModelValidate,
125 SqlType,
126 TaskId,
127 TrackedModel,
128 TypeInfo,
129 ValidateInput,
130 ValidateOptions,
131 ValidateResult,
132 Value,
133};
134
135pub use sqlmodel_macros::{Model, SqlEnum, Validate};
136
137pub use sqlmodel_query::{
138 BinaryOp, Expr, Join, JoinType, Limit, Offset, OrderBy, PolymorphicJoined, PolymorphicJoined2,
139 PolymorphicJoined3, PolymorphicJoinedSelect, PolymorphicJoinedSelect2,
140 PolymorphicJoinedSelect3, QueryBuilder, Select, UnaryOp, Where, delete, insert, raw_execute,
141 raw_query, select, update,
142};
143
144pub use sqlmodel_schema::{
145 CreateTable, Migration, MigrationRunner, MigrationStatus, SchemaBuilder, create_all,
146 create_table, drop_table,
147};
148
149pub use sqlmodel_pool::{
150 Pool, PoolConfig, PoolStats, PooledConnection, ReplicaPool, ReplicaStrategy,
151};
152
153pub use sqlmodel_session::{
154 GetOptions, ObjectKey, ObjectState, Session, SessionConfig, SessionDebugInfo,
155};
156
157#[macro_export]
176macro_rules! tracked {
177 ($ty:ident { $($field:ident : $value:expr),* $(,)? }) => {{
178 let inner = $ty { $($field: $value),* };
179 $crate::TrackedModel::from_explicit_field_names(inner, &[$(stringify!($field)),*])
180 }};
181 ($ty:ident { $($field:ident : $value:expr),* , .. $rest:expr $(,)? }) => {{
182 let inner = $ty { $($field: $value),*, .. $rest };
183 $crate::TrackedModel::from_explicit_field_names(inner, &[$(stringify!($field)),*])
184 }};
185}
186
187pub mod connection_session;
189pub mod session;
190pub use connection_session::{ConnectionSession, ConnectionSessionBuilder};
191
192#[cfg(feature = "console")]
194pub use connection_session::ConnectionBuilderExt;
195
196#[cfg(feature = "console")]
198mod global_console;
199#[cfg(feature = "console")]
200pub use global_console::{
201 global_console, has_global_console, init_auto_console, set_global_console,
202 set_global_shared_console,
203};
204
205#[cfg(feature = "console")]
207pub use sqlmodel_console::{
208 ConsoleAware,
210 OutputMode,
211 SqlModelConsole,
212 Theme,
213 renderables::{ErrorPanel, ErrorSeverity, PoolHealth, PoolStatsProvider, PoolStatusDisplay},
215};
216
217#[cfg(test)]
235mod generic_model_tests {
236 use super::*;
237 use serde::{Deserialize, Serialize};
238 use std::marker::PhantomData;
239
240 #[derive(Model, Debug, Clone, Serialize, Deserialize)]
243 struct TaggedModel<T: Clone + std::fmt::Debug + Send + Sync + Default> {
244 #[sqlmodel(primary_key)]
245 id: i64,
246 name: String,
247 #[sqlmodel(skip)]
248 _marker: PhantomData<T>,
249 }
250
251 #[derive(Model, Debug, Clone, Serialize, Deserialize)]
254 struct TypedResponse<T: Send + Sync> {
255 #[sqlmodel(primary_key)]
256 id: i64,
257 status_code: i32,
258 body: String,
259 #[sqlmodel(skip)]
260 _type: PhantomData<T>,
261 }
262
263 #[derive(Debug, Clone, Default)]
265 struct UserData;
266
267 #[derive(Debug, Clone, Default)]
268 struct OrderData;
269
270 #[test]
271 fn test_generic_model_with_phantom_data() {
272 let model: TaggedModel<UserData> = TaggedModel {
274 id: 1,
275 name: "test".to_string(),
276 _marker: PhantomData,
277 };
278 assert_eq!(model.id, 1);
279 assert_eq!(model.name, "test");
280 }
281
282 #[test]
283 fn test_generic_model_fields() {
284 let fields = <TaggedModel<UserData> as Model>::fields();
286 assert_eq!(fields.len(), 2);
288 assert!(fields.iter().any(|f| f.name == "id"));
289 assert!(fields.iter().any(|f| f.name == "name"));
290 }
291
292 #[test]
293 fn test_generic_model_table_name() {
294 assert_eq!(
296 <TaggedModel<UserData> as Model>::TABLE_NAME,
297 "tagged_models"
298 );
299 assert_eq!(
300 <TypedResponse<UserData> as Model>::TABLE_NAME,
301 "typed_responses"
302 );
303 }
304
305 #[test]
306 fn test_generic_model_primary_key() {
307 assert_eq!(<TaggedModel<UserData> as Model>::PRIMARY_KEY, &["id"]);
308 }
309
310 #[test]
311 fn test_generic_model_type_safety() {
312 let user_response: TypedResponse<UserData> = TypedResponse {
314 id: 1,
315 status_code: 200,
316 body: r#"{"name": "Alice"}"#.to_string(),
317 _type: PhantomData,
318 };
319
320 let order_response: TypedResponse<OrderData> = TypedResponse {
321 id: 2,
322 status_code: 201,
323 body: r#"{"order_id": 123}"#.to_string(),
324 _type: PhantomData,
325 };
326
327 assert_eq!(user_response.id, 1);
329 assert_eq!(order_response.id, 2);
330 }
331
332 #[test]
333 fn test_generic_model_to_row() {
334 let model: TaggedModel<UserData> = TaggedModel {
335 id: 1,
336 name: "test".to_string(),
337 _marker: PhantomData,
338 };
339 let row = model.to_row();
340 assert_eq!(row.len(), 2);
342 assert!(row.iter().any(|(name, _)| *name == "id"));
343 assert!(row.iter().any(|(name, _)| *name == "name"));
344 }
345
346 #[test]
347 fn test_generic_model_primary_key_value() {
348 let model: TaggedModel<UserData> = TaggedModel {
349 id: 42,
350 name: "test".to_string(),
351 _marker: PhantomData,
352 };
353 let pk = model.primary_key_value();
354 assert_eq!(pk.len(), 1);
355 assert_eq!(pk[0], Value::BigInt(42));
356 }
357
358 #[test]
359 fn test_generic_model_is_new() {
360 let new_model: TaggedModel<UserData> = TaggedModel {
361 id: 0,
362 name: "new".to_string(),
363 _marker: PhantomData,
364 };
365 let _ = new_model.is_new(); }
368}
369
370#[cfg(test)]
378mod inheritance_tests {
379 use super::*;
380 use serde::{Deserialize, Serialize};
381 use crate::InheritanceStrategy;
383 use sqlmodel_core::Value;
384
385 #[derive(Model, Debug, Clone, Serialize, Deserialize)]
387 #[sqlmodel(table, inheritance = "single", discriminator = "type_")]
388 struct Employee {
389 #[sqlmodel(primary_key)]
390 id: i64,
391 name: String,
392 type_: String,
393 }
394
395 #[derive(Model, Debug, Clone, Serialize, Deserialize)]
397 #[sqlmodel(inherits = "Employee", discriminator_value = "manager")]
398 struct Manager {
399 #[sqlmodel(primary_key)]
400 id: i64,
401 department: String,
402 }
403
404 #[derive(Model, Debug, Clone, Serialize, Deserialize)]
406 #[sqlmodel(table, inheritance = "joined")]
407 struct Person {
408 #[sqlmodel(primary_key)]
409 id: i64,
410 name: String,
411 }
412
413 #[derive(Model, Debug, Clone, Serialize, Deserialize)]
415 #[sqlmodel(table, inherits = "Person")]
416 struct Student {
417 #[sqlmodel(parent)]
418 person: Person,
419 #[sqlmodel(primary_key)]
420 id: i64,
421 grade: String,
422 }
423
424 #[derive(Model, Debug, Clone, Serialize, Deserialize)]
426 #[sqlmodel(table, inheritance = "concrete")]
427 struct BaseEntity {
428 #[sqlmodel(primary_key)]
429 id: i64,
430 created_at: i64,
431 }
432
433 #[derive(Model, Debug, Clone, Serialize, Deserialize)]
435 #[sqlmodel(table)]
436 struct NormalModel {
437 #[sqlmodel(primary_key)]
438 id: i64,
439 data: String,
440 }
441
442 #[test]
443 fn test_single_table_inheritance_base() {
444 let info = <Employee as Model>::inheritance();
445 assert_eq!(info.strategy, InheritanceStrategy::Single);
446 assert!(info.parent.is_none());
447 assert_eq!(info.discriminator_column, Some("type_"));
448 assert!(info.discriminator_value.is_none());
449 assert!(info.is_base());
450 assert!(!info.is_child());
451 }
452
453 #[test]
454 fn test_single_table_inheritance_child() {
455 let info = <Manager as Model>::inheritance();
456 assert_eq!(info.parent, Some(<Employee as Model>::TABLE_NAME));
457 assert_eq!(info.discriminator_column, Some("type_"));
458 assert_eq!(info.discriminator_value, Some("manager"));
459 assert!(info.is_child());
460 assert!(!info.is_base());
461 }
462
463 #[test]
464 fn test_single_table_inheritance_child_to_row_includes_discriminator() {
465 let m = Manager {
466 id: 1,
467 department: "ops".to_string(),
468 };
469 let row = m.to_row();
470
471 assert!(
472 row.iter()
473 .any(|(k, v)| *k == "type_" && *v == Value::Text("manager".to_string())),
474 "STI child to_row() must include discriminator value"
475 );
476 }
477
478 #[test]
479 fn test_joined_table_inheritance_base() {
480 let info = <Person as Model>::inheritance();
481 assert_eq!(info.strategy, InheritanceStrategy::Joined);
482 assert!(info.parent.is_none());
483 assert!(info.is_base());
484 }
485
486 #[test]
487 fn test_joined_table_inheritance_child() {
488 let info = <Student as Model>::inheritance();
489 assert_eq!(info.strategy, InheritanceStrategy::Joined);
490 assert_eq!(info.parent, Some(<Person as Model>::TABLE_NAME));
491 assert!(info.is_child());
492 }
493
494 #[test]
495 fn test_concrete_table_inheritance_base() {
496 let info = <BaseEntity as Model>::inheritance();
497 assert_eq!(info.strategy, InheritanceStrategy::Concrete);
498 assert!(info.parent.is_none());
499 assert!(info.is_base());
500 }
501
502 #[test]
503 fn test_no_inheritance() {
504 let info = <NormalModel as Model>::inheritance();
505 assert_eq!(info.strategy, InheritanceStrategy::None);
506 assert!(info.parent.is_none());
507 assert!(info.discriminator_value.is_none());
508 assert!(!info.is_base());
509 assert!(!info.is_child());
510 }
511
512 #[test]
513 fn test_inheritance_strategy_methods() {
514 let single = <Employee as Model>::inheritance();
516 assert!(single.strategy.uses_discriminator());
517 assert!(!single.strategy.requires_join());
518
519 let joined = <Person as Model>::inheritance();
521 assert!(!joined.strategy.uses_discriminator());
522 assert!(joined.strategy.requires_join());
523
524 let concrete = <BaseEntity as Model>::inheritance();
526 assert!(!concrete.strategy.uses_discriminator());
527 assert!(!concrete.strategy.requires_join());
528 }
529}
530
531#[cfg(test)]
539mod shard_key_tests {
540 use super::*;
541 use serde::{Deserialize, Serialize};
542
543 #[derive(Model, Debug, Clone, Serialize, Deserialize)]
545 #[sqlmodel(table, shard_key = "tenant_id")]
546 struct TenantData {
547 #[sqlmodel(primary_key)]
548 id: i64,
549 tenant_id: i64,
550 data: String,
551 }
552
553 #[derive(Model, Debug, Clone, Serialize, Deserialize)]
555 #[sqlmodel(table, shard_key = "region")]
556 struct RegionalData {
557 #[sqlmodel(primary_key)]
558 id: i64,
559 region: Option<String>,
560 value: i32,
561 }
562
563 #[derive(Model, Debug, Clone, Serialize, Deserialize)]
565 #[sqlmodel(table)]
566 struct UnshardedData {
567 #[sqlmodel(primary_key)]
568 id: i64,
569 data: String,
570 }
571
572 #[test]
573 fn test_shard_key_constant() {
574 assert_eq!(<TenantData as Model>::SHARD_KEY, Some("tenant_id"));
575 assert_eq!(<RegionalData as Model>::SHARD_KEY, Some("region"));
576 assert_eq!(<UnshardedData as Model>::SHARD_KEY, None);
577 }
578
579 #[test]
580 fn test_shard_key_value_non_optional() {
581 let data = TenantData {
582 id: 1,
583 tenant_id: 42,
584 data: "test".to_string(),
585 };
586 let shard_value = data.shard_key_value();
587 assert!(shard_value.is_some());
588 assert_eq!(shard_value.unwrap(), Value::BigInt(42));
589 }
590
591 #[test]
592 fn test_shard_key_value_optional_some() {
593 let data = RegionalData {
594 id: 1,
595 region: Some("us-west".to_string()),
596 value: 100,
597 };
598 let shard_value = data.shard_key_value();
599 assert!(shard_value.is_some());
600 assert_eq!(shard_value.unwrap(), Value::Text("us-west".to_string()));
601 }
602
603 #[test]
604 fn test_shard_key_value_optional_none() {
605 let data = RegionalData {
606 id: 1,
607 region: None,
608 value: 100,
609 };
610 let shard_value = data.shard_key_value();
611 assert!(shard_value.is_none());
612 }
613
614 #[test]
615 fn test_shard_key_value_unsharded() {
616 let data = UnshardedData {
617 id: 1,
618 data: "test".to_string(),
619 };
620 let shard_value = data.shard_key_value();
621 assert!(shard_value.is_none());
622 }
623}
624
625pub mod prelude {
631 pub use crate::{
632 Budget,
634 Connection,
636 ConnectionSession,
638 ConnectionSessionBuilder,
639 Cx,
640 DumpMode,
641 DumpOptions,
642 Error,
643 Expr,
645 FieldsSet,
646 GetOptions,
647 Hybrid,
648 Join,
649 JoinType,
650 Migration,
651 MigrationRunner,
652 Model,
653 ModelDump,
654 ObjectKey,
655 ObjectState,
656 OrderBy,
657 Outcome,
658 PolymorphicJoined,
659 PolymorphicJoined2,
660 PolymorphicJoined3,
661 PolymorphicJoinedSelect,
662 PolymorphicJoinedSelect2,
663 PolymorphicJoinedSelect3,
664 Pool,
666 PoolConfig,
667 RegionId,
668 Result,
669 Row,
670 Select,
671 Session,
673 SessionConfig,
674 SqlModelDump,
675 SqlModelValidate,
676 TaskId,
677 TrackedModel,
678 ValidateInput,
679 ValidateOptions,
680 ValidateResult,
681 Value,
682 create_table,
684 delete,
686 insert,
687 select,
688 update,
689 };
690 pub use sqlmodel_macros::{SqlEnum, Validate};
692
693 #[cfg(feature = "console")]
695 pub use crate::{
696 ConnectionBuilderExt,
698 ConsoleAware,
699 ErrorPanel,
700 ErrorSeverity,
701 OutputMode,
702 PoolHealth,
703 PoolStatsProvider,
704 PoolStatusDisplay,
705 SqlModelConsole,
706 Theme,
707 global_console,
709 has_global_console,
710 init_auto_console,
711 set_global_console,
712 set_global_shared_console,
713 };
714}