quillsql 2.2.4__py3-none-any.whl → 2.2.5__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/core.py CHANGED
@@ -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,
@@ -129,16 +126,14 @@ class Quill:
129
126
  return {
130
127
  "status": "error",
131
128
  "error": pivot_template_response.get("error"),
132
- "data": (pivot_template_response.get("metadata") or {}),
129
+ "data": pivot_template_response.get("metadata") or {},
133
130
  }
134
131
 
135
- pivot_metadata = pivot_template_response.get("metadata") or {}
136
- template = pivot_metadata.get("template")
137
- config = pivot_metadata.get("config") or {}
138
- distinct_values_query = pivot_metadata.get("distinctValuesQuery")
139
- row_count_query = pivot_metadata.get("rowCountQuery")
132
+ template = pivot_template_response.get("metadata", {}).get("template")
133
+ config = pivot_template_response.get("metadata", {}).get("config")
134
+ distinct_values_query = pivot_template_response.get("metadata", {}).get("distinctValuesQuery")
135
+ row_count_query = pivot_template_response.get("metadata", {}).get("rowCountQuery")
140
136
 
141
- # Step 2: Run the distinct values query to get unique values
142
137
  distinct_values = []
143
138
  if distinct_values_query:
144
139
  distinct_value_results = self.run_queries(
@@ -149,13 +144,11 @@ class Quill:
149
144
  None
150
145
  )
151
146
 
152
- # Parse distinct values from database results
153
147
  distinct_values = parse_distinct_values(
154
148
  distinct_value_results["queryResults"][0],
155
149
  config.get("databaseType")
156
150
  )
157
151
 
158
- # Step 3: Hydrate the template with the distinct values
159
152
  try:
160
153
  final_query = hydrate_pivot_template(template, distinct_values, config)
161
154
  except Exception as err:
@@ -165,10 +158,8 @@ class Quill:
165
158
  "data": {},
166
159
  }
167
160
 
168
- # Step 4: Run queries - pivot query and optional row count query
169
161
  queries_to_run = [final_query]
170
162
  if row_count_query:
171
- # Hydrate the rowCountQuery with the same distinct values
172
163
  hydrated_row_count_query = hydrate_pivot_template(
173
164
  row_count_query,
174
165
  distinct_values,
@@ -181,11 +172,10 @@ class Quill:
181
172
  self.target_connection.database_type,
182
173
  metadata.get("databaseType"),
183
174
  metadata,
184
- pivot_metadata.get("runQueryConfig"),
175
+ pivot_template_response.get("metadata", {}).get("runQueryConfig")
185
176
  )
186
177
 
187
- responseMetadata = pivot_metadata or {}
188
- # Set rows and fields from first query result (the pivot query)
178
+ responseMetadata = pivot_template_response.get("metadata") or {}
189
179
  if final_results.get("queryResults") and len(final_results["queryResults"]) >= 1:
190
180
  query_results = final_results["queryResults"][0]
191
181
  if query_results.get("rows"):
@@ -193,7 +183,6 @@ class Quill:
193
183
  if query_results.get("fields"):
194
184
  responseMetadata["fields"] = query_results["fields"]
195
185
 
196
- # Remove internal SDK fields before returning to frontend
197
186
  if "template" in responseMetadata:
198
187
  del responseMetadata["template"]
199
188
  if "distinctValuesQuery" in responseMetadata:
@@ -229,7 +218,7 @@ class Quill:
229
218
  return {
230
219
  'status': 'error',
231
220
  'error': response.get('error'),
232
- 'data': (response.get('metadata') or {}),
221
+ 'data': response.get('metadata') or {},
233
222
  }
234
223
 
235
224
  flag_query_results = self.run_queries(
@@ -238,22 +227,34 @@ class Quill:
238
227
  )
239
228
 
240
229
  tenant_flags = []
241
- response_metadata = response.get('metadata') or {}
242
- query_order = response_metadata.get('queryOrder') or []
230
+ query_order = (response.get('metadata') or {}).get('queryOrder') or []
243
231
  query_results = (flag_query_results or {}).get('queryResults') or []
244
- for tenant_field, query_result in zip(query_order, query_results):
245
- rows = []
246
- if isinstance(query_result, dict):
247
- rows = query_result.get('rows') or []
248
- flags = {
249
- row.get('quill_flag')
250
- for row in rows
251
- if isinstance(row, dict) and row.get('quill_flag') is not None
252
- }
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)
253
253
  tenant_flags.append({
254
254
  'tenantField': tenant_field,
255
- 'flags': list(flags),
255
+ 'flags': ordered_flags,
256
256
  })
257
+
257
258
  elif tenants[0] == SINGLE_TENANT and flags:
258
259
  if flags and isinstance(flags[0], dict):
259
260
  tenant_flags = [{'tenantField': SINGLE_TENANT, 'flags': flags}]
@@ -285,13 +286,14 @@ class Quill:
285
286
  and metadata.get("runQueryConfig").get("getColumns")
286
287
  else None
287
288
  )
288
- payload: dict = {
289
+ payload = {
289
290
  **metadata,
290
291
  "tenants": tenants,
291
292
  "flags": tenant_flags,
292
293
  "viewQuery": view_query,
293
- "preQueryResultsColumns": pre_query_columns,
294
294
  }
295
+ if pre_query_columns is not None:
296
+ payload["preQueryResultsColumns"] = pre_query_columns
295
297
  if admin_enabled is not None:
296
298
  payload["adminEnabled"] = admin_enabled
297
299
  if filters is not None:
@@ -338,21 +340,25 @@ class Quill:
338
340
  normalized_results.get("queryResults") or []
339
341
  )
340
342
 
341
- run_query_config = responseMetadata.get("runQueryConfig") or {}
342
- array_to_map = run_query_config.get("arrayToMap")
343
- if normalized_results.get("mapped_array") and array_to_map:
344
- target_collection = responseMetadata.get(array_to_map.get("arrayName"))
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"])
345
349
  if isinstance(target_collection, list):
346
- for index, mapped_rows in enumerate(normalized_results["mapped_array"]):
350
+ for index, array in enumerate(normalized_results["mapped_array"]):
347
351
  if index >= len(target_collection):
348
352
  continue
349
353
  target_entry = target_collection[index]
350
- if isinstance(target_entry, dict):
351
- target_entry[array_to_map.get("field")] = mapped_rows
352
- normalized_results.pop("mapped_array", None)
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"]
353
359
 
354
360
  query_results_list = normalized_results.get("queryResults") or []
355
- if len(query_results_list) == 1:
361
+ if len(query_results_list) == 1 and isinstance(query_results_list[0], dict):
356
362
  query_result = query_results_list[0]
357
363
  quill_results["metadata"]["rows"] = query_result.get("rows")
358
364
  quill_results["metadata"]["fields"] = query_result.get("fields")
@@ -483,3 +483,4 @@ def validate_template(template: str, config: PivotConfig) -> Dict[str, Any]:
483
483
  "errors": errors
484
484
  }
485
485
 
486
+
@@ -1,14 +1,21 @@
1
1
  def remove_fields(query_result, fields_to_remove):
2
+ if not isinstance(query_result, dict):
3
+ return query_result
2
4
  fields = [
3
5
  {"name": field["name"], "dataTypeID": field["dataTypeID"]}
4
- for field in query_result["fields"]
5
- if field["name"] not in fields_to_remove
6
+ for field in (query_result.get("fields") or [])
7
+ if field.get("name") not in fields_to_remove
6
8
  ]
7
- rows = [row for row in query_result["rows"]]
8
- for row in rows:
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)
9
15
  for field in fields_to_remove:
10
- if field in row:
11
- del row[field]
16
+ if field in filtered:
17
+ del filtered[field]
18
+ rows.append(filtered)
12
19
  return {"fields": fields, "rows": rows}
13
20
 
14
21
 
@@ -16,5 +23,8 @@ def array_to_map(queries, array_to_map, metadata, target_pool):
16
23
  mapped_array = []
17
24
  for i in range(len(queries)):
18
25
  query_result = target_pool.query(queries[i])
19
- mapped_array.append(query_result.get("rows"))
26
+ if isinstance(query_result, dict):
27
+ mapped_array.append(query_result.get("rows"))
28
+ else:
29
+ mapped_array.append([])
20
30
  return mapped_array
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: quillsql
3
- Version: 2.2.4
3
+ Version: 2.2.5
4
4
  Summary: Quill SDK for Python.
5
5
  Home-page: https://github.com/quill-sql/quill-python
6
6
  Author: Quill
@@ -1,5 +1,5 @@
1
1
  quillsql/__init__.py,sha256=FiuoxaNZveKXOPB0hkpfGNlpZKmSn3pRwcqm9HKYbCQ,180
2
- quillsql/core.py,sha256=HMmRtQQj3bWuLTIE8YuZaj6cAwh4bSui3pFe9pA9SgQ,23261
2
+ quillsql/core.py,sha256=OOvhFEya_DGmyE5U9nVUQ58ZBnePTNh5mKPg7OTSI_Q,23259
3
3
  quillsql/error.py,sha256=n9VKHw4FAgg7ZEAz2YQ8L_8FdRG_1shwGngf2iWhUSM,175
4
4
  quillsql/assets/__init__.py,sha256=oXQ2ZS5XDXkXTYjADxNfGt55cIn_rqfgWL2EDqjTyoI,45
5
5
  quillsql/assets/pgtypes.py,sha256=-B_2wUaoAsdX7_HnJhUlx4ptZQ6x-cXwuST9ACgGFdE,33820
@@ -10,11 +10,11 @@ quillsql/db/db_helper.py,sha256=qiIP-BM7R-3PhvWBELYjNazi-92EcQB0q9eN7Ej7XUA,2111
10
10
  quillsql/db/postgres.py,sha256=ZTLtUVTJHkqAj7nZkcwbmkSOwR2ySN7vS5snoxqLRN0,4156
11
11
  quillsql/utils/__init__.py,sha256=C2k9Xe0sG5XrP0XJo9K_-iej1S9PLMRKOYMeLxj7NYE,210
12
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
13
+ quillsql/utils/pivot_template.py,sha256=HXtb-DigrqFhdHKX2jWeYeFZNuWCfZSyNw31Fy2fIok,18283
14
+ quillsql/utils/run_query_processes.py,sha256=QwnMr5UwXdtO_W88lv5nBaf6pJ_h5oWQnYd8K9oHQ5s,1030
15
15
  quillsql/utils/schema_conversion.py,sha256=TFfMibN9nOsxNRhHw5YIFl3jGTvipG81bxX4LFDulUY,314
16
16
  quillsql/utils/tenants.py,sha256=ZD2FuKz0gjBVSsThHDv1P8PU6EL8E009NWihE5hAH-Q,2022
17
- quillsql-2.2.4.dist-info/METADATA,sha256=wEywCChkWsaEmZezh0DCkKUXHkgGLv0RR3OzCgEEWk0,1786
18
- quillsql-2.2.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
19
- quillsql-2.2.4.dist-info/top_level.txt,sha256=eU2vHnVqwpYQJ3ADl1Q-DIBzbYejZRUhcMdN_4zMCz8,9
20
- quillsql-2.2.4.dist-info/RECORD,,
17
+ quillsql-2.2.5.dist-info/METADATA,sha256=AB1wJfgnGMitTW25kmjortFqmUVK4dlY74PFhFNXkL0,1786
18
+ quillsql-2.2.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
19
+ quillsql-2.2.5.dist-info/top_level.txt,sha256=eU2vHnVqwpYQJ3ADl1Q-DIBzbYejZRUhcMdN_4zMCz8,9
20
+ quillsql-2.2.5.dist-info/RECORD,,