diff --git a/src/runtime/internal/collection.ts b/src/runtime/internal/collection.ts index 5f1e4ec93..7aa98fe94 100644 --- a/src/runtime/internal/collection.ts +++ b/src/runtime/internal/collection.ts @@ -1,15 +1,31 @@ import type { CollectionInfo } from '@nuxt/content' import contentManifest from '#content/manifest' +/** + * Refine raw fields from D1/SQLite query results into their proper JS types. + * Handles JSON parsing, boolean coercion (preserving null for absent fields), + * and removes empty JSON objects that arise from D1 column defaults. + */ export function refineContentFields(sql: string, doc: T) { const fields = findCollectionFields(sql) const item = { ...doc } as T for (const key in item) { if (fields[key as string] === 'json' && item[key] && item[key] !== 'undefined') { - item[key] = JSON.parse(item[key] as string) + const parsed = JSON.parse(item[key] as string) + if (key !== 'meta' && parsed && typeof parsed === 'object' && !Array.isArray(parsed) && Object.keys(parsed).length === 0) { + Reflect.deleteProperty(item as object, key) + } + else { + item[key] = parsed + } } if (fields[key as string] === 'boolean' && item[key] !== 'undefined') { - item[key] = Boolean(item[key]) as never + if (item[key] == null) { + Reflect.deleteProperty(item as object, key) + } + else { + item[key] = Boolean(item[key]) as never + } } } @@ -21,6 +37,7 @@ export function refineContentFields(sql: string, doc: T) { return item } +/** Extract the field type map for the collection referenced in the SQL query. */ function findCollectionFields(sql: string): Record { const table = sql.match(/FROM\s+(\w+)/) if (!table) { @@ -31,6 +48,7 @@ function findCollectionFields(sql: string): Record