mirror of
https://gitlab.com/MoonTestUse1/AdministrationItDepartmens.git
synced 2025-08-14 00:25:46 +02:00
Проверка 09.02.2025
This commit is contained in:
@@ -1,10 +1,9 @@
|
||||
# ext/compiler.py
|
||||
# Copyright (C) 2005-2024 the SQLAlchemy authors and contributors
|
||||
# Copyright (C) 2005-2025 the SQLAlchemy authors and contributors
|
||||
# <see AUTHORS file>
|
||||
#
|
||||
# This module is part of SQLAlchemy and is released under
|
||||
# the MIT License: https://www.opensource.org/licenses/mit-license.php
|
||||
# mypy: ignore-errors
|
||||
|
||||
r"""Provides an API for creation of custom ClauseElements and compilers.
|
||||
|
||||
@@ -18,9 +17,11 @@ more callables defining its compilation::
|
||||
from sqlalchemy.ext.compiler import compiles
|
||||
from sqlalchemy.sql.expression import ColumnClause
|
||||
|
||||
|
||||
class MyColumn(ColumnClause):
|
||||
inherit_cache = True
|
||||
|
||||
|
||||
@compiles(MyColumn)
|
||||
def compile_mycolumn(element, compiler, **kw):
|
||||
return "[%s]" % element.name
|
||||
@@ -32,10 +33,12 @@ when the object is compiled to a string::
|
||||
|
||||
from sqlalchemy import select
|
||||
|
||||
s = select(MyColumn('x'), MyColumn('y'))
|
||||
s = select(MyColumn("x"), MyColumn("y"))
|
||||
print(str(s))
|
||||
|
||||
Produces::
|
||||
Produces:
|
||||
|
||||
.. sourcecode:: sql
|
||||
|
||||
SELECT [x], [y]
|
||||
|
||||
@@ -47,6 +50,7 @@ invoked for the dialect in use::
|
||||
|
||||
from sqlalchemy.schema import DDLElement
|
||||
|
||||
|
||||
class AlterColumn(DDLElement):
|
||||
inherit_cache = False
|
||||
|
||||
@@ -54,14 +58,18 @@ invoked for the dialect in use::
|
||||
self.column = column
|
||||
self.cmd = cmd
|
||||
|
||||
|
||||
@compiles(AlterColumn)
|
||||
def visit_alter_column(element, compiler, **kw):
|
||||
return "ALTER COLUMN %s ..." % element.column.name
|
||||
|
||||
@compiles(AlterColumn, 'postgresql')
|
||||
|
||||
@compiles(AlterColumn, "postgresql")
|
||||
def visit_alter_column(element, compiler, **kw):
|
||||
return "ALTER TABLE %s ALTER COLUMN %s ..." % (element.table.name,
|
||||
element.column.name)
|
||||
return "ALTER TABLE %s ALTER COLUMN %s ..." % (
|
||||
element.table.name,
|
||||
element.column.name,
|
||||
)
|
||||
|
||||
The second ``visit_alter_table`` will be invoked when any ``postgresql``
|
||||
dialect is used.
|
||||
@@ -81,6 +89,7 @@ method which can be used for compilation of embedded attributes::
|
||||
|
||||
from sqlalchemy.sql.expression import Executable, ClauseElement
|
||||
|
||||
|
||||
class InsertFromSelect(Executable, ClauseElement):
|
||||
inherit_cache = False
|
||||
|
||||
@@ -88,20 +97,27 @@ method which can be used for compilation of embedded attributes::
|
||||
self.table = table
|
||||
self.select = select
|
||||
|
||||
|
||||
@compiles(InsertFromSelect)
|
||||
def visit_insert_from_select(element, compiler, **kw):
|
||||
return "INSERT INTO %s (%s)" % (
|
||||
compiler.process(element.table, asfrom=True, **kw),
|
||||
compiler.process(element.select, **kw)
|
||||
compiler.process(element.select, **kw),
|
||||
)
|
||||
|
||||
insert = InsertFromSelect(t1, select(t1).where(t1.c.x>5))
|
||||
|
||||
insert = InsertFromSelect(t1, select(t1).where(t1.c.x > 5))
|
||||
print(insert)
|
||||
|
||||
Produces::
|
||||
Produces (formatted for readability):
|
||||
|
||||
"INSERT INTO mytable (SELECT mytable.x, mytable.y, mytable.z
|
||||
FROM mytable WHERE mytable.x > :x_1)"
|
||||
.. sourcecode:: sql
|
||||
|
||||
INSERT INTO mytable (
|
||||
SELECT mytable.x, mytable.y, mytable.z
|
||||
FROM mytable
|
||||
WHERE mytable.x > :x_1
|
||||
)
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -121,11 +137,10 @@ below where we generate a CHECK constraint that embeds a SQL expression::
|
||||
|
||||
@compiles(MyConstraint)
|
||||
def compile_my_constraint(constraint, ddlcompiler, **kw):
|
||||
kw['literal_binds'] = True
|
||||
kw["literal_binds"] = True
|
||||
return "CONSTRAINT %s CHECK (%s)" % (
|
||||
constraint.name,
|
||||
ddlcompiler.sql_compiler.process(
|
||||
constraint.expression, **kw)
|
||||
ddlcompiler.sql_compiler.process(constraint.expression, **kw),
|
||||
)
|
||||
|
||||
Above, we add an additional flag to the process step as called by
|
||||
@@ -153,6 +168,7 @@ an endless loop. Such as, to add "prefix" to all insert statements::
|
||||
|
||||
from sqlalchemy.sql.expression import Insert
|
||||
|
||||
|
||||
@compiles(Insert)
|
||||
def prefix_inserts(insert, compiler, **kw):
|
||||
return compiler.visit_insert(insert.prefix_with("some prefix"), **kw)
|
||||
@@ -168,17 +184,16 @@ Changing Compilation of Types
|
||||
``compiler`` works for types, too, such as below where we implement the
|
||||
MS-SQL specific 'max' keyword for ``String``/``VARCHAR``::
|
||||
|
||||
@compiles(String, 'mssql')
|
||||
@compiles(VARCHAR, 'mssql')
|
||||
@compiles(String, "mssql")
|
||||
@compiles(VARCHAR, "mssql")
|
||||
def compile_varchar(element, compiler, **kw):
|
||||
if element.length == 'max':
|
||||
if element.length == "max":
|
||||
return "VARCHAR('max')"
|
||||
else:
|
||||
return compiler.visit_VARCHAR(element, **kw)
|
||||
|
||||
foo = Table('foo', metadata,
|
||||
Column('data', VARCHAR('max'))
|
||||
)
|
||||
|
||||
foo = Table("foo", metadata, Column("data", VARCHAR("max")))
|
||||
|
||||
Subclassing Guidelines
|
||||
======================
|
||||
@@ -216,18 +231,23 @@ A synopsis is as follows:
|
||||
|
||||
from sqlalchemy.sql.expression import FunctionElement
|
||||
|
||||
|
||||
class coalesce(FunctionElement):
|
||||
name = 'coalesce'
|
||||
name = "coalesce"
|
||||
inherit_cache = True
|
||||
|
||||
|
||||
@compiles(coalesce)
|
||||
def compile(element, compiler, **kw):
|
||||
return "coalesce(%s)" % compiler.process(element.clauses, **kw)
|
||||
|
||||
@compiles(coalesce, 'oracle')
|
||||
|
||||
@compiles(coalesce, "oracle")
|
||||
def compile(element, compiler, **kw):
|
||||
if len(element.clauses) > 2:
|
||||
raise TypeError("coalesce only supports two arguments on Oracle")
|
||||
raise TypeError(
|
||||
"coalesce only supports two arguments on " "Oracle Database"
|
||||
)
|
||||
return "nvl(%s)" % compiler.process(element.clauses, **kw)
|
||||
|
||||
* :class:`.ExecutableDDLElement` - The root of all DDL expressions,
|
||||
@@ -281,6 +301,7 @@ for example to the "synopsis" example indicated previously::
|
||||
class MyColumn(ColumnClause):
|
||||
inherit_cache = True
|
||||
|
||||
|
||||
@compiles(MyColumn)
|
||||
def compile_mycolumn(element, compiler, **kw):
|
||||
return "[%s]" % element.name
|
||||
@@ -319,11 +340,12 @@ caching::
|
||||
self.table = table
|
||||
self.select = select
|
||||
|
||||
|
||||
@compiles(InsertFromSelect)
|
||||
def visit_insert_from_select(element, compiler, **kw):
|
||||
return "INSERT INTO %s (%s)" % (
|
||||
compiler.process(element.table, asfrom=True, **kw),
|
||||
compiler.process(element.select, **kw)
|
||||
compiler.process(element.select, **kw),
|
||||
)
|
||||
|
||||
While it is also possible that the above ``InsertFromSelect`` could be made to
|
||||
@@ -359,28 +381,32 @@ For PostgreSQL and Microsoft SQL Server::
|
||||
from sqlalchemy.ext.compiler import compiles
|
||||
from sqlalchemy.types import DateTime
|
||||
|
||||
|
||||
class utcnow(expression.FunctionElement):
|
||||
type = DateTime()
|
||||
inherit_cache = True
|
||||
|
||||
@compiles(utcnow, 'postgresql')
|
||||
|
||||
@compiles(utcnow, "postgresql")
|
||||
def pg_utcnow(element, compiler, **kw):
|
||||
return "TIMEZONE('utc', CURRENT_TIMESTAMP)"
|
||||
|
||||
@compiles(utcnow, 'mssql')
|
||||
|
||||
@compiles(utcnow, "mssql")
|
||||
def ms_utcnow(element, compiler, **kw):
|
||||
return "GETUTCDATE()"
|
||||
|
||||
Example usage::
|
||||
|
||||
from sqlalchemy import (
|
||||
Table, Column, Integer, String, DateTime, MetaData
|
||||
)
|
||||
from sqlalchemy import Table, Column, Integer, String, DateTime, MetaData
|
||||
|
||||
metadata = MetaData()
|
||||
event = Table("event", metadata,
|
||||
event = Table(
|
||||
"event",
|
||||
metadata,
|
||||
Column("id", Integer, primary_key=True),
|
||||
Column("description", String(50), nullable=False),
|
||||
Column("timestamp", DateTime, server_default=utcnow())
|
||||
Column("timestamp", DateTime, server_default=utcnow()),
|
||||
)
|
||||
|
||||
"GREATEST" function
|
||||
@@ -395,30 +421,30 @@ accommodates two arguments::
|
||||
from sqlalchemy.ext.compiler import compiles
|
||||
from sqlalchemy.types import Numeric
|
||||
|
||||
|
||||
class greatest(expression.FunctionElement):
|
||||
type = Numeric()
|
||||
name = 'greatest'
|
||||
name = "greatest"
|
||||
inherit_cache = True
|
||||
|
||||
|
||||
@compiles(greatest)
|
||||
def default_greatest(element, compiler, **kw):
|
||||
return compiler.visit_function(element)
|
||||
|
||||
@compiles(greatest, 'sqlite')
|
||||
@compiles(greatest, 'mssql')
|
||||
@compiles(greatest, 'oracle')
|
||||
|
||||
@compiles(greatest, "sqlite")
|
||||
@compiles(greatest, "mssql")
|
||||
@compiles(greatest, "oracle")
|
||||
def case_greatest(element, compiler, **kw):
|
||||
arg1, arg2 = list(element.clauses)
|
||||
return compiler.process(case((arg1 > arg2, arg1), else_=arg2), **kw)
|
||||
|
||||
Example usage::
|
||||
|
||||
Session.query(Account).\
|
||||
filter(
|
||||
greatest(
|
||||
Account.checking_balance,
|
||||
Account.savings_balance) > 10000
|
||||
)
|
||||
Session.query(Account).filter(
|
||||
greatest(Account.checking_balance, Account.savings_balance) > 10000
|
||||
)
|
||||
|
||||
"false" expression
|
||||
------------------
|
||||
@@ -429,16 +455,19 @@ don't have a "false" constant::
|
||||
from sqlalchemy.sql import expression
|
||||
from sqlalchemy.ext.compiler import compiles
|
||||
|
||||
|
||||
class sql_false(expression.ColumnElement):
|
||||
inherit_cache = True
|
||||
|
||||
|
||||
@compiles(sql_false)
|
||||
def default_false(element, compiler, **kw):
|
||||
return "false"
|
||||
|
||||
@compiles(sql_false, 'mssql')
|
||||
@compiles(sql_false, 'mysql')
|
||||
@compiles(sql_false, 'oracle')
|
||||
|
||||
@compiles(sql_false, "mssql")
|
||||
@compiles(sql_false, "mysql")
|
||||
@compiles(sql_false, "oracle")
|
||||
def int_false(element, compiler, **kw):
|
||||
return "0"
|
||||
|
||||
@@ -448,19 +477,33 @@ Example usage::
|
||||
|
||||
exp = union_all(
|
||||
select(users.c.name, sql_false().label("enrolled")),
|
||||
select(customers.c.name, customers.c.enrolled)
|
||||
select(customers.c.name, customers.c.enrolled),
|
||||
)
|
||||
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
from typing import Callable
|
||||
from typing import Dict
|
||||
from typing import Type
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import TypeVar
|
||||
|
||||
from .. import exc
|
||||
from ..sql import sqltypes
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..sql.compiler import SQLCompiler
|
||||
|
||||
def compiles(class_, *specs):
|
||||
_F = TypeVar("_F", bound=Callable[..., Any])
|
||||
|
||||
|
||||
def compiles(class_: Type[Any], *specs: str) -> Callable[[_F], _F]:
|
||||
"""Register a function as a compiler for a
|
||||
given :class:`_expression.ClauseElement` type."""
|
||||
|
||||
def decorate(fn):
|
||||
def decorate(fn: _F) -> _F:
|
||||
# get an existing @compiles handler
|
||||
existing = class_.__dict__.get("_compiler_dispatcher", None)
|
||||
|
||||
@@ -473,7 +516,9 @@ def compiles(class_, *specs):
|
||||
|
||||
if existing_dispatch:
|
||||
|
||||
def _wrap_existing_dispatch(element, compiler, **kw):
|
||||
def _wrap_existing_dispatch(
|
||||
element: Any, compiler: SQLCompiler, **kw: Any
|
||||
) -> Any:
|
||||
try:
|
||||
return existing_dispatch(element, compiler, **kw)
|
||||
except exc.UnsupportedCompilationError as uce:
|
||||
@@ -505,7 +550,7 @@ def compiles(class_, *specs):
|
||||
return decorate
|
||||
|
||||
|
||||
def deregister(class_):
|
||||
def deregister(class_: Type[Any]) -> None:
|
||||
"""Remove all custom compilers associated with a given
|
||||
:class:`_expression.ClauseElement` type.
|
||||
|
||||
@@ -517,10 +562,10 @@ def deregister(class_):
|
||||
|
||||
|
||||
class _dispatcher:
|
||||
def __init__(self):
|
||||
self.specs = {}
|
||||
def __init__(self) -> None:
|
||||
self.specs: Dict[str, Callable[..., Any]] = {}
|
||||
|
||||
def __call__(self, element, compiler, **kw):
|
||||
def __call__(self, element: Any, compiler: SQLCompiler, **kw: Any) -> Any:
|
||||
# TODO: yes, this could also switch off of DBAPI in use.
|
||||
fn = self.specs.get(compiler.dialect.name, None)
|
||||
if not fn:
|
||||
|
||||
Reference in New Issue
Block a user