sqlspec 0.12.2__py3-none-any.whl → 0.13.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.

Potentially problematic release.


This version of sqlspec might be problematic. Click here for more details.

Files changed (113) hide show
  1. sqlspec/_sql.py +21 -180
  2. sqlspec/adapters/adbc/config.py +10 -12
  3. sqlspec/adapters/adbc/driver.py +120 -118
  4. sqlspec/adapters/aiosqlite/config.py +16 -3
  5. sqlspec/adapters/aiosqlite/driver.py +100 -130
  6. sqlspec/adapters/asyncmy/config.py +17 -4
  7. sqlspec/adapters/asyncmy/driver.py +123 -135
  8. sqlspec/adapters/asyncpg/config.py +17 -29
  9. sqlspec/adapters/asyncpg/driver.py +98 -140
  10. sqlspec/adapters/bigquery/config.py +4 -5
  11. sqlspec/adapters/bigquery/driver.py +125 -167
  12. sqlspec/adapters/duckdb/config.py +3 -6
  13. sqlspec/adapters/duckdb/driver.py +114 -111
  14. sqlspec/adapters/oracledb/config.py +32 -5
  15. sqlspec/adapters/oracledb/driver.py +242 -259
  16. sqlspec/adapters/psqlpy/config.py +18 -9
  17. sqlspec/adapters/psqlpy/driver.py +118 -93
  18. sqlspec/adapters/psycopg/config.py +44 -31
  19. sqlspec/adapters/psycopg/driver.py +283 -236
  20. sqlspec/adapters/sqlite/config.py +3 -3
  21. sqlspec/adapters/sqlite/driver.py +103 -97
  22. sqlspec/config.py +0 -4
  23. sqlspec/driver/_async.py +89 -98
  24. sqlspec/driver/_common.py +52 -17
  25. sqlspec/driver/_sync.py +81 -105
  26. sqlspec/driver/connection.py +207 -0
  27. sqlspec/driver/mixins/_csv_writer.py +91 -0
  28. sqlspec/driver/mixins/_pipeline.py +38 -49
  29. sqlspec/driver/mixins/_result_utils.py +27 -9
  30. sqlspec/driver/mixins/_storage.py +67 -181
  31. sqlspec/driver/mixins/_type_coercion.py +3 -4
  32. sqlspec/driver/parameters.py +138 -0
  33. sqlspec/exceptions.py +10 -2
  34. sqlspec/extensions/aiosql/adapter.py +0 -10
  35. sqlspec/extensions/litestar/handlers.py +0 -1
  36. sqlspec/extensions/litestar/plugin.py +0 -3
  37. sqlspec/extensions/litestar/providers.py +0 -14
  38. sqlspec/loader.py +25 -90
  39. sqlspec/protocols.py +542 -0
  40. sqlspec/service/__init__.py +3 -2
  41. sqlspec/service/_util.py +147 -0
  42. sqlspec/service/base.py +1116 -9
  43. sqlspec/statement/builder/__init__.py +42 -32
  44. sqlspec/statement/builder/_ddl_utils.py +0 -10
  45. sqlspec/statement/builder/_parsing_utils.py +10 -4
  46. sqlspec/statement/builder/base.py +67 -22
  47. sqlspec/statement/builder/column.py +283 -0
  48. sqlspec/statement/builder/ddl.py +91 -67
  49. sqlspec/statement/builder/delete.py +23 -7
  50. sqlspec/statement/builder/insert.py +29 -15
  51. sqlspec/statement/builder/merge.py +4 -4
  52. sqlspec/statement/builder/mixins/_aggregate_functions.py +113 -14
  53. sqlspec/statement/builder/mixins/_common_table_expr.py +0 -1
  54. sqlspec/statement/builder/mixins/_delete_from.py +1 -1
  55. sqlspec/statement/builder/mixins/_from.py +10 -8
  56. sqlspec/statement/builder/mixins/_group_by.py +0 -1
  57. sqlspec/statement/builder/mixins/_insert_from_select.py +0 -1
  58. sqlspec/statement/builder/mixins/_insert_values.py +0 -2
  59. sqlspec/statement/builder/mixins/_join.py +20 -13
  60. sqlspec/statement/builder/mixins/_limit_offset.py +3 -3
  61. sqlspec/statement/builder/mixins/_merge_clauses.py +3 -4
  62. sqlspec/statement/builder/mixins/_order_by.py +2 -2
  63. sqlspec/statement/builder/mixins/_pivot.py +4 -7
  64. sqlspec/statement/builder/mixins/_select_columns.py +6 -5
  65. sqlspec/statement/builder/mixins/_unpivot.py +6 -9
  66. sqlspec/statement/builder/mixins/_update_from.py +2 -1
  67. sqlspec/statement/builder/mixins/_update_set.py +11 -8
  68. sqlspec/statement/builder/mixins/_where.py +61 -34
  69. sqlspec/statement/builder/select.py +32 -17
  70. sqlspec/statement/builder/update.py +25 -11
  71. sqlspec/statement/filters.py +39 -14
  72. sqlspec/statement/parameter_manager.py +220 -0
  73. sqlspec/statement/parameters.py +210 -79
  74. sqlspec/statement/pipelines/__init__.py +166 -23
  75. sqlspec/statement/pipelines/analyzers/_analyzer.py +21 -20
  76. sqlspec/statement/pipelines/context.py +35 -39
  77. sqlspec/statement/pipelines/transformers/__init__.py +2 -3
  78. sqlspec/statement/pipelines/transformers/_expression_simplifier.py +19 -187
  79. sqlspec/statement/pipelines/transformers/_literal_parameterizer.py +628 -58
  80. sqlspec/statement/pipelines/transformers/_remove_comments_and_hints.py +76 -0
  81. sqlspec/statement/pipelines/validators/_dml_safety.py +33 -18
  82. sqlspec/statement/pipelines/validators/_parameter_style.py +87 -14
  83. sqlspec/statement/pipelines/validators/_performance.py +38 -23
  84. sqlspec/statement/pipelines/validators/_security.py +39 -62
  85. sqlspec/statement/result.py +37 -129
  86. sqlspec/statement/splitter.py +0 -12
  87. sqlspec/statement/sql.py +863 -391
  88. sqlspec/statement/sql_compiler.py +140 -0
  89. sqlspec/storage/__init__.py +10 -2
  90. sqlspec/storage/backends/fsspec.py +53 -8
  91. sqlspec/storage/backends/obstore.py +15 -19
  92. sqlspec/storage/capabilities.py +101 -0
  93. sqlspec/storage/registry.py +56 -83
  94. sqlspec/typing.py +6 -434
  95. sqlspec/utils/cached_property.py +25 -0
  96. sqlspec/utils/correlation.py +0 -2
  97. sqlspec/utils/logging.py +0 -6
  98. sqlspec/utils/sync_tools.py +0 -4
  99. sqlspec/utils/text.py +0 -5
  100. sqlspec/utils/type_guards.py +892 -0
  101. {sqlspec-0.12.2.dist-info → sqlspec-0.13.1.dist-info}/METADATA +1 -1
  102. sqlspec-0.13.1.dist-info/RECORD +150 -0
  103. sqlspec/statement/builder/protocols.py +0 -20
  104. sqlspec/statement/pipelines/base.py +0 -315
  105. sqlspec/statement/pipelines/result_types.py +0 -41
  106. sqlspec/statement/pipelines/transformers/_remove_comments.py +0 -66
  107. sqlspec/statement/pipelines/transformers/_remove_hints.py +0 -81
  108. sqlspec/statement/pipelines/validators/base.py +0 -67
  109. sqlspec/storage/protocol.py +0 -173
  110. sqlspec-0.12.2.dist-info/RECORD +0 -145
  111. {sqlspec-0.12.2.dist-info → sqlspec-0.13.1.dist-info}/WHEEL +0 -0
  112. {sqlspec-0.12.2.dist-info → sqlspec-0.13.1.dist-info}/licenses/LICENSE +0 -0
  113. {sqlspec-0.12.2.dist-info → sqlspec-0.13.1.dist-info}/licenses/NOTICE +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sqlspec
3
- Version: 0.12.2
3
+ Version: 0.13.1
4
4
  Summary: SQL Experiments in Python
5
5
  Project-URL: Discord, https://discord.gg/litestar
6
6
  Project-URL: Issue, https://github.com/litestar-org/sqlspec/issues/
@@ -0,0 +1,150 @@
1
+ sqlspec/__init__.py,sha256=hyVFQsYsgDWOZ2EPnW1LnATQVxGcYu3liBvSOvk4EQk,705
2
+ sqlspec/__metadata__.py,sha256=hNP3wXvtk8fQVPKGjRLpZ9mP-gaPJqzrmgm3UqpDIXQ,460
3
+ sqlspec/_serialization.py,sha256=7zox4G9zIps-DCdIEwYs4gwALfEOy1g_sWS4r5kpzO8,2604
4
+ sqlspec/_sql.py,sha256=zqMtVWBZzbnNErB8VyJkjDCPq0RNkhGUPA2ZCOtzmGo,35759
5
+ sqlspec/_typing.py,sha256=Vn1CTCfedAHZV3pKZP-l_mPw9pTxesCzRKVRypzNY_k,17903
6
+ sqlspec/base.py,sha256=a7adbCUzohf1MU-iP0TxazGsk9fsJhJmxuFKNWkgC6o,18355
7
+ sqlspec/config.py,sha256=NJg5cjITI3GBCm3ru-m9K3y_XLa0Ru8Z4suG3TjXRmw,12896
8
+ sqlspec/exceptions.py,sha256=T2h-tCN05sRKSpXDjPtYXvNgwInNVzTpha1PIkSUROQ,14168
9
+ sqlspec/loader.py,sha256=J0PaBiY8kC_gCI-3i8Vj3IBZIgKJ4TvRAJzMQerLZMQ,15354
10
+ sqlspec/protocols.py,sha256=ce9L1nqxpmDSQqUR6UoKB8f5eL0hFnp2ProrsMwMsKk,17218
11
+ sqlspec/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
+ sqlspec/typing.py,sha256=qkUcvruNzRUUfpv4AkbQezpy9SokhVHXlMbfFNwQlnU,8721
13
+ sqlspec/adapters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
+ sqlspec/adapters/adbc/__init__.py,sha256=v9bs7501PgEyzR1XIsEpE2Wdrj9DOYkZ4grysw72UXk,218
15
+ sqlspec/adapters/adbc/config.py,sha256=v_gk-C-StoWiSjmB9Ehl6ce2eGqUgb1-JUxSq3lS8l8,20022
16
+ sqlspec/adapters/adbc/driver.py,sha256=WP3YVS-9Y1aup9IQ7y4L8x9e414epcWCyhPHuBVp66w,16644
17
+ sqlspec/adapters/aiosqlite/__init__.py,sha256=7wPmhXQeu4jRi-LZzPxAPTdgRmgmyqCn9U-4wnCWoLM,258
18
+ sqlspec/adapters/aiosqlite/config.py,sha256=Ysbu6sLDVrUtztLRKgphQphxxUCaj2V4W55mLfK-lq0,7652
19
+ sqlspec/adapters/aiosqlite/driver.py,sha256=cfxuob0EmnLB3iCgpuqjw40-9ZWSmVLZ_UL3BNznXt0,11282
20
+ sqlspec/adapters/asyncmy/__init__.py,sha256=zYpebEt_PrNCifLcqXiCcWVm0Zl-LvWbFDromWwSTw8,270
21
+ sqlspec/adapters/asyncmy/config.py,sha256=VSEtK69IHjyjXA6c4AEKSIivGqKOz6B5G7IyCXREhug,10879
22
+ sqlspec/adapters/asyncmy/driver.py,sha256=7l9rsAxTiJhiTiBMQc0e1QwBDWopvfii5jgFwREITog,10085
23
+ sqlspec/adapters/asyncpg/__init__.py,sha256=svnbKlOin8jRL88AdAqflBEU-WEAzp0Thc2y50QsxIo,310
24
+ sqlspec/adapters/asyncpg/config.py,sha256=AAxEqH6ZbCUvr7nIokVurqhxfLgBdix07yFXIhDKSSg,12510
25
+ sqlspec/adapters/asyncpg/driver.py,sha256=X5IF5_NEiQ86aLspuqjY9Fh5OIluCCNa7TAzLEFENjQ,17572
26
+ sqlspec/adapters/bigquery/__init__.py,sha256=fWRH-BoCNX4rYwhU2DK64cXWpfkYpWIExddJAti0bxM,250
27
+ sqlspec/adapters/bigquery/config.py,sha256=iwQ3BPYtywjD17TaYh0YAO4X_ry5DkWIRKWPAeYrkzg,16929
28
+ sqlspec/adapters/bigquery/driver.py,sha256=2aVWjjVAWci92wyXKo5dVV9PGBb6uDkSvDBEEs1eFPw,30385
29
+ sqlspec/adapters/duckdb/__init__.py,sha256=I1f6szfpKKrq6WhyDoUXD3i3NN4yjsh94_fhP1URI5M,351
30
+ sqlspec/adapters/duckdb/config.py,sha256=DBfDLaS_y3qfdYgxCnfnWml7lj1OFOMeUrGxkt6kFj0,20304
31
+ sqlspec/adapters/duckdb/driver.py,sha256=JZipJMy1yUfedtlNZxd8pGTFVylve8ia4XeKfd7dd0c,18095
32
+ sqlspec/adapters/oracledb/__init__.py,sha256=nn3whn0UyBThoXnE1-5_byVuc9PJjvB2P896p7LpNZI,474
33
+ sqlspec/adapters/oracledb/config.py,sha256=wewrgAVbWuZVhIDfOUrf7B6GgkGX2tY-GNA-AYoaRNQ,23833
34
+ sqlspec/adapters/oracledb/driver.py,sha256=ZFOHGQwajIkG7PSWi_ER9QQRNdf18DyYho3L36m7CVU,24473
35
+ sqlspec/adapters/psqlpy/__init__.py,sha256=dp0-96V4SAbNEvOqlJ8PWEyJMYzZGElVoyneZqJ-fbQ,297
36
+ sqlspec/adapters/psqlpy/config.py,sha256=n62ku23eyL5hZPMt4dH0FsksFr89vNM4V-eKAABvQAA,16653
37
+ sqlspec/adapters/psqlpy/driver.py,sha256=liB3pGbDKuz2PyTd3QeDk3rRLKE57leviIdN_hqJHvg,9961
38
+ sqlspec/adapters/psycopg/__init__.py,sha256=ukkCUPrJPyAG78v4rOqcK4WZDs26PeB9Ra9qkFrGJ3E,484
39
+ sqlspec/adapters/psycopg/config.py,sha256=gjtms8wfL7BeUvfJG1K0TMZ6d3BtVzi5X5_enMS2Ieg,27759
40
+ sqlspec/adapters/psycopg/driver.py,sha256=UnnVJg5SwjReYWYX4fQ05JmL5hoJ1XeUby2m9IBrOgM,40064
41
+ sqlspec/adapters/sqlite/__init__.py,sha256=1lYrJ-DojUAOvXMoZRUJNEVyMmYhO41hMJnDWCEeXlw,234
42
+ sqlspec/adapters/sqlite/config.py,sha256=ph3FjdrbVkDaasGDEoZ-estP1NJdj8PqBJqpV-2IJxI,6191
43
+ sqlspec/adapters/sqlite/driver.py,sha256=0xBl7J5bPuv07fte5zPQj-bLhuiIC1_QPHu64i8Il80,12423
44
+ sqlspec/driver/__init__.py,sha256=0udRS5IlJ17HzOCvzapG8c_88yAwTQri1XLD_3fZxZU,671
45
+ sqlspec/driver/_async.py,sha256=ZSUNvVBU22KcpvKrDPJnlc6lnD49XLovS4vCQnr_OPA,9992
46
+ sqlspec/driver/_common.py,sha256=ALJyI6NS_pa0BOad0xiCMRwFLh4ykneaDW_xg9h8Z48,15811
47
+ sqlspec/driver/_sync.py,sha256=KzETeE-NHc1cOcX3LQ_88PejM-TJHD24UFQrB_yLDfQ,9832
48
+ sqlspec/driver/connection.py,sha256=zKP2p-VLxN07IPfOIBKMRELHN7ZMjmRVUKBgSW-6RQg,6610
49
+ sqlspec/driver/parameters.py,sha256=srU_7z3sB2vBu_lz9rAiDW2J2Ce47l12bqhxw6jEePE,4002
50
+ sqlspec/driver/mixins/__init__.py,sha256=-FSWLYq644NftRsmjmXMA9Q7_l7tIFAIh1ZyK0yrba8,652
51
+ sqlspec/driver/mixins/_csv_writer.py,sha256=-uRe7QZRWtdZTFG3Fiej4Ia8EyQcjYr7oPT6wb0qTOc,2716
52
+ sqlspec/driver/mixins/_pipeline.py,sha256=ESQyQo1ow_yerUvdFYS_CBy-6XS9tIow41j80yjCz4w,19588
53
+ sqlspec/driver/mixins/_result_utils.py,sha256=RvdE1BKwnTPx3aXDwnJEonJzp5PdT1Wgn63DGZyglvg,5692
54
+ sqlspec/driver/mixins/_sql_translator.py,sha256=p_PR4KBg9NKNpRpiEqA0hcUIttpdillHpnLUVJEcxuE,1519
55
+ sqlspec/driver/mixins/_storage.py,sha256=P6eIvCMCM6BMH4G0rbWZTb4Q54mmvtnTxk2pMp3JW7o,38558
56
+ sqlspec/driver/mixins/_type_coercion.py,sha256=ix-_p1-Yp9LhQdGFhFN1H_O8_VbVih-nzLPbsQiNFnE,4578
57
+ sqlspec/extensions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
58
+ sqlspec/extensions/aiosql/__init__.py,sha256=-9cefc9pYPf9vCgALoB-y1DtmcgRjKe2azfl6RIarAA,414
59
+ sqlspec/extensions/aiosql/adapter.py,sha256=BcJI0y0Hj5t5aH6_Kx_06EkKy3aBLsh7xIJH-LMMoGg,16544
60
+ sqlspec/extensions/litestar/__init__.py,sha256=aXF2g4-U86pdJHoOA6RCvZgnyHVBbjRhlWqcSuRX2gg,243
61
+ sqlspec/extensions/litestar/_utils.py,sha256=o-FuUj1_WkDrLxQxiP6hXDak66XfyRP3QLyEVKrIRjI,1954
62
+ sqlspec/extensions/litestar/config.py,sha256=vLXM425tCV3IbJiNO1ZG90ctjBTb9oQCuLsqCaUYmo8,4685
63
+ sqlspec/extensions/litestar/handlers.py,sha256=bVoWmHhCsHZkXZXYHE23yDaJlRoydfvU-boJjA3BSLE,10478
64
+ sqlspec/extensions/litestar/plugin.py,sha256=ysuy4dmF6VAhUkIcVOSPfv5HcBGmwSZ9_PjttBs81g4,5431
65
+ sqlspec/extensions/litestar/providers.py,sha256=wUGqPeNV58rPqL1iwDQg439C4y-Zg-eXEogjeFsv0iQ,21021
66
+ sqlspec/service/__init__.py,sha256=DayFSxYU4AMbcN0JWBuB1rtrOAs-amKIAIyTJXXNKH0,206
67
+ sqlspec/service/_util.py,sha256=K31tzlOsTXGhbXe4u5ltZYLExuaFtpiZoIHLOk8yNyM,6096
68
+ sqlspec/service/base.py,sha256=iW4LbrIxjrSt0mDPPSmuUGQgdQTFM-xgmZdThCLa5u4,40592
69
+ sqlspec/service/pagination.py,sha256=ndLQwsvswoISWEE_3IG9nmdHt42OZkVMJvr-2HTWsLw,619
70
+ sqlspec/statement/__init__.py,sha256=NDvdrpr1EqAZXp4HmhTVaRnWVscahPSHpmSO8DHSoMY,536
71
+ sqlspec/statement/filters.py,sha256=qX5KOe-rLmFwyD8xaUcTTkh45Dg1ViKx_hTAqjKtWh4,22565
72
+ sqlspec/statement/parameter_manager.py,sha256=nbeLzO2Hnm4Su8id-fKEELvWEI8dbbC5ZYiqo4jjbvc,9557
73
+ sqlspec/statement/parameters.py,sha256=8V9mNr5Lb4iZmHfucZB9HMYOI2OmhaNzr2ZnMSAYnKk,35791
74
+ sqlspec/statement/result.py,sha256=-yARFxg7Wsm8nAeHMpnJ58OLd2VujFiZx29wfo7eFVs,14514
75
+ sqlspec/statement/splitter.py,sha256=mCzJsNEtJFk4A0FdTELkG_qOggRFCQC_ZEJisVo9orY,24111
76
+ sqlspec/statement/sql.py,sha256=l_KrA91wlIAXIQiaOsvEqZbY-Hg6QWtF8Va2qr7mfCE,71916
77
+ sqlspec/statement/sql_compiler.py,sha256=f1UoGWjZTCLwOMBiG1R45_tq8oQlR8Qmm9fHKy_uXYA,5882
78
+ sqlspec/statement/builder/__init__.py,sha256=FMTnEKOIHCywjnqGXfOfzZzYKmciue0h37DG2KZAUZI,1610
79
+ sqlspec/statement/builder/_ddl_utils.py,sha256=P0INvHoOA9Mk7rmrga0xRvxF6YgNXchsg1Q3hfvlCqQ,4326
80
+ sqlspec/statement/builder/_parsing_utils.py,sha256=xAxWfa-mjjLPyweM9396lQy91G5MsxYyaJzTAoEiuAU,5753
81
+ sqlspec/statement/builder/base.py,sha256=DArCuNwDXslt73Jk5Io3WqUP1ZXA0e4cUXtzFjvQ5g4,14738
82
+ sqlspec/statement/builder/column.py,sha256=JWeZ5hnawCWm00jeojwm8i79p8oYNkg30SIdOOolNjM,11521
83
+ sqlspec/statement/builder/ddl.py,sha256=vqAebkN6JoX6n8aLVwZdyW3Xfyj3Ws6frWu-_7wy8uE,51516
84
+ sqlspec/statement/builder/delete.py,sha256=5BVwxcNY5nSgeZrZ4tSfdA2di3X8M3y7I5t9D35d0mk,2881
85
+ sqlspec/statement/builder/insert.py,sha256=Q2ArKq4BPP69G-OTxcUVgixlhsKjdOm248RJxtJFyps,10129
86
+ sqlspec/statement/builder/merge.py,sha256=SUrumqMrUBO1vMFWll45vvYj4DmrL3WuCZLdHap8ej8,2783
87
+ sqlspec/statement/builder/select.py,sha256=4UXNo9_13XQIqmzzovsRQBAwooFtBdzsolUoTzxgNE4,8642
88
+ sqlspec/statement/builder/update.py,sha256=qV5frucca42xuzSeAdBAqNnYTRyEZJrhkZ5uEI1eGKs,6245
89
+ sqlspec/statement/builder/mixins/__init__.py,sha256=B5GhsdySb_-DN3SvBlA2oimmymAJX3Rf4A7Xnz3uNN4,2887
90
+ sqlspec/statement/builder/mixins/_aggregate_functions.py,sha256=yeXm_mp0JDbzSe2N2vpJHbGVYmdnrCMqwdHXz2rJAVs,10551
91
+ sqlspec/statement/builder/mixins/_case_builder.py,sha256=fGdevoEZxmoJjsDV9Wwfom8vu3lmgF9B_o5HXCf25Kg,3047
92
+ sqlspec/statement/builder/mixins/_common_table_expr.py,sha256=R7BUdWEHpuPGumgBsUnUPaVLH0sF3oRiJRw-xXEkTj8,3694
93
+ sqlspec/statement/builder/mixins/_delete_from.py,sha256=HsJseeYY-HUoiTYRdPpCDG0kIHrhXOg_GA52RT7dEGY,1019
94
+ sqlspec/statement/builder/mixins/_from.py,sha256=bGcI7TuY3Z3Xx8oLR9jXx_d25s0db0uJBx4SSw0kKh8,2850
95
+ sqlspec/statement/builder/mixins/_group_by.py,sha256=gLbveNJuvk_FdZxYKBzx4cCQQvxqzecc_vmb5d8_Du0,4142
96
+ sqlspec/statement/builder/mixins/_having.py,sha256=X8-hdwEeJg4RYxyjhaYLvlkpzE0AwIPl6t8SPGz5gi0,1112
97
+ sqlspec/statement/builder/mixins/_insert_from_select.py,sha256=RMvdNXU1W7zqceOGwo_G_n0bbd-S63bBwOCs44H0j4Y,1801
98
+ sqlspec/statement/builder/mixins/_insert_into.py,sha256=7979JCYqKM_NRTHwkrJJY6l9lS2AQ-evZYRU8fs3yw0,1049
99
+ sqlspec/statement/builder/mixins/_insert_values.py,sha256=5kheKKtdpOVHSIPox88bYwtD4Rr5v1_J_K9Wmam7-Vk,2820
100
+ sqlspec/statement/builder/mixins/_join.py,sha256=lSGFtq_KJ985SCmUKmIx-4NwniIwQIVmLJYryF5mtc4,5658
101
+ sqlspec/statement/builder/mixins/_limit_offset.py,sha256=qLxBek2CpJz-k717ZTpJ5eVlQJ5McZPAQEwFbRM-XuI,1753
102
+ sqlspec/statement/builder/mixins/_merge_clauses.py,sha256=Tmi9Yb_7BPtFtpxj3splUTNQfjS8TdcN8TY9qJQqNNU,16798
103
+ sqlspec/statement/builder/mixins/_order_by.py,sha256=1yMXkl9MYd5uk3RRMWxhR4VCmvHGvwY6bojofFt6jc0,1717
104
+ sqlspec/statement/builder/mixins/_pivot.py,sha256=mnGNCZYbl00JAny6h9p-EQkhGNiNN8w--ZNd7X0Fs8I,3257
105
+ sqlspec/statement/builder/mixins/_returning.py,sha256=O39j2MEIcqiiUhFFGnyGwIXhLS7KrGigfZ9kPxFjjtI,1349
106
+ sqlspec/statement/builder/mixins/_select_columns.py,sha256=wVUg9ECJH6r1QEh7VWV6DGpb86oo4vuFHPpOx_G8Hcw,2421
107
+ sqlspec/statement/builder/mixins/_set_ops.py,sha256=uWV32ZAi2tojbS9b6Q0ZDIn1Rhbx4cCE42jhbVdm90I,5291
108
+ sqlspec/statement/builder/mixins/_unpivot.py,sha256=99tN2skDD3M77v7MyqisugxHR-6BB984FLX7iY4RpG0,3086
109
+ sqlspec/statement/builder/mixins/_update_from.py,sha256=NAHiL08NBoh8jFxZG_ZiSjbEDcIR9ni7-d--nVIXf6g,2540
110
+ sqlspec/statement/builder/mixins/_update_set.py,sha256=gLcGeBMSHqCGPrJz-pb5951g-4xCLJDltOzbMM1OQRM,4306
111
+ sqlspec/statement/builder/mixins/_update_table.py,sha256=FX3KezuHdu7YLQI4i5iniHWk1Lbzph8MzLcOM6iTd70,936
112
+ sqlspec/statement/builder/mixins/_where.py,sha256=kfttMYubr4zzOJkbxTh-U3lTt5uNFgkmjCEixs6n9LM,21227
113
+ sqlspec/statement/builder/mixins/_window_functions.py,sha256=8ldy06gK6jOlGg31oa1dCrG7IkfCVYvVr_f-lx0YcgU,3745
114
+ sqlspec/statement/pipelines/__init__.py,sha256=eFCKEmMqQAyDwfg9_kgE5e719OSC2nyhTme4IGmxb70,7326
115
+ sqlspec/statement/pipelines/context.py,sha256=mE7twvOydqyWQffp6KyMvOUl9FlTY9ypGL7M6SFYFK8,4210
116
+ sqlspec/statement/pipelines/analyzers/__init__.py,sha256=RY7W0AiWG-8qdrTmRSGlEofjrPPJCJUnNK-LRukKt5Q,330
117
+ sqlspec/statement/pipelines/analyzers/_analyzer.py,sha256=0_FDty6H_4JvQwee_NrzmptX9-VdhyAePXUstuq4MU4,27474
118
+ sqlspec/statement/pipelines/transformers/__init__.py,sha256=Kh4CE_izdwEsSF7Is6_6NXqtNmbLm5x5OWdnlUGp9ok,480
119
+ sqlspec/statement/pipelines/transformers/_expression_simplifier.py,sha256=0R2j046n12DDk1wGEmwX3f3KnaMUcSDWC0-lRmforjw,3385
120
+ sqlspec/statement/pipelines/transformers/_literal_parameterizer.py,sha256=N6a2lMGBHXcoHuSySY_9JhObNkPWabUBpR_25ZCnv0w,57183
121
+ sqlspec/statement/pipelines/transformers/_remove_comments_and_hints.py,sha256=-gM6VnlhNtQzSbQq44hQ5mhaPqNsjzeCaTgXTycgkOk,3008
122
+ sqlspec/statement/pipelines/validators/__init__.py,sha256=cdlwdLhOT2OwTbueIsA7bfRG2b6y-j7dw9pMzl5AP0M,747
123
+ sqlspec/statement/pipelines/validators/_dml_safety.py,sha256=s7Eee60u6w0K35vz4GVAwsB5Xy8zUqWhiIx_pRVfERo,10585
124
+ sqlspec/statement/pipelines/validators/_parameter_style.py,sha256=m8gNydG0KKyhmQyOEGZk8mhV_jLjT0vxIJy22AY8xkY,17840
125
+ sqlspec/statement/pipelines/validators/_performance.py,sha256=mTL5UB9Yj2XNjv31_CjqWHUAdj77iFtE7XDXQosG_20,26357
126
+ sqlspec/statement/pipelines/validators/_security.py,sha256=3WuH9n4j-VKOgmQnZvFIoI4MieRBVShtOZvXl2SJsyk,42103
127
+ sqlspec/storage/__init__.py,sha256=ZS8rmhN8e_h_df-Oab64Jh4EbddElBbmrtHkuO-KqOE,703
128
+ sqlspec/storage/capabilities.py,sha256=fsnQ9jbjHBFvd3P9yWAzfjPpVYUGcsTtR6fm5iOCvXY,3054
129
+ sqlspec/storage/registry.py,sha256=lv9pGt6vt0tDNAlao9qA7rSsFsCZtaOr48aG15IoMFA,10976
130
+ sqlspec/storage/backends/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
131
+ sqlspec/storage/backends/base.py,sha256=34XYQuz1tQ-q_ZZwOz-Kimgvl088SR3VUYJoA-STslc,6350
132
+ sqlspec/storage/backends/fsspec.py,sha256=wo40MwtEjNTc73ZNTCmNC2-Img0zldUCaFGh9H3BZuE,14715
133
+ sqlspec/storage/backends/obstore.py,sha256=FnoVzTzzNn5NRXR8GgETqD3Rq9C5EWAmfWmY4JDFVJE,21214
134
+ sqlspec/utils/__init__.py,sha256=_Ya8IZuc2cZIstXr_xjgnSfxICXHXvu5mfWsi2USDrw,183
135
+ sqlspec/utils/cached_property.py,sha256=Sw_JZxfChSJu72gvYBJPF-89FyyIJAPf-1ETlDq-F2E,648
136
+ sqlspec/utils/correlation.py,sha256=4jqpjMivxI1tQ13Ed-P0hLdFHUKUQ9GlvIM69_HOlS4,4370
137
+ sqlspec/utils/deprecation.py,sha256=zrmb_eKRlLWVA6dWrjUbN3Vz6D3_-Z_15Ixk4H-sDRk,3850
138
+ sqlspec/utils/fixtures.py,sha256=q_Pghpmw2VgJ9P0TfkyjSF5PvdaD5Y2Laha0Bj4IDrA,1838
139
+ sqlspec/utils/logging.py,sha256=56a5tqx4jfTqm20WDyj5c7Dy-h_O0KambIKOMr1-Oms,3780
140
+ sqlspec/utils/module_loader.py,sha256=9LcmEhy4T0jgkCaDVkxX47PSgJOMeJ8IV67yXEWBp-U,3074
141
+ sqlspec/utils/serializers.py,sha256=TKsRryRcYMnb8Z8MGkYGClIxcYvC8CW7MsrPQTJqEcY,154
142
+ sqlspec/utils/singleton.py,sha256=KZ7481tlDAxq6gcAlpULVqPLNc9P0XkHOEp7hfWIHcI,1096
143
+ sqlspec/utils/sync_tools.py,sha256=ckP1_uLh40C2pDvdc4FsR4NkmZVa1zEB8jhUxPLIuAI,8726
144
+ sqlspec/utils/text.py,sha256=DpEnRuSDv3acp4VQQGEOQixlJnLGZsN5YBws4rkI6t0,4756
145
+ sqlspec/utils/type_guards.py,sha256=uEtfznkkumiy2lnPOde35Ylzq2RrcPB-MBiWseMCADg,25722
146
+ sqlspec-0.13.1.dist-info/METADATA,sha256=WxPFx2SCx_K8lCfY18xnwH30ZxhxhLV9KyUAMl0MJxw,16663
147
+ sqlspec-0.13.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
148
+ sqlspec-0.13.1.dist-info/licenses/LICENSE,sha256=MdujfZ6l5HuLz4mElxlu049itenOR3gnhN1_Nd3nVcM,1078
149
+ sqlspec-0.13.1.dist-info/licenses/NOTICE,sha256=Lyir8ozXWov7CyYS4huVaOCNrtgL17P-bNV-5daLntQ,1634
150
+ sqlspec-0.13.1.dist-info/RECORD,,
@@ -1,20 +0,0 @@
1
- from typing import Any, Optional, Protocol, Union
2
-
3
- from sqlglot import exp
4
- from typing_extensions import Self
5
-
6
- __all__ = ("BuilderProtocol", "SelectBuilderProtocol")
7
-
8
-
9
- class BuilderProtocol(Protocol):
10
- _expression: Optional[exp.Expression]
11
- _parameters: dict[str, Any]
12
- _parameter_counter: int
13
- dialect: Any
14
- dialect_name: Optional[str]
15
-
16
- def add_parameter(self, value: Any, name: Optional[str] = None) -> tuple[Any, str]: ...
17
-
18
-
19
- class SelectBuilderProtocol(BuilderProtocol, Protocol):
20
- def select(self, *columns: Union[str, exp.Expression]) -> Self: ...
@@ -1,315 +0,0 @@
1
- """SQL Processing Pipeline Base.
2
-
3
- This module defines the core framework for constructing and executing a series of
4
- SQL processing steps, such as transformations and validations.
5
- """
6
-
7
- import contextlib
8
- from abc import ABC, abstractmethod
9
- from typing import TYPE_CHECKING, Optional
10
-
11
- import sqlglot # Added
12
- from sqlglot import exp
13
- from sqlglot.errors import ParseError as SQLGlotParseError # Added
14
- from typing_extensions import TypeVar
15
-
16
- from sqlspec.exceptions import RiskLevel, SQLValidationError
17
- from sqlspec.statement.pipelines.context import PipelineResult
18
- from sqlspec.statement.pipelines.result_types import ValidationError
19
- from sqlspec.utils.correlation import CorrelationContext
20
- from sqlspec.utils.logging import get_logger
21
-
22
- if TYPE_CHECKING:
23
- from collections.abc import Sequence
24
-
25
- from sqlglot.dialects.dialect import DialectType
26
-
27
- from sqlspec.statement.pipelines.context import SQLProcessingContext
28
- from sqlspec.statement.sql import SQLConfig, Statement
29
-
30
-
31
- __all__ = ("ProcessorProtocol", "SQLValidator", "StatementPipeline", "UsesExpression")
32
-
33
-
34
- logger = get_logger("pipelines")
35
-
36
- ExpressionT = TypeVar("ExpressionT", bound="exp.Expression")
37
- ResultT = TypeVar("ResultT")
38
-
39
-
40
- # Copied UsesExpression class here
41
- class UsesExpression:
42
- """Utility mixin class to get a sqlglot expression from various inputs."""
43
-
44
- @staticmethod
45
- def get_expression(statement: "Statement", dialect: "DialectType" = None) -> "exp.Expression":
46
- """Convert SQL input to expression.
47
-
48
- Args:
49
- statement: The SQL statement to convert to an expression.
50
- dialect: The SQL dialect.
51
-
52
- Raises:
53
- SQLValidationError: If the SQL parsing fails.
54
-
55
- Returns:
56
- An exp.Expression.
57
- """
58
- if isinstance(statement, exp.Expression):
59
- return statement
60
-
61
- # Local import to avoid circular dependency at module level
62
- from sqlspec.statement.sql import SQL
63
-
64
- if isinstance(statement, SQL):
65
- expr = statement.expression
66
- if expr is not None:
67
- return expr
68
- return sqlglot.parse_one(statement.sql, read=dialect)
69
-
70
- # Assuming statement is str hereafter
71
- sql_str = str(statement)
72
- if not sql_str or not sql_str.strip():
73
- return exp.Select()
74
-
75
- try:
76
- return sqlglot.parse_one(sql_str, read=dialect)
77
- except SQLGlotParseError as e:
78
- msg = f"SQL parsing failed: {e}"
79
- raise SQLValidationError(msg, sql_str, RiskLevel.HIGH) from e
80
-
81
-
82
- class ProcessorProtocol(ABC):
83
- """Defines the interface for a single processing step in the SQL pipeline."""
84
-
85
- @abstractmethod
86
- def process(
87
- self, expression: "Optional[exp.Expression]", context: "SQLProcessingContext"
88
- ) -> "Optional[exp.Expression]":
89
- """Processes an SQL expression.
90
-
91
- Args:
92
- expression: The SQL expression to process.
93
- context: The SQLProcessingContext holding the current state and config.
94
-
95
- Returns:
96
- The (possibly modified) SQL expression for transformers, or None for validators/analyzers.
97
- """
98
- raise NotImplementedError
99
-
100
-
101
- class StatementPipeline:
102
- """Orchestrates the processing of an SQL expression through transformers, validators, and analyzers."""
103
-
104
- def __init__(
105
- self,
106
- transformers: Optional[list[ProcessorProtocol]] = None,
107
- validators: Optional[list[ProcessorProtocol]] = None,
108
- analyzers: Optional[list[ProcessorProtocol]] = None,
109
- ) -> None:
110
- self.transformers = transformers or []
111
- self.validators = validators or []
112
- self.analyzers = analyzers or []
113
-
114
- def execute_pipeline(self, context: "SQLProcessingContext") -> "PipelineResult":
115
- """Executes the full pipeline (transform, validate, analyze) using the SQLProcessingContext."""
116
- CorrelationContext.get()
117
- if context.current_expression is None:
118
- if context.config.enable_parsing:
119
- try:
120
- context.current_expression = sqlglot.parse_one(context.initial_sql_string, dialect=context.dialect)
121
- except Exception as e:
122
- error = ValidationError(
123
- message=f"SQL Parsing Error: {e}",
124
- code="parsing-error",
125
- risk_level=RiskLevel.CRITICAL,
126
- processor="StatementPipeline",
127
- expression=None,
128
- )
129
- context.validation_errors.append(error)
130
-
131
- return PipelineResult(expression=exp.Select(), context=context)
132
- else:
133
- # If parsing is disabled and no expression given, it's a config error for the pipeline.
134
- # However, SQL._initialize_statement should have handled this by not calling the pipeline
135
- # or by ensuring current_expression is set if enable_parsing is false.
136
- # For safety, we can raise or create an error result.
137
-
138
- error = ValidationError(
139
- message="Pipeline executed without an initial expression and parsing disabled.",
140
- code="no-expression",
141
- risk_level=RiskLevel.CRITICAL,
142
- processor="StatementPipeline",
143
- expression=None,
144
- )
145
- context.validation_errors.append(error)
146
-
147
- return PipelineResult(
148
- expression=exp.Select(), # Default empty expression
149
- context=context,
150
- )
151
-
152
- # 1. Transformation Stage
153
- if context.config.enable_transformations:
154
- for transformer in self.transformers:
155
- transformer_name = transformer.__class__.__name__
156
- try:
157
- if context.current_expression is not None:
158
- context.current_expression = transformer.process(context.current_expression, context)
159
- except Exception as e:
160
- # Log transformation failure as a validation error
161
-
162
- error = ValidationError(
163
- message=f"Transformer {transformer_name} failed: {e}",
164
- code="transformer-failure",
165
- risk_level=RiskLevel.CRITICAL,
166
- processor=transformer_name,
167
- expression=context.current_expression,
168
- )
169
- context.validation_errors.append(error)
170
- logger.exception("Transformer %s failed", transformer_name)
171
- break
172
-
173
- # 2. Validation Stage
174
- if context.config.enable_validation:
175
- for validator_component in self.validators:
176
- validator_name = validator_component.__class__.__name__
177
- try:
178
- # Validators process and add errors to context
179
- if context.current_expression is not None:
180
- validator_component.process(context.current_expression, context)
181
- except Exception as e:
182
- # Log validator failure
183
-
184
- error = ValidationError(
185
- message=f"Validator {validator_name} failed: {e}",
186
- code="validator-failure",
187
- risk_level=RiskLevel.CRITICAL,
188
- processor=validator_name,
189
- expression=context.current_expression,
190
- )
191
- context.validation_errors.append(error)
192
- logger.exception("Validator %s failed", validator_name)
193
-
194
- # 3. Analysis Stage
195
- if context.config.enable_analysis and context.current_expression is not None:
196
- for analyzer_component in self.analyzers:
197
- analyzer_name = analyzer_component.__class__.__name__
198
- try:
199
- analyzer_component.process(context.current_expression, context)
200
- except Exception as e:
201
- error = ValidationError(
202
- message=f"Analyzer {analyzer_name} failed: {e}",
203
- code="analyzer-failure",
204
- risk_level=RiskLevel.MEDIUM,
205
- processor=analyzer_name,
206
- expression=context.current_expression,
207
- )
208
- context.validation_errors.append(error)
209
- logger.exception("Analyzer %s failed", analyzer_name)
210
-
211
- return PipelineResult(expression=context.current_expression or exp.Select(), context=context)
212
-
213
-
214
- class SQLValidator(ProcessorProtocol, UsesExpression):
215
- """Main SQL validator that orchestrates multiple validation checks.
216
- This class functions as a validation pipeline runner.
217
- """
218
-
219
- def __init__(
220
- self,
221
- validators: "Optional[Sequence[ProcessorProtocol]]" = None,
222
- min_risk_to_raise: "Optional[RiskLevel]" = RiskLevel.HIGH,
223
- ) -> None:
224
- self.validators: list[ProcessorProtocol] = list(validators) if validators is not None else []
225
- self.min_risk_to_raise = min_risk_to_raise
226
-
227
- def add_validator(self, validator: "ProcessorProtocol") -> None:
228
- """Add a validator to the pipeline."""
229
- self.validators.append(validator)
230
-
231
- def process(
232
- self, expression: "Optional[exp.Expression]", context: "SQLProcessingContext"
233
- ) -> "Optional[exp.Expression]":
234
- """Process the expression through all configured validators.
235
-
236
- Args:
237
- expression: The SQL expression to validate.
238
- context: The SQLProcessingContext holding the current state and config.
239
-
240
- Returns:
241
- The expression unchanged (validators don't transform).
242
- """
243
- if expression is None:
244
- return None
245
-
246
- if not context.config.enable_validation:
247
- # Skip validation - add a skip marker to context
248
- return expression
249
-
250
- self._run_validators(expression, context)
251
- return expression
252
-
253
- @staticmethod
254
- def _validate_safely(
255
- validator_instance: "ProcessorProtocol", expression: "exp.Expression", context: "SQLProcessingContext"
256
- ) -> None:
257
- try:
258
- validator_instance.process(expression, context)
259
- except Exception as e:
260
- # Add error to context
261
-
262
- error = ValidationError(
263
- message=f"Validator {validator_instance.__class__.__name__} error: {e}",
264
- code="validator-error",
265
- risk_level=RiskLevel.CRITICAL,
266
- processor=validator_instance.__class__.__name__,
267
- expression=expression,
268
- )
269
- context.validation_errors.append(error)
270
- logger.warning("Individual validator %s failed: %s", validator_instance.__class__.__name__, e)
271
-
272
- def _run_validators(self, expression: "Optional[exp.Expression]", context: "SQLProcessingContext") -> None:
273
- """Run all validators and handle exceptions."""
274
- if not expression:
275
- # If no expression, nothing to validate
276
- return
277
- for validator_instance in self.validators:
278
- self._validate_safely(validator_instance, expression, context)
279
-
280
- def validate(
281
- self, sql: "Statement", dialect: "DialectType", config: "Optional[SQLConfig]" = None
282
- ) -> "list[ValidationError]":
283
- """Convenience method to validate a raw SQL string or expression.
284
-
285
- Returns:
286
- List of ValidationError objects found during validation.
287
- """
288
- from sqlspec.statement.pipelines.context import SQLProcessingContext # Local import for context
289
- from sqlspec.statement.sql import SQLConfig # Local import for SQL.to_expression
290
-
291
- current_config = config or SQLConfig()
292
- expression_to_validate = self.get_expression(sql, dialect=dialect)
293
-
294
- # Create a context for this validation run
295
- validation_context = SQLProcessingContext(
296
- initial_sql_string=str(sql),
297
- dialect=dialect,
298
- config=current_config,
299
- current_expression=expression_to_validate,
300
- initial_expression=expression_to_validate,
301
- # Other context fields like parameters might not be strictly necessary for all validators
302
- # but good to pass if available or if validators might need them.
303
- # For a standalone validate() call, parameter context might be minimal.
304
- input_sql_had_placeholders=False, # Assume false for raw validation, or detect
305
- )
306
- if isinstance(sql, str):
307
- with contextlib.suppress(Exception):
308
- param_val = current_config.parameter_validator
309
- if param_val.extract_parameters(sql):
310
- validation_context.input_sql_had_placeholders = True
311
-
312
- self.process(expression_to_validate, validation_context)
313
-
314
- # Return the list of validation errors
315
- return list(validation_context.validation_errors)
@@ -1,41 +0,0 @@
1
- """Specific result types for the SQL processing pipeline."""
2
-
3
- from dataclasses import dataclass
4
- from typing import TYPE_CHECKING, Any, Optional
5
-
6
- if TYPE_CHECKING:
7
- from sqlglot import exp
8
-
9
- from sqlspec.exceptions import RiskLevel
10
-
11
- __all__ = ("AnalysisFinding", "TransformationLog", "ValidationError")
12
-
13
-
14
- @dataclass
15
- class ValidationError:
16
- """A specific validation issue found during processing."""
17
-
18
- message: str
19
- code: str # e.g., "risky-delete", "missing-where"
20
- risk_level: "RiskLevel"
21
- processor: str # Which processor found it
22
- expression: "Optional[exp.Expression]" = None # Problematic sub-expression
23
-
24
-
25
- @dataclass
26
- class AnalysisFinding:
27
- """Metadata discovered during analysis."""
28
-
29
- key: str # e.g., "complexity_score", "table_count"
30
- value: Any
31
- processor: str
32
-
33
-
34
- @dataclass
35
- class TransformationLog:
36
- """Record of a transformation applied."""
37
-
38
- description: str
39
- processor: str
40
- before: Optional[str] = None # SQL before transform
41
- after: Optional[str] = None # SQL after transform
@@ -1,66 +0,0 @@
1
- from typing import Optional
2
-
3
- from sqlglot import exp
4
-
5
- from sqlspec.statement.pipelines.base import ProcessorProtocol
6
- from sqlspec.statement.pipelines.context import SQLProcessingContext
7
-
8
- __all__ = ("CommentRemover",)
9
-
10
-
11
- class CommentRemover(ProcessorProtocol):
12
- """Removes standard SQL comments from expressions using SQLGlot's AST traversal.
13
-
14
- This transformer removes SQL comments while preserving functionality:
15
- - Removes line comments (-- comment)
16
- - Removes block comments (/* comment */)
17
- - Preserves string literals that contain comment-like patterns
18
- - Always preserves SQL hints and MySQL version comments (use HintRemover separately)
19
- - Uses SQLGlot's AST for reliable, context-aware comment detection
20
-
21
- Note: This transformer now focuses only on standard comments. Use HintRemover
22
- separately if you need to remove Oracle hints (/*+ hint */) or MySQL version
23
- comments (/*!50000 */).
24
-
25
- Args:
26
- enabled: Whether comment removal is enabled.
27
- """
28
-
29
- def __init__(self, enabled: bool = True) -> None:
30
- self.enabled = enabled
31
-
32
- def process(self, expression: Optional[exp.Expression], context: SQLProcessingContext) -> Optional[exp.Expression]:
33
- """Process the expression to remove comments using SQLGlot AST traversal."""
34
- if not self.enabled or expression is None or context.current_expression is None:
35
- return expression
36
-
37
- comments_removed_count = 0
38
-
39
- def _remove_comments(node: exp.Expression) -> "Optional[exp.Expression]":
40
- nonlocal comments_removed_count
41
- if hasattr(node, "comments") and node.comments:
42
- original_comment_count = len(node.comments)
43
- comments_to_keep = []
44
-
45
- for comment in node.comments:
46
- comment_text = str(comment).strip()
47
- hint_keywords = ["INDEX", "USE_NL", "USE_HASH", "PARALLEL", "FULL", "FIRST_ROWS", "ALL_ROWS"]
48
- is_hint = any(keyword in comment_text.upper() for keyword in hint_keywords)
49
-
50
- if is_hint or (comment_text.startswith("!") and comment_text.endswith("")):
51
- comments_to_keep.append(comment)
52
-
53
- if len(comments_to_keep) < original_comment_count:
54
- comments_removed_count += original_comment_count - len(comments_to_keep)
55
- node.pop_comments()
56
- if comments_to_keep:
57
- node.add_comments(comments_to_keep)
58
-
59
- return node
60
-
61
- cleaned_expression = context.current_expression.transform(_remove_comments, copy=True)
62
- context.current_expression = cleaned_expression
63
-
64
- context.metadata["comments_removed"] = comments_removed_count
65
-
66
- return cleaned_expression