@bakery-framework/plugin-db-explorer 2.2.1 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bakery-framework/plugin-db-explorer",
3
- "version": "2.2.1",
3
+ "version": "2.3.0",
4
4
  "description": "Bakery database explorer plugin: browse and edit rows, no raw SQL, no DDL.",
5
5
  "keywords": [
6
6
  "bakery",
@@ -33,8 +33,8 @@
33
33
  "!src/tests"
34
34
  ],
35
35
  "dependencies": {
36
- "@bakery-framework/core": "^2.2.1",
37
- "@bakery-framework/orm": "^2.2.1"
36
+ "@bakery-framework/core": "^2.3.0",
37
+ "@bakery-framework/orm": "^2.3.0"
38
38
  },
39
39
  "engines": {
40
40
  "bun": ">=1.4.0"
@@ -19,6 +19,7 @@ import { errorMsg, pluginLog } from '@bakery-framework/core/logger'
19
19
  import { Case, Try } from '@bakery-framework/core/utils'
20
20
  import type { JsonResponseData } from '@bakery-framework/core/utils/common'
21
21
  import { response } from '@bakery-framework/core/utils/http'
22
+ import { DB } from '@bakery-framework/orm/orm'
22
23
  import { currentCanWrite } from '../access'
23
24
  import { introspect, type TableFacts } from '../identity'
24
25
  import type { FieldError } from '../validate'
@@ -29,6 +30,27 @@ export type WriteStart =
29
30
  | { ok: true; table: TableFacts; body: Record<string, unknown> }
30
31
  | { ok: false; response: Envelope }
31
32
 
33
+ /**
34
+ * `DB`'s three writers, for a table named at runtime.
35
+ *
36
+ * The explorer writes to whatever the database holds, by names it reads from
37
+ * the database. An app that registers its schema narrows `DB.Insert.into`,
38
+ * `DB.Update.table` and `DB.Delete.from`, and their columns, to its own names,
39
+ * which are not the explorer's to know: every write here failed such an app's
40
+ * typecheck (11 errors in rows.ts and import.ts, 2.1.2 through 2.2.1), while
41
+ * this repo's gates compiled the explorer against no schema at all.
42
+ *
43
+ * `any` is the one table type that gives the builders back their unregistered
44
+ * shape (`never` makes the row `never`), and the ORM's own executables default
45
+ * to it for the same reason. What a schema would have checked, the row against
46
+ * the table, `validate.ts` checks against the live table instead.
47
+ */
48
+ export const byName = {
49
+ insert: (table: string) => DB.Insert.into<any>(table),
50
+ update: (table: string) => DB.Update.table<any>(table),
51
+ delete: (table: string) => DB.Delete.from<any>(table),
52
+ }
53
+
32
54
  /** A 400 carrying every field error, never only the first. */
33
55
  export function invalid(errors: FieldError[]): Envelope {
34
56
  return response.json.error(400, 'Invalid request', { errors })
@@ -19,7 +19,7 @@ import { DB } from '@bakery-framework/orm/orm'
19
19
  import { overLimit } from '../policy'
20
20
  import { isRollbackSignal, previewRollback } from '../preview'
21
21
  import { type FieldError, validateInsertRow } from '../validate'
22
- import { beginWrite, invalid, refuse } from './common'
22
+ import { beginWrite, byName, invalid, refuse } from './common'
23
23
 
24
24
  export type OnBadRow = 'stop' | 'skip'
25
25
 
@@ -70,7 +70,7 @@ export async function handleImport(
70
70
  return await Try.return(
71
71
  async () =>
72
72
  await DB.transaction(async () => {
73
- const result = await DB.Insert.into(table.name).values(records).run()
73
+ const result = await byName.insert(table.name).values(records).run()
74
74
  const report = {
75
75
  inserted: Number(result.changes ?? 0),
76
76
  skipped,
@@ -32,7 +32,13 @@ import {
32
32
  validateKey,
33
33
  validatePartial,
34
34
  } from '../validate'
35
- import { beginWrite, type Envelope, invalid, refuse } from './common'
35
+ import {
36
+ beginWrite,
37
+ byName,
38
+ type Envelope,
39
+ invalid,
40
+ refuse,
41
+ } from './common'
36
42
 
37
43
  /**
38
44
  * A conflict, as the caller sees it: which edit, which row, and what the row
@@ -150,7 +156,7 @@ export async function handleInsertRows(
150
156
  // wraps multiple batches in one transaction, so there is nothing to add
151
157
  // here, which is exactly why the insert goes through it rather than
152
158
  // through the adapter's own `insert()`.
153
- const insert = DB.Insert.into(table.name).values(records)
159
+ const insert = byName.insert(table.name).values(records)
154
160
  if (!returning) {
155
161
  const result = await insert.run()
156
162
  return response.json.success('inserted', {
@@ -225,7 +231,7 @@ export async function handleUpdateRow(
225
231
  const predicate = { ...key.where, ...expect.values }
226
232
  const result = await chain(
227
233
  (column, value) =>
228
- DB.Update.table(table.name).set(set.values).where(column, value),
234
+ byName.update(table.name).set(set.values).where(column, value),
229
235
  predicate,
230
236
  ).run()
231
237
 
@@ -404,7 +410,7 @@ async function applyCollapsedGroup(
404
410
  continue
405
411
  }
406
412
 
407
- let statement = DB.Update.table(table.name)
413
+ let statement = byName.update(table.name)
408
414
  .set(group.set)
409
415
  .where(group.column, DB.inList(chunk.map(m => m.value)))
410
416
  for (const [column, value] of Object.entries(group.expect)) {
@@ -523,7 +529,7 @@ export async function handleBulkEdit(
523
529
  const predicate = { ...edit.key, ...edit.expect }
524
530
  const result = await chain(
525
531
  (column, value) =>
526
- DB.Update.table(table.name).set(edit.set).where(column, value),
532
+ byName.update(table.name).set(edit.set).where(column, value),
527
533
  predicate,
528
534
  ).run()
529
535
 
@@ -612,7 +618,7 @@ export async function handleDeleteRows(
612
618
  const target = prepared[index]!
613
619
  const predicate = { ...target.key, ...target.expect }
614
620
  const result = await chain(
615
- (column, value) => DB.Delete.from(table.name).where(column, value),
621
+ (column, value) => byName.delete(table.name).where(column, value),
616
622
  predicate,
617
623
  ).run()
618
624