gaard-api 0.2.12__tar.gz → 0.2.13__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 (78) hide show
  1. {gaard_api-0.2.12/src/gaard_api.egg-info → gaard_api-0.2.13}/PKG-INFO +1 -1
  2. {gaard_api-0.2.12 → gaard_api-0.2.13}/pyproject.toml +1 -1
  3. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/admin/services.py +1 -0
  4. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/admin-web/assets/main.js +13 -12
  5. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/api/v1/admin.py +63 -22
  6. {gaard_api-0.2.12 → gaard_api-0.2.13/src/gaard_api.egg-info}/PKG-INFO +1 -1
  7. {gaard_api-0.2.12 → gaard_api-0.2.13}/tests/test_admin_api.py +44 -11
  8. {gaard_api-0.2.12 → gaard_api-0.2.13}/MANIFEST.in +0 -0
  9. {gaard_api-0.2.12 → gaard_api-0.2.13}/README.md +0 -0
  10. {gaard_api-0.2.12 → gaard_api-0.2.13}/setup.cfg +0 -0
  11. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/__init__.py +0 -0
  12. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/admin/__init__.py +0 -0
  13. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/admin/database.py +0 -0
  14. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/admin/database_initial.sql +0 -0
  15. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/admin/database_legacy_updates.sql +0 -0
  16. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/admin/database_updates.sql +0 -0
  17. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/admin/defaults.py +0 -0
  18. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/admin/migration_runner.py +0 -0
  19. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/admin/models.py +0 -0
  20. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/admin/prompt_runtime.py +0 -0
  21. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/admin/security.py +0 -0
  22. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/admin-web/assets/getgaard.svg +0 -0
  23. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/admin-web/assets/identity.js +0 -0
  24. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/admin-web/assets/styles.css +0 -0
  25. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/admin-web/assets/vendor/gridstack/gridstack-all.js +0 -0
  26. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/admin-web/assets/vendor/gridstack/gridstack.min.css +0 -0
  27. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/admin-web/index.html +0 -0
  28. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/admin-web/package.json +0 -0
  29. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/api/__init__.py +0 -0
  30. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/api/v1/__init__.py +0 -0
  31. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/api/v1/analysis.py +0 -0
  32. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/api/v1/dashboards.py +0 -0
  33. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/api/v1/prompts.py +0 -0
  34. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/api/v1/query.py +0 -0
  35. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/api/v1/schema.py +0 -0
  36. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/api_registry.py +0 -0
  37. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/auth_dependencies.py +0 -0
  38. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/auth_hooks.py +0 -0
  39. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/cli.py +0 -0
  40. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/cli_commands.py +0 -0
  41. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/conversations.py +0 -0
  42. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/core/__init__.py +0 -0
  43. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/core/error_handlers.py +0 -0
  44. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/core/schema_cache.py +0 -0
  45. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/core/settings.py +0 -0
  46. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/example_data/__init__.py +0 -0
  47. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/example_data/medical_poc/__init__.py +0 -0
  48. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/example_data/medical_poc/schema.sql +0 -0
  49. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/example_data/medical_poc/seed.sql +0 -0
  50. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/example_database.py +0 -0
  51. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/extension_services.py +0 -0
  52. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/extensions.py +0 -0
  53. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/license.py +0 -0
  54. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/main.py +0 -0
  55. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/package_updates.py +0 -0
  56. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/py.typed +0 -0
  57. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/query_hooks.py +0 -0
  58. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/server_cli.py +0 -0
  59. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/siem.py +0 -0
  60. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api/tls_http.py +0 -0
  61. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api.egg-info/SOURCES.txt +0 -0
  62. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api.egg-info/dependency_links.txt +0 -0
  63. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api.egg-info/entry_points.txt +0 -0
  64. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api.egg-info/requires.txt +0 -0
  65. {gaard_api-0.2.12 → gaard_api-0.2.13}/src/gaard_api.egg-info/top_level.txt +0 -0
  66. {gaard_api-0.2.12 → gaard_api-0.2.13}/tests/test_analysis_api.py +0 -0
  67. {gaard_api-0.2.12 → gaard_api-0.2.13}/tests/test_api_cli.py +0 -0
  68. {gaard_api-0.2.12 → gaard_api-0.2.13}/tests/test_api_registry.py +0 -0
  69. {gaard_api-0.2.12 → gaard_api-0.2.13}/tests/test_conversation_api.py +0 -0
  70. {gaard_api-0.2.12 → gaard_api-0.2.13}/tests/test_database_migrations.py +0 -0
  71. {gaard_api-0.2.12 → gaard_api-0.2.13}/tests/test_error_handlers.py +0 -0
  72. {gaard_api-0.2.12 → gaard_api-0.2.13}/tests/test_license_api.py +0 -0
  73. {gaard_api-0.2.12 → gaard_api-0.2.13}/tests/test_license_service.py +0 -0
  74. {gaard_api-0.2.12 → gaard_api-0.2.13}/tests/test_prompt_runtime.py +0 -0
  75. {gaard_api-0.2.12 → gaard_api-0.2.13}/tests/test_query_error_messages.py +0 -0
  76. {gaard_api-0.2.12 → gaard_api-0.2.13}/tests/test_server_cli.py +0 -0
  77. {gaard_api-0.2.12 → gaard_api-0.2.13}/tests/test_settings.py +0 -0
  78. {gaard_api-0.2.12 → gaard_api-0.2.13}/tests/test_tls_http.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gaard-api
3
- Version: 0.2.12
3
+ Version: 0.2.13
4
4
  Summary: GAARD backend web services providing admin interface
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "gaard-api"
7
- version = "0.2.12"
7
+ version = "0.2.13"
8
8
  description = "GAARD backend web services providing admin interface"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -2229,6 +2229,7 @@ def build_table_settings(
2229
2229
  tables[table.name] = {
2230
2230
  "selected": bool(existing.get("selected", True)),
2231
2231
  "description": str(existing.get("description", "")),
2232
+ "view_description": str(existing.get("view_description", "")),
2232
2233
  "primary_key_prompt": str(existing.get("primary_key_prompt", "")),
2233
2234
  "foreign_key_prompt": str(existing.get("foreign_key_prompt", "")),
2234
2235
  "join_logic": str(existing.get("join_logic", "")),
@@ -100,7 +100,7 @@ var state = {
100
100
  loadedName: "",
101
101
  loadedSql: "",
102
102
  name: "",
103
- description: "",
103
+ view_description: "",
104
104
  sql: "",
105
105
  error: "",
106
106
  success: "",
@@ -1926,7 +1926,7 @@ function renderDatasourceViewDialog() {
1926
1926
  </div>
1927
1927
  <form id="datasource-view-form" class="form-grid">
1928
1928
  <label>View name<input name="name" value="${escapeHtml(dialog.name || "")}" autocomplete="off" /></label>
1929
- <label>View description<textarea name="description">${escapeHtml(dialog.description || "")}</textarea></label>
1929
+ <label>View description<textarea name="view_description">${escapeHtml(dialog.view_description || "")}</textarea></label>
1930
1930
  <label>SQL<textarea name="sql" class="textarea-small" spellcheck="false">${escapeHtml(dialog.sql || "")}</textarea></label>
1931
1931
  ${busy === "load" ? `<p class="muted"><span class="spinner" aria-hidden="true"></span> Loading view definition.</p>` : ""}
1932
1932
  ${dialog.error ? `<p class="error">${escapeHtml(dialog.error)}</p>` : ""}
@@ -1976,6 +1976,7 @@ function getDatasourceSchemaDraftTables(rawTables, tableSettings) {
1976
1976
  state.datasourceSchemaDraftTables[table.name] = {
1977
1977
  selected: settings.selected !== false,
1978
1978
  description: settings.description || "",
1979
+ view_description: settings.view_description || "",
1979
1980
  primary_key_prompt: settings.primary_key_prompt || "",
1980
1981
  foreign_key_prompt: settings.foreign_key_prompt || "",
1981
1982
  join_logic: settings.join_logic || ""
@@ -3340,7 +3341,7 @@ function defaultDatasourceViewDialog() {
3340
3341
  loadedName: "",
3341
3342
  loadedSql: "",
3342
3343
  name: "",
3343
- description: "",
3344
+ view_description: "",
3344
3345
  sql: "",
3345
3346
  error: "",
3346
3347
  success: "",
@@ -3367,8 +3368,7 @@ async function openEditDatasourceViewDialog(event) {
3367
3368
  const rawTables = state.datasourceSchema?.item?.raw_schema?.tables || [];
3368
3369
  const tableSettings = state.datasourceSchema?.item?.table_settings?.tables || {};
3369
3370
  const draftSettings = getDatasourceSchemaDraftTables(rawTables, tableSettings)[viewName] || {};
3370
- const hasDraftDescription = Object.prototype.hasOwnProperty.call(draftSettings, "description");
3371
- const draftDescription = hasDraftDescription ? draftSettings.description || "" : "";
3371
+ const draftViewDescription = draftSettings.view_description || "";
3372
3372
  state.datasourceViewDialog = {
3373
3373
  ...defaultDatasourceViewDialog(),
3374
3374
  open: true,
@@ -3376,14 +3376,14 @@ async function openEditDatasourceViewDialog(event) {
3376
3376
  originalName: viewName,
3377
3377
  loadedName: viewName,
3378
3378
  name: viewName,
3379
- description: draftDescription,
3379
+ view_description: draftViewDescription,
3380
3380
  busy: "load"
3381
3381
  };
3382
3382
  render();
3383
3383
  try {
3384
3384
  const result = await api(`/api/v1/admin/datasources/${selected.id}/schema/views/${encodeURIComponent(viewName)}`);
3385
3385
  const item = result.item || {};
3386
- const description = hasDraftDescription ? draftDescription : item.description || "";
3386
+ const viewDescription = draftViewDescription || item.view_description || item.description || "";
3387
3387
  state.datasourceViewDialog = {
3388
3388
  ...state.datasourceViewDialog,
3389
3389
  mode: "edit",
@@ -3391,7 +3391,7 @@ async function openEditDatasourceViewDialog(event) {
3391
3391
  loadedName: item.name || viewName,
3392
3392
  loadedSql: item.sql || "",
3393
3393
  name: item.name || viewName,
3394
- description,
3394
+ view_description: viewDescription,
3395
3395
  sql: item.sql || "",
3396
3396
  busy: "",
3397
3397
  error: "",
@@ -3420,14 +3420,14 @@ function readDatasourceViewDialogPayload() {
3420
3420
  const dialog = state.datasourceViewDialog || {};
3421
3421
  return {
3422
3422
  name: String(dialog.name || "").trim(),
3423
- description: String(dialog.description || ""),
3423
+ view_description: String(dialog.view_description || ""),
3424
3424
  sql: String(dialog.sql || "")
3425
3425
  };
3426
3426
  }
3427
3427
  const data = new FormData(form);
3428
3428
  return {
3429
3429
  name: String(data.get("name") || "").trim(),
3430
- description: String(data.get("description") || ""),
3430
+ view_description: String(data.get("view_description") || ""),
3431
3431
  sql: String(data.get("sql") || "")
3432
3432
  };
3433
3433
  }
@@ -3464,7 +3464,7 @@ async function generateDatasourceViewSql() {
3464
3464
  try {
3465
3465
  const result = await api(`/api/v1/admin/datasources/${selected.id}/schema/views/generate-sql`, {
3466
3466
  method: "POST",
3467
- body: JSON.stringify({ name: payload.name, description: payload.description })
3467
+ body: JSON.stringify({ name: payload.name, view_description: payload.view_description })
3468
3468
  });
3469
3469
  state.datasourceViewDialog = {
3470
3470
  ...state.datasourceViewDialog,
@@ -3546,7 +3546,7 @@ async function saveDatasourceView(event) {
3546
3546
  const result = canSaveSettingsOnly
3547
3547
  ? await api(`/api/v1/admin/datasources/${selected.id}/schema/views/${encodeURIComponent(dialog.originalName || payload.name)}`, {
3548
3548
  method: "PUT",
3549
- body: JSON.stringify({ description: payload.description })
3549
+ body: JSON.stringify({ view_description: payload.view_description })
3550
3550
  })
3551
3551
  : dialog.mode === "edit"
3552
3552
  ? await api(`/api/v1/admin/datasources/${selected.id}/schema/views/${encodeURIComponent(dialog.originalName || payload.name)}/execute`, {
@@ -3689,6 +3689,7 @@ async function saveDatasourceSchema(event) {
3689
3689
  tables[table.name] = {
3690
3690
  selected: draft.selected !== false,
3691
3691
  description: draft.description || "",
3692
+ view_description: draft.view_description || "",
3692
3693
  primary_key_prompt: draft.primary_key_prompt || "",
3693
3694
  foreign_key_prompt: draft.foreign_key_prompt || "",
3694
3695
  join_logic: draft.join_logic || ""
@@ -363,22 +363,33 @@ class DatasourceSchemaTableSettingsRequest(BaseModel):
363
363
  class DatasourceViewSqlGenerationRequest(BaseModel):
364
364
  name: str = Field(min_length=1, max_length=128)
365
365
  description: str = Field(default="", max_length=20000)
366
+ view_description: str | None = Field(default=None, max_length=20000)
366
367
 
367
368
 
368
369
  class DatasourceViewExecuteRequest(BaseModel):
369
370
  name: str = Field(min_length=1, max_length=128)
370
371
  description: str = Field(default="", max_length=20000)
372
+ view_description: str | None = Field(default=None, max_length=20000)
371
373
  sql: str = Field(min_length=1, max_length=200000)
372
374
 
373
375
 
374
376
  class DatasourceViewUpdateRequest(BaseModel):
375
377
  name: str = Field(min_length=1, max_length=128)
376
378
  description: str = Field(default="", max_length=20000)
379
+ view_description: str | None = Field(default=None, max_length=20000)
377
380
  sql: str = Field(min_length=1, max_length=200000)
378
381
 
379
382
 
380
383
  class DatasourceViewSettingsRequest(BaseModel):
381
384
  description: str = Field(default="", max_length=20000)
385
+ view_description: str | None = Field(default=None, max_length=20000)
386
+
387
+
388
+ def request_view_description(request: Any) -> str:
389
+ view_description = getattr(request, "view_description", None)
390
+ if view_description is not None:
391
+ return view_description
392
+ return str(getattr(request, "description", ""))
382
393
 
383
394
 
384
395
  class BusinessLogicSuggestionUpdateRequest(BaseModel):
@@ -3248,6 +3259,27 @@ def datasource_view_description_from_cache(
3248
3259
  connector: DatasourceConnector,
3249
3260
  view_name: str,
3250
3261
  actor: str,
3262
+ ) -> str:
3263
+ cache = get_datasource_schema_cache(session, connector.id)
3264
+ if cache is None:
3265
+ cache = introspect_datasource_connector(session, connector, actor)
3266
+ settings = json_loads(cache.table_settings_json)
3267
+ tables = settings.get("tables", {})
3268
+ direct = tables.get(view_name, {})
3269
+ if direct:
3270
+ return str(direct.get("view_description", direct.get("description", "")))
3271
+ lowered = view_name.lower()
3272
+ for name, item in tables.items():
3273
+ if str(name).lower() == lowered:
3274
+ return str(item.get("view_description", item.get("description", "")))
3275
+ return ""
3276
+
3277
+
3278
+ def datasource_view_logic_from_cache(
3279
+ session: Session,
3280
+ connector: DatasourceConnector,
3281
+ view_name: str,
3282
+ actor: str,
3251
3283
  ) -> str:
3252
3284
  cache = get_datasource_schema_cache(session, connector.id)
3253
3285
  if cache is None:
@@ -3282,14 +3314,23 @@ def get_datasource_view_definition(
3282
3314
  finally:
3283
3315
  engine.dispose()
3284
3316
 
3317
+ view_description = datasource_view_description_from_cache(
3318
+ session,
3319
+ connector,
3320
+ existing_name,
3321
+ actor,
3322
+ )
3323
+ datasource_logic = datasource_view_logic_from_cache(
3324
+ session,
3325
+ connector,
3326
+ existing_name,
3327
+ actor,
3328
+ )
3285
3329
  return {
3286
3330
  "name": existing_name,
3287
- "description": datasource_view_description_from_cache(
3288
- session,
3289
- connector,
3290
- existing_name,
3291
- actor,
3292
- ),
3331
+ "description": view_description,
3332
+ "view_description": view_description,
3333
+ "datasource_logic": datasource_logic,
3293
3334
  "sql": view_sql_for_editor(connector, existing_name, definition),
3294
3335
  }
3295
3336
 
@@ -3298,7 +3339,7 @@ def save_datasource_view_settings_to_cache(
3298
3339
  session: Session,
3299
3340
  cache: DatasourceSchemaCache,
3300
3341
  view_name: str,
3301
- description: str,
3342
+ view_description: str,
3302
3343
  actor: str,
3303
3344
  ) -> DatasourceSchemaCache:
3304
3345
  schema = json_loads(cache.schema_json)
@@ -3315,7 +3356,7 @@ def save_datasource_view_settings_to_cache(
3315
3356
  table_settings = settings.setdefault("tables", {})
3316
3357
  existing = table_settings.setdefault(actual_view_name, {})
3317
3358
  existing["selected"] = True
3318
- existing["description"] = description.strip()
3359
+ existing["view_description"] = view_description.strip()
3319
3360
  return update_schema_table_settings(
3320
3361
  session=session,
3321
3362
  cache=cache,
@@ -3328,7 +3369,7 @@ def execute_datasource_view_sql(
3328
3369
  session: Session,
3329
3370
  connector: DatasourceConnector,
3330
3371
  view_name: str,
3331
- description: str,
3372
+ view_description: str,
3332
3373
  sql: str,
3333
3374
  actor: str,
3334
3375
  ) -> DatasourceSchemaCache:
@@ -3352,7 +3393,7 @@ def execute_datasource_view_sql(
3352
3393
  session,
3353
3394
  cache,
3354
3395
  normalized_name,
3355
- description,
3396
+ view_description,
3356
3397
  actor,
3357
3398
  )
3358
3399
 
@@ -3361,7 +3402,7 @@ def save_datasource_view_settings(
3361
3402
  session: Session,
3362
3403
  connector: DatasourceConnector,
3363
3404
  view_name: str,
3364
- description: str,
3405
+ view_description: str,
3365
3406
  actor: str,
3366
3407
  ) -> DatasourceSchemaCache:
3367
3408
  normalized_name = normalize_datasource_view_name(view_name)
@@ -3372,7 +3413,7 @@ def save_datasource_view_settings(
3372
3413
  session,
3373
3414
  cache,
3374
3415
  normalized_name,
3375
- description,
3416
+ view_description,
3376
3417
  actor,
3377
3418
  )
3378
3419
 
@@ -3382,7 +3423,7 @@ def update_datasource_view_sql(
3382
3423
  connector: DatasourceConnector,
3383
3424
  current_view_name: str,
3384
3425
  next_view_name: str,
3385
- description: str,
3426
+ view_description: str,
3386
3427
  sql: str,
3387
3428
  actor: str,
3388
3429
  ) -> DatasourceSchemaCache:
@@ -3416,7 +3457,7 @@ def update_datasource_view_sql(
3416
3457
  session,
3417
3458
  cache,
3418
3459
  next_name,
3419
- description,
3460
+ view_description,
3420
3461
  actor,
3421
3462
  )
3422
3463
 
@@ -3448,11 +3489,11 @@ def generate_datasource_view_sql(
3448
3489
  session: Session,
3449
3490
  connector: DatasourceConnector,
3450
3491
  view_name: str,
3451
- description: str,
3492
+ view_description: str,
3452
3493
  actor: str,
3453
3494
  ) -> str:
3454
3495
  normalized_name = normalize_datasource_view_name(view_name)
3455
- if not description.strip():
3496
+ if not view_description.strip():
3456
3497
  raise ValueError("View description is required to generate SQL.")
3457
3498
 
3458
3499
  cache = get_or_create_datasource_schema_cache(session, connector, actor)
@@ -3464,8 +3505,8 @@ def generate_datasource_view_sql(
3464
3505
  query_request = QueryRequest(
3465
3506
  question=(
3466
3507
  f"Create a SQL SELECT statement for a database view named {normalized_name}. "
3467
- "The SELECT must implement this datasource logic:\n"
3468
- f"{description.strip()}\n\n"
3508
+ "The SELECT must implement this view description:\n"
3509
+ f"{view_description.strip()}\n\n"
3469
3510
  "Return only one SELECT query. Do not create, drop, alter, insert, update or delete data."
3470
3511
  ),
3471
3512
  datasource_id=connector.connector_key,
@@ -3615,7 +3656,7 @@ def generate_datasource_view_sql_preview(
3615
3656
  session=session,
3616
3657
  connector=connector,
3617
3658
  view_name=request.name,
3618
- description=request.description,
3659
+ view_description=request_view_description(request),
3619
3660
  actor=user.username,
3620
3661
  )
3621
3662
  except (
@@ -3656,7 +3697,7 @@ def execute_datasource_view_sql_endpoint(
3656
3697
  session=session,
3657
3698
  connector=connector,
3658
3699
  view_name=request.name,
3659
- description=request.description,
3700
+ view_description=request_view_description(request),
3660
3701
  sql=request.sql,
3661
3702
  actor=user.username,
3662
3703
  )
@@ -3705,7 +3746,7 @@ def update_datasource_view_sql_endpoint(
3705
3746
  connector=connector,
3706
3747
  current_view_name=view_name,
3707
3748
  next_view_name=request.name,
3708
- description=request.description,
3749
+ view_description=request_view_description(request),
3709
3750
  sql=request.sql,
3710
3751
  actor=user.username,
3711
3752
  )
@@ -3756,7 +3797,7 @@ def save_datasource_view_settings_endpoint(
3756
3797
  session=session,
3757
3798
  connector=connector,
3758
3799
  view_name=view_name,
3759
- description=request.description,
3800
+ view_description=request_view_description(request),
3760
3801
  actor=user.username,
3761
3802
  )
3762
3803
  except (SQLAlchemyError, ValueError) as exc:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gaard-api
3
- Version: 0.2.12
3
+ Version: 0.2.13
4
4
  Summary: GAARD backend web services providing admin interface
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -3668,7 +3668,7 @@ def test_datasource_schema_views_can_be_created_saved_and_deleted(
3668
3668
  headers={"Authorization": f"Bearer {token}"},
3669
3669
  json={
3670
3670
  "name": "v_generated_active_patients",
3671
- "description": "Active patients count.",
3671
+ "view_description": "Active patients count.",
3672
3672
  },
3673
3673
  )
3674
3674
 
@@ -3682,7 +3682,7 @@ def test_datasource_schema_views_can_be_created_saved_and_deleted(
3682
3682
  headers={"Authorization": f"Bearer {token}"},
3683
3683
  json={
3684
3684
  "name": "v_active_patients",
3685
- "description": "Active patient names.",
3685
+ "view_description": "Active patient names.",
3686
3686
  "sql": (
3687
3687
  "CREATE VIEW v_active_patients AS "
3688
3688
  "SELECT id, first_name, last_name FROM patients WHERE status = 'active'"
@@ -3697,10 +3697,12 @@ def test_datasource_schema_views_can_be_created_saved_and_deleted(
3697
3697
  for table in created["raw_schema"]["tables"]
3698
3698
  )
3699
3699
  assert (
3700
- created["table_settings"]["tables"]["v_active_patients"]["description"]
3700
+ created["table_settings"]["tables"]["v_active_patients"]["view_description"]
3701
3701
  == "Active patient names."
3702
3702
  )
3703
+ assert created["table_settings"]["tables"]["v_active_patients"]["description"] == ""
3703
3704
  assert "View: v_active_patients" in created["formatted_schema"]
3705
+ assert "Active patient names." not in created["formatted_schema"]
3704
3706
 
3705
3707
  definition_response = admin_client.get(
3706
3708
  f"/api/v1/admin/datasources/{datasource['id']}/schema/views/v_active_patients",
@@ -3710,7 +3712,8 @@ def test_datasource_schema_views_can_be_created_saved_and_deleted(
3710
3712
  assert definition_response.status_code == 200
3711
3713
  definition = definition_response.json()["item"]
3712
3714
  assert definition["name"] == "v_active_patients"
3713
- assert definition["description"] == "Active patient names."
3715
+ assert definition["view_description"] == "Active patient names."
3716
+ assert definition["datasource_logic"] == ""
3714
3717
  assert definition["sql"].startswith("SELECT")
3715
3718
 
3716
3719
  duplicate_response = admin_client.post(
@@ -3718,7 +3721,7 @@ def test_datasource_schema_views_can_be_created_saved_and_deleted(
3718
3721
  headers={"Authorization": f"Bearer {token}"},
3719
3722
  json={
3720
3723
  "name": "v_active_patients",
3721
- "description": "Duplicate.",
3724
+ "view_description": "Duplicate.",
3722
3725
  "sql": "SELECT id FROM patients",
3723
3726
  },
3724
3727
  )
@@ -3731,7 +3734,7 @@ def test_datasource_schema_views_can_be_created_saved_and_deleted(
3731
3734
  headers={"Authorization": f"Bearer {token}"},
3732
3735
  json={
3733
3736
  "name": "v_current_patients",
3734
- "description": "Renamed active patient view.",
3737
+ "view_description": "Renamed active patient view.",
3735
3738
  "sql": "SELECT id, first_name FROM patients WHERE status = 'active'",
3736
3739
  },
3737
3740
  )
@@ -3747,23 +3750,53 @@ def test_datasource_schema_views_can_be_created_saved_and_deleted(
3747
3750
  for table in edited["raw_schema"]["tables"]
3748
3751
  )
3749
3752
  assert (
3750
- edited["table_settings"]["tables"]["v_current_patients"]["description"]
3753
+ edited["table_settings"]["tables"]["v_current_patients"]["view_description"]
3751
3754
  == "Renamed active patient view."
3752
3755
  )
3756
+ assert edited["table_settings"]["tables"]["v_current_patients"]["description"] == ""
3753
3757
 
3754
3758
  save_response = admin_client.put(
3755
3759
  f"/api/v1/admin/datasources/{datasource['id']}/schema/views/v_current_patients",
3756
3760
  headers={"Authorization": f"Bearer {token}"},
3757
- json={"description": "Updated active patient view logic."},
3761
+ json={"view_description": "Updated active patient view definition."},
3758
3762
  )
3759
3763
 
3760
3764
  assert save_response.status_code == 200
3761
3765
  saved = save_response.json()["item"]
3762
3766
  assert (
3763
- saved["table_settings"]["tables"]["v_current_patients"]["description"]
3764
- == "Updated active patient view logic."
3767
+ saved["table_settings"]["tables"]["v_current_patients"]["view_description"]
3768
+ == "Updated active patient view definition."
3765
3769
  )
3766
- assert "Updated active patient view logic." in saved["formatted_schema"]
3770
+ assert saved["table_settings"]["tables"]["v_current_patients"]["description"] == ""
3771
+ assert "Updated active patient view definition." not in saved["formatted_schema"]
3772
+
3773
+ logic_response = admin_client.put(
3774
+ f"/api/v1/admin/datasources/{datasource['id']}/schema/tables",
3775
+ headers={"Authorization": f"Bearer {token}"},
3776
+ json={
3777
+ "tables": {
3778
+ "v_current_patients": {
3779
+ "selected": True,
3780
+ "description": "Use this view for active patient lookup.",
3781
+ "view_description": "Updated active patient view definition.",
3782
+ "join_logic": "",
3783
+ }
3784
+ }
3785
+ },
3786
+ )
3787
+
3788
+ assert logic_response.status_code == 200
3789
+ logic_saved = logic_response.json()["item"]
3790
+ assert (
3791
+ logic_saved["table_settings"]["tables"]["v_current_patients"]["description"]
3792
+ == "Use this view for active patient lookup."
3793
+ )
3794
+ assert (
3795
+ logic_saved["table_settings"]["tables"]["v_current_patients"]["view_description"]
3796
+ == "Updated active patient view definition."
3797
+ )
3798
+ assert "Use this view for active patient lookup." in logic_saved["formatted_schema"]
3799
+ assert "Updated active patient view definition." not in logic_saved["formatted_schema"]
3767
3800
 
3768
3801
  delete_response = admin_client.delete(
3769
3802
  f"/api/v1/admin/datasources/{datasource['id']}/schema/views/v_current_patients",
File without changes
File without changes
File without changes