jaaql-middleware-python 4.34.1__tar.gz → 4.34.3__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 (77) hide show
  1. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/PKG-INFO +1 -1
  2. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/constants.py +1 -1
  3. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/mvc/model.py +78 -17
  4. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql_middleware_python.egg-info/PKG-INFO +1 -1
  5. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/LICENSE.txt +0 -0
  6. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/README.md +0 -0
  7. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/__init__.py +0 -0
  8. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/config/__init__.py +0 -0
  9. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/config/config-docker.ini +0 -0
  10. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/config/config-test.ini +0 -0
  11. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/config/config.ini +0 -0
  12. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/config_constants.py +0 -0
  13. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/db/__init__.py +0 -0
  14. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/db/db_interface.py +0 -0
  15. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/db/db_pg_interface.py +0 -0
  16. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/db/db_utils.py +0 -0
  17. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/db/db_utils_no_circ.py +0 -0
  18. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/documentation/__init__.py +0 -0
  19. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/documentation/documentation_internal.py +0 -0
  20. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/documentation/documentation_public.py +0 -0
  21. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/documentation/documentation_shared.py +0 -0
  22. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/email/__init__.py +0 -0
  23. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/email/email_manager.py +0 -0
  24. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/email/email_manager_service.py +0 -0
  25. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/email/patch_ems.py +0 -0
  26. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/exceptions/__init__.py +0 -0
  27. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/exceptions/custom_http_status.py +0 -0
  28. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/exceptions/http_status_exception.py +0 -0
  29. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/exceptions/jaaql_interpretable_handled_errors.py +0 -0
  30. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/exceptions/not_yet_implement_exception.py +0 -0
  31. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/generated_constants.py +0 -0
  32. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/interpreter/__init__.py +0 -0
  33. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/interpreter/interpret_jaaql.py +0 -0
  34. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/jaaql.py +0 -0
  35. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/migrations/__init__.py +0 -0
  36. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/migrations/migrations.py +0 -0
  37. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/mvc/__init__.py +0 -0
  38. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/mvc/base_controller.py +0 -0
  39. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/mvc/base_model.py +0 -0
  40. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/mvc/controller.py +0 -0
  41. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/mvc/controller_interface.py +0 -0
  42. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/mvc/exception_queries.py +0 -0
  43. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/mvc/generated_queries.py +0 -0
  44. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/mvc/handmade_queries.py +0 -0
  45. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/mvc/model_interface.py +0 -0
  46. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/mvc/response.py +0 -0
  47. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/openapi/__init__.py +0 -0
  48. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/openapi/swagger_documentation.py +0 -0
  49. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/patch.py +0 -0
  50. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/scripts/01.install_domains.generated.sql +0 -0
  51. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/scripts/02.install_super_user.exceptions.sql +0 -0
  52. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/scripts/03.install_super_user.handwritten.sql +0 -0
  53. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/scripts/04.install_jaaql_data_structures.generated.sql +0 -0
  54. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/scripts/05.install_static_data.generated.sql +0 -0
  55. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/scripts/06.install_jaaql.exceptions.sql +0 -0
  56. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/scripts/ZZZZ.generated_functions_views_and_permissions.sql +0 -0
  57. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/scripts/ZZZZ.reset_references.sql +0 -0
  58. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/scripts/swagger_template.html +0 -0
  59. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/services/__init__.py +0 -0
  60. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/services/cached_canned_query_service.py +0 -0
  61. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/services/migrations_manager_service.py +0 -0
  62. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/services/patch_mms.py +0 -0
  63. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/services/patch_shared_var_service.py +0 -0
  64. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/services/shared_var_service.py +0 -0
  65. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/utilities/__init__.py +0 -0
  66. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/utilities/cron.py +0 -0
  67. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/utilities/crypt_utils.py +0 -0
  68. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/utilities/options.py +0 -0
  69. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/utilities/utils.py +0 -0
  70. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/utilities/utils_no_project_imports.py +0 -0
  71. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql/utilities/vault.py +0 -0
  72. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql_middleware_python.egg-info/SOURCES.txt +0 -0
  73. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql_middleware_python.egg-info/dependency_links.txt +0 -0
  74. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql_middleware_python.egg-info/requires.txt +0 -0
  75. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/jaaql_middleware_python.egg-info/top_level.txt +0 -0
  76. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/setup.cfg +0 -0
  77. {jaaql_middleware_python-4.34.1 → jaaql_middleware_python-4.34.3}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jaaql-middleware-python
3
- Version: 4.34.1
3
+ Version: 4.34.3
4
4
  Summary: The jaaql package, allowing for rapid development and deployment of RESTful HTTP applications
5
5
  Home-page: https://github.com/JAAQL/JAAQL-middleware-python
6
6
  Author: Software Quality Measurement and Improvement bv
@@ -208,5 +208,5 @@ ROLE__postgres = "postgres"
208
208
 
209
209
  PROTOCOL__postgres = "postgresql://"
210
210
 
211
- VERSION = "4.34.1"
211
+ VERSION = "4.34.3"
212
212
 
@@ -203,28 +203,46 @@ class JAAQLModel(BaseJAAQLModel):
203
203
  def parse_gdesc_output(self, output):
204
204
  """
205
205
  Parse the output of gdesc to extract column names and types.
206
+
207
+ If duplicate column names exist, raise an exception listing them.
206
208
  """
207
209
  lines = output.strip().split('\n')
208
210
  columns = {}
209
211
  parsing = False
212
+
213
+ seen = {}
210
214
  for line in lines:
211
215
  if line.strip().replace(" ", "") == "Column|Type":
212
216
  # Found the header line
213
217
  parsing = True
214
218
  continue
219
+
215
220
  if parsing:
216
221
  if line.strip() == '':
217
222
  # End of table
218
223
  break
224
+
219
225
  # Parse the line
220
226
  parts = [part.strip() for part in line.strip().split('|')]
221
227
  if len(parts) >= 2:
222
228
  column_name = parts[0]
223
229
  column_type = parts[1]
230
+
231
+ seen[column_name] = seen.get(column_name, 0) + 1
232
+
233
+ # Still build the dict, but we'll error afterwards if duplicates exist
224
234
  columns[column_name] = {
225
235
  "type": column_type,
226
236
  "nullable": True # We can't figure this out with gdesc
227
237
  }
238
+
239
+ dupes = [name for name, count in seen.items() if count > 1]
240
+ if dupes:
241
+ dupes.sort()
242
+ # Include counts so it's unambiguous
243
+ dupe_str = ", ".join([f"{name} (x{seen[name]})" for name in dupes])
244
+ raise Exception("Duplicate output column names are not supported: " + dupe_str)
245
+
228
246
  return columns
229
247
 
230
248
  def fetch_domains(self, inputs: dict, account_id: str):
@@ -269,32 +287,58 @@ ORDER BY
269
287
  cost = None
270
288
  type_resolution_method = None
271
289
  columns = None
290
+
272
291
  try:
273
- results = execute_supplied_statement(db_connection, query["query"].strip(),
274
- do_prepare_only=my_uuid) # Fetch cursor descriptors here too and then merge
292
+ results = execute_supplied_statement(
293
+ db_connection,
294
+ query["query"].strip(),
295
+ do_prepare_only=my_uuid
296
+ )
275
297
  cost = float(results["rows"][0][0].split("..")[1].split(" ")[0])
276
298
  except Exception as ex:
277
299
  exc = str(ex).replace("PREPARE _jaaql_query_check_" + my_uuid + " as ", "").replace(
278
300
  " ... _jaaql_query_check_" + my_uuid + " as ", "")
279
301
 
280
302
  if exc is None and not cost_only:
303
+ # Try temp_view domain type resolution first
281
304
  try:
282
- domain_types = execute_supplied_statement(db_connection, query["query"].strip(), do_prepare_only=my_uuid, attempt_fetch_domain_types=True)
305
+ domain_types = execute_supplied_statement(
306
+ db_connection,
307
+ query["query"].strip(),
308
+ do_prepare_only=my_uuid,
309
+ attempt_fetch_domain_types=True
310
+ )
283
311
  type_resolution_method = "temp_view"
312
+
284
313
  temp_columns = [row[0] for row in domain_types['rows']]
285
- nullable = [row[4] for row in domain_types['rows']]
286
- temp_types = [row[3] if row[3] is not None else row[2] for row in domain_types['rows']]
287
- columns = {
288
- col: {
289
- "type": temp_types[idx],
290
- "nullable": nullable[idx]
314
+
315
+ # Detect duplicates BEFORE building the dict (dict would overwrite)
316
+ counts = {}
317
+ for c in temp_columns:
318
+ counts[c] = counts.get(c, 0) + 1
319
+
320
+ dupes = [name for name, count in counts.items() if count > 1]
321
+ if dupes:
322
+ dupes.sort()
323
+ dupe_str = ", ".join([f"{name} (x{counts[name]})" for name in dupes])
324
+ exc = "Duplicate output column names are not supported: " + dupe_str
325
+ columns = None
326
+ else:
327
+ nullable = [row[4] for row in domain_types['rows']]
328
+ temp_types = [row[3] if row[3] is not None else row[2] for row in domain_types['rows']]
329
+ columns = {
330
+ col: {
331
+ "type": temp_types[idx],
332
+ "nullable": nullable[idx]
333
+ }
334
+ for col, idx in zip(temp_columns, range(len(temp_columns)))
291
335
  }
292
- for col, idx in zip(temp_columns, range(len(temp_columns)))
293
- }
294
- except Exception as ex:
336
+
337
+ except Exception:
295
338
  pass # This is fine
296
339
 
297
- if columns is None:
340
+ # If temp_view didn't work, fallback to gdesc/psql
341
+ if columns is None and exc is None:
298
342
  try:
299
343
  type_resolution_method = "gdesc"
300
344
  psql = [
@@ -303,11 +347,22 @@ ORDER BY
303
347
  "-d", inputs[KEY__database],
304
348
  "-q", "-X", "--pset", "pager=off", "-f", "-"
305
349
  ]
306
- results = execute_supplied_statement(db_connection, query["query"].strip(), do_prepare_only=my_uuid, psql=psql,
307
- pre_psql="SET SESSION AUTHORIZATION \"" + account_id + "\";")
350
+ results = execute_supplied_statement(
351
+ db_connection,
352
+ query["query"].strip(),
353
+ do_prepare_only=my_uuid,
354
+ psql=psql,
355
+ pre_psql="SET SESSION AUTHORIZATION \"" + account_id + "\";"
356
+ )
357
+
358
+ # parse_gdesc_output now throws if duplicates exist
308
359
  columns = self.parse_gdesc_output(results['rows'][0])
309
- except:
360
+
361
+ except Exception as ex:
362
+ # This catches duplicate column errors and also any parse failures
363
+ exc = str(ex)
310
364
  type_resolution_method = "failed"
365
+ columns = None
311
366
 
312
367
  res.append({
313
368
  "location": query["file"] + ":" + str(query["line_number"]),
@@ -319,7 +374,13 @@ ORDER BY
319
374
  })
320
375
 
321
376
  if inputs.get("sort_cost", True):
322
- return sorted(res, key=lambda x: (x["exception"] if x["exception"] is not None else '', float('-inf') if x["cost"] is None else -x["cost"]))
377
+ return sorted(
378
+ res,
379
+ key=lambda x: (
380
+ x["exception"] if x["exception"] is not None else '',
381
+ float('-inf') if x["cost"] is None else -x["cost"]
382
+ )
383
+ )
323
384
  else:
324
385
  return res
325
386
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jaaql-middleware-python
3
- Version: 4.34.1
3
+ Version: 4.34.3
4
4
  Summary: The jaaql package, allowing for rapid development and deployment of RESTful HTTP applications
5
5
  Home-page: https://github.com/JAAQL/JAAQL-middleware-python
6
6
  Author: Software Quality Measurement and Improvement bv