@adecore/database 0.0.1 → 0.16.0-beta.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 (400) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +152 -1
  3. package/dist/DatabaseProvider.d.ts +13 -0
  4. package/dist/DatabaseProvider.js +17 -0
  5. package/dist/actions.d.ts +40 -0
  6. package/dist/actions.js +1 -0
  7. package/dist/client/client.d.ts +5 -0
  8. package/dist/client/client.js +245 -0
  9. package/dist/client/index.d.ts +2 -0
  10. package/dist/client/index.js +2 -0
  11. package/dist/client/types.d.ts +97 -0
  12. package/dist/client/types.js +13 -0
  13. package/dist/client-context.d.ts +16 -0
  14. package/dist/client-context.js +17 -0
  15. package/dist/connections/ConnectionForm.d.ts +10 -0
  16. package/dist/connections/ConnectionForm.js +145 -0
  17. package/dist/connections/ConnectionManager.d.ts +12 -0
  18. package/dist/connections/ConnectionManager.js +93 -0
  19. package/dist/connections/EngineIcon.d.ts +9 -0
  20. package/dist/connections/EngineIcon.js +7 -0
  21. package/dist/connections/connection-config.d.ts +16 -0
  22. package/dist/connections/connection-config.js +107 -0
  23. package/dist/connections/docker.d.ts +9 -0
  24. package/dist/connections/docker.js +38 -0
  25. package/dist/connections/engine-icons.d.ts +3 -0
  26. package/dist/connections/engine-icons.js +3 -0
  27. package/dist/connections/use-docker-containers.d.ts +17 -0
  28. package/dist/connections/use-docker-containers.js +26 -0
  29. package/dist/console/DestructiveDialog.d.ts +9 -0
  30. package/dist/console/DestructiveDialog.js +9 -0
  31. package/dist/console/HistoryPanel.d.ts +10 -0
  32. package/dist/console/HistoryPanel.js +15 -0
  33. package/dist/console/QueryConsole.d.ts +14 -0
  34. package/dist/console/QueryConsole.js +261 -0
  35. package/dist/console/SchemaPicker.d.ts +11 -0
  36. package/dist/console/SchemaPicker.js +8 -0
  37. package/dist/console/SqlEditor.d.ts +12 -0
  38. package/dist/console/SqlEditor.js +61 -0
  39. package/dist/console/StatementResultView.d.ts +18 -0
  40. package/dist/console/StatementResultView.js +32 -0
  41. package/dist/console/TransactionControls.d.ts +13 -0
  42. package/dist/console/TransactionControls.js +12 -0
  43. package/dist/console/destructive.d.ts +7 -0
  44. package/dist/console/destructive.js +43 -0
  45. package/dist/console/editing.d.ts +12 -0
  46. package/dist/console/editing.js +60 -0
  47. package/dist/console/history.d.ts +13 -0
  48. package/dist/console/history.js +43 -0
  49. package/dist/console/labels.d.ts +1 -0
  50. package/dist/console/labels.js +6 -0
  51. package/dist/console/outcome.d.ts +6 -0
  52. package/dist/console/outcome.js +11 -0
  53. package/dist/console/schemas.d.ts +2 -0
  54. package/dist/console/schemas.js +5 -0
  55. package/dist/console/shortcuts.d.ts +2 -0
  56. package/dist/console/shortcuts.js +3 -0
  57. package/dist/console/useConsoleHistory.d.ts +7 -0
  58. package/dist/console/useConsoleHistory.js +22 -0
  59. package/dist/ddl/alter-mysql.d.ts +4 -0
  60. package/dist/ddl/alter-mysql.js +79 -0
  61. package/dist/ddl/alter-sqlite.d.ts +4 -0
  62. package/dist/ddl/alter-sqlite.js +80 -0
  63. package/dist/ddl/alter.d.ts +4 -0
  64. package/dist/ddl/alter.js +24 -0
  65. package/dist/ddl/column.d.ts +9 -0
  66. package/dist/ddl/column.js +62 -0
  67. package/dist/ddl/create.d.ts +12 -0
  68. package/dist/ddl/create.js +74 -0
  69. package/dist/ddl/dialect.d.ts +12 -0
  70. package/dist/ddl/dialect.js +34 -0
  71. package/dist/ddl/diff.d.ts +34 -0
  72. package/dist/ddl/diff.js +111 -0
  73. package/dist/ddl/draft.d.ts +46 -0
  74. package/dist/ddl/draft.js +70 -0
  75. package/dist/ddl/index.d.ts +10 -0
  76. package/dist/ddl/index.js +10 -0
  77. package/dist/ddl/parse.d.ts +17 -0
  78. package/dist/ddl/parse.js +131 -0
  79. package/dist/ddl/statements.d.ts +6 -0
  80. package/dist/ddl/statements.js +12 -0
  81. package/dist/ddl/types.d.ts +6 -0
  82. package/dist/ddl/types.js +52 -0
  83. package/dist/ddl/validate.d.ts +7 -0
  84. package/dist/ddl/validate.js +38 -0
  85. package/dist/designer/ColumnsEditor.d.ts +2 -0
  86. package/dist/designer/ColumnsEditor.js +24 -0
  87. package/dist/designer/DesignerView.d.ts +25 -0
  88. package/dist/designer/DesignerView.js +33 -0
  89. package/dist/designer/ForeignKeysEditor.d.ts +7 -0
  90. package/dist/designer/ForeignKeysEditor.js +24 -0
  91. package/dist/designer/IndexesEditor.d.ts +2 -0
  92. package/dist/designer/IndexesEditor.js +13 -0
  93. package/dist/designer/NamePicker.d.ts +11 -0
  94. package/dist/designer/NamePicker.js +13 -0
  95. package/dist/designer/OptionsEditor.d.ts +2 -0
  96. package/dist/designer/OptionsEditor.js +17 -0
  97. package/dist/designer/SqlPreview.d.ts +12 -0
  98. package/dist/designer/SqlPreview.js +17 -0
  99. package/dist/designer/TableDesigner.d.ts +10 -0
  100. package/dist/designer/TableDesigner.js +103 -0
  101. package/dist/designer/edit.d.ts +17 -0
  102. package/dist/designer/edit.js +115 -0
  103. package/dist/designer/editor-props.d.ts +10 -0
  104. package/dist/designer/editor-props.js +1 -0
  105. package/dist/designer/plan.d.ts +9 -0
  106. package/dist/designer/plan.js +13 -0
  107. package/dist/designer/recover.d.ts +2 -0
  108. package/dist/designer/recover.js +18 -0
  109. package/dist/designer/useReferenceColumns.d.ts +3 -0
  110. package/dist/designer/useReferenceColumns.js +36 -0
  111. package/dist/explorer/DatabaseExplorer.d.ts +13 -0
  112. package/dist/explorer/DatabaseExplorer.js +264 -0
  113. package/dist/explorer/RowMenu.d.ts +11 -0
  114. package/dist/explorer/RowMenu.js +89 -0
  115. package/dist/explorer/TableDialog.d.ts +15 -0
  116. package/dist/explorer/TableDialog.js +50 -0
  117. package/dist/explorer/expansion.d.ts +7 -0
  118. package/dist/explorer/expansion.js +31 -0
  119. package/dist/explorer/table-statements.d.ts +5 -0
  120. package/dist/explorer/table-statements.js +12 -0
  121. package/dist/explorer/tree.d.ts +125 -0
  122. package/dist/explorer/tree.js +295 -0
  123. package/dist/explorer/use-explorer-loads.d.ts +12 -0
  124. package/dist/explorer/use-explorer-loads.js +109 -0
  125. package/dist/explorer/use-stored-expansion.d.ts +9 -0
  126. package/dist/explorer/use-stored-expansion.js +47 -0
  127. package/dist/grid/CellEditor.d.ts +9 -0
  128. package/dist/grid/CellEditor.js +29 -0
  129. package/dist/grid/CopyAsMenu.d.ts +7 -0
  130. package/dist/grid/CopyAsMenu.js +10 -0
  131. package/dist/grid/DataGrid.d.ts +36 -0
  132. package/dist/grid/DataGrid.js +512 -0
  133. package/dist/grid/EnumPicker.d.ts +17 -0
  134. package/dist/grid/EnumPicker.js +53 -0
  135. package/dist/grid/GridHeaderCell.d.ts +36 -0
  136. package/dist/grid/GridHeaderCell.js +69 -0
  137. package/dist/grid/RecordView.d.ts +20 -0
  138. package/dist/grid/RecordView.js +126 -0
  139. package/dist/grid/ValueDock.d.ts +11 -0
  140. package/dist/grid/ValueDock.js +28 -0
  141. package/dist/grid/aggregates.d.ts +22 -0
  142. package/dist/grid/aggregates.js +62 -0
  143. package/dist/grid/cell-range.d.ts +14 -0
  144. package/dist/grid/cell-range.js +11 -0
  145. package/dist/grid/column-layout.d.ts +18 -0
  146. package/dist/grid/column-layout.js +49 -0
  147. package/dist/grid/column-selection.d.ts +11 -0
  148. package/dist/grid/column-selection.js +28 -0
  149. package/dist/grid/column-view.d.ts +10 -0
  150. package/dist/grid/column-view.js +23 -0
  151. package/dist/grid/copy-formats.d.ts +15 -0
  152. package/dist/grid/copy-formats.js +80 -0
  153. package/dist/grid/display.d.ts +20 -0
  154. package/dist/grid/display.js +81 -0
  155. package/dist/grid/edit-value.d.ts +5 -0
  156. package/dist/grid/edit-value.js +55 -0
  157. package/dist/grid/enum-type.d.ts +7 -0
  158. package/dist/grid/enum-type.js +52 -0
  159. package/dist/grid/focused-value.d.ts +4 -0
  160. package/dist/grid/focused-value.js +19 -0
  161. package/dist/grid/layout.d.ts +22 -0
  162. package/dist/grid/layout.js +74 -0
  163. package/dist/grid/navigation.d.ts +15 -0
  164. package/dist/grid/navigation.js +52 -0
  165. package/dist/grid/row-selection.d.ts +9 -0
  166. package/dist/grid/row-selection.js +24 -0
  167. package/dist/grid/sort.d.ts +7 -0
  168. package/dist/grid/sort.js +7 -0
  169. package/dist/grid/types.d.ts +30 -0
  170. package/dist/grid/types.js +9 -0
  171. package/dist/host/helper-path.d.ts +7 -0
  172. package/dist/host/helper-path.js +15 -0
  173. package/dist/host/host.d.ts +2 -0
  174. package/dist/host/host.js +343 -0
  175. package/dist/host/index.d.ts +5 -0
  176. package/dist/host/index.js +4 -0
  177. package/dist/host/spawn.d.ts +7 -0
  178. package/dist/host/spawn.js +98 -0
  179. package/dist/host/types.d.ts +19 -0
  180. package/dist/host/types.js +1 -0
  181. package/dist/host/validate.d.ts +10 -0
  182. package/dist/host/validate.js +339 -0
  183. package/dist/index.d.ts +14 -0
  184. package/dist/index.js +13 -0
  185. package/dist/locales/en.json +577 -0
  186. package/dist/locales/nl.json +577 -0
  187. package/dist/locales.d.ts +4 -0
  188. package/dist/locales.js +14 -0
  189. package/dist/protocol/connection.d.ts +56 -0
  190. package/dist/protocol/connection.js +1 -0
  191. package/dist/protocol/errors.d.ts +7 -0
  192. package/dist/protocol/errors.js +1 -0
  193. package/dist/protocol/index.d.ts +5 -0
  194. package/dist/protocol/index.js +3 -0
  195. package/dist/protocol/messages.d.ts +250 -0
  196. package/dist/protocol/messages.js +2 -0
  197. package/dist/protocol/schema.d.ts +53 -0
  198. package/dist/protocol/schema.js +1 -0
  199. package/dist/protocol/values.d.ts +21 -0
  200. package/dist/protocol/values.js +15 -0
  201. package/dist/sql-split.d.ts +15 -0
  202. package/dist/sql-split.js +201 -0
  203. package/dist/sql.d.ts +29 -0
  204. package/dist/sql.js +104 -0
  205. package/dist/structure/StructureView.d.ts +14 -0
  206. package/dist/structure/StructureView.js +99 -0
  207. package/dist/structure/structure-text.d.ts +2 -0
  208. package/dist/structure/structure-text.js +2 -0
  209. package/dist/table/CommandField.d.ts +14 -0
  210. package/dist/table/CommandField.js +157 -0
  211. package/dist/table/ImportDialog.d.ts +27 -0
  212. package/dist/table/ImportDialog.js +28 -0
  213. package/dist/table/TableStatusBar.d.ts +19 -0
  214. package/dist/table/TableStatusBar.js +22 -0
  215. package/dist/table/TableToolbar.d.ts +43 -0
  216. package/dist/table/TableToolbar.js +16 -0
  217. package/dist/table/TableView.d.ts +13 -0
  218. package/dist/table/TableView.js +508 -0
  219. package/dist/table/command-field.d.ts +57 -0
  220. package/dist/table/command-field.js +203 -0
  221. package/dist/table/grid-rows.d.ts +23 -0
  222. package/dist/table/grid-rows.js +55 -0
  223. package/dist/table/import-mapping.d.ts +7 -0
  224. package/dist/table/import-mapping.js +28 -0
  225. package/dist/table/layout-store.d.ts +13 -0
  226. package/dist/table/layout-store.js +43 -0
  227. package/dist/table/paging.d.ts +12 -0
  228. package/dist/table/paging.js +20 -0
  229. package/dist/table/pending.d.ts +32 -0
  230. package/dist/table/pending.js +94 -0
  231. package/dist/table/references.d.ts +12 -0
  232. package/dist/table/references.js +21 -0
  233. package/dist/table/useLoaded.d.ts +7 -0
  234. package/dist/table/useLoaded.js +36 -0
  235. package/dist/table/useStoredLayout.d.ts +8 -0
  236. package/dist/table/useStoredLayout.js +39 -0
  237. package/dist/table/useTableTransfer.d.ts +51 -0
  238. package/dist/table/useTableTransfer.js +125 -0
  239. package/dist/testing/fake.d.ts +21 -0
  240. package/dist/testing/fake.js +372 -0
  241. package/dist/testing/index.d.ts +1 -0
  242. package/dist/testing/index.js +1 -0
  243. package/dist/use-popup-press.d.ts +1 -0
  244. package/dist/use-popup-press.js +24 -0
  245. package/dist/use-schema-change.d.ts +1 -0
  246. package/dist/use-schema-change.js +13 -0
  247. package/dist/use-stable-callback.d.ts +1 -0
  248. package/dist/use-stable-callback.js +9 -0
  249. package/dist/value/ValuePanel.d.ts +14 -0
  250. package/dist/value/ValuePanel.js +103 -0
  251. package/dist/value/draft.d.ts +33 -0
  252. package/dist/value/draft.js +44 -0
  253. package/dist/value/hex.d.ts +14 -0
  254. package/dist/value/hex.js +46 -0
  255. package/dist/value/json.d.ts +9 -0
  256. package/dist/value/json.js +71 -0
  257. package/dist/value/views.d.ts +22 -0
  258. package/dist/value/views.js +54 -0
  259. package/dist/workbench/DatabaseWorkbench.d.ts +9 -0
  260. package/dist/workbench/DatabaseWorkbench.js +179 -0
  261. package/dist/workbench/DesignerTab.d.ts +10 -0
  262. package/dist/workbench/DesignerTab.js +22 -0
  263. package/dist/workbench/TableTab.d.ts +10 -0
  264. package/dist/workbench/TableTab.js +8 -0
  265. package/dist/workbench/tabs.d.ts +42 -0
  266. package/dist/workbench/tabs.js +139 -0
  267. package/package.json +79 -3
  268. package/src/DatabaseProvider.tsx +37 -0
  269. package/src/actions.ts +34 -0
  270. package/src/client/client.ts +324 -0
  271. package/src/client/index.ts +18 -0
  272. package/src/client/types.ts +161 -0
  273. package/src/client-context.ts +35 -0
  274. package/src/connections/ConnectionForm.tsx +474 -0
  275. package/src/connections/ConnectionManager.tsx +224 -0
  276. package/src/connections/EngineIcon.tsx +18 -0
  277. package/src/connections/connection-config.ts +143 -0
  278. package/src/connections/docker.ts +50 -0
  279. package/src/connections/engine-icons.ts +5 -0
  280. package/src/connections/use-docker-containers.ts +41 -0
  281. package/src/console/DestructiveDialog.tsx +40 -0
  282. package/src/console/HistoryPanel.tsx +67 -0
  283. package/src/console/QueryConsole.tsx +439 -0
  284. package/src/console/SchemaPicker.tsx +32 -0
  285. package/src/console/SqlEditor.tsx +95 -0
  286. package/src/console/StatementResultView.tsx +176 -0
  287. package/src/console/TransactionControls.tsx +53 -0
  288. package/src/console/destructive.ts +60 -0
  289. package/src/console/editing.ts +77 -0
  290. package/src/console/history.ts +62 -0
  291. package/src/console/labels.ts +7 -0
  292. package/src/console/outcome.ts +14 -0
  293. package/src/console/schemas.ts +7 -0
  294. package/src/console/shortcuts.ts +4 -0
  295. package/src/console/useConsoleHistory.ts +39 -0
  296. package/src/ddl/alter-mysql.ts +90 -0
  297. package/src/ddl/alter-sqlite.ts +93 -0
  298. package/src/ddl/alter.ts +29 -0
  299. package/src/ddl/column.ts +74 -0
  300. package/src/ddl/create.ts +92 -0
  301. package/src/ddl/dialect.ts +53 -0
  302. package/src/ddl/diff.ts +164 -0
  303. package/src/ddl/draft.ts +136 -0
  304. package/src/ddl/index.ts +10 -0
  305. package/src/ddl/parse.ts +161 -0
  306. package/src/ddl/statements.ts +20 -0
  307. package/src/ddl/types.ts +60 -0
  308. package/src/ddl/validate.ts +47 -0
  309. package/src/designer/ColumnsEditor.tsx +204 -0
  310. package/src/designer/DesignerView.tsx +184 -0
  311. package/src/designer/ForeignKeysEditor.tsx +132 -0
  312. package/src/designer/IndexesEditor.tsx +63 -0
  313. package/src/designer/NamePicker.tsx +44 -0
  314. package/src/designer/OptionsEditor.tsx +101 -0
  315. package/src/designer/SqlPreview.tsx +56 -0
  316. package/src/designer/TableDesigner.tsx +186 -0
  317. package/src/designer/edit.ts +137 -0
  318. package/src/designer/editor-props.ts +13 -0
  319. package/src/designer/plan.ts +25 -0
  320. package/src/designer/recover.ts +20 -0
  321. package/src/designer/useReferenceColumns.ts +54 -0
  322. package/src/explorer/DatabaseExplorer.tsx +450 -0
  323. package/src/explorer/RowMenu.tsx +134 -0
  324. package/src/explorer/TableDialog.tsx +80 -0
  325. package/src/explorer/expansion.ts +47 -0
  326. package/src/explorer/table-statements.ts +18 -0
  327. package/src/explorer/tree.ts +453 -0
  328. package/src/explorer/use-explorer-loads.ts +157 -0
  329. package/src/explorer/use-stored-expansion.ts +66 -0
  330. package/src/grid/CellEditor.tsx +53 -0
  331. package/src/grid/CopyAsMenu.tsx +33 -0
  332. package/src/grid/DataGrid.tsx +871 -0
  333. package/src/grid/EnumPicker.tsx +108 -0
  334. package/src/grid/GridHeaderCell.tsx +243 -0
  335. package/src/grid/RecordView.tsx +293 -0
  336. package/src/grid/ValueDock.tsx +52 -0
  337. package/src/grid/aggregates.ts +94 -0
  338. package/src/grid/cell-range.ts +26 -0
  339. package/src/grid/column-layout.ts +71 -0
  340. package/src/grid/column-selection.ts +42 -0
  341. package/src/grid/column-view.ts +35 -0
  342. package/src/grid/copy-formats.ts +108 -0
  343. package/src/grid/display.ts +109 -0
  344. package/src/grid/edit-value.ts +60 -0
  345. package/src/grid/enum-type.ts +62 -0
  346. package/src/grid/focused-value.ts +23 -0
  347. package/src/grid/layout.ts +91 -0
  348. package/src/grid/navigation.ts +74 -0
  349. package/src/grid/row-selection.ts +35 -0
  350. package/src/grid/sort.ts +12 -0
  351. package/src/grid/types.ts +59 -0
  352. package/src/host/helper-path.ts +41 -0
  353. package/src/host/host.ts +456 -0
  354. package/src/host/index.ts +5 -0
  355. package/src/host/spawn.ts +124 -0
  356. package/src/host/types.ts +46 -0
  357. package/src/host/validate.ts +402 -0
  358. package/src/index.ts +37 -0
  359. package/src/locales/en.json +577 -0
  360. package/src/locales/nl.json +577 -0
  361. package/src/locales.ts +18 -0
  362. package/src/protocol/connection.ts +86 -0
  363. package/src/protocol/errors.ts +38 -0
  364. package/src/protocol/index.ts +33 -0
  365. package/src/protocol/messages.ts +168 -0
  366. package/src/protocol/schema.ts +76 -0
  367. package/src/protocol/values.ts +52 -0
  368. package/src/sql-split.ts +220 -0
  369. package/src/sql.ts +152 -0
  370. package/src/structure/StructureView.tsx +269 -0
  371. package/src/structure/structure-text.ts +4 -0
  372. package/src/table/CommandField.tsx +318 -0
  373. package/src/table/ImportDialog.tsx +168 -0
  374. package/src/table/TableStatusBar.tsx +91 -0
  375. package/src/table/TableToolbar.tsx +217 -0
  376. package/src/table/TableView.tsx +880 -0
  377. package/src/table/command-field.ts +285 -0
  378. package/src/table/grid-rows.ts +80 -0
  379. package/src/table/import-mapping.ts +37 -0
  380. package/src/table/layout-store.ts +62 -0
  381. package/src/table/paging.ts +33 -0
  382. package/src/table/pending.ts +143 -0
  383. package/src/table/references.ts +38 -0
  384. package/src/table/useLoaded.ts +58 -0
  385. package/src/table/useStoredLayout.ts +53 -0
  386. package/src/table/useTableTransfer.ts +187 -0
  387. package/src/testing/fake.ts +533 -0
  388. package/src/testing/index.ts +1 -0
  389. package/src/use-popup-press.ts +27 -0
  390. package/src/use-schema-change.ts +19 -0
  391. package/src/use-stable-callback.ts +12 -0
  392. package/src/value/ValuePanel.tsx +254 -0
  393. package/src/value/draft.ts +72 -0
  394. package/src/value/hex.ts +62 -0
  395. package/src/value/json.ts +74 -0
  396. package/src/value/views.ts +68 -0
  397. package/src/workbench/DatabaseWorkbench.tsx +348 -0
  398. package/src/workbench/DesignerTab.tsx +37 -0
  399. package/src/workbench/TableTab.tsx +27 -0
  400. package/src/workbench/tabs.ts +184 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Bas Milius
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,154 @@
1
1
  # @adecore/database
2
2
 
3
- A placeholder that reserves the name for trusted publishing. Install a later version.
3
+ [![npm](https://img.shields.io/npm/v/@adecore/database)](https://www.npmjs.com/package/@adecore/database)
4
+ [![Docs](https://img.shields.io/badge/docs-adecore.dev-blue)](https://adecore.dev/database/)
5
+
6
+ Browse, query and edit SQLite and MySQL or MariaDB databases from a desktop app. React views draw the connections, a table tree, the rows of a table, its structure, a designer that creates and alters tables, a query console and a workbench that puts them together. A host in the app's backend and a native helper that talks to the servers do the work behind them.
7
+
8
+ **[Documentation with a live demo of every view](https://adecore.dev/database/)**
9
+
10
+ ## Install
11
+
12
+ ```sh
13
+ bun add @adecore/database
14
+ ```
15
+
16
+ `@adecore/ui`, React 19, `react-dom`, `i18next` and `react-i18next` are peer dependencies; the app brings them. Only the page needs them. The host (`@adecore/database/host`) and the protocol (`@adecore/database/protocol`) import none of them.
17
+
18
+ ## Layers
19
+
20
+ ```
21
+ page views, createDatabaseClient(transport)
22
+ |
23
+ app channel ipcMain.handle, a utility process, a WebSocket (the app's own, with its own sender check)
24
+ |
25
+ backend createDatabaseHost, spawnHelper (Bun or Node)
26
+ |
27
+ helper adecore-database (native binary, one JSON message per line)
28
+ |
29
+ server SQLite file, MySQL or MariaDB
30
+ ```
31
+
32
+ The package does not carry the messages between the page and the backend. The app does, over a channel it already has and already guards.
33
+
34
+ ## Wire it up
35
+
36
+ In the backend, create one host per app and hand every request that comes over the channel to it. Check the sender first, and name the owner of the request: a window, a socket. When the owner goes away, release it.
37
+
38
+ ```ts
39
+ import { createDatabaseHost, spawnHelper } from '@adecore/database/host';
40
+
41
+ const host = createDatabaseHost({
42
+ start: () => spawnHelper(helperPath),
43
+ // Optional: turn down connections the page may not open.
44
+ authorize: (connection) => connection.engine !== 'sqlite' || connection.path.startsWith(dataFolder),
45
+ // Optional: the files the page may export to and import from. Every file is refused without it.
46
+ authorizeFile: (path, access, owner) => isChosenInDialog(owner, access, path),
47
+ // Optional: whether the page may list Docker containers. Refused without it.
48
+ authorizeDiscovery: (kind, owner) => isTrusted(owner)
49
+ });
50
+
51
+ ipcMain.handle('database:request', (event, request) => {
52
+ if (!isTrustedSender(event)) {
53
+ throw new Error('Untrusted sender.');
54
+ }
55
+
56
+ return host.handle(request, String(event.sender.id));
57
+ });
58
+
59
+ app.on('web-contents-created', (_event, contents) => {
60
+ const owner = String(contents.id);
61
+ contents.once('destroyed', () => void host.release(owner));
62
+ });
63
+ ```
64
+
65
+ On the page, make a client over a transport that sends a request and returns the response, then mount `DatabaseProvider` inside `UIProvider`:
66
+
67
+ ```tsx
68
+ import { createDatabaseClient, DatabaseProvider, TableView } from '@adecore/database';
69
+
70
+ const client = createDatabaseClient((request) => window.database.request(request));
71
+
72
+ createRoot(root).render(
73
+ <UIProvider i18n={i18next} formatSource={formatSource}>
74
+ <DatabaseProvider client={client}>
75
+ <TableView connection={connection} schema="main" table="customers" className="h-full" />
76
+ </DatabaseProvider>
77
+ </UIProvider>
78
+ );
79
+ ```
80
+
81
+ A `Connection` is `{ id, name, config }`. The app keeps the list, with the password in its own secure storage; the package stores nothing.
82
+
83
+ `DatabaseProvider` also takes three optional hooks into the app. Without them the views leave out what they cannot do.
84
+
85
+ ```tsx
86
+ <DatabaseProvider
87
+ client={client}
88
+ onAction={(action) => openInTab(action)}
89
+ storage={{ get: (key) => localStorage.getItem(key), set: (key, value) => (value === null ? localStorage.removeItem(key) : localStorage.setItem(key, value)) }}
90
+ files={{ save: (options) => window.app.saveFile(options), open: (options) => window.app.openFile(options) }}
91
+ >
92
+ ```
93
+
94
+ `onAction` receives a `DatabaseAction` when a view wants a table, a console or the designer opened, so the app decides where it goes. `storage` keeps layouts, console history and open tabs across a remount. `files` holds the app's save and open dialogs for export and import.
95
+
96
+ Tell Tailwind to scan the package for its classes, next to the `@source` line of `@adecore/ui`. The path is relative to the CSS file:
97
+
98
+ ```css
99
+ @import 'tailwindcss';
100
+ @import '@adecore/ui/theme.css';
101
+
102
+ @source "../node_modules/@adecore/ui/dist";
103
+ @source "../node_modules/@adecore/database/dist";
104
+ ```
105
+
106
+ The words live in the `database` namespace, in English and Dutch. `DatabaseProvider` adds them to the i18next instance of `UIProvider`.
107
+
108
+ ## The helper binary
109
+
110
+ The helper is a Rust program that holds the database drivers, so a crashing driver cannot take the backend down. The install brings a prebuilt one: `@adecore/database` lists a package per platform as an optional dependency (`@adecore/database-darwin-arm64` for Apple silicon, `-linux-x64`, `-linux-arm64` and `-win32-x64`), and the package manager installs the one that fits the machine. `helperPath()` returns its path, or `null` when the platform has no package or optional dependencies were left out.
111
+
112
+ ```ts
113
+ import { createDatabaseHost, helperPath, spawnHelper } from '@adecore/database/host';
114
+
115
+ const path = helperPath();
116
+
117
+ if (path === null) {
118
+ throw new Error('No prebuilt helper for this platform.');
119
+ }
120
+
121
+ const host = createDatabaseHost({ start: () => spawnHelper(path) });
122
+ ```
123
+
124
+ The Linux binaries link against glibc 2.35 or newer. An app that wants its own build, for another platform or a patched helper, builds it with cargo from this folder and passes that path to `spawnHelper` instead:
125
+
126
+ ```sh
127
+ cargo build --release --locked --manifest-path helper/Cargo.toml
128
+ ```
129
+
130
+ The binary is `helper/target/release/adecore-database`.
131
+
132
+ ### In an Electron app
133
+
134
+ A binary cannot run from inside an `app.asar` archive. `helperPath()` maps `app.asar` to `app.asar.unpacked`, so the app unpacks the platform packages. With electron-builder:
135
+
136
+ ```json
137
+ {
138
+ "asarUnpack": ["node_modules/@adecore/database-*/**"]
139
+ }
140
+ ```
141
+
142
+ Or copy the binary into `extraResources` and pass that path to `spawnHelper`, without `helperPath()`. Either way the app's own code signing and notarization cover the binary, so sign the unpacked file with the rest of the app. An app packaged for one platform from another machine needs the package of the target platform installed there.
143
+
144
+ ## Views and testing
145
+
146
+ `ConnectionManager` and `ConnectionForm` edit the saved connections: a SQLite file, or a MySQL or MariaDB server reached over TCP, a Unix socket, an SSH host or a Docker container. `DatabaseExplorer` is a tree of connections, schemas, tables and columns, with context menus. `TableView` pages through the rows of a table, filters and sorts them from one command field, and edits them. `StructureView` shows columns, indexes, foreign keys and the DDL. `TableDesigner` creates and alters a table and shows the SQL before it runs. `QueryConsole` runs SQL, with history, paging, transactions and export. `DatabaseWorkbench` is the explorer beside closable tabs for all of those.
147
+
148
+ `@adecore/database/testing` has `fakeDatabaseTransport`, an in-memory server behind the same transport, for demos and for tests of an app.
149
+
150
+ The documentation at https://adecore.dev/database/ has a page for each view, and guides for connections, files, security and the protocol.
151
+
152
+ ## License
153
+
154
+ MIT
@@ -0,0 +1,13 @@
1
+ import { type ReactNode } from 'react';
2
+ import type { DatabaseAction, DatabaseFiles, DatabaseStorage } from './actions.ts';
3
+ import type { DatabaseClient } from './client/types.ts';
4
+ import type { NumberNotation } from './grid/display.ts';
5
+ export interface DatabaseProviderProps {
6
+ client: DatabaseClient;
7
+ onAction?(action: DatabaseAction): void;
8
+ storage?: DatabaseStorage;
9
+ files?: DatabaseFiles;
10
+ numberNotation?: NumberNotation;
11
+ children: ReactNode;
12
+ }
13
+ export declare function DatabaseProvider({ client, onAction, storage, files, numberNotation, children }: DatabaseProviderProps): import("react").JSX.Element;
@@ -0,0 +1,17 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useMemo, useState } from 'react';
3
+ import { useTranslation } from 'react-i18next';
4
+ import { DatabaseContext } from './client-context.js';
5
+ import { addDatabaseResources } from './locales.js';
6
+ /* Hands every view below it the client and the app's hooks, and adds the package's words to the i18next the app's `UIProvider` was given. Mount it inside that provider. */
7
+ export function DatabaseProvider({ client, onAction, storage, files, numberNotation = 'database', children }) {
8
+ const { i18n } = useTranslation();
9
+ const [added, setAdded] = useState(null);
10
+ // In render, as `UIProvider` does, so the first view already reads its words.
11
+ if (added !== i18n) {
12
+ addDatabaseResources(i18n);
13
+ setAdded(i18n);
14
+ }
15
+ const value = useMemo(() => ({ client, onAction, storage, files, numberNotation }), [client, onAction, storage, files, numberNotation]);
16
+ return _jsx(DatabaseContext, { value: value, children: children });
17
+ }
@@ -0,0 +1,40 @@
1
+ import type { TableRef } from './client/types.ts';
2
+ export type DatabaseAction = {
3
+ readonly kind: 'open-table';
4
+ readonly ref: TableRef;
5
+ readonly view: 'data' | 'structure';
6
+ readonly where?: string;
7
+ } | {
8
+ readonly kind: 'open-console';
9
+ readonly connectionId: string;
10
+ readonly schema?: string;
11
+ readonly sql?: string;
12
+ } | {
13
+ readonly kind: 'new-table';
14
+ readonly connectionId: string;
15
+ readonly schema: string;
16
+ } | {
17
+ readonly kind: 'edit-table';
18
+ readonly ref: TableRef;
19
+ } | {
20
+ readonly kind: 'manage-connection';
21
+ readonly connectionId: string;
22
+ };
23
+ export interface ExplorerSelection {
24
+ readonly connectionId: string;
25
+ readonly schema?: string;
26
+ readonly table?: string;
27
+ }
28
+ export interface DatabaseStorage {
29
+ get(key: string): string | null;
30
+ set(key: string, value: string | null): void;
31
+ }
32
+ export interface DatabaseFiles {
33
+ save(options: {
34
+ readonly suggestedName: string;
35
+ readonly format: 'csv' | 'tsv' | 'json' | 'sql';
36
+ }): Promise<string | null>;
37
+ open(options: {
38
+ readonly formats: readonly ('csv' | 'tsv')[];
39
+ }): Promise<string | null>;
40
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,5 @@
1
+ import { type DatabaseClient, type DatabaseTransport } from './types.ts';
2
+ export interface DatabaseClientOptions {
3
+ readonly createId?: () => string;
4
+ }
5
+ export declare const createDatabaseClient: (transport: DatabaseTransport, options?: DatabaseClientOptions) => DatabaseClient;
@@ -0,0 +1,245 @@
1
+ import { DatabaseRequestError } from './types.js';
2
+ const cancelledError = () => new DatabaseRequestError('cancelled', 'The request was cancelled.');
3
+ const isUnknownSession = (error) => error instanceof DatabaseRequestError && error.code === 'unknown-session';
4
+ const LEADING_COMMENTS = /^(?:\s+|--[^\n]*(?:\n|$)|#[^\n]*(?:\n|$)|\/\*[\s\S]*?\*\/)+/;
5
+ const CHANGES_SHAPE = /^(?:create|alter|drop|rename|truncate)\b/i;
6
+ const changesShape = (sql) => CHANGES_SHAPE.test(sql.replace(LEADING_COMMENTS, ''));
7
+ /* Structural equality for the JSON a config is made of; a key set to `undefined` counts as absent. */
8
+ const isEqual = (left, right) => {
9
+ if (left === right) {
10
+ return true;
11
+ }
12
+ if (typeof left !== 'object' || typeof right !== 'object' || left === null || right === null) {
13
+ return false;
14
+ }
15
+ const leftKeys = Object.keys(left).filter((key) => left[key] !== undefined);
16
+ const rightKeys = Object.keys(right).filter((key) => right[key] !== undefined);
17
+ return (leftKeys.length === rightKeys.length &&
18
+ leftKeys.every((key) => isEqual(left[key], right[key])));
19
+ };
20
+ /* Rejects with `cancelled` as soon as the signal aborts, without waiting for the promise. */
21
+ const raceAbort = (promise, signal) => {
22
+ if (signal === undefined) {
23
+ return promise;
24
+ }
25
+ if (signal.aborted) {
26
+ promise.catch(() => { });
27
+ return Promise.reject(cancelledError());
28
+ }
29
+ return new Promise((resolve, reject) => {
30
+ const onAbort = () => reject(cancelledError());
31
+ signal.addEventListener('abort', onAbort, { once: true });
32
+ promise.then(resolve, reject).finally(() => signal.removeEventListener('abort', onAbort));
33
+ });
34
+ };
35
+ export const createDatabaseClient = (transport, options = {}) => {
36
+ const createId = options.createId ?? (() => crypto.randomUUID());
37
+ const live = new Map();
38
+ const schemaListeners = new Set();
39
+ const notifySchemaChange = (change) => {
40
+ for (const listener of [...schemaListeners]) {
41
+ try {
42
+ listener(change);
43
+ }
44
+ catch (error) {
45
+ // One failing listener must neither hide the result of the statement nor keep the others from hearing it.
46
+ console.error('A schema change listener failed.', error);
47
+ }
48
+ }
49
+ };
50
+ const send = async (method, params, signal) => {
51
+ if (signal?.aborted) {
52
+ throw cancelledError();
53
+ }
54
+ const id = createId();
55
+ const request = { id, method, params };
56
+ return new Promise((resolve, reject) => {
57
+ const onAbort = () => {
58
+ const cancel = { id: createId(), method: 'cancel', params: { request: id } };
59
+ new Promise((done) => done(transport(cancel))).catch(() => { });
60
+ reject(cancelledError());
61
+ };
62
+ signal?.addEventListener('abort', onAbort, { once: true });
63
+ new Promise((done) => done(transport(request)))
64
+ .then((response) => {
65
+ const { ok, result, error } = response;
66
+ if (ok) {
67
+ resolve(result);
68
+ }
69
+ else {
70
+ reject(new DatabaseRequestError(error.code, error.message, error.sqlState, error.change));
71
+ }
72
+ }, (error) => reject(new DatabaseRequestError('helper-unavailable', error instanceof Error ? error.message : String(error))))
73
+ .finally(() => signal?.removeEventListener('abort', onAbort));
74
+ });
75
+ };
76
+ const createSession = (initial, channel) => {
77
+ let connection = initial;
78
+ let opened = null;
79
+ let opening = null;
80
+ /* A session that was closed and is used again is findable again, so `disconnect` and `dispose` reach it. */
81
+ const track = () => {
82
+ let channels = live.get(connection.id);
83
+ if (channels === undefined) {
84
+ channels = new Map();
85
+ live.set(connection.id, channels);
86
+ }
87
+ if (!channels.has(channel)) {
88
+ channels.set(channel, created);
89
+ }
90
+ };
91
+ const open = () => {
92
+ if (opened !== null) {
93
+ return Promise.resolve(opened);
94
+ }
95
+ track();
96
+ opening ??= send('open', { connection: connection.config })
97
+ .then((result) => (opened = result))
98
+ .finally(() => {
99
+ opening = null;
100
+ });
101
+ return opening;
102
+ };
103
+ /* Reads are safe to send twice, so they open again and retry once; a write is not, so it only drops the session. */
104
+ const request = async (method, build, requestOptions, retry) => {
105
+ const signal = requestOptions?.signal;
106
+ if (signal?.aborted) {
107
+ throw cancelledError();
108
+ }
109
+ const current = await raceAbort(open(), signal);
110
+ try {
111
+ return await send(method, build(current.session), signal);
112
+ }
113
+ catch (error) {
114
+ if (!isUnknownSession(error)) {
115
+ throw error;
116
+ }
117
+ if (opened === current) {
118
+ opened = null;
119
+ }
120
+ if (retry) {
121
+ return request(method, build, requestOptions, false);
122
+ }
123
+ throw error;
124
+ }
125
+ };
126
+ const close = async () => {
127
+ const channels = live.get(connection.id);
128
+ if (channels?.get(channel) === created) {
129
+ channels.delete(channel);
130
+ if (channels.size === 0) {
131
+ live.delete(connection.id);
132
+ }
133
+ }
134
+ const current = opened ?? (opening === null ? null : await opening.catch(() => null));
135
+ opened = null;
136
+ if (current !== null) {
137
+ await send('close', { session: current.session }).catch(() => { });
138
+ }
139
+ };
140
+ const session = {
141
+ get connection() {
142
+ return connection;
143
+ },
144
+ async server(requestOptions) {
145
+ return (await raceAbort(open(), requestOptions?.signal)).server;
146
+ },
147
+ async schemas(requestOptions) {
148
+ return (await request('schemas', (id) => ({ session: id }), requestOptions, true)).schemas;
149
+ },
150
+ async tables(schema, requestOptions) {
151
+ return (await request('tables', (id) => ({ session: id, schema }), requestOptions, true)).tables;
152
+ },
153
+ structure(schema, table, requestOptions) {
154
+ return request('structure', (id) => ({ session: id, schema, table }), requestOptions, true);
155
+ },
156
+ rows(schema, table, query, requestOptions) {
157
+ return request('rows', (id) => ({ session: id, schema, table, ...query }), requestOptions, true);
158
+ },
159
+ async count(schema, table, where, requestOptions) {
160
+ const params = (id) => (where === undefined ? { session: id, schema, table } : { session: id, schema, table, where });
161
+ return (await request('count', params, requestOptions, true)).count;
162
+ },
163
+ async cell(schema, table, key, column, requestOptions) {
164
+ return (await request('cell', (id) => ({ session: id, schema, table, key, column }), requestOptions, true)).value;
165
+ },
166
+ async apply(schema, table, changes, requestOptions) {
167
+ return (await request('apply', (id) => ({ session: id, schema, table, changes }), requestOptions, false)).affected;
168
+ },
169
+ async execute(sql, executeOptions) {
170
+ const { signal: _signal, ...rest } = executeOptions ?? {};
171
+ const result = await request('execute', (id) => ({ session: id, sql, ...rest }), executeOptions, false);
172
+ if (result.results.some((item) => item.kind !== 'error' && changesShape(item.sql))) {
173
+ notifySchemaChange({ connectionId: connection.id, ...(rest.schema === undefined ? {} : { schema: rest.schema }) });
174
+ }
175
+ return result;
176
+ },
177
+ page(sql, query, requestOptions) {
178
+ return request('page', (id) => ({ session: id, sql, ...query }), requestOptions, true);
179
+ },
180
+ async transaction(action, requestOptions) {
181
+ return (await request('transaction', (id) => ({ session: id, action }), requestOptions, false)).active;
182
+ },
183
+ export(exportRequest, requestOptions) {
184
+ return request('export', (id) => ({ session: id, ...exportRequest }), requestOptions, false);
185
+ },
186
+ async import(schema, table, importRequest, requestOptions) {
187
+ return (await request('import', (id) => ({ session: id, schema, table, ...importRequest }), requestOptions, false)).rows;
188
+ },
189
+ close
190
+ };
191
+ const created = {
192
+ session,
193
+ close,
194
+ update(next) {
195
+ connection = next;
196
+ }
197
+ };
198
+ return created;
199
+ };
200
+ return {
201
+ test(config, requestOptions) {
202
+ return send('test', { connection: config }, requestOptions?.signal).then((result) => result.server);
203
+ },
204
+ async discover(kind, discoverOptions) {
205
+ const params = discoverOptions?.context === undefined ? { kind } : { kind, context: discoverOptions.context };
206
+ return (await send('discover', params, discoverOptions?.signal)).containers;
207
+ },
208
+ sample(path, format, header, requestOptions) {
209
+ return send('sample', { path, format, header }, requestOptions?.signal);
210
+ },
211
+ notifySchemaChange,
212
+ onSchemaChange(listener) {
213
+ schemaListeners.add(listener);
214
+ return () => {
215
+ schemaListeners.delete(listener);
216
+ };
217
+ },
218
+ session(connection, channel = '') {
219
+ let channels = live.get(connection.id);
220
+ const existing = channels?.get(channel);
221
+ if (existing !== undefined && isEqual(existing.session.connection.config, connection.config)) {
222
+ existing.update(connection);
223
+ return existing.session;
224
+ }
225
+ void existing?.close();
226
+ const created = createSession(connection, channel);
227
+ if (channels === undefined) {
228
+ channels = new Map();
229
+ live.set(connection.id, channels);
230
+ }
231
+ channels.set(channel, created);
232
+ return created.session;
233
+ },
234
+ async disconnect(connectionId) {
235
+ const existing = [...(live.get(connectionId)?.values() ?? [])];
236
+ live.delete(connectionId);
237
+ await Promise.all(existing.map((entry) => entry.close()));
238
+ },
239
+ async dispose() {
240
+ const all = [...live.values()].flatMap((channels) => [...channels.values()]);
241
+ live.clear();
242
+ await Promise.all(all.map((entry) => entry.close()));
243
+ }
244
+ };
245
+ };
@@ -0,0 +1,2 @@
1
+ export { createDatabaseClient, type DatabaseClientOptions } from './client.ts';
2
+ export { DatabaseRequestError, type Connection, type DatabaseClient, type DatabaseSession, type DatabaseTransport, type ExecuteOptions, type ExecuteResult, type ExportRequest, type ExportResult, type ImportRequest, type PageQuery, type RequestOptions, type RowsQuery, type SchemaChange, type TableRef } from './types.ts';
@@ -0,0 +1,2 @@
1
+ export { createDatabaseClient } from './client.js';
2
+ export { DatabaseRequestError } from './types.js';
@@ -0,0 +1,97 @@
1
+ import type { ConnectionConfig, DatabaseErrorCode, DockerContainer, ExportSource, FileFormat, DatabaseRequest, DatabaseResponse, RowChange, RowKey, RowsResult, SchemaInfo, ServerInfo, StatementResult, TableInfo, TableStructure, Value } from '../protocol/index.ts';
2
+ export type DatabaseTransport = (request: DatabaseRequest) => Promise<DatabaseResponse>;
3
+ export interface Connection {
4
+ readonly id: string;
5
+ readonly name: string;
6
+ readonly config: ConnectionConfig;
7
+ }
8
+ export interface TableRef {
9
+ readonly connectionId: string;
10
+ readonly schema: string;
11
+ readonly table: string;
12
+ }
13
+ export interface RequestOptions {
14
+ readonly signal?: AbortSignal;
15
+ }
16
+ export interface RowsQuery {
17
+ readonly where?: string;
18
+ readonly orderBy?: string;
19
+ readonly offset: number;
20
+ readonly limit: number;
21
+ readonly cellLimit?: number;
22
+ }
23
+ export interface ExecuteOptions extends RequestOptions {
24
+ readonly schema?: string;
25
+ readonly limit?: number;
26
+ readonly cellLimit?: number;
27
+ }
28
+ export interface DatabaseSession {
29
+ readonly connection: Connection;
30
+ server(options?: RequestOptions): Promise<ServerInfo>;
31
+ schemas(options?: RequestOptions): Promise<readonly SchemaInfo[]>;
32
+ tables(schema: string, options?: RequestOptions): Promise<readonly TableInfo[]>;
33
+ structure(schema: string, table: string, options?: RequestOptions): Promise<TableStructure>;
34
+ rows(schema: string, table: string, query: RowsQuery, options?: RequestOptions): Promise<RowsResult>;
35
+ count(schema: string, table: string, where?: string, options?: RequestOptions): Promise<number>;
36
+ cell(schema: string, table: string, key: RowKey, column: string, options?: RequestOptions): Promise<Value>;
37
+ apply(schema: string, table: string, changes: readonly RowChange[], options?: RequestOptions): Promise<number>;
38
+ execute(sql: string, options?: ExecuteOptions): Promise<ExecuteResult>;
39
+ page(sql: string, query: PageQuery, options?: RequestOptions): Promise<RowsResult>;
40
+ transaction(action: 'begin' | 'commit' | 'rollback', options?: RequestOptions): Promise<boolean>;
41
+ export(request: ExportRequest, options?: RequestOptions): Promise<ExportResult>;
42
+ import(schema: string, table: string, request: ImportRequest, options?: RequestOptions): Promise<number>;
43
+ close(): Promise<void>;
44
+ }
45
+ export interface ExecuteResult {
46
+ readonly results: readonly StatementResult[];
47
+ readonly inTransaction: boolean;
48
+ }
49
+ export interface PageQuery {
50
+ readonly schema?: string;
51
+ readonly offset: number;
52
+ readonly limit: number;
53
+ readonly cellLimit?: number;
54
+ }
55
+ export interface ExportRequest {
56
+ readonly source: ExportSource;
57
+ readonly format: FileFormat;
58
+ readonly path: string;
59
+ readonly header?: boolean;
60
+ readonly tableName?: string;
61
+ }
62
+ export interface ExportResult {
63
+ readonly rows: number;
64
+ readonly bytes: number;
65
+ readonly elapsedMs: number;
66
+ }
67
+ export interface ImportRequest {
68
+ readonly path: string;
69
+ readonly format: 'csv' | 'tsv';
70
+ readonly header: boolean;
71
+ readonly columns: readonly (string | null)[];
72
+ }
73
+ export interface SchemaChange {
74
+ readonly connectionId: string;
75
+ readonly schema?: string;
76
+ }
77
+ export interface DatabaseClient {
78
+ test(config: ConnectionConfig, options?: RequestOptions): Promise<ServerInfo>;
79
+ discover(kind: 'docker', options?: RequestOptions & {
80
+ readonly context?: string;
81
+ }): Promise<readonly DockerContainer[]>;
82
+ sample(path: string, format: 'csv' | 'tsv', header: boolean, options?: RequestOptions): Promise<{
83
+ readonly columns: readonly string[];
84
+ readonly rows: readonly (readonly string[])[];
85
+ }>;
86
+ notifySchemaChange(change: SchemaChange): void;
87
+ onSchemaChange(listener: (change: SchemaChange) => void): () => void;
88
+ session(connection: Connection, channel?: string): DatabaseSession;
89
+ disconnect(connectionId: string): Promise<void>;
90
+ dispose(): Promise<void>;
91
+ }
92
+ export declare class DatabaseRequestError extends Error {
93
+ readonly code: DatabaseErrorCode;
94
+ readonly sqlState: string | undefined;
95
+ readonly change: number | undefined;
96
+ constructor(code: DatabaseErrorCode, message: string, sqlState?: string, change?: number);
97
+ }
@@ -0,0 +1,13 @@
1
+ /* A request that failed, with the code of the protocol. */
2
+ export class DatabaseRequestError extends Error {
3
+ code;
4
+ sqlState;
5
+ change;
6
+ constructor(code, message, sqlState, change) {
7
+ super(message);
8
+ this.name = 'DatabaseRequestError';
9
+ this.code = code;
10
+ this.sqlState = sqlState;
11
+ this.change = change;
12
+ }
13
+ }
@@ -0,0 +1,16 @@
1
+ import type { DatabaseAction, DatabaseFiles, DatabaseStorage } from './actions.ts';
2
+ import type { DatabaseClient } from './client/types.ts';
3
+ import type { NumberNotation } from './grid/display.ts';
4
+ export interface DatabaseContextValue {
5
+ readonly client: DatabaseClient;
6
+ readonly onAction: ((action: DatabaseAction) => void) | undefined;
7
+ readonly storage: DatabaseStorage | undefined;
8
+ readonly files: DatabaseFiles | undefined;
9
+ readonly numberNotation: NumberNotation;
10
+ }
11
+ export declare const DatabaseContext: import("react").Context<DatabaseContextValue | null>;
12
+ export declare const useDatabaseClient: () => DatabaseClient;
13
+ export declare const useDatabaseAction: () => ((action: DatabaseAction) => void) | undefined;
14
+ export declare const useDatabaseStorage: () => DatabaseStorage | undefined;
15
+ export declare const useDatabaseFiles: () => DatabaseFiles | undefined;
16
+ export declare const useNumberNotation: () => NumberNotation;
@@ -0,0 +1,17 @@
1
+ import { createContext, use } from 'react';
2
+ export const DatabaseContext = createContext(null);
3
+ const useDatabaseContext = () => {
4
+ const value = use(DatabaseContext);
5
+ if (value === null) {
6
+ throw new Error('A database view needs a DatabaseProvider above it.');
7
+ }
8
+ return value;
9
+ };
10
+ export const useDatabaseClient = () => useDatabaseContext().client;
11
+ /* Hands an action to the app, or `undefined` when the app takes none, so a view can leave out what would go nowhere. */
12
+ export const useDatabaseAction = () => useDatabaseContext().onAction;
13
+ export const useDatabaseStorage = () => useDatabaseContext().storage;
14
+ /* The app's file dialogs; export and import stay hidden without them. */
15
+ export const useDatabaseFiles = () => useDatabaseContext().files;
16
+ /* Read without the guard of the other hooks: a grid drawn on its own, such as in a test, writes numbers as the database does. */
17
+ export const useNumberNotation = () => use(DatabaseContext)?.numberNotation ?? 'database';