db-mcp 1.1.1 → 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/README.md +247 -169
- package/dist/.tsbuildinfo +1 -0
- package/dist/adapters/database-adapter.d.ts +173 -0
- package/dist/adapters/database-adapter.d.ts.map +1 -0
- package/dist/adapters/query-validation.d.ts +20 -0
- package/dist/adapters/query-validation.d.ts.map +1 -0
- package/dist/adapters/registration/index.d.ts +4 -0
- package/dist/adapters/registration/index.d.ts.map +1 -0
- package/dist/adapters/registration/prompts.d.ts +7 -0
- package/dist/adapters/registration/prompts.d.ts.map +1 -0
- package/dist/adapters/registration/resources.d.ts +7 -0
- package/dist/adapters/registration/resources.d.ts.map +1 -0
- package/dist/adapters/registration/tools.d.ts +9 -0
- package/dist/adapters/registration/tools.d.ts.map +1 -0
- package/dist/adapters/sqlite/index.d.ts +9 -0
- package/dist/adapters/sqlite/index.d.ts.map +1 -0
- package/dist/adapters/sqlite/json-utils.d.ts +100 -0
- package/dist/adapters/sqlite/json-utils.d.ts.map +1 -0
- package/dist/adapters/sqlite/prompts/analysis.d.ts +23 -0
- package/dist/adapters/sqlite/prompts/analysis.d.ts.map +1 -0
- package/dist/adapters/sqlite/prompts/index.d.ts +16 -0
- package/dist/adapters/sqlite/prompts/index.d.ts.map +1 -0
- package/dist/adapters/sqlite/prompts/query.d.ts +19 -0
- package/dist/adapters/sqlite/prompts/query.d.ts.map +1 -0
- package/dist/adapters/sqlite/prompts/schema.d.ts +20 -0
- package/dist/adapters/sqlite/prompts/schema.d.ts.map +1 -0
- package/dist/adapters/sqlite/query-executor.d.ts +38 -0
- package/dist/adapters/sqlite/query-executor.d.ts.map +1 -0
- package/dist/adapters/sqlite/resources.d.ts +13 -0
- package/dist/adapters/sqlite/resources.d.ts.map +1 -0
- package/dist/adapters/sqlite/schema-manager.d.ts +69 -0
- package/dist/adapters/sqlite/schema-manager.d.ts.map +1 -0
- package/dist/adapters/sqlite/schemas/admin.d.ts +459 -0
- package/dist/adapters/sqlite/schemas/admin.d.ts.map +1 -0
- package/dist/adapters/sqlite/schemas/codemode.d.ts +30 -0
- package/dist/adapters/sqlite/schemas/codemode.d.ts.map +1 -0
- package/dist/adapters/sqlite/schemas/common.d.ts +9 -0
- package/dist/adapters/sqlite/schemas/common.d.ts.map +1 -0
- package/dist/adapters/sqlite/schemas/core.d.ts +530 -0
- package/dist/adapters/sqlite/schemas/core.d.ts.map +1 -0
- package/dist/adapters/sqlite/schemas/error-mixin.d.ts +10 -0
- package/dist/adapters/sqlite/schemas/error-mixin.d.ts.map +1 -0
- package/dist/adapters/sqlite/schemas/fts.d.ts +106 -0
- package/dist/adapters/sqlite/schemas/fts.d.ts.map +1 -0
- package/dist/adapters/sqlite/schemas/geo.d.ts +135 -0
- package/dist/adapters/sqlite/schemas/geo.d.ts.map +1 -0
- package/dist/adapters/sqlite/schemas/index.d.ts +23 -0
- package/dist/adapters/sqlite/schemas/index.d.ts.map +1 -0
- package/dist/adapters/sqlite/schemas/introspection.d.ts +583 -0
- package/dist/adapters/sqlite/schemas/introspection.d.ts.map +1 -0
- package/dist/adapters/sqlite/schemas/json.d.ts +849 -0
- package/dist/adapters/sqlite/schemas/json.d.ts.map +1 -0
- package/dist/adapters/sqlite/schemas/migration.d.ts +220 -0
- package/dist/adapters/sqlite/schemas/migration.d.ts.map +1 -0
- package/dist/adapters/sqlite/schemas/native.d.ts +235 -0
- package/dist/adapters/sqlite/schemas/native.d.ts.map +1 -0
- package/dist/adapters/sqlite/schemas/server.d.ts +13 -0
- package/dist/adapters/sqlite/schemas/server.d.ts.map +1 -0
- package/dist/adapters/sqlite/schemas/spatialite.d.ts +114 -0
- package/dist/adapters/sqlite/schemas/spatialite.d.ts.map +1 -0
- package/dist/adapters/sqlite/schemas/stats.d.ts +780 -0
- package/dist/adapters/sqlite/schemas/stats.d.ts.map +1 -0
- package/dist/adapters/sqlite/schemas/text.d.ts +570 -0
- package/dist/adapters/sqlite/schemas/text.d.ts.map +1 -0
- package/dist/adapters/sqlite/schemas/vector.d.ts +252 -0
- package/dist/adapters/sqlite/schemas/vector.d.ts.map +1 -0
- package/dist/adapters/sqlite/schemas/virtual.d.ts +257 -0
- package/dist/adapters/sqlite/schemas/virtual.d.ts.map +1 -0
- package/dist/adapters/sqlite/schemas/where.d.ts +20 -0
- package/dist/adapters/sqlite/schemas/where.d.ts.map +1 -0
- package/dist/adapters/sqlite/sqlite-adapter/lifecycle.d.ts +13 -0
- package/dist/adapters/sqlite/sqlite-adapter/lifecycle.d.ts.map +1 -0
- package/dist/adapters/sqlite/sqlite-adapter/schema.d.ts +7 -0
- package/dist/adapters/sqlite/sqlite-adapter/schema.d.ts.map +1 -0
- package/dist/adapters/sqlite/sqlite-adapter.d.ts +138 -0
- package/dist/adapters/sqlite/sqlite-adapter.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/admin/backup/analyze.d.ts +7 -0
- package/dist/adapters/sqlite/tools/admin/backup/analyze.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/admin/backup/create.d.ts +11 -0
- package/dist/adapters/sqlite/tools/admin/backup/create.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/admin/backup/dump.d.ts +7 -0
- package/dist/adapters/sqlite/tools/admin/backup/dump.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/admin/backup/index.d.ts +7 -0
- package/dist/adapters/sqlite/tools/admin/backup/index.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/admin/backup/integrity.d.ts +7 -0
- package/dist/adapters/sqlite/tools/admin/backup/integrity.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/admin/backup/optimize.d.ts +7 -0
- package/dist/adapters/sqlite/tools/admin/backup/optimize.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/admin/backup/restore.d.ts +7 -0
- package/dist/adapters/sqlite/tools/admin/backup/restore.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/admin/helpers.d.ts +18 -0
- package/dist/adapters/sqlite/tools/admin/helpers.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/admin/index.d.ts +10 -0
- package/dist/adapters/sqlite/tools/admin/index.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/admin/pragma.d.ts +37 -0
- package/dist/adapters/sqlite/tools/admin/pragma.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/admin/reindex.d.ts +10 -0
- package/dist/adapters/sqlite/tools/admin/reindex.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/admin/verify.d.ts +13 -0
- package/dist/adapters/sqlite/tools/admin/verify.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/admin/wal.d.ts +10 -0
- package/dist/adapters/sqlite/tools/admin/wal.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/codemode.d.ts +22 -0
- package/dist/adapters/sqlite/tools/codemode.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/column-validation.d.ts +26 -0
- package/dist/adapters/sqlite/tools/column-validation.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/core/alter-table.d.ts +11 -0
- package/dist/adapters/sqlite/tools/core/alter-table.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/core/constraints.d.ts +10 -0
- package/dist/adapters/sqlite/tools/core/constraints.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/core/convenience-helpers.d.ts +20 -0
- package/dist/adapters/sqlite/tools/core/convenience-helpers.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/core/convenience-schemas.d.ts +20 -0
- package/dist/adapters/sqlite/tools/core/convenience-schemas.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/core/convenience.d.ts +29 -0
- package/dist/adapters/sqlite/tools/core/convenience.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/core/datetime.d.ts +11 -0
- package/dist/adapters/sqlite/tools/core/datetime.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/core/index.d.ts +14 -0
- package/dist/adapters/sqlite/tools/core/index.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/core/indexes.d.ts +20 -0
- package/dist/adapters/sqlite/tools/core/indexes.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/core/queries.d.ts +16 -0
- package/dist/adapters/sqlite/tools/core/queries.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/core/tables.d.ts +37 -0
- package/dist/adapters/sqlite/tools/core/tables.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/core/triggers.d.ts +18 -0
- package/dist/adapters/sqlite/tools/core/triggers.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/fts.d.ts +13 -0
- package/dist/adapters/sqlite/tools/fts.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/geo.d.ts +14 -0
- package/dist/adapters/sqlite/tools/geo.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/index.d.ts +33 -0
- package/dist/adapters/sqlite/tools/index.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/introspection/analysis/constraints.d.ts +10 -0
- package/dist/adapters/sqlite/tools/introspection/analysis/constraints.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/introspection/analysis/diff.d.ts +11 -0
- package/dist/adapters/sqlite/tools/introspection/analysis/diff.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/introspection/analysis/index.d.ts +10 -0
- package/dist/adapters/sqlite/tools/introspection/analysis/index.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/introspection/analysis/risks.d.ts +9 -0
- package/dist/adapters/sqlite/tools/introspection/analysis/risks.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/introspection/analysis/snapshot.d.ts +40 -0
- package/dist/adapters/sqlite/tools/introspection/analysis/snapshot.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/introspection/diagnostics/index.d.ts +9 -0
- package/dist/adapters/sqlite/tools/introspection/diagnostics/index.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/introspection/diagnostics/indexes.d.ts +10 -0
- package/dist/adapters/sqlite/tools/introspection/diagnostics/indexes.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/introspection/diagnostics/query-plan.d.ts +10 -0
- package/dist/adapters/sqlite/tools/introspection/diagnostics/query-plan.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/introspection/diagnostics/storage.d.ts +10 -0
- package/dist/adapters/sqlite/tools/introspection/diagnostics/storage.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/introspection/graph/helpers.d.ts +44 -0
- package/dist/adapters/sqlite/tools/introspection/graph/helpers.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/introspection/graph/index.d.ts +9 -0
- package/dist/adapters/sqlite/tools/introspection/graph/index.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/introspection/graph/tools.d.ts +12 -0
- package/dist/adapters/sqlite/tools/introspection/graph/tools.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/introspection/index.d.ts +17 -0
- package/dist/adapters/sqlite/tools/introspection/index.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/json-helpers/helpers.d.ts +21 -0
- package/dist/adapters/sqlite/tools/json-helpers/helpers.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/json-helpers/index.d.ts +17 -0
- package/dist/adapters/sqlite/tools/json-helpers/index.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/json-helpers/read.d.ts +24 -0
- package/dist/adapters/sqlite/tools/json-helpers/read.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/json-helpers/write.d.ts +24 -0
- package/dist/adapters/sqlite/tools/json-helpers/write.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/json-operations/crud.d.ts +39 -0
- package/dist/adapters/sqlite/tools/json-operations/crud.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/json-operations/diff.d.ts +11 -0
- package/dist/adapters/sqlite/tools/json-operations/diff.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/json-operations/helpers.d.ts +18 -0
- package/dist/adapters/sqlite/tools/json-operations/helpers.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/json-operations/index.d.ts +10 -0
- package/dist/adapters/sqlite/tools/json-operations/index.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/json-operations/query.d.ts +24 -0
- package/dist/adapters/sqlite/tools/json-operations/query.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/json-operations/security.d.ts +19 -0
- package/dist/adapters/sqlite/tools/json-operations/security.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/json-operations/transform.d.ts +24 -0
- package/dist/adapters/sqlite/tools/json-operations/transform.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/migration/helpers.d.ts +34 -0
- package/dist/adapters/sqlite/tools/migration/helpers.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/migration/index.d.ts +15 -0
- package/dist/adapters/sqlite/tools/migration/index.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/migration/tracking/apply.d.ts +4 -0
- package/dist/adapters/sqlite/tools/migration/tracking/apply.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/migration/tracking/history.d.ts +4 -0
- package/dist/adapters/sqlite/tools/migration/tracking/history.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/migration/tracking/index.d.ts +7 -0
- package/dist/adapters/sqlite/tools/migration/tracking/index.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/migration/tracking/init.d.ts +4 -0
- package/dist/adapters/sqlite/tools/migration/tracking/init.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/migration/tracking/record.d.ts +4 -0
- package/dist/adapters/sqlite/tools/migration/tracking/record.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/migration/tracking/rollback.d.ts +4 -0
- package/dist/adapters/sqlite/tools/migration/tracking/rollback.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/migration/tracking/status.d.ts +4 -0
- package/dist/adapters/sqlite/tools/migration/tracking/status.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/stats/advanced.d.ts +28 -0
- package/dist/adapters/sqlite/tools/stats/advanced.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/stats/anomaly-detection.d.ts +22 -0
- package/dist/adapters/sqlite/tools/stats/anomaly-detection.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/stats/basic.d.ts +32 -0
- package/dist/adapters/sqlite/tools/stats/basic.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/stats/helpers.d.ts +27 -0
- package/dist/adapters/sqlite/tools/stats/helpers.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/stats/index.d.ts +12 -0
- package/dist/adapters/sqlite/tools/stats/index.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/stats/inference/hypothesis.d.ts +7 -0
- package/dist/adapters/sqlite/tools/stats/inference/hypothesis.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/stats/inference/index.d.ts +4 -0
- package/dist/adapters/sqlite/tools/stats/inference/index.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/stats/inference/outlier.d.ts +7 -0
- package/dist/adapters/sqlite/tools/stats/inference/outlier.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/stats/inference/regression.d.ts +7 -0
- package/dist/adapters/sqlite/tools/stats/inference/regression.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/stats/math-helpers.d.ts +17 -0
- package/dist/adapters/sqlite/tools/stats/math-helpers.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/stats/schema-risks.d.ts +15 -0
- package/dist/adapters/sqlite/tools/stats/schema-risks.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/text/formatting.d.ts +48 -0
- package/dist/adapters/sqlite/tools/text/formatting.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/text/helpers.d.ts +22 -0
- package/dist/adapters/sqlite/tools/text/helpers.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/text/index.d.ts +10 -0
- package/dist/adapters/sqlite/tools/text/index.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/text/regex.d.ts +21 -0
- package/dist/adapters/sqlite/tools/text/regex.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/text/search.d.ts +17 -0
- package/dist/adapters/sqlite/tools/text/search.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/text/sentiment.d.ts +13 -0
- package/dist/adapters/sqlite/tools/text/sentiment.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/text/validate.d.ts +11 -0
- package/dist/adapters/sqlite/tools/text/validate.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/vector/helpers.d.ts +11 -0
- package/dist/adapters/sqlite/tools/vector/helpers.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/vector/index.d.ts +14 -0
- package/dist/adapters/sqlite/tools/vector/index.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/vector/metadata.d.ts +28 -0
- package/dist/adapters/sqlite/tools/vector/metadata.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/vector/search.d.ts +16 -0
- package/dist/adapters/sqlite/tools/vector/search.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/vector/storage.d.ts +24 -0
- package/dist/adapters/sqlite/tools/vector/storage.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/vector/tools.d.ts +9 -0
- package/dist/adapters/sqlite/tools/vector/tools.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/virtual/analysis.d.ts +24 -0
- package/dist/adapters/sqlite/tools/virtual/analysis.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/virtual/extensions.d.ts +13 -0
- package/dist/adapters/sqlite/tools/virtual/extensions.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/virtual/helpers.d.ts +18 -0
- package/dist/adapters/sqlite/tools/virtual/helpers.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/virtual/index.d.ts +10 -0
- package/dist/adapters/sqlite/tools/virtual/index.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/virtual/views.d.ts +21 -0
- package/dist/adapters/sqlite/tools/virtual/views.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/virtual/vtable/analyze-csv.d.ts +4 -0
- package/dist/adapters/sqlite/tools/virtual/vtable/analyze-csv.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/virtual/vtable/csv.d.ts +4 -0
- package/dist/adapters/sqlite/tools/virtual/vtable/csv.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/virtual/vtable/drop.d.ts +4 -0
- package/dist/adapters/sqlite/tools/virtual/vtable/drop.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/virtual/vtable/index.d.ts +6 -0
- package/dist/adapters/sqlite/tools/virtual/vtable/index.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/virtual/vtable/info.d.ts +4 -0
- package/dist/adapters/sqlite/tools/virtual/vtable/info.d.ts.map +1 -0
- package/dist/adapters/sqlite/tools/virtual/vtable/list.d.ts +4 -0
- package/dist/adapters/sqlite/tools/virtual/vtable/list.d.ts.map +1 -0
- package/dist/adapters/sqlite/types.d.ts +89 -0
- package/dist/adapters/sqlite/types.d.ts.map +1 -0
- package/dist/adapters/sqlite-helpers.d.ts +51 -0
- package/dist/adapters/sqlite-helpers.d.ts.map +1 -0
- package/dist/adapters/sqlite-native/extensions.d.ts +17 -0
- package/dist/adapters/sqlite-native/extensions.d.ts.map +1 -0
- package/dist/adapters/sqlite-native/index.d.ts +11 -0
- package/dist/adapters/sqlite-native/index.d.ts.map +1 -0
- package/dist/adapters/sqlite-native/native-query-executor.d.ts +24 -0
- package/dist/adapters/sqlite-native/native-query-executor.d.ts.map +1 -0
- package/dist/adapters/sqlite-native/native-sqlite-adapter.d.ts +160 -0
- package/dist/adapters/sqlite-native/native-sqlite-adapter.d.ts.map +1 -0
- package/dist/adapters/sqlite-native/registration/index.d.ts +12 -0
- package/dist/adapters/sqlite-native/registration/index.d.ts.map +1 -0
- package/dist/adapters/sqlite-native/tools/spatialite/analysis.d.ts +23 -0
- package/dist/adapters/sqlite-native/tools/spatialite/analysis.d.ts.map +1 -0
- package/dist/adapters/sqlite-native/tools/spatialite/index.d.ts +15 -0
- package/dist/adapters/sqlite-native/tools/spatialite/index.d.ts.map +1 -0
- package/dist/adapters/sqlite-native/tools/spatialite/loader.d.ts +22 -0
- package/dist/adapters/sqlite-native/tools/spatialite/loader.d.ts.map +1 -0
- package/dist/adapters/sqlite-native/tools/spatialite/schemas.d.ts +78 -0
- package/dist/adapters/sqlite-native/tools/spatialite/schemas.d.ts.map +1 -0
- package/dist/adapters/sqlite-native/tools/spatialite/tools.d.ts +30 -0
- package/dist/adapters/sqlite-native/tools/spatialite/tools.d.ts.map +1 -0
- package/dist/adapters/sqlite-native/tools/transactions.d.ts +12 -0
- package/dist/adapters/sqlite-native/tools/transactions.d.ts.map +1 -0
- package/dist/adapters/sqlite-native/tools/window.d.ts +7 -0
- package/dist/adapters/sqlite-native/tools/window.d.ts.map +1 -0
- package/dist/adapters/sqlite-native/transaction-methods.d.ts +36 -0
- package/dist/adapters/sqlite-native/transaction-methods.d.ts.map +1 -0
- package/dist/audit/backup-manager.d.ts +90 -0
- package/dist/audit/backup-manager.d.ts.map +1 -0
- package/dist/audit/index.d.ts +11 -0
- package/dist/audit/index.d.ts.map +1 -0
- package/dist/audit/interceptor.d.ts +54 -0
- package/dist/audit/interceptor.d.ts.map +1 -0
- package/dist/audit/logger.d.ts +62 -0
- package/dist/audit/logger.d.ts.map +1 -0
- package/dist/audit/types.d.ts +112 -0
- package/dist/audit/types.d.ts.map +1 -0
- package/dist/auth/auth-context.d.ts +28 -0
- package/dist/auth/auth-context.d.ts.map +1 -0
- package/dist/auth/authorization-server-discovery.d.ts +90 -0
- package/dist/auth/authorization-server-discovery.d.ts.map +1 -0
- package/dist/auth/errors.d.ts +74 -0
- package/dist/auth/errors.d.ts.map +1 -0
- package/dist/auth/middleware/core.d.ts +22 -0
- package/dist/auth/middleware/core.d.ts.map +1 -0
- package/dist/auth/middleware/express-auth.d.ts +13 -0
- package/dist/auth/middleware/express-auth.d.ts.map +1 -0
- package/dist/auth/middleware/express-scopes.d.ts +6 -0
- package/dist/auth/middleware/express-scopes.d.ts.map +1 -0
- package/dist/auth/middleware/extraction.d.ts +2 -0
- package/dist/auth/middleware/extraction.d.ts.map +1 -0
- package/dist/auth/middleware/index.d.ts +5 -0
- package/dist/auth/middleware/index.d.ts.map +1 -0
- package/dist/auth/oauth-resource-server.d.ts +74 -0
- package/dist/auth/oauth-resource-server.d.ts.map +1 -0
- package/dist/auth/scope-map.d.ts +24 -0
- package/dist/auth/scope-map.d.ts.map +1 -0
- package/dist/auth/scopes/constants.d.ts +40 -0
- package/dist/auth/scopes/constants.d.ts.map +1 -0
- package/dist/auth/scopes/display.d.ts +5 -0
- package/dist/auth/scopes/display.d.ts.map +1 -0
- package/dist/auth/scopes/enforcement.d.ts +27 -0
- package/dist/auth/scopes/enforcement.d.ts.map +1 -0
- package/dist/auth/scopes/index.d.ts +6 -0
- package/dist/auth/scopes/index.d.ts.map +1 -0
- package/dist/auth/scopes/mapping.d.ts +39 -0
- package/dist/auth/scopes/mapping.d.ts.map +1 -0
- package/dist/auth/scopes/validation.d.ts +27 -0
- package/dist/auth/scopes/validation.d.ts.map +1 -0
- package/dist/auth/token-validator.d.ts +63 -0
- package/dist/auth/token-validator.d.ts.map +1 -0
- package/dist/auth/transport-agnostic.d.ts +11 -0
- package/dist/auth/transport-agnostic.d.ts.map +1 -0
- package/dist/auth/types.d.ts +257 -0
- package/dist/auth/types.d.ts.map +1 -0
- package/dist/chunk-E5IESRTK.js +489 -0
- package/dist/{chunk-TVIZ3XJH.js → chunk-FR65YPAH.js} +8509 -3925
- package/dist/{chunk-AOUL5SHS.js → chunk-L552U3QS.js} +880 -252
- package/dist/chunk-THATOQRT.js +2624 -0
- package/dist/chunk-W5WQVNVX.js +568 -0
- package/dist/cli.d.ts +7 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +114 -19
- package/dist/codemode/api-constants.d.ts +40 -0
- package/dist/codemode/api-constants.d.ts.map +1 -0
- package/dist/codemode/api.d.ts +70 -0
- package/dist/codemode/api.d.ts.map +1 -0
- package/dist/codemode/auto-return.d.ts +25 -0
- package/dist/codemode/auto-return.d.ts.map +1 -0
- package/dist/codemode/index.d.ts +12 -0
- package/dist/codemode/index.d.ts.map +1 -0
- package/dist/codemode/sandbox-factory.d.ts +72 -0
- package/dist/codemode/sandbox-factory.d.ts.map +1 -0
- package/dist/codemode/sandbox.d.ts +54 -0
- package/dist/codemode/sandbox.d.ts.map +1 -0
- package/dist/codemode/security.d.ts +45 -0
- package/dist/codemode/security.d.ts.map +1 -0
- package/dist/codemode/types.d.ts +167 -0
- package/dist/codemode/types.d.ts.map +1 -0
- package/dist/constants/server-instructions.d.ts +22 -0
- package/dist/constants/server-instructions.d.ts.map +1 -0
- package/dist/filtering/tool-constants.d.ts +45 -0
- package/dist/filtering/tool-constants.d.ts.map +1 -0
- package/dist/filtering/tool-filter.d.ts +82 -0
- package/dist/filtering/tool-filter.d.ts.map +1 -0
- package/dist/{http-VSB7DBJR.js → http-HWTUVFIA.js} +587 -358
- package/dist/index.d.ts +9 -842
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -5
- package/dist/server/mcp-server.d.ts +66 -0
- package/dist/server/mcp-server.d.ts.map +1 -0
- package/dist/server/registration/audit-tools.d.ts +13 -0
- package/dist/server/registration/audit-tools.d.ts.map +1 -0
- package/dist/server/registration/built-in-tools.d.ts +8 -0
- package/dist/server/registration/built-in-tools.d.ts.map +1 -0
- package/dist/server/registration/help-resources.d.ts +7 -0
- package/dist/server/registration/help-resources.d.ts.map +1 -0
- package/dist/server/registration/index.d.ts +4 -0
- package/dist/server/registration/index.d.ts.map +1 -0
- package/dist/{sqlite-26V3Y4MK.js → sqlite-6C3AJI4I.js} +115 -147
- package/dist/{sqlite-native-5O7FZJGB.js → sqlite-native-ZSSWCTYC.js} +1016 -349
- package/dist/transports/http/index.d.ts +8 -0
- package/dist/transports/http/index.d.ts.map +1 -0
- package/dist/transports/http/middleware.d.ts +25 -0
- package/dist/transports/http/middleware.d.ts.map +1 -0
- package/dist/transports/http/oauth.d.ts +24 -0
- package/dist/transports/http/oauth.d.ts.map +1 -0
- package/dist/transports/http/session.d.ts +2 -0
- package/dist/transports/http/session.d.ts.map +1 -0
- package/dist/transports/http/sessions/index.d.ts +4 -0
- package/dist/transports/http/sessions/index.d.ts.map +1 -0
- package/dist/transports/http/sessions/legacy-sse.d.ts +6 -0
- package/dist/transports/http/sessions/legacy-sse.d.ts.map +1 -0
- package/dist/transports/http/sessions/mutex.d.ts +6 -0
- package/dist/transports/http/sessions/mutex.d.ts.map +1 -0
- package/dist/transports/http/sessions/stateful.d.ts +12 -0
- package/dist/transports/http/sessions/stateful.d.ts.map +1 -0
- package/dist/transports/http/sessions/stateless.d.ts +6 -0
- package/dist/transports/http/sessions/stateless.d.ts.map +1 -0
- package/dist/transports/http/transport.d.ts +65 -0
- package/dist/transports/http/transport.d.ts.map +1 -0
- package/dist/transports/http/type-adapters.d.ts +20 -0
- package/dist/transports/http/type-adapters.d.ts.map +1 -0
- package/dist/transports/http/types.d.ts +120 -0
- package/dist/transports/http/types.d.ts.map +1 -0
- package/dist/types/adapter.d.ts +138 -0
- package/dist/types/adapter.d.ts.map +1 -0
- package/dist/types/auth.d.ts +79 -0
- package/dist/types/auth.d.ts.map +1 -0
- package/dist/types/database.d.ts +100 -0
- package/dist/types/database.d.ts.map +1 -0
- package/dist/types/filtering.d.ts +41 -0
- package/dist/types/filtering.d.ts.map +1 -0
- package/dist/types/index.d.ts +13 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/server.d.ts +48 -0
- package/dist/types/server.d.ts.map +1 -0
- package/dist/utils/annotations.d.ts +62 -0
- package/dist/utils/annotations.d.ts.map +1 -0
- package/dist/utils/errors/base.d.ts +33 -0
- package/dist/utils/errors/base.d.ts.map +1 -0
- package/dist/utils/errors/categories.d.ts +41 -0
- package/dist/utils/errors/categories.d.ts.map +1 -0
- package/dist/utils/errors/classes.d.ts +124 -0
- package/dist/utils/errors/classes.d.ts.map +1 -0
- package/dist/utils/errors/error-response-fields.d.ts +24 -0
- package/dist/utils/errors/error-response-fields.d.ts.map +1 -0
- package/dist/utils/errors/format.d.ts +74 -0
- package/dist/utils/errors/format.d.ts.map +1 -0
- package/dist/utils/errors/index.d.ts +11 -0
- package/dist/utils/errors/index.d.ts.map +1 -0
- package/dist/utils/errors/suggestions.d.ts +16 -0
- package/dist/utils/errors/suggestions.d.ts.map +1 -0
- package/dist/utils/icons.d.ts +19 -0
- package/dist/utils/icons.d.ts.map +1 -0
- package/dist/utils/identifiers.d.ts +121 -0
- package/dist/utils/identifiers.d.ts.map +1 -0
- package/dist/utils/index.d.ts +9 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/insights-manager.d.ts +39 -0
- package/dist/utils/insights-manager.d.ts.map +1 -0
- package/dist/utils/logger/error-codes.d.ts +48 -0
- package/dist/utils/logger/error-codes.d.ts.map +1 -0
- package/dist/utils/logger/index.d.ts +22 -0
- package/dist/utils/logger/index.d.ts.map +1 -0
- package/dist/utils/logger/logger.d.ts +94 -0
- package/dist/utils/logger/logger.d.ts.map +1 -0
- package/dist/utils/logger/module-logger.d.ts +28 -0
- package/dist/utils/logger/module-logger.d.ts.map +1 -0
- package/dist/utils/logger/types.d.ts +36 -0
- package/dist/utils/logger/types.d.ts.map +1 -0
- package/dist/utils/progress-utils.d.ts +54 -0
- package/dist/utils/progress-utils.d.ts.map +1 -0
- package/dist/utils/redaction.d.ts +4 -0
- package/dist/utils/redaction.d.ts.map +1 -0
- package/dist/utils/resource-annotations.d.ts +36 -0
- package/dist/utils/resource-annotations.d.ts.map +1 -0
- package/dist/utils/validate-json-path.d.ts +43 -0
- package/dist/utils/validate-json-path.d.ts.map +1 -0
- package/dist/utils/validate-path.d.ts +37 -0
- package/dist/utils/validate-path.d.ts.map +1 -0
- package/dist/utils/where-clause.d.ts +42 -0
- package/dist/utils/where-clause.d.ts.map +1 -0
- package/dist/version.d.ts +10 -0
- package/dist/version.d.ts.map +1 -0
- package/package.json +33 -20
- package/.gitattributes +0 -2
- package/dist/chunk-4IA3DB5C.js +0 -135
- package/dist/chunk-FW7UCRLN.js +0 -82
- package/dist/chunk-RHVEZ42P.js +0 -873
- package/dist/chunk-Z2GFQU3G.js +0 -363
- package/dist/worker-script.d.ts +0 -2
- package/dist/worker-script.js +0 -126
- package/playwright.config.ts +0 -101
- package/scripts/generate-server-instructions.ts +0 -111
- package/server.json +0 -52
- package/test-server/README.md +0 -118
- package/test-server/code-map.md +0 -409
- package/test-server/fixtures/sample.csv +0 -6
- package/test-server/reset-database.ps1 +0 -373
- package/test-server/sample.csv +0 -11
- package/test-server/test-agent-experience.md +0 -243
- package/test-server/test-database.sql +0 -388
- package/test-server/test-group-tools.md +0 -861
- package/test-server/test-help-resources.mjs +0 -238
- package/test-server/test-preflight.md +0 -53
- package/test-server/test-prompts.md +0 -354
- package/test-server/test-resources.md +0 -245
- package/test-server/test-tool-annotations.mjs +0 -157
- package/test-server/test-tools-advanced-1.md +0 -517
- package/test-server/test-tools-advanced-2.md +0 -487
- package/test-server/test-tools-codemode.md +0 -629
- package/test-server/test-tools.md +0 -176
- package/test-server/tool-reference.md +0 -236
- package/tsconfig.test.json +0 -9
|
@@ -1,41 +1,49 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { DatabaseAdapter } from './chunk-
|
|
3
|
-
import { write, readOnly, VERSION, admin, getToolGroupIcon, idempotent } from './chunk-
|
|
4
|
-
import { formatHandlerError, ValidationError, ConfigurationError, ConnectionError, ResourceNotFoundError,
|
|
5
|
-
import { logger, ERROR_CODES, DbMcpError } from './chunk-AOUL5SHS.js';
|
|
1
|
+
import { RowRecordSchema, WhereConditionSchema, sanitizeIdentifier, buildWhereClause, resolveAliases, autoEnableWal, detectAndSetJsonbSupport, SchemaManager, applyCommonPragmas, isDDL, getResourceDefinitions, getPromptDefinitions, validateIdentifier, normalizeSqliteParams, translateSqliteError, getCoreTools, getJsonOperationTools, getJsonHelperTools, getTextTools, getStatsTools, getVirtualTools, getVectorTools, getGeoTools, getAdminTools, getIntrospectionTools, getMigrationTools, getCodeModeTools, validateTableExists, FtsHeadlineSchema } from './chunk-FR65YPAH.js';
|
|
2
|
+
import { DatabaseAdapter } from './chunk-W5WQVNVX.js';
|
|
3
|
+
import { ErrorResponseFields, write, readOnly, VERSION, admin, writeFs, getToolGroupIcon, idempotent } from './chunk-E5IESRTK.js';
|
|
4
|
+
import { logger, formatHandlerError, ValidationError, ConfigurationError, ERROR_CODES, ConnectionError, DbMcpError, ResourceNotFoundError, ExtensionNotAvailableError } from './chunk-L552U3QS.js';
|
|
6
5
|
import Database from 'better-sqlite3';
|
|
7
6
|
import { z } from 'zod';
|
|
8
|
-
import
|
|
9
|
-
import fs from 'fs';
|
|
7
|
+
import { createRequire } from 'module';
|
|
10
8
|
import { fileURLToPath } from 'url';
|
|
9
|
+
import path2 from 'path';
|
|
10
|
+
import fs from 'fs';
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
12
|
+
var FtsCreateOutputSchema = z.object({
|
|
13
|
+
success: z.boolean(),
|
|
14
|
+
message: z.string().optional(),
|
|
15
|
+
tableName: z.string().optional(),
|
|
16
|
+
triggersCreated: z.array(z.string()).optional()
|
|
17
|
+
}).extend(ErrorResponseFields.shape);
|
|
18
|
+
var FtsResultSchema = z.object({
|
|
19
|
+
rank: z.number().nullable().optional(),
|
|
20
|
+
bm25: z.number().nullable().optional()
|
|
21
|
+
}).loose();
|
|
22
|
+
var FtsSearchOutputSchema = z.object({
|
|
23
|
+
success: z.boolean(),
|
|
24
|
+
rowCount: z.number().optional(),
|
|
25
|
+
results: z.array(FtsResultSchema).optional()
|
|
26
|
+
}).extend(ErrorResponseFields.shape);
|
|
27
|
+
var FtsRebuildOutputSchema = z.object({
|
|
28
|
+
success: z.boolean(),
|
|
29
|
+
message: z.string().optional(),
|
|
30
|
+
tableName: z.string().optional()
|
|
31
|
+
}).extend(ErrorResponseFields.shape);
|
|
32
|
+
var FtsHeadlineOutputSchema = z.object({
|
|
33
|
+
success: z.boolean(),
|
|
34
|
+
rowCount: z.number().optional(),
|
|
35
|
+
results: z.array(
|
|
36
|
+
z.object({
|
|
37
|
+
headline: z.string().optional(),
|
|
38
|
+
snippet: z.string().optional(),
|
|
39
|
+
rank: z.number().nullable().optional()
|
|
40
|
+
}).loose()
|
|
41
|
+
).optional()
|
|
42
|
+
}).extend(ErrorResponseFields.shape);
|
|
36
43
|
var coerceEnumValues = (allowed) => (val) => typeof val === "string" && allowed.includes(val) ? val : void 0;
|
|
37
44
|
var FtsCreateSchema = z.object({
|
|
38
|
-
tableName: z.string().describe("Name of the FTS table to create"),
|
|
45
|
+
tableName: z.string().optional().describe("Name of the FTS table to create"),
|
|
46
|
+
ftsTable: z.string().optional().describe("Name of the FTS table to create (alias)"),
|
|
39
47
|
sourceTable: z.string().describe("Source table to index"),
|
|
40
48
|
columns: z.array(z.string()).describe("Columns to include in the index"),
|
|
41
49
|
contentTable: z.string().optional().describe("Content table for external content FTS"),
|
|
@@ -43,19 +51,21 @@ var FtsCreateSchema = z.object({
|
|
|
43
51
|
coerceEnumValues(["unicode61", "ascii", "porter"]),
|
|
44
52
|
z.enum(["unicode61", "ascii", "porter"]).optional().default("unicode61")
|
|
45
53
|
),
|
|
46
|
-
createTriggers: z.boolean().optional().default(true).describe(
|
|
47
|
-
"Create INSERT/UPDATE/DELETE triggers for auto-sync (only for external content tables)"
|
|
48
|
-
)
|
|
54
|
+
createTriggers: z.boolean().optional().default(true).describe("Create triggers")
|
|
49
55
|
});
|
|
50
56
|
var FtsSearchSchema = z.object({
|
|
51
57
|
table: z.string().describe("FTS table name"),
|
|
52
58
|
query: z.string().describe("Full-text search query"),
|
|
53
59
|
columns: z.array(z.string()).optional().describe("Specific columns to search"),
|
|
54
|
-
limit: z.preprocess(
|
|
55
|
-
(
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
60
|
+
limit: z.preprocess((val) => {
|
|
61
|
+
if (typeof val === "string") {
|
|
62
|
+
const parsed = Number(val);
|
|
63
|
+
return isNaN(parsed) ? val : parsed;
|
|
64
|
+
}
|
|
65
|
+
return val;
|
|
66
|
+
}, z.number().optional().default(100)),
|
|
67
|
+
highlight: z.boolean().optional().default(false).describe("Include highlighted snippets"),
|
|
68
|
+
includeRowData: z.boolean().optional().default(true).describe("Include full row data in results")
|
|
59
69
|
});
|
|
60
70
|
var FtsRebuildSchema = z.object({
|
|
61
71
|
table: z.string().describe("FTS table name to rebuild")
|
|
@@ -66,14 +76,42 @@ var FtsMatchInfoSchema = z.object({
|
|
|
66
76
|
format: z.preprocess(
|
|
67
77
|
coerceEnumValues(["bm25", "rank"]),
|
|
68
78
|
z.enum(["bm25", "rank"]).optional().default("bm25")
|
|
69
|
-
)
|
|
79
|
+
),
|
|
80
|
+
includeRowData: z.boolean().optional().default(true).describe("Include full row data in results")
|
|
70
81
|
});
|
|
82
|
+
|
|
83
|
+
// src/adapters/sqlite/tools/fts.ts
|
|
84
|
+
function buildFts5UnavailableError(tableName) {
|
|
85
|
+
return {
|
|
86
|
+
success: false,
|
|
87
|
+
message: "FTS5 module unavailable",
|
|
88
|
+
tableName: tableName ?? "",
|
|
89
|
+
error: "FTS5 module unavailable",
|
|
90
|
+
hint: "FTS5 requires native SQLite backend (--sqlite-native). WASM mode (sql.js) does not include this module."
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function isFts5UnavailableError(error) {
|
|
94
|
+
return error instanceof Error && error.message.toLowerCase().includes("no such module: fts5");
|
|
95
|
+
}
|
|
96
|
+
function isFts5Available(adapter) {
|
|
97
|
+
return adapter.isNativeBackend();
|
|
98
|
+
}
|
|
99
|
+
function buildFts5SearchUnavailableError() {
|
|
100
|
+
return {
|
|
101
|
+
success: false,
|
|
102
|
+
rowCount: 0,
|
|
103
|
+
results: [],
|
|
104
|
+
error: "FTS5 module unavailable",
|
|
105
|
+
hint: "FTS5 requires native SQLite backend (--sqlite-native). WASM mode (sql.js) does not include this module."
|
|
106
|
+
};
|
|
107
|
+
}
|
|
71
108
|
function getFtsTools(adapter) {
|
|
72
109
|
return [
|
|
73
110
|
createFtsCreateTool(adapter),
|
|
74
111
|
createFtsSearchTool(adapter),
|
|
75
112
|
createFtsRebuildTool(adapter),
|
|
76
|
-
createFtsMatchInfoTool(adapter)
|
|
113
|
+
createFtsMatchInfoTool(adapter),
|
|
114
|
+
createFtsHeadlineTool(adapter)
|
|
77
115
|
];
|
|
78
116
|
}
|
|
79
117
|
function createFtsCreateTool(adapter) {
|
|
@@ -88,7 +126,13 @@ function createFtsCreateTool(adapter) {
|
|
|
88
126
|
handler: async (params, _context) => {
|
|
89
127
|
try {
|
|
90
128
|
const input = FtsCreateSchema.parse(params);
|
|
91
|
-
|
|
129
|
+
const targetTableName = input.tableName || input.ftsTable;
|
|
130
|
+
if (!targetTableName) {
|
|
131
|
+
throw new ValidationError(
|
|
132
|
+
"Must provide either tableName or ftsTable"
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
sanitizeIdentifier(targetTableName);
|
|
92
136
|
sanitizeIdentifier(input.sourceTable);
|
|
93
137
|
for (const col of input.columns) {
|
|
94
138
|
sanitizeIdentifier(col);
|
|
@@ -98,31 +142,31 @@ function createFtsCreateTool(adapter) {
|
|
|
98
142
|
const effectiveContentTable = input.contentTable ?? input.sourceTable;
|
|
99
143
|
sanitizeIdentifier(effectiveContentTable);
|
|
100
144
|
options += `, content="${effectiveContentTable}"`;
|
|
101
|
-
const sql = `CREATE VIRTUAL TABLE IF NOT EXISTS "${
|
|
145
|
+
const sql = `CREATE VIRTUAL TABLE IF NOT EXISTS "${targetTableName}" USING fts5(${columnList}, ${options})`;
|
|
102
146
|
await adapter.executeQuery(sql);
|
|
103
147
|
let triggersCreated = [];
|
|
104
148
|
if (input.createTriggers) {
|
|
105
149
|
triggersCreated = await createSyncTriggers(
|
|
106
150
|
adapter,
|
|
107
|
-
|
|
151
|
+
targetTableName,
|
|
108
152
|
effectiveContentTable,
|
|
109
153
|
input.columns
|
|
110
154
|
);
|
|
111
155
|
}
|
|
112
156
|
await adapter.executeQuery(
|
|
113
|
-
`INSERT INTO "${
|
|
157
|
+
`INSERT INTO "${targetTableName}"("${targetTableName}") VALUES('rebuild')`
|
|
114
158
|
);
|
|
115
|
-
const message = triggersCreated.length ? `FTS5 table '${
|
|
159
|
+
const message = triggersCreated.length ? `FTS5 table '${targetTableName}' created with ${triggersCreated.length} sync triggers` : `FTS5 table '${targetTableName}' created`;
|
|
116
160
|
return {
|
|
117
161
|
success: true,
|
|
118
162
|
message,
|
|
119
|
-
tableName:
|
|
163
|
+
tableName: targetTableName,
|
|
120
164
|
triggersCreated: triggersCreated.length ? triggersCreated : void 0
|
|
121
165
|
};
|
|
122
166
|
} catch (error) {
|
|
123
167
|
if (isFts5UnavailableError(error)) {
|
|
124
168
|
return buildFts5UnavailableError(
|
|
125
|
-
params?.tableName
|
|
169
|
+
params?.tableName || params?.ftsTable
|
|
126
170
|
);
|
|
127
171
|
}
|
|
128
172
|
return formatHandlerError(error);
|
|
@@ -141,7 +185,7 @@ async function createSyncTriggers(adapter, ftsTable, contentTable, columns) {
|
|
|
141
185
|
INSERT INTO "${ftsTable}"(rowid, ${colList}) VALUES (NEW.rowid, ${newColList});
|
|
142
186
|
END;
|
|
143
187
|
`;
|
|
144
|
-
await adapter.
|
|
188
|
+
await adapter.rawQuery(insertTrigger, void 0);
|
|
145
189
|
triggersCreated.push(insertTriggerName);
|
|
146
190
|
const deleteTriggerName = `${ftsTable}_ad`;
|
|
147
191
|
const deleteTrigger = `
|
|
@@ -149,7 +193,7 @@ async function createSyncTriggers(adapter, ftsTable, contentTable, columns) {
|
|
|
149
193
|
INSERT INTO "${ftsTable}"("${ftsTable}", rowid, ${colList}) VALUES('delete', OLD.rowid, ${oldColList});
|
|
150
194
|
END;
|
|
151
195
|
`;
|
|
152
|
-
await adapter.
|
|
196
|
+
await adapter.rawQuery(deleteTrigger, void 0);
|
|
153
197
|
triggersCreated.push(deleteTriggerName);
|
|
154
198
|
const updateTriggerName = `${ftsTable}_au`;
|
|
155
199
|
const updateTrigger = `
|
|
@@ -158,7 +202,7 @@ async function createSyncTriggers(adapter, ftsTable, contentTable, columns) {
|
|
|
158
202
|
INSERT INTO "${ftsTable}"(rowid, ${colList}) VALUES (NEW.rowid, ${newColList});
|
|
159
203
|
END;
|
|
160
204
|
`;
|
|
161
|
-
await adapter.
|
|
205
|
+
await adapter.rawQuery(updateTrigger, void 0);
|
|
162
206
|
triggersCreated.push(updateTriggerName);
|
|
163
207
|
return triggersCreated;
|
|
164
208
|
}
|
|
@@ -174,18 +218,19 @@ function createFtsSearchTool(adapter) {
|
|
|
174
218
|
handler: async (params, _context) => {
|
|
175
219
|
try {
|
|
176
220
|
const input = FtsSearchSchema.parse(params);
|
|
221
|
+
const queryParams = [];
|
|
177
222
|
if (!isFts5Available(adapter)) {
|
|
178
223
|
return buildFts5SearchUnavailableError();
|
|
179
224
|
}
|
|
180
225
|
sanitizeIdentifier(input.table);
|
|
181
226
|
await validateTableExists(adapter, input.table);
|
|
182
|
-
let selectClause = "*";
|
|
227
|
+
let selectClause = input.includeRowData ? "*" : "rowid";
|
|
183
228
|
if (input.highlight) {
|
|
184
|
-
selectClause
|
|
229
|
+
selectClause += `, highlight("${input.table}", 0, '<b>', '</b>') as snippet`;
|
|
185
230
|
}
|
|
186
231
|
if (input.query === "*" || input.query.trim() === "") {
|
|
187
232
|
const sql2 = `SELECT ${selectClause}, NULL as rank FROM "${input.table}" ORDER BY rowid LIMIT ${input.limit}`;
|
|
188
|
-
const result2 = await adapter.executeReadQuery(sql2);
|
|
233
|
+
const result2 = await adapter.executeReadQuery(sql2, queryParams);
|
|
189
234
|
return {
|
|
190
235
|
success: true,
|
|
191
236
|
rowCount: result2.rows?.length ?? 0,
|
|
@@ -202,7 +247,7 @@ function createFtsSearchTool(adapter) {
|
|
|
202
247
|
matchExpr = `"${input.table}" MATCH '${colFilter}'`;
|
|
203
248
|
}
|
|
204
249
|
const sql = `SELECT ${selectClause}, rank FROM "${input.table}" WHERE ${matchExpr} ORDER BY rank LIMIT ${input.limit}`;
|
|
205
|
-
const result = await adapter.executeReadQuery(sql);
|
|
250
|
+
const result = await adapter.executeReadQuery(sql, queryParams);
|
|
206
251
|
return {
|
|
207
252
|
success: true,
|
|
208
253
|
rowCount: result.rows?.length ?? 0,
|
|
@@ -264,6 +309,7 @@ function createFtsMatchInfoTool(adapter) {
|
|
|
264
309
|
handler: async (params, _context) => {
|
|
265
310
|
try {
|
|
266
311
|
const input = FtsMatchInfoSchema.parse(params);
|
|
312
|
+
const queryParams = [];
|
|
267
313
|
if (!isFts5Available(adapter)) {
|
|
268
314
|
return buildFts5SearchUnavailableError();
|
|
269
315
|
}
|
|
@@ -276,8 +322,71 @@ function createFtsMatchInfoTool(adapter) {
|
|
|
276
322
|
} else {
|
|
277
323
|
rankExpr = "rank";
|
|
278
324
|
}
|
|
279
|
-
const
|
|
280
|
-
const
|
|
325
|
+
const selectCols = input.includeRowData ? "*" : "rowid";
|
|
326
|
+
const sql = `SELECT ${selectCols}, ${rankExpr} as score FROM "${input.table}" WHERE "${input.table}" MATCH '${queryEscaped}' ORDER BY score`;
|
|
327
|
+
const result = await adapter.executeReadQuery(sql, queryParams);
|
|
328
|
+
return {
|
|
329
|
+
success: true,
|
|
330
|
+
rowCount: result.rows?.length ?? 0,
|
|
331
|
+
results: result.rows
|
|
332
|
+
};
|
|
333
|
+
} catch (error) {
|
|
334
|
+
if (isFts5UnavailableError(error)) {
|
|
335
|
+
return buildFts5SearchUnavailableError();
|
|
336
|
+
}
|
|
337
|
+
return formatHandlerError(error);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
function createFtsHeadlineTool(adapter) {
|
|
343
|
+
return {
|
|
344
|
+
name: "sqlite_fts_headline",
|
|
345
|
+
description: "Generate highlighted snippets from FTS5 full-text search results. Returns headline (highlight) and snippet (context window) for each match.",
|
|
346
|
+
group: "text",
|
|
347
|
+
inputSchema: FtsHeadlineSchema,
|
|
348
|
+
outputSchema: FtsHeadlineOutputSchema,
|
|
349
|
+
requiredScopes: ["read"],
|
|
350
|
+
annotations: readOnly("FTS Headline"),
|
|
351
|
+
handler: async (params, _context) => {
|
|
352
|
+
try {
|
|
353
|
+
const input = FtsHeadlineSchema.parse(params);
|
|
354
|
+
const queryParams = [];
|
|
355
|
+
if (!isFts5Available(adapter)) {
|
|
356
|
+
return buildFts5SearchUnavailableError();
|
|
357
|
+
}
|
|
358
|
+
sanitizeIdentifier(input.table);
|
|
359
|
+
await validateTableExists(adapter, input.table);
|
|
360
|
+
const queryEscaped = input.query.replace(/'/g, "''");
|
|
361
|
+
let columnIndex = 0;
|
|
362
|
+
if (input.column) {
|
|
363
|
+
const colResult = await adapter.executeReadQuery(
|
|
364
|
+
`PRAGMA table_info("${input.table}")`,
|
|
365
|
+
queryParams
|
|
366
|
+
);
|
|
367
|
+
const colRows = colResult.rows ?? [];
|
|
368
|
+
const found = colRows.findIndex(
|
|
369
|
+
(r) => String(r["name"]) === input.column
|
|
370
|
+
);
|
|
371
|
+
if (found >= 0) {
|
|
372
|
+
columnIndex = found;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
const startSel = input.startSel.replace(/'/g, "''");
|
|
376
|
+
const stopSel = input.stopSel.replace(/'/g, "''");
|
|
377
|
+
const highlightExpr = `highlight("${input.table}", ${String(columnIndex)}, '${startSel}', '${stopSel}')`;
|
|
378
|
+
const snippetExpr = `snippet("${input.table}", ${String(columnIndex)}, '${startSel}', '${stopSel}', '...', ${String(input.snippetWords)})`;
|
|
379
|
+
if (input.query === "*" || input.query.trim() === "") {
|
|
380
|
+
const sql2 = `SELECT *, NULL as headline, NULL as snippet, NULL as rank FROM "${input.table}" ORDER BY rowid LIMIT ${String(input.limit)}`;
|
|
381
|
+
const result2 = await adapter.executeReadQuery(sql2, queryParams);
|
|
382
|
+
return {
|
|
383
|
+
success: true,
|
|
384
|
+
rowCount: result2.rows?.length ?? 0,
|
|
385
|
+
results: result2.rows
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
const sql = `SELECT ${highlightExpr} as headline, ${snippetExpr} as snippet, rank FROM "${input.table}" WHERE "${input.table}" MATCH '${queryEscaped}' ORDER BY rank LIMIT ${String(input.limit)}`;
|
|
389
|
+
const result = await adapter.executeReadQuery(sql, queryParams);
|
|
281
390
|
return {
|
|
282
391
|
success: true,
|
|
283
392
|
rowCount: result.rows?.length ?? 0,
|
|
@@ -292,17 +401,166 @@ function createFtsMatchInfoTool(adapter) {
|
|
|
292
401
|
}
|
|
293
402
|
};
|
|
294
403
|
}
|
|
295
|
-
var
|
|
404
|
+
var TransactionBeginOutputSchema = z.object({
|
|
405
|
+
success: z.boolean(),
|
|
406
|
+
message: z.string().optional(),
|
|
407
|
+
mode: z.string().optional()
|
|
408
|
+
}).extend(ErrorResponseFields.shape);
|
|
409
|
+
var TransactionCommitOutputSchema = z.object({
|
|
410
|
+
success: z.boolean(),
|
|
411
|
+
message: z.string().optional()
|
|
412
|
+
}).extend(ErrorResponseFields.shape);
|
|
413
|
+
var TransactionRollbackOutputSchema = z.object({
|
|
414
|
+
success: z.boolean(),
|
|
415
|
+
message: z.string().optional()
|
|
416
|
+
}).extend(ErrorResponseFields.shape);
|
|
417
|
+
var TransactionSavepointOutputSchema = z.object({
|
|
418
|
+
success: z.boolean(),
|
|
419
|
+
message: z.string().optional(),
|
|
420
|
+
name: z.string().optional(),
|
|
421
|
+
savepoint: z.string().optional()
|
|
422
|
+
}).extend(ErrorResponseFields.shape);
|
|
423
|
+
var TransactionReleaseOutputSchema = z.object({
|
|
424
|
+
success: z.boolean(),
|
|
425
|
+
message: z.string().optional(),
|
|
426
|
+
name: z.string().optional(),
|
|
427
|
+
savepoint: z.string().optional()
|
|
428
|
+
}).extend(ErrorResponseFields.shape);
|
|
429
|
+
var TransactionRollbackToOutputSchema = z.object({
|
|
430
|
+
success: z.boolean(),
|
|
431
|
+
message: z.string().optional(),
|
|
432
|
+
name: z.string().optional(),
|
|
433
|
+
savepoint: z.string().optional()
|
|
434
|
+
}).extend(ErrorResponseFields.shape);
|
|
435
|
+
var TransactionExecuteOutputSchema = z.object({
|
|
436
|
+
success: z.boolean(),
|
|
437
|
+
message: z.string().optional(),
|
|
438
|
+
statementsExecuted: z.number().optional(),
|
|
439
|
+
results: z.array(z.unknown()).optional()
|
|
440
|
+
}).extend(ErrorResponseFields.shape);
|
|
441
|
+
var TransactionStatusOutputSchema = z.object({
|
|
442
|
+
success: z.boolean(),
|
|
443
|
+
status: z.enum(["active", "none"]).optional().describe(
|
|
444
|
+
'Transaction state: "active" (transaction in progress) or "none" (no active transaction)'
|
|
445
|
+
),
|
|
446
|
+
active: z.boolean().optional().describe("Whether a transaction is currently in progress"),
|
|
447
|
+
message: z.string().optional()
|
|
448
|
+
}).extend(ErrorResponseFields.shape);
|
|
449
|
+
var RowNumberResultSchema = z.object({
|
|
450
|
+
row_number: z.number()
|
|
451
|
+
}).loose();
|
|
452
|
+
var WindowRowNumberOutputSchema = z.object({
|
|
453
|
+
success: z.boolean(),
|
|
454
|
+
rowCount: z.number().optional(),
|
|
455
|
+
rows: z.array(RowNumberResultSchema).optional(),
|
|
456
|
+
hint: z.string().optional()
|
|
457
|
+
}).extend(ErrorResponseFields.shape);
|
|
458
|
+
var RankResultSchema = z.object({
|
|
459
|
+
rank: z.number().optional(),
|
|
460
|
+
dense_rank: z.number().optional(),
|
|
461
|
+
percent_rank: z.number().optional()
|
|
462
|
+
}).loose();
|
|
463
|
+
var WindowRankOutputSchema = z.object({
|
|
464
|
+
success: z.boolean(),
|
|
465
|
+
rankType: z.string().optional(),
|
|
466
|
+
rowCount: z.number().optional(),
|
|
467
|
+
rows: z.array(RankResultSchema).optional(),
|
|
468
|
+
hint: z.string().optional()
|
|
469
|
+
}).extend(ErrorResponseFields.shape);
|
|
470
|
+
var LagLeadResultSchema = z.object({
|
|
471
|
+
lag_value: z.unknown().optional(),
|
|
472
|
+
lead_value: z.unknown().optional()
|
|
473
|
+
}).loose();
|
|
474
|
+
var WindowLagLeadOutputSchema = z.object({
|
|
475
|
+
success: z.boolean(),
|
|
476
|
+
direction: z.string().optional(),
|
|
477
|
+
offset: z.number().optional(),
|
|
478
|
+
rowCount: z.number().optional(),
|
|
479
|
+
rows: z.array(LagLeadResultSchema).optional(),
|
|
480
|
+
hint: z.string().optional()
|
|
481
|
+
}).extend(ErrorResponseFields.shape);
|
|
482
|
+
var RunningTotalResultSchema = z.object({
|
|
483
|
+
running_total: z.number()
|
|
484
|
+
}).loose();
|
|
485
|
+
var WindowRunningTotalOutputSchema = z.object({
|
|
486
|
+
success: z.boolean(),
|
|
487
|
+
valueColumn: z.string().optional(),
|
|
488
|
+
rowCount: z.number().optional(),
|
|
489
|
+
rows: z.array(RunningTotalResultSchema).optional(),
|
|
490
|
+
hint: z.string().optional()
|
|
491
|
+
}).extend(ErrorResponseFields.shape);
|
|
492
|
+
var MovingAvgResultSchema = z.object({
|
|
493
|
+
moving_avg: z.number()
|
|
494
|
+
}).loose();
|
|
495
|
+
var WindowMovingAvgOutputSchema = z.object({
|
|
496
|
+
success: z.boolean(),
|
|
497
|
+
valueColumn: z.string().optional(),
|
|
498
|
+
windowSize: z.number().optional(),
|
|
499
|
+
rowCount: z.number().optional(),
|
|
500
|
+
rows: z.array(MovingAvgResultSchema).optional(),
|
|
501
|
+
hint: z.string().optional()
|
|
502
|
+
}).extend(ErrorResponseFields.shape);
|
|
503
|
+
var NtileResultSchema = z.object({
|
|
504
|
+
ntile: z.number()
|
|
505
|
+
}).loose();
|
|
506
|
+
var WindowNtileOutputSchema = z.object({
|
|
507
|
+
success: z.boolean(),
|
|
508
|
+
buckets: z.number().optional(),
|
|
509
|
+
rowCount: z.number().optional(),
|
|
510
|
+
rows: z.array(NtileResultSchema).optional(),
|
|
511
|
+
hint: z.string().optional()
|
|
512
|
+
}).extend(ErrorResponseFields.shape);
|
|
513
|
+
var SpatialiteLoadOutputSchema = z.object({
|
|
514
|
+
success: z.boolean(),
|
|
515
|
+
message: z.string().optional(),
|
|
516
|
+
alreadyLoaded: z.boolean().optional(),
|
|
517
|
+
extensionPath: z.string().optional(),
|
|
518
|
+
searchedPaths: z.array(z.string()).optional()
|
|
519
|
+
}).extend(ErrorResponseFields.shape);
|
|
520
|
+
var SpatialiteCreateTableOutputSchema = z.object({
|
|
521
|
+
success: z.boolean(),
|
|
522
|
+
message: z.string().optional(),
|
|
523
|
+
tableName: z.string().optional(),
|
|
524
|
+
alreadyExists: z.boolean().optional(),
|
|
525
|
+
geometryColumn: z.string().optional(),
|
|
526
|
+
geometryType: z.string().optional(),
|
|
527
|
+
srid: z.number().optional()
|
|
528
|
+
}).extend(ErrorResponseFields.shape);
|
|
529
|
+
var SpatialiteQueryOutputSchema = z.object({
|
|
530
|
+
success: z.boolean(),
|
|
531
|
+
rowCount: z.number().optional(),
|
|
532
|
+
rows: z.array(RowRecordSchema).optional()
|
|
533
|
+
}).extend(ErrorResponseFields.shape);
|
|
534
|
+
var SpatialiteIndexOutputSchema = z.object({
|
|
535
|
+
success: z.boolean(),
|
|
536
|
+
message: z.string().optional(),
|
|
537
|
+
action: z.string().optional(),
|
|
538
|
+
alreadyExists: z.boolean().optional(),
|
|
539
|
+
alreadyDropped: z.boolean().optional(),
|
|
540
|
+
indexed: z.boolean().optional(),
|
|
541
|
+
valid: z.boolean().nullable().optional()
|
|
542
|
+
}).extend(ErrorResponseFields.shape);
|
|
543
|
+
var SpatialiteAnalyzeOutputSchema = z.object({
|
|
544
|
+
success: z.boolean(),
|
|
545
|
+
analysisType: z.string().optional(),
|
|
546
|
+
rowCount: z.number().optional(),
|
|
547
|
+
results: z.array(RowRecordSchema).optional()
|
|
548
|
+
}).extend(ErrorResponseFields.shape);
|
|
549
|
+
var SpatialiteTransformOutputSchema = z.object({
|
|
550
|
+
success: z.boolean(),
|
|
551
|
+
operation: z.string().optional(),
|
|
552
|
+
result: z.string().optional()
|
|
553
|
+
}).extend(ErrorResponseFields.shape);
|
|
554
|
+
var SpatialiteImportOutputSchema = z.object({
|
|
555
|
+
success: z.boolean(),
|
|
556
|
+
message: z.string().optional(),
|
|
557
|
+
rowsAffected: z.number().optional()
|
|
558
|
+
}).extend(ErrorResponseFields.shape);
|
|
559
|
+
|
|
560
|
+
// src/adapters/sqlite-native/tools/transactions.ts
|
|
296
561
|
var BeginTransactionSchema = z.object({
|
|
297
|
-
mode: z.
|
|
298
|
-
|
|
299
|
-
if (typeof val !== "string") return void 0;
|
|
300
|
-
const normalized = val.toLowerCase();
|
|
301
|
-
return VALID_MODES.includes(normalized) ? normalized : void 0;
|
|
302
|
-
},
|
|
303
|
-
z.enum(["deferred", "immediate", "exclusive"]).optional().default("deferred").describe(
|
|
304
|
-
"Transaction mode: deferred waits for first write, immediate acquires lock immediately, exclusive blocks all access"
|
|
305
|
-
)
|
|
562
|
+
mode: z.enum(["deferred", "immediate", "exclusive"]).optional().default("deferred").describe(
|
|
563
|
+
"Transaction mode: deferred waits for first write, immediate acquires lock immediately, exclusive blocks all access"
|
|
306
564
|
)
|
|
307
565
|
});
|
|
308
566
|
var SavepointSchema = z.object({
|
|
@@ -315,6 +573,7 @@ var ExecuteInTransactionSchema = z.object({
|
|
|
315
573
|
function getTransactionTools(adapter) {
|
|
316
574
|
return [
|
|
317
575
|
createBeginTransactionTool(adapter),
|
|
576
|
+
createTransactionStatusTool(adapter),
|
|
318
577
|
createCommitTransactionTool(adapter),
|
|
319
578
|
createRollbackTransactionTool(adapter),
|
|
320
579
|
createSavepointTool(adapter),
|
|
@@ -327,7 +586,7 @@ function createBeginTransactionTool(adapter) {
|
|
|
327
586
|
return {
|
|
328
587
|
name: "sqlite_transaction_begin",
|
|
329
588
|
description: "Begin a new transaction. Use immediate or exclusive mode for write-heavy operations.",
|
|
330
|
-
group: "
|
|
589
|
+
group: "transactions",
|
|
331
590
|
inputSchema: BeginTransactionSchema,
|
|
332
591
|
outputSchema: TransactionBeginOutputSchema,
|
|
333
592
|
annotations: write("Begin Transaction"),
|
|
@@ -348,11 +607,36 @@ function createBeginTransactionTool(adapter) {
|
|
|
348
607
|
}
|
|
349
608
|
};
|
|
350
609
|
}
|
|
610
|
+
function createTransactionStatusTool(adapter) {
|
|
611
|
+
return {
|
|
612
|
+
name: "sqlite_transaction_status",
|
|
613
|
+
description: "Check whether a transaction is currently active. Returns status and a boolean flag. Read-only \u2014 does not alter transaction state.",
|
|
614
|
+
group: "transactions",
|
|
615
|
+
inputSchema: z.object({}),
|
|
616
|
+
outputSchema: TransactionStatusOutputSchema,
|
|
617
|
+
annotations: readOnly("Transaction Status"),
|
|
618
|
+
requiredScopes: ["read"],
|
|
619
|
+
handler: (_params, _context) => {
|
|
620
|
+
try {
|
|
621
|
+
const db = adapter.getDatabase();
|
|
622
|
+
const active = db.inTransaction;
|
|
623
|
+
return Promise.resolve({
|
|
624
|
+
success: true,
|
|
625
|
+
status: active ? "active" : "none",
|
|
626
|
+
active,
|
|
627
|
+
message: active ? "A transaction is currently active." : "No transaction is active."
|
|
628
|
+
});
|
|
629
|
+
} catch (error) {
|
|
630
|
+
return Promise.resolve(formatHandlerError(error));
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
};
|
|
634
|
+
}
|
|
351
635
|
function createCommitTransactionTool(adapter) {
|
|
352
636
|
return {
|
|
353
637
|
name: "sqlite_transaction_commit",
|
|
354
638
|
description: "Commit the current transaction, making all changes permanent.",
|
|
355
|
-
group: "
|
|
639
|
+
group: "transactions",
|
|
356
640
|
inputSchema: z.object({}),
|
|
357
641
|
outputSchema: TransactionCommitOutputSchema,
|
|
358
642
|
annotations: write("Commit Transaction"),
|
|
@@ -374,7 +658,7 @@ function createRollbackTransactionTool(adapter) {
|
|
|
374
658
|
return {
|
|
375
659
|
name: "sqlite_transaction_rollback",
|
|
376
660
|
description: "Rollback the current transaction, discarding all changes.",
|
|
377
|
-
group: "
|
|
661
|
+
group: "transactions",
|
|
378
662
|
outputSchema: TransactionRollbackOutputSchema,
|
|
379
663
|
inputSchema: z.object({}),
|
|
380
664
|
annotations: write("Rollback Transaction"),
|
|
@@ -396,7 +680,7 @@ function createSavepointTool(adapter) {
|
|
|
396
680
|
return {
|
|
397
681
|
name: "sqlite_transaction_savepoint",
|
|
398
682
|
description: "Create a savepoint within the current transaction for partial rollback.",
|
|
399
|
-
group: "
|
|
683
|
+
group: "transactions",
|
|
400
684
|
outputSchema: TransactionSavepointOutputSchema,
|
|
401
685
|
inputSchema: SavepointSchema,
|
|
402
686
|
annotations: write("Create Savepoint"),
|
|
@@ -429,7 +713,7 @@ function createReleaseSavepointTool(adapter) {
|
|
|
429
713
|
return {
|
|
430
714
|
name: "sqlite_transaction_release",
|
|
431
715
|
description: "Release a savepoint, keeping the changes made since it was created.",
|
|
432
|
-
group: "
|
|
716
|
+
group: "transactions",
|
|
433
717
|
inputSchema: SavepointSchema,
|
|
434
718
|
outputSchema: TransactionReleaseOutputSchema,
|
|
435
719
|
annotations: write("Release Savepoint"),
|
|
@@ -462,7 +746,7 @@ function createRollbackToSavepointTool(adapter) {
|
|
|
462
746
|
return {
|
|
463
747
|
name: "sqlite_transaction_rollback_to",
|
|
464
748
|
description: "Rollback to a savepoint, discarding changes made after it was created.",
|
|
465
|
-
group: "
|
|
749
|
+
group: "transactions",
|
|
466
750
|
inputSchema: SavepointSchema,
|
|
467
751
|
outputSchema: TransactionRollbackToOutputSchema,
|
|
468
752
|
annotations: write("Rollback to Savepoint"),
|
|
@@ -495,43 +779,65 @@ function createExecuteInTransactionTool(adapter) {
|
|
|
495
779
|
return {
|
|
496
780
|
name: "sqlite_transaction_execute",
|
|
497
781
|
description: "Execute multiple SQL statements in a single transaction. Automatically commits on success or rolls back on error.",
|
|
498
|
-
group: "
|
|
782
|
+
group: "transactions",
|
|
499
783
|
outputSchema: TransactionExecuteOutputSchema,
|
|
500
784
|
inputSchema: ExecuteInTransactionSchema,
|
|
501
785
|
annotations: write("Execute in Transaction"),
|
|
502
786
|
requiredScopes: ["write"],
|
|
503
787
|
handler: async (params, _context) => {
|
|
788
|
+
const queryParams = [];
|
|
504
789
|
let input;
|
|
505
790
|
try {
|
|
506
791
|
input = ExecuteInTransactionSchema.parse(params);
|
|
792
|
+
if (input.statements.length === 0) {
|
|
793
|
+
throw new ValidationError("Must provide at least one SQL statement");
|
|
794
|
+
}
|
|
507
795
|
} catch (error) {
|
|
796
|
+
const errObj = formatHandlerError(error);
|
|
508
797
|
return {
|
|
509
|
-
...
|
|
510
|
-
message: "",
|
|
798
|
+
...errObj,
|
|
799
|
+
message: errObj.error || "Transaction execution failed",
|
|
511
800
|
statementsExecuted: 0,
|
|
512
801
|
results: []
|
|
513
802
|
};
|
|
514
803
|
}
|
|
515
804
|
const results = [];
|
|
516
805
|
let success = true;
|
|
806
|
+
let transactionStarted = false;
|
|
807
|
+
const db = adapter.getDatabase();
|
|
808
|
+
const originallyInTransaction = db.inTransaction;
|
|
517
809
|
try {
|
|
518
|
-
|
|
810
|
+
if (!originallyInTransaction) {
|
|
811
|
+
adapter.beginTransaction();
|
|
812
|
+
transactionStarted = true;
|
|
813
|
+
}
|
|
519
814
|
for (const statement of input.statements) {
|
|
520
815
|
try {
|
|
521
816
|
const isSelect = statement.trim().toUpperCase().startsWith("SELECT");
|
|
522
817
|
if (isSelect) {
|
|
523
|
-
const result = await adapter.executeReadQuery(
|
|
818
|
+
const result = await adapter.executeReadQuery(
|
|
819
|
+
statement,
|
|
820
|
+
queryParams
|
|
821
|
+
);
|
|
524
822
|
const rowCount = result.rows?.length ?? 0;
|
|
525
823
|
const statementResult = {
|
|
526
824
|
statement: statement.substring(0, 100) + (statement.length > 100 ? "..." : ""),
|
|
527
825
|
rowCount
|
|
528
826
|
};
|
|
529
827
|
if (result.rows) {
|
|
530
|
-
|
|
828
|
+
if (result.rows.length > 50) {
|
|
829
|
+
statementResult.rows = result.rows.slice(0, 50);
|
|
830
|
+
statementResult.error = "Result truncated to 50 rows. Use sqlite_read_query with LIMIT for larger datasets.";
|
|
831
|
+
} else {
|
|
832
|
+
statementResult.rows = result.rows;
|
|
833
|
+
}
|
|
531
834
|
}
|
|
532
835
|
results.push(statementResult);
|
|
533
836
|
} else {
|
|
534
|
-
const result = await adapter.executeWriteQuery(
|
|
837
|
+
const result = await adapter.executeWriteQuery(
|
|
838
|
+
statement,
|
|
839
|
+
queryParams
|
|
840
|
+
);
|
|
535
841
|
results.push({
|
|
536
842
|
statement: statement.substring(0, 100) + (statement.length > 100 ? "..." : ""),
|
|
537
843
|
rowsAffected: result.rowsAffected ?? 0
|
|
@@ -549,25 +855,38 @@ function createExecuteInTransactionTool(adapter) {
|
|
|
549
855
|
success = false;
|
|
550
856
|
}
|
|
551
857
|
}
|
|
552
|
-
|
|
858
|
+
if (transactionStarted) {
|
|
859
|
+
adapter.commitTransaction();
|
|
860
|
+
}
|
|
553
861
|
return {
|
|
554
862
|
success,
|
|
863
|
+
error: success ? void 0 : "Transaction completed with errors",
|
|
555
864
|
message: success ? "Transaction completed successfully" : "Transaction completed with errors",
|
|
556
865
|
statementsExecuted: input.statements.length,
|
|
557
866
|
results
|
|
558
867
|
};
|
|
559
868
|
} catch (error) {
|
|
560
869
|
let rollbackFailure;
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
870
|
+
if (transactionStarted) {
|
|
871
|
+
try {
|
|
872
|
+
adapter.rollbackTransaction();
|
|
873
|
+
} catch (rbError) {
|
|
874
|
+
rollbackFailure = rbError instanceof Error ? rbError.message : String(rbError);
|
|
875
|
+
}
|
|
876
|
+
} else if (originallyInTransaction && input.rollbackOnError) {
|
|
877
|
+
try {
|
|
878
|
+
adapter.rollbackTransaction();
|
|
879
|
+
} catch (rbError) {
|
|
880
|
+
rollbackFailure = rbError instanceof Error ? rbError.message : String(rbError);
|
|
881
|
+
}
|
|
565
882
|
}
|
|
566
883
|
const message = error instanceof Error ? error.message : String(error);
|
|
567
884
|
const formatted = formatHandlerError(error);
|
|
568
885
|
let rollbackMessage = `Transaction rolled back: ${message}`;
|
|
569
886
|
if (rollbackFailure) {
|
|
570
887
|
rollbackMessage += ` (rollback error: ${rollbackFailure})`;
|
|
888
|
+
} else if (!transactionStarted && !originallyInTransaction) {
|
|
889
|
+
rollbackMessage = `Transaction failed to start: ${message}`;
|
|
571
890
|
}
|
|
572
891
|
return {
|
|
573
892
|
...formatted,
|
|
@@ -580,7 +899,14 @@ function createExecuteInTransactionTool(adapter) {
|
|
|
580
899
|
}
|
|
581
900
|
};
|
|
582
901
|
}
|
|
583
|
-
var coerceNumber = (val) =>
|
|
902
|
+
var coerceNumber = (val) => {
|
|
903
|
+
if (typeof val === "string") {
|
|
904
|
+
if (val.trim() === "") return void 0;
|
|
905
|
+
const num = Number(val);
|
|
906
|
+
return isNaN(num) ? val : num;
|
|
907
|
+
}
|
|
908
|
+
return val;
|
|
909
|
+
};
|
|
584
910
|
var coerceEnumValues2 = (allowed) => (val) => typeof val === "string" && allowed.includes(val) ? val : void 0;
|
|
585
911
|
var VALID_DIRECTIONS = ["lag", "lead"];
|
|
586
912
|
var RowNumberSchema = z.object({
|
|
@@ -588,10 +914,10 @@ var RowNumberSchema = z.object({
|
|
|
588
914
|
orderBy: z.string().describe("Column(s) to order by"),
|
|
589
915
|
partitionBy: z.string().optional().describe("Column(s) to partition by"),
|
|
590
916
|
selectColumns: z.array(z.string()).optional().describe("Columns to include in result"),
|
|
591
|
-
|
|
917
|
+
conditions: z.array(WhereConditionSchema).optional().describe("Optional WHERE clause conditions"),
|
|
592
918
|
limit: z.preprocess(
|
|
593
919
|
coerceNumber,
|
|
594
|
-
z.number().optional().default(
|
|
920
|
+
z.number().optional().default(20).describe("Maximum rows to return")
|
|
595
921
|
)
|
|
596
922
|
});
|
|
597
923
|
var RankSchema = z.object({
|
|
@@ -603,10 +929,10 @@ var RankSchema = z.object({
|
|
|
603
929
|
coerceEnumValues2(["rank", "dense_rank", "percent_rank"]),
|
|
604
930
|
z.enum(["rank", "dense_rank", "percent_rank"]).optional().default("rank").describe("Rank function type")
|
|
605
931
|
),
|
|
606
|
-
|
|
932
|
+
conditions: z.array(WhereConditionSchema).optional().describe("Optional WHERE clause conditions"),
|
|
607
933
|
limit: z.preprocess(
|
|
608
934
|
coerceNumber,
|
|
609
|
-
z.number().optional().default(
|
|
935
|
+
z.number().optional().default(20).describe("Maximum rows to return")
|
|
610
936
|
)
|
|
611
937
|
});
|
|
612
938
|
var LagLeadSchema = z.object({
|
|
@@ -621,10 +947,10 @@ var LagLeadSchema = z.object({
|
|
|
621
947
|
defaultValue: z.string().optional().describe("Default value if no row exists"),
|
|
622
948
|
partitionBy: z.string().optional().describe("Column(s) to partition by"),
|
|
623
949
|
selectColumns: z.array(z.string()).optional().describe("Columns to include in result"),
|
|
624
|
-
|
|
950
|
+
conditions: z.array(WhereConditionSchema).optional().describe("Optional WHERE clause conditions"),
|
|
625
951
|
limit: z.preprocess(
|
|
626
952
|
coerceNumber,
|
|
627
|
-
z.number().optional().default(
|
|
953
|
+
z.number().optional().default(20).describe("Maximum rows to return")
|
|
628
954
|
)
|
|
629
955
|
});
|
|
630
956
|
var RunningTotalSchema = z.object({
|
|
@@ -633,10 +959,10 @@ var RunningTotalSchema = z.object({
|
|
|
633
959
|
orderBy: z.string().describe("Column(s) to order by"),
|
|
634
960
|
partitionBy: z.string().optional().describe("Reset running total for each partition"),
|
|
635
961
|
selectColumns: z.array(z.string()).optional().describe("Columns to include in result"),
|
|
636
|
-
|
|
962
|
+
conditions: z.array(WhereConditionSchema).optional().describe("Optional WHERE clause conditions"),
|
|
637
963
|
limit: z.preprocess(
|
|
638
964
|
coerceNumber,
|
|
639
|
-
z.number().optional().default(
|
|
965
|
+
z.number().optional().default(20).describe("Maximum rows to return")
|
|
640
966
|
)
|
|
641
967
|
});
|
|
642
968
|
var MovingAverageSchema = z.object({
|
|
@@ -645,14 +971,14 @@ var MovingAverageSchema = z.object({
|
|
|
645
971
|
orderBy: z.string().describe("Column(s) to order by"),
|
|
646
972
|
windowSize: z.preprocess(
|
|
647
973
|
coerceNumber,
|
|
648
|
-
z.number().
|
|
974
|
+
z.number().describe("Number of rows in the moving window")
|
|
649
975
|
),
|
|
650
976
|
partitionBy: z.string().optional().describe("Column(s) to partition by"),
|
|
651
977
|
selectColumns: z.array(z.string()).optional().describe("Columns to include in result"),
|
|
652
|
-
|
|
978
|
+
conditions: z.array(WhereConditionSchema).optional().describe("Optional WHERE clause conditions"),
|
|
653
979
|
limit: z.preprocess(
|
|
654
980
|
coerceNumber,
|
|
655
|
-
z.number().optional().default(
|
|
981
|
+
z.number().optional().default(20).describe("Maximum rows to return")
|
|
656
982
|
)
|
|
657
983
|
});
|
|
658
984
|
var NtileSchema = z.object({
|
|
@@ -660,24 +986,18 @@ var NtileSchema = z.object({
|
|
|
660
986
|
orderBy: z.string().describe("Column(s) to order by"),
|
|
661
987
|
buckets: z.preprocess(
|
|
662
988
|
coerceNumber,
|
|
663
|
-
z.number().
|
|
989
|
+
z.number().describe("Number of buckets (e.g., 4 for quartiles)")
|
|
664
990
|
),
|
|
665
991
|
partitionBy: z.string().optional().describe("Column(s) to partition by"),
|
|
666
992
|
selectColumns: z.array(z.string()).optional().describe("Columns to include in result"),
|
|
667
|
-
|
|
993
|
+
conditions: z.array(WhereConditionSchema).optional().describe("Optional WHERE clause conditions"),
|
|
668
994
|
limit: z.preprocess(
|
|
669
995
|
coerceNumber,
|
|
670
|
-
z.number().optional().default(
|
|
996
|
+
z.number().optional().default(20).describe("Maximum rows to return")
|
|
671
997
|
)
|
|
672
998
|
});
|
|
673
999
|
async function validateTableExists2(adapter, table) {
|
|
674
|
-
|
|
675
|
-
throw new DbMcpError(
|
|
676
|
-
"Invalid table name",
|
|
677
|
-
"NATIVE_WINDOW_INVALID_TABLE",
|
|
678
|
-
"validation" /* VALIDATION */
|
|
679
|
-
);
|
|
680
|
-
}
|
|
1000
|
+
validateIdentifier(table);
|
|
681
1001
|
const result = await adapter.executeReadQuery(
|
|
682
1002
|
`SELECT 1 FROM sqlite_master WHERE type IN ('table', 'view') AND name='${table}'`
|
|
683
1003
|
);
|
|
@@ -694,13 +1014,7 @@ async function validateTableExists2(adapter, table) {
|
|
|
694
1014
|
}
|
|
695
1015
|
}
|
|
696
1016
|
async function validateColumnInTable(adapter, table, column) {
|
|
697
|
-
|
|
698
|
-
throw new DbMcpError(
|
|
699
|
-
"Invalid column name",
|
|
700
|
-
"NATIVE_WINDOW_INVALID_COLUMN",
|
|
701
|
-
"validation" /* VALIDATION */
|
|
702
|
-
);
|
|
703
|
-
}
|
|
1017
|
+
validateIdentifier(column);
|
|
704
1018
|
const tableInfo = await adapter.executeReadQuery(
|
|
705
1019
|
`SELECT name FROM pragma_table_info('${table}') WHERE name='${column}'`
|
|
706
1020
|
);
|
|
@@ -723,16 +1037,128 @@ async function validateOrderByColumns(adapter, table, orderBy) {
|
|
|
723
1037
|
const firstToken = tokens[0];
|
|
724
1038
|
if (!firstToken) continue;
|
|
725
1039
|
const colName = firstToken.replace(/^"|"$/g, "");
|
|
726
|
-
if (/[
|
|
1040
|
+
if (/[;()+*/]/.test(colName)) {
|
|
1041
|
+
throw new DbMcpError(
|
|
1042
|
+
`Invalid ORDER BY expression: '${colName}' contains disallowed characters. Only column names with optional ASC/DESC are permitted.`,
|
|
1043
|
+
"NATIVE_WINDOW_INVALID_ORDERBY",
|
|
1044
|
+
"validation" /* VALIDATION */
|
|
1045
|
+
);
|
|
1046
|
+
}
|
|
727
1047
|
if (/^(ASC|DESC)$/i.test(colName)) continue;
|
|
1048
|
+
if (colName.includes(".")) {
|
|
1049
|
+
for (const segment of colName.split(".")) {
|
|
1050
|
+
validateIdentifier(segment);
|
|
1051
|
+
}
|
|
1052
|
+
continue;
|
|
1053
|
+
}
|
|
728
1054
|
await validateColumnInTable(adapter, table, colName);
|
|
729
1055
|
}
|
|
730
1056
|
}
|
|
731
|
-
function
|
|
732
|
-
if (selectColumns
|
|
733
|
-
return
|
|
1057
|
+
async function resolveSelectColumns(adapter, table, selectColumns, rankCol) {
|
|
1058
|
+
if (selectColumns && selectColumns.length > 0) {
|
|
1059
|
+
return {
|
|
1060
|
+
columnList: selectColumns.map((c) => sanitizeIdentifier(c)).join(", ")
|
|
1061
|
+
};
|
|
1062
|
+
}
|
|
1063
|
+
const tableInfo = await adapter.executeReadQuery(
|
|
1064
|
+
`PRAGMA table_info('${table}')`
|
|
1065
|
+
);
|
|
1066
|
+
const TEXT_TYPES = /* @__PURE__ */ new Set([
|
|
1067
|
+
"text",
|
|
1068
|
+
"blob",
|
|
1069
|
+
"clob",
|
|
1070
|
+
"varchar",
|
|
1071
|
+
"nvarchar",
|
|
1072
|
+
"char"
|
|
1073
|
+
]);
|
|
1074
|
+
const LONG_CONTENT_PATTERNS = [
|
|
1075
|
+
"description",
|
|
1076
|
+
"body",
|
|
1077
|
+
"bio",
|
|
1078
|
+
"content",
|
|
1079
|
+
"notes",
|
|
1080
|
+
"summary",
|
|
1081
|
+
"comment",
|
|
1082
|
+
"details",
|
|
1083
|
+
"html",
|
|
1084
|
+
"markdown",
|
|
1085
|
+
"text",
|
|
1086
|
+
"message",
|
|
1087
|
+
"payload",
|
|
1088
|
+
"raw",
|
|
1089
|
+
"data",
|
|
1090
|
+
"log",
|
|
1091
|
+
"blob"
|
|
1092
|
+
];
|
|
1093
|
+
const excluded = [];
|
|
1094
|
+
const included = [];
|
|
1095
|
+
for (const c of tableInfo.rows ?? []) {
|
|
1096
|
+
const colName = c["name"];
|
|
1097
|
+
const colType = (c["type"] ?? "").toLowerCase();
|
|
1098
|
+
const nameLower = colName.toLowerCase();
|
|
1099
|
+
const isText = [...TEXT_TYPES].some(
|
|
1100
|
+
(t) => colType === t || colType.startsWith(t)
|
|
1101
|
+
);
|
|
1102
|
+
const isRankCol = rankCol ? nameLower === rankCol.toLowerCase() : false;
|
|
1103
|
+
const isLongContent = LONG_CONTENT_PATTERNS.some(
|
|
1104
|
+
(p) => nameLower === p || nameLower.endsWith(`_${p}`) || nameLower.startsWith(`${p}_`)
|
|
1105
|
+
);
|
|
1106
|
+
if (isText && !isRankCol && isLongContent) {
|
|
1107
|
+
excluded.push(colName);
|
|
1108
|
+
} else {
|
|
1109
|
+
included.push(colName);
|
|
1110
|
+
}
|
|
734
1111
|
}
|
|
735
|
-
|
|
1112
|
+
if (included.length > 10) {
|
|
1113
|
+
throw new ValidationError(
|
|
1114
|
+
`Table '${table}' has too many columns (${included.length} remaining after text filtering). You must explicitly provide 'selectColumns' to prevent context window bloat.`,
|
|
1115
|
+
"INVALID_INPUT"
|
|
1116
|
+
);
|
|
1117
|
+
}
|
|
1118
|
+
if (excluded.length > 0 && included.length > 0) {
|
|
1119
|
+
return {
|
|
1120
|
+
columnList: included.map((c) => sanitizeIdentifier(c)).join(", "),
|
|
1121
|
+
hint: `Excluded ${excluded.length} long-content column(s) (${excluded.join(", ")}) to reduce payload. Use selectColumns to override.`
|
|
1122
|
+
};
|
|
1123
|
+
}
|
|
1124
|
+
return { columnList: "*" };
|
|
1125
|
+
}
|
|
1126
|
+
function sanitizePartitionBy(partitionBy) {
|
|
1127
|
+
const columns = partitionBy.split(",").map((c) => c.trim()).filter(Boolean);
|
|
1128
|
+
for (const col of columns) {
|
|
1129
|
+
validateIdentifier(col);
|
|
1130
|
+
}
|
|
1131
|
+
return columns.map((c) => sanitizeIdentifier(c)).join(", ");
|
|
1132
|
+
}
|
|
1133
|
+
function sanitizeOrderByExpr(orderBy) {
|
|
1134
|
+
const parts = orderBy.split(",");
|
|
1135
|
+
const sanitized = [];
|
|
1136
|
+
for (const part of parts) {
|
|
1137
|
+
const tokens = part.trim().split(/\s+/);
|
|
1138
|
+
const colToken = tokens[0];
|
|
1139
|
+
if (!colToken) continue;
|
|
1140
|
+
const colName = colToken.replace(/^"|"$/g, "");
|
|
1141
|
+
validateIdentifier(colName);
|
|
1142
|
+
const direction = tokens[1];
|
|
1143
|
+
if (direction && /^(ASC|DESC)$/i.test(direction)) {
|
|
1144
|
+
sanitized.push(
|
|
1145
|
+
`${sanitizeIdentifier(colName)} ${direction.toUpperCase()}`
|
|
1146
|
+
);
|
|
1147
|
+
} else {
|
|
1148
|
+
sanitized.push(sanitizeIdentifier(colName));
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
return sanitized.join(", ");
|
|
1152
|
+
}
|
|
1153
|
+
function validateDefaultValue(value) {
|
|
1154
|
+
if (/^-?\d+(\.\d+)?$/.test(value)) return;
|
|
1155
|
+
if (/^'[^']*'$/.test(value)) return;
|
|
1156
|
+
if (/^NULL$/i.test(value)) return;
|
|
1157
|
+
throw new DbMcpError(
|
|
1158
|
+
`Invalid default value: '${value}'. Only numeric literals, single-quoted strings, or NULL are permitted.`,
|
|
1159
|
+
"NATIVE_WINDOW_INVALID_DEFAULT",
|
|
1160
|
+
"validation" /* VALIDATION */
|
|
1161
|
+
);
|
|
736
1162
|
}
|
|
737
1163
|
function getWindowTools(adapter) {
|
|
738
1164
|
return [
|
|
@@ -754,28 +1180,41 @@ function createRowNumberTool(adapter) {
|
|
|
754
1180
|
annotations: readOnly("Window Row Number"),
|
|
755
1181
|
requiredScopes: ["read"],
|
|
756
1182
|
handler: async (params, _context) => {
|
|
1183
|
+
const queryParams = [];
|
|
757
1184
|
try {
|
|
758
1185
|
const input = RowNumberSchema.parse(params);
|
|
759
1186
|
await validateTableExists2(adapter, input.table);
|
|
760
1187
|
await validateOrderByColumns(adapter, input.table, input.orderBy);
|
|
761
|
-
const columns =
|
|
762
|
-
|
|
1188
|
+
const { columnList: columns, hint } = await resolveSelectColumns(
|
|
1189
|
+
adapter,
|
|
1190
|
+
input.table,
|
|
1191
|
+
input.selectColumns
|
|
1192
|
+
);
|
|
1193
|
+
const partition = input.partitionBy ? `PARTITION BY ${sanitizePartitionBy(input.partitionBy)}` : "";
|
|
1194
|
+
const orderByExpr = sanitizeOrderByExpr(input.orderBy);
|
|
763
1195
|
let sql = `
|
|
764
1196
|
SELECT ${columns},
|
|
765
|
-
ROW_NUMBER() OVER (${partition} ORDER BY ${
|
|
766
|
-
FROM
|
|
1197
|
+
ROW_NUMBER() OVER (${partition} ORDER BY ${orderByExpr}) as row_number
|
|
1198
|
+
FROM ${sanitizeIdentifier(input.table)}
|
|
767
1199
|
`;
|
|
768
|
-
if (input.
|
|
769
|
-
|
|
770
|
-
|
|
1200
|
+
if (input.conditions) {
|
|
1201
|
+
const { sql: whereSql, params: whereParams } = buildWhereClause(
|
|
1202
|
+
input.conditions
|
|
1203
|
+
);
|
|
1204
|
+
if (whereSql !== "") {
|
|
1205
|
+
sql += ` WHERE ${whereSql}`;
|
|
1206
|
+
queryParams.push(...whereParams);
|
|
1207
|
+
}
|
|
771
1208
|
}
|
|
772
1209
|
sql += ` LIMIT ${input.limit}`;
|
|
773
|
-
const result = await adapter.executeReadQuery(sql);
|
|
774
|
-
|
|
1210
|
+
const result = await adapter.executeReadQuery(sql, queryParams);
|
|
1211
|
+
const response = {
|
|
775
1212
|
success: true,
|
|
776
1213
|
rowCount: result.rows?.length ?? 0,
|
|
777
1214
|
rows: result.rows
|
|
778
1215
|
};
|
|
1216
|
+
if (hint) response["hint"] = hint;
|
|
1217
|
+
return response;
|
|
779
1218
|
} catch (error) {
|
|
780
1219
|
return formatHandlerError(error);
|
|
781
1220
|
}
|
|
@@ -794,28 +1233,41 @@ function createRankTool(adapter) {
|
|
|
794
1233
|
handler: async (params, _context) => {
|
|
795
1234
|
try {
|
|
796
1235
|
const input = RankSchema.parse(params);
|
|
1236
|
+
const queryParams = [];
|
|
797
1237
|
await validateTableExists2(adapter, input.table);
|
|
798
1238
|
await validateOrderByColumns(adapter, input.table, input.orderBy);
|
|
799
|
-
const columns =
|
|
800
|
-
|
|
1239
|
+
const { columnList: columns, hint } = await resolveSelectColumns(
|
|
1240
|
+
adapter,
|
|
1241
|
+
input.table,
|
|
1242
|
+
input.selectColumns
|
|
1243
|
+
);
|
|
1244
|
+
const partition = input.partitionBy ? `PARTITION BY ${sanitizePartitionBy(input.partitionBy)}` : "";
|
|
801
1245
|
const rankFunc = input.rankType.toUpperCase();
|
|
1246
|
+
const orderByExpr = sanitizeOrderByExpr(input.orderBy);
|
|
802
1247
|
let sql = `
|
|
803
1248
|
SELECT ${columns},
|
|
804
|
-
${rankFunc}() OVER (${partition} ORDER BY ${
|
|
805
|
-
FROM
|
|
1249
|
+
${rankFunc}() OVER (${partition} ORDER BY ${orderByExpr}) as ${input.rankType}
|
|
1250
|
+
FROM ${sanitizeIdentifier(input.table)}
|
|
806
1251
|
`;
|
|
807
|
-
if (input.
|
|
808
|
-
|
|
809
|
-
|
|
1252
|
+
if (input.conditions) {
|
|
1253
|
+
const { sql: whereSql, params: whereParams } = buildWhereClause(
|
|
1254
|
+
input.conditions
|
|
1255
|
+
);
|
|
1256
|
+
if (whereSql !== "") {
|
|
1257
|
+
sql += ` WHERE ${whereSql}`;
|
|
1258
|
+
queryParams.push(...whereParams);
|
|
1259
|
+
}
|
|
810
1260
|
}
|
|
811
1261
|
sql += ` LIMIT ${input.limit}`;
|
|
812
|
-
const result = await adapter.executeReadQuery(sql);
|
|
813
|
-
|
|
1262
|
+
const result = await adapter.executeReadQuery(sql, queryParams);
|
|
1263
|
+
const response = {
|
|
814
1264
|
success: true,
|
|
815
1265
|
rankType: input.rankType,
|
|
816
1266
|
rowCount: result.rows?.length ?? 0,
|
|
817
1267
|
rows: result.rows
|
|
818
1268
|
};
|
|
1269
|
+
if (hint) response["hint"] = hint;
|
|
1270
|
+
return response;
|
|
819
1271
|
} catch (error) {
|
|
820
1272
|
return formatHandlerError(error);
|
|
821
1273
|
}
|
|
@@ -833,7 +1285,10 @@ function createLagLeadTool(adapter) {
|
|
|
833
1285
|
requiredScopes: ["read"],
|
|
834
1286
|
handler: async (params, _context) => {
|
|
835
1287
|
try {
|
|
836
|
-
const input = LagLeadSchema.parse(
|
|
1288
|
+
const input = LagLeadSchema.parse(
|
|
1289
|
+
resolveAliases(params, { valueColumn: "column" })
|
|
1290
|
+
);
|
|
1291
|
+
const queryParams = [];
|
|
837
1292
|
const normalizedDirection = input.direction.toLowerCase();
|
|
838
1293
|
if (!VALID_DIRECTIONS.includes(
|
|
839
1294
|
normalizedDirection
|
|
@@ -849,28 +1304,45 @@ function createLagLeadTool(adapter) {
|
|
|
849
1304
|
await validateTableExists2(adapter, input.table);
|
|
850
1305
|
await validateColumnInTable(adapter, input.table, input.column);
|
|
851
1306
|
await validateOrderByColumns(adapter, input.table, input.orderBy);
|
|
852
|
-
const columns =
|
|
853
|
-
|
|
1307
|
+
const { columnList: columns, hint } = await resolveSelectColumns(
|
|
1308
|
+
adapter,
|
|
1309
|
+
input.table,
|
|
1310
|
+
input.selectColumns,
|
|
1311
|
+
input.column
|
|
1312
|
+
);
|
|
1313
|
+
const partition = input.partitionBy ? `PARTITION BY ${sanitizePartitionBy(input.partitionBy)}` : "";
|
|
854
1314
|
const func = normalizedDirection.toUpperCase();
|
|
855
|
-
|
|
1315
|
+
let defaultVal = "";
|
|
1316
|
+
if (input.defaultValue !== void 0) {
|
|
1317
|
+
validateDefaultValue(input.defaultValue);
|
|
1318
|
+
defaultVal = `, ${input.defaultValue}`;
|
|
1319
|
+
}
|
|
1320
|
+
const orderByExpr = sanitizeOrderByExpr(input.orderBy);
|
|
856
1321
|
let sql = `
|
|
857
1322
|
SELECT ${columns},
|
|
858
|
-
${func}(
|
|
859
|
-
FROM
|
|
1323
|
+
${func}(${sanitizeIdentifier(input.column)}, ${input.offset}${defaultVal}) OVER (${partition} ORDER BY ${orderByExpr}) as ${normalizedDirection}_value
|
|
1324
|
+
FROM ${sanitizeIdentifier(input.table)}
|
|
860
1325
|
`;
|
|
861
|
-
if (input.
|
|
862
|
-
|
|
863
|
-
|
|
1326
|
+
if (input.conditions) {
|
|
1327
|
+
const { sql: whereSql, params: whereParams } = buildWhereClause(
|
|
1328
|
+
input.conditions
|
|
1329
|
+
);
|
|
1330
|
+
if (whereSql !== "") {
|
|
1331
|
+
sql += ` WHERE ${whereSql}`;
|
|
1332
|
+
queryParams.push(...whereParams);
|
|
1333
|
+
}
|
|
864
1334
|
}
|
|
865
1335
|
sql += ` LIMIT ${input.limit}`;
|
|
866
|
-
const result = await adapter.executeReadQuery(sql);
|
|
867
|
-
|
|
1336
|
+
const result = await adapter.executeReadQuery(sql, queryParams);
|
|
1337
|
+
const response = {
|
|
868
1338
|
success: true,
|
|
869
1339
|
direction: normalizedDirection,
|
|
870
1340
|
offset: input.offset,
|
|
871
1341
|
rowCount: result.rows?.length ?? 0,
|
|
872
1342
|
rows: result.rows
|
|
873
1343
|
};
|
|
1344
|
+
if (hint) response["hint"] = hint;
|
|
1345
|
+
return response;
|
|
874
1346
|
} catch (error) {
|
|
875
1347
|
return formatHandlerError(error);
|
|
876
1348
|
}
|
|
@@ -887,6 +1359,7 @@ function createRunningTotalTool(adapter) {
|
|
|
887
1359
|
annotations: readOnly("Window Running Total"),
|
|
888
1360
|
requiredScopes: ["read"],
|
|
889
1361
|
handler: async (params, _context) => {
|
|
1362
|
+
const queryParams = [];
|
|
890
1363
|
try {
|
|
891
1364
|
const input = RunningTotalSchema.parse(
|
|
892
1365
|
resolveAliases(params, { valueColumn: "column" })
|
|
@@ -894,25 +1367,38 @@ function createRunningTotalTool(adapter) {
|
|
|
894
1367
|
await validateTableExists2(adapter, input.table);
|
|
895
1368
|
await validateColumnInTable(adapter, input.table, input.column);
|
|
896
1369
|
await validateOrderByColumns(adapter, input.table, input.orderBy);
|
|
897
|
-
const columns =
|
|
898
|
-
|
|
1370
|
+
const { columnList: columns, hint } = await resolveSelectColumns(
|
|
1371
|
+
adapter,
|
|
1372
|
+
input.table,
|
|
1373
|
+
input.selectColumns,
|
|
1374
|
+
input.column
|
|
1375
|
+
);
|
|
1376
|
+
const partition = input.partitionBy ? `PARTITION BY ${sanitizePartitionBy(input.partitionBy)}` : "";
|
|
1377
|
+
const orderByExpr = sanitizeOrderByExpr(input.orderBy);
|
|
899
1378
|
let sql = `
|
|
900
1379
|
SELECT ${columns},
|
|
901
|
-
SUM(
|
|
902
|
-
FROM
|
|
1380
|
+
SUM(${sanitizeIdentifier(input.column)}) OVER (${partition} ORDER BY ${orderByExpr} ROWS UNBOUNDED PRECEDING) as running_total
|
|
1381
|
+
FROM ${sanitizeIdentifier(input.table)}
|
|
903
1382
|
`;
|
|
904
|
-
if (input.
|
|
905
|
-
|
|
906
|
-
|
|
1383
|
+
if (input.conditions) {
|
|
1384
|
+
const { sql: whereSql, params: whereParams } = buildWhereClause(
|
|
1385
|
+
input.conditions
|
|
1386
|
+
);
|
|
1387
|
+
if (whereSql !== "") {
|
|
1388
|
+
sql += ` WHERE ${whereSql}`;
|
|
1389
|
+
queryParams.push(...whereParams);
|
|
1390
|
+
}
|
|
907
1391
|
}
|
|
908
1392
|
sql += ` LIMIT ${input.limit}`;
|
|
909
|
-
const result = await adapter.executeReadQuery(sql);
|
|
910
|
-
|
|
1393
|
+
const result = await adapter.executeReadQuery(sql, queryParams);
|
|
1394
|
+
const response = {
|
|
911
1395
|
success: true,
|
|
912
1396
|
valueColumn: input.column,
|
|
913
1397
|
rowCount: result.rows?.length ?? 0,
|
|
914
1398
|
rows: result.rows
|
|
915
1399
|
};
|
|
1400
|
+
if (hint) response["hint"] = hint;
|
|
1401
|
+
return response;
|
|
916
1402
|
} catch (error) {
|
|
917
1403
|
return formatHandlerError(error);
|
|
918
1404
|
}
|
|
@@ -929,43 +1415,48 @@ function createMovingAverageTool(adapter) {
|
|
|
929
1415
|
annotations: readOnly("Window Moving Average"),
|
|
930
1416
|
requiredScopes: ["read"],
|
|
931
1417
|
handler: async (params, _context) => {
|
|
1418
|
+
const queryParams = [];
|
|
932
1419
|
try {
|
|
933
1420
|
const input = MovingAverageSchema.parse(
|
|
934
1421
|
resolveAliases(params, { valueColumn: "column" })
|
|
935
1422
|
);
|
|
936
|
-
if (input.windowSize === void 0) {
|
|
937
|
-
return {
|
|
938
|
-
success: false,
|
|
939
|
-
error: "'windowSize' is required",
|
|
940
|
-
code: "VALIDATION_ERROR",
|
|
941
|
-
category: "validation",
|
|
942
|
-
recoverable: false
|
|
943
|
-
};
|
|
944
|
-
}
|
|
945
1423
|
await validateTableExists2(adapter, input.table);
|
|
946
1424
|
await validateColumnInTable(adapter, input.table, input.column);
|
|
947
1425
|
await validateOrderByColumns(adapter, input.table, input.orderBy);
|
|
948
|
-
const columns =
|
|
949
|
-
|
|
1426
|
+
const { columnList: columns, hint } = await resolveSelectColumns(
|
|
1427
|
+
adapter,
|
|
1428
|
+
input.table,
|
|
1429
|
+
input.selectColumns,
|
|
1430
|
+
input.column
|
|
1431
|
+
);
|
|
1432
|
+
const partition = input.partitionBy ? `PARTITION BY ${sanitizePartitionBy(input.partitionBy)}` : "";
|
|
950
1433
|
const preceding = input.windowSize - 1;
|
|
1434
|
+
const orderByExpr = sanitizeOrderByExpr(input.orderBy);
|
|
951
1435
|
let sql = `
|
|
952
1436
|
SELECT ${columns},
|
|
953
|
-
AVG(
|
|
954
|
-
FROM
|
|
1437
|
+
AVG(${sanitizeIdentifier(input.column)}) OVER (${partition} ORDER BY ${orderByExpr} ROWS BETWEEN ${preceding} PRECEDING AND CURRENT ROW) as moving_avg
|
|
1438
|
+
FROM ${sanitizeIdentifier(input.table)}
|
|
955
1439
|
`;
|
|
956
|
-
if (input.
|
|
957
|
-
|
|
958
|
-
|
|
1440
|
+
if (input.conditions) {
|
|
1441
|
+
const { sql: whereSql, params: whereParams } = buildWhereClause(
|
|
1442
|
+
input.conditions
|
|
1443
|
+
);
|
|
1444
|
+
if (whereSql !== "") {
|
|
1445
|
+
sql += ` WHERE ${whereSql}`;
|
|
1446
|
+
queryParams.push(...whereParams);
|
|
1447
|
+
}
|
|
959
1448
|
}
|
|
960
1449
|
sql += ` LIMIT ${input.limit}`;
|
|
961
|
-
const result = await adapter.executeReadQuery(sql);
|
|
962
|
-
|
|
1450
|
+
const result = await adapter.executeReadQuery(sql, queryParams);
|
|
1451
|
+
const response = {
|
|
963
1452
|
success: true,
|
|
964
1453
|
valueColumn: input.column,
|
|
965
1454
|
windowSize: input.windowSize,
|
|
966
1455
|
rowCount: result.rows?.length ?? 0,
|
|
967
1456
|
rows: result.rows
|
|
968
1457
|
};
|
|
1458
|
+
if (hint) response["hint"] = hint;
|
|
1459
|
+
return response;
|
|
969
1460
|
} catch (error) {
|
|
970
1461
|
return formatHandlerError(error);
|
|
971
1462
|
}
|
|
@@ -984,43 +1475,54 @@ function createNtileTool(adapter) {
|
|
|
984
1475
|
handler: async (params, _context) => {
|
|
985
1476
|
try {
|
|
986
1477
|
const input = NtileSchema.parse(params);
|
|
987
|
-
|
|
988
|
-
return {
|
|
989
|
-
success: false,
|
|
990
|
-
error: "'buckets' is required",
|
|
991
|
-
code: "VALIDATION_ERROR",
|
|
992
|
-
category: "validation",
|
|
993
|
-
recoverable: false
|
|
994
|
-
};
|
|
995
|
-
}
|
|
1478
|
+
const queryParams = [];
|
|
996
1479
|
await validateTableExists2(adapter, input.table);
|
|
997
1480
|
await validateOrderByColumns(adapter, input.table, input.orderBy);
|
|
998
|
-
const columns =
|
|
999
|
-
|
|
1481
|
+
const { columnList: columns, hint } = await resolveSelectColumns(
|
|
1482
|
+
adapter,
|
|
1483
|
+
input.table,
|
|
1484
|
+
input.selectColumns
|
|
1485
|
+
);
|
|
1486
|
+
const partition = input.partitionBy ? `PARTITION BY ${sanitizePartitionBy(input.partitionBy)}` : "";
|
|
1487
|
+
const orderByExpr = sanitizeOrderByExpr(input.orderBy);
|
|
1000
1488
|
let sql = `
|
|
1001
1489
|
SELECT ${columns},
|
|
1002
|
-
NTILE(${input.buckets}) OVER (${partition} ORDER BY ${
|
|
1003
|
-
FROM
|
|
1490
|
+
NTILE(${input.buckets}) OVER (${partition} ORDER BY ${orderByExpr}) as ntile
|
|
1491
|
+
FROM ${sanitizeIdentifier(input.table)}
|
|
1004
1492
|
`;
|
|
1005
|
-
if (input.
|
|
1006
|
-
|
|
1007
|
-
|
|
1493
|
+
if (input.conditions) {
|
|
1494
|
+
const { sql: whereSql, params: whereParams } = buildWhereClause(
|
|
1495
|
+
input.conditions
|
|
1496
|
+
);
|
|
1497
|
+
if (whereSql !== "") {
|
|
1498
|
+
sql += ` WHERE ${whereSql}`;
|
|
1499
|
+
queryParams.push(...whereParams);
|
|
1500
|
+
}
|
|
1008
1501
|
}
|
|
1009
1502
|
sql += ` LIMIT ${input.limit}`;
|
|
1010
|
-
const result = await adapter.executeReadQuery(sql);
|
|
1011
|
-
|
|
1503
|
+
const result = await adapter.executeReadQuery(sql, queryParams);
|
|
1504
|
+
const response = {
|
|
1012
1505
|
success: true,
|
|
1013
1506
|
buckets: input.buckets,
|
|
1014
1507
|
rowCount: result.rows?.length ?? 0,
|
|
1015
1508
|
rows: result.rows
|
|
1016
1509
|
};
|
|
1510
|
+
if (hint) response["hint"] = hint;
|
|
1511
|
+
return response;
|
|
1017
1512
|
} catch (error) {
|
|
1018
1513
|
return formatHandlerError(error);
|
|
1019
1514
|
}
|
|
1020
1515
|
}
|
|
1021
1516
|
};
|
|
1022
1517
|
}
|
|
1023
|
-
var coerceNumber2 = (val) =>
|
|
1518
|
+
var coerceNumber2 = (val) => {
|
|
1519
|
+
if (typeof val === "string") {
|
|
1520
|
+
if (val.trim() === "") return void 0;
|
|
1521
|
+
const num = Number(val);
|
|
1522
|
+
return isNaN(num) ? val : num;
|
|
1523
|
+
}
|
|
1524
|
+
return val;
|
|
1525
|
+
};
|
|
1024
1526
|
var coerceBoolean = (val) => typeof val === "string" ? val === "true" ? true : val === "false" ? false : void 0 : val;
|
|
1025
1527
|
function createEnumCoercer(validValues) {
|
|
1026
1528
|
return (val) => typeof val === "string" && validValues.includes(val) ? val : typeof val === "string" ? void 0 : val;
|
|
@@ -1051,9 +1553,20 @@ var VALID_OPERATIONS = [
|
|
|
1051
1553
|
"envelope",
|
|
1052
1554
|
"simplify"
|
|
1053
1555
|
];
|
|
1556
|
+
var VALID_COLUMN_TYPES = [
|
|
1557
|
+
"TEXT",
|
|
1558
|
+
"INTEGER",
|
|
1559
|
+
"REAL",
|
|
1560
|
+
"BLOB",
|
|
1561
|
+
"NUMERIC",
|
|
1562
|
+
"VARCHAR",
|
|
1563
|
+
"BOOLEAN",
|
|
1564
|
+
"DATE",
|
|
1565
|
+
"DATETIME",
|
|
1566
|
+
"TIMESTAMP"
|
|
1567
|
+
];
|
|
1054
1568
|
var coerceGeometryType = createEnumCoercer(VALID_GEOMETRY_TYPES);
|
|
1055
1569
|
var LoadSpatialiteSchema = z.object({
|
|
1056
|
-
extensionPath: z.string().optional().describe("Custom path to mod_spatialite extension"),
|
|
1057
1570
|
forceReload: z.preprocess(
|
|
1058
1571
|
coerceBoolean,
|
|
1059
1572
|
z.boolean().optional().default(false).describe("Force reload if already loaded")
|
|
@@ -1081,7 +1594,7 @@ var CreateSpatialTableSchema = z.object({
|
|
|
1081
1594
|
additionalColumns: z.array(
|
|
1082
1595
|
z.object({
|
|
1083
1596
|
name: z.string(),
|
|
1084
|
-
type: z.
|
|
1597
|
+
type: z.enum(VALID_COLUMN_TYPES).optional().default("TEXT")
|
|
1085
1598
|
})
|
|
1086
1599
|
).optional().default([]).describe("Additional non-spatial columns")
|
|
1087
1600
|
});
|
|
@@ -1151,8 +1664,9 @@ var SpatialImportSchema = z.object({
|
|
|
1151
1664
|
),
|
|
1152
1665
|
additionalData: z.record(z.string(), z.unknown()).optional().describe("Additional column values")
|
|
1153
1666
|
});
|
|
1154
|
-
|
|
1155
|
-
|
|
1667
|
+
var require2 = createRequire(import.meta.url);
|
|
1668
|
+
var __filename$1 = fileURLToPath(import.meta.url);
|
|
1669
|
+
var __dirname$1 = path2.dirname(__filename$1);
|
|
1156
1670
|
var SPATIALITE_PATHS = [
|
|
1157
1671
|
process.env["SPATIALITE_PATH"],
|
|
1158
1672
|
"mod_spatialite",
|
|
@@ -1163,20 +1677,27 @@ var SPATIALITE_PATHS = [
|
|
|
1163
1677
|
"/usr/local/lib/mod_spatialite.dylib"
|
|
1164
1678
|
].filter((p) => Boolean(p));
|
|
1165
1679
|
var loadedDatabases = /* @__PURE__ */ new WeakSet();
|
|
1166
|
-
function tryLoadSpatialite(adapter
|
|
1680
|
+
function tryLoadSpatialite(adapter) {
|
|
1167
1681
|
const db = adapter.getDatabase();
|
|
1168
1682
|
if (db === null) {
|
|
1169
1683
|
return { success: false, error: "Database not connected" };
|
|
1170
1684
|
}
|
|
1171
|
-
const paths =
|
|
1172
|
-
const chosenPathForEnv =
|
|
1685
|
+
const paths = SPATIALITE_PATHS;
|
|
1686
|
+
const chosenPathForEnv = process.env["SPATIALITE_PATH"];
|
|
1687
|
+
let dllCookie = null;
|
|
1688
|
+
let win32Dll = null;
|
|
1173
1689
|
if (process.platform === "win32" && chosenPathForEnv) {
|
|
1174
1690
|
const looksLikeFsPath = chosenPathForEnv.includes("/") || chosenPathForEnv.includes("\\");
|
|
1175
1691
|
if (looksLikeFsPath) {
|
|
1176
1692
|
const extensionDir = chosenPathForEnv.replace(/[/\\][^/\\]+$/, "");
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1693
|
+
try {
|
|
1694
|
+
const addonPath = path2.resolve(
|
|
1695
|
+
__dirname$1,
|
|
1696
|
+
"../../../../../build/Release/win32_dll.node"
|
|
1697
|
+
);
|
|
1698
|
+
win32Dll = require2(addonPath);
|
|
1699
|
+
dllCookie = win32Dll.addDllDirectory(extensionDir);
|
|
1700
|
+
} catch {
|
|
1180
1701
|
}
|
|
1181
1702
|
}
|
|
1182
1703
|
}
|
|
@@ -1185,10 +1706,16 @@ function tryLoadSpatialite(adapter, customPath) {
|
|
|
1185
1706
|
db.loadExtension(candidatePath);
|
|
1186
1707
|
db.exec("SELECT InitSpatialMetaData(1)");
|
|
1187
1708
|
loadedDatabases.add(db);
|
|
1709
|
+
if (win32Dll !== null && dllCookie !== null) {
|
|
1710
|
+
win32Dll.removeDllDirectory(dllCookie);
|
|
1711
|
+
}
|
|
1188
1712
|
return { success: true, path: candidatePath };
|
|
1189
1713
|
} catch {
|
|
1190
1714
|
}
|
|
1191
1715
|
}
|
|
1716
|
+
if (win32Dll !== null && dllCookie !== null) {
|
|
1717
|
+
win32Dll.removeDllDirectory(dllCookie);
|
|
1718
|
+
}
|
|
1192
1719
|
return {
|
|
1193
1720
|
success: false,
|
|
1194
1721
|
error: "SpatiaLite extension not found. Install mod_spatialite and set SPATIALITE_PATH environment variable."
|
|
@@ -1211,11 +1738,9 @@ function ensureSpatialite(adapter) {
|
|
|
1211
1738
|
if (!isSpatialiteLoaded(adapter)) {
|
|
1212
1739
|
const result = tryLoadSpatialite(adapter);
|
|
1213
1740
|
if (!result.success) {
|
|
1214
|
-
throw new
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
"connection" /* CONNECTION */
|
|
1218
|
-
);
|
|
1741
|
+
throw new ExtensionNotAvailableError("SpatiaLite", {
|
|
1742
|
+
suggestion: "Install mod_spatialite and set SPATIALITE_PATH environment variable."
|
|
1743
|
+
});
|
|
1219
1744
|
}
|
|
1220
1745
|
}
|
|
1221
1746
|
}
|
|
@@ -1240,7 +1765,7 @@ function createLoadSpatialiteTool(adapter) {
|
|
|
1240
1765
|
alreadyLoaded: true
|
|
1241
1766
|
});
|
|
1242
1767
|
}
|
|
1243
|
-
const result = tryLoadSpatialite(adapter
|
|
1768
|
+
const result = tryLoadSpatialite(adapter);
|
|
1244
1769
|
if (result.success) {
|
|
1245
1770
|
return Promise.resolve({
|
|
1246
1771
|
success: true,
|
|
@@ -1275,7 +1800,9 @@ function createSpatialTableTool(adapter) {
|
|
|
1275
1800
|
try {
|
|
1276
1801
|
const input = CreateSpatialTableSchema.parse(params);
|
|
1277
1802
|
ensureSpatialite(adapter);
|
|
1278
|
-
|
|
1803
|
+
try {
|
|
1804
|
+
validateIdentifier(input.tableName);
|
|
1805
|
+
} catch {
|
|
1279
1806
|
return {
|
|
1280
1807
|
success: false,
|
|
1281
1808
|
error: `Invalid table name: '${input.tableName}'`,
|
|
@@ -1284,8 +1811,20 @@ function createSpatialTableTool(adapter) {
|
|
|
1284
1811
|
recoverable: false
|
|
1285
1812
|
};
|
|
1286
1813
|
}
|
|
1814
|
+
try {
|
|
1815
|
+
validateIdentifier(input.geometryColumn);
|
|
1816
|
+
} catch {
|
|
1817
|
+
return {
|
|
1818
|
+
success: false,
|
|
1819
|
+
error: `Invalid geometry column name: '${input.geometryColumn}'`,
|
|
1820
|
+
code: "VALIDATION_ERROR",
|
|
1821
|
+
category: "validation",
|
|
1822
|
+
recoverable: false
|
|
1823
|
+
};
|
|
1824
|
+
}
|
|
1287
1825
|
const existsCheck = await adapter.executeReadQuery(
|
|
1288
|
-
`SELECT name FROM sqlite_master WHERE type='table' AND name
|
|
1826
|
+
`SELECT name FROM sqlite_master WHERE type='table' AND name=?`,
|
|
1827
|
+
[input.tableName]
|
|
1289
1828
|
);
|
|
1290
1829
|
const alreadyExists = existsCheck.rows != null && existsCheck.rows.length > 0;
|
|
1291
1830
|
if (alreadyExists) {
|
|
@@ -1298,7 +1837,9 @@ function createSpatialTableTool(adapter) {
|
|
|
1298
1837
|
}
|
|
1299
1838
|
const columns = ["id INTEGER PRIMARY KEY AUTOINCREMENT"];
|
|
1300
1839
|
for (const col of input.additionalColumns) {
|
|
1301
|
-
|
|
1840
|
+
try {
|
|
1841
|
+
validateIdentifier(col.name);
|
|
1842
|
+
} catch {
|
|
1302
1843
|
return {
|
|
1303
1844
|
success: false,
|
|
1304
1845
|
error: `Invalid column name: '${col.name}'`,
|
|
@@ -1307,10 +1848,10 @@ function createSpatialTableTool(adapter) {
|
|
|
1307
1848
|
recoverable: false
|
|
1308
1849
|
};
|
|
1309
1850
|
}
|
|
1310
|
-
columns.push(
|
|
1851
|
+
columns.push(`${sanitizeIdentifier(col.name)} ${col.type}`);
|
|
1311
1852
|
}
|
|
1312
1853
|
await adapter.executeWriteQuery(
|
|
1313
|
-
`CREATE TABLE
|
|
1854
|
+
`CREATE TABLE ${sanitizeIdentifier(input.tableName)} (${columns.join(", ")})`
|
|
1314
1855
|
);
|
|
1315
1856
|
const addResult = await adapter.executeReadQuery(
|
|
1316
1857
|
`SELECT AddGeometryColumn('${input.tableName}', '${input.geometryColumn}', ${input.srid}, '${input.geometryType}', 'XY')`
|
|
@@ -1389,7 +1930,9 @@ function createSpatialIndexTool(adapter) {
|
|
|
1389
1930
|
try {
|
|
1390
1931
|
const input = SpatialIndexSchema.parse(params);
|
|
1391
1932
|
ensureSpatialite(adapter);
|
|
1392
|
-
|
|
1933
|
+
try {
|
|
1934
|
+
validateIdentifier(input.tableName);
|
|
1935
|
+
} catch {
|
|
1393
1936
|
return {
|
|
1394
1937
|
success: false,
|
|
1395
1938
|
error: `Invalid table name: '${input.tableName}'`,
|
|
@@ -1407,8 +1950,20 @@ function createSpatialIndexTool(adapter) {
|
|
|
1407
1950
|
recoverable: false
|
|
1408
1951
|
};
|
|
1409
1952
|
}
|
|
1953
|
+
try {
|
|
1954
|
+
validateIdentifier(input.geometryColumn);
|
|
1955
|
+
} catch {
|
|
1956
|
+
return {
|
|
1957
|
+
success: false,
|
|
1958
|
+
error: `Invalid geometry column name: '${input.geometryColumn}'`,
|
|
1959
|
+
code: "VALIDATION_ERROR",
|
|
1960
|
+
category: "validation",
|
|
1961
|
+
recoverable: false
|
|
1962
|
+
};
|
|
1963
|
+
}
|
|
1410
1964
|
const tableCheck = await adapter.executeReadQuery(
|
|
1411
|
-
`SELECT name FROM sqlite_master WHERE type='table' AND name
|
|
1965
|
+
`SELECT name FROM sqlite_master WHERE type='table' AND name=?`,
|
|
1966
|
+
[input.tableName]
|
|
1412
1967
|
);
|
|
1413
1968
|
if (!tableCheck.rows || tableCheck.rows.length === 0) {
|
|
1414
1969
|
return {
|
|
@@ -1422,9 +1977,10 @@ function createSpatialIndexTool(adapter) {
|
|
|
1422
1977
|
}
|
|
1423
1978
|
const indexExists = async () => {
|
|
1424
1979
|
const idxCheck = await adapter.executeReadQuery(
|
|
1425
|
-
`SELECT
|
|
1980
|
+
`SELECT spatial_index_enabled FROM geometry_columns WHERE f_table_name = '${input.tableName}' AND f_geometry_column = '${input.geometryColumn}'`
|
|
1426
1981
|
);
|
|
1427
|
-
|
|
1982
|
+
const val = idxCheck.rows?.[0]?.["spatial_index_enabled"];
|
|
1983
|
+
return val === 1 || val === "1";
|
|
1428
1984
|
};
|
|
1429
1985
|
switch (input.action) {
|
|
1430
1986
|
case "create": {
|
|
@@ -1436,9 +1992,18 @@ function createSpatialIndexTool(adapter) {
|
|
|
1436
1992
|
action: "create"
|
|
1437
1993
|
};
|
|
1438
1994
|
}
|
|
1439
|
-
await adapter.executeReadQuery(
|
|
1440
|
-
`SELECT CreateSpatialIndex('${input.tableName}', '${input.geometryColumn}')`
|
|
1995
|
+
const createRes = await adapter.executeReadQuery(
|
|
1996
|
+
`SELECT CreateSpatialIndex('${input.tableName}', '${input.geometryColumn}') as res`
|
|
1441
1997
|
);
|
|
1998
|
+
if (createRes.rows?.[0]?.["res"] === 0) {
|
|
1999
|
+
return {
|
|
2000
|
+
success: false,
|
|
2001
|
+
error: `Failed to create spatial index on ${input.tableName}.${input.geometryColumn}`,
|
|
2002
|
+
code: "SPATIAL_INDEX_CREATE_FAILED",
|
|
2003
|
+
category: "internal",
|
|
2004
|
+
recoverable: false
|
|
2005
|
+
};
|
|
2006
|
+
}
|
|
1442
2007
|
return {
|
|
1443
2008
|
success: true,
|
|
1444
2009
|
message: `Spatial index created on ${input.tableName}.${input.geometryColumn}`,
|
|
@@ -1454,9 +2019,18 @@ function createSpatialIndexTool(adapter) {
|
|
|
1454
2019
|
action: "drop"
|
|
1455
2020
|
};
|
|
1456
2021
|
}
|
|
1457
|
-
await adapter.executeReadQuery(
|
|
1458
|
-
`SELECT DisableSpatialIndex('${input.tableName}', '${input.geometryColumn}')`
|
|
2022
|
+
const dropRes = await adapter.executeReadQuery(
|
|
2023
|
+
`SELECT DisableSpatialIndex('${input.tableName}', '${input.geometryColumn}') as res`
|
|
1459
2024
|
);
|
|
2025
|
+
if (dropRes.rows?.[0]?.["res"] === 0) {
|
|
2026
|
+
return {
|
|
2027
|
+
success: false,
|
|
2028
|
+
error: `Failed to drop spatial index on ${input.tableName}.${input.geometryColumn}`,
|
|
2029
|
+
code: "SPATIAL_INDEX_DROP_FAILED",
|
|
2030
|
+
category: "internal",
|
|
2031
|
+
recoverable: false
|
|
2032
|
+
};
|
|
2033
|
+
}
|
|
1460
2034
|
return {
|
|
1461
2035
|
success: true,
|
|
1462
2036
|
message: `Spatial index dropped from ${input.tableName}.${input.geometryColumn}`,
|
|
@@ -1531,6 +2105,7 @@ function createSpatialAnalysisTool(adapter) {
|
|
|
1531
2105
|
requiredScopes: ["read"],
|
|
1532
2106
|
annotations: readOnly("SpatiaLite Analyze"),
|
|
1533
2107
|
handler: async (params, _context) => {
|
|
2108
|
+
const queryParams = [];
|
|
1534
2109
|
try {
|
|
1535
2110
|
const input = SpatialAnalysisSchema.parse(params);
|
|
1536
2111
|
ensureSpatialite(adapter);
|
|
@@ -1545,7 +2120,9 @@ function createSpatialAnalysisTool(adapter) {
|
|
|
1545
2120
|
recoverable: false
|
|
1546
2121
|
};
|
|
1547
2122
|
}
|
|
1548
|
-
|
|
2123
|
+
try {
|
|
2124
|
+
validateIdentifier(input.sourceTable);
|
|
2125
|
+
} catch {
|
|
1549
2126
|
return {
|
|
1550
2127
|
success: false,
|
|
1551
2128
|
error: `Invalid source table name: '${input.sourceTable}'`,
|
|
@@ -1554,10 +2131,25 @@ function createSpatialAnalysisTool(adapter) {
|
|
|
1554
2131
|
recoverable: false
|
|
1555
2132
|
};
|
|
1556
2133
|
}
|
|
1557
|
-
if (input.targetTable
|
|
2134
|
+
if (input.targetTable) {
|
|
2135
|
+
try {
|
|
2136
|
+
validateIdentifier(input.targetTable);
|
|
2137
|
+
} catch {
|
|
2138
|
+
return {
|
|
2139
|
+
success: false,
|
|
2140
|
+
error: `Invalid target table name: '${input.targetTable}'`,
|
|
2141
|
+
code: "VALIDATION_ERROR",
|
|
2142
|
+
category: "validation",
|
|
2143
|
+
recoverable: false
|
|
2144
|
+
};
|
|
2145
|
+
}
|
|
2146
|
+
}
|
|
2147
|
+
try {
|
|
2148
|
+
validateIdentifier(input.geometryColumn);
|
|
2149
|
+
} catch {
|
|
1558
2150
|
return {
|
|
1559
2151
|
success: false,
|
|
1560
|
-
error: `Invalid
|
|
2152
|
+
error: `Invalid geometry column name: '${input.geometryColumn}'`,
|
|
1561
2153
|
code: "VALIDATION_ERROR",
|
|
1562
2154
|
category: "validation",
|
|
1563
2155
|
recoverable: false
|
|
@@ -1565,15 +2157,18 @@ function createSpatialAnalysisTool(adapter) {
|
|
|
1565
2157
|
}
|
|
1566
2158
|
let query;
|
|
1567
2159
|
switch (input.analysisType) {
|
|
1568
|
-
case "spatial_extent":
|
|
2160
|
+
case "spatial_extent": {
|
|
2161
|
+
const geomCol = sanitizeIdentifier(input.geometryColumn);
|
|
2162
|
+
const srcTable = sanitizeIdentifier(input.sourceTable);
|
|
1569
2163
|
query = `SELECT
|
|
1570
|
-
MbrMinX(Extent(
|
|
1571
|
-
MbrMinY(Extent(
|
|
1572
|
-
MbrMaxX(Extent(
|
|
1573
|
-
MbrMaxY(Extent(
|
|
2164
|
+
MbrMinX(Extent(${geomCol})) as min_x,
|
|
2165
|
+
MbrMinY(Extent(${geomCol})) as min_y,
|
|
2166
|
+
MbrMaxX(Extent(${geomCol})) as max_x,
|
|
2167
|
+
MbrMaxY(Extent(${geomCol})) as max_y,
|
|
1574
2168
|
COUNT(*) as feature_count
|
|
1575
|
-
FROM
|
|
2169
|
+
FROM ${srcTable}`;
|
|
1576
2170
|
break;
|
|
2171
|
+
}
|
|
1577
2172
|
case "nearest_neighbor": {
|
|
1578
2173
|
if (!input.targetTable) {
|
|
1579
2174
|
return {
|
|
@@ -1584,13 +2179,16 @@ function createSpatialAnalysisTool(adapter) {
|
|
|
1584
2179
|
recoverable: false
|
|
1585
2180
|
};
|
|
1586
2181
|
}
|
|
2182
|
+
const geomCol = sanitizeIdentifier(input.geometryColumn);
|
|
2183
|
+
const srcTable = sanitizeIdentifier(input.sourceTable);
|
|
2184
|
+
const tgtTable = sanitizeIdentifier(input.targetTable);
|
|
1587
2185
|
const sameTable = input.sourceTable === input.targetTable;
|
|
1588
2186
|
const selfFilter = sameTable && input.excludeSelf ? "WHERE s.id != t.id" : "";
|
|
1589
|
-
const geomColumns = input.includeGeometry ? `, AsText(s
|
|
2187
|
+
const geomColumns = input.includeGeometry ? `, AsText(s.${geomCol}) as source_geom, AsText(t.${geomCol}) as target_geom` : "";
|
|
1590
2188
|
query = `SELECT
|
|
1591
2189
|
s.id as source_id, t.id as target_id,
|
|
1592
|
-
ST_Distance(s
|
|
1593
|
-
FROM
|
|
2190
|
+
ST_Distance(s.${geomCol}, t.${geomCol}) as distance${geomColumns}
|
|
2191
|
+
FROM ${srcTable} s, ${tgtTable} t
|
|
1594
2192
|
${selfFilter}
|
|
1595
2193
|
ORDER BY distance LIMIT ${input.limit}`;
|
|
1596
2194
|
break;
|
|
@@ -1605,11 +2203,14 @@ function createSpatialAnalysisTool(adapter) {
|
|
|
1605
2203
|
recoverable: false
|
|
1606
2204
|
};
|
|
1607
2205
|
}
|
|
1608
|
-
const
|
|
2206
|
+
const geomCol = sanitizeIdentifier(input.geometryColumn);
|
|
2207
|
+
const srcTable = sanitizeIdentifier(input.sourceTable);
|
|
2208
|
+
const tgtTable = sanitizeIdentifier(input.targetTable);
|
|
2209
|
+
const geomCols = input.includeGeometry ? `, AsText(s.${geomCol}) as source_geom, AsText(t.${geomCol}) as target_geom` : "";
|
|
1609
2210
|
query = `SELECT
|
|
1610
2211
|
s.id as source_id, t.id as target_id${geomCols}
|
|
1611
|
-
FROM
|
|
1612
|
-
WHERE ST_Within(s
|
|
2212
|
+
FROM ${srcTable} s, ${tgtTable} t
|
|
2213
|
+
WHERE ST_Within(s.${geomCol}, t.${geomCol})
|
|
1613
2214
|
LIMIT ${input.limit}`;
|
|
1614
2215
|
break;
|
|
1615
2216
|
}
|
|
@@ -1617,9 +2218,12 @@ function createSpatialAnalysisTool(adapter) {
|
|
|
1617
2218
|
const dmTarget = input.targetTable ?? input.sourceTable;
|
|
1618
2219
|
const dmSameTable = dmTarget === input.sourceTable;
|
|
1619
2220
|
const dmFilter = dmSameTable ? "WHERE a.id < b.id" : "";
|
|
2221
|
+
const geomCol = sanitizeIdentifier(input.geometryColumn);
|
|
2222
|
+
const srcTable = sanitizeIdentifier(input.sourceTable);
|
|
2223
|
+
const dmTgtTable = sanitizeIdentifier(dmTarget);
|
|
1620
2224
|
query = `SELECT a.id as id1, b.id as id2,
|
|
1621
|
-
ST_Distance(a
|
|
1622
|
-
FROM
|
|
2225
|
+
ST_Distance(a.${geomCol}, b.${geomCol}) as distance
|
|
2226
|
+
FROM ${srcTable} a, ${dmTgtTable} b
|
|
1623
2227
|
${dmFilter}
|
|
1624
2228
|
ORDER BY distance LIMIT ${input.limit}`;
|
|
1625
2229
|
break;
|
|
@@ -1627,7 +2231,7 @@ function createSpatialAnalysisTool(adapter) {
|
|
|
1627
2231
|
default:
|
|
1628
2232
|
query = "SELECT 1";
|
|
1629
2233
|
}
|
|
1630
|
-
const result = await adapter.executeReadQuery(query);
|
|
2234
|
+
const result = await adapter.executeReadQuery(query, queryParams);
|
|
1631
2235
|
return {
|
|
1632
2236
|
success: true,
|
|
1633
2237
|
analysisType: input.analysisType,
|
|
@@ -1650,6 +2254,7 @@ function createGeometryTransformTool(adapter) {
|
|
|
1650
2254
|
requiredScopes: ["read"],
|
|
1651
2255
|
annotations: readOnly("SpatiaLite Transform"),
|
|
1652
2256
|
handler: async (params, _context) => {
|
|
2257
|
+
const queryParams = [];
|
|
1653
2258
|
try {
|
|
1654
2259
|
const input = GeometryTransformSchema.parse(params);
|
|
1655
2260
|
ensureSpatialite(adapter);
|
|
@@ -1665,71 +2270,69 @@ function createGeometryTransformTool(adapter) {
|
|
|
1665
2270
|
let query;
|
|
1666
2271
|
switch (input.operation) {
|
|
1667
2272
|
case "buffer": {
|
|
1668
|
-
const bufferGeom = `Buffer(GeomFromText(
|
|
2273
|
+
const bufferGeom = `Buffer(GeomFromText(?, CAST(? AS INTEGER)), ?)`;
|
|
1669
2274
|
const defaultTolerance = Math.max(1e-4, input.distance * 0.01);
|
|
1670
2275
|
const tolerance = input.simplifyTolerance ?? defaultTolerance;
|
|
1671
|
-
const finalGeom = tolerance > 0 ? `Simplify(${bufferGeom}, ${tolerance})` : bufferGeom;
|
|
2276
|
+
const finalGeom = tolerance > 0 ? `Simplify(${bufferGeom}, ${String(tolerance)})` : bufferGeom;
|
|
1672
2277
|
query = `SELECT AsText(${finalGeom}) as result`;
|
|
2278
|
+
queryParams.push(input.geometry1, input.srid, input.distance);
|
|
1673
2279
|
break;
|
|
1674
2280
|
}
|
|
1675
|
-
case "intersection":
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
}
|
|
1685
|
-
query = `SELECT AsText(Intersection(
|
|
1686
|
-
GeomFromText('${input.geometry1}', ${input.srid}),
|
|
1687
|
-
GeomFromText('${input.geometry2}', ${input.srid})
|
|
1688
|
-
)) as result`;
|
|
2281
|
+
case "intersection": {
|
|
2282
|
+
const intersectionGeom = `Intersection(GeomFromText(?, CAST(? AS INTEGER)), GeomFromText(?, CAST(? AS INTEGER)))`;
|
|
2283
|
+
query = `SELECT AsText(${intersectionGeom}) as result`;
|
|
2284
|
+
queryParams.push(
|
|
2285
|
+
input.geometry1,
|
|
2286
|
+
input.srid,
|
|
2287
|
+
input.geometry2,
|
|
2288
|
+
input.srid
|
|
2289
|
+
);
|
|
1689
2290
|
break;
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
query = `SELECT AsText(GUnion(
|
|
1701
|
-
GeomFromText('${input.geometry1}', ${input.srid}),
|
|
1702
|
-
GeomFromText('${input.geometry2}', ${input.srid})
|
|
1703
|
-
)) as result`;
|
|
2291
|
+
}
|
|
2292
|
+
case "union": {
|
|
2293
|
+
const unionGeom = `GUnion(GeomFromText(?, CAST(? AS INTEGER)), GeomFromText(?, CAST(? AS INTEGER)))`;
|
|
2294
|
+
query = `SELECT AsText(${unionGeom}) as result`;
|
|
2295
|
+
queryParams.push(
|
|
2296
|
+
input.geometry1,
|
|
2297
|
+
input.srid,
|
|
2298
|
+
input.geometry2,
|
|
2299
|
+
input.srid
|
|
2300
|
+
);
|
|
1704
2301
|
break;
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
query = `SELECT AsText(Difference(
|
|
1716
|
-
GeomFromText('${input.geometry1}', ${input.srid}),
|
|
1717
|
-
GeomFromText('${input.geometry2}', ${input.srid})
|
|
1718
|
-
)) as result`;
|
|
2302
|
+
}
|
|
2303
|
+
case "difference": {
|
|
2304
|
+
const differenceGeom = `Difference(GeomFromText(?, CAST(? AS INTEGER)), GeomFromText(?, CAST(? AS INTEGER)))`;
|
|
2305
|
+
query = `SELECT AsText(${differenceGeom}) as result`;
|
|
2306
|
+
queryParams.push(
|
|
2307
|
+
input.geometry1,
|
|
2308
|
+
input.srid,
|
|
2309
|
+
input.geometry2,
|
|
2310
|
+
input.srid
|
|
2311
|
+
);
|
|
1719
2312
|
break;
|
|
1720
|
-
|
|
1721
|
-
|
|
2313
|
+
}
|
|
2314
|
+
case "centroid": {
|
|
2315
|
+
const centroidGeom = `Centroid(GeomFromText(?, CAST(? AS INTEGER)))`;
|
|
2316
|
+
query = `SELECT AsText(${centroidGeom}) as result`;
|
|
2317
|
+
queryParams.push(input.geometry1, input.srid);
|
|
1722
2318
|
break;
|
|
1723
|
-
|
|
1724
|
-
|
|
2319
|
+
}
|
|
2320
|
+
case "envelope": {
|
|
2321
|
+
const envelopeGeom = `Envelope(GeomFromText(?, CAST(? AS INTEGER)))`;
|
|
2322
|
+
query = `SELECT AsText(${envelopeGeom}) as result`;
|
|
2323
|
+
queryParams.push(input.geometry1, input.srid);
|
|
1725
2324
|
break;
|
|
1726
|
-
|
|
1727
|
-
|
|
2325
|
+
}
|
|
2326
|
+
case "simplify": {
|
|
2327
|
+
const simplifyGeom = `Simplify(GeomFromText(?, CAST(? AS INTEGER)), ?)`;
|
|
2328
|
+
query = `SELECT AsText(${simplifyGeom}) as result`;
|
|
2329
|
+
queryParams.push(input.geometry1, input.srid, input.distance);
|
|
1728
2330
|
break;
|
|
2331
|
+
}
|
|
1729
2332
|
default:
|
|
1730
2333
|
query = "SELECT 1";
|
|
1731
2334
|
}
|
|
1732
|
-
const result = await adapter.executeReadQuery(query);
|
|
2335
|
+
const result = await adapter.executeReadQuery(query, queryParams);
|
|
1733
2336
|
const wktResult = result.rows?.[0]?.["result"];
|
|
1734
2337
|
if (wktResult === null || wktResult === void 0) {
|
|
1735
2338
|
return {
|
|
@@ -1759,7 +2362,7 @@ function createSpatialImportTool(adapter) {
|
|
|
1759
2362
|
inputSchema: SpatialImportSchema,
|
|
1760
2363
|
outputSchema: SpatialiteImportOutputSchema,
|
|
1761
2364
|
requiredScopes: ["write"],
|
|
1762
|
-
annotations:
|
|
2365
|
+
annotations: writeFs("SpatiaLite Import"),
|
|
1763
2366
|
handler: async (params, _context) => {
|
|
1764
2367
|
try {
|
|
1765
2368
|
const input = SpatialImportSchema.parse(params);
|
|
@@ -1773,7 +2376,9 @@ function createSpatialImportTool(adapter) {
|
|
|
1773
2376
|
recoverable: false
|
|
1774
2377
|
};
|
|
1775
2378
|
}
|
|
1776
|
-
|
|
2379
|
+
try {
|
|
2380
|
+
validateIdentifier(input.tableName);
|
|
2381
|
+
} catch {
|
|
1777
2382
|
return {
|
|
1778
2383
|
success: false,
|
|
1779
2384
|
error: `Invalid table name: '${input.tableName}'`,
|
|
@@ -1786,10 +2391,23 @@ function createSpatialImportTool(adapter) {
|
|
|
1786
2391
|
if (input.format === "geojson") {
|
|
1787
2392
|
try {
|
|
1788
2393
|
JSON.parse(input.data);
|
|
2394
|
+
const geojsonCheck = await adapter.executeReadQuery(
|
|
2395
|
+
`SELECT ST_IsValid(GeomFromGeoJSON(?)) as valid`,
|
|
2396
|
+
[input.data]
|
|
2397
|
+
);
|
|
2398
|
+
const isValid2 = geojsonCheck.rows?.[0]?.["valid"];
|
|
2399
|
+
if (isValid2 !== 1) {
|
|
2400
|
+
return {
|
|
2401
|
+
success: false,
|
|
2402
|
+
error: `Invalid GeoJSON geometry: could not be parsed by SpatiaLite (must be a valid Geometry object)`,
|
|
2403
|
+
code: "VALIDATION_ERROR",
|
|
2404
|
+
category: "validation",
|
|
2405
|
+
recoverable: false
|
|
2406
|
+
};
|
|
2407
|
+
}
|
|
1789
2408
|
const columns2 = ["geom"];
|
|
1790
|
-
const
|
|
1791
|
-
|
|
1792
|
-
];
|
|
2409
|
+
const placeholders2 = [`SetSRID(GeomFromGeoJSON(?), ?)`];
|
|
2410
|
+
const insertParams2 = [input.data, input.srid];
|
|
1793
2411
|
if (input.additionalData) {
|
|
1794
2412
|
for (const [key, value] of Object.entries(input.additionalData)) {
|
|
1795
2413
|
if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(key)) {
|
|
@@ -1801,14 +2419,16 @@ function createSpatialImportTool(adapter) {
|
|
|
1801
2419
|
recoverable: false
|
|
1802
2420
|
};
|
|
1803
2421
|
}
|
|
1804
|
-
columns2.push(
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
);
|
|
2422
|
+
columns2.push(sanitizeIdentifier(key));
|
|
2423
|
+
placeholders2.push("?");
|
|
2424
|
+
insertParams2.push(value);
|
|
1808
2425
|
}
|
|
1809
2426
|
}
|
|
1810
|
-
const sql2 = `INSERT INTO
|
|
1811
|
-
const insertResult2 = await adapter.executeWriteQuery(
|
|
2427
|
+
const sql2 = `INSERT INTO ${sanitizeIdentifier(input.tableName)} (${columns2.join(", ")}) VALUES (${placeholders2.join(", ")})`;
|
|
2428
|
+
const insertResult2 = await adapter.executeWriteQuery(
|
|
2429
|
+
sql2,
|
|
2430
|
+
insertParams2
|
|
2431
|
+
);
|
|
1812
2432
|
return {
|
|
1813
2433
|
success: true,
|
|
1814
2434
|
message: "GeoJSON geometry imported",
|
|
@@ -1827,10 +2447,11 @@ function createSpatialImportTool(adapter) {
|
|
|
1827
2447
|
wkt = input.data;
|
|
1828
2448
|
}
|
|
1829
2449
|
const wktCheck = await adapter.executeReadQuery(
|
|
1830
|
-
`SELECT GeomFromText(
|
|
2450
|
+
`SELECT ST_IsValid(GeomFromText(?, CAST(? AS INTEGER))) as valid`,
|
|
2451
|
+
[wkt, input.srid]
|
|
1831
2452
|
);
|
|
1832
|
-
const
|
|
1833
|
-
if (
|
|
2453
|
+
const isValid = wktCheck.rows?.[0]?.["valid"];
|
|
2454
|
+
if (isValid !== 1) {
|
|
1834
2455
|
return {
|
|
1835
2456
|
success: false,
|
|
1836
2457
|
error: `Invalid WKT geometry: '${wkt}' could not be parsed`,
|
|
@@ -1840,7 +2461,8 @@ function createSpatialImportTool(adapter) {
|
|
|
1840
2461
|
};
|
|
1841
2462
|
}
|
|
1842
2463
|
const columns = ["geom"];
|
|
1843
|
-
const
|
|
2464
|
+
const placeholders = [`GeomFromText(?, CAST(? AS INTEGER))`];
|
|
2465
|
+
const insertParams = [wkt, input.srid];
|
|
1844
2466
|
if (input.additionalData) {
|
|
1845
2467
|
for (const [key, value] of Object.entries(input.additionalData)) {
|
|
1846
2468
|
if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(key)) {
|
|
@@ -1852,14 +2474,13 @@ function createSpatialImportTool(adapter) {
|
|
|
1852
2474
|
recoverable: false
|
|
1853
2475
|
};
|
|
1854
2476
|
}
|
|
1855
|
-
columns.push(
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
);
|
|
2477
|
+
columns.push(sanitizeIdentifier(key));
|
|
2478
|
+
placeholders.push("?");
|
|
2479
|
+
insertParams.push(value);
|
|
1859
2480
|
}
|
|
1860
2481
|
}
|
|
1861
|
-
const sql = `INSERT INTO
|
|
1862
|
-
const insertResult = await adapter.executeWriteQuery(sql);
|
|
2482
|
+
const sql = `INSERT INTO ${sanitizeIdentifier(input.tableName)} (${columns.join(", ")}) VALUES (${placeholders.join(", ")})`;
|
|
2483
|
+
const insertResult = await adapter.executeWriteQuery(sql, insertParams);
|
|
1863
2484
|
return {
|
|
1864
2485
|
success: true,
|
|
1865
2486
|
message: "WKT geometry imported",
|
|
@@ -1920,16 +2541,16 @@ function getNativeToolDefinitions(adapter) {
|
|
|
1920
2541
|
function findProjectRoot(startDir) {
|
|
1921
2542
|
let dir = startDir;
|
|
1922
2543
|
for (let i = 0; i < 10; i++) {
|
|
1923
|
-
if (fs.existsSync(
|
|
1924
|
-
const parent =
|
|
2544
|
+
if (fs.existsSync(path2.join(dir, "package.json"))) return dir;
|
|
2545
|
+
const parent = path2.dirname(dir);
|
|
1925
2546
|
if (parent === dir) break;
|
|
1926
2547
|
dir = parent;
|
|
1927
2548
|
}
|
|
1928
2549
|
return startDir;
|
|
1929
2550
|
}
|
|
1930
2551
|
var __moduleFilename = fileURLToPath(import.meta.url);
|
|
1931
|
-
var PROJECT_ROOT = findProjectRoot(
|
|
1932
|
-
var EXTENSIONS_DIR =
|
|
2552
|
+
var PROJECT_ROOT = findProjectRoot(path2.dirname(__moduleFilename));
|
|
2553
|
+
var EXTENSIONS_DIR = path2.join(PROJECT_ROOT, "extensions");
|
|
1933
2554
|
function tryLoadExtension(db, name, envVar, candidates, log2) {
|
|
1934
2555
|
for (const extPath of candidates) {
|
|
1935
2556
|
try {
|
|
@@ -1949,12 +2570,12 @@ function loadSpatialite(db, log2) {
|
|
|
1949
2570
|
const spatialitePaths = [
|
|
1950
2571
|
process.env["SPATIALITE_PATH"],
|
|
1951
2572
|
// Absolute paths to local extensions
|
|
1952
|
-
|
|
2573
|
+
path2.join(
|
|
1953
2574
|
EXTENSIONS_DIR,
|
|
1954
2575
|
"mod_spatialite-5.1.0-win-amd64",
|
|
1955
2576
|
"mod_spatialite"
|
|
1956
2577
|
),
|
|
1957
|
-
|
|
2578
|
+
path2.join(
|
|
1958
2579
|
EXTENSIONS_DIR,
|
|
1959
2580
|
"mod_spatialite-5.1.0-win-amd64",
|
|
1960
2581
|
"mod_spatialite.dll"
|
|
@@ -1968,7 +2589,7 @@ function loadSpatialite(db, log2) {
|
|
|
1968
2589
|
].filter((p) => Boolean(p));
|
|
1969
2590
|
const envSpatialitePath = process.env["SPATIALITE_PATH"];
|
|
1970
2591
|
if (envSpatialitePath && process.platform === "win32") {
|
|
1971
|
-
const spatialiteExtDir =
|
|
2592
|
+
const spatialiteExtDir = path2.dirname(envSpatialitePath);
|
|
1972
2593
|
const currentPath = process.env["PATH"] ?? "";
|
|
1973
2594
|
if (!currentPath.includes(spatialiteExtDir)) {
|
|
1974
2595
|
process.env["PATH"] = spatialiteExtDir + ";" + currentPath;
|
|
@@ -1980,8 +2601,8 @@ function loadCsvExtension(db, log2) {
|
|
|
1980
2601
|
const csvPaths = [
|
|
1981
2602
|
process.env["CSV_EXTENSION_PATH"],
|
|
1982
2603
|
// sqlite-xsv extension with absolute paths
|
|
1983
|
-
|
|
1984
|
-
|
|
2604
|
+
path2.join(EXTENSIONS_DIR, "xsv0.dll"),
|
|
2605
|
+
path2.join(EXTENSIONS_DIR, "xsv0"),
|
|
1985
2606
|
// System paths
|
|
1986
2607
|
"xsv0",
|
|
1987
2608
|
"xsv0.dll",
|
|
@@ -2043,18 +2664,7 @@ function nativeExecuteRead(db, sql, params, log2) {
|
|
|
2043
2664
|
executionTimeMs: Date.now() - start
|
|
2044
2665
|
});
|
|
2045
2666
|
} catch (error) {
|
|
2046
|
-
|
|
2047
|
-
log2.error(`Query failed: ${message}`, {
|
|
2048
|
-
code: ERROR_CODES.DB.QUERY_FAILED.full
|
|
2049
|
-
});
|
|
2050
|
-
throw new QueryError(
|
|
2051
|
-
`Query execution failed: ${message}`,
|
|
2052
|
-
"DB_QUERY_FAILED",
|
|
2053
|
-
{
|
|
2054
|
-
sql,
|
|
2055
|
-
cause: error instanceof Error ? error : void 0
|
|
2056
|
-
}
|
|
2057
|
-
);
|
|
2667
|
+
translateSqliteError(error, sql, "Query execution", log2);
|
|
2058
2668
|
}
|
|
2059
2669
|
}
|
|
2060
2670
|
function nativeExecuteWrite(db, sql, params, log2) {
|
|
@@ -2062,21 +2672,27 @@ function nativeExecuteWrite(db, sql, params, log2) {
|
|
|
2062
2672
|
try {
|
|
2063
2673
|
const stmt = db.prepare(sql);
|
|
2064
2674
|
const normalizedParams = normalizeSqliteParams(params);
|
|
2675
|
+
if (stmt.reader) {
|
|
2676
|
+
const rows = normalizedParams ? stmt.all(...normalizedParams) : stmt.all();
|
|
2677
|
+
return Promise.resolve({
|
|
2678
|
+
rows,
|
|
2679
|
+
rowsAffected: rows.length,
|
|
2680
|
+
// .all() does not return changes, but we know it's rows.length for RETURNING
|
|
2681
|
+
executionTimeMs: Date.now() - start
|
|
2682
|
+
});
|
|
2683
|
+
}
|
|
2065
2684
|
const info = normalizedParams ? stmt.run(...normalizedParams) : stmt.run();
|
|
2066
|
-
|
|
2685
|
+
const result = {
|
|
2067
2686
|
rows: [],
|
|
2068
2687
|
rowsAffected: info.changes,
|
|
2069
2688
|
executionTimeMs: Date.now() - start
|
|
2070
|
-
}
|
|
2689
|
+
};
|
|
2690
|
+
if (info.lastInsertRowid !== void 0) {
|
|
2691
|
+
result.lastInsertId = Number(info.lastInsertRowid);
|
|
2692
|
+
}
|
|
2693
|
+
return Promise.resolve(result);
|
|
2071
2694
|
} catch (error) {
|
|
2072
|
-
|
|
2073
|
-
log2.error(`Write query failed: ${message}`, {
|
|
2074
|
-
code: ERROR_CODES.DB.QUERY_FAILED.full
|
|
2075
|
-
});
|
|
2076
|
-
throw new QueryError(`Write query failed: ${message}`, "DB_WRITE_FAILED", {
|
|
2077
|
-
sql,
|
|
2078
|
-
cause: error instanceof Error ? error : void 0
|
|
2079
|
-
});
|
|
2695
|
+
translateSqliteError(error, sql, "Write query", log2);
|
|
2080
2696
|
}
|
|
2081
2697
|
}
|
|
2082
2698
|
|
|
@@ -2099,7 +2715,8 @@ var NativeSqliteAdapter = class extends DatabaseAdapter {
|
|
|
2099
2715
|
*/
|
|
2100
2716
|
getConfiguredPath() {
|
|
2101
2717
|
const config = this.config;
|
|
2102
|
-
|
|
2718
|
+
const path3 = config?.filePath ?? config?.connectionString ?? ":memory:";
|
|
2719
|
+
return path3;
|
|
2103
2720
|
}
|
|
2104
2721
|
db = null;
|
|
2105
2722
|
schemaManager = null;
|
|
@@ -2137,6 +2754,17 @@ var NativeSqliteAdapter = class extends DatabaseAdapter {
|
|
|
2137
2754
|
const versionResult = db.prepare("SELECT sqlite_version()").get();
|
|
2138
2755
|
return versionResult?.["sqlite_version()"] ?? "0.0.0";
|
|
2139
2756
|
}, log);
|
|
2757
|
+
if (sqliteConfig.initializationSql && Array.isArray(sqliteConfig.initializationSql)) {
|
|
2758
|
+
for (const sql of sqliteConfig.initializationSql) {
|
|
2759
|
+
db.exec(sql);
|
|
2760
|
+
}
|
|
2761
|
+
log.info(
|
|
2762
|
+
`Executed ${sqliteConfig.initializationSql.length} initialization SQL statements`,
|
|
2763
|
+
{
|
|
2764
|
+
code: "SQLITE_INIT_SQL"
|
|
2765
|
+
}
|
|
2766
|
+
);
|
|
2767
|
+
}
|
|
2140
2768
|
this.schemaManager = new SchemaManager(this);
|
|
2141
2769
|
this.connected = true;
|
|
2142
2770
|
} catch (error) {
|
|
@@ -2230,6 +2858,7 @@ var NativeSqliteAdapter = class extends DatabaseAdapter {
|
|
|
2230
2858
|
*/
|
|
2231
2859
|
executeReadQuery(sql, params) {
|
|
2232
2860
|
this.ensureConnected();
|
|
2861
|
+
this.validateQuery(sql, true);
|
|
2233
2862
|
return nativeExecuteRead(this.ensureDb(), sql, params, log);
|
|
2234
2863
|
}
|
|
2235
2864
|
/**
|
|
@@ -2237,6 +2866,7 @@ var NativeSqliteAdapter = class extends DatabaseAdapter {
|
|
|
2237
2866
|
*/
|
|
2238
2867
|
executeWriteQuery(sql, params) {
|
|
2239
2868
|
this.ensureConnected();
|
|
2869
|
+
this.validateQuery(sql, false);
|
|
2240
2870
|
const result = nativeExecuteWrite(this.ensureDb(), sql, params, log);
|
|
2241
2871
|
if (isDDL(sql)) {
|
|
2242
2872
|
this.clearSchemaCache();
|
|
@@ -2248,11 +2878,26 @@ var NativeSqliteAdapter = class extends DatabaseAdapter {
|
|
|
2248
2878
|
*/
|
|
2249
2879
|
executeQuery(sql, params) {
|
|
2250
2880
|
const trimmed = sql.trim().toUpperCase();
|
|
2251
|
-
if (trimmed.startsWith("
|
|
2881
|
+
if (trimmed.startsWith("PRAGMA")) {
|
|
2882
|
+
if (sql.includes("=") || sql.includes("(")) {
|
|
2883
|
+
return this.executeWriteQuery(sql, params);
|
|
2884
|
+
}
|
|
2885
|
+
return this.executeReadQuery(sql, params);
|
|
2886
|
+
}
|
|
2887
|
+
if (trimmed.startsWith("SELECT") || trimmed.startsWith("EXPLAIN")) {
|
|
2252
2888
|
return this.executeReadQuery(sql, params);
|
|
2253
2889
|
}
|
|
2254
2890
|
return this.executeWriteQuery(sql, params);
|
|
2255
2891
|
}
|
|
2892
|
+
/**
|
|
2893
|
+
* Execute a SQL script containing multiple statements
|
|
2894
|
+
*/
|
|
2895
|
+
executeScript(sql) {
|
|
2896
|
+
this.ensureConnected();
|
|
2897
|
+
this.ensureDb().exec(sql);
|
|
2898
|
+
this.clearSchemaCache();
|
|
2899
|
+
return Promise.resolve();
|
|
2900
|
+
}
|
|
2256
2901
|
/**
|
|
2257
2902
|
* Get schema information (cached via SchemaManager)
|
|
2258
2903
|
*/
|
|
@@ -2328,6 +2973,23 @@ var NativeSqliteAdapter = class extends DatabaseAdapter {
|
|
|
2328
2973
|
listSchemas() {
|
|
2329
2974
|
return Promise.resolve(["main"]);
|
|
2330
2975
|
}
|
|
2976
|
+
/**
|
|
2977
|
+
* Get indexes, optionally for a specific table (cached via SchemaManager)
|
|
2978
|
+
*/
|
|
2979
|
+
async getIndexes(table) {
|
|
2980
|
+
this.ensureConnected();
|
|
2981
|
+
if (this.schemaManager) {
|
|
2982
|
+
if (table) {
|
|
2983
|
+
return this.schemaManager.getTableIndexes(table);
|
|
2984
|
+
}
|
|
2985
|
+
return this.schemaManager.getAllIndexes();
|
|
2986
|
+
}
|
|
2987
|
+
const all = await this.getAllIndexes();
|
|
2988
|
+
if (table) {
|
|
2989
|
+
return all.filter((i) => i.tableName === table);
|
|
2990
|
+
}
|
|
2991
|
+
return all;
|
|
2992
|
+
}
|
|
2331
2993
|
/**
|
|
2332
2994
|
* Get all indexes in the database (cached via SchemaManager)
|
|
2333
2995
|
* Required by sqlite_indexes resource
|
|
@@ -2393,7 +3055,8 @@ var NativeSqliteAdapter = class extends DatabaseAdapter {
|
|
|
2393
3055
|
"admin",
|
|
2394
3056
|
"geo",
|
|
2395
3057
|
"introspection",
|
|
2396
|
-
"migration"
|
|
3058
|
+
"migration",
|
|
3059
|
+
"transactions"
|
|
2397
3060
|
];
|
|
2398
3061
|
}
|
|
2399
3062
|
/**
|
|
@@ -2452,7 +3115,11 @@ var NativeSqliteAdapter = class extends DatabaseAdapter {
|
|
|
2452
3115
|
* Execute raw SQL and return results (for tools)
|
|
2453
3116
|
*/
|
|
2454
3117
|
rawQuery(sql, params) {
|
|
2455
|
-
|
|
3118
|
+
const trimmed = sql.trim().toUpperCase();
|
|
3119
|
+
if (trimmed.startsWith("SELECT") || trimmed.startsWith("EXPLAIN") || trimmed.startsWith("PRAGMA") && !sql.includes("=") && !sql.includes("(")) {
|
|
3120
|
+
return nativeExecuteRead(this.ensureDb(), sql, params, log);
|
|
3121
|
+
}
|
|
3122
|
+
return nativeExecuteWrite(this.ensureDb(), sql, params, log);
|
|
2456
3123
|
}
|
|
2457
3124
|
/**
|
|
2458
3125
|
* Begin a transaction
|