reydb 1.1.58__py3-none-any.whl → 1.1.60__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
reydb/rorm.py CHANGED
@@ -12,18 +12,25 @@
12
12
  from typing import Self, Any, Type, TypeVar, Generic, Final, overload
13
13
  from collections.abc import Callable
14
14
  from functools import wraps as functools_wraps
15
+ from inspect import iscoroutinefunction as inspect_iscoroutinefunction
15
16
  from pydantic import ConfigDict, field_validator as pydantic_field_validator, model_validator as pydantic_model_validator
16
17
  from sqlalchemy.orm import SessionTransaction
18
+ from sqlalchemy.ext.asyncio import AsyncSessionTransaction
17
19
  from sqlalchemy.sql import sqltypes
18
20
  from sqlalchemy.sql.sqltypes import TypeEngine
19
21
  from sqlalchemy.sql.dml import Insert, Update, Delete
20
22
  from sqlmodel import SQLModel, Session, Table
21
- from sqlmodel.main import SQLModelMetaclass, FieldInfo
23
+ from sqlmodel.ext.asyncio.session import AsyncSession
24
+ from sqlmodel.main import SQLModelMetaclass, FieldInfo, default_registry
22
25
  from sqlmodel.sql._expression_select_cls import SelectOfScalar as Select
23
- from reykit.rbase import CallableT, Null, is_instance
26
+ from reykit.rbase import CallableT, Null, throw, is_instance
24
27
 
25
28
  from . import rdb
26
- from .rbase import DatabaseBase
29
+ from .rbase import (
30
+ SessionT,
31
+ SessionTransactionT,
32
+ DatabaseBase
33
+ )
27
34
 
28
35
 
29
36
  __all__ = (
@@ -31,17 +38,35 @@ __all__ = (
31
38
  'DatabaseORMModelMeta',
32
39
  'DatabaseORMModel',
33
40
  'DatabaseORMModelField',
41
+ 'DatabaseORMSuper',
34
42
  'DatabaseORM',
43
+ 'DatabaseORMAsync',
44
+ 'DatabaseORMSessionSuper',
35
45
  'DatabaseORMSession',
46
+ 'DatabaseORMSessionAsync',
47
+ 'DatabaseORMStatementSuper',
36
48
  'DatabaseORMStatement',
49
+ 'DatabaseORMStatementAsync',
37
50
  'DatabaseORMStatementSelect',
38
51
  'DatabaseORMStatementInsert',
39
52
  'DatabaseORMStatementUpdate',
40
- 'DatabaseORMStatementDelete'
53
+ 'DatabaseORMStatementDelete',
54
+ 'DatabaseORMStatementSelectAsync',
55
+ 'DatabaseORMStatementInsertAsync',
56
+ 'DatabaseORMStatementUpdateAsync',
57
+ 'DatabaseORMStatementDeleteAsync'
41
58
  )
42
59
 
43
60
 
44
- ModelT = TypeVar('ModelT', bound='DatabaseORMModel')
61
+ DatabaseT = TypeVar('DatabaseT', 'rdb.Database', 'rdb.DatabaseAsync')
62
+ DatabaseORMModelT = TypeVar('DatabaseORMModelT', bound='DatabaseORMModel')
63
+ DatabaseORMT = TypeVar('DatabaseORMT', 'DatabaseORM', 'DatabaseORMAsync')
64
+ DatabaseORMSessionT = TypeVar('DatabaseORMSessionT', 'DatabaseORMSession', 'DatabaseORMSessionAsync')
65
+ DatabaseORMStatementReturn = TypeVar('DatabaseORMStatementReturn')
66
+ DatabaseORMStatementSelectT = TypeVar('DatabaseORMStatementSelectT', 'DatabaseORMStatementSelect', 'DatabaseORMStatementSelectAsync')
67
+ DatabaseORMStatementInsertT = TypeVar('DatabaseORMStatementInsertT', 'DatabaseORMStatementInsert', 'DatabaseORMStatementInsertAsync')
68
+ DatabaseORMStatementUpdateT = TypeVar('DatabaseORMStatementUpdateT', 'DatabaseORMStatementUpdate', 'DatabaseORMStatementUpdateAsync')
69
+ DatabaseORMStatementDeleteT = TypeVar('DatabaseORMStatementDeleteT', 'DatabaseORMStatementDelete', 'DatabaseORMStatementDeleteAsync')
45
70
 
46
71
 
47
72
  class DatabaseORMBase(DatabaseBase):
@@ -78,6 +103,16 @@ class DatabaseORMModelMeta(DatabaseORMBase, SQLModelMetaclass):
78
103
  if attrs['__module__'] == '__main__':
79
104
  table_args = attrs.setdefault('__table_args__', {})
80
105
  table_args['quote'] = True
106
+
107
+ ## Charset.
108
+ attrs.setdefault('__charset__', 'utf8mb4')
109
+ table_args['mysql_charset'] = attrs.pop('__charset__')
110
+
111
+ ## Name.
112
+ if '__name__' in attrs:
113
+ table_args['name'] = attrs.pop('__name__')
114
+
115
+ ## Comment.
81
116
  if '__comment__' in attrs:
82
117
  table_args['comment'] = attrs.pop('__comment__')
83
118
 
@@ -219,7 +254,7 @@ class DatabaseORMModelField(DatabaseBase, FieldInfo):
219
254
  field_type: TypeEngine | None = None,
220
255
  key: bool = False,
221
256
  key_auto: bool = False,
222
- non_null: bool = False,
257
+ not_null: bool = False,
223
258
  index_n: bool = False,
224
259
  index_u: bool = False,
225
260
  comment: str | None = None,
@@ -257,7 +292,7 @@ class DatabaseORMModelField(DatabaseBase, FieldInfo):
257
292
  - `None`: Based type annotation automatic judgment.
258
293
  key : Whether the field is primary key.
259
294
  key_auto : Whether the field is automatic increment primary key.
260
- non_null : Whether the field is non null constraint.
295
+ not_null : Whether the field is not null constraint.
261
296
  index_n : Whether the field add normal index.
262
297
  index_u : Whether the field add unique index.
263
298
  comment : Field commment.
@@ -338,8 +373,8 @@ class DatabaseORMModelField(DatabaseBase, FieldInfo):
338
373
  kwargs['sa_column_kwargs']['autoincrement'] = False
339
374
 
340
375
  ## Non null.
341
- if 'non_null' in kwargs:
342
- kwargs['nullable'] = not kwargs.pop('non_null')
376
+ if 'not_null' in kwargs:
377
+ kwargs['nullable'] = not kwargs.pop('not_null')
343
378
  else:
344
379
  kwargs['nullable'] = True
345
380
 
@@ -351,25 +386,31 @@ class DatabaseORMModelField(DatabaseBase, FieldInfo):
351
386
  super().__init__(**kwargs)
352
387
 
353
388
 
354
- class DatabaseORM(DatabaseORMBase):
389
+ class DatabaseORMSuper(DatabaseORMBase, Generic[DatabaseT, DatabaseORMSessionT]):
355
390
  """
356
- Database ORM type.
391
+ Database ORM super type.
357
392
 
358
393
  Attributes
359
394
  ----------
395
+ metaData : Registry metadata instance.
360
396
  DatabaseModel : Database ORM model type.
361
- Field : Factory function of database ORM model field.
397
+ Field : Database ORM model field type.
398
+ Config : Database ORM model config type.
399
+ types : Database ORM model filed types module.
400
+ wrap_validate_model : Create decorator of validate database ORM model.
401
+ wrap_validate_filed : Create decorator of validate database ORM model field.
362
402
  """
363
403
 
404
+ metaData = default_registry.metadata
364
405
  Model = DatabaseORMModel
365
406
  Field = DatabaseORMModelField
366
407
  Config = ConfigDict
367
- tyeps = sqltypes
368
- wrap_validate_filed = pydantic_field_validator
408
+ types = sqltypes
369
409
  wrap_validate_model = pydantic_model_validator
410
+ wrap_validate_filed = pydantic_field_validator
370
411
 
371
412
 
372
- def __init__(self, db: 'rdb.Database') -> None:
413
+ def __init__(self, db: DatabaseT) -> None:
373
414
  """
374
415
  Build instance attributes.
375
416
 
@@ -380,16 +421,22 @@ class DatabaseORM(DatabaseORMBase):
380
421
 
381
422
  # Build.
382
423
  self.db = db
383
- self._session = self.session(True)
424
+ self.__sess = self.session(True)
384
425
 
385
426
  ## Method.
386
- self.get = self._session.get
387
- self.gets = self._session.gets
388
- self.all = self._session.all
389
- self.add = self._session.add
427
+ self.create = self.__sess.create
428
+ self.drop = self.__sess.drop
429
+ self.get = self.__sess.get
430
+ self.gets = self.__sess.gets
431
+ self.all = self.__sess.all
432
+ self.add = self.__sess.add
433
+ self.select = self.__sess.select
434
+ self.insert = self.__sess.insert
435
+ self.update = self.__sess.update
436
+ self.delete = self.__sess.delete
390
437
 
391
438
 
392
- def session(self, autocommit: bool = False):
439
+ def session(self, autocommit: bool = False) -> DatabaseORMSessionT:
393
440
  """
394
441
  Build DataBase ORM session instance.
395
442
 
@@ -403,68 +450,67 @@ class DatabaseORM(DatabaseORMBase):
403
450
  """
404
451
 
405
452
  # Build.
406
- sess = DatabaseORMSession(self, autocommit)
453
+ match self:
454
+ case DatabaseORM():
455
+ sess = DatabaseORMSession(self, autocommit)
456
+ case DatabaseORMAsync():
457
+ sess = DatabaseORMSessionAsync(self, autocommit)
407
458
 
408
459
  return sess
409
460
 
410
461
 
411
- def create(
412
- self,
413
- *models: Type[DatabaseORMModel] | DatabaseORMModel,
414
- skip: bool = False
415
- ) -> None:
416
- """
417
- Create table.
418
-
419
- Parameters
420
- ----------
421
- models : ORM model instances.
422
- check : Skip existing table and not mapping model.
423
- """
424
-
425
- # Create.
426
- for model in models:
427
- table = model.table()
428
- if (
429
- not skip
430
- or table is not None
431
- ):
432
- table.create(self.db.engine, checkfirst=skip)
462
+ class DatabaseORM(DatabaseORMSuper['rdb.Database', 'DatabaseORMSession']):
463
+ """
464
+ Database ORM type.
433
465
 
466
+ Attributes
467
+ ----------
468
+ metaData : Registry metadata instance.
469
+ DatabaseModel : Database ORM model type.
470
+ Field : Database ORM model field type.
471
+ Config : Database ORM model config type.
472
+ types : Database ORM model filed types module.
473
+ wrap_validate_model : Create decorator of validate database ORM model.
474
+ wrap_validate_filed : Create decorator of validate database ORM model field.
475
+ """
434
476
 
435
- def drop(
436
- self,
437
- *models: Type[DatabaseORMModel] | DatabaseORMModel,
438
- skip: bool = False
439
- ) -> None:
440
- """
441
- Delete table.
442
477
 
443
- Parameters
444
- ----------
445
- models : ORM model instances.
446
- check : Skip not exist table and not mapping model.
447
- """
478
+ class DatabaseORMAsync(DatabaseORMSuper['rdb.DatabaseAsync', 'DatabaseORMSessionAsync']):
479
+ """
480
+ Asynchronous database ORM type.
448
481
 
449
- # Create.
450
- for model in models:
451
- table = model.table()
452
- if (
453
- not skip
454
- or table is not None
455
- ):
456
- table.drop(self.db.engine, checkfirst=skip)
482
+ Attributes
483
+ ----------
484
+ metaData : Registry metadata instance.
485
+ DatabaseModel : Database ORM model type.
486
+ Field : Database ORM model field type.
487
+ Config : Database ORM model config type.
488
+ types : Database ORM model filed types module.
489
+ wrap_validate_model : Create decorator of validate database ORM model.
490
+ wrap_validate_filed : Create decorator of validate database ORM model field.
491
+ """
457
492
 
458
493
 
459
- class DatabaseORMSession(DatabaseORMBase):
494
+ class DatabaseORMSessionSuper(
495
+ DatabaseORMBase,
496
+ Generic[
497
+ DatabaseORMT,
498
+ SessionT,
499
+ SessionTransactionT,
500
+ DatabaseORMStatementSelectT,
501
+ DatabaseORMStatementInsertT,
502
+ DatabaseORMStatementUpdateT,
503
+ DatabaseORMStatementDeleteT
504
+ ]
505
+ ):
460
506
  """
461
- Database ORM session type, based ORM model.
507
+ Database ORM session super type.
462
508
  """
463
509
 
464
510
 
465
511
  def __init__(
466
512
  self,
467
- orm: 'DatabaseORM',
513
+ orm: DatabaseORMT,
468
514
  autocommit: bool = False
469
515
  ) -> None:
470
516
  """
@@ -479,41 +525,132 @@ class DatabaseORMSession(DatabaseORMBase):
479
525
  # Build.
480
526
  self.orm = orm
481
527
  self.autocommit = autocommit
482
- self.session: Session | None = None
483
- self.begin: SessionTransaction | None = None
528
+ self.sess: SessionT | None = None
529
+ self.begin: SessionTransactionT | None = None
484
530
 
485
531
 
486
- def commit(self) -> None:
532
+ def select(self, model: Type[DatabaseORMModelT] | DatabaseORMModelT) -> DatabaseORMStatementSelectT:
487
533
  """
488
- Commit cumulative executions.
534
+ Build database ORM select instance.
535
+
536
+ Parameters
537
+ ----------
538
+ model : ORM model instance.
539
+
540
+ Returns
541
+ -------
542
+ Instance.
489
543
  """
490
544
 
491
- # Commit.
492
- if self.begin is not None:
493
- self.begin.commit()
494
- self.begin = None
545
+ # Handle parameter.
546
+ if is_instance(model):
547
+ model = type(model)
495
548
 
549
+ # Build.
550
+ match self:
551
+ case DatabaseORMSession():
552
+ select = DatabaseORMStatementSelect[DatabaseORMModelT](self, model)
553
+ case DatabaseORMSessionAsync():
554
+ select = DatabaseORMStatementSelectAsync[DatabaseORMModelT](self, model)
496
555
 
497
- def rollback(self) -> None:
556
+ return select
557
+
558
+
559
+ def insert(self, model: Type[DatabaseORMModelT] | DatabaseORMModelT) -> DatabaseORMStatementInsertT:
498
560
  """
499
- Rollback cumulative executions.
561
+ Build database ORM insert instance.
562
+
563
+ Parameters
564
+ ----------
565
+ model : ORM model instance.
566
+
567
+ Returns
568
+ -------
569
+ Instance.
500
570
  """
571
+ print(model)
572
+ # Handle parameter.
573
+ if is_instance(model):
574
+ model = type(model)
501
575
 
502
- # Rollback.
503
- if self.begin is not None:
504
- self.begin.rollback()
505
- self.begin = None
576
+ # Build.
577
+ match self:
578
+ case DatabaseORMSession():
579
+ insert = DatabaseORMStatementInsert[DatabaseORMModelT](self, model)
580
+ case DatabaseORMSessionAsync():
581
+ insert = DatabaseORMStatementInsertAsync[DatabaseORMModelT](self, model)
506
582
 
583
+ return insert
507
584
 
508
- def close(self) -> None:
585
+
586
+ def update(self, model: Type[DatabaseORMModelT] | DatabaseORMModelT) -> DatabaseORMStatementUpdateT:
587
+ """
588
+ Build database ORM update instance.
589
+
590
+ Parameters
591
+ ----------
592
+ model : ORM model instance.
593
+
594
+ Returns
595
+ -------
596
+ Instance.
509
597
  """
510
- Close database connection.
598
+
599
+ # Handle parameter.
600
+ if is_instance(model):
601
+ model = type(model)
602
+
603
+ # Build.
604
+ match self:
605
+ case DatabaseORMSession():
606
+ update = DatabaseORMStatementUpdate[DatabaseORMModelT](self, model)
607
+ case DatabaseORMSessionAsync():
608
+ update = DatabaseORMStatementUpdateAsync[DatabaseORMModelT](self, model)
609
+
610
+ return update
611
+
612
+
613
+ def delete(self, model: Type[DatabaseORMModelT] | DatabaseORMModelT) -> DatabaseORMStatementDeleteT:
511
614
  """
615
+ Build database ORM delete instance.
512
616
 
513
- # Close.
514
- if self.session is not None:
515
- self.session.close()
516
- self.session = None
617
+ Parameters
618
+ ----------
619
+ model : ORM model instance.
620
+
621
+ Returns
622
+ -------
623
+ Instance.
624
+ """
625
+
626
+ # Handle parameter.
627
+ if is_instance(model):
628
+ model = type(model)
629
+
630
+ # Build.
631
+ match self:
632
+ case DatabaseORMSession():
633
+ delete = DatabaseORMStatementDelete[DatabaseORMModelT](self, model)
634
+ case DatabaseORMSessionAsync():
635
+ delete = DatabaseORMStatementDeleteAsync[DatabaseORMModelT](self, model)
636
+
637
+ return delete
638
+
639
+
640
+ class DatabaseORMSession(
641
+ DatabaseORMSessionSuper[
642
+ DatabaseORM,
643
+ Session,
644
+ SessionTransaction,
645
+ 'DatabaseORMStatementSelect',
646
+ 'DatabaseORMStatementInsert',
647
+ 'DatabaseORMStatementUpdate',
648
+ 'DatabaseORMStatementDelete'
649
+ ]
650
+ ):
651
+ """
652
+ Database ORM session type.
653
+ """
517
654
 
518
655
 
519
656
  def __enter__(self) -> Self:
@@ -546,11 +683,76 @@ class DatabaseORMSession(DatabaseORMBase):
546
683
  self.commit()
547
684
 
548
685
  # Close.
549
- else:
550
- self.close()
686
+ self.close()
687
+
688
+
689
+ def get_sess(self) -> Session:
690
+ """
691
+ Get `Session` instance.
692
+
693
+ Returns
694
+ -------
695
+ Instance.
696
+ """
697
+
698
+ # Create.
699
+ if self.sess is None:
700
+ self.sess = Session(self.orm.db.engine)
701
+
702
+ return self.sess
703
+
704
+
705
+ def get_begin(self) -> SessionTransaction:
706
+ """
707
+ Get `SessionTransaction` instance.
708
+
709
+ Returns
710
+ -------
711
+ Instance.
712
+ """
713
+
714
+ # Create.
715
+ if self.begin is None:
716
+ conn = self.get_sess()
717
+ self.begin = conn.begin()
718
+
719
+ return self.begin
720
+
721
+
722
+ def commit(self) -> None:
723
+ """
724
+ Commit cumulative executions.
725
+ """
726
+
727
+ # Commit.
728
+ if self.begin is not None:
729
+ self.begin.commit()
730
+ self.begin = None
731
+
732
+
733
+ def rollback(self) -> None:
734
+ """
735
+ Rollback cumulative executions.
736
+ """
737
+
738
+ # Rollback.
739
+ if self.begin is not None:
740
+ self.begin.rollback()
741
+ self.begin = None
551
742
 
552
743
 
553
- __del__ = close
744
+ def close(self) -> None:
745
+ """
746
+ Close database session.
747
+ """
748
+
749
+ # Close.
750
+ if self.begin is not None:
751
+ self.begin.close()
752
+ self.begin = None
753
+ if self.sess is not None:
754
+ self.sess.close()
755
+ self.sess = None
554
756
 
555
757
 
556
758
  def wrap_transact(method: CallableT) -> CallableT:
@@ -572,12 +774,12 @@ class DatabaseORMSession(DatabaseORMBase):
572
774
  def wrap(self: 'DatabaseORMSession', *args, **kwargs):
573
775
 
574
776
  # Session.
575
- if self.session is None:
576
- self.session = Session(self.orm.db.engine)
777
+ if self.sess is None:
778
+ self.sess = Session(self.orm.db.engine)
577
779
 
578
780
  # Begin.
579
781
  if self.begin is None:
580
- self.begin = self.session.begin()
782
+ self.begin = self.sess.begin()
581
783
 
582
784
  # Execute.
583
785
  result = method(self, *args, **kwargs)
@@ -600,18 +802,26 @@ class DatabaseORMSession(DatabaseORMBase):
600
802
  skip: bool = False
601
803
  ) -> None:
602
804
  """
603
- Create table.
805
+ Create tables.
604
806
 
605
807
  Parameters
606
808
  ----------
607
809
  models : ORM model instances.
608
- check : Skip existing table.
810
+ skip : Whether skip existing table.
609
811
  """
610
812
 
813
+ # Handle parameter.
814
+ tables = [
815
+ model.table()
816
+ for model in models
817
+ ]
818
+
819
+ ## Check.
820
+ if None in tables:
821
+ throw(ValueError, tables)
822
+
611
823
  # Create.
612
- for model in models:
613
- table = model.table()
614
- table.create(self.session.connection(), checkfirst=skip)
824
+ self.orm.metaData.create_all(self.orm.db.engine, tables, skip)
615
825
 
616
826
 
617
827
  @wrap_transact
@@ -621,22 +831,30 @@ class DatabaseORMSession(DatabaseORMBase):
621
831
  skip: bool = False
622
832
  ) -> None:
623
833
  """
624
- Delete table.
834
+ Delete tables.
625
835
 
626
836
  Parameters
627
837
  ----------
628
838
  models : ORM model instances.
629
- check : Skip not exist table.
839
+ skip : Skip not exist table.
630
840
  """
631
841
 
632
- # Create.
633
- for model in models:
634
- table = model.table()
635
- table.drop(self.session.connection(), checkfirst=skip)
842
+ # Handle parameter.
843
+ tables = [
844
+ model.table()
845
+ for model in models
846
+ ]
847
+
848
+ ## Check.
849
+ if None in tables:
850
+ throw(ValueError, tables)
851
+
852
+ # Drop.
853
+ self.orm.metaData.drop_all(self.orm.db.engine, tables, skip)
636
854
 
637
855
 
638
856
  @wrap_transact
639
- def get(self, model: Type[ModelT] | ModelT, key: Any | tuple[Any]) -> ModelT | None:
857
+ def get(self, model: Type[DatabaseORMModelT] | DatabaseORMModelT, key: Any | tuple[Any]) -> DatabaseORMModelT | None:
640
858
  """
641
859
  Select records by primary key.
642
860
 
@@ -657,20 +875,20 @@ class DatabaseORMSession(DatabaseORMBase):
657
875
  model = type(model)
658
876
 
659
877
  # Get.
660
- result = self.session.get(model, key)
878
+ result = self.sess.get(model, key)
661
879
 
662
880
  # Autucommit.
663
881
  if (
664
882
  self.autocommit
665
883
  and result is not None
666
884
  ):
667
- self.session.expunge(result)
885
+ self.sess.expunge(result)
668
886
 
669
887
  return result
670
888
 
671
889
 
672
890
  @wrap_transact
673
- def gets(self, model: Type[ModelT] | ModelT, *keys: Any | tuple[Any]) -> list[ModelT]:
891
+ def gets(self, model: Type[DatabaseORMModelT] | DatabaseORMModelT, *keys: Any | tuple[Any]) -> list[DatabaseORMModelT]:
674
892
  """
675
893
  Select records by primary key sequence.
676
894
 
@@ -694,14 +912,14 @@ class DatabaseORMSession(DatabaseORMBase):
694
912
  results = [
695
913
  result
696
914
  for key in keys
697
- if (result := self.session.get(model, key)) is not None
915
+ if (result := self.sess.get(model, key)) is not None
698
916
  ]
699
917
 
700
918
  return results
701
919
 
702
920
 
703
921
  @wrap_transact
704
- def all(self, model: Type[ModelT] | ModelT) -> list[ModelT]:
922
+ def all(self, model: Type[DatabaseORMModelT] | DatabaseORMModelT) -> list[DatabaseORMModelT]:
705
923
  """
706
924
  Select all records.
707
925
 
@@ -720,7 +938,7 @@ class DatabaseORMSession(DatabaseORMBase):
720
938
 
721
939
  # Get.
722
940
  select = Select(model)
723
- models = self.session.exec(select)
941
+ models = self.sess.exec(select)
724
942
  models = list(models)
725
943
 
726
944
  return models
@@ -737,7 +955,7 @@ class DatabaseORMSession(DatabaseORMBase):
737
955
  """
738
956
 
739
957
  # Add.
740
- self.session.add_all(models)
958
+ self.sess.add_all(models)
741
959
 
742
960
 
743
961
  @wrap_transact
@@ -752,7 +970,7 @@ class DatabaseORMSession(DatabaseORMBase):
752
970
 
753
971
  # Delete.
754
972
  for model in models:
755
- self.session.delete(model)
973
+ self.sess.delete(model)
756
974
 
757
975
 
758
976
  @wrap_transact
@@ -767,7 +985,7 @@ class DatabaseORMSession(DatabaseORMBase):
767
985
 
768
986
  # Refresh.
769
987
  for model in models:
770
- self.session.refresh(model)
988
+ self.sess.refresh(model)
771
989
 
772
990
 
773
991
  @wrap_transact
@@ -782,115 +1000,387 @@ class DatabaseORMSession(DatabaseORMBase):
782
1000
 
783
1001
  # Refresh.
784
1002
  for model in models:
785
- self.session.expire(model)
1003
+ self.sess.expire(model)
1004
+
1005
+
1006
+ class DatabaseORMSessionAsync(
1007
+ DatabaseORMSessionSuper[
1008
+ DatabaseORMAsync,
1009
+ AsyncSession,
1010
+ AsyncSessionTransaction,
1011
+ 'DatabaseORMStatementSelectAsync',
1012
+ 'DatabaseORMStatementInsertAsync',
1013
+ 'DatabaseORMStatementUpdateAsync',
1014
+ 'DatabaseORMStatementDeleteAsync'
1015
+ ]
1016
+ ):
1017
+ """
1018
+ Asynchronous database ORM session type.
1019
+ """
786
1020
 
787
1021
 
788
- @wrap_transact
789
- def select(self, model: Type[ModelT] | ModelT):
1022
+ async def __aenter__(self) -> Self:
1023
+ """
1024
+ Asynchronous enter syntax `with`.
1025
+
1026
+ Returns
1027
+ -------
1028
+ Self.
1029
+ """
1030
+
1031
+ return self
1032
+
1033
+
1034
+ async def __aexit__(
1035
+ self,
1036
+ exc_type: type[BaseException] | None,
1037
+ *_
1038
+ ) -> None:
790
1039
  """
791
- Build `DatabaseORMSelect` instance.
1040
+ Asynchronous exit syntax `with`.
792
1041
 
793
1042
  Parameters
794
1043
  ----------
795
- model : ORM model instance.
1044
+ exc_type : Exception type.
1045
+ """
1046
+
1047
+ # Commit.
1048
+ if exc_type is None:
1049
+ await self.commit()
1050
+
1051
+ # Close.
1052
+ await self.close()
1053
+ await self.orm.db.dispose()
1054
+
1055
+
1056
+ def get_sess(self) -> AsyncSession:
1057
+ """
1058
+ Get `AsyncSession` instance.
796
1059
 
797
1060
  Returns
798
1061
  -------
799
1062
  Instance.
800
1063
  """
801
1064
 
1065
+ # Create.
1066
+ if self.sess is None:
1067
+ self.sess = AsyncSession(self.orm.db.engine)
1068
+
1069
+ return self.sess
1070
+
1071
+
1072
+ async def get_begin(self) -> AsyncSessionTransaction:
1073
+ """
1074
+ Asynchronous get `AsyncSessionTransaction` instance.
1075
+
1076
+ Returns
1077
+ -------
1078
+ Instance.
1079
+ """
1080
+
1081
+ # Create.
1082
+ if self.begin is None:
1083
+ sess = self.get_sess()
1084
+ self.begin = await sess.begin()
1085
+
1086
+ return self.begin
1087
+
1088
+
1089
+ async def commit(self) -> None:
1090
+ """
1091
+ Asynchronous commit cumulative executions.
1092
+ """
1093
+
1094
+ # Commit.
1095
+ if self.begin is not None:
1096
+ await self.begin.commit()
1097
+ self.begin = None
1098
+
1099
+
1100
+ async def rollback(self) -> None:
1101
+ """
1102
+ Asynchronous rollback cumulative executions.
1103
+ """
1104
+
1105
+ # Rollback.
1106
+ if self.begin is not None:
1107
+ await self.begin.rollback()
1108
+ self.begin = None
1109
+
1110
+
1111
+ async def close(self) -> None:
1112
+ """
1113
+ Asynchronous close database session.
1114
+ """
1115
+
1116
+ # Close.
1117
+ if self.begin is not None:
1118
+ await self.begin.rollback()
1119
+ self.begin = None
1120
+ if self.sess is not None:
1121
+ await self.sess.close()
1122
+ self.sess = None
1123
+
1124
+
1125
+ def wrap_transact(method: CallableT) -> CallableT:
1126
+ """
1127
+ Asynchronous decorator, automated transaction.
1128
+
1129
+ Parameters
1130
+ ----------
1131
+ method : Method.
1132
+
1133
+ Returns
1134
+ -------
1135
+ Decorated method.
1136
+ """
1137
+
1138
+
1139
+ # Define.
1140
+ @functools_wraps(method)
1141
+ async def wrap(self: 'DatabaseORMSessionAsync', *args, **kwargs):
1142
+
1143
+ # Transaction.
1144
+ await self.get_begin()
1145
+
1146
+ # Execute.
1147
+ if inspect_iscoroutinefunction(method):
1148
+ result = await method(self, *args, **kwargs)
1149
+ else:
1150
+ result = method(self, *args, **kwargs)
1151
+
1152
+ # Automatic commit.
1153
+ if self.autocommit:
1154
+ await self.commit()
1155
+ await self.close()
1156
+ await self.orm.db.dispose()
1157
+
1158
+ return result
1159
+
1160
+
1161
+ return wrap
1162
+
1163
+
1164
+ @wrap_transact
1165
+ async def create(
1166
+ self,
1167
+ *models: Type[DatabaseORMModel] | DatabaseORMModel,
1168
+ skip: bool = False
1169
+ ) -> None:
1170
+ """
1171
+ Asynchronous create tables.
1172
+
1173
+ Parameters
1174
+ ----------
1175
+ models : ORM model instances.
1176
+ skip : Whether skip existing table.
1177
+ """
1178
+
802
1179
  # Handle parameter.
803
- if is_instance(model):
804
- model = type(model)
1180
+ tables = [
1181
+ model.table()
1182
+ for model in models
1183
+ ]
805
1184
 
806
- # Build.
807
- select = DatabaseORMStatementSelect[ModelT](self, model)
1185
+ ## Check.
1186
+ if None in tables:
1187
+ throw(ValueError, tables)
808
1188
 
809
- return select
1189
+ # Create.
1190
+ conn = await self.sess.connection()
1191
+ await conn.run_sync(self.orm.metaData.create_all, tables, skip)
1192
+
1193
+
1194
+ @wrap_transact
1195
+ async def drop(
1196
+ self,
1197
+ *models: Type[DatabaseORMModel] | DatabaseORMModel,
1198
+ skip: bool = False
1199
+ ) -> None:
1200
+ """
1201
+ Asynchronous delete tables.
1202
+
1203
+ Parameters
1204
+ ----------
1205
+ models : ORM model instances.
1206
+ skip : Skip not exist table.
1207
+ """
1208
+
1209
+ # Handle parameter.
1210
+ tables = [
1211
+ model.table()
1212
+ for model in models
1213
+ ]
1214
+
1215
+ ## Check.
1216
+ if None in tables:
1217
+ throw(ValueError, tables)
1218
+
1219
+ # Drop.
1220
+ conn = await self.sess.connection()
1221
+ await conn.run_sync(self.orm.metaData.drop_all, tables, skip)
810
1222
 
811
1223
 
812
1224
  @wrap_transact
813
- def insert(self, model: Type[ModelT] | ModelT):
1225
+ async def get(self, model: Type[DatabaseORMModelT] | DatabaseORMModelT, key: Any | tuple[Any]) -> DatabaseORMModelT | None:
814
1226
  """
815
- Build `DatabaseORMInsert` instance.
1227
+ Asynchronous select records by primary key.
816
1228
 
817
1229
  Parameters
818
1230
  ----------
819
- model : ORM model instance.
1231
+ model : ORM model type or instance.
1232
+ key : Primary key.
1233
+ - `Any`: Single primary key.
1234
+ - `tuple[Any]`: Composite primary key.
820
1235
 
821
1236
  Returns
822
1237
  -------
823
- Instance.
1238
+ With records ORM model instance or null.
824
1239
  """
825
1240
 
826
1241
  # Handle parameter.
827
1242
  if is_instance(model):
828
1243
  model = type(model)
829
1244
 
830
- # Build.
831
- select = DatabaseORMStatementInsert[ModelT](self, model)
1245
+ # Get.
1246
+ result = await self.sess.get(model, key)
832
1247
 
833
- return select
1248
+ # Autucommit.
1249
+ if (
1250
+ self.autocommit
1251
+ and result is not None
1252
+ ):
1253
+ self.sess.expunge(result)
1254
+
1255
+ return result
834
1256
 
835
1257
 
836
1258
  @wrap_transact
837
- def update(self, model: Type[ModelT] | ModelT):
1259
+ async def gets(self, model: Type[DatabaseORMModelT] | DatabaseORMModelT, *keys: Any | tuple[Any]) -> list[DatabaseORMModelT]:
838
1260
  """
839
- Build `DatabaseORMUpdate` instance.
1261
+ Asynchronous select records by primary key sequence.
840
1262
 
841
1263
  Parameters
842
1264
  ----------
843
- model : ORM model instance.
1265
+ model : ORM model type or instance.
1266
+ keys : Primary key sequence.
1267
+ - `Any`: Single primary key.
1268
+ - `tuple[Any]`: Composite primary key.
844
1269
 
845
1270
  Returns
846
1271
  -------
847
- Instance.
1272
+ With records ORM model instance list.
848
1273
  """
849
1274
 
850
1275
  # Handle parameter.
851
1276
  if is_instance(model):
852
1277
  model = type(model)
853
1278
 
854
- # Build.
855
- select = DatabaseORMStatementUpdate[ModelT](self, model)
1279
+ # Get.
1280
+ results = [
1281
+ result
1282
+ for key in keys
1283
+ if (result := await self.sess.get(model, key)) is not None
1284
+ ]
856
1285
 
857
- return select
1286
+ return results
858
1287
 
859
1288
 
860
1289
  @wrap_transact
861
- def delete(self, model: Type[ModelT] | ModelT):
1290
+ async def all(self, model: Type[DatabaseORMModelT] | DatabaseORMModelT) -> list[DatabaseORMModelT]:
862
1291
  """
863
- Build `DatabaseORMDelete` instance.
1292
+ Asynchronous select all records.
864
1293
 
865
1294
  Parameters
866
1295
  ----------
867
- model : ORM model instance.
1296
+ model : ORM model type or instance.
868
1297
 
869
1298
  Returns
870
1299
  -------
871
- Instance.
1300
+ With records ORM model instance list.
872
1301
  """
873
1302
 
874
1303
  # Handle parameter.
875
1304
  if is_instance(model):
876
1305
  model = type(model)
877
1306
 
878
- # Build.
879
- select = DatabaseORMStatementDelete[ModelT](self, model)
1307
+ # Get.
1308
+ select = Select(model)
1309
+ models = await self.sess.exec(select)
1310
+ models = list(models)
880
1311
 
881
- return select
1312
+ return models
882
1313
 
883
1314
 
884
- class DatabaseORMStatement(DatabaseORMBase):
1315
+ @wrap_transact
1316
+ async def add(self, *models: DatabaseORMModel) -> None:
1317
+ """
1318
+ Asynchronous insert records.
1319
+
1320
+ Parameters
1321
+ ----------
1322
+ models : ORM model instances.
1323
+ """
1324
+
1325
+ # Add.
1326
+ self.sess.add_all(models)
1327
+
1328
+
1329
+ @wrap_transact
1330
+ async def rm(self, *models: DatabaseORMModel) -> None:
1331
+ """
1332
+ Asynchronous delete records.
1333
+
1334
+ Parameters
1335
+ ----------
1336
+ models : ORM model instances.
1337
+ """
1338
+
1339
+ # Delete.
1340
+ for model in models:
1341
+ await self.sess.delete(model)
1342
+
1343
+
1344
+ @wrap_transact
1345
+ async def refresh(self, *models: DatabaseORMModel) -> None:
1346
+ """
1347
+ Asynchronous refresh records.
1348
+
1349
+ Parameters
1350
+ ----------
1351
+ models : ORM model instances.
1352
+ """
1353
+
1354
+ # Refresh.
1355
+ for model in models:
1356
+ await self.sess.refresh(model)
1357
+
1358
+
1359
+ @wrap_transact
1360
+ async def expire(self, *models: DatabaseORMModel) -> None:
1361
+ """
1362
+ Asynchronous mark records to expire, refresh on next call.
1363
+
1364
+ Parameters
1365
+ ----------
1366
+ models : ORM model instances.
1367
+ """
1368
+
1369
+ # Refresh.
1370
+ for model in models:
1371
+ self.sess.expire(model)
1372
+
1373
+
1374
+ class DatabaseORMStatementSuper(DatabaseORMBase, Generic[DatabaseORMSessionT]):
885
1375
  """
886
- Database ORM statement type.
1376
+ Database ORM statement super type.
887
1377
  """
888
1378
 
889
1379
 
890
1380
  def __init__(
891
1381
  self,
892
- sess: DatabaseORMSession,
893
- model: Type[ModelT]
1382
+ sess: DatabaseORMSessionT,
1383
+ model: Type[DatabaseORMModelT]
894
1384
  ) -> None:
895
1385
  """
896
1386
  Build instance attributes.
@@ -902,23 +1392,77 @@ class DatabaseORMStatement(DatabaseORMBase):
902
1392
  """
903
1393
 
904
1394
  # Super.
905
- super().__init__(self.model)
1395
+ super().__init__(model)
906
1396
 
907
1397
  # Build.
908
1398
  self.sess = sess
909
1399
  self.model = model
910
1400
 
911
1401
 
912
- def execute(self) -> None:
1402
+ class DatabaseORMStatement(DatabaseORMStatementSuper[DatabaseORMSession], Generic[DatabaseORMStatementReturn]):
1403
+ """
1404
+ Database ORM statement type.
1405
+ """
1406
+
1407
+
1408
+ def execute(self) -> DatabaseORMStatementReturn:
913
1409
  """
914
1410
  Execute statement.
915
1411
  """
916
1412
 
1413
+ # Transaction.
1414
+ self.sess.get_begin()
1415
+
917
1416
  # Execute.
918
- self.sess.session.exec(self)
1417
+ result = self.sess.sess.exec(self)
1418
+
1419
+ ## Select.
1420
+ if isinstance(self, Select):
1421
+ result = list(result)
1422
+ else:
1423
+ result = None
919
1424
 
1425
+ # Automatic commit.
1426
+ if self.sess.autocommit:
1427
+ self.sess.commit()
1428
+ self.sess.close()
920
1429
 
921
- class DatabaseORMStatementSelect(DatabaseORMStatement, Select, Generic[ModelT]):
1430
+ return result
1431
+
1432
+
1433
+ class DatabaseORMStatementAsync(DatabaseORMStatementSuper[DatabaseORMSessionAsync], Generic[DatabaseORMStatementReturn]):
1434
+ """
1435
+ Asynchronous dtabase ORM statement type.
1436
+ """
1437
+
1438
+
1439
+ async def execute(self) -> DatabaseORMStatementReturn:
1440
+ """
1441
+ Asynchronous execute statement.
1442
+ """
1443
+
1444
+ # Transaction.
1445
+ await self.sess.get_begin()
1446
+
1447
+ # Execute.
1448
+ result = await self.sess.sess.exec(self)
1449
+
1450
+ ## Select.
1451
+ if isinstance(self, Select):
1452
+ result = list(result)
1453
+ else:
1454
+ result = None
1455
+
1456
+ # Automatic commit.
1457
+ if self.sess.autocommit:
1458
+ await self.sess.commit()
1459
+ await self.sess.close()
1460
+ await self.sess.orm.db.dispose()
1461
+
1462
+ return result
1463
+
1464
+
1465
+ class DatabaseORMStatementSelect(DatabaseORMStatement[list[DatabaseORMModelT]], Select, Generic[DatabaseORMModelT]):
922
1466
  """
923
1467
  Database ORM `select` statement type.
924
1468
 
@@ -930,25 +1474,45 @@ class DatabaseORMStatementSelect(DatabaseORMStatement, Select, Generic[ModelT]):
930
1474
  inherit_cache: Final = True
931
1475
 
932
1476
 
933
- def execute(self) -> list[ModelT]:
934
- """
935
- Execute self statement.
1477
+ class DatabaseORMStatementInsert(DatabaseORMStatement[None], Insert, Generic[DatabaseORMModelT]):
1478
+ """
1479
+ Database ORM `insert` statement type.
936
1480
 
937
- Returns
938
- -------
939
- With records ORM model instance list.
940
- """
1481
+ Attributes
1482
+ ----------
1483
+ inherit_cache : Compatible `Select` type.
1484
+ """
941
1485
 
942
- # Execute.
943
- result = self.sess.session.exec(self)
944
- models = list(result)
1486
+ inherit_cache: Final = True
945
1487
 
946
- return models
947
1488
 
1489
+ class DatabaseORMStatementUpdate(DatabaseORMStatement[None], Update, Generic[DatabaseORMModelT]):
1490
+ """
1491
+ Database ORM `update` statement type.
948
1492
 
949
- class DatabaseORMStatementInsert(Generic[ModelT], DatabaseORMStatement, Insert):
1493
+ Attributes
1494
+ ----------
1495
+ inherit_cache : Compatible `Update` type.
950
1496
  """
951
- Database ORM `insert` statement type.
1497
+
1498
+ inherit_cache: Final = True
1499
+
1500
+
1501
+ class DatabaseORMStatementDelete(DatabaseORMStatement[None], Delete, Generic[DatabaseORMModelT]):
1502
+ """
1503
+ Database ORM `delete` statement type.
1504
+
1505
+ Attributes
1506
+ ----------
1507
+ inherit_cache : Compatible `Delete` type.
1508
+ """
1509
+
1510
+ inherit_cache: Final = True
1511
+
1512
+
1513
+ class DatabaseORMStatementSelectAsync(DatabaseORMStatementAsync[list[DatabaseORMModelT]], Select, Generic[DatabaseORMModelT]):
1514
+ """
1515
+ Asynchronous database ORM `select` statement type.
952
1516
 
953
1517
  Attributes
954
1518
  ----------
@@ -958,9 +1522,21 @@ class DatabaseORMStatementInsert(Generic[ModelT], DatabaseORMStatement, Insert):
958
1522
  inherit_cache: Final = True
959
1523
 
960
1524
 
961
- class DatabaseORMStatementUpdate(Generic[ModelT], DatabaseORMStatement, Update):
1525
+ class DatabaseORMStatementInsertAsync(DatabaseORMStatementAsync[None], Insert, Generic[DatabaseORMModelT]):
962
1526
  """
963
- Database ORM `update` statement type.
1527
+ Asynchronous database ORM `insert` statement type.
1528
+
1529
+ Attributes
1530
+ ----------
1531
+ inherit_cache : Compatible `Select` type.
1532
+ """
1533
+
1534
+ inherit_cache: Final = True
1535
+
1536
+
1537
+ class DatabaseORMStatementUpdateAsync(DatabaseORMStatementAsync[None], Update, Generic[DatabaseORMModelT]):
1538
+ """
1539
+ Asynchronous database ORM `update` statement type.
964
1540
 
965
1541
  Attributes
966
1542
  ----------
@@ -970,9 +1546,9 @@ class DatabaseORMStatementUpdate(Generic[ModelT], DatabaseORMStatement, Update):
970
1546
  inherit_cache: Final = True
971
1547
 
972
1548
 
973
- class DatabaseORMStatementDelete(Generic[ModelT], DatabaseORMStatement, Delete):
1549
+ class DatabaseORMStatementDeleteAsync(DatabaseORMStatementAsync[None], Delete, Generic[DatabaseORMModelT]):
974
1550
  """
975
- Database ORM `delete` statement type.
1551
+ Asynchronous database ORM `delete` statement type.
976
1552
 
977
1553
  Attributes
978
1554
  ----------