ApiLogicServer 14.3.25__py3-none-any.whl → 14.5.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.
- api_logic_server_cli/add_cust/add_cust.py +283 -0
- api_logic_server_cli/api_logic_server.py +18 -250
- api_logic_server_cli/api_logic_server_info.yaml +3 -3
- api_logic_server_cli/cli.py +54 -35
- api_logic_server_cli/create_from_model/__pycache__/api_logic_server_utils.cpython-312.pyc +0 -0
- api_logic_server_cli/create_from_model/__pycache__/create_db_from_model.cpython-312.pyc +0 -0
- api_logic_server_cli/create_from_model/__pycache__/dbml.cpython-312.pyc +0 -0
- api_logic_server_cli/create_from_model/__pycache__/ont_build.cpython-312.pyc +0 -0
- api_logic_server_cli/create_from_model/__pycache__/ont_create.cpython-312.pyc +0 -0
- api_logic_server_cli/create_from_model/api_logic_server_utils.py +47 -0
- api_logic_server_cli/create_from_model/create_db_from_model.py +2 -0
- api_logic_server_cli/create_from_model/dbml.py +113 -58
- api_logic_server_cli/create_from_model/ont_build.py +102 -74
- api_logic_server_cli/create_from_model/ont_create.py +7 -6
- api_logic_server_cli/create_from_model/safrs-react-admin-npm-build/static/.DS_Store +0 -0
- api_logic_server_cli/database/basic_demo.sqlite +0 -0
- api_logic_server_cli/database/basic_demo.txt +1 -0
- api_logic_server_cli/database/basic_demo_wg.sqlite +0 -0
- api_logic_server_cli/database/nw-gold-fix.sql +62 -0
- api_logic_server_cli/database/nw-gold.sqlite +0 -0
- api_logic_server_cli/{prototypes/manager/webgenai → fragments}/docker-compose.yml +1 -1
- api_logic_server_cli/genai/genai.py +42 -11
- api_logic_server_cli/genai/genai_graphics.py +252 -38
- api_logic_server_cli/genai/genai_svcs.py +20 -12
- api_logic_server_cli/manager.py +22 -12
- api_logic_server_cli/prototypes/.DS_Store +0 -0
- api_logic_server_cli/prototypes/base/.DS_Store +0 -0
- api_logic_server_cli/prototypes/base/.vscode/launch.json +22 -2
- api_logic_server_cli/prototypes/base/api/expose_api_models.py +3 -1
- api_logic_server_cli/prototypes/base/api_logic_server_run.py +5 -2
- api_logic_server_cli/prototypes/base/config/activate_logicbank.py +1 -0
- api_logic_server_cli/prototypes/base/config/config.py +123 -25
- api_logic_server_cli/prototypes/base/config/default.env +7 -1
- api_logic_server_cli/prototypes/base/config/logging.yml +1 -0
- api_logic_server_cli/prototypes/base/config/server_setup.py +33 -1
- api_logic_server_cli/prototypes/base/database/test_data/readme.md +5 -2
- api_logic_server_cli/prototypes/base/devops/docker-standard-image/docker-compose-standard-image.yml +7 -2
- api_logic_server_cli/prototypes/base/docs/training/logic_bank_api.prompt +314 -0
- api_logic_server_cli/prototypes/base/docs/training/logic_example.py +41 -0
- api_logic_server_cli/prototypes/base/integration/kafka/kafka_producer.py +12 -5
- api_logic_server_cli/prototypes/base/integration/n8n/n8n_producer.py +68 -21
- api_logic_server_cli/prototypes/base/integration/n8n/n8n_readme.md +19 -0
- api_logic_server_cli/prototypes/base/integration/system/FlaskKafka.py +5 -1
- api_logic_server_cli/prototypes/base/test/basic/server_test.py +1 -1
- api_logic_server_cli/prototypes/base/ui/templates/bar_chart.jinja +64 -0
- api_logic_server_cli/prototypes/basic_demo/README.md +29 -52
- api_logic_server_cli/prototypes/basic_demo/customizations/api/.DS_Store +0 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/api/api_discovery/mcp_server_executor.py +138 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/api/api_discovery/openapi.py +92 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/api/api_discovery/proper_update_def.json +71 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/config/default.env +13 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/database/db.sqlite +0 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/database/models.py +131 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/.DS_Store +0 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/.DS_Store +0 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/1_langchain_loader.py +71 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/2_gpt_mcp_prompt.txt +19 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/README_mcp.md +13 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/mcp_client_executor.py +295 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/mcp_schema.txt +47 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/mcp_server_discovery.json +9 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/multi_mcp_flow/multi_mcp_flow.png +0 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/multi_mcp_flow/multi_mcp_orchestration.yaml +49 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/multi_mcp_flow/wny mcp flows.png +0 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/natlang_to_api.py +73 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/curl.txt +5 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/images/MCP Overview.png +0 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/images/MCP_Arch.png +0 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/images/MCP_Overview_Executor.png +0 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/invoke_llm/1 - prompt_messages_array.json +10 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/invoke_llm/2 - completion_tool_context.json +12 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/llm_schema.txt +38 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/nw_swagger_2.yaml +17393 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/nw_swagger_3.yaml +16660 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/nw_swagger_3_relaxed.yaml +109 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/proxy_server.py +51 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/proxy_serverZ.py +72 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/validate_jsonapi.py +64 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/run_executor.py +23 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/swagger_converter.py +65 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/z_old/3_executor_test_agent.py +52 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/openai_function/3_executor_test_agent.py +52 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/openai_function/README_functon.md +201 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/openai_function/ai_plugin.json +17 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/openai_function/nw-swagger_3.json +1731 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/openai_function/snippets.txt +5 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/openai_function/swagger_3 genai_demo_with_get.json +1731 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/openai_function/swagger_3.json +1782 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/openai_function/swagger_3_genai_demo.json +264 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/openai_function/swagger_3_genai_demo_with_update.json +1782 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/logic/declare_logic.py +62 -44
- api_logic_server_cli/prototypes/basic_demo/customizations/security/declare_security.py +11 -12
- api_logic_server_cli/prototypes/basic_demo/customizations/ui/admin/admin.yaml +166 -0
- api_logic_server_cli/prototypes/basic_demo/iteration/api/{customize_api.py → api_discovery/order_b2b.py} +17 -23
- api_logic_server_cli/prototypes/basic_demo/iteration/database/db.sqlite +0 -0
- api_logic_server_cli/prototypes/basic_demo/iteration/integration/row_dict_maps/OrderB2B.py +6 -5
- api_logic_server_cli/prototypes/basic_demo/iteration/integration/row_dict_maps/OrderShipping.py +4 -4
- api_logic_server_cli/prototypes/basic_demo/iteration/logic/declare_logic.py +69 -43
- api_logic_server_cli/prototypes/basic_demo/iteration/ui/admin/admin.yaml +125 -50
- api_logic_server_cli/prototypes/genai_demo/ui/admin/admin.yaml +1 -1
- api_logic_server_cli/prototypes/manager/README.md +30 -4
- api_logic_server_cli/prototypes/manager/README_X.md +663 -0
- api_logic_server_cli/prototypes/manager/system/genai/.DS_Store +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/.DS_Store +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/.DS_Store +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo.prompt +0 -10
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo.response_example +32 -10
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/docs/002_create_db_models.prompt +4 -4
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/docs/003_create_db_models.response +77 -47
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_informal.prompt +1 -1
- api_logic_server_cli/prototypes/manager/system/genai/graphics_templates/dashboard_services.jinja +83 -0
- api_logic_server_cli/prototypes/manager/system/genai/graphics_templates/graphics_dashboard_WIP.py +34 -0
- api_logic_server_cli/prototypes/manager/system/genai/graphics_templates/{graphics_services.py → graphics_services_api_xxx.py} +0 -9
- api_logic_server_cli/prototypes/manager/system/genai/graphics_templates/graphics_services_db.jinja +46 -0
- api_logic_server_cli/prototypes/manager/system/genai/graphics_templates/graphics_services_db_each_method.jinja +36 -0
- api_logic_server_cli/prototypes/manager/system/genai/prompt_inserts/graphics.prompt +7 -3
- api_logic_server_cli/prototypes/manager/system/genai/prompt_inserts/response_format.prompt +8 -1
- api_logic_server_cli/prototypes/manager/system/install-ApiLogicServer-dev/install-ApiLogicServer-dev.ps1 +100 -0
- api_logic_server_cli/prototypes/manager/system/install-ApiLogicServer-dev/install-ApiLogicServer-dev.sh +116 -0
- api_logic_server_cli/prototypes/manager/system/install-ApiLogicServer-dev/readme.md +7 -0
- api_logic_server_cli/prototypes/manager/system/style-guide.yaml +2 -2
- api_logic_server_cli/prototypes/manager/webgenai/README.md +6 -0
- api_logic_server_cli/prototypes/nw/docs/graphics/count_orders_by_category.prompt +1 -0
- api_logic_server_cli/prototypes/nw/docs/graphics/order_count_by_month.prompt +1 -0
- api_logic_server_cli/prototypes/nw/docs/graphics/request copy.json +892 -0
- api_logic_server_cli/prototypes/nw/docs/graphics/request.json +6 -0
- api_logic_server_cli/prototypes/nw/docs/graphics/response.json +17 -0
- api_logic_server_cli/prototypes/nw/docs/graphics/response.yaml +59 -0
- api_logic_server_cli/prototypes/nw/docs/graphics/sales_by_category.prompt +1 -0
- api_logic_server_cli/prototypes/nw/ui/admin/home.js +5 -4
- api_logic_server_cli/prototypes/nw/ui/app_model_custom.yaml +851 -1082
- api_logic_server_cli/prototypes/nw_no_cust/Tutorial.md +45 -26
- api_logic_server_cli/prototypes/nw_no_cust/api/api_discovery/openapi.py +130 -0
- api_logic_server_cli/prototypes/nw_no_cust/api/api_discovery/proper_update_def.json +71 -0
- api_logic_server_cli/prototypes/nw_no_cust/config/default.env +13 -0
- api_logic_server_cli/prototypes/nw_no_cust/docs/graphics/count_orders_by_category.prompt +1 -0
- api_logic_server_cli/prototypes/nw_no_cust/docs/graphics/sales_by_employee.prompt +1 -0
- api_logic_server_cli/prototypes/ont_app/ontimize_seed/nginx/nginx.conf +2 -2
- api_logic_server_cli/prototypes/ont_app/ontimize_seed/package-lock.json +9725 -1180
- api_logic_server_cli/prototypes/ont_app/ontimize_seed/package.json +6 -9
- api_logic_server_cli/prototypes/ont_app/ontimize_seed/src/app/app.config.ts +2 -1
- api_logic_server_cli/prototypes/ont_app/ontimize_seed/src/app/shared/app.services.config.ts +1 -1
- api_logic_server_cli/prototypes/ont_app/ontimize_seed/src/assets/css/app.scss +4 -0
- api_logic_server_cli/prototypes/ont_app/ontimize_seed/src/assets/i18n/en.json +1 -1
- api_logic_server_cli/prototypes/ont_app/ontimize_seed/src/assets/i18n/es.json +14 -12
- api_logic_server_cli/prototypes/ont_app/ontimize_seed/src/environments/environment.prod.ts +5 -5
- api_logic_server_cli/prototypes/ont_app/ontimize_seed/src/environments/environment.ts +5 -5
- api_logic_server_cli/prototypes/ont_app/templates/app_config.jinja +1 -1
- api_logic_server_cli/prototypes/ont_app/templates/date_template.html +1 -1
- api_logic_server_cli/prototypes/ont_app/templates/detail_template.html +1 -1
- api_logic_server_cli/prototypes/ont_app/templates/new_template.html +16 -16
- api_logic_server_cli/prototypes/ont_app/templates/textarea_template.html +1 -1
- api_logic_server_cli/prototypes/ont_app/templates/timestamp_template.html +1 -1
- api_logic_server_cli/prototypes/sample_ai/logic/declare_logic.py +30 -13
- apilogicserver-14.5.0.dist-info/METADATA +76 -0
- {apilogicserver-14.3.25.dist-info → apilogicserver-14.5.0.dist-info}/RECORD +160 -88
- {apilogicserver-14.3.25.dist-info → apilogicserver-14.5.0.dist-info}/WHEEL +1 -1
- api_logic_server_cli/prototypes/basic_demo/apply_customizations.ps1 +0 -17
- api_logic_server_cli/prototypes/basic_demo/apply_customizations.sh +0 -14
- api_logic_server_cli/prototypes/basic_demo/apply_iteration.ps1 +0 -20
- api_logic_server_cli/prototypes/basic_demo/apply_iteration.sh +0 -15
- api_logic_server_cli/prototypes/manager/system/genai/graphics_templates/service_template_jsonapi_rpc.jinja +0 -37
- api_logic_server_cli/prototypes/manager/system/genai/graphics_templates/service_template_unused.jinja +0 -38
- apilogicserver-14.3.25.dist-info/METADATA +0 -167
- {apilogicserver-14.3.25.dist-info → apilogicserver-14.5.0.dist-info}/entry_points.txt +0 -0
- {apilogicserver-14.3.25.dist-info → apilogicserver-14.5.0.dist-info}/licenses/LICENSE +0 -0
- {apilogicserver-14.3.25.dist-info → apilogicserver-14.5.0.dist-info}/top_level.txt +0 -0
|
@@ -12,21 +12,19 @@ See how to build a complete database system -- in minutes instead of weeks or mo
|
|
|
12
12
|
|
|
13
13
|
We'll use API Logic Server (open source), providing:
|
|
14
14
|
|
|
15
|
-
| Key Feature
|
|
16
|
-
|
|
|
17
|
-
| **Automation**
|
|
18
|
-
| **Customization** | Declarative logic and security <br> 5 rules vs. 200 lines of Python | 40X less backend code
|
|
19
|
-
| **Iteration**
|
|
15
|
+
| Key Feature | Providing | Why It Matters |
|
|
16
|
+
| :---------------- | :------------------------------------------------------------------ | :-------------------------------------------------- |
|
|
17
|
+
| **Automation** | Instant Project Creation:<br>An API and an Admin web app | Unblock UI App Dev<br>Instant Agile Collaboration |
|
|
18
|
+
| **Customization** | Declarative logic and security <br> 5 rules vs. 200 lines of Python | 40X less backend code |
|
|
19
|
+
| **Iteration** | Revising the data model, and <br>Adding rules plus Python | Iterative development <br> Extensiblity with Python |
|
|
20
20
|
|
|
21
21
|
The entire process takes 10 minutes, instead of several weeks using traditional development.
|
|
22
22
|
|
|
23
23
|
You can use this article in several ways:
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
* Self-demo with video - you can also use [this video](https://www.youtube.com/watch?v=sD6RFp8S6Fg) (it's the same system, but the database is created with ChatGPT).
|
|
25
|
+
- Conceptual Overview - focus on the basic process. Operational details are moved to the Appendix to retain focus on the concepts.
|
|
26
|
+
- Self-demo - you can create this system yourself.
|
|
27
|
+
- Self-demo with video - you can also use [this video](https://www.youtube.com/watch?v=sD6RFp8S6Fg) (it's the same system, but the database is created with ChatGPT).
|
|
30
28
|
|
|
31
29
|
|
|
32
30
|
|
|
@@ -45,9 +43,7 @@ This creates a project by reading your schema. The database is Customer, Orders
|
|
|
45
43
|
You can open with VSCode, and run it as follows:
|
|
46
44
|
|
|
47
45
|
1. **Create Virtual Environment:** as shown in the Appendix.
|
|
48
|
-
|
|
49
46
|
2. **Start the Server:** F5 (also described in the Appendix).
|
|
50
|
-
|
|
51
47
|
3. **Start the Admin App:** either use the links provided in the IDE console, or click [http://localhost:5656/](http://localhost:5656/). The screen shown below should appear in your Browser.
|
|
52
48
|
|
|
53
49
|
The sections below explore the system that has been created (which would be similar for your own database).
|
|
@@ -58,7 +54,7 @@ The sections below explore the system that has been created (which would be simi
|
|
|
58
54
|
|
|
59
55
|
The system creates an API with end points for each table, with filtering, sorting, pagination, optimistic locking and related data access -- **[self-serve](https://apilogicserver.github.io/Docs/API-Self-Serve/), ready for custom app dev.**
|
|
60
56
|
|
|
61
|
-
|
|
57
|
+

|
|
62
58
|
|
|
63
59
|
### Admin App
|
|
64
60
|
|
|
@@ -66,32 +62,29 @@ It also creates an Admin App: multi-page, multi-table apps -- ready for **[busin
|
|
|
66
62
|
|
|
67
63
|
You can click Customer 2, see their Orders, and Items.
|
|
68
64
|
|
|
69
|
-
|
|
65
|
+

|
|
70
66
|
|
|
71
67
|
## 2. Customize in your IDE
|
|
72
68
|
|
|
73
69
|
While API/UI automation is a great start, it's critical to enforce logic and security. Here's how.
|
|
74
70
|
|
|
75
|
-
The follwing
|
|
71
|
+
The follwing *add customizations* process simulates adding security to your project, and using your IDE to declare logic and security in `logic/declare_logic.sh` and `security/declare_security.py`. You can diff these files to their created versions, and/or examine the declared logic.
|
|
76
72
|
|
|
77
73
|
In a terminal window for your project:
|
|
78
74
|
|
|
79
75
|
**1. Stop the Server** (Red Stop button, or Shift-F5 -- see Appendix)
|
|
80
76
|
|
|
81
|
-
**2.
|
|
77
|
+
**2. Add Customizations**
|
|
82
78
|
|
|
83
79
|
```bash
|
|
84
|
-
|
|
85
|
-
sh apply_customizations.sh
|
|
86
|
-
|
|
87
|
-
#windows
|
|
88
|
-
./apply_customizations.ps1
|
|
80
|
+
als add-cust
|
|
89
81
|
```
|
|
82
|
+
|
|
90
83
|
|
|
91
84
|
|
|
92
85
|
### Declare Security
|
|
93
86
|
|
|
94
|
-
The
|
|
87
|
+
The *add customizations* process above has simulated the `ApiLogicServer add-auth` command, and using your IDE to declare security in `logic/declare_logic.sh`.
|
|
95
88
|
|
|
96
89
|
To see security in action:
|
|
97
90
|
|
|
@@ -115,7 +108,7 @@ Logic (multi-table derivations and constraints) is a significant portion of a sy
|
|
|
115
108
|
|
|
116
109
|
Rules are declared in Python, simplified with IDE code completion. The screen below shows the 5 rules for **Check Credit Logic.**
|
|
117
110
|
|
|
118
|
-
The
|
|
111
|
+
The *add customizations* process above has simulated the process of using your IDE to declare logic in `logic/declare_logic.sh`.
|
|
119
112
|
|
|
120
113
|
To see logic in action:
|
|
121
114
|
|
|
@@ -169,11 +162,9 @@ Not only are spreadsheet-like rules 40X more concise, they meaningfully simplify
|
|
|
169
162
|
|
|
170
163
|
The follwing `apply_iteration` process simulates an iteration:
|
|
171
164
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
* revised logic - in `logic/declare_logic.py`, we replace the 2 lines for the `models.Item.Amount` formula with this (next screenshot shows revised logic executing with breakpoint):
|
|
165
|
+
- acquires a new database with `Product.CarbonNeutral`
|
|
166
|
+
- and a revised `ui/admin/admin.yaml` that shows this new column
|
|
167
|
+
- revised logic - in `logic/declare_logic.py`, we replace the 2 lines for the `models.Item.Amount` formula with this (next screenshot shows revised logic executing with breakpoint):
|
|
177
168
|
|
|
178
169
|
```python
|
|
179
170
|
def derive_amount(row: models.Item, old_row: models.Item, logic_row: LogicRow):
|
|
@@ -185,8 +176,6 @@ The follwing `apply_iteration` process simulates an iteration:
|
|
|
185
176
|
Rule.formula(derive=models.Item.Amount, calling=derive_amount)
|
|
186
177
|
```
|
|
187
178
|
|
|
188
|
-
* issues the `ApiLogicServer rebuild-from-database` command that rebuilds your project (the database models, the api), while preserving the customizations we made above.
|
|
189
|
-
|
|
190
179
|
In a terminal window for your project:
|
|
191
180
|
|
|
192
181
|
**1. Stop the Server** (Red Stop button, or Shift-F5 -- see Appendix)
|
|
@@ -194,12 +183,10 @@ In a terminal window for your project:
|
|
|
194
183
|
**2. Apply Iteration**
|
|
195
184
|
|
|
196
185
|
```bash
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
#windows
|
|
201
|
-
./apply_iteration.ps1
|
|
186
|
+
als add-cust
|
|
187
|
+
als rebuild-from-database
|
|
202
188
|
```
|
|
189
|
+
|
|
203
190
|
|
|
204
191
|
|
|
205
192
|
**3. Set the breakpoint as shown**
|
|
@@ -210,7 +197,7 @@ sh apply_iteration.sh
|
|
|
210
197
|
|
|
211
198
|
At the breakpoint, note you can use standard debugger services to debug your logic (examine `Item` attributes, step, etc).
|
|
212
199
|
|
|
213
|
-
|
|
200
|
+
!
|
|
214
201
|
|
|
215
202
|
|
|
216
203
|
|
|
@@ -250,11 +237,9 @@ Note we rebuilt the project from our altered database, illustrating we can **ite
|
|
|
250
237
|
|
|
251
238
|
Of course, we all know that all businesses the world over depend on the `hello world` app. This is provided in `api/customize_api`. Observe that it's:
|
|
252
239
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
* and, for database access, SQLAlchemy. Note all updates from custom APIs also enforce your logic.
|
|
240
|
+
- standard Python
|
|
241
|
+
- using Flask
|
|
242
|
+
- and, for database access, SQLAlchemy. Note all updates from custom APIs also enforce your logic.
|
|
258
243
|
|
|
259
244
|
|
|
260
245
|
|
|
@@ -270,7 +255,7 @@ API Logic Server also creates scripts for deployment. While these are ***not re
|
|
|
270
255
|
|
|
271
256
|
## Summary
|
|
272
257
|
|
|
273
|
-
|
|
258
|
+

|
|
274
259
|
|
|
275
260
|
In minutes - not days or weeks - you've used API Logic Server to convert an idea into **working software,** added **logic and security,** and **iterated** to meet new requirements.
|
|
276
261
|
|
|
@@ -282,8 +267,9 @@ To dive deeper, you can install [API Logic Server](https://apilogicserver.github
|
|
|
282
267
|
|
|
283
268
|
## Appendix: Database Schema
|
|
284
269
|
|
|
285
|
-
<img src="https://github.com/ApiLogicServer/Docs/blob/main/docs/images/basic_demo/basic_demo_data_model.jpeg?raw=true" width="500">
|
|
286
270
|
|
|
271
|
+
|
|
272
|
+

|
|
287
273
|
|
|
288
274
|
|
|
289
275
|
## Appendix: Procedures
|
|
@@ -321,28 +307,19 @@ For PyCharm, start the server with CTL-D, Stop with red stop button.
|
|
|
321
307
|
To enter a new Order:
|
|
322
308
|
|
|
323
309
|
1. Click `Customer 1``
|
|
324
|
-
|
|
325
310
|
2. Click `+ ADD NEW ORDER`
|
|
326
|
-
|
|
327
311
|
3. Set `Notes` to "hurry", and press `SAVE AND SHOW`
|
|
328
|
-
|
|
329
312
|
4. Click `+ ADD NEW ITEM`
|
|
330
|
-
|
|
331
313
|
5. Enter Quantity 1, lookup "Product 1", and click `SAVE AND ADD ANOTHER`
|
|
332
|
-
|
|
333
314
|
6. Enter Quantity 2000, lookup "Product 2", and click `SAVE`
|
|
334
|
-
|
|
335
315
|
7. Observe the constraint error, triggered by rollups from the `Item` to the `Order` and `Customer`
|
|
336
|
-
|
|
337
316
|
8. Correct the quantity to 2, and click `Save`
|
|
338
317
|
|
|
339
|
-
|
|
340
318
|
**4. Update the Order**
|
|
341
319
|
|
|
342
320
|
To explore our new logic for green products:
|
|
343
321
|
|
|
344
322
|
1. Access the previous order, and `ADD NEW ITEM`
|
|
345
|
-
|
|
346
323
|
2. Enter quantity 11, lookup product `Green`, and click `Save`.
|
|
347
324
|
|
|
348
325
|
|
|
Binary file
|
api_logic_server_cli/prototypes/basic_demo/customizations/api/api_discovery/mcp_server_executor.py
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
from flask import request, jsonify
|
|
2
|
+
from flask import Flask, redirect, send_from_directory, send_file
|
|
3
|
+
import logging
|
|
4
|
+
import os
|
|
5
|
+
import json
|
|
6
|
+
import io
|
|
7
|
+
|
|
8
|
+
import requests
|
|
9
|
+
from config.config import Args # circular import error if at top
|
|
10
|
+
|
|
11
|
+
app_logger = logging.getLogger("api_logic_server_app")
|
|
12
|
+
|
|
13
|
+
def add_service(app, api, project_dir, swagger_host: str, PORT: str, method_decorators = []):
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
def get_server_url():
|
|
17
|
+
""" return the server URL for the OpenAPI spec """
|
|
18
|
+
result = f'http://{Args.instance.swagger_host}:{Args.instance.swagger_port}'
|
|
19
|
+
# get env variable API_LOGIC_SERVER_TUNNEL (or None)
|
|
20
|
+
if tunnel_url := os.getenv("API_LOGIC_SERVER_TUNNEL", None):
|
|
21
|
+
app_logger.info(f".. tunnel URL: {tunnel_url}")
|
|
22
|
+
result = tunnel_url
|
|
23
|
+
return result # + '/api'
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@app.before_request
|
|
27
|
+
def before_any_request():
|
|
28
|
+
# print(f"[DEBUG] Incoming request: {request.method} {request.url}")
|
|
29
|
+
if activate_openapi_logging := True:
|
|
30
|
+
if request.content_type == 'application/json' and request.method in ['POST', 'PUT', 'PATCH']:
|
|
31
|
+
# openapi: Incoming request: PATCH http://localhost:5656/api/Customer/1/ {'data': {'attributes': {'credit_limit': 5555}, 'type': 'Customer', 'id': '1'}}
|
|
32
|
+
# openapi: Incoming request: PATCH http://6f6f-2601-644-4900-d6f0-ecc9-6df3-8863-c5b2.ngrok-free.app/api/Customer/1 {'credit_limit': 5555}
|
|
33
|
+
|
|
34
|
+
app_logger.info(f"openapi: Incoming request: {request.method} {request.url} {str(request.json)}")
|
|
35
|
+
else:
|
|
36
|
+
app_logger.info(f"openapi: Incoming request: {request.method} {request.url}")
|
|
37
|
+
# app_logger.info(f"openapi: Incoming request headers: {request.headers}")
|
|
38
|
+
|
|
39
|
+
chatgpt_request_json = {
|
|
40
|
+
"credit_limit": 25000,
|
|
41
|
+
}
|
|
42
|
+
standard_request_json = {
|
|
43
|
+
"data": {
|
|
44
|
+
"type": "Customer",
|
|
45
|
+
"id": "ALFKI",
|
|
46
|
+
"attributes": {
|
|
47
|
+
"name": "Alice",
|
|
48
|
+
"credit_limit": 25000,
|
|
49
|
+
"balance": 12345
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
swagger_request_json = {
|
|
54
|
+
'data': {
|
|
55
|
+
'attributes': {
|
|
56
|
+
'credit_limit': 5555
|
|
57
|
+
},
|
|
58
|
+
'type': 'Customer',
|
|
59
|
+
'id': '1'
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
pass
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@app.route('/mcp_server_executor', methods=['GET'])
|
|
66
|
+
def mcp_server_executor(path=None):
|
|
67
|
+
''' sample response printed in mcp_client_executor.py:
|
|
68
|
+
FIXME - incorrect.
|
|
69
|
+
But do provide: https://localhost:5656/.well-known/mcp.json
|
|
70
|
+
```
|
|
71
|
+
MCP MCP Response (simulated):
|
|
72
|
+
{
|
|
73
|
+
"get_json": {
|
|
74
|
+
"filter": {
|
|
75
|
+
"filter": {
|
|
76
|
+
"credit_limit": {
|
|
77
|
+
"gt": 4000
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
"headers": {
|
|
81
|
+
"Accept": "application/vnd.api+json",
|
|
82
|
+
"Authorization": "Bearer your_token"
|
|
83
|
+
},
|
|
84
|
+
"type": "Customer",
|
|
85
|
+
"url": "http://localhost:5656/api/Customer"
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
"name": "mcp_server_executor",
|
|
89
|
+
"openapiUrl": "TUNNEL_URL/api/openapi.json",
|
|
90
|
+
"serverUrl": "TUNNEL_URL/api"
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
'''
|
|
94
|
+
get_json = request.get_json()
|
|
95
|
+
app_logger.info(f"mcp_server_executor sees mcp request: \n{json.dumps(get_json, indent=4)}")
|
|
96
|
+
|
|
97
|
+
# process verb, filter here (stub for now)
|
|
98
|
+
filter_json = get_json['filter'] # {"credit_limit": {"gt": 4000}} # todo: bunch'o parsing here
|
|
99
|
+
|
|
100
|
+
filter_json = {"name": "credit_limit", "op": "gt", "val":4000} # https://github.com/thomaxxl/safrs/wiki/JsonApi-filtering
|
|
101
|
+
filter = json.dumps(filter_json) # {"name": "credit_limit", "op": "gt", "val": 4000}
|
|
102
|
+
get_uri = get_json['url'] + '?filter=' + filter # get_uri = "http://localhost:5656/api/Customer?filter[credit_limit]=1000"
|
|
103
|
+
response = requests.get(url=get_uri, headers= request.headers)
|
|
104
|
+
|
|
105
|
+
return response.json(), 200, {'Content-Type': 'application/json; charset=utf-8'}
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
@app.route('/.well-known/mcp.json', methods=['GET'])
|
|
109
|
+
def mcp_discovery(path=None):
|
|
110
|
+
''' called by mcp_client_executor for discovery, eg:
|
|
111
|
+
```
|
|
112
|
+
{
|
|
113
|
+
"tool_type": "json-api",
|
|
114
|
+
"base_url": "https://crm.company.com",
|
|
115
|
+
"resources": [
|
|
116
|
+
{
|
|
117
|
+
"name": "Customer",
|
|
118
|
+
"path": "/Customer",
|
|
119
|
+
"methods": ["GET", "PATCH"],
|
|
120
|
+
"fields": ["id", "name", "balance", "credit_limit"],
|
|
121
|
+
"filterable": ["name", "credit_limit"],
|
|
122
|
+
"example": "List customers with credit over 5000"
|
|
123
|
+
}
|
|
124
|
+
]
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
test: curl -X GET "http://localhost:5656/.well-known/mcp.json"
|
|
128
|
+
'''
|
|
129
|
+
# return docs/mcp_schema.json
|
|
130
|
+
schema_path = os.path.join(project_dir, "docs", "mcp_schema.json")
|
|
131
|
+
try:
|
|
132
|
+
with open(schema_path, "r") as schema_file:
|
|
133
|
+
schema = json.load(schema_file)
|
|
134
|
+
return jsonify(schema), 200
|
|
135
|
+
except Exception as e:
|
|
136
|
+
app_logger.error(f"Error loading MCP schema: {e}")
|
|
137
|
+
return jsonify({"error": "MCP schema not found"}), 404
|
|
138
|
+
pass
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
from flask import request, jsonify
|
|
2
|
+
from flask import Flask, redirect, send_from_directory, send_file
|
|
3
|
+
import logging
|
|
4
|
+
import os
|
|
5
|
+
import json
|
|
6
|
+
import io
|
|
7
|
+
from config.config import Args # circular import error if at top
|
|
8
|
+
|
|
9
|
+
app_logger = logging.getLogger("api_logic_server_app")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def add_service(app, api, project_dir, swagger_host: str, PORT: str, method_decorators = []):
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
def get_server_url():
|
|
17
|
+
""" return the server URL for the OpenAPI spec """
|
|
18
|
+
result = f'http://{Args.instance.swagger_host}:{Args.instance.swagger_port}'
|
|
19
|
+
# get env variable API_LOGIC_SERVER_TUNNEL (or None)
|
|
20
|
+
if tunnel_url := os.getenv("API_LOGIC_SERVER_TUNNEL", None):
|
|
21
|
+
app_logger.info(f".. tunnel URL: {tunnel_url}")
|
|
22
|
+
result = tunnel_url
|
|
23
|
+
return result # + '/api'
|
|
24
|
+
|
|
25
|
+
@app.route('/mcp.json')
|
|
26
|
+
def mcp(path=None):
|
|
27
|
+
'''
|
|
28
|
+
test: curl -X GET http://localhost:5656/mcp.json
|
|
29
|
+
'''
|
|
30
|
+
|
|
31
|
+
mcp_json = {
|
|
32
|
+
"name": "MCP genai_demo test",
|
|
33
|
+
"description": "You are an AI Planner + Executor for a live JSON:API server.",
|
|
34
|
+
"instructions": [
|
|
35
|
+
"When a user gives you a natural language goal (e.g., 'list customers from Germany'), you:",
|
|
36
|
+
"Identify the resource (Customer, Order, Product).",
|
|
37
|
+
"Map filters (e.g., Country=Germany).",
|
|
38
|
+
"Construct a JSON:API call to the live endpoint (through a function called fetch_resource).",
|
|
39
|
+
"Execute the live API call through the function.",
|
|
40
|
+
"Format and display the results neatly."
|
|
41
|
+
],
|
|
42
|
+
"serverUrl": "http://localhost:5656/api",
|
|
43
|
+
"openapiUrl": "http://localhost:5656/api/openapi.json",
|
|
44
|
+
"apiStandard": "JSON:API (application/vnd.api+json)"
|
|
45
|
+
}
|
|
46
|
+
mcp_json["serverUrl"] = get_server_url() + '/api'
|
|
47
|
+
mcp_json["openapiUrl"] = get_server_url() + '/api/openapi.json'
|
|
48
|
+
# return jsonify(mcp), 200, {'Content-Type': 'text/plain; charset=utf-8'}
|
|
49
|
+
return jsonify(mcp_json), 200, {'Content-Type': 'application/json; charset=utf-8'}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@app.route('/api/openapi.json')
|
|
53
|
+
def openapi(path=None):
|
|
54
|
+
""" return integration/openai_plugin/swagger_3.json
|
|
55
|
+
* with updated tunnel URL if API_LOGIC_SERVER_TUNNEL is set
|
|
56
|
+
|
|
57
|
+
test: curl -X GET http://localhost:5656/api/openapi.json
|
|
58
|
+
like: curl -X GET http://localhost:5656/api/swagger.json
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
# read dict from json file integration/openai_plugin/swagger_3.json
|
|
62
|
+
with open("integration/openai_function/swagger_3.json", "r") as json_file:
|
|
63
|
+
swagger_dict = json.load(json_file)
|
|
64
|
+
app_logger.info(f"openapi: Swagger JSON loaded: {swagger_dict}")
|
|
65
|
+
|
|
66
|
+
server_url = get_server_url()
|
|
67
|
+
swagger_dict["servers"][0]["url"] = server_url + '/api'
|
|
68
|
+
|
|
69
|
+
# convert dict to buffered stream
|
|
70
|
+
swagger_dict_mem = io.BytesIO(json.dumps(swagger_dict).encode('utf-8'))
|
|
71
|
+
return send_file(swagger_dict_mem, mimetype='text/json')
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@app.route('/api/ai_plugin')
|
|
75
|
+
def ai_plugin(path=None):
|
|
76
|
+
""" return integration/openai_plugin/ai_plugin.json (disparaged)
|
|
77
|
+
* with updated tunnel URL if API_LOGIC_SERVER_TUNNEL is set
|
|
78
|
+
|
|
79
|
+
test: curl -X GET http://localhost:5656/api/ai_plugin
|
|
80
|
+
"""
|
|
81
|
+
|
|
82
|
+
# read dict from json file integration/openai_plugin/swagger_3.json
|
|
83
|
+
with open("integration/openai_plugin/ai_plugin.json", "r") as json_file:
|
|
84
|
+
swagger_dict = json.load(json_file)
|
|
85
|
+
app_logger.info(f"openapi: ai_plugin JSON loaded: {swagger_dict}")
|
|
86
|
+
|
|
87
|
+
server_url = get_server_url()
|
|
88
|
+
swagger_dict["servers"][0]["url"] = server_url
|
|
89
|
+
|
|
90
|
+
# convert dict to buffered stream
|
|
91
|
+
swagger_dict_mem = io.BytesIO(json.dumps(swagger_dict).encode('utf-8'))
|
|
92
|
+
return send_file(swagger_dict_mem, mimetype='text/json')
|
api_logic_server_cli/prototypes/basic_demo/customizations/api/api_discovery/proper_update_def.json
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"/Customer/{id}": {
|
|
3
|
+
"patch": {
|
|
4
|
+
"summary": "Update Customer by ID",
|
|
5
|
+
"operationId": "updateCustomer",
|
|
6
|
+
"parameters": [
|
|
7
|
+
{
|
|
8
|
+
"name": "id",
|
|
9
|
+
"in": "path",
|
|
10
|
+
"required": true,
|
|
11
|
+
"schema": {
|
|
12
|
+
"type": "string"
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
],
|
|
16
|
+
"requestBody": {
|
|
17
|
+
"required": true,
|
|
18
|
+
"content": {
|
|
19
|
+
"application/vnd.api+json": {
|
|
20
|
+
"schema": {
|
|
21
|
+
"type": "object",
|
|
22
|
+
"required": ["data"],
|
|
23
|
+
"properties": {
|
|
24
|
+
"data": {
|
|
25
|
+
"type": "object",
|
|
26
|
+
"required": ["type", "id", "attributes"],
|
|
27
|
+
"properties": {
|
|
28
|
+
"type": {
|
|
29
|
+
"type": "string",
|
|
30
|
+
"enum": ["Customer"]
|
|
31
|
+
},
|
|
32
|
+
"id": {
|
|
33
|
+
"type": "string"
|
|
34
|
+
},
|
|
35
|
+
"attributes": {
|
|
36
|
+
"type": "object",
|
|
37
|
+
"properties": {
|
|
38
|
+
"name": {
|
|
39
|
+
"type": "string"
|
|
40
|
+
},
|
|
41
|
+
"credit_limit": {
|
|
42
|
+
"type": "number"
|
|
43
|
+
},
|
|
44
|
+
"balance": {
|
|
45
|
+
"type": "number"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
"responses": {
|
|
57
|
+
"200": {
|
|
58
|
+
"description": "Customer updated",
|
|
59
|
+
"content": {
|
|
60
|
+
"application/vnd.api+json": {
|
|
61
|
+
"schema": {
|
|
62
|
+
"type": "object"
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
SECRET_KEY = "whatnothow"
|
|
2
|
+
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
|
3
|
+
SQLAlCHEMY_ECHO = False
|
|
4
|
+
# AGGREGATE_DEFAULTS = True
|
|
5
|
+
# ALL_DEFAULTS = True
|
|
6
|
+
# APILOGICPROJECT_KAFKA_PRODUCER = "{\"bootstrap.servers\": \"localhost:9092\"}"
|
|
7
|
+
# SQLALCHEMY_DATABASE_URI=db.sqlite
|
|
8
|
+
|
|
9
|
+
SECURITY_ENABLED = false
|
|
10
|
+
|
|
11
|
+
# if using tunnel for mcp, function, or ai_plugin
|
|
12
|
+
# eg, https://tunnel_url.ngrok-free.app
|
|
13
|
+
API_LOGIC_SERVER_TUNNEL = "TUNNEL_URL"
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
from sqlalchemy import DECIMAL, DateTime # API Logic Server GenAI assist
|
|
3
|
+
from sqlalchemy import Boolean, Column, DECIMAL, Date, ForeignKey, Integer, String
|
|
4
|
+
from sqlalchemy.orm import relationship
|
|
5
|
+
from sqlalchemy.ext.declarative import declarative_base
|
|
6
|
+
|
|
7
|
+
########################################################################################################################
|
|
8
|
+
# Classes describing database for SqlAlchemy ORM, initially created by schema introspection.
|
|
9
|
+
#
|
|
10
|
+
# Alter this file per your database maintenance policy
|
|
11
|
+
# See https://apilogicserver.github.io/Docs/Project-Rebuild/#rebuilding
|
|
12
|
+
#
|
|
13
|
+
# Created: May 14, 2025 10:47:47
|
|
14
|
+
# Database: sqlite:////Users/val/dev/ApiLogicServer/ApiLogicServer-dev/servers/basic_demo/database/db.sqlite
|
|
15
|
+
# Dialect: sqlite
|
|
16
|
+
#
|
|
17
|
+
# mypy: ignore-errors
|
|
18
|
+
########################################################################################################################
|
|
19
|
+
|
|
20
|
+
from database.system.SAFRSBaseX import SAFRSBaseX, TestBase
|
|
21
|
+
from flask_login import UserMixin
|
|
22
|
+
import safrs, flask_sqlalchemy, os
|
|
23
|
+
from safrs import jsonapi_attr
|
|
24
|
+
from flask_sqlalchemy import SQLAlchemy
|
|
25
|
+
from sqlalchemy.orm import relationship
|
|
26
|
+
from sqlalchemy.orm import Mapped
|
|
27
|
+
from sqlalchemy.sql.sqltypes import NullType
|
|
28
|
+
from typing import List
|
|
29
|
+
|
|
30
|
+
db = SQLAlchemy()
|
|
31
|
+
Base = declarative_base() # type: flask_sqlalchemy.model.DefaultMeta
|
|
32
|
+
metadata = Base.metadata
|
|
33
|
+
|
|
34
|
+
#NullType = db.String # datatype fixup
|
|
35
|
+
#TIMESTAMP= db.TIMESTAMP
|
|
36
|
+
|
|
37
|
+
from sqlalchemy.dialects.sqlite import *
|
|
38
|
+
|
|
39
|
+
if os.getenv('APILOGICPROJECT_NO_FLASK') is None or os.getenv('APILOGICPROJECT_NO_FLASK') == 'None':
|
|
40
|
+
Base = SAFRSBaseX # enables rules to be used outside of Flask, e.g., test data loading
|
|
41
|
+
else:
|
|
42
|
+
Base = TestBase # ensure proper types, so rules work for data loading
|
|
43
|
+
print('*** Models.py Using TestBase ***')
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class Customer(Base): # type: ignore
|
|
48
|
+
__tablename__ = 'customer'
|
|
49
|
+
_s_collection_name = 'Customer' # type: ignore
|
|
50
|
+
|
|
51
|
+
id = Column(Integer, primary_key=True)
|
|
52
|
+
name = Column(String)
|
|
53
|
+
balance : DECIMAL = Column(DECIMAL)
|
|
54
|
+
credit_limit : DECIMAL = Column(DECIMAL)
|
|
55
|
+
email = Column(String)
|
|
56
|
+
email_opt_out = Column(Boolean)
|
|
57
|
+
|
|
58
|
+
# parent relationships (access parent)
|
|
59
|
+
|
|
60
|
+
# child relationships (access children)
|
|
61
|
+
EmailList : Mapped[List["Email"]] = relationship(back_populates="customer")
|
|
62
|
+
OrderList : Mapped[List["Order"]] = relationship(back_populates="customer")
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class Product(Base): # type: ignore
|
|
67
|
+
__tablename__ = 'product'
|
|
68
|
+
_s_collection_name = 'Product' # type: ignore
|
|
69
|
+
|
|
70
|
+
id = Column(Integer, primary_key=True)
|
|
71
|
+
name = Column(String)
|
|
72
|
+
unit_price : DECIMAL = Column(DECIMAL)
|
|
73
|
+
|
|
74
|
+
# parent relationships (access parent)
|
|
75
|
+
|
|
76
|
+
# child relationships (access children)
|
|
77
|
+
ItemList : Mapped[List["Item"]] = relationship(back_populates="product")
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class Email(Base): # type: ignore
|
|
82
|
+
__tablename__ = 'email'
|
|
83
|
+
_s_collection_name = 'Email' # type: ignore
|
|
84
|
+
|
|
85
|
+
id = Column(Integer, primary_key=True)
|
|
86
|
+
message = Column(String)
|
|
87
|
+
customer_id = Column(ForeignKey('customer.id'), nullable=False)
|
|
88
|
+
CreatedOn = Column(Date)
|
|
89
|
+
|
|
90
|
+
# parent relationships (access parent)
|
|
91
|
+
customer : Mapped["Customer"] = relationship(back_populates=("EmailList"))
|
|
92
|
+
|
|
93
|
+
# child relationships (access children)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class Order(Base): # type: ignore
|
|
98
|
+
__tablename__ = 'order'
|
|
99
|
+
_s_collection_name = 'Order' # type: ignore
|
|
100
|
+
|
|
101
|
+
id = Column(Integer, primary_key=True)
|
|
102
|
+
notes = Column(String)
|
|
103
|
+
customer_id = Column(ForeignKey('customer.id'), nullable=False)
|
|
104
|
+
CreatedOn = Column(Date)
|
|
105
|
+
date_shipped = Column(Date)
|
|
106
|
+
amount_total : DECIMAL = Column(DECIMAL)
|
|
107
|
+
|
|
108
|
+
# parent relationships (access parent)
|
|
109
|
+
customer : Mapped["Customer"] = relationship(back_populates=("OrderList"))
|
|
110
|
+
|
|
111
|
+
# child relationships (access children)
|
|
112
|
+
ItemList : Mapped[List["Item"]] = relationship(back_populates="order")
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class Item(Base): # type: ignore
|
|
117
|
+
__tablename__ = 'item'
|
|
118
|
+
_s_collection_name = 'Item' # type: ignore
|
|
119
|
+
|
|
120
|
+
id = Column(Integer, primary_key=True)
|
|
121
|
+
order_id = Column(ForeignKey('order.id'))
|
|
122
|
+
product_id = Column(ForeignKey('product.id'), nullable=False)
|
|
123
|
+
quantity = Column(Integer, nullable=False)
|
|
124
|
+
amount : DECIMAL = Column(DECIMAL)
|
|
125
|
+
unit_price : DECIMAL = Column(DECIMAL)
|
|
126
|
+
|
|
127
|
+
# parent relationships (access parent)
|
|
128
|
+
order : Mapped["Order"] = relationship(back_populates=("ItemList"))
|
|
129
|
+
product : Mapped["Product"] = relationship(back_populates=("ItemList"))
|
|
130
|
+
|
|
131
|
+
# child relationships (access children)
|