From f73064334b1cfda99d65de278345c3ac7a0dcf87 Mon Sep 17 00:00:00 2001 From: moromisato Date: Mon, 21 Sep 2026 16:47:49 -0300 Subject: [PATCH] Inherit the framed flag on derived versioned value schemas When a collection's schema is a versioned type, the builder derives a per-version value schema so stored values keep their version dispatch. That derived type was registered without a framed flag, so it always fell back to the default (framed) regardless of the source type. A versioned schema declared `framed: false` therefore still wrote framed values on disk, which readers built before framing existed cannot decode. Pass the source schema's framed flag through to the derived type, and add a test that a `framed: false` versioned collection value stays unframed. --- builder/index.js | 1 + test/versions.js | 52 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/builder/index.js b/builder/index.js index db8f0ef..e381ee1 100644 --- a/builder/index.js +++ b/builder/index.js @@ -136,6 +136,7 @@ class Collection extends DBType { if (!external) return { external: false, fqn: getFQN(schema.namespace, schema.name) } this.builder.schema.register({ derived: true, + framed: schema.framed, namespace: schema.namespace, name: schema.name + type, versions diff --git a/test/versions.js b/test/versions.js index 3fcf77b..7127980 100644 --- a/test/versions.js +++ b/test/versions.js @@ -1,6 +1,7 @@ const { test } = require('./helpers') const tmp = require('test-tmp') const path = require('path') +const fs = require('fs') test.bee('define versionField on collection', async function ({ build }, t) { const dir = await tmp(t, { dir: path.join(__dirname, 'fixtures/tmp') }) @@ -35,6 +36,26 @@ test.bee('define versionField on collection', async function ({ build }, t) { await dbVersions.close() }) +test.bee( + 'a versioned collection value inherits the framed flag of its schema', + async function ({ build }, t) { + const framedDir = await tmp(t, { dir: path.join(__dirname, 'fixtures/tmp') }) + const framedDb = await build(createVersionedDB, { dir: framedDir }) + const framed = fs.readFileSync(path.join(framedDir, 'hyperdb', 'messages.js'), 'utf8') + t.ok(framed.includes('// framed version'), 'a versioned value is framed by default') + await framedDb.close() + + const unframedDir = await tmp(t, { dir: path.join(__dirname, 'fixtures/tmp') }) + const unframedDb = await build(createUnframedVersionedDB, { dir: unframedDir }) + const unframed = fs.readFileSync(path.join(unframedDir, 'hyperdb', 'messages.js'), 'utf8') + t.absent( + unframed.includes('// framed version'), + 'framed: false carries through to the derived value' + ) + await unframedDb.close() + } +) + test.bee('versioned collection schema maps old rows on read', async function ({ build }, t) { const dir = await tmp(t, { dir: path.join(__dirname, 'fixtures/tmp') }) @@ -220,6 +241,37 @@ function createVersionedDB(HyperDB, Hyperschema, paths) { HyperDB.toDisk(db) } +function createUnframedVersionedDB(HyperDB, Hyperschema, paths) { + const schema = Hyperschema.from(paths.schema) + const example = schema.namespace('example') + + registerThingV1(example) + + example.register({ + name: 'thing', + framed: false, + versions: [ + { + version: 1, + type: '@example/thing-v1' + } + ] + }) + + Hyperschema.toDisk(schema) + + const db = HyperDB.from(paths.schema, paths.db) + const exampleDB = db.namespace('example') + + exampleDB.collections.register({ + name: 'things', + schema: '@example/thing', + key: ['id'] + }) + + HyperDB.toDisk(db) +} + function createVersionedDBWithV2(HyperDB, Hyperschema, paths) { const schema = Hyperschema.from(paths.schema) const example = schema.namespace('example')