@loopback/sequelize 0.1.0 → 0.2.0
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 +79 -3
- package/dist/.sandbox/{6646miobBk → 67481g1551m}/controllers/index.js +2 -0
- package/dist/.sandbox/67481g1551m/controllers/product.controller.js +177 -0
- package/dist/.sandbox/{6646miobBk → 67481g1551m}/controllers/test.controller.base.js +9 -7
- package/dist/.sandbox/67481g1551m/controllers/transaction.controller.js +157 -0
- package/dist/.sandbox/67481g1551m/datasources/config.js +43 -0
- package/dist/.sandbox/67481g1551m/datasources/primary.datasource.js +28 -0
- package/dist/.sandbox/67481g1551m/datasources/secondary.datasource.js +28 -0
- package/dist/.sandbox/{6646miobBk → 67481g1551m}/models/index.js +8 -7
- package/dist/.sandbox/67481g1551m/models/product.model.js +41 -0
- package/dist/.sandbox/{6646miobBk → 67481g1551m}/repositories/appointment.repository.js +3 -3
- package/dist/.sandbox/{6646miobBk → 67481g1551m}/repositories/book.repository.js +3 -3
- package/dist/.sandbox/{6646miobBk → 67481g1551m}/repositories/category.repository.js +3 -3
- package/dist/.sandbox/{6646miobBk → 67481g1551m}/repositories/developer.repository.js +3 -3
- package/dist/.sandbox/{6646miobBk → 67481g1551m}/repositories/doctor.repository.js +3 -3
- package/dist/.sandbox/{6646miobBk → 67481g1551m}/repositories/index.js +8 -7
- package/dist/.sandbox/{6646miobBk → 67481g1551m}/repositories/patient.repository.js +3 -3
- package/dist/.sandbox/67481g1551m/repositories/product.repository.js +20 -0
- package/dist/.sandbox/{6646miobBk → 67481g1551m}/repositories/programming-language.repository.js +3 -3
- package/dist/.sandbox/{6646miobBk → 67481g1551m}/repositories/todo-list.repository.js +3 -3
- package/dist/.sandbox/{6646miobBk → 67481g1551m}/repositories/todo.repository.js +3 -3
- package/dist/.sandbox/{6646miobBk → 67481g1551m}/repositories/user.repository.js +3 -7
- package/dist/sequelize/connector-mapping.d.ts +15 -1
- package/dist/sequelize/connector-mapping.js +38 -1
- package/dist/sequelize/connector-mapping.js.map +1 -1
- package/dist/sequelize/sequelize.datasource.base.d.ts +13 -2
- package/dist/sequelize/sequelize.datasource.base.js +79 -26
- package/dist/sequelize/sequelize.datasource.base.js.map +1 -1
- package/dist/sequelize/sequelize.repository.base.d.ts +4 -3
- package/dist/sequelize/sequelize.repository.base.js +12 -7
- package/dist/sequelize/sequelize.repository.base.js.map +1 -1
- package/dist/types.d.ts +4 -0
- package/dist/types.js +6 -1
- package/dist/types.js.map +1 -1
- package/package.json +13 -13
- package/src/sequelize/connector-mapping.ts +53 -1
- package/src/sequelize/sequelize.datasource.base.ts +110 -25
- package/src/sequelize/sequelize.repository.base.ts +22 -8
- package/src/types.ts +5 -0
- package/dist/.sandbox/6646miobBk/datasources/db.datasource.js +0 -28
- /package/dist/.sandbox/{6646miobBk → 67481g1551m}/application.js +0 -0
- /package/dist/.sandbox/{6646miobBk → 67481g1551m}/controllers/book-category.controller.js +0 -0
- /package/dist/.sandbox/{6646miobBk → 67481g1551m}/controllers/book.controller.js +0 -0
- /package/dist/.sandbox/{6646miobBk → 67481g1551m}/controllers/category.controller.js +0 -0
- /package/dist/.sandbox/{6646miobBk → 67481g1551m}/controllers/developer.controller.js +0 -0
- /package/dist/.sandbox/{6646miobBk → 67481g1551m}/controllers/doctor-patient.controller.js +0 -0
- /package/dist/.sandbox/{6646miobBk → 67481g1551m}/controllers/doctor.controller.js +0 -0
- /package/dist/.sandbox/{6646miobBk → 67481g1551m}/controllers/patient.controller.js +0 -0
- /package/dist/.sandbox/{6646miobBk → 67481g1551m}/controllers/programming-languange.controller.js +0 -0
- /package/dist/.sandbox/{6646miobBk → 67481g1551m}/controllers/todo-list-todo.controller.js +0 -0
- /package/dist/.sandbox/{6646miobBk → 67481g1551m}/controllers/todo-list.controller.js +0 -0
- /package/dist/.sandbox/{6646miobBk → 67481g1551m}/controllers/todo-todo-list.controller.js +0 -0
- /package/dist/.sandbox/{6646miobBk → 67481g1551m}/controllers/todo.controller.js +0 -0
- /package/dist/.sandbox/{6646miobBk → 67481g1551m}/controllers/user-todo-list.controller.js +0 -0
- /package/dist/.sandbox/{6646miobBk → 67481g1551m}/controllers/user.controller.js +0 -0
- /package/dist/.sandbox/{6646miobBk → 67481g1551m}/models/appointment.model.js +0 -0
- /package/dist/.sandbox/{6646miobBk → 67481g1551m}/models/book.model.js +0 -0
- /package/dist/.sandbox/{6646miobBk → 67481g1551m}/models/category.model.js +0 -0
- /package/dist/.sandbox/{6646miobBk → 67481g1551m}/models/developer.model.js +0 -0
- /package/dist/.sandbox/{6646miobBk → 67481g1551m}/models/doctor.model.js +0 -0
- /package/dist/.sandbox/{6646miobBk → 67481g1551m}/models/patient.model.js +0 -0
- /package/dist/.sandbox/{6646miobBk → 67481g1551m}/models/programming-language.model.js +0 -0
- /package/dist/.sandbox/{6646miobBk → 67481g1551m}/models/todo-list.model.js +0 -0
- /package/dist/.sandbox/{6646miobBk → 67481g1551m}/models/todo.model.js +0 -0
- /package/dist/.sandbox/{6646miobBk → 67481g1551m}/models/user.model.js +0 -0
package/README.md
CHANGED
|
@@ -128,6 +128,84 @@ contains "Art" in their title, which belongs to category "Programming":
|
|
|
128
128
|
}
|
|
129
129
|
```
|
|
130
130
|
|
|
131
|
+
## SQL Transactions
|
|
132
|
+
|
|
133
|
+
A Sequelize repository can perform operations in a transaction using the
|
|
134
|
+
`beginTransaction()` method.
|
|
135
|
+
|
|
136
|
+
### Isolation levels
|
|
137
|
+
|
|
138
|
+
When you call `beginTransaction()`, you can optionally specify a transaction
|
|
139
|
+
isolation level. It support the following isolation levels:
|
|
140
|
+
|
|
141
|
+
- `Transaction.ISOLATION_LEVELS.READ_UNCOMMITTED` (default)
|
|
142
|
+
- `Transaction.ISOLATION_LEVELS.READ_COMMITTED`
|
|
143
|
+
- `Transaction.ISOLATION_LEVELS.REPEATABLE_READ`
|
|
144
|
+
- `Transaction.ISOLATION_LEVELS.SERIALIZABLE`
|
|
145
|
+
|
|
146
|
+
### Options
|
|
147
|
+
|
|
148
|
+
Following are the supported options:
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
{
|
|
152
|
+
autocommit?: boolean;
|
|
153
|
+
isolationLevel?: Transaction.ISOLATION_LEVELS;
|
|
154
|
+
type?: Transaction.TYPES;
|
|
155
|
+
deferrable?: string | Deferrable;
|
|
156
|
+
/**
|
|
157
|
+
* Parent transaction.
|
|
158
|
+
*/
|
|
159
|
+
transaction?: Transaction | null;
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Example
|
|
164
|
+
|
|
165
|
+
```ts
|
|
166
|
+
// Get repository instances. In a typical application, instances are injected
|
|
167
|
+
// via dependency injection using `@repository` decorator.
|
|
168
|
+
const userRepo = await app.getRepository(UserRepository);
|
|
169
|
+
|
|
170
|
+
// Begin a new transaction.
|
|
171
|
+
// It's also possible to call `userRepo.dataSource.beginTransaction` instead.
|
|
172
|
+
const tx = await userRepo.beginTransaction({
|
|
173
|
+
isolationLevel: Transaction.ISOLATION_LEVELS.SERIALIZABLE,
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
try {
|
|
177
|
+
// Then, we do some calls passing this transaction as an option:
|
|
178
|
+
const user = await userRepo.create(
|
|
179
|
+
{
|
|
180
|
+
firstName: 'Jon',
|
|
181
|
+
lastName: 'Doe',
|
|
182
|
+
},
|
|
183
|
+
{transaction: tx},
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
await userRepo.updateById(
|
|
187
|
+
user.id,
|
|
188
|
+
{
|
|
189
|
+
firstName: 'John',
|
|
190
|
+
},
|
|
191
|
+
{transaction: tx},
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
// If the execution reaches this line, no errors were thrown.
|
|
195
|
+
// We commit the transaction.
|
|
196
|
+
await tx.commit();
|
|
197
|
+
} catch (error) {
|
|
198
|
+
// If the execution reaches this line, an error was thrown.
|
|
199
|
+
// We rollback the transaction.
|
|
200
|
+
await tx.rollback();
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Switching from loopback defaults to sequelize transaction is as simple as
|
|
205
|
+
[this commit](https://github.com/shubhamp-sf/loopback4-sequelize-transaction-example/commit/321791c93ffd10c3af13e8b891396ae99b632a23)
|
|
206
|
+
in
|
|
207
|
+
[loopback4-sequelize-transaction-example](https://github.com/shubhamp-sf/loopback4-sequelize-transaction-example).
|
|
208
|
+
|
|
131
209
|
<!-- tutorial-end -->
|
|
132
210
|
|
|
133
211
|
## Debug strings reference
|
|
@@ -167,11 +245,9 @@ debugging. To learn more about how to use them, see
|
|
|
167
245
|
|
|
168
246
|
Please note, the current implementation does not support the following:
|
|
169
247
|
|
|
170
|
-
1.
|
|
171
|
-
2. Loopback Migrations (via default `migrate.ts`). Though you're good if using
|
|
248
|
+
1. Loopback Migrations (via default `migrate.ts`). Though you're good if using
|
|
172
249
|
external packages like
|
|
173
250
|
[`db-migrate`](https://www.npmjs.com/package/db-migrate).
|
|
174
|
-
3. Connection Pooling is not implemented yet.
|
|
175
251
|
|
|
176
252
|
Community contribution is welcome.
|
|
177
253
|
|
|
@@ -8,12 +8,14 @@ tslib_1.__exportStar(require("./developer.controller"), exports);
|
|
|
8
8
|
tslib_1.__exportStar(require("./doctor-patient.controller"), exports);
|
|
9
9
|
tslib_1.__exportStar(require("./doctor.controller"), exports);
|
|
10
10
|
tslib_1.__exportStar(require("./patient.controller"), exports);
|
|
11
|
+
tslib_1.__exportStar(require("./product.controller"), exports);
|
|
11
12
|
tslib_1.__exportStar(require("./programming-languange.controller"), exports);
|
|
12
13
|
tslib_1.__exportStar(require("./test.controller.base"), exports);
|
|
13
14
|
tslib_1.__exportStar(require("./todo-list-todo.controller"), exports);
|
|
14
15
|
tslib_1.__exportStar(require("./todo-list.controller"), exports);
|
|
15
16
|
tslib_1.__exportStar(require("./todo-todo-list.controller"), exports);
|
|
16
17
|
tslib_1.__exportStar(require("./todo.controller"), exports);
|
|
18
|
+
tslib_1.__exportStar(require("./transaction.controller"), exports);
|
|
17
19
|
tslib_1.__exportStar(require("./user-todo-list.controller"), exports);
|
|
18
20
|
tslib_1.__exportStar(require("./user.controller"), exports);
|
|
19
21
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ProductController = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const repository_1 = require("@loopback/repository");
|
|
6
|
+
const rest_1 = require("@loopback/rest");
|
|
7
|
+
const models_1 = require("../models");
|
|
8
|
+
const repositories_1 = require("../repositories");
|
|
9
|
+
const test_controller_base_1 = require("./test.controller.base");
|
|
10
|
+
let ProductController = class ProductController extends test_controller_base_1.TestControllerBase {
|
|
11
|
+
constructor(productRepository) {
|
|
12
|
+
super(productRepository);
|
|
13
|
+
this.productRepository = productRepository;
|
|
14
|
+
}
|
|
15
|
+
async create(product) {
|
|
16
|
+
return this.productRepository.create(product);
|
|
17
|
+
}
|
|
18
|
+
async count(where) {
|
|
19
|
+
return this.productRepository.count(where);
|
|
20
|
+
}
|
|
21
|
+
async find(filter) {
|
|
22
|
+
return this.productRepository.find(filter);
|
|
23
|
+
}
|
|
24
|
+
async updateAll(product, where) {
|
|
25
|
+
return this.productRepository.updateAll(product, where);
|
|
26
|
+
}
|
|
27
|
+
async findById(id, filter) {
|
|
28
|
+
return this.productRepository.findById(id, filter);
|
|
29
|
+
}
|
|
30
|
+
async updateById(id, product) {
|
|
31
|
+
await this.productRepository.updateById(id, product);
|
|
32
|
+
}
|
|
33
|
+
async replaceById(id, product) {
|
|
34
|
+
await this.productRepository.replaceById(id, product);
|
|
35
|
+
}
|
|
36
|
+
async deleteById(id) {
|
|
37
|
+
await this.productRepository.deleteById(id);
|
|
38
|
+
}
|
|
39
|
+
async syncSequelizeModel() {
|
|
40
|
+
await this.beforeEach();
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
tslib_1.__decorate([
|
|
44
|
+
(0, rest_1.post)('/products'),
|
|
45
|
+
(0, rest_1.response)(200, {
|
|
46
|
+
description: 'Product model instance',
|
|
47
|
+
content: { 'application/json': { schema: (0, rest_1.getModelSchemaRef)(models_1.Product) } },
|
|
48
|
+
}),
|
|
49
|
+
tslib_1.__param(0, (0, rest_1.requestBody)({
|
|
50
|
+
content: {
|
|
51
|
+
'application/json': {
|
|
52
|
+
schema: (0, rest_1.getModelSchemaRef)(models_1.Product, {
|
|
53
|
+
title: 'NewProduct',
|
|
54
|
+
exclude: ['id'],
|
|
55
|
+
}),
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
})),
|
|
59
|
+
tslib_1.__metadata("design:type", Function),
|
|
60
|
+
tslib_1.__metadata("design:paramtypes", [Object]),
|
|
61
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
62
|
+
], ProductController.prototype, "create", null);
|
|
63
|
+
tslib_1.__decorate([
|
|
64
|
+
(0, rest_1.get)('/products/count'),
|
|
65
|
+
(0, rest_1.response)(200, {
|
|
66
|
+
description: 'Product model count',
|
|
67
|
+
content: { 'application/json': { schema: repository_1.CountSchema } },
|
|
68
|
+
}),
|
|
69
|
+
tslib_1.__param(0, rest_1.param.where(models_1.Product)),
|
|
70
|
+
tslib_1.__metadata("design:type", Function),
|
|
71
|
+
tslib_1.__metadata("design:paramtypes", [Object]),
|
|
72
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
73
|
+
], ProductController.prototype, "count", null);
|
|
74
|
+
tslib_1.__decorate([
|
|
75
|
+
(0, rest_1.get)('/products'),
|
|
76
|
+
(0, rest_1.response)(200, {
|
|
77
|
+
description: 'Array of Product model instances',
|
|
78
|
+
content: {
|
|
79
|
+
'application/json': {
|
|
80
|
+
schema: {
|
|
81
|
+
type: 'array',
|
|
82
|
+
items: (0, rest_1.getModelSchemaRef)(models_1.Product, { includeRelations: true }),
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
}),
|
|
87
|
+
tslib_1.__param(0, rest_1.param.filter(models_1.Product)),
|
|
88
|
+
tslib_1.__metadata("design:type", Function),
|
|
89
|
+
tslib_1.__metadata("design:paramtypes", [Object]),
|
|
90
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
91
|
+
], ProductController.prototype, "find", null);
|
|
92
|
+
tslib_1.__decorate([
|
|
93
|
+
(0, rest_1.patch)('/products'),
|
|
94
|
+
(0, rest_1.response)(200, {
|
|
95
|
+
description: 'Product PATCH success count',
|
|
96
|
+
content: { 'application/json': { schema: repository_1.CountSchema } },
|
|
97
|
+
}),
|
|
98
|
+
tslib_1.__param(0, (0, rest_1.requestBody)({
|
|
99
|
+
content: {
|
|
100
|
+
'application/json': {
|
|
101
|
+
schema: (0, rest_1.getModelSchemaRef)(models_1.Product, { partial: true }),
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
})),
|
|
105
|
+
tslib_1.__param(1, rest_1.param.where(models_1.Product)),
|
|
106
|
+
tslib_1.__metadata("design:type", Function),
|
|
107
|
+
tslib_1.__metadata("design:paramtypes", [models_1.Product, Object]),
|
|
108
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
109
|
+
], ProductController.prototype, "updateAll", null);
|
|
110
|
+
tslib_1.__decorate([
|
|
111
|
+
(0, rest_1.get)('/products/{id}'),
|
|
112
|
+
(0, rest_1.response)(200, {
|
|
113
|
+
description: 'Product model instance',
|
|
114
|
+
content: {
|
|
115
|
+
'application/json': {
|
|
116
|
+
schema: (0, rest_1.getModelSchemaRef)(models_1.Product, { includeRelations: true }),
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
}),
|
|
120
|
+
tslib_1.__param(0, rest_1.param.path.number('id')),
|
|
121
|
+
tslib_1.__param(1, rest_1.param.filter(models_1.Product, { exclude: 'where' })),
|
|
122
|
+
tslib_1.__metadata("design:type", Function),
|
|
123
|
+
tslib_1.__metadata("design:paramtypes", [Number, Object]),
|
|
124
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
125
|
+
], ProductController.prototype, "findById", null);
|
|
126
|
+
tslib_1.__decorate([
|
|
127
|
+
(0, rest_1.patch)('/products/{id}'),
|
|
128
|
+
(0, rest_1.response)(204, {
|
|
129
|
+
description: 'Product PATCH success',
|
|
130
|
+
}),
|
|
131
|
+
tslib_1.__param(0, rest_1.param.path.number('id')),
|
|
132
|
+
tslib_1.__param(1, (0, rest_1.requestBody)({
|
|
133
|
+
content: {
|
|
134
|
+
'application/json': {
|
|
135
|
+
schema: (0, rest_1.getModelSchemaRef)(models_1.Product, { partial: true }),
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
})),
|
|
139
|
+
tslib_1.__metadata("design:type", Function),
|
|
140
|
+
tslib_1.__metadata("design:paramtypes", [Number, models_1.Product]),
|
|
141
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
142
|
+
], ProductController.prototype, "updateById", null);
|
|
143
|
+
tslib_1.__decorate([
|
|
144
|
+
(0, rest_1.put)('/products/{id}'),
|
|
145
|
+
(0, rest_1.response)(204, {
|
|
146
|
+
description: 'Product PUT success',
|
|
147
|
+
}),
|
|
148
|
+
tslib_1.__param(0, rest_1.param.path.number('id')),
|
|
149
|
+
tslib_1.__param(1, (0, rest_1.requestBody)()),
|
|
150
|
+
tslib_1.__metadata("design:type", Function),
|
|
151
|
+
tslib_1.__metadata("design:paramtypes", [Number, models_1.Product]),
|
|
152
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
153
|
+
], ProductController.prototype, "replaceById", null);
|
|
154
|
+
tslib_1.__decorate([
|
|
155
|
+
(0, rest_1.del)('/products/{id}'),
|
|
156
|
+
(0, rest_1.response)(204, {
|
|
157
|
+
description: 'Product DELETE success',
|
|
158
|
+
}),
|
|
159
|
+
tslib_1.__param(0, rest_1.param.path.number('id')),
|
|
160
|
+
tslib_1.__metadata("design:type", Function),
|
|
161
|
+
tslib_1.__metadata("design:paramtypes", [Number]),
|
|
162
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
163
|
+
], ProductController.prototype, "deleteById", null);
|
|
164
|
+
tslib_1.__decorate([
|
|
165
|
+
(0, rest_1.get)('/products/sync-sequelize-model'),
|
|
166
|
+
(0, rest_1.response)(200),
|
|
167
|
+
tslib_1.__metadata("design:type", Function),
|
|
168
|
+
tslib_1.__metadata("design:paramtypes", []),
|
|
169
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
170
|
+
], ProductController.prototype, "syncSequelizeModel", null);
|
|
171
|
+
ProductController = tslib_1.__decorate([
|
|
172
|
+
tslib_1.__param(0, (0, repository_1.repository)(repositories_1.ProductRepository)),
|
|
173
|
+
tslib_1.__metadata("design:paramtypes", [repositories_1.ProductRepository])
|
|
174
|
+
], ProductController);
|
|
175
|
+
exports.ProductController = ProductController;
|
|
176
|
+
//# sourceMappingURL=product.controller.js.map
|
|
177
|
+
//# sourceMappingURL=/Users/dianalau/code/loopback/loopback-next/extensions/sequelize/dist/__tests__/fixtures/controllers/product.controller.js.map
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.TestControllerBase = void 0;
|
|
4
4
|
class TestControllerBase {
|
|
5
|
-
constructor(
|
|
6
|
-
this.
|
|
5
|
+
constructor(...repositories) {
|
|
6
|
+
this.repositories = repositories;
|
|
7
7
|
}
|
|
8
8
|
/**
|
|
9
9
|
* `beforeEach` is only for testing purposes in the controller,
|
|
@@ -12,12 +12,14 @@ class TestControllerBase {
|
|
|
12
12
|
* to run migrations instead, to sync model definitions to the target database.
|
|
13
13
|
*/
|
|
14
14
|
async beforeEach(options = {}) {
|
|
15
|
-
const syncOptions = { force:
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
const syncOptions = { force: true };
|
|
16
|
+
for (const repository of this.repositories) {
|
|
17
|
+
if (options.syncAll) {
|
|
18
|
+
await repository.syncLoadedSequelizeModels(syncOptions);
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
await repository.syncSequelizeModel(syncOptions);
|
|
19
22
|
}
|
|
20
|
-
await this.repository.syncSequelizeModel(syncOptions);
|
|
21
23
|
}
|
|
22
24
|
}
|
|
23
25
|
exports.TestControllerBase = TestControllerBase;
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TransactionController = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const repository_1 = require("@loopback/repository");
|
|
6
|
+
const rest_1 = require("@loopback/rest");
|
|
7
|
+
const models_1 = require("../models");
|
|
8
|
+
const repositories_1 = require("../repositories");
|
|
9
|
+
const types_1 = require("./../../../types");
|
|
10
|
+
const test_controller_base_1 = require("./test.controller.base");
|
|
11
|
+
let TransactionController = class TransactionController extends test_controller_base_1.TestControllerBase {
|
|
12
|
+
constructor(todoListRepository, productRepository) {
|
|
13
|
+
super(todoListRepository, productRepository);
|
|
14
|
+
this.todoListRepository = todoListRepository;
|
|
15
|
+
this.productRepository = productRepository;
|
|
16
|
+
}
|
|
17
|
+
// create todo-list entry using transaction
|
|
18
|
+
async ensureTransactionCommit(todoList) {
|
|
19
|
+
const tx = await this.todoListRepository.beginTransaction({
|
|
20
|
+
isolationLevel: types_1.Transaction.ISOLATION_LEVELS.SERIALIZABLE,
|
|
21
|
+
});
|
|
22
|
+
try {
|
|
23
|
+
const created = await this.todoListRepository.create(todoList, {
|
|
24
|
+
transaction: tx,
|
|
25
|
+
});
|
|
26
|
+
await tx.commit();
|
|
27
|
+
return created;
|
|
28
|
+
}
|
|
29
|
+
catch (err) {
|
|
30
|
+
await tx.rollback();
|
|
31
|
+
throw err;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
// create todo-list entry using transaction but rollback
|
|
35
|
+
async ensureRollback(todoList) {
|
|
36
|
+
const tx = await this.todoListRepository.beginTransaction({
|
|
37
|
+
isolationLevel: types_1.Transaction.ISOLATION_LEVELS.READ_COMMITTED,
|
|
38
|
+
});
|
|
39
|
+
const created = await this.todoListRepository.create(todoList, {
|
|
40
|
+
transaction: tx,
|
|
41
|
+
});
|
|
42
|
+
await tx.rollback();
|
|
43
|
+
// In real applications if you're rolling back. Don't return created entities to user
|
|
44
|
+
// For test cases it's required here. (to get the id)
|
|
45
|
+
return created;
|
|
46
|
+
}
|
|
47
|
+
// create todo-list entry using transaction but don't commit or rollback
|
|
48
|
+
async ensureIsolatedTransaction(todoList) {
|
|
49
|
+
const tx = await this.todoListRepository.beginTransaction({
|
|
50
|
+
isolationLevel: types_1.Transaction.ISOLATION_LEVELS.READ_COMMITTED,
|
|
51
|
+
});
|
|
52
|
+
const created = await this.todoListRepository.create(todoList, {
|
|
53
|
+
transaction: tx,
|
|
54
|
+
});
|
|
55
|
+
let err = {};
|
|
56
|
+
// reading before commit in READ_COMMITED level should not find the entity
|
|
57
|
+
const findBeforeCommit = await this.todoListRepository
|
|
58
|
+
.findById(created.id)
|
|
59
|
+
.catch(e => (err = e));
|
|
60
|
+
await tx.commit();
|
|
61
|
+
// throwing it after commit to avoid deadlocks
|
|
62
|
+
if (err) {
|
|
63
|
+
throw err;
|
|
64
|
+
}
|
|
65
|
+
return findBeforeCommit;
|
|
66
|
+
}
|
|
67
|
+
async ensureLocalTransactions() {
|
|
68
|
+
// "Todo List" model is from Primary Datasource
|
|
69
|
+
// and "AnyObject" model is from Secondary Datasource
|
|
70
|
+
// this test case is to ensure transaction created on
|
|
71
|
+
// one datasource can't be used in another
|
|
72
|
+
const tx = await this.todoListRepository.beginTransaction({
|
|
73
|
+
isolationLevel: types_1.Transaction.ISOLATION_LEVELS.SERIALIZABLE,
|
|
74
|
+
});
|
|
75
|
+
let err = null;
|
|
76
|
+
try {
|
|
77
|
+
await this.productRepository.create({
|
|
78
|
+
name: 'phone',
|
|
79
|
+
price: 5000,
|
|
80
|
+
}, {
|
|
81
|
+
transaction: tx,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
catch (e) {
|
|
85
|
+
err = e;
|
|
86
|
+
}
|
|
87
|
+
await tx.commit();
|
|
88
|
+
if (err) {
|
|
89
|
+
throw new rest_1.HttpErrors[406](err.message);
|
|
90
|
+
}
|
|
91
|
+
// Won't reach till here if test passes
|
|
92
|
+
throw new rest_1.HttpErrors[406]('Product created with non-local transaction.');
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
tslib_1.__decorate([
|
|
96
|
+
(0, rest_1.post)('/transactions/todo-lists/commit'),
|
|
97
|
+
tslib_1.__param(0, (0, rest_1.requestBody)({
|
|
98
|
+
content: {
|
|
99
|
+
'application/json': {
|
|
100
|
+
schema: (0, rest_1.getModelSchemaRef)(models_1.TodoList, {
|
|
101
|
+
title: 'NewTodoList',
|
|
102
|
+
exclude: ['id'],
|
|
103
|
+
}),
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
})),
|
|
107
|
+
tslib_1.__metadata("design:type", Function),
|
|
108
|
+
tslib_1.__metadata("design:paramtypes", [Object]),
|
|
109
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
110
|
+
], TransactionController.prototype, "ensureTransactionCommit", null);
|
|
111
|
+
tslib_1.__decorate([
|
|
112
|
+
(0, rest_1.post)('/transactions/todo-lists/rollback'),
|
|
113
|
+
tslib_1.__param(0, (0, rest_1.requestBody)({
|
|
114
|
+
content: {
|
|
115
|
+
'application/json': {
|
|
116
|
+
schema: (0, rest_1.getModelSchemaRef)(models_1.TodoList, {
|
|
117
|
+
title: 'NewTodoList',
|
|
118
|
+
exclude: ['id'],
|
|
119
|
+
}),
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
})),
|
|
123
|
+
tslib_1.__metadata("design:type", Function),
|
|
124
|
+
tslib_1.__metadata("design:paramtypes", [Object]),
|
|
125
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
126
|
+
], TransactionController.prototype, "ensureRollback", null);
|
|
127
|
+
tslib_1.__decorate([
|
|
128
|
+
(0, rest_1.post)('/transactions/todo-lists/isolation/read_commited'),
|
|
129
|
+
tslib_1.__param(0, (0, rest_1.requestBody)({
|
|
130
|
+
content: {
|
|
131
|
+
'application/json': {
|
|
132
|
+
schema: (0, rest_1.getModelSchemaRef)(models_1.TodoList, {
|
|
133
|
+
title: 'NewTodoList',
|
|
134
|
+
exclude: ['id'],
|
|
135
|
+
}),
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
})),
|
|
139
|
+
tslib_1.__metadata("design:type", Function),
|
|
140
|
+
tslib_1.__metadata("design:paramtypes", [Object]),
|
|
141
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
142
|
+
], TransactionController.prototype, "ensureIsolatedTransaction", null);
|
|
143
|
+
tslib_1.__decorate([
|
|
144
|
+
(0, rest_1.get)('/transactions/ensure-local'),
|
|
145
|
+
tslib_1.__metadata("design:type", Function),
|
|
146
|
+
tslib_1.__metadata("design:paramtypes", []),
|
|
147
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
148
|
+
], TransactionController.prototype, "ensureLocalTransactions", null);
|
|
149
|
+
TransactionController = tslib_1.__decorate([
|
|
150
|
+
tslib_1.__param(0, (0, repository_1.repository)(repositories_1.TodoListRepository)),
|
|
151
|
+
tslib_1.__param(1, (0, repository_1.repository)(repositories_1.ProductRepository)),
|
|
152
|
+
tslib_1.__metadata("design:paramtypes", [repositories_1.TodoListRepository,
|
|
153
|
+
repositories_1.ProductRepository])
|
|
154
|
+
], TransactionController);
|
|
155
|
+
exports.TransactionController = TransactionController;
|
|
156
|
+
//# sourceMappingURL=transaction.controller.js.map
|
|
157
|
+
//# sourceMappingURL=/Users/dianalau/code/loopback/loopback-next/extensions/sequelize/dist/__tests__/fixtures/controllers/transaction.controller.js.map
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.datasourceTestConfig = void 0;
|
|
4
|
+
exports.datasourceTestConfig = {
|
|
5
|
+
primary: {
|
|
6
|
+
postgresql: {
|
|
7
|
+
name: 'primary',
|
|
8
|
+
connector: 'postgresql',
|
|
9
|
+
host: 'localhost',
|
|
10
|
+
port: 5001,
|
|
11
|
+
user: 'postgres',
|
|
12
|
+
password: 'super-secret',
|
|
13
|
+
database: 'postgres',
|
|
14
|
+
},
|
|
15
|
+
sqlite3: {
|
|
16
|
+
name: 'primary',
|
|
17
|
+
host: '0.0.0.0',
|
|
18
|
+
connector: 'sqlite3',
|
|
19
|
+
database: 'transaction-primary',
|
|
20
|
+
file: ':memory:',
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
secondary: {
|
|
24
|
+
postgresql: {
|
|
25
|
+
name: 'secondary',
|
|
26
|
+
connector: 'postgresql',
|
|
27
|
+
host: 'localhost',
|
|
28
|
+
port: 5002,
|
|
29
|
+
user: 'postgres',
|
|
30
|
+
password: 'super-secret',
|
|
31
|
+
database: 'postgres',
|
|
32
|
+
},
|
|
33
|
+
sqlite3: {
|
|
34
|
+
name: 'secondary',
|
|
35
|
+
host: '0.0.0.0',
|
|
36
|
+
connector: 'sqlite3',
|
|
37
|
+
database: 'transaction-secondary',
|
|
38
|
+
file: ':memory:',
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
//# sourceMappingURL=config.js.map
|
|
43
|
+
//# sourceMappingURL=/Users/dianalau/code/loopback/loopback-next/extensions/sequelize/dist/__tests__/fixtures/datasources/config.js.map
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PrimaryDataSource = exports.config = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const core_1 = require("@loopback/core");
|
|
6
|
+
const sequelize_1 = require("../../../sequelize");
|
|
7
|
+
const config_1 = require("./config");
|
|
8
|
+
// DEVELOPMENT NOTE:
|
|
9
|
+
// "Few Test cases for database transaction features won't work for in-memory
|
|
10
|
+
// database configuration like sqlite3, change this to postgresql while developing to run
|
|
11
|
+
// all test cases of transactional repo including those of isolation levels.
|
|
12
|
+
// but ensure it's set to sqlite3 before commiting changes."
|
|
13
|
+
exports.config = config_1.datasourceTestConfig['primary']['sqlite3'];
|
|
14
|
+
let PrimaryDataSource = class PrimaryDataSource extends sequelize_1.SequelizeDataSource {
|
|
15
|
+
constructor(dsConfig = exports.config) {
|
|
16
|
+
super(dsConfig);
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
PrimaryDataSource.dataSourceName = 'primary';
|
|
20
|
+
PrimaryDataSource.defaultConfig = exports.config;
|
|
21
|
+
PrimaryDataSource = tslib_1.__decorate([
|
|
22
|
+
(0, core_1.lifeCycleObserver)('datasource'),
|
|
23
|
+
tslib_1.__param(0, (0, core_1.inject)('datasources.config.primary', { optional: true })),
|
|
24
|
+
tslib_1.__metadata("design:paramtypes", [Object])
|
|
25
|
+
], PrimaryDataSource);
|
|
26
|
+
exports.PrimaryDataSource = PrimaryDataSource;
|
|
27
|
+
//# sourceMappingURL=primary.datasource.js.map
|
|
28
|
+
//# sourceMappingURL=/Users/dianalau/code/loopback/loopback-next/extensions/sequelize/dist/__tests__/fixtures/datasources/primary.datasource.js.map
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SecondaryDataSource = exports.config = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const core_1 = require("@loopback/core");
|
|
6
|
+
const sequelize_1 = require("../../../sequelize");
|
|
7
|
+
const config_1 = require("./config");
|
|
8
|
+
// DEVELOPMENT NOTE:
|
|
9
|
+
// "Few Test cases for database transaction features won't work for in-memory
|
|
10
|
+
// database configuration like sqlite3, change this to postgresql while developing to run
|
|
11
|
+
// all test cases of transactional repo including those of isolation levels.
|
|
12
|
+
// but ensure it's set to sqlite3 before commiting changes."
|
|
13
|
+
exports.config = config_1.datasourceTestConfig['secondary']['sqlite3'];
|
|
14
|
+
let SecondaryDataSource = class SecondaryDataSource extends sequelize_1.SequelizeDataSource {
|
|
15
|
+
constructor(dsConfig = exports.config) {
|
|
16
|
+
super(dsConfig);
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
SecondaryDataSource.dataSourceName = 'secondary';
|
|
20
|
+
SecondaryDataSource.defaultConfig = exports.config;
|
|
21
|
+
SecondaryDataSource = tslib_1.__decorate([
|
|
22
|
+
(0, core_1.lifeCycleObserver)('datasource'),
|
|
23
|
+
tslib_1.__param(0, (0, core_1.inject)('datasources.config.secondary', { optional: true })),
|
|
24
|
+
tslib_1.__metadata("design:paramtypes", [Object])
|
|
25
|
+
], SecondaryDataSource);
|
|
26
|
+
exports.SecondaryDataSource = SecondaryDataSource;
|
|
27
|
+
//# sourceMappingURL=secondary.datasource.js.map
|
|
28
|
+
//# sourceMappingURL=/Users/dianalau/code/loopback/loopback-next/extensions/sequelize/dist/__tests__/fixtures/datasources/secondary.datasource.js.map
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
|
-
tslib_1.__exportStar(require("./todo.model"), exports);
|
|
5
|
-
tslib_1.__exportStar(require("./todo-list.model"), exports);
|
|
6
|
-
tslib_1.__exportStar(require("./user.model"), exports);
|
|
7
|
-
tslib_1.__exportStar(require("./doctor.model"), exports);
|
|
8
|
-
tslib_1.__exportStar(require("./patient.model"), exports);
|
|
9
4
|
tslib_1.__exportStar(require("./appointment.model"), exports);
|
|
10
|
-
tslib_1.__exportStar(require("./programming-language.model"), exports);
|
|
11
|
-
tslib_1.__exportStar(require("./developer.model"), exports);
|
|
12
5
|
tslib_1.__exportStar(require("./book.model"), exports);
|
|
13
6
|
tslib_1.__exportStar(require("./category.model"), exports);
|
|
7
|
+
tslib_1.__exportStar(require("./developer.model"), exports);
|
|
8
|
+
tslib_1.__exportStar(require("./doctor.model"), exports);
|
|
9
|
+
tslib_1.__exportStar(require("./patient.model"), exports);
|
|
10
|
+
tslib_1.__exportStar(require("./product.model"), exports);
|
|
11
|
+
tslib_1.__exportStar(require("./programming-language.model"), exports);
|
|
12
|
+
tslib_1.__exportStar(require("./todo-list.model"), exports);
|
|
13
|
+
tslib_1.__exportStar(require("./todo.model"), exports);
|
|
14
|
+
tslib_1.__exportStar(require("./user.model"), exports);
|
|
14
15
|
//# sourceMappingURL=index.js.map
|
|
15
16
|
//# sourceMappingURL=/Users/dianalau/code/loopback/loopback-next/extensions/sequelize/dist/__tests__/fixtures/models/index.js.map
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Product = exports.TableInSecondaryDB = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const repository_1 = require("@loopback/repository");
|
|
6
|
+
exports.TableInSecondaryDB = 'products';
|
|
7
|
+
let Product = class Product extends repository_1.Entity {
|
|
8
|
+
constructor(data) {
|
|
9
|
+
super(data);
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
tslib_1.__decorate([
|
|
13
|
+
(0, repository_1.property)({
|
|
14
|
+
type: 'number',
|
|
15
|
+
id: true,
|
|
16
|
+
generated: true,
|
|
17
|
+
}),
|
|
18
|
+
tslib_1.__metadata("design:type", Number)
|
|
19
|
+
], Product.prototype, "id", void 0);
|
|
20
|
+
tslib_1.__decorate([
|
|
21
|
+
(0, repository_1.property)({
|
|
22
|
+
type: 'string',
|
|
23
|
+
required: true,
|
|
24
|
+
}),
|
|
25
|
+
tslib_1.__metadata("design:type", String)
|
|
26
|
+
], Product.prototype, "name", void 0);
|
|
27
|
+
tslib_1.__decorate([
|
|
28
|
+
(0, repository_1.property)({
|
|
29
|
+
type: 'number',
|
|
30
|
+
}),
|
|
31
|
+
tslib_1.__metadata("design:type", Number)
|
|
32
|
+
], Product.prototype, "price", void 0);
|
|
33
|
+
Product = tslib_1.__decorate([
|
|
34
|
+
(0, repository_1.model)({
|
|
35
|
+
name: exports.TableInSecondaryDB,
|
|
36
|
+
}),
|
|
37
|
+
tslib_1.__metadata("design:paramtypes", [Object])
|
|
38
|
+
], Product);
|
|
39
|
+
exports.Product = Product;
|
|
40
|
+
//# sourceMappingURL=product.model.js.map
|
|
41
|
+
//# sourceMappingURL=/Users/dianalau/code/loopback/loopback-next/extensions/sequelize/dist/__tests__/fixtures/models/product.model.js.map
|
|
@@ -4,7 +4,7 @@ exports.AppointmentRepository = void 0;
|
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const core_1 = require("@loopback/core");
|
|
6
6
|
const sequelize_1 = require("../../../sequelize");
|
|
7
|
-
const
|
|
7
|
+
const primary_datasource_1 = require("../datasources/primary.datasource");
|
|
8
8
|
const index_1 = require("../models/index");
|
|
9
9
|
let AppointmentRepository = class AppointmentRepository extends sequelize_1.SequelizeCrudRepository {
|
|
10
10
|
constructor(dataSource) {
|
|
@@ -12,8 +12,8 @@ let AppointmentRepository = class AppointmentRepository extends sequelize_1.Sequ
|
|
|
12
12
|
}
|
|
13
13
|
};
|
|
14
14
|
AppointmentRepository = tslib_1.__decorate([
|
|
15
|
-
tslib_1.__param(0, (0, core_1.inject)('datasources.
|
|
16
|
-
tslib_1.__metadata("design:paramtypes", [
|
|
15
|
+
tslib_1.__param(0, (0, core_1.inject)('datasources.primary')),
|
|
16
|
+
tslib_1.__metadata("design:paramtypes", [primary_datasource_1.PrimaryDataSource])
|
|
17
17
|
], AppointmentRepository);
|
|
18
18
|
exports.AppointmentRepository = AppointmentRepository;
|
|
19
19
|
//# sourceMappingURL=appointment.repository.js.map
|