@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
@@ -0,0 +1,38 @@
1
+ import { wholeValueOf } from '../grid/focused-value.ts';
2
+ import type { Shown } from '../grid/display.ts';
3
+ import type { Engine, ForeignKeyInfo, ValueKind } from '../protocol/index.ts';
4
+ import { matchCondition, type ColumnMatch } from '../sql.ts';
5
+
6
+ /* Where a foreign key points for one row: the referenced table and the condition that picks the row out. */
7
+ export interface Reference {
8
+ readonly schema: string;
9
+ readonly table: string;
10
+ readonly where: string;
11
+ }
12
+
13
+ /* The foreign key a column is part of; the first one when a column sits in several. */
14
+ export const foreignKeyOf = (foreignKeys: readonly ForeignKeyInfo[], column: string): ForeignKeyInfo | undefined =>
15
+ foreignKeys.find((key) => key.columns.includes(column));
16
+
17
+ /*
18
+ * The row a foreign key points to, from the cells of the referencing row. `null` when any column of
19
+ * the key is NULL (it references nothing), is only a preview, or is not among the columns.
20
+ */
21
+ export const referenceOf = (
22
+ engine: Engine,
23
+ key: ForeignKeyInfo,
24
+ columns: readonly { readonly name: string; readonly kind: ValueKind }[],
25
+ cells: readonly Shown[]
26
+ ): Reference | null => {
27
+ const matches: ColumnMatch[] = [];
28
+ for (const [position, name] of key.columns.entries()) {
29
+ const referenced = key.referencedColumns[position];
30
+ const index = columns.findIndex((column) => column.name === name);
31
+ const value = index < 0 ? undefined : wholeValueOf(cells[index] ?? null);
32
+ if (referenced === undefined || value === undefined || value === null) {
33
+ return null;
34
+ }
35
+ matches.push({ column: referenced, value, kind: columns[index]!.kind });
36
+ }
37
+ return matches.length === 0 ? null : { schema: key.referencedSchema, table: key.referencedTable, where: matchCondition(engine, matches) };
38
+ };
@@ -0,0 +1,58 @@
1
+ import { useEffect, useRef, useState } from 'react';
2
+ import { messageOf } from '@adecore/ui';
3
+
4
+ export interface Loaded<T> {
5
+ /* The last value that arrived; stays while the next one loads, so a page does not vanish under a reload. */
6
+ value: T | null;
7
+ loading: boolean;
8
+ error: string | null;
9
+ reload(): void;
10
+ }
11
+
12
+ interface State<T> {
13
+ key: string;
14
+ version: number;
15
+ value: T | null;
16
+ error: string | null;
17
+ }
18
+
19
+ /*
20
+ * Runs `load` when `key` changes or `reload` is called, and aborts the run that is still going.
21
+ * `key` has to name everything `load` reads, since `load` itself is a new function on every render.
22
+ * A value belongs to the hook's owner, which is remounted for a different subject, so it outlives a key change.
23
+ */
24
+ export function useLoaded<T>(load: (signal: AbortSignal) => Promise<T>, key: string): Loaded<T> {
25
+ const loader = useRef(load);
26
+ const [version, setVersion] = useState(0);
27
+ // Loading is not a state of its own: it is that the last answer is not for this key and this version.
28
+ const [state, setState] = useState<State<T>>({ key: '', version: -1, value: null, error: null });
29
+
30
+ useEffect(() => {
31
+ loader.current = load;
32
+ });
33
+
34
+ useEffect(() => {
35
+ const controller = new AbortController();
36
+ loader.current(controller.signal).then(
37
+ (value) => {
38
+ if (!controller.signal.aborted) {
39
+ setState({ key, version, value, error: null });
40
+ }
41
+ },
42
+ (error: unknown) => {
43
+ if (!controller.signal.aborted) {
44
+ setState((now) => ({ key, version, value: now.value, error: messageOf(error) }));
45
+ }
46
+ }
47
+ );
48
+ return () => controller.abort();
49
+ }, [key, version]);
50
+
51
+ const answered = state.key === key && state.version === version;
52
+ return {
53
+ value: state.value,
54
+ loading: !answered,
55
+ error: answered ? state.error : null,
56
+ reload: () => setVersion((now) => now + 1)
57
+ };
58
+ }
@@ -0,0 +1,53 @@
1
+ import { useCallback, useEffect, useRef, useState } from 'react';
2
+ import type { DatabaseStorage } from '../actions.ts';
3
+ import { EMPTY_LAYOUT, parseStoredLayout, serializeLayout, type StoredLayout } from './layout-store.ts';
4
+
5
+ /* How long a change waits for the next before it is written, so a drag of a column edge is one write. */
6
+ export const STORE_DELAY_MS = 500;
7
+
8
+ export interface StoredLayoutHandle {
9
+ /* What was stored when the view mounted, or `null` when nothing usable was. */
10
+ readonly stored: StoredLayout | null;
11
+ /* Merges a change into what is remembered and writes it after a pause. Does nothing without storage. */
12
+ remember(change: Partial<StoredLayout>): void;
13
+ }
14
+
15
+ /*
16
+ * The layout of one table's view in the app's storage. It is read once, on mount, and written back
17
+ * in the background: the last change is still written when the view unmounts.
18
+ */
19
+ export function useStoredLayout(storage: DatabaseStorage | undefined, key: string): StoredLayoutHandle {
20
+ const [stored] = useState(() => (storage === undefined ? null : parseStoredLayout(storage.get(key))));
21
+ const latest = useRef<StoredLayout>(stored ?? EMPTY_LAYOUT);
22
+ const dirty = useRef(false);
23
+ const timer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);
24
+ const target = useRef({ storage, key });
25
+
26
+ useEffect(() => {
27
+ target.current = { storage, key };
28
+ });
29
+
30
+ const write = useCallback((): void => {
31
+ clearTimeout(timer.current);
32
+ timer.current = undefined;
33
+ if (dirty.current) {
34
+ dirty.current = false;
35
+ target.current.storage?.set(target.current.key, serializeLayout(latest.current));
36
+ }
37
+ }, []);
38
+
39
+ useEffect(() => write, [write]);
40
+
41
+ return {
42
+ stored,
43
+ remember: (change) => {
44
+ if (storage === undefined) {
45
+ return;
46
+ }
47
+ latest.current = { ...latest.current, ...change };
48
+ dirty.current = true;
49
+ clearTimeout(timer.current);
50
+ timer.current = setTimeout(write, STORE_DELAY_MS);
51
+ }
52
+ };
53
+ }
@@ -0,0 +1,187 @@
1
+ import { useEffect, useRef, useState } from 'react';
2
+ import { messageOf } from '@adecore/ui';
3
+ import type { DatabaseFiles } from '../actions.ts';
4
+ import { DatabaseRequestError, type DatabaseClient, type DatabaseSession } from '../client/types.ts';
5
+ import type { FileFormat, TableStructure } from '../protocol/index.ts';
6
+ import type { ImportSample } from './ImportDialog.tsx';
7
+ import { formatOfPath, importableColumns, mapColumn, matchColumns, type ImportFormat } from './import-mapping.ts';
8
+
9
+ /* What the strip over the table says about an export or an import. */
10
+ export type TransferNotice =
11
+ | { readonly kind: 'exporting'; readonly format: FileFormat }
12
+ | { readonly kind: 'exported'; readonly rows: number }
13
+ | { readonly kind: 'imported'; readonly rows: number }
14
+ | { readonly kind: 'failed'; readonly message: string };
15
+
16
+ /* The import a person is setting up. */
17
+ export interface ImportDraft {
18
+ readonly path: string;
19
+ readonly format: ImportFormat;
20
+ readonly header: boolean;
21
+ /* `null` while a new sample is read. */
22
+ readonly sample: ImportSample | null;
23
+ readonly mapping: readonly (string | null)[];
24
+ readonly busy: boolean;
25
+ readonly error: string | null;
26
+ }
27
+
28
+ export interface TableTransferInput {
29
+ readonly client: DatabaseClient;
30
+ readonly session: DatabaseSession;
31
+ /* Without the app's file dialogs there is no export and no import. */
32
+ readonly files: DatabaseFiles | undefined;
33
+ readonly schema: string;
34
+ readonly table: string;
35
+ readonly structure: TableStructure | null;
36
+ /* The filters as applied, which an export respects. */
37
+ readonly where: string;
38
+ readonly orderBy: string;
39
+ /* Rows were added; the table reloads. */
40
+ readonly onImported: () => void;
41
+ }
42
+
43
+ export interface TableTransfer {
44
+ readonly notice: TransferNotice | null;
45
+ readonly importDraft: ImportDraft | null;
46
+ exportAs(format: FileFormat): void;
47
+ /* Stops the export that is running. */
48
+ cancelExport(): void;
49
+ dismiss(): void;
50
+ chooseImportFile(): void;
51
+ changeHeader(header: boolean): void;
52
+ changeMapping(fileColumn: number, tableColumn: string | null): void;
53
+ runImport(): void;
54
+ closeImport(): void;
55
+ }
56
+
57
+ /* Export of the table as filtered, and import of a file into it, with the state both need between the dialogs and the strip. */
58
+ export function useTableTransfer({ client, session, files, schema, table, structure, where, orderBy, onImported }: TableTransferInput): TableTransfer {
59
+ const [notice, setNotice] = useState<TransferNotice | null>(null);
60
+ const [importDraft, setImportDraft] = useState<ImportDraft | null>(null);
61
+ const exporting = useRef<AbortController | null>(null);
62
+ const sampling = useRef<AbortController | null>(null);
63
+ const tableColumns = structure === null ? [] : importableColumns(structure.columns).map((column) => column.name);
64
+
65
+ useEffect(() => {
66
+ if (notice?.kind !== 'exported' && notice?.kind !== 'imported') {
67
+ return;
68
+ }
69
+ const timer = setTimeout(() => setNotice(null), 8000);
70
+ return () => clearTimeout(timer);
71
+ }, [notice]);
72
+
73
+ useEffect(() => () => sampling.current?.abort(), []);
74
+
75
+ const exportAs = (format: FileFormat): void => {
76
+ if (files === undefined || exporting.current !== null) {
77
+ return;
78
+ }
79
+ void (async () => {
80
+ const path = await files.save({ suggestedName: `${table}.${format}`, format });
81
+ if (path === null) {
82
+ return;
83
+ }
84
+ const controller = new AbortController();
85
+ exporting.current = controller;
86
+ setNotice({ kind: 'exporting', format });
87
+ try {
88
+ const result = await session.export(
89
+ { source: { kind: 'table', schema, table, where: where || undefined, orderBy: orderBy || undefined }, format, path },
90
+ { signal: controller.signal }
91
+ );
92
+ setNotice({ kind: 'exported', rows: result.rows });
93
+ } catch (error) {
94
+ const cancelled = controller.signal.aborted || (error instanceof DatabaseRequestError && error.code === 'cancelled');
95
+ setNotice(cancelled ? null : { kind: 'failed', message: messageOf(error) });
96
+ } finally {
97
+ exporting.current = null;
98
+ }
99
+ })();
100
+ };
101
+
102
+ const sample = async (path: string, format: ImportFormat, header: boolean): Promise<ImportSample> => {
103
+ sampling.current?.abort();
104
+ const controller = new AbortController();
105
+ sampling.current = controller;
106
+ return await client.sample(path, format, header, { signal: controller.signal });
107
+ };
108
+
109
+ const chooseImportFile = (): void => {
110
+ if (files === undefined || structure === null) {
111
+ return;
112
+ }
113
+ void (async () => {
114
+ const path = await files.open({ formats: ['csv', 'tsv'] });
115
+ if (path === null) {
116
+ return;
117
+ }
118
+ const format = formatOfPath(path);
119
+ try {
120
+ const read = await sample(path, format, true);
121
+ setImportDraft({ path, format, header: true, sample: read, mapping: matchColumns(read.columns, tableColumns, true), busy: false, error: null });
122
+ } catch (error) {
123
+ setNotice({ kind: 'failed', message: messageOf(error) });
124
+ }
125
+ })();
126
+ };
127
+
128
+ const changeHeader = (header: boolean): void => {
129
+ if (importDraft === null) {
130
+ return;
131
+ }
132
+ const { path, format } = importDraft;
133
+ setImportDraft({ ...importDraft, header, sample: null, error: null });
134
+ void (async () => {
135
+ try {
136
+ const read = await sample(path, format, header);
137
+ setImportDraft((now) =>
138
+ now === null || now.path !== path ? now : { ...now, header, sample: read, mapping: matchColumns(read.columns, tableColumns, header) }
139
+ );
140
+ } catch (error) {
141
+ if (!(error instanceof DatabaseRequestError && error.code === 'cancelled')) {
142
+ setImportDraft((now) => (now === null || now.path !== path ? now : { ...now, error: messageOf(error) }));
143
+ }
144
+ }
145
+ })();
146
+ };
147
+
148
+ const changeMapping = (fileColumn: number, tableColumn: string | null): void => {
149
+ setImportDraft((now) => (now === null ? now : { ...now, mapping: mapColumn(now.mapping, fileColumn, tableColumn) }));
150
+ };
151
+
152
+ const runImport = (): void => {
153
+ if (importDraft === null || importDraft.busy || importDraft.sample === null) {
154
+ return;
155
+ }
156
+ const { path, format, header, mapping } = importDraft;
157
+ setImportDraft({ ...importDraft, busy: true, error: null });
158
+ void (async () => {
159
+ try {
160
+ const rows = await session.import(schema, table, { path, format, header, columns: mapping });
161
+ setImportDraft(null);
162
+ setNotice({ kind: 'imported', rows });
163
+ onImported();
164
+ } catch (error) {
165
+ setImportDraft((now) => (now === null ? now : { ...now, busy: false, error: messageOf(error) }));
166
+ }
167
+ })();
168
+ };
169
+
170
+ const closeImport = (): void => {
171
+ sampling.current?.abort();
172
+ setImportDraft(null);
173
+ };
174
+
175
+ return {
176
+ notice,
177
+ importDraft,
178
+ exportAs,
179
+ cancelExport: () => exporting.current?.abort(),
180
+ dismiss: () => setNotice(null),
181
+ chooseImportFile,
182
+ changeHeader,
183
+ changeMapping,
184
+ runImport,
185
+ closeImport
186
+ };
187
+ }