UNPKG

9.1 kBJavaScriptView Raw
1"use strict";
2/*
3 * @adonisjs/lucid
4 *
5 * (c) Harminder Virk <virk@adonisjs.com>
6 *
7 * For the full copyright and license information, please view the LICENSE
8 * file that was distributed with this source code.
9 */
10Object.defineProperty(exports, "__esModule", { value: true });
11exports.TransactionClient = void 0;
12const events_1 = require("events");
13const hooks_1 = require("@poppinss/hooks");
14const QueryBuilder_1 = require("../Orm/QueryBuilder");
15const Raw_1 = require("../Database/StaticBuilder/Raw");
16const Raw_2 = require("../Database/QueryBuilder/Raw");
17const Insert_1 = require("../Database/QueryBuilder/Insert");
18const Reference_1 = require("../Database/StaticBuilder/Reference");
19const Database_1 = require("../Database/QueryBuilder/Database");
20/**
21 * Transaction uses a dedicated connection from the connection pool
22 * and executes queries inside a given transaction.
23 */
24class TransactionClient extends events_1.EventEmitter {
25 constructor(knexClient, dialect, connectionName, debug, emitter) {
26 super();
27 Object.defineProperty(this, "knexClient", {
28 enumerable: true,
29 configurable: true,
30 writable: true,
31 value: knexClient
32 });
33 Object.defineProperty(this, "dialect", {
34 enumerable: true,
35 configurable: true,
36 writable: true,
37 value: dialect
38 });
39 Object.defineProperty(this, "connectionName", {
40 enumerable: true,
41 configurable: true,
42 writable: true,
43 value: connectionName
44 });
45 Object.defineProperty(this, "debug", {
46 enumerable: true,
47 configurable: true,
48 writable: true,
49 value: debug
50 });
51 Object.defineProperty(this, "emitter", {
52 enumerable: true,
53 configurable: true,
54 writable: true,
55 value: emitter
56 });
57 /**
58 * Always true
59 */
60 Object.defineProperty(this, "isTransaction", {
61 enumerable: true,
62 configurable: true,
63 writable: true,
64 value: true
65 });
66 /**
67 * Transactions are always in write mode, since they always needs
68 * the primary connection
69 */
70 Object.defineProperty(this, "mode", {
71 enumerable: true,
72 configurable: true,
73 writable: true,
74 value: 'dual'
75 });
76 /**
77 * The profiler to be used for profiling queries
78 */
79 Object.defineProperty(this, "profiler", {
80 enumerable: true,
81 configurable: true,
82 writable: true,
83 value: void 0
84 });
85 Object.defineProperty(this, "hooks", {
86 enumerable: true,
87 configurable: true,
88 writable: true,
89 value: new hooks_1.Hooks()
90 });
91 /**
92 * Lucid models listens for transaction events to delete the reference. During
93 * testing, it is common to generate more than 10 model instances and hence
94 * the max listeners limit needs to be removed
95 */
96 this.setMaxListeners(Infinity);
97 }
98 /**
99 * Whether or not transaction has been completed
100 */
101 get isCompleted() {
102 return this.knexClient.isCompleted();
103 }
104 /**
105 * Returns schema instance for the write client
106 */
107 get schema() {
108 return this.getWriteClient().schema;
109 }
110 /**
111 * Returns the read client. Which is just a single client in case
112 * of transactions
113 */
114 getReadClient() {
115 return this.knexClient;
116 }
117 /**
118 * Returns the write client. Which is just a single client in case
119 * of transactions
120 */
121 getWriteClient() {
122 return this.knexClient;
123 }
124 /**
125 * Truncate tables inside a transaction
126 */
127 async truncate(table, cascade = false) {
128 await this.dialect.truncate(table, cascade);
129 }
130 /**
131 * Returns an array of table names
132 */
133 async getAllTables(schemas) {
134 return this.dialect.getAllTables(schemas);
135 }
136 /**
137 * Get columns info inside a transaction. You won't need it here, however
138 * added for API compatibility with the [[QueryClient]] class
139 */
140 async columnsInfo(table, column) {
141 const query = this.knexClient.select(table);
142 const result = await (column ? query.columnInfo(column) : query.columnInfo());
143 return result;
144 }
145 /**
146 * Get a new query builder instance
147 */
148 knexQuery() {
149 return this.knexClient.queryBuilder();
150 }
151 /**
152 * Returns the knex raw query builder instance. The query builder is always
153 * created from the `write` client, so before executing the query, you
154 * may want to decide which client to use.
155 */
156 knexRawQuery(sql, bindings) {
157 return bindings ? this.knexClient.raw(sql, bindings) : this.knexClient.raw(sql);
158 }
159 /**
160 * Returns a query builder instance for a given model. The `connection`
161 * and `profiler` is passed down to the model, so that it continue
162 * using the same options
163 */
164 modelQuery(model) {
165 return new QueryBuilder_1.ModelQueryBuilder(this.knexQuery(), model, this);
166 }
167 /**
168 * Get a new query builder instance
169 */
170 query() {
171 return new Database_1.DatabaseQueryBuilder(this.knexQuery(), this);
172 }
173 /**
174 * Get a new insert query builder instance
175 */
176 insertQuery() {
177 return new Insert_1.InsertQueryBuilder(this.knexQuery(), this);
178 }
179 /**
180 * Execute raw query on transaction
181 */
182 rawQuery(sql, bindings) {
183 return new Raw_2.RawQueryBuilder(this.knexClient.raw(sql, bindings), this);
184 }
185 /**
186 * Returns an instance of raw builder. This raw builder queries
187 * cannot be executed. Use `rawQuery`, if you want to execute
188 * queries raw queries.
189 */
190 raw(sql, bindings) {
191 return new Raw_1.RawBuilder(sql, bindings);
192 }
193 /**
194 * Returns reference builder.
195 */
196 ref(reference) {
197 return new Reference_1.ReferenceBuilder(reference, this.knexClient.client);
198 }
199 /**
200 * Returns another instance of transaction with save point
201 */
202 async transaction(callback, options) {
203 const trx = await this.knexClient.transaction(options);
204 const transaction = new TransactionClient(trx, this.dialect, this.connectionName, this.debug, this.emitter);
205 /**
206 * Always make sure to pass the profiler down the chain
207 */
208 transaction.profiler = this.profiler?.create('trx:begin', { state: 'begin' });
209 /**
210 * Self managed transaction
211 */
212 if (typeof callback === 'function') {
213 try {
214 const response = await callback(transaction);
215 !transaction.isCompleted && (await transaction.commit());
216 return response;
217 }
218 catch (error) {
219 await transaction.rollback();
220 throw error;
221 }
222 }
223 return transaction;
224 }
225 /**
226 * Same as [[Transaction.query]] but also selects the table
227 */
228 from(table) {
229 return this.query().from(table);
230 }
231 /**
232 * Same as [[Transaction.insertTable]] but also selects the table
233 */
234 table(table) {
235 return this.insertQuery().table(table);
236 }
237 /**
238 * Register after commit or rollback hook
239 */
240 after(event, handler) {
241 this.hooks.add('after', event, handler);
242 return this;
243 }
244 /**
245 * Commit the transaction
246 */
247 async commit() {
248 try {
249 await this.knexClient.commit();
250 this.profiler?.end({ state: 'commit' });
251 this.emit('commit', this);
252 this.removeAllListeners();
253 }
254 catch (error) {
255 this.profiler?.end({ state: 'commit' });
256 this.removeAllListeners();
257 throw error;
258 }
259 try {
260 await this.hooks.exec('after', 'commit');
261 this.hooks.clear('after');
262 }
263 catch { }
264 }
265 /**
266 * Rollback the transaction
267 */
268 async rollback() {
269 try {
270 await this.knexClient.rollback();
271 this.profiler?.end({ state: 'rollback' });
272 this.emit('rollback', this);
273 this.removeAllListeners();
274 }
275 catch (error) {
276 this.profiler?.end({ state: 'rollback' });
277 this.removeAllListeners();
278 throw error;
279 }
280 try {
281 await this.hooks.exec('after', 'rollback');
282 this.hooks.clear('after');
283 }
284 catch { }
285 }
286 /**
287 * Get advisory lock on the selected connection
288 */
289 getAdvisoryLock(key, timeout) {
290 return this.dialect.getAdvisoryLock(key, timeout);
291 }
292 /**
293 * Release advisory lock
294 */
295 releaseAdvisoryLock(key) {
296 return this.dialect.releaseAdvisoryLock(key);
297 }
298}
299exports.TransactionClient = TransactionClient;