sqlew 3.6.10 → 3.7.0
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.
- package/CHANGELOG.md +318 -0
- package/README.md +54 -39
- package/assets/config.example.toml +93 -0
- package/assets/kanban-visualizer.png +0 -0
- package/assets/sample-agents/sqlew-architect.md +32 -13
- package/assets/sample-agents/sqlew-researcher.md +70 -17
- package/assets/sample-agents/sqlew-scrum-master.md +60 -25
- package/assets/schema.sql +2 -2
- package/dist/adapters/auth/auth-factory.d.ts +86 -0
- package/dist/adapters/auth/auth-factory.d.ts.map +1 -0
- package/dist/adapters/auth/auth-factory.js +103 -0
- package/dist/adapters/auth/auth-factory.js.map +1 -0
- package/dist/adapters/auth/auth-types.d.ts +30 -0
- package/dist/adapters/auth/auth-types.d.ts.map +1 -0
- package/dist/adapters/auth/auth-types.js +30 -0
- package/dist/adapters/auth/auth-types.js.map +1 -0
- package/dist/adapters/auth/base-auth-provider.d.ts +327 -0
- package/dist/adapters/auth/base-auth-provider.d.ts.map +1 -0
- package/dist/adapters/auth/base-auth-provider.js +111 -0
- package/dist/adapters/auth/base-auth-provider.js.map +1 -0
- package/dist/adapters/auth/direct-auth-provider.d.ts +356 -0
- package/dist/adapters/auth/direct-auth-provider.d.ts.map +1 -0
- package/dist/adapters/auth/direct-auth-provider.js +406 -0
- package/dist/adapters/auth/direct-auth-provider.js.map +1 -0
- package/dist/adapters/base-adapter.d.ts +638 -0
- package/dist/adapters/base-adapter.d.ts.map +1 -0
- package/dist/adapters/base-adapter.js +557 -0
- package/dist/adapters/base-adapter.js.map +1 -0
- package/dist/adapters/index.d.ts +13 -2
- package/dist/adapters/index.d.ts.map +1 -1
- package/dist/adapters/index.js +27 -5
- package/dist/adapters/index.js.map +1 -1
- package/dist/adapters/mysql-adapter.d.ts +547 -6
- package/dist/adapters/mysql-adapter.d.ts.map +1 -1
- package/dist/adapters/mysql-adapter.js +651 -32
- package/dist/adapters/mysql-adapter.js.map +1 -1
- package/dist/adapters/postgresql-adapter.d.ts +15 -4
- package/dist/adapters/postgresql-adapter.d.ts.map +1 -1
- package/dist/adapters/postgresql-adapter.js +19 -2
- package/dist/adapters/postgresql-adapter.js.map +1 -1
- package/dist/adapters/sqlite-adapter.d.ts +35 -5
- package/dist/adapters/sqlite-adapter.d.ts.map +1 -1
- package/dist/adapters/sqlite-adapter.js +57 -18
- package/dist/adapters/sqlite-adapter.js.map +1 -1
- package/dist/cli/db-dump.d.ts +32 -0
- package/dist/cli/db-dump.d.ts.map +1 -0
- package/dist/cli/db-dump.js +409 -0
- package/dist/cli/db-dump.js.map +1 -0
- package/dist/cli.js +24 -14
- package/dist/cli.js.map +1 -1
- package/dist/config/knex/bootstrap/20251025020452_create_master_tables.d.ts.map +1 -0
- package/dist/{migrations → config}/knex/bootstrap/20251025020452_create_master_tables.js +7 -2
- package/dist/config/knex/bootstrap/20251025020452_create_master_tables.js.map +1 -0
- package/dist/config/knex/bootstrap/20251025021152_create_transaction_tables.d.ts.map +1 -0
- package/dist/{migrations → config}/knex/bootstrap/20251025021152_create_transaction_tables.js +49 -50
- package/dist/config/knex/bootstrap/20251025021152_create_transaction_tables.js.map +1 -0
- package/dist/config/knex/bootstrap/20251025021351_create_indexes.d.ts.map +1 -0
- package/dist/config/knex/bootstrap/20251025021351_create_indexes.js.map +1 -0
- package/dist/config/knex/bootstrap/20251025021416_seed_master_data.d.ts.map +1 -0
- package/dist/{migrations → config}/knex/bootstrap/20251025021416_seed_master_data.js +11 -6
- package/dist/config/knex/bootstrap/20251025021416_seed_master_data.js.map +1 -0
- package/dist/config/knex/bootstrap/20251025070349_create_views.d.ts.map +1 -0
- package/dist/{migrations → config}/knex/bootstrap/20251025070349_create_views.js +66 -14
- package/dist/config/knex/bootstrap/20251025070349_create_views.js.map +1 -0
- package/dist/config/knex/enhancements/20251025081221_add_link_type_to_task_decision_links.d.ts.map +1 -0
- package/dist/config/knex/enhancements/20251025081221_add_link_type_to_task_decision_links.js +22 -0
- package/dist/config/knex/enhancements/20251025081221_add_link_type_to_task_decision_links.js.map +1 -0
- package/dist/config/knex/enhancements/20251025082220_fix_task_dependencies_columns.d.ts.map +1 -0
- package/dist/config/knex/enhancements/20251025082220_fix_task_dependencies_columns.js.map +1 -0
- package/dist/config/knex/enhancements/20251025090000_create_help_system_tables.d.ts.map +1 -0
- package/dist/{migrations → config}/knex/enhancements/20251025090000_create_help_system_tables.js +6 -0
- package/dist/config/knex/enhancements/20251025090000_create_help_system_tables.js.map +1 -0
- package/dist/config/knex/enhancements/20251025090100_seed_help_categories_and_use_cases.d.ts.map +1 -0
- package/dist/{migrations → config}/knex/enhancements/20251025090100_seed_help_categories_and_use_cases.js +6 -0
- package/dist/config/knex/enhancements/20251025090100_seed_help_categories_and_use_cases.js.map +1 -0
- package/dist/config/knex/enhancements/20251025100000_seed_help_metadata.d.ts.map +1 -0
- package/dist/{migrations → config}/knex/enhancements/20251025100000_seed_help_metadata.js +6 -0
- package/dist/config/knex/enhancements/20251025100000_seed_help_metadata.js.map +1 -0
- package/dist/config/knex/enhancements/20251025100100_seed_remaining_use_cases.d.ts.map +1 -0
- package/dist/config/knex/enhancements/20251025100100_seed_remaining_use_cases.js.map +1 -0
- package/dist/config/knex/enhancements/20251025120000_add_cascade_to_task_dependencies.d.ts.map +1 -0
- package/dist/{migrations → config}/knex/enhancements/20251025120000_add_cascade_to_task_dependencies.js +7 -0
- package/dist/config/knex/enhancements/20251025120000_add_cascade_to_task_dependencies.js.map +1 -0
- package/dist/config/knex/enhancements/20251027000000_add_agent_reuse_system.d.ts.map +1 -0
- package/dist/config/knex/enhancements/20251027000000_add_agent_reuse_system.js +62 -0
- package/dist/config/knex/enhancements/20251027000000_add_agent_reuse_system.js.map +1 -0
- package/dist/config/knex/enhancements/20251027010000_add_task_constraint_to_decision_context.d.ts.map +1 -0
- package/dist/config/knex/enhancements/20251027010000_add_task_constraint_to_decision_context.js.map +1 -0
- package/dist/config/knex/enhancements/20251027020000_update_agent_reusability.d.ts.map +1 -0
- package/dist/{migrations → config}/knex/enhancements/20251027020000_update_agent_reusability.js +6 -0
- package/dist/config/knex/enhancements/20251027020000_update_agent_reusability.js.map +1 -0
- package/dist/config/knex/enhancements/20251028000000_simplify_agent_system.d.ts.map +1 -0
- package/dist/{migrations → config}/knex/enhancements/20251028000000_simplify_agent_system.js +6 -0
- package/dist/config/knex/enhancements/20251028000000_simplify_agent_system.js.map +1 -0
- package/dist/config/knex/enhancements/20251031000000_drop_orphaned_message_view.d.ts +13 -0
- package/dist/config/knex/enhancements/20251031000000_drop_orphaned_message_view.d.ts.map +1 -0
- package/dist/config/knex/enhancements/20251031000000_drop_orphaned_message_view.js +48 -0
- package/dist/config/knex/enhancements/20251031000000_drop_orphaned_message_view.js.map +1 -0
- package/dist/config/knex/enhancements/20251104000003_rename_constraints_created_by_to_agent_id.d.ts +24 -0
- package/dist/config/knex/enhancements/20251104000003_rename_constraints_created_by_to_agent_id.d.ts.map +1 -0
- package/dist/config/knex/enhancements/20251104000003_rename_constraints_created_by_to_agent_id.js +189 -0
- package/dist/config/knex/enhancements/20251104000003_rename_constraints_created_by_to_agent_id.js.map +1 -0
- package/dist/config/knex/enhancements/20251105000000_add_token_usage_table.d.ts +16 -0
- package/dist/config/knex/enhancements/20251105000000_add_token_usage_table.d.ts.map +1 -0
- package/dist/config/knex/enhancements/20251105000000_add_token_usage_table.js +65 -0
- package/dist/config/knex/enhancements/20251105000000_add_token_usage_table.js.map +1 -0
- package/dist/config/knex/enhancements/20251105000001_rename_decision_context_decided_by_to_agent_id.d.ts +23 -0
- package/dist/config/knex/enhancements/20251105000001_rename_decision_context_decided_by_to_agent_id.d.ts.map +1 -0
- package/dist/config/knex/enhancements/20251105000001_rename_decision_context_decided_by_to_agent_id.js +118 -0
- package/dist/config/knex/enhancements/20251105000001_rename_decision_context_decided_by_to_agent_id.js.map +1 -0
- package/dist/config/knex/upgrades/20251024010000_upgrade_v1_0_to_v1_1.d.ts.map +1 -0
- package/dist/config/knex/upgrades/20251024010000_upgrade_v1_0_to_v1_1.js.map +1 -0
- package/dist/config/knex/upgrades/20251024020000_upgrade_v2_0_to_v2_1.d.ts.map +1 -0
- package/dist/config/knex/upgrades/20251024020000_upgrade_v2_0_to_v2_1.js.map +1 -0
- package/dist/config/knex/upgrades/20251024030000_upgrade_v2_1_to_v3_0.d.ts.map +1 -0
- package/dist/config/knex/upgrades/20251024030000_upgrade_v2_1_to_v3_0.js.map +1 -0
- package/dist/config/knex/upgrades/20251024040000_upgrade_v3_0_to_v3_2.d.ts.map +1 -0
- package/dist/config/knex/upgrades/20251024040000_upgrade_v3_0_to_v3_2.js.map +1 -0
- package/dist/config/knex/upgrades/20251024050000_upgrade_v3_2_0_to_v3_2_2.d.ts.map +1 -0
- package/dist/config/knex/upgrades/20251024050000_upgrade_v3_2_0_to_v3_2_2.js.map +1 -0
- package/dist/config/knex/upgrades/20251024060000_upgrade_v3_4_to_v3_5.d.ts.map +1 -0
- package/dist/config/knex/upgrades/20251024060000_upgrade_v3_4_to_v3_5.js.map +1 -0
- package/dist/config/knex/upgrades/20251024070000_upgrade_v3_5_to_v3_6.d.ts.map +1 -0
- package/dist/config/knex/upgrades/20251024070000_upgrade_v3_5_to_v3_6.js.map +1 -0
- package/dist/config/knex/upgrades/20251104000000_add_multi_project_v3_7_0.d.ts +49 -0
- package/dist/config/knex/upgrades/20251104000000_add_multi_project_v3_7_0.d.ts.map +1 -0
- package/dist/config/knex/upgrades/20251104000000_add_multi_project_v3_7_0.js +864 -0
- package/dist/config/knex/upgrades/20251104000000_add_multi_project_v3_7_0.js.map +1 -0
- package/dist/config/loader.d.ts +19 -1
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +149 -4
- package/dist/config/loader.js.map +1 -1
- package/dist/config/types.d.ts +261 -2
- package/dist/config/types.d.ts.map +1 -1
- package/dist/config/types.js.map +1 -1
- package/dist/config/writer.d.ts +65 -0
- package/dist/config/writer.d.ts.map +1 -0
- package/dist/config/writer.js +139 -0
- package/dist/config/writer.js.map +1 -0
- package/dist/database.d.ts +11 -2
- package/dist/database.d.ts.map +1 -1
- package/dist/database.js +62 -6
- package/dist/database.js.map +1 -1
- package/dist/index.js +165 -35
- package/dist/index.js.map +1 -1
- package/dist/knexfile.d.ts.map +1 -1
- package/dist/knexfile.js +88 -12
- package/dist/knexfile.js.map +1 -1
- package/dist/tests/all-features.test.js +15 -3
- package/dist/tests/all-features.test.js.map +1 -1
- package/dist/tests/config-loader.test.d.ts +6 -0
- package/dist/tests/config-loader.test.d.ts.map +1 -0
- package/dist/tests/config-loader.test.js +201 -0
- package/dist/tests/config-loader.test.js.map +1 -0
- package/dist/tests/connection-manager-integration.test.d.ts +2 -0
- package/dist/tests/connection-manager-integration.test.d.ts.map +1 -0
- package/dist/tests/connection-manager-integration.test.js +431 -0
- package/dist/tests/connection-manager-integration.test.js.map +1 -0
- package/dist/tests/connection-manager.test.d.ts +2 -0
- package/dist/tests/connection-manager.test.d.ts.map +1 -0
- package/dist/tests/connection-manager.test.js +361 -0
- package/dist/tests/connection-manager.test.js.map +1 -0
- package/dist/tests/dump-import.test.d.ts +15 -0
- package/dist/tests/dump-import.test.d.ts.map +1 -0
- package/dist/tests/dump-import.test.js +430 -0
- package/dist/tests/dump-import.test.js.map +1 -0
- package/dist/tests/migration-idempotency.test.d.ts +2 -0
- package/dist/tests/migration-idempotency.test.d.ts.map +1 -0
- package/dist/tests/migration-idempotency.test.js +330 -0
- package/dist/tests/migration-idempotency.test.js.map +1 -0
- package/dist/tests/migration-upgrade-paths.test.d.ts +2 -0
- package/dist/tests/migration-upgrade-paths.test.d.ts.map +1 -0
- package/dist/tests/migration-upgrade-paths.test.js +248 -0
- package/dist/tests/migration-upgrade-paths.test.js.map +1 -0
- package/dist/tests/multi-project-migration.test.d.ts +17 -0
- package/dist/tests/multi-project-migration.test.d.ts.map +1 -0
- package/dist/tests/multi-project-migration.test.js +399 -0
- package/dist/tests/multi-project-migration.test.js.map +1 -0
- package/dist/tests/multi-project.test.d.ts +5 -0
- package/dist/tests/multi-project.test.d.ts.map +1 -0
- package/dist/tests/multi-project.test.js +238 -0
- package/dist/tests/multi-project.test.js.map +1 -0
- package/dist/tests/schema-migration.test.d.ts +8 -0
- package/dist/tests/schema-migration.test.d.ts.map +1 -0
- package/dist/tests/schema-migration.test.js +108 -0
- package/dist/tests/schema-migration.test.js.map +1 -0
- package/dist/tests/sql-dump-converters.test.d.ts +7 -0
- package/dist/tests/sql-dump-converters.test.d.ts.map +1 -0
- package/dist/tests/sql-dump-converters.test.js +314 -0
- package/dist/tests/sql-dump-converters.test.js.map +1 -0
- package/dist/tests/sql-dump-cross-database.test.d.ts +21 -0
- package/dist/tests/sql-dump-cross-database.test.d.ts.map +1 -0
- package/dist/tests/sql-dump-cross-database.test.js +314 -0
- package/dist/tests/sql-dump-cross-database.test.js.map +1 -0
- package/dist/tests/sql-dump-default-conversions.test.d.ts +8 -0
- package/dist/tests/sql-dump-default-conversions.test.d.ts.map +1 -0
- package/dist/tests/sql-dump-default-conversions.test.js +141 -0
- package/dist/tests/sql-dump-default-conversions.test.js.map +1 -0
- package/dist/tests/sql-dump-fk-constraints.test.d.ts +13 -0
- package/dist/tests/sql-dump-fk-constraints.test.d.ts.map +1 -0
- package/dist/tests/sql-dump-fk-constraints.test.js +381 -0
- package/dist/tests/sql-dump-fk-constraints.test.js.map +1 -0
- package/dist/tests/sql-dump-indexes.test.d.ts +12 -0
- package/dist/tests/sql-dump-indexes.test.d.ts.map +1 -0
- package/dist/tests/sql-dump-indexes.test.js +269 -0
- package/dist/tests/sql-dump-indexes.test.js.map +1 -0
- package/dist/tests/sql-dump-integration.test.d.ts +16 -0
- package/dist/tests/sql-dump-integration.test.d.ts.map +1 -0
- package/dist/tests/sql-dump-integration.test.js +342 -0
- package/dist/tests/sql-dump-integration.test.js.map +1 -0
- package/dist/tests/sql-dump-table-ordering.test.d.ts +8 -0
- package/dist/tests/sql-dump-table-ordering.test.d.ts.map +1 -0
- package/dist/tests/sql-dump-table-ordering.test.js +253 -0
- package/dist/tests/sql-dump-table-ordering.test.js.map +1 -0
- package/dist/tests/tasks.link-file-backward-compat.test.js +11 -1
- package/dist/tests/tasks.link-file-backward-compat.test.js.map +1 -1
- package/dist/tests/tasks.watch-files-action.test.js +11 -1
- package/dist/tests/tasks.watch-files-action.test.js.map +1 -1
- package/dist/tests/type-conversion.test.d.ts +8 -0
- package/dist/tests/type-conversion.test.d.ts.map +1 -0
- package/dist/tests/type-conversion.test.js +312 -0
- package/dist/tests/type-conversion.test.js.map +1 -0
- package/dist/tests/utils/test-helpers.d.ts +93 -0
- package/dist/tests/utils/test-helpers.d.ts.map +1 -0
- package/dist/tests/utils/test-helpers.js +407 -0
- package/dist/tests/utils/test-helpers.js.map +1 -0
- package/dist/tools/config.d.ts +58 -0
- package/dist/tools/config.d.ts.map +1 -0
- package/dist/tools/config.js +281 -0
- package/dist/tools/config.js.map +1 -0
- package/dist/tools/constraints.d.ts.map +1 -1
- package/dist/tools/constraints.js +138 -122
- package/dist/tools/constraints.js.map +1 -1
- package/dist/tools/context.d.ts.map +1 -1
- package/dist/tools/context.js +216 -109
- package/dist/tools/context.js.map +1 -1
- package/dist/tools/files.d.ts.map +1 -1
- package/dist/tools/files.js +123 -102
- package/dist/tools/files.js.map +1 -1
- package/dist/tools/tasks.d.ts.map +1 -1
- package/dist/tools/tasks.js +581 -518
- package/dist/tools/tasks.js.map +1 -1
- package/dist/tools/utils.d.ts +5 -0
- package/dist/tools/utils.d.ts.map +1 -1
- package/dist/tools/utils.js +176 -122
- package/dist/tools/utils.js.map +1 -1
- package/dist/types.d.ts +9 -26
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/cleanup.d.ts +3 -0
- package/dist/utils/cleanup.d.ts.map +1 -1
- package/dist/utils/cleanup.js +14 -2
- package/dist/utils/cleanup.js.map +1 -1
- package/dist/utils/connection-manager.d.ts +59 -0
- package/dist/utils/connection-manager.d.ts.map +1 -0
- package/dist/utils/connection-manager.js +178 -0
- package/dist/utils/connection-manager.js.map +1 -0
- package/dist/utils/debug-logger.d.ts +8 -4
- package/dist/utils/debug-logger.d.ts.map +1 -1
- package/dist/utils/debug-logger.js +27 -7
- package/dist/utils/debug-logger.js.map +1 -1
- package/dist/utils/error-handler.d.ts +2 -2
- package/dist/utils/error-handler.d.ts.map +1 -1
- package/dist/utils/error-handler.js +10 -7
- package/dist/utils/error-handler.js.map +1 -1
- package/dist/utils/parameter-validator.d.ts.map +1 -1
- package/dist/utils/parameter-validator.js +36 -15
- package/dist/utils/parameter-validator.js.map +1 -1
- package/dist/utils/project-context.d.ts +111 -0
- package/dist/utils/project-context.d.ts.map +1 -0
- package/dist/utils/project-context.js +187 -0
- package/dist/utils/project-context.js.map +1 -0
- package/dist/utils/sql-dump-converters.d.ts +188 -0
- package/dist/utils/sql-dump-converters.d.ts.map +1 -0
- package/dist/utils/sql-dump-converters.js +311 -0
- package/dist/utils/sql-dump-converters.js.map +1 -0
- package/dist/utils/sql-dump.d.ts +102 -0
- package/dist/utils/sql-dump.d.ts.map +1 -0
- package/dist/utils/sql-dump.js +1550 -0
- package/dist/utils/sql-dump.js.map +1 -0
- package/dist/utils/vcs-adapter.d.ts +42 -0
- package/dist/utils/vcs-adapter.d.ts.map +1 -1
- package/dist/utils/vcs-adapter.js +154 -0
- package/dist/utils/vcs-adapter.js.map +1 -1
- package/docs/BASEADAPTER_IMPLEMENTATION.md +399 -0
- package/docs/DATABASE_AUTH.md +445 -0
- package/docs/DATABASE_MIGRATION.md +247 -0
- package/docs/MULTI_PROJECT_ARCHITECTURE.md +497 -0
- package/package.json +12 -4
- package/dist/migrations/knex/bootstrap/20251025020452_create_master_tables.d.ts.map +0 -1
- package/dist/migrations/knex/bootstrap/20251025020452_create_master_tables.js.map +0 -1
- package/dist/migrations/knex/bootstrap/20251025021152_create_transaction_tables.d.ts.map +0 -1
- package/dist/migrations/knex/bootstrap/20251025021152_create_transaction_tables.js.map +0 -1
- package/dist/migrations/knex/bootstrap/20251025021351_create_indexes.d.ts.map +0 -1
- package/dist/migrations/knex/bootstrap/20251025021351_create_indexes.js.map +0 -1
- package/dist/migrations/knex/bootstrap/20251025021416_seed_master_data.d.ts.map +0 -1
- package/dist/migrations/knex/bootstrap/20251025021416_seed_master_data.js.map +0 -1
- package/dist/migrations/knex/bootstrap/20251025070349_create_views.d.ts.map +0 -1
- package/dist/migrations/knex/bootstrap/20251025070349_create_views.js.map +0 -1
- package/dist/migrations/knex/enhancements/20251025081221_add_link_type_to_task_decision_links.d.ts.map +0 -1
- package/dist/migrations/knex/enhancements/20251025081221_add_link_type_to_task_decision_links.js +0 -15
- package/dist/migrations/knex/enhancements/20251025081221_add_link_type_to_task_decision_links.js.map +0 -1
- package/dist/migrations/knex/enhancements/20251025082220_fix_task_dependencies_columns.d.ts.map +0 -1
- package/dist/migrations/knex/enhancements/20251025082220_fix_task_dependencies_columns.js.map +0 -1
- package/dist/migrations/knex/enhancements/20251025090000_create_help_system_tables.d.ts.map +0 -1
- package/dist/migrations/knex/enhancements/20251025090000_create_help_system_tables.js.map +0 -1
- package/dist/migrations/knex/enhancements/20251025090100_seed_help_categories_and_use_cases.d.ts.map +0 -1
- package/dist/migrations/knex/enhancements/20251025090100_seed_help_categories_and_use_cases.js.map +0 -1
- package/dist/migrations/knex/enhancements/20251025100000_seed_help_metadata.d.ts.map +0 -1
- package/dist/migrations/knex/enhancements/20251025100000_seed_help_metadata.js.map +0 -1
- package/dist/migrations/knex/enhancements/20251025100100_seed_remaining_use_cases.d.ts.map +0 -1
- package/dist/migrations/knex/enhancements/20251025100100_seed_remaining_use_cases.js.map +0 -1
- package/dist/migrations/knex/enhancements/20251025120000_add_cascade_to_task_dependencies.d.ts.map +0 -1
- package/dist/migrations/knex/enhancements/20251025120000_add_cascade_to_task_dependencies.js.map +0 -1
- package/dist/migrations/knex/enhancements/20251027000000_add_agent_reuse_system.d.ts.map +0 -1
- package/dist/migrations/knex/enhancements/20251027000000_add_agent_reuse_system.js +0 -34
- package/dist/migrations/knex/enhancements/20251027000000_add_agent_reuse_system.js.map +0 -1
- package/dist/migrations/knex/enhancements/20251027010000_add_task_constraint_to_decision_context.d.ts.map +0 -1
- package/dist/migrations/knex/enhancements/20251027010000_add_task_constraint_to_decision_context.js.map +0 -1
- package/dist/migrations/knex/enhancements/20251027020000_update_agent_reusability.d.ts.map +0 -1
- package/dist/migrations/knex/enhancements/20251027020000_update_agent_reusability.js.map +0 -1
- package/dist/migrations/knex/enhancements/20251028000000_simplify_agent_system.d.ts.map +0 -1
- package/dist/migrations/knex/enhancements/20251028000000_simplify_agent_system.js.map +0 -1
- package/dist/migrations/knex/upgrades/20251024010000_upgrade_v1_0_to_v1_1.d.ts.map +0 -1
- package/dist/migrations/knex/upgrades/20251024010000_upgrade_v1_0_to_v1_1.js.map +0 -1
- package/dist/migrations/knex/upgrades/20251024020000_upgrade_v2_0_to_v2_1.d.ts.map +0 -1
- package/dist/migrations/knex/upgrades/20251024020000_upgrade_v2_0_to_v2_1.js.map +0 -1
- package/dist/migrations/knex/upgrades/20251024030000_upgrade_v2_1_to_v3_0.d.ts.map +0 -1
- package/dist/migrations/knex/upgrades/20251024030000_upgrade_v2_1_to_v3_0.js.map +0 -1
- package/dist/migrations/knex/upgrades/20251024040000_upgrade_v3_0_to_v3_2.d.ts.map +0 -1
- package/dist/migrations/knex/upgrades/20251024040000_upgrade_v3_0_to_v3_2.js.map +0 -1
- package/dist/migrations/knex/upgrades/20251024050000_upgrade_v3_2_0_to_v3_2_2.d.ts.map +0 -1
- package/dist/migrations/knex/upgrades/20251024050000_upgrade_v3_2_0_to_v3_2_2.js.map +0 -1
- package/dist/migrations/knex/upgrades/20251024060000_upgrade_v3_4_to_v3_5.d.ts.map +0 -1
- package/dist/migrations/knex/upgrades/20251024060000_upgrade_v3_4_to_v3_5.js.map +0 -1
- package/dist/migrations/knex/upgrades/20251024070000_upgrade_v3_5_to_v3_6.d.ts.map +0 -1
- package/dist/migrations/knex/upgrades/20251024070000_upgrade_v3_5_to_v3_6.js.map +0 -1
- /package/dist/{migrations → config}/knex/bootstrap/20251025020452_create_master_tables.d.ts +0 -0
- /package/dist/{migrations → config}/knex/bootstrap/20251025021152_create_transaction_tables.d.ts +0 -0
- /package/dist/{migrations → config}/knex/bootstrap/20251025021351_create_indexes.d.ts +0 -0
- /package/dist/{migrations → config}/knex/bootstrap/20251025021351_create_indexes.js +0 -0
- /package/dist/{migrations → config}/knex/bootstrap/20251025021416_seed_master_data.d.ts +0 -0
- /package/dist/{migrations → config}/knex/bootstrap/20251025070349_create_views.d.ts +0 -0
- /package/dist/{migrations → config}/knex/enhancements/20251025081221_add_link_type_to_task_decision_links.d.ts +0 -0
- /package/dist/{migrations → config}/knex/enhancements/20251025082220_fix_task_dependencies_columns.d.ts +0 -0
- /package/dist/{migrations → config}/knex/enhancements/20251025082220_fix_task_dependencies_columns.js +0 -0
- /package/dist/{migrations → config}/knex/enhancements/20251025090000_create_help_system_tables.d.ts +0 -0
- /package/dist/{migrations → config}/knex/enhancements/20251025090100_seed_help_categories_and_use_cases.d.ts +0 -0
- /package/dist/{migrations → config}/knex/enhancements/20251025100000_seed_help_metadata.d.ts +0 -0
- /package/dist/{migrations → config}/knex/enhancements/20251025100100_seed_remaining_use_cases.d.ts +0 -0
- /package/dist/{migrations → config}/knex/enhancements/20251025100100_seed_remaining_use_cases.js +0 -0
- /package/dist/{migrations → config}/knex/enhancements/20251025120000_add_cascade_to_task_dependencies.d.ts +0 -0
- /package/dist/{migrations → config}/knex/enhancements/20251027000000_add_agent_reuse_system.d.ts +0 -0
- /package/dist/{migrations → config}/knex/enhancements/20251027010000_add_task_constraint_to_decision_context.d.ts +0 -0
- /package/dist/{migrations → config}/knex/enhancements/20251027010000_add_task_constraint_to_decision_context.js +0 -0
- /package/dist/{migrations → config}/knex/enhancements/20251027020000_update_agent_reusability.d.ts +0 -0
- /package/dist/{migrations → config}/knex/enhancements/20251028000000_simplify_agent_system.d.ts +0 -0
- /package/dist/{migrations → config}/knex/upgrades/20251024010000_upgrade_v1_0_to_v1_1.d.ts +0 -0
- /package/dist/{migrations → config}/knex/upgrades/20251024010000_upgrade_v1_0_to_v1_1.js +0 -0
- /package/dist/{migrations → config}/knex/upgrades/20251024020000_upgrade_v2_0_to_v2_1.d.ts +0 -0
- /package/dist/{migrations → config}/knex/upgrades/20251024020000_upgrade_v2_0_to_v2_1.js +0 -0
- /package/dist/{migrations → config}/knex/upgrades/20251024030000_upgrade_v2_1_to_v3_0.d.ts +0 -0
- /package/dist/{migrations → config}/knex/upgrades/20251024030000_upgrade_v2_1_to_v3_0.js +0 -0
- /package/dist/{migrations → config}/knex/upgrades/20251024040000_upgrade_v3_0_to_v3_2.d.ts +0 -0
- /package/dist/{migrations → config}/knex/upgrades/20251024040000_upgrade_v3_0_to_v3_2.js +0 -0
- /package/dist/{migrations → config}/knex/upgrades/20251024050000_upgrade_v3_2_0_to_v3_2_2.d.ts +0 -0
- /package/dist/{migrations → config}/knex/upgrades/20251024050000_upgrade_v3_2_0_to_v3_2_2.js +0 -0
- /package/dist/{migrations → config}/knex/upgrades/20251024060000_upgrade_v3_4_to_v3_5.d.ts +0 -0
- /package/dist/{migrations → config}/knex/upgrades/20251024060000_upgrade_v3_4_to_v3_5.js +0 -0
- /package/dist/{migrations → config}/knex/upgrades/20251024070000_upgrade_v3_5_to_v3_6.d.ts +0 -0
- /package/dist/{migrations → config}/knex/upgrades/20251024070000_upgrade_v3_5_to_v3_6.js +0 -0
|
@@ -1,63 +1,682 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import { BaseAdapter } from './base-adapter.js';
|
|
2
|
+
/**
|
|
3
|
+
* MySQL adapter implementation with authentication support.
|
|
4
|
+
*
|
|
5
|
+
* This adapter provides MySQL-specific implementations for database operations,
|
|
6
|
+
* integrating with the authentication layer for secure connections via SSH tunnels,
|
|
7
|
+
* direct connections, or cloud IAM (AWS RDS, GCP Cloud SQL).
|
|
8
|
+
*
|
|
9
|
+
* **MySQL-Specific Features:**
|
|
10
|
+
* - ON DUPLICATE KEY UPDATE for upserts
|
|
11
|
+
* - JSON_EXTRACT() and JSON_OBJECT() for JSON operations
|
|
12
|
+
* - GROUP_CONCAT() for string aggregation
|
|
13
|
+
* - LAST_INSERT_ID() for retrieving inserted IDs
|
|
14
|
+
* - UNIX_TIMESTAMP() and FROM_UNIXTIME() for epoch conversions
|
|
15
|
+
* - AUTO_INCREMENT with UNSIGNED for ID columns
|
|
16
|
+
* - UTF8MB4 character set support for full Unicode
|
|
17
|
+
*
|
|
18
|
+
* **Supported MySQL Versions:**
|
|
19
|
+
* - MySQL 8.0+ (full feature support)
|
|
20
|
+
* - MySQL 5.7+ (basic feature support)
|
|
21
|
+
*
|
|
22
|
+
* **Authentication Methods:**
|
|
23
|
+
* - Direct: Standard username/password authentication
|
|
24
|
+
* - SSH Tunnel: Connect via SSH bastion host
|
|
25
|
+
* - AWS RDS IAM: Token-based authentication for AWS RDS
|
|
26
|
+
* - GCP Cloud SQL IAM: Token-based authentication for Cloud SQL
|
|
27
|
+
*
|
|
28
|
+
* @extends BaseAdapter
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* // Direct connection
|
|
32
|
+
* const adapter = new MySQLAdapter({
|
|
33
|
+
* type: 'mysql',
|
|
34
|
+
* connection: {
|
|
35
|
+
* host: 'localhost',
|
|
36
|
+
* port: 3306,
|
|
37
|
+
* database: 'mydb'
|
|
38
|
+
* },
|
|
39
|
+
* auth: {
|
|
40
|
+
* type: 'direct',
|
|
41
|
+
* user: 'root',
|
|
42
|
+
* password: 'password'
|
|
43
|
+
* }
|
|
44
|
+
* });
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* // SSH tunnel connection
|
|
48
|
+
* const adapter = new MySQLAdapter({
|
|
49
|
+
* type: 'mysql',
|
|
50
|
+
* connection: {
|
|
51
|
+
* host: 'db.internal',
|
|
52
|
+
* port: 3306,
|
|
53
|
+
* database: 'production'
|
|
54
|
+
* },
|
|
55
|
+
* auth: {
|
|
56
|
+
* type: 'ssh',
|
|
57
|
+
* user: 'dbuser',
|
|
58
|
+
* password: 'dbpass',
|
|
59
|
+
* ssh: {
|
|
60
|
+
* host: 'bastion.example.com',
|
|
61
|
+
* username: 'deploy',
|
|
62
|
+
* privateKeyPath: '/path/to/key.pem'
|
|
63
|
+
* }
|
|
64
|
+
* }
|
|
65
|
+
* });
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* // AWS RDS IAM authentication
|
|
69
|
+
* const adapter = new MySQLAdapter({
|
|
70
|
+
* type: 'mysql',
|
|
71
|
+
* connection: {
|
|
72
|
+
* host: 'mydb.cluster-xxx.us-east-1.rds.amazonaws.com',
|
|
73
|
+
* port: 3306,
|
|
74
|
+
* database: 'production'
|
|
75
|
+
* },
|
|
76
|
+
* auth: {
|
|
77
|
+
* type: 'aws-iam',
|
|
78
|
+
* region: 'us-east-1'
|
|
79
|
+
* }
|
|
80
|
+
* });
|
|
81
|
+
*/
|
|
82
|
+
export class MySQLAdapter extends BaseAdapter {
|
|
6
83
|
// Feature detection
|
|
7
|
-
supportsReturning = false;
|
|
8
|
-
supportsJSON = true;
|
|
9
|
-
supportsUpsert = true;
|
|
10
|
-
supportsCTE = true;
|
|
11
|
-
supportsWindowFunctions = true;
|
|
12
|
-
supportsSavepoints = true;
|
|
84
|
+
supportsReturning = false; // MySQL doesn't support RETURNING clause
|
|
85
|
+
supportsJSON = true; // MySQL 5.7+ has native JSON support
|
|
86
|
+
supportsUpsert = true; // ON DUPLICATE KEY UPDATE
|
|
87
|
+
supportsCTE = true; // MySQL 8.0+ supports WITH clause
|
|
88
|
+
supportsWindowFunctions = true; // MySQL 8.0+ supports window functions
|
|
89
|
+
supportsSavepoints = true; // Full savepoint support
|
|
13
90
|
databaseName = 'mysql';
|
|
14
|
-
|
|
15
|
-
|
|
91
|
+
/**
|
|
92
|
+
* Creates a new MySQL adapter instance.
|
|
93
|
+
*
|
|
94
|
+
* @param {DatabaseConfig} config - Database configuration with auth settings
|
|
95
|
+
*/
|
|
96
|
+
constructor(config) {
|
|
97
|
+
super(config);
|
|
16
98
|
}
|
|
17
|
-
|
|
18
|
-
|
|
99
|
+
/**
|
|
100
|
+
* Returns the Knex dialect for MySQL.
|
|
101
|
+
*
|
|
102
|
+
* Uses 'mysql2' driver which supports:
|
|
103
|
+
* - Prepared statements
|
|
104
|
+
* - Binary protocol
|
|
105
|
+
* - Promise-based API
|
|
106
|
+
* - Full Unicode (UTF8MB4)
|
|
107
|
+
*
|
|
108
|
+
* @returns {string} 'mysql2' dialect identifier
|
|
109
|
+
*/
|
|
110
|
+
getDialect() {
|
|
111
|
+
return 'mysql2';
|
|
19
112
|
}
|
|
20
|
-
|
|
21
|
-
|
|
113
|
+
/**
|
|
114
|
+
* Initializes MySQL-specific session settings.
|
|
115
|
+
*
|
|
116
|
+
* **Configuration Applied:**
|
|
117
|
+
* - Character set: UTF8MB4 for full Unicode support (including emojis)
|
|
118
|
+
* - Collation: utf8mb4_unicode_ci for proper sorting
|
|
119
|
+
* - SQL mode: TRADITIONAL for strict SQL compliance
|
|
120
|
+
* - Timezone: UTC for consistent timestamp handling
|
|
121
|
+
* - Transaction isolation: READ COMMITTED (default)
|
|
122
|
+
*
|
|
123
|
+
* **Important Notes:**
|
|
124
|
+
* - UTF8MB4 requires MySQL 5.5.3+
|
|
125
|
+
* - These settings apply to the current session only
|
|
126
|
+
* - Connection pool creates new sessions with these settings
|
|
127
|
+
*
|
|
128
|
+
* @returns {Promise<void>}
|
|
129
|
+
*
|
|
130
|
+
* @throws {Error} If MySQL server version is incompatible
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* // Called automatically after connect()
|
|
134
|
+
* await adapter.connect();
|
|
135
|
+
* // Session is now configured with UTF8MB4 and UTC timezone
|
|
136
|
+
*/
|
|
137
|
+
async initialize() {
|
|
138
|
+
const knex = this.getKnex();
|
|
139
|
+
// Validate database exists
|
|
140
|
+
const dbName = this.config.connection?.database;
|
|
141
|
+
if (!dbName) {
|
|
142
|
+
throw new Error('MySQL adapter requires database name in configuration');
|
|
143
|
+
}
|
|
144
|
+
try {
|
|
145
|
+
// Query to check if we can access the database
|
|
146
|
+
const result = await knex.raw('SELECT DATABASE() as db');
|
|
147
|
+
const currentDb = result[0]?.[0]?.db;
|
|
148
|
+
if (!currentDb || currentDb !== dbName) {
|
|
149
|
+
throw new Error(`Database '${dbName}' does not exist or cannot be accessed. ` +
|
|
150
|
+
`Please create it manually: CREATE DATABASE ${dbName} CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
catch (error) {
|
|
154
|
+
if (error.code === 'ER_BAD_DB_ERROR') {
|
|
155
|
+
throw new Error(`Database '${dbName}' does not exist. ` +
|
|
156
|
+
`Please create it manually before connecting. Required privileges: SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, INDEX, DROP, REFERENCES`);
|
|
157
|
+
}
|
|
158
|
+
throw error;
|
|
159
|
+
}
|
|
160
|
+
// Configure character set and collation for full Unicode support
|
|
161
|
+
await knex.raw("SET NAMES 'utf8mb4' COLLATE 'utf8mb4_unicode_ci'");
|
|
162
|
+
// Set timezone to UTC for consistent timestamp handling
|
|
163
|
+
await knex.raw("SET time_zone = '+00:00'");
|
|
164
|
+
// Set SQL mode for strict compliance and safety
|
|
165
|
+
await knex.raw("SET sql_mode = 'TRADITIONAL'");
|
|
22
166
|
}
|
|
167
|
+
// ============================================================================
|
|
168
|
+
// Query Adaptations - MySQL-specific implementations
|
|
169
|
+
// ============================================================================
|
|
170
|
+
/**
|
|
171
|
+
* Inserts a row and returns the inserted record.
|
|
172
|
+
*
|
|
173
|
+
* MySQL doesn't support RETURNING clause, so this method:
|
|
174
|
+
* 1. Inserts the row
|
|
175
|
+
* 2. Retrieves LAST_INSERT_ID()
|
|
176
|
+
* 3. Queries the inserted row by ID
|
|
177
|
+
*
|
|
178
|
+
* **Important Notes:**
|
|
179
|
+
* - Assumes table has an auto-increment `id` column
|
|
180
|
+
* - LAST_INSERT_ID() is connection-specific (thread-safe)
|
|
181
|
+
* - For tables without auto-increment ID, use composite unique keys
|
|
182
|
+
*
|
|
183
|
+
* @template T - Record type
|
|
184
|
+
* @param {string} table - Table name
|
|
185
|
+
* @param {Partial<T>} data - Data to insert
|
|
186
|
+
* @returns {Promise<T>} Inserted record
|
|
187
|
+
*
|
|
188
|
+
* @throws {Error} If insert fails or record cannot be retrieved
|
|
189
|
+
*
|
|
190
|
+
* @example
|
|
191
|
+
* // Insert user and return full record
|
|
192
|
+
* const user = await adapter.insertReturning<User>('users', {
|
|
193
|
+
* name: 'Alice',
|
|
194
|
+
* email: 'alice@example.com'
|
|
195
|
+
* });
|
|
196
|
+
* console.log(user.id); // Auto-generated ID
|
|
197
|
+
*
|
|
198
|
+
* @example
|
|
199
|
+
* // With transaction
|
|
200
|
+
* await adapter.transaction(async (trx) => {
|
|
201
|
+
* const user = await adapter.insertReturning<User>('users', {
|
|
202
|
+
* name: 'Bob'
|
|
203
|
+
* });
|
|
204
|
+
* await trx('profiles').insert({ user_id: user.id });
|
|
205
|
+
* });
|
|
206
|
+
*/
|
|
23
207
|
async insertReturning(table, data) {
|
|
24
|
-
|
|
208
|
+
const knex = this.getKnex();
|
|
209
|
+
// Insert and get the auto-increment ID
|
|
210
|
+
const [insertId] = await knex(table).insert(data);
|
|
211
|
+
// Retrieve the inserted row using LAST_INSERT_ID()
|
|
212
|
+
const result = await knex(table).where({ id: insertId }).first();
|
|
213
|
+
if (!result) {
|
|
214
|
+
throw new Error(`Failed to retrieve inserted row from ${table}`);
|
|
215
|
+
}
|
|
216
|
+
return result;
|
|
25
217
|
}
|
|
218
|
+
/**
|
|
219
|
+
* Upserts a row using MySQL's ON DUPLICATE KEY UPDATE syntax.
|
|
220
|
+
*
|
|
221
|
+
* **Behavior:**
|
|
222
|
+
* - If row with conflicting key exists: UPDATE specified columns
|
|
223
|
+
* - If no conflict: INSERT new row
|
|
224
|
+
* - Returns number of affected rows (1 = insert, 2 = update)
|
|
225
|
+
*
|
|
226
|
+
* **Important Notes:**
|
|
227
|
+
* - Requires UNIQUE index or PRIMARY KEY on conflictColumns
|
|
228
|
+
* - MySQL counts updates as 2 affected rows (1 delete + 1 insert internally)
|
|
229
|
+
* - If updateColumns not specified, updates all columns except conflict columns
|
|
230
|
+
*
|
|
231
|
+
* @template T - Record type
|
|
232
|
+
* @param {string} table - Table name
|
|
233
|
+
* @param {Partial<T>} data - Data to insert/update
|
|
234
|
+
* @param {string[]} conflictColumns - Columns that define uniqueness (must have UNIQUE index)
|
|
235
|
+
* @param {string[]} [updateColumns] - Columns to update on conflict (default: all except conflict columns)
|
|
236
|
+
* @returns {Promise<number>} Affected rows (1 = insert, 2 = update)
|
|
237
|
+
*
|
|
238
|
+
* @throws {Error} If conflictColumns don't have UNIQUE index
|
|
239
|
+
*
|
|
240
|
+
* @example
|
|
241
|
+
* // Upsert user by email (UNIQUE index on email)
|
|
242
|
+
* await adapter.upsert('users',
|
|
243
|
+
* { email: 'alice@example.com', name: 'Alice Updated', age: 30 },
|
|
244
|
+
* ['email'], // Conflict column
|
|
245
|
+
* ['name', 'age'] // Update these on conflict
|
|
246
|
+
* );
|
|
247
|
+
*
|
|
248
|
+
* @example
|
|
249
|
+
* // Upsert with composite key
|
|
250
|
+
* await adapter.upsert('user_settings',
|
|
251
|
+
* { user_id: 1, setting_key: 'theme', value: 'dark' },
|
|
252
|
+
* ['user_id', 'setting_key'] // Composite UNIQUE key
|
|
253
|
+
* );
|
|
254
|
+
*/
|
|
26
255
|
async upsert(table, data, conflictColumns, updateColumns) {
|
|
27
|
-
|
|
256
|
+
const knex = this.getKnex();
|
|
257
|
+
// Determine which columns to update on conflict
|
|
258
|
+
const columnsToUpdate = updateColumns || Object.keys(data).filter(key => !conflictColumns.includes(key));
|
|
259
|
+
// Build update data for ON DUPLICATE KEY UPDATE clause
|
|
260
|
+
const updateData = columnsToUpdate.reduce((acc, col) => {
|
|
261
|
+
acc[col] = data[col];
|
|
262
|
+
return acc;
|
|
263
|
+
}, {});
|
|
264
|
+
// Use Knex's onConflict() which generates ON DUPLICATE KEY UPDATE for MySQL
|
|
265
|
+
const result = await knex(table)
|
|
266
|
+
.insert(data)
|
|
267
|
+
.onConflict(conflictColumns)
|
|
268
|
+
.merge(updateData);
|
|
269
|
+
return result.length;
|
|
28
270
|
}
|
|
271
|
+
/**
|
|
272
|
+
* Extracts a value from a JSON column using JSON_EXTRACT().
|
|
273
|
+
*
|
|
274
|
+
* **MySQL JSON Path Syntax:**
|
|
275
|
+
* - `$` - Root element
|
|
276
|
+
* - `$.key` - Object member
|
|
277
|
+
* - `$[n]` - Array element
|
|
278
|
+
* - `$.key[n]` - Nested access
|
|
279
|
+
* - `$.*.key` - Wildcard member
|
|
280
|
+
*
|
|
281
|
+
* **Important Notes:**
|
|
282
|
+
* - Returns JSON value (may need JSON_UNQUOTE() for strings)
|
|
283
|
+
* - Path must start with `$` (auto-prepended if missing)
|
|
284
|
+
* - Returns NULL if path doesn't exist
|
|
285
|
+
*
|
|
286
|
+
* @param {string} column - JSON column name
|
|
287
|
+
* @param {string} path - JSON path (e.g., '$.address.city' or 'address.city')
|
|
288
|
+
* @returns {Knex.Raw} Raw SQL expression for JSON extraction
|
|
289
|
+
*
|
|
290
|
+
* @example
|
|
291
|
+
* // Extract nested value
|
|
292
|
+
* const query = knex('users').select(
|
|
293
|
+
* adapter.jsonExtract('metadata', '$.address.city').as('city')
|
|
294
|
+
* );
|
|
295
|
+
* // SELECT JSON_EXTRACT(`metadata`, '$.address.city') AS `city` FROM `users`
|
|
296
|
+
*
|
|
297
|
+
* @example
|
|
298
|
+
* // Array element access
|
|
299
|
+
* const query = knex('orders').select(
|
|
300
|
+
* adapter.jsonExtract('items', '$[0].name').as('first_item')
|
|
301
|
+
* );
|
|
302
|
+
*/
|
|
29
303
|
jsonExtract(column, path) {
|
|
30
|
-
|
|
304
|
+
const knex = this.getKnex();
|
|
305
|
+
// Ensure path starts with $ for MySQL JSON path syntax
|
|
306
|
+
const jsonPath = path.startsWith('$') ? path : `$.${path}`;
|
|
307
|
+
return knex.raw('JSON_EXTRACT(??, ?)', [column, jsonPath]);
|
|
31
308
|
}
|
|
309
|
+
/**
|
|
310
|
+
* Builds a JSON object from field values using JSON_OBJECT().
|
|
311
|
+
*
|
|
312
|
+
* **Behavior:**
|
|
313
|
+
* - Takes key-value pairs and returns JSON object
|
|
314
|
+
* - Automatically handles NULL values
|
|
315
|
+
* - Returns NULL if all values are NULL
|
|
316
|
+
*
|
|
317
|
+
* @param {Record<string, any>} fields - Object with key-value pairs
|
|
318
|
+
* @returns {Knex.Raw} Raw SQL expression for JSON object construction
|
|
319
|
+
*
|
|
320
|
+
* @example
|
|
321
|
+
* // Build JSON object from columns
|
|
322
|
+
* const query = knex('users').select(
|
|
323
|
+
* adapter.jsonBuildObject({
|
|
324
|
+
* name: knex.ref('name'),
|
|
325
|
+
* email: knex.ref('email'),
|
|
326
|
+
* age: knex.ref('age')
|
|
327
|
+
* }).as('user_json')
|
|
328
|
+
* );
|
|
329
|
+
* // SELECT JSON_OBJECT('name', `name`, 'email', `email`, 'age', `age`) AS `user_json`
|
|
330
|
+
*
|
|
331
|
+
* @example
|
|
332
|
+
* // With literal values
|
|
333
|
+
* const query = knex('orders').insert({
|
|
334
|
+
* metadata: adapter.jsonBuildObject({
|
|
335
|
+
* source: 'web',
|
|
336
|
+
* campaign: 'summer-sale',
|
|
337
|
+
* discount: 10
|
|
338
|
+
* })
|
|
339
|
+
* });
|
|
340
|
+
*/
|
|
32
341
|
jsonBuildObject(fields) {
|
|
33
|
-
|
|
342
|
+
const knex = this.getKnex();
|
|
343
|
+
const keys = Object.keys(fields);
|
|
344
|
+
const values = Object.values(fields);
|
|
345
|
+
// Build arguments array: [key1, value1, key2, value2, ...]
|
|
346
|
+
const args = [];
|
|
347
|
+
keys.forEach((key, i) => {
|
|
348
|
+
args.push(key);
|
|
349
|
+
args.push(values[i]);
|
|
350
|
+
});
|
|
351
|
+
// Create placeholders for JSON_OBJECT(?, ?, ?, ?, ...)
|
|
352
|
+
const placeholders = args.map(() => '?').join(', ');
|
|
353
|
+
return knex.raw(`JSON_OBJECT(${placeholders})`, args);
|
|
34
354
|
}
|
|
355
|
+
/**
|
|
356
|
+
* Returns current Unix timestamp using UNIX_TIMESTAMP().
|
|
357
|
+
*
|
|
358
|
+
* **Behavior:**
|
|
359
|
+
* - Returns seconds since Unix epoch (1970-01-01 00:00:00 UTC)
|
|
360
|
+
* - Always returns UTC timestamp regardless of session timezone
|
|
361
|
+
* - Integer value (no fractional seconds)
|
|
362
|
+
*
|
|
363
|
+
* @returns {Knex.Raw} Raw SQL expression for current timestamp
|
|
364
|
+
*
|
|
365
|
+
* @example
|
|
366
|
+
* // Insert with current timestamp
|
|
367
|
+
* await knex('events').insert({
|
|
368
|
+
* name: 'user_login',
|
|
369
|
+
* created_at: adapter.currentTimestamp()
|
|
370
|
+
* });
|
|
371
|
+
* // INSERT INTO `events` (`name`, `created_at`) VALUES ('user_login', UNIX_TIMESTAMP())
|
|
372
|
+
*
|
|
373
|
+
* @example
|
|
374
|
+
* // Update with current timestamp
|
|
375
|
+
* await knex('users')
|
|
376
|
+
* .where({ id: userId })
|
|
377
|
+
* .update({ last_seen: adapter.currentTimestamp() });
|
|
378
|
+
*/
|
|
35
379
|
currentTimestamp() {
|
|
36
|
-
|
|
380
|
+
return this.getKnex().raw('UNIX_TIMESTAMP()');
|
|
37
381
|
}
|
|
382
|
+
/**
|
|
383
|
+
* Converts Unix epoch timestamp to MySQL datetime using FROM_UNIXTIME().
|
|
384
|
+
*
|
|
385
|
+
* **Behavior:**
|
|
386
|
+
* - Converts integer epoch to DATETIME
|
|
387
|
+
* - Returns UTC datetime (session timezone affects display)
|
|
388
|
+
* - Handles NULL values
|
|
389
|
+
*
|
|
390
|
+
* @param {string} epochColumn - Column containing Unix epoch timestamp
|
|
391
|
+
* @returns {Knex.Raw} Raw SQL expression for epoch conversion
|
|
392
|
+
*
|
|
393
|
+
* @example
|
|
394
|
+
* // Convert epoch to datetime for display
|
|
395
|
+
* const query = knex('events').select(
|
|
396
|
+
* 'name',
|
|
397
|
+
* adapter.fromUnixEpoch('created_at').as('created_datetime')
|
|
398
|
+
* );
|
|
399
|
+
* // SELECT `name`, FROM_UNIXTIME(`created_at`) AS `created_datetime` FROM `events`
|
|
400
|
+
*
|
|
401
|
+
* @example
|
|
402
|
+
* // Filter by datetime range using epoch column
|
|
403
|
+
* const query = knex('logs')
|
|
404
|
+
* .where(adapter.fromUnixEpoch('timestamp'), '>=', '2024-01-01')
|
|
405
|
+
* .andWhere(adapter.fromUnixEpoch('timestamp'), '<', '2024-02-01');
|
|
406
|
+
*/
|
|
38
407
|
fromUnixEpoch(epochColumn) {
|
|
39
|
-
|
|
408
|
+
return this.getKnex().raw('FROM_UNIXTIME(??)', [epochColumn]);
|
|
40
409
|
}
|
|
410
|
+
/**
|
|
411
|
+
* Converts MySQL datetime to Unix epoch using UNIX_TIMESTAMP().
|
|
412
|
+
*
|
|
413
|
+
* **Behavior:**
|
|
414
|
+
* - Converts DATETIME/TIMESTAMP to integer epoch
|
|
415
|
+
* - Assumes input is UTC
|
|
416
|
+
* - Handles NULL values
|
|
417
|
+
*
|
|
418
|
+
* @param {string} timestampColumn - Column containing datetime value
|
|
419
|
+
* @returns {Knex.Raw} Raw SQL expression for datetime conversion
|
|
420
|
+
*
|
|
421
|
+
* @example
|
|
422
|
+
* // Convert datetime to epoch for storage
|
|
423
|
+
* const query = knex('events').insert({
|
|
424
|
+
* name: 'signup',
|
|
425
|
+
* timestamp: adapter.toUnixEpoch('NOW()')
|
|
426
|
+
* });
|
|
427
|
+
*
|
|
428
|
+
* @example
|
|
429
|
+
* // Calculate time difference in seconds
|
|
430
|
+
* const query = knex('sessions').select(
|
|
431
|
+
* knex.raw('?? - ??', [
|
|
432
|
+
* adapter.toUnixEpoch('logout_time'),
|
|
433
|
+
* adapter.toUnixEpoch('login_time')
|
|
434
|
+
* ]).as('duration_seconds')
|
|
435
|
+
* );
|
|
436
|
+
*/
|
|
41
437
|
toUnixEpoch(timestampColumn) {
|
|
42
|
-
|
|
438
|
+
return this.getKnex().raw('UNIX_TIMESTAMP(??)', [timestampColumn]);
|
|
43
439
|
}
|
|
440
|
+
/**
|
|
441
|
+
* Concatenates string values using CONCAT().
|
|
442
|
+
*
|
|
443
|
+
* **Behavior:**
|
|
444
|
+
* - Returns NULL if any argument is NULL
|
|
445
|
+
* - Automatically converts non-string types to strings
|
|
446
|
+
* - Empty strings are preserved
|
|
447
|
+
*
|
|
448
|
+
* **Alternative:** Use CONCAT_WS() for separator-based concatenation
|
|
449
|
+
*
|
|
450
|
+
* @param {...(string | Knex.Raw)[]} values - Values to concatenate
|
|
451
|
+
* @returns {Knex.Raw} Raw SQL expression for concatenation
|
|
452
|
+
*
|
|
453
|
+
* @example
|
|
454
|
+
* // Concatenate columns
|
|
455
|
+
* const query = knex('users').select(
|
|
456
|
+
* adapter.concat(
|
|
457
|
+
* knex.ref('first_name'),
|
|
458
|
+
* ' ',
|
|
459
|
+
* knex.ref('last_name')
|
|
460
|
+
* ).as('full_name')
|
|
461
|
+
* );
|
|
462
|
+
* // SELECT CONCAT(`first_name`, ' ', `last_name`) AS `full_name` FROM `users`
|
|
463
|
+
*
|
|
464
|
+
* @example
|
|
465
|
+
* // Build URL from parts
|
|
466
|
+
* const query = knex('products').select(
|
|
467
|
+
* adapter.concat(
|
|
468
|
+
* 'https://example.com/products/',
|
|
469
|
+
* knex.ref('slug')
|
|
470
|
+
* ).as('url')
|
|
471
|
+
* );
|
|
472
|
+
*/
|
|
44
473
|
concat(...values) {
|
|
45
|
-
|
|
474
|
+
const knex = this.getKnex();
|
|
475
|
+
const placeholders = values.map(() => '?').join(', ');
|
|
476
|
+
return knex.raw(`CONCAT(${placeholders})`, values);
|
|
46
477
|
}
|
|
47
|
-
|
|
48
|
-
|
|
478
|
+
/**
|
|
479
|
+
* Aggregates strings with separator using GROUP_CONCAT().
|
|
480
|
+
*
|
|
481
|
+
* **Behavior:**
|
|
482
|
+
* - Concatenates values from multiple rows into single string
|
|
483
|
+
* - Default separator: comma (,)
|
|
484
|
+
* - NULL values are skipped
|
|
485
|
+
* - Result may be truncated by group_concat_max_len setting
|
|
486
|
+
*
|
|
487
|
+
* **Important Notes:**
|
|
488
|
+
* - Default max length: 1024 bytes (can be increased with SET group_concat_max_len)
|
|
489
|
+
* - Use with GROUP BY for grouped aggregation
|
|
490
|
+
* - For large results, increase group_concat_max_len session variable
|
|
491
|
+
*
|
|
492
|
+
* @param {string} column - Column to aggregate
|
|
493
|
+
* @param {string} [separator=','] - Separator between values
|
|
494
|
+
* @returns {Knex.Raw} Raw SQL expression for string aggregation
|
|
495
|
+
*
|
|
496
|
+
* @example
|
|
497
|
+
* // Get comma-separated list of tags
|
|
498
|
+
* const query = knex('posts')
|
|
499
|
+
* .select('posts.id', 'posts.title')
|
|
500
|
+
* .select(adapter.stringAgg('tags.name').as('tags'))
|
|
501
|
+
* .leftJoin('post_tags', 'posts.id', 'post_tags.post_id')
|
|
502
|
+
* .leftJoin('tags', 'post_tags.tag_id', 'tags.id')
|
|
503
|
+
* .groupBy('posts.id');
|
|
504
|
+
* // Result: { id: 1, title: 'Post', tags: 'javascript,typescript,node' }
|
|
505
|
+
*
|
|
506
|
+
* @example
|
|
507
|
+
* // Custom separator
|
|
508
|
+
* const query = knex('users')
|
|
509
|
+
* .select('department')
|
|
510
|
+
* .select(adapter.stringAgg('name', '; ').as('members'))
|
|
511
|
+
* .groupBy('department');
|
|
512
|
+
*/
|
|
513
|
+
stringAgg(column, separator = ',') {
|
|
514
|
+
return this.getKnex().raw('GROUP_CONCAT(?? SEPARATOR ?)', [column, separator]);
|
|
49
515
|
}
|
|
516
|
+
// ============================================================================
|
|
517
|
+
// Transaction Support
|
|
518
|
+
// ============================================================================
|
|
519
|
+
/**
|
|
520
|
+
* Executes a callback within a database transaction.
|
|
521
|
+
*
|
|
522
|
+
* Delegates to BaseAdapter's transaction() method, which uses Knex's
|
|
523
|
+
* transaction management with automatic commit/rollback.
|
|
524
|
+
*
|
|
525
|
+
* **MySQL Transaction Characteristics:**
|
|
526
|
+
* - Default isolation level: REPEATABLE READ
|
|
527
|
+
* - Supports nested transactions via savepoints
|
|
528
|
+
* - Automatic rollback on error
|
|
529
|
+
* - Deadlock detection and retry recommended for production
|
|
530
|
+
*
|
|
531
|
+
* @template T - Return type
|
|
532
|
+
* @param {Function} callback - Transaction callback
|
|
533
|
+
* @param {Object} [options] - Transaction options
|
|
534
|
+
* @param {string} [options.isolationLevel] - Isolation level
|
|
535
|
+
* @returns {Promise<T>} Transaction result
|
|
536
|
+
*
|
|
537
|
+
* @example
|
|
538
|
+
* // Bank transfer with transaction
|
|
539
|
+
* await adapter.transaction(async (trx) => {
|
|
540
|
+
* await trx('accounts')
|
|
541
|
+
* .where({ id: fromAccount })
|
|
542
|
+
* .decrement('balance', amount);
|
|
543
|
+
*
|
|
544
|
+
* await trx('accounts')
|
|
545
|
+
* .where({ id: toAccount })
|
|
546
|
+
* .increment('balance', amount);
|
|
547
|
+
* });
|
|
548
|
+
*
|
|
549
|
+
* @example
|
|
550
|
+
* // With isolation level
|
|
551
|
+
* await adapter.transaction(async (trx) => {
|
|
552
|
+
* // ... transaction operations ...
|
|
553
|
+
* }, { isolationLevel: 'serializable' });
|
|
554
|
+
*/
|
|
50
555
|
async transaction(callback, options) {
|
|
51
|
-
|
|
556
|
+
// Delegate to BaseAdapter's implementation
|
|
557
|
+
return super.transaction(callback, options);
|
|
52
558
|
}
|
|
559
|
+
/**
|
|
560
|
+
* Creates a savepoint within a transaction.
|
|
561
|
+
*
|
|
562
|
+
* **MySQL Savepoint Behavior:**
|
|
563
|
+
* - Allows partial rollback within transaction
|
|
564
|
+
* - Savepoint names are case-insensitive
|
|
565
|
+
* - Automatically released on transaction commit
|
|
566
|
+
* - Rolled back on transaction rollback
|
|
567
|
+
*
|
|
568
|
+
* @template T - Return type
|
|
569
|
+
* @param {Knex.Transaction} trx - Parent transaction
|
|
570
|
+
* @param {Function} callback - Savepoint callback
|
|
571
|
+
* @returns {Promise<T>} Savepoint result
|
|
572
|
+
*
|
|
573
|
+
* @throws {Error} If savepoint operation fails
|
|
574
|
+
*
|
|
575
|
+
* @example
|
|
576
|
+
* // Use savepoint for partial rollback
|
|
577
|
+
* await adapter.transaction(async (trx) => {
|
|
578
|
+
* await trx('users').insert({ name: 'Alice' });
|
|
579
|
+
*
|
|
580
|
+
* try {
|
|
581
|
+
* await adapter.savepoint(trx, async (sp) => {
|
|
582
|
+
* await sp('users').insert({ name: 'Bob' });
|
|
583
|
+
* throw new Error('Bob insert failed');
|
|
584
|
+
* });
|
|
585
|
+
* } catch (error) {
|
|
586
|
+
* // Bob insert rolled back, Alice insert preserved
|
|
587
|
+
* }
|
|
588
|
+
*
|
|
589
|
+
* await trx('users').insert({ name: 'Charlie' });
|
|
590
|
+
* });
|
|
591
|
+
*/
|
|
53
592
|
async savepoint(trx, callback) {
|
|
54
|
-
|
|
593
|
+
return trx.savepoint(callback);
|
|
55
594
|
}
|
|
595
|
+
// ============================================================================
|
|
596
|
+
// Schema Management
|
|
597
|
+
// ============================================================================
|
|
598
|
+
/**
|
|
599
|
+
* Checks if a table exists in the database.
|
|
600
|
+
*
|
|
601
|
+
* Queries INFORMATION_SCHEMA.TABLES which is the standard MySQL approach
|
|
602
|
+
* for table existence checking.
|
|
603
|
+
*
|
|
604
|
+
* **Important Notes:**
|
|
605
|
+
* - Case sensitivity depends on operating system (Linux: case-sensitive, Windows: case-insensitive)
|
|
606
|
+
* - Uses current database (from connection config)
|
|
607
|
+
* - Checks both base tables and views
|
|
608
|
+
*
|
|
609
|
+
* @param {string} tableName - Table name to check
|
|
610
|
+
* @returns {Promise<boolean>} True if table exists, false otherwise
|
|
611
|
+
*
|
|
612
|
+
* @example
|
|
613
|
+
* // Check before creating table
|
|
614
|
+
* if (!(await adapter.tableExists('users'))) {
|
|
615
|
+
* await knex.schema.createTable('users', (table) => {
|
|
616
|
+
* adapter.autoIncrementColumn(table);
|
|
617
|
+
* table.string('name');
|
|
618
|
+
* });
|
|
619
|
+
* }
|
|
620
|
+
*
|
|
621
|
+
* @example
|
|
622
|
+
* // Conditional migration
|
|
623
|
+
* if (await adapter.tableExists('old_table')) {
|
|
624
|
+
* await knex.raw('RENAME TABLE old_table TO new_table');
|
|
625
|
+
* }
|
|
626
|
+
*/
|
|
56
627
|
async tableExists(tableName) {
|
|
57
|
-
|
|
628
|
+
const knex = this.getKnex();
|
|
629
|
+
const database = this.config.connection.database;
|
|
630
|
+
const result = await knex.raw(`SELECT TABLE_NAME
|
|
631
|
+
FROM INFORMATION_SCHEMA.TABLES
|
|
632
|
+
WHERE TABLE_SCHEMA = ?
|
|
633
|
+
AND TABLE_NAME = ?`, [database, tableName]);
|
|
634
|
+
return result[0].length > 0;
|
|
58
635
|
}
|
|
59
|
-
|
|
60
|
-
|
|
636
|
+
/**
|
|
637
|
+
* Adds an auto-increment primary key column to a table.
|
|
638
|
+
*
|
|
639
|
+
* **MySQL AUTO_INCREMENT Behavior:**
|
|
640
|
+
* - Generates sequential integer IDs starting from 1
|
|
641
|
+
* - Must be indexed (PRIMARY KEY or UNIQUE)
|
|
642
|
+
* - Only one AUTO_INCREMENT column per table
|
|
643
|
+
* - Uses UNSIGNED INT for larger range (0 to 4,294,967,295)
|
|
644
|
+
*
|
|
645
|
+
* **Column Characteristics:**
|
|
646
|
+
* - Type: INTEGER UNSIGNED
|
|
647
|
+
* - Primary Key: Yes
|
|
648
|
+
* - Auto Increment: Yes
|
|
649
|
+
* - Not Nullable: Yes
|
|
650
|
+
*
|
|
651
|
+
* @param {Knex.CreateTableBuilder} table - Knex table builder
|
|
652
|
+
* @param {string} [columnName='id'] - Column name (default: 'id')
|
|
653
|
+
*
|
|
654
|
+
* @example
|
|
655
|
+
* // Create table with auto-increment ID
|
|
656
|
+
* await knex.schema.createTable('users', (table) => {
|
|
657
|
+
* adapter.autoIncrementColumn(table);
|
|
658
|
+
* table.string('name').notNullable();
|
|
659
|
+
* table.string('email').unique();
|
|
660
|
+
* table.timestamps(true, true);
|
|
661
|
+
* });
|
|
662
|
+
* // CREATE TABLE `users` (
|
|
663
|
+
* // `id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
|
664
|
+
* // `name` VARCHAR(255) NOT NULL,
|
|
665
|
+
* // `email` VARCHAR(255) UNIQUE,
|
|
666
|
+
* // `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
667
|
+
* // `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
|
668
|
+
* // )
|
|
669
|
+
*
|
|
670
|
+
* @example
|
|
671
|
+
* // Custom column name
|
|
672
|
+
* await knex.schema.createTable('orders', (table) => {
|
|
673
|
+
* adapter.autoIncrementColumn(table, 'order_id');
|
|
674
|
+
* table.integer('user_id').unsigned().notNullable();
|
|
675
|
+
* });
|
|
676
|
+
*/
|
|
677
|
+
autoIncrementColumn(table, columnName = 'id') {
|
|
678
|
+
// Use increments() which creates UNSIGNED INT AUTO_INCREMENT PRIMARY KEY
|
|
679
|
+
table.increments(columnName).unsigned();
|
|
61
680
|
}
|
|
62
681
|
}
|
|
63
682
|
//# sourceMappingURL=mysql-adapter.js.map
|