sqlscope-rs 0.1.0__tar.gz

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 (37) hide show
  1. sqlscope_rs-0.1.0/Cargo.lock +397 -0
  2. sqlscope_rs-0.1.0/Cargo.toml +29 -0
  3. sqlscope_rs-0.1.0/PKG-INFO +38 -0
  4. sqlscope_rs-0.1.0/README.md +23 -0
  5. sqlscope_rs-0.1.0/crates/sqlscope/Cargo.toml +23 -0
  6. sqlscope_rs-0.1.0/crates/sqlscope/README.md +189 -0
  7. sqlscope_rs-0.1.0/crates/sqlscope/src/ast.rs +353 -0
  8. sqlscope_rs-0.1.0/crates/sqlscope/src/column_origins.rs +85 -0
  9. sqlscope_rs-0.1.0/crates/sqlscope/src/column_usages.rs +168 -0
  10. sqlscope_rs-0.1.0/crates/sqlscope/src/error.rs +104 -0
  11. sqlscope_rs-0.1.0/crates/sqlscope/src/inject_ctes.rs +136 -0
  12. sqlscope_rs-0.1.0/crates/sqlscope/src/lib.rs +38 -0
  13. sqlscope_rs-0.1.0/crates/sqlscope/src/normalize.rs +170 -0
  14. sqlscope_rs-0.1.0/crates/sqlscope/src/options.rs +165 -0
  15. sqlscope_rs-0.1.0/crates/sqlscope/src/output_columns.rs +176 -0
  16. sqlscope_rs-0.1.0/crates/sqlscope/src/resolver.rs +1061 -0
  17. sqlscope_rs-0.1.0/crates/sqlscope/src/rewrite.rs +670 -0
  18. sqlscope_rs-0.1.0/crates/sqlscope/src/rewrite_tables.rs +278 -0
  19. sqlscope_rs-0.1.0/crates/sqlscope/src/row_filter.rs +220 -0
  20. sqlscope_rs-0.1.0/crates/sqlscope/src/schema.rs +70 -0
  21. sqlscope_rs-0.1.0/crates/sqlscope/tests/column_origins.rs +288 -0
  22. sqlscope_rs-0.1.0/crates/sqlscope/tests/common/mod.rs +152 -0
  23. sqlscope_rs-0.1.0/crates/sqlscope/tests/guards.rs +97 -0
  24. sqlscope_rs-0.1.0/crates/sqlscope/tests/inject_ctes.rs +273 -0
  25. sqlscope_rs-0.1.0/crates/sqlscope/tests/output_columns.rs +237 -0
  26. sqlscope_rs-0.1.0/crates/sqlscope/tests/referenced_columns.rs +722 -0
  27. sqlscope_rs-0.1.0/crates/sqlscope/tests/rewrite_tables.rs +478 -0
  28. sqlscope_rs-0.1.0/crates/sqlscope/tests/row_filter.rs +616 -0
  29. sqlscope_rs-0.1.0/pyproject.toml +33 -0
  30. sqlscope_rs-0.1.0/python/Cargo.toml +21 -0
  31. sqlscope_rs-0.1.0/python/README.md +23 -0
  32. sqlscope_rs-0.1.0/python/build.rs +4 -0
  33. sqlscope_rs-0.1.0/python/sqlscope/__init__.py +269 -0
  34. sqlscope_rs-0.1.0/python/sqlscope/_native.pyi +39 -0
  35. sqlscope_rs-0.1.0/python/sqlscope/py.typed +0 -0
  36. sqlscope_rs-0.1.0/python/src/lib.rs +215 -0
  37. sqlscope_rs-0.1.0/python/tests/test_sqlscope.py +105 -0
@@ -0,0 +1,397 @@
1
+ # This file is automatically @generated by Cargo.
2
+ # It is not intended for manual editing.
3
+ version = 3
4
+
5
+ [[package]]
6
+ name = "aho-corasick"
7
+ version = "1.1.5"
8
+ source = "registry+https://github.com/rust-lang/crates.io-index"
9
+ checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba"
10
+ dependencies = [
11
+ "memchr",
12
+ ]
13
+
14
+ [[package]]
15
+ name = "ar_archive_writer"
16
+ version = "0.5.3"
17
+ source = "registry+https://github.com/rust-lang/crates.io-index"
18
+ checksum = "73cd58deff2140a0a8eae87e417bd01db68a33e148aa93d1e8cd837e55e312b6"
19
+ dependencies = [
20
+ "object",
21
+ ]
22
+
23
+ [[package]]
24
+ name = "cc"
25
+ version = "1.6.0"
26
+ source = "registry+https://github.com/rust-lang/crates.io-index"
27
+ checksum = "f74872d07caf508b30a21f6836e7d7016a2eaf7d9ff4f48deaa58cd8a0407630"
28
+ dependencies = [
29
+ "find-msvc-tools",
30
+ "shlex",
31
+ ]
32
+
33
+ [[package]]
34
+ name = "cfg-if"
35
+ version = "1.0.5"
36
+ source = "registry+https://github.com/rust-lang/crates.io-index"
37
+ checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600"
38
+
39
+ [[package]]
40
+ name = "find-msvc-tools"
41
+ version = "0.1.14"
42
+ source = "registry+https://github.com/rust-lang/crates.io-index"
43
+ checksum = "aedcfb3409746eddb02b9e19ebda1c3394f759a152e48ee875a0844d1b955484"
44
+
45
+ [[package]]
46
+ name = "heck"
47
+ version = "0.5.0"
48
+ source = "registry+https://github.com/rust-lang/crates.io-index"
49
+ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
50
+
51
+ [[package]]
52
+ name = "itoa"
53
+ version = "1.0.18"
54
+ source = "registry+https://github.com/rust-lang/crates.io-index"
55
+ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
56
+
57
+ [[package]]
58
+ name = "libc"
59
+ version = "0.2.190"
60
+ source = "registry+https://github.com/rust-lang/crates.io-index"
61
+ checksum = "ce5d3ddc6d3fa000eb1536d85e147bfe31aacaba692ed6a876f95cb7c855be78"
62
+
63
+ [[package]]
64
+ name = "memchr"
65
+ version = "2.8.3"
66
+ source = "registry+https://github.com/rust-lang/crates.io-index"
67
+ checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
68
+
69
+ [[package]]
70
+ name = "object"
71
+ version = "0.39.1"
72
+ source = "registry+https://github.com/rust-lang/crates.io-index"
73
+ checksum = "2e5a6c098c7a3b6547378093f5cc30bc54fd361ce711e05293a5cc589562739b"
74
+ dependencies = [
75
+ "memchr",
76
+ ]
77
+
78
+ [[package]]
79
+ name = "once_cell"
80
+ version = "1.21.4"
81
+ source = "registry+https://github.com/rust-lang/crates.io-index"
82
+ checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
83
+
84
+ [[package]]
85
+ name = "polyglot-sql"
86
+ version = "0.13.1"
87
+ source = "registry+https://github.com/rust-lang/crates.io-index"
88
+ checksum = "8bd560fb7445798460480716cac803d740bef433c4043c0cac47a7a0c3f4732f"
89
+ dependencies = [
90
+ "polyglot-sql-ast-derive",
91
+ "serde",
92
+ "serde_json",
93
+ "stacker",
94
+ "thiserror",
95
+ "unicode-segmentation",
96
+ ]
97
+
98
+ [[package]]
99
+ name = "polyglot-sql-ast-derive"
100
+ version = "0.13.1"
101
+ source = "registry+https://github.com/rust-lang/crates.io-index"
102
+ checksum = "3a43b746b86d14a9888e8e535efae4e8315a484caa94e9a0d78bdefe58f22e44"
103
+ dependencies = [
104
+ "proc-macro2",
105
+ "quote",
106
+ "syn 2.0.119",
107
+ ]
108
+
109
+ [[package]]
110
+ name = "portable-atomic"
111
+ version = "1.15.0"
112
+ source = "registry+https://github.com/rust-lang/crates.io-index"
113
+ checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85"
114
+
115
+ [[package]]
116
+ name = "proc-macro2"
117
+ version = "1.0.107"
118
+ source = "registry+https://github.com/rust-lang/crates.io-index"
119
+ checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
120
+ dependencies = [
121
+ "unicode-ident",
122
+ ]
123
+
124
+ [[package]]
125
+ name = "psm"
126
+ version = "0.1.32"
127
+ source = "registry+https://github.com/rust-lang/crates.io-index"
128
+ checksum = "4dcd034599e63b970727f70d79e02d62390a4a84f7c6b827c27c46d5ac3fa622"
129
+ dependencies = [
130
+ "ar_archive_writer",
131
+ "cc",
132
+ ]
133
+
134
+ [[package]]
135
+ name = "pyo3"
136
+ version = "0.29.3"
137
+ source = "registry+https://github.com/rust-lang/crates.io-index"
138
+ checksum = "700d18fa267b73b9b521fd7e13580e2f446916f176cacee1ab63fcc8191f1655"
139
+ dependencies = [
140
+ "libc",
141
+ "once_cell",
142
+ "portable-atomic",
143
+ "pyo3-build-config",
144
+ "pyo3-ffi",
145
+ "pyo3-macros",
146
+ ]
147
+
148
+ [[package]]
149
+ name = "pyo3-build-config"
150
+ version = "0.29.3"
151
+ source = "registry+https://github.com/rust-lang/crates.io-index"
152
+ checksum = "7b3fc0c4d08f6bb10e71fe39dfb9e2f59c6eb6854e22ec8092f50c69a4499adb"
153
+ dependencies = [
154
+ "target-lexicon",
155
+ ]
156
+
157
+ [[package]]
158
+ name = "pyo3-ffi"
159
+ version = "0.29.3"
160
+ source = "registry+https://github.com/rust-lang/crates.io-index"
161
+ checksum = "dfc0b8e19df29aad7086cf977bb0c2a2f143e30567eb113e9cf72b62ca698330"
162
+ dependencies = [
163
+ "libc",
164
+ "pyo3-build-config",
165
+ ]
166
+
167
+ [[package]]
168
+ name = "pyo3-macros"
169
+ version = "0.29.3"
170
+ source = "registry+https://github.com/rust-lang/crates.io-index"
171
+ checksum = "6100e8a4b5eba53afaa5ed078364851a0b2499c553a44c31026b929049b49dc6"
172
+ dependencies = [
173
+ "proc-macro2",
174
+ "pyo3-macros-backend",
175
+ "quote",
176
+ "syn 2.0.119",
177
+ ]
178
+
179
+ [[package]]
180
+ name = "pyo3-macros-backend"
181
+ version = "0.29.3"
182
+ source = "registry+https://github.com/rust-lang/crates.io-index"
183
+ checksum = "6143877a16e82b5a727b7127ff4cd86858a24a28d745d72f43e6f227c7b1bdb3"
184
+ dependencies = [
185
+ "heck",
186
+ "proc-macro2",
187
+ "quote",
188
+ "syn 2.0.119",
189
+ ]
190
+
191
+ [[package]]
192
+ name = "quote"
193
+ version = "1.0.47"
194
+ source = "registry+https://github.com/rust-lang/crates.io-index"
195
+ checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
196
+ dependencies = [
197
+ "proc-macro2",
198
+ ]
199
+
200
+ [[package]]
201
+ name = "regex"
202
+ version = "1.13.1"
203
+ source = "registry+https://github.com/rust-lang/crates.io-index"
204
+ checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d"
205
+ dependencies = [
206
+ "aho-corasick",
207
+ "memchr",
208
+ "regex-automata",
209
+ "regex-syntax",
210
+ ]
211
+
212
+ [[package]]
213
+ name = "regex-automata"
214
+ version = "0.4.18"
215
+ source = "registry+https://github.com/rust-lang/crates.io-index"
216
+ checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2"
217
+ dependencies = [
218
+ "aho-corasick",
219
+ "memchr",
220
+ "regex-syntax",
221
+ ]
222
+
223
+ [[package]]
224
+ name = "regex-syntax"
225
+ version = "0.8.11"
226
+ source = "registry+https://github.com/rust-lang/crates.io-index"
227
+ checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
228
+
229
+ [[package]]
230
+ name = "serde"
231
+ version = "1.0.229"
232
+ source = "registry+https://github.com/rust-lang/crates.io-index"
233
+ checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba"
234
+ dependencies = [
235
+ "serde_core",
236
+ "serde_derive",
237
+ ]
238
+
239
+ [[package]]
240
+ name = "serde_core"
241
+ version = "1.0.229"
242
+ source = "registry+https://github.com/rust-lang/crates.io-index"
243
+ checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48"
244
+ dependencies = [
245
+ "serde_derive",
246
+ ]
247
+
248
+ [[package]]
249
+ name = "serde_derive"
250
+ version = "1.0.229"
251
+ source = "registry+https://github.com/rust-lang/crates.io-index"
252
+ checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
253
+ dependencies = [
254
+ "proc-macro2",
255
+ "quote",
256
+ "syn 3.0.6",
257
+ ]
258
+
259
+ [[package]]
260
+ name = "serde_json"
261
+ version = "1.0.151"
262
+ source = "registry+https://github.com/rust-lang/crates.io-index"
263
+ checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14"
264
+ dependencies = [
265
+ "itoa",
266
+ "memchr",
267
+ "serde",
268
+ "serde_core",
269
+ "zmij",
270
+ ]
271
+
272
+ [[package]]
273
+ name = "shlex"
274
+ version = "2.0.1"
275
+ source = "registry+https://github.com/rust-lang/crates.io-index"
276
+ checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba"
277
+
278
+ [[package]]
279
+ name = "sqlscope"
280
+ version = "0.1.0"
281
+ dependencies = [
282
+ "polyglot-sql",
283
+ "regex",
284
+ "stacker",
285
+ ]
286
+
287
+ [[package]]
288
+ name = "sqlscope-python"
289
+ version = "0.1.0"
290
+ dependencies = [
291
+ "pyo3",
292
+ "pyo3-build-config",
293
+ "sqlscope",
294
+ ]
295
+
296
+ [[package]]
297
+ name = "sqlscope-wasm"
298
+ version = "0.1.0"
299
+ dependencies = [
300
+ "serde",
301
+ "serde_json",
302
+ "sqlscope",
303
+ ]
304
+
305
+ [[package]]
306
+ name = "stacker"
307
+ version = "0.1.25"
308
+ source = "registry+https://github.com/rust-lang/crates.io-index"
309
+ checksum = "707f49d46706bacf8a2b00d51dace3f9de527c13eec3778f570c411f89e69967"
310
+ dependencies = [
311
+ "cc",
312
+ "cfg-if",
313
+ "libc",
314
+ "psm",
315
+ "windows-sys",
316
+ ]
317
+
318
+ [[package]]
319
+ name = "syn"
320
+ version = "2.0.119"
321
+ source = "registry+https://github.com/rust-lang/crates.io-index"
322
+ checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"
323
+ dependencies = [
324
+ "proc-macro2",
325
+ "quote",
326
+ "unicode-ident",
327
+ ]
328
+
329
+ [[package]]
330
+ name = "syn"
331
+ version = "3.0.6"
332
+ source = "registry+https://github.com/rust-lang/crates.io-index"
333
+ checksum = "8593e8e72159ed2257d083c7a454a85cbf854f37a0966d8d483aff8c8a3ebcee"
334
+ dependencies = [
335
+ "proc-macro2",
336
+ "quote",
337
+ "unicode-ident",
338
+ ]
339
+
340
+ [[package]]
341
+ name = "target-lexicon"
342
+ version = "0.13.5"
343
+ source = "registry+https://github.com/rust-lang/crates.io-index"
344
+ checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
345
+
346
+ [[package]]
347
+ name = "thiserror"
348
+ version = "1.0.69"
349
+ source = "registry+https://github.com/rust-lang/crates.io-index"
350
+ checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
351
+ dependencies = [
352
+ "thiserror-impl",
353
+ ]
354
+
355
+ [[package]]
356
+ name = "thiserror-impl"
357
+ version = "1.0.69"
358
+ source = "registry+https://github.com/rust-lang/crates.io-index"
359
+ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
360
+ dependencies = [
361
+ "proc-macro2",
362
+ "quote",
363
+ "syn 2.0.119",
364
+ ]
365
+
366
+ [[package]]
367
+ name = "unicode-ident"
368
+ version = "1.0.26"
369
+ source = "registry+https://github.com/rust-lang/crates.io-index"
370
+ checksum = "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954"
371
+
372
+ [[package]]
373
+ name = "unicode-segmentation"
374
+ version = "1.13.3"
375
+ source = "registry+https://github.com/rust-lang/crates.io-index"
376
+ checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8"
377
+
378
+ [[package]]
379
+ name = "windows-link"
380
+ version = "0.2.1"
381
+ source = "registry+https://github.com/rust-lang/crates.io-index"
382
+ checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
383
+
384
+ [[package]]
385
+ name = "windows-sys"
386
+ version = "0.61.2"
387
+ source = "registry+https://github.com/rust-lang/crates.io-index"
388
+ checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
389
+ dependencies = [
390
+ "windows-link",
391
+ ]
392
+
393
+ [[package]]
394
+ name = "zmij"
395
+ version = "1.0.23"
396
+ source = "registry+https://github.com/rust-lang/crates.io-index"
397
+ checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"
@@ -0,0 +1,29 @@
1
+ [workspace]
2
+ resolver = "2"
3
+ members = ["crates/sqlscope", "python"]
4
+
5
+ [workspace.package]
6
+ version = "0.1.0"
7
+ edition = "2021"
8
+ rust-version = "1.88"
9
+ license = "MIT"
10
+ repository = "https://github.com/dcalsky/sqlscope"
11
+ homepage = "https://github.com/dcalsky/sqlscope"
12
+ authors = ["dcalsky <dcalsky@gmail.com>"]
13
+
14
+ [workspace.dependencies]
15
+ polyglot-sql = { version = "=0.13.1", default-features = false }
16
+ serde = { version = "1", features = ["derive"] }
17
+ serde_json = "1"
18
+ regex = "1"
19
+
20
+ [profile.release]
21
+ lto = true
22
+ codegen-units = 1
23
+
24
+ # Size-optimized build of the WebAssembly module embedded in the Go SDK.
25
+ [profile.wasm]
26
+ inherits = "release"
27
+ opt-level = "s"
28
+ strip = true
29
+ panic = "abort"
@@ -0,0 +1,38 @@
1
+ Metadata-Version: 2.4
2
+ Name: sqlscope-rs
3
+ Version: 0.1.0
4
+ Classifier: Programming Language :: Python :: 3
5
+ Classifier: Programming Language :: Rust
6
+ Classifier: Topic :: Database
7
+ Classifier: Typing :: Typed
8
+ Summary: Scope-aware SQL analysis and rewriting: row filters, CTE injection, table rewrites, column lineage.
9
+ Keywords: sql,lineage,row-level-security,parser
10
+ License-Expression: MIT
11
+ Requires-Python: >=3.9
12
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
13
+ Project-URL: Repository, https://github.com/dcalsky/sqlscope
14
+
15
+ # sqlscope (Python)
16
+
17
+ Scope-aware SQL analysis and rewriting, backed by the Rust
18
+ [sqlscope](https://github.com/dcalsky/sqlscope) crate.
19
+
20
+ ```bash
21
+ pip install sqlscope-rs
22
+ ```
23
+
24
+ ```python
25
+ import sqlscope
26
+
27
+ sqlscope.apply_row_filter("SELECT id FROM orders", "tenant_id = 7", dialect="postgres")
28
+ # 'SELECT id FROM (SELECT * FROM orders WHERE tenant_id = 7) AS orders'
29
+
30
+ sqlscope.column_origins(
31
+ "SELECT o.id, p.amount FROM orders o JOIN payments p ON o.id = p.order_id WHERE o.status = 'PAID'"
32
+ )
33
+ # {'orders': ['id'], 'payments': ['amount']}
34
+ ```
35
+
36
+ See the [project README](https://github.com/dcalsky/sqlscope#readme) for the
37
+ full API.
38
+
@@ -0,0 +1,23 @@
1
+ # sqlscope (Python)
2
+
3
+ Scope-aware SQL analysis and rewriting, backed by the Rust
4
+ [sqlscope](https://github.com/dcalsky/sqlscope) crate.
5
+
6
+ ```bash
7
+ pip install sqlscope-rs
8
+ ```
9
+
10
+ ```python
11
+ import sqlscope
12
+
13
+ sqlscope.apply_row_filter("SELECT id FROM orders", "tenant_id = 7", dialect="postgres")
14
+ # 'SELECT id FROM (SELECT * FROM orders WHERE tenant_id = 7) AS orders'
15
+
16
+ sqlscope.column_origins(
17
+ "SELECT o.id, p.amount FROM orders o JOIN payments p ON o.id = p.order_id WHERE o.status = 'PAID'"
18
+ )
19
+ # {'orders': ['id'], 'payments': ['amount']}
20
+ ```
21
+
22
+ See the [project README](https://github.com/dcalsky/sqlscope#readme) for the
23
+ full API.
@@ -0,0 +1,23 @@
1
+ [package]
2
+ name = "sqlscope"
3
+ description = "Scope-aware SQL analysis and rewriting: row filters, CTE injection, table rewrites, column lineage and references."
4
+ version.workspace = true
5
+ edition.workspace = true
6
+ rust-version.workspace = true
7
+ license.workspace = true
8
+ repository.workspace = true
9
+ homepage.workspace = true
10
+ authors.workspace = true
11
+ keywords = ["sql", "lineage", "parser", "row-level-security", "polyglot"]
12
+ categories = ["parser-implementations", "database"]
13
+ readme = "README.md"
14
+
15
+ [features]
16
+ default = ["stacker"]
17
+ # Grow the native stack on deep parser recursion. Disable for wasm targets.
18
+ stacker = ["polyglot-sql/stacker", "dep:stacker"]
19
+
20
+ [dependencies]
21
+ polyglot-sql = { workspace = true, features = ["all-dialects", "generate", "ast-tools", "semantic"] }
22
+ regex.workspace = true
23
+ stacker = { version = "0.1", optional = true }
@@ -0,0 +1,189 @@
1
+ # sqlscope
2
+
3
+ Scope-aware SQL analysis and rewriting for Rust, Python and Go, built on the
4
+ [polyglot](https://github.com/tobilg/polyglot) SQL engine (30+ dialects).
5
+
6
+ | Operation | Purpose |
7
+ | --- | --- |
8
+ | `apply_row_filter` | Filter every in-scope table by a predicate (row-level security). |
9
+ | `inject_ctes` | Prepend CTE definitions to a query's root `WITH`. |
10
+ | `rewrite_tables` | Replace table references with derived tables. |
11
+ | `column_origins` | Source columns whose values reach the result (column lineage). |
12
+ | `output_columns` | Names of the columns a statement outputs. |
13
+ | `referenced_columns` | Columns referenced anywhere (filters included), per table. |
14
+ | `column_usages` | Column references together with the clause they appear in. |
15
+
16
+ Everything works on the parsed AST, never by splicing SQL text, and resolves
17
+ names with SQL scoping rules: CTE shadowing, correlated subqueries, set
18
+ operations, derived tables, `USING`, `PIVOT`, `UNNEST`, lateral views.
19
+
20
+ ## Install
21
+
22
+ | Language | Package |
23
+ | --- | --- |
24
+ | Rust | `cargo add sqlscope` |
25
+ | Python | `pip install sqlscope-rs` (imported as `sqlscope`; wheels for Linux, macOS, Windows; Python ≥ 3.9) |
26
+ | Go | `go get github.com/dcalsky/sqlscope/go` (pure Go, no cgo) |
27
+
28
+ ## Usage
29
+
30
+ ### Rust
31
+
32
+ ```rust
33
+ use sqlscope::{apply_row_filter, column_origins, Dialect, Options};
34
+
35
+ let sql = apply_row_filter(
36
+ "SELECT id FROM orders",
37
+ "tenant_id = 7",
38
+ &Options::new().dialect(Dialect::POSTGRES),
39
+ )?;
40
+ assert_eq!(sql, "SELECT id FROM (SELECT * FROM orders WHERE tenant_id = 7) AS orders");
41
+
42
+ let origins = column_origins(
43
+ "SELECT o.id, p.amount FROM orders o JOIN payments p ON o.id = p.order_id WHERE o.status = 'PAID'",
44
+ &Options::new(),
45
+ )?;
46
+ assert_eq!(origins["orders"], ["id"]);
47
+ assert_eq!(origins["payments"], ["amount"]);
48
+ ```
49
+
50
+ ### Python
51
+
52
+ ```python
53
+ import sqlscope
54
+
55
+ sqlscope.apply_row_filter("SELECT id FROM orders", "tenant_id = 7", dialect="postgres")
56
+ # 'SELECT id FROM (SELECT * FROM orders WHERE tenant_id = 7) AS orders'
57
+
58
+ sqlscope.column_usages("SELECT id FROM orders WHERE status = 'PAID'")
59
+ # [ColumnUsage(table='orders', column='id', clause=<Clause.SELECT>),
60
+ # ColumnUsage(table='orders', column='status', clause=<Clause.WHERE>)]
61
+ ```
62
+
63
+ ### Go
64
+
65
+ ```go
66
+ import "github.com/dcalsky/sqlscope/go"
67
+
68
+ sql, err := sqlscope.ApplyRowFilter(
69
+ "SELECT id FROM orders", "tenant_id = 7",
70
+ sqlscope.WithDialect("postgres"),
71
+ sqlscope.WithTableNames("orders"),
72
+ )
73
+
74
+ cols, err := sqlscope.ColumnOrigins(sql,
75
+ sqlscope.WithSchema(map[string][]string{"orders": {"id", "tenant_id"}}))
76
+ ```
77
+
78
+ The Go SDK runs the Rust engine compiled to WebAssembly with
79
+ [wazero](https://wazero.io). The engine is compiled once per process on first
80
+ use (about a second); call `sqlscope.Init()` at startup to do it eagerly.
81
+
82
+ ## Options
83
+
84
+ Every operation takes the same options. Settings an operation does not read
85
+ are ignored.
86
+
87
+ | Rust (`Options::`) | Python keyword | Go | Read by |
88
+ | --- | --- | --- | --- |
89
+ | `dialect` | `dialect` | `WithDialect` | all (default `trino`) |
90
+ | `schema` | `schema` | `WithSchema` | `column_origins`, `output_columns`, `referenced_columns`, `column_usages` |
91
+ | `table_names` | `table_names` | `WithTableNames` | `apply_row_filter` |
92
+ | `table_patterns` | `table_patterns` | `WithTableRegexp` | `apply_row_filter` |
93
+ | `default_db` | `default_db` | `WithDefaultDB` | `apply_row_filter` |
94
+ | `strip_catalogs` | `strip_catalogs` | `WithStripCatalogs` | `rewrite_tables` |
95
+
96
+ `schema` maps table names (bare, `schema.table` or `catalog.schema.table`) to
97
+ their ordered columns. It expands `*` and attributes unqualified columns. A
98
+ table listed with no columns has zero columns; an unlisted table is unknown.
99
+
100
+ ## Operations
101
+
102
+ ### `apply_row_filter(sql, predicate)`
103
+
104
+ ```text
105
+ SELECT * FROM a -> SELECT * FROM (SELECT * FROM a WHERE <predicate>) AS a
106
+ ```
107
+
108
+ Wraps every in-scope physical table of a `SELECT` or set operation in a
109
+ filtered derived table, which keeps the filter correct across outer joins,
110
+ CTEs, subqueries and set operations. CTE references, table functions and
111
+ `DUAL` are never wrapped. The predicate is parsed as one boolean expression
112
+ (extra clauses, statements or unbalanced parentheses are rejected); bind or
113
+ escape its values before calling. Qualified column references
114
+ (`schema.table.col`) are rebound onto the derived-table alias, and
115
+ same-named tables get distinct aliases (`s1_t`, `s2_t`).
116
+
117
+ ### `inject_ctes(sql, ctes)`
118
+
119
+ Adds `name AS (query)` definitions before the query's existing CTEs, in order,
120
+ so each may use earlier ones. Names that collide with another definition or
121
+ an existing root CTE are rejected.
122
+
123
+ ### `rewrite_tables(sql, rewrites)`
124
+
125
+ Replaces references to a `schema.table` match key with
126
+ `(SELECT * FROM target)` or a `UNION DISTINCT` over several tables, keeping
127
+ the reference's alias and rebinding qualified columns.
128
+
129
+ ### `column_origins(sql)`
130
+
131
+ The source columns whose **values** reach the result, keyed by root table.
132
+ Filter-only positions (`WHERE`, `JOIN ... ON`, `GROUP BY`, `HAVING`, top-level
133
+ `ORDER BY`) and the right side of `INTERSECT`/`EXCEPT` are excluded; window
134
+ `PARTITION BY`/`ORDER BY` count. Accepts `CREATE VIEW`, `CREATE TABLE AS`,
135
+ `INSERT ... SELECT` and friends, and the assigned values of `UPDATE`/`MERGE`.
136
+
137
+ ### `output_columns(sql)`
138
+
139
+ Output column names in order. Unaliased expressions are `_col{i}`; `*`
140
+ expands from the schema or stays `"*"`. Explicit column lists on views,
141
+ `CREATE TABLE` and `INSERT` win. `CREATE TABLE (... LIKE t ...)` needs `t`'s
142
+ schema. Returns none for statements without columns.
143
+
144
+ ### `referenced_columns(sql)` / `column_usages(sql)`
145
+
146
+ Every column a statement reads, anywhere, including `DELETE`/`UPDATE`/`MERGE`
147
+ — a superset of `column_origins`. `column_usages` adds the clause
148
+ (`SELECT`, `WHERE`, `JOIN_ON`, `GROUP_BY`, `ORDER_BY`, `UPDATE_SET_VALUE`,
149
+ `MERGE_ON`, ...). Projection aliases and ordinals (`ORDER BY 1`) resolve to
150
+ their source columns. Resolution fails open: a reference that cannot be
151
+ attributed precisely is attributed to every candidate table, never dropped.
152
+
153
+ ## Errors
154
+
155
+ | Kind | Rust `ErrorKind` | Python | Go |
156
+ | --- | --- | --- | --- |
157
+ | Invalid option or argument | `InvalidArgument` | `InvalidArgumentError` | `ErrInvalidArgument` |
158
+ | SQL does not parse | `Parse` | `ParseError` | `ErrParse` |
159
+ | Unsupported statement or input over a safety limit | `Unsupported` | `UnsupportedError` | `ErrUnsupported` |
160
+ | Bug (invalid output) | `Internal` | `InternalError` | `ErrInternal` |
161
+
162
+ Input is limited to 1 MiB and 256 levels of parser nesting on every platform.
163
+ Rewrites regenerate SQL from the AST (normalized formatting, comments
164
+ removed, optimizer hints kept) and verify that the output parses before
165
+ returning it; when nothing needs rewriting, the input is returned unchanged.
166
+
167
+ ## Development
168
+
169
+ ```bash
170
+ cargo test --workspace --exclude sqlscope-python # Rust
171
+ cd python && uv venv && uv pip install maturin pytest \
172
+ && .venv/bin/maturin develop && .venv/bin/pytest # Python
173
+ scripts/build-wasm.sh && (cd go && go test ./...) # Go
174
+ ```
175
+
176
+ `scripts/build-wasm.sh` needs the `wasm32-wasip1` Rust target and regenerates
177
+ `go/internal/wasm/sqlscope.wasm.gz`, which is committed so `go get` works. CI
178
+ rebuilds it on every run, tests the Go SDK against the fresh build, and on
179
+ `main` commits it back when it changed.
180
+
181
+ To release, bump `version` in the root `Cargo.toml`, wait for CI on `main`
182
+ to finish (it may commit an updated engine), then tag that commit:
183
+ `git tag vX.Y.Z && git push origin vX.Y.Z`. The release workflow runs CI,
184
+ publishes the wheels to PyPI, tags the Go module as `go/vX.Y.Z` and attaches
185
+ the wheels, sdist and WebAssembly engine to a GitHub release.
186
+
187
+ ## License
188
+
189
+ MIT