ormlambda 4.4.0__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 (151) hide show
  1. {ormlambda-4.4.0 → ormlambda-4.4.14}/PKG-INFO +8 -4
  2. {ormlambda-4.4.0 → ormlambda-4.4.14}/README.md +2 -2
  3. {ormlambda-4.4.0 → ormlambda-4.4.14}/pyproject.toml +20 -4
  4. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/__init__.py +12 -0
  5. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/common/__init__.py +1 -0
  6. ormlambda-4.4.14/src/ormlambda/common/constants.py +1 -0
  7. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/common/enums/union_type.py +1 -1
  8. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/common/errors/__init__.py +53 -1
  9. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/common/global_checker.py +1 -1
  10. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/base.py +58 -42
  11. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/caster/caster.py +3 -1
  12. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/caster/types/__init__.py +1 -1
  13. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/caster/types/json.py +1 -0
  14. ormlambda-4.4.14/src/ormlambda/dialects/mysql/repository/__init__.py +1 -0
  15. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/repository/repository.py +0 -2
  16. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/repository/response.py +13 -3
  17. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/clause_info/clause_info.py +108 -71
  18. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/clauses/alias.py +1 -1
  19. ormlambda-4.4.14/src/ormlambda/sql/clauses/delete.py +25 -0
  20. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/clauses/insert.py +1 -1
  21. ormlambda-4.4.14/src/ormlambda/sql/clauses/update.py +26 -0
  22. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/clauses/where.py +0 -1
  23. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/column/column.py +42 -49
  24. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/column/column_proxy.py +4 -0
  25. {ormlambda-4.4.0/src/ormlambda/types → ormlambda-4.4.14/src/ormlambda/sql/column}/metadata.py +10 -7
  26. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/compiler.py +6 -1
  27. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/ddl.py +2 -2
  28. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/functions/interface/__init__.py +1 -3
  29. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/sqltypes.py +20 -2
  30. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/table/fields.py +4 -6
  31. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/table/table.py +34 -1
  32. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/type_api.py +8 -4
  33. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/statements/interfaces/IStatements.py +28 -8
  34. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/statements/query_builder.py +25 -21
  35. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/statements/statements.py +19 -22
  36. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/statements/types.py +1 -1
  37. ormlambda-4.4.14/src/ormlambda/util/__init__.py +50 -0
  38. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/util/langhelpers.py +1 -1
  39. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/util/preloaded.py +2 -1
  40. ormlambda-4.4.0/src/ormlambda/dialects/mysql/repository/__init__.py +0 -1
  41. ormlambda-4.4.0/src/ormlambda/errors.py +0 -26
  42. ormlambda-4.4.0/src/ormlambda/sql/clauses/delete.py +0 -21
  43. ormlambda-4.4.0/src/ormlambda/sql/clauses/update.py +0 -23
  44. ormlambda-4.4.0/src/ormlambda/types/__init__.py +0 -24
  45. ormlambda-4.4.0/src/ormlambda/util/__init__.py +0 -9
  46. {ormlambda-4.4.0 → ormlambda-4.4.14}/AUTHORS +0 -0
  47. {ormlambda-4.4.0 → ormlambda-4.4.14}/LICENSE +0 -0
  48. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/caster/__init__.py +0 -0
  49. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/caster/base_caster.py +0 -0
  50. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/caster/caster.py +0 -0
  51. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/caster/interfaces/ICaster.py +0 -0
  52. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/caster/interfaces/__init__.py +0 -0
  53. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/common/enums/__init__.py +0 -0
  54. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/common/enums/condition_types.py +0 -0
  55. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/common/enums/join_type.py +0 -0
  56. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/common/enums/order_type.py +0 -0
  57. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/common/interfaces/IJoinSelector.py +0 -0
  58. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/common/interfaces/IQueryCommand.py +0 -0
  59. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/common/interfaces/__init__.py +0 -0
  60. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/dialects/__init__.py +0 -0
  61. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/dialects/default/__init__.py +0 -0
  62. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/dialects/default/base.py +0 -0
  63. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/__init__.py +0 -0
  64. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/caster/__init__.py +0 -0
  65. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/caster/types/boolean.py +0 -0
  66. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/caster/types/bytes.py +0 -0
  67. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/caster/types/date.py +0 -0
  68. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/caster/types/datetime.py +0 -0
  69. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/caster/types/decimal.py +0 -0
  70. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/caster/types/float.py +0 -0
  71. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/caster/types/int.py +0 -0
  72. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/caster/types/iterable.py +0 -0
  73. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/caster/types/none.py +0 -0
  74. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/caster/types/point.py +0 -0
  75. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/caster/types/string.py +0 -0
  76. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/clauses/ST_AsText.py +0 -0
  77. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/clauses/ST_Contains.py +0 -0
  78. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/clauses/__init__.py +0 -0
  79. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/mysqlconnector.py +0 -0
  80. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/repository/pool_types.py +0 -0
  81. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/dialects/mysql/types.py +0 -0
  82. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/dialects/sqlite/__init__.py +0 -0
  83. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/dialects/sqlite/base.py +0 -0
  84. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/dialects/sqlite/pysqlite.py +0 -0
  85. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/engine/__init__.py +0 -0
  86. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/engine/base.py +0 -0
  87. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/engine/create.py +0 -0
  88. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/engine/url.py +0 -0
  89. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/engine/utils.py +0 -0
  90. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/env.py +0 -0
  91. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/model/__init__.py +0 -0
  92. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/model/base_model.py +0 -0
  93. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/repository/__init__.py +0 -0
  94. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/repository/base_repository.py +0 -0
  95. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/repository/interfaces/IDatabaseConnection.py +0 -0
  96. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/repository/interfaces/IRepositoryBase.py +0 -0
  97. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/repository/interfaces/__init__.py +0 -0
  98. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/__init__.py +0 -0
  99. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/clause_info/__init__.py +0 -0
  100. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/clause_info/interface/IClauseInfo.py +0 -0
  101. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/clause_info/interface/__init__.py +0 -0
  102. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/clauses/__init__.py +0 -0
  103. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/clauses/group_by.py +0 -0
  104. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/clauses/having.py +0 -0
  105. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/clauses/join/__init__.py +0 -0
  106. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/clauses/join/join_context.py +0 -0
  107. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/clauses/joins.py +0 -0
  108. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/clauses/limit.py +0 -0
  109. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/clauses/offset.py +0 -0
  110. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/clauses/order.py +0 -0
  111. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/clauses/select.py +0 -0
  112. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/clauses/upsert.py +0 -0
  113. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/column/__init__.py +0 -0
  114. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/column_table_proxy.py +0 -0
  115. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/comparer.py +0 -0
  116. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/context/__init__.py +0 -0
  117. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/elements.py +0 -0
  118. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/foreign_key.py +0 -0
  119. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/functions/__init__.py +0 -0
  120. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/functions/aggregate/__init__.py +0 -0
  121. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/functions/aggregate/avg.py +0 -0
  122. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/functions/aggregate/concat.py +0 -0
  123. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/functions/aggregate/count.py +0 -0
  124. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/functions/aggregate/max.py +0 -0
  125. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/functions/aggregate/min.py +0 -0
  126. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/functions/aggregate/sum.py +0 -0
  127. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/functions/base.py +0 -0
  128. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/functions/datetime/__init__.py +0 -0
  129. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/functions/mathematical/__init__.py +0 -0
  130. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/functions/mathematical/abs.py +0 -0
  131. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/functions/mathematical/ceil.py +0 -0
  132. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/functions/mathematical/floor.py +0 -0
  133. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/functions/mathematical/mod.py +0 -0
  134. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/functions/mathematical/pow.py +0 -0
  135. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/functions/mathematical/rand.py +0 -0
  136. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/functions/mathematical/round.py +0 -0
  137. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/functions/mathematical/sqrt.py +0 -0
  138. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/functions/mathematical/truncate.py +0 -0
  139. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/functions/string/__init__.py +0 -0
  140. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/table/__init__.py +0 -0
  141. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/table/table_constructor.py +0 -0
  142. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/table/table_proxy.py +0 -0
  143. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/types.py +0 -0
  144. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/sql/visitors.py +0 -0
  145. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/statements/__init__.py +0 -0
  146. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/statements/base_statement.py +0 -0
  147. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/statements/interfaces/__init__.py +0 -0
  148. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/util/module_tree/__init__.py +0 -0
  149. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/util/module_tree/dfs_traversal.py +0 -0
  150. {ormlambda-4.4.0 → ormlambda-4.4.14}/src/ormlambda/util/module_tree/dynamic_module.py +0 -0
  151. {ormlambda-4.4.0 → 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.0
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,9 +1,6 @@
1
- [tool.ruff]
2
- line-length = 320
3
-
4
1
  [tool.poetry]
5
2
  name = "ormlambda"
6
- version = "4.4.0"
3
+ version = "4.4.14"
7
4
  description = "ORM designed to interact with the database (currently with MySQL) using lambda functions and nested functions"
8
5
  authors = ["p-hzamora <p.hzamora@icloud.com>"]
9
6
  readme = "README.md"
@@ -21,8 +18,27 @@ ruff = "^0.4.5"
21
18
  parameterized = "^0.9.0"
22
19
  pydantic = "^2.11.1"
23
20
  sqlserver = "^0.0.17.1"
21
+ pytest = "^8.4.2"
22
+
23
+ [tool.ruff]
24
+ line-length = 320
24
25
 
26
+ [tool.pytest.ini_options]
27
+ testpaths = ["src/test"]
28
+ python_files = ["test_*.py"]
29
+ python_classes = ["Test*"]
30
+ python_functions = ["test_*"]
31
+ addopts = [
32
+ "-v", # verbose output
33
+ "--strict-markers", # error on unknown markers
34
+ "--tb=short", # shorter traceback format
35
+ ]
36
+
37
+ markers = [
38
+ "slow: Slow test (deselect with '-m \"not slow\"')",
39
+ ]
25
40
 
26
41
  [build-system]
27
42
  requires = ["poetry-core"]
28
43
  build-backend = "poetry.core.masonry.api"
44
+
@@ -80,4 +80,16 @@ from .sql import functions as functions
80
80
  from .sql.functions import * # noqa: F403
81
81
  from . import util as _util
82
82
 
83
+
84
+ from .sql.column.metadata import PrimaryKey as PrimaryKey
85
+ from .sql.column.metadata import AutoGenerated as AutoGenerated
86
+ from .sql.column.metadata import AutoIncrement as AutoIncrement
87
+ from .sql.column.metadata import Unique as Unique
88
+ from .sql.column.metadata import CheckTypes as CheckTypes
89
+ from .sql.column.metadata import Default as Default
90
+ from .sql.column.metadata import NotNull as NotNull
91
+
92
+ from ormlambda.statements.interfaces import IStatements as IStatements
93
+ from ormlambda.engine import Engine as Engine
94
+
83
95
  _util.import_prefix("ormlambda")
@@ -1 +1,2 @@
1
1
  from .global_checker import GlobalChecker as GlobalChecker
2
+ from .constants import DOT as DOT
@@ -0,0 +1 @@
1
+ DOT = "."
@@ -6,4 +6,4 @@ class UnionEnum(str, enum.Enum):
6
6
  OR = "OR"
7
7
 
8
8
  def __str__(self):
9
- return super().__str__()
9
+ return super().__str__()
@@ -6,6 +6,17 @@ from ormlambda import util
6
6
 
7
7
  if tp.TYPE_CHECKING:
8
8
  from ormlambda.sql.clause_info import ClauseInfo
9
+ from ormlambda.sql import Column
10
+
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"
9
20
 
10
21
 
11
22
  class UnmatchedLambdaParameterError(Exception):
@@ -42,7 +53,7 @@ class FunctionFunctionError[T](Exception):
42
53
  Get the class name of those classes that inherit from 'IFunction' class in order to create a better error message.
43
54
  """
44
55
 
45
- IFunction = util.preloaded.sql_functions.IFunction
56
+ IFunction = util.preloaded.sql_functions.IFunction
46
57
  res: set[str] = set()
47
58
  if not isinstance(clauses, tp.Iterable):
48
59
  return clauses.__class__.__name__
@@ -58,3 +69,44 @@ class NotCallableError(ValueError):
58
69
 
59
70
  def __str__(self) -> str:
60
71
  return f"You must provide a function or callable to proceed with the query creation. Passed '{self.args[0].__class__.__name__}' "
72
+
73
+
74
+ class CompileError(Exception):
75
+ """Exception raised for errors in the compilation process."""
76
+
77
+ def __init__(self, message):
78
+ super().__init__(message)
79
+ self.message = message
80
+
81
+ def __str__(self):
82
+ return f"CompileError: {self.message}"
83
+
84
+
85
+ class NoSuchModuleError(Exception):
86
+ """Raised when a dynamically-loaded module (usually a database dialect)
87
+ of a particular name cannot be located."""
88
+
89
+ def __str__(self):
90
+ return f"NoSuchModuleError: {self.args[0]}"
91
+
92
+
93
+ class DuplicatedClauseNameError(Exception):
94
+ def __init__(self, names: tuple[str], **kw):
95
+ self.names = names
96
+ super().__init__(**kw)
97
+
98
+ def __str__(self):
99
+ return f"Some clauses has the same alias. {self.names}\nTry wrapping the clause with the 'Alias' class first or setting 'avoid_duplicates' param as 'True'"
100
+
101
+
102
+ class ColumnError(ValueError):
103
+ def __init__(self, column: Column, *args):
104
+ super().__init__(*args)
105
+ self.column = column
106
+ self.clause: str = ""
107
+
108
+ def set_clause(self, value: str) -> None:
109
+ self.clause = value
110
+
111
+ def __str__(self):
112
+ return f"The column '{self.column.column_name}' does not exist. Check the name you used inside of '{self.clause}' clause."
@@ -29,7 +29,7 @@ class GlobalChecker[T: TableProxy]:
29
29
  try:
30
30
  table_proxy = TableProxy(table)
31
31
 
32
- if not callable(lambda_func):
32
+ if not callable(lambda_func):
33
33
  raise NotCallableError(lambda_func)
34
34
 
35
35
  if isinstance(lambda_func, Iterable):
@@ -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,
@@ -103,10 +102,10 @@ class MySQLCompiler(compiler.SQLCompiler):
103
102
 
104
103
  def visit_table_proxy(self, table: TableProxy, **kw) -> str:
105
104
  param = {
106
- "table": None,
107
- "column": table._table_class.__table_name__,
108
- "dialect": self.dialect,
105
+ "table": table._table_class,
106
+ "column": None,
109
107
  "alias_clause": alias if (alias := table.get_table_chain()) else None,
108
+ "dialect": self.dialect,
110
109
  **kw,
111
110
  }
112
111
  return ClauseInfo(**param).query(dialect=self.dialect)
@@ -129,7 +128,7 @@ class MySQLCompiler(compiler.SQLCompiler):
129
128
  params = {
130
129
  "table": column.table,
131
130
  "column": column,
132
- "alias_table": alias_table if alias_table else "{table}",
131
+ "alias_table": alias_table,
133
132
  "alias_clause": column.alias or "{column}",
134
133
  "dtype": column._column.dtype,
135
134
  "dialect": self.dialect,
@@ -167,7 +166,7 @@ class MySQLCompiler(compiler.SQLCompiler):
167
166
 
168
167
  return f"{lcond} {comparer.compare} {rcond}"
169
168
 
170
- def visit_where(self, where: Where) -> str:
169
+ def visit_where(self, where: Where, sep: str = " ", **kw) -> str:
171
170
  assert (n := len(where.comparers)) == len(where.restrictive)
172
171
 
173
172
  if not where.comparers:
@@ -178,17 +177,17 @@ class MySQLCompiler(compiler.SQLCompiler):
178
177
  for i in range(n):
179
178
  comp = where.comparers[i]
180
179
 
181
- string = comp.compile(self.dialect).string
180
+ string = comp.compile(self.dialect, **kw).string
182
181
 
183
182
  condition = f"({string})" if isinstance(comp, ComparerCluster) else string
184
183
 
185
- union = f" {where.restrictive[i + 1]} " if i != n - 1 else ""
184
+ union = f" {where.restrictive[i + 1]}{sep}" if i != n - 1 else ""
186
185
 
187
186
  condition += union
188
187
  cond.append(condition)
189
- return f" WHERE {"".join(cond)}"
188
+ return f"WHERE{sep}{''.join(cond)}"
190
189
 
191
- def visit_having(self, having: Having) -> str:
190
+ def visit_having(self, having: Having, sep: str = " ", **kw) -> str:
192
191
  assert (n := len(having.comparers)) == len(having.restrictive)
193
192
 
194
193
  if not having.comparers:
@@ -199,23 +198,23 @@ class MySQLCompiler(compiler.SQLCompiler):
199
198
  for i in range(n):
200
199
  comp = having.comparers[i]
201
200
 
202
- string = comp.compile(self.dialect).string
201
+ string = comp.compile(self.dialect, **kw).string
203
202
 
204
203
  condition = f"({string})" if isinstance(comp, ComparerCluster) else string
205
204
 
206
- union = f" {having.restrictive[i + 1]} " if i != n - 1 else ""
205
+ union = f" {having.restrictive[i + 1]}{sep}" if i != n - 1 else ""
207
206
 
208
207
  condition += union
209
208
  cond.append(condition)
210
- return f" HAVING {"".join(cond)}"
209
+ return f"HAVING{sep}{''.join(cond)}"
211
210
 
212
211
  def visit_join(self, join: JoinSelector) -> str:
213
212
  rt = join.rcon.table
214
213
  rtable = TableProxy(table_class=rt, path=join.rcon.path)
215
214
 
216
- 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
217
216
  left_table_clause = join.lcon.compile(self.dialect, alias_clause=None).string
218
- 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
219
218
  list_ = [
220
219
  join._by.value, # inner join
221
220
  from_clause,
@@ -226,7 +225,7 @@ class MySQLCompiler(compiler.SQLCompiler):
226
225
  ]
227
226
  return " ".join([x for x in list_ if x is not None])
228
227
 
229
- def visit_select(self, select: Select):
228
+ def visit_select(self, select: Select, sep: str = " ", **kw):
230
229
  params = {}
231
230
 
232
231
  # COMMENT: when passing alias into 'select' method, we gonna replace the current aliases of columns with the generic one.
@@ -236,15 +235,17 @@ class MySQLCompiler(compiler.SQLCompiler):
236
235
  elif select.alias:
237
236
  params["alias_clause"] = select.alias
238
237
 
239
- columns = ClauseInfo.join_clauses(select.columns, ",", dialect=self.dialect, **params)
238
+ columns = ClauseInfo.join_clauses(select.columns, sep, dialect=self.dialect, **params)
239
+
240
240
  from_ = ClauseInfo(
241
- select._table,
242
- None,
243
- alias_table=select._alias_table,
241
+ table=select._table,
242
+ column=None,
243
+ alias_table="{table}",
244
244
  dialect=self.dialect,
245
+ first_apperance=True,
245
246
  ).query(self.dialect)
246
247
 
247
- return f"SELECT {columns} FROM {from_}"
248
+ return f"SELECT{sep}{columns}{sep}FROM {from_}"
248
249
 
249
250
  def visit_group_by(self, groupby: GroupBy):
250
251
  column = ", ".join(x.compile(self.dialect, alias_clause=None).string for x in groupby.column)
@@ -320,11 +321,18 @@ class MySQLCompiler(compiler.SQLCompiler):
320
321
  unknown_rows = f"({', '.join(wildcards)})" # The number of "%s" must match the dict 'dicc_0' length
321
322
 
322
323
  insert.cleaned_values = [tuple(x) for x in col_values]
323
- query = f"INSERT INTO {insert.table.__table_name__} {f'({join_cols})'} VALUES {unknown_rows}"
324
+ query = f"INSERT INTO {self.visit_table(insert.table)} {f'({join_cols})'} VALUES {unknown_rows}"
324
325
  return query
325
326
 
326
327
  def visit_delete(self, delete: Delete, **kw) -> str:
327
- return f"DELETE FROM {delete.table.__table_name__}"
328
+ query = f"DELETE FROM {self.visit_table(delete.table)}"
329
+
330
+ if delete.where.comparers:
331
+ # COMMENT: We need to change the Where.restrictive due to if we use more than one where, we want to use "OR" instead "AND"
332
+ for x in range(len(delete.where.restrictive)):
333
+ delete.where.restrictive[x] = "OR"
334
+ query += " " + delete.where.compile(self.dialect).string
335
+ return query
328
336
 
329
337
  def visit_upsert(self, upsert: Upsert, **kw) -> str:
330
338
  """
@@ -436,6 +444,11 @@ class MySQLCompiler(compiler.SQLCompiler):
436
444
  set_query: str = ",".join(["=".join(col_data) for col_data in col_names])
437
445
 
438
446
  query = f"UPDATE {update.table.__table_name__} SET {set_query}"
447
+
448
+ if update.where.comparers:
449
+ where_string = update.where.compile(self.dialect).string
450
+
451
+ query += " " + where_string
439
452
  update.cleaned_values = tuple(update.cleaned_values)
440
453
  return query
441
454
 
@@ -452,7 +465,7 @@ class MySQLCompiler(compiler.SQLCompiler):
452
465
  else:
453
466
  column = count.column
454
467
 
455
- return ClauseInfo.concat_alias_and_column(f"COUNT({column})", count.alias)
468
+ return ClauseInfo.concat_clause_with_his_alias(f"COUNT({column})", count.alias)
456
469
 
457
470
  def visit_order(self, order: Order, **kw) -> str:
458
471
  ORDER = "ORDER BY"
@@ -499,10 +512,10 @@ class MySQLCompiler(compiler.SQLCompiler):
499
512
  clause_info = ClauseInfo(
500
513
  table=None,
501
514
  column=f"CONCAT({', '.join(columns)})",
502
- alias_clause=concat.alias,
503
515
  dialect=self.dialect,
516
+ literal=True
504
517
  )
505
- return clause_info.query(self.dialect)
518
+ return f"{clause_info.query(self.dialect)} AS {ClauseInfo.wrapped_with_quotes(concat.alias)}"
506
519
 
507
520
  def visit_max(self, obj: Max, **kw) -> str:
508
521
  return self._compile_aggregate_method("MAX", obj, **kw)
@@ -531,7 +544,7 @@ class MySQLCompiler(compiler.SQLCompiler):
531
544
  def visit_pow(self, obj: Pow, **kw) -> str:
532
545
  attr = {**kw, "alias_clause": None}
533
546
  column = obj.column.compile(self.dialect, **attr).string
534
- 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)
535
548
 
536
549
  def visit_sqrt(self, obj: Sqrt, **kw) -> str:
537
550
  return self._compile_aggregate_method("SQRT", obj, **kw)
@@ -539,7 +552,7 @@ class MySQLCompiler(compiler.SQLCompiler):
539
552
  def visit_mod(self, obj: Mod, **kw) -> str:
540
553
  attr = {**kw, "alias_clause": None}
541
554
  column = obj.column.compile(self.dialect, **attr).string
542
- 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)
543
556
 
544
557
  def visit_rand(self, obj: Rand, **kw) -> str:
545
558
  return self._compile_aggregate_method("RAND", obj, **kw)
@@ -547,28 +560,30 @@ class MySQLCompiler(compiler.SQLCompiler):
547
560
  def visit_truncate(self, obj: Truncate, **kw) -> str:
548
561
  attr = {**kw, "alias_clause": None}
549
562
  column = obj.column.compile(self.dialect, **attr).string
550
- 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)
551
564
 
552
565
  def _compile_aggregate_method(self, name: str, function: IFunction, **kw) -> str:
553
566
  attr = {**kw, "alias_clause": None}
554
567
  column = function.column.compile(self.dialect, **attr).string
555
- return ClauseInfo.concat_alias_and_column(f"{name}({column})", function.alias)
568
+ return ClauseInfo.concat_clause_with_his_alias(f"{name}({column})", function.alias)
556
569
 
557
570
  def visit_st_astext(self, st_astext: ST_AsText) -> str:
558
571
  # avoid use placeholder when using IFunction because no make sense.
559
572
  if st_astext.alias and (found := ClauseInfo._keyRegex.findall(st_astext.alias)):
560
573
  raise NotKeysInIFunctionError(found)
561
- 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)
562
575
 
563
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))
564
579
  attr1 = st_contains.column.compile(self.dialect, alias_clause=None).string
565
- 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)
566
581
  return f"ST_Contains({attr1}, {attr2})"
567
582
 
568
583
 
569
584
  class MySQLDDLCompiler(compiler.DDLCompiler):
570
585
  def get_column_specification(self, column: Column, **kwargs):
571
- colspec = column.column_name + " " + self.dialect.type_compiler_instance.process(column.dbtype)
586
+ colspec = column.column_name + " " + self.dialect.type_compiler_instance.process(column.dtype)
572
587
  default = self.get_column_default_string(column)
573
588
  if default is not None:
574
589
  colspec += " DEFAULT " + default
@@ -587,7 +602,8 @@ class MySQLDDLCompiler(compiler.DDLCompiler):
587
602
  compare = fk.resolved_function()
588
603
  lcon = compare.left_condition
589
604
  rcon = compare.right_condition
590
- 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})"
591
607
 
592
608
 
593
609
  class MySQLTypeCompiler(compiler.GenericTypeCompiler):
@@ -1,4 +1,5 @@
1
1
  from __future__ import annotations
2
+ from typing import Union
2
3
  from ormlambda.caster.caster import Caster
3
4
 
4
5
 
@@ -41,5 +42,6 @@ class MySQLCaster(Caster):
41
42
  list: IterableCaster,
42
43
  bool: BooleanCaster,
43
44
  Decimal: DecimalCaster,
44
- dict:JsonCaster
45
+ dict: JsonCaster,
46
+ Union[list | dict]: JsonCaster,
45
47
  }
@@ -9,4 +9,4 @@ from .iterable import IterableCaster as IterableCaster
9
9
  from .boolean import BooleanCaster as BooleanCaster
10
10
  from .date import DateCaster as DateCaster
11
11
  from .decimal import DecimalCaster as DecimalCaster
12
- from .json import JsonCaster as JsonCaster
12
+ from .json import JsonCaster as JsonCaster
@@ -2,6 +2,7 @@ from typing import Optional
2
2
  from ormlambda.caster import BaseCaster, Caster
3
3
  import json
4
4
 
5
+
5
6
  class JsonCaster[TType](BaseCaster[dict, TType]):
6
7
  def __init__(self, value: dict, type_value: TType):
7
8
  super().__init__(value, type_value)
@@ -0,0 +1 @@
1
+ from .repository import MySQLRepository # noqa: F401
@@ -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)
@@ -5,8 +5,10 @@ import shapely as shp
5
5
 
6
6
  # Custom libraries
7
7
  from ormlambda.sql.clauses import Alias
8
+ from ormlambda import ColumnProxy
8
9
 
9
10
  if TYPE_CHECKING:
11
+ from ormlambda.sql.types import SelectCol
10
12
  from ormlambda.sql.clause_info import ClauseInfo
11
13
  from ormlambda import Table
12
14
  from ormlambda.sql.clauses import Select
@@ -69,12 +71,11 @@ class Response[TFlavour, *Ts]:
69
71
  nonlocal data
70
72
  result = []
71
73
  for value in data:
72
- if len(value) ==1:
74
+ if len(value) == 1:
73
75
  result.append(value[0])
74
76
  continue
75
77
  result.append(value)
76
78
 
77
-
78
79
  return result
79
80
 
80
81
  def _set(**kwargs) -> list[set]:
@@ -130,7 +131,7 @@ class Response[TFlavour, *Ts]:
130
131
  for i, data in enumerate(row):
131
132
  alias = self._columns[i]
132
133
  clause = self._select[alias]
133
- dtype = clause.dtype if hasattr(clause, "dtype") else None
134
+ dtype = self.get_python_type(clause)
134
135
  parse_data = self._caster.for_value(data, value_type=dtype).from_database
135
136
  new_row.append(parse_data)
136
137
  new_row = tuple(new_row)
@@ -146,3 +147,12 @@ class Response[TFlavour, *Ts]:
146
147
  return False
147
148
 
148
149
  return clause_info.dtype is shp.Point
150
+
151
+ @staticmethod
152
+ def get_python_type[T](value: SelectCol) -> Type[T]:
153
+ if isinstance(value, ColumnProxy):
154
+ return value.dtype.python_type
155
+
156
+ if hasattr(value, "dtype"):
157
+ return value.dtype
158
+ return None