Skip to content

Commit 5c03793

Browse files
committed
fix: add sql metadata output serialization support
1 parent 55d8454 commit 5c03793

File tree

2 files changed

+102
-0
lines changed

2 files changed

+102
-0
lines changed

src/notebooks/deepnote/deepnoteDataConverter.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,10 @@ export class DeepnoteDataConverter {
220220
);
221221
} else if (item.mime === 'application/vnd.vega.v5+json') {
222222
data['application/vnd.vega.v5+json'] = JSON.parse(new TextDecoder().decode(item.data));
223+
} else if (item.mime === 'application/vnd.deepnote.sql-output-metadata+json') {
224+
data['application/vnd.deepnote.sql-output-metadata+json'] = JSON.parse(
225+
new TextDecoder().decode(item.data)
226+
);
223227
}
224228
}
225229

@@ -305,6 +309,15 @@ export class DeepnoteDataConverter {
305309
);
306310
}
307311

312+
if (data['application/vnd.deepnote.sql-output-metadata+json']) {
313+
items.push(
314+
NotebookCellOutputItem.json(
315+
data['application/vnd.deepnote.sql-output-metadata+json'],
316+
'application/vnd.deepnote.sql-output-metadata+json'
317+
)
318+
);
319+
}
320+
308321
if (data['application/vnd.vegalite.v5+json']) {
309322
const patchedVegaLiteSpec = produce(
310323
data['application/vnd.vegalite.v5+json'] as TopLevel<LayerSpec<Field>>,

src/notebooks/deepnote/deepnoteDataConverter.unit.test.ts

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,48 @@ suite('DeepnoteDataConverter', () => {
431431
assert.strictEqual(outputs[0].items[0].mime, 'text/plain');
432432
assert.strictEqual(new TextDecoder().decode(outputs[0].items[0].data), 'fallback text');
433433
});
434+
435+
test('converts SQL metadata output', () => {
436+
const sqlMetadata = {
437+
status: 'read_from_cache_success',
438+
cache_created_at: '2024-10-21T10:30:00Z',
439+
compiled_query: 'SELECT * FROM users',
440+
variable_type: 'dataframe',
441+
integration_id: 'postgres-prod',
442+
size_in_bytes: 2621440
443+
};
444+
445+
const deepnoteOutputs: DeepnoteOutput[] = [
446+
{
447+
output_type: 'execute_result',
448+
execution_count: 1,
449+
data: {
450+
'application/vnd.deepnote.sql-output-metadata+json': sqlMetadata
451+
}
452+
}
453+
];
454+
455+
const blocks: DeepnoteBlock[] = [
456+
{
457+
blockGroup: 'test-group',
458+
id: 'block1',
459+
type: 'code',
460+
content: 'SELECT * FROM users',
461+
sortingKey: 'a0',
462+
outputs: deepnoteOutputs
463+
}
464+
];
465+
466+
const cells = converter.convertBlocksToCells(blocks);
467+
const outputs = cells[0].outputs!;
468+
469+
assert.strictEqual(outputs.length, 1);
470+
assert.strictEqual(outputs[0].items.length, 1);
471+
assert.strictEqual(outputs[0].items[0].mime, 'application/vnd.deepnote.sql-output-metadata+json');
472+
473+
const outputData = JSON.parse(new TextDecoder().decode(outputs[0].items[0].data));
474+
assert.deepStrictEqual(outputData, sqlMetadata);
475+
});
434476
});
435477

436478
suite('round trip conversion', () => {
@@ -468,6 +510,53 @@ suite('DeepnoteDataConverter', () => {
468510
assert.deepStrictEqual(roundTripBlocks, originalBlocks);
469511
});
470512

513+
test('SQL metadata output round-trips correctly', () => {
514+
const sqlMetadata = {
515+
status: 'read_from_cache_success',
516+
cache_created_at: '2024-10-21T10:30:00Z',
517+
compiled_query: 'SELECT * FROM users WHERE active = true',
518+
variable_type: 'dataframe',
519+
integration_id: 'postgres-prod',
520+
size_in_bytes: 2621440
521+
};
522+
523+
const originalBlocks: DeepnoteBlock[] = [
524+
{
525+
blockGroup: 'test-group',
526+
id: 'sql-block',
527+
type: 'code',
528+
content: 'SELECT * FROM users WHERE active = true',
529+
sortingKey: 'a0',
530+
executionCount: 1,
531+
metadata: {},
532+
outputs: [
533+
{
534+
output_type: 'execute_result',
535+
execution_count: 1,
536+
data: {
537+
'application/vnd.deepnote.sql-output-metadata+json': sqlMetadata
538+
}
539+
}
540+
]
541+
}
542+
];
543+
544+
const cells = converter.convertBlocksToCells(originalBlocks);
545+
const roundTripBlocks = converter.convertCellsToBlocks(cells);
546+
547+
// The round-trip should preserve the SQL metadata output
548+
assert.strictEqual(roundTripBlocks.length, 1);
549+
assert.strictEqual(roundTripBlocks[0].id, 'sql-block');
550+
assert.strictEqual(roundTripBlocks[0].outputs?.length, 1);
551+
552+
const output = roundTripBlocks[0].outputs![0] as {
553+
output_type: string;
554+
data?: Record<string, unknown>;
555+
};
556+
assert.strictEqual(output.output_type, 'execute_result');
557+
assert.deepStrictEqual(output.data?.['application/vnd.deepnote.sql-output-metadata+json'], sqlMetadata);
558+
});
559+
471560
test('real deepnote notebook round-trips without losing data', () => {
472561
// Inline test data representing a real Deepnote notebook with various block types
473562
// blockGroup is an optional field not in the DeepnoteBlock interface, so we cast as any

0 commit comments

Comments
 (0)