ApiLogicServer 15.0.47__py3-none-any.whl → 15.0.54__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/api_logic_server.py +18 -5
- api_logic_server_cli/api_logic_server_info.yaml +3 -3
- api_logic_server_cli/cli.py +20 -16
- api_logic_server_cli/create_from_model/api_logic_server_utils.py +10 -1
- api_logic_server_cli/manager.py +24 -13
- api_logic_server_cli/prototypes/base/.github/.copilot-instructions.md +39 -3
- api_logic_server_cli/prototypes/base/config/config.py +15 -0
- api_logic_server_cli/prototypes/base/database/alembic/alembic_run.py +98 -0
- api_logic_server_cli/prototypes/base/database/alembic/readme_alembic.md +36 -0
- api_logic_server_cli/prototypes/base/docs/training/admin_app_1_context.prompt.md +40 -0
- api_logic_server_cli/prototypes/base/integration/mcp/mcp_client_executor.py +2 -2
- api_logic_server_cli/prototypes/base/venv_setup/requirements-no-cli.txt +5 -4
- api_logic_server_cli/prototypes/basic_demo/_config.yml +8 -0
- api_logic_server_cli/prototypes/basic_demo/_layouts/redirect.html +15 -0
- api_logic_server_cli/prototypes/basic_demo/docs/system-creation-vibe.md +161 -0
- api_logic_server_cli/prototypes/basic_demo/logic/declarative-vs-procedural-comparison.html +110 -0
- api_logic_server_cli/prototypes/basic_demo/logic/procedural/declarative-vs-procedural-comparison.md +295 -0
- api_logic_server_cli/prototypes/manager/.vscode/settings.json +1 -1
- api_logic_server_cli/prototypes/manager/{run_sample.sh → samples/docker_samples/run_sample_docker.sh} +4 -4
- api_logic_server_cli/prototypes/manager/samples/docker_samples/run_web_genai.sh +5 -0
- api_logic_server_cli/prototypes/manager/samples/prompts/add_email.prompt +8 -0
- api_logic_server_cli/prototypes/manager/samples/prompts/elections.prompt +3 -0
- api_logic_server_cli/prototypes/manager/samples/prompts/emp_dept.prompt +4 -0
- api_logic_server_cli/prototypes/manager/samples/prompts/genai_demo.prompt +13 -0
- api_logic_server_cli/prototypes/manager/samples/readme_samples.md +25 -11
- api_logic_server_cli/prototypes/manager/system/app_model_editor/venv_setup/requirements-no-cli.txt +5 -4
- api_logic_server_cli/prototypes/manager/system/genai/app_templates/app_learning/Admin-App-Resource-Learning-Prompt.md +1 -1
- api_logic_server_cli/prototypes/manager/system/genai/app_templates/react-admin-template/package.json +1 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/venv_setup/requirements-no-cli.txt +5 -4
- api_logic_server_cli/prototypes/manager/system/install-ApiLogicServer-dev/install-ApiLogicServer-dev.ps1 +7 -3
- api_logic_server_cli/prototypes/ont_app/ontimize_seed/package.json +2 -2
- api_logic_server_cli/sqlacodegen_wrapper/sqlacodegen/sqlacodegen/codegen.py +4 -2
- api_logic_server_cli/sqlacodegen_wrapper/sqlacodegen/sqlacodegen/main.py +25 -5
- api_logic_server_cli/sqlacodegen_wrapper/sqlacodegen_wrapper.py +30 -10
- {apilogicserver-15.0.47.dist-info → apilogicserver-15.0.54.dist-info}/METADATA +6 -5
- {apilogicserver-15.0.47.dist-info → apilogicserver-15.0.54.dist-info}/RECORD +40 -111
- api_logic_server_cli/create_from_model/__pycache__/__init__.cpython-312.pyc +0 -0
- api_logic_server_cli/create_from_model/__pycache__/api_expose_api_models_creator.cpython-312.pyc +0 -0
- 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__/meta_model.cpython-312.pyc +0 -0
- api_logic_server_cli/create_from_model/__pycache__/model_creation_services.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/__pycache__/ui_admin_creator.cpython-312.pyc +0 -0
- api_logic_server_cli/create_from_model/__pycache__/uri_info.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/base/.devcontainer-option/.copilot-instructions.md +0 -178
- api_logic_server_cli/prototypes/base/database/alembic/readme.md +0 -18
- api_logic_server_cli/prototypes/base/database/system/SAFRSBaseX.pyZ +0 -73
- api_logic_server_cli/prototypes/basic_demo/customizations/database/system/SAFRSBaseX.py +0 -139
- api_logic_server_cli/prototypes/manager/run_web_genai.sh +0 -6
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/__pycache__/api_logic_server_run.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/api/__pycache__/__init__.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/api/__pycache__/customize_api.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/api/__pycache__/expose_api_models.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/api/__pycache__/json_encoder.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/api/api_discovery/__pycache__/auto_discovery.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/api/api_discovery/__pycache__/new_service.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/api/api_discovery/__pycache__/newer_service.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/api/api_discovery/__pycache__/ontimize_api.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/api/api_discovery/__pycache__/system.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/api/system/__pycache__/api_utils.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/api/system/__pycache__/custom_endpoint.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/api/system/__pycache__/expression_parser.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/api/system/__pycache__/gen_csv_report.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/api/system/__pycache__/gen_pdf_report.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/api/system/opt_locking/__pycache__/opt_locking.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/config/__pycache__/__init__.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/config/__pycache__/activate_logicbank.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/config/__pycache__/config.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/config/__pycache__/server_setup.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/database/__pycache__/__init__.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/database/__pycache__/bind_dbs.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/database/__pycache__/customize_models.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/database/__pycache__/models.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/database/alembic/__pycache__/env.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/database/database_discovery/__pycache__/authentication_models.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/database/database_discovery/__pycache__/auto_discovery.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/database/db_debug/__pycache__/db_debug.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/database/system/__pycache__/SAFRSBaseX.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/database/test_data/__pycache__/alp_init.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/database/test_data/__pycache__/response2code.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/database/test_data/__pycache__/test_data_preamble.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/devops/keycloak/unused/__pycache__/auth_provider.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/devops/python-anywhere/__pycache__/python_anywhere_wsgi.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/integration/kafka/__pycache__/kafka_consumer.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/integration/kafka/__pycache__/kafka_producer.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/integration/n8n/__pycache__/n8n_producer.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/integration/system/__pycache__/FlaskKafka.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/integration/system/__pycache__/RowDictMapper.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/logic/__pycache__/declare_logic.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/logic/__pycache__/load_verify_rules.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/logic/logic_discovery/__pycache__/auto_discovery.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/security/__pycache__/__init__.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/security/__pycache__/declare_security.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/security/authentication_provider/__pycache__/__init__.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/security/authentication_provider/__pycache__/abstract_authentication_provider.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/security/authentication_provider/keycloak/__pycache__/auth_provider.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/security/authentication_provider/memory/__pycache__/auth_provider.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/security/authentication_provider/memory/__pycache__/auth_provider_no_swagger.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/security/authentication_provider/sql/__pycache__/auth_provider.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/security/system/__pycache__/authentication.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/security/system/__pycache__/authorization.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/test/__pycache__/__init__.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/test/api_logic_server_behave/__pycache__/__init__.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/test/api_logic_server_behave/__pycache__/behave_logic_report.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/test/api_logic_server_behave/__pycache__/behave_run.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/test/api_logic_server_behave/features/steps/__pycache__/about.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/test/api_logic_server_behave/features/steps/__pycache__/test_utils.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/test/basic/__pycache__/server_test.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/ui/__pycache__/__init__.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/ui/admin/__pycache__/admin_loader.cpython-312.pyc +0 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/venv_setup/__pycache__/py.cpython-312.pyc +0 -0
- api_logic_server_cli/sqlacodegen_wrapper/__pycache__/__init__.cpython-312.pyc +0 -0
- api_logic_server_cli/sqlacodegen_wrapper/__pycache__/sqlacodegen_wrapper.cpython-312.pyc +0 -0
- api_logic_server_cli/sqlacodegen_wrapper/sqlacodegen/__pycache__/__init__.cpython-312.pyc +0 -0
- api_logic_server_cli/sqlacodegen_wrapper/sqlacodegen/sqlacodegen/__pycache__/__init__.cpython-312.pyc +0 -0
- api_logic_server_cli/sqlacodegen_wrapper/sqlacodegen/sqlacodegen/__pycache__/codegen.cpython-312.pyc +0 -0
- {apilogicserver-15.0.47.dist-info → apilogicserver-15.0.54.dist-info}/WHEEL +0 -0
- {apilogicserver-15.0.47.dist-info → apilogicserver-15.0.54.dist-info}/entry_points.txt +0 -0
- {apilogicserver-15.0.47.dist-info → apilogicserver-15.0.54.dist-info}/licenses/LICENSE +0 -0
- {apilogicserver-15.0.47.dist-info → apilogicserver-15.0.54.dist-info}/top_level.txt +0 -0
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
# GitHub Copilot Instructions for GenAI-Logic (aka API Logic Server) Projects
|
|
2
|
-
|
|
3
|
-
## Project Type: Auto-Generated Microservice
|
|
4
|
-
|
|
5
|
-
This is a **GenAI-Logic (aka API Logic Server) project** - a complete, working microservice - auto-generated from a database schema.
|
|
6
|
-
|
|
7
|
-
## ⚠️ IMPORTANT: What's Already Built
|
|
8
|
-
|
|
9
|
-
**DO NOT recreate these - they're already working:**
|
|
10
|
-
|
|
11
|
-
1. **Admin Web Application** - Live at `http://localhost:5656`
|
|
12
|
-
2. **REST API Endpoints** - All database tables exposed at `/api/*`
|
|
13
|
-
3. **Database Models** - Complete SQLAlchemy ORM in `database/models.py`
|
|
14
|
-
4. **Authentication System** - JWT-based auth framework
|
|
15
|
-
5. **Business Logic Engine** - Declarative rules system
|
|
16
|
-
|
|
17
|
-
## 🎯 Common Tasks
|
|
18
|
-
|
|
19
|
-
If the user asks "what do I do now?", these subsections are good suggestions.
|
|
20
|
-
|
|
21
|
-
List these as choices, do not just do all of them at once - that would be overwhelming.
|
|
22
|
-
|
|
23
|
-
### 🚀 To Run This Project
|
|
24
|
-
|
|
25
|
-
Use F5 (pre-configured run configuration - supports debugger for server logic), or (when focused on client apps):
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
|
-
python api_logic_server_run.py
|
|
29
|
-
# Then open: http://localhost:5656
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
### Adding Business Logic
|
|
33
|
-
Use `docs/training` to accept Natural Language logic, and translate it into rules like:
|
|
34
|
-
|
|
35
|
-
```python
|
|
36
|
-
# Edit: logic/declare_logic.py
|
|
37
|
-
Rule.sum(derive=Customer.Balance, as_sum_of=Order.AmountTotal)
|
|
38
|
-
Rule.constraint(validate=Customer, as_condition=lambda row: row.Balance <= row.CreditLimit)
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
Generally CoPilot solicits Natural Language logic for translation (see logic/logic_discovery/readme_logic_discovery.md),
|
|
42
|
-
but you can also offer to suggest rules.
|
|
43
|
-
|
|
44
|
-
### Adding MCP
|
|
45
|
-
|
|
46
|
-
The API is automatically MCP-enabled.
|
|
47
|
-
|
|
48
|
-
To add MCP Client (requires OpenAI key):
|
|
49
|
-
|
|
50
|
-
```bash
|
|
51
|
-
# Add MCP Client
|
|
52
|
-
genai-logic genai-add-mcp-client
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
### Configuring Admin UI
|
|
56
|
-
|
|
57
|
-
This is built when project is created - no need to add it.
|
|
58
|
-
Customize by editing the underlying yaml.
|
|
59
|
-
|
|
60
|
-
```yaml
|
|
61
|
-
# Edit: ui/admin/admin.yaml
|
|
62
|
-
resources:
|
|
63
|
-
Customer:
|
|
64
|
-
attributes:
|
|
65
|
-
- name: CompanyName
|
|
66
|
-
search: true
|
|
67
|
-
sort: true
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
### Create and Customize React Apps
|
|
71
|
-
|
|
72
|
-
Complete customization is provided by generating a React Application (requires OpenAI key, Node):
|
|
73
|
-
|
|
74
|
-
```bash
|
|
75
|
-
# Create: ui/admin/my-app-name
|
|
76
|
-
genai-logic genai-add-app --app-name=my-app-name --vibe
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
Then, `npm install` and `npm start`
|
|
80
|
-
|
|
81
|
-
Temporary restriction: security must be disabled.
|
|
82
|
-
|
|
83
|
-
Customize using CoPilot chat, with `docs/training`.
|
|
84
|
-
|
|
85
|
-
### Security - Role-Based Access Control
|
|
86
|
-
|
|
87
|
-
Configure:
|
|
88
|
-
```
|
|
89
|
-
als add-auth --provider-type=sql --db-url=
|
|
90
|
-
als add-auth --provider-type=sql --db_url=postgresql://postgres:p@localhost/authdb
|
|
91
|
-
|
|
92
|
-
als add-auth --provider-type=keycloak --db-url=localhost
|
|
93
|
-
als add-auth --provider-type=keycloak --db-url=hardened
|
|
94
|
-
|
|
95
|
-
als add-auth --provider-type=None # to disable
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
Keycloak quick start [(more information here:)](https://apilogicserver.github.io/Docs/Security-Keycloak/)
|
|
99
|
-
```bash
|
|
100
|
-
cd devops/keycloak
|
|
101
|
-
docker compose up
|
|
102
|
-
als add-auth --provider-type=keycloak --db-url=localhost
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
For more on KeyCloak: https://apilogicserver.github.io/Docs/Security-Keycloak/
|
|
106
|
-
|
|
107
|
-
Declaration:
|
|
108
|
-
```python
|
|
109
|
-
# Edit: security/declare_security.py
|
|
110
|
-
Grant(on_entity=Customer, to_role=sales, filter=lambda: Customer.SalesRep == current_user())
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
### Adding Custom API Endpoints
|
|
114
|
-
```python
|
|
115
|
-
# Edit: api/customize_api.py
|
|
116
|
-
@app.route('/api/custom-endpoint')
|
|
117
|
-
def my_endpoint():
|
|
118
|
-
return {"message": "Custom endpoint"}
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
### Customize Models - Add Derived attributes
|
|
122
|
-
|
|
123
|
-
Here is a sample derived attribute, `proper_salary`:
|
|
124
|
-
|
|
125
|
-
```python
|
|
126
|
-
|
|
127
|
-
# add derived attribute: https://github.com/thomaxxl/safrs/blob/master/examples/demo_pythonanywhere_com.py
|
|
128
|
-
@add_method(models.Employee)
|
|
129
|
-
@jsonapi_attr
|
|
130
|
-
def __proper_salary__(self): # type: ignore [no-redef]
|
|
131
|
-
import database.models as models
|
|
132
|
-
import decimal
|
|
133
|
-
if isinstance(self, models.Employee):
|
|
134
|
-
rtn_value = self.Salary
|
|
135
|
-
if rtn_value is None:
|
|
136
|
-
rtn_value = decimal.Decimal('0')
|
|
137
|
-
rtn_value = decimal.Decimal('1.25') * rtn_value
|
|
138
|
-
self._proper_salary = int(rtn_value)
|
|
139
|
-
return self._proper_salary
|
|
140
|
-
else:
|
|
141
|
-
rtn_value = decimal.Decimal('0')
|
|
142
|
-
self._proper_salary = int(rtn_value)
|
|
143
|
-
return self._proper_salary
|
|
144
|
-
|
|
145
|
-
@add_method(models.Employee)
|
|
146
|
-
@__proper_salary__.setter
|
|
147
|
-
def _proper_salary(self, value): # type: ignore [no-redef]
|
|
148
|
-
self._proper_salary = value
|
|
149
|
-
print(f'_proper_salary={self._proper_salary}')
|
|
150
|
-
pass
|
|
151
|
-
|
|
152
|
-
models.Employee.ProperSalary = __proper_salary__
|
|
153
|
-
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
When customizing SQLAlchemy models:
|
|
157
|
-
|
|
158
|
-
Don't use direct comparisons with database fields in computed properties
|
|
159
|
-
Convert to Python values first using float(), int(), str()
|
|
160
|
-
Use property() function instead of @jsonapi_attr for computed properties
|
|
161
|
-
Always add error handling for type conversions
|
|
162
|
-
|
|
163
|
-
## 📁 Key Directories
|
|
164
|
-
|
|
165
|
-
- `logic/` - Business rules (declarative)
|
|
166
|
-
- `api/` - REST API customization
|
|
167
|
-
- `security/` - Authentication/authorization
|
|
168
|
-
- `database/` - Data models and schemas
|
|
169
|
-
- `ui/admin/` - Admin interface configuration
|
|
170
|
-
- `ui/app/` - Alternative Angular admin app
|
|
171
|
-
|
|
172
|
-
## 💡 Helpful Context
|
|
173
|
-
|
|
174
|
-
- This uses Flask + SQLAlchemy + SAFRS for JSON:API
|
|
175
|
-
- Admin UI is React-based with automatic CRUD generation
|
|
176
|
-
- Business logic uses LogicBank (declarative rule engine)
|
|
177
|
-
- Everything is auto-generated from database introspection
|
|
178
|
-
- Focus on CUSTOMIZATION, not re-creation
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
The diagram below illustrates a simple path for enacting changes to the data model, and using [Alembic](https://alembic.sqlalchemy.org/en/latest/index.html) to automate the database changes:
|
|
2
|
-
|
|
3
|
-
1. Update `database/models.py` (e.g., add columns, tables)
|
|
4
|
-
2. Use alembic to compute the revisions
|
|
5
|
-
```bash
|
|
6
|
-
cd database
|
|
7
|
-
alembic revision --autogenerate -m "Added Tables and Columns"
|
|
8
|
-
```
|
|
9
|
-
3. Edit the revision file to signify your understanding (see below)
|
|
10
|
-
4. Activate the change
|
|
11
|
-
```bash
|
|
12
|
-
alembic upgrade head
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-

|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
Then, run `rebuild-from-model`. For more information, see [Database Design Changes](https://apilogicserver.github.io/Docs/Database-Changes/).
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
from sqlalchemy.ext.declarative import declarative_base
|
|
2
|
-
from sqlalchemy import Column, DECIMAL, Date, ForeignKey, Integer, String
|
|
3
|
-
from safrs import SAFRSBase
|
|
4
|
-
from flask_login import UserMixin
|
|
5
|
-
import safrs, flask_sqlalchemy
|
|
6
|
-
from safrs import jsonapi_attr
|
|
7
|
-
from flask_sqlalchemy import SQLAlchemy
|
|
8
|
-
from datetime import datetime
|
|
9
|
-
|
|
10
|
-
Base = declarative_base() # type: flask_sqlalchemy.model.DefaultMeta
|
|
11
|
-
#vh new x
|
|
12
|
-
@classmethod
|
|
13
|
-
def jsonapi_filter(cls):
|
|
14
|
-
"""
|
|
15
|
-
Use this to override SAFRS JSON:API filtering
|
|
16
|
-
|
|
17
|
-
Returns:
|
|
18
|
-
_type_: SQLAlchemy query filter
|
|
19
|
-
"""
|
|
20
|
-
from sqlalchemy import text, or_, and_
|
|
21
|
-
from flask import request
|
|
22
|
-
expressions = []
|
|
23
|
-
sqlWhere = ""
|
|
24
|
-
query = cls._s_query
|
|
25
|
-
if args := request.args:
|
|
26
|
-
from api.system.expression_parser import advancedFilter
|
|
27
|
-
expressions, sqlWhere = advancedFilter(cls, args)
|
|
28
|
-
if sqlWhere != "":
|
|
29
|
-
return query.filter(text(sqlWhere))
|
|
30
|
-
else:
|
|
31
|
-
return query.filter(or_(*expressions))
|
|
32
|
-
|
|
33
|
-
class SAFRSBaseX(SAFRSBase, safrs.DB.Model):
|
|
34
|
-
__abstract__ = True
|
|
35
|
-
if do_enable_ont_advanced_filters := False:
|
|
36
|
-
jsonapi_filter = jsonapi_filter
|
|
37
|
-
|
|
38
|
-
def _s_parse_attr_value(self, attr_name: str, attr_val: any):
|
|
39
|
-
"""
|
|
40
|
-
Parse the given jsonapi attribute value so it can be stored in the db
|
|
41
|
-
:param attr_name: attribute name
|
|
42
|
-
:param attr_val: attribute value
|
|
43
|
-
:return: parsed value
|
|
44
|
-
"""
|
|
45
|
-
attr = self.__class__._s_jsonapi_attrs.get(attr_name, None)
|
|
46
|
-
if hasattr(attr, "type"): # pragma: no cover
|
|
47
|
-
|
|
48
|
-
if str(attr.type) in ["DATE", "DATETIME"] and attr_val:
|
|
49
|
-
try:
|
|
50
|
-
attr_val = attr_val.replace("T", " ")
|
|
51
|
-
datetime.strptime(attr_val, '%Y-%m-%d %H:%M')
|
|
52
|
-
attr_val += ":00"
|
|
53
|
-
except ValueError:
|
|
54
|
-
pass
|
|
55
|
-
except Exception as exc:
|
|
56
|
-
safrs.log.warning(exc)
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
return super()._s_parse_attr_value(attr_name, attr_val)
|
|
60
|
-
|
|
61
|
-
class TestBase(Base):
|
|
62
|
-
__abstract__ = True
|
|
63
|
-
def __init__(self, *args, **kwargs):
|
|
64
|
-
for name, val in kwargs.items():
|
|
65
|
-
col = getattr(self.__class__, name)
|
|
66
|
-
if 'amount_total' == name:
|
|
67
|
-
debug_stop = 'stop'
|
|
68
|
-
if val is not None:
|
|
69
|
-
if str(col.type) in ["DATE", "DATETIME"]:
|
|
70
|
-
pass
|
|
71
|
-
else:
|
|
72
|
-
kwargs[name] = col.type.python_type(val)
|
|
73
|
-
return super().__init__(*args, **kwargs)
|
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
from sqlalchemy.ext.declarative import declarative_base
|
|
3
|
-
from sqlalchemy import Column, DECIMAL, Date, ForeignKey, Integer, String
|
|
4
|
-
from safrs import SAFRSBase, ValidationError
|
|
5
|
-
from flask_login import UserMixin
|
|
6
|
-
import safrs, flask_sqlalchemy
|
|
7
|
-
from safrs import jsonapi_attr
|
|
8
|
-
from flask_sqlalchemy import SQLAlchemy
|
|
9
|
-
from datetime import datetime
|
|
10
|
-
import operator
|
|
11
|
-
import json
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
Base = declarative_base() # type: flask_sqlalchemy.model.DefaultMeta
|
|
15
|
-
#vh new x
|
|
16
|
-
@classmethod
|
|
17
|
-
def jsonapi_filter(cls):
|
|
18
|
-
"""
|
|
19
|
-
Use this to override SAFRS JSON:API filtering
|
|
20
|
-
|
|
21
|
-
Returns:
|
|
22
|
-
_type_: SQLAlchemy query filter
|
|
23
|
-
"""
|
|
24
|
-
from sqlalchemy import text, or_, and_
|
|
25
|
-
from flask import request
|
|
26
|
-
expressions = []
|
|
27
|
-
sqlWhere = ""
|
|
28
|
-
query = cls._s_query
|
|
29
|
-
if args := request.args:
|
|
30
|
-
from api.system.expression_parser import advancedFilter
|
|
31
|
-
expressions, sqlWhere = advancedFilter(cls, args)
|
|
32
|
-
if sqlWhere != "":
|
|
33
|
-
return query.filter(text(sqlWhere))
|
|
34
|
-
else:
|
|
35
|
-
return query.filter(and_(*expressions))
|
|
36
|
-
|
|
37
|
-
class SAFRSBaseX(SAFRSBase, safrs.DB.Model):
|
|
38
|
-
__abstract__ = True
|
|
39
|
-
if do_enable_ont_advanced_filters := False:
|
|
40
|
-
jsonapi_filter = jsonapi_filter
|
|
41
|
-
|
|
42
|
-
def _s_parse_attr_value(self, attr_name: str, attr_val: any):
|
|
43
|
-
"""
|
|
44
|
-
Parse the given jsonapi attribute value so it can be stored in the db
|
|
45
|
-
:param attr_name: attribute name
|
|
46
|
-
:param attr_val: attribute value
|
|
47
|
-
:return: parsed value
|
|
48
|
-
"""
|
|
49
|
-
attr = self.__class__._s_jsonapi_attrs.get(attr_name, None)
|
|
50
|
-
if hasattr(attr, "type"): # pragma: no cover
|
|
51
|
-
|
|
52
|
-
if str(attr.type) in ["DATE", "DATETIME"] and attr_val:
|
|
53
|
-
try:
|
|
54
|
-
attr_val = attr_val.replace("T", " ")
|
|
55
|
-
datetime.strptime(attr_val, '%Y-%m-%d %H:%M')
|
|
56
|
-
attr_val += ":00"
|
|
57
|
-
except ValueError:
|
|
58
|
-
pass
|
|
59
|
-
except Exception as exc:
|
|
60
|
-
safrs.log.warning(exc)
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
return super()._s_parse_attr_value(attr_name, attr_val)
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
@classmethod
|
|
67
|
-
def _s_filter(cls, *filter_args, **filter_kwargs):
|
|
68
|
-
"""
|
|
69
|
-
Apply a filter to this model
|
|
70
|
-
:param filter_args: A list of filters information to apply, passed as a request URL parameter.
|
|
71
|
-
Each filter object has the following fields:
|
|
72
|
-
- name: The name of the field you want to filter on.
|
|
73
|
-
- op: The operation you want to use (all sqlalchemy operations are available). The valid values are:
|
|
74
|
-
- like: Invoke SQL like (or "ilike", "match", "notilike")
|
|
75
|
-
- eq: check if field is equal to something
|
|
76
|
-
- ge: check if field is greater than or equal to something
|
|
77
|
-
- gt: check if field is greater than to something
|
|
78
|
-
- ne: check if field is not equal to something
|
|
79
|
-
- is_: check if field is a value
|
|
80
|
-
- is_not: check if field is not a value
|
|
81
|
-
- le: check if field is less than or equal to something
|
|
82
|
-
- lt: check if field is less than to something
|
|
83
|
-
- val: The value that you want to compare.
|
|
84
|
-
:return: sqla query object
|
|
85
|
-
"""
|
|
86
|
-
try:
|
|
87
|
-
filters = json.loads(filter_args[0])
|
|
88
|
-
except json.decoder.JSONDecodeError:
|
|
89
|
-
raise ValidationError("Invalid filter format (see https://github.com/thomaxxl/safrs/wiki)")
|
|
90
|
-
|
|
91
|
-
if not isinstance(filters, list):
|
|
92
|
-
filters = [filters]
|
|
93
|
-
|
|
94
|
-
expressions = []
|
|
95
|
-
query = cls._s_query
|
|
96
|
-
|
|
97
|
-
for filt in filters:
|
|
98
|
-
if not isinstance(filt, dict):
|
|
99
|
-
safrs.log.warning(f"Invalid filter '{filt}'")
|
|
100
|
-
continue
|
|
101
|
-
attr_name = filt.get("name")
|
|
102
|
-
attr_val = filt.get("val")
|
|
103
|
-
if attr_name != "id" and attr_name not in cls._s_jsonapi_attrs:
|
|
104
|
-
raise ValidationError(f'Invalid filter "{filt}", unknown attribute "{attr_name}"')
|
|
105
|
-
|
|
106
|
-
op_name = filt.get("op", "").strip("_")
|
|
107
|
-
attr = cls._s_jsonapi_attrs[attr_name] if attr_name != "id" else cls.id
|
|
108
|
-
if op_name in ["in", "notin"]:
|
|
109
|
-
op = getattr(attr, op_name + "_")
|
|
110
|
-
query = query.filter(op(attr_val))
|
|
111
|
-
elif op_name in ["like", "ilike", "match", "notilike"] and hasattr(attr, "like"):
|
|
112
|
-
# => attr is Column or InstrumentedAttribute
|
|
113
|
-
like = getattr(attr, op_name)
|
|
114
|
-
expressions.append(like(attr_val))
|
|
115
|
-
elif not hasattr(operator, op_name):
|
|
116
|
-
raise ValidationError(f'Invalid filter "{filt}", unknown operator "{op_name}"')
|
|
117
|
-
else:
|
|
118
|
-
op = getattr(operator, op_name)
|
|
119
|
-
expressions.append(op(attr, attr_val))
|
|
120
|
-
|
|
121
|
-
if len(filters) > 1:
|
|
122
|
-
return query.filter(operator.and_(*expressions))
|
|
123
|
-
else:
|
|
124
|
-
return query.filter(*expressions)
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
class TestBase(Base):
|
|
128
|
-
__abstract__ = True
|
|
129
|
-
def __init__(self, *args, **kwargs):
|
|
130
|
-
for name, val in kwargs.items():
|
|
131
|
-
col = getattr(self.__class__, name)
|
|
132
|
-
if 'amount_total' == name:
|
|
133
|
-
debug_stop = 'stop'
|
|
134
|
-
if val is not None:
|
|
135
|
-
if str(col.type) in ["DATE", "DATETIME"]:
|
|
136
|
-
pass
|
|
137
|
-
else:
|
|
138
|
-
kwargs[name] = col.type.python_type(val)
|
|
139
|
-
return super().__init__(*args, **kwargs)
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
api_logic_server_cli/sqlacodegen_wrapper/sqlacodegen/sqlacodegen/__pycache__/codegen.cpython-312.pyc
DELETED
|
Binary file
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|