Skip to content

Commit d952ac3

Browse files
committed
fix(core): merge manifest schema into runtime registrations
1 parent cb9e8d4 commit d952ac3

2 files changed

Lines changed: 346 additions & 51 deletions

File tree

packages/core/src/__tests__/external-runtime-hydration.test.ts

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,118 @@ describe('external runtime field hydration', () => {
406406
).resolves.toEqual([]);
407407
});
408408

409+
it('merges manifest schema into an already-registered external class with the same qualified key', () => {
410+
const packageName = '@happyvertical/smrt-runtime-fixture-recaps';
411+
const registrationKey = createQualifiedName(
412+
packageName,
413+
'FixtureRuntimeMeetingRecap',
414+
);
415+
416+
@smrt({
417+
packageName,
418+
tableStrategy: 'sti',
419+
tableName: 'fixture_runtime_contents',
420+
api: false,
421+
cli: false,
422+
mcp: false,
423+
})
424+
class FixtureRuntimeContent extends SmrtObject {}
425+
426+
@smrt({
427+
packageName,
428+
api: false,
429+
cli: false,
430+
mcp: false,
431+
})
432+
class FixtureRuntimeMeetingRecap extends FixtureRuntimeContent {
433+
@field()
434+
meetingId: string = '';
435+
}
436+
437+
const before = ObjectRegistry.findClass(registrationKey);
438+
expect(before).toBeDefined();
439+
expect(before?.schema?.tableName).toBe('fixture_runtime_contents');
440+
expect(before?.fields.has('meetingId')).toBe(true);
441+
expect(before?.fields.has('councilId')).toBe(false);
442+
expect(before?.fields.has('body')).toBe(false);
443+
444+
const beforeDefinitions = ObjectRegistry.getAllSchemasAsDefinitions();
445+
expect(
446+
beforeDefinitions.fixture_runtime_contents.columns.meeting_id,
447+
).toBeDefined();
448+
expect(
449+
beforeDefinitions.fixture_runtime_contents.columns.council_id,
450+
).toBeUndefined();
451+
expect(
452+
beforeDefinitions.fixture_runtime_contents.columns.body,
453+
).toBeUndefined();
454+
455+
ObjectRegistry.registerFromManifest(
456+
'FixtureRuntimeMeetingRecap',
457+
{
458+
className: 'FixtureRuntimeMeetingRecap',
459+
extends: 'FixtureRuntimeContent',
460+
decoratorConfig: {
461+
tableStrategy: 'sti',
462+
tableName: 'fixture_runtime_contents',
463+
api: false,
464+
cli: false,
465+
mcp: false,
466+
},
467+
fields: {
468+
meetingId: { type: 'text' },
469+
councilId: { type: 'text' },
470+
body: { type: 'text' },
471+
},
472+
schema: {
473+
tableName: 'fixture_runtime_contents',
474+
ddl: `CREATE TABLE IF NOT EXISTS "fixture_runtime_contents" (
475+
"id" TEXT PRIMARY KEY NOT NULL,
476+
"slug" TEXT NOT NULL,
477+
"context" TEXT NOT NULL DEFAULT '',
478+
"created_at" TIMESTAMP NOT NULL DEFAULT current_timestamp,
479+
"updated_at" TIMESTAMP NOT NULL DEFAULT current_timestamp,
480+
"_meta_type" TEXT NOT NULL DEFAULT '',
481+
"_meta_data" JSON,
482+
"meeting_id" TEXT DEFAULT '',
483+
"council_id" TEXT DEFAULT '',
484+
"body" TEXT DEFAULT ''
485+
);`,
486+
columns: {
487+
meeting_id: { type: 'TEXT', defaultValue: '' },
488+
council_id: { type: 'TEXT', defaultValue: '' },
489+
body: { type: 'TEXT', defaultValue: '' },
490+
},
491+
indexes: [],
492+
triggers: [],
493+
foreignKeys: [],
494+
dependencies: [],
495+
version: '1.0.0',
496+
},
497+
},
498+
packageName,
499+
);
500+
501+
const after = ObjectRegistry.findClass(registrationKey);
502+
expect(after).toBeDefined();
503+
expect(after?.schema?.tableName).toBe('fixture_runtime_contents');
504+
expect(after?.qualifiedName).toBe(registrationKey);
505+
expect(after?.fields.has('meetingId')).toBe(true);
506+
expect(after?.fields.has('councilId')).toBe(true);
507+
expect(after?.fields.has('body')).toBe(true);
508+
509+
const definitions = ObjectRegistry.getAllSchemasAsDefinitions();
510+
expect(definitions.fixture_runtime_contents).toBeDefined();
511+
expect(
512+
definitions.fixture_runtime_contents.columns.meeting_id,
513+
).toBeDefined();
514+
expect(
515+
definitions.fixture_runtime_contents.columns.council_id,
516+
).toBeDefined();
517+
expect(definitions.fixture_runtime_contents.columns.body).toBeDefined();
518+
expect(definitions.fixture_runtime_meeting_recaps).toBeUndefined();
519+
});
520+
409521
it('hydrates STI sibling field types before save so missing booleans do not serialize as empty strings', async () => {
410522
const packageName = '@happyvertical/smrt-runtime-fixture-events';
411523

0 commit comments

Comments
 (0)