Skip to content

Commit 5b081d2

Browse files
committed
test(cli): enter os migrate unmapped-columns in the one-shot family rosters
The absent-database roster (empty work on a missing table, the control reads a retired column), the bootSchemaStack caller table, and the --json stdout purity family. Re-exported beside account-issuer. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016GiHYRmLSNWTfbX9gVQkpz
1 parent 93ae3a4 commit 5b081d2

4 files changed

Lines changed: 37 additions & 0 deletions

File tree

‎packages/cli/src/commands/migrate/data-commands.absent-database.integration.test.ts‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@
5858
* (`--json` and human), a booted database holding one row of work for each
5959
* (the control: the door READS the table and reports the row), and the four
6060
* doors that already exited 0 on the absent database, which still do.
61+
*
62+
* [#21573] `os migrate unmapped-columns` joined the roster later, born with
63+
* the same answer: it asks `tableAbsent` before the differ. Its control row is
64+
* a retired field's column on `os21529_contact`, holding a value.
6165
*/
6266

6367
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
@@ -418,6 +422,9 @@ await k('sys_secret').insert({
418422
await k('sys_file').insert({
419423
id: 'file_21552', key: 'attachments/os21552.txt', name: 'os21552.txt', size: 12, scope: 'attachments', status: 'committed',
420424
});
425+
// A retired field's column: in the table, in no metadata, holding a value.
426+
await k.raw('ALTER TABLE os21529_contact ADD COLUMN legacy_note text');
427+
await k('os21529_contact').insert({ id: 'con_21573', name: 'Ann', legacy_note: 'kept-21573' });
421428
await raw.disconnect();
422429
process.stderr.write('[fixture] seeded\\n');
423430
process.exit(0);
@@ -513,6 +520,19 @@ const DOORS: readonly Door[] = [
513520
tables: ['sys_file', 'sys_attachment'],
514521
work: (doc) => expect(doc).toMatchObject({ filesScanned: 1, stranded: 1 }),
515522
},
523+
{
524+
// Born after #21552 with the family's answer: it asks `tableAbsent` before
525+
// the differ, so an absent table is empty work and is never read.
526+
name: 'migrate unmapped-columns',
527+
argv: ['migrate', 'unmapped-columns', '--object', 'os21529_contact'],
528+
empty: (doc) => expect(doc).toMatchObject({ object: 'os21529_contact', columns: [], count: 0, records: [] }),
529+
humanEmpty: /No unmapped column on os21529_contact/,
530+
tables: ['os21529_contact'],
531+
work: (doc) => {
532+
expect(doc.columns).toEqual([{ column: 'legacy_note', actual: 'text' }]);
533+
expect(doc.records).toContainEqual({ id: 'con_21573', values: { legacy_note: 'kept-21573' } });
534+
},
535+
},
516536
];
517537

518538
/** The four doors that already answered the absent database with exit 0: they must still. */

‎packages/cli/src/index.ts‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ export { default as MigrateRecordedByCommand } from './commands/migrate/recorded
3535
// `sys_account.issuer` is dropped and account identity re-keys onto
3636
// (provider_id, account_id).
3737
export { default as MigrateAccountIssuerCommand } from './commands/migrate/account-issuer.js';
38+
// #21573: the operator-only read of the columns `os migrate plan` reports as
39+
// `unmapped_column` for one object, keyed by record id, for a conversion run
40+
// before `os migrate apply --allow-destructive` drops them.
41+
export { default as MigrateUnmappedColumnsCommand } from './commands/migrate/unmapped-columns.js';
3842

3943
// ─── Environments topic subcommands ─────────────────────────────────
4044
export { default as EnvironmentsListCommand } from './commands/environments/list.js';

‎packages/cli/src/utils/schema-migrate.one-shot-family.integration.test.ts‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ import MigratePlan from '../commands/migrate/plan.js';
6666
import MigrateRecordedBy from '../commands/migrate/recorded-by.js';
6767
import MigrateResume from '../commands/migrate/resume.js';
6868
import MigrateSummaryNulls from '../commands/migrate/summary-nulls.js';
69+
import MigrateUnmappedColumns from '../commands/migrate/unmapped-columns.js';
6970
import MigrateValueShapes from '../commands/migrate/value-shapes.js';
7071
import SecretOrphans from '../commands/secret/orphans.js';
7172
import SecretRewrap from '../commands/secret/rewrap.js';
@@ -211,6 +212,14 @@ const CALLERS: Record<string, Caller> = {
211212
noWrite: [{ label: 'migrate summary-nulls', argv: ['--database-url', '@DB@', '--json'] }],
212213
write: [{ label: 'migrate summary-nulls --apply', argv: ['--apply', '--yes', '--database-url', '@DB@', '--json'] }],
213214
},
215+
'commands/migrate/unmapped-columns.ts': {
216+
run: invoke(MigrateUnmappedColumns),
217+
// `osf_lead` is declared by both releases; the next one adds a column,
218+
// which is pending work and not an unmapped one, so the run reads nothing.
219+
noWrite: [{ label: 'migrate unmapped-columns', argv: ['--object', 'osf_lead', '--database-url', '@DB@', '--json'] }],
220+
write: [],
221+
note: 'a read-only report: it has no writing mode, and dropping the columns is `os migrate apply --allow-destructive`',
222+
},
214223
'commands/migrate/value-shapes.ts': {
215224
run: invoke(MigrateValueShapes),
216225
noWrite: [{ label: 'migrate value-shapes', argv: ['--database-url', '@DB@', '--json'] }],

‎packages/cli/test/json-stdout-purity.e2e.test.ts‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,10 @@ const FAMILY: Record<string, string[]> = {
104104
'migrate recorded-by': [],
105105
'migrate resume': [],
106106
'migrate summary-nulls': [],
107+
// One object per run, so it needs a name: the fixture's own `jp_ticket`,
108+
// which the composed host config registers. No database file exists, so the
109+
// face driven here is its empty-work answer for a table not there yet.
110+
'migrate unmapped-columns': ['--object', 'jp_ticket'],
107111
'migrate value-shapes': [],
108112
// Report-only is its DEFAULT and the only form driven here: without
109113
// `--delete` it boots, reports and writes nothing, so the family gains a

0 commit comments

Comments
 (0)