@proteinjs/db-driver-spanner 1.11.1 → 1.12.1

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.
@@ -0,0 +1,88 @@
1
+ import { SpannerDriver } from '@proteinjs/db-driver-spanner';
2
+ import { StringColumn, Table, withRecordColumns, Record } from '@proteinjs/db';
3
+ import { getDropTestTable } from './util/getDropTestTable';
4
+ import { SpannerEmulatorProvisioner } from './util/SpannerEmulatorProvisioner';
5
+ import '../generated/test/index';
6
+
7
+ const spannerDriver = new SpannerDriver({
8
+ projectId: 'proteinjs-test',
9
+ instanceName: 'proteinjs-test',
10
+ databaseName: 'test',
11
+ });
12
+
13
+ interface WideningRecord extends Record {
14
+ title?: string;
15
+ label?: string;
16
+ }
17
+
18
+ /** Same table declared twice — narrow (creation-time) and widened (the schema change under test). */
19
+ const wideningTable = (titleLength: number | 'MAX'): Table<WideningRecord> => {
20
+ return new (class extends Table<WideningRecord> {
21
+ name = 'db_test_string_widening';
22
+ columns = withRecordColumns<WideningRecord>({
23
+ title: new StringColumn('title', undefined, titleLength),
24
+ label: new StringColumn('label', { nullable: false }),
25
+ });
26
+ })();
27
+ };
28
+
29
+ describe('Spanner STRING widening', () => {
30
+ const dropTable = getDropTestTable(spannerDriver);
31
+ const tableManager = spannerDriver.getTableManager();
32
+
33
+ beforeAll(async () => {
34
+ await SpannerEmulatorProvisioner.ensureProvisioned({
35
+ projectId: 'proteinjs-test',
36
+ instanceName: 'proteinjs-test',
37
+ databaseName: 'test',
38
+ });
39
+ await dropTable(wideningTable(255));
40
+ }, 30000);
41
+
42
+ afterAll(async () => {
43
+ await dropTable(wideningTable(255));
44
+ await SpannerEmulatorProvisioner.release();
45
+ }, 30000);
46
+
47
+ test('widens STRING(255) to STRING(MAX) in place, preserving rows and nullability', async () => {
48
+ const narrow = wideningTable(255);
49
+ await tableManager.loadTable(narrow);
50
+ const id = 'widening-test-row';
51
+ await spannerDriver.runDml(() => ({
52
+ sql: 'INSERT INTO db_test_string_widening (id, title, label) VALUES (@id, @title, @label)',
53
+ namedParams: {
54
+ params: { id, title: 'short title', label: 'keep' },
55
+ types: { id: 'string', title: 'string', label: 'string' },
56
+ },
57
+ }));
58
+
59
+ const widened = wideningTable('MAX');
60
+ await tableManager.loadTable(widened);
61
+
62
+ const columnMetadata = await tableManager.schemaMetadata.getColumnMetadata(widened);
63
+ expect(columnMetadata['title'].type).toBe('STRING(MAX)');
64
+ // The untouched NOT NULL column keeps its constraint through the alter pass.
65
+ expect(columnMetadata['label'].isNullable).toBe(false);
66
+
67
+ // Pre-existing row survives, and the column now accepts values beyond the old limit.
68
+ const longTitle = 'x'.repeat(3000);
69
+ await spannerDriver.runDml(() => ({
70
+ sql: 'UPDATE db_test_string_widening SET title = @title WHERE id = @id',
71
+ namedParams: { params: { id, title: longTitle }, types: { id: 'string', title: 'string' } },
72
+ }));
73
+ const rows = await spannerDriver.runQuery(() => ({
74
+ sql: 'SELECT title, label FROM db_test_string_widening WHERE id = @id',
75
+ namedParams: { params: { id }, types: { id: 'string' } },
76
+ }));
77
+ expect(rows[0].title).toBe(longTitle);
78
+ expect(rows[0].label).toBe('keep');
79
+ }, 60000);
80
+
81
+ test('non-widening type changes still throw', async () => {
82
+ const widened = wideningTable('MAX');
83
+ await tableManager.loadTable(widened);
84
+
85
+ const narrowed = wideningTable(255);
86
+ await expect(tableManager.loadTable(narrowed)).rejects.toThrow(/Unable to change column types in Spanner/);
87
+ }, 60000);
88
+ });