1# sql/roles.py 2# Copyright (C) 2005-2021 the SQLAlchemy authors and contributors 3# <see AUTHORS file> 4# 5# This module is part of SQLAlchemy and is released under 6# the MIT License: https://www.opensource.org/licenses/mit-license.php 7 8from .. import util 9 10 11class SQLRole(object): 12 """Define a "role" within a SQL statement structure. 13 14 Classes within SQL Core participate within SQLRole hierarchies in order 15 to more accurately indicate where they may be used within SQL statements 16 of all types. 17 18 .. versionadded:: 1.4 19 20 """ 21 22 allows_lambda = False 23 uses_inspection = False 24 25 26class UsesInspection(object): 27 _post_inspect = None 28 uses_inspection = True 29 30 31class AllowsLambdaRole(object): 32 allows_lambda = True 33 34 35class HasCacheKeyRole(SQLRole): 36 _role_name = "Cacheable Core or ORM object" 37 38 39class LiteralValueRole(SQLRole): 40 _role_name = "Literal Python value" 41 42 43class ColumnArgumentRole(SQLRole): 44 _role_name = "Column expression" 45 46 47class ColumnArgumentOrKeyRole(ColumnArgumentRole): 48 _role_name = "Column expression or string key" 49 50 51class StrAsPlainColumnRole(ColumnArgumentRole): 52 _role_name = "Column expression or string key" 53 54 55class ColumnListRole(SQLRole): 56 """Elements suitable for forming comma separated lists of expressions.""" 57 58 59class TruncatedLabelRole(SQLRole): 60 _role_name = "String SQL identifier" 61 62 63class ColumnsClauseRole(AllowsLambdaRole, UsesInspection, ColumnListRole): 64 _role_name = "Column expression or FROM clause" 65 66 @property 67 def _select_iterable(self): 68 raise NotImplementedError() 69 70 71class LimitOffsetRole(SQLRole): 72 _role_name = "LIMIT / OFFSET expression" 73 74 75class ByOfRole(ColumnListRole): 76 _role_name = "GROUP BY / OF / etc. expression" 77 78 79class GroupByRole(AllowsLambdaRole, UsesInspection, ByOfRole): 80 # note there's a special case right now where you can pass a whole 81 # ORM entity to group_by() and it splits out. we may not want to keep 82 # this around 83 84 _role_name = "GROUP BY expression" 85 86 87class OrderByRole(AllowsLambdaRole, ByOfRole): 88 _role_name = "ORDER BY expression" 89 90 91class StructuralRole(SQLRole): 92 pass 93 94 95class StatementOptionRole(StructuralRole): 96 _role_name = "statement sub-expression element" 97 98 99class OnClauseRole(AllowsLambdaRole, StructuralRole): 100 _role_name = "SQL expression for ON clause" 101 102 103class WhereHavingRole(OnClauseRole): 104 _role_name = "SQL expression for WHERE/HAVING role" 105 106 107class ExpressionElementRole(SQLRole): 108 _role_name = "SQL expression element" 109 110 111class ConstExprRole(ExpressionElementRole): 112 _role_name = "Constant True/False/None expression" 113 114 115class LabeledColumnExprRole(ExpressionElementRole): 116 pass 117 118 119class BinaryElementRole(ExpressionElementRole): 120 _role_name = "SQL expression element or literal value" 121 122 123class InElementRole(SQLRole): 124 _role_name = ( 125 "IN expression list, SELECT construct, or bound parameter object" 126 ) 127 128 129class JoinTargetRole(AllowsLambdaRole, UsesInspection, StructuralRole): 130 _role_name = ( 131 "Join target, typically a FROM expression, or ORM " 132 "relationship attribute" 133 ) 134 135 136class FromClauseRole(ColumnsClauseRole, JoinTargetRole): 137 _role_name = "FROM expression, such as a Table or alias() object" 138 139 _is_subquery = False 140 141 @property 142 def _hide_froms(self): 143 raise NotImplementedError() 144 145 146class StrictFromClauseRole(FromClauseRole): 147 # does not allow text() or select() objects 148 149 @property 150 def description(self): 151 raise NotImplementedError() 152 153 154class AnonymizedFromClauseRole(StrictFromClauseRole): 155 # calls .alias() as a post processor 156 157 def _anonymous_fromclause(self, name=None, flat=False): 158 raise NotImplementedError() 159 160 161class ReturnsRowsRole(SQLRole): 162 _role_name = ( 163 "Row returning expression such as a SELECT, a FROM clause, or an " 164 "INSERT/UPDATE/DELETE with RETURNING" 165 ) 166 167 168class StatementRole(SQLRole): 169 _role_name = "Executable SQL or text() construct" 170 171 _propagate_attrs = util.immutabledict() 172 173 174class SelectStatementRole(StatementRole, ReturnsRowsRole): 175 _role_name = "SELECT construct or equivalent text() construct" 176 177 def subquery(self): 178 raise NotImplementedError( 179 "All SelectStatementRole objects should implement a " 180 ".subquery() method." 181 ) 182 183 184class HasCTERole(ReturnsRowsRole): 185 pass 186 187 188class IsCTERole(SQLRole): 189 _role_name = "CTE object" 190 191 192class CompoundElementRole(AllowsLambdaRole, SQLRole): 193 """SELECT statements inside a CompoundSelect, e.g. UNION, EXTRACT, etc.""" 194 195 _role_name = ( 196 "SELECT construct for inclusion in a UNION or other set construct" 197 ) 198 199 200# TODO: are we using this? 201class DMLRole(StatementRole): 202 pass 203 204 205class DMLTableRole(FromClauseRole): 206 _role_name = "subject table for an INSERT, UPDATE or DELETE" 207 208 209class DMLColumnRole(SQLRole): 210 _role_name = "SET/VALUES column expression or string key" 211 212 213class DMLSelectRole(SQLRole): 214 """A SELECT statement embedded in DML, typically INSERT from SELECT""" 215 216 _role_name = "SELECT statement or equivalent textual object" 217 218 219class DDLRole(StatementRole): 220 pass 221 222 223class DDLExpressionRole(StructuralRole): 224 _role_name = "SQL expression element for DDL constraint" 225 226 227class DDLConstraintColumnRole(SQLRole): 228 _role_name = "String column name or column expression for DDL constraint" 229 230 231class DDLReferredColumnRole(DDLConstraintColumnRole): 232 _role_name = ( 233 "String column name or Column object for DDL foreign key constraint" 234 ) 235