db-mcp 1.0.2 → 1.1.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.
Files changed (241) hide show
  1. package/.gitattributes +2 -0
  2. package/LICENSE +1 -1
  3. package/README.md +244 -518
  4. package/dist/chunk-4IA3DB5C.js +135 -0
  5. package/dist/chunk-AOUL5SHS.js +930 -0
  6. package/dist/chunk-DWJXQEFA.js +13759 -0
  7. package/dist/chunk-DZQLDEQS.js +879 -0
  8. package/dist/chunk-S5IDDSSB.js +74 -0
  9. package/dist/chunk-Z2GFQU3G.js +363 -0
  10. package/dist/cli.d.ts +0 -7
  11. package/dist/cli.js +227 -183
  12. package/dist/http-VSB7DBJR.js +1541 -0
  13. package/dist/index.d.ts +842 -10
  14. package/dist/index.js +5 -17
  15. package/dist/sqlite-VHBA4ABV.js +600 -0
  16. package/dist/sqlite-native-D2LH5ZT7.js +2498 -0
  17. package/dist/worker-script.d.ts +2 -0
  18. package/dist/worker-script.js +126 -0
  19. package/package.json +26 -16
  20. package/playwright.config.ts +101 -0
  21. package/scripts/generate-server-instructions.ts +111 -0
  22. package/server.json +5 -6
  23. package/test-server/README.md +118 -0
  24. package/test-server/code-map.md +409 -0
  25. package/test-server/fixtures/sample.csv +6 -0
  26. package/test-server/reset-database.ps1 +373 -0
  27. package/test-server/sample.csv +11 -0
  28. package/test-server/test-agent-experience.md +243 -0
  29. package/test-server/test-database.sql +388 -0
  30. package/test-server/test-group-tools.md +861 -0
  31. package/test-server/test-help-resources.mjs +238 -0
  32. package/test-server/test-preflight.md +53 -0
  33. package/test-server/test-prompts.md +354 -0
  34. package/test-server/test-resources.md +245 -0
  35. package/test-server/test-tool-annotations.mjs +157 -0
  36. package/test-server/test-tools-advanced-1.md +517 -0
  37. package/test-server/test-tools-advanced-2.md +487 -0
  38. package/test-server/test-tools-codemode.md +629 -0
  39. package/test-server/test-tools.md +176 -0
  40. package/test-server/tool-reference.md +236 -0
  41. package/tsconfig.test.json +9 -0
  42. package/dist/adapters/DatabaseAdapter.d.ts +0 -141
  43. package/dist/adapters/DatabaseAdapter.d.ts.map +0 -1
  44. package/dist/adapters/DatabaseAdapter.js +0 -131
  45. package/dist/adapters/DatabaseAdapter.js.map +0 -1
  46. package/dist/adapters/sqlite/SchemaManager.d.ts +0 -58
  47. package/dist/adapters/sqlite/SchemaManager.d.ts.map +0 -1
  48. package/dist/adapters/sqlite/SchemaManager.js +0 -187
  49. package/dist/adapters/sqlite/SchemaManager.js.map +0 -1
  50. package/dist/adapters/sqlite/SqliteAdapter.d.ts +0 -161
  51. package/dist/adapters/sqlite/SqliteAdapter.d.ts.map +0 -1
  52. package/dist/adapters/sqlite/SqliteAdapter.js +0 -741
  53. package/dist/adapters/sqlite/SqliteAdapter.js.map +0 -1
  54. package/dist/adapters/sqlite/index.d.ts +0 -9
  55. package/dist/adapters/sqlite/index.d.ts.map +0 -1
  56. package/dist/adapters/sqlite/index.js +0 -8
  57. package/dist/adapters/sqlite/index.js.map +0 -1
  58. package/dist/adapters/sqlite/json-utils.d.ts +0 -100
  59. package/dist/adapters/sqlite/json-utils.d.ts.map +0 -1
  60. package/dist/adapters/sqlite/json-utils.js +0 -274
  61. package/dist/adapters/sqlite/json-utils.js.map +0 -1
  62. package/dist/adapters/sqlite/output-schemas.d.ts +0 -1187
  63. package/dist/adapters/sqlite/output-schemas.d.ts.map +0 -1
  64. package/dist/adapters/sqlite/output-schemas.js +0 -1337
  65. package/dist/adapters/sqlite/output-schemas.js.map +0 -1
  66. package/dist/adapters/sqlite/prompts.d.ts +0 -13
  67. package/dist/adapters/sqlite/prompts.d.ts.map +0 -1
  68. package/dist/adapters/sqlite/prompts.js +0 -605
  69. package/dist/adapters/sqlite/prompts.js.map +0 -1
  70. package/dist/adapters/sqlite/resources.d.ts +0 -13
  71. package/dist/adapters/sqlite/resources.d.ts.map +0 -1
  72. package/dist/adapters/sqlite/resources.js +0 -251
  73. package/dist/adapters/sqlite/resources.js.map +0 -1
  74. package/dist/adapters/sqlite/tools/admin.d.ts +0 -14
  75. package/dist/adapters/sqlite/tools/admin.d.ts.map +0 -1
  76. package/dist/adapters/sqlite/tools/admin.js +0 -788
  77. package/dist/adapters/sqlite/tools/admin.js.map +0 -1
  78. package/dist/adapters/sqlite/tools/core.d.ts +0 -25
  79. package/dist/adapters/sqlite/tools/core.d.ts.map +0 -1
  80. package/dist/adapters/sqlite/tools/core.js +0 -359
  81. package/dist/adapters/sqlite/tools/core.js.map +0 -1
  82. package/dist/adapters/sqlite/tools/fts.d.ts +0 -13
  83. package/dist/adapters/sqlite/tools/fts.d.ts.map +0 -1
  84. package/dist/adapters/sqlite/tools/fts.js +0 -347
  85. package/dist/adapters/sqlite/tools/fts.js.map +0 -1
  86. package/dist/adapters/sqlite/tools/geo.d.ts +0 -14
  87. package/dist/adapters/sqlite/tools/geo.d.ts.map +0 -1
  88. package/dist/adapters/sqlite/tools/geo.js +0 -252
  89. package/dist/adapters/sqlite/tools/geo.js.map +0 -1
  90. package/dist/adapters/sqlite/tools/index.d.ts +0 -30
  91. package/dist/adapters/sqlite/tools/index.d.ts.map +0 -1
  92. package/dist/adapters/sqlite/tools/index.js +0 -61
  93. package/dist/adapters/sqlite/tools/index.js.map +0 -1
  94. package/dist/adapters/sqlite/tools/json-helpers.d.ts +0 -14
  95. package/dist/adapters/sqlite/tools/json-helpers.d.ts.map +0 -1
  96. package/dist/adapters/sqlite/tools/json-helpers.js +0 -477
  97. package/dist/adapters/sqlite/tools/json-helpers.js.map +0 -1
  98. package/dist/adapters/sqlite/tools/json-operations.d.ts +0 -14
  99. package/dist/adapters/sqlite/tools/json-operations.d.ts.map +0 -1
  100. package/dist/adapters/sqlite/tools/json-operations.js +0 -839
  101. package/dist/adapters/sqlite/tools/json-operations.js.map +0 -1
  102. package/dist/adapters/sqlite/tools/stats.d.ts +0 -15
  103. package/dist/adapters/sqlite/tools/stats.d.ts.map +0 -1
  104. package/dist/adapters/sqlite/tools/stats.js +0 -1219
  105. package/dist/adapters/sqlite/tools/stats.js.map +0 -1
  106. package/dist/adapters/sqlite/tools/text.d.ts +0 -14
  107. package/dist/adapters/sqlite/tools/text.d.ts.map +0 -1
  108. package/dist/adapters/sqlite/tools/text.js +0 -1141
  109. package/dist/adapters/sqlite/tools/text.js.map +0 -1
  110. package/dist/adapters/sqlite/tools/vector.d.ts +0 -14
  111. package/dist/adapters/sqlite/tools/vector.d.ts.map +0 -1
  112. package/dist/adapters/sqlite/tools/vector.js +0 -613
  113. package/dist/adapters/sqlite/tools/vector.js.map +0 -1
  114. package/dist/adapters/sqlite/tools/virtual.d.ts +0 -13
  115. package/dist/adapters/sqlite/tools/virtual.d.ts.map +0 -1
  116. package/dist/adapters/sqlite/tools/virtual.js +0 -930
  117. package/dist/adapters/sqlite/tools/virtual.js.map +0 -1
  118. package/dist/adapters/sqlite/types.d.ts +0 -207
  119. package/dist/adapters/sqlite/types.d.ts.map +0 -1
  120. package/dist/adapters/sqlite/types.js +0 -186
  121. package/dist/adapters/sqlite/types.js.map +0 -1
  122. package/dist/adapters/sqlite-native/NativeSqliteAdapter.d.ts +0 -163
  123. package/dist/adapters/sqlite-native/NativeSqliteAdapter.d.ts.map +0 -1
  124. package/dist/adapters/sqlite-native/NativeSqliteAdapter.js +0 -748
  125. package/dist/adapters/sqlite-native/NativeSqliteAdapter.js.map +0 -1
  126. package/dist/adapters/sqlite-native/index.d.ts +0 -11
  127. package/dist/adapters/sqlite-native/index.d.ts.map +0 -1
  128. package/dist/adapters/sqlite-native/index.js +0 -11
  129. package/dist/adapters/sqlite-native/index.js.map +0 -1
  130. package/dist/adapters/sqlite-native/tools/spatialite.d.ts +0 -19
  131. package/dist/adapters/sqlite-native/tools/spatialite.d.ts.map +0 -1
  132. package/dist/adapters/sqlite-native/tools/spatialite.js +0 -628
  133. package/dist/adapters/sqlite-native/tools/spatialite.js.map +0 -1
  134. package/dist/adapters/sqlite-native/tools/transactions.d.ts +0 -12
  135. package/dist/adapters/sqlite-native/tools/transactions.d.ts.map +0 -1
  136. package/dist/adapters/sqlite-native/tools/transactions.js +0 -255
  137. package/dist/adapters/sqlite-native/tools/transactions.js.map +0 -1
  138. package/dist/adapters/sqlite-native/tools/window.d.ts +0 -12
  139. package/dist/adapters/sqlite-native/tools/window.d.ts.map +0 -1
  140. package/dist/adapters/sqlite-native/tools/window.js +0 -370
  141. package/dist/adapters/sqlite-native/tools/window.js.map +0 -1
  142. package/dist/auth/AuthorizationServerDiscovery.d.ts +0 -90
  143. package/dist/auth/AuthorizationServerDiscovery.d.ts.map +0 -1
  144. package/dist/auth/AuthorizationServerDiscovery.js +0 -204
  145. package/dist/auth/AuthorizationServerDiscovery.js.map +0 -1
  146. package/dist/auth/OAuthResourceServer.d.ts +0 -65
  147. package/dist/auth/OAuthResourceServer.d.ts.map +0 -1
  148. package/dist/auth/OAuthResourceServer.js +0 -121
  149. package/dist/auth/OAuthResourceServer.js.map +0 -1
  150. package/dist/auth/TokenValidator.d.ts +0 -60
  151. package/dist/auth/TokenValidator.d.ts.map +0 -1
  152. package/dist/auth/TokenValidator.js +0 -235
  153. package/dist/auth/TokenValidator.js.map +0 -1
  154. package/dist/auth/errors.d.ts +0 -74
  155. package/dist/auth/errors.d.ts.map +0 -1
  156. package/dist/auth/errors.js +0 -133
  157. package/dist/auth/errors.js.map +0 -1
  158. package/dist/auth/index.d.ts +0 -13
  159. package/dist/auth/index.d.ts.map +0 -1
  160. package/dist/auth/index.js +0 -15
  161. package/dist/auth/index.js.map +0 -1
  162. package/dist/auth/middleware.d.ts +0 -81
  163. package/dist/auth/middleware.d.ts.map +0 -1
  164. package/dist/auth/middleware.js +0 -291
  165. package/dist/auth/middleware.js.map +0 -1
  166. package/dist/auth/scopes.d.ts +0 -136
  167. package/dist/auth/scopes.d.ts.map +0 -1
  168. package/dist/auth/scopes.js +0 -349
  169. package/dist/auth/scopes.js.map +0 -1
  170. package/dist/auth/types.d.ts +0 -257
  171. package/dist/auth/types.d.ts.map +0 -1
  172. package/dist/auth/types.js +0 -8
  173. package/dist/auth/types.js.map +0 -1
  174. package/dist/cli.d.ts.map +0 -1
  175. package/dist/cli.js.map +0 -1
  176. package/dist/constants/ServerInstructions.d.ts +0 -45
  177. package/dist/constants/ServerInstructions.d.ts.map +0 -1
  178. package/dist/constants/ServerInstructions.js +0 -356
  179. package/dist/constants/ServerInstructions.js.map +0 -1
  180. package/dist/filtering/ToolConstants.d.ts +0 -34
  181. package/dist/filtering/ToolConstants.d.ts.map +0 -1
  182. package/dist/filtering/ToolConstants.js +0 -174
  183. package/dist/filtering/ToolConstants.js.map +0 -1
  184. package/dist/filtering/ToolFilter.d.ts +0 -82
  185. package/dist/filtering/ToolFilter.d.ts.map +0 -1
  186. package/dist/filtering/ToolFilter.js +0 -296
  187. package/dist/filtering/ToolFilter.js.map +0 -1
  188. package/dist/index.d.ts.map +0 -1
  189. package/dist/index.js.map +0 -1
  190. package/dist/server/McpServer.d.ts +0 -61
  191. package/dist/server/McpServer.d.ts.map +0 -1
  192. package/dist/server/McpServer.js +0 -270
  193. package/dist/server/McpServer.js.map +0 -1
  194. package/dist/transports/http.d.ts +0 -134
  195. package/dist/transports/http.d.ts.map +0 -1
  196. package/dist/transports/http.js +0 -516
  197. package/dist/transports/http.js.map +0 -1
  198. package/dist/transports/index.d.ts +0 -5
  199. package/dist/transports/index.d.ts.map +0 -1
  200. package/dist/transports/index.js +0 -5
  201. package/dist/transports/index.js.map +0 -1
  202. package/dist/types/index.d.ts +0 -380
  203. package/dist/types/index.d.ts.map +0 -1
  204. package/dist/types/index.js +0 -68
  205. package/dist/types/index.js.map +0 -1
  206. package/dist/utils/annotations.d.ts +0 -44
  207. package/dist/utils/annotations.d.ts.map +0 -1
  208. package/dist/utils/annotations.js +0 -77
  209. package/dist/utils/annotations.js.map +0 -1
  210. package/dist/utils/errors.d.ts +0 -155
  211. package/dist/utils/errors.d.ts.map +0 -1
  212. package/dist/utils/errors.js +0 -329
  213. package/dist/utils/errors.js.map +0 -1
  214. package/dist/utils/identifiers.d.ts +0 -121
  215. package/dist/utils/identifiers.d.ts.map +0 -1
  216. package/dist/utils/identifiers.js +0 -319
  217. package/dist/utils/identifiers.js.map +0 -1
  218. package/dist/utils/index.d.ts +0 -7
  219. package/dist/utils/index.d.ts.map +0 -1
  220. package/dist/utils/index.js +0 -7
  221. package/dist/utils/index.js.map +0 -1
  222. package/dist/utils/insightsManager.d.ts +0 -39
  223. package/dist/utils/insightsManager.d.ts.map +0 -1
  224. package/dist/utils/insightsManager.js +0 -63
  225. package/dist/utils/insightsManager.js.map +0 -1
  226. package/dist/utils/logger.d.ts +0 -189
  227. package/dist/utils/logger.d.ts.map +0 -1
  228. package/dist/utils/logger.js +0 -394
  229. package/dist/utils/logger.js.map +0 -1
  230. package/dist/utils/progress-utils.d.ts +0 -54
  231. package/dist/utils/progress-utils.d.ts.map +0 -1
  232. package/dist/utils/progress-utils.js +0 -74
  233. package/dist/utils/progress-utils.js.map +0 -1
  234. package/dist/utils/resourceAnnotations.d.ts +0 -36
  235. package/dist/utils/resourceAnnotations.d.ts.map +0 -1
  236. package/dist/utils/resourceAnnotations.js +0 -57
  237. package/dist/utils/resourceAnnotations.js.map +0 -1
  238. package/dist/utils/where-clause.d.ts +0 -41
  239. package/dist/utils/where-clause.d.ts.map +0 -1
  240. package/dist/utils/where-clause.js +0 -116
  241. package/dist/utils/where-clause.js.map +0 -1
@@ -0,0 +1,517 @@
1
+ # Advanced Stress Test — db-mcp (SQLite)
2
+
3
+ **Test WASM Mode Only. Ignore Native content**
4
+
5
+ **Step 1:** Read `server-instructions.ts` and `src/constants/server-instructions/gotchas.md` using `view_file` (not grep or search) to understand documented behaviors, edge cases, and response structures.
6
+
7
+ **Step 2:** Execute each numbered stress test below using `sqlite_execute_code` (code mode), not scripts/terminal.
8
+
9
+ **Note**: If your attempt to cleanup after testing fails, it's because the database is locked. Move on. I will drop them.
10
+
11
+ ## Code Mode Execution
12
+
13
+ All tests should be executed via `sqlite_execute_code` code mode. Tests are written in direct tool call syntax for readability — translate to code mode:
14
+
15
+ | Direct Tool Call | Code Mode Equivalent |
16
+ | --------------------------------------------------------- | ------------------------------------------------------------- |
17
+ | `sqlite_read_query({query: "..."})` | `sqlite.core.readQuery({query: "..."})` |
18
+ | `sqlite_write_query({query: "..."})` | `sqlite.core.writeQuery({query: "..."})` |
19
+ | `sqlite_create_table({tableName: "...", columns: [...]})` | `sqlite.core.createTable({tableName: "...", columns: [...]})` |
20
+ | `sqlite_describe_table({tableName: "..."})` | `sqlite.core.describeTable({tableName: "..."})` |
21
+ | `sqlite_drop_table({tableName: "..."})` | `sqlite.core.dropTable({tableName: "..."})` |
22
+ | `sqlite_create_index({...})` | `sqlite.core.createIndex({...})` |
23
+ | `sqlite_get_indexes({tableName: "..."})` | `sqlite.core.getIndexes({tableName: "..."})` |
24
+ | `sqlite_json_*({...})` | `sqlite.json.*({...})` |
25
+ | `sqlite_text_*` / `sqlite_regex_*` / etc. | `sqlite.text.*` |
26
+ | `sqlite_stats_*` / `sqlite_window_*` | `sqlite.stats.*` |
27
+ | `sqlite_vector_*` | `sqlite.vector.*` |
28
+ | `sqlite_fts_*` | `sqlite.text.*` (FTS tools are in the text group) |
29
+
30
+ **Key rules:**
31
+
32
+ - Use `sqlite.<group>.help()` to discover method names and parameters for each group
33
+ - State **persists** across `sqlite_execute_code` calls — create a table in one call, query it in the next
34
+ - Do **NOT** pass `readonly: true` when tests need to create/write/drop objects
35
+ - Group multiple related tests into a single code mode call when practical
36
+
37
+ ## Test Database Schema
38
+
39
+ Same as `test-tools.md` — refer to that file for the full schema reference. Key tables: `test_products` (16 rows), `test_orders` (20), `test_jsonb_docs` (6), `test_articles` (8), `test_users` (9), `test_measurements` (200), `test_embeddings` (20), `test_locations` (15), `test_categories` (17), `test_events` (100).
40
+
41
+ ## Naming & Cleanup
42
+
43
+ - **Temporary tables**: Prefix with `stress_` (e.g., `stress_empty_table`)
44
+ - **Temporary indexes**: Prefix with `stress_idx_`
45
+ - **Temporary views**: Prefix with `stress_view_`
46
+ - **Cleanup**: Attempt to remove all `temp_*` tables. If DROP fails due to a database lock, note the leftover tables and move on — they are inert and will be cleaned up on next database regeneration
47
+
48
+ ## Reporting Format
49
+
50
+ - ❌ Fail: Tool errors or produces incorrect results (include error message)
51
+ - ⚠️ Issue: Unexpected behavior or improvement opportunity
52
+ - 📦 Payload: Unnecessarily large response that should be optimized — **blocking, equally important as ❌ bugs**. Oversized payloads waste LLM context window tokens and degrade downstream tool-calling quality. Report the response size in KB and suggest a concrete optimization (e.g., filter system tables, add `compact` option, omit empty arrays).
53
+ - ✅ Confirmed: Edge case handled correctly (use only inline during testing; omit from Final Summary)
54
+
55
+ ### Error Code Consistency
56
+
57
+ When rating errors, flag any generic code (`RESOURCE_ERROR`, `UNKNOWN_ERROR`) that should be a specific code (e.g., `TABLE_NOT_FOUND`, `COLUMN_NOT_FOUND`, `VALIDATION_ERROR`). These are fixable in `src/utils/errors/` (see `suggestions.ts` and `classes.ts`) by adding a `code` override to the matching error class. Treat as ⚠️ Issue and include in fix plan.
58
+
59
+ ## Post-Test Procedures
60
+
61
+ At the end, confirm cleanup of all `stress_*` objects, then **fix every finding** — not just ❌ Fails, but also ⚠️ Issues (behavioral improvements, missing warnings, error code consistency) and 📦 Payload problems (responses that should be truncated or offer a `limit` param). Create a plan covering all finding architecturally consistent with other tools/tool groups. If the plan does not require important decision choices, proceed with implementation. When complete, update the changelog (being careful not to create duplicate headers), and commit without pushing. Then re-test your fixes with direct MCP calls.
62
+
63
+ ---
64
+
65
+ ## core Group Advanced Tests
66
+
67
+ ### Built-in Tools (3)
68
+
69
+ 1. server_info
70
+ 2. server_health
71
+ 3. list_adapters
72
+
73
+ ### core Group Tools (9)
74
+
75
+ 4. sqlite_read_query
76
+ 5. sqlite_write_query
77
+ 6. sqlite_create_table
78
+ 7. sqlite_list_tables
79
+ 8. sqlite_describe_table
80
+ 9. sqlite_drop_table
81
+ 10. sqlite_get_indexes
82
+ 11. sqlite_create_index
83
+ 12. sqlite_drop_index
84
+
85
+ ### Category 1: Boundary Values & Empty States
86
+
87
+ **1.1 Empty Table Operations**
88
+
89
+ Create `stress_empty_table (id INTEGER PRIMARY KEY, name TEXT, value REAL)`, then test:
90
+
91
+ 1. `sqlite_read_query({query: "SELECT COUNT(*) AS n FROM stress_empty_table"})` → `{rows: [{n: 0}]}`
92
+ 2. `sqlite_describe_table({tableName: "stress_empty_table"})` → valid schema with 3 columns
93
+ 3. `sqlite_get_indexes({tableName: "stress_empty_table"})` → empty or primary key only
94
+
95
+ **1.2 Single-Row Table**
96
+
97
+ Insert one row into `stress_empty_table`: `(1, 'solo', 42.0)`, then test:
98
+
99
+ 4. `sqlite_read_query({query: "SELECT * FROM stress_empty_table"})` → exactly 1 row
100
+
101
+ **1.3 NULL-Heavy Data**
102
+
103
+ Insert 4 more rows: 3 with `name IS NULL AND value IS NULL`, 1 with actual values:
104
+
105
+ 5. `sqlite_read_query({query: "SELECT COUNT(*) AS n FROM stress_empty_table WHERE value IS NULL"})` → `{rows: [{n: 3}]}`
106
+ 6. `sqlite_read_query({query: "SELECT COUNT(value) AS n FROM stress_empty_table"})` → `{rows: [{n: 2}]}` (COUNT of non-null values)
107
+
108
+ ### Category 2: State Pollution & Idempotency
109
+
110
+ **2.1 Create-Drop-Recreate Cycles**
111
+
112
+ 7. `sqlite_create_table` → create `stress_cycle_table (id INTEGER PRIMARY KEY, data TEXT)`
113
+ 8. `sqlite_create_index` → create `stress_idx_cycle` on `stress_cycle_table(data)`
114
+ 9. `sqlite_drop_table({tableName: "stress_cycle_table"})` → success
115
+ 10. `sqlite_drop_table({tableName: "stress_cycle_table"})` → expect structured error or `{existed: false}` (not a raw crash)
116
+ 11. `sqlite_create_table` → recreate `stress_cycle_table` → success (no orphaned metadata)
117
+ 12. Cleanup: drop `stress_cycle_table`
118
+
119
+ **2.2 Duplicate Object Detection**
120
+
121
+ 13. `sqlite_create_table` with the table name `test_products` → expect error or "already exists" indication (not silent overwrite)
122
+ 14. `sqlite_create_index` on `idx_orders_status` (already exists on `test_orders`) → expect error or "already exists" indication
123
+
124
+ ### Category 3: Error Message Quality
125
+
126
+ For each test, verify the error returns a **structured response** (`{success: false, error: "..."}`) — NOT a raw MCP exception. Rate each error message: does it include enough context to diagnose the problem?
127
+
128
+ **3.1 Nonexistent Objects**
129
+
130
+ 15. `sqlite_describe_table({tableName: "nonexistent_table_xyz"})` → error should mention table name
131
+ 16. `sqlite_read_query({query: "SELECT * FROM nonexistent_table_xyz"})` → error should mention table name
132
+ 17. `sqlite_get_indexes({tableName: "nonexistent_table_xyz"})` → report behavior
133
+ 18. `sqlite_write_query({query: "INSERT INTO nonexistent_table_xyz VALUES (1)"})` → structured error
134
+
135
+ **3.2 Invalid SQL**
136
+
137
+ 19. `sqlite_read_query({query: "SELEKT * FROM test_products"})` → structured error with SQL syntax context
138
+ 20. `sqlite_write_query({query: "INSERT INTO test_products (nonexistent_col) VALUES (1)"})` → structured error mentioning column
139
+
140
+ **3.3 Type/Constraint Violations**
141
+
142
+ 21. `sqlite_write_query({query: "INSERT INTO test_products (id) VALUES (1)"})` → duplicate primary key error (id=1 exists)
143
+
144
+ ### Category 4: Large Payload & Truncation Verification
145
+
146
+ 22. `sqlite_read_query({query: "SELECT * FROM test_measurements"})` → 200 rows — verify response size, check if truncation/limit is applied
147
+ 23. `sqlite_read_query({query: "SELECT * FROM test_measurements LIMIT 5"})` → exactly 5 rows
148
+ 24. `sqlite_read_query({query: "SELECT * FROM test_events"})` → 100 rows — check payload size
149
+
150
+ ### Final Cleanup
151
+
152
+ Drop all `stress_*` tables created during testing and confirm `test_products` row count is still 16 (no pollution).
153
+
154
+ ---
155
+
156
+ ## json Group Advanced Tests
157
+
158
+ ### Built-in Tools (3)
159
+
160
+ 1. server_info
161
+ 2. server_health
162
+ 3. list_adapters
163
+
164
+ ### json Group Tools (23)
165
+
166
+ 4. sqlite_json_valid
167
+ 5. sqlite_json_extract
168
+ 6. sqlite_json_set
169
+ 7. sqlite_json_remove
170
+ 8. sqlite_json_type
171
+ 9. sqlite_json_array_length
172
+ 10. sqlite_json_array_append
173
+ 11. sqlite_json_keys
174
+ 12. sqlite_json_each
175
+ 13. sqlite_json_group_array
176
+ 14. sqlite_json_group_object
177
+ 15. sqlite_json_pretty
178
+ 16. sqlite_jsonb_convert
179
+ 17. sqlite_json_storage_info
180
+ 18. sqlite_json_normalize_column
181
+ 19. sqlite_json_insert
182
+ 20. sqlite_json_update
183
+ 21. sqlite_json_select
184
+ 22. sqlite_json_query
185
+ 23. sqlite_json_validate_path
186
+ 24. sqlite_json_merge
187
+ 25. sqlite_json_analyze_schema
188
+ 26. sqlite_create_json_collection
189
+
190
+ ### Category 1: Deep JSON Operations
191
+
192
+ **1.1 Deeply Nested Access**
193
+
194
+ 1. `sqlite_json_extract({table: "test_jsonb_docs", column: "doc", path: "$.nested.level1.level2", whereClause: "id = 4"})` → `"deep value"`
195
+ 2. `sqlite_json_extract({table: "test_jsonb_docs", column: "doc", path: "$.nested.level1.nonexistent", whereClause: "id = 4"})` → null or empty (not error)
196
+ 3. `sqlite_json_extract({table: "test_jsonb_docs", column: "doc", path: "$.nonexistent_key", whereClause: "id = 1"})` → null or empty
197
+
198
+ **1.2 Array Manipulation Edge Cases**
199
+
200
+ 4. `sqlite_json_array_length({table: "test_jsonb_docs", column: "tags", whereClause: "id = 3"})` → 3 (["mcp","protocol","ai"])
201
+ 5. Create `stress_json_test` with a row containing `tags = '[]'` (empty array) → `sqlite_json_array_length` → 0
202
+ 6. `sqlite_json_each` on an empty array → 0 expanded rows (not error)
203
+
204
+ **1.3 Merge Conflict Behavior**
205
+
206
+ > **Note:** `sqlite_json_merge` is table-bound (requires `table`, `column`, `mergeData`, `whereClause`) — it uses `json_patch()` which follows RFC 7396 merge-patch semantics.
207
+
208
+ Insert test rows into `stress_json_test`: row 2 = `{"a": 1, "b": {"c": 2}}`, row 3 = `{"a": [1, 2]}`:
209
+
210
+ 7. `sqlite_json_merge({table: "stress_json_test", column: "tags", mergeData: {"b": {"d": 3}}, whereClause: "id = 2"})` → verify deep merge: `b.c` should survive (`json_patch` recursively merges objects, so `b.c` is preserved alongside new `b.d`)
211
+ 8. `sqlite_json_merge({table: "stress_json_test", column: "tags", mergeData: {"a": [3, 4]}, whereClause: "id = 3"})` → arrays are replaced (not concatenated) per RFC 7396
212
+
213
+ **1.4 Type Coercion Edge Cases**
214
+
215
+ 9. `sqlite_json_type({table: "test_jsonb_docs", column: "doc", path: "$.views", whereClause: "id = 1"})` → `"integer"` (views=1250)
216
+ 10. `sqlite_json_type({table: "test_jsonb_docs", column: "doc", path: "$.rating", whereClause: "id = 1"})` → `"real"` (rating=4.5)
217
+ 11. `sqlite_json_type({table: "test_jsonb_docs", column: "doc", path: "$.nested", whereClause: "id = 4"})` → `"object"`
218
+
219
+ ### Category 2: JSON Query & Filter Stress
220
+
221
+ > **Note:** `sqlite_json_query` uses `filterPaths` (equality-only, `Record<path, value>`) and `selectPaths` — not `conditions` with operators.
222
+
223
+ 12. `sqlite_json_query({table: "test_jsonb_docs", column: "doc", filterPaths: {"$.type": "article"}})` → 4 rows (all articles)
224
+ 13. `sqlite_json_query({table: "test_jsonb_docs", column: "doc", filterPaths: {"$.type": "article", "$.author": "Alice"}, selectPaths: ["$.title", "$.views"]})` → 1 row (Alice's article)
225
+ 14. `sqlite_json_query({table: "test_events", column: "payload", filterPaths: {"$.page": "home"}})` → 25 rows (every 4th event)
226
+
227
+ ### Category 3: Error Message Quality
228
+
229
+ 15. `sqlite_json_extract({table: "nonexistent_table_xyz", column: "doc", path: "$.x"})` → structured error mentioning table name
230
+ 16. `sqlite_json_extract({table: "test_jsonb_docs", column: "nonexistent_col", path: "$.x"})` → structured error mentioning column name
231
+ 17. `sqlite_json_set({table: "test_jsonb_docs", column: "doc", path: "$.author", value: "\"Modified\"", whereClause: "id = 99999"})` → report behavior for nonexistent row
232
+ 18. `sqlite_json_validate_path({path: ""})` → report behavior for empty path
233
+
234
+ ### Category 4: Write Operation Safety
235
+
236
+ 19. Create `stress_json_write` table → insert 3 JSON documents → perform `sqlite_json_set`, `sqlite_json_remove`, `sqlite_json_insert` → verify mutations → cleanup
237
+ > **Note:** `sqlite_json_insert` is a **row-level INSERT** (creates a new row with JSON data), not a path-level JSON insert like SQLite's `json_insert()` function.
238
+ 20. `sqlite_json_normalize_column` on `stress_json_write` → verify keys are sorted/compacted without data loss
239
+
240
+ ### Final Cleanup
241
+
242
+ Drop all `stress_*` tables. Confirm `test_jsonb_docs` row count is still 6 and contents are unchanged.
243
+
244
+ ---
245
+
246
+ ## text Group Advanced Tests
247
+
248
+ ### Built-in Tools (3)
249
+
250
+ 1. server_info
251
+ 2. server_health
252
+ 3. list_adapters
253
+
254
+ ### text Group Tools — Native (17)
255
+
256
+ 4. sqlite_regex_extract
257
+ 5. sqlite_regex_match
258
+ 6. sqlite_text_split
259
+ 7. sqlite_text_concat
260
+ 8. sqlite_text_replace
261
+ 9. sqlite_text_trim
262
+ 10. sqlite_text_case
263
+ 11. sqlite_text_substring
264
+ 12. sqlite_fuzzy_match
265
+ 13. sqlite_phonetic_match
266
+ 14. sqlite_text_normalize
267
+ 15. sqlite_text_validate
268
+ 16. sqlite_advanced_search
269
+ 17. sqlite_fts_create `[NATIVE ONLY]`
270
+ 18. sqlite_fts_search `[NATIVE ONLY]`
271
+ 19. sqlite_fts_rebuild `[NATIVE ONLY]`
272
+ 20. sqlite_fts_match_info `[NATIVE ONLY]`
273
+
274
+ ### text Group Tools — WASM (13)
275
+
276
+ Same as Native minus the 4 FTS5 tools (items 17-20).
277
+
278
+ ### Category 1: Regex Edge Cases
279
+
280
+ 1. `sqlite_regex_match({table: "test_users", column: "email", pattern: "^[a-z]+\\.[a-z]+@"})` → verify matching against dotted local parts (john.doe, jane.smith, etc.)
281
+ 2. `sqlite_regex_match({table: "test_users", column: "phone", pattern: "^\\+1"})` → US phone numbers only (6 users, 1 NULL excluded)
282
+ 3. `sqlite_regex_extract({table: "test_users", column: "email", pattern: "@(.+)$", groupIndex: 1})` → full domain extraction
283
+ 4. `sqlite_regex_match({table: "test_users", column: "bio", pattern: ".*"})` → should match all non-NULL bios (all 9 users have bios)
284
+
285
+ ### Category 2: Fuzzy/Phonetic Matching Stress
286
+
287
+ 5. `sqlite_fuzzy_match({table: "test_products", column: "name", search: "Keyborad", maxDistance: 3})` → should find "Mechanical Keyboard" (Levenshtein)
288
+ 6. `sqlite_fuzzy_match({table: "test_products", column: "name", search: "LAPTOP", maxDistance: 2, tokenize: true})` → should match "Laptop" token in "Laptop Pro 15"
289
+ 7. `sqlite_fuzzy_match({table: "test_products", column: "name", search: "xyznonexistent", maxDistance: 1})` → 0 results
290
+ 8. `sqlite_phonetic_match({table: "test_users", column: "username", search: "jon", algorithm: "soundex"})` → 0 results expected (Soundex: "jon"=J500 ≠ "johndoe"=J530; single-word usernames aren't tokenized)
291
+ 9. `sqlite_phonetic_match({table: "test_users", column: "username", search: "smith", algorithm: "soundex"})` → report behavior (janesmith contains "smith" as suffix)
292
+ 10. `sqlite_advanced_search({table: "test_users", column: "username", searchTerm: "jhn", techniques: ["exact", "fuzzy", "phonetic"], fuzzyThreshold: 0.3})` → should find John via fuzzy/phonetic even with low threshold
293
+
294
+ ### Category 3: Text Transformation Edge Cases
295
+
296
+ 11. `sqlite_text_normalize({table: "test_products", column: "name", mode: "strip_accents"})` → `"Café Décor Light"` becomes `"Cafe Decor Light"` — verify ALL rows returned, not just the accented one
297
+ 12. `sqlite_text_normalize({table: "test_products", column: "name", mode: "nfkc"})` → NFKC normalization (compatibility decomposition + canonical composition)
298
+ 13. `sqlite_text_case({table: "test_users", column: "username", mode: "upper"})` → verify 9 uppercased usernames
299
+ 14. `sqlite_text_case({table: "test_users", column: "username", mode: "lower"})` → verify idempotent (already lowercase)
300
+ 15. `sqlite_text_substring({table: "test_users", column: "email", start: 1, length: 3})` → first 3 chars of each email
301
+
302
+ ### Category 4: Validation Patterns
303
+
304
+ 16. `sqlite_text_validate({table: "test_users", column: "email", pattern: "email"})` → expect all 9 valid
305
+ 17. `sqlite_text_validate({table: "test_users", column: "phone", pattern: "phone"})` → report valid/invalid/null counts
306
+ 18. `sqlite_text_validate({table: "test_users", column: "email", pattern: "custom", customPattern: "^.+@.+\\..{2,}$"})` → custom regex validation
307
+
308
+ ### Category 5: FTS5 State Integrity `[NATIVE ONLY]`
309
+
310
+ 19. `sqlite_fts_search({table: "test_articles_fts", query: "database"})` → verify results include articles about databases
311
+ 20. After base tests confirm FTS works, test rebuild: `sqlite_fts_rebuild({table: "test_articles_fts"})` → success
312
+ 21. `sqlite_fts_search({table: "test_articles_fts", query: "database"})` → verify same results after rebuild (idempotent)
313
+ 22. `sqlite_fts_search({table: "test_articles_fts", query: "SQLite AND database"})` → boolean operator test
314
+ 23. `sqlite_fts_search({table: "test_articles_fts", query: "\"full-text search\""})` → phrase query test
315
+
316
+ ### Category 6: WASM Boundary Verification
317
+
318
+ For WASM testing only — verify graceful degradation:
319
+
320
+ 24. Confirm FTS5 tools are NOT present in the tool list (WASM mode should exclude them)
321
+ 25. All 13 non-FTS text tools should work identically in WASM and Native
322
+
323
+ ### Category 7: Error Message Quality
324
+
325
+ 26. `sqlite_regex_match({table: "nonexistent_table_xyz", column: "x", pattern: "."})` → structured error
326
+ 27. `sqlite_fuzzy_match({table: "test_users", column: "nonexistent_col", search: "test"})` → structured error
327
+ 28. `sqlite_text_validate({table: "test_users", column: "email", pattern: "custom"})` → error about missing `customPattern` when pattern=custom
328
+ 29. `sqlite_fts_search({table: "nonexistent_fts_xyz", query: "test"})` `[NATIVE ONLY]` → structured error
329
+
330
+ ### Final Cleanup
331
+
332
+ Confirm `test_articles` row count is still 8. Verify FTS index integrity with `sqlite_fts_match_info` `[NATIVE ONLY]`.
333
+
334
+ ---
335
+
336
+ ## stats Group Advanced Tests
337
+
338
+ ### Built-in Tools (3)
339
+
340
+ 1. server_info
341
+ 2. server_health
342
+ 3. list_adapters
343
+
344
+ ### stats Group Tools — Native (19)
345
+
346
+ 4. sqlite_stats_basic
347
+ 5. sqlite_stats_count
348
+ 6. sqlite_stats_group_by
349
+ 7. sqlite_stats_histogram
350
+ 8. sqlite_stats_percentile
351
+ 9. sqlite_stats_correlation
352
+ 10. sqlite_stats_top_n
353
+ 11. sqlite_stats_distinct
354
+ 12. sqlite_stats_summary
355
+ 13. sqlite_stats_frequency
356
+ 14. sqlite_stats_outliers
357
+ 15. sqlite_stats_regression
358
+ 16. sqlite_stats_hypothesis
359
+ 17. sqlite_window_row_number `[NATIVE ONLY]`
360
+ 18. sqlite_window_rank `[NATIVE ONLY]`
361
+ 19. sqlite_window_lag_lead `[NATIVE ONLY]`
362
+ 20. sqlite_window_running_total `[NATIVE ONLY]`
363
+ 21. sqlite_window_moving_avg `[NATIVE ONLY]`
364
+ 22. sqlite_window_ntile `[NATIVE ONLY]`
365
+
366
+ ### stats Group Tools — WASM (13)
367
+
368
+ Same as Native minus the 6 window function tools (items 17-22).
369
+
370
+ ### Category 1: Boundary Values & Empty States
371
+
372
+ Create `stress_stats_table (id INTEGER PRIMARY KEY, value REAL, category TEXT)`:
373
+
374
+ **1.1 Empty Table Statistics**
375
+
376
+ 1. `sqlite_stats_basic({table: "stress_stats_table", column: "value"})` → expect graceful error or empty stats (not a crash)
377
+ 2. `sqlite_stats_count({table: "stress_stats_table"})` → `{count: 0}`
378
+ 3. `sqlite_stats_histogram({table: "stress_stats_table", column: "value", buckets: 5})` → expect graceful handling
379
+
380
+ **1.2 Single-Row Statistics**
381
+
382
+ Insert one row: `(1, 42.0, 'test')`:
383
+
384
+ 4. `sqlite_stats_basic({table: "stress_stats_table", column: "value"})` → count=1, min=max=avg=42.0
385
+ 5. `sqlite_stats_percentile({table: "stress_stats_table", column: "value", percentiles: [25, 50, 75]})` → all should equal 42
386
+ 6. `sqlite_stats_regression({table: "stress_stats_table", xColumn: "id", yColumn: "value", degree: 1})` → expect graceful handling (regression undefined for n=1)
387
+
388
+ **1.3 NULL-Heavy Data**
389
+
390
+ Insert 5 rows: 3 with `value IS NULL`, 2 with actual values:
391
+
392
+ 7. `sqlite_stats_basic({table: "stress_stats_table", column: "value"})` → should only count non-null values (3 total: 42.0 + 2 new)
393
+ 8. `sqlite_stats_count({table: "stress_stats_table", column: "value"})` → non-null count only
394
+
395
+ **1.4 Extreme Numeric Values**
396
+
397
+ Insert: `(value: 99999999.99)`, `(value: -99999999.99)`, `(value: 0.0)`, `(value: 0.01)`:
398
+
399
+ 9. `sqlite_stats_basic({table: "stress_stats_table", column: "value"})` → verify min/max/avg handle extreme values correctly
400
+
401
+ ### Category 2: Statistical Edge Cases
402
+
403
+ 10. `sqlite_stats_correlation({table: "test_products", column1: "id", column2: "id"})` → self-correlation = 1.0 (or very close)
404
+ 11. `sqlite_stats_hypothesis({table: "test_measurements", column: "temperature", testType: "ttest_one", expectedMean: 999})` → should reject null hypothesis (very different from actual mean)
405
+ 12. `sqlite_stats_outliers({table: "test_measurements", column: "temperature", method: "iqr"})` → IQR-based outliers
406
+ 13. `sqlite_stats_outliers({table: "test_measurements", column: "temperature", method: "zscore"})` → Z-score-based outliers (compare with IQR)
407
+ 14. `sqlite_stats_regression({table: "test_measurements", xColumn: "temperature", yColumn: "humidity", degree: 2})` → quadratic regression coefficients
408
+
409
+ ### Category 3: Window Functions `[NATIVE ONLY]`
410
+
411
+ 15. `sqlite_window_row_number({table: "test_products", orderBy: "price DESC"})` → 16 rows with sequential row numbers, Laptop Pro 15 at #1
412
+ > **Note:** `window_row_number` and `window_rank` do NOT have a `direction` param — embed direction in the `orderBy` string (e.g., `"price DESC"`).
413
+ 16. `sqlite_window_rank({table: "test_orders", orderBy: "total_price DESC"})` → ranks with potential ties
414
+ 17. `sqlite_window_running_total({table: "test_orders", valueColumn: "total_price", orderBy: "order_date"})` → monotonically increasing cumulative total
415
+ 18. `sqlite_window_moving_avg({table: "test_measurements", valueColumn: "temperature", windowSize: 10, orderBy: "measured_at"})` → moving average with 10-row window
416
+ 19. `sqlite_window_ntile({table: "test_products", buckets: 4, orderBy: "price"})` → 4 groups of ~4 products each
417
+
418
+ ### Category 4: Error Message Quality
419
+
420
+ 20. `sqlite_stats_basic({table: "nonexistent_table_xyz", column: "x"})` → structured error mentioning table name
421
+ 21. `sqlite_stats_basic({table: "test_products", column: "nonexistent_col"})` → structured error mentioning column name
422
+ 22. `sqlite_stats_correlation({table: "test_products", column1: "name", column2: "description"})` → error about non-numeric columns (both TEXT)
423
+ 23. `sqlite_stats_histogram({table: "test_products", column: "price", buckets: 0})` → error (must be > 0)
424
+ 24. `sqlite_stats_histogram({table: "test_products", column: "price", buckets: -1})` → error
425
+
426
+ ### Category 5: WASM Boundary Verification
427
+
428
+ For WASM testing only:
429
+
430
+ 25. Confirm window function tools are NOT present in the tool list
431
+ 26. All 13 non-window stats tools should produce identical results in WASM and Native
432
+
433
+ ### Final Cleanup
434
+
435
+ Drop `stress_stats_table`. Confirm `test_measurements` (200 rows) and `test_products` (16 rows) are unchanged.
436
+
437
+ ---
438
+
439
+ ## vector Group Advanced Tests
440
+
441
+ > **Note:** Vector tools use pure JS computations with JSON-stored vectors — all 12 tools work identically in both WASM and Native modes.
442
+
443
+ ### Built-in Tools (3)
444
+
445
+ 1. server_info
446
+ 2. server_health
447
+ 3. list_adapters
448
+
449
+ ### vector Group Tools (11)
450
+
451
+ 4. sqlite_vector_create_table
452
+ 5. sqlite_vector_store
453
+ 6. sqlite_vector_batch_store
454
+ 7. sqlite_vector_search
455
+ 8. sqlite_vector_get
456
+ 9. sqlite_vector_delete
457
+ 10. sqlite_vector_count
458
+ 11. sqlite_vector_stats
459
+ 12. sqlite_vector_dimensions
460
+ 13. sqlite_vector_normalize
461
+ 14. sqlite_vector_distance
462
+
463
+ ### Category 1: Boundary Values
464
+
465
+ > **Note:** Vector tools use `tableName` for create, but `table` for other operations. Store/batch-store require `idColumn` and `vectorColumn`. Search requires `vectorColumn` and `queryVector`.
466
+
467
+ **1.1 Empty Vector Table**
468
+
469
+ 1. `sqlite_vector_create_table({tableName: "stress_vec_empty", dimensions: 4})` → success (creates columns: id, vector, dimensions)
470
+ 2. `sqlite_vector_count({table: "stress_vec_empty"})` → `{count: 0}`
471
+ 3. `sqlite_vector_search({table: "stress_vec_empty", vectorColumn: "vector", queryVector: [1, 2, 3, 4], metric: "cosine", limit: 5})` → empty results (not error)
472
+ 4. `sqlite_vector_stats({table: "stress_vec_empty", vectorColumn: "vector"})` → graceful handling: `{count: 0, message: "No valid vectors found"}`
473
+ 5. `sqlite_vector_dimensions({table: "stress_vec_empty", vectorColumn: "vector"})` → `{dimensions: null, message: "No vectors found"}` (inferred from data, not schema)
474
+
475
+ **1.2 Single-Vector Table**
476
+
477
+ 6. `sqlite_vector_store({table: "stress_vec_empty", idColumn: "id", vectorColumn: "vector", id: 1, vector: [1, 0, 0, 0]})` → success
478
+ 7. `sqlite_vector_search({table: "stress_vec_empty", vectorColumn: "vector", queryVector: [1, 0, 0, 0], metric: "cosine", limit: 5})` → exactly 1 result, similarity = 1
479
+
480
+ ### Category 2: Distance Metric Verification
481
+
482
+ 8. `sqlite_vector_distance({vector1: [1, 0, 0], vector2: [0, 1, 0], metric: "cosine"})` → ≈ 1.0 (orthogonal)
483
+ 9. `sqlite_vector_distance({vector1: [1, 0, 0], vector2: [1, 0, 0], metric: "cosine"})` → ≈ 0.0 (identical)
484
+ 10. `sqlite_vector_distance({vector1: [1, 0, 0], vector2: [-1, 0, 0], metric: "cosine"})` → ≈ 2.0 (opposite)
485
+ 11. `sqlite_vector_distance({vector1: [3, 4], vector2: [0, 0], metric: "euclidean"})` → exactly 5.0
486
+ 12. `sqlite_vector_distance({vector1: [1, 2, 3], vector2: [1, 2, 3], metric: "euclidean"})` → exactly 0.0
487
+ 13. `sqlite_vector_normalize({vector: [3, 4]})` → `{normalized: [0.6, 0.8], originalMagnitude: 5.0}`
488
+ 14. `sqlite_vector_normalize({vector: [0, 0, 0]})` → `{normalized: [0, 0, 0], originalMagnitude: 0}` (zero vector returns zero — no crash)
489
+
490
+ ### Category 3: Dimension Mismatch
491
+
492
+ > **Note:** Dimension validation on store is best-effort — checks `dimensions` column of existing rows. `sqlite_vector_distance` enforces strictly.
493
+
494
+ 15. `sqlite_vector_store({table: "stress_vec_empty", idColumn: "id", vectorColumn: "vector", id: 2, vector: [1, 2]})` → dimension mismatch error (table has 4-dim rows)
495
+ 16. `sqlite_vector_search({table: "stress_vec_empty", vectorColumn: "vector", queryVector: [1, 2], metric: "cosine"})` → search still runs (dimension mismatch is silently handled via try/catch in similarity calculation)
496
+ 17. `sqlite_vector_distance({vector1: [1, 2, 3], vector2: [1, 2], metric: "cosine"})` → structured error: "Vector dimensions must match"
497
+
498
+ ### Category 4: Batch Operations
499
+
500
+ 18. `sqlite_vector_batch_store({table: "stress_vec_empty", idColumn: "id", vectorColumn: "vector", items: []})` → `{stored: 0, message: "No items provided"}`
501
+ 19. `sqlite_vector_batch_store` with 50 vectors into `stress_vec_empty` → verify `{stored: 50}`
502
+ 20. `sqlite_vector_count({table: "stress_vec_empty"})` → `{count: 51}` (1 from earlier + 50 batch)
503
+
504
+ ### Category 5: Category Filtering
505
+
506
+ 21. `sqlite_vector_search({table: "test_embeddings", vectorColumn: "embedding", queryVector: [0.12, 0.45, -0.23, 0.78, 0.34, -0.56, 0.89, 0.01], metric: "cosine", limit: 20, whereClause: "category = 'tech'"})` → only tech category results (4 rows)
507
+ 22. `sqlite_vector_search({table: "test_embeddings", vectorColumn: "embedding", queryVector: [0.12, 0.45, -0.23, 0.78, 0.34, -0.56, 0.89, 0.01], metric: "cosine", limit: 20, whereClause: "category = 'nonexistent'"})` → 0 results (not error)
508
+
509
+ ### Category 6: Error Message Quality
510
+
511
+ 23. `sqlite_vector_search({table: "nonexistent_table_xyz", vectorColumn: "v", queryVector: [1, 2, 3], metric: "cosine"})` → structured error mentioning table name
512
+ 24. `sqlite_vector_get({table: "test_embeddings", idColumn: "id", vectorColumn: "embedding", id: 99999})` → `{success: false, error: "Vector not found"}`
513
+ 25. `sqlite_vector_delete({table: "test_embeddings", idColumn: "id", ids: [99999]})` → `{success: true, deleted: 0}` (idempotent)
514
+
515
+ ### Final Cleanup
516
+
517
+ Drop `stress_vec_empty`. Confirm `test_embeddings` count is still 20.