ApiLogicServer 14.3.20__py3-none-any.whl → 14.4.0__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.
Files changed (107) hide show
  1. api_logic_server_cli/api_logic_server.py +5 -14
  2. api_logic_server_cli/api_logic_server_info.yaml +3 -3
  3. api_logic_server_cli/cli.py +52 -5
  4. api_logic_server_cli/create_from_model/__pycache__/create_db_from_model.cpython-312.pyc +0 -0
  5. api_logic_server_cli/create_from_model/__pycache__/ont_build.cpython-312.pyc +0 -0
  6. api_logic_server_cli/create_from_model/__pycache__/ont_create.cpython-312.pyc +0 -0
  7. api_logic_server_cli/create_from_model/create_db_from_model.py +2 -0
  8. api_logic_server_cli/create_from_model/ont_build.py +19 -14
  9. api_logic_server_cli/create_from_model/ont_create.py +5 -5
  10. api_logic_server_cli/create_from_model/safrs-react-admin-npm-build/static/.DS_Store +0 -0
  11. api_logic_server_cli/database/nw-gold-fix.sql +62 -0
  12. api_logic_server_cli/database/nw-gold.sqlite +0 -0
  13. api_logic_server_cli/fragments/docker-compose.yml +27 -0
  14. api_logic_server_cli/genai/genai.py +43 -11
  15. api_logic_server_cli/genai/genai_graphics.py +379 -0
  16. api_logic_server_cli/genai/genai_logic_builder.py +2 -2
  17. api_logic_server_cli/genai/genai_svcs.py +24 -8
  18. api_logic_server_cli/manager.py +19 -10
  19. api_logic_server_cli/prototypes/.DS_Store +0 -0
  20. api_logic_server_cli/prototypes/base/.DS_Store +0 -0
  21. api_logic_server_cli/prototypes/base/.vscode/launch.json +19 -0
  22. api_logic_server_cli/prototypes/base/api/expose_api_models.py +3 -1
  23. api_logic_server_cli/prototypes/base/api_logic_server_run.py +5 -2
  24. api_logic_server_cli/prototypes/base/config/activate_logicbank.py +1 -0
  25. api_logic_server_cli/prototypes/base/config/config.py +95 -24
  26. api_logic_server_cli/prototypes/base/config/logging.yml +1 -0
  27. api_logic_server_cli/prototypes/base/config/server_setup.py +33 -1
  28. api_logic_server_cli/prototypes/base/database/test_data/readme.md +3 -1
  29. api_logic_server_cli/prototypes/base/devops/docker-standard-image/docker-compose-standard-image.yml +7 -2
  30. api_logic_server_cli/prototypes/base/docs/graphics/readme.md +12 -0
  31. api_logic_server_cli/prototypes/base/docs/training/logic_bank_api.prompt +314 -0
  32. api_logic_server_cli/prototypes/base/docs/training/logic_example.py +41 -0
  33. api_logic_server_cli/prototypes/base/integration/kafka/kafka_producer.py +7 -3
  34. api_logic_server_cli/prototypes/base/integration/system/FlaskKafka.py +5 -1
  35. api_logic_server_cli/prototypes/base/security/authentication_provider/keycloak/auth_provider.py +1 -1
  36. api_logic_server_cli/prototypes/base/security/declare_security.py +4 -0
  37. api_logic_server_cli/prototypes/base/ui/admin/admin_loader.py +3 -1
  38. api_logic_server_cli/prototypes/base/ui/templates/bar_chart.jinja +64 -0
  39. api_logic_server_cli/prototypes/genai_demo/ui/admin/admin.yaml +1 -1
  40. api_logic_server_cli/prototypes/manager/README.md +56 -5
  41. api_logic_server_cli/prototypes/manager/system/genai/.DS_Store +0 -0
  42. api_logic_server_cli/prototypes/manager/system/genai/examples/.DS_Store +0 -0
  43. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/.DS_Store +0 -0
  44. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo.prompt +0 -8
  45. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo.response_example +90 -60
  46. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/docs/002_create_db_models.prompt +4 -4
  47. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/docs/003_create_db_models.response +77 -47
  48. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_informal.prompt +1 -1
  49. api_logic_server_cli/prototypes/manager/system/genai/graphics_templates/dashboard_services.jinja +83 -0
  50. api_logic_server_cli/prototypes/manager/system/genai/graphics_templates/graphics_dashboard_WIP.py +34 -0
  51. api_logic_server_cli/prototypes/manager/system/genai/graphics_templates/graphics_services_api_xxx.py +32 -0
  52. api_logic_server_cli/prototypes/manager/system/genai/graphics_templates/graphics_services_db.jinja +46 -0
  53. api_logic_server_cli/prototypes/manager/system/genai/graphics_templates/graphics_services_db_each_method.jinja +36 -0
  54. api_logic_server_cli/prototypes/manager/system/genai/graphics_templates/html_template.jinja +76 -0
  55. api_logic_server_cli/prototypes/manager/system/genai/graphics_templates/index.html +19 -0
  56. api_logic_server_cli/prototypes/manager/system/genai/graphics_templates/sales_by_region.jinja +63 -0
  57. api_logic_server_cli/prototypes/manager/system/genai/prompt_inserts/graphics.prompt +22 -0
  58. api_logic_server_cli/prototypes/manager/system/genai/prompt_inserts/graphics_request.prompt +5 -0
  59. api_logic_server_cli/prototypes/manager/system/genai/prompt_inserts/response_format.prompt +15 -0
  60. api_logic_server_cli/prototypes/manager/system/genai/prompt_inserts/sqlite_inserts.prompt +2 -0
  61. api_logic_server_cli/prototypes/manager/system/install-ApiLogicServer-dev/install-ApiLogicServer-dev.ps1 +100 -0
  62. api_logic_server_cli/prototypes/manager/system/install-ApiLogicServer-dev/install-ApiLogicServer-dev.sh +116 -0
  63. api_logic_server_cli/prototypes/manager/system/install-ApiLogicServer-dev/readme.md +7 -0
  64. api_logic_server_cli/prototypes/manager/system/style-guide.yaml +2 -2
  65. api_logic_server_cli/prototypes/manager/webgenai/README.md +6 -0
  66. api_logic_server_cli/prototypes/nw/docs/graphics/count_orders_by_category.prompt +1 -0
  67. api_logic_server_cli/prototypes/nw/docs/graphics/order_count_by_month.prompt +1 -0
  68. api_logic_server_cli/prototypes/nw/docs/graphics/request copy.json +892 -0
  69. api_logic_server_cli/prototypes/nw/docs/graphics/request.json +6 -0
  70. api_logic_server_cli/prototypes/nw/docs/graphics/response.json +17 -0
  71. api_logic_server_cli/prototypes/nw/docs/graphics/response.yaml +59 -0
  72. api_logic_server_cli/prototypes/nw/docs/graphics/sales_by_category.prompt +1 -0
  73. api_logic_server_cli/prototypes/nw/ui/admin/home.js +5 -4
  74. api_logic_server_cli/prototypes/nw/ui/app_model_custom.yaml +851 -1082
  75. api_logic_server_cli/prototypes/nw_no_cust/docs/graphics/count_orders_by_category.prompt +1 -0
  76. api_logic_server_cli/prototypes/nw_no_cust/docs/graphics/request copy.json +892 -0
  77. api_logic_server_cli/prototypes/nw_no_cust/docs/graphics/request.json +6 -0
  78. api_logic_server_cli/prototypes/nw_no_cust/docs/graphics/response.json +17 -0
  79. api_logic_server_cli/prototypes/nw_no_cust/docs/graphics/response.yaml +59 -0
  80. api_logic_server_cli/prototypes/nw_no_cust/docs/graphics/sales_by_category.prompt +1 -0
  81. api_logic_server_cli/prototypes/nw_no_cust/docs/graphics/sales_by_employee.prompt +1 -0
  82. api_logic_server_cli/prototypes/nw_no_cust/integration/mcp/1_langchain_loader.py +19 -0
  83. api_logic_server_cli/prototypes/nw_no_cust/integration/mcp/2_gpt_mcp_prompt.txt +19 -0
  84. api_logic_server_cli/prototypes/nw_no_cust/integration/mcp/3_executor_test_agent.py +38 -0
  85. api_logic_server_cli/prototypes/nw_no_cust/integration/mcp/README.md +17 -0
  86. api_logic_server_cli/prototypes/nw_no_cust/integration/mcp/resources/curl.txt +4 -0
  87. api_logic_server_cli/prototypes/nw_no_cust/integration/mcp/resources/nw_swagger_3.yaml +16660 -0
  88. api_logic_server_cli/prototypes/nw_no_cust/integration/mcp/run_executor.py +23 -0
  89. api_logic_server_cli/prototypes/ont_app/ontimize_seed/nginx/nginx.conf +2 -2
  90. api_logic_server_cli/prototypes/ont_app/ontimize_seed/package.json +6 -6
  91. api_logic_server_cli/prototypes/ont_app/ontimize_seed/src/app/app.config.ts +2 -1
  92. api_logic_server_cli/prototypes/ont_app/ontimize_seed/src/environments/environment.prod.ts +5 -5
  93. api_logic_server_cli/prototypes/ont_app/ontimize_seed/src/environments/environment.ts +5 -5
  94. api_logic_server_cli/prototypes/ont_app/templates/app_config.jinja +1 -1
  95. api_logic_server_cli/prototypes/ont_app/templates/detail_template.html +1 -1
  96. api_logic_server_cli/prototypes/ont_app/templates/new_template.html +16 -16
  97. apilogicserver-14.4.0.dist-info/METADATA +76 -0
  98. {apilogicserver-14.3.20.dist-info → apilogicserver-14.4.0.dist-info}/RECORD +102 -59
  99. {apilogicserver-14.3.20.dist-info → apilogicserver-14.4.0.dist-info}/WHEEL +1 -1
  100. api_logic_server_cli/prototypes/manager/system/genai/prompt_inserts/zsqlite_inserts_iterations.prompt +0 -29
  101. api_logic_server_cli/prototypes/manager/webgenai/docker-compose-webg.yml +0 -33
  102. api_logic_server_cli/prototypes/manager/webgenai/webg_config/license.json +0 -6
  103. api_logic_server_cli/prototypes/manager/webgenai/webg_config/web_genai.txt +0 -13
  104. apilogicserver-14.3.20.dist-info/METADATA +0 -167
  105. {apilogicserver-14.3.20.dist-info → apilogicserver-14.4.0.dist-info}/entry_points.txt +0 -0
  106. {apilogicserver-14.3.20.dist-info → apilogicserver-14.4.0.dist-info}/licenses/LICENSE +0 -0
  107. {apilogicserver-14.3.20.dist-info → apilogicserver-14.4.0.dist-info}/top_level.txt +0 -0
@@ -44,8 +44,12 @@ def kafka_producer():
44
44
  if "client.id" not in conf:
45
45
  conf["client.id"] = socket.gethostname()
46
46
  # conf = {'bootstrap.servers': 'localhost:9092', 'client.id': socket.gethostname()}
47
- producer = Producer(conf)
48
- logger.debug(f'\nKafka producer connected')
47
+ try:
48
+ producer = Producer(conf)
49
+ logger.debug(f'\nKafka producer connected')
50
+ except Exception as ke:
51
+ logger.debug(f'Kafka producer error: {ke}')
52
+ producer = None
49
53
 
50
54
  from sqlalchemy.inspection import inspect
51
55
 
@@ -64,7 +68,7 @@ def get_primary_key(logic_row: LogicRow):
64
68
 
65
69
 
66
70
  def send_kafka_message(kafka_topic: str, kafka_key: str = None, msg: str="", json_root_name: str = "",
67
- logic_row: LogicRow = None, row_dict_mapper: RowDictMapper = None, payload: dict = None):
71
+ logic_row: LogicRow = None, row_dict_mapper: RowDictMapper = None, payload: dict = None):
68
72
  """ Send Kafka message regarding logic_row, mapped by row_dict_mapper
69
73
 
70
74
  * Typically called from declare_logic event
@@ -64,7 +64,11 @@ class FlaskKafka():
64
64
  logger.info(f" - FlaskKafka._start: begin polling (v {__version__}), with \n -- conf: {self.conf} \n -- topics: {topics}")
65
65
  consumer = Consumer(self.conf)
66
66
  consumer.subscribe(topics=list(topics))
67
- while True:
67
+ while True and len(topics) > 0:
68
+ if self.interrupt_event.is_set():
69
+ logger.info("Kafka thread interrupted")
70
+ break
71
+
68
72
  msg = consumer.poll(1.0)
69
73
  logger.debug(f' - KafkaConnect._start - consuming consumer.poll(1.0): {msg}')
70
74
  if msg is None:
@@ -78,7 +78,7 @@ class Authentication_Provider(Abstract_Authentication_Provider):
78
78
  from flask import jsonify, request
79
79
  from config.config import Args # circular import error if at top
80
80
 
81
- jwks_uri = Args.instance.keycloak_base + '/protocol/openid-connect/certs'
81
+ jwks_uri = Args.instance.keycloak_base_url + '/protocol/openid-connect/certs'
82
82
  for i in range(100):
83
83
  # we retry a couple of times in case there are connection problems
84
84
  try:
@@ -34,6 +34,8 @@ class Roles():
34
34
  admin = "CS_ADMIN"
35
35
  public="public" # p1/p (no roles, but gets public)
36
36
  sa="sa"
37
+ default_roles_kcals = "default-roles-kcals"
38
+ uma_authorization = "uma_authorization"
37
39
 
38
40
  DefaultRolePermission(to_role=Roles.sa, can_read=True, can_update=True, can_insert=True, can_delete=True)
39
41
  DefaultRolePermission(to_role=Roles.tenant, can_read=True, can_delete=True)
@@ -43,3 +45,5 @@ DefaultRolePermission(to_role=Roles.teller, can_read=True, can_insert=True,can_u
43
45
  DefaultRolePermission(to_role=Roles.customer, can_read=True, can_insert=True,can_update=True, can_delete=False)
44
46
  DefaultRolePermission(to_role=Roles.read_only, can_read=True, can_insert=False,can_update=False, can_delete=False)
45
47
  DefaultRolePermission(to_role=Roles.public, can_read=True, can_insert=False,can_update=False, can_delete=False)
48
+ DefaultRolePermission(to_role=Roles.default_roles_kcals, can_read=True, can_insert=True,can_update=True, can_delete=False)
49
+ DefaultRolePermission(to_role=Roles.uma_authorization, can_read=True, can_insert=True,can_update=True, can_delete=False)
@@ -140,7 +140,7 @@ def admin_events(flask_app: Flask, args: Args, validation_error: ValidationError
140
140
  if "keycloak" in provider_name:
141
141
  s = (f'\n'
142
142
  f' keycloak:\n'
143
- f' url: {args.keycloak_base_url}\n'
143
+ f' url: {args.keycloak_base}\n'
144
144
  f' realm: {args.keycloak_realm}\n'
145
145
  f' clientId: {args.keycloak_client_id}\n'
146
146
  )
@@ -148,6 +148,8 @@ def admin_events(flask_app: Flask, args: Args, validation_error: ValidationError
148
148
  elif "sql" in provider_name:
149
149
  sql_auth_config = f'\n endpoint: {args.http_scheme}://{args.swagger_host}:{args.swagger_port}/{args.api_prefix[1:]}/auth/login\n'
150
150
  content = content.replace("'{system-default}'", sql_auth_config)
151
+ elif getattr(Config.SECURITY_PROVIDER, 'auth_config', None):
152
+ content = content.replace("'{system-default}'", Config.SECURITY_PROVIDER.auth_config)
151
153
  else:
152
154
  sys.exit(f"ERROR[admin_loader]: unknown security type: {Config.SECURITY_PROVIDER}")
153
155
 
@@ -0,0 +1,64 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Sales by Region</title>
7
+ <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
8
+ <style>
9
+ body {
10
+ margin: 0;
11
+ padding: 0;
12
+ display: flex;
13
+ overflow: hidden;
14
+ justify-content: center;
15
+ align-items: center;
16
+ height: 100%;
17
+ box-sizing: border-box;
18
+ }
19
+ canvas {
20
+ display: block;
21
+ }
22
+ </style>
23
+ </head>
24
+ <body>
25
+ <canvas id="salesChart" width="200" height="200"></canvas>
26
+ <script>
27
+ const labels = [];
28
+ const data = [];
29
+ result = {{ result | tojson }};
30
+ console.log(result);
31
+ const type = result.chart_type;
32
+ const title = result.title;
33
+ const columns = result.columns;
34
+ console.log(JSON.stringify(result));
35
+ result.results.forEach(item => {
36
+ labels.push(item[columns[0]]);
37
+ data.push(parseFloat(item[columns[1]]));
38
+ });
39
+ const ctx = document.getElementById('salesChart').getContext('2d');
40
+ const salesChart = new Chart(ctx, {
41
+ type: type,
42
+ data: {
43
+ labels: labels,
44
+ datasets: [{
45
+ label: title,
46
+ data: data,
47
+ backgroundColor: {{ color | tojson }},
48
+ borderColor: 'rgba(75, 192, 192, 1)',
49
+ borderWidth: 1
50
+ }]
51
+ },
52
+ options: {
53
+ responsive: true,
54
+ maintainAspectRatio: false,
55
+ scales: {
56
+ y: {
57
+ beginAtZero: true
58
+ }
59
+ }
60
+ }
61
+ });
62
+ </script>
63
+ </body>
64
+ </html>
@@ -135,7 +135,7 @@ settings:
135
135
  new_mode: dialog
136
136
  pick_style: list
137
137
  row_height: small,
138
- serviceType: OntimizeEE
138
+ serviceType: JSONAPI
139
139
  startSessionPath: /auth/login
140
140
  style: light
141
141
  thousand_separator: ','
@@ -98,7 +98,7 @@ Then, try your own databases [(db-url examples here)](https://apilogicserver.git
98
98
 
99
99
  <br>You can do this with or without signup:
100
100
 
101
- 1. If you have signed up, this will create and open a project called `genai_demo` from `genai_demo.prompt` (available in left Explorer pane):
101
+ 1. If you have signed up (see *To obtain a ChatGPT API Key*, below), this will create and open a project called `genai_demo` from `genai_demo.prompt` (available in left Explorer pane):
102
102
 
103
103
  ```bash
104
104
  als genai --using=system/genai/examples/genai_demo/genai_demo.prompt --project-name=genai_demo
@@ -122,6 +122,20 @@ Verify it's operating properly:
122
122
 
123
123
  </br>
124
124
 
125
+
126
+ <details markdown>
127
+
128
+ <summary> To obtain a ChatGPT API Key</summary>
129
+
130
+ <br>GenAI-Logic uses OpenAI, which requires an Open API Key:
131
+
132
+ 1. Obtain one from [here](https://platform.openai.com/account/api-keys) or [here](https://platform.openai.com/api-keys)
133
+ 2. Authorize payments [here](https://platform.openai.com/settings/organization/billing/overview)
134
+
135
+ </details>
136
+
137
+ </br>
138
+
125
139
  <details markdown>
126
140
 
127
141
  <summary> What Just Happened? &nbsp;&nbsp;&nbsp;Next Steps...</summary>
@@ -151,20 +165,28 @@ Verify it's operating properly:
151
165
 
152
166
  <summary> You can iterate the logic and data model</summary>
153
167
 
154
- <br>Logic iterations are particuarly useful. For example, here we take the basic check-credit logic, and add:
168
+ <br>The approach for an iteration is to create a new project from an existing one:
169
+
170
+ 1. add another prompt to an existing projects `docs` directory, specifying your changes
171
+ 2. use `als genai`, specifying
172
+ * `--using` existing projects `docs` directory, and
173
+ * `--project-name` as the output project
174
+
175
+ **Logic iterations** are particuarly useful. For example, here we take the basic check-credit logic, and add:
155
176
 
156
177
  > Provide a 10% discount when buying more than 10 carbon neutral products.<br><br>The Item carbon neutral is copied from the Product carbon neutral
157
178
 
158
- Explore [genai_demo_iteration_discount](system/genai/examples/genai_demo/genai_demo_iteration_discount). This will add carbon_neutral to the data model, and update the logic to provide the discount:
179
+ Explore [genai_demo_iteration_discount](system/genai/examples/genai_demo/genai_demo_iteration_discount). It's an iteration of basic_demo (see system/genai/examples/genai_demo/genai_demo_iteration_discount/002_create_db_models.prompt). This will add carbon_neutral to the data model, and update the logic to provide the discount:
159
180
 
160
181
  ```bash title='Iterate Business Logic'
161
182
  # Iterate with data model and logic
162
- als genai --project-name='genai_demo_with_logic' --using=system/genai/examples/genai_demo/genai_demo_iteration
183
+ als genai --project-name='genai_demo_with_discount' --using=system/genai/examples/genai_demo/genai_demo_iteration_discount
163
184
  # open Docs/db.dbml
164
185
  ```
186
+
165
187
  <br>
166
188
 
167
- You can add new columns/tables, while keeping the prior model intact:
189
+ You can perform **model iterations:** add new columns/tables, while keeping the prior model intact. First, we create a project with no logic, perhaps just to see the screens (this step is optional, provided just to illustrate that iterations create new projects from existing ones):
168
190
 
169
191
  ```bash title='Iterate Without Logic'
170
192
  # Step 1 - create without logic
@@ -172,6 +194,8 @@ als genai --project-name='genai_demo_no_logic' --using=system/genai/examples/gen
172
194
  # open Docs/db.dbml
173
195
  ```
174
196
 
197
+ Then, we would create another prompt in the docs directory with our model changes. We've already created these for you in `system/genai/examples/genai_demo/genai_demo_iteration` - we use that to alter the data model (see `system/genai/examples/genai_demo/genai_demo_iteration/004_iteration_renames_logic.prompt`):
198
+
175
199
  ```bash title='Iterate With Logic'
176
200
  # Iterate with data model and logic
177
201
  als genai --project-name='genai_demo_with_logic' --using=system/genai/examples/genai_demo/genai_demo_iteration
@@ -488,6 +512,18 @@ als create --project-name=sample_ai --from-model=sample_ai.py --db-url=sqlite
488
512
 
489
513
  4. This will create your database, create an API Logic Project from it, and launch your IDE.
490
514
 
515
+ 5. Create business logic
516
+
517
+ * You can create logic with either your IDE (and code completion), or Natural Language
518
+ * To use Natural Language:
519
+
520
+ 1. Use the CoPilot chat,
521
+ 2. Paste the logic above
522
+ 3. Copy it to `logic/declare_logic.py` after `discover_logic()`
523
+
524
+ * Alert: Table and Column Names may require correction to conform to the model
525
+ * Alert: you may to apply [defaulting](https://apilogicserver.github.io/Docs/Logic-Use/#insert-defaulting), and initialize derived attributes in your database
526
+
491
527
  </details>
492
528
  </br>
493
529
 
@@ -544,6 +580,21 @@ ApiLogicServer create --project-name=samples/nw_sample_nocust --db-url=nw
544
580
 
545
581
  &nbsp;
546
582
 
583
+ ## Explore WebGenAI
584
+
585
+ In addition to the CLI examples above, you can use [WebGenAI](https://apilogicserver.github.io/Docs/WebGenAI/) - a web interface for creating projects from prompts. You can install WebGenAI on a server, so that created projects are easy to review with colleagues.
586
+
587
+ To try WebGenAI:
588
+
589
+ ```bash
590
+ cd webgenai
591
+ docker compose up
592
+ ```
593
+
594
+ You will be directed to the registration process. You will also require a ChatGPT API Key as described above.
595
+
596
+ &nbsp;
597
+
547
598
  &nbsp;
548
599
 
549
600
  ## Appendix: Quick Basic Demo
@@ -2,8 +2,6 @@ Create a system with customers, orders, items and products.
2
2
 
3
3
  Include a notes field for orders.
4
4
 
5
- Use LogicBank to enforce business logic.
6
-
7
5
  Use case: Check Credit
8
6
  1. The Customer's balance is less than the credit limit
9
7
  2. The Customer's balance is the sum of the Order amount_total where date_shipped is null
@@ -13,9 +11,3 @@ Use case: Check Credit
13
11
 
14
12
  Use case: App Integration
15
13
  1. Send the Order to Kafka topic 'order_shipping' if the date_shipped is not None.
16
-
17
- Ensure each customer and product has a unique name.
18
-
19
- Ensure each Item quantity is not null.
20
-
21
- Ensure each order has a valid customer_id that exists in the Customer table.
@@ -2,140 +2,170 @@
2
2
  "models": [
3
3
  {
4
4
  "classname": "Customer",
5
- "code": "class Customer(Base):\n __tablename__ = 'customer'\n id = Column(Integer, primary_key=True, autoincrement=True)\n name = Column(String, unique=True)\n balance = Column(DECIMAL)\n credit_limit = Column(DECIMAL)",
6
- "description": "Represents a customer in the system with unique name, balance, and credit limit attributes.",
5
+ "code": "class Customer(Base):\n __tablename__ = 'customer'\n\n id = Column(Integer, primary_key=True, autoincrement=True)\n name = Column(String, unique=True)\n balance = Column(DECIMAL)\n credit_limit = Column(DECIMAL)",
6
+ "description": "Defines the Customer entity with a unique name, balance, and credit limit.",
7
7
  "name": "Customer"
8
8
  },
9
9
  {
10
10
  "classname": "Order",
11
- "code": "class Order(Base):\n __tablename__ = 'order'\n id = Column(Integer, primary_key=True, autoincrement=True)\n customer_id = Column(Integer, ForeignKey('customer.id'))\n date_shipped = Column(Date)\n amount_total = Column(DECIMAL)\n notes = Column(String)",
12
- "description": "Represents an order made by a customer, including a notes field.",
11
+ "code": "class Order(Base):\n __tablename__ = 'order'\n\n id = Column(Integer, primary_key=True, autoincrement=True)\n notes = Column(String)\n customer_id = Column(Integer, ForeignKey('customer.id'), nullable=False)\n date_shipped = Column(Date)\n amount_total = Column(DECIMAL)",
12
+ "description": "Defines the Order entity which belongs to a customer. Includes notes and amount total.",
13
13
  "name": "Order"
14
14
  },
15
15
  {
16
16
  "classname": "Item",
17
- "code": "class Item(Base):\n __tablename__ = 'item'\n id = Column(Integer, primary_key=True, autoincrement=True)\n order_id = Column(Integer, ForeignKey('order.id'))\n product_id = Column(Integer, ForeignKey('product.id'))\n quantity = Column(Integer, nullable=False)\n unit_price = Column(DECIMAL)\n amount = Column(DECIMAL)",
18
- "description": "Represents an item in an order, including quantity and pricing details.",
17
+ "code": "class Item(Base):\n __tablename__ = 'item'\n\n id = Column(Integer, primary_key=True, autoincrement=True)\n order_id = Column(Integer, ForeignKey('order.id'))\n product_id = Column(Integer, ForeignKey('product.id'), nullable=False)\n quantity = Column(Integer, nullable=False)\n amount = Column(DECIMAL)\n unit_price = Column(DECIMAL)",
18
+ "description": "Defines the Item entity with quantity, amounts, and unit price details.",
19
19
  "name": "Item"
20
20
  },
21
21
  {
22
22
  "classname": "Product",
23
- "code": "class Product(Base):\n __tablename__ = 'product'\n id = Column(Integer, primary_key=True, autoincrement=True)\n name = Column(String)\n unit_price = Column(DECIMAL)",
24
- "description": "Represents a product available in the system with a unit price.",
23
+ "code": "class Product(Base):\n __tablename__ = 'product'\n\n id = Column(Integer, primary_key=True, autoincrement=True)\n name = Column(String, unique=True)\n unit_price = Column(DECIMAL)",
24
+ "description": "Defines the Product entity with a unique name and unit price.",
25
25
  "name": "Product"
26
26
  }
27
27
  ],
28
28
  "rules": [
29
29
  {
30
30
  "name": "Customer Balance Constraint",
31
- "description": "Ensures the customer's balance is aligned with the credit limit.",
32
- "use_case": "Customer.balance <= credit_limit",
31
+ "description": "Ensure the customer's balance is less than their credit limit.",
32
+ "use_case": "Check Credit",
33
33
  "entity": "Customer",
34
- "code": "Rule.constraint(validate=Customer,\n as_condition=lambda row: row.balance <= row.credit_limit,\n error_msg='Customer balance ({row.balance}) exceeds credit limit ({row.credit_limit})')"
34
+ "code": "Rule.constraint(validate=Customer, as_condition=lambda row: row.balance <= row.credit_limit, error_msg=\"Customer balance ({row.balance}) exceeds credit limit ({row.credit_limit})\")"
35
35
  },
36
36
  {
37
37
  "name": "Customer Balance Derivation",
38
- "description": "Calculates the customer's balance as the sum of orders' amount_total where date_shipped is null.",
39
- "use_case": "Customer.balance = Sum(Order.amount_total where date_shipped is null)",
38
+ "description": "Derive the customer's balance as the sum of order totals where not yet shipped.",
39
+ "use_case": "Check Credit",
40
40
  "entity": "Customer",
41
41
  "code": "Rule.sum(derive=Customer.balance, as_sum_of=Order.amount_total, where=lambda row: row.date_shipped is None)"
42
42
  },
43
43
  {
44
- "name": "Order Amount Total Derivation",
45
- "description": "Calculates order's amount_total as the sum of item amounts.",
46
- "use_case": "Order.amount_total = Sum(Item.amount)",
44
+ "name": "Order Total Derivation",
45
+ "description": "Derive the order's total amount from the sum of item amounts.",
46
+ "use_case": "Check Credit",
47
47
  "entity": "Order",
48
48
  "code": "Rule.sum(derive=Order.amount_total, as_sum_of=Item.amount)"
49
49
  },
50
50
  {
51
- "name": "Item Amount Derivation",
52
- "description": "Calculates item amount as quantity multiplied by unit price.",
53
- "use_case": "Item.amount = quantity * unit_price",
51
+ "name": "Item Amount Calculation",
52
+ "description": "Calculate item amount based on quantity and unit price.",
53
+ "use_case": "Check Credit",
54
54
  "entity": "Item",
55
55
  "code": "Rule.formula(derive=Item.amount, as_expression=lambda row: row.quantity * row.unit_price)"
56
56
  },
57
57
  {
58
- "name": "Copy Item Unit Price",
59
- "description": "Copies the product's unit price to the item.",
60
- "use_case": "Store the Item.unit_price as a copy from Product.unit_price",
58
+ "name": "Item Unit Price Copy",
59
+ "description": "Copy unit price from product to item.",
60
+ "use_case": "Check Credit",
61
61
  "entity": "Item",
62
62
  "code": "Rule.copy(derive=Item.unit_price, from_parent=Product.unit_price)"
63
63
  },
64
64
  {
65
- "name": "Order Kafka Integration",
66
- "description": "Sends the order to Kafka topic 'order_shipping' if the date shipped is not None.",
65
+ "name": "Order Kafka Notification",
66
+ "description": "Send order details to Kafka if order is shipped.",
67
67
  "use_case": "App Integration",
68
68
  "entity": "Order",
69
- "code": "Rule.after_flush_row_event(on_class=Order, calling=kafka_producer.send_row_to_kafka, if_condition=lambda row: row.date_shipped is not None, with_args={\"topic\": \"order_shipping\"})"
69
+ "code": "Rule.after_flush_row_event(on_class=Order, calling=kafka_producer.send_row_to_kafka, if_condition=lambda row: row.date_shipped is not None, with_args={'topic': 'order_shipping'})"
70
70
  }
71
71
  ],
72
- "test_data": "Insert test data into the tables with values compatible with the derived logic.",
72
+ "graphics": [
73
+ {
74
+ "sqlalchemy_query": "session.query(Product.name, func.sum(Item.amount).label('TotalSales')).join(Item, Product.id == Item.product_id).filter(Order.date_shipped.isnot(None)).group_by(Product.name).order_by(func.sum(Item.amount).desc())",
75
+ "sql_query": "SELECT Product.name, SUM(Item.amount) AS TotalSales FROM Product JOIN Item ON Product.id = Item.product_id JOIN Order ON Item.order_id = Order.id WHERE Order.date_shipped IS NOT NULL GROUP BY Product.name ORDER BY TotalSales DESC",
76
+ "classes_used": "Product, Item, Order",
77
+ "class_x_axis": "Product",
78
+ "name": "sales_by_product",
79
+ "prompt": "Graph Sales by Product",
80
+ "title": "Sales by Product",
81
+ "xAxis": "Product",
82
+ "yAxis": "Total Sales",
83
+ "dashboard": true,
84
+ "graph_type": "Bar",
85
+ "html_code": "var data = result.result; var categories = data.map(item => item[0]); var totals = data.map(item => item[1]); var ctx = document.getElementById('salesByProductChart').getContext('2d'); new Chart(ctx, {type: 'bar', data: {labels: categories, datasets: [{label: 'Sales by Product', data: totals}]}});"
86
+ },
87
+ {
88
+ "sqlalchemy_query": "session.query(Customer.name, func.sum(Order.amount_total).label('TotalCustomerSales')).join(Order, Customer.id == Order.customer_id).filter(Order.date_shipped.isnot(None)).group_by(Customer.name).order_by(func.sum(Order.amount_total).desc())",
89
+ "sql_query": "SELECT Customer.name, SUM(Order.amount_total) AS TotalCustomerSales FROM Customer JOIN Order ON Customer.id = Order.customer_id WHERE Order.date_shipped IS NOT NULL GROUP BY Customer.name ORDER BY TotalCustomerSales DESC",
90
+ "classes_used": "Customer, Order",
91
+ "class_x_axis": "Customer",
92
+ "name": "sales_by_customer",
93
+ "prompt": "Graph Sales by Customer",
94
+ "title": "Sales by Customer",
95
+ "xAxis": "Customer",
96
+ "yAxis": "Total Sales",
97
+ "dashboard": true,
98
+ "graph_type": "Bar",
99
+ "html_code": "var data = result.result; var customers = data.map(item => item[0]); var sales = data.map(item => item[1]); var ctx = document.getElementById('salesByCustomerChart').getContext('2d'); new Chart(ctx, {type: 'bar', data: {labels: customers, datasets: [{label: 'Sales by Customer', data: sales}]}});"
100
+ }
101
+ ],
102
+ "test_data": "This is the test data generated for Customers, Orders, Items, and Products in the new system.",
73
103
  "test_data_rows": [
74
104
  {
75
- "test_data_row_variable": "test_customer_1",
76
- "code": "test_customer_1 = Customer(name='Customer 1', balance=150, credit_limit=1000)"
105
+ "test_data_row_variable": "customer1",
106
+ "code": "customer1 = Customer(name=\"Alice\", balance=90.00, credit_limit=5000.00)"
77
107
  },
78
108
  {
79
- "test_data_row_variable": "test_customer_2",
80
- "code": "test_customer_2 = Customer(name='Customer 2', balance=275, credit_limit=750)"
109
+ "test_data_row_variable": "customer2",
110
+ "code": "customer2 = Customer(name=\"Bob\", balance=0.00, credit_limit=3000.00)"
81
111
  },
82
112
  {
83
- "test_data_row_variable": "test_customer_3",
84
- "code": "test_customer_3 = Customer(name='Customer 3', balance=150, credit_limit=1500)"
113
+ "test_data_row_variable": "customer3",
114
+ "code": "customer3 = Customer(name=\"Charlie\", balance=220.00, credit_limit=2000.00)"
85
115
  },
86
116
  {
87
- "test_data_row_variable": "test_customer_4",
88
- "code": "test_customer_4 = Customer(name='Customer 4', balance=0, credit_limit=1200)"
117
+ "test_data_row_variable": "customer4",
118
+ "code": "customer4 = Customer(name=\"Diana\", balance=0.00, credit_limit=1000.00)"
89
119
  },
90
120
  {
91
- "test_data_row_variable": "test_order_1",
92
- "code": "test_order_1 = Order(customer_id=1, notes='Order 1 notes', amount_total=150)"
121
+ "test_data_row_variable": "product1",
122
+ "code": "product1 = Product(name=\"Gadget\", unit_price=150.00)"
93
123
  },
94
124
  {
95
- "test_data_row_variable": "test_order_2",
96
- "code": "test_order_2 = Order(customer_id=2, notes='Order 2 notes', amount_total=225)"
125
+ "test_data_row_variable": "product2",
126
+ "code": "product2 = Product(name=\"Widget\", unit_price=90.00)"
97
127
  },
98
128
  {
99
- "test_data_row_variable": "test_order_3",
100
- "code": "test_order_3 = Order(customer_id=2, notes='Order 3 notes', amount_total=50)"
129
+ "test_data_row_variable": "product3",
130
+ "code": "product3 = Product(name=\"Thingamajig\", unit_price=75.00)"
101
131
  },
102
132
  {
103
- "test_data_row_variable": "test_order_4",
104
- "code": "test_order_4 = Order(customer_id=3, notes='Order 4 notes', amount_total=150)"
133
+ "test_data_row_variable": "product4",
134
+ "code": "product4 = Product(name=\"Doodad\", unit_price=110.00)"
105
135
  },
106
136
  {
107
- "test_data_row_variable": "test_item_1",
108
- "code": "test_item_1 = Item(order_id=1, product_id=1, quantity=3, unit_price=50, amount=150)"
137
+ "test_data_row_variable": "order1",
138
+ "code": "order1 = Order(notes=\"First Order\", customer_id=2, date_shipped=date(2023, 3, 22), amount_total=300.00)"
109
139
  },
110
140
  {
111
- "test_data_row_variable": "test_item_2",
112
- "code": "test_item_2 = Item(order_id=2, product_id=2, quantity=2, unit_price=25, amount=50)"
141
+ "test_data_row_variable": "order2",
142
+ "code": "order2 = Order(notes=\"Second Order\", customer_id=1, date_shipped=None, amount_total=90.00)"
113
143
  },
114
144
  {
115
- "test_data_row_variable": "test_item_3",
116
- "code": "test_item_3 = Item(order_id=3, product_id=3, quantity=3, unit_price=75, amount=225)"
145
+ "test_data_row_variable": "order3",
146
+ "code": "order3 = Order(notes=\"Pending Shipment\", customer_id=3, date_shipped=None, amount_total=220.00)"
117
147
  },
118
148
  {
119
- "test_data_row_variable": "test_item_4",
120
- "code": "test_item_4 = Item(order_id=4, product_id=1, quantity=3, unit_price=50, amount=150)"
149
+ "test_data_row_variable": "order4",
150
+ "code": "order4 = Order(notes=\"Urgent Order\", customer_id=4, date_shipped=date(2023, 7, 15), amount_total=220.00)"
121
151
  },
122
152
  {
123
- "test_data_row_variable": "test_product_1",
124
- "code": "test_product_1 = Product(name='Product 1', unit_price=50)"
153
+ "test_data_row_variable": "item1",
154
+ "code": "item1 = Item(order_id=1, product_id=1, quantity=2, amount=300.00, unit_price=150.00)"
125
155
  },
126
156
  {
127
- "test_data_row_variable": "test_product_2",
128
- "code": "test_product_2 = Product(name='Product 2', unit_price=25)"
157
+ "test_data_row_variable": "item2",
158
+ "code": "item2 = Item(order_id=2, product_id=2, quantity=1, amount=90.00, unit_price=90.00)"
129
159
  },
130
160
  {
131
- "test_data_row_variable": "test_product_3",
132
- "code": "test_product_3 = Product(name='Product 3', unit_price=75)"
161
+ "test_data_row_variable": "item3",
162
+ "code": "item3 = Item(order_id=3, product_id=4, quantity=2, amount=220.00, unit_price=110.00)"
133
163
  },
134
164
  {
135
- "test_data_row_variable": "test_product_4",
136
- "code": "test_product_4 = Product(name='Product 4', unit_price=100)"
165
+ "test_data_row_variable": "item4",
166
+ "code": "item4 = Item(order_id=4, product_id=3, quantity=4, amount=300.00, unit_price=75.00)"
137
167
  }
138
168
  ],
139
- "test_data_sqlite": "INSERT INTO customers (name, balance, credit_limit) VALUES ('Customer 1', 300, 1000);\nINSERT INTO customers (name, balance, credit_limit) VALUES ('Customer 2', 500, 750);\nINSERT INTO customers (name, balance, credit_limit) VALUES ('Customer 3', 0, 1500);\nINSERT INTO customers (name, balance, credit_limit) VALUES ('Customer 4', 200, 1200);\n\nINSERT INTO orders (customer_id, notes, date_shipped, amount_total) VALUES (1, 'Order 1 notes', NULL, 150);\nINSERT INTO orders (customer_id, notes, date_shipped, amount_total) VALUES (2, 'Order 2 notes', NULL, 0);\nINSERT INTO orders (customer_id, notes, date_shipped, amount_total) VALUES (2, 'Order 3 notes', NULL, 0);\nINSERT INTO orders (customer_id, notes, date_shipped, amount_total) VALUES (3, 'Order 4 notes', NULL, 150);\n\nINSERT INTO items (order_id, product_id, quantity, unit_price, amount) VALUES (1, 1, 3, 50, 150);\nINSERT INTO items (order_id, product_id, quantity, unit_price, amount) VALUES (2, 2, 2, 25, 0);\nINSERT INTO items (order_id, product_id, quantity, unit_price, amount) VALUES (3, 3, 1, 75, 0);\nINSERT INTO items (order_id, product_id, quantity, unit_price, amount) VALUES (4, 1, 3, 50, 150);\n\nINSERT INTO products (name, unit_price) VALUES ('Product 1', 50);\nINSERT INTO products (name, unit_price) VALUES ('Product 2', 25);\nINSERT INTO products (name, unit_price) VALUES ('Product 3', 75);\nINSERT INTO products (name, unit_price) VALUES ('Product 4', 100);",
140
- "name": "OrderManagementSystem"
169
+ "test_data_sqlite": "INSERT INTO customer (name, balance, credit_limit) VALUES ('Alice', 1000.00, 5000.00);\nINSERT INTO customer (name, balance, credit_limit) VALUES ('Bob', 2000.00, 3000.00);\nINSERT INTO customer (name, balance, credit_limit) VALUES ('Charlie', 500.00, 2000.00);\nINSERT INTO customer (name, balance, credit_limit) VALUES ('Diana', 0.00, 1000.00);\n\nINSERT INTO product (name, unit_price) VALUES ('Gadget', 150.00);\nINSERT INTO product (name, unit_price) VALUES ('Widget', 90.00);\nINSERT INTO product (name, unit_price) VALUES ('Thingamajig', 75.00);\nINSERT INTO product (name, unit_price) VALUES ('Doodad', 110.00);\n\nINSERT INTO [order] (notes, customer_id, date_shipped, amount_total) VALUES ('First Order', 1, '2023-03-22', 300.00);\nINSERT INTO [order] (notes, customer_id, date_shipped, amount_total) VALUES ('Second Order', 2, NULL, 0.00);\nINSERT INTO [order] (notes, customer_id, date_shipped, amount_total) VALUES ('Pending Shipment', 3, NULL, 300.00);\nINSERT INTO [order] (notes, customer_id, date_shipped, amount_total) VALUES ('Urgent Order', 4, '2023-07-15', 220.00);\n\nINSERT INTO item (order_id, product_id, quantity, amount, unit_price) VALUES (1, 1, 2, 300.00, 150.00);\nINSERT INTO item (order_id, product_id, quantity, amount, unit_price) VALUES (2, 2, 1, 90.00, 90.00);\nINSERT INTO item (order_id, product_id, quantity, amount, unit_price) VALUES (3, 4, 2, 220.00, 110.00);\nINSERT INTO item (order_id, product_id, quantity, amount, unit_price) VALUES (4, 3, 4, 300.00, 75.00);",
170
+ "name": "CustomerOrderSystem"
141
171
  }
@@ -5,8 +5,6 @@ Create a system with customers, orders, items and products.
5
5
 
6
6
  Include a notes field for orders.
7
7
 
8
- Use LogicBank to enforce these requirements (do not generate check constraints); be sure to update the data model and *all* test data with any attributes used in the logic:
9
-
10
8
  Use case: Check Credit
11
9
  1. The Customer's balance is less than the credit limit
12
10
  2. The Customer's balance is the sum of the Order amount_total where date_shipped is null
@@ -17,12 +15,14 @@ Use case: Check Credit
17
15
  Use case: App Integration
18
16
  1. Send the Order to Kafka topic 'order_shipping' if the date_shipped is not None.
19
17
 
20
- Ensure each customer and product has a unique name.
18
+ Ensure each customer has a unique name.
21
19
 
22
20
  Ensure each Item quantity is not null.
23
21
 
24
22
  Ensure each order has a valid customer_id that exists in the Customer table.
25
- .
23
+
24
+ Graph sales by month, for dashboard.
25
+ Graph Sales by Product, for dashboard.
26
26
  </Requirements>
27
27
 
28
28
  Hints: use autonum keys (for all tables - including for link/join/junction/intersection tables), allow nulls, foreign keys, no check constraints.