@neverinfamous/mysql-mcp 2.3.0 → 3.0.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/.dockerignore +1 -0
- package/.gitattributes +18 -0
- package/.github/workflows/codeql.yml +2 -10
- package/.github/workflows/docker-publish.yml +15 -13
- package/CHANGELOG.md +287 -1
- package/DOCKER_README.md +100 -265
- package/Dockerfile +5 -0
- package/README.md +124 -59
- package/VERSION +1 -1
- package/dist/__tests__/mocks/adapter.d.ts.map +1 -1
- package/dist/__tests__/mocks/adapter.js +2 -0
- package/dist/__tests__/mocks/adapter.js.map +1 -1
- package/dist/adapters/DatabaseAdapter.d.ts.map +1 -1
- package/dist/adapters/DatabaseAdapter.js +50 -9
- package/dist/adapters/DatabaseAdapter.js.map +1 -1
- package/dist/adapters/mysql/MySQLAdapter.d.ts +6 -0
- package/dist/adapters/mysql/MySQLAdapter.d.ts.map +1 -1
- package/dist/adapters/mysql/MySQLAdapter.js +8 -0
- package/dist/adapters/mysql/MySQLAdapter.js.map +1 -1
- package/dist/adapters/mysql/SchemaManager.js +16 -15
- package/dist/adapters/mysql/SchemaManager.js.map +1 -1
- package/dist/adapters/mysql/prompts/index.js +10 -20
- package/dist/adapters/mysql/prompts/index.js.map +1 -1
- package/dist/adapters/mysql/prompts/proxysqlSetup.js +1 -1
- package/dist/adapters/mysql/resources/docstore.d.ts.map +1 -1
- package/dist/adapters/mysql/resources/docstore.js +10 -7
- package/dist/adapters/mysql/resources/docstore.js.map +1 -1
- package/dist/adapters/mysql/resources/events.js +11 -8
- package/dist/adapters/mysql/resources/events.js.map +1 -1
- package/dist/adapters/mysql/resources/indexes.d.ts.map +1 -1
- package/dist/adapters/mysql/resources/indexes.js +12 -15
- package/dist/adapters/mysql/resources/indexes.js.map +1 -1
- package/dist/adapters/mysql/resources/innodb.d.ts.map +1 -1
- package/dist/adapters/mysql/resources/innodb.js +20 -17
- package/dist/adapters/mysql/resources/innodb.js.map +1 -1
- package/dist/adapters/mysql/resources/locks.d.ts.map +1 -1
- package/dist/adapters/mysql/resources/locks.js +9 -6
- package/dist/adapters/mysql/resources/locks.js.map +1 -1
- package/dist/adapters/mysql/resources/performance.d.ts.map +1 -1
- package/dist/adapters/mysql/resources/performance.js +15 -15
- package/dist/adapters/mysql/resources/performance.js.map +1 -1
- package/dist/adapters/mysql/resources/spatial.d.ts.map +1 -1
- package/dist/adapters/mysql/resources/spatial.js +9 -6
- package/dist/adapters/mysql/resources/spatial.js.map +1 -1
- package/dist/adapters/mysql/resources/sysschema.d.ts.map +1 -1
- package/dist/adapters/mysql/resources/sysschema.js +12 -9
- package/dist/adapters/mysql/resources/sysschema.js.map +1 -1
- package/dist/adapters/mysql/tools/admin/backup.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/admin/backup.js +170 -121
- package/dist/adapters/mysql/tools/admin/backup.js.map +1 -1
- package/dist/adapters/mysql/tools/admin/maintenance.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/admin/maintenance.js +106 -57
- package/dist/adapters/mysql/tools/admin/maintenance.js.map +1 -1
- package/dist/adapters/mysql/tools/admin/monitoring.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/admin/monitoring.js +183 -101
- package/dist/adapters/mysql/tools/admin/monitoring.js.map +1 -1
- package/dist/adapters/mysql/tools/cluster/group-replication.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/cluster/group-replication.js +164 -120
- package/dist/adapters/mysql/tools/cluster/group-replication.js.map +1 -1
- package/dist/adapters/mysql/tools/cluster/innodb-cluster.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/cluster/innodb-cluster.js +212 -145
- package/dist/adapters/mysql/tools/cluster/innodb-cluster.js.map +1 -1
- package/dist/adapters/mysql/tools/codemode/index.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/codemode/index.js +6 -4
- package/dist/adapters/mysql/tools/codemode/index.js.map +1 -1
- package/dist/adapters/mysql/tools/core.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/core.js +152 -29
- package/dist/adapters/mysql/tools/core.js.map +1 -1
- package/dist/adapters/mysql/tools/docstore.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/docstore.js +340 -163
- package/dist/adapters/mysql/tools/docstore.js.map +1 -1
- package/dist/adapters/mysql/tools/events.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/events.js +284 -198
- package/dist/adapters/mysql/tools/events.js.map +1 -1
- package/dist/adapters/mysql/tools/json/core.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/json/core.js +11 -39
- package/dist/adapters/mysql/tools/json/core.js.map +1 -1
- package/dist/adapters/mysql/tools/json/enhanced.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/json/enhanced.js +15 -33
- package/dist/adapters/mysql/tools/json/enhanced.js.map +1 -1
- package/dist/adapters/mysql/tools/json/helpers.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/json/helpers.js +13 -24
- package/dist/adapters/mysql/tools/json/helpers.js.map +1 -1
- package/dist/adapters/mysql/tools/partitioning.js +3 -0
- package/dist/adapters/mysql/tools/partitioning.js.map +1 -1
- package/dist/adapters/mysql/tools/performance/analysis.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/performance/analysis.js +89 -60
- package/dist/adapters/mysql/tools/performance/analysis.js.map +1 -1
- package/dist/adapters/mysql/tools/performance/optimization.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/performance/optimization.js +151 -127
- package/dist/adapters/mysql/tools/performance/optimization.js.map +1 -1
- package/dist/adapters/mysql/tools/proxysql.d.ts +1 -1
- package/dist/adapters/mysql/tools/proxysql.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/proxysql.js +289 -176
- package/dist/adapters/mysql/tools/proxysql.js.map +1 -1
- package/dist/adapters/mysql/tools/replication.js +75 -49
- package/dist/adapters/mysql/tools/replication.js.map +1 -1
- package/dist/adapters/mysql/tools/roles.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/roles.js +224 -182
- package/dist/adapters/mysql/tools/roles.js.map +1 -1
- package/dist/adapters/mysql/tools/router.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/router.js +168 -67
- package/dist/adapters/mysql/tools/router.js.map +1 -1
- package/dist/adapters/mysql/tools/schema/constraints.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/schema/constraints.js +21 -3
- package/dist/adapters/mysql/tools/schema/constraints.js.map +1 -1
- package/dist/adapters/mysql/tools/schema/management.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/schema/management.js +61 -14
- package/dist/adapters/mysql/tools/schema/management.js.map +1 -1
- package/dist/adapters/mysql/tools/schema/routines.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/schema/routines.js +27 -4
- package/dist/adapters/mysql/tools/schema/routines.js.map +1 -1
- package/dist/adapters/mysql/tools/schema/scheduled_events.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/schema/scheduled_events.js +24 -3
- package/dist/adapters/mysql/tools/schema/scheduled_events.js.map +1 -1
- package/dist/adapters/mysql/tools/schema/triggers.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/schema/triggers.js +23 -2
- package/dist/adapters/mysql/tools/schema/triggers.js.map +1 -1
- package/dist/adapters/mysql/tools/schema/views.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/schema/views.js +47 -7
- package/dist/adapters/mysql/tools/schema/views.js.map +1 -1
- package/dist/adapters/mysql/tools/security/audit.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/security/audit.js +102 -34
- package/dist/adapters/mysql/tools/security/audit.js.map +1 -1
- package/dist/adapters/mysql/tools/security/data-protection.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/security/data-protection.js +264 -205
- package/dist/adapters/mysql/tools/security/data-protection.js.map +1 -1
- package/dist/adapters/mysql/tools/security/encryption.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/security/encryption.js +137 -104
- package/dist/adapters/mysql/tools/security/encryption.js.map +1 -1
- package/dist/adapters/mysql/tools/shell/backup.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/shell/backup.js +71 -59
- package/dist/adapters/mysql/tools/shell/backup.js.map +1 -1
- package/dist/adapters/mysql/tools/shell/restore.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/shell/restore.js +61 -47
- package/dist/adapters/mysql/tools/shell/restore.js.map +1 -1
- package/dist/adapters/mysql/tools/spatial/geometry.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/spatial/geometry.js +19 -5
- package/dist/adapters/mysql/tools/spatial/geometry.js.map +1 -1
- package/dist/adapters/mysql/tools/spatial/operations.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/spatial/operations.js +42 -17
- package/dist/adapters/mysql/tools/spatial/operations.js.map +1 -1
- package/dist/adapters/mysql/tools/spatial/queries.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/spatial/queries.js +109 -57
- package/dist/adapters/mysql/tools/spatial/queries.js.map +1 -1
- package/dist/adapters/mysql/tools/spatial/setup.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/spatial/setup.js +103 -50
- package/dist/adapters/mysql/tools/spatial/setup.js.map +1 -1
- package/dist/adapters/mysql/tools/stats/comparative.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/stats/comparative.js +128 -79
- package/dist/adapters/mysql/tools/stats/comparative.js.map +1 -1
- package/dist/adapters/mysql/tools/stats/descriptive.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/stats/descriptive.js +174 -102
- package/dist/adapters/mysql/tools/stats/descriptive.js.map +1 -1
- package/dist/adapters/mysql/tools/sysschema/activity.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/sysschema/activity.js +50 -25
- package/dist/adapters/mysql/tools/sysschema/activity.js.map +1 -1
- package/dist/adapters/mysql/tools/sysschema/performance.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/sysschema/performance.js +121 -66
- package/dist/adapters/mysql/tools/sysschema/performance.js.map +1 -1
- package/dist/adapters/mysql/tools/sysschema/resources.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/sysschema/resources.js +101 -64
- package/dist/adapters/mysql/tools/sysschema/resources.js.map +1 -1
- package/dist/adapters/mysql/tools/text/fulltext.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/text/fulltext.js +18 -32
- package/dist/adapters/mysql/tools/text/fulltext.js.map +1 -1
- package/dist/adapters/mysql/tools/transactions.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/transactions.js +48 -23
- package/dist/adapters/mysql/tools/transactions.js.map +1 -1
- package/dist/adapters/mysql/types/proxysql-types.d.ts +15 -0
- package/dist/adapters/mysql/types/proxysql-types.d.ts.map +1 -1
- package/dist/adapters/mysql/types/proxysql-types.js +33 -1
- package/dist/adapters/mysql/types/proxysql-types.js.map +1 -1
- package/dist/adapters/mysql/types/router-types.d.ts +1 -1
- package/dist/adapters/mysql/types/router-types.js +1 -1
- package/dist/adapters/mysql/types/router-types.js.map +1 -1
- package/dist/adapters/mysql/types/shell-types.js +2 -2
- package/dist/adapters/mysql/types/shell-types.js.map +1 -1
- package/dist/adapters/mysql/types.d.ts +485 -21
- package/dist/adapters/mysql/types.d.ts.map +1 -1
- package/dist/adapters/mysql/types.js +546 -19
- package/dist/adapters/mysql/types.js.map +1 -1
- package/dist/auth/scopes.js +1 -1
- package/dist/auth/scopes.js.map +1 -1
- package/dist/codemode/api.d.ts +3 -2
- package/dist/codemode/api.d.ts.map +1 -1
- package/dist/codemode/api.js +80 -5
- package/dist/codemode/api.js.map +1 -1
- package/dist/codemode/sandbox-factory.js +1 -1
- package/dist/codemode/sandbox-factory.js.map +1 -1
- package/dist/codemode/types.d.ts +26 -0
- package/dist/codemode/types.d.ts.map +1 -1
- package/dist/codemode/types.js +2 -0
- package/dist/codemode/types.js.map +1 -1
- package/dist/codemode/worker-sandbox.d.ts +4 -2
- package/dist/codemode/worker-sandbox.d.ts.map +1 -1
- package/dist/codemode/worker-sandbox.js +66 -7
- package/dist/codemode/worker-sandbox.js.map +1 -1
- package/dist/codemode/worker-script.d.ts +3 -0
- package/dist/codemode/worker-script.d.ts.map +1 -1
- package/dist/codemode/worker-script.js +128 -75
- package/dist/codemode/worker-script.js.map +1 -1
- package/dist/constants/ServerInstructions.d.ts +1 -1
- package/dist/constants/ServerInstructions.d.ts.map +1 -1
- package/dist/constants/ServerInstructions.js +37 -31
- package/dist/constants/ServerInstructions.js.map +1 -1
- package/dist/filtering/ToolConstants.d.ts +1 -1
- package/dist/filtering/ToolConstants.d.ts.map +1 -1
- package/dist/filtering/ToolConstants.js +1 -2
- package/dist/filtering/ToolConstants.js.map +1 -1
- package/dist/pool/ConnectionPool.d.ts.map +1 -1
- package/dist/pool/ConnectionPool.js.map +1 -1
- package/dist/transports/http.d.ts.map +1 -1
- package/dist/transports/http.js +6 -0
- package/dist/transports/http.js.map +1 -1
- package/dist/utils/validators.d.ts +1 -1
- package/dist/utils/validators.d.ts.map +1 -1
- package/dist/utils/validators.js.map +1 -1
- package/package.json +4 -4
- package/releases/v2.3.0-release-notes.md +20 -20
- package/releases/v2.3.1-release-notes.md +34 -0
- package/releases/v3.0.0-release-notes.md +81 -0
- package/src/__tests__/mocks/adapter.ts +3 -0
- package/src/__tests__/perf.test.ts +6 -6
- package/src/adapters/DatabaseAdapter.ts +58 -9
- package/src/adapters/__tests__/DatabaseAdapter.test.ts +89 -8
- package/src/adapters/mysql/MySQLAdapter.ts +17 -2
- package/src/adapters/mysql/SchemaManager.ts +21 -21
- package/src/adapters/mysql/__tests__/MySQLAdapter.test.ts +1 -1
- package/src/adapters/mysql/prompts/index.ts +12 -22
- package/src/adapters/mysql/prompts/proxysqlSetup.ts +1 -1
- package/src/adapters/mysql/resources/docstore.ts +13 -10
- package/src/adapters/mysql/resources/events.ts +12 -12
- package/src/adapters/mysql/resources/indexes.ts +17 -19
- package/src/adapters/mysql/resources/innodb.ts +23 -22
- package/src/adapters/mysql/resources/locks.ts +9 -7
- package/src/adapters/mysql/resources/performance.ts +23 -18
- package/src/adapters/mysql/resources/spatial.ts +9 -7
- package/src/adapters/mysql/resources/sysschema.ts +12 -11
- package/src/adapters/mysql/tools/__tests__/core.test.ts +126 -55
- package/src/adapters/mysql/tools/__tests__/docstore.test.ts +459 -88
- package/src/adapters/mysql/tools/__tests__/events.test.ts +281 -103
- package/src/adapters/mysql/tools/__tests__/proxysql.test.ts +128 -28
- package/src/adapters/mysql/tools/__tests__/replication.test.ts +48 -2
- package/src/adapters/mysql/tools/__tests__/roles.test.ts +15 -18
- package/src/adapters/mysql/tools/__tests__/router.test.ts +32 -5
- package/src/adapters/mysql/tools/__tests__/security.test.ts +126 -2
- package/src/adapters/mysql/tools/__tests__/security_injection.test.ts +84 -76
- package/src/adapters/mysql/tools/__tests__/security_integration.test.ts +47 -50
- package/src/adapters/mysql/tools/__tests__/spatial.test.ts +11 -10
- package/src/adapters/mysql/tools/__tests__/spatial_handler.test.ts +54 -38
- package/src/adapters/mysql/tools/__tests__/stats.test.ts +285 -152
- package/src/adapters/mysql/tools/__tests__/transactions.test.ts +13 -13
- package/src/adapters/mysql/tools/admin/__tests__/backup.test.ts +171 -25
- package/src/adapters/mysql/tools/admin/__tests__/maintenance.test.ts +240 -4
- package/src/adapters/mysql/tools/admin/__tests__/monitoring-summary.test.ts +274 -0
- package/src/adapters/mysql/tools/admin/__tests__/monitoring.test.ts +94 -5
- package/src/adapters/mysql/tools/admin/backup.ts +193 -143
- package/src/adapters/mysql/tools/admin/maintenance.ts +118 -69
- package/src/adapters/mysql/tools/admin/monitoring.ts +201 -125
- package/src/adapters/mysql/tools/cluster/__tests__/group-replication.test.ts +69 -0
- package/src/adapters/mysql/tools/cluster/__tests__/innodb-cluster.test.ts +141 -0
- package/src/adapters/mysql/tools/cluster/group-replication.ts +172 -132
- package/src/adapters/mysql/tools/cluster/innodb-cluster.ts +231 -157
- package/src/adapters/mysql/tools/codemode/__tests__/codemode-tool.test.ts +227 -0
- package/src/adapters/mysql/tools/codemode/index.ts +5 -3
- package/src/adapters/mysql/tools/core.ts +152 -38
- package/src/adapters/mysql/tools/docstore.ts +422 -205
- package/src/adapters/mysql/tools/events.ts +334 -233
- package/src/adapters/mysql/tools/json/__tests__/core.test.ts +20 -0
- package/src/adapters/mysql/tools/json/__tests__/enhanced.test.ts +82 -50
- package/src/adapters/mysql/tools/json/__tests__/helpers.test.ts +42 -3
- package/src/adapters/mysql/tools/json/core.ts +21 -42
- package/src/adapters/mysql/tools/json/enhanced.ts +22 -37
- package/src/adapters/mysql/tools/json/helpers.ts +21 -25
- package/src/adapters/mysql/tools/partitioning.ts +3 -0
- package/src/adapters/mysql/tools/performance/__tests__/analysis.test.ts +98 -5
- package/src/adapters/mysql/tools/performance/__tests__/optimization-coverage.test.ts +515 -0
- package/src/adapters/mysql/tools/performance/__tests__/optimization.test.ts +187 -0
- package/src/adapters/mysql/tools/performance/analysis.ts +95 -69
- package/src/adapters/mysql/tools/performance/optimization.ts +182 -153
- package/src/adapters/mysql/tools/proxysql.ts +314 -209
- package/src/adapters/mysql/tools/replication.ts +84 -57
- package/src/adapters/mysql/tools/roles.ts +274 -226
- package/src/adapters/mysql/tools/router.ts +181 -85
- package/src/adapters/mysql/tools/schema/__tests__/constraints.test.ts +13 -0
- package/src/adapters/mysql/tools/schema/__tests__/management.test.ts +60 -25
- package/src/adapters/mysql/tools/schema/__tests__/scheduled_events.test.ts +11 -0
- package/src/adapters/mysql/tools/schema/__tests__/triggers.test.ts +25 -4
- package/src/adapters/mysql/tools/schema/__tests__/views.test.ts +46 -14
- package/src/adapters/mysql/tools/schema/constraints.ts +22 -3
- package/src/adapters/mysql/tools/schema/management.ts +60 -15
- package/src/adapters/mysql/tools/schema/routines.ts +26 -4
- package/src/adapters/mysql/tools/schema/scheduled_events.ts +25 -3
- package/src/adapters/mysql/tools/schema/triggers.ts +27 -2
- package/src/adapters/mysql/tools/schema/views.ts +46 -8
- package/src/adapters/mysql/tools/security/__tests__/audit.test.ts +90 -4
- package/src/adapters/mysql/tools/security/audit.ts +113 -39
- package/src/adapters/mysql/tools/security/data-protection.ts +293 -233
- package/src/adapters/mysql/tools/security/encryption.ts +172 -139
- package/src/adapters/mysql/tools/shell/__tests__/backup.test.ts +29 -0
- package/src/adapters/mysql/tools/shell/backup.ts +90 -73
- package/src/adapters/mysql/tools/shell/restore.ts +62 -48
- package/src/adapters/mysql/tools/spatial/__tests__/operations.test.ts +22 -14
- package/src/adapters/mysql/tools/spatial/__tests__/queries.test.ts +65 -51
- package/src/adapters/mysql/tools/spatial/geometry.ts +23 -7
- package/src/adapters/mysql/tools/spatial/operations.ts +60 -31
- package/src/adapters/mysql/tools/spatial/queries.ts +142 -65
- package/src/adapters/mysql/tools/spatial/setup.ts +121 -55
- package/src/adapters/mysql/tools/stats/__tests__/comparative.test.ts +12 -10
- package/src/adapters/mysql/tools/stats/comparative.ts +150 -98
- package/src/adapters/mysql/tools/stats/descriptive.ts +204 -127
- package/src/adapters/mysql/tools/sysschema/__tests__/error-paths.test.ts +222 -0
- package/src/adapters/mysql/tools/sysschema/__tests__/performance.test.ts +45 -0
- package/src/adapters/mysql/tools/sysschema/__tests__/resources.test.ts +6 -3
- package/src/adapters/mysql/tools/sysschema/activity.ts +52 -27
- package/src/adapters/mysql/tools/sysschema/performance.ts +132 -68
- package/src/adapters/mysql/tools/sysschema/resources.ts +105 -67
- package/src/adapters/mysql/tools/text/__tests__/fulltext.test.ts +45 -17
- package/src/adapters/mysql/tools/text/fulltext.ts +27 -38
- package/src/adapters/mysql/tools/transactions.ts +49 -24
- package/src/adapters/mysql/types/proxysql-types.ts +38 -1
- package/src/adapters/mysql/types/router-types.ts +1 -1
- package/src/adapters/mysql/types/shell-types.ts +2 -2
- package/src/adapters/mysql/types.ts +632 -19
- package/src/auth/__tests__/scopes.test.ts +2 -2
- package/src/auth/scopes.ts +1 -1
- package/src/codemode/__tests__/api.test.ts +417 -0
- package/src/codemode/__tests__/sandbox-factory.test.ts +158 -0
- package/src/codemode/__tests__/sandbox.test.ts +301 -0
- package/src/codemode/__tests__/security.test.ts +368 -0
- package/src/codemode/__tests__/worker-sandbox.test.ts +179 -0
- package/src/codemode/__tests__/worker-script.test.ts +226 -0
- package/src/codemode/api.ts +89 -5
- package/src/codemode/sandbox-factory.ts +1 -1
- package/src/codemode/types.ts +34 -0
- package/src/codemode/worker-sandbox.ts +74 -7
- package/src/codemode/worker-script.ts +157 -86
- package/src/constants/ServerInstructions.ts +37 -31
- package/src/filtering/ToolConstants.ts +1 -2
- package/src/filtering/__tests__/ToolFilter.test.ts +9 -9
- package/src/pool/ConnectionPool.ts +4 -1
- package/src/transports/__tests__/http.test.ts +15 -3
- package/src/transports/http.ts +12 -0
- package/src/utils/validators.ts +2 -1
- package/vitest.config.ts +3 -1
- package/CODE_MODE.md +0 -245
|
@@ -143,9 +143,11 @@ describe("Handler Execution", () => {
|
|
|
143
143
|
it("should reject invalid collection names", async () => {
|
|
144
144
|
const tool = tools.find((t) => t.name === "mysql_doc_create_collection")!;
|
|
145
145
|
|
|
146
|
-
await
|
|
147
|
-
|
|
148
|
-
|
|
146
|
+
const result = await tool.handler({ name: "invalid-name" }, mockContext);
|
|
147
|
+
expect(result).toEqual({
|
|
148
|
+
success: false,
|
|
149
|
+
error: "Invalid collection name",
|
|
150
|
+
});
|
|
149
151
|
});
|
|
150
152
|
|
|
151
153
|
it("should add validation when specified", async () => {
|
|
@@ -175,7 +177,9 @@ describe("Handler Execution", () => {
|
|
|
175
177
|
});
|
|
176
178
|
|
|
177
179
|
it("should support ifNotExists parameter", async () => {
|
|
178
|
-
mockAdapter.executeQuery
|
|
180
|
+
mockAdapter.executeQuery
|
|
181
|
+
.mockResolvedValueOnce(createMockQueryResult([])) // checkCollectionExists → false
|
|
182
|
+
.mockResolvedValue(createMockQueryResult([])); // CREATE TABLE succeeds
|
|
179
183
|
|
|
180
184
|
const tool = tools.find((t) => t.name === "mysql_doc_create_collection")!;
|
|
181
185
|
await tool.handler(
|
|
@@ -183,8 +187,30 @@ describe("Handler Execution", () => {
|
|
|
183
187
|
mockContext,
|
|
184
188
|
);
|
|
185
189
|
|
|
186
|
-
const
|
|
187
|
-
|
|
190
|
+
const calls = mockAdapter.executeQuery.mock.calls;
|
|
191
|
+
const createCall = calls[calls.length - 1][0] as string;
|
|
192
|
+
expect(createCall).toContain("CREATE TABLE IF NOT EXISTS");
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it("should return skipped when collection already exists with ifNotExists", async () => {
|
|
196
|
+
mockAdapter.executeQuery.mockResolvedValueOnce(
|
|
197
|
+
createMockQueryResult([{ "1": 1 }]), // checkCollectionExists → true
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
const tool = tools.find((t) => t.name === "mysql_doc_create_collection")!;
|
|
201
|
+
const result = await tool.handler(
|
|
202
|
+
{ name: "my_collection", ifNotExists: true },
|
|
203
|
+
mockContext,
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
expect(result).toEqual({
|
|
207
|
+
success: true,
|
|
208
|
+
skipped: true,
|
|
209
|
+
collection: "my_collection",
|
|
210
|
+
reason: "Collection already exists",
|
|
211
|
+
});
|
|
212
|
+
// Should NOT have called CREATE TABLE
|
|
213
|
+
expect(mockAdapter.executeQuery).toHaveBeenCalledTimes(1);
|
|
188
214
|
});
|
|
189
215
|
|
|
190
216
|
it("should not use IF NOT EXISTS by default", async () => {
|
|
@@ -194,7 +220,8 @@ describe("Handler Execution", () => {
|
|
|
194
220
|
await tool.handler({ name: "my_collection" }, mockContext);
|
|
195
221
|
|
|
196
222
|
const call = mockAdapter.executeQuery.mock.calls[0][0] as string;
|
|
197
|
-
expect(call).toContain("CREATE TABLE
|
|
223
|
+
expect(call).toContain("CREATE TABLE");
|
|
224
|
+
expect(call).toContain("`my_collection`");
|
|
198
225
|
expect(call).not.toContain("IF NOT EXISTS");
|
|
199
226
|
});
|
|
200
227
|
|
|
@@ -207,14 +234,33 @@ describe("Handler Execution", () => {
|
|
|
207
234
|
const result = (await tool.handler(
|
|
208
235
|
{ name: "my_collection" },
|
|
209
236
|
mockContext,
|
|
210
|
-
)) as { success: boolean;
|
|
237
|
+
)) as { success: boolean; error: string };
|
|
211
238
|
|
|
212
239
|
expect(result).toHaveProperty("success", false);
|
|
213
240
|
expect(result).toHaveProperty(
|
|
214
|
-
"
|
|
241
|
+
"error",
|
|
215
242
|
"Collection 'my_collection' already exists",
|
|
216
243
|
);
|
|
217
244
|
});
|
|
245
|
+
|
|
246
|
+
it("should return exists: false for nonexistent schema", async () => {
|
|
247
|
+
mockAdapter.executeQuery.mockRejectedValue(
|
|
248
|
+
new Error(
|
|
249
|
+
"Query failed: Execute failed: Unknown database 'fake_schema'",
|
|
250
|
+
),
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
const tool = tools.find((t) => t.name === "mysql_doc_create_collection")!;
|
|
254
|
+
const result = await tool.handler(
|
|
255
|
+
{ name: "my_collection", schema: "fake_schema" },
|
|
256
|
+
mockContext,
|
|
257
|
+
);
|
|
258
|
+
|
|
259
|
+
expect(result).toEqual({
|
|
260
|
+
exists: false,
|
|
261
|
+
schema: "fake_schema",
|
|
262
|
+
});
|
|
263
|
+
});
|
|
218
264
|
});
|
|
219
265
|
|
|
220
266
|
describe("mysql_doc_drop_collection", () => {
|
|
@@ -260,9 +306,14 @@ describe("Handler Execution", () => {
|
|
|
260
306
|
|
|
261
307
|
it("should reject invalid collection names", async () => {
|
|
262
308
|
const tool = tools.find((t) => t.name === "mysql_doc_drop_collection")!;
|
|
263
|
-
await
|
|
264
|
-
|
|
265
|
-
|
|
309
|
+
const result = await tool.handler(
|
|
310
|
+
{ name: "bad;drop table users" },
|
|
311
|
+
mockContext,
|
|
312
|
+
);
|
|
313
|
+
expect(result).toEqual({
|
|
314
|
+
success: false,
|
|
315
|
+
error: "Invalid collection name",
|
|
316
|
+
});
|
|
266
317
|
});
|
|
267
318
|
|
|
268
319
|
it("should return graceful error when collection does not exist", async () => {
|
|
@@ -274,20 +325,34 @@ describe("Handler Execution", () => {
|
|
|
274
325
|
const result = (await tool.handler(
|
|
275
326
|
{ name: "nonexistent", ifExists: false },
|
|
276
327
|
mockContext,
|
|
277
|
-
)) as { success: boolean;
|
|
328
|
+
)) as { success: boolean; error: string };
|
|
278
329
|
|
|
279
330
|
expect(result).toHaveProperty("success", false);
|
|
280
331
|
expect(result).toHaveProperty(
|
|
281
|
-
"
|
|
332
|
+
"error",
|
|
282
333
|
"Collection 'nonexistent' does not exist",
|
|
283
334
|
);
|
|
284
335
|
});
|
|
336
|
+
|
|
337
|
+
it("should return exists: false for nonexistent schema", async () => {
|
|
338
|
+
mockAdapter.executeQuery.mockResolvedValueOnce(createMockQueryResult([])); // schema does not exist
|
|
339
|
+
|
|
340
|
+
const tool = tools.find((t) => t.name === "mysql_doc_drop_collection")!;
|
|
341
|
+
const result = await tool.handler(
|
|
342
|
+
{ name: "users", schema: "nonexistent_schema" },
|
|
343
|
+
mockContext,
|
|
344
|
+
);
|
|
345
|
+
|
|
346
|
+
expect(mockAdapter.executeQuery).toHaveBeenCalledTimes(1);
|
|
347
|
+
expect(result).toEqual({
|
|
348
|
+
exists: false,
|
|
349
|
+
schema: "nonexistent_schema",
|
|
350
|
+
});
|
|
351
|
+
});
|
|
285
352
|
});
|
|
286
353
|
|
|
287
354
|
describe("mysql_doc_find", () => {
|
|
288
|
-
it("should query documents with
|
|
289
|
-
// First call: collection existence check
|
|
290
|
-
// Second call: actual document query
|
|
355
|
+
it("should query documents with valid filter", async () => {
|
|
291
356
|
mockAdapter.executeQuery
|
|
292
357
|
.mockResolvedValueOnce(createMockQueryResult([{ "1": 1 }])) // collection exists
|
|
293
358
|
.mockResolvedValueOnce(
|
|
@@ -298,19 +363,86 @@ describe("Handler Execution", () => {
|
|
|
298
363
|
const result = await tool.handler(
|
|
299
364
|
{
|
|
300
365
|
collection: "users",
|
|
301
|
-
filter: "$.age
|
|
366
|
+
filter: "$.age",
|
|
302
367
|
},
|
|
303
368
|
mockContext,
|
|
304
369
|
);
|
|
305
370
|
|
|
306
371
|
expect(mockAdapter.executeQuery).toHaveBeenCalledTimes(2);
|
|
307
372
|
const call = mockAdapter.executeQuery.mock.calls[1][0] as string;
|
|
308
|
-
expect(call).toContain(
|
|
309
|
-
"WHERE JSON_EXTRACT(doc, '$.age > 20') IS NOT NULL",
|
|
310
|
-
);
|
|
373
|
+
expect(call).toContain("WHERE JSON_EXTRACT(doc, '$.age') IS NOT NULL");
|
|
311
374
|
expect(result).toHaveProperty("documents");
|
|
312
375
|
});
|
|
313
376
|
|
|
377
|
+
it("should reject SQL injection in filter", async () => {
|
|
378
|
+
mockAdapter.executeQuery.mockResolvedValueOnce(
|
|
379
|
+
createMockQueryResult([{ "1": 1 }]),
|
|
380
|
+
); // collection exists
|
|
381
|
+
|
|
382
|
+
const tool = tools.find((t) => t.name === "mysql_doc_find")!;
|
|
383
|
+
const result = await tool.handler(
|
|
384
|
+
{
|
|
385
|
+
collection: "users",
|
|
386
|
+
filter: "$') IS NOT NULL OR 1=1 -- ",
|
|
387
|
+
},
|
|
388
|
+
mockContext,
|
|
389
|
+
);
|
|
390
|
+
|
|
391
|
+
expect(result).toHaveProperty("success", false);
|
|
392
|
+
expect(result).toHaveProperty("error");
|
|
393
|
+
// Should NOT have executed the document query
|
|
394
|
+
expect(mockAdapter.executeQuery).toHaveBeenCalledTimes(1);
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
it("should reject invalid JSON path in filter", async () => {
|
|
398
|
+
mockAdapter.executeQuery.mockResolvedValueOnce(
|
|
399
|
+
createMockQueryResult([{ "1": 1 }]),
|
|
400
|
+
); // collection exists
|
|
401
|
+
|
|
402
|
+
const tool = tools.find((t) => t.name === "mysql_doc_find")!;
|
|
403
|
+
const result = await tool.handler(
|
|
404
|
+
{
|
|
405
|
+
collection: "users",
|
|
406
|
+
filter: "$.age > 20",
|
|
407
|
+
},
|
|
408
|
+
mockContext,
|
|
409
|
+
);
|
|
410
|
+
|
|
411
|
+
expect(result).toHaveProperty("success", false);
|
|
412
|
+
expect(result).toHaveProperty("error");
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
it("should use schema parameter for collection lookup", async () => {
|
|
416
|
+
mockAdapter.executeQuery
|
|
417
|
+
.mockResolvedValueOnce(
|
|
418
|
+
createMockQueryResult([{ SCHEMA_NAME: "otherdb" }]),
|
|
419
|
+
) // schema exists
|
|
420
|
+
.mockResolvedValueOnce(createMockQueryResult([{ "1": 1 }])) // collection exists
|
|
421
|
+
.mockResolvedValueOnce(createMockQueryResult([]));
|
|
422
|
+
|
|
423
|
+
const tool = tools.find((t) => t.name === "mysql_doc_find")!;
|
|
424
|
+
await tool.handler(
|
|
425
|
+
{ collection: "my_coll", schema: "otherdb" },
|
|
426
|
+
mockContext,
|
|
427
|
+
);
|
|
428
|
+
|
|
429
|
+
// First call: schema existence check
|
|
430
|
+
expect(mockAdapter.executeQuery).toHaveBeenNthCalledWith(
|
|
431
|
+
1,
|
|
432
|
+
expect.stringContaining("SCHEMATA"),
|
|
433
|
+
["otherdb"],
|
|
434
|
+
);
|
|
435
|
+
// Second call: collection existence check with schema
|
|
436
|
+
expect(mockAdapter.executeQuery).toHaveBeenNthCalledWith(
|
|
437
|
+
2,
|
|
438
|
+
expect.any(String),
|
|
439
|
+
["otherdb", "my_coll"],
|
|
440
|
+
);
|
|
441
|
+
// Query should use qualified table ref
|
|
442
|
+
const queryCall = mockAdapter.executeQuery.mock.calls[2][0] as string;
|
|
443
|
+
expect(queryCall).toContain("`otherdb`.`my_coll`");
|
|
444
|
+
});
|
|
445
|
+
|
|
314
446
|
it("should return exists: false without error field for nonexistent collection", async () => {
|
|
315
447
|
mockAdapter.executeQuery.mockResolvedValueOnce(createMockQueryResult([])); // collection does not exist
|
|
316
448
|
|
|
@@ -386,9 +518,14 @@ describe("Handler Execution", () => {
|
|
|
386
518
|
|
|
387
519
|
it("should validate collection name", async () => {
|
|
388
520
|
const tool = tools.find((t) => t.name === "mysql_doc_find")!;
|
|
389
|
-
await
|
|
390
|
-
|
|
391
|
-
|
|
521
|
+
const result = await tool.handler(
|
|
522
|
+
{ collection: "invalid-name; --" },
|
|
523
|
+
mockContext,
|
|
524
|
+
);
|
|
525
|
+
expect(result).toEqual({
|
|
526
|
+
success: false,
|
|
527
|
+
error: "Invalid collection name",
|
|
528
|
+
});
|
|
392
529
|
});
|
|
393
530
|
|
|
394
531
|
it("should return graceful response when collection does not exist", async () => {
|
|
@@ -410,6 +547,22 @@ describe("Handler Execution", () => {
|
|
|
410
547
|
expect(result).not.toHaveProperty("error");
|
|
411
548
|
expect(mockAdapter.executeQuery).toHaveBeenCalledTimes(1);
|
|
412
549
|
});
|
|
550
|
+
|
|
551
|
+
it("should return exists: false for nonexistent schema", async () => {
|
|
552
|
+
mockAdapter.executeQuery.mockResolvedValueOnce(createMockQueryResult([])); // schema does not exist
|
|
553
|
+
|
|
554
|
+
const tool = tools.find((t) => t.name === "mysql_doc_find")!;
|
|
555
|
+
const result = await tool.handler(
|
|
556
|
+
{ collection: "users", schema: "nonexistent_schema" },
|
|
557
|
+
mockContext,
|
|
558
|
+
);
|
|
559
|
+
|
|
560
|
+
expect(mockAdapter.executeQuery).toHaveBeenCalledTimes(1);
|
|
561
|
+
expect(result).toEqual({
|
|
562
|
+
exists: false,
|
|
563
|
+
schema: "nonexistent_schema",
|
|
564
|
+
});
|
|
565
|
+
});
|
|
413
566
|
});
|
|
414
567
|
|
|
415
568
|
describe("mysql_doc_add", () => {
|
|
@@ -454,15 +607,17 @@ describe("Handler Execution", () => {
|
|
|
454
607
|
|
|
455
608
|
it("should reject invalid collection names", async () => {
|
|
456
609
|
const tool = tools.find((t) => t.name === "mysql_doc_add")!;
|
|
457
|
-
await
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
610
|
+
const result = await tool.handler(
|
|
611
|
+
{
|
|
612
|
+
collection: "invalid-name",
|
|
613
|
+
documents: [{ name: "test" }],
|
|
614
|
+
},
|
|
615
|
+
mockContext,
|
|
616
|
+
);
|
|
617
|
+
expect(result).toEqual({
|
|
618
|
+
success: false,
|
|
619
|
+
error: "Invalid collection name",
|
|
620
|
+
});
|
|
466
621
|
});
|
|
467
622
|
|
|
468
623
|
it("should return graceful response when collection does not exist", async () => {
|
|
@@ -481,6 +636,61 @@ describe("Handler Execution", () => {
|
|
|
481
636
|
expect(result).toHaveProperty("collection", "nonexistent");
|
|
482
637
|
expect(mockAdapter.executeQuery).toHaveBeenCalledTimes(1);
|
|
483
638
|
});
|
|
639
|
+
|
|
640
|
+
it("should return exists: false for nonexistent schema", async () => {
|
|
641
|
+
mockAdapter.executeQuery.mockResolvedValueOnce(createMockQueryResult([])); // schema does not exist
|
|
642
|
+
|
|
643
|
+
const tool = tools.find((t) => t.name === "mysql_doc_add")!;
|
|
644
|
+
const result = await tool.handler(
|
|
645
|
+
{
|
|
646
|
+
collection: "users",
|
|
647
|
+
schema: "nonexistent_schema",
|
|
648
|
+
documents: [{ name: "test" }],
|
|
649
|
+
},
|
|
650
|
+
mockContext,
|
|
651
|
+
);
|
|
652
|
+
|
|
653
|
+
expect(mockAdapter.executeQuery).toHaveBeenCalledTimes(1);
|
|
654
|
+
expect(result).toEqual({
|
|
655
|
+
exists: false,
|
|
656
|
+
schema: "nonexistent_schema",
|
|
657
|
+
});
|
|
658
|
+
});
|
|
659
|
+
|
|
660
|
+
it("should use schema parameter for collection lookup", async () => {
|
|
661
|
+
mockAdapter.executeQuery
|
|
662
|
+
.mockResolvedValueOnce(
|
|
663
|
+
createMockQueryResult([{ SCHEMA_NAME: "otherdb" }]),
|
|
664
|
+
) // schema exists
|
|
665
|
+
.mockResolvedValueOnce(createMockQueryResult([{ "1": 1 }])) // collection exists
|
|
666
|
+
.mockResolvedValue(createMockQueryResult([]));
|
|
667
|
+
|
|
668
|
+
const tool = tools.find((t) => t.name === "mysql_doc_add")!;
|
|
669
|
+
await tool.handler(
|
|
670
|
+
{
|
|
671
|
+
collection: "my_coll",
|
|
672
|
+
schema: "otherdb",
|
|
673
|
+
documents: [{ name: "test" }],
|
|
674
|
+
},
|
|
675
|
+
mockContext,
|
|
676
|
+
);
|
|
677
|
+
|
|
678
|
+
// First call: schema existence check
|
|
679
|
+
expect(mockAdapter.executeQuery).toHaveBeenNthCalledWith(
|
|
680
|
+
1,
|
|
681
|
+
expect.stringContaining("SCHEMATA"),
|
|
682
|
+
["otherdb"],
|
|
683
|
+
);
|
|
684
|
+
// Second call: collection existence check with schema
|
|
685
|
+
expect(mockAdapter.executeQuery).toHaveBeenNthCalledWith(
|
|
686
|
+
2,
|
|
687
|
+
expect.any(String),
|
|
688
|
+
["otherdb", "my_coll"],
|
|
689
|
+
);
|
|
690
|
+
// Insert should use qualified table ref
|
|
691
|
+
const insertCall = mockAdapter.executeQuery.mock.calls[2][0] as string;
|
|
692
|
+
expect(insertCall).toContain("`otherdb`.`my_coll`");
|
|
693
|
+
});
|
|
484
694
|
});
|
|
485
695
|
|
|
486
696
|
describe("mysql_doc_modify", () => {
|
|
@@ -546,32 +756,36 @@ describe("Handler Execution", () => {
|
|
|
546
756
|
expect(call).toContain("UPDATE `users` SET");
|
|
547
757
|
});
|
|
548
758
|
|
|
549
|
-
it("should
|
|
759
|
+
it("should return error if no modifications specified", async () => {
|
|
550
760
|
const tool = tools.find((t) => t.name === "mysql_doc_modify")!;
|
|
551
761
|
|
|
552
|
-
await
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
762
|
+
const result = await tool.handler(
|
|
763
|
+
{
|
|
764
|
+
collection: "users",
|
|
765
|
+
filter: "$.active",
|
|
766
|
+
},
|
|
767
|
+
mockContext,
|
|
768
|
+
);
|
|
769
|
+
expect(result).toEqual({
|
|
770
|
+
success: false,
|
|
771
|
+
error: "No modifications specified",
|
|
772
|
+
});
|
|
561
773
|
});
|
|
562
774
|
|
|
563
775
|
it("should reject invalid collection names", async () => {
|
|
564
776
|
const tool = tools.find((t) => t.name === "mysql_doc_modify")!;
|
|
565
|
-
await
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
777
|
+
const result = await tool.handler(
|
|
778
|
+
{
|
|
779
|
+
collection: "invalid-name",
|
|
780
|
+
filter: "$.id",
|
|
781
|
+
set: { a: 1 },
|
|
782
|
+
},
|
|
783
|
+
mockContext,
|
|
784
|
+
);
|
|
785
|
+
expect(result).toEqual({
|
|
786
|
+
success: false,
|
|
787
|
+
error: "Invalid collection name",
|
|
788
|
+
});
|
|
575
789
|
});
|
|
576
790
|
|
|
577
791
|
it("should return graceful response when collection does not exist", async () => {
|
|
@@ -591,6 +805,50 @@ describe("Handler Execution", () => {
|
|
|
591
805
|
expect(result).toHaveProperty("collection", "nonexistent");
|
|
592
806
|
expect(mockAdapter.executeQuery).toHaveBeenCalledTimes(1);
|
|
593
807
|
});
|
|
808
|
+
|
|
809
|
+
it("should return exists: false for nonexistent schema", async () => {
|
|
810
|
+
mockAdapter.executeQuery.mockResolvedValueOnce(createMockQueryResult([])); // schema does not exist
|
|
811
|
+
|
|
812
|
+
const tool = tools.find((t) => t.name === "mysql_doc_modify")!;
|
|
813
|
+
const result = await tool.handler(
|
|
814
|
+
{
|
|
815
|
+
collection: "users",
|
|
816
|
+
schema: "nonexistent_schema",
|
|
817
|
+
filter: "$.name",
|
|
818
|
+
set: { status: "active" },
|
|
819
|
+
},
|
|
820
|
+
mockContext,
|
|
821
|
+
);
|
|
822
|
+
|
|
823
|
+
expect(mockAdapter.executeQuery).toHaveBeenCalledTimes(1);
|
|
824
|
+
expect(result).toEqual({
|
|
825
|
+
exists: false,
|
|
826
|
+
schema: "nonexistent_schema",
|
|
827
|
+
});
|
|
828
|
+
});
|
|
829
|
+
|
|
830
|
+
it("should use schema parameter for collection lookup", async () => {
|
|
831
|
+
mockAdapter.executeQuery
|
|
832
|
+
.mockResolvedValueOnce(
|
|
833
|
+
createMockQueryResult([{ SCHEMA_NAME: "otherdb" }]),
|
|
834
|
+
) // schema exists
|
|
835
|
+
.mockResolvedValueOnce(createMockQueryResult([{ "1": 1 }])) // collection exists
|
|
836
|
+
.mockResolvedValueOnce(createMockQueryResult([], 2));
|
|
837
|
+
|
|
838
|
+
const tool = tools.find((t) => t.name === "mysql_doc_modify")!;
|
|
839
|
+
await tool.handler(
|
|
840
|
+
{
|
|
841
|
+
collection: "my_coll",
|
|
842
|
+
schema: "otherdb",
|
|
843
|
+
filter: "$.name",
|
|
844
|
+
set: { status: "active" },
|
|
845
|
+
},
|
|
846
|
+
mockContext,
|
|
847
|
+
);
|
|
848
|
+
|
|
849
|
+
const updateCall = mockAdapter.executeQuery.mock.calls[2][0] as string;
|
|
850
|
+
expect(updateCall).toContain("`otherdb`.`my_coll`");
|
|
851
|
+
});
|
|
594
852
|
});
|
|
595
853
|
|
|
596
854
|
describe("mysql_doc_remove", () => {
|
|
@@ -617,15 +875,17 @@ describe("Handler Execution", () => {
|
|
|
617
875
|
|
|
618
876
|
it("should reject invalid collection names", async () => {
|
|
619
877
|
const tool = tools.find((t) => t.name === "mysql_doc_remove")!;
|
|
620
|
-
await
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
878
|
+
const result = await tool.handler(
|
|
879
|
+
{
|
|
880
|
+
collection: "invalid-name",
|
|
881
|
+
filter: "$.id",
|
|
882
|
+
},
|
|
883
|
+
mockContext,
|
|
884
|
+
);
|
|
885
|
+
expect(result).toEqual({
|
|
886
|
+
success: false,
|
|
887
|
+
error: "Invalid collection name",
|
|
888
|
+
});
|
|
629
889
|
});
|
|
630
890
|
|
|
631
891
|
it("should return graceful response when collection does not exist", async () => {
|
|
@@ -644,6 +904,48 @@ describe("Handler Execution", () => {
|
|
|
644
904
|
expect(result).toHaveProperty("collection", "nonexistent");
|
|
645
905
|
expect(mockAdapter.executeQuery).toHaveBeenCalledTimes(1);
|
|
646
906
|
});
|
|
907
|
+
|
|
908
|
+
it("should return exists: false for nonexistent schema", async () => {
|
|
909
|
+
mockAdapter.executeQuery.mockResolvedValueOnce(createMockQueryResult([])); // schema does not exist
|
|
910
|
+
|
|
911
|
+
const tool = tools.find((t) => t.name === "mysql_doc_remove")!;
|
|
912
|
+
const result = await tool.handler(
|
|
913
|
+
{
|
|
914
|
+
collection: "users",
|
|
915
|
+
schema: "nonexistent_schema",
|
|
916
|
+
filter: "$.id",
|
|
917
|
+
},
|
|
918
|
+
mockContext,
|
|
919
|
+
);
|
|
920
|
+
|
|
921
|
+
expect(mockAdapter.executeQuery).toHaveBeenCalledTimes(1);
|
|
922
|
+
expect(result).toEqual({
|
|
923
|
+
exists: false,
|
|
924
|
+
schema: "nonexistent_schema",
|
|
925
|
+
});
|
|
926
|
+
});
|
|
927
|
+
|
|
928
|
+
it("should use schema parameter for collection lookup", async () => {
|
|
929
|
+
mockAdapter.executeQuery
|
|
930
|
+
.mockResolvedValueOnce(
|
|
931
|
+
createMockQueryResult([{ SCHEMA_NAME: "otherdb" }]),
|
|
932
|
+
) // schema exists
|
|
933
|
+
.mockResolvedValueOnce(createMockQueryResult([{ "1": 1 }])) // collection exists
|
|
934
|
+
.mockResolvedValueOnce(createMockQueryResult([], 1));
|
|
935
|
+
|
|
936
|
+
const tool = tools.find((t) => t.name === "mysql_doc_remove")!;
|
|
937
|
+
await tool.handler(
|
|
938
|
+
{
|
|
939
|
+
collection: "my_coll",
|
|
940
|
+
schema: "otherdb",
|
|
941
|
+
filter: "$.name",
|
|
942
|
+
},
|
|
943
|
+
mockContext,
|
|
944
|
+
);
|
|
945
|
+
|
|
946
|
+
const deleteCall = mockAdapter.executeQuery.mock.calls[2][0] as string;
|
|
947
|
+
expect(deleteCall).toContain("`otherdb`.`my_coll`");
|
|
948
|
+
});
|
|
647
949
|
});
|
|
648
950
|
|
|
649
951
|
describe("mysql_doc_create_index", () => {
|
|
@@ -719,30 +1021,31 @@ describe("Handler Execution", () => {
|
|
|
719
1021
|
|
|
720
1022
|
it("should reject invalid collection names", async () => {
|
|
721
1023
|
const tool = tools.find((t) => t.name === "mysql_doc_create_index")!;
|
|
722
|
-
await
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
1024
|
+
const result = await tool.handler(
|
|
1025
|
+
{
|
|
1026
|
+
collection: "invalid-name",
|
|
1027
|
+
name: "index",
|
|
1028
|
+
fields: [{ path: "email", type: "TEXT" }],
|
|
1029
|
+
},
|
|
1030
|
+
mockContext,
|
|
1031
|
+
);
|
|
1032
|
+
expect(result).toEqual({
|
|
1033
|
+
success: false,
|
|
1034
|
+
error: "Invalid collection name",
|
|
1035
|
+
});
|
|
732
1036
|
});
|
|
733
1037
|
|
|
734
1038
|
it("should reject invalid index names", async () => {
|
|
735
1039
|
const tool = tools.find((t) => t.name === "mysql_doc_create_index")!;
|
|
736
|
-
await
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
).rejects.toThrow("Invalid index name");
|
|
1040
|
+
const result = await tool.handler(
|
|
1041
|
+
{
|
|
1042
|
+
collection: "valid_coll",
|
|
1043
|
+
name: "invalid-index",
|
|
1044
|
+
fields: [{ path: "email", type: "TEXT" }],
|
|
1045
|
+
},
|
|
1046
|
+
mockContext,
|
|
1047
|
+
);
|
|
1048
|
+
expect(result).toEqual({ success: false, error: "Invalid index name" });
|
|
746
1049
|
});
|
|
747
1050
|
|
|
748
1051
|
it("should return graceful response when collection does not exist", async () => {
|
|
@@ -763,6 +1066,53 @@ describe("Handler Execution", () => {
|
|
|
763
1066
|
expect(mockAdapter.executeQuery).toHaveBeenCalledTimes(1);
|
|
764
1067
|
});
|
|
765
1068
|
|
|
1069
|
+
it("should return exists: false for nonexistent schema", async () => {
|
|
1070
|
+
mockAdapter.executeQuery.mockResolvedValueOnce(createMockQueryResult([])); // schema does not exist
|
|
1071
|
+
|
|
1072
|
+
const tool = tools.find((t) => t.name === "mysql_doc_create_index")!;
|
|
1073
|
+
const result = await tool.handler(
|
|
1074
|
+
{
|
|
1075
|
+
collection: "users",
|
|
1076
|
+
schema: "nonexistent_schema",
|
|
1077
|
+
name: "idx_test",
|
|
1078
|
+
fields: [{ path: "email", type: "TEXT" }],
|
|
1079
|
+
},
|
|
1080
|
+
mockContext,
|
|
1081
|
+
);
|
|
1082
|
+
|
|
1083
|
+
expect(mockAdapter.executeQuery).toHaveBeenCalledTimes(1);
|
|
1084
|
+
expect(result).toEqual({
|
|
1085
|
+
exists: false,
|
|
1086
|
+
schema: "nonexistent_schema",
|
|
1087
|
+
});
|
|
1088
|
+
});
|
|
1089
|
+
|
|
1090
|
+
it("should use schema parameter for collection lookup", async () => {
|
|
1091
|
+
mockAdapter.executeQuery
|
|
1092
|
+
.mockResolvedValueOnce(
|
|
1093
|
+
createMockQueryResult([{ SCHEMA_NAME: "otherdb" }]),
|
|
1094
|
+
) // schema exists
|
|
1095
|
+
.mockResolvedValueOnce(createMockQueryResult([{ "1": 1 }])) // collection exists
|
|
1096
|
+
.mockResolvedValue(createMockQueryResult([]));
|
|
1097
|
+
|
|
1098
|
+
const tool = tools.find((t) => t.name === "mysql_doc_create_index")!;
|
|
1099
|
+
await tool.handler(
|
|
1100
|
+
{
|
|
1101
|
+
collection: "my_coll",
|
|
1102
|
+
schema: "otherdb",
|
|
1103
|
+
name: "idx_name",
|
|
1104
|
+
fields: [{ path: "name", type: "TEXT" }],
|
|
1105
|
+
},
|
|
1106
|
+
mockContext,
|
|
1107
|
+
);
|
|
1108
|
+
|
|
1109
|
+
// ALTER TABLE and CREATE INDEX should use qualified table ref
|
|
1110
|
+
const alterCall = mockAdapter.executeQuery.mock.calls[2][0] as string;
|
|
1111
|
+
expect(alterCall).toContain("`otherdb`.`my_coll`");
|
|
1112
|
+
const indexCall = mockAdapter.executeQuery.mock.calls[3][0] as string;
|
|
1113
|
+
expect(indexCall).toContain("`otherdb`.`my_coll`");
|
|
1114
|
+
});
|
|
1115
|
+
|
|
766
1116
|
it("should return graceful error on duplicate column", async () => {
|
|
767
1117
|
mockAdapter.executeQuery
|
|
768
1118
|
.mockResolvedValueOnce(createMockQueryResult([{ "1": 1 }])) // collection exists
|
|
@@ -776,10 +1126,10 @@ describe("Handler Execution", () => {
|
|
|
776
1126
|
fields: [{ path: "email", type: "TEXT" }],
|
|
777
1127
|
},
|
|
778
1128
|
mockContext,
|
|
779
|
-
)) as { success: boolean;
|
|
1129
|
+
)) as { success: boolean; error: string };
|
|
780
1130
|
|
|
781
1131
|
expect(result).toHaveProperty("success", false);
|
|
782
|
-
expect(result.
|
|
1132
|
+
expect(result.error).toContain("already exist");
|
|
783
1133
|
});
|
|
784
1134
|
});
|
|
785
1135
|
|
|
@@ -806,13 +1156,18 @@ describe("Handler Execution", () => {
|
|
|
806
1156
|
|
|
807
1157
|
it("should reject invalid collection names", async () => {
|
|
808
1158
|
const tool = tools.find((t) => t.name === "mysql_doc_collection_info")!;
|
|
809
|
-
await
|
|
810
|
-
|
|
811
|
-
|
|
1159
|
+
const result = await tool.handler(
|
|
1160
|
+
{ collection: "invalid-nam$" },
|
|
1161
|
+
mockContext,
|
|
1162
|
+
);
|
|
1163
|
+
expect(result).toEqual({
|
|
1164
|
+
success: false,
|
|
1165
|
+
error: "Invalid collection name",
|
|
1166
|
+
});
|
|
812
1167
|
});
|
|
813
1168
|
|
|
814
1169
|
it("should return graceful response when collection does not exist", async () => {
|
|
815
|
-
mockAdapter.executeQuery.mockResolvedValueOnce(createMockQueryResult([])); // collection does not exist
|
|
1170
|
+
mockAdapter.executeQuery.mockResolvedValueOnce(createMockQueryResult([])); // collection does not exist (no schema → skip schema check)
|
|
816
1171
|
|
|
817
1172
|
const tool = tools.find((t) => t.name === "mysql_doc_collection_info")!;
|
|
818
1173
|
const result = (await tool.handler(
|
|
@@ -824,5 +1179,21 @@ describe("Handler Execution", () => {
|
|
|
824
1179
|
expect(result).toHaveProperty("collection", "nonexistent");
|
|
825
1180
|
expect(mockAdapter.executeQuery).toHaveBeenCalledTimes(1);
|
|
826
1181
|
});
|
|
1182
|
+
|
|
1183
|
+
it("should return exists: false for nonexistent schema", async () => {
|
|
1184
|
+
mockAdapter.executeQuery.mockResolvedValueOnce(createMockQueryResult([])); // schema does not exist
|
|
1185
|
+
|
|
1186
|
+
const tool = tools.find((t) => t.name === "mysql_doc_collection_info")!;
|
|
1187
|
+
const result = await tool.handler(
|
|
1188
|
+
{ collection: "users", schema: "nonexistent_schema" },
|
|
1189
|
+
mockContext,
|
|
1190
|
+
);
|
|
1191
|
+
|
|
1192
|
+
expect(mockAdapter.executeQuery).toHaveBeenCalledTimes(1);
|
|
1193
|
+
expect(result).toEqual({
|
|
1194
|
+
exists: false,
|
|
1195
|
+
schema: "nonexistent_schema",
|
|
1196
|
+
});
|
|
1197
|
+
});
|
|
827
1198
|
});
|
|
828
1199
|
});
|