ormlambda 4.4.4__tar.gz → 4.4.14__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.
Files changed (146) hide show
  1. {ormlambda-4.4.4 → ormlambda-4.4.14}/PKG-INFO +8 -4
  2. {ormlambda-4.4.4 → ormlambda-4.4.14}/README.md +2 -2
  3. {ormlambda-4.4.4 → ormlambda-4.4.14}/pyproject.toml +1 -1
  4. ormlambda-4.4.14/src/ormlambda/common/constants.py +1 -0
  5. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/common/errors/__init__.py +10 -0
  6. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/base.py +31 -30
  7. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/repository/repository.py +0 -2
  8. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/clause_info/clause_info.py +90 -74
  9. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/column/column.py +20 -15
  10. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/compiler.py +6 -1
  11. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/ddl.py +2 -2
  12. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/sqltypes.py +3 -0
  13. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/table/table.py +2 -2
  14. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/statements/interfaces/IStatements.py +11 -3
  15. ormlambda-4.4.4/src/ormlambda/common/constants.py +0 -1
  16. {ormlambda-4.4.4 → ormlambda-4.4.14}/AUTHORS +0 -0
  17. {ormlambda-4.4.4 → ormlambda-4.4.14}/LICENSE +0 -0
  18. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/__init__.py +0 -0
  19. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/caster/__init__.py +0 -0
  20. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/caster/base_caster.py +0 -0
  21. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/caster/caster.py +0 -0
  22. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/caster/interfaces/ICaster.py +0 -0
  23. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/caster/interfaces/__init__.py +0 -0
  24. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/common/__init__.py +0 -0
  25. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/common/enums/__init__.py +0 -0
  26. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/common/enums/condition_types.py +0 -0
  27. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/common/enums/join_type.py +0 -0
  28. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/common/enums/order_type.py +0 -0
  29. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/common/enums/union_type.py +0 -0
  30. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/common/global_checker.py +0 -0
  31. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/common/interfaces/IJoinSelector.py +0 -0
  32. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/common/interfaces/IQueryCommand.py +0 -0
  33. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/common/interfaces/__init__.py +0 -0
  34. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/dialects/__init__.py +0 -0
  35. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/dialects/default/__init__.py +0 -0
  36. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/dialects/default/base.py +0 -0
  37. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/__init__.py +0 -0
  38. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/caster/__init__.py +0 -0
  39. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/caster/caster.py +0 -0
  40. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/caster/types/__init__.py +0 -0
  41. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/caster/types/boolean.py +0 -0
  42. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/caster/types/bytes.py +0 -0
  43. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/caster/types/date.py +0 -0
  44. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/caster/types/datetime.py +0 -0
  45. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/caster/types/decimal.py +0 -0
  46. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/caster/types/float.py +0 -0
  47. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/caster/types/int.py +0 -0
  48. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/caster/types/iterable.py +0 -0
  49. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/caster/types/json.py +0 -0
  50. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/caster/types/none.py +0 -0
  51. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/caster/types/point.py +0 -0
  52. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/caster/types/string.py +0 -0
  53. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/clauses/ST_AsText.py +0 -0
  54. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/clauses/ST_Contains.py +0 -0
  55. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/clauses/__init__.py +0 -0
  56. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/mysqlconnector.py +0 -0
  57. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/repository/__init__.py +0 -0
  58. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/repository/pool_types.py +0 -0
  59. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/types.py +0 -0
  60. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/dialects/sqlite/__init__.py +0 -0
  61. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/dialects/sqlite/base.py +0 -0
  62. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/dialects/sqlite/pysqlite.py +0 -0
  63. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/engine/__init__.py +0 -0
  64. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/engine/base.py +0 -0
  65. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/engine/create.py +0 -0
  66. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/engine/url.py +0 -0
  67. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/engine/utils.py +0 -0
  68. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/env.py +0 -0
  69. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/model/__init__.py +0 -0
  70. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/model/base_model.py +0 -0
  71. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/repository/__init__.py +0 -0
  72. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/repository/base_repository.py +0 -0
  73. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/repository/interfaces/IDatabaseConnection.py +0 -0
  74. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/repository/interfaces/IRepositoryBase.py +0 -0
  75. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/repository/interfaces/__init__.py +0 -0
  76. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/repository/response.py +0 -0
  77. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/__init__.py +0 -0
  78. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/clause_info/__init__.py +0 -0
  79. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/clause_info/interface/IClauseInfo.py +0 -0
  80. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/clause_info/interface/__init__.py +0 -0
  81. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/clauses/__init__.py +0 -0
  82. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/clauses/alias.py +0 -0
  83. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/clauses/delete.py +0 -0
  84. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/clauses/group_by.py +0 -0
  85. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/clauses/having.py +0 -0
  86. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/clauses/insert.py +0 -0
  87. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/clauses/join/__init__.py +0 -0
  88. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/clauses/join/join_context.py +0 -0
  89. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/clauses/joins.py +0 -0
  90. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/clauses/limit.py +0 -0
  91. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/clauses/offset.py +0 -0
  92. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/clauses/order.py +0 -0
  93. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/clauses/select.py +0 -0
  94. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/clauses/update.py +0 -0
  95. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/clauses/upsert.py +0 -0
  96. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/clauses/where.py +0 -0
  97. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/column/__init__.py +0 -0
  98. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/column/column_proxy.py +0 -0
  99. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/column/metadata.py +0 -0
  100. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/column_table_proxy.py +0 -0
  101. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/comparer.py +0 -0
  102. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/context/__init__.py +0 -0
  103. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/elements.py +0 -0
  104. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/foreign_key.py +0 -0
  105. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/functions/__init__.py +0 -0
  106. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/functions/aggregate/__init__.py +0 -0
  107. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/functions/aggregate/avg.py +0 -0
  108. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/functions/aggregate/concat.py +0 -0
  109. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/functions/aggregate/count.py +0 -0
  110. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/functions/aggregate/max.py +0 -0
  111. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/functions/aggregate/min.py +0 -0
  112. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/functions/aggregate/sum.py +0 -0
  113. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/functions/base.py +0 -0
  114. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/functions/datetime/__init__.py +0 -0
  115. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/functions/interface/__init__.py +0 -0
  116. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/functions/mathematical/__init__.py +0 -0
  117. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/functions/mathematical/abs.py +0 -0
  118. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/functions/mathematical/ceil.py +0 -0
  119. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/functions/mathematical/floor.py +0 -0
  120. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/functions/mathematical/mod.py +0 -0
  121. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/functions/mathematical/pow.py +0 -0
  122. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/functions/mathematical/rand.py +0 -0
  123. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/functions/mathematical/round.py +0 -0
  124. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/functions/mathematical/sqrt.py +0 -0
  125. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/functions/mathematical/truncate.py +0 -0
  126. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/functions/string/__init__.py +0 -0
  127. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/table/__init__.py +0 -0
  128. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/table/fields.py +0 -0
  129. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/table/table_constructor.py +0 -0
  130. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/table/table_proxy.py +0 -0
  131. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/type_api.py +0 -0
  132. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/types.py +0 -0
  133. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/sql/visitors.py +0 -0
  134. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/statements/__init__.py +0 -0
  135. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/statements/base_statement.py +0 -0
  136. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/statements/interfaces/__init__.py +0 -0
  137. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/statements/query_builder.py +0 -0
  138. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/statements/statements.py +0 -0
  139. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/statements/types.py +0 -0
  140. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/util/__init__.py +0 -0
  141. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/util/langhelpers.py +0 -0
  142. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/util/module_tree/__init__.py +0 -0
  143. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/util/module_tree/dfs_traversal.py +0 -0
  144. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/util/module_tree/dynamic_module.py +0 -0
  145. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/util/preloaded.py +0 -0
  146. {ormlambda-4.4.4 → ormlambda-4.4.14}/src/ormlambda/util/typing.py +0 -0
@@ -1,12 +1,16 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: ormlambda
3
- Version: 4.4.4
3
+ Version: 4.4.14
4
4
  Summary: ORM designed to interact with the database (currently with MySQL) using lambda functions and nested functions
5
+ License-File: AUTHORS
6
+ License-File: LICENSE
5
7
  Author: p-hzamora
6
8
  Author-email: p.hzamora@icloud.com
7
9
  Requires-Python: >=3.12,<4.0
8
10
  Classifier: Programming Language :: Python :: 3
9
11
  Classifier: Programming Language :: Python :: 3.12
12
+ Classifier: Programming Language :: Python :: 3.13
13
+ Classifier: Programming Language :: Python :: 3.14
10
14
  Requires-Dist: mysql-connector-python (>=9.0.0,<10.0.0)
11
15
  Requires-Dist: shapely (>=2.0.6,<3.0.0)
12
16
  Description-Content-Type: text/markdown
@@ -76,7 +80,7 @@ db = create_engine('mysql://root:1234@localhost:3306/sakila')
76
80
 
77
81
  AddressModel = ORM(Address, db)
78
82
 
79
- result = AddressModel.where(Address.City.Country.country.regex(r"^[aA]")).select(
83
+ result = AddressModel.where(lambda x: x.City.Country.country.regex(r"^[aA]")).select(
80
84
  lambda address: (
81
85
  address,
82
86
  address.City,
@@ -104,7 +108,7 @@ result = AddressModel.where(
104
108
  Additionally, we can filter by others tables. For example, we can return all addresses for each city where `country_id` = 87 (Spain)
105
109
 
106
110
  ```python
107
- result = AddressModel.where(Address.City.Country.country_id == 87).select()
111
+ result = AddressModel.where(lambda x: x.City.Country.country_id == 87).select()
108
112
  ```
109
113
 
110
114
  We can also return `Address`, `City` or `Country` if needed.
@@ -63,7 +63,7 @@ db = create_engine('mysql://root:1234@localhost:3306/sakila')
63
63
 
64
64
  AddressModel = ORM(Address, db)
65
65
 
66
- result = AddressModel.where(Address.City.Country.country.regex(r"^[aA]")).select(
66
+ result = AddressModel.where(lambda x: x.City.Country.country.regex(r"^[aA]")).select(
67
67
  lambda address: (
68
68
  address,
69
69
  address.City,
@@ -91,7 +91,7 @@ result = AddressModel.where(
91
91
  Additionally, we can filter by others tables. For example, we can return all addresses for each city where `country_id` = 87 (Spain)
92
92
 
93
93
  ```python
94
- result = AddressModel.where(Address.City.Country.country_id == 87).select()
94
+ result = AddressModel.where(lambda x: x.City.Country.country_id == 87).select()
95
95
  ```
96
96
 
97
97
  We can also return `Address`, `City` or `Country` if needed.
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "ormlambda"
3
- version = "4.4.4"
3
+ version = "4.4.14"
4
4
  description = "ORM designed to interact with the database (currently with MySQL) using lambda functions and nested functions"
5
5
  authors = ["p-hzamora <p.hzamora@icloud.com>"]
6
6
  readme = "README.md"
@@ -0,0 +1 @@
1
+ DOT = "."
@@ -9,6 +9,16 @@ if tp.TYPE_CHECKING:
9
9
  from ormlambda.sql import Column
10
10
 
11
11
 
12
+ class ReplacePlaceholderError(ValueError):
13
+ def __init__(self, placeholder: str, attribute: str, *args):
14
+ super().__init__(*args)
15
+ self.placeholder: str = placeholder
16
+ self.attr: str = attribute
17
+
18
+ def __str__(self):
19
+ return "You cannot use {" + self.placeholder + "} placeholder without using '" + self.attr + "' attribute"
20
+
21
+
12
22
  class UnmatchedLambdaParameterError(Exception):
13
23
  def __init__(self, expected_params: int, function: tp.Callable[..., tp.Any], *args: object) -> None:
14
24
  super().__init__(*args)
@@ -11,15 +11,6 @@ from .. import default
11
11
  from typing import TYPE_CHECKING, Any, Iterable, Type
12
12
  from ormlambda.sql.comparer import Comparer, ComparerCluster
13
13
 
14
- if TYPE_CHECKING:
15
- from ormlambda.sql.functions.interface import IFunction
16
- from ormlambda.sql.types import ColumnType
17
- from test.test_clause_info import ST_Contains
18
- from ormlambda import JoinSelector
19
- from ormlambda.sql.column.column import Column
20
- from mysql import connector
21
- from ormlambda.dialects.mysql.clauses import ST_AsText
22
-
23
14
  from .types import (
24
15
  _NumericType,
25
16
  _NumericCommonType,
@@ -64,6 +55,14 @@ from .repository import MySQLRepository
64
55
 
65
56
 
66
57
  if TYPE_CHECKING:
58
+ from ormlambda.sql.functions.interface import IFunction
59
+ from ormlambda.sql.types import ColumnType
60
+ from test.test_clause_info import ST_Contains
61
+ from ormlambda import JoinSelector
62
+ from ormlambda.sql.column.column import Column
63
+ from mysql import connector
64
+ from ormlambda.dialects.mysql.clauses import ST_AsText
65
+
67
66
  from ormlambda.sql.clauses import (
68
67
  Select,
69
68
  Insert,
@@ -101,15 +100,12 @@ class MySQLCompiler(compiler.SQLCompiler):
101
100
  render_table_with_column_in_update_from = True
102
101
  """Overridden from base SQLCompiler value"""
103
102
 
104
- def visit_table(self, table: Table):
105
- return ClauseInfo(table=table, dialect=self.dialect).query(dialect=self.dialect)
106
-
107
103
  def visit_table_proxy(self, table: TableProxy, **kw) -> str:
108
104
  param = {
109
- "table": None,
110
- "column": table._table_class.__table_name__,
111
- "dialect": self.dialect,
105
+ "table": table._table_class,
106
+ "column": None,
112
107
  "alias_clause": alias if (alias := table.get_table_chain()) else None,
108
+ "dialect": self.dialect,
113
109
  **kw,
114
110
  }
115
111
  return ClauseInfo(**param).query(dialect=self.dialect)
@@ -132,7 +128,7 @@ class MySQLCompiler(compiler.SQLCompiler):
132
128
  params = {
133
129
  "table": column.table,
134
130
  "column": column,
135
- "alias_table": alias_table if alias_table else "{table}",
131
+ "alias_table": alias_table,
136
132
  "alias_clause": column.alias or "{column}",
137
133
  "dtype": column._column.dtype,
138
134
  "dialect": self.dialect,
@@ -216,9 +212,9 @@ class MySQLCompiler(compiler.SQLCompiler):
216
212
  rt = join.rcon.table
217
213
  rtable = TableProxy(table_class=rt, path=join.rcon.path)
218
214
 
219
- from_clause = rtable.compile(self.dialect, alias_clause=join.alias).string
215
+ from_clause = rtable.compile(self.dialect, alias_table=join.alias, first_apperance=True).string
220
216
  left_table_clause = join.lcon.compile(self.dialect, alias_clause=None).string
221
- right_table_clause = join.rcon.compile(self.dialect, alias_table=join.alias, alias_clause=None).string
217
+ right_table_clause = join.rcon.compile(self.dialect, alias_clause=None).string
222
218
  list_ = [
223
219
  join._by.value, # inner join
224
220
  from_clause,
@@ -242,9 +238,11 @@ class MySQLCompiler(compiler.SQLCompiler):
242
238
  columns = ClauseInfo.join_clauses(select.columns, sep, dialect=self.dialect, **params)
243
239
 
244
240
  from_ = ClauseInfo(
245
- select._table,
246
- None,
241
+ table=select._table,
242
+ column=None,
243
+ alias_table="{table}",
247
244
  dialect=self.dialect,
245
+ first_apperance=True,
248
246
  ).query(self.dialect)
249
247
 
250
248
  return f"SELECT{sep}{columns}{sep}FROM {from_}"
@@ -467,7 +465,7 @@ class MySQLCompiler(compiler.SQLCompiler):
467
465
  else:
468
466
  column = count.column
469
467
 
470
- return ClauseInfo.concat_alias_and_column(f"COUNT({column})", count.alias)
468
+ return ClauseInfo.concat_clause_with_his_alias(f"COUNT({column})", count.alias)
471
469
 
472
470
  def visit_order(self, order: Order, **kw) -> str:
473
471
  ORDER = "ORDER BY"
@@ -514,10 +512,10 @@ class MySQLCompiler(compiler.SQLCompiler):
514
512
  clause_info = ClauseInfo(
515
513
  table=None,
516
514
  column=f"CONCAT({', '.join(columns)})",
517
- alias_clause=concat.alias,
518
515
  dialect=self.dialect,
516
+ literal=True
519
517
  )
520
- return clause_info.query(self.dialect)
518
+ return f"{clause_info.query(self.dialect)} AS {ClauseInfo.wrapped_with_quotes(concat.alias)}"
521
519
 
522
520
  def visit_max(self, obj: Max, **kw) -> str:
523
521
  return self._compile_aggregate_method("MAX", obj, **kw)
@@ -546,7 +544,7 @@ class MySQLCompiler(compiler.SQLCompiler):
546
544
  def visit_pow(self, obj: Pow, **kw) -> str:
547
545
  attr = {**kw, "alias_clause": None}
548
546
  column = obj.column.compile(self.dialect, **attr).string
549
- return ClauseInfo.concat_alias_and_column(f"POW({column}, {obj._exponent})", obj.alias)
547
+ return ClauseInfo.concat_clause_with_his_alias(f"POW({column}, {obj._exponent})", obj.alias)
550
548
 
551
549
  def visit_sqrt(self, obj: Sqrt, **kw) -> str:
552
550
  return self._compile_aggregate_method("SQRT", obj, **kw)
@@ -554,7 +552,7 @@ class MySQLCompiler(compiler.SQLCompiler):
554
552
  def visit_mod(self, obj: Mod, **kw) -> str:
555
553
  attr = {**kw, "alias_clause": None}
556
554
  column = obj.column.compile(self.dialect, **attr).string
557
- return ClauseInfo.concat_alias_and_column(f"MOD({column}, {obj._divisor})", obj.alias)
555
+ return ClauseInfo.concat_clause_with_his_alias(f"MOD({column}, {obj._divisor})", obj.alias)
558
556
 
559
557
  def visit_rand(self, obj: Rand, **kw) -> str:
560
558
  return self._compile_aggregate_method("RAND", obj, **kw)
@@ -562,22 +560,24 @@ class MySQLCompiler(compiler.SQLCompiler):
562
560
  def visit_truncate(self, obj: Truncate, **kw) -> str:
563
561
  attr = {**kw, "alias_clause": None}
564
562
  column = obj.column.compile(self.dialect, **attr).string
565
- return ClauseInfo.concat_alias_and_column(f"TRUNCATE({column}, {obj._decimal})", obj.alias)
563
+ return ClauseInfo.concat_clause_with_his_alias(f"TRUNCATE({column}, {obj._decimal})", obj.alias)
566
564
 
567
565
  def _compile_aggregate_method(self, name: str, function: IFunction, **kw) -> str:
568
566
  attr = {**kw, "alias_clause": None}
569
567
  column = function.column.compile(self.dialect, **attr).string
570
- return ClauseInfo.concat_alias_and_column(f"{name}({column})", function.alias)
568
+ return ClauseInfo.concat_clause_with_his_alias(f"{name}({column})", function.alias)
571
569
 
572
570
  def visit_st_astext(self, st_astext: ST_AsText) -> str:
573
571
  # avoid use placeholder when using IFunction because no make sense.
574
572
  if st_astext.alias and (found := ClauseInfo._keyRegex.findall(st_astext.alias)):
575
573
  raise NotKeysInIFunctionError(found)
576
- return ClauseInfo.concat_alias_and_column(f"ST_AsText({st_astext.column.compile(self.dialect, alias_clause=None).string})", st_astext.alias)
574
+ return ClauseInfo.concat_clause_with_his_alias(f"ST_AsText({st_astext.column.compile(self.dialect, alias_clause=None).string})", st_astext.alias)
577
575
 
578
576
  def visit_st_contains(self, st_contains: ST_Contains) -> str:
577
+ # FIXME [ ]: It's not working as expected. Should be something like
578
+ # ST_Contains(`table_type`.points, ST_GeomFromText(%s))
579
579
  attr1 = st_contains.column.compile(self.dialect, alias_clause=None).string
580
- attr2 = ClauseInfo(None, st_contains.point, dialect=self.dialect).query(self.dialect, alias_clause=None)
580
+ attr2 = ClauseInfo(None, st_contains.point, dialect=self.dialect).query(self.dialect)
581
581
  return f"ST_Contains({attr1}, {attr2})"
582
582
 
583
583
 
@@ -602,7 +602,8 @@ class MySQLDDLCompiler(compiler.DDLCompiler):
602
602
  compare = fk.resolved_function()
603
603
  lcon = compare.left_condition
604
604
  rcon = compare.right_condition
605
- return f"FOREIGN KEY ({lcon.column_name}) REFERENCES {rcon.table.__table_name__}({rcon.column_name})"
605
+ rdb = f"{ClauseInfo.wrapped_with_quotes(db)}." if (db := compare.right_condition.table.__db_name__) else ""
606
+ return f"FOREIGN KEY ({lcon.column_name}) REFERENCES {rdb}{rcon.table.__table_name__}({rcon.column_name})"
606
607
 
607
608
 
608
609
  class MySQLTypeCompiler(compiler.GenericTypeCompiler):
@@ -187,8 +187,6 @@ class MySQLRepository(BaseRepository[MySQLConnectionPool]):
187
187
  @override
188
188
  def table_exists(self, name: str) -> bool:
189
189
  with self.get_connection() as cnx:
190
- if not cnx.database:
191
- raise Exception("No database selected")
192
190
  with cnx.cursor(buffered=True) as cursor:
193
191
  cursor.execute(f"SHOW TABLES LIKE {Caster.PLACEHOLDER};", (name,))
194
192
  res = cursor.fetchmany(1)
@@ -4,7 +4,7 @@ import typing as tp
4
4
  import re
5
5
 
6
6
  from ormlambda.sql.types import ASTERISK
7
- from ormlambda.common.errors import DuplicatedClauseNameError
7
+ from ormlambda.common.errors import DuplicatedClauseNameError, ReplacePlaceholderError
8
8
  from .interface import IClauseInfo
9
9
  from ormlambda.common import GlobalChecker, DOT
10
10
  from ormlambda import util
@@ -19,16 +19,6 @@ if tp.TYPE_CHECKING:
19
19
  from ormlambda.dialects import Dialect
20
20
 
21
21
 
22
- class ReplacePlaceholderError(ValueError):
23
- def __init__(self, placeholder: str, attribute: str, *args):
24
- super().__init__(*args)
25
- self.placeholder: str = placeholder
26
- self.attr: str = attribute
27
-
28
- def __str__(self):
29
- return "You cannot use {" + self.placeholder + "} placeholder without using '" + self.attr + "' attribute"
30
-
31
-
32
22
  class ClauseInfo[T: Table](IClauseInfo[T]):
33
23
  _keyRegex: re.Pattern = re.compile(r"{([^{}:]+)}")
34
24
 
@@ -43,11 +33,11 @@ class ClauseInfo[T: Table](IClauseInfo[T]):
43
33
  @tp.overload
44
34
  def __init__(self, table: TableType[T], keep_asterisk: tp.Optional[bool] = ...): ...
45
35
  @tp.overload
46
- def __init__(self, table: TableType[T], preserve_context: tp.Optional[bool] = ...): ...
47
- @tp.overload
48
36
  def __init__[TProp](self, table: TableType[T], dtype: tp.Optional[TProp] = ...): ...
49
37
  @tp.overload
50
38
  def __init__(self, table: TableType[T], literal: bool = ...): ...
39
+ @tp.overload
40
+ def __init__(self, table: TableType[T], first_apperance: bool = ...): ...
51
41
 
52
42
  @tp.overload
53
43
  def __init__(self, dialect: Dialect, *args, **kwargs): ...
@@ -59,9 +49,9 @@ class ClauseInfo[T: Table](IClauseInfo[T]):
59
49
  alias_table: tp.Optional[AliasType[ColumnProxy]] = None,
60
50
  alias_clause: tp.Optional[AliasType[ColumnProxy]] = None,
61
51
  keep_asterisk: bool = False,
62
- preserve_context: bool = False,
63
52
  dtype: tp.Optional[TProp] = None,
64
53
  literal: bool = False,
54
+ first_apperance: bool = False,
65
55
  *,
66
56
  dialect: Dialect,
67
57
  **kw,
@@ -75,21 +65,22 @@ class ClauseInfo[T: Table](IClauseInfo[T]):
75
65
  self._alias_table: tp.Optional[AliasType[ColumnProxy]] = alias_table
76
66
  self._alias_clause: tp.Optional[AliasType[ColumnProxy]] = alias_clause
77
67
  self._keep_asterisk: bool = keep_asterisk
78
- self._preserve_context: bool = preserve_context
79
68
  self._dtype = dtype
80
69
  self._literal = literal
70
+ self._first_apperance = first_apperance
81
71
 
82
72
  self._dialect: Dialect = dialect
83
73
 
84
74
  self._placeholderValues: dict[str, tp.Callable[[TProp], str]] = {
85
75
  "column": self.replace_column_placeholder,
86
76
  "table": self.replace_table_placeholder,
77
+ "db": self.replace_db_placeholder,
87
78
  }
88
79
 
89
80
  super().__init__(**kw)
90
81
 
91
82
  def __repr__(self) -> str:
92
- return f"{type(self).__name__}: query -> {self.query(self._dialect)}"
83
+ return f"{type(self).__name__}: {self.table}->{self.column}"
93
84
 
94
85
  def replace_column_placeholder[TProp](self, column: ColumnType[TProp]) -> str:
95
86
  if not column:
@@ -97,15 +88,35 @@ class ClauseInfo[T: Table](IClauseInfo[T]):
97
88
  return self._column_resolver(column)
98
89
 
99
90
  def replace_table_placeholder[TProp](self, _: ColumnType[TProp]) -> str:
100
- if not self.table:
91
+ if not self._table:
101
92
  raise ReplacePlaceholderError("table", "table")
102
- return self.table.__table_name__
103
93
 
94
+ # We need to return the name itself without database because we're using it to replace {table} not {db}
95
+ return self._table.__table_name__
96
+
97
+ def replace_db_placeholder[TProp](self, _: ColumnType[TProp]) -> str:
98
+ if not self._table:
99
+ raise ReplacePlaceholderError("db", "table")
100
+
101
+ # We need to return the name itself without database because we're using it to replace {table} not {db}
102
+ return self._table.__db_name__
103
+
104
+ @util.preload_module("ormlambda.sql")
104
105
  @property
105
- def table(self) -> TableType[T]:
106
+ def table(self) -> str:
107
+ if not self._first_apperance and self.alias_table:
108
+ return self.wrapped_with_quotes(self.alias_table)
109
+
110
+ ForeignKey = util.preloaded.sql_foreign_key.ForeignKey
106
111
  if self.is_foreign_key(self._table):
107
- return self._table.tright
108
- return self._table
112
+ table = tp.cast(ForeignKey, self._table).tright
113
+ else:
114
+ table = self._table
115
+
116
+ if not table:
117
+ return None
118
+
119
+ return table.__table_name__ if not table.__db_name__ else self.join_db_and_table(table)
109
120
 
110
121
  @table.setter
111
122
  def table(self, value: TableType[T]) -> None:
@@ -113,26 +124,34 @@ class ClauseInfo[T: Table](IClauseInfo[T]):
113
124
 
114
125
  @property
115
126
  def alias_clause(self) -> tp.Optional[str]:
116
- alias = self._alias_clause
117
- return self._alias_resolver(alias)
127
+ """
128
+ It must be conditioned by the column. If no columns is set and an alias_clause is specified, the alias will not be applied.
129
+ """
130
+ if not self.column:
131
+ return None
132
+ return self._alias_resolver(self._alias_clause)
118
133
 
119
- # TODOL [ ]: if we using this setter, we don't update the _context with the new value. Study if it's necessary
120
134
  @alias_clause.setter
121
135
  def alias_clause(self, value: str) -> str:
122
136
  self._alias_clause = value
123
137
 
124
138
  @property
125
139
  def alias_table(self) -> tp.Optional[str]:
126
- alias = self._alias_table
140
+ return self._alias_resolver(self._alias_table)
127
141
 
128
- return self._alias_resolver(alias)
129
-
130
-
131
- # TODOL [ ]: if we using this setter, we don't update the _context with the new value. Study if it's necessary
132
142
  @alias_table.setter
133
143
  def alias_table(self, value: str) -> str:
134
144
  self._alias_table = value
135
145
 
146
+ def _alias_resolver(self, alias: AliasType[ColumnProxy]) -> tp.Optional[str]:
147
+ if alias is None:
148
+ return None
149
+
150
+ if callable(alias):
151
+ return self._alias_resolver(alias(self._column))
152
+
153
+ return self._replace_placeholder(alias)
154
+
136
155
  def replaced_alias(self, value: str) -> tp.Optional[str]:
137
156
  return value
138
157
 
@@ -164,7 +183,7 @@ class ClauseInfo[T: Table](IClauseInfo[T]):
164
183
  return self._dtype
165
184
 
166
185
  if isinstance(self._column, Column):
167
- return self._column.dbtype
186
+ return self._column.dtype
168
187
 
169
188
  if isinstance(self._column, type):
170
189
  return self._column
@@ -176,36 +195,40 @@ class ClauseInfo[T: Table](IClauseInfo[T]):
176
195
  def compile(self, dialect: Dialect, **kwargs) -> str:
177
196
  return self._create_query(dialect, **kwargs)
178
197
 
179
- def _create_query(self, dialect: Dialect, **kwargs) -> str:
198
+ def _create_query(self, dialect: Dialect) -> str:
180
199
  # when passing some value that is not a column name
181
- if not self.table and not self._alias_clause:
182
- return self.column
183
-
184
- if not self.table and self._alias_clause:
185
- # it means that we are passing an object with alias. We should delete '' around the object
186
- alias_clause = self.alias_clause
187
- return self.concat_alias_and_column(self._column, alias_clause)
188
200
 
189
- # When passing the Table itself without 'column'
190
- if self.table and not self._column:
191
- if not self._alias_table:
192
- return self.join_db_and_table(self.table)
201
+ table = self.table
202
+ column = self.column
193
203
 
194
- alias_table = self.alias_table
195
- return self.concat_alias_and_column(self.table.__table_name__, alias_table)
204
+ if self._first_apperance:
205
+ return self.concat_clause_with_his_alias(table, self.alias_table)
196
206
 
197
207
  if self._return_all_columns():
198
208
  return self._get_all_columns(dialect)
199
- return self._join_table_and_column(self._column, dialect)
200
209
 
201
- @classmethod
202
- def join_db_and_table(cls, table: str| Table, table_name: tp.Optional[str] = None) -> str:
203
- table_name = table.__table_name__ if (not table_name and hasattr(table,"__table_name__")) else table_name
210
+ if not table:
211
+ return column
212
+
213
+ if not column:
214
+ if self.alias_clause:
215
+ return self.concat_clause_with_his_alias(table, self.alias_clause)
216
+ return table
217
+
218
+ clause = f"{table}{DOT}{column}"
204
219
 
205
- db = table.__db_name__ if hasattr(table,"__db_name__") else None
220
+ caster = dialect.caster()
221
+
222
+ dtype = str if self.is_table(self.dtype) else self.dtype
223
+ wrapped_clause = caster.for_value(clause, dtype).wildcard_to_select(clause)
224
+ return self.concat_clause_with_his_alias(wrapped_clause, self.alias_clause)
206
225
 
207
- wrapped_table = cls.wrapped_with_quotes(table_name)
226
+ @classmethod
227
+ def join_db_and_table(cls, table: Table) -> str:
228
+ db = table.__db_name__
229
+ tbl = table.__table_name__
208
230
 
231
+ wrapped_table = cls.wrapped_with_quotes(tbl)
209
232
  if db:
210
233
  wrapped_db = cls.wrapped_with_quotes(db)
211
234
  return f"{wrapped_db}{DOT}{wrapped_table}"
@@ -216,24 +239,24 @@ class ClauseInfo[T: Table](IClauseInfo[T]):
216
239
  def _join_table_and_column[TProp](self, column: ColumnType[TProp], dialect: Dialect) -> str:
217
240
  ColumnProxy = util.preloaded.sql_column.ColumnProxy
218
241
 
219
- caster = dialect.caster()
242
+ # Avoid adding 'database name' when we have alias_table
220
243
 
221
- if self.alias_table:
222
- col = column.table if hasattr(column, "table") else column
223
- table = self.join_db_and_table(col, self.alias_table)
224
- elif isinstance(column, ColumnProxy):
244
+ if isinstance(column, ColumnProxy):
225
245
  table_name: str = column.get_table_chain()
226
- table = self.join_db_and_table(column.table, table_name)
246
+
247
+ self.alias_table = table_name
227
248
  else:
228
- table = self.table.__table_name__
249
+ table = self.table
229
250
 
230
251
  column: str = self._column_resolver(column)
231
252
 
232
253
  table_column = f"{table}{DOT}{column}"
233
254
 
255
+ caster = dialect.caster()
256
+
234
257
  dtype = str if self.is_table(self.dtype) else self.dtype
235
258
  wrapped_column = caster.for_value(table_column, dtype).wildcard_to_select(table_column)
236
- return self.concat_alias_and_column(wrapped_column, self.alias_clause)
259
+ return self.concat_clause_with_his_alias(wrapped_column, self.alias_clause)
237
260
 
238
261
  def _return_all_columns(self) -> bool:
239
262
  if self._keep_asterisk:
@@ -251,7 +274,7 @@ class ClauseInfo[T: Table](IClauseInfo[T]):
251
274
  def _get_all_columns(self, dialect: Dialect) -> str:
252
275
  def ClauseCreator(column: str) -> ClauseInfo:
253
276
  return ClauseInfo(
254
- table=self.table,
277
+ table=self._table,
255
278
  column=column,
256
279
  alias_table=self._alias_table,
257
280
  alias_clause=self._alias_clause,
@@ -262,12 +285,14 @@ class ClauseInfo[T: Table](IClauseInfo[T]):
262
285
  if self._alias_table and self._alias_clause: # We'll add an "*" when we are certain that we have included 'alias_clause' attr
263
286
  return self._join_table_and_column(ASTERISK, dialect)
264
287
 
265
- columns: list[ClauseInfo] = [ClauseCreator(column).query(dialect) for column in self.table.get_columns()]
288
+ columns: list[ClauseInfo] = [ClauseCreator(column).query(dialect) for column in self._table.get_columns()]
266
289
 
267
290
  return ", ".join(columns)
268
291
 
269
- # FIXME [x]: Study how to deacoplate from mysql database
270
292
  def _column_resolver[TProp](self, column: ColumnType[TProp]) -> str:
293
+ if not column:
294
+ return None
295
+
271
296
  if isinstance(column, ClauseInfo):
272
297
  return column.query(self._dialect)
273
298
 
@@ -313,21 +338,12 @@ class ClauseInfo[T: Table](IClauseInfo[T]):
313
338
  return func(self._column)
314
339
 
315
340
  @classmethod
316
- def concat_alias_and_column(cls, column: str, alias_clause: tp.Optional[str] = None) -> str:
341
+ def concat_clause_with_his_alias(cls, clause: str, alias_clause: tp.Optional[str] = None) -> str:
317
342
  if alias_clause is None:
318
- return column
319
- alias = f"{column} AS {cls.wrapped_with_quotes(alias_clause)}"
343
+ return clause
344
+ alias = f"{clause} AS {cls.wrapped_with_quotes(alias_clause)}"
320
345
  return alias
321
346
 
322
- def _alias_resolver(self, alias: AliasType[ColumnProxy]) -> tp.Optional[str]:
323
- if alias is None:
324
- return None
325
-
326
- if callable(alias):
327
- return self._alias_resolver(alias(self._column))
328
-
329
- return self._replace_placeholder(alias)
330
-
331
347
  @util.preload_module("ormlambda.sql.clauses")
332
348
  @staticmethod
333
349
  def join_clauses(clauses: list[ColumnProxy], chr: str = " ", *, dialect: Dialect, **kw) -> str:
@@ -340,7 +356,7 @@ class ClauseInfo[T: Table](IClauseInfo[T]):
340
356
  if isinstance(c, IComparer):
341
357
  comparer = f"({c.compile(dialect, alias_clause=None).string})"
342
358
 
343
- query = ClauseInfo(None, comparer, alias_clause=c.alias, dialect=dialect).query(dialect)
359
+ query = ClauseInfo(None, comparer, dialect=dialect, literal=True).query(dialect) + " AS " + ClauseInfo.wrapped_with_quotes(c.alias)
344
360
  queries.append(query)
345
361
  continue
346
362
  # That update control the alias we set by default on select clause
@@ -138,6 +138,25 @@ class Column[TProp](ClauseElement):
138
138
  """Read the metada when using Annotated typing class, and set the attributes accordingly"""
139
139
 
140
140
  TypeEngine = util.preloaded.sql_type_api.TypeEngine
141
+ ANNOTATED_SELECTOR: dict[ObjType, Callable[[Column, ObjType], None]] = {
142
+ TypeEngine: lambda x, data: setattr(x, "_dtype", data),
143
+ PrimaryKey: lambda x, _: setattr(x, "is_primary_key", True),
144
+ AutoGenerated: lambda x, _: setattr(x, "is_auto_generated", True),
145
+ AutoIncrement: lambda x, _: setattr(x, "is_auto_increment", True),
146
+ Unique: lambda x, _: setattr(x, "is_unique", True),
147
+ CheckTypes: lambda x, _: setattr(x, "_check", True),
148
+ Default: lambda x, meta: (
149
+ setattr(x, "default_value", cast(Default, meta).value),
150
+ setattr(x, "is_auto_generated", True),
151
+ ),
152
+ NotNull: lambda x, _: setattr(x, "is_not_null", True),
153
+ }
154
+
155
+ def get_handler(obj_type: ObjType) -> Optional[Callable[[Column, ObjType], None]]:
156
+ for key, handler in ANNOTATED_SELECTOR.items():
157
+ if issubclass(obj_type, key):
158
+ return handler
159
+ return None
141
160
 
142
161
  annotations = get_type_hints(obj, include_extras=True)
143
162
  if name in annotations:
@@ -149,24 +168,10 @@ class Column[TProp](ClauseElement):
149
168
 
150
169
  type ObjType = Metadata | TypeEngine
151
170
 
152
- ANNOTATED_SELECTOR: dict[ObjType, Callable[[Column, ObjType], None]] = {
153
- TypeEngine: lambda x, data: setattr(x, "_dtype", data),
154
- PrimaryKey: lambda x, _: setattr(x, "is_primary_key", True),
155
- AutoGenerated: lambda x, _: setattr(x, "is_auto_generated", True),
156
- AutoIncrement: lambda x, _: setattr(x, "is_auto_increment", True),
157
- Unique: lambda x, _: setattr(x, "is_unique", True),
158
- CheckTypes: lambda x, _: setattr(x, "_check", True),
159
- Default: lambda x, meta: (
160
- setattr(x, "default_value", cast(Default, meta).value),
161
- setattr(x, "is_auto_generated", True),
162
- ),
163
- NotNull: lambda x, _: setattr(x, "is_not_null", True),
164
- }
165
-
166
171
  for meta in metadata:
167
172
  if not isinstance(meta, Metadata | TypeEngine):
168
173
  raise ValueError(f"When using 'Annotated' to pass metadata into Column, you must instantiate those metadata. You passed '{meta.__name__}'")
169
- func = ANNOTATED_SELECTOR.get(type(meta), None)
174
+ func = get_handler(type(meta))
170
175
 
171
176
  if not func:
172
177
  continue
@@ -13,8 +13,10 @@ from ormlambda.sql.sqltypes import resolve_primitive_types
13
13
 
14
14
  from .visitors import Visitor
15
15
  from ormlambda.sql.type_api import TypeEngine
16
+ from ormlambda.sql.clause_info import ClauseInfo
16
17
 
17
18
  if TYPE_CHECKING:
19
+ from ormlambda import Table
18
20
  from ormlambda import Column
19
21
  from .visitors import Element
20
22
  from .elements import ClauseElement
@@ -141,6 +143,9 @@ class TypeCompiler(Visitor):
141
143
  class SQLCompiler(Compiled):
142
144
  is_sql = True
143
145
 
146
+ def visit_table(self, table: Table):
147
+ return ClauseInfo(table=table, dialect=self.dialect).query(dialect=self.dialect)
148
+
144
149
 
145
150
  class DDLCompiler(Compiled):
146
151
  is_ddl = True
@@ -210,7 +215,7 @@ class DDLCompiler(Compiled):
210
215
  foreign_keys_string.append(fk.compile(self.dialect, orig_table=tablecls).string)
211
216
  table_options = " ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"
212
217
 
213
- sql = f"CREATE TABLE {tablecls.__table_name__} (\n\t"
218
+ sql = f"CREATE TABLE {SQLCompiler.visit_table(self,tablecls)} (\n\t"
214
219
  sql += ",\n\t".join(column_sql)
215
220
  sql += "\n\t" if not foreign_keys else ",\n\t"
216
221
  sql += ",\n\t".join(foreign_keys_string)