UNPKG

5.18 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.QueryRunner = void 0;
12const utils_1 = require("@poppinss/utils");
13const QueryReporter_1 = require("../QueryReporter");
14/**
15 * Query runner exposes the API for executing knex query builder by using the
16 * read/write replicas supported only by Lucid.
17 *
18 * Also it will emit the query data and profile the queries as well.
19 */
20class QueryRunner {
21 constructor(client, debug, logData) {
22 Object.defineProperty(this, "client", {
23 enumerable: true,
24 configurable: true,
25 writable: true,
26 value: client
27 });
28 Object.defineProperty(this, "debug", {
29 enumerable: true,
30 configurable: true,
31 writable: true,
32 value: debug
33 });
34 Object.defineProperty(this, "logData", {
35 enumerable: true,
36 configurable: true,
37 writable: true,
38 value: logData
39 });
40 Object.defineProperty(this, "reporter", {
41 enumerable: true,
42 configurable: true,
43 writable: true,
44 value: new QueryReporter_1.QueryReporter(this.client, this.debug, this.logData)
45 });
46 }
47 /**
48 * Is query dialect using sqlite database or not
49 */
50 isUsingSqlite() {
51 return this.client.dialect.name === 'sqlite3';
52 }
53 /**
54 * Find if query has a transaction attached to it, by using
55 * `useTransaction` method
56 */
57 isInTransaction(query) {
58 return query['client'].transacting;
59 }
60 /**
61 * Find if query is a write query or not.
62 */
63 isWriteQuery(query) {
64 return ['update', 'del', 'delete', 'insert'].includes(query['_method']);
65 }
66 /**
67 * Returns read or write client by inspecting the query
68 */
69 getQueryClient(query) {
70 return this.isWriteQuery(query) ? this.client.getWriteClient() : this.client.getReadClient();
71 }
72 /**
73 * Executes the query by handling exceptions and returns it back
74 * gracefully.
75 */
76 async executeQuery(query) {
77 try {
78 const result = await query;
79 return [undefined, result];
80 }
81 catch (error) {
82 return [error, undefined];
83 }
84 }
85 /**
86 * Executes the knex builder directly
87 */
88 async executeDirectly(query) {
89 /**
90 * We listen for query event on the knex query builder to avoid calling
91 * toSQL too many times and also get the actual time it took to
92 * execute the query
93 */
94 query['once']('query', (sql) => this.reporter.begin({ ...this.logData, ...sql }));
95 const [error, result] = await this.executeQuery(query);
96 this.reporter.end(error);
97 if (error) {
98 throw error;
99 }
100 return result;
101 }
102 /**
103 * Executes query by using a proper read or write connection.
104 */
105 async executeUsingManagedConnection(query) {
106 const queryClient = this.getQueryClient(query);
107 /**
108 * Acquire connection from the knex connection pool. This is will
109 * use the rounding robin mechanism and force set it on
110 * the query.
111 */
112 const connection = await queryClient.client.acquireConnection();
113 query.connection(connection);
114 /**
115 * We listen for query event on the knex query builder to avoid calling
116 * toSQL too many times and also get the actual time it took to
117 * execute the query
118 */
119 query['once']('query', (sql) => this.reporter.begin({ ...this.logData, ...sql }));
120 /**
121 * Execute query and report event and profiler data
122 */
123 const [error, result] = await this.executeQuery(query);
124 this.reporter.end(error);
125 /**
126 * Make sure to always release the connection
127 */
128 queryClient.client.releaseConnection(connection);
129 /**
130 * If there was an error, raise it or return the result
131 */
132 if (error) {
133 throw error;
134 }
135 return result;
136 }
137 /**
138 * Run query by managing its life-cycle
139 */
140 async run(query) {
141 /**
142 * We execute the queries using transaction or using sqlite database
143 * directly.
144 *
145 * - The transaction already has a pre-acquired connection.
146 * - There is no concept of read/write replicas in sqlite.
147 */
148 if (this.isUsingSqlite() || this.isInTransaction(query)) {
149 return this.executeDirectly(query);
150 }
151 /**
152 * Cannot execute write queries with client in read mode
153 */
154 if (this.isWriteQuery(query) && this.client.mode === 'read') {
155 throw new utils_1.Exception('Updates and deletes cannot be performed in read mode');
156 }
157 return this.executeUsingManagedConnection(query);
158 }
159}
160exports.QueryRunner = QueryRunner;