@hazeljs/prisma 0.2.0-beta.55 → 0.2.0-beta.56
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__mocks__/@prisma/client/runtime/library.d.ts +10 -0
- package/dist/__mocks__/@prisma/client/runtime/library.d.ts.map +1 -0
- package/dist/__mocks__/@prisma/client/runtime/library.js +13 -0
- package/dist/__mocks__/@prisma/client.d.ts +7 -0
- package/dist/__mocks__/@prisma/client.d.ts.map +1 -0
- package/dist/__mocks__/@prisma/client.js +11 -0
- package/dist/prisma.test.d.ts +2 -0
- package/dist/prisma.test.d.ts.map +1 -0
- package/dist/prisma.test.js +271 -0
- package/package.json +2 -2
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare class PrismaClientKnownRequestError extends Error {
|
|
2
|
+
code: string;
|
|
3
|
+
meta?: Record<string, unknown>;
|
|
4
|
+
clientVersion: string;
|
|
5
|
+
constructor(message: string, { code, meta }: {
|
|
6
|
+
code: string;
|
|
7
|
+
meta?: Record<string, unknown>;
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=library.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"library.d.ts","sourceRoot":"","sources":["../../../../../src/__mocks__/@prisma/client/runtime/library.ts"],"names":[],"mappings":"AAAA,qBAAa,6BAA8B,SAAQ,KAAK;IACtD,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,aAAa,EAAE,MAAM,CAAC;gBAEV,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE;CAO9F"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PrismaClientKnownRequestError = void 0;
|
|
4
|
+
class PrismaClientKnownRequestError extends Error {
|
|
5
|
+
constructor(message, { code, meta }) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = 'PrismaClientKnownRequestError';
|
|
8
|
+
this.code = code;
|
|
9
|
+
this.meta = meta;
|
|
10
|
+
this.clientVersion = '5.0.0';
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
exports.PrismaClientKnownRequestError = PrismaClientKnownRequestError;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/__mocks__/@prisma/client.ts"],"names":[],"mappings":"AAAA,qBAAa,YAAY;IACvB,GAAG,2BAAa;IAChB,QAAQ,2BAA0C;IAClD,WAAW,2BAA0C;gBAEzC,QAAQ,CAAC,EAAE,OAAO;CAC/B"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PrismaClient = void 0;
|
|
4
|
+
class PrismaClient {
|
|
5
|
+
constructor(_options) {
|
|
6
|
+
this.$on = jest.fn();
|
|
7
|
+
this.$connect = jest.fn().mockResolvedValue(undefined);
|
|
8
|
+
this.$disconnect = jest.fn().mockResolvedValue(undefined);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
exports.PrismaClient = PrismaClient;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prisma.test.d.ts","sourceRoot":"","sources":["../src/prisma.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/// <reference types="jest" />
|
|
3
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
4
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
5
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
6
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
7
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
8
|
+
};
|
|
9
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
10
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
11
|
+
};
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
jest.mock('@hazeljs/core', () => ({
|
|
14
|
+
__esModule: true,
|
|
15
|
+
Injectable: () => () => undefined,
|
|
16
|
+
HazelModule: () => () => undefined,
|
|
17
|
+
Module: () => () => undefined,
|
|
18
|
+
RepositoryOptions: class {
|
|
19
|
+
},
|
|
20
|
+
logger: { info: jest.fn(), debug: jest.fn(), warn: jest.fn(), error: jest.fn() },
|
|
21
|
+
default: { info: jest.fn(), debug: jest.fn(), warn: jest.fn(), error: jest.fn() },
|
|
22
|
+
}));
|
|
23
|
+
const core_1 = __importDefault(require("@hazeljs/core"));
|
|
24
|
+
const prisma_service_1 = require("./prisma.service");
|
|
25
|
+
const base_repository_1 = require("./base.repository");
|
|
26
|
+
const repository_decorator_1 = require("./repository.decorator");
|
|
27
|
+
const library_1 = require("./__mocks__/@prisma/client/runtime/library");
|
|
28
|
+
// ─── PrismaService ────────────────────────────────────────────────────────────
|
|
29
|
+
describe('PrismaService', () => {
|
|
30
|
+
let service;
|
|
31
|
+
let $onMock;
|
|
32
|
+
beforeEach(() => {
|
|
33
|
+
service = new prisma_service_1.PrismaService();
|
|
34
|
+
$onMock = service.$on;
|
|
35
|
+
});
|
|
36
|
+
it('instantiates without error', () => {
|
|
37
|
+
expect(service).toBeDefined();
|
|
38
|
+
});
|
|
39
|
+
it('registers $on handler for query events', () => {
|
|
40
|
+
expect($onMock).toHaveBeenCalledWith('query', expect.any(Function));
|
|
41
|
+
});
|
|
42
|
+
it('registers $on handler for error events', () => {
|
|
43
|
+
expect($onMock).toHaveBeenCalledWith('error', expect.any(Function));
|
|
44
|
+
});
|
|
45
|
+
it('query event callback logs valid query events', () => {
|
|
46
|
+
const queryCallback = $onMock.mock.calls.find(([evt]) => evt === 'query')?.[1];
|
|
47
|
+
expect(queryCallback).toBeDefined();
|
|
48
|
+
queryCallback({ query: 'SELECT 1', params: '[]', duration: 5 });
|
|
49
|
+
expect(core_1.default.debug).toHaveBeenCalled();
|
|
50
|
+
});
|
|
51
|
+
it('query event callback ignores non-query events', () => {
|
|
52
|
+
const queryCallback = $onMock.mock.calls.find(([evt]) => evt === 'query')?.[1];
|
|
53
|
+
jest.clearAllMocks();
|
|
54
|
+
queryCallback({ message: 'not a query event' });
|
|
55
|
+
expect(core_1.default.debug).not.toHaveBeenCalled();
|
|
56
|
+
});
|
|
57
|
+
it('error event callback logs prisma error events', () => {
|
|
58
|
+
const errorCallback = $onMock.mock.calls.find(([evt]) => evt === 'error')?.[1];
|
|
59
|
+
expect(errorCallback).toBeDefined();
|
|
60
|
+
errorCallback({ message: 'some error' });
|
|
61
|
+
expect(core_1.default.error).toHaveBeenCalled();
|
|
62
|
+
});
|
|
63
|
+
it('error event callback ignores events without message', () => {
|
|
64
|
+
const errorCallback = $onMock.mock.calls.find(([evt]) => evt === 'error')?.[1];
|
|
65
|
+
jest.clearAllMocks();
|
|
66
|
+
errorCallback({ query: 'SELECT 1', params: '[]', duration: 2 });
|
|
67
|
+
expect(core_1.default.error).not.toHaveBeenCalled();
|
|
68
|
+
});
|
|
69
|
+
it('onModuleInit calls $connect and resolves', async () => {
|
|
70
|
+
await expect(service.onModuleInit()).resolves.toBeUndefined();
|
|
71
|
+
expect(service.$connect).toHaveBeenCalled();
|
|
72
|
+
});
|
|
73
|
+
it('onModuleInit throws and logs when $connect rejects', async () => {
|
|
74
|
+
service.$connect.mockRejectedValueOnce(new Error('connection refused'));
|
|
75
|
+
await expect(service.onModuleInit()).rejects.toThrow('connection refused');
|
|
76
|
+
});
|
|
77
|
+
it('onModuleDestroy calls $disconnect and resolves', async () => {
|
|
78
|
+
await expect(service.onModuleDestroy()).resolves.toBeUndefined();
|
|
79
|
+
expect(service.$disconnect).toHaveBeenCalled();
|
|
80
|
+
});
|
|
81
|
+
it('onModuleDestroy throws and logs when $disconnect rejects', async () => {
|
|
82
|
+
service.$disconnect.mockRejectedValueOnce(new Error('disconnect failed'));
|
|
83
|
+
await expect(service.onModuleDestroy()).rejects.toThrow('disconnect failed');
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
function buildMockDelegate() {
|
|
87
|
+
return {
|
|
88
|
+
findMany: jest.fn(),
|
|
89
|
+
findUnique: jest.fn(),
|
|
90
|
+
create: jest.fn(),
|
|
91
|
+
update: jest.fn(),
|
|
92
|
+
delete: jest.fn(),
|
|
93
|
+
count: jest.fn(),
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
class TestRepository extends base_repository_1.BaseRepository {
|
|
97
|
+
constructor(prisma) {
|
|
98
|
+
super(prisma, 'testModel');
|
|
99
|
+
}
|
|
100
|
+
// Expose protected handleError for testing
|
|
101
|
+
testHandleError(error) {
|
|
102
|
+
return this.handleError(error);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
function buildRepo() {
|
|
106
|
+
const delegate = buildMockDelegate();
|
|
107
|
+
const mockPrisma = {
|
|
108
|
+
$on: jest.fn(),
|
|
109
|
+
$connect: jest.fn().mockResolvedValue(undefined),
|
|
110
|
+
$disconnect: jest.fn().mockResolvedValue(undefined),
|
|
111
|
+
testModel: delegate,
|
|
112
|
+
};
|
|
113
|
+
const repo = new TestRepository(mockPrisma);
|
|
114
|
+
return { repo, delegate };
|
|
115
|
+
}
|
|
116
|
+
describe('BaseRepository', () => {
|
|
117
|
+
describe('findMany()', () => {
|
|
118
|
+
it('returns all records', async () => {
|
|
119
|
+
const { repo, delegate } = buildRepo();
|
|
120
|
+
const records = [
|
|
121
|
+
{ id: 1, name: 'Alice' },
|
|
122
|
+
{ id: 2, name: 'Bob' },
|
|
123
|
+
];
|
|
124
|
+
delegate.findMany.mockResolvedValue(records);
|
|
125
|
+
await expect(repo.findMany()).resolves.toEqual(records);
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
describe('findOne()', () => {
|
|
129
|
+
it('returns matching record', async () => {
|
|
130
|
+
const { repo, delegate } = buildRepo();
|
|
131
|
+
const record = { id: 1, name: 'Alice' };
|
|
132
|
+
delegate.findUnique.mockResolvedValue(record);
|
|
133
|
+
await expect(repo.findOne({ id: 1 })).resolves.toEqual(record);
|
|
134
|
+
expect(delegate.findUnique).toHaveBeenCalledWith({ where: { id: 1 } });
|
|
135
|
+
});
|
|
136
|
+
it('returns null when not found', async () => {
|
|
137
|
+
const { repo, delegate } = buildRepo();
|
|
138
|
+
delegate.findUnique.mockResolvedValue(null);
|
|
139
|
+
await expect(repo.findOne({ id: 99 })).resolves.toBeNull();
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
describe('create()', () => {
|
|
143
|
+
it('creates and returns a record', async () => {
|
|
144
|
+
const { repo, delegate } = buildRepo();
|
|
145
|
+
const created = { id: 3, name: 'Charlie' };
|
|
146
|
+
delegate.create.mockResolvedValue(created);
|
|
147
|
+
await expect(repo.create({ name: 'Charlie' })).resolves.toEqual(created);
|
|
148
|
+
expect(delegate.create).toHaveBeenCalledWith({ data: { name: 'Charlie' } });
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
describe('update()', () => {
|
|
152
|
+
it('updates and returns the updated record', async () => {
|
|
153
|
+
const { repo, delegate } = buildRepo();
|
|
154
|
+
const updated = { id: 1, name: 'Updated' };
|
|
155
|
+
delegate.update.mockResolvedValue(updated);
|
|
156
|
+
await expect(repo.update({ id: 1 }, { name: 'Updated' })).resolves.toEqual(updated);
|
|
157
|
+
expect(delegate.update).toHaveBeenCalledWith({ where: { id: 1 }, data: { name: 'Updated' } });
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
describe('delete()', () => {
|
|
161
|
+
it('deletes and returns the deleted record', async () => {
|
|
162
|
+
const { repo, delegate } = buildRepo();
|
|
163
|
+
const deleted = { id: 1, name: 'Alice' };
|
|
164
|
+
delegate.delete.mockResolvedValue(deleted);
|
|
165
|
+
await expect(repo.delete({ id: 1 })).resolves.toEqual(deleted);
|
|
166
|
+
expect(delegate.delete).toHaveBeenCalledWith({ where: { id: 1 } });
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
describe('count()', () => {
|
|
170
|
+
it('returns record count', async () => {
|
|
171
|
+
const { repo, delegate } = buildRepo();
|
|
172
|
+
delegate.count.mockResolvedValue(5);
|
|
173
|
+
await expect(repo.count()).resolves.toBe(5);
|
|
174
|
+
});
|
|
175
|
+
it('passes args to count', async () => {
|
|
176
|
+
const { repo, delegate } = buildRepo();
|
|
177
|
+
delegate.count.mockResolvedValue(2);
|
|
178
|
+
const args = { where: { name: 'Alice' } };
|
|
179
|
+
await expect(repo.count(args)).resolves.toBe(2);
|
|
180
|
+
expect(delegate.count).toHaveBeenCalledWith(args);
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
describe('prismaClient / modelDelegate getters', () => {
|
|
184
|
+
it('prismaClient returns the prisma instance', () => {
|
|
185
|
+
const { repo } = buildRepo();
|
|
186
|
+
expect(repo.prismaClient).toBeDefined();
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
describe('handleError()', () => {
|
|
190
|
+
it('throws unique constraint error for P2002 with target', () => {
|
|
191
|
+
const { repo } = buildRepo();
|
|
192
|
+
const err = new library_1.PrismaClientKnownRequestError('unique', {
|
|
193
|
+
code: 'P2002',
|
|
194
|
+
meta: { target: ['email', 'username'] },
|
|
195
|
+
});
|
|
196
|
+
expect(() => repo.testHandleError(err)).toThrow('Unique constraint violation on fields: email, username');
|
|
197
|
+
});
|
|
198
|
+
it('throws unique constraint error for P2002 without target', () => {
|
|
199
|
+
const { repo } = buildRepo();
|
|
200
|
+
const err = new library_1.PrismaClientKnownRequestError('unique', { code: 'P2002' });
|
|
201
|
+
expect(() => repo.testHandleError(err)).toThrow('Unique constraint violation on field');
|
|
202
|
+
});
|
|
203
|
+
it('throws not found error for P2025', () => {
|
|
204
|
+
const { repo } = buildRepo();
|
|
205
|
+
const err = new library_1.PrismaClientKnownRequestError('not found', { code: 'P2025' });
|
|
206
|
+
expect(() => repo.testHandleError(err)).toThrow('Record not found');
|
|
207
|
+
});
|
|
208
|
+
it('throws foreign key error for P2003', () => {
|
|
209
|
+
const { repo } = buildRepo();
|
|
210
|
+
const err = new library_1.PrismaClientKnownRequestError('fk', { code: 'P2003' });
|
|
211
|
+
expect(() => repo.testHandleError(err)).toThrow('Foreign key constraint violation');
|
|
212
|
+
});
|
|
213
|
+
it('throws generic db error for unknown prisma code', () => {
|
|
214
|
+
const { repo } = buildRepo();
|
|
215
|
+
const err = new library_1.PrismaClientKnownRequestError('unknown', { code: 'P9999' });
|
|
216
|
+
expect(() => repo.testHandleError(err)).toThrow('Database error:');
|
|
217
|
+
});
|
|
218
|
+
it('throws wrapped error for non-prisma errors', () => {
|
|
219
|
+
const { repo } = buildRepo();
|
|
220
|
+
expect(() => repo.testHandleError(new Error('generic error'))).toThrow('Database error: generic error');
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
// ─── Repository decorator ─────────────────────────────────────────────────────
|
|
225
|
+
describe('@Repository decorator', () => {
|
|
226
|
+
it('sets hazel:repository metadata with string shorthand', () => {
|
|
227
|
+
let UserRepo = class UserRepo {
|
|
228
|
+
};
|
|
229
|
+
UserRepo = __decorate([
|
|
230
|
+
(0, repository_decorator_1.Repository)('user')
|
|
231
|
+
], UserRepo);
|
|
232
|
+
const meta = Reflect.getMetadata('hazel:repository', UserRepo);
|
|
233
|
+
expect(meta).toEqual({ model: 'user' });
|
|
234
|
+
});
|
|
235
|
+
it('sets hazel:repository metadata with options object', () => {
|
|
236
|
+
let PostRepo = class PostRepo {
|
|
237
|
+
};
|
|
238
|
+
PostRepo = __decorate([
|
|
239
|
+
(0, repository_decorator_1.Repository)({ model: 'post' })
|
|
240
|
+
], PostRepo);
|
|
241
|
+
const meta = Reflect.getMetadata('hazel:repository', PostRepo);
|
|
242
|
+
expect(meta).toEqual({ model: 'post' });
|
|
243
|
+
});
|
|
244
|
+
it('sets hazel:injectable metadata', () => {
|
|
245
|
+
let CommentRepo = class CommentRepo {
|
|
246
|
+
};
|
|
247
|
+
CommentRepo = __decorate([
|
|
248
|
+
(0, repository_decorator_1.Repository)('comment')
|
|
249
|
+
], CommentRepo);
|
|
250
|
+
const injectable = Reflect.getMetadata('hazel:injectable', CommentRepo);
|
|
251
|
+
expect(injectable).toEqual({});
|
|
252
|
+
});
|
|
253
|
+
it('sets hazel:scope metadata when scope is provided', () => {
|
|
254
|
+
let SessionRepo = class SessionRepo {
|
|
255
|
+
};
|
|
256
|
+
SessionRepo = __decorate([
|
|
257
|
+
(0, repository_decorator_1.Repository)({ model: 'session', scope: 'REQUEST' })
|
|
258
|
+
], SessionRepo);
|
|
259
|
+
const scope = Reflect.getMetadata('hazel:scope', SessionRepo);
|
|
260
|
+
expect(scope).toBe('REQUEST');
|
|
261
|
+
});
|
|
262
|
+
it('sets hazel:injectable metadata with scope when scope is provided', () => {
|
|
263
|
+
let LogRepo = class LogRepo {
|
|
264
|
+
};
|
|
265
|
+
LogRepo = __decorate([
|
|
266
|
+
(0, repository_decorator_1.Repository)({ model: 'log', scope: 'TRANSIENT' })
|
|
267
|
+
], LogRepo);
|
|
268
|
+
const injectable = Reflect.getMetadata('hazel:injectable', LogRepo);
|
|
269
|
+
expect(injectable).toEqual({ scope: 'TRANSIENT' });
|
|
270
|
+
});
|
|
271
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hazeljs/prisma",
|
|
3
|
-
"version": "0.2.0-beta.
|
|
3
|
+
"version": "0.2.0-beta.56",
|
|
4
4
|
"description": "Prisma ORM integration for HazelJS framework",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -50,5 +50,5 @@
|
|
|
50
50
|
"peerDependencies": {
|
|
51
51
|
"@hazeljs/core": ">=0.2.0-beta.0"
|
|
52
52
|
},
|
|
53
|
-
"gitHead": "
|
|
53
|
+
"gitHead": "c2737e90974458a8438eee623726f0a453b66b8b"
|
|
54
54
|
}
|