iceaxe 0.7.1__tar.gz → 0.8.0__tar.gz

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.

Potentially problematic release.


This version of iceaxe might be problematic. Click here for more details.

Files changed (81) hide show
  1. {iceaxe-0.7.1/iceaxe.egg-info → iceaxe-0.8.0}/PKG-INFO +1 -1
  2. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/__tests__/schemas/test_actions.py +1 -0
  3. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/__tests__/schemas/test_db_memory_serializer.py +46 -0
  4. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/__tests__/test_queries.py +159 -0
  5. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/base.py +1 -0
  6. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/field.py +13 -0
  7. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/functions.py +527 -1
  8. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/queries.py +5 -1
  9. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/schemas/db_memory_serializer.py +6 -0
  10. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/schemas/db_stubs.py +4 -0
  11. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/session_optimized.c +38 -23
  12. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/sql_types.py +1 -0
  13. {iceaxe-0.7.1 → iceaxe-0.8.0/iceaxe.egg-info}/PKG-INFO +1 -1
  14. {iceaxe-0.7.1 → iceaxe-0.8.0}/pyproject.toml +1 -1
  15. {iceaxe-0.7.1 → iceaxe-0.8.0}/LICENSE +0 -0
  16. {iceaxe-0.7.1 → iceaxe-0.8.0}/MANIFEST.in +0 -0
  17. {iceaxe-0.7.1 → iceaxe-0.8.0}/README.md +0 -0
  18. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/__init__.py +0 -0
  19. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/__tests__/__init__.py +0 -0
  20. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/__tests__/benchmarks/__init__.py +0 -0
  21. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/__tests__/benchmarks/test_bulk_insert.py +0 -0
  22. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/__tests__/benchmarks/test_select.py +0 -0
  23. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/__tests__/conf_models.py +0 -0
  24. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/__tests__/conftest.py +0 -0
  25. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/__tests__/docker_helpers.py +0 -0
  26. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/__tests__/helpers.py +0 -0
  27. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/__tests__/migrations/__init__.py +0 -0
  28. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/__tests__/migrations/conftest.py +0 -0
  29. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/__tests__/migrations/test_action_sorter.py +0 -0
  30. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/__tests__/migrations/test_generator.py +0 -0
  31. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/__tests__/migrations/test_generics.py +0 -0
  32. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/__tests__/mountaineer/__init__.py +0 -0
  33. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/__tests__/mountaineer/dependencies/__init__.py +0 -0
  34. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/__tests__/mountaineer/dependencies/test_core.py +0 -0
  35. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/__tests__/schemas/__init__.py +0 -0
  36. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/__tests__/schemas/test_cli.py +0 -0
  37. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/__tests__/schemas/test_db_serializer.py +0 -0
  38. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/__tests__/schemas/test_db_stubs.py +0 -0
  39. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/__tests__/test_alias.py +0 -0
  40. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/__tests__/test_base.py +0 -0
  41. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/__tests__/test_comparison.py +0 -0
  42. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/__tests__/test_field.py +0 -0
  43. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/__tests__/test_helpers.py +0 -0
  44. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/__tests__/test_modifications.py +0 -0
  45. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/__tests__/test_queries_str.py +0 -0
  46. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/__tests__/test_session.py +0 -0
  47. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/__tests__/test_text_search.py +0 -0
  48. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/alias_values.py +0 -0
  49. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/comparison.py +0 -0
  50. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/generics.py +0 -0
  51. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/io.py +0 -0
  52. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/logging.py +0 -0
  53. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/migrations/__init__.py +0 -0
  54. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/migrations/action_sorter.py +0 -0
  55. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/migrations/cli.py +0 -0
  56. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/migrations/client_io.py +0 -0
  57. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/migrations/generator.py +0 -0
  58. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/migrations/migration.py +0 -0
  59. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/migrations/migrator.py +0 -0
  60. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/modifications.py +0 -0
  61. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/mountaineer/__init__.py +0 -0
  62. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/mountaineer/cli.py +0 -0
  63. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/mountaineer/config.py +0 -0
  64. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/mountaineer/dependencies/__init__.py +0 -0
  65. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/mountaineer/dependencies/core.py +0 -0
  66. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/postgres.py +0 -0
  67. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/py.typed +0 -0
  68. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/queries_str.py +0 -0
  69. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/schemas/__init__.py +0 -0
  70. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/schemas/actions.py +0 -0
  71. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/schemas/cli.py +0 -0
  72. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/schemas/db_serializer.py +0 -0
  73. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/session.py +0 -0
  74. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/session_optimized.pyx +0 -0
  75. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe/typing.py +0 -0
  76. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe.egg-info/SOURCES.txt +0 -0
  77. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe.egg-info/dependency_links.txt +0 -0
  78. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe.egg-info/requires.txt +0 -0
  79. {iceaxe-0.7.1 → iceaxe-0.8.0}/iceaxe.egg-info/top_level.txt +0 -0
  80. {iceaxe-0.7.1 → iceaxe-0.8.0}/setup.cfg +0 -0
  81. {iceaxe-0.7.1 → iceaxe-0.8.0}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: iceaxe
3
- Version: 0.7.1
3
+ Version: 0.8.0
4
4
  Summary: A modern, fast ORM for Python.
5
5
  Author-email: Pierce Freeman <pierce@freeman.vc>
6
6
  Requires-Python: >=3.11
@@ -262,6 +262,7 @@ async def test_add_column_any_type(
262
262
  (ColumnType.DECIMAL, ColumnType.NUMERIC),
263
263
  (ColumnType.SERIAL, ColumnType.INTEGER),
264
264
  (ColumnType.BIGSERIAL, ColumnType.BIGINT),
265
+ (ColumnType.SMALLSERIAL, ColumnType.SMALLINT),
265
266
  (ColumnType.CHAR, "character"),
266
267
  (ColumnType.TIME_WITHOUT_TIME_ZONE, "time without time zone"),
267
268
  (ColumnType.TIMESTAMP_WITHOUT_TIME_ZONE, "timestamp without time zone"),
@@ -1523,3 +1523,49 @@ def test_multiple_primary_keys_warning():
1523
1523
  assert "multiple fields marked as primary_key=True" in warning_message
1524
1524
  assert "composite primary key constraint" in warning_message
1525
1525
  assert "Consider using only one primary key field" in warning_message
1526
+
1527
+
1528
+ def test_explicit_type_override(clear_all_database_objects):
1529
+ """
1530
+ Test that explicit_type parameter overrides automatic type inference.
1531
+ """
1532
+
1533
+ class TestModel(TableBase):
1534
+ id: int = Field(primary_key=True)
1535
+ # This should be BIGINT instead of INTEGER due to explicit_type
1536
+ big_number: int = Field(explicit_type=ColumnType.BIGINT)
1537
+ # This should be TEXT instead of VARCHAR due to explicit_type
1538
+ long_text: str = Field(explicit_type=ColumnType.TEXT)
1539
+ # This should be JSONB instead of JSON due to explicit_type
1540
+ data: dict = Field(is_json=True, explicit_type=ColumnType.JSONB)
1541
+ # Normal field without explicit_type for comparison
1542
+ normal_field: str = Field()
1543
+
1544
+ migrator = DatabaseMemorySerializer()
1545
+ db_objects = list(migrator.delegate([TestModel]))
1546
+
1547
+ # Extract column definitions
1548
+ columns = [obj for obj, _ in db_objects if isinstance(obj, DBColumn)]
1549
+
1550
+ # Find each column and verify the type
1551
+ big_number_column = next(c for c in columns if c.column_name == "big_number")
1552
+ assert big_number_column.column_type == ColumnType.BIGINT
1553
+ assert not big_number_column.nullable
1554
+
1555
+ long_text_column = next(c for c in columns if c.column_name == "long_text")
1556
+ assert long_text_column.column_type == ColumnType.TEXT
1557
+ assert not long_text_column.nullable
1558
+
1559
+ data_column = next(c for c in columns if c.column_name == "data")
1560
+ assert data_column.column_type == ColumnType.JSONB
1561
+ assert not data_column.nullable
1562
+
1563
+ # Verify normal field still uses automatic inference
1564
+ normal_field_column = next(c for c in columns if c.column_name == "normal_field")
1565
+ assert normal_field_column.column_type == ColumnType.VARCHAR
1566
+ assert not normal_field_column.nullable
1567
+
1568
+ # Verify the id field uses automatic inference (INTEGER)
1569
+ id_column = next(c for c in columns if c.column_name == "id")
1570
+ assert id_column.column_type == ColumnType.INTEGER
1571
+ assert not id_column.nullable
@@ -5,6 +5,7 @@ import pytest
5
5
 
6
6
  from iceaxe.__tests__.conf_models import (
7
7
  ArtifactDemo,
8
+ ComplexDemo,
8
9
  Employee,
9
10
  FunctionDemoModel,
10
11
  UserDemo,
@@ -316,6 +317,13 @@ def test_function_transformations():
316
317
  [],
317
318
  )
318
319
 
320
+ # Test unnest function
321
+ new_query = QueryBuilder().select(func.unnest(ComplexDemo.string_list))
322
+ assert new_query.build() == (
323
+ 'SELECT unnest("complexdemo"."string_list") AS aggregate_0 FROM "complexdemo"',
324
+ [],
325
+ )
326
+
319
327
  # Test type conversion functions
320
328
  new_query = QueryBuilder().select(
321
329
  (
@@ -337,6 +345,157 @@ def test_function_transformations():
337
345
  )
338
346
 
339
347
 
348
+ def test_array_operators():
349
+ # Test ANY operator
350
+ new_query = (
351
+ QueryBuilder()
352
+ .select(ComplexDemo)
353
+ .where(func.any(ComplexDemo.string_list) == "python")
354
+ )
355
+ assert new_query.build() == (
356
+ 'SELECT "complexdemo"."id" AS "complexdemo_id", "complexdemo"."string_list" AS "complexdemo_string_list", '
357
+ '"complexdemo"."json_data" AS "complexdemo_json_data" FROM "complexdemo" WHERE \'python\' = ANY("complexdemo"."string_list")',
358
+ [],
359
+ )
360
+
361
+ # Test ALL operator
362
+ new_query = (
363
+ QueryBuilder()
364
+ .select(ComplexDemo)
365
+ .where(func.all(ComplexDemo.string_list) == "active")
366
+ )
367
+ assert new_query.build() == (
368
+ 'SELECT "complexdemo"."id" AS "complexdemo_id", "complexdemo"."string_list" AS "complexdemo_string_list", '
369
+ '"complexdemo"."json_data" AS "complexdemo_json_data" FROM "complexdemo" WHERE \'active\' = ALL("complexdemo"."string_list")',
370
+ [],
371
+ )
372
+
373
+ # Test array_contains operator (@>)
374
+ new_query = (
375
+ QueryBuilder()
376
+ .select(ComplexDemo)
377
+ .where(
378
+ func.array_contains(ComplexDemo.string_list, ["python", "django"]) == True # noqa: E712
379
+ )
380
+ )
381
+ assert new_query.build() == (
382
+ 'SELECT "complexdemo"."id" AS "complexdemo_id", "complexdemo"."string_list" AS "complexdemo_string_list", '
383
+ '"complexdemo"."json_data" AS "complexdemo_json_data" FROM "complexdemo" WHERE "complexdemo"."string_list" @> ARRAY[\'python\',\'django\'] = $1',
384
+ [True],
385
+ )
386
+
387
+ # Test array_contained_by operator (<@)
388
+ new_query = (
389
+ QueryBuilder()
390
+ .select(ComplexDemo)
391
+ .where(
392
+ func.array_contained_by( # noqa: E712
393
+ ComplexDemo.string_list, ["python", "java", "go", "rust"]
394
+ )
395
+ == True
396
+ )
397
+ )
398
+ assert new_query.build() == (
399
+ 'SELECT "complexdemo"."id" AS "complexdemo_id", "complexdemo"."string_list" AS "complexdemo_string_list", '
400
+ '"complexdemo"."json_data" AS "complexdemo_json_data" FROM "complexdemo" WHERE "complexdemo"."string_list" <@ ARRAY[\'python\',\'java\',\'go\',\'rust\'] = $1',
401
+ [True],
402
+ )
403
+
404
+ # Test array_overlaps operator (&&)
405
+ new_query = (
406
+ QueryBuilder()
407
+ .select(ComplexDemo)
408
+ .where(
409
+ func.array_overlaps( # noqa: E712
410
+ ComplexDemo.string_list, ["python", "data-science", "ml"]
411
+ )
412
+ == True
413
+ )
414
+ )
415
+ assert new_query.build() == (
416
+ 'SELECT "complexdemo"."id" AS "complexdemo_id", "complexdemo"."string_list" AS "complexdemo_string_list", '
417
+ '"complexdemo"."json_data" AS "complexdemo_json_data" FROM "complexdemo" WHERE "complexdemo"."string_list" && ARRAY[\'python\',\'data-science\',\'ml\'] = $1',
418
+ [True],
419
+ )
420
+
421
+
422
+ def test_array_comparison_operators():
423
+ # Test ANY with different operators
424
+ new_query = (
425
+ QueryBuilder()
426
+ .select(ComplexDemo)
427
+ .where(func.any(ComplexDemo.string_list) != "inactive")
428
+ )
429
+ assert new_query.build() == (
430
+ 'SELECT "complexdemo"."id" AS "complexdemo_id", "complexdemo"."string_list" AS "complexdemo_string_list", '
431
+ '"complexdemo"."json_data" AS "complexdemo_json_data" FROM "complexdemo" WHERE \'inactive\' != ANY("complexdemo"."string_list")',
432
+ [],
433
+ )
434
+
435
+ # Test ALL with >= operator
436
+ new_query = (
437
+ QueryBuilder()
438
+ .select(ComplexDemo)
439
+ .where(func.all(ComplexDemo.string_list) >= "a")
440
+ )
441
+ assert new_query.build() == (
442
+ 'SELECT "complexdemo"."id" AS "complexdemo_id", "complexdemo"."string_list" AS "complexdemo_string_list", '
443
+ '"complexdemo"."json_data" AS "complexdemo_json_data" FROM "complexdemo" WHERE \'a\' >= ALL("complexdemo"."string_list")',
444
+ [],
445
+ )
446
+
447
+
448
+ def test_array_manipulation_functions():
449
+ # Test array_append
450
+ new_query = QueryBuilder().select(
451
+ func.array_append(ComplexDemo.string_list, "new-tag")
452
+ )
453
+ assert new_query.build() == (
454
+ 'SELECT array_append("complexdemo"."string_list", \'new-tag\') AS aggregate_0 FROM "complexdemo"',
455
+ [],
456
+ )
457
+
458
+ # Test array_prepend
459
+ new_query = QueryBuilder().select(
460
+ func.array_prepend("featured", ComplexDemo.string_list)
461
+ )
462
+ assert new_query.build() == (
463
+ 'SELECT array_prepend(\'featured\', "complexdemo"."string_list") AS aggregate_0 FROM "complexdemo"',
464
+ [],
465
+ )
466
+
467
+ # Test array_cat with field - this would require a join in practice
468
+ # For now, let's test with a simpler case using the same table
469
+ # or we could test array_cat with a literal array which is more common
470
+
471
+ # Test array_cat with literal array
472
+ new_query = QueryBuilder().select(
473
+ func.array_cat(ComplexDemo.string_list, ["admin", "superuser"])
474
+ )
475
+ assert new_query.build() == (
476
+ 'SELECT array_cat("complexdemo"."string_list", ARRAY[\'admin\',\'superuser\']) AS aggregate_0 FROM "complexdemo"',
477
+ [],
478
+ )
479
+
480
+ # Test array_position
481
+ new_query = QueryBuilder().select(
482
+ func.array_position(ComplexDemo.string_list, "python")
483
+ )
484
+ assert new_query.build() == (
485
+ 'SELECT array_position("complexdemo"."string_list", \'python\') AS aggregate_0 FROM "complexdemo"',
486
+ [],
487
+ )
488
+
489
+ # Test array_remove
490
+ new_query = QueryBuilder().select(
491
+ func.array_remove(ComplexDemo.string_list, "deprecated")
492
+ )
493
+ assert new_query.build() == (
494
+ 'SELECT array_remove("complexdemo"."string_list", \'deprecated\') AS aggregate_0 FROM "complexdemo"',
495
+ [],
496
+ )
497
+
498
+
340
499
  def test_invalid_where_condition():
341
500
  with pytest.raises(ValueError):
342
501
  QueryBuilder().select(UserDemo.id).where("invalid condition") # type: ignore
@@ -76,6 +76,7 @@ class DBModelMetaclass(_model_construction.ModelMetaclass):
76
76
  index=False,
77
77
  check_expression=None,
78
78
  is_json=False,
79
+ explicit_type=None,
79
80
  )
80
81
  for field, info in cls.model_fields.items()
81
82
  }
@@ -19,6 +19,7 @@ from pydantic_core import PydanticUndefined
19
19
  from iceaxe.comparison import ComparisonBase
20
20
  from iceaxe.postgres import PostgresFieldBase
21
21
  from iceaxe.queries_str import QueryIdentifier, QueryLiteral
22
+ from iceaxe.sql_types import ColumnType
22
23
 
23
24
  if TYPE_CHECKING:
24
25
  from iceaxe.base import TableBase
@@ -37,6 +38,7 @@ class DBFieldInputs(_FieldInfoInputs, total=False):
37
38
  index: bool
38
39
  check_expression: str | None
39
40
  is_json: bool
41
+ explicit_type: ColumnType | None
40
42
 
41
43
 
42
44
  class DBFieldInfo(FieldInfo):
@@ -97,6 +99,12 @@ class DBFieldInfo(FieldInfo):
97
99
  When True, the field's value will be JSON serialized before storage.
98
100
  """
99
101
 
102
+ explicit_type: ColumnType | None = None
103
+ """
104
+ Explicitly specify the SQL column type for this field.
105
+ When set, this type takes precedence over automatic type inference.
106
+ """
107
+
100
108
  def __init__(self, **kwargs: Unpack[DBFieldInputs]):
101
109
  """
102
110
  Initialize a new DBFieldInfo instance with the given field configuration.
@@ -119,6 +127,7 @@ class DBFieldInfo(FieldInfo):
119
127
  self.index = kwargs.pop("index", False)
120
128
  self.check_expression = kwargs.pop("check_expression", None)
121
129
  self.is_json = kwargs.pop("is_json", False)
130
+ self.explicit_type = kwargs.pop("explicit_type", None)
122
131
 
123
132
  @classmethod
124
133
  def extend_field(
@@ -131,6 +140,7 @@ class DBFieldInfo(FieldInfo):
131
140
  index: bool,
132
141
  check_expression: str | None,
133
142
  is_json: bool,
143
+ explicit_type: ColumnType | None,
134
144
  ):
135
145
  """
136
146
  Helper function to extend a Pydantic FieldInfo with database-specific attributes.
@@ -144,6 +154,7 @@ class DBFieldInfo(FieldInfo):
144
154
  index=index,
145
155
  check_expression=check_expression,
146
156
  is_json=is_json,
157
+ explicit_type=explicit_type,
147
158
  **field._attributes_set, # type: ignore
148
159
  )
149
160
 
@@ -168,6 +179,7 @@ def __get_db_field(_: Callable[Concatenate[Any, P], Any] = PydanticField): # ty
168
179
  index: bool = False,
169
180
  check_expression: str | None = None,
170
181
  is_json: bool = False,
182
+ explicit_type: ColumnType | None = None,
171
183
  default: Any = _Unset,
172
184
  default_factory: (
173
185
  Callable[[], Any] | Callable[[dict[str, Any]], Any] | None
@@ -192,6 +204,7 @@ def __get_db_field(_: Callable[Concatenate[Any, P], Any] = PydanticField): # ty
192
204
  index=index,
193
205
  check_expression=check_expression,
194
206
  is_json=is_json,
207
+ explicit_type=explicit_type,
195
208
  ),
196
209
  )
197
210