Skip to content

Commit c12142f

Browse files
Register services on orbitRegistry (#434)
* Register services on orbitRegistry * Fix lint * Update orbit-registry.ts * Remove some factories
1 parent 0e6fb20 commit c12142f

File tree

18 files changed

+151
-139
lines changed

18 files changed

+151
-139
lines changed

README.md

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,6 @@ In a new vite based app, we can use `import.meta.glob` to grab all the things we
8888
to register and pass them to `setupOrbit. You may want to set this up in your application route's `beforeModel` hook.
8989

9090
```ts
91-
import { getOwner } from "@ember/owner";
9291
import Route from "@ember/routing/route";
9392
import { service } from "@ember/service";
9493
import { setupOrbit, type Store } from "ember-orbit";
@@ -109,10 +108,7 @@ export default class ApplicationRoute extends Route {
109108
@service declare store: Store;
110109

111110
async beforeModel() {
112-
const application = getOwner(this);
113-
114111
setupOrbit(
115-
application,
116112
{
117113
...dataModels,
118114
...dataSources,
@@ -637,7 +633,6 @@ enable the coordinator. Let's do this in our application route's `beforeModel`
637633
hook (in `app/routes/application.js`):
638634

639635
```ts
640-
import { getOwner } from "@ember/owner";
641636
import Route from "@ember/routing/route";
642637
import { service } from "@ember/service";
643638
import { setupOrbit, type Store } from "ember-orbit";
@@ -658,10 +653,7 @@ export default class ApplicationRoute extends Route {
658653
@service declare store: Store;
659654

660655
async beforeModel() {
661-
const application = getOwner(this);
662-
663656
setupOrbit(
664-
application,
665657
{
666658
...dataModels,
667659
...dataSources,
File renamed without changes.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import {
2+
ModelAwareNormalizer,
3+
type ModelRecordNormalizerSettings,
4+
} from '../utils/model-aware-normalizer.ts';
5+
import { orbitRegistry } from '../utils/orbit-registry.ts';
6+
7+
export default {
8+
create(injections: ModelRecordNormalizerSettings): ModelAwareNormalizer {
9+
injections.keyMap = orbitRegistry.services.keyMap;
10+
injections.schema = orbitRegistry.services.schema;
11+
12+
return new ModelAwareNormalizer(injections);
13+
},
14+
};
File renamed without changes.
Lines changed: 98 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,86 +1,129 @@
1-
import type Owner from '@ember/owner';
21
import DataSourceStore from '../../data-sources/store.ts';
32
import type MemorySourceFactory from '../factories/memory-source-factory.ts';
43
import type ModelFactory from '../model-factory.ts';
4+
import DataKeyMap from '../services/data-key-map.ts';
5+
import DataNormalizer from '../services/data-normalizer.ts';
6+
import DataSchema from '../services/data-schema.ts';
7+
import DataValidator from '../services/data-validator.ts';
58
import { getName } from '../utils/get-name.ts';
69
import { orbitRegistry } from '../utils/orbit-registry.ts';
710
import type { Strategy } from '@orbit/coordinator';
811
import type { Bucket } from '@orbit/core';
912
import { type MemorySourceSettings } from '@orbit/memory';
1013

11-
type Folder =
12-
| '/data-buckets/'
13-
| '/data-models/'
14-
| '/data-sources/'
15-
| '/data-strategies/';
16-
1714
interface FactoryForFolderType {
1815
'/data-buckets/': { default: { create(): Bucket } };
1916
'/data-models/': { default: ModelFactory };
2017
'/data-sources/': { default: typeof MemorySourceFactory };
2118
'/data-strategies/': { default: { create(): Strategy } };
2219
}
2320

24-
function injectModules(modules: Record<string, unknown>) {
25-
const folderConfig = {
26-
'/data-buckets/': { registry: orbitRegistry.registrations.buckets },
27-
'/data-models/': { registry: orbitRegistry.registrations.models },
28-
'/data-sources/': { registry: orbitRegistry.registrations.sources },
29-
'/data-strategies/': { registry: orbitRegistry.registrations.strategies },
30-
};
31-
32-
for (const [folder, { registry }] of Object.entries(folderConfig) as [
33-
Folder,
34-
{ registry: any },
35-
][]) {
36-
const matches = Object.entries(modules).filter(([key]) =>
37-
key.includes(folder),
21+
function injectDataBuckets(modules: Record<string, unknown>) {
22+
const registry = orbitRegistry.registrations.buckets;
23+
const matches = Object.entries(modules);
24+
25+
if (matches.length > 1) {
26+
throw new Error(
27+
`Expected only one file under /data-buckets/, found ${matches.length}: ` +
28+
matches.map(([key]) => key).join(', '),
3829
);
30+
}
3931

40-
if (folder === '/data-buckets/' && matches.length > 1) {
41-
throw new Error(
42-
`Expected only one file under /data-buckets/, found ${matches.length}: ` +
43-
matches.map(([key]) => key).join(', '),
44-
);
45-
}
32+
for (const [, module] of matches) {
33+
registry['main'] = (
34+
module as FactoryForFolderType['/data-buckets/']
35+
).default?.create?.();
36+
}
37+
}
38+
39+
function injectDataModels(modules: Record<string, unknown>) {
40+
const folder = '/data-models/';
41+
const registry = orbitRegistry.registrations.models;
42+
43+
for (const [key, module] of Object.entries(modules)) {
44+
let [, name] = key.split(folder);
45+
name = getName(name as string);
46+
47+
registry[name] =
48+
(module as FactoryForFolderType['/data-models/']).default ??
49+
(module as ModelFactory);
50+
}
51+
}
52+
53+
function injectDataSources(modules: Record<string, unknown>) {
54+
const folder = '/data-sources/';
55+
const registry = orbitRegistry.registrations.sources;
56+
57+
for (const [key, module] of Object.entries(modules)) {
58+
let [, name] = key.split(folder);
59+
name = getName(name as string);
60+
61+
registry[name] = (module as FactoryForFolderType['/data-sources/']).default // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
62+
?.create?.({} as any);
63+
}
64+
}
4665

47-
for (const [key, module] of matches) {
48-
if (folder === '/data-buckets/') {
49-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
50-
registry['main'] = (
51-
module as FactoryForFolderType['/data-buckets/']
52-
).default?.create?.();
53-
continue;
54-
}
55-
56-
let [, name] = key.split(folder);
57-
name = getName(name as string);
58-
59-
if (folder === '/data-models/') {
60-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
61-
registry[name] =
62-
(module as FactoryForFolderType[typeof folder]).default ??
63-
(module as ModelFactory);
64-
} else {
65-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
66-
registry[name] = (module as FactoryForFolderType[typeof folder]).default // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
67-
?.create?.({} as any);
68-
}
66+
function injectDataStrategies(modules: Record<string, unknown>) {
67+
const folder = '/data-strategies/';
68+
const registry = orbitRegistry.registrations.strategies;
69+
70+
for (const [key, module] of Object.entries(modules)) {
71+
let [, name] = key.split(folder);
72+
name = getName(name as string);
73+
74+
registry[name] = (
75+
module as FactoryForFolderType['/data-strategies/']
76+
).default?.create?.();
77+
}
78+
}
79+
80+
function injectModules(modules: Record<string, unknown>) {
81+
const bucketModules: Record<string, unknown> = {};
82+
const modelModules: Record<string, unknown> = {};
83+
const sourceModules: Record<string, unknown> = {};
84+
const strategyModules: Record<string, unknown> = {};
85+
86+
for (const [key, module] of Object.entries(modules)) {
87+
if (key.includes('/data-buckets/')) {
88+
bucketModules[key] = module;
89+
} else if (key.includes('/data-models/')) {
90+
modelModules[key] = module;
91+
} else if (key.includes('/data-sources/')) {
92+
sourceModules[key] = module;
93+
} else if (key.includes('/data-strategies/')) {
94+
strategyModules[key] = module;
6995
}
7096
}
7197

72-
// Register the store source after processing all modules
73-
orbitRegistry.registrations.sources['store'] = DataSourceStore.create(
74-
{} as MemorySourceSettings,
75-
);
98+
injectDataBuckets(bucketModules);
99+
injectDataModels(modelModules);
100+
injectServices();
101+
injectDataSources(sourceModules);
102+
injectDataStrategies(strategyModules);
103+
}
104+
105+
function injectServices() {
106+
const keyMap = DataKeyMap.create();
107+
const schema = DataSchema.create();
108+
orbitRegistry.services.keyMap = keyMap;
109+
orbitRegistry.services.schema = schema;
110+
orbitRegistry.services.normalizer = DataNormalizer.create({
111+
keyMap,
112+
schema,
113+
});
114+
orbitRegistry.services.validatorFor = DataValidator.create({
115+
validators: {},
116+
});
76117
}
77118

78119
export function setupOrbit(
79-
application: Owner,
80120
modules: Record<string, unknown>,
81121
config?: { schemaVersion?: number },
82122
) {
83-
orbitRegistry.application = application;
84123
orbitRegistry.schemaVersion = config?.schemaVersion;
85124
injectModules(modules);
125+
// Register the store source after processing all modules
126+
orbitRegistry.registrations.sources['store'] = DataSourceStore.create(
127+
{} as MemorySourceSettings,
128+
);
86129
}

src/services/data-normalizer.ts renamed to src/-private/utils/model-aware-normalizer.ts

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,9 @@
1-
import type Owner from '@ember/owner';
2-
import Service, { service } from '@ember/service';
1+
import { Model } from '../../index.ts';
32
import {
43
type RecordFieldsOrModel,
54
type RecordIdentityOrModel,
6-
} from '../-private/utils/model-aware-types.ts';
7-
import {
8-
normalizeModelFields,
9-
type ModelFields,
10-
} from '../-private/utils/model-fields.ts';
11-
import { Model } from '../index.ts';
5+
} from './model-aware-types.ts';
6+
import { normalizeModelFields, type ModelFields } from './model-fields.ts';
127
import {
138
RecordKeyMap,
149
RecordSchema,
@@ -33,23 +28,14 @@ export function isStandardRecord(
3328
);
3429
}
3530

36-
export default class ModelAwareNormalizer
37-
extends Service
31+
export class ModelAwareNormalizer
3832
implements
3933
RecordNormalizer<string, RecordIdentityOrModel, RecordFieldsOrModel>
4034
{
41-
@service declare dataKeyMap: RecordKeyMap;
42-
@service declare dataSchema: RecordSchema;
43-
4435
protected _normalizer: StandardRecordNormalizer;
4536

46-
constructor(owner: Owner) {
47-
super(owner);
48-
49-
this._normalizer = new StandardRecordNormalizer({
50-
keyMap: this.dataKeyMap,
51-
schema: this.dataSchema,
52-
});
37+
constructor(settings: ModelRecordNormalizerSettings) {
38+
this._normalizer = new StandardRecordNormalizer(settings);
5339
}
5440

5541
get keyMap(): RecordKeyMap | undefined {

src/-private/utils/orbit-registry.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,25 @@
1-
import type Owner from '@ember/owner';
21
import type ModelFactory from '../model-factory.ts';
32
import type { Strategy } from '@orbit/coordinator';
43
import type { Bucket } from '@orbit/core';
54
import type { Source } from '@orbit/data';
5+
import type {
6+
RecordIdentity,
7+
RecordKeyMap,
8+
RecordNormalizer,
9+
RecordSchema,
10+
StandardRecordValidator,
11+
UninitializedRecord,
12+
} from '@orbit/records';
13+
import type { StandardValidator, ValidatorForFn } from '@orbit/validators';
14+
15+
type ServicesMap = {
16+
keyMap: RecordKeyMap;
17+
normalizer: RecordNormalizer<string, RecordIdentity, UninitializedRecord>;
18+
schema: RecordSchema;
19+
validatorFor: ValidatorForFn<StandardValidator | StandardRecordValidator>;
20+
};
621

722
class OrbitRegistry {
8-
application: Owner | null = null;
923
registrations: {
1024
buckets: Record<'main', Bucket>;
1125
models: Record<string, ModelFactory>;
@@ -17,6 +31,7 @@ class OrbitRegistry {
1731
sources: {},
1832
strategies: {},
1933
};
34+
services: ServicesMap = {} as ServicesMap;
2035
schemaVersion?: number;
2136
}
2237

Lines changed: 5 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,12 @@
1-
import type ApplicationInstance from '@ember/application/instance';
21
import { orbitRegistry } from './orbit-registry.ts';
3-
import type {
4-
RecordIdentity,
5-
RecordKeyMap,
6-
RecordNormalizer,
7-
RecordSchema,
8-
RecordSourceSettings,
9-
StandardRecordValidator,
10-
UninitializedRecord,
11-
} from '@orbit/records';
12-
import type { StandardValidator, ValidatorForFn } from '@orbit/validators';
2+
import type { RecordSourceSettings } from '@orbit/records';
133

144
export function applyStandardSourceInjections(
155
injections: RecordSourceSettings,
166
): void {
17-
const app = orbitRegistry.application as ApplicationInstance;
18-
19-
injections.schema = app.lookup('service:data-schema') as RecordSchema;
20-
217
injections.bucket = orbitRegistry.registrations.buckets['main'];
22-
23-
injections.keyMap = app.lookup('service:data-key-map') as RecordKeyMap;
24-
25-
injections.normalizer = app.lookup(
26-
'service:data-normalizer',
27-
) as RecordNormalizer<string, RecordIdentity, UninitializedRecord>;
28-
29-
injections.validatorFor = app.lookup(
30-
'service:data-validator',
31-
) as ValidatorForFn<StandardValidator | StandardRecordValidator>;
8+
injections.keyMap = orbitRegistry.services.keyMap;
9+
injections.normalizer = orbitRegistry.services.normalizer;
10+
injections.schema = orbitRegistry.services.schema;
11+
injections.validatorFor = orbitRegistry.services.validatorFor;
3212
}

src/index.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
export { default as CoordinatorFactory } from './-private/factories/coordinator-factory.ts';
2-
export { default as KeyMapFactory } from './-private/factories/key-map-factory.ts';
3-
export { default as SchemaFactory } from './-private/factories/schema-factory.ts';
42
export { default as MemorySourceFactory } from './-private/factories/memory-source-factory.ts';
53
export { default as StoreFactory } from './-private/factories/memory-source-factory.ts';
64
export { default as attr } from './-private/fields/attr.ts';
@@ -14,4 +12,5 @@ export { default as Store, type StoreSettings } from './-private/store.ts';
1412
export { default as LiveQuery } from './-private/live-query.ts';
1513
// Provide `belongsTo` as an alias to `hasOne`
1614
export { default as belongsTo } from './-private/fields/has-one.ts';
15+
export { orbitRegistry } from './-private/utils/orbit-registry.ts';
1716
export { setupOrbit } from './-private/system/ember-orbit-setup.ts';

0 commit comments

Comments
 (0)