ormlambda 3.12.2__py3-none-any.whl → 3.34.1__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 (145) 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/databases/__init__.py +0 -1
  11. ormlambda/databases/my_sql/__init__.py +0 -1
  12. ormlambda/databases/my_sql/caster/caster.py +23 -19
  13. ormlambda/databases/my_sql/caster/types/__init__.py +3 -0
  14. ormlambda/databases/my_sql/caster/types/boolean.py +35 -0
  15. ormlambda/databases/my_sql/caster/types/bytes.py +7 -7
  16. ormlambda/databases/my_sql/caster/types/date.py +34 -0
  17. ormlambda/databases/my_sql/caster/types/datetime.py +7 -7
  18. ormlambda/databases/my_sql/caster/types/decimal.py +32 -0
  19. ormlambda/databases/my_sql/caster/types/float.py +7 -7
  20. ormlambda/databases/my_sql/caster/types/int.py +7 -7
  21. ormlambda/databases/my_sql/caster/types/iterable.py +7 -7
  22. ormlambda/databases/my_sql/caster/types/none.py +8 -7
  23. ormlambda/databases/my_sql/caster/types/point.py +4 -4
  24. ormlambda/databases/my_sql/caster/types/string.py +7 -7
  25. ormlambda/databases/my_sql/clauses/ST_AsText.py +8 -7
  26. ormlambda/databases/my_sql/clauses/ST_Contains.py +10 -5
  27. ormlambda/databases/my_sql/clauses/__init__.py +4 -10
  28. ormlambda/databases/my_sql/clauses/count.py +5 -15
  29. ormlambda/databases/my_sql/clauses/delete.py +3 -50
  30. ormlambda/databases/my_sql/clauses/group_by.py +3 -16
  31. ormlambda/databases/my_sql/clauses/having.py +2 -6
  32. ormlambda/databases/my_sql/clauses/insert.py +4 -92
  33. ormlambda/databases/my_sql/clauses/joins.py +5 -140
  34. ormlambda/databases/my_sql/clauses/limit.py +4 -15
  35. ormlambda/databases/my_sql/clauses/offset.py +4 -15
  36. ormlambda/databases/my_sql/clauses/order.py +4 -61
  37. ormlambda/databases/my_sql/clauses/update.py +4 -67
  38. ormlambda/databases/my_sql/clauses/upsert.py +3 -66
  39. ormlambda/databases/my_sql/clauses/where.py +4 -42
  40. ormlambda/databases/my_sql/repository.py +217 -0
  41. ormlambda/dialects/__init__.py +39 -0
  42. ormlambda/dialects/default/__init__.py +1 -0
  43. ormlambda/dialects/default/base.py +39 -0
  44. ormlambda/dialects/interface/__init__.py +1 -0
  45. ormlambda/dialects/interface/dialect.py +78 -0
  46. ormlambda/dialects/mysql/__init__.py +8 -0
  47. ormlambda/dialects/mysql/base.py +387 -0
  48. ormlambda/dialects/mysql/mysqlconnector.py +46 -0
  49. ormlambda/dialects/mysql/types.py +732 -0
  50. ormlambda/dialects/sqlite/__init__.py +5 -0
  51. ormlambda/dialects/sqlite/base.py +47 -0
  52. ormlambda/dialects/sqlite/pysqlite.py +32 -0
  53. ormlambda/engine/__init__.py +1 -0
  54. ormlambda/engine/base.py +58 -0
  55. ormlambda/engine/create.py +9 -23
  56. ormlambda/engine/url.py +31 -19
  57. ormlambda/env.py +30 -0
  58. ormlambda/errors.py +17 -0
  59. ormlambda/model/base_model.py +7 -9
  60. ormlambda/repository/base_repository.py +36 -5
  61. ormlambda/repository/interfaces/IRepositoryBase.py +121 -7
  62. ormlambda/repository/response.py +134 -0
  63. ormlambda/sql/clause_info/aggregate_function_base.py +19 -9
  64. ormlambda/sql/clause_info/clause_info.py +34 -17
  65. ormlambda/sql/clauses/__init__.py +14 -0
  66. ormlambda/{databases/my_sql → sql}/clauses/alias.py +23 -6
  67. ormlambda/sql/clauses/count.py +57 -0
  68. ormlambda/sql/clauses/delete.py +71 -0
  69. ormlambda/sql/clauses/group_by.py +30 -0
  70. ormlambda/sql/clauses/having.py +21 -0
  71. ormlambda/sql/clauses/insert.py +104 -0
  72. ormlambda/sql/clauses/interfaces/__init__.py +5 -0
  73. ormlambda/{components → sql/clauses}/join/join_context.py +15 -7
  74. ormlambda/sql/clauses/joins.py +159 -0
  75. ormlambda/sql/clauses/limit.py +15 -0
  76. ormlambda/sql/clauses/offset.py +15 -0
  77. ormlambda/sql/clauses/order.py +55 -0
  78. ormlambda/{databases/my_sql → sql}/clauses/select.py +12 -13
  79. ormlambda/sql/clauses/update.py +84 -0
  80. ormlambda/sql/clauses/upsert.py +77 -0
  81. ormlambda/sql/clauses/where.py +65 -0
  82. ormlambda/sql/column/__init__.py +1 -0
  83. ormlambda/sql/{column.py → column/column.py} +82 -22
  84. ormlambda/sql/comparer.py +51 -37
  85. ormlambda/sql/compiler.py +427 -0
  86. ormlambda/sql/ddl.py +68 -0
  87. ormlambda/sql/elements.py +36 -0
  88. ormlambda/sql/foreign_key.py +43 -39
  89. ormlambda/{databases/my_sql → sql}/functions/concat.py +13 -5
  90. ormlambda/{databases/my_sql → sql}/functions/max.py +9 -4
  91. ormlambda/{databases/my_sql → sql}/functions/min.py +9 -13
  92. ormlambda/{databases/my_sql → sql}/functions/sum.py +8 -10
  93. ormlambda/sql/sqltypes.py +647 -0
  94. ormlambda/sql/table/__init__.py +1 -1
  95. ormlambda/sql/table/table.py +179 -0
  96. ormlambda/sql/table/table_constructor.py +1 -208
  97. ormlambda/sql/type_api.py +35 -0
  98. ormlambda/sql/types.py +3 -1
  99. ormlambda/sql/visitors.py +74 -0
  100. ormlambda/statements/__init__.py +1 -0
  101. ormlambda/statements/base_statement.py +28 -38
  102. ormlambda/statements/interfaces/IStatements.py +5 -4
  103. ormlambda/{databases/my_sql → statements}/query_builder.py +35 -30
  104. ormlambda/{databases/my_sql → statements}/statements.py +50 -60
  105. ormlambda/statements/types.py +2 -2
  106. ormlambda/types/__init__.py +24 -0
  107. ormlambda/types/metadata.py +42 -0
  108. ormlambda/util/__init__.py +88 -0
  109. ormlambda/util/load_module.py +21 -0
  110. ormlambda/util/plugin_loader.py +32 -0
  111. ormlambda/util/typing.py +6 -0
  112. ormlambda-3.34.1.dist-info/AUTHORS +32 -0
  113. {ormlambda-3.12.2.dist-info → ormlambda-3.34.1.dist-info}/METADATA +2 -3
  114. ormlambda-3.34.1.dist-info/RECORD +157 -0
  115. {ormlambda-3.12.2.dist-info → ormlambda-3.34.1.dist-info}/WHEEL +1 -1
  116. ormlambda/components/__init__.py +0 -4
  117. ormlambda/components/delete/__init__.py +0 -2
  118. ormlambda/components/delete/abstract_delete.py +0 -17
  119. ormlambda/components/insert/__init__.py +0 -2
  120. ormlambda/components/insert/abstract_insert.py +0 -25
  121. ormlambda/components/select/__init__.py +0 -1
  122. ormlambda/components/update/__init__.py +0 -2
  123. ormlambda/components/update/abstract_update.py +0 -29
  124. ormlambda/components/upsert/__init__.py +0 -2
  125. ormlambda/components/upsert/abstract_upsert.py +0 -25
  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/repository/__init__.py +0 -1
  129. ormlambda/databases/my_sql/repository/repository.py +0 -351
  130. ormlambda/engine/template.py +0 -47
  131. ormlambda/sql/dtypes.py +0 -94
  132. ormlambda/utils/__init__.py +0 -1
  133. ormlambda-3.12.2.dist-info/RECORD +0 -125
  134. /ormlambda/databases/my_sql/{types.py → pool_types.py} +0 -0
  135. /ormlambda/{components/delete → sql/clauses/interfaces}/IDelete.py +0 -0
  136. /ormlambda/{components/insert → sql/clauses/interfaces}/IInsert.py +0 -0
  137. /ormlambda/{components/select → sql/clauses/interfaces}/ISelect.py +0 -0
  138. /ormlambda/{components/update → sql/clauses/interfaces}/IUpdate.py +0 -0
  139. /ormlambda/{components/upsert → sql/clauses/interfaces}/IUpsert.py +0 -0
  140. /ormlambda/{components → sql/clauses}/join/__init__.py +0 -0
  141. /ormlambda/{databases/my_sql → sql}/functions/__init__.py +0 -0
  142. /ormlambda/{utils → util}/module_tree/__init__.py +0 -0
  143. /ormlambda/{utils → util}/module_tree/dfs_traversal.py +0 -0
  144. /ormlambda/{utils → util}/module_tree/dynamic_module.py +0 -0
  145. {ormlambda-3.12.2.dist-info → ormlambda-3.34.1.dist-info}/LICENSE +0 -0
@@ -0,0 +1,427 @@
1
+ from __future__ import annotations
2
+ import abc
3
+ from typing import Any, ClassVar, Optional, TYPE_CHECKING
4
+
5
+ from ormlambda.sql.ddl import CreateColumn
6
+ from ormlambda.sql.foreign_key import ForeignKey
7
+ from ormlambda.sql.sqltypes import resolve_primitive_types
8
+
9
+ from .visitors import Visitor
10
+ from ormlambda import util
11
+ from ormlambda.sql.type_api import TypeEngine
12
+
13
+ if TYPE_CHECKING:
14
+ from ormlambda import Column
15
+ from .visitors import Element
16
+ from .elements import ClauseElement
17
+ from ormlambda.dialects import Dialect
18
+ from ormlambda.sql.ddl import CreateTable, CreateSchema, DropSchema
19
+ from .sqltypes import (
20
+ INTEGER,
21
+ SMALLINTEGER,
22
+ BIGINTEGER,
23
+ NUMERIC,
24
+ FLOAT,
25
+ REAL,
26
+ DOUBLE,
27
+ STRING,
28
+ TEXT,
29
+ UNICODE,
30
+ UNICODETEXT,
31
+ NCHAR,
32
+ VARCHAR,
33
+ NVARCHAR,
34
+ CHAR,
35
+ DATE,
36
+ TIME,
37
+ DATETIME,
38
+ TIMESTAMP,
39
+ BOOLEAN,
40
+ LARGEBINARY,
41
+ VARBINARY,
42
+ ENUM,
43
+ POINT,
44
+ )
45
+
46
+ from ormlambda.sql.clauses import (
47
+ Insert,
48
+ Delete,
49
+ Upsert,
50
+ Update,
51
+ Limit,
52
+ Offset,
53
+ Count,
54
+ Where,
55
+ Having,
56
+ Order,
57
+ Concat,
58
+ Max,
59
+ Min,
60
+ Sum,
61
+ Groupby,
62
+ )
63
+
64
+
65
+ class Compiled:
66
+ """Represent a compiled SQL or DDL expression.
67
+
68
+ The ``__str__`` method of the ``Compiled`` object should produce
69
+ the actual text of the statement. ``Compiled`` objects are
70
+ specific to their underlying database dialect, and also may
71
+ or may not be specific to the columns referenced within a
72
+ particular set of bind parameters. In no case should the
73
+ ``Compiled`` object be dependent on the actual values of those
74
+ bind parameters, even though it may reference those values as
75
+ defaults.
76
+ """
77
+
78
+ dialect: Dialect
79
+ "The dialect to compile against."
80
+
81
+ statement: Optional[ClauseElement] = None
82
+ "The statement to compile."
83
+
84
+ string: str = ""
85
+ "The string representation of the ``statement``"
86
+
87
+ _gen_time: float
88
+ "The time when the statement was generated."
89
+
90
+ is_sql: ClassVar[bool] = False
91
+ is_ddl: ClassVar[bool] = False
92
+
93
+ def __init__(
94
+ self,
95
+ dialect: Dialect,
96
+ statement: Optional[ClauseElement] = None,
97
+ **kw: Any,
98
+ ) -> None:
99
+ """Construct a new :class:`.Compiled` object.
100
+
101
+ :param dialect: :class:`.Dialect` to compile against.
102
+
103
+ :param statement: :class:`_expression.ClauseElement` to be compiled.
104
+
105
+ """
106
+ self.dialect = dialect
107
+
108
+ if statement is not None:
109
+ self.statement = statement
110
+ self.string = self.process(self.statement, **kw)
111
+
112
+ @property
113
+ def sql_compiler(self):
114
+ """Return a Compiled that is capable of processing SQL expressions.
115
+
116
+ If this compiler is one, it would likely just return 'self'.
117
+
118
+ """
119
+
120
+ raise NotImplementedError()
121
+
122
+ def process(self, obj: Element, **kwargs: Any) -> str:
123
+ return obj._compiler_dispatch(self, **kwargs)
124
+
125
+
126
+ class TypeCompiler(Visitor):
127
+ """Base class for all type compilers."""
128
+
129
+ def __init__(self, dialect: Dialect):
130
+ self.dialect = dialect
131
+
132
+ def process(self, type_: TypeEngine[Any], **kw: Any) -> str:
133
+ """Process a type object into a string representation.
134
+
135
+ :param type_: The type object to process.
136
+ :param kw: Additional keyword arguments.
137
+ :return: The string representation of the type object.
138
+ """
139
+ if not isinstance(type_, TypeEngine):
140
+ type_ = resolve_primitive_types(type_)
141
+ return type_._compiler_dispatch(self, **kw)
142
+
143
+
144
+ class SQLCompiler(Compiled, abc.ABC):
145
+ is_sql = True
146
+
147
+ @abc.abstractmethod
148
+ def visit_insert(self, insert: Insert, **kw) -> Insert: ...
149
+ @abc.abstractmethod
150
+ def visit_delete(self, delete: Delete, **kw) -> Delete: ...
151
+ @abc.abstractmethod
152
+ def visit_upsert(self, upsert: Upsert, **kw) -> Upsert: ...
153
+ @abc.abstractmethod
154
+ def visit_update(self, update: Update, **kw) -> Update: ...
155
+ @abc.abstractmethod
156
+ def visit_limit(self, limit: Limit, **kw) -> Limit: ...
157
+ @abc.abstractmethod
158
+ def visit_offset(self, offset: Offset, **kw) -> Offset: ...
159
+ @abc.abstractmethod
160
+ def visit_count(self, count: Count, **kw) -> Count: ...
161
+ @abc.abstractmethod
162
+ def visit_where(self, where: Where, **kw) -> Where: ...
163
+ @abc.abstractmethod
164
+ def visit_having(self, having: Having, **kw) -> Having: ...
165
+ @abc.abstractmethod
166
+ def visit_order(self, order: Order, **kw) -> Order: ...
167
+ @abc.abstractmethod
168
+ def visit_concat(self, concat: Concat, **kw) -> Concat: ...
169
+ @abc.abstractmethod
170
+ def visit_max(self, max: Max, **kw) -> Max: ...
171
+ @abc.abstractmethod
172
+ def visit_min(self, min: Min, **kw) -> Min: ...
173
+ @abc.abstractmethod
174
+ def visit_sum(self, sum: Sum, **kw) -> Sum: ...
175
+ @abc.abstractmethod
176
+ def visit_group_by(self, groupby: Groupby, **kw) -> Groupby: ...
177
+
178
+
179
+ class DDLCompiler(Compiled):
180
+ is_ddl = True
181
+
182
+ if TYPE_CHECKING:
183
+
184
+ def __init__(
185
+ self,
186
+ dialect: Dialect,
187
+ statement: Optional[ClauseElement] = None,
188
+ **kw: Any,
189
+ ) -> None: ...
190
+
191
+ @property
192
+ def sql_compiler(self):
193
+ """Return a SQL compiler that is capable of processing SQL expressions.
194
+
195
+ This method returns the SQL compiler for the dialect, which is
196
+ used to process SQL expressions.
197
+
198
+ """
199
+ return self.dialect.statement_compiler(self.dialect, None)
200
+
201
+ def visit_create_schema(self, create: CreateSchema, **kw) -> str:
202
+ """
203
+ Generate a CREATE SCHEMA SQL statement for MySQL.
204
+
205
+ Args:
206
+ schema_name (str): Name of the schema/database to create
207
+ if_not_exists (bool): Whether to include IF NOT EXISTS clause
208
+
209
+ Returns:
210
+ str: The SQL CREATE SCHEMA statement
211
+
212
+ Raises:
213
+ ValueError: If schema_name is empty or contains invalid characters
214
+ """
215
+ schema_name = create.schema
216
+
217
+ util.avoid_sql_injection(schema_name)
218
+
219
+ if_not_exists_clause = "IF NOT EXISTS " if create.if_not_exists else ""
220
+ return f"CREATE SCHEMA {if_not_exists_clause}{schema_name};"
221
+
222
+ def visit_drop_schema(self, drop: DropSchema, **kw):
223
+ if_exists_clause = "IF EXISTS " if drop.if_exists else ""
224
+ return f"DROP SCHEMA {if_exists_clause}{drop.schema};"
225
+
226
+ def visit_schema_exists(self, schema: str) -> bool:
227
+ return f"SHOW DATABASES LIKE {schema};"
228
+ # return f"SHOW DATABASES LIKE {self.dialect.caster.PLACEHOLDER};", (schema,)
229
+
230
+ def visit_create_table(self, create: CreateTable, **kw) -> str:
231
+ tablecls = create.element
232
+ column_sql: list[str] = []
233
+ for create_col in create.columns:
234
+ try:
235
+ processed = self.process(create_col)
236
+ if processed is not None:
237
+ column_sql.append(processed)
238
+
239
+ except Exception:
240
+ raise
241
+
242
+ foreign_keys = ForeignKey.create_query(tablecls, self.dialect)
243
+ table_options = " ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"
244
+
245
+ sql = f"CREATE TABLE {tablecls.__table_name__} (\n\t"
246
+ sql += ",\n\t".join(column_sql)
247
+ sql += "\n\t" if not foreign_keys else ",\n\t"
248
+ sql += ",\n\t".join(foreign_keys)
249
+ sql += f"\n){table_options};"
250
+ return sql
251
+
252
+ def visit_create_column(self, create: CreateColumn, first_pk=False, **kw): # noqa: F821
253
+ column = create.element
254
+ return self.get_column_specification(column)
255
+
256
+ def get_column_specification(self, column: Column, **kwargs):
257
+ colspec = column.column_name + " " + self.dialect.type_compiler_instance.process(column.dtype)
258
+ default = self.get_column_default_string(column)
259
+ if default is not None:
260
+ colspec += " DEFAULT " + default
261
+
262
+ if column.is_not_null:
263
+ colspec += " NOT NULL"
264
+
265
+ if column.is_primary_key:
266
+ colspec += " PRIMARY KEY"
267
+ return colspec
268
+
269
+ def get_column_default_string(self, column: Column) -> Optional[str]:
270
+ if isinstance(column.default_value, str):
271
+ return column.default_value
272
+ if not column.default_value:
273
+ return None
274
+ return None
275
+
276
+
277
+ class GenericTypeCompiler(TypeCompiler):
278
+ """Generic type compiler
279
+
280
+ This class is used to compile ormlambda types into their
281
+ string representations for the given dialect.
282
+ """
283
+
284
+ def _render_string_type(self, type_: STRING, name: str, length_override: Optional[int] = None):
285
+ text = name
286
+ if length_override:
287
+ text += "(%d)" % length_override
288
+ elif type_.length:
289
+ text += "(%d)" % type_.length
290
+ if type_.collation:
291
+ text += ' COLLATE "%s"' % type_.collation
292
+ return text
293
+
294
+ def visit_INTEGER(self, type_: INTEGER, **kw):
295
+ return "INTEGER"
296
+
297
+ def visit_SMALLINTEGER(self, type_: SMALLINTEGER, **kw):
298
+ return "SMALLINTEGER"
299
+
300
+ def visit_BIGINTEGER(self, type_: BIGINTEGER, **kw):
301
+ return "BIGINTEGER"
302
+
303
+ def visit_NUMERIC(self, type_: NUMERIC, **kw):
304
+ return "NUMERIC"
305
+
306
+ def visit_FLOAT(self, type_: FLOAT, **kw):
307
+ return "FLOAT"
308
+
309
+ def visit_REAL(self, type_: REAL, **kw):
310
+ return "REAL"
311
+
312
+ def visit_DOUBLE(self, type_: DOUBLE, **kw):
313
+ return "DOUBLE"
314
+
315
+ def visit_TEXT(self, type_: TEXT, **kw):
316
+ return self._render_string_type(type_, "TEXT", **kw)
317
+
318
+ def visit_UNICODE(self, type_: UNICODE, **kw):
319
+ return self._render_string_type(type_, "UNICODE", **kw)
320
+
321
+ def visit_UNICODETEXT(self, type_: UNICODETEXT, **kw):
322
+ return self._render_string_type(type_, "UNICODETEXT", **kw)
323
+
324
+ def visit_CHAR(self, type_: CHAR, **kw):
325
+ return self._render_string_type(type_, "CHAR", **kw)
326
+
327
+ def visit_NCHAR(self, type_: NCHAR, **kw):
328
+ return self._render_string_type(type_, "NCHAR", **kw)
329
+
330
+ def visit_VARCHAR(self, type_: VARCHAR, **kw):
331
+ return self._render_string_type(type_, "VARCHAR", **kw)
332
+
333
+ def visit_NVARCHAR(self, type_: NVARCHAR, **kw):
334
+ return self._render_string_type(type_, "NVARCHAR", **kw)
335
+
336
+ def visit_DATE(self, type_: DATE, **kw):
337
+ return "DATE"
338
+
339
+ def visit_TIME(self, type_: TIME, **kw):
340
+ return "TIME"
341
+
342
+ def visit_DATETIME(self, type_: DATETIME, **kw):
343
+ return "DATETIME"
344
+
345
+ def visit_TIMESTAMP(self, type_: TIMESTAMP, **kw):
346
+ return "TIMESTAMP"
347
+
348
+ def visit_BOOLEAN(self, type_: BOOLEAN, **kw):
349
+ return "BOOLEAN"
350
+
351
+ def visit_LARGEBINARY(self, type_: LARGEBINARY, **kw):
352
+ return "LARGEBINARY"
353
+
354
+ def visit_VARBINARY(self, type_: VARBINARY, **kw):
355
+ return "VARBINARY"
356
+
357
+ def visit_ENUM(self, type_: ENUM, **kw):
358
+ return "ENUM"
359
+
360
+ def visit_BLOB(self, type_: LARGEBINARY, **kw):
361
+ return "BLOB"
362
+
363
+ def visit_null(self, type_: POINT, **kw):
364
+ return "NULL"
365
+
366
+ def visit_POINT(self, _type: POINT, **kw):
367
+ return "POINT"
368
+
369
+ def visit_uuid(self, type_, **kw):
370
+ if not type_.native_uuid or not self.dialect.supports_native_uuid:
371
+ return self._render_string_type(type_, "CHAR", length_override=32)
372
+ else:
373
+ return self.visit_UUID(type_, **kw)
374
+
375
+ def visit_large_binary(self, type_, **kw):
376
+ return self.visit_BLOB(type_, **kw)
377
+
378
+ def visit_boolean(self, type_, **kw):
379
+ return self.visit_BOOLEAN(type_, **kw)
380
+
381
+ def visit_time(self, type_, **kw):
382
+ return self.visit_TIME(type_, **kw)
383
+
384
+ def visit_datetime(self, type_, **kw):
385
+ return self.visit_DATETIME(type_, **kw)
386
+
387
+ def visit_date(self, type_, **kw):
388
+ return self.visit_DATE(type_, **kw)
389
+
390
+ def visit_big_integer(self, type_, **kw):
391
+ return self.visit_BIGINT(type_, **kw)
392
+
393
+ def visit_small_integer(self, type_, **kw):
394
+ return self.visit_SMALLINT(type_, **kw)
395
+
396
+ def visit_integer(self, type_, **kw):
397
+ return self.visit_INTEGER(type_, **kw)
398
+
399
+ def visit_real(self, type_, **kw):
400
+ return self.visit_REAL(type_, **kw)
401
+
402
+ def visit_float(self, type_, **kw):
403
+ return self.visit_FLOAT(type_, **kw)
404
+
405
+ def visit_double(self, type_, **kw):
406
+ return self.visit_DOUBLE(type_, **kw)
407
+
408
+ def visit_numeric(self, type_, **kw):
409
+ return self.visit_NUMERIC(type_, **kw)
410
+
411
+ def visit_string(self, type_, **kw):
412
+ return self.visit_VARCHAR(type_, **kw)
413
+
414
+ def visit_unicode(self, type_, **kw):
415
+ return self.visit_VARCHAR(type_, **kw)
416
+
417
+ def visit_text(self, type_, **kw):
418
+ return self.visit_TEXT(type_, **kw)
419
+
420
+ def visit_unicode_text(self, type_, **kw):
421
+ return self.visit_TEXT(type_, **kw)
422
+
423
+ def visit_enum(self, type_, **kw):
424
+ return self.visit_VARCHAR(type_, **kw)
425
+
426
+ def visit_point(self, type_: POINT, **kw):
427
+ return self.visit_POINT(type_, **kw)
ormlambda/sql/ddl.py ADDED
@@ -0,0 +1,68 @@
1
+ from __future__ import annotations
2
+ from typing import TYPE_CHECKING
3
+ from .elements import ClauseElement
4
+
5
+ if TYPE_CHECKING:
6
+ from ormlambda.dialects.interface.dialect import Dialect
7
+ from ormlambda import Column
8
+ from ormlambda import Table
9
+
10
+
11
+ class BaseDDLElement(ClauseElement):
12
+ """
13
+ Base class for all DDL elements.
14
+ """
15
+
16
+ __visit_name__ = "ddl_element"
17
+
18
+ def _compiler(self, dialect: Dialect, **kw) -> str:
19
+ """
20
+ Compile the DDL element into a SQL string.
21
+ """
22
+ return dialect.ddl_compiler(dialect, self, **kw)
23
+
24
+
25
+ class CreateTable(BaseDDLElement):
26
+ """
27
+ Class representing a CREATE TABLE statement.
28
+ """
29
+
30
+ __visit_name__ = "create_table"
31
+
32
+ def __init__(self, element: Table):
33
+ self.element = element
34
+ self.columns = [CreateColumn(c) for c in element.get_columns()]
35
+
36
+
37
+ class CreateColumn[T](BaseDDLElement):
38
+ """
39
+ Class representing a column in a CREATE TABLE statement.
40
+ """
41
+
42
+ __visit_name__ = "create_column"
43
+
44
+ def __init__(self, element: Column[T]):
45
+ self.element = element
46
+
47
+
48
+ class CreateSchema(BaseDDLElement):
49
+ __visit_name__ = "create_schema"
50
+
51
+ def __init__(self, schema: str, if_not_exists: bool = True):
52
+ self.schema: str = schema
53
+ self.if_not_exists: bool = if_not_exists
54
+
55
+
56
+ class DropSchema(BaseDDLElement):
57
+ __visit_name__ = "drop_schema"
58
+
59
+ def __init__(self, schema: str, if_exists: bool = True):
60
+ self.schema = schema
61
+ self.if_exists = if_exists
62
+
63
+
64
+ class SchemaExists(BaseDDLElement):
65
+ __visit_name__ = "schema_exists"
66
+
67
+ def __init__(self, schema: str):
68
+ self.schema = schema
@@ -0,0 +1,36 @@
1
+ from __future__ import annotations
2
+ from typing import Optional, Any, TYPE_CHECKING
3
+
4
+ from .visitors import Element
5
+
6
+ if TYPE_CHECKING:
7
+ from ormlambda.dialects import Dialect
8
+ from .compiler import Compiled
9
+
10
+
11
+ class CompilerElement(Element):
12
+ """
13
+ Base class for all compiler elements
14
+ """
15
+
16
+ __slots__ = ()
17
+ __visit_name__ = "compiler_element"
18
+
19
+ def compile(self, dialect: Optional[Dialect] = None, **kw: Any) -> Compiled:
20
+ if dialect is None:
21
+ raise TypeError("Either bind or dialect must be provided.")
22
+ return self._compiler(dialect, **kw)
23
+
24
+ def _compiler(self, dialect: Dialect, **kw: Any) -> Compiled:
25
+ """
26
+ Compile the element into a SQL string.
27
+ """
28
+ return dialect.statement_compiler(dialect, self, **kw)
29
+
30
+
31
+ class ClauseElement(CompilerElement):
32
+ """
33
+ Base class for all clause elements.
34
+ """
35
+
36
+ __visit_name__ = "clause_element"
@@ -1,13 +1,14 @@
1
1
  from __future__ import annotations
2
- from typing import Callable, TYPE_CHECKING, Optional, Any, Type, cast, overload
2
+ from typing import Callable, TYPE_CHECKING, Optional, Any, Type, cast, overload, ClassVar
3
3
 
4
4
  from ormlambda.common.interfaces.IQueryCommand import IQuery
5
-
5
+ from ormlambda.sql.elements import Element
6
6
 
7
7
  if TYPE_CHECKING:
8
8
  from ormlambda.sql.comparer import Comparer
9
9
  from ormlambda import Table
10
10
  from ormlambda.sql.clause_info.clause_info_context import ClauseContextType
11
+ from ormlambda.dialects import Dialect
11
12
 
12
13
 
13
14
  class ForeignKeyContext(set["ForeignKey"]):
@@ -32,49 +33,51 @@ class ForeignKeyContext(set["ForeignKey"]):
32
33
  return super().add(element)
33
34
 
34
35
 
35
- class ForeignKey[TLeft: Table, TRight: Table](IQuery):
36
- stored_calls: ForeignKeyContext = ForeignKeyContext()
36
+ class ForeignKey[TLeft: Table, TRight: Table](Element, IQuery):
37
+ __visit_name__ = "foreign_key"
38
+
39
+ stored_calls: ClassVar[ForeignKeyContext] = ForeignKeyContext()
37
40
 
38
41
  @overload
39
- def __new__[LProp, RProp](self, comparer: Comparer[LProp, RProp], clause_name: str) -> None: ...
42
+ def __new__(self, comparer: Comparer, clause_name: str) -> None: ...
40
43
  @overload
41
- def __new__[LProp, TRight, RProp](cls, tright: Type[TRight], relationship: Callable[[TLeft, TRight], Any | Comparer[TLeft, LProp, TRight, RProp]], keep_alive: bool = ...) -> TRight: ...
42
-
43
- def __new__[LProp, TRight, RProp](
44
+ def __new__[TRight](
44
45
  cls,
45
- tright: Optional[TRight] = None,
46
- relationship: Optional[Callable[[TLeft, TRight], Any | Comparer[TLeft, LProp, TRight, RProp]]] = None,
47
- *,
48
- comparer: Optional[Comparer] = None,
49
- clause_name: Optional[str] = None,
50
- keep_alive: bool = False,
51
- ) -> TRight:
46
+ tright: Type[TRight],
47
+ relationship: Callable[[TLeft, TRight], Any | Comparer],
48
+ keep_alive: bool = ...,
49
+ dialect: Dialect = ...,
50
+ ) -> TRight: ...
51
+
52
+ def __new__[TRight](cls, *args, **kwargs) -> TRight:
52
53
  return super().__new__(cls)
53
54
 
54
- def __init__[LProp, RProp](
55
+ def __init__(
55
56
  self,
56
57
  tright: Optional[TRight] = None,
57
- relationship: Optional[Callable[[TLeft, TRight], Any | Comparer[TLeft, LProp, TRight, RProp]]] = None,
58
+ relationship: Optional[Callable[[TLeft, TRight], Any | Comparer]] = None,
58
59
  *,
59
60
  comparer: Optional[Comparer] = None,
60
61
  clause_name: Optional[str] = None,
61
62
  keep_alive: bool = False,
63
+ **kwargs: Any,
62
64
  ) -> None:
65
+ self.kwargs = kwargs
63
66
  self._keep_alive = keep_alive
64
67
  if comparer is not None and clause_name is not None:
65
- self.__init__with_comparer(comparer, clause_name)
68
+ self.__init__with_comparer(comparer, clause_name, **kwargs)
66
69
  else:
67
70
  self.__init_with_callable(tright, relationship)
68
71
 
69
- def __init__with_comparer[LProp, RProp](self, comparer: Comparer[LProp, RProp], clause_name: str) -> None:
72
+ def __init__with_comparer(self, comparer: Comparer, clause_name: str, **kwargs) -> None:
70
73
  self._relationship = None
71
- self._tleft: TLeft = comparer.left_condition.table
72
- self._tright: TRight = comparer.right_condition.table
74
+ self._tleft: TLeft = comparer.left_condition(**kwargs).table
75
+ self._tright: TRight = comparer.right_condition(**kwargs).table
73
76
  self._clause_name: str = clause_name
74
- self._comparer: Comparer[LProp, RProp] = comparer
77
+ self._comparer: Comparer = comparer
75
78
 
76
- def __init_with_callable[LProp, RProp](self, tright: Optional[TRight], relationship: Optional[Callable[[TLeft, TRight], Comparer[LProp, RProp]]]) -> None:
77
- self._relationship: Callable[[TLeft, TRight], Comparer[LProp, RProp]] = relationship
79
+ def __init_with_callable(self, tright: Optional[TRight], relationship: Optional[Callable[[TLeft, TRight], Comparer]]) -> None:
80
+ self._relationship: Callable[[TLeft, TRight], Comparer] = relationship
78
81
  self._tleft: TLeft = None
79
82
  self._tright: TRight = tright
80
83
  self._clause_name: str = None
@@ -113,29 +116,29 @@ class ForeignKey[TLeft: Table, TRight: Table](IQuery):
113
116
  def clause_name(self) -> str:
114
117
  return self._clause_name
115
118
 
116
- @property
117
- def query(self) -> str:
118
- compare = self.resolved_function()
119
- rcon = alias if (alias := compare.right_condition.alias_table) else compare.right_condition.table.__table_name__
120
- return f"FOREIGN KEY ({self._tleft.__table_name__}) REFERENCES {rcon}({compare.right_condition._column.column_name})"
121
-
122
- @property
123
- def alias(self) -> str:
124
- self._comparer = self.resolved_function()
125
- lcol = self._comparer.left_condition._column.column_name
126
- rcol = self._comparer.right_condition._column.column_name
119
+ def query(self, dialect: Dialect, **kwargs) -> str:
120
+ compare = self.resolved_function(dialect)
121
+ left_col = compare.left_condition(dialect).column
122
+ rcon = alias if (alias := compare.right_condition(dialect).alias_table) else compare.right_condition(dialect).table.__table_name__
123
+ return f"FOREIGN KEY ({left_col}) REFERENCES {rcon}({compare.right_condition(dialect).column})"
124
+
125
+ def get_alias(self, dialect: Dialect) -> str:
126
+ self._comparer = self.resolved_function(dialect)
127
+ self._comparer._dialect = dialect
128
+ lcol = self._comparer.left_condition(dialect)._column.column_name
129
+ rcol = self._comparer.right_condition(dialect)._column.column_name
127
130
  return f"{self.tleft.__table_name__}_{lcol}_{rcol}"
128
131
 
129
132
  @classmethod
130
- def create_query(cls, orig_table: Table) -> list[str]:
133
+ def create_query(cls, orig_table: Table, dialect: Dialect) -> list[str]:
131
134
  clauses: list[str] = []
132
135
 
133
- for attr in vars(orig_table):
136
+ for attr in orig_table.__dict__.values():
134
137
  if isinstance(attr, ForeignKey):
135
- clauses.append(attr.query)
138
+ clauses.append(attr.query(dialect))
136
139
  return clauses
137
140
 
138
- def resolved_function[LProp: Any, RProp: Any](self, context: ClauseContextType = None) -> Comparer[LProp, RProp]:
141
+ def resolved_function[LProp: Any, RProp: Any](self, dialect: Dialect, context: Optional[ClauseContextType] = None) -> Comparer:
139
142
  """ """
140
143
  if self._comparer is not None:
141
144
  return self._comparer
@@ -144,4 +147,5 @@ class ForeignKey[TLeft: Table, TRight: Table](IQuery):
144
147
  right = self._tright
145
148
  comparer = self._relationship(left, right)
146
149
  comparer.set_context(context)
150
+ comparer._dialect = dialect
147
151
  return comparer