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
|
@@ -12,10 +12,12 @@ ApiLogicServer CLI: given a database url, create [and run] customizable ApiLogic
|
|
|
12
12
|
Called from api_logic_server_cli.py, by instantiating the ProjectRun object.
|
|
13
13
|
'''
|
|
14
14
|
|
|
15
|
-
__version__ = "15.00.
|
|
15
|
+
__version__ = "15.00.54" # last public release: 15.00.52 (15.00.12)
|
|
16
16
|
recent_changes = \
|
|
17
17
|
f'\n\nRecent Changes:\n' +\
|
|
18
|
-
"\t07/
|
|
18
|
+
"\t07/23/2024 - 15.00.54: system vibe support \n"\
|
|
19
|
+
"\t07/20/2024 - 15.00.52: Python 3.13 compatibility fixes - psycopg2→psycopg3, SQLAlchemy 2.0+, pkg_resources→importlib.metadata. mgr dbs \n"\
|
|
20
|
+
"\t07/17/2024 - 15.00.49: venv fix+, ext bldr * fix, copilot vibe tweaks - creation, mcp logic, basic_demo autonums \n"\
|
|
19
21
|
"\t07/10/2024 - 15.00.41: copilot vibe support for logic, UI, MCP, bug[98] \n"\
|
|
20
22
|
"\t06/30/2024 - 15.00.33: Tech Preview: genai-logic genai-add-app --vibe, bug [96, 97] \n"\
|
|
21
23
|
"\t06/10/2024 - 15.00.12: MCP Security, win fixes for readme, graphics quotes \n"\
|
|
@@ -389,6 +391,7 @@ def create_project_and_overlay_prototypes(project: 'ProjectRun', msg: str) -> st
|
|
|
389
391
|
joinpath('prototypes/basic_demo')
|
|
390
392
|
recursive_overwrite(nw_dir, project.project_directory)
|
|
391
393
|
create_utils.copy_md(project = project, from_doc_file = "Sample-Basic-Demo.md")
|
|
394
|
+
create_utils.copy_md(project = project, from_doc_file = "Sample-Basic-Demo-Vibe.md", to_project_file="README-VIBE.md")
|
|
392
395
|
|
|
393
396
|
|
|
394
397
|
if project.db_url == "mysql+pymysql://root:p@localhost:3306/classicmodels":
|
|
@@ -463,6 +466,13 @@ def create_project_and_overlay_prototypes(project: 'ProjectRun', msg: str) -> st
|
|
|
463
466
|
copy_sqlite = True
|
|
464
467
|
if copy_sqlite == False or "sqlite" not in project.abs_db_url:
|
|
465
468
|
db_uri = get_windows_path_with_slashes(project.abs_db_url)
|
|
469
|
+
|
|
470
|
+
# Convert PostgreSQL URL for Python 3.13+ compatibility
|
|
471
|
+
import sys
|
|
472
|
+
if sys.version_info >= (3, 13) and db_uri.startswith('postgresql://'):
|
|
473
|
+
db_uri = db_uri.replace('postgresql://', 'postgresql+psycopg://')
|
|
474
|
+
log.debug(f'.. ..Converted PostgreSQL URL for Python 3.13+: {db_uri}')
|
|
475
|
+
|
|
466
476
|
create_utils.replace_string_in_file(search_for="replace_db_url",
|
|
467
477
|
replace_with=db_uri,
|
|
468
478
|
in_file=f'{project.project_directory}/config/config.py')
|
|
@@ -915,7 +925,10 @@ def start_open_with(project: Project):
|
|
|
915
925
|
|
|
916
926
|
def invoke_extended_builder(builder_path, db_url, project_directory, model_creation_services):
|
|
917
927
|
# spec = importlib.util.spec_from_file_location("module.name", "/path/to/file.py")
|
|
918
|
-
|
|
928
|
+
use_builder_path = builder_path
|
|
929
|
+
if builder_path == '*':
|
|
930
|
+
use_builder_path = Path('extended_builder.py')
|
|
931
|
+
spec = importlib.util.spec_from_file_location("module.name", use_builder_path)
|
|
919
932
|
extended_builder = importlib.util.module_from_spec(spec)
|
|
920
933
|
spec.loader.exec_module(extended_builder) # runs "bare" module code (e.g., initialization)
|
|
921
934
|
extended_builder.extended_builder(db_url, project_directory, model_creation_services) # extended_builder.MyClass()
|
|
@@ -1194,8 +1207,8 @@ class ProjectRun(Project):
|
|
|
1194
1207
|
log.debug(f'.. .. ..Copying sqlite database to: database/{self.bind_key}_db.sqlite')
|
|
1195
1208
|
db_loc = self.abs_db_url.replace("sqlite:///", "")
|
|
1196
1209
|
if os.name == "nt":
|
|
1197
|
-
if db_loc.startswith("C:\C:"): # windows
|
|
1198
|
-
db_loc = db_loc.replace("C:\C:", "C:") # remove unk junk
|
|
1210
|
+
if db_loc.startswith(r"C:\C:"): # windows
|
|
1211
|
+
db_loc = db_loc.replace(r"C:\C:", "C:") # remove unk junk
|
|
1199
1212
|
target_db_loc_actual = str(self.project_directory_path.joinpath(f'database/{self.bind_key}_db.sqlite'))
|
|
1200
1213
|
# target: /Users/val/dev/ApiLogicServer/ApiLogicServer-dev/org_git/servers/NW_NoCust/database/Todo_db.sqlite
|
|
1201
1214
|
# e.g., /Users/val/dev/ApiLogicServer/ApiLogicServer-dev/servers/NW_NoCust/database
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
last_created_date: July
|
|
2
|
-
last_created_project_name:
|
|
3
|
-
last_created_version: 15.00.
|
|
1
|
+
last_created_date: July 23, 2025 12:12:14
|
|
2
|
+
last_created_project_name: ../../../servers/basic_demo
|
|
3
|
+
last_created_version: 15.00.53
|
api_logic_server_cli/cli.py
CHANGED
|
@@ -188,14 +188,16 @@ def main(ctx):
|
|
|
188
188
|
Creation is from your database (--db-url identifies a SQLAlchemy database)
|
|
189
189
|
|
|
190
190
|
\b
|
|
191
|
-
|
|
191
|
+
Synonym to genai-logic: gail | gal
|
|
192
|
+
\b
|
|
193
|
+
Doc: https://apilogicserver.github.io/Docs/Doc-Home/
|
|
192
194
|
And: https://apilogicserver.github.io/Docs/Database-Connectivity/
|
|
193
195
|
\b
|
|
194
196
|
Suggestions:
|
|
195
197
|
|
|
196
198
|
\b
|
|
197
|
-
|
|
198
|
-
|
|
199
|
+
genai-logic start # create and manage projects
|
|
200
|
+
genai-logic create --db-url= --project-name= # defaults to Northwind sample
|
|
199
201
|
"""
|
|
200
202
|
pass # all commands come through here
|
|
201
203
|
|
|
@@ -1083,13 +1085,13 @@ def genai_iterate(ctx, project_name: str, using: str):
|
|
|
1083
1085
|
help="your_code.py for additional build automation")
|
|
1084
1086
|
@click.option('--include_tables',
|
|
1085
1087
|
default=f'',
|
|
1086
|
-
help="yml for include
|
|
1088
|
+
help="yml for include, exclude")
|
|
1087
1089
|
@click.option('--include-tables', 'include_tables',
|
|
1088
1090
|
default=f'',
|
|
1089
|
-
help="yml for include
|
|
1091
|
+
help="yml for include, exclude")
|
|
1090
1092
|
@click.option('--infer_primary_key/--no_infer_primary_key',
|
|
1091
1093
|
default=False, is_flag=True,
|
|
1092
|
-
help="
|
|
1094
|
+
help="Infer primary_key for unique cols")
|
|
1093
1095
|
@click.option('--infer-primary-key/--no-infer-primary-key', 'infer_primary_key',
|
|
1094
1096
|
default=False, is_flag=True,
|
|
1095
1097
|
help="Infer primary-key for unique cols")
|
|
@@ -1250,22 +1252,22 @@ def create(ctx, project_name: str, db_url: str, not_exposed: str, api_name: str,
|
|
|
1250
1252
|
help="Swagger hostname (default is localhost)")
|
|
1251
1253
|
@click.option('--extended_builder',
|
|
1252
1254
|
default=f'',
|
|
1253
|
-
help="
|
|
1255
|
+
help="your python for additional build automation")
|
|
1254
1256
|
@click.option('--extended-builder', 'extended_builder',
|
|
1255
1257
|
default=f'',
|
|
1256
|
-
help="
|
|
1258
|
+
help="your python for additional build automation")
|
|
1257
1259
|
@click.option('--include_tables',
|
|
1258
1260
|
default=f'',
|
|
1259
|
-
help="yml for include
|
|
1261
|
+
help="yml for include / exclude")
|
|
1260
1262
|
@click.option('--include-tables', 'include_tables',
|
|
1261
1263
|
default=f'',
|
|
1262
|
-
help="yml for include
|
|
1264
|
+
help="yml for include / exclude")
|
|
1263
1265
|
@click.option('--infer_primary_key/--no_infer_primary_key',
|
|
1264
1266
|
default=False, is_flag=True,
|
|
1265
|
-
help="Infer primary
|
|
1267
|
+
help="Infer primary key for unique cols")
|
|
1266
1268
|
@click.option('--infer-primary-key/--no-infer-primary-key', 'infer_primary_key',
|
|
1267
1269
|
default=False, is_flag=True,
|
|
1268
|
-
help="
|
|
1270
|
+
help="Unique cols infer primary key")
|
|
1269
1271
|
@click.pass_context
|
|
1270
1272
|
def create_and_run(ctx, project_name: str, db_url: str, not_exposed: str, api_name: str,
|
|
1271
1273
|
from_git: str,
|
|
@@ -1280,11 +1282,13 @@ def create_and_run(ctx, project_name: str, db_url: str, not_exposed: str, api_na
|
|
|
1280
1282
|
host: str,
|
|
1281
1283
|
port: str,
|
|
1282
1284
|
swagger_host: str,
|
|
1283
|
-
favorites: str,
|
|
1285
|
+
favorites: str,
|
|
1286
|
+
non_favorites: str,
|
|
1284
1287
|
extended_builder: str,
|
|
1285
1288
|
include_tables: str,
|
|
1286
1289
|
multi_api: click.BOOL,
|
|
1287
|
-
opt_locking: str,
|
|
1290
|
+
opt_locking: str,
|
|
1291
|
+
opt_locking_attr: str,
|
|
1288
1292
|
id_column_alias: str,
|
|
1289
1293
|
infer_primary_key: click.BOOL):
|
|
1290
1294
|
"""
|
|
@@ -2122,7 +2126,7 @@ if __name__ == '__main__': # debugger & python command line start here
|
|
|
2122
2126
|
"show-args" in api_logic_server_info_file_dict:
|
|
2123
2127
|
print_args(commands, f'\nCommand Line Arguments:')
|
|
2124
2128
|
python_version = sys.version_info
|
|
2125
|
-
assert python_version[0] >= 3 and python_version[1] in [10,11,12], \
|
|
2126
|
-
"... Requires Python >=3.10, !=3.11.0, !=3.11.1, 3.12"
|
|
2129
|
+
assert python_version[0] >= 3 and python_version[1] in [10,11,12, 13], \
|
|
2130
|
+
"... Requires Python >=3.10, !=3.11.0, !=3.11.1, 3.12, 3.13"
|
|
2127
2131
|
main()
|
|
2128
2132
|
|
|
@@ -197,6 +197,12 @@ def copy_md(project, from_doc_file: str, to_project_file: str = "README.md"):
|
|
|
197
197
|
else:
|
|
198
198
|
each_line = each_line.replace('.md', '') # hmm... todo: find out why this exists
|
|
199
199
|
pass
|
|
200
|
+
if from_doc_file == 'Sample-Basic-Demo-Vibe.md' and 'title=' in each_line:
|
|
201
|
+
# extract the quoted text after 'title=' into title
|
|
202
|
+
match = re.search(r'title\s*=\s*["\']([^"\']+)["\']', each_line)
|
|
203
|
+
if match:
|
|
204
|
+
title = match.group(1)
|
|
205
|
+
readme_lines_md.append('**' + title + ':**\n')
|
|
200
206
|
readme_lines_md.append(each_line)
|
|
201
207
|
with open(str(to_file), "w") as readme_file:
|
|
202
208
|
readme_file.writelines(readme_lines_md)
|
|
@@ -293,10 +299,13 @@ def get_abs_db_url(msg, project: Project, is_auth: bool = False):
|
|
|
293
299
|
else:
|
|
294
300
|
rtn_abs_db_url = f'sqlite:///{str(project.api_logic_server_dir_path.joinpath("prototypes/sample_ai/database/chatgpt/sample_ai_items.sqlite"))}'
|
|
295
301
|
# log.info('.. using installed nw sample database')
|
|
296
|
-
else:
|
|
302
|
+
else: # for win, might be: sqlite:////C:\\Users\\val\\dev\\ApiLogicServer\\ApiLogicServer-dev\\org_git\\ApiLogicServer-src\\api_logic_server_cli\\database\\mcp.sqlite
|
|
297
303
|
url = url_to_process[10: len(url_to_process)]
|
|
304
|
+
if url_to_process.startswith('sqlite:////c:'):
|
|
305
|
+
url = url_to_process[11: len(url_to_process)]
|
|
298
306
|
rtn_abs_db_url = abspath(url)
|
|
299
307
|
rtn_abs_db_url = 'sqlite:///' + rtn_abs_db_url
|
|
308
|
+
pass
|
|
300
309
|
elif url_to_process == 'sqlsvr-sample': # work-around - VSCode run config arg parsing
|
|
301
310
|
rtn_abs_db_url = 'mssql+pyodbc://sa:Posey3861@localhost:1433/SampleDB?driver=ODBC+Driver+18+for+SQL+Server&trusted_connection=no&Encrypt=no'
|
|
302
311
|
elif url_to_process == 'sqlsvr-nwlogic': # work-around - VSCode run config arg parsing
|
api_logic_server_cli/manager.py
CHANGED
|
@@ -36,9 +36,9 @@ def create_manager(clean: bool, open_with: str, api_logic_server_path: Path,
|
|
|
36
36
|
samples (bool, optional): Whether to create large samples (prevent win max file length)
|
|
37
37
|
"""
|
|
38
38
|
|
|
39
|
-
def
|
|
39
|
+
def copy_sqlite_dbs(cli_path: Path, mgr_path: Path):
|
|
40
40
|
"""
|
|
41
|
-
|
|
41
|
+
Copy sample sqlite databases to mgr/samples/dbs (clearer than db abbreviations).
|
|
42
42
|
|
|
43
43
|
Args:
|
|
44
44
|
cli_path (Path): loc of cli.py in the manager's venv
|
|
@@ -48,16 +48,27 @@ def create_manager(clean: bool, open_with: str, api_logic_server_path: Path,
|
|
|
48
48
|
Creates a symbolic link from 'cli_path/database/basic_demo.sqlite' to 'mgr_path/samples/dbs/basic_demo'.
|
|
49
49
|
|
|
50
50
|
"""
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
51
|
+
if use_syn_link := False:
|
|
52
|
+
# could create symbolic link - thanks https://www.geeksforgeeks.org/python/python-os-symlink-method/
|
|
53
|
+
# but this fails on windows due to permissions
|
|
54
|
+
try:
|
|
55
|
+
os.symlink(cli_path.parent / 'database/basic_demo.sqlite', mgr_path / 'samples/dbs/basic_demo.sqlite')
|
|
56
|
+
os.symlink(cli_path.parent / 'database/nw-gold.sqlite', mgr_path / 'samples/dbs/nw.sqlite')
|
|
57
|
+
os.symlink(cli_path.parent / 'database/Chinook_Sqlite.sqlite', mgr_path / 'samples/dbs/chinook.sqlite')
|
|
58
|
+
os.symlink(cli_path.parent / 'database/classicmodels.sqlite', mgr_path / 'samples/dbs/classicmodels.sqlite')
|
|
59
|
+
log.debug("✅ Manager Creation - SymLink created: samples/dbs/")
|
|
60
|
+
except Exception as e:
|
|
61
|
+
log.debug(f"❌ Manager Creation - Copy samples/dbs SymLink creation failed: {str(e)}")
|
|
62
|
+
else:
|
|
63
|
+
try:
|
|
64
|
+
copyfile(cli_path.parent / 'database/basic_demo.sqlite', mgr_path / 'samples/dbs/basic_demo.sqlite')
|
|
65
|
+
copyfile(cli_path.parent / 'database/nw-gold.sqlite', mgr_path / 'samples/dbs/nw.sqlite')
|
|
66
|
+
copyfile(cli_path.parent / 'database/Chinook_Sqlite.sqlite', mgr_path / 'samples/dbs/chinook.sqlite')
|
|
67
|
+
copyfile(cli_path.parent / 'database/classicmodels.sqlite', mgr_path / 'samples/dbs/classicmodels.sqlite')
|
|
68
|
+
copyfile(cli_path.parent / 'database/todos.sqlite', mgr_path / 'samples/dbs/todos.sqlite')
|
|
69
|
+
log.debug("✅ Manager Creation - Created: samples/dbs/")
|
|
70
|
+
except Exception as e:
|
|
71
|
+
log.debug(f"❌ Manager Creation - Copy samples/dbs creation failed: {str(e)}")
|
|
61
72
|
|
|
62
73
|
|
|
63
74
|
log = logging.getLogger(__name__)
|
|
@@ -218,7 +229,7 @@ def create_manager(clean: bool, open_with: str, api_logic_server_path: Path,
|
|
|
218
229
|
create_utils.replace_string_in_file(search_for = 'cli_path',
|
|
219
230
|
replace_with=str(cli_str),
|
|
220
231
|
in_file=vscode_launch_path)
|
|
221
|
-
|
|
232
|
+
copy_sqlite_dbs(cli_path=cli_path, mgr_path=to_dir)
|
|
222
233
|
|
|
223
234
|
if env_path.exists():
|
|
224
235
|
create_utils.replace_string_in_file(search_for = 'APILOGICSERVER_AUTO_OPEN=code',
|
|
@@ -37,11 +37,14 @@ python api_logic_server_run.py
|
|
|
37
37
|
Rule.sum(derive=Customer.Balance, as_sum_of=Order.AmountTotal)
|
|
38
38
|
Rule.constraint(validate=Customer, as_condition=lambda row: row.Balance <= row.CreditLimit)
|
|
39
39
|
```
|
|
40
|
+
|
|
41
|
+
As described in `docs/training/logic_bank_api.prompt`, logic includes rules for sums, formulas, constraints, and more. They also include events, which are used to trigger actions like sending emails or updating related records.
|
|
42
|
+
|
|
40
43
|
For project `basic_demo`, the best place to begin is to provide CoPilot with the natural language logic below. CoPilot will then offer to translate the logic into LogicBank rules. Also
|
|
41
44
|
1. Provide the analysis (below) showing the 44X code reduction.
|
|
42
45
|
2. Stress the importance of business logic - it's half the project, and requires an underlying rules engine. Using AI alone is not sufficient - you will wind up with procedural code, with the issues noted in the analysis below.
|
|
43
46
|
|
|
44
|
-
Here's the natural language logic to provide to
|
|
47
|
+
Here's the natural language logic to provide to CoPilot:
|
|
45
48
|
|
|
46
49
|
```text
|
|
47
50
|
Use case: Check Credit
|
|
@@ -126,6 +129,8 @@ Then, `npm install` and `npm start`
|
|
|
126
129
|
|
|
127
130
|
Temporary restriction: security must be disabled.
|
|
128
131
|
|
|
132
|
+
**IMPORTANT**: When working with React apps, ALWAYS read `docs/training` first. This file contains critical data access provider configuration that was built when the project was created. The data provider handles JSON:API communication and record context - ignore this at your peril.
|
|
133
|
+
|
|
129
134
|
Customize using CoPilot chat, with `docs/training`.
|
|
130
135
|
|
|
131
136
|
### Security - Role-Based Access Control
|
|
@@ -164,9 +169,13 @@ def my_endpoint():
|
|
|
164
169
|
return {"message": "Custom endpoint"}
|
|
165
170
|
```
|
|
166
171
|
|
|
167
|
-
### Customize Models - Add Attributes
|
|
172
|
+
### Customize Models - Add Tables, Attributes
|
|
173
|
+
|
|
174
|
+
Update `database/model.py`, and use `database/alembic` to update the database (highly impactful - request permission). This is *generally* preferrable to updating the database directly, since some platforms may not have database CLI tools.
|
|
168
175
|
|
|
169
|
-
|
|
176
|
+
If altering `database/models.py`, be sure to follow the patterns shown in the existing models. Note they not typically contain a `__bind_key__`.
|
|
177
|
+
|
|
178
|
+
```python
|
|
170
179
|
|
|
171
180
|
### Addressing `Missing Attributes` during logic loading at project startup
|
|
172
181
|
|
|
@@ -216,6 +225,33 @@ Convert to Python values first using float(), int(), str()
|
|
|
216
225
|
Use property() function instead of @jsonapi_attr for computed properties
|
|
217
226
|
Always add error handling for type conversions
|
|
218
227
|
|
|
228
|
+
### Adding events
|
|
229
|
+
LogicBank rules are the preferred approach to logic, but you will sometimes need to add events. This is done in `logic/declare_logic.py` (important: the function MUST come first):
|
|
230
|
+
|
|
231
|
+
```python
|
|
232
|
+
# Example: Log email activity after SysEmail is committed
|
|
233
|
+
|
|
234
|
+
def sys_email_after_commit(row: models.SysEmail, old_row: models.SysEmail, logic_row: LogicRow):
|
|
235
|
+
"""
|
|
236
|
+
After SysEmail is committed, log 'email sent'
|
|
237
|
+
unless the customer has opted out
|
|
238
|
+
"""
|
|
239
|
+
if not row.customer.email_opt_out:
|
|
240
|
+
logic_row.log(f"📧 Email sent to {row.customer.name} - Subject: {row.subject}")
|
|
241
|
+
else:
|
|
242
|
+
logic_row.log(f"🚫 Email blocked for {row.customer.name} - Customer opted out")
|
|
243
|
+
|
|
244
|
+
Rule.commit_row_event(on_class=SysEmail, calling=sys_email_after_commit)
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
LogicBank event types include:
|
|
248
|
+
- `Rule.commit_row_event()` - fires after transaction commits
|
|
249
|
+
- `Rule.after_insert()` - fires after row insert
|
|
250
|
+
- `Rule.after_update()` - fires after row update
|
|
251
|
+
- `Rule.after_delete()` - fires after row delete
|
|
252
|
+
|
|
253
|
+
All events receive `(row, old_row, logic_row)` parameters and should use `logic_row.log()` for logging.
|
|
254
|
+
|
|
219
255
|
## 📁 Key Directories
|
|
220
256
|
|
|
221
257
|
- `logic/` - Business rules (declarative)
|
|
@@ -133,6 +133,12 @@ class Config:
|
|
|
133
133
|
SQLALCHEMY_DATABASE_URI : typing.Optional[str] = f"replace_db_url"
|
|
134
134
|
# override SQLALCHEMY_DATABASE_URI here as required
|
|
135
135
|
|
|
136
|
+
# Python 3.13+ compatibility: Convert PostgreSQL URLs to use psycopg3
|
|
137
|
+
import sys
|
|
138
|
+
if sys.version_info >= (3, 13) and SQLALCHEMY_DATABASE_URI.startswith('postgresql://'):
|
|
139
|
+
SQLALCHEMY_DATABASE_URI = SQLALCHEMY_DATABASE_URI.replace('postgresql://', 'postgresql+psycopg://')
|
|
140
|
+
app_logger.debug(f'config.py - converted PostgreSQL URL for Python 3.13+: {SQLALCHEMY_DATABASE_URI}')
|
|
141
|
+
|
|
136
142
|
BACKTIC_AS_QUOTE = False # use backtic as quote for table names for API Bridge
|
|
137
143
|
if SQLALCHEMY_DATABASE_URI.startswith("mysql") or SQLALCHEMY_DATABASE_URI.startswith("mariadb"):
|
|
138
144
|
BACKTIC_AS_QUOTE = True
|
|
@@ -145,6 +151,11 @@ class Config:
|
|
|
145
151
|
if os.getenv('SQLALCHEMY_DATABASE_URI'): # e.g. export SECURITY_ENABLED=true
|
|
146
152
|
SQLALCHEMY_DATABASE_URI = os.getenv('SQLALCHEMY_DATABASE_URI')
|
|
147
153
|
app_logger.debug(f'.. overridden from env variable: {SQLALCHEMY_DATABASE_URI}')
|
|
154
|
+
|
|
155
|
+
# Python 3.13+ compatibility: Convert PostgreSQL URLs to use psycopg3 (for env override)
|
|
156
|
+
if sys.version_info >= (3, 13) and SQLALCHEMY_DATABASE_URI.startswith('postgresql://'):
|
|
157
|
+
SQLALCHEMY_DATABASE_URI = SQLALCHEMY_DATABASE_URI.replace('postgresql://', 'postgresql+psycopg://')
|
|
158
|
+
app_logger.debug(f'config.py - converted PostgreSQL URL for Python 3.13+: {SQLALCHEMY_DATABASE_URI}')
|
|
148
159
|
|
|
149
160
|
|
|
150
161
|
# KEYCLOAK Args
|
|
@@ -178,6 +189,10 @@ class Config:
|
|
|
178
189
|
# Begin Multi-Database URLs (from ApiLogicServer add-db...)
|
|
179
190
|
auth_db_path = str(project_path.joinpath('database/authentication_db.sqlite'))
|
|
180
191
|
SQLALCHEMY_DATABASE_URI_AUTHENTICATION = f'sqlite:///{auth_db_path}'
|
|
192
|
+
# Python 3.13+ compatibility: Convert PostgreSQL URLs to use psycopg3 (for env override)
|
|
193
|
+
if sys.version_info >= (3, 13) and SQLALCHEMY_DATABASE_URI_AUTHENTICATION.startswith('postgresql://'):
|
|
194
|
+
SQLALCHEMY_DATABASE_URI_AUTHENTICATION = SQLALCHEMY_DATABASE_URI_AUTHENTICATION.replace('postgresql://', 'postgresql+psycopg://')
|
|
195
|
+
app_logger.debug(f'config.py - converted PostgreSQL URL for Python 3.13+: {SQLALCHEMY_DATABASE_URI_AUTHENTICATION}')
|
|
181
196
|
app_logger.info(f'config.py - SQLALCHEMY_DATABASE_URI_AUTHENTICATION: {SQLALCHEMY_DATABASE_URI_AUTHENTICATION}\n')
|
|
182
197
|
|
|
183
198
|
# as desired, use env variable: export SQLALCHEMY_DATABASE_URI='sqlite:////Users/val/dev/servers/docker_api_logic_project/database/db.sqliteXX'
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import subprocess
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
'''
|
|
6
|
+
Pushes the current database/models.py to the database.
|
|
7
|
+
python database/alembic/alembic_run.py [--non-interactive]
|
|
8
|
+
'''
|
|
9
|
+
|
|
10
|
+
def prompt(msg, non_interactive=False):
|
|
11
|
+
if non_interactive:
|
|
12
|
+
print(f"{msg}")
|
|
13
|
+
print("Running in non-interactive mode...")
|
|
14
|
+
return
|
|
15
|
+
try:
|
|
16
|
+
input(f"{msg}\nPress Enter to continue or Ctrl+C to abort...")
|
|
17
|
+
except EOFError:
|
|
18
|
+
print("Running in non-interactive mode (no stdin available)...")
|
|
19
|
+
return
|
|
20
|
+
|
|
21
|
+
def run(cmd, env=None):
|
|
22
|
+
print(f"Running: {cmd}")
|
|
23
|
+
result = subprocess.run(cmd, shell=True, env=env)
|
|
24
|
+
if result.returncode != 0:
|
|
25
|
+
print(f"Command failed: {cmd}")
|
|
26
|
+
sys.exit(result.returncode)
|
|
27
|
+
|
|
28
|
+
def main():
|
|
29
|
+
# Check for non-interactive mode more safely
|
|
30
|
+
non_interactive = "--non-interactive" in sys.argv
|
|
31
|
+
if not non_interactive:
|
|
32
|
+
try:
|
|
33
|
+
non_interactive = not sys.stdin.isatty()
|
|
34
|
+
except:
|
|
35
|
+
# If we can't check stdin, assume non-interactive
|
|
36
|
+
non_interactive = True
|
|
37
|
+
|
|
38
|
+
orig_dir = os.getcwd()
|
|
39
|
+
# Change to the database directory (parent of alembic directory) where alembic.ini is located
|
|
40
|
+
db_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
41
|
+
print(f"Changing directory to {db_dir}")
|
|
42
|
+
os.chdir(db_dir)
|
|
43
|
+
|
|
44
|
+
env = os.environ.copy()
|
|
45
|
+
env["APILOGICPROJECT_NO_FLASK"] = "True" # ~ export APILOGICPROJECT_NO_FLASK=True
|
|
46
|
+
|
|
47
|
+
print("\n\nThis script will update your database schema to match models.py using Alembic.")
|
|
48
|
+
print("Steps:")
|
|
49
|
+
print("1. Set APILOGICPROJECT_NO_FLASK=True -- eg, export APILOGICPROJECT_NO_FLASK=True")
|
|
50
|
+
print("2. Run: alembic upgrade head")
|
|
51
|
+
print("3. Run: alembic revision --autogenerate -m \"message\"")
|
|
52
|
+
prompt("Ready to proceed?", non_interactive)
|
|
53
|
+
|
|
54
|
+
run("alembic upgrade head", env=env)
|
|
55
|
+
print("Database schema updated to latest migration.")
|
|
56
|
+
|
|
57
|
+
prompt("Now, a new migration will be generated to match models.py.", non_interactive)
|
|
58
|
+
if non_interactive:
|
|
59
|
+
msg = "autogenerated"
|
|
60
|
+
else:
|
|
61
|
+
try:
|
|
62
|
+
msg = input("Enter a message for the migration (default: 'autogenerated'): ") or "autogenerated"
|
|
63
|
+
except EOFError:
|
|
64
|
+
msg = "autogenerated"
|
|
65
|
+
run(f'alembic revision --autogenerate -m "{msg}"', env=env)
|
|
66
|
+
|
|
67
|
+
# Find the latest migration file
|
|
68
|
+
versions_dir = os.path.join(db_dir, "alembic", "versions")
|
|
69
|
+
migration_files = sorted(
|
|
70
|
+
[f for f in os.listdir(versions_dir) if f.endswith(".py")],
|
|
71
|
+
key=lambda x: os.path.getmtime(os.path.join(versions_dir, x)),
|
|
72
|
+
reverse=True
|
|
73
|
+
)
|
|
74
|
+
if migration_files:
|
|
75
|
+
latest_file = os.path.join(versions_dir, migration_files[0])
|
|
76
|
+
with open(latest_file, "r") as f:
|
|
77
|
+
lines = f.readlines()
|
|
78
|
+
with open(latest_file, "w") as f:
|
|
79
|
+
for line in lines:
|
|
80
|
+
f.write(line)
|
|
81
|
+
if line.strip().startswith("def downgrade"):
|
|
82
|
+
f.write(" return\n")
|
|
83
|
+
break
|
|
84
|
+
else:
|
|
85
|
+
print("No migration file found.")
|
|
86
|
+
sys.exit(1)
|
|
87
|
+
|
|
88
|
+
# Apply the newly generated migration after modifying the migration file
|
|
89
|
+
prompt(f"Migration file generated: {latest_file}\nIt is recommended to review this migration file before proceeding.", non_interactive)
|
|
90
|
+
run("alembic upgrade head", env=env)
|
|
91
|
+
|
|
92
|
+
print("Migration file updated: downgrade will do nothing.")
|
|
93
|
+
print("Consider updating ui/admin/admin.yaml to reflect schema changes.")
|
|
94
|
+
os.chdir(orig_dir)
|
|
95
|
+
print("\nSuccess! Database schema and migrations are up to date.\n\n")
|
|
96
|
+
|
|
97
|
+
if __name__ == "__main__":
|
|
98
|
+
main()
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
You can push changes to `database/models.py' to your database automatically, or manually.
|
|
2
|
+
|
|
3
|
+
<br>
|
|
4
|
+
|
|
5
|
+
## Automatic
|
|
6
|
+
|
|
7
|
+
Use:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
python database/alembic/alembic_run.py [--non-interactive]
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
<br>
|
|
14
|
+
|
|
15
|
+
## Manual
|
|
16
|
+
|
|
17
|
+
The diagram below illustrates a path for enacting changes to the data model, and using [Alembic](https://alembic.sqlalchemy.org/en/latest/index.html) to automate the database changes:
|
|
18
|
+
|
|
19
|
+
1. Update `database/models.py` (e.g., add columns, tables)
|
|
20
|
+
2. Use alembic to compute the revisions
|
|
21
|
+
```bash
|
|
22
|
+
cd database
|
|
23
|
+
export APILOGICPROJECT_NO_FLASK=True
|
|
24
|
+
alembic revision --autogenerate -m "Added Tables and Columns"
|
|
25
|
+
```
|
|
26
|
+
3. **Edit the revision file** to signify your understanding (see below)
|
|
27
|
+
4. Activate the change
|
|
28
|
+
```bash
|
|
29
|
+
alembic upgrade head
|
|
30
|
+
unset APILOGICPROJECT_NO_FLASK
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+

|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
To update your admin app, run `rebuild-from-model`. For more information, see [Database Design Changes](https://apilogicserver.github.io/Docs/Database-Changes/).
|
|
@@ -1,3 +1,43 @@
|
|
|
1
1
|
|
|
2
2
|
Generate a full React Admin application using the following instructions.
|
|
3
3
|
The result must be a runnable React app (`npm start`) that connects to the supplied JSON:API, with fully implemented components (no placeholders or empty files).
|
|
4
|
+
|
|
5
|
+
## Critical Data Access Provider Configuration
|
|
6
|
+
|
|
7
|
+
This project uses a **pre-configured JSON:API data provider** that was built when the project was created.
|
|
8
|
+
|
|
9
|
+
### Key Requirements:
|
|
10
|
+
|
|
11
|
+
1. **Data Provider**: Use the existing `jsonapiClient` from `./rav4-jsonapi-client/ra-jsonapi-client`
|
|
12
|
+
2. **Record Context**: For custom components (like cards), ALWAYS wrap with `<RecordContextProvider value={record}>`
|
|
13
|
+
3. **List Data Access**: Use `useListContext()` to get data and loading state
|
|
14
|
+
4. **Individual Records**: Use `useRecordContext()` to access record data within providers
|
|
15
|
+
5. **API Root**: The data provider connects to `conf.api_root` (typically `http://localhost:5656/api`)
|
|
16
|
+
|
|
17
|
+
### Example Pattern for Custom List Views:
|
|
18
|
+
```javascript
|
|
19
|
+
import { useListContext, RecordContextProvider, useRecordContext } from 'react-admin';
|
|
20
|
+
|
|
21
|
+
const CustomGrid = () => {
|
|
22
|
+
const { data, isLoading } = useListContext();
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<Grid container>
|
|
26
|
+
{data?.map(record => (
|
|
27
|
+
<Grid item key={record.id}>
|
|
28
|
+
<RecordContextProvider value={record}>
|
|
29
|
+
<CustomCard />
|
|
30
|
+
</RecordContextProvider>
|
|
31
|
+
</Grid>
|
|
32
|
+
))}
|
|
33
|
+
</Grid>
|
|
34
|
+
);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const CustomCard = () => {
|
|
38
|
+
const record = useRecordContext();
|
|
39
|
+
return <Card>{record.name}</Card>;
|
|
40
|
+
};
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### CRITICAL: Do NOT create new data providers or modify the existing JSON:API client configuration. The project's data flow depends on the pre-built provider.
|
|
@@ -147,12 +147,12 @@ def query_llm_with_nl(learnings_and_schema: str, nl_query: str):
|
|
|
147
147
|
else:
|
|
148
148
|
# read integration/mcp/mcp_tool_context.json
|
|
149
149
|
tool_context_file_path = os.path.join(os.path.dirname(__file__), "../../integration/mcp/examples/mcp_tool_context_response_get.json")
|
|
150
|
-
if
|
|
150
|
+
if 'send email' in nl_query:
|
|
151
151
|
tool_context_file_path = os.path.join(os.path.dirname(__file__), "../../integration/mcp/examples/mcp_tool_context_response.json")
|
|
152
152
|
try:
|
|
153
153
|
with open(tool_context_file_path, "r") as tool_context_file:
|
|
154
154
|
tool_context_str = tool_context_file.read()
|
|
155
|
-
|
|
155
|
+
log.info(f"\n\n2c. Tool context from file {tool_context_file_path}:\n" + tool_context_str)
|
|
156
156
|
except FileNotFoundError:
|
|
157
157
|
raise ConstraintException(f"Tool context file not found at {tool_context_file_path}.")
|
|
158
158
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
PyJWT==2.6.0
|
|
2
2
|
python-dateutil==2.8.2
|
|
3
3
|
six==1.16.0
|
|
4
|
-
SQLAlchemy
|
|
5
|
-
Flask-SQLAlchemy
|
|
6
|
-
SQLAlchemy-Utils
|
|
4
|
+
SQLAlchemy>=2.0.0
|
|
5
|
+
Flask-SQLAlchemy>=3.0.0
|
|
6
|
+
SQLAlchemy-Utils>=0.38.2
|
|
7
7
|
Werkzeug==2.2.3
|
|
8
8
|
logicbankutils==0.6.0
|
|
9
9
|
inflect==5.0.2
|
|
@@ -25,7 +25,8 @@ PyMySQL==1.0.2
|
|
|
25
25
|
cryptography==36.0.1
|
|
26
26
|
requests==2.27.1
|
|
27
27
|
gunicorn==20.1.0
|
|
28
|
-
psycopg2-binary
|
|
28
|
+
psycopg2-binary>=2.9.5; python_version < '3.13'
|
|
29
|
+
psycopg[binary]>=3.1.0; python_version >= '3.13'
|
|
29
30
|
DotMap==1.3.25
|
|
30
31
|
WTForms==2.3.3
|
|
31
32
|
behave==1.2.6
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta http-equiv="refresh" content="1;url={{ page.redirect }}" />
|
|
6
|
+
<link rel="canonical" href="{{ page.redirect }}" />
|
|
7
|
+
<script type="text/javascript">
|
|
8
|
+
window.location.href = "{{ page.redirect }}"
|
|
9
|
+
</script>
|
|
10
|
+
<title>Page Redirection</title>
|
|
11
|
+
</head>
|
|
12
|
+
<body>
|
|
13
|
+
If you are not redirected automatically, follow <a href='{{ page.redirect }}'>this link</a>.
|
|
14
|
+
</body>
|
|
15
|
+
</html>
|