quillsql 2.2.3__tar.gz → 2.2.5__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.
- {quillsql-2.2.3 → quillsql-2.2.5}/PKG-INFO +1 -1
- {quillsql-2.2.3 → quillsql-2.2.5}/quillsql/core.py +40 -32
- {quillsql-2.2.3 → quillsql-2.2.5}/quillsql/utils/pivot_template.py +1 -0
- quillsql-2.2.5/quillsql/utils/run_query_processes.py +30 -0
- {quillsql-2.2.3 → quillsql-2.2.5}/quillsql.egg-info/PKG-INFO +1 -1
- {quillsql-2.2.3 → quillsql-2.2.5}/setup.py +1 -1
- quillsql-2.2.5/tests/test_core.py +196 -0
- quillsql-2.2.3/quillsql/utils/run_query_processes.py +0 -20
- quillsql-2.2.3/tests/test_core.py +0 -53
- {quillsql-2.2.3 → quillsql-2.2.5}/README.md +0 -0
- {quillsql-2.2.3 → quillsql-2.2.5}/quillsql/__init__.py +0 -0
- {quillsql-2.2.3 → quillsql-2.2.5}/quillsql/assets/__init__.py +0 -0
- {quillsql-2.2.3 → quillsql-2.2.5}/quillsql/assets/pgtypes.py +0 -0
- {quillsql-2.2.3 → quillsql-2.2.5}/quillsql/db/__init__.py +0 -0
- {quillsql-2.2.3 → quillsql-2.2.5}/quillsql/db/bigquery.py +0 -0
- {quillsql-2.2.3 → quillsql-2.2.5}/quillsql/db/cached_connection.py +0 -0
- {quillsql-2.2.3 → quillsql-2.2.5}/quillsql/db/db_helper.py +0 -0
- {quillsql-2.2.3 → quillsql-2.2.5}/quillsql/db/postgres.py +0 -0
- {quillsql-2.2.3 → quillsql-2.2.5}/quillsql/error.py +0 -0
- {quillsql-2.2.3 → quillsql-2.2.5}/quillsql/utils/__init__.py +0 -0
- {quillsql-2.2.3 → quillsql-2.2.5}/quillsql/utils/filters.py +0 -0
- {quillsql-2.2.3 → quillsql-2.2.5}/quillsql/utils/schema_conversion.py +0 -0
- {quillsql-2.2.3 → quillsql-2.2.5}/quillsql/utils/tenants.py +0 -0
- {quillsql-2.2.3 → quillsql-2.2.5}/quillsql.egg-info/SOURCES.txt +0 -0
- {quillsql-2.2.3 → quillsql-2.2.5}/quillsql.egg-info/dependency_links.txt +0 -0
- {quillsql-2.2.3 → quillsql-2.2.5}/quillsql.egg-info/requires.txt +0 -0
- {quillsql-2.2.3 → quillsql-2.2.5}/quillsql.egg-info/top_level.txt +0 -0
- {quillsql-2.2.3 → quillsql-2.2.5}/setup.cfg +0 -0
|
@@ -91,8 +91,6 @@ class Quill:
|
|
|
91
91
|
):
|
|
92
92
|
if not tenants:
|
|
93
93
|
raise ValueError("You may not pass an empty tenants array.")
|
|
94
|
-
if flags and not flags:
|
|
95
|
-
raise ValueError("You may not pass an empty flags array.")
|
|
96
94
|
|
|
97
95
|
responseMetadata = {}
|
|
98
96
|
if not metadata:
|
|
@@ -108,7 +106,6 @@ class Quill:
|
|
|
108
106
|
|
|
109
107
|
# Handle pivot-template task
|
|
110
108
|
if task == "pivot-template":
|
|
111
|
-
# Step 1: Get pivot template and queries from server
|
|
112
109
|
pivot_payload = {
|
|
113
110
|
**metadata,
|
|
114
111
|
"tenants": tenants,
|
|
@@ -137,7 +134,6 @@ class Quill:
|
|
|
137
134
|
distinct_values_query = pivot_template_response.get("metadata", {}).get("distinctValuesQuery")
|
|
138
135
|
row_count_query = pivot_template_response.get("metadata", {}).get("rowCountQuery")
|
|
139
136
|
|
|
140
|
-
# Step 2: Run the distinct values query to get unique values
|
|
141
137
|
distinct_values = []
|
|
142
138
|
if distinct_values_query:
|
|
143
139
|
distinct_value_results = self.run_queries(
|
|
@@ -148,13 +144,11 @@ class Quill:
|
|
|
148
144
|
None
|
|
149
145
|
)
|
|
150
146
|
|
|
151
|
-
# Parse distinct values from database results
|
|
152
147
|
distinct_values = parse_distinct_values(
|
|
153
148
|
distinct_value_results["queryResults"][0],
|
|
154
149
|
config.get("databaseType")
|
|
155
150
|
)
|
|
156
151
|
|
|
157
|
-
# Step 3: Hydrate the template with the distinct values
|
|
158
152
|
try:
|
|
159
153
|
final_query = hydrate_pivot_template(template, distinct_values, config)
|
|
160
154
|
except Exception as err:
|
|
@@ -164,10 +158,8 @@ class Quill:
|
|
|
164
158
|
"data": {},
|
|
165
159
|
}
|
|
166
160
|
|
|
167
|
-
# Step 4: Run queries - pivot query and optional row count query
|
|
168
161
|
queries_to_run = [final_query]
|
|
169
162
|
if row_count_query:
|
|
170
|
-
# Hydrate the rowCountQuery with the same distinct values
|
|
171
163
|
hydrated_row_count_query = hydrate_pivot_template(
|
|
172
164
|
row_count_query,
|
|
173
165
|
distinct_values,
|
|
@@ -184,7 +176,6 @@ class Quill:
|
|
|
184
176
|
)
|
|
185
177
|
|
|
186
178
|
responseMetadata = pivot_template_response.get("metadata") or {}
|
|
187
|
-
# Set rows and fields from first query result (the pivot query)
|
|
188
179
|
if final_results.get("queryResults") and len(final_results["queryResults"]) >= 1:
|
|
189
180
|
query_results = final_results["queryResults"][0]
|
|
190
181
|
if query_results.get("rows"):
|
|
@@ -192,7 +183,6 @@ class Quill:
|
|
|
192
183
|
if query_results.get("fields"):
|
|
193
184
|
responseMetadata["fields"] = query_results["fields"]
|
|
194
185
|
|
|
195
|
-
# Remove internal SDK fields before returning to frontend
|
|
196
186
|
if "template" in responseMetadata:
|
|
197
187
|
del responseMetadata["template"]
|
|
198
188
|
if "distinctValuesQuery" in responseMetadata:
|
|
@@ -237,21 +227,34 @@ class Quill:
|
|
|
237
227
|
)
|
|
238
228
|
|
|
239
229
|
tenant_flags = []
|
|
240
|
-
query_order = response.get('metadata'
|
|
230
|
+
query_order = (response.get('metadata') or {}).get('queryOrder') or []
|
|
241
231
|
query_results = (flag_query_results or {}).get('queryResults') or []
|
|
242
|
-
for
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
232
|
+
for index, tenant_field in enumerate(query_order):
|
|
233
|
+
query_result = (
|
|
234
|
+
query_results[index]
|
|
235
|
+
if index < len(query_results)
|
|
236
|
+
else {}
|
|
237
|
+
)
|
|
238
|
+
rows = (
|
|
239
|
+
query_result.get('rows')
|
|
240
|
+
if isinstance(query_result, dict)
|
|
241
|
+
else []
|
|
242
|
+
)
|
|
243
|
+
ordered_flags = []
|
|
244
|
+
seen = set()
|
|
245
|
+
for row in rows or []:
|
|
246
|
+
if not isinstance(row, dict):
|
|
247
|
+
continue
|
|
248
|
+
flag = row.get('quill_flag')
|
|
249
|
+
if flag is None or flag in seen:
|
|
250
|
+
continue
|
|
251
|
+
seen.add(flag)
|
|
252
|
+
ordered_flags.append(flag)
|
|
251
253
|
tenant_flags.append({
|
|
252
254
|
'tenantField': tenant_field,
|
|
253
|
-
'flags':
|
|
255
|
+
'flags': ordered_flags,
|
|
254
256
|
})
|
|
257
|
+
|
|
255
258
|
elif tenants[0] == SINGLE_TENANT and flags:
|
|
256
259
|
if flags and isinstance(flags[0], dict):
|
|
257
260
|
tenant_flags = [{'tenantField': SINGLE_TENANT, 'flags': flags}]
|
|
@@ -283,13 +286,14 @@ class Quill:
|
|
|
283
286
|
and metadata.get("runQueryConfig").get("getColumns")
|
|
284
287
|
else None
|
|
285
288
|
)
|
|
286
|
-
payload
|
|
289
|
+
payload = {
|
|
287
290
|
**metadata,
|
|
288
291
|
"tenants": tenants,
|
|
289
292
|
"flags": tenant_flags,
|
|
290
293
|
"viewQuery": view_query,
|
|
291
|
-
"preQueryResultsColumns": pre_query_columns,
|
|
292
294
|
}
|
|
295
|
+
if pre_query_columns is not None:
|
|
296
|
+
payload["preQueryResultsColumns"] = pre_query_columns
|
|
293
297
|
if admin_enabled is not None:
|
|
294
298
|
payload["adminEnabled"] = admin_enabled
|
|
295
299
|
if filters is not None:
|
|
@@ -336,21 +340,25 @@ class Quill:
|
|
|
336
340
|
normalized_results.get("queryResults") or []
|
|
337
341
|
)
|
|
338
342
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
+
if (
|
|
344
|
+
normalized_results.get("mapped_array")
|
|
345
|
+
and metadata.get("runQueryConfig", {}).get("arrayToMap")
|
|
346
|
+
):
|
|
347
|
+
array_to_map = metadata["runQueryConfig"]["arrayToMap"]
|
|
348
|
+
target_collection = responseMetadata.get(array_to_map["arrayName"])
|
|
343
349
|
if isinstance(target_collection, list):
|
|
344
|
-
for index,
|
|
350
|
+
for index, array in enumerate(normalized_results["mapped_array"]):
|
|
345
351
|
if index >= len(target_collection):
|
|
346
352
|
continue
|
|
347
353
|
target_entry = target_collection[index]
|
|
348
|
-
if isinstance(target_entry, dict):
|
|
349
|
-
target_entry
|
|
350
|
-
|
|
354
|
+
if not isinstance(target_entry, dict):
|
|
355
|
+
target_entry = {}
|
|
356
|
+
target_collection[index] = target_entry
|
|
357
|
+
target_entry[array_to_map["field"]] = array if array is not None else []
|
|
358
|
+
del normalized_results["mapped_array"]
|
|
351
359
|
|
|
352
360
|
query_results_list = normalized_results.get("queryResults") or []
|
|
353
|
-
if len(query_results_list) == 1:
|
|
361
|
+
if len(query_results_list) == 1 and isinstance(query_results_list[0], dict):
|
|
354
362
|
query_result = query_results_list[0]
|
|
355
363
|
quill_results["metadata"]["rows"] = query_result.get("rows")
|
|
356
364
|
quill_results["metadata"]["fields"] = query_result.get("fields")
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
def remove_fields(query_result, fields_to_remove):
|
|
2
|
+
if not isinstance(query_result, dict):
|
|
3
|
+
return query_result
|
|
4
|
+
fields = [
|
|
5
|
+
{"name": field["name"], "dataTypeID": field["dataTypeID"]}
|
|
6
|
+
for field in (query_result.get("fields") or [])
|
|
7
|
+
if field.get("name") not in fields_to_remove
|
|
8
|
+
]
|
|
9
|
+
rows = []
|
|
10
|
+
for row in query_result.get("rows") or []:
|
|
11
|
+
if not isinstance(row, dict):
|
|
12
|
+
rows.append(row)
|
|
13
|
+
continue
|
|
14
|
+
filtered = dict(row)
|
|
15
|
+
for field in fields_to_remove:
|
|
16
|
+
if field in filtered:
|
|
17
|
+
del filtered[field]
|
|
18
|
+
rows.append(filtered)
|
|
19
|
+
return {"fields": fields, "rows": rows}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def array_to_map(queries, array_to_map, metadata, target_pool):
|
|
23
|
+
mapped_array = []
|
|
24
|
+
for i in range(len(queries)):
|
|
25
|
+
query_result = target_pool.query(queries[i])
|
|
26
|
+
if isinstance(query_result, dict):
|
|
27
|
+
mapped_array.append(query_result.get("rows"))
|
|
28
|
+
else:
|
|
29
|
+
mapped_array.append([])
|
|
30
|
+
return mapped_array
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
from unittest.mock import MagicMock, patch
|
|
4
|
+
|
|
5
|
+
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
|
|
6
|
+
|
|
7
|
+
from quillsql.core import Quill
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@patch("quillsql.core.CachedConnection")
|
|
11
|
+
def test_query_handles_none_tenant_flag_responses(mock_cached_connection):
|
|
12
|
+
mock_connection = MagicMock()
|
|
13
|
+
mock_connection.database_type = "PostgreSQL"
|
|
14
|
+
mock_cached_connection.return_value = mock_connection
|
|
15
|
+
|
|
16
|
+
quill = Quill(
|
|
17
|
+
private_key=os.getenv("PRIVATE_KEY"),
|
|
18
|
+
database_type=os.getenv("DB_TYPE"),
|
|
19
|
+
database_connection_string=os.getenv("DB_URL")
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
quill.run_queries = MagicMock(
|
|
23
|
+
side_effect=[
|
|
24
|
+
{"queryResults": [None]},
|
|
25
|
+
{"queryResults": []},
|
|
26
|
+
]
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
def post_quill_side_effect(path, payload):
|
|
30
|
+
if path == "tenant-mapped-flags":
|
|
31
|
+
return {
|
|
32
|
+
"queries": [
|
|
33
|
+
'SELECT * FROM (SELECT "id" AS "customer_id", "name" AS "quill_label", "id" AS "quill_flag" FROM "public"."customers") AS "subq_owner_query" WHERE "customer_id" IN (2)'
|
|
34
|
+
],
|
|
35
|
+
"metadata": {"queryOrder": ["customer_id"]},
|
|
36
|
+
}
|
|
37
|
+
return {"queries": [], "metadata": {}}
|
|
38
|
+
|
|
39
|
+
quill.post_quill = MagicMock(side_effect=post_quill_side_effect)
|
|
40
|
+
|
|
41
|
+
result = quill.query(
|
|
42
|
+
tenants=["tenant-1"],
|
|
43
|
+
metadata={
|
|
44
|
+
"task": "report",
|
|
45
|
+
"clientId": "client-123",
|
|
46
|
+
"reportId": "report-456",
|
|
47
|
+
"databaseType": "PostgreSQL",
|
|
48
|
+
},
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
assert result["status"] == "success"
|
|
52
|
+
assert result["data"] == {}
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@patch("quillsql.core.CachedConnection")
|
|
56
|
+
def test_query_handles_tenant_flag_metadata_none(mock_cached_connection):
|
|
57
|
+
mock_connection = MagicMock()
|
|
58
|
+
mock_connection.database_type = "PostgreSQL"
|
|
59
|
+
mock_cached_connection.return_value = mock_connection
|
|
60
|
+
|
|
61
|
+
quill = Quill(
|
|
62
|
+
private_key=os.getenv("PRIVATE_KEY"),
|
|
63
|
+
database_type=os.getenv("DB_TYPE"),
|
|
64
|
+
database_connection_string=os.getenv("DB_URL")
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
quill.run_queries = MagicMock(
|
|
68
|
+
side_effect=[
|
|
69
|
+
{"queryResults": [{"rows": [{"quill_flag": "alpha"}]}]},
|
|
70
|
+
{"queryResults": []},
|
|
71
|
+
]
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
def post_quill_side_effect(path, payload):
|
|
75
|
+
if path == "tenant-mapped-flags":
|
|
76
|
+
return {
|
|
77
|
+
"queries": [
|
|
78
|
+
'SELECT * FROM (SELECT "id" AS "customer_id", "name" AS "quill_label", "id" AS "quill_flag" FROM "public"."customers") AS "subq_owner_query" WHERE "customer_id" IN (2)'
|
|
79
|
+
],
|
|
80
|
+
"metadata": None,
|
|
81
|
+
}
|
|
82
|
+
return {"queries": [], "metadata": {}}
|
|
83
|
+
|
|
84
|
+
quill.post_quill = MagicMock(side_effect=post_quill_side_effect)
|
|
85
|
+
|
|
86
|
+
result = quill.query(
|
|
87
|
+
tenants=[{"tenantField": "customer_id", "tenantIds": [2]}],
|
|
88
|
+
metadata={
|
|
89
|
+
"task": "report",
|
|
90
|
+
"clientId": "client-123",
|
|
91
|
+
"reportId": "report-456",
|
|
92
|
+
"databaseType": "PostgreSQL",
|
|
93
|
+
},
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
assert result["status"] == "success"
|
|
97
|
+
assert result["data"] == {}
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
@patch("quillsql.core.CachedConnection")
|
|
101
|
+
def test_query_handles_array_to_map_with_null_mapped_rows(mock_cached_connection):
|
|
102
|
+
mock_connection = MagicMock()
|
|
103
|
+
mock_connection.database_type = "PostgreSQL"
|
|
104
|
+
mock_cached_connection.return_value = mock_connection
|
|
105
|
+
|
|
106
|
+
quill = Quill(
|
|
107
|
+
private_key=os.getenv("PRIVATE_KEY"),
|
|
108
|
+
database_type=os.getenv("DB_TYPE"),
|
|
109
|
+
database_connection_string=os.getenv("DB_URL")
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
quill.run_queries = MagicMock(
|
|
113
|
+
side_effect=[
|
|
114
|
+
{"queryResults": []}, # tenant-mapped-flags
|
|
115
|
+
{"queryResults": [], "mapped_array": [None]}, # main query
|
|
116
|
+
]
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
def post_quill_side_effect(path, payload):
|
|
120
|
+
if path == "tenant-mapped-flags":
|
|
121
|
+
return {"queries": [], "metadata": {"queryOrder": []}}
|
|
122
|
+
if path == "filter-options":
|
|
123
|
+
return {
|
|
124
|
+
"queries": ["SELECT 1"],
|
|
125
|
+
"metadata": {
|
|
126
|
+
"filters": [{"label": "Driver"}],
|
|
127
|
+
"runQueryConfig": {
|
|
128
|
+
"arrayToMap": {"arrayName": "filters", "field": "options"}
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
}
|
|
132
|
+
return {"queries": [], "metadata": {}}
|
|
133
|
+
|
|
134
|
+
quill.post_quill = MagicMock(side_effect=post_quill_side_effect)
|
|
135
|
+
|
|
136
|
+
result = quill.query(
|
|
137
|
+
tenants=[{"tenantField": "customer_id", "tenantIds": [2]}],
|
|
138
|
+
metadata={
|
|
139
|
+
"task": "filter-options",
|
|
140
|
+
"clientId": "client-123",
|
|
141
|
+
"filter": {"field": "user_name"},
|
|
142
|
+
},
|
|
143
|
+
flags=[],
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
assert result["status"] == "success"
|
|
147
|
+
assert result["data"]["filters"][0]["options"] == []
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
@patch("quillsql.core.CachedConnection")
|
|
151
|
+
def test_query_handles_fields_to_remove_with_null_results(mock_cached_connection):
|
|
152
|
+
mock_connection = MagicMock()
|
|
153
|
+
mock_connection.database_type = "PostgreSQL"
|
|
154
|
+
mock_cached_connection.return_value = mock_connection
|
|
155
|
+
|
|
156
|
+
quill = Quill(
|
|
157
|
+
private_key=os.getenv("PRIVATE_KEY"),
|
|
158
|
+
database_type=os.getenv("DB_TYPE"),
|
|
159
|
+
database_connection_string=os.getenv("DB_URL")
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
quill.run_queries = MagicMock(
|
|
163
|
+
side_effect=[
|
|
164
|
+
{"queryResults": []}, # tenant-mapped-flags
|
|
165
|
+
{"queryResults": [None]}, # main run_queries
|
|
166
|
+
]
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
def post_quill_side_effect(path, payload):
|
|
170
|
+
if path == "tenant-mapped-flags":
|
|
171
|
+
return {"queries": [], "metadata": {"queryOrder": []}}
|
|
172
|
+
if path == "report":
|
|
173
|
+
return {
|
|
174
|
+
"queries": ["SELECT 1"],
|
|
175
|
+
"metadata": {
|
|
176
|
+
"runQueryConfig": {"fieldsToRemove": ["customer_id"]},
|
|
177
|
+
},
|
|
178
|
+
}
|
|
179
|
+
return {"queries": [], "metadata": {}}
|
|
180
|
+
|
|
181
|
+
quill.post_quill = MagicMock(side_effect=post_quill_side_effect)
|
|
182
|
+
|
|
183
|
+
result = quill.query(
|
|
184
|
+
tenants=[{"tenantField": "customer_id", "tenantIds": [2]}],
|
|
185
|
+
metadata={
|
|
186
|
+
"task": "report",
|
|
187
|
+
"clientId": "client-123",
|
|
188
|
+
"reportId": "report-456",
|
|
189
|
+
"databaseType": "PostgreSQL",
|
|
190
|
+
},
|
|
191
|
+
flags=[],
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
assert result["status"] == "success"
|
|
195
|
+
assert result["queries"]["queryResults"][0] is None
|
|
196
|
+
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
def remove_fields(query_result, fields_to_remove):
|
|
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
|
-
|
|
14
|
-
|
|
15
|
-
def array_to_map(queries, array_to_map, metadata, target_pool):
|
|
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,53 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import sys
|
|
3
|
-
from unittest.mock import MagicMock, patch
|
|
4
|
-
|
|
5
|
-
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
|
|
6
|
-
|
|
7
|
-
from quillsql.core import Quill
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
@patch("quillsql.core.CachedConnection")
|
|
11
|
-
def test_query_handles_none_tenant_flag_responses(mock_cached_connection):
|
|
12
|
-
mock_connection = MagicMock()
|
|
13
|
-
mock_connection.database_type = "PostgreSQL"
|
|
14
|
-
mock_cached_connection.return_value = mock_connection
|
|
15
|
-
|
|
16
|
-
quill = Quill(
|
|
17
|
-
private_key="test-key",
|
|
18
|
-
database_type="PostgreSQL",
|
|
19
|
-
database_config={},
|
|
20
|
-
)
|
|
21
|
-
|
|
22
|
-
quill.run_queries = MagicMock(
|
|
23
|
-
side_effect=[
|
|
24
|
-
{"queryResults": [None]},
|
|
25
|
-
{"queryResults": []},
|
|
26
|
-
]
|
|
27
|
-
)
|
|
28
|
-
|
|
29
|
-
def post_quill_side_effect(path, payload):
|
|
30
|
-
if path == "tenant-mapped-flags":
|
|
31
|
-
return {
|
|
32
|
-
"queries": [
|
|
33
|
-
'SELECT * FROM (SELECT "id" AS "customer_id", "name" AS "quill_label", "id" AS "quill_flag" FROM "public"."customers") AS "subq_owner_query" WHERE "customer_id" IN (2)'
|
|
34
|
-
],
|
|
35
|
-
"metadata": {"queryOrder": ["customer_id"]},
|
|
36
|
-
}
|
|
37
|
-
return {"queries": [], "metadata": {}}
|
|
38
|
-
|
|
39
|
-
quill.post_quill = MagicMock(side_effect=post_quill_side_effect)
|
|
40
|
-
|
|
41
|
-
result = quill.query(
|
|
42
|
-
tenants=["tenant-1"],
|
|
43
|
-
metadata={
|
|
44
|
-
"task": "report",
|
|
45
|
-
"clientId": "client-123",
|
|
46
|
-
"reportId": "report-456",
|
|
47
|
-
"databaseType": "PostgreSQL",
|
|
48
|
-
},
|
|
49
|
-
)
|
|
50
|
-
|
|
51
|
-
assert result["status"] == "success"
|
|
52
|
-
assert result["data"] == {}
|
|
53
|
-
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|