From af4e90262e8f9ba75afc416b732344ecc350cb04 Mon Sep 17 00:00:00 2001 From: Sabin Hertanu Date: Wed, 5 Aug 2026 03:09:04 +0200 Subject: [PATCH] fix: register data models under their camelCase record type Model files are kebab-case on disk, so setupOrbit received keys like '../data-models/planetary-system.ts' and registered the model as 'planetary-system'. Both consumers of registrations.models look models up by camelCase record type instead: - DataSchema builds its model map from getRegisteredModels(), which camelized the keys before indexing the un-camelized registry, so the lookup returned undefined and destructuring threw during setupOrbit. - Cache#modelFactoryFor(type) is called with the record type, so it hit the same mismatch. Camelize once at registration and let getRegisteredModels return the keys as stored, so registration and lookup agree. Single-word names were unaffected, which is why the existing suite passed: tests supply already-camelCase keys to createStore, and the test app's data-models folder only holds moon.ts and planet.ts. --- src/-private/system/ember-orbit-setup.ts | 6 ++- src/-private/utils/orbit-registry.ts | 3 +- .../kebab-case-model-names-test.ts | 37 +++++++++++++++++++ 3 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 tests/integration/kebab-case-model-names-test.ts diff --git a/src/-private/system/ember-orbit-setup.ts b/src/-private/system/ember-orbit-setup.ts index 4171b5d..8038add 100644 --- a/src/-private/system/ember-orbit-setup.ts +++ b/src/-private/system/ember-orbit-setup.ts @@ -20,6 +20,7 @@ import { import type { Strategy } from '@orbit/coordinator'; import type { Bucket } from '@orbit/core'; import { type MemorySourceSettings } from '@orbit/memory'; +import { camelize } from '@orbit/serializers'; interface FactoryForFolderType { '/data-buckets/': { default: { create(injections: object): Bucket } }; @@ -63,7 +64,10 @@ function registerDataModels( for (const [key, module] of Object.entries(modules)) { let [, name] = key.split(folder); - name = getName(name as string); + // Model file names are kebab-case on disk but record types are camelCase, + // so normalize here: every other consumer of `registrations.models` + // (the schema service, Cache#modelFactoryFor) looks models up by type. + name = camelize(getName(name as string)); registry[name] = (module as FactoryForFolderType['/data-models/']).default ?? diff --git a/src/-private/utils/orbit-registry.ts b/src/-private/utils/orbit-registry.ts index 9f02460..a2b185a 100644 --- a/src/-private/utils/orbit-registry.ts +++ b/src/-private/utils/orbit-registry.ts @@ -14,7 +14,6 @@ import type { StandardRecordValidator, UninitializedRecord, } from '@orbit/records'; -import { camelize } from '@orbit/serializers'; import type { StandardValidator, ValidatorForFn } from '@orbit/validators'; export type ServicesMap = { @@ -41,7 +40,7 @@ export class OrbitRegistry { services: ServicesMap = {} as ServicesMap; schemaVersion?: number; getRegisteredModels(): string[] { - return Object.keys(this.registrations.models).map(camelize); + return Object.keys(this.registrations.models); } } diff --git a/tests/integration/kebab-case-model-names-test.ts b/tests/integration/kebab-case-model-names-test.ts new file mode 100644 index 0000000..2d273c1 --- /dev/null +++ b/tests/integration/kebab-case-model-names-test.ts @@ -0,0 +1,37 @@ +import { setupTest } from 'ember-qunit'; +import { module, test } from 'qunit'; +import { Store } from '#src/index.ts'; +import { PlanetarySystem } from '../support/dummy-models'; +import { createStore } from '../support/store'; + +// Data model files are kebab-case on disk, so `import.meta.glob` hands +// `setupOrbit` keys like `../data-models/planetary-system.ts` while record +// types stay camelCase. Registering under a kebab-case key must still produce +// a model reachable as `planetarySystem`. +module('Integration - kebab-case model file names', function (hooks) { + setupTest(hooks); + + let store: Store; + + hooks.beforeEach(function () { + store = createStore(this.owner, { + 'planetary-system': PlanetarySystem, + }); + }); + + test('the model is present in the schema under its camelCase type', function (assert) { + assert.true( + store.schema.hasModel('planetarySystem'), + 'schema knows the camelCase type', + ); + }); + + test('records of that type can be added', async function (assert) { + const system = await store.addRecord({ + type: 'planetarySystem', + name: 'Home', + }); + + assert.strictEqual(system.name, 'Home', 'record was created'); + }); +});