bqsqlparse 0.1.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.
bqsqlparse/nodes.py ADDED
@@ -0,0 +1,728 @@
1
+ """AST node definitions for bqsqlparse.
2
+
3
+ Every node is a dataclass inheriting from :class:`Node`, which provides
4
+ generic child iteration (``children``), tree walking (``walk``) and SQL
5
+ re-generation (``sql``).
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from dataclasses import dataclass, field, fields
11
+ from typing import Iterator, List, Optional, Tuple, Union
12
+
13
+
14
+ class Node:
15
+ """Base class for all AST nodes."""
16
+
17
+ def children(self) -> Iterator["Node"]:
18
+ for f in fields(self): # type: ignore[arg-type]
19
+ v = getattr(self, f.name)
20
+ if isinstance(v, Node):
21
+ yield v
22
+ elif isinstance(v, (list, tuple)):
23
+ for x in v:
24
+ if isinstance(x, Node):
25
+ yield x
26
+ elif isinstance(x, (list, tuple)):
27
+ for y in x:
28
+ if isinstance(y, Node):
29
+ yield y
30
+
31
+ def walk(self) -> Iterator["Node"]:
32
+ yield self
33
+ for c in self.children():
34
+ yield from c.walk()
35
+
36
+ def find_all(self, *types) -> Iterator["Node"]:
37
+ for n in self.walk():
38
+ if isinstance(n, types):
39
+ yield n
40
+
41
+ def sql(self) -> str:
42
+ from .unparse import to_sql
43
+
44
+ return to_sql(self)
45
+
46
+ def __repr__(self) -> str: # pragma: no cover - debugging aid
47
+ parts = []
48
+ for f in fields(self): # type: ignore[arg-type]
49
+ v = getattr(self, f.name)
50
+ if v in (None, [], (), False):
51
+ continue
52
+ parts.append(f"{f.name}={v!r}")
53
+ return f"{type(self).__name__}({', '.join(parts)})"
54
+
55
+
56
+ Expr = Node # alias for readability
57
+
58
+
59
+ # ---------------------------------------------------------------------------
60
+ # Types
61
+ # ---------------------------------------------------------------------------
62
+
63
+ @dataclass(repr=False)
64
+ class StructFieldType(Node):
65
+ name: Optional[str]
66
+ type: "TypeNode"
67
+
68
+
69
+ @dataclass(repr=False)
70
+ class TypeNode(Node):
71
+ name: str
72
+ params: List[str] = field(default_factory=list)
73
+ element: Optional["TypeNode"] = None # ARRAY<T> / RANGE<T>
74
+ fields_: List[StructFieldType] = field(default_factory=list) # STRUCT<...>
75
+
76
+
77
+ # ---------------------------------------------------------------------------
78
+ # Expressions
79
+ # ---------------------------------------------------------------------------
80
+
81
+ @dataclass(repr=False)
82
+ class Literal(Node):
83
+ value: object
84
+ kind: str # 'string' | 'bytes' | 'number' | 'bool' | 'null' | 'default'
85
+
86
+
87
+ @dataclass(repr=False)
88
+ class TypedLiteral(Node):
89
+ """DATE '2024-01-01', TIMESTAMP '...', NUMERIC '1.5', JSON '{"a":1}' ..."""
90
+
91
+ type_name: str
92
+ value: str
93
+
94
+
95
+ @dataclass(repr=False)
96
+ class ColumnRef(Node):
97
+ """A dotted identifier path: column, table.column, alias.struct.field ..."""
98
+
99
+ path: List[str]
100
+
101
+
102
+ @dataclass(repr=False)
103
+ class Param(Node):
104
+ name: str # '@name', '@@sysvar' or '?'
105
+
106
+
107
+ @dataclass(repr=False)
108
+ class ReplaceItem(Node):
109
+ expr: Expr
110
+ name: str
111
+
112
+
113
+ @dataclass(repr=False)
114
+ class Star(Node):
115
+ prefix: List[str] = field(default_factory=list) # for t.* / t.struct.*
116
+ except_: List[str] = field(default_factory=list)
117
+ replace: List[ReplaceItem] = field(default_factory=list)
118
+
119
+
120
+ @dataclass(repr=False)
121
+ class BinaryOp(Node):
122
+ op: str
123
+ left: Expr
124
+ right: Expr
125
+
126
+
127
+ @dataclass(repr=False)
128
+ class UnaryOp(Node):
129
+ op: str # '-', '+', '~', 'NOT'
130
+ operand: Expr
131
+
132
+
133
+ @dataclass(repr=False)
134
+ class Between(Node):
135
+ expr: Expr
136
+ low: Expr
137
+ high: Expr
138
+ negated: bool = False
139
+
140
+
141
+ @dataclass(repr=False)
142
+ class InExpr(Node):
143
+ expr: Expr
144
+ values: Optional[List[Expr]] = None
145
+ query: Optional["Query"] = None
146
+ unnest: Optional[Expr] = None
147
+ negated: bool = False
148
+
149
+
150
+ @dataclass(repr=False)
151
+ class LikeExpr(Node):
152
+ expr: Expr
153
+ patterns: List[Expr]
154
+ quantifier: Optional[str] = None # ANY | ALL | SOME
155
+ negated: bool = False
156
+
157
+
158
+ @dataclass(repr=False)
159
+ class IsExpr(Node):
160
+ expr: Expr
161
+ value: str # NULL | TRUE | FALSE | UNKNOWN
162
+ negated: bool = False
163
+
164
+
165
+ @dataclass(repr=False)
166
+ class WhenClause(Node):
167
+ condition: Expr
168
+ result: Expr
169
+
170
+
171
+ @dataclass(repr=False)
172
+ class Case(Node):
173
+ operand: Optional[Expr]
174
+ whens: List[WhenClause]
175
+ else_: Optional[Expr] = None
176
+
177
+
178
+ @dataclass(repr=False)
179
+ class Cast(Node):
180
+ expr: Expr
181
+ to_type: TypeNode
182
+ safe: bool = False
183
+ format: Optional[Expr] = None
184
+
185
+
186
+ @dataclass(repr=False)
187
+ class Extract(Node):
188
+ part: str
189
+ expr: Expr
190
+ at_time_zone: Optional[Expr] = None
191
+
192
+
193
+ @dataclass(repr=False)
194
+ class IntervalExpr(Node):
195
+ value: Expr
196
+ unit: str
197
+ to_unit: Optional[str] = None
198
+
199
+
200
+ @dataclass(repr=False)
201
+ class ArrayExpr(Node):
202
+ elements: List[Expr]
203
+ elem_type: Optional[TypeNode] = None
204
+
205
+
206
+ @dataclass(repr=False)
207
+ class StructFieldValue(Node):
208
+ expr: Expr
209
+ name: Optional[str] = None
210
+
211
+
212
+ @dataclass(repr=False)
213
+ class StructExpr(Node):
214
+ fields_: List[StructFieldValue]
215
+ type_fields: Optional[List[StructFieldType]] = None
216
+
217
+
218
+ @dataclass(repr=False)
219
+ class Subscript(Node):
220
+ base: Expr
221
+ index: Expr
222
+ mode: Optional[str] = None # OFFSET | ORDINAL | SAFE_OFFSET | SAFE_ORDINAL | None
223
+
224
+
225
+ @dataclass(repr=False)
226
+ class FieldAccess(Node):
227
+ base: Expr
228
+ field_name: str
229
+
230
+
231
+ @dataclass(repr=False)
232
+ class OrderItem(Node):
233
+ expr: Expr
234
+ desc: Optional[bool] = None
235
+ nulls: Optional[str] = None # FIRST | LAST
236
+
237
+
238
+ @dataclass(repr=False)
239
+ class FrameBound(Node):
240
+ kind: str # 'UNBOUNDED PRECEDING' | 'CURRENT ROW' | 'PRECEDING' | 'FOLLOWING'
241
+ value: Optional[Expr] = None
242
+
243
+
244
+ @dataclass(repr=False)
245
+ class WindowFrame(Node):
246
+ unit: str # ROWS | RANGE | GROUPS
247
+ start: FrameBound
248
+ end: Optional[FrameBound] = None
249
+
250
+
251
+ @dataclass(repr=False)
252
+ class WindowSpec(Node):
253
+ name: Optional[str] = None # base named window
254
+ partition_by: List[Expr] = field(default_factory=list)
255
+ order_by: List[OrderItem] = field(default_factory=list)
256
+ frame: Optional[WindowFrame] = None
257
+ is_ref: bool = False # OVER window_name (no parens)
258
+
259
+
260
+ @dataclass(repr=False)
261
+ class NamedArg(Node):
262
+ name: str
263
+ value: Expr
264
+
265
+
266
+ @dataclass(repr=False)
267
+ class HavingModifier(Node):
268
+ kind: str # MAX | MIN
269
+ expr: Expr
270
+
271
+
272
+ @dataclass(repr=False)
273
+ class FuncCall(Node):
274
+ name: List[str] # e.g. ['SAFE', 'SUBSTR'] or ['my_ds', 'my_udf']
275
+ args: List[Expr] = field(default_factory=list)
276
+ distinct: bool = False
277
+ nulls: Optional[str] = None # IGNORE | RESPECT
278
+ order_by: List[OrderItem] = field(default_factory=list)
279
+ limit: Optional[Expr] = None
280
+ having: Optional[HavingModifier] = None
281
+ over: Optional[WindowSpec] = None
282
+
283
+ @property
284
+ def name_str(self) -> str:
285
+ return ".".join(self.name).upper()
286
+
287
+
288
+ @dataclass(repr=False)
289
+ class ScalarSubquery(Node):
290
+ query: "Query"
291
+
292
+
293
+ @dataclass(repr=False)
294
+ class ArraySubquery(Node):
295
+ query: "Query"
296
+
297
+
298
+ @dataclass(repr=False)
299
+ class ExistsSubquery(Node):
300
+ query: "Query"
301
+
302
+
303
+ # ---------------------------------------------------------------------------
304
+ # Query structure
305
+ # ---------------------------------------------------------------------------
306
+
307
+ @dataclass(repr=False)
308
+ class SelectItem(Node):
309
+ expr: Expr
310
+ alias: Optional[str] = None
311
+
312
+
313
+ @dataclass(repr=False)
314
+ class GroupBy(Node):
315
+ kind: str # 'exprs' | 'rollup' | 'cube' | 'sets' | 'all'
316
+ exprs: List[Expr] = field(default_factory=list)
317
+ sets: List[List[Expr]] = field(default_factory=list)
318
+
319
+
320
+ @dataclass(repr=False)
321
+ class NamedWindow(Node):
322
+ name: str
323
+ spec: WindowSpec
324
+
325
+
326
+ @dataclass(repr=False)
327
+ class Select(Node):
328
+ items: List[Node] # SelectItem | Star
329
+ distinct: bool = False
330
+ as_mode: Optional[str] = None # STRUCT | VALUE
331
+ from_: Optional[Node] = None
332
+ where: Optional[Expr] = None
333
+ group_by: Optional[GroupBy] = None
334
+ having: Optional[Expr] = None
335
+ qualify: Optional[Expr] = None
336
+ windows: List[NamedWindow] = field(default_factory=list)
337
+
338
+
339
+ @dataclass(repr=False)
340
+ class SetOp(Node):
341
+ op: str # UNION | INTERSECT | EXCEPT
342
+ all: bool
343
+ left: Node
344
+ right: Node
345
+
346
+
347
+ @dataclass(repr=False)
348
+ class CTE(Node):
349
+ name: str
350
+ query: "Query"
351
+
352
+
353
+ @dataclass(repr=False)
354
+ class Query(Node):
355
+ body: Node # Select | SetOp | Query
356
+ ctes: List[CTE] = field(default_factory=list)
357
+ recursive: bool = False
358
+ order_by: List[OrderItem] = field(default_factory=list)
359
+ limit: Optional[Expr] = None
360
+ offset: Optional[Expr] = None
361
+
362
+
363
+ # ---------------------------------------------------------------------------
364
+ # FROM clause items
365
+ # ---------------------------------------------------------------------------
366
+
367
+ @dataclass(repr=False)
368
+ class TableSample(Node):
369
+ method: str
370
+ value: Expr
371
+ unit: str = "PERCENT"
372
+
373
+
374
+ @dataclass(repr=False)
375
+ class TableRef(Node):
376
+ path: List[str]
377
+ alias: Optional[str] = None
378
+ system_time: Optional[Expr] = None
379
+ sample: Optional[TableSample] = None
380
+
381
+ @property
382
+ def full_name(self) -> str:
383
+ return ".".join(self.path)
384
+
385
+
386
+ @dataclass(repr=False)
387
+ class SubqueryRef(Node):
388
+ query: Query
389
+ alias: Optional[str] = None
390
+
391
+
392
+ @dataclass(repr=False)
393
+ class UnnestRef(Node):
394
+ expr: Expr
395
+ alias: Optional[str] = None
396
+ with_offset: bool = False
397
+ offset_alias: Optional[str] = None
398
+
399
+
400
+ @dataclass(repr=False)
401
+ class TableFuncRef(Node):
402
+ name: List[str]
403
+ args: List[Expr] = field(default_factory=list)
404
+ alias: Optional[str] = None
405
+
406
+
407
+ @dataclass(repr=False)
408
+ class Join(Node):
409
+ kind: str # INNER | LEFT | RIGHT | FULL | CROSS
410
+ left: Node
411
+ right: Node
412
+ on: Optional[Expr] = None
413
+ using: List[str] = field(default_factory=list)
414
+
415
+
416
+ @dataclass(repr=False)
417
+ class PivotAgg(Node):
418
+ func: FuncCall
419
+ alias: Optional[str] = None
420
+
421
+
422
+ @dataclass(repr=False)
423
+ class PivotValue(Node):
424
+ value: Expr
425
+ alias: Optional[str] = None
426
+
427
+
428
+ @dataclass(repr=False)
429
+ class PivotRef(Node):
430
+ input: Node
431
+ aggregates: List[PivotAgg]
432
+ for_col: Expr
433
+ in_values: List[PivotValue]
434
+ alias: Optional[str] = None
435
+
436
+
437
+ @dataclass(repr=False)
438
+ class UnpivotGroup(Node):
439
+ columns: List[List[str]] # one or more column paths per group
440
+ label: Optional[Expr] = None
441
+
442
+
443
+ @dataclass(repr=False)
444
+ class UnpivotRef(Node):
445
+ input: Node
446
+ value_columns: List[str]
447
+ name_column: str
448
+ groups: List[UnpivotGroup]
449
+ include_nulls: Optional[bool] = None
450
+ alias: Optional[str] = None
451
+
452
+
453
+ # ---------------------------------------------------------------------------
454
+ # Statements
455
+ # ---------------------------------------------------------------------------
456
+
457
+ @dataclass(repr=False)
458
+ class ColumnDef(Node):
459
+ name: str
460
+ type: Optional[TypeNode] = None
461
+ options_sql: Optional[str] = None
462
+
463
+
464
+ @dataclass(repr=False)
465
+ class CreateTableAsSelect(Node):
466
+ kind: str # TABLE | VIEW | MATERIALIZED VIEW
467
+ name: List[str]
468
+ query: Optional[Query] = None
469
+ replace: bool = False
470
+ temp: bool = False
471
+ if_not_exists: bool = False
472
+ columns: List[ColumnDef] = field(default_factory=list)
473
+ partition_by: Optional[Expr] = None
474
+ cluster_by: List[Expr] = field(default_factory=list)
475
+ options_sql: Optional[str] = None
476
+
477
+ @property
478
+ def full_name(self) -> str:
479
+ return ".".join(self.name)
480
+
481
+
482
+ @dataclass(repr=False)
483
+ class InsertStmt(Node):
484
+ table: List[str]
485
+ columns: List[str] = field(default_factory=list)
486
+ query: Optional[Query] = None
487
+ values: List[List[Expr]] = field(default_factory=list)
488
+
489
+ @property
490
+ def full_name(self) -> str:
491
+ return ".".join(self.table)
492
+
493
+
494
+ @dataclass(repr=False)
495
+ class Assignment(Node):
496
+ target: List[str]
497
+ value: Expr
498
+
499
+
500
+ @dataclass(repr=False)
501
+ class UpdateStmt(Node):
502
+ table: List[str]
503
+ assignments: List[Assignment]
504
+ alias: Optional[str] = None
505
+ from_: Optional[Node] = None
506
+ where: Optional[Expr] = None
507
+
508
+ @property
509
+ def full_name(self) -> str:
510
+ return ".".join(self.table)
511
+
512
+
513
+ @dataclass(repr=False)
514
+ class DeleteStmt(Node):
515
+ table: List[str]
516
+ alias: Optional[str] = None
517
+ where: Optional[Expr] = None
518
+
519
+ @property
520
+ def full_name(self) -> str:
521
+ return ".".join(self.table)
522
+
523
+
524
+ @dataclass(repr=False)
525
+ class MergeWhen(Node):
526
+ match_kind: str # MATCHED | NOT_MATCHED | NOT_MATCHED_BY_SOURCE
527
+ action_kind: str # UPDATE | DELETE | INSERT | INSERT_ROW
528
+ condition: Optional[Expr] = None
529
+ assignments: List[Assignment] = field(default_factory=list)
530
+ columns: List[str] = field(default_factory=list)
531
+ values: List[Expr] = field(default_factory=list)
532
+
533
+
534
+ @dataclass(repr=False)
535
+ class MergeStmt(Node):
536
+ target: List[str]
537
+ source: Node # TableRef | SubqueryRef
538
+ on: Expr
539
+ whens: List[MergeWhen]
540
+ alias: Optional[str] = None
541
+
542
+ @property
543
+ def full_name(self) -> str:
544
+ return ".".join(self.target)
545
+
546
+
547
+ # ---------------------------------------------------------------------------
548
+ # Scripting (procedural language)
549
+ # ---------------------------------------------------------------------------
550
+
551
+ @dataclass(repr=False)
552
+ class DeclareStmt(Node):
553
+ names: List[str]
554
+ type: Optional[TypeNode] = None
555
+ default: Optional[Expr] = None
556
+
557
+
558
+ @dataclass(repr=False)
559
+ class SetStmt(Node):
560
+ targets: List[str] # variable names (or @@system vars)
561
+ value: Expr # a StructExpr models the (a, b) = (1, 2) form
562
+
563
+
564
+ @dataclass(repr=False)
565
+ class ScriptBlock(Node):
566
+ """BEGIN ... [EXCEPTION WHEN ERROR THEN ...] END"""
567
+
568
+ statements: List[Node]
569
+ exception_statements: List[Node] = field(default_factory=list)
570
+ has_exception_handler: bool = False
571
+ label: Optional[str] = None
572
+
573
+
574
+ @dataclass(repr=False)
575
+ class IfBranch(Node):
576
+ condition: Expr
577
+ statements: List[Node]
578
+
579
+
580
+ @dataclass(repr=False)
581
+ class IfStmt(Node):
582
+ branches: List[IfBranch] # IF + ELSEIFs, in order
583
+ else_statements: List[Node] = field(default_factory=list)
584
+
585
+
586
+ @dataclass(repr=False)
587
+ class LoopStmt(Node):
588
+ statements: List[Node]
589
+ label: Optional[str] = None
590
+
591
+
592
+ @dataclass(repr=False)
593
+ class WhileStmt(Node):
594
+ condition: Expr
595
+ statements: List[Node]
596
+ label: Optional[str] = None
597
+
598
+
599
+ @dataclass(repr=False)
600
+ class RepeatStmt(Node):
601
+ statements: List[Node]
602
+ until: Expr = None
603
+ label: Optional[str] = None
604
+
605
+
606
+ @dataclass(repr=False)
607
+ class ForInStmt(Node):
608
+ var: str
609
+ query: "Query"
610
+ statements: List[Node]
611
+ label: Optional[str] = None
612
+
613
+
614
+ @dataclass(repr=False)
615
+ class BreakContinueStmt(Node):
616
+ kind: str # BREAK | LEAVE | CONTINUE | ITERATE
617
+ label: Optional[str] = None
618
+
619
+
620
+ @dataclass(repr=False)
621
+ class CallStmt(Node):
622
+ name: List[str]
623
+ args: List[Expr] = field(default_factory=list)
624
+
625
+ @property
626
+ def full_name(self) -> str:
627
+ return ".".join(self.name)
628
+
629
+
630
+ @dataclass(repr=False)
631
+ class ReturnStmt(Node):
632
+ pass
633
+
634
+
635
+ @dataclass(repr=False)
636
+ class RaiseStmt(Node):
637
+ message: Optional[Expr] = None
638
+
639
+
640
+ @dataclass(repr=False)
641
+ class ExecuteImmediate(Node):
642
+ sql_expr: Expr
643
+ into: List[str] = field(default_factory=list)
644
+ using: List[Tuple[Expr, Optional[str]]] = field(default_factory=list)
645
+
646
+
647
+ @dataclass(repr=False)
648
+ class AssertStmt(Node):
649
+ condition: Expr
650
+ message: Optional[Expr] = None
651
+
652
+
653
+ @dataclass(repr=False)
654
+ class TransactionStmt(Node):
655
+ kind: str # BEGIN | COMMIT | ROLLBACK
656
+
657
+
658
+ @dataclass(repr=False)
659
+ class TruncateStmt(Node):
660
+ table: List[str]
661
+
662
+ @property
663
+ def full_name(self) -> str:
664
+ return ".".join(self.table)
665
+
666
+
667
+ @dataclass(repr=False)
668
+ class DropStmt(Node):
669
+ kind: str # TABLE | VIEW | MATERIALIZED VIEW | FUNCTION | PROCEDURE | ...
670
+ name: List[str]
671
+ if_exists: bool = False
672
+
673
+ @property
674
+ def full_name(self) -> str:
675
+ return ".".join(self.name)
676
+
677
+
678
+ @dataclass(repr=False)
679
+ class RoutineParam(Node):
680
+ name: str
681
+ type: Optional[TypeNode] = None
682
+ mode: Optional[str] = None # IN | OUT | INOUT (procedures only)
683
+
684
+
685
+ @dataclass(repr=False)
686
+ class CreateProcedure(Node):
687
+ name: List[str]
688
+ params: List[RoutineParam]
689
+ body: ScriptBlock
690
+ replace: bool = False
691
+ if_not_exists: bool = False
692
+ options_sql: Optional[str] = None
693
+
694
+ @property
695
+ def full_name(self) -> str:
696
+ return ".".join(self.name)
697
+
698
+
699
+ @dataclass(repr=False)
700
+ class CreateFunction(Node):
701
+ name: List[str]
702
+ params: List[RoutineParam] = field(default_factory=list)
703
+ returns: Optional[TypeNode] = None
704
+ returns_table: List[StructFieldType] = field(default_factory=list)
705
+ language: Optional[str] = None
706
+ body_expr: Optional[Expr] = None # SQL UDF: AS (expr)
707
+ body_query: Optional["Query"] = None # TVF: AS (SELECT ...)
708
+ body_string: Optional[str] = None # JS UDF: AS "..."
709
+ replace: bool = False
710
+ temp: bool = False
711
+ if_not_exists: bool = False
712
+ table_function: bool = False
713
+ aggregate: bool = False
714
+ deterministic: Optional[bool] = None
715
+ options_sql: Optional[str] = None
716
+
717
+ @property
718
+ def full_name(self) -> str:
719
+ return ".".join(self.name)
720
+
721
+
722
+ Statement = Union[
723
+ Query, CreateTableAsSelect, InsertStmt, UpdateStmt, DeleteStmt, MergeStmt,
724
+ DeclareStmt, SetStmt, ScriptBlock, IfStmt, LoopStmt, WhileStmt, RepeatStmt,
725
+ ForInStmt, BreakContinueStmt, CallStmt, ReturnStmt, RaiseStmt,
726
+ ExecuteImmediate, AssertStmt, TransactionStmt, TruncateStmt, DropStmt,
727
+ CreateProcedure, CreateFunction,
728
+ ]