Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"@orbit/utils": "^0.17.0",
"@orbit/validators": "^0.17.0",
"decorator-transforms": "^2.2.2",
"ember-primitives": "^0.40.0",
"ember-strict-application-resolver": "^0.1.0"
},
"devDependencies": {
Expand Down
276 changes: 276 additions & 0 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion src/-private/decorators/orbit.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { orbitRegistry } from '../utils/orbit-registry.ts';
import { getOwner } from '@ember/owner';
import type Owner from '@ember/owner';
import { getOrbitRegistry } from '../utils/orbit-registry.ts';

function getDescriptor(serviceName: string) {
return {
get() {
const owner = getOwner(this) as Owner;
const orbitRegistry = getOrbitRegistry(owner);
const services = orbitRegistry.services;
const service = services[serviceName as keyof typeof services];

Expand Down
9 changes: 7 additions & 2 deletions src/-private/model-factory.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { getOwner, setOwner } from '@ember/owner';
import type Owner from '@ember/owner';
import type Cache from './cache.ts';
import type Model from './model.ts';
import type { ModelSettings } from './model.ts';
import { orbitRegistry } from './utils/orbit-registry.ts';
import { getOrbitRegistry } from './utils/orbit-registry.ts';
import Orbit from '@orbit/core';
import { cloneRecordIdentity, type RecordIdentity } from '@orbit/records';
import type { Dict } from '@orbit/utils';
Expand All @@ -17,6 +19,8 @@ export default class ModelFactory {
#modelFactoryMap: Dict<Factory>;

constructor(cache: Cache) {
const owner = getOwner(cache) as Owner;
setOwner(this, owner);
this.#cache = cache;
this.#modelFactoryMap = {};
}
Expand All @@ -34,7 +38,8 @@ export default class ModelFactory {
let modelFactory = this.#modelFactoryMap[type];

if (!modelFactory) {
modelFactory = orbitRegistry.registrations.models[
const owner = getOwner(this) as Owner;
modelFactory = getOrbitRegistry(owner).registrations.models[
type as keyof object
] as unknown as Factory;
assert(
Expand Down
6 changes: 5 additions & 1 deletion src/-private/services/data-coordinator.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { orbitRegistry } from '../utils/orbit-registry.ts';
import { getOwner } from '@ember/owner';
import type Owner from '@ember/owner';
import { getOrbitRegistry } from '../utils/orbit-registry.ts';
import { Coordinator, type CoordinatorOptions } from '@orbit/coordinator';

export type CoordinatorInjections = {
Expand All @@ -8,6 +10,8 @@ export type CoordinatorInjections = {

export default {
create(injections: CoordinatorInjections = {}): Coordinator {
const owner = getOwner(injections) as Owner;
const orbitRegistry = getOrbitRegistry(owner);
const sourceNames = Object.keys(orbitRegistry.registrations.sources);
injections.sources = sourceNames
.map((name) => {
Expand Down
6 changes: 5 additions & 1 deletion src/-private/services/data-normalizer.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { getOwner } from '@ember/owner';
import type Owner from '@ember/owner';
import {
ModelAwareNormalizer,
type ModelRecordNormalizerSettings,
} from '../utils/model-aware-normalizer.ts';
import { orbitRegistry } from '../utils/orbit-registry.ts';
import { getOrbitRegistry } from '../utils/orbit-registry.ts';

export default {
create(injections: ModelRecordNormalizerSettings): ModelAwareNormalizer {
const owner = getOwner(injections) as Owner;
const orbitRegistry = getOrbitRegistry(owner);
injections.keyMap = orbitRegistry.services.dataKeyMap;
injections.schema = orbitRegistry.services.dataSchema;

Expand Down
14 changes: 7 additions & 7 deletions src/-private/services/data-schema.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
import { orbitRegistry } from '../utils/orbit-registry.ts';
import { getOwner } from '@ember/-internals/owner';
import type Owner from '@ember/owner';
import { getOrbitRegistry } from '../utils/orbit-registry.ts';
import { RecordSchema, type RecordSchemaSettings } from '@orbit/records';
import { camelize } from '@orbit/serializers';

function getRegisteredModels(): string[] {
return Object.keys(orbitRegistry.registrations.models).map(camelize);
}

export type SchemaInjections = { modelNames?: string[] } & RecordSchemaSettings;

export default {
create(injections: SchemaInjections = {}): RecordSchema {
const owner = getOwner(injections) as Owner;
const orbitRegistry = getOrbitRegistry(owner);

if (injections.models === undefined) {
let modelNames: Array<string>;
if (injections.modelNames) {
modelNames = injections.modelNames;
delete injections.modelNames;
} else {
modelNames = getRegisteredModels();
modelNames = orbitRegistry.getRegisteredModels();
}

injections.models = {};
Expand Down
6 changes: 5 additions & 1 deletion src/-private/services/store.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
import { getOwner } from '@ember/owner';
import type Owner from '@ember/owner';
import Store, { type StoreSettings } from '../store.ts';
import type {
ModelAwareQueryBuilder,
ModelAwareTransformBuilder,
} from '../utils/model-aware-types.ts';
import { orbitRegistry } from '../utils/orbit-registry.ts';
import { getOrbitRegistry } from '../utils/orbit-registry.ts';
import type { RequestOptions } from '@orbit/data';
import type MemorySource from '@orbit/memory';
import type { RecordCacheUpdateDetails } from '@orbit/record-cache';
import type { RecordSourceQueryOptions } from '@orbit/records';

export default {
create(injections: StoreSettings): Store {
const owner = getOwner(injections) as Owner;
const orbitRegistry = getOrbitRegistry(owner);
injections.source = orbitRegistry.registrations.sources[
'store'
] as MemorySource<
Expand Down
48 changes: 36 additions & 12 deletions src/-private/system/ember-orbit-setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ import DataValidator from '../services/data-validator.ts';
import StoreService from '../services/store.ts';
import type { StoreSettings } from '../store.ts';
import { getName } from '../utils/get-name.ts';
import { orbitRegistry } from '../utils/orbit-registry.ts';
import {
getOrbitRegistry,
type OrbitRegistry,
} from '../utils/orbit-registry.ts';
import type { Strategy } from '@orbit/coordinator';
import type { Bucket } from '@orbit/core';
import { type MemorySourceSettings } from '@orbit/memory';
Expand All @@ -25,7 +28,11 @@ interface FactoryForFolderType {
'/data-strategies/': { default: { create(injections: object): Strategy } };
}

function registerDataBuckets(owner: Owner, modules: Record<string, unknown>) {
function registerDataBuckets(
orbitRegistry: OrbitRegistry,
owner: Owner,
modules: Record<string, unknown>,
) {
const registry = orbitRegistry.registrations.buckets;
const matches = Object.entries(modules);

Expand All @@ -47,7 +54,10 @@ function registerDataBuckets(owner: Owner, modules: Record<string, unknown>) {
}
}

function registerDataModels(modules: Record<string, unknown>) {
function registerDataModels(
orbitRegistry: OrbitRegistry,
modules: Record<string, unknown>,
) {
const folder = '/data-models/';
const registry = orbitRegistry.registrations.models;

Expand All @@ -61,7 +71,11 @@ function registerDataModels(modules: Record<string, unknown>) {
}
}

function registerDataSources(owner: Owner, modules: Record<string, unknown>) {
function registerDataSources(
orbitRegistry: OrbitRegistry,
owner: Owner,
modules: Record<string, unknown>,
) {
const folder = '/data-sources/';
const registry = orbitRegistry.registrations.sources;

Expand All @@ -80,6 +94,7 @@ function registerDataSources(owner: Owner, modules: Record<string, unknown>) {
}

function registerDataStrategies(
orbitRegistry: OrbitRegistry,
owner: Owner,
modules: Record<string, unknown>,
) {
Expand All @@ -104,7 +119,10 @@ function registerDataStrategies(
* Registers the "injectable" services needed to inject into
* the `injections` of all the other things.
*/
function registerInjectableServices(owner: Owner) {
function registerInjectableServices(
orbitRegistry: OrbitRegistry,
owner: Owner,
) {
const keyMap = DataKeyMap.create();
orbitRegistry.services.dataKeyMap = keyMap;

Expand All @@ -129,7 +147,11 @@ function registerInjectableServices(owner: Owner) {
DataValidator.create(validatorSettings);
}

function registerModules(owner: Owner, modules: Record<string, unknown>) {
function registerModules(
orbitRegistry: OrbitRegistry,
owner: Owner,
modules: Record<string, unknown>,
) {
const bucketModules: Record<string, unknown> = {};
const modelModules: Record<string, unknown> = {};
const sourceModules: Record<string, unknown> = {};
Expand All @@ -147,13 +169,13 @@ function registerModules(owner: Owner, modules: Record<string, unknown>) {
}
}
// Create buckets and models first because they do not need anything injected.
registerDataBuckets(owner, bucketModules);
registerDataModels(modelModules);
registerDataBuckets(orbitRegistry, owner, bucketModules);
registerDataModels(orbitRegistry, modelModules);
// Register the services we need to inject into all the other things.
registerInjectableServices(owner);
registerInjectableServices(orbitRegistry, owner);
// Then register the sources themselves
registerDataSources(owner, sourceModules);
registerDataStrategies(owner, strategyModules);
registerDataSources(orbitRegistry, owner, sourceModules);
registerDataStrategies(orbitRegistry, owner, strategyModules);

const storeSourceSettings = {} as MemorySourceSettings;
setOwner(storeSourceSettings, owner);
Expand All @@ -176,6 +198,8 @@ export function setupOrbit(
modules: Record<string, unknown>,
config?: { schemaVersion?: number },
) {
const orbitRegistry = getOrbitRegistry(owner);
orbitRegistry.schemaVersion = config?.schemaVersion;
registerModules(owner, modules);
registerModules(orbitRegistry, owner, modules);
return orbitRegistry;
}
17 changes: 15 additions & 2 deletions src/-private/utils/orbit-registry.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { assert } from '@ember/debug';
import type Owner from '@ember/owner';
import { createStore } from 'ember-primitives/store';
import type ModelFactory from '../model-factory.ts';
import type Store from '../store.ts';
import type { Coordinator, Strategy } from '@orbit/coordinator';
Expand All @@ -11,6 +14,7 @@ import type {
StandardRecordValidator,
UninitializedRecord,
} from '@orbit/records';
import { camelize } from '@orbit/serializers';
import type { StandardValidator, ValidatorForFn } from '@orbit/validators';

export type ServicesMap = {
Expand All @@ -22,7 +26,7 @@ export type ServicesMap = {
store: Store;
};

class OrbitRegistry {
export class OrbitRegistry {
registrations: {
buckets: Record<'main', Bucket>;
models: Record<string, ModelFactory>;
Expand All @@ -36,6 +40,15 @@ class OrbitRegistry {
};
services: ServicesMap = {} as ServicesMap;
schemaVersion?: number;
getRegisteredModels(): string[] {
return Object.keys(this.registrations.models).map(camelize);
}
}

export const orbitRegistry = new OrbitRegistry();
export function getOrbitRegistry(owner: Owner) {
assert(
`expected key to be an owner`,
typeof owner === 'object' && 'lookup' in owner,
);
return createStore(owner, OrbitRegistry);
}
6 changes: 5 additions & 1 deletion src/-private/utils/standard-injections.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import { orbitRegistry } from './orbit-registry.ts';
import { getOwner } from '@ember/owner';
import type Owner from '@ember/owner';
import { getOrbitRegistry } from './orbit-registry.ts';
import type { RecordSourceSettings } from '@orbit/records';

export function applyStandardSourceInjections(
injections: RecordSourceSettings,
): void {
const owner = getOwner(injections) as Owner;
const orbitRegistry = getOrbitRegistry(owner);
injections.bucket = orbitRegistry.registrations.buckets['main'];
injections.keyMap = orbitRegistry.services.dataKeyMap;
injections.normalizer = orbitRegistry.services.dataNormalizer;
Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export { default as hasOne } from './-private/fields/has-one.ts';
export { default as key } from './-private/fields/key.ts';

export { applyStandardSourceInjections } from './-private/utils/standard-injections.ts';
export { orbitRegistry } from './-private/utils/orbit-registry.ts';
export { getOrbitRegistry } from './-private/utils/orbit-registry.ts';
export { orbit } from './-private/decorators/orbit.ts';

export { default as Cache } from './-private/cache.ts';
Expand Down
5 changes: 4 additions & 1 deletion src/test-support/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { orbitRegistry } from '../-private/utils/orbit-registry.ts';
import type Owner from '@ember/owner';
import { getOrbitRegistry } from '../-private/utils/orbit-registry.ts';
import type { Store } from '../index.ts';
import type { Source } from '@orbit/data';

export async function waitForSource(
sourceOrSourceName: Store | Source | string,
owner: Owner,
): Promise<void> {
let source;
if (typeof sourceOrSourceName === 'string') {
const orbitRegistry = getOrbitRegistry(owner);
source = orbitRegistry.registrations.sources[sourceOrSourceName] as Source;
if (!source) {
throw new Error(
Expand Down
2 changes: 1 addition & 1 deletion tests/integration/cache-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -583,7 +583,7 @@ module('Integration - Cache', function (hooks) {
name: 'Callisto',
});
callisto.planet = jupiter;
await waitForSource(store);
await waitForSource(store, this.owner);
assert.strictEqual(cache.peekRelatedRecord(callisto, 'planet'), jupiter);
});

Expand Down
11 changes: 8 additions & 3 deletions tests/integration/wait-for-source-helper-test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { waitForSource } from '#src/test-support/index.ts';
import { setupTest } from 'ember-qunit';
import { module, test } from 'qunit';
import { orbitRegistry } from '#src/-private/utils/orbit-registry.ts';
import {
getOrbitRegistry,
OrbitRegistry,
} from '#src/-private/utils/orbit-registry.ts';
import { Store } from '#src/index.ts';
import { Planet } from '../support/dummy-models';
import { createStore } from '../support/store';
Expand All @@ -10,11 +13,13 @@ import { MemorySource } from '@orbit/memory';
import type { RecordOperation } from '@orbit/records';

module('waitForSource helper', function (hooks) {
let orbitRegistry: OrbitRegistry;
let store: Store;

setupTest(hooks);

test('it resolves once all the pending requests to the given source have synced', async function (assert) {
orbitRegistry = getOrbitRegistry(this.owner);
store = createStore(this.owner, { planet: Planet });

const backup = new MemorySource({ schema: store.schema });
Expand All @@ -25,7 +30,7 @@ module('waitForSource helper', function (hooks) {

await store.addRecord({ type: 'planet', name: 'Earth' });

await waitForSource(backup);
await waitForSource(backup, this.owner);

assert.ok(backup.requestQueue.empty);
assert.ok(backup.syncQueue.empty);
Expand All @@ -45,7 +50,7 @@ module('waitForSource helper', function (hooks) {

await store.addRecord({ type: 'planet', name: 'Earth' });

await waitForSource('backup');
await waitForSource('backup', this.owner);

assert.ok(backup.requestQueue.empty);
assert.ok(backup.syncQueue.empty);
Expand Down
Loading