Skip to content

Commit

Permalink
feat(plugin-core): add repository generator
Browse files Browse the repository at this point in the history
  • Loading branch information
guiseek committed Oct 4, 2021
1 parent 4f7649a commit 2a6e897
Show file tree
Hide file tree
Showing 14 changed files with 326 additions and 3 deletions.
11 changes: 11 additions & 0 deletions libs/plugin/core/generators.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@
"schema": "./src/generators/presentation/schema.json",
"description": "Add a presentation layer",
"hidden": true
},
"repository": {
"factory": "./src/generators/repository/generator.compat#generatorSchematic",
"schema": "./src/generators/repository/schema.json",
"description": "Add a abstract and implementation repository",
"hidden": true
}
},
"generators": {
Expand All @@ -37,6 +43,11 @@
"factory": "./src/generators/presentation/generator",
"schema": "./src/generators/presentation/schema.json",
"description": "Presentation"
},
"repository": {
"factory": "./src/generators/repository/generator",
"schema": "./src/generators/repository/schema.json",
"description": "Add a abstract and implementation repository"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { <%= entity.className %>InMemoryRepository } from './<%= entity.propertyName %>.inmemory.repository';
import { <%= entity.className %>Repository } from '@<%= npmScope %>/<%= projectDomain %>';
import { forkJoin } from 'rxjs';

describe('<%= entity.className %> In Memory Repository', () => {
let repo: <%= entity.className %>Repository;

beforeEach(() => {
repo = new <%= entity.className %>InMemoryRepository([
{
id: '1',
title: 'one'
},
{
id: '2',
title: 'two'
},
{
id: '3',
title: 'three'
},
]);
});

it('get all', (done) => {
repo.getAll<%= entity.className %>s().subscribe((<%= entity.propertyName %>s) => {
expect(<%= entity.propertyName %>s.length).toEqual(3);
done();
});
});

it('add <%= entity.propertyName %>', (done) => {
const name = 'bar';
const add$ = repo.add<%= entity.className %>({name});
const all$ = repo.getAll<%= entity.className %>s();

forkJoin([add$, all$]).subscribe(([<%= entity.propertyName %>, <%= entity.propertyName %>s]) => {
expect(<%= entity.propertyName %>.name).toEqual('bar');
expect(<%= entity.propertyName %>s.length).toEqual(4);
done();
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { <%= entity.className %>Repository, <%= entity.className %>Entity } from '@<%= npmScope %>/<%= projectDomain %>';
import { <%= entity.className %>MockMapper } from './mapper/<%= entity.fileName %>-mock.mapper';
import { <%= entity.className %>MockDto } from './dto/<%= entity.fileName %>-mock.dto';
import { Observable, of } from 'rxjs';
import { map } from 'rxjs/operators';

export class <%= entity.className %>InMemoryRepository implements <%= entity.className %>Repository {
constructor(private data: <%= entity.className %>MockDto[] = []) {}

private mapper = new <%= entity.className %>MockMapper();

public getAll<%= entity.className %>s(): Observable<<%= entity.className %>Entity[]> {
return of(this.data).pipe(map((mocks) => mocks.map(this.mapper.mapTo)));
}

public add<%= entity.className %>({ name }: Pick<<%= entity.className %>Entity, 'name'>): Observable<<%= entity.className %>Entity> {
const id = 'item-' + new Date().getTime();
const <%= entity.propertyName %>: <%= entity.className %>Entity = <%= entity.className %>Entity.create({ id, name });

this.data.push(this.mapper.mapFrom(<%= entity.propertyName %>));
return of(<%= entity.propertyName %>);
}

public get<%= entity.className %>ById(id: string): Observable<<%= entity.className %>Entity> {
return of<<%= entity.className %>MockDto>(
this.data.find((<%= entity.propertyName %>) => <%= entity.propertyName %>.id === id) as <%= entity.className %>MockDto
).pipe(map(this.mapper.mapTo));
}

public update<%= entity.className %>(id: string, <%= entity.propertyName %>: <%= entity.className %>Entity): Observable<<%= entity.className %>Entity> {
const record = this.data.findIndex((<%= entity.propertyName %>) => <%= entity.propertyName %>.id === id)
this.data[record] = this.mapper.mapFrom(<%= entity.propertyName %>);
return of(this.mapper.mapTo(this.data[record]));
}

public remove<%= entity.className %>(id: string): Observable<<%= entity.className %>Entity> {
const idx = this.data.findIndex((t) => t.id === id);
const <%= entity.propertyName %> = this.data.find((t) => t.id === id);

this.data.splice(idx, 1);

return of<<%= entity.className %>MockDto>(<%= entity.propertyName %> as <%= entity.className %>MockDto).pipe(map(this.mapper.mapTo));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export class <%= entity.className %>MockDto {
id: string;
title: string;

constructor(params: <%= entity.className %>MockDto) {
this.id = params.id;
this.title = params.title;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { <%= entity.className %>MockDto } from '../dto/<%= entity.propertyName %>-mock.dto';
import { <%= entity.className %>Entity } from '@<%= npmScope %>/<%= projectDomain %>';
import { Mapper } from '@nx-clean/core';

export class <%= entity.className %>MockMapper implements Mapper<<%= entity.className %>Entity, <%= entity.className %>MockDto> {
mapFrom(input: <%= entity.className %>Entity): <%= entity.className %>MockDto {
return {
id: input?.id,
title: input?.name
};
}

mapTo(input: <%= entity.className %>MockDto): <%= entity.className %>Entity {
const <%= entity.propertyName %> = <%= entity.className %>Entity.create({
id: input?.id,
name: input?.title
});

return <%= entity.propertyName %>;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { <%= entity.className %>Entity } from './<%= entity.fileName %>.entity';

describe('<%= entity.className %> Entity', () => {
it('should be properly initialized', () => {
const model = <%= entity.className %>Entity.create({
id: '1',
name: 'foo',
});

expect(model.id).toEqual('1');
expect(model.name).toEqual('foo');
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export class <%= entity.className %>Entity {
id: string;
name: string;

private constructor(params: <%= entity.className %>Entity) {
this.id = params?.id;
this.name = params?.name;
}

static create(params: <%= entity.className %>Entity) {
return new this(params);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { <%= entity.className %>Entity } from '../entity/<%= entity.fileName %>.entity';
import { Observable } from 'rxjs';

export abstract class <%= entity.className %>Repository {
public abstract getAll<%= entity.className %>s(): Observable<<%= entity.className %>Entity[]>;
public abstract add<%= entity.className %>(<%= entity.propertyName %>: Pick<<%= entity.className %>Entity, 'name'>): Observable<<%= entity.className %>Entity>;
public abstract update<%= entity.className %>(id: string, <%= entity.propertyName %>: <%= entity.className %>Entity): Observable<<%= entity.className %>Entity>;
public abstract remove<%= entity.className %>(id: string): Observable<<%= entity.className %>Entity>;
public abstract get<%= entity.className %>ById(id: string): Observable<<%= entity.className %>Entity>;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
const variable = "<%= projectName %>";
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { convertNxGenerator } from '@nrwl/devkit';
import generator from './generator';

export const generatorSchematic = convertNxGenerator(generator);
85 changes: 85 additions & 0 deletions libs/plugin/core/src/generators/repository/generator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import {
Tree,
names,
generateFiles,
offsetFromRoot,
readProjectConfiguration,
readWorkspaceConfiguration,
} from '@nrwl/devkit';
import { join } from 'path';
import {
ImplRepositoryGeneratorSchema,
NormalizedSchema,
RepositoryGeneratorSchema,
TemplateOptions,
} from './schema';

export default function (host: Tree, options: RepositoryGeneratorSchema): void;

export default function (
host: Tree,
options: ImplRepositoryGeneratorSchema
): void {
const normalizedOptions = normalizeOptions(host, options);

if (options.name && options.domain) {
const domain = readProjectConfiguration(host, options.domain);

addFiles(
host,
normalizedOptions,
__dirname + '/files/domain',
domain.sourceRoot
);
}

if (options.impl && options.data) {
if (!options.name) {
throw new Error('You need to add a name');
}

const data = readProjectConfiguration(host, options.data);

addFiles(
host,
normalizedOptions,
__dirname + '/files/data',
data.sourceRoot
);
}
}

function normalizeOptions(
host: Tree,
options: ImplRepositoryGeneratorSchema
): NormalizedSchema {
const npmScope = readWorkspaceConfiguration(host).npmScope;
const projectDomain = options.domain;
const projectData = options.data;
return {
...options,
projectDomain,
projectData,
npmScope,
};
}

function addFiles(
host: Tree,
options: NormalizedSchema,
dir: string,
target: string
) {
const entity = names(options.name);

const templateOptions: TemplateOptions = {
...options,
...names(options.name),
model: entity.fileName,
offsetFromRoot: offsetFromRoot(target),
template: '',
entity,
};

generateFiles(host, join(dir, 'files'), target, templateOptions);
}
31 changes: 31 additions & 0 deletions libs/plugin/core/src/generators/repository/schema.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
export interface RepositoryGeneratorSchema {
name: string;
domain: string;
impl?: boolean;
}

export interface ImplRepositoryGeneratorSchema extends RepositoryGeneratorSchema {
impl: boolean;
data: string;
}

export interface NormalizedSchema extends RepositoryGeneratorSchema {
projectDomain: string;
projectData: string;
npmScope: string;
}

export interface Names {
name: string;
className: string;
propertyName: string;
constantName: string;
fileName: string;
}

export interface TemplateOptions extends NormalizedSchema, Names {
offsetFromRoot: string;
entity: Names;
model: string;
template: string;
}
38 changes: 38 additions & 0 deletions libs/plugin/core/src/generators/repository/schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"$schema": "http://json-schema.org/schema",
"cli": "nx",
"id": "Repository",
"title": "",
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "",
"$default": {
"$source": "argv",
"index": 0
},
"x-prompt": "What name would you like to use?"
},
"domain": {
"type": "string",
"description": "The name of the domain library.",
"$default": {
"$source": "projectName"
}
},
"impl": {
"type": "boolean",
"description": "Would you like to add a implementation?",
"default": false
},
"data": {
"type": "string",
"description": "The name of the data library.",
"$default": {
"$source": "projectName"
}
}
},
"required": ["name", "domain"]
}
6 changes: 3 additions & 3 deletions libs/plugin/core/src/utils/add-files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,19 @@ export function addFiles(
host: Tree,
options: DomainPluginCoreNormalizedSchema,
dir: string
);
): void

export function addFiles(
host: Tree,
options: DataPluginCoreNormalizedSchema,
dir: string
);
): void

export function addFiles(
host: Tree,
options: PresentationPluginCoreNormalizedSchema,
dir: string
) {
): void {
const libNames = names(options.name);

const templateOptions: Record<string, any> = {
Expand Down

0 comments on commit 2a6e897

Please sign in to comment.