ApiLogicServer 15.0.61__py3-none-any.whl → 15.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (531) hide show
  1. api_logic_server_cli/api_logic_server.py +4 -3
  2. api_logic_server_cli/api_logic_server_info.yaml +2 -2
  3. api_logic_server_cli/cli.py +2 -2
  4. api_logic_server_cli/database/basic_demo.sqlite +0 -0
  5. api_logic_server_cli/genai/{genai_admin_app.py → genai_react_app.py} +10 -2
  6. api_logic_server_cli/prototypes/base/.github/.copilot-instructions.md +321 -2
  7. api_logic_server_cli/prototypes/base/docs/training/logic_bank_api.prompt +27 -0
  8. api_logic_server_cli/prototypes/base/logic/logic_discovery/use_case.py +5 -1
  9. api_logic_server_cli/prototypes/base/test/readme_test.md +395 -0
  10. api_logic_server_cli/prototypes/basic_demo/customizations/database/db.sqlite +0 -0
  11. api_logic_server_cli/prototypes/basic_demo/docs/models-not-code.png +0 -0
  12. api_logic_server_cli/prototypes/basic_demo/docs/runtime engines.png +0 -0
  13. api_logic_server_cli/prototypes/basic_demo/iteration/database/db.sqlite +0 -0
  14. api_logic_server_cli/prototypes/basic_demo/logic/procedural/credit_service.py +204 -0
  15. api_logic_server_cli/prototypes/manager/.github/.copilot-instructions.md +1 -12
  16. api_logic_server_cli/prototypes/manager/.vscode/launch.json +2 -1
  17. api_logic_server_cli/prototypes/manager/samples/basic_demo/.devcontainer-option/For_VSCode.dockerfile +10 -0
  18. api_logic_server_cli/prototypes/manager/samples/basic_demo/.devcontainer-option/devcontainer.json +64 -0
  19. api_logic_server_cli/prototypes/manager/samples/basic_demo/.devcontainer-option/readme.md +1 -0
  20. api_logic_server_cli/prototypes/manager/samples/basic_demo/.devcontainer-option/setup.sh +10 -0
  21. api_logic_server_cli/prototypes/manager/samples/basic_demo/.env +4 -0
  22. api_logic_server_cli/prototypes/manager/samples/basic_demo/.github/.copilot-instructions.md +581 -0
  23. api_logic_server_cli/prototypes/manager/samples/basic_demo/.gitignore +9 -0
  24. api_logic_server_cli/prototypes/manager/samples/basic_demo/.idea/runConfigurations/ApiLogicServer.xml +24 -0
  25. api_logic_server_cli/prototypes/manager/samples/basic_demo/.idea/runConfigurations/Report_Behave_Logic.xml +24 -0
  26. api_logic_server_cli/prototypes/manager/samples/basic_demo/.idea/runConfigurations/Run_Behave.xml +24 -0
  27. api_logic_server_cli/prototypes/manager/samples/basic_demo/.idea/runConfigurations/Windows_Run_Behave.xml +24 -0
  28. api_logic_server_cli/prototypes/manager/samples/basic_demo/.idea/runConfigurations/run___No_Security.xml +25 -0
  29. api_logic_server_cli/prototypes/manager/samples/basic_demo/.idea/runConfigurations/run_docker.xml +59 -0
  30. api_logic_server_cli/prototypes/manager/samples/basic_demo/.vscode/launch.json +314 -0
  31. api_logic_server_cli/prototypes/manager/samples/basic_demo/.vscode/settings.json +40 -0
  32. api_logic_server_cli/prototypes/manager/samples/basic_demo/.vscode/venv_init.sh +64 -0
  33. api_logic_server_cli/prototypes/manager/samples/basic_demo/_config.yml +8 -0
  34. api_logic_server_cli/prototypes/manager/samples/basic_demo/_layouts/redirect.html +15 -0
  35. api_logic_server_cli/prototypes/manager/samples/basic_demo/api/__init__.py +0 -0
  36. api_logic_server_cli/prototypes/manager/samples/basic_demo/api/api_discovery/auto_discovery.py +27 -0
  37. api_logic_server_cli/prototypes/manager/samples/basic_demo/api/api_discovery/mcp_discovery.py +97 -0
  38. api_logic_server_cli/prototypes/manager/samples/basic_demo/api/api_discovery/mcp_expose_api_models.py +53 -0
  39. api_logic_server_cli/prototypes/manager/samples/basic_demo/api/api_discovery/new_service.py +21 -0
  40. api_logic_server_cli/prototypes/manager/samples/basic_demo/api/api_discovery/newer_service.py +21 -0
  41. api_logic_server_cli/prototypes/manager/samples/basic_demo/api/api_discovery/ontimize_api.py +495 -0
  42. api_logic_server_cli/prototypes/manager/samples/basic_demo/api/api_discovery/order_b2b_service.py +60 -0
  43. api_logic_server_cli/prototypes/manager/samples/basic_demo/api/api_discovery/system.py +77 -0
  44. api_logic_server_cli/prototypes/manager/samples/basic_demo/api/customize_api.py +63 -0
  45. api_logic_server_cli/prototypes/manager/samples/basic_demo/api/expose_api_models.py +52 -0
  46. api_logic_server_cli/prototypes/manager/samples/basic_demo/api/json_encoder.py +17 -0
  47. api_logic_server_cli/prototypes/manager/samples/basic_demo/api/readme_customize_api.md +103 -0
  48. api_logic_server_cli/prototypes/manager/samples/basic_demo/api/system/api_utils.py +171 -0
  49. api_logic_server_cli/prototypes/manager/samples/basic_demo/api/system/custom_endpoint.py +1085 -0
  50. api_logic_server_cli/prototypes/manager/samples/basic_demo/api/system/expression_parser.py +685 -0
  51. api_logic_server_cli/prototypes/manager/samples/basic_demo/api/system/gen_csv_report.py +41 -0
  52. api_logic_server_cli/prototypes/manager/samples/basic_demo/api/system/gen_pdf_report.py +215 -0
  53. api_logic_server_cli/prototypes/manager/samples/basic_demo/api/system/opt_locking/opt_locking.py +158 -0
  54. api_logic_server_cli/prototypes/manager/samples/basic_demo/api/system/opt_locking/readme.md +225 -0
  55. api_logic_server_cli/prototypes/manager/samples/basic_demo/api_logic_server_run.py +162 -0
  56. api_logic_server_cli/prototypes/manager/samples/basic_demo/config/__init__.py +0 -0
  57. api_logic_server_cli/prototypes/manager/samples/basic_demo/config/activate_logicbank.py +46 -0
  58. api_logic_server_cli/prototypes/manager/samples/basic_demo/config/config.py +772 -0
  59. api_logic_server_cli/prototypes/manager/samples/basic_demo/config/default.env +16 -0
  60. api_logic_server_cli/prototypes/manager/samples/basic_demo/config/logging-reduced.yml +112 -0
  61. api_logic_server_cli/prototypes/manager/samples/basic_demo/config/logging.yml +123 -0
  62. api_logic_server_cli/prototypes/manager/samples/basic_demo/config/mypy.ini +25 -0
  63. api_logic_server_cli/prototypes/manager/samples/basic_demo/config/server_setup.py +459 -0
  64. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/api/api_discovery/openapi.py +92 -0
  65. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/config/default.env +13 -0
  66. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/database/db.sqlite +0 -0
  67. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/database/models.py +130 -0
  68. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/docs/mcp_learning/mcp_discovery.json +108 -0
  69. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/logic/cocktail-napkin.jpg +0 -0
  70. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/logic/declare_logic.py +106 -0
  71. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/logic/logic_discovery/email_request.py +49 -0
  72. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/logic/logic_discovery/simple_constraints.py +25 -0
  73. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/security/declare_security.py +60 -0
  74. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/ui/admin/admin.yaml +162 -0
  75. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/ui/admin/home.js +48 -0
  76. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/ui/reference_react_app/README.md +17 -0
  77. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/ui/reference_react_app/README_create_react_app.md +70 -0
  78. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/ui/reference_react_app/package-lock.json +18469 -0
  79. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/ui/reference_react_app/package.json +47 -0
  80. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/ui/reference_react_app/public/favicon.ico +0 -0
  81. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/ui/reference_react_app/public/index.html +43 -0
  82. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/ui/reference_react_app/public/logo192.png +0 -0
  83. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/ui/reference_react_app/public/logo512.png +0 -0
  84. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/ui/reference_react_app/public/manifest.json +25 -0
  85. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/ui/reference_react_app/public/robots.txt +3 -0
  86. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/ui/reference_react_app/src/App.css +38 -0
  87. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/ui/reference_react_app/src/App.js +61 -0
  88. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/ui/reference_react_app/src/App.test.js +8 -0
  89. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/ui/reference_react_app/src/Config-reference.js +527 -0
  90. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/ui/reference_react_app/src/Config.js +527 -0
  91. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/ui/reference_react_app/src/Customer-reference.js +216 -0
  92. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/ui/reference_react_app/src/Customer.js +230 -0
  93. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/ui/reference_react_app/src/Item.js +170 -0
  94. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/ui/reference_react_app/src/Order.js +207 -0
  95. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/ui/reference_react_app/src/Product.js +140 -0
  96. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/ui/reference_react_app/src/SysEmail.js +157 -0
  97. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/ui/reference_react_app/src/SysMcp.js +110 -0
  98. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/ui/reference_react_app/src/app_loader.js +24 -0
  99. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/ui/reference_react_app/src/index.css +13 -0
  100. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/ui/reference_react_app/src/index.js +17 -0
  101. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/ui/reference_react_app/src/logo.svg +1 -0
  102. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/ui/reference_react_app/src/rav4-jsonapi-client/.eslintrc +5 -0
  103. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/ui/reference_react_app/src/rav4-jsonapi-client/.yarnrc.yml +4 -0
  104. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/ui/reference_react_app/src/rav4-jsonapi-client/default-settings.js +25 -0
  105. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/ui/reference_react_app/src/rav4-jsonapi-client/default-settings.ts +25 -0
  106. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/ui/reference_react_app/src/rav4-jsonapi-client/errors.js +116 -0
  107. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/ui/reference_react_app/src/rav4-jsonapi-client/errors.ts +116 -0
  108. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/ui/reference_react_app/src/rav4-jsonapi-client/index.test.tsx +7 -0
  109. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/ui/reference_react_app/src/rav4-jsonapi-client/index.tsx +11 -0
  110. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/ui/reference_react_app/src/rav4-jsonapi-client/ra-jsonapi-client.js +577 -0
  111. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/ui/reference_react_app/src/rav4-jsonapi-client/ra-jsonapi-client.ts +577 -0
  112. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/ui/reference_react_app/src/rav4-jsonapi-client/resourceLookup.js +124 -0
  113. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/ui/reference_react_app/src/rav4-jsonapi-client/resourceLookup.ts +124 -0
  114. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/ui/reference_react_app/src/rav4-jsonapi-client/styles.module.css +9 -0
  115. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/ui/reference_react_app/src/reportWebVitals.js +13 -0
  116. api_logic_server_cli/prototypes/manager/samples/basic_demo/customizations/ui/reference_react_app/src/setupTests.js +5 -0
  117. api_logic_server_cli/prototypes/manager/samples/basic_demo/database/__init__.py +0 -0
  118. api_logic_server_cli/prototypes/manager/samples/basic_demo/database/alembic/alembic_run.py +98 -0
  119. api_logic_server_cli/prototypes/manager/samples/basic_demo/database/alembic/env.py +78 -0
  120. api_logic_server_cli/prototypes/manager/samples/basic_demo/database/alembic/readme_alembic.md +36 -0
  121. api_logic_server_cli/prototypes/manager/samples/basic_demo/database/alembic/script.py.mako +24 -0
  122. api_logic_server_cli/prototypes/manager/samples/basic_demo/database/alembic/versions/ae6a5c2fdc47_autogenerated.py +34 -0
  123. api_logic_server_cli/prototypes/manager/samples/basic_demo/database/alembic/versions/readme.md +1 -0
  124. api_logic_server_cli/prototypes/manager/samples/basic_demo/database/alembic.ini +103 -0
  125. api_logic_server_cli/prototypes/manager/samples/basic_demo/database/authentication_db.sqlite +0 -0
  126. api_logic_server_cli/prototypes/manager/samples/basic_demo/database/bind_dbs.py +25 -0
  127. api_logic_server_cli/prototypes/manager/samples/basic_demo/database/customize_models.py +19 -0
  128. api_logic_server_cli/prototypes/manager/samples/basic_demo/database/database_discovery/authentication_models.py +183 -0
  129. api_logic_server_cli/prototypes/manager/samples/basic_demo/database/database_discovery/auto_discovery.py +27 -0
  130. api_logic_server_cli/prototypes/manager/samples/basic_demo/database/db.sqlite +0 -0
  131. api_logic_server_cli/prototypes/manager/samples/basic_demo/database/db_debug/db_debug.py +90 -0
  132. api_logic_server_cli/prototypes/manager/samples/basic_demo/database/mcp_db.sqlite +0 -0
  133. api_logic_server_cli/prototypes/manager/samples/basic_demo/database/mcp_models.py +58 -0
  134. api_logic_server_cli/prototypes/manager/samples/basic_demo/database/models.py +132 -0
  135. api_logic_server_cli/prototypes/manager/samples/basic_demo/database/system/SAFRSBaseX.py +139 -0
  136. api_logic_server_cli/prototypes/manager/samples/basic_demo/database/test_data/alp_init.py +40 -0
  137. api_logic_server_cli/prototypes/manager/samples/basic_demo/database/test_data/readme.md +13 -0
  138. api_logic_server_cli/prototypes/manager/samples/basic_demo/database/test_data/response2code.py +148 -0
  139. api_logic_server_cli/prototypes/manager/samples/basic_demo/database/test_data/test_data_preamble.py +83 -0
  140. api_logic_server_cli/prototypes/manager/samples/basic_demo/devops/auth-db/authdb_mysql.Dockerfile +65 -0
  141. api_logic_server_cli/prototypes/manager/samples/basic_demo/devops/auth-db/authdb_mysql.sql +112 -0
  142. api_logic_server_cli/prototypes/manager/samples/basic_demo/devops/auth-db/authdb_postgres.sql +57 -0
  143. api_logic_server_cli/prototypes/manager/samples/basic_demo/devops/docker-compose-dev-azure/azure-deploy.sh +98 -0
  144. api_logic_server_cli/prototypes/manager/samples/basic_demo/devops/docker-compose-dev-local/docker-compose-dev-local.yml +38 -0
  145. api_logic_server_cli/prototypes/manager/samples/basic_demo/devops/docker-compose-dev-local/docker-compose.sh +34 -0
  146. api_logic_server_cli/prototypes/manager/samples/basic_demo/devops/docker-image/build_image.dockerfile +20 -0
  147. api_logic_server_cli/prototypes/manager/samples/basic_demo/devops/docker-image/build_image.sh +67 -0
  148. api_logic_server_cli/prototypes/manager/samples/basic_demo/devops/docker-image/env.list +35 -0
  149. api_logic_server_cli/prototypes/manager/samples/basic_demo/devops/docker-image/run_image.sh +23 -0
  150. api_logic_server_cli/prototypes/manager/samples/basic_demo/devops/docker-standard-image/docker-compose-standard-image.yml +33 -0
  151. api_logic_server_cli/prototypes/manager/samples/basic_demo/devops/docker-standard-image/env.list +55 -0
  152. api_logic_server_cli/prototypes/manager/samples/basic_demo/devops/keycloak/data/h2/keycloakdb.mv.db +0 -0
  153. api_logic_server_cli/prototypes/manager/samples/basic_demo/devops/keycloak/data/h2/keycloakdb.trace.db +236 -0
  154. api_logic_server_cli/prototypes/manager/samples/basic_demo/devops/keycloak/data/import/kcals-realm.json +1807 -0
  155. api_logic_server_cli/prototypes/manager/samples/basic_demo/devops/keycloak/data/import/kcals-users-0.json +24 -0
  156. api_logic_server_cli/prototypes/manager/samples/basic_demo/devops/keycloak/data/import/master-realm.json +1953 -0
  157. api_logic_server_cli/prototypes/manager/samples/basic_demo/devops/keycloak/data/import/master-users-0.json +23 -0
  158. api_logic_server_cli/prototypes/manager/samples/basic_demo/devops/keycloak/data/tmp/kc-gzip-cache/nnbna/js/keycloak.js.gz +0 -0
  159. api_logic_server_cli/prototypes/manager/samples/basic_demo/devops/keycloak/docker-compose-dev-network.yml +31 -0
  160. api_logic_server_cli/prototypes/manager/samples/basic_demo/devops/keycloak/docker-compose-nginx.yml +48 -0
  161. api_logic_server_cli/prototypes/manager/samples/basic_demo/devops/keycloak/docker-compose.yml +24 -0
  162. api_logic_server_cli/prototypes/manager/samples/basic_demo/devops/keycloak/import/kcals-realm.json +1898 -0
  163. api_logic_server_cli/prototypes/manager/samples/basic_demo/devops/keycloak/import/kcals-users-0.json +319 -0
  164. api_logic_server_cli/prototypes/manager/samples/basic_demo/devops/keycloak/import/master-realm.json +1953 -0
  165. api_logic_server_cli/prototypes/manager/samples/basic_demo/devops/keycloak/import/master-users-0.json +23 -0
  166. api_logic_server_cli/prototypes/manager/samples/basic_demo/devops/keycloak/nginx/cert.pem +25 -0
  167. api_logic_server_cli/prototypes/manager/samples/basic_demo/devops/keycloak/nginx/key.pem +28 -0
  168. api_logic_server_cli/prototypes/manager/samples/basic_demo/devops/keycloak/nginx/nginx.conf +73 -0
  169. api_logic_server_cli/prototypes/manager/samples/basic_demo/devops/keycloak/startup_log_nginx.txt +0 -0
  170. api_logic_server_cli/prototypes/manager/samples/basic_demo/devops/keycloak/startup_log_no_nginx.txt +0 -0
  171. api_logic_server_cli/prototypes/manager/samples/basic_demo/devops/keycloak/unused/auth_provider.py +80 -0
  172. api_logic_server_cli/prototypes/manager/samples/basic_demo/devops/keycloak/unused/unused-docker-compose-keycloak.sh +13 -0
  173. api_logic_server_cli/prototypes/manager/samples/basic_demo/devops/python-anywhere/python_anywhere_wsgi.py +116 -0
  174. api_logic_server_cli/prototypes/manager/samples/basic_demo/devops/readme-devops.md +31 -0
  175. api_logic_server_cli/prototypes/manager/samples/basic_demo/docs/db.dbml +14 -0
  176. api_logic_server_cli/prototypes/manager/samples/basic_demo/docs/graphics/readme.md +12 -0
  177. api_logic_server_cli/prototypes/manager/samples/basic_demo/docs/logic/readme.md +19 -0
  178. api_logic_server_cli/prototypes/manager/samples/basic_demo/docs/logic_suggestions/readme_logic_suggestions.md +3 -0
  179. api_logic_server_cli/prototypes/manager/samples/basic_demo/docs/mcp_learning/mcp.prompt +39 -0
  180. api_logic_server_cli/prototypes/manager/samples/basic_demo/docs/mcp_learning/mcp_schema.json +30 -0
  181. api_logic_server_cli/prototypes/manager/samples/basic_demo/docs/models-not-code.png +0 -0
  182. api_logic_server_cli/prototypes/manager/samples/basic_demo/docs/runtime engines.png +0 -0
  183. api_logic_server_cli/prototypes/manager/samples/basic_demo/docs/system-creation-vibe.md +158 -0
  184. api_logic_server_cli/prototypes/manager/samples/basic_demo/docs/training/admin_app_1_context.prompt.md +43 -0
  185. api_logic_server_cli/prototypes/manager/samples/basic_demo/docs/training/admin_app_2_functionality.prompt.md +69 -0
  186. api_logic_server_cli/prototypes/manager/samples/basic_demo/docs/training/admin_app_3_architecture.prompt.md +29 -0
  187. api_logic_server_cli/prototypes/manager/samples/basic_demo/docs/training/logic_bank_api.prompt +342 -0
  188. api_logic_server_cli/prototypes/manager/samples/basic_demo/docs/training/logic_example.py +41 -0
  189. api_logic_server_cli/prototypes/manager/samples/basic_demo/docs/training/react_map.prompt.md +13 -0
  190. api_logic_server_cli/prototypes/manager/samples/basic_demo/docs/training/react_tree.prompt.md +10 -0
  191. api_logic_server_cli/prototypes/manager/samples/basic_demo/integration/kafka/kafka_consumer.py +60 -0
  192. api_logic_server_cli/prototypes/manager/samples/basic_demo/integration/kafka/kafka_producer.py +127 -0
  193. api_logic_server_cli/prototypes/manager/samples/basic_demo/integration/kafka/kafka_readme.md +3 -0
  194. api_logic_server_cli/prototypes/manager/samples/basic_demo/integration/mcp/examples/mcp_context_results.txt +142 -0
  195. api_logic_server_cli/prototypes/manager/samples/basic_demo/integration/mcp/examples/mcp_discovery_response.json +150 -0
  196. api_logic_server_cli/prototypes/manager/samples/basic_demo/integration/mcp/examples/mcp_request.prompt +46 -0
  197. api_logic_server_cli/prototypes/manager/samples/basic_demo/integration/mcp/examples/mcp_schema.txt +47 -0
  198. api_logic_server_cli/prototypes/manager/samples/basic_demo/integration/mcp/examples/mcp_tool_context_response.json +34 -0
  199. api_logic_server_cli/prototypes/manager/samples/basic_demo/integration/mcp/examples/mcp_tool_context_response_get.json +18 -0
  200. api_logic_server_cli/prototypes/manager/samples/basic_demo/integration/mcp/mcp_client_executor.py +545 -0
  201. api_logic_server_cli/prototypes/manager/samples/basic_demo/integration/mcp/mcp_server_discovery.json +9 -0
  202. api_logic_server_cli/prototypes/manager/samples/basic_demo/integration/mcp/readme-mcp.md +9 -0
  203. api_logic_server_cli/prototypes/manager/samples/basic_demo/integration/n8n/N8N_WebHook_from_ApiLogicServer.json +394 -0
  204. api_logic_server_cli/prototypes/manager/samples/basic_demo/integration/n8n/n8n_producer.py +172 -0
  205. api_logic_server_cli/prototypes/manager/samples/basic_demo/integration/n8n/n8n_readme.md +67 -0
  206. api_logic_server_cli/prototypes/manager/samples/basic_demo/integration/row_dict_maps/OrderB2BMapper.py +54 -0
  207. api_logic_server_cli/prototypes/manager/samples/basic_demo/integration/row_dict_maps/row_dict_maps_readme.md +3 -0
  208. api_logic_server_cli/prototypes/manager/samples/basic_demo/integration/system/FlaskKafka.py +105 -0
  209. api_logic_server_cli/prototypes/manager/samples/basic_demo/integration/system/RowDictMapper.py +416 -0
  210. api_logic_server_cli/prototypes/manager/samples/basic_demo/iteration/api/api_discovery/order_b2b.py +92 -0
  211. api_logic_server_cli/prototypes/manager/samples/basic_demo/iteration/database/db.sqlite +0 -0
  212. api_logic_server_cli/prototypes/manager/samples/basic_demo/iteration/docs/er_diagram.png +0 -0
  213. api_logic_server_cli/prototypes/manager/samples/basic_demo/iteration/integration/row_dict_maps/OrderB2B.py +36 -0
  214. api_logic_server_cli/prototypes/manager/samples/basic_demo/iteration/integration/row_dict_maps/OrderShipping.py +30 -0
  215. api_logic_server_cli/prototypes/manager/samples/basic_demo/iteration/logic/declare_logic.py +147 -0
  216. api_logic_server_cli/prototypes/manager/samples/basic_demo/iteration/ui/admin/admin.yaml +175 -0
  217. api_logic_server_cli/prototypes/manager/samples/basic_demo/logic/declarative-vs-procedural-comparison.html +110 -0
  218. api_logic_server_cli/prototypes/manager/samples/basic_demo/logic/declare_logic.py +81 -0
  219. api_logic_server_cli/prototypes/manager/samples/basic_demo/logic/load_verify_rules.py +217 -0
  220. api_logic_server_cli/prototypes/manager/samples/basic_demo/logic/logic_discovery/app_integration.py +23 -0
  221. api_logic_server_cli/prototypes/manager/samples/basic_demo/logic/logic_discovery/auto_discovery.py +52 -0
  222. api_logic_server_cli/prototypes/manager/samples/basic_demo/logic/logic_discovery/check_credit.py +44 -0
  223. api_logic_server_cli/prototypes/manager/samples/basic_demo/logic/logic_discovery/mcp_client_executor_request.py +50 -0
  224. api_logic_server_cli/prototypes/manager/samples/basic_demo/logic/logic_discovery/readme_logic_discovery.md +9 -0
  225. api_logic_server_cli/prototypes/manager/samples/basic_demo/logic/logic_discovery/use_case.py +31 -0
  226. api_logic_server_cli/prototypes/manager/samples/basic_demo/logic/procedural/credit_service.py +204 -0
  227. api_logic_server_cli/prototypes/manager/samples/basic_demo/logic/procedural/declarative-vs-procedural-comparison.md +295 -0
  228. api_logic_server_cli/prototypes/manager/samples/basic_demo/logic/procedural/declarative-vs-procedural-comparison.png +0 -0
  229. api_logic_server_cli/prototypes/manager/samples/basic_demo/logic/readme_logic.md +249 -0
  230. api_logic_server_cli/prototypes/manager/samples/basic_demo/readme.md +495 -0
  231. api_logic_server_cli/prototypes/manager/samples/basic_demo/readme_project.md +43 -0
  232. api_logic_server_cli/prototypes/manager/samples/basic_demo/readme_standard.md +492 -0
  233. api_logic_server_cli/prototypes/manager/samples/basic_demo/readme_vibe.md +353 -0
  234. api_logic_server_cli/prototypes/manager/samples/basic_demo/requirements.txt +3 -0
  235. api_logic_server_cli/prototypes/manager/samples/basic_demo/run.ps1 +30 -0
  236. api_logic_server_cli/prototypes/manager/samples/basic_demo/run.sh +55 -0
  237. api_logic_server_cli/prototypes/manager/samples/basic_demo/security/__init__.py +0 -0
  238. api_logic_server_cli/prototypes/manager/samples/basic_demo/security/authentication_provider/__init__.py +0 -0
  239. api_logic_server_cli/prototypes/manager/samples/basic_demo/security/authentication_provider/abstract_authentication_provider.py +34 -0
  240. api_logic_server_cli/prototypes/manager/samples/basic_demo/security/authentication_provider/keycloak/auth_provider.py +238 -0
  241. api_logic_server_cli/prototypes/manager/samples/basic_demo/security/authentication_provider/memory/auth_provider.py +161 -0
  242. api_logic_server_cli/prototypes/manager/samples/basic_demo/security/authentication_provider/memory/auth_provider_no_swagger.py +98 -0
  243. api_logic_server_cli/prototypes/manager/samples/basic_demo/security/authentication_provider/sql/auth_provider.py +127 -0
  244. api_logic_server_cli/prototypes/manager/samples/basic_demo/security/declare_security.py +49 -0
  245. api_logic_server_cli/prototypes/manager/samples/basic_demo/security/readme_security.md +16 -0
  246. api_logic_server_cli/prototypes/manager/samples/basic_demo/security/system/authentication.py +129 -0
  247. api_logic_server_cli/prototypes/manager/samples/basic_demo/security/system/authorization.py +473 -0
  248. api_logic_server_cli/prototypes/manager/samples/basic_demo/security/system/custom_swagger.json +62 -0
  249. api_logic_server_cli/prototypes/manager/samples/basic_demo/test/__init__.py +0 -0
  250. api_logic_server_cli/prototypes/manager/samples/basic_demo/test/api_logic_server_behave/__init__.py +0 -0
  251. api_logic_server_cli/prototypes/manager/samples/basic_demo/test/api_logic_server_behave/behave_logic_report.py +256 -0
  252. api_logic_server_cli/prototypes/manager/samples/basic_demo/test/api_logic_server_behave/behave_run.py +64 -0
  253. api_logic_server_cli/prototypes/manager/samples/basic_demo/test/api_logic_server_behave/features/about.feature +12 -0
  254. api_logic_server_cli/prototypes/manager/samples/basic_demo/test/api_logic_server_behave/features/steps/about.py +20 -0
  255. api_logic_server_cli/prototypes/manager/samples/basic_demo/test/api_logic_server_behave/features/steps/test_utils.py +133 -0
  256. api_logic_server_cli/prototypes/manager/samples/basic_demo/test/api_logic_server_behave/logs/behave.log +0 -0
  257. api_logic_server_cli/prototypes/manager/samples/basic_demo/test/api_logic_server_behave/reports/Behave Logic Report Intro micro.md +4 -0
  258. api_logic_server_cli/prototypes/manager/samples/basic_demo/test/api_logic_server_behave/reports/Behave Logic Report Intro.md +75 -0
  259. api_logic_server_cli/prototypes/manager/samples/basic_demo/test/api_logic_server_behave/reports/Behave Logic Report Sample.md +1180 -0
  260. api_logic_server_cli/prototypes/manager/samples/basic_demo/test/basic/server_test.py +33 -0
  261. api_logic_server_cli/prototypes/manager/samples/basic_demo/test/readme_test.md +395 -0
  262. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/__init__.py +0 -0
  263. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/admin/admin.yaml +173 -0
  264. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/admin/admin_loader.py +217 -0
  265. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/admin/authentication_admin.yaml +99 -0
  266. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/admin/home.js +48 -0
  267. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/admin/mcp_admin.yaml +53 -0
  268. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/.browserslistrc +12 -0
  269. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/.dockerignore +47 -0
  270. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/.editorconfig +16 -0
  271. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/.eslintrc.json +51 -0
  272. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/.gitignore +47 -0
  273. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/README.md +42 -0
  274. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/angular.json +206 -0
  275. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/app_model.yaml +303 -0
  276. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/docker-compose-ontimize.yml +54 -0
  277. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/e2e/protractor.conf.js +32 -0
  278. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/e2e/src/app.e2e-spec.ts +23 -0
  279. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/e2e/src/app.po.ts +11 -0
  280. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/e2e/tsconfig.json +13 -0
  281. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/karma.conf.js +32 -0
  282. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/nginx/nginx.conf +29 -0
  283. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/ngsw-config.json +29 -0
  284. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/package-lock.json +22651 -0
  285. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/package.json +69 -0
  286. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/app-routing.module.ts +25 -0
  287. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/app.component.html +1 -0
  288. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/app.component.scss +1 -0
  289. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/app.component.spec.ts +35 -0
  290. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/app.component.ts +9 -0
  291. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/app.config.ts +43 -0
  292. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/app.module.ts +37 -0
  293. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/login/login-routing.module.ts +12 -0
  294. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/login/login.component.html +58 -0
  295. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/login/login.component.scss +155 -0
  296. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/login/login.component.ts +81 -0
  297. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/login/login.module.ts +18 -0
  298. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/login/login.theme.scss +51 -0
  299. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/Customer/Customer-routing.module.ts +37 -0
  300. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/Customer/Customer.module.ts +19 -0
  301. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/Customer/detail/Customer-detail.component.html +90 -0
  302. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/Customer/detail/Customer-detail.component.scss +0 -0
  303. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/Customer/detail/Customer-detail.component.ts +32 -0
  304. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/Customer/home/Customer-home.component.html +44 -0
  305. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/Customer/home/Customer-home.component.scss +0 -0
  306. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/Customer/home/Customer-home.component.ts +23 -0
  307. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/Customer/new/Customer-new.component.html +26 -0
  308. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/Customer/new/Customer-new.component.scss +0 -0
  309. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/Customer/new/Customer-new.component.ts +18 -0
  310. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/Item/Item-routing.module.ts +30 -0
  311. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/Item/Item.module.ts +19 -0
  312. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/Item/detail/Item-detail.component.html +72 -0
  313. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/Item/detail/Item-detail.component.scss +0 -0
  314. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/Item/detail/Item-detail.component.ts +32 -0
  315. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/Item/home/Item-home.component.html +55 -0
  316. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/Item/home/Item-home.component.scss +0 -0
  317. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/Item/home/Item-home.component.ts +23 -0
  318. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/Item/new/Item-new.component.html +60 -0
  319. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/Item/new/Item-new.component.scss +0 -0
  320. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/Item/new/Item-new.component.ts +18 -0
  321. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/Order/Order-routing.module.ts +37 -0
  322. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/Order/Order.module.ts +19 -0
  323. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/Order/detail/Order-detail.component.html +114 -0
  324. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/Order/detail/Order-detail.component.scss +0 -0
  325. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/Order/detail/Order-detail.component.ts +32 -0
  326. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/Order/home/Order-home.component.html +48 -0
  327. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/Order/home/Order-home.component.scss +0 -0
  328. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/Order/home/Order-home.component.ts +23 -0
  329. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/Order/new/Order-new.component.html +43 -0
  330. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/Order/new/Order-new.component.scss +0 -0
  331. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/Order/new/Order-new.component.ts +18 -0
  332. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/Product/Product-routing.module.ts +37 -0
  333. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/Product/Product.module.ts +19 -0
  334. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/Product/detail/Product-detail.component.html +91 -0
  335. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/Product/detail/Product-detail.component.scss +0 -0
  336. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/Product/detail/Product-detail.component.ts +32 -0
  337. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/Product/home/Product-home.component.html +35 -0
  338. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/Product/home/Product-home.component.scss +0 -0
  339. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/Product/home/Product-home.component.ts +23 -0
  340. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/Product/new/Product-new.component.html +20 -0
  341. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/Product/new/Product-new.component.scss +0 -0
  342. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/Product/new/Product-new.component.ts +18 -0
  343. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/about/about-routing.module.ts +13 -0
  344. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/about/about.component.html +39 -0
  345. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/about/about.component.scss +35 -0
  346. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/about/about.component.ts +17 -0
  347. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/about/about.module.ts +18 -0
  348. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/about/about.theme.scss +14 -0
  349. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/home/home-routing.module.ts +17 -0
  350. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/home/home.component.html +1 -0
  351. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/home/home.component.scss +3 -0
  352. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/home/home.component.ts +21 -0
  353. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/home/home.module.ts +18 -0
  354. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/main-routing.module.ts +32 -0
  355. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/main-theme.scss +56 -0
  356. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/main.component.html +8 -0
  357. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/main.component.scss +1 -0
  358. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/main.component.ts +20 -0
  359. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/main.module.ts +22 -0
  360. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/settings/settings-routing.module.ts +14 -0
  361. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/settings/settings.component.html +14 -0
  362. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/settings/settings.component.scss +44 -0
  363. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/settings/settings.component.ts +46 -0
  364. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/main/settings/settings.module.ts +18 -0
  365. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/shared/Customer-card/Customer-card.component.html +1 -0
  366. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/shared/Customer-card/Customer-card.component.scss +0 -0
  367. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/shared/Customer-card/Customer-card.component.ts +16 -0
  368. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/shared/Item-card/Item-card.component.html +1 -0
  369. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/shared/Item-card/Item-card.component.scss +0 -0
  370. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/shared/Item-card/Item-card.component.ts +16 -0
  371. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/shared/Order-card/Order-card.component.html +1 -0
  372. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/shared/Order-card/Order-card.component.scss +0 -0
  373. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/shared/Order-card/Order-card.component.ts +16 -0
  374. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/shared/Product-card/Product-card.component.html +1 -0
  375. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/shared/Product-card/Product-card.component.scss +0 -0
  376. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/shared/Product-card/Product-card.component.ts +16 -0
  377. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/shared/app.menu.config.ts +45 -0
  378. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/shared/app.services.config.ts +5 -0
  379. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/shared/constant.ts +4 -0
  380. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/app/shared/shared.module.ts +15 -0
  381. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/assets/.gitkeep +0 -0
  382. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/assets/css/app.scss +20 -0
  383. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/assets/css/loader.css +173 -0
  384. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/assets/i18n/en.json +44 -0
  385. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/assets/i18n/es.json +42 -0
  386. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/assets/icons/ontimize128.png +0 -0
  387. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/assets/icons/ontimize16.png +0 -0
  388. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/assets/icons/ontimize256.png +0 -0
  389. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/assets/icons/ontimize32.png +0 -0
  390. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/assets/icons/ontimize48.png +0 -0
  391. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/assets/icons/ontimize64.png +0 -0
  392. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/assets/icons/ontimize72.png +0 -0
  393. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/assets/icons/ontimize96.png +0 -0
  394. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/assets/images/github.png +0 -0
  395. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/assets/images/login_bg.png +0 -0
  396. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/assets/images/no-image-transparent.png +0 -0
  397. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/assets/images/no-image.png +0 -0
  398. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/assets/images/ontimize.png +0 -0
  399. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/assets/images/ontimize_web_log.png +0 -0
  400. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/assets/images/sidenav-closed.png +0 -0
  401. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/assets/images/sidenav-closed.svg +1 -0
  402. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/assets/images/sidenav-opened.png +0 -0
  403. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/assets/images/sidenav-opened.svg +1 -0
  404. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/assets/images/user_profile.png +0 -0
  405. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/assets/js/domchange.js +110 -0
  406. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/assets/js/keyboard.js +24 -0
  407. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/environments/environment.prod.ts +11 -0
  408. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/environments/environment.ts +15 -0
  409. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/favicon.ico +0 -0
  410. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/index.html +30 -0
  411. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/main.ts +15 -0
  412. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/manifest.webmanifest +59 -0
  413. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/polyfills.ts +66 -0
  414. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/styles.scss +1 -0
  415. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/src/test.ts +16 -0
  416. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/tsconfig.app.json +18 -0
  417. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/tsconfig.json +25 -0
  418. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/app/tsconfig.spec.json +18 -0
  419. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/images/Employee/andrew.jpg +0 -0
  420. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/images/Employee/anne.jpg +0 -0
  421. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/images/Employee/janet.jpg +0 -0
  422. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/images/Employee/laura.jpg +0 -0
  423. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/images/Employee/margaret.jpg +0 -0
  424. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/images/Employee/michael.jpg +0 -0
  425. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/images/Employee/nancy.jpg +0 -0
  426. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/images/Employee/robert.jpg +0 -0
  427. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/images/Employee/steven.jpg +0 -0
  428. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/images/Product/beverages.gif +0 -0
  429. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/images/Product/cereals.gif +0 -0
  430. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/images/Product/condiments.gif +0 -0
  431. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/images/Product/confections.gif +0 -0
  432. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/images/Product/diary.gif +0 -0
  433. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/images/Product/meat.gif +0 -0
  434. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/images/Product/produce.gif +0 -0
  435. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/images/Product/seafood.gif +0 -0
  436. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app/README.md +16 -0
  437. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app/README_create_react_app.md +70 -0
  438. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app/package-lock.json +18469 -0
  439. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app/package.json +47 -0
  440. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app/public/favicon.ico +0 -0
  441. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app/public/index.html +43 -0
  442. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app/public/logo192.png +0 -0
  443. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app/public/logo512.png +0 -0
  444. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app/public/manifest.json +25 -0
  445. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app/public/robots.txt +3 -0
  446. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app/src/App.css +38 -0
  447. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app/src/App.js +80 -0
  448. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app/src/App.test.js +8 -0
  449. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app/src/Config.js +527 -0
  450. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app/src/Customer.js +218 -0
  451. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app/src/Item.js +190 -0
  452. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app/src/Order.js +189 -0
  453. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app/src/Product.js +159 -0
  454. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app/src/app_loader.js +24 -0
  455. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app/src/index.css +13 -0
  456. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app/src/index.js +17 -0
  457. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app/src/logo.svg +1 -0
  458. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app/src/rav4-jsonapi-client/.eslintrc +5 -0
  459. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app/src/rav4-jsonapi-client/.yarnrc.yml +4 -0
  460. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app/src/rav4-jsonapi-client/default-settings.js +25 -0
  461. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app/src/rav4-jsonapi-client/default-settings.ts +25 -0
  462. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app/src/rav4-jsonapi-client/errors.js +116 -0
  463. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app/src/rav4-jsonapi-client/errors.ts +116 -0
  464. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app/src/rav4-jsonapi-client/index.test.tsx +7 -0
  465. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app/src/rav4-jsonapi-client/index.tsx +11 -0
  466. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app/src/rav4-jsonapi-client/ra-jsonapi-client.js +577 -0
  467. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app/src/rav4-jsonapi-client/ra-jsonapi-client.ts +577 -0
  468. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app/src/rav4-jsonapi-client/resourceLookup.js +124 -0
  469. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app/src/rav4-jsonapi-client/resourceLookup.ts +124 -0
  470. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app/src/rav4-jsonapi-client/styles.module.css +9 -0
  471. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app/src/reportWebVitals.js +13 -0
  472. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app/src/setupTests.js +5 -0
  473. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app-cards/README.md +20 -0
  474. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app-cards/README_create_react_app.md +72 -0
  475. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app-cards/package-lock.json +18469 -0
  476. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app-cards/package.json +47 -0
  477. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app-cards/product-cards.png +0 -0
  478. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app-cards/public/favicon.ico +0 -0
  479. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app-cards/public/index.html +43 -0
  480. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app-cards/public/logo192.png +0 -0
  481. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app-cards/public/logo512.png +0 -0
  482. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app-cards/public/manifest.json +25 -0
  483. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app-cards/public/robots.txt +3 -0
  484. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app-cards/src/App.css +38 -0
  485. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app-cards/src/App.js +80 -0
  486. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app-cards/src/App.test.js +8 -0
  487. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app-cards/src/Config.js +527 -0
  488. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app-cards/src/Customer.js +218 -0
  489. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app-cards/src/Item.js +190 -0
  490. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app-cards/src/Order.js +189 -0
  491. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app-cards/src/Product.js +241 -0
  492. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app-cards/src/app_loader.js +24 -0
  493. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app-cards/src/index.css +13 -0
  494. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app-cards/src/index.js +17 -0
  495. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app-cards/src/logo.svg +1 -0
  496. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app-cards/src/rav4-jsonapi-client/.eslintrc +5 -0
  497. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app-cards/src/rav4-jsonapi-client/.yarnrc.yml +4 -0
  498. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app-cards/src/rav4-jsonapi-client/default-settings.js +25 -0
  499. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app-cards/src/rav4-jsonapi-client/default-settings.ts +25 -0
  500. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app-cards/src/rav4-jsonapi-client/errors.js +116 -0
  501. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app-cards/src/rav4-jsonapi-client/errors.ts +116 -0
  502. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app-cards/src/rav4-jsonapi-client/index.test.tsx +7 -0
  503. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app-cards/src/rav4-jsonapi-client/index.tsx +11 -0
  504. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app-cards/src/rav4-jsonapi-client/ra-jsonapi-client.js +577 -0
  505. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app-cards/src/rav4-jsonapi-client/ra-jsonapi-client.ts +577 -0
  506. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app-cards/src/rav4-jsonapi-client/resourceLookup.js +124 -0
  507. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app-cards/src/rav4-jsonapi-client/resourceLookup.ts +124 -0
  508. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app-cards/src/rav4-jsonapi-client/styles.module.css +9 -0
  509. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app-cards/src/reportWebVitals.js +13 -0
  510. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/my-react-app-cards/src/setupTests.js +5 -0
  511. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/templates/bar_chart.jinja +64 -0
  512. api_logic_server_cli/prototypes/manager/samples/basic_demo/ui/templates/content.html +3 -0
  513. api_logic_server_cli/prototypes/manager/samples/basic_demo/venv_setup/py.py +121 -0
  514. api_logic_server_cli/prototypes/manager/samples/basic_demo/venv_setup/readme_venv.md +20 -0
  515. api_logic_server_cli/prototypes/manager/samples/basic_demo/venv_setup/requirements-no-cli.txt +33 -0
  516. api_logic_server_cli/prototypes/manager/samples/basic_demo/venv_setup/venv-linux.sh +28 -0
  517. api_logic_server_cli/prototypes/manager/samples/basic_demo/venv_setup/venv.ps1 +21 -0
  518. api_logic_server_cli/prototypes/manager/samples/basic_demo/venv_setup/venv.sh +28 -0
  519. api_logic_server_cli/prototypes/manager/samples/dbs/readme_dbs.md +4 -4
  520. api_logic_server_cli/prototypes/manager/samples/readme_samples.md +13 -6
  521. api_logic_server_cli/prototypes/manager/system/Manager_workspace.code-workspace +3 -2
  522. api_logic_server_cli/prototypes/nw/test/readme_test_nw.md +224 -0
  523. {apilogicserver-15.0.61.dist-info → apilogicserver-15.1.0.dist-info}/METADATA +1 -1
  524. {apilogicserver-15.0.61.dist-info → apilogicserver-15.1.0.dist-info}/RECORD +528 -24
  525. api_logic_server_cli/prototypes/manager/.vscode/.copilot-instructions.md +0 -58
  526. api_logic_server_cli/prototypes/manager/.vscode/ApiLogicServer.code-workspace +0 -15
  527. api_logic_server_cli/prototypes/nw/test/readme_test.md +0 -13
  528. {apilogicserver-15.0.61.dist-info → apilogicserver-15.1.0.dist-info}/WHEEL +0 -0
  529. {apilogicserver-15.0.61.dist-info → apilogicserver-15.1.0.dist-info}/entry_points.txt +0 -0
  530. {apilogicserver-15.0.61.dist-info → apilogicserver-15.1.0.dist-info}/licenses/LICENSE +0 -0
  531. {apilogicserver-15.0.61.dist-info → apilogicserver-15.1.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,1085 @@
1
+ from __future__ import annotations # enables Resource self reference
2
+ import sqlalchemy
3
+ import logging
4
+ import contextlib
5
+ from sqlalchemy import Column, Table, ForeignKey
6
+ from sqlalchemy.orm.decl_api import DeclarativeMeta #sqlalchemy.orm.decl_api.DeclarativeMeta
7
+ from sqlalchemy.orm import relationships, relationship
8
+ from sqlalchemy.ext.declarative import declarative_base
9
+ from sqlalchemy_utils import get_referencing_foreign_keys
10
+ from sqlalchemy import event, MetaData, and_, or_
11
+ from sqlalchemy.inspection import inspect
12
+ from sqlalchemy.sql import text
13
+ from flask import jsonify
14
+ from sqlalchemy_utils.query_chain import QueryChain
15
+ import flask_sqlalchemy
16
+ import safrs
17
+ from safrs.errors import JsonapiError, ValidationError
18
+ from security.system.authorization import Security
19
+ from typing import List, Dict, Tuple
20
+ import json
21
+ import requests
22
+ import config.config as config
23
+ from config.config import Args
24
+ from api.system.expression_parser import parsePayload
25
+
26
+ resource_logger = logging.getLogger("api.customize_api")
27
+
28
+ db = safrs.DB
29
+ """this is a safrs db not DB"""
30
+
31
+ session = db.session # type: sqlalchemy.orm.scoping.scoped_session
32
+
33
+
34
+ class DotDict(dict):
35
+ """ dot.notation access to dictionary attributes """
36
+ # thanks: https://stackoverflow.com/questions/2352181/how-to-use-a-dot-to-access-members-of-dictionary/28463329
37
+ __getattr__ = dict.get
38
+ __setattr__ = dict.__setitem__
39
+ __delattr__ = dict.__delitem__
40
+
41
+
42
+ class CustomEndpoint():
43
+ """
44
+ Nested CustomEndpoint Definition. Internal system services for Ontimize.
45
+
46
+ customer = CustomEndpoint(model_class=models.Customer, alias="Customer"
47
+ , fields = [(models.Customer.CompanyName, "Customer Name")]
48
+ , children = [
49
+ CustomEndpoint(model_class=models.Order, alias = "orders"
50
+ , join_on=models.Order.CustomerId
51
+ , fields = [(models.Order.AmountTotal, "Total"),(models.Order.ShippedDate, "Ship Date")]
52
+ , children = CustomEndpoint(model_class=models.OrderDetail, alias="details"
53
+ , join_on=models.OrderDetail.OrderId
54
+ , fields = [models.OrderDetail.Quantity, models.OrderDetail.Amount]
55
+ , children = CustomEndpoint(model_class=models.Product, alias="data"
56
+ , join_on=models.OrderDetail.ProductId
57
+ , fields=[models.Product.UnitPrice, models.Product.UnitsInStock]
58
+ , isParent=True
59
+ , isCombined=False
60
+ )
61
+ )
62
+ ),
63
+ CustomEndpoint(model_class=models.OrderAudit, alias="orderAudit") # sibling child
64
+ ]
65
+ )
66
+ result = customer.execute(customer,"", "ALFKI")
67
+ # or
68
+ #result = customer.get(request,"OrderList&OrderList.OrderDetailList&OrderList.OrderDetailList.Product", "ALFKI")
69
+ """
70
+
71
+ def __init__(self
72
+ , model_class: DeclarativeMeta | None
73
+ , alias: str = ""
74
+ , fields: list[tuple[Column, str] | Column] = []
75
+ , children: list[CustomEndpoint] | CustomEndpoint = []
76
+ , join_on: list[tuple[Column] | Column] = None
77
+ , calling: callable = None
78
+ , filter_by: str = None
79
+ , order_by: Column = None
80
+ , isParent: bool = False
81
+ , isCombined: bool = False
82
+ , pagesize: int = 100
83
+ , offset: int = 0
84
+ ):
85
+ """
86
+
87
+ Declare a custom user shaped resource.
88
+
89
+ Args:
90
+ :model_class (DeclarativeMeta | None): model.TableName
91
+ :alias (str, optional): _description_. Defaults to "".
92
+ :fields (list[tuple[Column, str] | Column], optional): model.Table.Column. Defaults to [].
93
+ :children (list[CustomEndpoint] | CustomEndpoint, optional): CustomEndpoint(). Defaults to []. (OneToMany)
94
+ join_on: list[tuple[Column, Column]] - this is a tuple of parent/child multiple field joins
95
+ :calling - name of function (passing row for virtual attributes or modification)
96
+ :filter_by is string object in SQL format (e.g. '"ShipDate" != null')
97
+ :order_by is Column object used to sort aac result (e.g. order_by=models.Customer.Name)
98
+ :isParent = if True - use parent foreign key to join single lookup (ManyToOne)
99
+ :isCombined = combine the fields of the isParent = routeTrue with the _parentResource (flatten)
100
+
101
+ """
102
+ if not model_class:
103
+ raise ValueError("CustomEndpoint model_class=models.EntityName is required")
104
+ #if join_on is None and children is not None or parent is not None:
105
+ # raise ValueError("join_on= is required if using children (child column)")
106
+
107
+ self._model_class = model_class
108
+ self.alias = alias or model_class._s_type.lower()
109
+ self.fields = fields
110
+ self.children = children or []
111
+ self.calling = calling
112
+ self.filter_by = filter_by
113
+ self.order_by = order_by
114
+ self.isCombined = isCombined
115
+ self.join_on = join_on
116
+ self.isParent= isParent
117
+ self.pagesize = pagesize
118
+ self.offset = offset
119
+ self.totalQueryRecordsNumber = 999
120
+ self.startRecordIndex = 0
121
+ if isinstance(join_on, tuple):
122
+ if len(join_on) > 0:
123
+ # get parent or child
124
+ self.foreignKey = join_on[0] # - if we have multiple joins
125
+ else:
126
+ self.foreignKey = join_on
127
+
128
+ # Internal Private
129
+ self.primaryKey: str = inspect(model_class).primary_key[0].name
130
+ self.primaryKeyType: str = inspect(self._model_class).primary_key[0].type
131
+ self._model_class_name: str = self._model_class._s_class_name
132
+ # inspect(model_class).primary_key[0].type = Integer() ...
133
+ self._parentResource: CustomEndpoint = None # ROOT
134
+ self._pkeyList: list = [] # primary key list collect when needed - do not store
135
+ self._fkeyList: list = [] # foreign_key list (used by isParent) collect when needed - do not store
136
+ self._dictRows: list = [] # temporary holding for query results (Phase 1)
137
+ self._parentRow = Dict[str, any] # keep track of linkage
138
+ self._method = None
139
+ self._href = None
140
+ self._columnNames = [k.key for k in self._model_class._s_columns]
141
+ key = self._model_class_name
142
+ from api.api_discovery.ontimize_api import getMetaData
143
+ resources = getMetaData(key)
144
+ self._attributes = resources["resources"][key]["attributes"]
145
+ self._quote = '`' if Args.backtic_as_quote else '"'
146
+
147
+ def __str__(self):
148
+ return f"Alias {self.alias} Model: {self._model_class.__name__} PrimaryKey: {self.primaryKey} FilterBy: {self.filter_by} OrderBy: {self.order_by}"
149
+
150
+ def get(self: CustomEndpoint, request: safrs.request.SAFRSRequest, include: str, altKey: str = None) -> dict:
151
+ """_summary_
152
+
153
+ Args:
154
+ :self (CustomEndpoint):
155
+ :request (safrs.request.SAFRSRequest):
156
+ :include (str): name(s) of relationship from swagger include=
157
+ :altKey (str, optional): Defaults to None.
158
+
159
+ Returns:
160
+ dict: JSON result
161
+ """
162
+ if request.method == 'OPTIONS':
163
+ return jsonify(success=True)
164
+
165
+ serverURL = f"{request.host_url}api"
166
+ query = f"{serverURL}/{self._model_class_name}?include={include}"
167
+ args = request.args
168
+ key, value, limit, offset, order_by, filter_ = self.parseArgs(args)
169
+ if altKey is not None:
170
+ query += f"&filter%5B{self.primaryKey}%5D={altKey}"
171
+ elif key is not None and value is not None:
172
+ query += f"&filter%5B{key}%5D={value}"
173
+ else:
174
+ #query = query if filter_ is None or filter_ is '1=1' else f"{query} and {filter_}"
175
+ query = (
176
+ query
177
+ if filter_ is None or filter_ == '1=1'
178
+ else f"{query} and {filter_}"
179
+ )
180
+ self._href = f"{request.url_root[:-1]}{request.path}"
181
+ print(f"limit: {limit}, offset: {offset}, sort: {order_by}, query: {query}")
182
+ params = {'page[limit]': limit, 'page[offset]': offset}
183
+ resource_logger.debug(f"CustomEndpoint get using query: {query}")
184
+ if Args.security_enabled:
185
+ jwt = request.headers.get("Authorization") or ""
186
+ header = {"Authorization": jwt,"Content-Type": "application/json"}
187
+ result = requests.get(query, headers=header, params=params)
188
+ else:
189
+ result = requests.get(query, params=params)
190
+ if result.status_code == 200:
191
+ jsonResult = json.loads(result.content)
192
+ self._populateResponse(jsonResult) # Pass the JSON result to CustomEndpoint
193
+ result = self.execute(request) # a dict of args
194
+ return result
195
+ return {"error": result.status_code}
196
+
197
+ def execute(self: CustomEndpoint, request: safrs.request.SAFRSRequest, altKey: str = None) -> dict:
198
+ """
199
+ execute a model_class resource
200
+ Args:
201
+ :self (CustomEndpoint):
202
+ : request SarfsRequest (holds args and data payload, etc)
203
+ : altKey optional <key> passed from @app.route("/foo/<altKey>")
204
+
205
+ 'page[offset]=0 or offset=0
206
+ 'page[limit]=10 or limit=10
207
+ 'sort=CompanyName'
208
+ 'filter[id]=ALFKI or Id=ALFKI
209
+
210
+ #self._model_class.get_instance("ALFKI") returns the Cusomter/OrderList/OrderDetailList and Product
211
+ #util.row_to_dict(self._model_class.get_instance("ALFKI").OrderList[0].OrderDetailList[0].Product)
212
+ #for f in util.row_to_dict(self._model_class.get_instance("ALFKI")).get("relationships") :print(f'{util.row_to_dict(self._model_class.get_instance("ALFKI"))}.{f}')
213
+ #self._model_class.get_instance('ALFKI')._s_relationships.get("OrderList").synchronize_pairs
214
+ #"Manager" in self._model_class._s_relationships.keys() #_s_jsonapi_attrs.keys()
215
+ #rom .jsonapi_formatting import jsonapi_filter_query, jsonapi_filter_list, jsonapi_sort, jsonapi_format_response, paginate
216
+ #self._model_class.__mapper__.relationships.get("Manages").primaryjoin.left or right left.key or right.key
217
+
218
+ '''
219
+
220
+ Returns:
221
+ dict: data dict from sql
222
+ """
223
+ expressions = []
224
+ args = {}
225
+ payload = {}
226
+ result = {}
227
+ jwt = ""
228
+ pkey = None
229
+ value = None
230
+ if request is not None:
231
+ jwt = request.headers.get("Authorization") or ""
232
+ method = request.method
233
+ self._method = method
234
+ args = request.args
235
+ if len(request.data) > 0:
236
+ payload = json.loads(request.data.decode('utf-8'))
237
+ self._printIncludes(1) # debug print
238
+ if method == 'DELETE':
239
+ raise ValidationError( 'Delete is not supported at this time')
240
+ elif method == 'OPTIONS':
241
+ return jsonify(success=True)
242
+ elif method in ["PUT","PATCH"]:
243
+ api = "api" # TODO Args.api_prefix()
244
+ serverURL = f"{request.host_url}{api}"
245
+ url = f"{serverURL}/{self._model_class_name}"
246
+ return self.handlePayload(method=method, payload=payload, url=url, jwt=jwt, altKey=altKey)
247
+ elif method == 'POST':
248
+ try:
249
+ return self.insert_or_update(payload=payload, altKey=altKey)
250
+ except Exception as ex:
251
+ raise ValidationError( f'{method} error on entity {self._model_class_name} msg: {ex}') from ex
252
+ elif method == 'GET':
253
+ if payload:
254
+ expressions, filter_, columns, sqltypes, offset, limit, order_by, data = parsePayload(clz=self._model_class, payload=payload)
255
+ else:
256
+ pkey , value, limit, offset, order_by , filter_ = self.parseArgs(args)
257
+ #serverURL = f"{request.host_url}api"
258
+ #query = f"{serverURL}/{self._model_class_name}"
259
+ self.startRecordIndex = int(offset)
260
+ resource_logger.debug(f"CustomEndpoint execute on: {self._model_class_name} using alias: {self.alias}")
261
+ filter_by = None
262
+ #key = args.get(pkey) if args.get(pkey) is not None else args.get(f"filter[{pkey}]")
263
+ _quote = '`' if Args.backtic_as_quote else '"'
264
+ if value is not None and value != 'undefined':
265
+ filter_by = f'{_quote}{pkey}{_quote} = {self.quoteStr(value)}'
266
+ self._pkeyList.append(self.quoteStr(value))
267
+ elif altKey is not None:
268
+ filter_by = f'{_quote}{pkey}{_quote} = {self.quoteStr(altKey)}'
269
+ self._pkeyList.append(self.quoteStr(altKey))
270
+ filter_by = filter_by if filter_ is None else f"{filter_by} and {filter_}" if filter_by is not None else filter_
271
+ self._href = f"{request.url_root[:-1]}{request.path}"
272
+ limit = max(self.pagesize, int(limit))
273
+ print(f"limit: {limit}, offset: {offset}, sort: {order_by},filter_by: {filter_by}, add_filter {filter_}")
274
+ try:
275
+ self._createRows(limit=limit,offset=offset,order_by=order_by,filter_by=filter_by, expressions=expressions)
276
+ self._executeChildren()
277
+ self._modifyRows(result)
278
+ return json.dumps(result, indent=4, ensure_ascii=False).encode('utf8')
279
+ except Exception as ex:
280
+ resource_logger.error(f"CustomEndpoint error {ex}")
281
+ return f"'error': {ex}"
282
+
283
+ def _executeChildren(self):
284
+ """
285
+ Recursive execution of included CustomEndpoints
286
+ """
287
+ if isinstance(self.children, CustomEndpoint):
288
+ self.children._parentResource = self
289
+ self.children._href = f"{self.modifyPath(self._href)}{self.children._model_class_name}"
290
+ self.children._processChildren()
291
+ elif len(self.children) > 0:
292
+ for child in self.children:
293
+ child._parentResource = self
294
+ child._href = f"{self.modifyPath(self._href)}{child._model_class_name}"
295
+ child._processChildren()
296
+
297
+ def _collectPKeys(self, keyName)-> list:
298
+ keyList = []
299
+ if keyName is None:
300
+ return keyList
301
+ for row in self._dictRows:
302
+ if keyName in row:
303
+ key = row.get(keyName)
304
+ if key is not None and key not in keyList:
305
+ keyList.append(key)
306
+
307
+ self._pkeyList = keyList
308
+ return keyList
309
+
310
+ def _collectParentKeys(self, keyName: str) -> list:
311
+ keyList = []
312
+ #if not self.isParent or keyName is None:
313
+ if self._parentResource is None or keyName is None:
314
+ return self._parentResource._pkeyList
315
+ for row in self._parentResource._dictRows:
316
+ if keyName in row:
317
+ key = row.get(keyName)
318
+ if key is not None and key not in keyList:
319
+ keyList.append(key)
320
+
321
+ self._fkeyList = keyList
322
+ return keyList
323
+
324
+ def _createRows(self,limit:int = 10, offset = 0, filter_by: str = None, order_by: str = None, expressions: list = []):
325
+ """
326
+ execute and store rows based on list of keys in model
327
+ :limit = 10
328
+ :offset = 0
329
+ :filter_by root only
330
+ :order_by root only
331
+ :expressions = list of expressions
332
+ """
333
+ # If _populateResponse is used - the _dictRows are already filled
334
+ # or the parent resource has now rows - so no need to fetch
335
+ if len(self._dictRows) > 0 or \
336
+ (self._parentResource is not None \
337
+ and len(self._parentResource._dictRows) == 0):
338
+ return
339
+ model_class = self._model_class
340
+ model_class_name = self._model_class_name
341
+ queryFilter = self._createFilterFromKeys()
342
+ session_qry= session.query(model_class)
343
+ #result = session.execute(select(model_class).where(text("Id = 'ALFKI'"))).all() #.join(models.Customer.OrderList)).order()
344
+ if queryFilter is None or queryFilter == 'None':
345
+ #query = select(self._model_class)
346
+ resource_logger.debug(
347
+ f"CreateRows on {model_class_name} using filter_by: {self.filter_by} order_by: {self.order_by}")
348
+ if self.filter_by is not None:
349
+ qry = session_qry.filter(text(self.filter_by))
350
+ if self.order_by is not None:
351
+ qry = qry.order_by(self.order_by)
352
+ if filter_by is not None and 'undefined' not in filter_by:
353
+ resource_logger.debug(
354
+ f"Adding filter_by: {filter_by}")
355
+ qry = qry.filter(text(filter_by))
356
+ rows = qry.limit(limit).offset(offset).all()
357
+ else:
358
+ if filter_by is not None:
359
+ resource_logger.debug(
360
+ f"Adding filter_by: {filter_by}")
361
+ session_qry = session_qry.filter(text(filter_by))
362
+
363
+ if order_by:
364
+ if isinstance(order_by, list) and len(order_by) > 0:
365
+ col_name = order_by[0]["columnName"]
366
+ direction = order_by[0]["ascendent"] if "ascendent" in order_by[0] else False
367
+ for a in self._attributes:
368
+ if a['attr'].key == col_name:
369
+ col_name = f"{a['attr'].columns[0].name } { 'asc' if direction else 'desc'}"
370
+ q = '"'
371
+ col_name = f"{q}{a['attr'].columns[0].name}{q}"
372
+ break
373
+ session_qry = session_qry.order_by(text(col_name))
374
+ else:
375
+ if order_by in self._attributes:
376
+ session_qry = session_qry.order_by(text(order_by))
377
+ rows = session_qry.limit(limit).offset(offset).all()
378
+ else:
379
+ resource_logger.debug(
380
+ f"CreateRows on {model_class_name} using QueryFilter: {queryFilter} order_by: {self.order_by}")
381
+ if self.order_by is not None:
382
+ if self.order_by in self._attributes:
383
+ session_qry = session_qry.filter(text(queryFilter)).order_by(self.order_by)
384
+ elif self.filter_by is None:
385
+ session_qry = session_qry.filter(text(queryFilter))
386
+ else:
387
+ if filter_by:
388
+ resource_logger.debug(
389
+ f"Adding on {model_class_name} using filter_by: {filter_by}")
390
+ session_qry = session_qry.filter(text(filter_by))#.filter(text(self.filter_by))
391
+ if order_by:
392
+ col_name = order_by[0]["columnName"]
393
+ for a in self._attributes:
394
+ if a['attr'].key == col_name:
395
+ col_name = a['attr'].columns[0].name
396
+ break
397
+ session_qry = session_qry.order_by(text(col_name))
398
+ rows = session_qry.limit(limit).offset(offset).all()
399
+ if rows:
400
+ dictRows = self.rows_to_dict(rows)
401
+ self._dictRows = dictRows
402
+
403
+
404
+ def _createFilterFromKeys(self):
405
+ aFilter = None
406
+ if self.join_on:
407
+ """
408
+ join_on=[(models.SourceDatum.clientId, models.SourceDatum.clientId),(models.SourceDatum.dataYear, models.SourceDatum.priorYear)]
409
+ we may have multiple joins - need to collect each one
410
+ #clientId in (clientId keys) and dataYear in (priorYear keys)
411
+ #result += F"{and} " + self._extractedFromKeys(keyName, keys)
412
+
413
+ """
414
+ if isinstance(self.join_on, list):
415
+ andOp = ""
416
+ for join in self.join_on:
417
+ aFilter = self.buildJoin(andOp, join)
418
+ andOp = " and "
419
+ else:
420
+ aFilter = self.buildJoin("", self.join_on)
421
+
422
+ return aFilter
423
+
424
+ def buildJoin(self, andOp: str, join: Column) -> str:
425
+ joinStr = None
426
+ if join is not None:
427
+ if join.__class__.__name__ == 'InstrumentedAttribute':
428
+ if hasattr(join,"prop") and join.prop.__class__.__name__ == 'RelationshipProperty':
429
+ # pass #oin.prop._join_condition.foreign_key_columns
430
+ for l in join.prop._join_condition.foreign_key_columns:
431
+ fkeyName = self.primaryKey if self.isParent else l.key
432
+ self.foreignKey = l
433
+ keyName = l.key if self.isParent else self.primaryKey
434
+ else:
435
+ fkeyName = self.primaryKey if self.isParent else join.key #child - parent pkey is implied
436
+ keyName = join.key if self.isParent else self.primaryKey
437
+
438
+ elif len(join) == 2:
439
+ pkeyName = join[0].key #parent
440
+ fkeyName = join[1].key #child
441
+ self.primaryKey = fkeyName if self.isParent else self.primaryKey
442
+ self.foreignKey = join[1] if self.isParent else join[0]
443
+ keyName = join[1].key if self.isParent else pkeyName
444
+
445
+ keys = self._collectParentKeys(keyName)
446
+ if keys is not None:
447
+ joinStrKeys = self._extractedFromKeys(fkeyName , keys)
448
+ return f"{andOp}{joinStrKeys}"
449
+ return None
450
+
451
+
452
+ def _extractedFromKeys(self, keyName: str, keys: object):
453
+ if keys is None or len(keys) == 0:
454
+ return None
455
+ keys = f"{keys}"
456
+ keys = keys.replace("[", "")
457
+ keys = keys.replace("]", "")
458
+ result = ""
459
+ if len(keys) > 0:
460
+ result = f'{keyName} in ({keys})'
461
+ result = result.replace(".", "\".\"")
462
+ if self.filter_by is not None:
463
+ result += f" and text({self.filter_by})"
464
+ return result
465
+
466
+ def _printIncludes(self, level: int):
467
+ parenName = self._parentResource._model_class_name if self._parentResource is not None else "None"
468
+ if self.foreignKey:
469
+ print(
470
+ level * ' ', f"CustomEndpoint alias: {self.alias} model: {self._model_class.__name__} primaryKey: {self.primaryKey} join_on: {self.foreignKey} parent: {parenName}")
471
+ else:
472
+ print(
473
+ level * ' ', f"CustomEndpoint alias: {self.alias} model: {self._model_class.__name__} primaryKey: {self.primaryKey} parent: {parenName}")
474
+ if isinstance(self.fields, tuple) and len(self.fields) > 0:
475
+ fields = self.getPrintableFields()
476
+ print(level * ' ', f"Fields: {fields}", sep=", ")
477
+ elif isinstance(self.fields, sqlalchemy.orm.attributes.InstrumentedAttribute):
478
+ print(level * ' ', f"Fields: {self.fields.key}", sep=", ")
479
+ if isinstance(self.children, CustomEndpoint):
480
+ self.children._parentResource = self
481
+ self.children._printIncludes(level + 1)
482
+ elif len(self.children) > 0:
483
+ for incl in self.children:
484
+ incl._parentResource = self
485
+ incl._printIncludes(level + 1)
486
+
487
+ def getPrintableFields(self):
488
+ result = ""
489
+ if len(self.fields) > 0:
490
+ for fld in self.fields:
491
+ if isinstance(fld, str):
492
+ result += f" alias: {fld} "
493
+ elif isinstance(self.fields, sqlalchemy.orm.attributes.InstrumentedAttribute):
494
+ result += f" {fld[0].key} " if isinstance(fld, tuple) else f" {fld} "
495
+ return result
496
+
497
+ def _modifyRows(self, result):
498
+ """
499
+ Start at root row and descend to each child
500
+ Args:
501
+ result dict modified and shaped JSON
502
+ """
503
+ result[self.alias] = []
504
+ for row in self._dictRows:
505
+ newRow = self._modifyRow(row)
506
+ result[self.alias].append(newRow)
507
+ #need to link each newRow with one or more childRows
508
+ if isinstance(self.children, CustomEndpoint):
509
+ self.children._linkAndModifyRows(row, newRow)
510
+ elif len(self.children) > 0:
511
+ for child in self.children:
512
+ child._linkAndModifyRows(row, newRow)
513
+
514
+ def _linkAndModifyRows(self, row: dict, modifiedRow: dict):
515
+ """
516
+ link rows to parent
517
+ Args:
518
+ row (dict): this is the parent row
519
+ modifiedRow (dict): this is the same row that has been modified
520
+ """
521
+ if not self.isCombined:
522
+ modifiedRow[self.alias] = []
523
+ self._parentRow = DotDict(row)
524
+ pkeyValue = row[self.foreignKey.key] if self.isParent and self.foreignKey.key in row else row[self.primaryKey]
525
+ fkey = self.primaryKey if self.isParent and self.primaryKey in row else self.foreignKey.key if self.foreignKey is not None else None
526
+ for dictRow in self._dictRows:
527
+ if fkey is not None and f"{pkeyValue}" == f"{dictRow[fkey]}":
528
+ newRow = self._modifyRow(dictRow)
529
+ if self.isParent and self.isCombined:
530
+ modifiedRow |= newRow
531
+ else:
532
+ modifiedRow[self.alias].append(newRow)
533
+ if isinstance(self.children, CustomEndpoint):
534
+ self.children._linkAndModifyRows(dictRow, newRow)
535
+ elif len(self.children) > 0:
536
+ for include in self.children:
537
+ include._linkAndModifyRows(dictRow, newRow)
538
+
539
+ def _modifyRow(self, dict_row: dict) -> dict:
540
+ #row = self.transform('LAC','',dict_row)
541
+ newRow = DotDict({})
542
+ tableRow = DotDict(dict_row)
543
+ if isinstance(self.fields, sqlalchemy.orm.attributes.InstrumentedAttribute):
544
+ f = self.fields
545
+ fieldName = f[0].key if isinstance(f, tuple) else f.key
546
+ alias = f[1] if isinstance(f, tuple) else fieldName
547
+ if fieldName in tableRow:
548
+ newRow[alias] = tableRow[fieldName]
549
+ elif len(self.fields) > 0:
550
+ for f in self.fields:
551
+ if isinstance(f,str):
552
+ fieldName = f
553
+ alias = fieldName
554
+ elif isinstance(f[0], sqlalchemy.sql. schema.Column):
555
+ alias = f[0].description
556
+ fieldName = f[1] if isinstance(f, tuple) else fieldName
557
+ else:
558
+ fieldName = f[0].key if isinstance(f, tuple) else f.key
559
+ alias = f[1] if isinstance(f, tuple) else fieldName
560
+ if fieldName in tableRow:
561
+ newRow[alias] = tableRow[fieldName]
562
+ else:
563
+ newRow = tableRow
564
+ # allow adding or changes using defined function
565
+ if self.calling is not None:
566
+ try:
567
+ resource_logger.debug(f"calling function {self.calling}")
568
+ self.calling(newRow, tableRow, self._parentRow)
569
+ except Exception as ex:
570
+ resource_logger.error(f"unable to execute fn {self.calling} error: {ex}")
571
+ if not self.isCombined:
572
+ self.insertCheckSum(newRow, tableRow)
573
+
574
+ return newRow
575
+
576
+ def insertCheckSum(self, newRow: dict, tableRow: dict):
577
+ if Args.opt_locking == "required" \
578
+ and ("S_CheckSum" not in newRow and "S_CheckSum" in tableRow):
579
+ newRow["S_CheckSum"] = tableRow.S_CheckSum
580
+ newRow = self.move_checksum(newRow)
581
+ elif "@metadata" in tableRow:
582
+ newRow["@metadata"] = tableRow["@metadata"]
583
+ if "S_CheckSum" in newRow:
584
+ newRow.pop("S_CheckSum")
585
+
586
+
587
+ def addRowToResult(self, result: any, rows: any):
588
+ """_summary_
589
+
590
+ Args:
591
+ result (any): this is the final output
592
+ rows (any): the unmodified dict rows
593
+ """
594
+ if self.foreignKey is None:
595
+ return
596
+ fkey = self.foreignKey.key if isinstance(self.foreignKey, object) else self.foreignKey
597
+ resource_logger.debug(f"Add Row to Result {self._model_class_name} using {fkey}")
598
+ keyList = self._fkeyList if self.isParent else self._parentResource._pkeyList
599
+ for parentKey in keyList:
600
+ for r in result:
601
+ r[self.alias] = []
602
+ for row in rows:
603
+ fkeyValue = row.get(fkey)
604
+ if parentKey == fkeyValue:
605
+ #modifiedRow = self._modifyRow(row)
606
+ r[self.alias].append(row)
607
+
608
+ def _populateResponse(self, jsonResponse):
609
+ """
610
+ Given a json response extract and populate internal dictRows
611
+ Args:
612
+ jsonResponse (_type_): _description_
613
+ """
614
+ #assume 1 data row
615
+ jsonDict = DotDict(jsonResponse)
616
+ if len(jsonDict.data) == 0:
617
+ return
618
+ for data in jsonDict.data:
619
+ key = data["id"]
620
+ row = data["attributes"]
621
+ if self.primaryKey == "id" and "id" not in row:
622
+ row["id"] = key #this is a hack since id is a jsonapi reserved value
623
+ self._dictRows.append(row)
624
+ if key not in self._pkeyList:
625
+ self._pkeyList.append(key)
626
+ model_type = data["type"]
627
+ resource_logger.debug(f"_populateResponse row class on {self._model_class_name} using model_type: {model_type} with key {key}")
628
+ if self.children is not None:
629
+ included = jsonDict.included
630
+ if len(included) == 0:
631
+ return
632
+ if isinstance(self.children, list):
633
+ for child in self.children:
634
+ child._parentResource = self
635
+ child.processIncludedRows(included)
636
+ else:
637
+ self.children._parentResource = self
638
+ self.children.processIncludedRows(included)
639
+
640
+ def processIncludedRows(self, included: list):
641
+ for parentKey in self._parentResource._pkeyList:
642
+ for row in included:
643
+ model_class_name = row["type"]
644
+ if model_class_name == self._model_class_name:
645
+ resource_logger.debug(f"includeRow for {self._model_class_name}")
646
+ attrRow = row["attributes"]
647
+ if "id" not in "attrs" and "id" in row:
648
+ attrRow["id"] = row["id"]
649
+ keyName = self.primaryKey if self.isParent else self.join_on.key
650
+ if keyName in attrRow and parentKey == attrRow[keyName]:
651
+ resource_logger.debug(f"includeRow for {self._model_class_name} checking {model_class_name} using Key: {keyName} ")
652
+ #links = row["links"]
653
+ #relns = row["relationships"]
654
+ self._dictRows.append(attrRow)
655
+ key = attrRow[self.primaryKey]
656
+ if key not in self._pkeyList:
657
+ self._pkeyList.append(key)
658
+ if self.children is not None:
659
+ if isinstance(self.children, list):
660
+ for child in self.children:
661
+ child._parentResource = self
662
+ child.processIncludedRows(included)
663
+ else:
664
+ self.children._parentResource = self
665
+ self.children.processIncludedRows(included)
666
+
667
+ def insert_or_update(self, payload: dict,altKey: str = None) -> any:
668
+ p = []
669
+ if not isinstance(payload, list):
670
+ p.append(payload)
671
+ else:
672
+ p = payload
673
+ result = []
674
+ for row in p:
675
+ clz = self.copy_dict_to_row(payload=row)
676
+ if altKey is not None:
677
+ setattr(clz, self.primaryKey, altKey)
678
+ session.add(clz)
679
+ session.commit()
680
+ d = {}
681
+ for column in clz.__table__.columns:
682
+ d[column.name] = str(getattr(clz, column.name))
683
+ result.append(d)
684
+ return result
685
+
686
+ def handlePayload(self, method: str, payload: any, url: str, jwt: str,altKey: str = None) -> any:
687
+ """ tests
688
+ stmt = ""
689
+ if method == 'POST':
690
+ stmt = insert(self._model_class).values(payload)
691
+ #elif stmt = update(self._model_class).values(payload) #.where(self.primaryKey = 1)
692
+ clz = self._model_class
693
+ key = self.populateClass(clz, payload)
694
+ db.session.add(clz)
695
+ #db.engine.execute(stmt)
696
+ # db.session.select().filter_by().one()
697
+ return db.engine.execute(f"select * from {self._model_class_name} limit 1").one()
698
+ """
699
+ j = self.create_args(method, payload, altKey)
700
+ # check payload for a single row
701
+ clz = self._model_class
702
+ #key = self.populateClass(clz, payload)
703
+ print(self.to_dict(payload))
704
+ # need to do a loop to post/patch each level
705
+ #pkey = None
706
+ #for row, model_clz in self.getRowFrom(payload, pkey): #cascade primary key
707
+ # pkey = insert(self.model_clz).values(dmlColumnKeyMapping(row)).returning(model_clz.get(self.primary_key))
708
+ # or
709
+ # populate(model_clz, row, pkey)
710
+ # session.add(model_clz)
711
+ # pkey = model_clz.get(self.primary_key) if hassattr(model_clz, self.primary_key) else None
712
+
713
+ key = altKey if altKey else payload[self.primaryKey] if self.primaryKey in payload else "-1"
714
+ if Args.security_enabled:
715
+ header = {"Authorization": jwt,"Content-Type": "application/json","accept": "application/vnd.api+json"}
716
+ response = (
717
+ requests.post(url=url, json=j, headers=header) #insert(self._model_class).values(self.dmlColumnKeyMapping(row)).returning("id")
718
+ if method == 'POST'
719
+ else requests.patch(url=f"{url}/{key}", json=j, headers=header) #update(self._model_class).values(self.dmlColumnKeyMapping(row))
720
+ )
721
+ else:
722
+ response = {}
723
+ if method == "POST":
724
+ response = requests.post(url=url, json=j)
725
+ elif method in ["PUT","PATCH" ]:
726
+ response = requests.patch(url=f"{url}/{key}", data=j)
727
+ data = json.loads(response.text)["data"]["attributes"]
728
+ return json.dumps(data,indent=4, ensure_ascii=False).encode('utf8') if response.status_code < 301 else response.content
729
+
730
+ def populateClass(self, clz, payload):
731
+ for p in payload:
732
+ clz(p = payload[p])
733
+ return clz[self.primaryKey]
734
+
735
+ def create_args(self, method:str, attributes:any, altKey:str = None):
736
+ key = altKey if altKey else attributes[self.primaryKey] if self.primaryKey in attributes else None
737
+ result = None
738
+ if key is None or method == 'POST':
739
+ result = \
740
+ { "data": {
741
+ "attributes": attributes,
742
+ "type": self._model_class_name
743
+ }
744
+ }
745
+ else:
746
+ result = \
747
+ { "data": {
748
+ "attributes": self.move_metadata(attributes),
749
+ "type": self._model_class_name,
750
+ "id": int(key) if self.primaryKeyType.python_type == int else key
751
+ }
752
+ }
753
+ v = str(result)
754
+ v = v.replace("'","\"",1000)
755
+ return json.loads(v.replace("None","null",100))
756
+
757
+ def move_metadata(self, json_dict:dict) -> dict:
758
+ if "@metadata" in json_dict:
759
+ if json_dict["@metadata"]["checksum"] != 'override':
760
+ json_dict["S_CheckSum"] = json_dict["@metadata"]["checksum"]
761
+ json_dict.pop("@metadata")
762
+ return json_dict
763
+
764
+ def quoteStr(self, val):
765
+ return val if f"{self.primaryKeyType}" == 'INTEGER' else f"'{val}'"
766
+
767
+ def rows_to_dict(self: CustomEndpoint, result: flask_sqlalchemy.BaseQuery) -> list:
768
+ """
769
+ Converts SQLAlchemy result to dict array
770
+
771
+ Args:
772
+ result (object): SQLAlchemy result
773
+
774
+ Returns:
775
+ dict: dict array
776
+ """
777
+ from decimal import Decimal
778
+ import datetime
779
+ rows = []
780
+ for each_row in result:
781
+ row_as_dict = {}
782
+ print(f'type(each_row): {type(each_row)}')
783
+ if isinstance (each_row, sqlalchemy.engine.row.Row): # sqlalchemy.engine.row
784
+ row_as_dict = each_row._asdict()
785
+ else:
786
+ for a,v, in each_row.__dict__.items():
787
+ if a != "_sa_instance_state":
788
+ if isinstance(v, Decimal):
789
+ row_as_dict[a] = str(v)
790
+ elif isinstance(v, datetime.date):
791
+ row_as_dict[a] = v.strftime('%Y-%m-%d %H:%M:%S')
792
+ else:
793
+ row_as_dict[a] = v
794
+ if hasattr(each_row,"id"):
795
+ with contextlib.suppress(Exception):
796
+ row_as_dict["id"] = each_row.id
797
+ rows.append(row_as_dict)
798
+ return rows
799
+
800
+ def row_to_dict(self: CustomEndpoint, row
801
+ , replace_attribute_tag: str = ""
802
+ , remove_links_relationships: bool = False) -> dict:
803
+ """
804
+ returns dict suitable for safrs response
805
+
806
+ Args:
807
+ row (safrs.DB.Model): a SQLAlchemy row
808
+ replace_attribute_tag (str): replace _attribute_ tag with this name
809
+ remove_links_relationships (bool): remove these tags
810
+ Returns:
811
+ _type_: dict (suitable for flask response)
812
+ """
813
+ row_as_dict = jsonify(row).json
814
+ resource_logger.debug(f'Row: {row_as_dict}')
815
+ if replace_attribute_tag != "":
816
+ row_as_dict[replace_attribute_tag] = row_as_dict.pop('attributes')
817
+ if remove_links_relationships:
818
+ row_as_dict.pop('links')
819
+ row_as_dict.pop('relationships')
820
+ if not hasattr(row_as_dict,"id"):
821
+ with contextlib.suppress(Exception):
822
+ row_as_dict["id"] = row["id"]
823
+ return row_as_dict
824
+
825
+ def _processChildren(self):
826
+ resource_logger.debug(
827
+ f"_executeChildren a child: {self._model_class_name} isParent: {self.isParent}")
828
+ self._createRows()
829
+ self._executeChildren()
830
+
831
+ def parseArgs(self,args):
832
+ '''
833
+ Args = filter.data.data.data = "someexpression=N"
834
+ '''
835
+ tenant_filter = None
836
+ _filter = None
837
+ pkey = self.primaryKey
838
+ dots = self.getAlias()
839
+ filter_with_alias = f"filter.{dots}"if len(dots) > 0 else ""
840
+ value = args.get(pkey) if args.get(pkey) is not None else args.get(f"filter[{pkey}]")
841
+ #if value is None:
842
+ _sys_filter:str = args.get("sysfilter")
843
+ _filter:str = args.get("filter") if args.get("filter") is not None else args.get(filter_with_alias) if args.get(filter_with_alias) is not None else None
844
+
845
+ if _sys_filter:
846
+ if _sys_filter.startswith("equal("):
847
+ f = _sys_filter[6:-1].split(":")
848
+ pkey = f[0]
849
+ value = f[1]
850
+ elif _filter:
851
+ f = _filter.split("=")
852
+ if len(f) > 1 and f[1] != 'undefined' and f[0] == self.primaryKey:
853
+ q = '' if f[0] in ['OFFICEID','CUSTOMERID','ACCOUNTID','BRANCHID'] else "'"
854
+ pkey = f'"{f[0]}"'
855
+ value = f"{q}{f[1]}{q}"
856
+
857
+ limit = args.get("page[limit]") or args.get("pagesize") or 20
858
+ offset = args.get("page[offset]") or args.get("offset") or 0
859
+ sort = args.get("sort")
860
+ tenant_filter = _filter if _filter is not None else "1=1"
861
+
862
+ return pkey, value, limit, offset, sort, tenant_filter
863
+
864
+ def getAlias(self):
865
+ #fillter.data.data.data="someexpression=areaCode<3"
866
+ dots = ""
867
+ if self.children is not None:
868
+ if isinstance(self.children, CustomEndpoint):
869
+ return f"{self.alias}.{self.children.alias}"
870
+ for child in self.children:
871
+ if dots == "":
872
+ dots = f".{self.alias}"
873
+ dots = f"{dots}.{child.alias}"
874
+ return dots
875
+
876
+ def transform(self, style:str, key:str, json_: dict) -> dict:
877
+ # use this to change the output (pipeline) of the result
878
+ json_dict = {}
879
+ json_result = []
880
+ result = []
881
+ try:
882
+ if self._method == 'OPTIONS':
883
+ return json_
884
+ #TODO - fixup asscii to utf-8
885
+ json_dict = json.loads(json_) if isinstance(json_, bytes) else json_
886
+ json_result = json_dict.get(key, json_dict) if key in json_dict else json_dict if isinstance(json_dict, list) else [json_dict]
887
+ except Exception as ex:
888
+ resource_logger.error(f"Transform Error on style {style} using key: {key} on {json_} error: {ex}")
889
+ return json_
890
+
891
+
892
+ if isinstance(json_result,list):
893
+ newRes = []
894
+ for row in json_result:
895
+ r = self.move_checksum(row)
896
+ newRes.append(r)
897
+ result = newRes
898
+ result = self.move_checksum(json_result)
899
+ result if isinstance(result,list) else [result]
900
+
901
+ if style == "JSONAPI":
902
+ # Ontimize using the JSONAPI with the API Bridge
903
+ data = []
904
+ for row in result:
905
+ pkey = row[self.primaryKey] if self.primaryKey in row else None
906
+ if pkey is None:
907
+ pkey = row["id"] if "id" in row else row["Id"] if "Id" in row else None
908
+ data.append({"attributes": row,"type": self._model_class_name, "id": pkey })
909
+ data = {"data": data,
910
+ "meta": {
911
+ "count": len(result),
912
+ "limit": self.pagesize,
913
+ "total": len(result)
914
+ }
915
+ }
916
+ result = data
917
+ elif style == "OntimizeEE":
918
+ #API Bridge - lets Ontimize work out-of-the-box
919
+ recordsNumber = self.totalQueryRecordsNumber #if len(result) == 0 else self.startRecordIndex
920
+ startRecord = self.startRecordIndex
921
+ result = {"code":0,"totalQueryRecordsNumber": recordsNumber, "startRecordIndex": startRecord, "message":"ApiLogicServer","data": result ,"sqlTypes":{}}
922
+ #if style == "LAC": default
923
+ return result
924
+
925
+
926
+ def move_checksum(self, json_dict:any) -> dict:
927
+ if isinstance(json_dict, dict):
928
+ if "S_CheckSum" in json_dict:
929
+ checksum = json_dict["S_CheckSum"]
930
+ pk = json_dict[self.primaryKey] if self.primaryKey in json_dict else ""
931
+ href = f"{self._href}/{pk}" if self._href is not None else ""
932
+ json_dict["@metadata"] = { "checksum" : checksum, "href": href}
933
+ json_dict.pop("S_CheckSum")
934
+ if "_check_sum_" in json_dict:
935
+ json_dict.pop("_check_sum_")
936
+ elif isinstance(json_dict,list):
937
+ for json_ in json_dict:
938
+ self.move_checksum(json_)
939
+ if self.children is not None:
940
+ if isinstance(self.children, list):
941
+ for child in self.children:
942
+ if child.alias in json_dict:
943
+ child.move_checksum(json_dict[child.alias])
944
+ else:
945
+ if self.children.alias in json_dict:
946
+ self.children.move_checksum(json_dict[self.children.alias])
947
+ return json_dict
948
+
949
+ def to_dict(self, row: object, current_endpoint: 'CustomEndpoint' = None) -> dict:
950
+ """returns row as dict per custom resource definition, with subobjects
951
+
952
+ Args:
953
+ row (_type_): a SQLAlchemy row
954
+
955
+ Returns:
956
+ dict: row formatted as dict
957
+ """
958
+ custom_endpoint = self
959
+ if current_endpoint is not None:
960
+ custom_endpoint = current_endpoint
961
+ # row_as_dict = self.row_to_dict(row)
962
+ row_as_dict = {}
963
+ for each_field in custom_endpoint.fields:
964
+ if isinstance(each_field, tuple):
965
+ row_as_dict[each_field[1]] = getattr(row, each_field[0].name)
966
+ else:
967
+ if isinstance(each_field, str):
968
+ print("Coding error - you need to use TUPLE for attr/alias")
969
+ row_as_dict[each_field.name] = getattr(row, each_field.name)
970
+
971
+ custom_endpoint_child_list = custom_endpoint.children
972
+ if isinstance(custom_endpoint_child_list, list) is False:
973
+ custom_endpoint_child_list = []
974
+ custom_endpoint_child_list.append(custom_endpoint.children)
975
+ for each_child_def in custom_endpoint_child_list:
976
+ child_property_name = each_child_def.role_name
977
+ if child_property_name == '':
978
+ child_property_name = "OrderList" # TODO default from class name
979
+ if child_property_name.startswith('Product'):
980
+ debug = 'good breakpoint'
981
+ row_dict_child_list = getattr(row, child_property_name)
982
+ row_as_dict[each_child_def.alias] = []
983
+ if each_child_def.isParent:
984
+ the_parent = getattr(row, child_property_name)
985
+ the_parent_to_dict = self.to_dict(row = the_parent, current_endpoint = each_child_def)
986
+ row_as_dict[each_child_def.alias].append(the_parent_to_dict)
987
+ else:
988
+ for each_child in row_dict_child_list:
989
+ each_child_to_dict = self.to_dict(row = each_child, current_endpoint = each_child_def)
990
+ row_as_dict[each_child_def.alias].append(each_child_to_dict)
991
+ return row_as_dict
992
+
993
+
994
+ def to_row(self, row_dict: dict, current_endpoint: 'CustomEndpoint' = None) -> object:
995
+ """Returns SQLAlchemy row(s), converted from safrs-request per subclass custom resource
996
+
997
+ Args:
998
+ safrs_request: a
999
+ current_endpoint (IntegrationEndpoint, optional): _description_. Defaults to None.
1000
+
1001
+ Returns:
1002
+ object: SQLAlchemy row / sub-rows, ready to insert
1003
+ """
1004
+
1005
+ print( f"to_row receives row_dict: {row_dict}" )
1006
+
1007
+ custom_endpoint = self
1008
+ if current_endpoint is not None:
1009
+ custom_endpoint = current_endpoint
1010
+ sql_alchemy_row = custom_endpoint._model_class() # new instance
1011
+ for each_field in custom_endpoint.fields: # attr mapping TODO 1 field, not array
1012
+ if isinstance(each_field, tuple):
1013
+ setattr(sql_alchemy_row, each_field[0].name, row_dict[each_field[1]])
1014
+ else:
1015
+ if isinstance(each_field, str):
1016
+ print("Coding error - you need to use TUPLE for attr/alias")
1017
+ setattr(sql_alchemy_row, each_field.name, row_dict[each_field.name])
1018
+ row_dict = self.move_metadata(row_dict) ## Validate TODO
1019
+ custom_endpoint_child_list = custom_endpoint.children
1020
+ if isinstance(custom_endpoint_child_list, list) is False:
1021
+ custom_endpoint_child_list = []
1022
+ custom_endpoint_child_list.append(custom_endpoint.children)
1023
+ for each_child_def in custom_endpoint_child_list:
1024
+ child_property_name = each_child_def.alias
1025
+ if child_property_name.startswith('Items'):
1026
+ debug = 'good breakpoint'
1027
+ if child_property_name in row_dict:
1028
+ row_dict_child_list = row_dict[child_property_name]
1029
+ # row_as_dict[each_child_def.alias] = [] # set up row_dict child array
1030
+ if each_child_def.isParent:
1031
+ #the_parent = getattr(row, child_property_name)
1032
+ #the_parent_to_dict = self.to_dict(row = the_parent, current_endpoint = each_child_def)
1033
+ #row_as_dict[each_child_def.alias].append(the_parent_to_dict)
1034
+ pass
1035
+ else:
1036
+ for each_row_dict_child in row_dict_child_list: # recurse for each_child
1037
+ each_child_row = self.to_row(row_dict = each_row_dict_child, current_endpoint = each_child_def)
1038
+ child_list = getattr(sql_alchemy_row, each_child_def.role_name)
1039
+ child_list.append(each_child_row)
1040
+ return sql_alchemy_row
1041
+
1042
+ def modifyPath(self, path):
1043
+ p = path.split("/")
1044
+ return path.replace(p[len(p)-1],"")
1045
+
1046
+ def insert(self, request: any, payload: dict) -> any:
1047
+ sqlalchemy_row = self.copy_dict_to_row(payload)
1048
+ session.add(sqlalchemy_row)
1049
+ session.commit()
1050
+ session.flush()
1051
+ return sqlalchemy_row
1052
+
1053
+ def update(self, payload: dict, pkey: any) -> any:
1054
+ payload = self.move_metadata(payload)
1055
+ sqlalchemy_row = self.copy_dict_to_row(payload)
1056
+ session.add(sqlalchemy_row)
1057
+ session.commit()
1058
+ session.flush()
1059
+ return sqlalchemy_row
1060
+
1061
+ def copy_dict_to_row(self, payload: dict) -> any:
1062
+ sql_alchemy_row = self._model_class()
1063
+ if "@metadata" in payload:
1064
+ payload.pop("@metadata")
1065
+ for v in payload:
1066
+ if v in self._columnNames:
1067
+ setattr(sql_alchemy_row, v , payload[v])
1068
+ return sql_alchemy_row
1069
+
1070
+ def transform_to_safrs(self, payload: any, pkey: any = None):
1071
+ if pkey is None:
1072
+ return {"data":
1073
+ {
1074
+ "attributes": payload
1075
+ },
1076
+ "type" : self._model_class_name
1077
+ }
1078
+ else:
1079
+ return {"data":
1080
+ {
1081
+ "attributes": payload
1082
+ },
1083
+ "type" : self._model_class_name,
1084
+ "id": pkey
1085
+ }