Skip to content

Commit aa7ed66

Browse files
feat(data): add initial standalone APIs (#3647)
Closes #3553
1 parent 72b1876 commit aa7ed66

File tree

5 files changed

+266
-255
lines changed

5 files changed

+266
-255
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { InjectionToken } from '@angular/core';
2+
import { MetaReducer } from '@ngrx/store';
3+
import { EntityCache } from './reducers/entity-cache';
4+
import { EntityAction } from './actions/entity-action';
5+
import { EntityMetadataMap } from './entity-metadata/entity-metadata';
6+
import { EntityCollection } from './reducers/entity-collection';
7+
8+
export interface EntityDataModuleConfig {
9+
entityMetadata?: EntityMetadataMap;
10+
entityCacheMetaReducers?: (
11+
| MetaReducer<EntityCache>
12+
| InjectionToken<MetaReducer<EntityCache>>
13+
)[];
14+
entityCollectionMetaReducers?: MetaReducer<EntityCollection, EntityAction>[];
15+
// Initial EntityCache state or a function that returns that state
16+
initialEntityCacheState?: EntityCache | (() => EntityCache);
17+
pluralNames?: { [name: string]: string };
18+
}
Lines changed: 11 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,10 @@
1+
import { ModuleWithProviders, NgModule } from '@angular/core';
2+
import { EntityDataModuleConfig } from './entity-data-config';
13
import {
2-
ModuleWithProviders,
3-
NgModule,
4-
Inject,
5-
Injector,
6-
InjectionToken,
7-
Optional,
8-
OnDestroy,
9-
} from '@angular/core';
10-
11-
import {
12-
Action,
13-
combineReducers,
14-
MetaReducer,
15-
ReducerManager,
16-
StoreModule,
17-
} from '@ngrx/store';
18-
19-
import { CorrelationIdGenerator } from './utils/correlation-id-generator';
20-
import { EntityDispatcherDefaultOptions } from './dispatchers/entity-dispatcher-default-options';
21-
import { EntityAction } from './actions/entity-action';
22-
import { EntityActionFactory } from './actions/entity-action-factory';
23-
import { EntityCache } from './reducers/entity-cache';
24-
import { EntityCacheDispatcher } from './dispatchers/entity-cache-dispatcher';
25-
import { entityCacheSelectorProvider } from './selectors/entity-cache-selector';
26-
import { EntityCollectionServiceElementsFactory } from './entity-services/entity-collection-service-elements-factory';
27-
import { EntityCollectionServiceFactory } from './entity-services/entity-collection-service-factory';
28-
import { EntityServices } from './entity-services/entity-services';
29-
import { EntityCollection } from './reducers/entity-collection';
30-
import { EntityCollectionCreator } from './reducers/entity-collection-creator';
31-
import { EntityCollectionReducerFactory } from './reducers/entity-collection-reducer';
32-
import { EntityCollectionReducerMethodsFactory } from './reducers/entity-collection-reducer-methods';
33-
import { EntityCollectionReducerRegistry } from './reducers/entity-collection-reducer-registry';
34-
import { EntityDispatcherFactory } from './dispatchers/entity-dispatcher-factory';
35-
import { EntityDefinitionService } from './entity-metadata/entity-definition.service';
36-
import { EntityMetadataMap } from './entity-metadata/entity-metadata';
37-
import { EntityCacheReducerFactory } from './reducers/entity-cache-reducer';
38-
import {
39-
ENTITY_CACHE_NAME,
40-
ENTITY_CACHE_NAME_TOKEN,
41-
ENTITY_CACHE_META_REDUCERS,
42-
ENTITY_COLLECTION_META_REDUCERS,
43-
INITIAL_ENTITY_CACHE_STATE,
44-
} from './reducers/constants';
45-
46-
import { DefaultLogger } from './utils/default-logger';
47-
import { EntitySelectorsFactory } from './selectors/entity-selectors';
48-
import { EntitySelectors$Factory } from './selectors/entity-selectors$';
49-
import { EntityServicesBase } from './entity-services/entity-services-base';
50-
import { EntityServicesElements } from './entity-services/entity-services-elements';
51-
import { Logger, PLURAL_NAMES_TOKEN } from './utils/interfaces';
52-
53-
export interface EntityDataModuleConfig {
54-
entityMetadata?: EntityMetadataMap;
55-
entityCacheMetaReducers?: (
56-
| MetaReducer<EntityCache, Action>
57-
| InjectionToken<MetaReducer<EntityCache, Action>>
58-
)[];
59-
entityCollectionMetaReducers?: MetaReducer<EntityCollection, EntityAction>[];
60-
// Initial EntityCache state or a function that returns that state
61-
initialEntityCacheState?: EntityCache | (() => EntityCache);
62-
pluralNames?: { [name: string]: string };
63-
}
4+
provideRootEntityDataWithoutEffects,
5+
ENTITY_DATA_WITHOUT_EFFECTS_PROVIDERS,
6+
initializeEntityDataWithoutEffects,
7+
} from './provide-entity-data';
648

659
/**
6610
* Module without effects or dataservices which means no HTTP calls
@@ -69,105 +13,19 @@ export interface EntityDataModuleConfig {
6913
* therefore opt-out of @ngrx/effects for entities
7014
*/
7115
@NgModule({
72-
imports: [
73-
StoreModule, // rely on Store feature providers rather than Store.forFeature()
74-
],
75-
providers: [
76-
CorrelationIdGenerator,
77-
EntityDispatcherDefaultOptions,
78-
EntityActionFactory,
79-
EntityCacheDispatcher,
80-
EntityCacheReducerFactory,
81-
entityCacheSelectorProvider,
82-
EntityCollectionCreator,
83-
EntityCollectionReducerFactory,
84-
EntityCollectionReducerMethodsFactory,
85-
EntityCollectionReducerRegistry,
86-
EntityCollectionServiceElementsFactory,
87-
EntityCollectionServiceFactory,
88-
EntityDefinitionService,
89-
EntityDispatcherFactory,
90-
EntitySelectorsFactory,
91-
EntitySelectors$Factory,
92-
EntityServicesElements,
93-
{ provide: ENTITY_CACHE_NAME_TOKEN, useValue: ENTITY_CACHE_NAME },
94-
{ provide: EntityServices, useClass: EntityServicesBase },
95-
{ provide: Logger, useClass: DefaultLogger },
96-
],
16+
providers: [ENTITY_DATA_WITHOUT_EFFECTS_PROVIDERS],
9717
})
98-
export class EntityDataModuleWithoutEffects implements OnDestroy {
99-
private entityCacheFeature: any;
100-
18+
export class EntityDataModuleWithoutEffects {
10119
static forRoot(
10220
config: EntityDataModuleConfig
10321
): ModuleWithProviders<EntityDataModuleWithoutEffects> {
10422
return {
10523
ngModule: EntityDataModuleWithoutEffects,
106-
providers: [
107-
{
108-
provide: ENTITY_CACHE_META_REDUCERS,
109-
useValue: config.entityCacheMetaReducers
110-
? config.entityCacheMetaReducers
111-
: [],
112-
},
113-
{
114-
provide: ENTITY_COLLECTION_META_REDUCERS,
115-
useValue: config.entityCollectionMetaReducers
116-
? config.entityCollectionMetaReducers
117-
: [],
118-
},
119-
{
120-
provide: PLURAL_NAMES_TOKEN,
121-
multi: true,
122-
useValue: config.pluralNames ? config.pluralNames : {},
123-
},
124-
],
125-
};
126-
}
127-
128-
constructor(
129-
private reducerManager: ReducerManager,
130-
entityCacheReducerFactory: EntityCacheReducerFactory,
131-
private injector: Injector,
132-
// optional params
133-
@Optional()
134-
@Inject(ENTITY_CACHE_NAME_TOKEN)
135-
private entityCacheName: string,
136-
@Optional()
137-
@Inject(INITIAL_ENTITY_CACHE_STATE)
138-
private initialState: any,
139-
@Optional()
140-
@Inject(ENTITY_CACHE_META_REDUCERS)
141-
private metaReducers: (
142-
| MetaReducer<EntityCache, Action>
143-
| InjectionToken<MetaReducer<EntityCache, Action>>
144-
)[]
145-
) {
146-
// Add the @ngrx/data feature to the Store's features
147-
// as Store.forFeature does for StoreFeatureModule
148-
const key = entityCacheName || ENTITY_CACHE_NAME;
149-
150-
initialState =
151-
typeof initialState === 'function' ? initialState() : initialState;
152-
153-
const reducers: MetaReducer<EntityCache, Action>[] = (
154-
metaReducers || []
155-
).map((mr) => {
156-
return mr instanceof InjectionToken ? injector.get(mr) : mr;
157-
});
158-
159-
this.entityCacheFeature = {
160-
key,
161-
reducers: entityCacheReducerFactory.create(),
162-
reducerFactory: combineReducers,
163-
initialState: initialState || {},
164-
metaReducers: reducers,
24+
providers: [provideRootEntityDataWithoutEffects(config)],
16525
};
166-
reducerManager.addFeature(this.entityCacheFeature);
16726
}
16827

169-
// eslint-disable-next-line @angular-eslint/contextual-lifecycle
170-
ngOnDestroy() {
171-
this.reducerManager.removeFeature(this.entityCacheFeature);
28+
constructor() {
29+
initializeEntityDataWithoutEffects();
17230
}
17331
}
Lines changed: 13 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,22 @@
11
import { ModuleWithProviders, NgModule } from '@angular/core';
22

3-
import { EffectsModule, EffectSources } from '@ngrx/effects';
4-
5-
import { DefaultDataServiceFactory } from './dataservices/default-data.service';
6-
7-
import {
8-
DefaultPersistenceResultHandler,
9-
PersistenceResultHandler,
10-
} from './dataservices/persistence-result-handler.service';
11-
12-
import {
13-
DefaultHttpUrlGenerator,
14-
HttpUrlGenerator,
15-
} from './dataservices/http-url-generator';
16-
17-
import { EntityCacheDataService } from './dataservices/entity-cache-data.service';
18-
import { EntityCacheEffects } from './effects/entity-cache-effects';
19-
import { EntityDataService } from './dataservices/entity-data.service';
20-
import { EntityEffects } from './effects/entity-effects';
21-
22-
import { ENTITY_METADATA_TOKEN } from './entity-metadata/entity-metadata';
23-
24-
import {
25-
ENTITY_CACHE_META_REDUCERS,
26-
ENTITY_COLLECTION_META_REDUCERS,
27-
} from './reducers/constants';
28-
import { Pluralizer, PLURAL_NAMES_TOKEN } from './utils/interfaces';
29-
import { DefaultPluralizer } from './utils/default-pluralizer';
30-
3+
import { EntityDataModuleConfig } from './entity-data-config';
4+
import { EntityDataModuleWithoutEffects } from './entity-data-without-effects.module';
315
import {
32-
EntityDataModuleConfig,
33-
EntityDataModuleWithoutEffects,
34-
} from './entity-data-without-effects.module';
6+
ENTITY_DATA_PROVIDERS,
7+
initializeEntityData,
8+
provideRootEntityData,
9+
provideRootEntityDataWithoutEffects,
10+
} from './provide-entity-data';
3511

3612
/**
3713
* entity-data main module includes effects and HTTP data services
3814
* Configure with `forRoot`.
3915
* No `forFeature` yet.
4016
*/
4117
@NgModule({
42-
imports: [
43-
EntityDataModuleWithoutEffects,
44-
EffectsModule, // do not supply effects because can't replace later
45-
],
46-
providers: [
47-
DefaultDataServiceFactory,
48-
EntityCacheDataService,
49-
EntityDataService,
50-
EntityCacheEffects,
51-
EntityEffects,
52-
{ provide: HttpUrlGenerator, useClass: DefaultHttpUrlGenerator },
53-
{
54-
provide: PersistenceResultHandler,
55-
useClass: DefaultPersistenceResultHandler,
56-
},
57-
{ provide: Pluralizer, useClass: DefaultPluralizer },
58-
],
18+
imports: [EntityDataModuleWithoutEffects],
19+
providers: [ENTITY_DATA_PROVIDERS],
5920
})
6021
export class EntityDataModule {
6122
static forRoot(
@@ -64,59 +25,13 @@ export class EntityDataModule {
6425
return {
6526
ngModule: EntityDataModule,
6627
providers: [
67-
// TODO: Moved these effects classes up to EntityDataModule itself
68-
// Remove this comment if that was a mistake.
69-
// EntityCacheEffects,
70-
// EntityEffects,
71-
{
72-
provide: ENTITY_METADATA_TOKEN,
73-
multi: true,
74-
useValue: config.entityMetadata ? config.entityMetadata : [],
75-
},
76-
{
77-
provide: ENTITY_CACHE_META_REDUCERS,
78-
useValue: config.entityCacheMetaReducers
79-
? config.entityCacheMetaReducers
80-
: [],
81-
},
82-
{
83-
provide: ENTITY_COLLECTION_META_REDUCERS,
84-
useValue: config.entityCollectionMetaReducers
85-
? config.entityCollectionMetaReducers
86-
: [],
87-
},
88-
{
89-
provide: PLURAL_NAMES_TOKEN,
90-
multi: true,
91-
useValue: config.pluralNames ? config.pluralNames : {},
92-
},
28+
provideRootEntityDataWithoutEffects(config),
29+
provideRootEntityData(config),
9330
],
9431
};
9532
}
9633

97-
constructor(
98-
private effectSources: EffectSources,
99-
entityCacheEffects: EntityCacheEffects,
100-
entityEffects: EntityEffects
101-
) {
102-
// We can't use `forFeature()` because, if we did, the developer could not
103-
// replace the entity-data `EntityEffects` with a custom alternative.
104-
// Replacing that class is an extensibility point we need.
105-
//
106-
// The FEATURE_EFFECTS token is not exposed, so can't use that technique.
107-
// Warning: this alternative approach relies on an undocumented API
108-
// to add effect directly rather than through `forFeature()`.
109-
// The danger is that EffectsModule.forFeature evolves and we no longer perform a crucial step.
110-
this.addEffects(entityCacheEffects);
111-
this.addEffects(entityEffects);
112-
}
113-
114-
/**
115-
* Add another class instance that contains effects.
116-
* @param effectSourceInstance a class instance that implements effects.
117-
* Warning: undocumented @ngrx/effects API
118-
*/
119-
addEffects(effectSourceInstance: any) {
120-
this.effectSources.addEffects(effectSourceInstance);
34+
constructor() {
35+
initializeEntityData();
12136
}
12237
}

modules/data/src/index.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -190,9 +190,15 @@ export {
190190
toUpdateFactory,
191191
} from './utils/utilities';
192192

193+
// // EntityDataConfig
194+
export { EntityDataModuleConfig } from './entity-data-config';
195+
193196
// // EntityDataModule
194-
export {
195-
EntityDataModuleConfig,
196-
EntityDataModuleWithoutEffects,
197-
} from './entity-data-without-effects.module';
197+
export { EntityDataModuleWithoutEffects } from './entity-data-without-effects.module';
198198
export { EntityDataModule } from './entity-data.module';
199+
200+
// // Standalone APIs
201+
export {
202+
provideEntityData,
203+
provideEntityDataWithoutEffects,
204+
} from './provide-entity-data';

0 commit comments

Comments
 (0)