@hazeljs/typeorm 0.2.0-rc.8 → 0.2.1
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/README.md +2 -2
- package/dist/base.repository.test.js +75 -0
- package/dist/typeorm.module.test.js +57 -1
- package/dist/typeorm.service.test.js +85 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -153,9 +153,9 @@ export class TransferService {
|
|
|
153
153
|
## Links
|
|
154
154
|
|
|
155
155
|
- [TypeORM docs](https://typeorm.io)
|
|
156
|
-
- [HazelJS](https://hazeljs.
|
|
156
|
+
- [HazelJS](https://hazeljs.ai)
|
|
157
157
|
- [GitHub](https://github.com/hazel-js/hazeljs)
|
|
158
158
|
|
|
159
159
|
## License
|
|
160
160
|
|
|
161
|
-
Apache 2.0 © [HazelJS](https://hazeljs.
|
|
161
|
+
Apache 2.0 © [HazelJS](https://hazeljs.ai)
|
|
@@ -42,6 +42,43 @@ describe('BaseRepository', () => {
|
|
|
42
42
|
expect(typeof result).toBe('number');
|
|
43
43
|
expect(result).toBe(0);
|
|
44
44
|
});
|
|
45
|
+
it('should delegate findOne to TypeORM repository', async () => {
|
|
46
|
+
const entity = { id: 1, name: 'a' };
|
|
47
|
+
repo['repository'].findOne.mockResolvedValueOnce(entity);
|
|
48
|
+
const result = await repo.findOne({ where: { id: 1 } });
|
|
49
|
+
expect(result).toEqual(entity);
|
|
50
|
+
});
|
|
51
|
+
it('should delegate create to TypeORM repository', async () => {
|
|
52
|
+
const created = { id: 1, name: 'new' };
|
|
53
|
+
repo['repository'].create.mockReturnValueOnce(created);
|
|
54
|
+
repo['repository'].save.mockResolvedValueOnce(created);
|
|
55
|
+
const result = await repo.create({ name: 'new' });
|
|
56
|
+
expect(repo['repository'].create).toHaveBeenCalledWith({ name: 'new' });
|
|
57
|
+
expect(repo['repository'].save).toHaveBeenCalledWith(created);
|
|
58
|
+
expect(result).toEqual(created);
|
|
59
|
+
});
|
|
60
|
+
it('should delegate save to TypeORM repository', async () => {
|
|
61
|
+
const entity = { id: 1, name: 'updated' };
|
|
62
|
+
repo['repository'].save.mockResolvedValueOnce(entity);
|
|
63
|
+
const result = await repo.save(entity);
|
|
64
|
+
expect(result).toEqual(entity);
|
|
65
|
+
});
|
|
66
|
+
it('should delegate update to TypeORM repository', async () => {
|
|
67
|
+
repo['repository'].update.mockResolvedValueOnce(undefined);
|
|
68
|
+
await repo.update({ id: 1 }, { name: 'updated' });
|
|
69
|
+
expect(repo['repository'].update).toHaveBeenCalledWith({ id: 1 }, { name: 'updated' });
|
|
70
|
+
});
|
|
71
|
+
it('should delegate delete to TypeORM repository', async () => {
|
|
72
|
+
repo['repository'].delete.mockResolvedValueOnce(undefined);
|
|
73
|
+
await repo.delete({ id: 1 });
|
|
74
|
+
expect(repo['repository'].delete).toHaveBeenCalledWith({ id: 1 });
|
|
75
|
+
});
|
|
76
|
+
it('should call find with empty options when options undefined', async () => {
|
|
77
|
+
repo['repository'].find.mockClear();
|
|
78
|
+
repo['repository'].find.mockResolvedValueOnce([]);
|
|
79
|
+
await repo.find();
|
|
80
|
+
expect(repo['repository'].find).toHaveBeenCalledWith({});
|
|
81
|
+
});
|
|
45
82
|
describe('handleError', () => {
|
|
46
83
|
it('should throw on generic error', () => {
|
|
47
84
|
expect(() => repo['handleError'](new Error('db error'))).toThrow('Database error: db error');
|
|
@@ -51,10 +88,48 @@ describe('BaseRepository', () => {
|
|
|
51
88
|
err.code = '23505';
|
|
52
89
|
expect(() => repo['handleError'](err)).toThrow(/Unique constraint/);
|
|
53
90
|
});
|
|
91
|
+
it('should map unique constraint 23505 with constraint name', () => {
|
|
92
|
+
const err = new Error('duplicate');
|
|
93
|
+
err.code = '23505';
|
|
94
|
+
err.constraint = 'users_email_key';
|
|
95
|
+
expect(() => repo['handleError'](err)).toThrow('users_email_key');
|
|
96
|
+
});
|
|
54
97
|
it('should map foreign key code 23503', () => {
|
|
55
98
|
const err = new Error('fk');
|
|
56
99
|
err.code = '23503';
|
|
57
100
|
expect(() => repo['handleError'](err)).toThrow('Foreign key constraint violation');
|
|
58
101
|
});
|
|
102
|
+
it('should map EntityNotFoundError by name', () => {
|
|
103
|
+
const err = new Error('not found');
|
|
104
|
+
err.name = 'EntityNotFoundError';
|
|
105
|
+
expect(() => repo['handleError'](err)).toThrow('Record not found');
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
describe('error propagation', () => {
|
|
109
|
+
it('should call handleError when findOne throws', async () => {
|
|
110
|
+
repo['repository'].findOne.mockRejectedValueOnce(new Error('db fail'));
|
|
111
|
+
await expect(repo.findOne({ where: { id: 1 } })).rejects.toThrow('Database error: db fail');
|
|
112
|
+
});
|
|
113
|
+
it('should call handleError when create/save throws', async () => {
|
|
114
|
+
repo['repository'].create.mockReturnValue({});
|
|
115
|
+
repo['repository'].save.mockRejectedValueOnce(new Error('insert fail'));
|
|
116
|
+
await expect(repo.create({ name: 'x' })).rejects.toThrow('Database error: insert fail');
|
|
117
|
+
});
|
|
118
|
+
it('should call handleError when save (entity) throws', async () => {
|
|
119
|
+
repo['repository'].save.mockRejectedValueOnce(new Error('save fail'));
|
|
120
|
+
await expect(repo.save({ id: 1, name: 'x' })).rejects.toThrow('Database error: save fail');
|
|
121
|
+
});
|
|
122
|
+
it('should call handleError when update throws', async () => {
|
|
123
|
+
repo['repository'].update.mockRejectedValueOnce(new Error('update fail'));
|
|
124
|
+
await expect(repo.update({ id: 1 }, { name: 'y' })).rejects.toThrow('Database error: update fail');
|
|
125
|
+
});
|
|
126
|
+
it('should call handleError when delete throws', async () => {
|
|
127
|
+
repo['repository'].delete.mockRejectedValueOnce(new Error('delete fail'));
|
|
128
|
+
await expect(repo.delete({ id: 1 })).rejects.toThrow('Database error: delete fail');
|
|
129
|
+
});
|
|
130
|
+
it('should call handleError when count throws', async () => {
|
|
131
|
+
repo['repository'].count.mockRejectedValueOnce(new Error('count fail'));
|
|
132
|
+
await expect(repo.count({})).rejects.toThrow('Database error: count fail');
|
|
133
|
+
});
|
|
59
134
|
});
|
|
60
135
|
});
|
|
@@ -1,7 +1,41 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
36
|
const typeorm_module_1 = require("./typeorm.module");
|
|
4
37
|
const typeorm_service_1 = require("./typeorm.service");
|
|
38
|
+
const typeorm = __importStar(require("typeorm"));
|
|
5
39
|
describe('TypeOrmModule', () => {
|
|
6
40
|
it('should export TypeOrmModule class', () => {
|
|
7
41
|
expect(typeorm_module_1.TypeOrmModule).toBeDefined();
|
|
@@ -35,8 +69,30 @@ describe('TypeOrmModule', () => {
|
|
|
35
69
|
});
|
|
36
70
|
const provider = result.providers[0];
|
|
37
71
|
expect(provider.useFactory).toBeDefined();
|
|
38
|
-
// useFactory creates DataSource(options) and TypeOrmService; skip calling it to avoid requiring pg driver
|
|
39
72
|
expect(typeof provider.useFactory).toBe('function');
|
|
40
73
|
});
|
|
74
|
+
it('useFactory creates DataSource and TypeOrmService (forRoot body coverage)', async () => {
|
|
75
|
+
const mockDs = {
|
|
76
|
+
isInitialized: false,
|
|
77
|
+
initialize: jest.fn().mockResolvedValue(undefined),
|
|
78
|
+
destroy: jest.fn().mockResolvedValue(undefined),
|
|
79
|
+
getRepository: jest.fn(() => ({})),
|
|
80
|
+
};
|
|
81
|
+
const spy = jest.spyOn(typeorm, 'DataSource').mockImplementation(() => mockDs);
|
|
82
|
+
const result = typeorm_module_1.TypeOrmModule.forRoot({
|
|
83
|
+
type: 'sqlite',
|
|
84
|
+
database: ':memory:',
|
|
85
|
+
synchronize: true,
|
|
86
|
+
});
|
|
87
|
+
const provider = result.providers[0];
|
|
88
|
+
const service = provider.useFactory();
|
|
89
|
+
expect(service).toBeDefined();
|
|
90
|
+
expect(service.ready).toBeDefined();
|
|
91
|
+
await service.ready();
|
|
92
|
+
expect(service.dataSource).toBe(mockDs);
|
|
93
|
+
expect(mockDs.initialize).toHaveBeenCalledTimes(1);
|
|
94
|
+
await service.onModuleDestroy();
|
|
95
|
+
spy.mockRestore();
|
|
96
|
+
});
|
|
41
97
|
});
|
|
42
98
|
});
|
|
@@ -1,5 +1,39 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
const typeorm = __importStar(require("typeorm"));
|
|
3
37
|
const typeorm_service_1 = require("./typeorm.service");
|
|
4
38
|
describe('TypeOrmService', () => {
|
|
5
39
|
describe('with provided DataSource', () => {
|
|
@@ -65,6 +99,57 @@ describe('TypeOrmService', () => {
|
|
|
65
99
|
expect(repo).toBe(mockRepo);
|
|
66
100
|
});
|
|
67
101
|
});
|
|
102
|
+
describe('with options.options (DataSourceOptions)', () => {
|
|
103
|
+
it('creates DataSource from options and initializes', async () => {
|
|
104
|
+
const mockDs = {
|
|
105
|
+
isInitialized: false,
|
|
106
|
+
initialize: jest.fn().mockResolvedValue(undefined),
|
|
107
|
+
destroy: jest.fn().mockResolvedValue(undefined),
|
|
108
|
+
getRepository: jest.fn(() => ({})),
|
|
109
|
+
};
|
|
110
|
+
const spy = jest
|
|
111
|
+
.spyOn(typeorm, 'DataSource')
|
|
112
|
+
.mockImplementation(() => mockDs);
|
|
113
|
+
const service = new typeorm_service_1.TypeOrmService({
|
|
114
|
+
options: {
|
|
115
|
+
type: 'sqlite',
|
|
116
|
+
database: ':memory:',
|
|
117
|
+
synchronize: true,
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
await service.ready();
|
|
121
|
+
expect(service.dataSource).toBe(mockDs);
|
|
122
|
+
expect(mockDs.initialize).toHaveBeenCalledTimes(1);
|
|
123
|
+
spy.mockRestore();
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
describe('when initialize() rejects', () => {
|
|
127
|
+
it('surfaces error from ready() and leaves DataSource uninitialized', async () => {
|
|
128
|
+
const mockDs = {
|
|
129
|
+
isInitialized: false,
|
|
130
|
+
initialize: jest.fn().mockRejectedValue(new Error('connection refused')),
|
|
131
|
+
destroy: jest.fn(),
|
|
132
|
+
getRepository: jest.fn(() => ({})),
|
|
133
|
+
};
|
|
134
|
+
const dataSource = mockDs;
|
|
135
|
+
const service = new typeorm_service_1.TypeOrmService({ dataSource });
|
|
136
|
+
await expect(service.ready()).rejects.toThrow('connection refused');
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
describe('when destroy() throws in onModuleDestroy', () => {
|
|
140
|
+
it('logs and rethrows', async () => {
|
|
141
|
+
const mockDs = {
|
|
142
|
+
isInitialized: true,
|
|
143
|
+
initialize: jest.fn(),
|
|
144
|
+
destroy: jest.fn().mockRejectedValue(new Error('destroy failed')),
|
|
145
|
+
getRepository: jest.fn(() => ({})),
|
|
146
|
+
};
|
|
147
|
+
const dataSource = mockDs;
|
|
148
|
+
const service = new typeorm_service_1.TypeOrmService({ dataSource });
|
|
149
|
+
await service.ready();
|
|
150
|
+
await expect(service.onModuleDestroy()).rejects.toThrow('destroy failed');
|
|
151
|
+
});
|
|
152
|
+
});
|
|
68
153
|
describe('without options or dataSource', () => {
|
|
69
154
|
const origEnv = process.env.DATABASE_URL;
|
|
70
155
|
afterEach(() => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hazeljs/typeorm",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "TypeORM integration for HazelJS framework",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -45,9 +45,9 @@
|
|
|
45
45
|
"bugs": {
|
|
46
46
|
"url": "https://github.com/hazeljs/hazel-js/issues"
|
|
47
47
|
},
|
|
48
|
-
"homepage": "https://hazeljs.
|
|
48
|
+
"homepage": "https://hazeljs.ai",
|
|
49
49
|
"peerDependencies": {
|
|
50
50
|
"@hazeljs/core": ">=0.2.0-beta.0"
|
|
51
51
|
},
|
|
52
|
-
"gitHead": "
|
|
52
|
+
"gitHead": "736a56e3d70b51050608cffae2394de3a3487f20"
|
|
53
53
|
}
|