Skip to content

Commit f25d319

Browse files
committed
feat(json-api-nestjs-typeorm): Adapter for typerorm
Move adapter for typeorm as separate package
1 parent f202ebc commit f25d319

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+5855
-0
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"extends": ["../../../.eslintrc.base.json"],
3+
"ignorePatterns": ["!**/*"],
4+
"overrides": [
5+
{
6+
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
7+
"rules": {}
8+
},
9+
{
10+
"files": ["*.ts", "*.tsx"],
11+
"rules": {}
12+
},
13+
{
14+
"files": ["*.js", "*.jsx"],
15+
"rules": {}
16+
},
17+
{
18+
"files": ["*.json"],
19+
"parser": "jsonc-eslint-parser",
20+
"rules": {
21+
"@nx/dependency-checks": [
22+
"error",
23+
{
24+
"ignoredFiles": ["{projectRoot}/eslint.config.{js,cjs,mjs}"]
25+
}
26+
]
27+
}
28+
}
29+
]
30+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# json-api-nestjs-typeorm
2+
3+
This library was generated with [Nx](https://nx.dev).
4+
5+
## Building
6+
7+
Run `nx build json-api-nestjs-typeorm` to build the library.
8+
9+
## Running unit tests
10+
11+
Run `nx test json-api-nestjs-typeorm` to execute the unit tests via [Jest](https://jestjs.io).
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
export default {
2+
displayName: 'json-api-nestjs-typeorm',
3+
preset: '../../../jest.preset.js',
4+
testEnvironment: 'node',
5+
transform: {
6+
'^.+\\.[tj]s$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }],
7+
},
8+
moduleFileExtensions: ['ts', 'js', 'html'],
9+
coverageDirectory: '../../../coverage/libs/json-api/json-api-nestjs-typeorm',
10+
};
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"name": "@klerick/json-api-nestjs-typeorm",
3+
"version": "0.0.1",
4+
"dependencies": {
5+
"tslib": "^2.3.0"
6+
},
7+
"type": "commonjs",
8+
"main": "./src/index.js",
9+
"typings": "./src/index.d.ts"
10+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{
2+
"name": "json-api-nestjs-typeorm",
3+
"$schema": "../../../node_modules/nx/schemas/project-schema.json",
4+
"sourceRoot": "libs/json-api/json-api-nestjs-typeorm/src",
5+
"projectType": "library",
6+
"release": {
7+
"version": {
8+
"generatorOptions": {
9+
"packageRoot": "dist/{projectRoot}",
10+
"currentVersionResolver": "git-tag"
11+
}
12+
}
13+
},
14+
"tags": ["type:lib", "lib:json-api-nestjs", "lib:json-api-nestjs-typeorm", "type:publish"],
15+
"targets": {
16+
"build": {
17+
"executor": "@nx/js:tsc",
18+
"outputs": ["{options.outputPath}"],
19+
"options": {
20+
"outputPath": "dist/libs/json-api/json-api-nestjs-typeorm",
21+
"tsConfig": "libs/json-api/json-api-nestjs-typeorm/tsconfig.lib.json",
22+
"packageJson": "libs/json-api/json-api-nestjs-typeorm/package.json",
23+
"main": "libs/json-api/json-api-nestjs-typeorm/src/index.ts",
24+
"assets": ["libs/json-api/json-api-nestjs-typeorm/*.md"],
25+
"buildableProjectDepsInPackageJsonType": "peerDependencies",
26+
"generateExportsField": true
27+
}
28+
},
29+
"nx-release-publish": {
30+
"options": {
31+
"packageRoot": "dist/{projectRoot}"
32+
}
33+
}
34+
},
35+
"implicitDependencies": ["json-api-nestjs"]
36+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './lib/type-orm-json-api.module';
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export const SUB_QUERY_ALIAS_FOR_PAGINATION = 'subQueryWithLimitOffset';
2+
export const ALIAS_FOR_PAGINATION = 'aliasForPagination';
3+
export const DEFAULT_CONNECTION_NAME = 'default';
4+
export const CURRENT_ENTITY_REPOSITORY = Symbol('CURRENT_ENTITY_REPOSITORY');
5+
export const CURRENT_DATA_SOURCE_TOKEN = Symbol('CURRENT_DATA_SOURCE_TOKEN');
6+
export const CURRENT_ENTITY_MANAGER_TOKEN = Symbol(
7+
'CURRENT_ENTITY_MANAGER_TOKEN'
8+
);
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
import { FactoryProvider } from '@nestjs/common';
2+
import { getDataSourceToken } from '@nestjs/typeorm';
3+
import {
4+
EntityParam,
5+
CheckRelationName,
6+
FindOneRowEntity,
7+
RunInTransaction,
8+
PrepareParams,
9+
FIND_ONE_ROW_ENTITY,
10+
CHECK_RELATION_NAME,
11+
RUN_IN_TRANSACTION_FUNCTION,
12+
ORM_SERVICE,
13+
MODULE_OPTIONS_TOKEN,
14+
ENTITY_PARAM_MAP,
15+
} from '@klerick/json-api-nestjs';
16+
import { getEntityName } from '@klerick/json-api-nestjs-shared';
17+
18+
import { kebabCase } from 'change-case-commonjs';
19+
import { DataSource, EntityManager, EntityTarget, Repository } from 'typeorm';
20+
21+
import {
22+
CURRENT_DATA_SOURCE_TOKEN,
23+
CURRENT_ENTITY_MANAGER_TOKEN,
24+
CURRENT_ENTITY_REPOSITORY,
25+
} from '../constants';
26+
27+
import { TypeOrmService, TypeormUtilsService } from '../service';
28+
29+
import { TypeOrmParam } from '../type';
30+
31+
import {
32+
getProps,
33+
getRelation,
34+
getPropsType,
35+
getPropsNullable,
36+
getPrimaryColumnName,
37+
getPrimaryColumnType,
38+
getRelationProperty,
39+
getArrayType,
40+
} from '../orm-helper';
41+
import { EntityClass } from '@mikro-orm/core';
42+
43+
export function CurrentDataSourceProvider(
44+
connectionName?: string
45+
): FactoryProvider<DataSource> {
46+
return {
47+
provide: CURRENT_DATA_SOURCE_TOKEN,
48+
useFactory: (dataSource: DataSource) => dataSource,
49+
inject: [getDataSourceToken(connectionName)],
50+
};
51+
}
52+
53+
export function CurrentEntityManager(): FactoryProvider<EntityManager> {
54+
return {
55+
provide: CURRENT_ENTITY_MANAGER_TOKEN,
56+
useFactory: (dataSource: DataSource) => dataSource.manager,
57+
inject: [CURRENT_DATA_SOURCE_TOKEN],
58+
};
59+
}
60+
61+
export function CurrentEntityRepository<E extends object>(
62+
entity: E
63+
): FactoryProvider<Repository<E>> {
64+
return {
65+
provide: CURRENT_ENTITY_REPOSITORY,
66+
useFactory: (entityManager: EntityManager) =>
67+
entityManager.getRepository(entity as unknown as EntityTarget<E>),
68+
inject: [CURRENT_ENTITY_MANAGER_TOKEN],
69+
};
70+
}
71+
72+
export function EntityPropsMap<E extends object>(entities: EntityClass<E>[]) {
73+
return {
74+
provide: ENTITY_PARAM_MAP,
75+
inject: [CURRENT_ENTITY_MANAGER_TOKEN],
76+
useFactory: (entityManager: EntityManager) => {
77+
const mapProperty = new Map<EntityClass<E>, EntityParam<E>>();
78+
79+
for (const item of entities) {
80+
const entityRepo = entityManager.getRepository<E>(item);
81+
82+
const className = getEntityName(item);
83+
mapProperty.set(item, {
84+
props: getProps(entityRepo),
85+
propsType: getPropsType(entityRepo),
86+
propsNullable: getPropsNullable(entityRepo),
87+
primaryColumnName: getPrimaryColumnName(entityRepo),
88+
primaryColumnType: getPrimaryColumnType(entityRepo),
89+
propsArrayType: getArrayType(entityRepo),
90+
typeName: kebabCase(className),
91+
className: className,
92+
relations: getRelation(entityRepo),
93+
relationProperty: getRelationProperty(entityRepo),
94+
});
95+
}
96+
return mapProperty;
97+
},
98+
};
99+
}
100+
101+
export function FindOneRowEntityFactory<E extends object>(): FactoryProvider<
102+
FindOneRowEntity<E>
103+
> {
104+
return {
105+
provide: FIND_ONE_ROW_ENTITY,
106+
inject: [CURRENT_ENTITY_REPOSITORY, TypeormUtilsService],
107+
useFactory: (
108+
repository: Repository<E>,
109+
typeormUtilsService: TypeormUtilsService<E>
110+
) => {
111+
return async (entity, value) => {
112+
const params = 'params';
113+
return await repository
114+
.createQueryBuilder(typeormUtilsService.currentAlias)
115+
.where(
116+
`${typeormUtilsService.getAliasPath(
117+
typeormUtilsService.currentPrimaryColumn
118+
)} = :${params}`
119+
)
120+
.setParameters({
121+
[params]: value,
122+
})
123+
.getOne();
124+
};
125+
},
126+
};
127+
}
128+
129+
export function CheckRelationNameFactory<
130+
E extends object,
131+
IdKey extends string = 'id'
132+
>(): FactoryProvider<CheckRelationName<E>> {
133+
return {
134+
provide: CHECK_RELATION_NAME,
135+
inject: [TypeormUtilsService],
136+
useFactory(typeormUtilsService: TypeormUtilsService<E, IdKey>) {
137+
return (entity, value) =>
138+
!!(typeormUtilsService.relationFields as any).find(
139+
(i: any) => i === value
140+
);
141+
},
142+
};
143+
}
144+
145+
export function RunInTransactionFactory(): FactoryProvider<RunInTransaction> {
146+
return {
147+
provide: RUN_IN_TRANSACTION_FUNCTION,
148+
inject: [MODULE_OPTIONS_TOKEN, CURRENT_DATA_SOURCE_TOKEN],
149+
useFactory(options: PrepareParams<TypeOrmParam>, dataSource: DataSource) {
150+
const {
151+
options: { runInTransaction },
152+
} = options;
153+
154+
if (runInTransaction && typeof runInTransaction === 'function') {
155+
return (callback) =>
156+
runInTransaction('READ COMMITTED', () => callback());
157+
}
158+
159+
return async (callback) => {
160+
const queryRunner = dataSource.createQueryRunner();
161+
await queryRunner.startTransaction('READ UNCOMMITTED');
162+
let result: unknown;
163+
try {
164+
result = await callback();
165+
await queryRunner.commitTransaction();
166+
} catch (e) {
167+
await queryRunner.rollbackTransaction();
168+
throw e;
169+
} finally {
170+
await queryRunner.release();
171+
}
172+
return result;
173+
};
174+
},
175+
};
176+
}
177+
178+
export function OrmServiceFactory() {
179+
return {
180+
provide: ORM_SERVICE,
181+
useClass: TypeOrmService,
182+
};
183+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './type-orm-json-api.module';
2+
export * from './type';
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import {
2+
PrimaryGeneratedColumn,
3+
OneToOne,
4+
Column,
5+
Entity,
6+
UpdateDateColumn,
7+
} from 'typeorm';
8+
9+
import { Users, IUsers } from './index';
10+
11+
export type IAddresses = Addresses;
12+
13+
@Entity('addresses')
14+
export class Addresses {
15+
@PrimaryGeneratedColumn()
16+
public id!: number;
17+
18+
@Column({
19+
type: 'varchar',
20+
length: 70,
21+
nullable: true,
22+
default: 'NULL',
23+
})
24+
public city!: string;
25+
26+
@Column({
27+
type: 'varchar',
28+
length: 70,
29+
nullable: true,
30+
default: 'NULL',
31+
})
32+
public state!: string;
33+
34+
@Column({
35+
type: 'varchar',
36+
length: 68,
37+
nullable: true,
38+
default: 'NULL',
39+
})
40+
public country!: string;
41+
42+
@Column({
43+
name: 'array_field',
44+
type: 'varchar',
45+
nullable: true,
46+
default: () => 'NULL',
47+
array: true,
48+
})
49+
public arrayField!: string[];
50+
51+
@Column({
52+
name: 'created_at',
53+
type: 'timestamp',
54+
nullable: true,
55+
default: () => 'CURRENT_TIMESTAMP(0)',
56+
})
57+
public createdAt!: Date;
58+
59+
@UpdateDateColumn({
60+
name: 'updated_at',
61+
type: 'timestamp',
62+
nullable: true,
63+
default: () => 'CURRENT_TIMESTAMP(0)',
64+
})
65+
public updatedAt!: Date;
66+
67+
@OneToOne(() => Users, (item) => item.addresses)
68+
public user!: IUsers;
69+
}

0 commit comments

Comments
 (0)