Skip to content

Commit 18f4a0c

Browse files
committed
feat(json-api-nestjs): Microro orm
Create orm methode, create general transform service, use this service for swagger and zod
1 parent 8cd7955 commit 18f4a0c

26 files changed

+5393
-0
lines changed
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import { Knex as TypeKnex } from '@mikro-orm/knex';
2+
import { MikroORM } from '@mikro-orm/core';
3+
import { PostgreSqlDriver } from '@mikro-orm/postgresql';
4+
import { SqlHighlighter } from '@mikro-orm/sql-highlighter';
5+
6+
import Knex from 'knex';
7+
import * as ClientPgLite from 'knex-pglite';
8+
9+
import {
10+
Addresses,
11+
Comments,
12+
Notes,
13+
Roles,
14+
UserGroups,
15+
Users,
16+
} from '../entities';
17+
18+
let knexInst: TypeKnex;
19+
20+
export async function sharedConnect(): Promise<TypeKnex> {
21+
// @ts-ignore
22+
// return globalThis.pgLite;
23+
24+
if (knexInst) {
25+
return knexInst;
26+
}
27+
28+
const pgLite = await Promise.all([
29+
import('@electric-sql/pglite'),
30+
// @ts-ignore
31+
import('@electric-sql/pglite/contrib/uuid_ossp'),
32+
]).then(
33+
([{ PGlite }, { uuid_ossp }]) =>
34+
new PGlite({
35+
extensions: { uuid_ossp },
36+
})
37+
);
38+
39+
knexInst = Knex({
40+
// @ts-ignore
41+
client: ClientPgLite,
42+
dialect: 'postgres',
43+
// @ts-ignore
44+
connection: { pglite: pgLite },
45+
});
46+
47+
return knexInst;
48+
}
49+
50+
export async function initMikroOrm(knex: TypeKnex, testDbName: string) {
51+
const result = await knex.raw(
52+
`select 1 from pg_database where datname = '${testDbName}'`
53+
);
54+
55+
if ((result['rows'] as []).length === 0) {
56+
await knex.raw(`create database ??`, [testDbName]);
57+
}
58+
59+
const orm = await MikroORM.init<PostgreSqlDriver>({
60+
highlighter: new SqlHighlighter(),
61+
driver: PostgreSqlDriver,
62+
dbName: testDbName,
63+
driverOptions: knexInst,
64+
entities: [Users, UserGroups, Roles, Comments, Addresses, Notes],
65+
allowGlobalContext: true,
66+
schema: 'public',
67+
debug: ['query', 'query-params'],
68+
});
69+
70+
if ((result['rows'] as []).length === 0) {
71+
const sql = await orm.getSchemaGenerator().getCreateSchemaSQL();
72+
const statements = sql.split(';').filter((s) => s.trim().length > 0); // Разбиваем на отдельные команды
73+
74+
for (const statement of statements) {
75+
await orm.em.execute(statement);
76+
}
77+
}
78+
79+
return orm;
80+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { EntityManager, MikroORM } from '@mikro-orm/core';
2+
3+
import {
4+
dbRandomName,
5+
getModuleForPgLite,
6+
pullData,
7+
Users,
8+
} from '../../../../mock-utils/microrom';
9+
import { MicroOrmService } from '../../service';
10+
11+
import {
12+
CURRENT_ENTITY_MANAGER_TOKEN,
13+
ORM_SERVICE,
14+
} from '../../../../constants';
15+
import { deleteOne } from './delete-one';
16+
17+
describe('delete-one', () => {
18+
let mikroORMUsers: MikroORM;
19+
let microOrmServiceUser: MicroOrmService<Users>;
20+
let em: EntityManager;
21+
let dbName: string;
22+
beforeAll(async () => {
23+
dbName = dbRandomName();
24+
const moduleUsers = await getModuleForPgLite(Users, dbName);
25+
microOrmServiceUser = moduleUsers.get<MicroOrmService<Users>>(ORM_SERVICE);
26+
mikroORMUsers = moduleUsers.get(MikroORM);
27+
em = moduleUsers.get(CURRENT_ENTITY_MANAGER_TOKEN);
28+
await pullData(em, 10);
29+
});
30+
31+
afterEach(() => {
32+
jest.clearAllMocks();
33+
jest.restoreAllMocks();
34+
});
35+
36+
afterAll(() => {
37+
mikroORMUsers.close(true);
38+
});
39+
40+
it('Delete one item', async () => {
41+
const checkData = await microOrmServiceUser.microOrmUtilService
42+
.queryBuilder()
43+
.limit(1)
44+
.execute('get', true);
45+
46+
await deleteOne.call<
47+
MicroOrmService<Users>,
48+
Parameters<typeof deleteOne<Users>>,
49+
ReturnType<typeof deleteOne<Users>>
50+
>(microOrmServiceUser, checkData.id);
51+
52+
const result = await microOrmServiceUser.microOrmUtilService
53+
.queryBuilder()
54+
.where({
55+
id: checkData.id,
56+
})
57+
.execute('get', true);
58+
59+
expect(result).toBe(null);
60+
});
61+
});
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { MicroOrmService } from '../../service';
2+
import { ObjectLiteral } from '../../../../types';
3+
4+
export async function deleteOne<E extends ObjectLiteral>(
5+
this: MicroOrmService<E>,
6+
id: number | string
7+
): Promise<void> {
8+
const data = await this.microOrmUtilService
9+
.queryBuilder()
10+
.where({
11+
[this.microOrmUtilService.currentPrimaryColumn]: id,
12+
})
13+
.getSingleResult();
14+
15+
if (!data) return void 0;
16+
17+
await this.microOrmUtilService.entityManager.removeAndFlush(data);
18+
19+
return void 0;
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
import { Collection, EntityManager, MikroORM } from '@mikro-orm/core';
2+
import { faker } from '@faker-js/faker';
3+
4+
import {
5+
Addresses,
6+
dbRandomName,
7+
getModuleForPgLite,
8+
Notes,
9+
pullData,
10+
Roles,
11+
UserGroups,
12+
Users,
13+
Comments,
14+
pullAddress,
15+
} from '../../../../mock-utils/microrom';
16+
import { MicroOrmService } from '../../service';
17+
18+
import {
19+
CURRENT_ENTITY_MANAGER_TOKEN,
20+
ORM_SERVICE,
21+
} from '../../../../constants';
22+
23+
import { deleteRelationship } from './delete-relationship';
24+
import { BadRequestException } from '@nestjs/common';
25+
import { EntityRelation } from '@klerick/json-api-nestjs-shared';
26+
27+
describe('delete-relationship', () => {
28+
let mikroORMUsers: MikroORM;
29+
let microOrmServiceUser: MicroOrmService<Users>;
30+
let em: EntityManager;
31+
let dbName: string;
32+
let addressForTest: Addresses;
33+
let addresses: Addresses;
34+
let userGroup: UserGroups;
35+
let notes: Collection<Notes>;
36+
let roles: Collection<Roles>;
37+
let comments: Collection<Comments>;
38+
let userObject: Users;
39+
let newUser: Users;
40+
beforeAll(async () => {
41+
dbName = dbRandomName();
42+
const moduleUsers = await getModuleForPgLite(Users, dbName);
43+
microOrmServiceUser = moduleUsers.get<MicroOrmService<Users>>(ORM_SERVICE);
44+
mikroORMUsers = moduleUsers.get(MikroORM);
45+
em = moduleUsers.get(CURRENT_ENTITY_MANAGER_TOKEN);
46+
await pullData(em, 10);
47+
});
48+
49+
beforeEach(async () => {
50+
const data = await microOrmServiceUser.microOrmUtilService
51+
.queryBuilder()
52+
.leftJoinAndSelect('Users.addresses', 'Addresses_addresses', {}, ['id'])
53+
.leftJoinAndSelect('Users.comments', 'Comments_comments', {}, ['id'])
54+
.leftJoinAndSelect('Users.roles', 'Roles__roles', {}, ['id'])
55+
.leftJoinAndSelect('Users.notes', 'Notes__notes', {}, ['id'])
56+
.leftJoinAndSelect('Users.userGroup', 'UserGroups__userGroup', {}, ['id'])
57+
.where({
58+
roles: {
59+
$exists: true,
60+
},
61+
userGroup: {
62+
$exists: true,
63+
},
64+
})
65+
.limit(1)
66+
.getSingleResult();
67+
68+
if (!data) throw new Error();
69+
({ roles, notes, userGroup, addresses, comments, ...userObject as any } =
70+
data);
71+
const firstName = faker.person.firstName();
72+
const lastName = faker.person.lastName();
73+
newUser = {
74+
id: faker.number.int({ min: 0, max: 999999 }),
75+
firstName: firstName,
76+
lastName: lastName,
77+
isActive: faker.datatype.boolean(),
78+
login: faker.internet.userName({
79+
lastName: firstName,
80+
firstName: lastName,
81+
}),
82+
testReal: [faker.number.float({ fractionDigits: 4 })],
83+
testArrayNull: null,
84+
testDate: faker.date.anytime(),
85+
} as Users;
86+
87+
addressForTest = await pullAddress();
88+
await em.persistAndFlush(addressForTest);
89+
});
90+
91+
afterEach(() => {
92+
jest.clearAllMocks();
93+
jest.restoreAllMocks();
94+
});
95+
96+
afterAll(() => {
97+
mikroORMUsers.close(true);
98+
});
99+
100+
it('should be ok', async () => {
101+
const saveCount = roles.length;
102+
const [roles1, roles2] = roles;
103+
await deleteRelationship.call<
104+
MicroOrmService<Users>,
105+
Parameters<typeof deleteRelationship<Users, EntityRelation<Users>>>,
106+
ReturnType<typeof deleteRelationship<Users, EntityRelation<Users>>>
107+
>(microOrmServiceUser, userObject.id, 'roles', [
108+
{ type: 'roles', id: roles1.id.toString() },
109+
]);
110+
111+
await deleteRelationship.call<
112+
MicroOrmService<Users>,
113+
Parameters<typeof deleteRelationship<Users, EntityRelation<Users>>>,
114+
ReturnType<typeof deleteRelationship<Users, EntityRelation<Users>>>
115+
>(microOrmServiceUser, userObject.id, 'userGroup', {
116+
type: 'user-groups',
117+
id: userGroup.id.toString(),
118+
});
119+
120+
const checkData = await microOrmServiceUser.microOrmUtilService
121+
.queryBuilder()
122+
.leftJoinAndSelect('Users.roles', 'Roles__roles', {}, ['id'])
123+
.leftJoinAndSelect('Users.userGroup', 'UserGroups__userGroup', {}, ['id'])
124+
.where({
125+
id: userObject.id,
126+
})
127+
.getSingleResult();
128+
129+
expect(checkData?.roles.length).toBe(saveCount - 1);
130+
expect(checkData?.roles.map((i) => i.id)).not.toContain(roles1.id);
131+
expect(checkData?.userGroup).toBe(null);
132+
});
133+
134+
it('should be error', async () => {
135+
await expect(
136+
deleteRelationship.call<
137+
MicroOrmService<Users>,
138+
Parameters<typeof deleteRelationship<Users, EntityRelation<Users>>>,
139+
ReturnType<typeof deleteRelationship<Users, EntityRelation<Users>>>
140+
>(microOrmServiceUser, userObject.id, 'roles', {
141+
type: 'roles',
142+
id: '1000',
143+
})
144+
).rejects.toThrow();
145+
146+
await expect(
147+
deleteRelationship.call<
148+
MicroOrmService<Users>,
149+
Parameters<typeof deleteRelationship<Users, EntityRelation<Users>>>,
150+
ReturnType<typeof deleteRelationship<Users, EntityRelation<Users>>>
151+
>(microOrmServiceUser, userObject.id, 'roles', [
152+
{
153+
type: 'roles',
154+
id: '1000',
155+
},
156+
])
157+
).rejects.toThrow();
158+
159+
await expect(
160+
deleteRelationship.call<
161+
MicroOrmService<Users>,
162+
Parameters<typeof deleteRelationship<Users, EntityRelation<Users>>>,
163+
ReturnType<typeof deleteRelationship<Users, EntityRelation<Users>>>
164+
>(microOrmServiceUser, userObject.id, 'userGroup', [
165+
{
166+
type: 'user-groups',
167+
id: '10000',
168+
},
169+
])
170+
).rejects.toThrow();
171+
await expect(
172+
deleteRelationship.call<
173+
MicroOrmService<Users>,
174+
Parameters<typeof deleteRelationship<Users, EntityRelation<Users>>>,
175+
ReturnType<typeof deleteRelationship<Users, EntityRelation<Users>>>
176+
>(microOrmServiceUser, userObject.id, 'userGroup', {
177+
type: 'user-groups',
178+
id: '10000',
179+
})
180+
).rejects.toThrow();
181+
});
182+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { EntityRelation } from '@klerick/json-api-nestjs-shared';
2+
3+
import { ObjectLiteral } from '../../../../types';
4+
5+
import { PostRelationshipData } from '../../../mixin/zod';
6+
import { MicroOrmService } from '../../service';
7+
8+
export async function deleteRelationship<
9+
E extends ObjectLiteral,
10+
Rel extends EntityRelation<E>
11+
>(
12+
this: MicroOrmService<E>,
13+
id: number | string,
14+
rel: Rel,
15+
input: PostRelationshipData
16+
): Promise<void> {
17+
const idsResult = await this.microOrmUtilService.validateRelationInputData(
18+
rel,
19+
input
20+
);
21+
22+
const currentEntityRef = this.microOrmUtilService.entityManager.getReference(
23+
this.microOrmUtilService.entity,
24+
id as any
25+
);
26+
27+
if (Array.isArray(idsResult)) {
28+
const relEntity = this.microOrmUtilService.getRelation(rel as any).entity();
29+
const relRef = idsResult.map((i) =>
30+
this.microOrmUtilService.entityManager.getReference(relEntity, i as any)
31+
);
32+
currentEntityRef[rel].remove(...relRef);
33+
} else {
34+
if (
35+
currentEntityRef[rel][this.microOrmUtilService.getPrimaryNameFor(rel)] ==
36+
idsResult
37+
) {
38+
// @ts-ignore
39+
currentEntityRef[rel] = null;
40+
}
41+
}
42+
43+
await this.microOrmUtilService.entityManager.flush();
44+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy