piccolo 1.27.1__py3-none-any.whl → 1.29.0__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.
Files changed (132) hide show
  1. piccolo/__init__.py +1 -1
  2. piccolo/apps/app/commands/new.py +3 -3
  3. piccolo/apps/asgi/commands/new.py +2 -3
  4. piccolo/apps/asgi/commands/templates/app/_blacksheep_app.py.jinja +57 -29
  5. piccolo/apps/asgi/commands/templates/app/_esmerald_app.py.jinja +48 -21
  6. piccolo/apps/asgi/commands/templates/app/_falcon_app.py.jinja +63 -8
  7. piccolo/apps/asgi/commands/templates/app/_fastapi_app.py.jinja +51 -24
  8. piccolo/apps/asgi/commands/templates/app/_litestar_app.py.jinja +34 -10
  9. piccolo/apps/asgi/commands/templates/app/_quart_app.py.jinja +38 -15
  10. piccolo/apps/asgi/commands/templates/app/_sanic_app.py.jinja +34 -11
  11. piccolo/apps/fixtures/commands/dump.py +8 -8
  12. piccolo/apps/fixtures/commands/load.py +5 -5
  13. piccolo/apps/fixtures/commands/shared.py +9 -9
  14. piccolo/apps/migrations/auto/diffable_table.py +12 -12
  15. piccolo/apps/migrations/auto/migration_manager.py +59 -66
  16. piccolo/apps/migrations/auto/operations.py +14 -14
  17. piccolo/apps/migrations/auto/schema_differ.py +35 -34
  18. piccolo/apps/migrations/auto/schema_snapshot.py +3 -4
  19. piccolo/apps/migrations/auto/serialisation.py +27 -24
  20. piccolo/apps/migrations/auto/serialisation_legacy.py +2 -2
  21. piccolo/apps/migrations/commands/backwards.py +1 -2
  22. piccolo/apps/migrations/commands/base.py +12 -12
  23. piccolo/apps/migrations/commands/check.py +2 -3
  24. piccolo/apps/migrations/commands/clean.py +3 -3
  25. piccolo/apps/migrations/commands/forwards.py +1 -2
  26. piccolo/apps/migrations/commands/new.py +6 -6
  27. piccolo/apps/migrations/tables.py +3 -3
  28. piccolo/apps/playground/commands/run.py +72 -13
  29. piccolo/apps/schema/commands/generate.py +49 -49
  30. piccolo/apps/schema/commands/graph.py +5 -5
  31. piccolo/apps/shell/commands/run.py +1 -2
  32. piccolo/apps/sql_shell/commands/run.py +4 -4
  33. piccolo/apps/tester/commands/run.py +3 -3
  34. piccolo/apps/user/commands/change_permissions.py +6 -6
  35. piccolo/apps/user/commands/create.py +7 -7
  36. piccolo/apps/user/commands/list.py +2 -2
  37. piccolo/apps/user/tables.py +8 -8
  38. piccolo/columns/base.py +84 -52
  39. piccolo/columns/choices.py +2 -2
  40. piccolo/columns/column_types.py +299 -177
  41. piccolo/columns/combination.py +15 -12
  42. piccolo/columns/defaults/base.py +4 -4
  43. piccolo/columns/defaults/date.py +4 -3
  44. piccolo/columns/defaults/interval.py +4 -3
  45. piccolo/columns/defaults/time.py +4 -3
  46. piccolo/columns/defaults/timestamp.py +4 -3
  47. piccolo/columns/defaults/timestamptz.py +4 -3
  48. piccolo/columns/defaults/uuid.py +3 -2
  49. piccolo/columns/m2m.py +28 -35
  50. piccolo/columns/readable.py +4 -3
  51. piccolo/columns/reference.py +9 -9
  52. piccolo/conf/apps.py +53 -54
  53. piccolo/custom_types.py +28 -6
  54. piccolo/engine/base.py +14 -14
  55. piccolo/engine/cockroach.py +5 -4
  56. piccolo/engine/finder.py +2 -2
  57. piccolo/engine/postgres.py +20 -19
  58. piccolo/engine/sqlite.py +23 -22
  59. piccolo/query/base.py +30 -29
  60. piccolo/query/functions/__init__.py +12 -0
  61. piccolo/query/functions/aggregate.py +4 -3
  62. piccolo/query/functions/array.py +151 -0
  63. piccolo/query/functions/base.py +3 -3
  64. piccolo/query/functions/datetime.py +22 -22
  65. piccolo/query/functions/string.py +4 -4
  66. piccolo/query/functions/type_conversion.py +30 -15
  67. piccolo/query/methods/alter.py +47 -46
  68. piccolo/query/methods/count.py +11 -10
  69. piccolo/query/methods/create.py +6 -5
  70. piccolo/query/methods/create_index.py +9 -8
  71. piccolo/query/methods/delete.py +7 -6
  72. piccolo/query/methods/drop_index.py +7 -6
  73. piccolo/query/methods/exists.py +6 -5
  74. piccolo/query/methods/indexes.py +4 -4
  75. piccolo/query/methods/insert.py +21 -14
  76. piccolo/query/methods/objects.py +60 -50
  77. piccolo/query/methods/raw.py +7 -6
  78. piccolo/query/methods/refresh.py +8 -7
  79. piccolo/query/methods/select.py +56 -49
  80. piccolo/query/methods/table_exists.py +5 -5
  81. piccolo/query/methods/update.py +8 -7
  82. piccolo/query/mixins.py +56 -61
  83. piccolo/query/operators/json.py +11 -11
  84. piccolo/query/proxy.py +8 -9
  85. piccolo/querystring.py +14 -15
  86. piccolo/schema.py +10 -10
  87. piccolo/table.py +105 -98
  88. piccolo/table_reflection.py +9 -9
  89. piccolo/testing/model_builder.py +16 -13
  90. piccolo/testing/random_builder.py +14 -2
  91. piccolo/testing/test_case.py +4 -4
  92. piccolo/utils/dictionary.py +3 -3
  93. piccolo/utils/encoding.py +5 -5
  94. piccolo/utils/lazy_loader.py +3 -3
  95. piccolo/utils/list.py +7 -8
  96. piccolo/utils/objects.py +4 -6
  97. piccolo/utils/pydantic.py +21 -24
  98. piccolo/utils/sql_values.py +3 -3
  99. piccolo/utils/sync.py +4 -3
  100. piccolo/utils/warnings.py +1 -2
  101. {piccolo-1.27.1.dist-info → piccolo-1.29.0.dist-info}/METADATA +1 -1
  102. {piccolo-1.27.1.dist-info → piccolo-1.29.0.dist-info}/RECORD +132 -131
  103. tests/apps/fixtures/commands/test_dump_load.py +1 -2
  104. tests/apps/migrations/auto/integration/test_migrations.py +32 -7
  105. tests/apps/migrations/auto/test_migration_manager.py +2 -2
  106. tests/apps/migrations/auto/test_schema_differ.py +22 -23
  107. tests/apps/migrations/commands/test_forwards_backwards.py +3 -3
  108. tests/columns/m2m/base.py +20 -49
  109. tests/columns/test_array.py +176 -10
  110. tests/columns/test_boolean.py +2 -4
  111. tests/columns/test_combination.py +29 -1
  112. tests/columns/test_db_column_name.py +2 -2
  113. tests/engine/test_extra_nodes.py +2 -2
  114. tests/engine/test_pool.py +3 -3
  115. tests/engine/test_transaction.py +4 -4
  116. tests/query/test_freeze.py +4 -4
  117. tests/table/instance/test_get_related.py +2 -2
  118. tests/table/test_alter.py +4 -4
  119. tests/table/test_indexes.py +1 -2
  120. tests/table/test_metaclass.py +7 -3
  121. tests/table/test_refresh.py +2 -2
  122. tests/table/test_select.py +58 -0
  123. tests/table/test_str.py +30 -22
  124. tests/table/test_update.py +18 -3
  125. tests/testing/test_model_builder.py +1 -2
  126. tests/testing/test_random_builder.py +5 -0
  127. tests/utils/test_pydantic.py +152 -134
  128. tests/utils/test_table_reflection.py +1 -2
  129. {piccolo-1.27.1.dist-info → piccolo-1.29.0.dist-info}/WHEEL +0 -0
  130. {piccolo-1.27.1.dist-info → piccolo-1.29.0.dist-info}/entry_points.txt +0 -0
  131. {piccolo-1.27.1.dist-info → piccolo-1.29.0.dist-info}/licenses/LICENSE +0 -0
  132. {piccolo-1.27.1.dist-info → piccolo-1.29.0.dist-info}/top_level.txt +0 -0
@@ -29,11 +29,21 @@ from __future__ import annotations
29
29
  import copy
30
30
  import decimal
31
31
  import inspect
32
- import typing as t
33
32
  import uuid
33
+ from collections.abc import Callable
34
34
  from dataclasses import dataclass
35
35
  from datetime import date, datetime, time, timedelta
36
36
  from enum import Enum
37
+ from typing import (
38
+ TYPE_CHECKING,
39
+ Any,
40
+ Generic,
41
+ Literal,
42
+ Optional,
43
+ Union,
44
+ cast,
45
+ overload,
46
+ )
37
47
 
38
48
  from typing_extensions import Unpack
39
49
 
@@ -71,8 +81,9 @@ from piccolo.querystring import QueryString
71
81
  from piccolo.utils.encoding import dump_json
72
82
  from piccolo.utils.warnings import colored_warning
73
83
 
74
- if t.TYPE_CHECKING: # pragma: no cover
84
+ if TYPE_CHECKING: # pragma: no cover
75
85
  from piccolo.columns.base import ColumnMeta
86
+ from piccolo.query.functions.array import ArrayItemType, ArrayType
76
87
  from piccolo.query.operators.json import (
77
88
  GetChildElement,
78
89
  GetElementFromPath,
@@ -94,7 +105,7 @@ class ConcatDelegate:
94
105
  def get_querystring(
95
106
  self,
96
107
  column: Column,
97
- value: t.Union[str, Column, QueryString],
108
+ value: Union[str, Column, QueryString],
98
109
  reverse: bool = False,
99
110
  ) -> QueryString:
100
111
  """
@@ -137,8 +148,8 @@ class MathDelegate:
137
148
  def get_querystring(
138
149
  self,
139
150
  column_name: str,
140
- operator: t.Literal["+", "-", "/", "*"],
141
- value: t.Union[int, float, Integer],
151
+ operator: Literal["+", "-", "/", "*"],
152
+ value: Union[int, float, Integer],
142
153
  reverse: bool = False,
143
154
  ) -> QueryString:
144
155
  if isinstance(value, Integer):
@@ -147,8 +158,8 @@ class MathDelegate:
147
158
  raise ValueError(
148
159
  "Adding values across joins isn't currently supported."
149
160
  )
150
- column_name = column._meta.db_column_name
151
- return QueryString(f"{column_name} {operator} {column_name}")
161
+ other_column_name = value._meta.db_column_name
162
+ return QueryString(f"{column_name} {operator} {other_column_name}")
152
163
  elif isinstance(value, (int, float)):
153
164
  if reverse:
154
165
  return QueryString(f"{{}} {operator} {column_name}", value)
@@ -184,7 +195,7 @@ class TimedeltaDelegate:
184
195
 
185
196
  # Maps the attribute name in Python's timedelta to what it's called in
186
197
  # Postgres.
187
- postgres_attr_map: t.Dict[str, str] = {
198
+ postgres_attr_map: dict[str, str] = {
188
199
  "days": "DAYS",
189
200
  "seconds": "SECONDS",
190
201
  "microseconds": "MICROSECONDS",
@@ -233,7 +244,7 @@ class TimedeltaDelegate:
233
244
  def get_querystring(
234
245
  self,
235
246
  column: Column,
236
- operator: t.Literal["+", "-"],
247
+ operator: Literal["+", "-"],
237
248
  value: timedelta,
238
249
  engine_type: str,
239
250
  ) -> QueryString:
@@ -318,8 +329,8 @@ class Varchar(Column):
318
329
 
319
330
  def __init__(
320
331
  self,
321
- length: t.Optional[int] = 255,
322
- default: t.Union[str, Enum, t.Callable[[], str], None] = "",
332
+ length: Optional[int] = 255,
333
+ default: Union[str, Enum, Callable[[], str], None] = "",
323
334
  **kwargs: Unpack[ColumnKwargs],
324
335
  ) -> None:
325
336
  self._validate_default(default, (str, None))
@@ -335,13 +346,13 @@ class Varchar(Column):
335
346
  ###########################################################################
336
347
  # For update queries
337
348
 
338
- def __add__(self, value: t.Union[str, Varchar, Text]) -> QueryString:
349
+ def __add__(self, value: Union[str, Varchar, Text]) -> QueryString:
339
350
  return self.concat_delegate.get_querystring(
340
351
  column=self,
341
352
  value=value,
342
353
  )
343
354
 
344
- def __radd__(self, value: t.Union[str, Varchar, Text]) -> QueryString:
355
+ def __radd__(self, value: Union[str, Varchar, Text]) -> QueryString:
345
356
  return self.concat_delegate.get_querystring(
346
357
  column=self,
347
358
  value=value,
@@ -351,16 +362,16 @@ class Varchar(Column):
351
362
  ###########################################################################
352
363
  # Descriptors
353
364
 
354
- @t.overload
365
+ @overload
355
366
  def __get__(self, obj: Table, objtype=None) -> str: ...
356
367
 
357
- @t.overload
368
+ @overload
358
369
  def __get__(self, obj: None, objtype=None) -> Varchar: ...
359
370
 
360
371
  def __get__(self, obj, objtype=None):
361
372
  return obj.__dict__[self._meta.name] if obj else self
362
373
 
363
- def __set__(self, obj, value: t.Union[str, None]):
374
+ def __set__(self, obj, value: Union[str, None]):
364
375
  obj.__dict__[self._meta.name] = value
365
376
 
366
377
 
@@ -388,16 +399,16 @@ class Secret(Varchar):
388
399
  ###########################################################################
389
400
  # Descriptors
390
401
 
391
- @t.overload
402
+ @overload
392
403
  def __get__(self, obj: Table, objtype=None) -> str: ...
393
404
 
394
- @t.overload
405
+ @overload
395
406
  def __get__(self, obj: None, objtype=None) -> Secret: ...
396
407
 
397
408
  def __get__(self, obj, objtype=None):
398
409
  return obj.__dict__[self._meta.name] if obj else self
399
410
 
400
- def __set__(self, obj, value: t.Union[str, None]):
411
+ def __set__(self, obj, value: Union[str, None]):
401
412
  obj.__dict__[self._meta.name] = value
402
413
 
403
414
 
@@ -427,7 +438,7 @@ class Text(Column):
427
438
 
428
439
  def __init__(
429
440
  self,
430
- default: t.Union[str, Enum, None, t.Callable[[], str]] = "",
441
+ default: Union[str, Enum, None, Callable[[], str]] = "",
431
442
  **kwargs: Unpack[ColumnKwargs],
432
443
  ) -> None:
433
444
  self._validate_default(default, (str, None))
@@ -437,13 +448,13 @@ class Text(Column):
437
448
  ###########################################################################
438
449
  # For update queries
439
450
 
440
- def __add__(self, value: t.Union[str, Varchar, Text]) -> QueryString:
451
+ def __add__(self, value: Union[str, Varchar, Text]) -> QueryString:
441
452
  return self.concat_delegate.get_querystring(
442
453
  column=self,
443
454
  value=value,
444
455
  )
445
456
 
446
- def __radd__(self, value: t.Union[str, Varchar, Text]) -> QueryString:
457
+ def __radd__(self, value: Union[str, Varchar, Text]) -> QueryString:
447
458
  return self.concat_delegate.get_querystring(
448
459
  column=self,
449
460
  value=value,
@@ -453,16 +464,16 @@ class Text(Column):
453
464
  ###########################################################################
454
465
  # Descriptors
455
466
 
456
- @t.overload
467
+ @overload
457
468
  def __get__(self, obj: Table, objtype=None) -> str: ...
458
469
 
459
- @t.overload
470
+ @overload
460
471
  def __get__(self, obj: None, objtype=None) -> Text: ...
461
472
 
462
473
  def __get__(self, obj, objtype=None):
463
474
  return obj.__dict__[self._meta.name] if obj else self
464
475
 
465
- def __set__(self, obj, value: t.Union[str, None]):
476
+ def __set__(self, obj, value: Union[str, None]):
466
477
  obj.__dict__[self._meta.name] = value
467
478
 
468
479
 
@@ -519,16 +530,16 @@ class UUID(Column):
519
530
  ###########################################################################
520
531
  # Descriptors
521
532
 
522
- @t.overload
533
+ @overload
523
534
  def __get__(self, obj: Table, objtype=None) -> uuid.UUID: ...
524
535
 
525
- @t.overload
536
+ @overload
526
537
  def __get__(self, obj: None, objtype=None) -> UUID: ...
527
538
 
528
539
  def __get__(self, obj, objtype=None):
529
540
  return obj.__dict__[self._meta.name] if obj else self
530
541
 
531
- def __set__(self, obj, value: t.Union[uuid.UUID, None]):
542
+ def __set__(self, obj, value: Union[uuid.UUID, None]):
532
543
  obj.__dict__[self._meta.name] = value
533
544
 
534
545
 
@@ -556,7 +567,7 @@ class Integer(Column):
556
567
 
557
568
  def __init__(
558
569
  self,
559
- default: t.Union[int, Enum, t.Callable[[], int], None] = 0,
570
+ default: Union[int, Enum, Callable[[], int], None] = 0,
560
571
  **kwargs: Unpack[ColumnKwargs],
561
572
  ) -> None:
562
573
  self._validate_default(default, (int, None))
@@ -566,12 +577,12 @@ class Integer(Column):
566
577
  ###########################################################################
567
578
  # For update queries
568
579
 
569
- def __add__(self, value: t.Union[int, float, Integer]) -> QueryString:
580
+ def __add__(self, value: Union[int, float, Integer]) -> QueryString:
570
581
  return self.math_delegate.get_querystring(
571
582
  column_name=self._meta.db_column_name, operator="+", value=value
572
583
  )
573
584
 
574
- def __radd__(self, value: t.Union[int, float, Integer]) -> QueryString:
585
+ def __radd__(self, value: Union[int, float, Integer]) -> QueryString:
575
586
  return self.math_delegate.get_querystring(
576
587
  column_name=self._meta.db_column_name,
577
588
  operator="+",
@@ -579,12 +590,12 @@ class Integer(Column):
579
590
  reverse=True,
580
591
  )
581
592
 
582
- def __sub__(self, value: t.Union[int, float, Integer]) -> QueryString:
593
+ def __sub__(self, value: Union[int, float, Integer]) -> QueryString:
583
594
  return self.math_delegate.get_querystring(
584
595
  column_name=self._meta.db_column_name, operator="-", value=value
585
596
  )
586
597
 
587
- def __rsub__(self, value: t.Union[int, float, Integer]) -> QueryString:
598
+ def __rsub__(self, value: Union[int, float, Integer]) -> QueryString:
588
599
  return self.math_delegate.get_querystring(
589
600
  column_name=self._meta.db_column_name,
590
601
  operator="-",
@@ -592,12 +603,12 @@ class Integer(Column):
592
603
  reverse=True,
593
604
  )
594
605
 
595
- def __mul__(self, value: t.Union[int, float, Integer]) -> QueryString:
606
+ def __mul__(self, value: Union[int, float, Integer]) -> QueryString:
596
607
  return self.math_delegate.get_querystring(
597
608
  column_name=self._meta.db_column_name, operator="*", value=value
598
609
  )
599
610
 
600
- def __rmul__(self, value: t.Union[int, float, Integer]) -> QueryString:
611
+ def __rmul__(self, value: Union[int, float, Integer]) -> QueryString:
601
612
  return self.math_delegate.get_querystring(
602
613
  column_name=self._meta.db_column_name,
603
614
  operator="*",
@@ -605,12 +616,12 @@ class Integer(Column):
605
616
  reverse=True,
606
617
  )
607
618
 
608
- def __truediv__(self, value: t.Union[int, float, Integer]) -> QueryString:
619
+ def __truediv__(self, value: Union[int, float, Integer]) -> QueryString:
609
620
  return self.math_delegate.get_querystring(
610
621
  column_name=self._meta.db_column_name, operator="/", value=value
611
622
  )
612
623
 
613
- def __rtruediv__(self, value: t.Union[int, float, Integer]) -> QueryString:
624
+ def __rtruediv__(self, value: Union[int, float, Integer]) -> QueryString:
614
625
  return self.math_delegate.get_querystring(
615
626
  column_name=self._meta.db_column_name,
616
627
  operator="/",
@@ -618,14 +629,12 @@ class Integer(Column):
618
629
  reverse=True,
619
630
  )
620
631
 
621
- def __floordiv__(self, value: t.Union[int, float, Integer]) -> QueryString:
632
+ def __floordiv__(self, value: Union[int, float, Integer]) -> QueryString:
622
633
  return self.math_delegate.get_querystring(
623
634
  column_name=self._meta.db_column_name, operator="/", value=value
624
635
  )
625
636
 
626
- def __rfloordiv__(
627
- self, value: t.Union[int, float, Integer]
628
- ) -> QueryString:
637
+ def __rfloordiv__(self, value: Union[int, float, Integer]) -> QueryString:
629
638
  return self.math_delegate.get_querystring(
630
639
  column_name=self._meta.db_column_name,
631
640
  operator="/",
@@ -636,16 +645,16 @@ class Integer(Column):
636
645
  ###########################################################################
637
646
  # Descriptors
638
647
 
639
- @t.overload
648
+ @overload
640
649
  def __get__(self, obj: Table, objtype=None) -> int: ...
641
650
 
642
- @t.overload
651
+ @overload
643
652
  def __get__(self, obj: None, objtype=None) -> Integer: ...
644
653
 
645
654
  def __get__(self, obj, objtype=None):
646
655
  return obj.__dict__[self._meta.name] if obj else self
647
656
 
648
- def __set__(self, obj, value: t.Union[int, None]):
657
+ def __set__(self, obj, value: Union[int, None]):
649
658
  obj.__dict__[self._meta.name] = value
650
659
 
651
660
 
@@ -692,16 +701,16 @@ class BigInt(Integer):
692
701
  ###########################################################################
693
702
  # Descriptors
694
703
 
695
- @t.overload
704
+ @overload
696
705
  def __get__(self, obj: Table, objtype=None) -> int: ...
697
706
 
698
- @t.overload
707
+ @overload
699
708
  def __get__(self, obj: None, objtype=None) -> BigInt: ...
700
709
 
701
710
  def __get__(self, obj, objtype=None):
702
711
  return obj.__dict__[self._meta.name] if obj else self
703
712
 
704
- def __set__(self, obj, value: t.Union[int, None]):
713
+ def __set__(self, obj, value: Union[int, None]):
705
714
  obj.__dict__[self._meta.name] = value
706
715
 
707
716
 
@@ -740,16 +749,16 @@ class SmallInt(Integer):
740
749
  ###########################################################################
741
750
  # Descriptors
742
751
 
743
- @t.overload
752
+ @overload
744
753
  def __get__(self, obj: Table, objtype=None) -> int: ...
745
754
 
746
- @t.overload
755
+ @overload
747
756
  def __get__(self, obj: None, objtype=None) -> SmallInt: ...
748
757
 
749
758
  def __get__(self, obj, objtype=None):
750
759
  return obj.__dict__[self._meta.name] if obj else self
751
760
 
752
- def __set__(self, obj, value: t.Union[int, None]):
761
+ def __set__(self, obj, value: Union[int, None]):
753
762
  obj.__dict__[self._meta.name] = value
754
763
 
755
764
 
@@ -790,16 +799,16 @@ class Serial(Column):
790
799
  ###########################################################################
791
800
  # Descriptors
792
801
 
793
- @t.overload
802
+ @overload
794
803
  def __get__(self, obj: Table, objtype=None) -> int: ...
795
804
 
796
- @t.overload
805
+ @overload
797
806
  def __get__(self, obj: None, objtype=None) -> Serial: ...
798
807
 
799
808
  def __get__(self, obj, objtype=None):
800
809
  return obj.__dict__[self._meta.name] if obj else self
801
810
 
802
- def __set__(self, obj, value: t.Union[int, None]):
811
+ def __set__(self, obj, value: Union[int, None]):
803
812
  obj.__dict__[self._meta.name] = value
804
813
 
805
814
 
@@ -822,16 +831,16 @@ class BigSerial(Serial):
822
831
  ###########################################################################
823
832
  # Descriptors
824
833
 
825
- @t.overload
834
+ @overload
826
835
  def __get__(self, obj: Table, objtype=None) -> int: ...
827
836
 
828
- @t.overload
837
+ @overload
829
838
  def __get__(self, obj: None, objtype=None) -> BigSerial: ...
830
839
 
831
840
  def __get__(self, obj, objtype=None):
832
841
  return obj.__dict__[self._meta.name] if obj else self
833
842
 
834
- def __set__(self, obj, value: t.Union[int, None]):
843
+ def __set__(self, obj, value: Union[int, None]):
835
844
  obj.__dict__[self._meta.name] = value
836
845
 
837
846
 
@@ -858,16 +867,16 @@ class PrimaryKey(Serial):
858
867
  ###########################################################################
859
868
  # Descriptors
860
869
 
861
- @t.overload
870
+ @overload
862
871
  def __get__(self, obj: Table, objtype=None) -> int: ...
863
872
 
864
- @t.overload
873
+ @overload
865
874
  def __get__(self, obj: None, objtype=None) -> PrimaryKey: ...
866
875
 
867
876
  def __get__(self, obj, objtype=None):
868
877
  return obj.__dict__[self._meta.name] if obj else self
869
878
 
870
- def __set__(self, obj, value: t.Union[int, None]):
879
+ def __set__(self, obj, value: Union[int, None]):
871
880
  obj.__dict__[self._meta.name] = value
872
881
 
873
882
 
@@ -947,16 +956,16 @@ class Timestamp(Column):
947
956
  ###########################################################################
948
957
  # Descriptors
949
958
 
950
- @t.overload
959
+ @overload
951
960
  def __get__(self, obj: Table, objtype=None) -> datetime: ...
952
961
 
953
- @t.overload
962
+ @overload
954
963
  def __get__(self, obj: None, objtype=None) -> Timestamp: ...
955
964
 
956
965
  def __get__(self, obj, objtype=None):
957
966
  return obj.__dict__[self._meta.name] if obj else self
958
967
 
959
- def __set__(self, obj, value: t.Union[datetime, None]):
968
+ def __set__(self, obj, value: Union[datetime, None]):
960
969
  obj.__dict__[self._meta.name] = value
961
970
 
962
971
 
@@ -1043,16 +1052,16 @@ class Timestamptz(Column):
1043
1052
  ###########################################################################
1044
1053
  # Descriptors
1045
1054
 
1046
- @t.overload
1055
+ @overload
1047
1056
  def __get__(self, obj: Table, objtype=None) -> datetime: ...
1048
1057
 
1049
- @t.overload
1058
+ @overload
1050
1059
  def __get__(self, obj: None, objtype=None) -> Timestamptz: ...
1051
1060
 
1052
1061
  def __get__(self, obj, objtype=None):
1053
1062
  return obj.__dict__[self._meta.name] if obj else self
1054
1063
 
1055
- def __set__(self, obj, value: t.Union[datetime, None]):
1064
+ def __set__(self, obj, value: Union[datetime, None]):
1056
1065
  obj.__dict__[self._meta.name] = value
1057
1066
 
1058
1067
 
@@ -1124,16 +1133,16 @@ class Date(Column):
1124
1133
  ###########################################################################
1125
1134
  # Descriptors
1126
1135
 
1127
- @t.overload
1136
+ @overload
1128
1137
  def __get__(self, obj: Table, objtype=None) -> date: ...
1129
1138
 
1130
- @t.overload
1139
+ @overload
1131
1140
  def __get__(self, obj: None, objtype=None) -> Date: ...
1132
1141
 
1133
1142
  def __get__(self, obj, objtype=None):
1134
1143
  return obj.__dict__[self._meta.name] if obj else self
1135
1144
 
1136
- def __set__(self, obj, value: t.Union[date, None]):
1145
+ def __set__(self, obj, value: Union[date, None]):
1137
1146
  obj.__dict__[self._meta.name] = value
1138
1147
 
1139
1148
 
@@ -1202,16 +1211,16 @@ class Time(Column):
1202
1211
  ###########################################################################
1203
1212
  # Descriptors
1204
1213
 
1205
- @t.overload
1214
+ @overload
1206
1215
  def __get__(self, obj: Table, objtype=None) -> time: ...
1207
1216
 
1208
- @t.overload
1217
+ @overload
1209
1218
  def __get__(self, obj: None, objtype=None) -> Time: ...
1210
1219
 
1211
1220
  def __get__(self, obj, objtype=None):
1212
1221
  return obj.__dict__[self._meta.name] if obj else self
1213
1222
 
1214
- def __set__(self, obj, value: t.Union[time, None]):
1223
+ def __set__(self, obj, value: Union[time, None]):
1215
1224
  obj.__dict__[self._meta.name] = value
1216
1225
 
1217
1226
 
@@ -1292,16 +1301,16 @@ class Interval(Column):
1292
1301
  ###########################################################################
1293
1302
  # Descriptors
1294
1303
 
1295
- @t.overload
1304
+ @overload
1296
1305
  def __get__(self, obj: Table, objtype=None) -> timedelta: ...
1297
1306
 
1298
- @t.overload
1307
+ @overload
1299
1308
  def __get__(self, obj: None, objtype=None) -> Interval: ...
1300
1309
 
1301
1310
  def __get__(self, obj, objtype=None):
1302
1311
  return obj.__dict__[self._meta.name] if obj else self
1303
1312
 
1304
- def __set__(self, obj, value: t.Union[timedelta, None]):
1313
+ def __set__(self, obj, value: Union[timedelta, None]):
1305
1314
  obj.__dict__[self._meta.name] = value
1306
1315
 
1307
1316
 
@@ -1333,7 +1342,7 @@ class Boolean(Column):
1333
1342
 
1334
1343
  def __init__(
1335
1344
  self,
1336
- default: t.Union[bool, Enum, t.Callable[[], bool], None] = False,
1345
+ default: Union[bool, Enum, Callable[[], bool], None] = False,
1337
1346
  **kwargs: Unpack[ColumnKwargs],
1338
1347
  ) -> None:
1339
1348
  self._validate_default(default, (bool, None))
@@ -1383,16 +1392,16 @@ class Boolean(Column):
1383
1392
  ###########################################################################
1384
1393
  # Descriptors
1385
1394
 
1386
- @t.overload
1395
+ @overload
1387
1396
  def __get__(self, obj: Table, objtype=None) -> bool: ...
1388
1397
 
1389
- @t.overload
1398
+ @overload
1390
1399
  def __get__(self, obj: None, objtype=None) -> Boolean: ...
1391
1400
 
1392
1401
  def __get__(self, obj, objtype=None):
1393
1402
  return obj.__dict__[self._meta.name] if obj else self
1394
1403
 
1395
- def __set__(self, obj, value: t.Union[bool, None]):
1404
+ def __set__(self, obj, value: Union[bool, None]):
1396
1405
  obj.__dict__[self._meta.name] = value
1397
1406
 
1398
1407
 
@@ -1443,14 +1452,14 @@ class Numeric(Column):
1443
1452
  return "NUMERIC"
1444
1453
 
1445
1454
  @property
1446
- def precision(self) -> t.Optional[int]:
1455
+ def precision(self) -> Optional[int]:
1447
1456
  """
1448
1457
  The total number of digits allowed.
1449
1458
  """
1450
1459
  return self.digits[0] if self.digits is not None else None
1451
1460
 
1452
1461
  @property
1453
- def scale(self) -> t.Optional[int]:
1462
+ def scale(self) -> Optional[int]:
1454
1463
  """
1455
1464
  The number of digits after the decimal point.
1456
1465
  """
@@ -1458,9 +1467,9 @@ class Numeric(Column):
1458
1467
 
1459
1468
  def __init__(
1460
1469
  self,
1461
- digits: t.Optional[t.Tuple[int, int]] = None,
1462
- default: t.Union[
1463
- decimal.Decimal, Enum, t.Callable[[], decimal.Decimal], None
1470
+ digits: Optional[tuple[int, int]] = None,
1471
+ default: Union[
1472
+ decimal.Decimal, Enum, Callable[[], decimal.Decimal], None
1464
1473
  ] = decimal.Decimal(0.0),
1465
1474
  **kwargs: Unpack[ColumnKwargs],
1466
1475
  ) -> None:
@@ -1483,16 +1492,16 @@ class Numeric(Column):
1483
1492
  ###########################################################################
1484
1493
  # Descriptors
1485
1494
 
1486
- @t.overload
1495
+ @overload
1487
1496
  def __get__(self, obj: Table, objtype=None) -> decimal.Decimal: ...
1488
1497
 
1489
- @t.overload
1498
+ @overload
1490
1499
  def __get__(self, obj: None, objtype=None) -> Numeric: ...
1491
1500
 
1492
1501
  def __get__(self, obj, objtype=None):
1493
1502
  return obj.__dict__[self._meta.name] if obj else self
1494
1503
 
1495
- def __set__(self, obj, value: t.Union[decimal.Decimal, None]):
1504
+ def __set__(self, obj, value: Union[decimal.Decimal, None]):
1496
1505
  obj.__dict__[self._meta.name] = value
1497
1506
 
1498
1507
 
@@ -1504,16 +1513,16 @@ class Decimal(Numeric):
1504
1513
  ###########################################################################
1505
1514
  # Descriptors
1506
1515
 
1507
- @t.overload
1516
+ @overload
1508
1517
  def __get__(self, obj: Table, objtype=None) -> decimal.Decimal: ...
1509
1518
 
1510
- @t.overload
1519
+ @overload
1511
1520
  def __get__(self, obj: None, objtype=None) -> Decimal: ...
1512
1521
 
1513
1522
  def __get__(self, obj, objtype=None):
1514
1523
  return obj.__dict__[self._meta.name] if obj else self
1515
1524
 
1516
- def __set__(self, obj, value: t.Union[decimal.Decimal, None]):
1525
+ def __set__(self, obj, value: Union[decimal.Decimal, None]):
1517
1526
  obj.__dict__[self._meta.name] = value
1518
1527
 
1519
1528
 
@@ -1542,9 +1551,13 @@ class Real(Column):
1542
1551
 
1543
1552
  def __init__(
1544
1553
  self,
1545
- default: t.Union[float, Enum, t.Callable[[], float], None] = 0.0,
1554
+ default: Union[float, Enum, Callable[[], float], None] = 0.0,
1546
1555
  **kwargs: Unpack[ColumnKwargs],
1547
1556
  ) -> None:
1557
+ if isinstance(default, int):
1558
+ # For example, allow `0` as a valid default.
1559
+ default = float(default)
1560
+
1548
1561
  self._validate_default(default, (float, None))
1549
1562
  self.default = default
1550
1563
  super().__init__(default=default, **kwargs)
@@ -1552,16 +1565,16 @@ class Real(Column):
1552
1565
  ###########################################################################
1553
1566
  # Descriptors
1554
1567
 
1555
- @t.overload
1568
+ @overload
1556
1569
  def __get__(self, obj: Table, objtype=None) -> float: ...
1557
1570
 
1558
- @t.overload
1571
+ @overload
1559
1572
  def __get__(self, obj: None, objtype=None) -> Real: ...
1560
1573
 
1561
1574
  def __get__(self, obj, objtype=None):
1562
1575
  return obj.__dict__[self._meta.name] if obj else self
1563
1576
 
1564
- def __set__(self, obj, value: t.Union[float, None]):
1577
+ def __set__(self, obj, value: Union[float, None]):
1565
1578
  obj.__dict__[self._meta.name] = value
1566
1579
 
1567
1580
 
@@ -1573,16 +1586,16 @@ class Float(Real):
1573
1586
  ###########################################################################
1574
1587
  # Descriptors
1575
1588
 
1576
- @t.overload
1589
+ @overload
1577
1590
  def __get__(self, obj: Table, objtype=None) -> float: ...
1578
1591
 
1579
- @t.overload
1592
+ @overload
1580
1593
  def __get__(self, obj: None, objtype=None) -> Float: ...
1581
1594
 
1582
1595
  def __get__(self, obj, objtype=None):
1583
1596
  return obj.__dict__[self._meta.name] if obj else self
1584
1597
 
1585
- def __set__(self, obj, value: t.Union[float, None]):
1598
+ def __set__(self, obj, value: Union[float, None]):
1586
1599
  obj.__dict__[self._meta.name] = value
1587
1600
 
1588
1601
 
@@ -1598,16 +1611,16 @@ class DoublePrecision(Real):
1598
1611
  ###########################################################################
1599
1612
  # Descriptors
1600
1613
 
1601
- @t.overload
1614
+ @overload
1602
1615
  def __get__(self, obj: Table, objtype=None) -> float: ...
1603
1616
 
1604
- @t.overload
1617
+ @overload
1605
1618
  def __get__(self, obj: None, objtype=None) -> DoublePrecision: ...
1606
1619
 
1607
1620
  def __get__(self, obj, objtype=None):
1608
1621
  return obj.__dict__[self._meta.name] if obj else self
1609
1622
 
1610
- def __set__(self, obj, value: t.Union[float, None]):
1623
+ def __set__(self, obj, value: Union[float, None]):
1611
1624
  obj.__dict__[self._meta.name] = value
1612
1625
 
1613
1626
 
@@ -1619,7 +1632,7 @@ class ForeignKeySetupResponse:
1619
1632
  is_lazy: bool
1620
1633
 
1621
1634
 
1622
- class ForeignKey(Column, t.Generic[ReferencedTable]):
1635
+ class ForeignKey(Column, Generic[ReferencedTable]):
1623
1636
  """
1624
1637
  Used to reference another table. Uses the same type as the primary key
1625
1638
  column on the table it references.
@@ -1832,50 +1845,50 @@ class ForeignKey(Column, t.Generic[ReferencedTable]):
1832
1845
  target_column = self._foreign_key_meta.resolved_target_column
1833
1846
  return target_column.value_type
1834
1847
 
1835
- @t.overload
1848
+ @overload
1836
1849
  def __init__(
1837
1850
  self,
1838
- references: t.Type[ReferencedTable],
1839
- default: t.Any = None,
1851
+ references: type[ReferencedTable],
1852
+ default: Any = None,
1840
1853
  null: bool = True,
1841
1854
  on_delete: OnDelete = OnDelete.cascade,
1842
1855
  on_update: OnUpdate = OnUpdate.cascade,
1843
- target_column: t.Union[str, Column, None] = None,
1856
+ target_column: Union[str, Column, None] = None,
1844
1857
  **kwargs,
1845
1858
  ) -> None: ...
1846
1859
 
1847
- @t.overload
1860
+ @overload
1848
1861
  def __init__(
1849
1862
  self,
1850
1863
  references: LazyTableReference,
1851
- default: t.Any = None,
1864
+ default: Any = None,
1852
1865
  null: bool = True,
1853
1866
  on_delete: OnDelete = OnDelete.cascade,
1854
1867
  on_update: OnUpdate = OnUpdate.cascade,
1855
- target_column: t.Union[str, Column, None] = None,
1868
+ target_column: Union[str, Column, None] = None,
1856
1869
  **kwargs,
1857
1870
  ) -> None: ...
1858
1871
 
1859
- @t.overload
1872
+ @overload
1860
1873
  def __init__(
1861
1874
  self,
1862
1875
  references: str,
1863
- default: t.Any = None,
1876
+ default: Any = None,
1864
1877
  null: bool = True,
1865
1878
  on_delete: OnDelete = OnDelete.cascade,
1866
1879
  on_update: OnUpdate = OnUpdate.cascade,
1867
- target_column: t.Union[str, Column, None] = None,
1880
+ target_column: Union[str, Column, None] = None,
1868
1881
  **kwargs,
1869
1882
  ) -> None: ...
1870
1883
 
1871
1884
  def __init__(
1872
1885
  self,
1873
- references: t.Union[t.Type[ReferencedTable], LazyTableReference, str],
1874
- default: t.Any = None,
1886
+ references: Union[type[ReferencedTable], LazyTableReference, str],
1887
+ default: Any = None,
1875
1888
  null: bool = True,
1876
1889
  on_delete: OnDelete = OnDelete.cascade,
1877
1890
  on_update: OnUpdate = OnUpdate.cascade,
1878
- target_column: t.Union[str, Column, None] = None,
1891
+ target_column: Union[str, Column, None] = None,
1879
1892
  **kwargs,
1880
1893
  ) -> None:
1881
1894
  from piccolo.table import Table
@@ -1914,7 +1927,7 @@ class ForeignKey(Column, t.Generic[ReferencedTable]):
1914
1927
  target_column=target_column,
1915
1928
  )
1916
1929
 
1917
- def _setup(self, table_class: t.Type[Table]) -> ForeignKeySetupResponse:
1930
+ def _setup(self, table_class: type[Table]) -> ForeignKeySetupResponse:
1918
1931
  """
1919
1932
  This is called by the ``TableMetaclass``. A ``ForeignKey`` column can
1920
1933
  only be completely setup once it's parent ``Table`` is known.
@@ -1965,9 +1978,9 @@ class ForeignKey(Column, t.Generic[ReferencedTable]):
1965
1978
 
1966
1979
  if is_table_class:
1967
1980
  # Record the reverse relationship on the target table.
1968
- t.cast(
1969
- t.Type[Table], references
1970
- )._meta._foreign_key_references.append(self)
1981
+ cast(type[Table], references)._meta._foreign_key_references.append(
1982
+ self
1983
+ )
1971
1984
 
1972
1985
  # Allow columns on the referenced table to be accessed via
1973
1986
  # auto completion.
@@ -1982,8 +1995,8 @@ class ForeignKey(Column, t.Generic[ReferencedTable]):
1982
1995
  return column
1983
1996
 
1984
1997
  def all_columns(
1985
- self, exclude: t.Optional[t.List[t.Union[Column, str]]] = None
1986
- ) -> t.List[Column]:
1998
+ self, exclude: Optional[list[Union[Column, str]]] = None
1999
+ ) -> list[Column]:
1987
2000
  """
1988
2001
  Allow a user to access all of the columns on the related table. This is
1989
2002
  intended for use with ``select`` queries, and saves the user from
@@ -2088,8 +2101,8 @@ class ForeignKey(Column, t.Generic[ReferencedTable]):
2088
2101
  return foreign_key
2089
2102
 
2090
2103
  def all_related(
2091
- self, exclude: t.Optional[t.List[t.Union[ForeignKey, str]]] = None
2092
- ) -> t.List[ForeignKey]:
2104
+ self, exclude: Optional[list[Union[ForeignKey, str]]] = None
2105
+ ) -> list[ForeignKey]:
2093
2106
  """
2094
2107
  Returns each ``ForeignKey`` column on the related table. This is
2095
2108
  intended for use with ``objects`` queries, where you want to return
@@ -2157,7 +2170,7 @@ class ForeignKey(Column, t.Generic[ReferencedTable]):
2157
2170
  _fk_meta.proxy_columns.append(_column)
2158
2171
 
2159
2172
  @property
2160
- def _(self) -> t.Type[ReferencedTable]:
2173
+ def _(self) -> type[ReferencedTable]:
2161
2174
  """
2162
2175
  This allows us specify joins in a way which is friendly to static type
2163
2176
  checkers like Mypy and Pyright.
@@ -2188,9 +2201,9 @@ class ForeignKey(Column, t.Generic[ReferencedTable]):
2188
2201
  easily know if any of your joins contain typos.
2189
2202
 
2190
2203
  """
2191
- return t.cast(t.Type[ReferencedTable], self)
2204
+ return cast(type[ReferencedTable], self)
2192
2205
 
2193
- def __getattribute__(self, name: str) -> t.Union[Column, t.Any]:
2206
+ def __getattribute__(self, name: str) -> Union[Column, Any]:
2194
2207
  """
2195
2208
  Returns attributes unmodified unless they're Column instances, in which
2196
2209
  case a copy is returned with an updated call_chain (which records the
@@ -2217,7 +2230,7 @@ class ForeignKey(Column, t.Generic[ReferencedTable]):
2217
2230
  if name.startswith("_"):
2218
2231
  return value
2219
2232
 
2220
- foreignkey_class: t.Type[ForeignKey] = object.__getattribute__(
2233
+ foreignkey_class: type[ForeignKey] = object.__getattribute__(
2221
2234
  self, "__class__"
2222
2235
  )
2223
2236
 
@@ -2270,21 +2283,21 @@ class ForeignKey(Column, t.Generic[ReferencedTable]):
2270
2283
  ###########################################################################
2271
2284
  # Descriptors
2272
2285
 
2273
- @t.overload
2274
- def __get__(self, obj: Table, objtype=None) -> t.Any: ...
2286
+ @overload
2287
+ def __get__(self, obj: Table, objtype=None) -> Any: ...
2275
2288
 
2276
- @t.overload
2289
+ @overload
2277
2290
  def __get__(
2278
2291
  self, obj: None, objtype=None
2279
2292
  ) -> ForeignKey[ReferencedTable]: ...
2280
2293
 
2281
- @t.overload
2282
- def __get__(self, obj: t.Any, objtype=None) -> t.Any: ...
2294
+ @overload
2295
+ def __get__(self, obj: Any, objtype=None) -> Any: ...
2283
2296
 
2284
2297
  def __get__(self, obj, objtype=None):
2285
2298
  return obj.__dict__[self._meta.name] if obj else self
2286
2299
 
2287
- def __set__(self, obj, value: t.Any):
2300
+ def __set__(self, obj, value: Any):
2288
2301
  obj.__dict__[self._meta.name] = value
2289
2302
 
2290
2303
 
@@ -2307,11 +2320,11 @@ class JSON(Column):
2307
2320
 
2308
2321
  def __init__(
2309
2322
  self,
2310
- default: t.Union[
2323
+ default: Union[
2311
2324
  str,
2312
- t.List,
2313
- t.Dict,
2314
- t.Callable[[], t.Union[str, t.List, t.Dict]],
2325
+ list,
2326
+ dict,
2327
+ Callable[[], Union[str, list, dict]],
2315
2328
  None,
2316
2329
  ] = "{}",
2317
2330
  **kwargs: Unpack[ColumnKwargs],
@@ -2324,7 +2337,7 @@ class JSON(Column):
2324
2337
  self.default = default
2325
2338
  super().__init__(default=default, **kwargs)
2326
2339
 
2327
- self.json_operator: t.Optional[str] = None
2340
+ self.json_operator: Optional[str] = None
2328
2341
 
2329
2342
  @property
2330
2343
  def column_type(self):
@@ -2336,7 +2349,7 @@ class JSON(Column):
2336
2349
 
2337
2350
  ###########################################################################
2338
2351
 
2339
- def arrow(self, key: t.Union[str, int, QueryString]) -> GetChildElement:
2352
+ def arrow(self, key: Union[str, int, QueryString]) -> GetChildElement:
2340
2353
  """
2341
2354
  Allows a child element of the JSON structure to be returned - for
2342
2355
  example::
@@ -2352,7 +2365,7 @@ class JSON(Column):
2352
2365
  return GetChildElement(identifier=self, key=key, alias=alias)
2353
2366
 
2354
2367
  def __getitem__(
2355
- self, value: t.Union[str, int, QueryString]
2368
+ self, value: Union[str, int, QueryString]
2356
2369
  ) -> GetChildElement:
2357
2370
  """
2358
2371
  A shortcut for the ``arrow`` method, used for retrieving a child
@@ -2371,7 +2384,7 @@ class JSON(Column):
2371
2384
 
2372
2385
  def from_path(
2373
2386
  self,
2374
- path: t.List[t.Union[str, int]],
2387
+ path: list[Union[str, int]],
2375
2388
  ) -> GetElementFromPath:
2376
2389
  """
2377
2390
  Allows an element of the JSON structure to be returned, which can be
@@ -2407,16 +2420,16 @@ class JSON(Column):
2407
2420
  ###########################################################################
2408
2421
  # Descriptors
2409
2422
 
2410
- @t.overload
2423
+ @overload
2411
2424
  def __get__(self, obj: Table, objtype=None) -> str: ...
2412
2425
 
2413
- @t.overload
2426
+ @overload
2414
2427
  def __get__(self, obj: None, objtype=None) -> JSON: ...
2415
2428
 
2416
2429
  def __get__(self, obj, objtype=None):
2417
2430
  return obj.__dict__[self._meta.name] if obj else self
2418
2431
 
2419
- def __set__(self, obj, value: t.Union[str, t.Dict]):
2432
+ def __set__(self, obj, value: Union[str, dict]):
2420
2433
  obj.__dict__[self._meta.name] = value
2421
2434
 
2422
2435
 
@@ -2440,16 +2453,16 @@ class JSONB(JSON):
2440
2453
  ###########################################################################
2441
2454
  # Descriptors
2442
2455
 
2443
- @t.overload
2456
+ @overload
2444
2457
  def __get__(self, obj: Table, objtype=None) -> str: ...
2445
2458
 
2446
- @t.overload
2459
+ @overload
2447
2460
  def __get__(self, obj: None, objtype=None) -> JSONB: ...
2448
2461
 
2449
2462
  def __get__(self, obj, objtype=None):
2450
2463
  return obj.__dict__[self._meta.name] if obj else self
2451
2464
 
2452
- def __set__(self, obj, value: t.Union[str, t.Dict]):
2465
+ def __set__(self, obj, value: Union[str, dict]):
2453
2466
  obj.__dict__[self._meta.name] = value
2454
2467
 
2455
2468
 
@@ -2489,12 +2502,12 @@ class Bytea(Column):
2489
2502
 
2490
2503
  def __init__(
2491
2504
  self,
2492
- default: t.Union[
2505
+ default: Union[
2493
2506
  bytes,
2494
2507
  bytearray,
2495
2508
  Enum,
2496
- t.Callable[[], bytes],
2497
- t.Callable[[], bytearray],
2509
+ Callable[[], bytes],
2510
+ Callable[[], bytearray],
2498
2511
  None,
2499
2512
  ] = b"",
2500
2513
  **kwargs: Unpack[ColumnKwargs],
@@ -2510,10 +2523,10 @@ class Bytea(Column):
2510
2523
  ###########################################################################
2511
2524
  # Descriptors
2512
2525
 
2513
- @t.overload
2526
+ @overload
2514
2527
  def __get__(self, obj: Table, objtype=None) -> bytes: ...
2515
2528
 
2516
- @t.overload
2529
+ @overload
2517
2530
  def __get__(self, obj: None, objtype=None) -> Bytea: ...
2518
2531
 
2519
2532
  def __get__(self, obj, objtype=None):
@@ -2531,10 +2544,10 @@ class Blob(Bytea):
2531
2544
  ###########################################################################
2532
2545
  # Descriptors
2533
2546
 
2534
- @t.overload
2547
+ @overload
2535
2548
  def __get__(self, obj: Table, objtype=None) -> bytes: ...
2536
2549
 
2537
- @t.overload
2550
+ @overload
2538
2551
  def __get__(self, obj: None, objtype=None) -> Blob: ...
2539
2552
 
2540
2553
  def __get__(self, obj, objtype=None):
@@ -2594,9 +2607,7 @@ class Array(Column):
2594
2607
  def __init__(
2595
2608
  self,
2596
2609
  base_column: Column,
2597
- default: t.Union[
2598
- t.List, Enum, t.Callable[[], t.List], None
2599
- ] = ListProxy(),
2610
+ default: Union[list, Enum, Callable[[], list], None] = ListProxy(),
2600
2611
  **kwargs: Unpack[ColumnKwargs],
2601
2612
  ) -> None:
2602
2613
  if isinstance(base_column, ForeignKey):
@@ -2622,7 +2633,7 @@ class Array(Column):
2622
2633
 
2623
2634
  self.base_column = base_column
2624
2635
  self.default = default
2625
- self.index: t.Optional[int] = None
2636
+ self.index: Optional[int] = None
2626
2637
  super().__init__(default=default, base_column=base_column, **kwargs)
2627
2638
 
2628
2639
  @property
@@ -2641,7 +2652,7 @@ class Array(Column):
2641
2652
  )
2642
2653
  raise Exception("Unrecognized engine type")
2643
2654
 
2644
- def _setup_base_column(self, table_class: t.Type[Table]):
2655
+ def _setup_base_column(self, table_class: type[Table]):
2645
2656
  """
2646
2657
  Called from the ``Table.__init_subclass__`` - makes sure
2647
2658
  that the ``base_column`` has a reference to the parent table.
@@ -2687,7 +2698,7 @@ class Array(Column):
2687
2698
  else:
2688
2699
  return self.base_column
2689
2700
 
2690
- def _get_inner_value_type(self) -> t.Type:
2701
+ def _get_inner_value_type(self) -> type:
2691
2702
  """
2692
2703
  A helper function to get the innermost value type for the array. For
2693
2704
  example::
@@ -2728,7 +2739,7 @@ class Array(Column):
2728
2739
  if value < 0:
2729
2740
  raise ValueError("Only positive integers are allowed.")
2730
2741
 
2731
- instance = t.cast(Array, self.copy())
2742
+ instance = cast(Array, self.copy())
2732
2743
 
2733
2744
  # We deliberately add 1, as Postgres treats the first array element
2734
2745
  # as index 1.
@@ -2751,7 +2762,7 @@ class Array(Column):
2751
2762
 
2752
2763
  return QueryString(select_string)
2753
2764
 
2754
- def any(self, value: t.Any) -> Where:
2765
+ def any(self, value: Any) -> Where:
2755
2766
  """
2756
2767
  Check if any of the items in the array match the given value.
2757
2768
 
@@ -2769,7 +2780,7 @@ class Array(Column):
2769
2780
  else:
2770
2781
  raise ValueError("Unrecognised engine type")
2771
2782
 
2772
- def not_any(self, value: t.Any) -> Where:
2783
+ def not_any(self, value: Any) -> Where:
2773
2784
  """
2774
2785
  Check if the given value isn't in the array.
2775
2786
 
@@ -2787,7 +2798,7 @@ class Array(Column):
2787
2798
  else:
2788
2799
  raise ValueError("Unrecognised engine type")
2789
2800
 
2790
- def all(self, value: t.Any) -> Where:
2801
+ def all(self, value: Any) -> Where:
2791
2802
  """
2792
2803
  Check if all of the items in the array match the given value.
2793
2804
 
@@ -2805,9 +2816,12 @@ class Array(Column):
2805
2816
  else:
2806
2817
  raise ValueError("Unrecognised engine type")
2807
2818
 
2808
- def cat(self, value: t.Union[t.Any, t.List[t.Any]]) -> QueryString:
2819
+ def cat(self, value: ArrayType) -> QueryString:
2809
2820
  """
2810
- Used in an ``update`` query to append items to an array.
2821
+ A convenient way of accessing the
2822
+ :class:`ArrayCat <piccolo.query.functions.array.ArrayCat>` function.
2823
+
2824
+ Used in an ``update`` query to concatenate two arrays.
2811
2825
 
2812
2826
  .. code-block:: python
2813
2827
 
@@ -2815,7 +2829,8 @@ class Array(Column):
2815
2829
  ... Ticket.seat_numbers: Ticket.seat_numbers.cat([1000])
2816
2830
  ... }).where(Ticket.id == 1)
2817
2831
 
2818
- You can also use the ``+`` symbol if you prefer:
2832
+ You can also use the ``+`` symbol if you prefer. To concatenate to
2833
+ the end:
2819
2834
 
2820
2835
  .. code-block:: python
2821
2836
 
@@ -2823,33 +2838,140 @@ class Array(Column):
2823
2838
  ... Ticket.seat_numbers: Ticket.seat_numbers + [1000]
2824
2839
  ... }).where(Ticket.id == 1)
2825
2840
 
2841
+ To concatenate to the start:
2842
+
2843
+ .. code-block:: python
2844
+
2845
+ >>> await Ticket.update({
2846
+ ... Ticket.seat_numbers: [1000] + Ticket.seat_numbers
2847
+ ... }).where(Ticket.id == 1)
2848
+
2849
+ You can concatenate multiple arrays in one go:
2850
+
2851
+ .. code-block:: python
2852
+
2853
+ >>> await Ticket.update({
2854
+ ... Ticket.seat_numbers: [1000] + Ticket.seat_numbers + [2000]
2855
+ ... }).where(Ticket.id == 1)
2856
+
2857
+ .. note:: Postgres / CockroachDB only
2858
+
2826
2859
  """
2827
- engine_type = self._meta.engine_type
2828
- if engine_type != "postgres" and engine_type != "cockroach":
2829
- raise ValueError(
2830
- "Only Postgres and Cockroach support array appending."
2831
- )
2860
+ from piccolo.query.functions.array import ArrayCat
2832
2861
 
2862
+ # Keep this for backwards compatibility - we had this as a convenience
2863
+ # for users, but it would be nice to remove it in the future.
2833
2864
  if not isinstance(value, list):
2834
2865
  value = [value]
2835
2866
 
2836
- db_column_name = self._meta.db_column_name
2837
- return QueryString(f'array_cat("{db_column_name}", {{}})', value)
2867
+ return ArrayCat(array_1=self, array_2=value)
2868
+
2869
+ def remove(self, value: ArrayItemType) -> QueryString:
2870
+ """
2871
+ A convenient way of accessing the
2872
+ :class:`ArrayRemove <piccolo.query.functions.array.ArrayRemove>`
2873
+ function.
2874
+
2875
+ Used in an ``update`` query to remove an item from an array.
2876
+
2877
+ .. code-block:: python
2878
+
2879
+ >>> await Ticket.update({
2880
+ ... Ticket.seat_numbers: Ticket.seat_numbers.remove(1000)
2881
+ ... }).where(Ticket.id == 1)
2882
+
2883
+ .. note:: Postgres / CockroachDB only
2884
+
2885
+ """
2886
+ from piccolo.query.functions.array import ArrayRemove
2887
+
2888
+ return ArrayRemove(array=self, value=value)
2889
+
2890
+ def prepend(self, value: ArrayItemType) -> QueryString:
2891
+ """
2892
+ A convenient way of accessing the
2893
+ :class:`ArrayPrepend <piccolo.query.functions.array.ArrayPrepend>`
2894
+ function.
2895
+
2896
+ Used in an ``update`` query to prepend an item to an array.
2838
2897
 
2839
- def __add__(self, value: t.Union[t.Any, t.List[t.Any]]) -> QueryString:
2898
+ .. code-block:: python
2899
+
2900
+ >>> await Ticket.update({
2901
+ ... Ticket.seat_numbers: Ticket.seat_numbers.prepend(1000)
2902
+ ... }).where(Ticket.id == 1)
2903
+
2904
+ .. note:: Postgres / CockroachDB only
2905
+
2906
+ """
2907
+ from piccolo.query.functions.array import ArrayPrepend
2908
+
2909
+ return ArrayPrepend(array=self, value=value)
2910
+
2911
+ def append(self, value: ArrayItemType) -> QueryString:
2912
+ """
2913
+ A convenient way of accessing the
2914
+ :class:`ArrayAppend <piccolo.query.functions.array.ArrayAppend>`
2915
+ function.
2916
+
2917
+ Used in an ``update`` query to append an item to an array.
2918
+
2919
+ .. code-block:: python
2920
+
2921
+ >>> await Ticket.update({
2922
+ ... Ticket.seat_numbers: Ticket.seat_numbers.append(1000)
2923
+ ... }).where(Ticket.id == 1)
2924
+
2925
+ .. note:: Postgres / CockroachDB only
2926
+
2927
+ """
2928
+ from piccolo.query.functions.array import ArrayAppend
2929
+
2930
+ return ArrayAppend(array=self, value=value)
2931
+
2932
+ def replace(
2933
+ self, old_value: ArrayItemType, new_value: ArrayItemType
2934
+ ) -> QueryString:
2935
+ """
2936
+ A convenient way of accessing the
2937
+ :class:`ArrayReplace <piccolo.query.functions.array.ArrayReplace>`
2938
+ function.
2939
+
2940
+ Used in an ``update`` query to replace each array item
2941
+ equal to the given value with a new value.
2942
+
2943
+ .. code-block:: python
2944
+
2945
+ >>> await Ticket.update({
2946
+ ... Ticket.seat_numbers: Ticket.seat_numbers.replace(1000, 500)
2947
+ ... }).where(Ticket.id == 1)
2948
+
2949
+ .. note:: Postgres / CockroachDB only
2950
+
2951
+ """
2952
+ from piccolo.query.functions.array import ArrayReplace
2953
+
2954
+ return ArrayReplace(self, old_value=old_value, new_value=new_value)
2955
+
2956
+ def __add__(self, value: ArrayType) -> QueryString:
2840
2957
  return self.cat(value)
2841
2958
 
2959
+ def __radd__(self, value: ArrayType) -> QueryString:
2960
+ from piccolo.query.functions.array import ArrayCat
2961
+
2962
+ return ArrayCat(array_1=value, array_2=self)
2963
+
2842
2964
  ###########################################################################
2843
2965
  # Descriptors
2844
2966
 
2845
- @t.overload
2846
- def __get__(self, obj: Table, objtype=None) -> t.List[t.Any]: ...
2967
+ @overload
2968
+ def __get__(self, obj: Table, objtype=None) -> list[Any]: ...
2847
2969
 
2848
- @t.overload
2970
+ @overload
2849
2971
  def __get__(self, obj: None, objtype=None) -> Array: ...
2850
2972
 
2851
2973
  def __get__(self, obj, objtype=None):
2852
2974
  return obj.__dict__[self._meta.name] if obj else self
2853
2975
 
2854
- def __set__(self, obj, value: t.List[t.Any]):
2976
+ def __set__(self, obj, value: list[Any]):
2855
2977
  obj.__dict__[self._meta.name] = value