ormlambda 3.12.2__py3-none-any.whl → 3.34.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. ormlambda/__init__.py +2 -0
  2. ormlambda/caster/__init__.py +1 -1
  3. ormlambda/caster/caster.py +29 -12
  4. ormlambda/common/abstract_classes/clause_info_converter.py +4 -12
  5. ormlambda/common/abstract_classes/decomposition_query.py +17 -2
  6. ormlambda/common/abstract_classes/non_query_base.py +9 -7
  7. ormlambda/common/abstract_classes/query_base.py +3 -1
  8. ormlambda/common/errors/__init__.py +29 -0
  9. ormlambda/common/interfaces/IQueryCommand.py +6 -2
  10. ormlambda/dialects/__init__.py +39 -0
  11. ormlambda/dialects/default/__init__.py +1 -0
  12. ormlambda/dialects/default/base.py +39 -0
  13. ormlambda/dialects/interface/__init__.py +1 -0
  14. ormlambda/dialects/interface/dialect.py +78 -0
  15. ormlambda/dialects/mysql/__init__.py +38 -0
  16. ormlambda/dialects/mysql/base.py +388 -0
  17. ormlambda/dialects/mysql/caster/caster.py +39 -0
  18. ormlambda/{databases/my_sql → dialects/mysql}/caster/types/__init__.py +1 -0
  19. ormlambda/dialects/mysql/caster/types/boolean.py +35 -0
  20. ormlambda/{databases/my_sql → dialects/mysql}/caster/types/bytes.py +7 -7
  21. ormlambda/{databases/my_sql → dialects/mysql}/caster/types/datetime.py +7 -7
  22. ormlambda/{databases/my_sql → dialects/mysql}/caster/types/float.py +7 -7
  23. ormlambda/{databases/my_sql → dialects/mysql}/caster/types/int.py +7 -7
  24. ormlambda/{databases/my_sql → dialects/mysql}/caster/types/iterable.py +7 -7
  25. ormlambda/{databases/my_sql → dialects/mysql}/caster/types/none.py +8 -7
  26. ormlambda/{databases/my_sql → dialects/mysql}/caster/types/point.py +4 -4
  27. ormlambda/{databases/my_sql → dialects/mysql}/caster/types/string.py +7 -7
  28. ormlambda/{databases/my_sql → dialects/mysql}/clauses/ST_AsText.py +8 -7
  29. ormlambda/{databases/my_sql → dialects/mysql}/clauses/ST_Contains.py +10 -5
  30. ormlambda/dialects/mysql/clauses/__init__.py +13 -0
  31. ormlambda/dialects/mysql/clauses/count.py +33 -0
  32. ormlambda/dialects/mysql/clauses/delete.py +9 -0
  33. ormlambda/dialects/mysql/clauses/group_by.py +17 -0
  34. ormlambda/dialects/mysql/clauses/having.py +12 -0
  35. ormlambda/dialects/mysql/clauses/insert.py +9 -0
  36. ormlambda/dialects/mysql/clauses/joins.py +14 -0
  37. ormlambda/dialects/mysql/clauses/limit.py +6 -0
  38. ormlambda/dialects/mysql/clauses/offset.py +6 -0
  39. ormlambda/dialects/mysql/clauses/order.py +8 -0
  40. ormlambda/dialects/mysql/clauses/update.py +8 -0
  41. ormlambda/dialects/mysql/clauses/upsert.py +9 -0
  42. ormlambda/dialects/mysql/clauses/where.py +7 -0
  43. ormlambda/dialects/mysql/mysqlconnector.py +46 -0
  44. ormlambda/dialects/mysql/repository/__init__.py +1 -0
  45. ormlambda/dialects/mysql/repository/repository.py +212 -0
  46. ormlambda/dialects/mysql/types.py +732 -0
  47. ormlambda/dialects/sqlite/__init__.py +5 -0
  48. ormlambda/dialects/sqlite/base.py +47 -0
  49. ormlambda/dialects/sqlite/pysqlite.py +32 -0
  50. ormlambda/engine/__init__.py +1 -0
  51. ormlambda/engine/base.py +77 -0
  52. ormlambda/engine/create.py +9 -23
  53. ormlambda/engine/url.py +31 -19
  54. ormlambda/env.py +30 -0
  55. ormlambda/errors.py +17 -0
  56. ormlambda/model/base_model.py +7 -9
  57. ormlambda/repository/base_repository.py +36 -5
  58. ormlambda/repository/interfaces/IRepositoryBase.py +119 -12
  59. ormlambda/repository/response.py +134 -0
  60. ormlambda/sql/clause_info/aggregate_function_base.py +19 -9
  61. ormlambda/sql/clause_info/clause_info.py +34 -17
  62. ormlambda/sql/clauses/__init__.py +14 -0
  63. ormlambda/{databases/my_sql → sql}/clauses/alias.py +23 -6
  64. ormlambda/{databases/my_sql → sql}/clauses/count.py +15 -1
  65. ormlambda/{databases/my_sql → sql}/clauses/delete.py +22 -7
  66. ormlambda/sql/clauses/group_by.py +30 -0
  67. ormlambda/{databases/my_sql → sql}/clauses/having.py +7 -2
  68. ormlambda/{databases/my_sql → sql}/clauses/insert.py +16 -9
  69. ormlambda/sql/clauses/interfaces/__init__.py +5 -0
  70. ormlambda/{components → sql/clauses}/join/join_context.py +15 -7
  71. ormlambda/{databases/my_sql → sql}/clauses/joins.py +29 -19
  72. ormlambda/sql/clauses/limit.py +15 -0
  73. ormlambda/sql/clauses/offset.py +15 -0
  74. ormlambda/{databases/my_sql → sql}/clauses/order.py +14 -24
  75. ormlambda/{databases/my_sql → sql}/clauses/select.py +12 -13
  76. ormlambda/{databases/my_sql → sql}/clauses/update.py +24 -11
  77. ormlambda/{databases/my_sql → sql}/clauses/upsert.py +17 -12
  78. ormlambda/{databases/my_sql → sql}/clauses/where.py +28 -8
  79. ormlambda/sql/column/__init__.py +1 -0
  80. ormlambda/sql/{column.py → column/column.py} +82 -22
  81. ormlambda/sql/comparer.py +51 -37
  82. ormlambda/sql/compiler.py +668 -0
  83. ormlambda/sql/ddl.py +82 -0
  84. ormlambda/sql/elements.py +36 -0
  85. ormlambda/sql/foreign_key.py +61 -39
  86. ormlambda/{databases/my_sql → sql}/functions/concat.py +13 -5
  87. ormlambda/{databases/my_sql → sql}/functions/max.py +9 -4
  88. ormlambda/{databases/my_sql → sql}/functions/min.py +9 -13
  89. ormlambda/{databases/my_sql → sql}/functions/sum.py +8 -10
  90. ormlambda/sql/sqltypes.py +647 -0
  91. ormlambda/sql/table/__init__.py +1 -1
  92. ormlambda/sql/table/table.py +175 -0
  93. ormlambda/sql/table/table_constructor.py +1 -208
  94. ormlambda/sql/type_api.py +35 -0
  95. ormlambda/sql/types.py +3 -1
  96. ormlambda/sql/visitors.py +74 -0
  97. ormlambda/statements/__init__.py +1 -0
  98. ormlambda/statements/base_statement.py +28 -38
  99. ormlambda/statements/interfaces/IStatements.py +8 -4
  100. ormlambda/{databases/my_sql → statements}/query_builder.py +35 -30
  101. ormlambda/{databases/my_sql → statements}/statements.py +57 -61
  102. ormlambda/statements/types.py +2 -2
  103. ormlambda/types/__init__.py +24 -0
  104. ormlambda/types/metadata.py +42 -0
  105. ormlambda/util/__init__.py +87 -0
  106. ormlambda/{utils → util}/module_tree/dynamic_module.py +1 -1
  107. ormlambda/util/plugin_loader.py +32 -0
  108. ormlambda/util/typing.py +6 -0
  109. ormlambda-3.34.0.dist-info/AUTHORS +32 -0
  110. {ormlambda-3.12.2.dist-info → ormlambda-3.34.0.dist-info}/METADATA +1 -1
  111. ormlambda-3.34.0.dist-info/RECORD +152 -0
  112. ormlambda/components/__init__.py +0 -4
  113. ormlambda/components/delete/__init__.py +0 -2
  114. ormlambda/components/delete/abstract_delete.py +0 -17
  115. ormlambda/components/insert/__init__.py +0 -2
  116. ormlambda/components/insert/abstract_insert.py +0 -25
  117. ormlambda/components/select/__init__.py +0 -1
  118. ormlambda/components/update/__init__.py +0 -2
  119. ormlambda/components/update/abstract_update.py +0 -29
  120. ormlambda/components/upsert/__init__.py +0 -2
  121. ormlambda/components/upsert/abstract_upsert.py +0 -25
  122. ormlambda/databases/__init__.py +0 -5
  123. ormlambda/databases/my_sql/__init__.py +0 -4
  124. ormlambda/databases/my_sql/caster/caster.py +0 -39
  125. ormlambda/databases/my_sql/clauses/__init__.py +0 -20
  126. ormlambda/databases/my_sql/clauses/create_database.py +0 -35
  127. ormlambda/databases/my_sql/clauses/drop_database.py +0 -17
  128. ormlambda/databases/my_sql/clauses/drop_table.py +0 -26
  129. ormlambda/databases/my_sql/clauses/group_by.py +0 -30
  130. ormlambda/databases/my_sql/clauses/limit.py +0 -17
  131. ormlambda/databases/my_sql/clauses/offset.py +0 -17
  132. ormlambda/databases/my_sql/repository/__init__.py +0 -1
  133. ormlambda/databases/my_sql/repository/repository.py +0 -351
  134. ormlambda/engine/template.py +0 -47
  135. ormlambda/sql/dtypes.py +0 -94
  136. ormlambda/utils/__init__.py +0 -1
  137. ormlambda-3.12.2.dist-info/RECORD +0 -125
  138. /ormlambda/{databases/my_sql → dialects/mysql}/caster/__init__.py +0 -0
  139. /ormlambda/{databases/my_sql/types.py → dialects/mysql/repository/pool_types.py} +0 -0
  140. /ormlambda/{components/delete → sql/clauses/interfaces}/IDelete.py +0 -0
  141. /ormlambda/{components/insert → sql/clauses/interfaces}/IInsert.py +0 -0
  142. /ormlambda/{components/select → sql/clauses/interfaces}/ISelect.py +0 -0
  143. /ormlambda/{components/update → sql/clauses/interfaces}/IUpdate.py +0 -0
  144. /ormlambda/{components/upsert → sql/clauses/interfaces}/IUpsert.py +0 -0
  145. /ormlambda/{components → sql/clauses}/join/__init__.py +0 -0
  146. /ormlambda/{databases/my_sql → sql}/functions/__init__.py +0 -0
  147. /ormlambda/{utils → util}/module_tree/__init__.py +0 -0
  148. /ormlambda/{utils → util}/module_tree/dfs_traversal.py +0 -0
  149. {ormlambda-3.12.2.dist-info → ormlambda-3.34.0.dist-info}/LICENSE +0 -0
  150. {ormlambda-3.12.2.dist-info → ormlambda-3.34.0.dist-info}/WHEEL +0 -0
@@ -0,0 +1,388 @@
1
+ from __future__ import annotations
2
+ from types import ModuleType
3
+ from ormlambda.sql import compiler
4
+ from .. import default
5
+ from typing import TYPE_CHECKING, Any, Iterable
6
+
7
+ if TYPE_CHECKING:
8
+ from ormlambda.sql.column.column import Column
9
+ from mysql import connector
10
+
11
+ from .types import (
12
+ _NumericType,
13
+ _StringType,
14
+ NUMERIC,
15
+ DECIMAL,
16
+ DOUBLE,
17
+ REAL,
18
+ FLOAT,
19
+ INTEGER,
20
+ BIGINT,
21
+ MEDIUMINT,
22
+ TINYINT,
23
+ SMALLINT,
24
+ BIT,
25
+ TIME,
26
+ TIMESTAMP,
27
+ DATETIME,
28
+ YEAR,
29
+ TEXT,
30
+ TINYTEXT,
31
+ MEDIUMTEXT,
32
+ LONGTEXT,
33
+ NVARCHAR,
34
+ NCHAR,
35
+ TINYBLOB,
36
+ MEDIUMBLOB,
37
+ LONGBLOB,
38
+ )
39
+ from ormlambda.sql.sqltypes import BLOB
40
+
41
+ from .caster import MySQLCaster
42
+ from .repository import MySQLRepository
43
+
44
+
45
+ if TYPE_CHECKING:
46
+ from ormlambda.sql.clauses import (
47
+ Select,
48
+ Insert,
49
+ Delete,
50
+ Upsert,
51
+ Update,
52
+ Limit,
53
+ Offset,
54
+ Count,
55
+ Where,
56
+ Having,
57
+ Order,
58
+ GroupBy,
59
+ )
60
+
61
+ from ormlambda.sql.functions import (
62
+ Concat,
63
+ Max,
64
+ Min,
65
+ Sum,
66
+ )
67
+
68
+
69
+ from ormlambda.sql.clause_info.clause_info_context import ClauseInfoContext
70
+
71
+
72
+ class MySQLCompiler(compiler.SQLCompiler):
73
+ render_table_with_column_in_update_from = True
74
+ """Overridden from base SQLCompiler value"""
75
+
76
+ def visit_select(self, select: Select, **kw):
77
+ return f"{select.CLAUSE} {select.COLUMNS} FROM {select.FROM.query(self.dialect,**kw)}"
78
+
79
+ def visit_group_by(self, groupby: GroupBy, **kw):
80
+ column = groupby._create_query(self.dialect, **kw)
81
+ return f"{groupby.FUNCTION_NAME()} {column}"
82
+
83
+ def visit_limit(self, limit: Limit, **kw):
84
+ return f"{limit.LIMIT} {limit._number}"
85
+
86
+ # TODOH []: include the rest of visit methods
87
+ def visit_insert(self, insert: Insert, **kw) -> Insert: ...
88
+ def visit_delete(self, delete: Delete, **kw) -> Delete: ...
89
+ def visit_upsert(self, upsert: Upsert, **kw) -> Upsert: ...
90
+ def visit_update(self, update: Update, **kw) -> Update: ...
91
+ def visit_offset(self, offset: Offset, **kw) -> Offset:
92
+ return f"{offset.OFFSET} {offset._number}"
93
+
94
+ def visit_count(self, count: Count, **kw) -> Count: ...
95
+ def visit_where(self, where: Where, **kw) -> Where: ...
96
+ def visit_having(self, having: Having, **kw) -> Having: ...
97
+ def visit_order(self, order: Order, **kw) -> Order:
98
+ string_columns: list[str] = []
99
+ columns = order.unresolved_column
100
+
101
+ # if this attr is not iterable means that we only pass one column without wrapped in a list or tuple
102
+ if isinstance(columns, str):
103
+ string_columns = f"{columns} {str(order._order_type[0])}"
104
+ return f"{order.FUNCTION_NAME()} {string_columns}"
105
+
106
+ if not isinstance(columns, Iterable):
107
+ columns = (columns,)
108
+
109
+ assert len(columns) == len(order._order_type)
110
+
111
+ context = ClauseInfoContext(table_context=order._context._table_context, clause_context=None) if order._context else None
112
+ for index, clause in enumerate(order._convert_into_clauseInfo(columns, context, dialect=self.dialect)):
113
+ clause.alias_clause = None
114
+ string_columns.append(f"{clause.query(self.dialect,**kw)} {str(order._order_type[index])}")
115
+
116
+ return f"{order.FUNCTION_NAME()} {', '.join(string_columns)}"
117
+
118
+ def visit_concat(self, concat: Concat, **kw) -> Concat: ...
119
+ def visit_max(self, max: Max, **kw) -> Max: ...
120
+ def visit_min(self, min: Min, **kw) -> Min: ...
121
+ def visit_sum(self, sum: Sum, **kw) -> Sum: ...
122
+
123
+
124
+ class MySQLDDLCompiler(compiler.DDLCompiler):
125
+ def get_column_specification(self, column: Column, **kwargs):
126
+ colspec = column.column_name + " " + self.dialect.type_compiler_instance.process(column.dtype)
127
+ default = self.get_column_default_string(column)
128
+ if default is not None:
129
+ colspec += " DEFAULT " + default
130
+
131
+ if column.is_not_null:
132
+ colspec += " NOT NULL"
133
+
134
+ if column.is_primary_key:
135
+ colspec += " PRIMARY KEY"
136
+
137
+ colspec += " AUTO_INCREMENT" if column.is_auto_increment else ""
138
+
139
+ return colspec
140
+
141
+
142
+ class MySQLTypeCompiler(compiler.GenericTypeCompiler):
143
+ def mysql_type(self, type_: Any) -> bool:
144
+ return isinstance(type_, (_StringType, _NumericType))
145
+
146
+ def _extend_numeric(self, type_: _NumericType, spec: str) -> str:
147
+ "Extend a numeric-type declaration with MySQL specific extensions."
148
+
149
+ if not self.mysql_type(type_):
150
+ return spec
151
+
152
+ if type_.unsigned:
153
+ spec += " UNSIGNED"
154
+ if type_.zerofill:
155
+ spec += " ZEROFILL"
156
+ return spec
157
+
158
+ def _extend_string(self, type_: _StringType, defaults, spec):
159
+ """Extend a string-type declaration with standard SQL CHARACTER SET /
160
+ COLLATE annotations and MySQL specific extensions.
161
+
162
+ """
163
+
164
+ def attr(name):
165
+ return getattr(type_, name, defaults.get(name))
166
+
167
+ if attr("charset"):
168
+ charset = f"CHARACTER SET {attr("charset")}"
169
+ elif attr("ascii"):
170
+ charset = "ASCII"
171
+ elif attr("unicode"):
172
+ charset = "UNICODE"
173
+ else:
174
+ charset = None
175
+
176
+ if attr("collation"):
177
+ collation = f"COLLATE {type_.collation}"
178
+ elif attr("binary"):
179
+ collation = "BINARY"
180
+ else:
181
+ collation = None
182
+
183
+ if attr("national"):
184
+ # NATIONAL (aka NCHAR/NVARCHAR) trumps charsets.
185
+ return " ".join([c for c in ("NATIONAL", spec, collation) if c is not None])
186
+ return " ".join([c for c in (spec, charset, collation) if c is not None])
187
+
188
+ def visit_INTEGER(self, type_: INTEGER, **kw):
189
+ if self.mysql_type(type_) and type_.display_width is not None:
190
+ return self._extend_numeric(
191
+ type_,
192
+ f"INTEGER(%({type_.display_width})s)",
193
+ )
194
+ else:
195
+ return self._extend_numeric(type_, "INTEGER")
196
+
197
+ def visit_VARCHAR(self, type_, **kw):
198
+ if type_.length is None:
199
+ raise ValueError("VARCHAR requires a length on dialect %s" % self.dialect.name)
200
+ return self._extend_string(type_, {}, "VARCHAR(%d)" % type_.length)
201
+
202
+ def visit_CHAR(self, type_, **kw):
203
+ if type_.length is not None:
204
+ return self._extend_string(type_, {}, "CHAR(%(length)s)" % {"length": type_.length})
205
+ else:
206
+ return self._extend_string(type_, {}, "CHAR")
207
+
208
+ def visit_NUMERIC(self, type_: NUMERIC, **kw):
209
+ return "NUMERIC"
210
+
211
+ def visit_DECIMAL(self, type_: DECIMAL, **kw):
212
+ return "DECIMAL"
213
+
214
+ def visit_DOUBLE(self, type_: DOUBLE, **kw):
215
+ return "DOUBLE"
216
+
217
+ def visit_REAL(self, type_: REAL, **kw):
218
+ return "REAL"
219
+
220
+ def visit_FLOAT(self, type_: FLOAT, **kw):
221
+ return "FLOAT"
222
+
223
+ def visit_BIGINT(self, type_: BIGINT, **kw):
224
+ return "BIGINT"
225
+
226
+ def visit_MEDIUMINT(self, type_: MEDIUMINT, **kw):
227
+ return "MEDIUMINT"
228
+
229
+ def visit_TINYINT(self, type_: TINYINT, **kw):
230
+ return "TINYINT"
231
+
232
+ def visit_SMALLINT(self, type_: SMALLINT, **kw):
233
+ return "SMALLINT"
234
+
235
+ def visit_BIT(self, type_: BIT, **kw):
236
+ return "BIT"
237
+
238
+ def visit_TIME(self, type_: TIME, **kw):
239
+ return "TIME"
240
+
241
+ def visit_TIMESTAMP(self, type_: TIMESTAMP, **kw):
242
+ return "TIMESTAMP"
243
+
244
+ def visit_DATETIME(self, type_: DATETIME, **kw):
245
+ return "DATETIME"
246
+
247
+ def visit_YEAR(self, type_: YEAR, **kw):
248
+ return "YEAR"
249
+
250
+ def visit_TEXT(self, type_: TEXT, **kw):
251
+ if type_.length is not None:
252
+ return self._extend_string(type_, {}, f"TEXT({type_.length})")
253
+ return self._extend_string(type_, {}, "TEXT")
254
+
255
+ def visit_TINYTEXT(self, type_: TINYTEXT, **kw):
256
+ return "TINYTEXT"
257
+
258
+ def visit_MEDIUMTEXT(self, type_: MEDIUMTEXT, **kw):
259
+ return "MEDIUMTEXT"
260
+
261
+ def visit_LONGTEXT(self, type_: LONGTEXT, **kw):
262
+ return "LONGTEXT"
263
+
264
+ def visit_NVARCHAR(self, type_: NVARCHAR, **kw):
265
+ return "NVARCHAR"
266
+
267
+ def visit_NCHAR(self, type_: NCHAR, **kw):
268
+ return "NCHAR"
269
+
270
+ def visit_TINYBLOB(self, type_: TINYBLOB, **kw):
271
+ return "TINYBLOB"
272
+
273
+ def visit_BLOB(self, type_: BLOB, **kw) -> str:
274
+ blob = "BLOB"
275
+ blob += f"({type_.length})" if type_.length is not None else ""
276
+ return blob
277
+
278
+ def visit_MEDIUMBLOB(self, type_: MEDIUMBLOB, **kw):
279
+ return "MEDIUMBLOB"
280
+
281
+ def visit_LONGBLOB(self, type_: LONGBLOB, **kw):
282
+ return "LONGBLOB"
283
+
284
+ # region visit lowercase
285
+
286
+ def visit_integer(self, type_: INTEGER, **kw):
287
+ return self.visit_INTEGER(type_, **kw)
288
+
289
+ def visit_varchar(self, type_, **kw):
290
+ return self.visit_VARCHAR(type_, **kw)
291
+
292
+ def visit_char(self, type_, **kw):
293
+ return self.visit_CHAR(type_, **kw)
294
+
295
+ def visit_numeric(self, type_: NUMERIC, **kw):
296
+ return self.visit_NUMERIC(type_, **kw)
297
+
298
+ def visit_decimal(self, type_: DECIMAL, **kw):
299
+ return self.visit_DECIMAL(type_, **kw)
300
+
301
+ def visit_double(self, type_: DOUBLE, **kw):
302
+ return self.visit_DOUBLE(type_, **kw)
303
+
304
+ def visit_real(self, type_: REAL, **kw):
305
+ return self.visit_REAL(type_, **kw)
306
+
307
+ def visit_float(self, type_: FLOAT, **kw):
308
+ return self.visit_FLOAT(type_, **kw)
309
+
310
+ def visit_bigint(self, type_: BIGINT, **kw):
311
+ return self.visit_BIGINT(type_, **kw)
312
+
313
+ def visit_mediumint(self, type_: MEDIUMINT, **kw):
314
+ return self.visit_MEDIUMINT(type_, **kw)
315
+
316
+ def visit_tinyint(self, type_: TINYINT, **kw):
317
+ return self.visit_TINYINT(type_, **kw)
318
+
319
+ def visit_smallint(self, type_: SMALLINT, **kw):
320
+ return self.visit_SMALLINT(type_, **kw)
321
+
322
+ def visit_bit(self, type_: BIT, **kw):
323
+ return self.visit_BIT(type_, **kw)
324
+
325
+ def visit_time(self, type_: TIME, **kw):
326
+ return self.visit_TIME(type_, **kw)
327
+
328
+ def visit_timestamp(self, type_: TIMESTAMP, **kw):
329
+ return self.visit_TIMESTAMP(type_, **kw)
330
+
331
+ def visit_datetime(self, type_: DATETIME, **kw):
332
+ return self.visit_DATETIME(type_, **kw)
333
+
334
+ def visit_year(self, type_: YEAR, **kw):
335
+ return self.visit_YEAR(type_, **kw)
336
+
337
+ def visit_text(self, type_: TEXT, **kw):
338
+ return self.visit_TEXT(type_, **kw)
339
+
340
+ def visit_tinytext(self, type_: TINYTEXT, **kw):
341
+ return self.visit_TINYTEXT(type_, **kw)
342
+
343
+ def visit_mediumtext(self, type_: MEDIUMTEXT, **kw):
344
+ return self.visit_MEDIUMTEXT(type_, **kw)
345
+
346
+ def visit_longtext(self, type_: LONGTEXT, **kw):
347
+ return self.visit_LONGTEXT(type_, **kw)
348
+
349
+ def visit_nvarchar(self, type_: NVARCHAR, **kw):
350
+ return self.visit_NVARCHAR(type_, **kw)
351
+
352
+ def visit_nchar(self, type_: NCHAR, **kw):
353
+ return self.visit_NCHAR(type_, **kw)
354
+
355
+ def visit_tinyblob(self, type_: TINYBLOB, **kw):
356
+ return self.visit_TINYBLOB(type_, **kw)
357
+
358
+ def visit_mediumblob(self, type_: MEDIUMBLOB, **kw):
359
+ return self.visit_MEDIUMBLOB(type_, **kw)
360
+
361
+ def visit_longblob(self, type_: LONGBLOB, **kw):
362
+ return self.visit_LONGBLOB(type_, **kw)
363
+
364
+ # endregion
365
+
366
+
367
+ class MySQLDialect(default.DefaultDialect):
368
+ """Details of the MySQL dialect.
369
+ Not used directly in application code.
370
+ """
371
+
372
+ dbapi: connector
373
+ name = "mysql"
374
+
375
+ statement_compiler = MySQLCompiler
376
+ ddl_compiler = MySQLDDLCompiler
377
+ type_compiler_cls = MySQLTypeCompiler
378
+ repository_cls = MySQLRepository
379
+ caster = MySQLCaster
380
+
381
+ def __init__(self, **kwargs):
382
+ super().__init__(**kwargs)
383
+
384
+ @classmethod
385
+ def import_dbapi(cls) -> ModuleType:
386
+ from mysql import connector
387
+
388
+ return connector
@@ -0,0 +1,39 @@
1
+ from __future__ import annotations
2
+ from ormlambda.caster.caster import Caster
3
+
4
+
5
+ from .types import (
6
+ StringCaster,
7
+ IntegerCaster,
8
+ FloatCaster,
9
+ PointCaster,
10
+ NoneTypeCaster,
11
+ DatetimeCaster,
12
+ BytesCaster,
13
+ IterableCaster,
14
+ BooleanCaster,
15
+ )
16
+
17
+ from shapely import Point
18
+ from types import NoneType
19
+ from datetime import datetime
20
+
21
+
22
+ class MySQLCaster(Caster):
23
+ PLACEHOLDER = "%s"
24
+
25
+ @classmethod
26
+ def CASTER_SELECTOR(cls):
27
+ return {
28
+ str: StringCaster,
29
+ int: IntegerCaster,
30
+ float: FloatCaster,
31
+ Point: PointCaster,
32
+ NoneType: NoneTypeCaster,
33
+ datetime: DatetimeCaster,
34
+ bytes: BytesCaster,
35
+ bytearray: BytesCaster,
36
+ tuple: IterableCaster,
37
+ list: IterableCaster,
38
+ bool: BooleanCaster,
39
+ }
@@ -6,3 +6,4 @@ from .none import NoneTypeCaster as NoneTypeCaster
6
6
  from .datetime import DatetimeCaster as DatetimeCaster
7
7
  from .bytes import BytesCaster as BytesCaster
8
8
  from .iterable import IterableCaster as IterableCaster
9
+ from .boolean import BooleanCaster as BooleanCaster
@@ -0,0 +1,35 @@
1
+ from typing import Optional
2
+ from ormlambda.caster import BaseCaster, Caster
3
+
4
+
5
+ class BooleanCaster[TType](BaseCaster[bool, TType]):
6
+ """
7
+ MySQL uses 0/1 for booleans stored in TINYINT
8
+ """
9
+
10
+ def __init__(self, value: bool, type_value: TType):
11
+ super().__init__(value, type_value)
12
+
13
+ def wildcard_to_select(self, value: Optional[str] = None) -> str:
14
+ return Caster.PLACEHOLDER if value is None else value
15
+
16
+ def wildcard_to_where(self, value: Optional[str] = None) -> str:
17
+ return Caster.PLACEHOLDER if value is None else value
18
+
19
+ def wildcard_to_insert(self, value: Optional[str] = None) -> str:
20
+ return Caster.PLACEHOLDER if value is None else value
21
+
22
+ @property
23
+ @BaseCaster.return_value_if_exists
24
+ def to_database(self) -> Optional[int]:
25
+ return 1 if self.value else 0
26
+
27
+ @property
28
+ @BaseCaster.return_value_if_exists
29
+ def from_database(self) -> Optional[bool]:
30
+ return bool(self.value)
31
+
32
+ @property
33
+ @BaseCaster.return_value_if_exists
34
+ def string_data(self) -> Optional[str]:
35
+ return str(bool(self.value))
@@ -1,19 +1,19 @@
1
1
  from typing import Optional
2
- from ormlambda.caster import BaseCaster, PLACEHOLDER
2
+ from ormlambda.caster import BaseCaster, Caster
3
3
 
4
4
 
5
5
  class BytesCaster[TType](BaseCaster[bytes, TType]):
6
6
  def __init__(self, value: bytes, type_value: TType):
7
7
  super().__init__(value, type_value)
8
8
 
9
- def wildcard_to_select(self, value: str = PLACEHOLDER) -> str:
10
- return value
9
+ def wildcard_to_select(self, value: Optional[str] = None) -> str:
10
+ return Caster.PLACEHOLDER if value is None else value
11
11
 
12
- def wildcard_to_where(self, value: str = PLACEHOLDER) -> str:
13
- return value
12
+ def wildcard_to_where(self, value: Optional[str] = None) -> str:
13
+ return Caster.PLACEHOLDER if value is None else value
14
14
 
15
- def wildcard_to_insert(self, value: str = PLACEHOLDER) -> str:
16
- return value
15
+ def wildcard_to_insert(self, value: Optional[str] = None) -> str:
16
+ return Caster.PLACEHOLDER if value is None else value
17
17
 
18
18
  @property
19
19
  @BaseCaster.return_value_if_exists
@@ -1,5 +1,5 @@
1
1
  from typing import Optional
2
- from ormlambda.caster import BaseCaster, PLACEHOLDER
2
+ from ormlambda.caster import BaseCaster, Caster
3
3
  from datetime import datetime
4
4
  from .string import StringCaster
5
5
 
@@ -8,14 +8,14 @@ class DatetimeCaster[TType](BaseCaster[datetime, TType]):
8
8
  def __init__(self, value: datetime, type_value: TType):
9
9
  super().__init__(value, type_value)
10
10
 
11
- def wildcard_to_select(self, value: str = PLACEHOLDER) -> str:
12
- return value
11
+ def wildcard_to_select(self, value: Optional[str] = None) -> str:
12
+ return Caster.PLACEHOLDER if value is None else value
13
13
 
14
- def wildcard_to_where(self, value: str = PLACEHOLDER) -> str:
15
- return value
14
+ def wildcard_to_where(self, value: Optional[str] = None) -> str:
15
+ return Caster.PLACEHOLDER if value is None else value
16
16
 
17
- def wildcard_to_insert(self, value: str = PLACEHOLDER) -> str:
18
- return value
17
+ def wildcard_to_insert(self, value: Optional[str] = None) -> str:
18
+ return Caster.PLACEHOLDER if value is None else value
19
19
 
20
20
  @property
21
21
  @BaseCaster.return_value_if_exists
@@ -1,19 +1,19 @@
1
1
  from typing import Optional
2
- from ormlambda.caster import BaseCaster, PLACEHOLDER
2
+ from ormlambda.caster import BaseCaster, Caster
3
3
 
4
4
 
5
5
  class FloatCaster[TType](BaseCaster[float, TType]):
6
6
  def __init__(self, value: float, type_value: TType):
7
7
  super().__init__(value, type_value)
8
8
 
9
- def wildcard_to_select(self, value: str = PLACEHOLDER) -> str:
10
- return value
9
+ def wildcard_to_select(self, value: Optional[str] = None) -> str:
10
+ return Caster.PLACEHOLDER if value is None else value
11
11
 
12
- def wildcard_to_where(self, value: str = PLACEHOLDER) -> str:
13
- return value
12
+ def wildcard_to_where(self, value: Optional[str] = None) -> str:
13
+ return Caster.PLACEHOLDER if value is None else value
14
14
 
15
- def wildcard_to_insert(self, value: str = PLACEHOLDER) -> str:
16
- return value
15
+ def wildcard_to_insert(self, value: Optional[str] = None) -> str:
16
+ return Caster.PLACEHOLDER if value is None else value
17
17
 
18
18
  @property
19
19
  @BaseCaster.return_value_if_exists
@@ -1,19 +1,19 @@
1
1
  from typing import Optional
2
- from ormlambda.caster import BaseCaster, PLACEHOLDER
2
+ from ormlambda.caster import BaseCaster, Caster
3
3
 
4
4
 
5
5
  class IntegerCaster[TType](BaseCaster[int, TType]):
6
6
  def __init__(self, value: int, type_value: TType):
7
7
  super().__init__(value, type_value)
8
8
 
9
- def wildcard_to_select(self, value: str = PLACEHOLDER) -> str:
10
- return value
9
+ def wildcard_to_select(self, value: Optional[str] = None) -> str:
10
+ return Caster.PLACEHOLDER if value is None else value
11
11
 
12
- def wildcard_to_where(self, value: str = PLACEHOLDER) -> str:
13
- return value
12
+ def wildcard_to_where(self, value: Optional[str] = None) -> str:
13
+ return Caster.PLACEHOLDER if value is None else value
14
14
 
15
- def wildcard_to_insert(self, value: str = PLACEHOLDER) -> str:
16
- return value
15
+ def wildcard_to_insert(self, value: Optional[str] = None) -> str:
16
+ return Caster.PLACEHOLDER if value is None else value
17
17
 
18
18
  @property
19
19
  @BaseCaster.return_value_if_exists
@@ -1,19 +1,19 @@
1
1
  from typing import Optional
2
- from ormlambda.caster import BaseCaster, PLACEHOLDER
2
+ from ormlambda.caster import BaseCaster, Caster
3
3
 
4
4
 
5
5
  class IterableCaster[TType](BaseCaster[bytes, TType]):
6
6
  def __init__(self, value: bytes, type_value: TType):
7
7
  super().__init__(value, type_value)
8
8
 
9
- def wildcard_to_select(self, value: str = PLACEHOLDER) -> str:
10
- return value
9
+ def wildcard_to_select(self, value: Optional[str] = None) -> str:
10
+ return Caster.PLACEHOLDER if value is None else value
11
11
 
12
- def wildcard_to_where(self, value: str = PLACEHOLDER) -> str:
13
- return value
12
+ def wildcard_to_where(self, value: Optional[str] = None) -> str:
13
+ return Caster.PLACEHOLDER if value is None else value
14
14
 
15
- def wildcard_to_insert(self, value: str = PLACEHOLDER) -> str:
16
- return value
15
+ def wildcard_to_insert(self, value: Optional[str] = None) -> str:
16
+ return Caster.PLACEHOLDER if value is None else value
17
17
 
18
18
  @property
19
19
  @BaseCaster.return_value_if_exists
@@ -1,19 +1,20 @@
1
1
  from types import NoneType
2
- from ormlambda.caster import BaseCaster, PLACEHOLDER
2
+ from typing import Optional
3
+ from ormlambda.caster import BaseCaster, Caster
3
4
 
4
5
 
5
6
  class NoneTypeCaster[TType](BaseCaster[NoneType, TType]):
6
7
  def __init__(self, value: NoneType, type_value: TType):
7
8
  super().__init__(value, type_value)
8
9
 
9
- def wildcard_to_select(self, value: str = PLACEHOLDER) -> str:
10
- return value
10
+ def wildcard_to_select(self, value: Optional[str] = None) -> str:
11
+ return Caster.PLACEHOLDER if value is None else value
11
12
 
12
- def wildcard_to_where(self, value: str = PLACEHOLDER) -> str:
13
- return value
13
+ def wildcard_to_where(self, value: Optional[str] = None) -> str:
14
+ return Caster.PLACEHOLDER if value is None else value
14
15
 
15
- def wildcard_to_insert(self, value: str = PLACEHOLDER) -> str:
16
- return value
16
+ def wildcard_to_insert(self, value: Optional[str] = None) -> str:
17
+ return Caster.PLACEHOLDER if value is None else value
17
18
 
18
19
  # TODOL: cheched if it's right
19
20
  @property
@@ -1,5 +1,5 @@
1
1
  from typing import Optional
2
- from ormlambda.caster import BaseCaster, PLACEHOLDER
2
+ from ormlambda.caster import BaseCaster, Caster
3
3
  from shapely import Point
4
4
  import shapely.wkt as wkt
5
5
  from shapely import wkb
@@ -9,13 +9,13 @@ class PointCaster[TType](BaseCaster[Point, TType]):
9
9
  def __init__(self, value: bytes | str, type_value: TType):
10
10
  super().__init__(value, type_value)
11
11
 
12
- def wildcard_to_select(self, value: str = PLACEHOLDER) -> str:
12
+ def wildcard_to_select(self, value: str = Caster.PLACEHOLDER) -> str:
13
13
  return f"ST_AsText({value})"
14
14
 
15
- def wildcard_to_where(self, value: str = PLACEHOLDER) -> str:
15
+ def wildcard_to_where(self, value: str = Caster.PLACEHOLDER) -> str:
16
16
  return f"ST_AsText({value})"
17
17
 
18
- def wildcard_to_insert(self, value: str = PLACEHOLDER) -> str:
18
+ def wildcard_to_insert(self, value: str = Caster.PLACEHOLDER) -> str:
19
19
  return f"ST_GeomFromText({value})"
20
20
 
21
21
  @property
@@ -1,19 +1,19 @@
1
1
  from typing import Optional
2
- from ormlambda.caster import BaseCaster, PLACEHOLDER
2
+ from ormlambda.caster import BaseCaster, Caster
3
3
 
4
4
 
5
5
  class StringCaster[TType](BaseCaster[str, TType]):
6
6
  def __init__(self, value: str, type_value: TType):
7
7
  super().__init__(value, type_value)
8
8
 
9
- def wildcard_to_select(self, value: str = PLACEHOLDER) -> str:
10
- return value
9
+ def wildcard_to_select(self, value: Optional[str] = None) -> str:
10
+ return Caster.PLACEHOLDER if value is None else value
11
11
 
12
- def wildcard_to_where(self, value: str = PLACEHOLDER) -> str:
13
- return value
12
+ def wildcard_to_where(self, value: Optional[str] = None) -> str:
13
+ return Caster.PLACEHOLDER if value is None else value
14
14
 
15
- def wildcard_to_insert(self, value: str = PLACEHOLDER) -> str:
16
- return value
15
+ def wildcard_to_insert(self, value: Optional[str] = None) -> str:
16
+ return Caster.PLACEHOLDER if value is None else value
17
17
 
18
18
  @property
19
19
  @BaseCaster.return_value_if_exists