quillsql 2.1.6__py3-none-any.whl → 2.2.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.
- quillsql/__init__.py +2 -1
- quillsql/assets/__init__.py +1 -1
- quillsql/assets/pgtypes.py +696 -2781
- quillsql/core.py +427 -54
- quillsql/db/__init__.py +1 -1
- quillsql/db/bigquery.py +108 -74
- quillsql/db/cached_connection.py +6 -5
- quillsql/db/db_helper.py +36 -17
- quillsql/db/postgres.py +94 -39
- quillsql/error.py +4 -4
- quillsql/utils/__init__.py +2 -1
- quillsql/utils/filters.py +180 -0
- quillsql/utils/pivot_template.py +485 -0
- quillsql/utils/run_query_processes.py +17 -16
- quillsql/utils/schema_conversion.py +6 -3
- quillsql/utils/tenants.py +60 -0
- quillsql-2.2.1.dist-info/METADATA +69 -0
- quillsql-2.2.1.dist-info/RECORD +20 -0
- {quillsql-2.1.6.dist-info → quillsql-2.2.1.dist-info}/WHEEL +1 -1
- quillsql-2.1.6.dist-info/METADATA +0 -72
- quillsql-2.1.6.dist-info/RECORD +0 -17
- {quillsql-2.1.6.dist-info → quillsql-2.2.1.dist-info}/top_level.txt +0 -0
|
@@ -1,19 +1,20 @@
|
|
|
1
|
-
import json
|
|
2
|
-
|
|
3
1
|
def remove_fields(query_result, fields_to_remove):
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
2
|
+
fields = [
|
|
3
|
+
{"name": field["name"], "dataTypeID": field["dataTypeID"]}
|
|
4
|
+
for field in query_result["fields"]
|
|
5
|
+
if field["name"] not in fields_to_remove
|
|
6
|
+
]
|
|
7
|
+
rows = [row for row in query_result["rows"]]
|
|
8
|
+
for row in rows:
|
|
9
|
+
for field in fields_to_remove:
|
|
10
|
+
if field in row:
|
|
11
|
+
del row[field]
|
|
12
|
+
return {"fields": fields, "rows": rows}
|
|
13
|
+
|
|
15
14
|
|
|
16
15
|
def array_to_map(queries, array_to_map, metadata, target_pool):
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
mapped_array = []
|
|
17
|
+
for i in range(len(queries)):
|
|
18
|
+
query_result = target_pool.query(queries[i])
|
|
19
|
+
mapped_array.append(query_result.get("rows"))
|
|
20
|
+
return mapped_array
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
from quillsql.assets.pgtypes import PG_TYPES
|
|
2
2
|
|
|
3
|
+
|
|
3
4
|
def convert_type_to_postgres(data_type_id):
|
|
4
|
-
|
|
5
|
-
pg_type = next(
|
|
6
|
-
|
|
5
|
+
# find the object in PG_TYPES that matches the type
|
|
6
|
+
pg_type = next(
|
|
7
|
+
(pg_type for pg_type in PG_TYPES if pg_type["oid"] == data_type_id), None
|
|
8
|
+
)
|
|
9
|
+
return pg_type["typname"] if pg_type else data_type_id
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
from typing import Union, List, Dict
|
|
2
|
+
|
|
3
|
+
# Type aliases for clarity
|
|
4
|
+
TenantId = Union[str, int]
|
|
5
|
+
TenantInfo = Dict[str, Union[str, List[TenantId]]]
|
|
6
|
+
Tenants = Union[List[TenantId], List[TenantInfo]]
|
|
7
|
+
|
|
8
|
+
def extract_tenant_ids(tenants: Tenants) -> List[TenantId]:
|
|
9
|
+
"""
|
|
10
|
+
Extract tenant IDs from the tenants parameter, which can be either a list of IDs
|
|
11
|
+
or a list of tenant info dictionaries.
|
|
12
|
+
|
|
13
|
+
Args:
|
|
14
|
+
tenants: Either a list of tenant IDs (strings/integers) or a list of tenant info dictionaries
|
|
15
|
+
|
|
16
|
+
Returns:
|
|
17
|
+
List of tenant IDs
|
|
18
|
+
|
|
19
|
+
Raises:
|
|
20
|
+
ValueError: If the tenants parameter format is invalid
|
|
21
|
+
"""
|
|
22
|
+
if not tenants:
|
|
23
|
+
raise ValueError("Invalid format for tenants: empty list")
|
|
24
|
+
|
|
25
|
+
first_tenant = tenants[0]
|
|
26
|
+
|
|
27
|
+
if isinstance(first_tenant, (str, int)):
|
|
28
|
+
return tenants # type: ignore
|
|
29
|
+
elif isinstance(first_tenant, dict) and "tenantIds" in first_tenant:
|
|
30
|
+
# TODO: support multiple tenants in future
|
|
31
|
+
return first_tenant["tenantIds"]
|
|
32
|
+
else:
|
|
33
|
+
raise ValueError("Invalid format for tenants")
|
|
34
|
+
|
|
35
|
+
def extract_tenant_field(tenants: Tenants, dashboard_owner: str) -> str:
|
|
36
|
+
"""
|
|
37
|
+
Extract tenant field from the tenants parameter, falling back to dashboard_owner
|
|
38
|
+
if tenants is a simple list of IDs.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
tenants: Either a list of tenant IDs (strings/integers) or a list of tenant info dictionaries
|
|
42
|
+
dashboard_owner: The default tenant field to use if tenants is a simple list
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
The tenant field string
|
|
46
|
+
|
|
47
|
+
Raises:
|
|
48
|
+
ValueError: If the tenants parameter format is invalid
|
|
49
|
+
"""
|
|
50
|
+
if not tenants:
|
|
51
|
+
raise ValueError("Invalid format for tenants: empty list")
|
|
52
|
+
|
|
53
|
+
first_tenant = tenants[0]
|
|
54
|
+
|
|
55
|
+
if isinstance(first_tenant, (str, int)):
|
|
56
|
+
return dashboard_owner
|
|
57
|
+
elif isinstance(first_tenant, dict) and "tenantField" in first_tenant:
|
|
58
|
+
return first_tenant["tenantField"]
|
|
59
|
+
else:
|
|
60
|
+
raise ValueError("Invalid format for tenants")
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: quillsql
|
|
3
|
+
Version: 2.2.1
|
|
4
|
+
Summary: Quill SDK for Python.
|
|
5
|
+
Home-page: https://github.com/quill-sql/quill-python
|
|
6
|
+
Author: Quill
|
|
7
|
+
Author-email: shawn@quill.co
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
Requires-Dist: psycopg2-binary
|
|
10
|
+
Requires-Dist: requests
|
|
11
|
+
Requires-Dist: redis
|
|
12
|
+
Requires-Dist: python-dotenv
|
|
13
|
+
Requires-Dist: pytest
|
|
14
|
+
Requires-Dist: google-cloud-bigquery
|
|
15
|
+
Requires-Dist: google-auth
|
|
16
|
+
Dynamic: author
|
|
17
|
+
Dynamic: author-email
|
|
18
|
+
Dynamic: description
|
|
19
|
+
Dynamic: description-content-type
|
|
20
|
+
Dynamic: home-page
|
|
21
|
+
Dynamic: requires-dist
|
|
22
|
+
Dynamic: summary
|
|
23
|
+
|
|
24
|
+
# Quill Python SDK
|
|
25
|
+
|
|
26
|
+
## Quickstart
|
|
27
|
+
|
|
28
|
+
First, install the quillsql package by running:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
$ pip install quillsql
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Then, add a `/quill` endpoint to your existing python server. For example, if
|
|
35
|
+
you were running a FASTAPI app, you would just add the endpoint like this:
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
from quillsql import Quill
|
|
39
|
+
|
|
40
|
+
quill = Quill(
|
|
41
|
+
private_key=os.getenv("QULL_PRIVATE_KEY"),
|
|
42
|
+
database_connection_string=os.getenv("POSTGRES_READ"),
|
|
43
|
+
database_type="postgresql"
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
security = HTTPBearer()
|
|
47
|
+
|
|
48
|
+
async def authenticate_jwt(token: str = Depends(security)):
|
|
49
|
+
# Your JWT validation logic here
|
|
50
|
+
# Return user object or raise HTTPException
|
|
51
|
+
user = validate_jwt_token(token.credentials)
|
|
52
|
+
return user
|
|
53
|
+
|
|
54
|
+
@app.post("/quill")
|
|
55
|
+
async def quill_post(data: Request, user: dict = Depends(authenticate_jwt)):
|
|
56
|
+
# assuming user fetched via auth middleware has an userId
|
|
57
|
+
user_id = user["user_id"]
|
|
58
|
+
body = await data.json()
|
|
59
|
+
metadata = body.get("metadata")
|
|
60
|
+
|
|
61
|
+
result = quill.query(
|
|
62
|
+
tenants=[{"tenantField": "user_id", "tenantIds": [user_id]}],
|
|
63
|
+
metadata=metadata
|
|
64
|
+
)
|
|
65
|
+
return result
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Then you can run your app like normally. Pass in this route to our react library
|
|
69
|
+
on the frontend and you all set!
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
quillsql/__init__.py,sha256=FiuoxaNZveKXOPB0hkpfGNlpZKmSn3pRwcqm9HKYbCQ,180
|
|
2
|
+
quillsql/core.py,sha256=cWWu_ME3kapzv1fBhoJLmkA7QIlbVCAOMHyce_VE3BU,22464
|
|
3
|
+
quillsql/error.py,sha256=n9VKHw4FAgg7ZEAz2YQ8L_8FdRG_1shwGngf2iWhUSM,175
|
|
4
|
+
quillsql/assets/__init__.py,sha256=oXQ2ZS5XDXkXTYjADxNfGt55cIn_rqfgWL2EDqjTyoI,45
|
|
5
|
+
quillsql/assets/pgtypes.py,sha256=-B_2wUaoAsdX7_HnJhUlx4ptZQ6x-cXwuST9ACgGFdE,33820
|
|
6
|
+
quillsql/db/__init__.py,sha256=sPgYMF3eqKuc2k96i1Re8NHazLdGKCVN-rs15F1sovw,63
|
|
7
|
+
quillsql/db/bigquery.py,sha256=xJv3WUjyDmnfwaAAeLTTezUEw_qxrxQy-CTCwj8Hmjs,4811
|
|
8
|
+
quillsql/db/cached_connection.py,sha256=Pp0R2XGY-QuQYh8ThiDxSwNb6SEuEKfZcQRcvzjeC28,2556
|
|
9
|
+
quillsql/db/db_helper.py,sha256=qiIP-BM7R-3PhvWBELYjNazi-92EcQB0q9eN7Ej7XUA,2111
|
|
10
|
+
quillsql/db/postgres.py,sha256=ZTLtUVTJHkqAj7nZkcwbmkSOwR2ySN7vS5snoxqLRN0,4156
|
|
11
|
+
quillsql/utils/__init__.py,sha256=C2k9Xe0sG5XrP0XJo9K_-iej1S9PLMRKOYMeLxj7NYE,210
|
|
12
|
+
quillsql/utils/filters.py,sha256=REXOLIQZDHL4EDKtConXY9_GaqUmc2uTcyUa2_4MvAg,6786
|
|
13
|
+
quillsql/utils/pivot_template.py,sha256=NzHO7Ux8GVAKY-DUtsOmE7TUls2q6FJG2kgJxVWq-wQ,18282
|
|
14
|
+
quillsql/utils/run_query_processes.py,sha256=FRmNvjTDLUBr7MqDKQmivdC0anwybMXUyzQbKnaZx70,698
|
|
15
|
+
quillsql/utils/schema_conversion.py,sha256=TFfMibN9nOsxNRhHw5YIFl3jGTvipG81bxX4LFDulUY,314
|
|
16
|
+
quillsql/utils/tenants.py,sha256=ZD2FuKz0gjBVSsThHDv1P8PU6EL8E009NWihE5hAH-Q,2022
|
|
17
|
+
quillsql-2.2.1.dist-info/METADATA,sha256=AImLKL4nUys0Yz6i_12iPMHLxi4q5KHnxZJWRoIyw7U,1786
|
|
18
|
+
quillsql-2.2.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
19
|
+
quillsql-2.2.1.dist-info/top_level.txt,sha256=eU2vHnVqwpYQJ3ADl1Q-DIBzbYejZRUhcMdN_4zMCz8,9
|
|
20
|
+
quillsql-2.2.1.dist-info/RECORD,,
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: quillsql
|
|
3
|
-
Version: 2.1.6
|
|
4
|
-
Summary: Quill SDK for Python.
|
|
5
|
-
Home-page: https://github.com/quill-sql/quill-python
|
|
6
|
-
Author: Quill
|
|
7
|
-
Author-email: shawn@quillsql.com
|
|
8
|
-
Description-Content-Type: text/markdown
|
|
9
|
-
Requires-Dist: psycopg2-binary
|
|
10
|
-
Requires-Dist: requests
|
|
11
|
-
Requires-Dist: redis
|
|
12
|
-
Requires-Dist: python-dotenv
|
|
13
|
-
Requires-Dist: pytest
|
|
14
|
-
Requires-Dist: google-cloud-bigquery
|
|
15
|
-
Requires-Dist: google-auth
|
|
16
|
-
|
|
17
|
-
# Quill Python SDK
|
|
18
|
-
|
|
19
|
-
## Quickstart
|
|
20
|
-
|
|
21
|
-
First, install the quillsql package by running:
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
$ pip install quillsql
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
Then, add a `/quill` endpoint to your existing python server. For example, if
|
|
28
|
-
you were running a FASTAPI app, you would just add the endpoint like this:
|
|
29
|
-
|
|
30
|
-
```python
|
|
31
|
-
from quillsql import Quill
|
|
32
|
-
from fastapi import FastAPI, Request
|
|
33
|
-
|
|
34
|
-
app = FastAPI()
|
|
35
|
-
|
|
36
|
-
quill = Quill(
|
|
37
|
-
private_key=<YOUR_PRIVATE_KEY_HERE>,
|
|
38
|
-
database_connection_string=<YOUR_DB_CONNECTION_STRING_HERE>,
|
|
39
|
-
)
|
|
40
|
-
|
|
41
|
-
# ... your existing endpoints here ...
|
|
42
|
-
|
|
43
|
-
@app.post("/quill")
|
|
44
|
-
async def quill_post(data: Request):
|
|
45
|
-
body = await data.json()
|
|
46
|
-
return quill.query(org_id="2", data=body)
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
Then you can run your app like normally. Pass in this route to our react library
|
|
50
|
-
on the frontend and you all set!
|
|
51
|
-
|
|
52
|
-
## For local testing (dev purposes only)
|
|
53
|
-
|
|
54
|
-
```
|
|
55
|
-
pipenv install
|
|
56
|
-
pipenv shell
|
|
57
|
-
uvicorn examples.fastapi-server.app:app --reload --port 3000
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
You are now ready to ping your local server at http://localhost:3000.
|
|
61
|
-
|
|
62
|
-
## Troubleshooting
|
|
63
|
-
|
|
64
|
-
If you run into issues with `Library not loaded: @rpath/libpq.5.dylib` or `no LC_RPATH's found`, try uninstalling and reinstalling postgres on your machine. For example, using homebrew:
|
|
65
|
-
|
|
66
|
-
```bash
|
|
67
|
-
$ brew uninstall c
|
|
68
|
-
$ brew update
|
|
69
|
-
$ brew install postgresql
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
If you're still having this issue, this resource might also be useful for you: https://www.psycopg.org/docs/install.html.
|
quillsql-2.1.6.dist-info/RECORD
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
quillsql/__init__.py,sha256=xxVDrfIXLIbt45yHKGYRbqmgXSPe03uNbqENMLUnUC8,70
|
|
2
|
-
quillsql/core.py,sha256=cCoCLwudlfmOj-o2hW-7Bwx5-XrCvXxQg3iNpTDX6z0,7670
|
|
3
|
-
quillsql/error.py,sha256=XltjRgdBcq3lQN0KdUba5eDzA21yQ7KisIjvqqUSELI,161
|
|
4
|
-
quillsql/assets/__init__.py,sha256=PX43SCko4w5P197YXghGI2VAq3-X1J91IO_tWY7rpiM,44
|
|
5
|
-
quillsql/assets/pgtypes.py,sha256=qWAcGO6QfWN6XXtGI7cMreNSeTjw-xNgcc1aLoq9EV0,40768
|
|
6
|
-
quillsql/db/__init__.py,sha256=mBGMd22nAtp9CdTpEG1Ty47zvSpO8gGejORCACF3-3c,62
|
|
7
|
-
quillsql/db/bigquery.py,sha256=Hzs2DjJ9p8l-HywvaaAk5PbadueNgTVDyDMpCGTcd48,4220
|
|
8
|
-
quillsql/db/cached_connection.py,sha256=1y_GzW5mIAYpmGKJjxpBqmFafpmgUA0Qm9oW_ufyPko,2570
|
|
9
|
-
quillsql/db/db_helper.py,sha256=PFAcX2V26sIaR-hF8orGGltKXdEzR5b_enMSOHlAMUg,2054
|
|
10
|
-
quillsql/db/postgres.py,sha256=iw71feFvnCDBMKpeGbhiJ_4Z4h7AlUi4Hk12Pfyzx6c,2799
|
|
11
|
-
quillsql/utils/__init__.py,sha256=jJLp0OkFQdWohu8vIijfggiWf4eWmeAafVzx3YpdE4E,75
|
|
12
|
-
quillsql/utils/run_query_processes.py,sha256=hElCVACq6bz1_jVIjQUrZzI1CPY188I3_5sHc21jtOc,673
|
|
13
|
-
quillsql/utils/schema_conversion.py,sha256=MwFk95SIZ8OX5EAv141QXLjmCef-1z8jiVKlW71-sk8,297
|
|
14
|
-
quillsql-2.1.6.dist-info/METADATA,sha256=HNtsQyw_xKnQasZ5OKDvKNZf_1OS_qCbPQguu-YTk_U,1809
|
|
15
|
-
quillsql-2.1.6.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
|
16
|
-
quillsql-2.1.6.dist-info/top_level.txt,sha256=eU2vHnVqwpYQJ3ADl1Q-DIBzbYejZRUhcMdN_4zMCz8,9
|
|
17
|
-
quillsql-2.1.6.dist-info/RECORD,,
|
|
File without changes
|