UNPKG

5.8 kBJavaScriptView Raw
1// Copyright IBM Corp. 2014,2019. All Rights Reserved.
2// Node module: loopback-connector
3// This file is licensed under the MIT License.
4// License text available at https://opensource.org/licenses/MIT
5
6'use strict';
7/*
8 * A mockup connector that extends SQL connector
9 */
10const util = require('util');
11const SQLConnector = require('../../lib/sql');
12const debug = require('debug')('loopback:connector:test-sql');
13
14let transactionId = 0;
15
16function MockTransaction(connector, name) {
17 this.connector = connector;
18 this.name = name;
19 this.data = {};
20}
21
22MockTransaction.prototype.commit = function(cb) {
23 const self = this;
24 // Merge data from this TX to the global data var
25 for (const m in this.data) {
26 self.connector.data[m] = self.connector.data[m] || [];
27 for (let i = 0, n = this.data[m].length; i < n; i++) {
28 self.connector.data[m].push(this.data[m]);
29 }
30 }
31 this.data = {};
32 cb();
33};
34
35MockTransaction.prototype.rollback = function(cb) {
36 this.data = {};
37 cb();
38};
39
40exports.initialize = function initializeDataSource(dataSource, callback) {
41 process.nextTick(function() {
42 if (callback) {
43 const connector = new TestConnector(dataSource.settings);
44 connector.dataSource = dataSource;
45 dataSource.connector = connector;
46 callback(null, connector);
47 }
48 });
49};
50
51function TestConnector(settings) {
52 SQLConnector.call(this, 'testdb', settings);
53 this._tables = {};
54 this.data = {};
55}
56
57util.inherits(TestConnector, SQLConnector);
58
59TestConnector.prototype.escapeName = function(name) {
60 return '`' + name + '`';
61};
62
63TestConnector.prototype.dbName = function(name) {
64 return name.toUpperCase();
65};
66
67TestConnector.prototype.getPlaceholderForValue = function(key) {
68 return '$' + key;
69};
70
71TestConnector.prototype.escapeValue = function(value) {
72 if (typeof value === 'number' || typeof value === 'boolean') {
73 return value;
74 }
75 if (typeof value === 'string') {
76 return "'" + value + "'";
77 }
78 if (value == null) {
79 return 'NULL';
80 }
81 if (typeof value === 'object') {
82 return String(value);
83 }
84 return value;
85};
86
87TestConnector.prototype.toColumnValue = function(prop, val) {
88 return val;
89};
90
91TestConnector.prototype._buildLimit = function(model, limit, offset) {
92 if (isNaN(limit)) {
93 limit = 0;
94 }
95 if (isNaN(offset)) {
96 offset = 0;
97 }
98 if (!limit && !offset) {
99 return '';
100 }
101 return 'LIMIT ' + (offset ? (offset + ',' + limit) : limit);
102};
103
104TestConnector.prototype.applyPagination =
105 function(model, stmt, filter) {
106 /* jshint unused:false */
107 const limitClause = this._buildLimit(model, filter.limit,
108 filter.offset || filter.skip);
109 return stmt.merge(limitClause);
110 };
111
112TestConnector.prototype.escapeName = function(name) {
113 return '`' + name + '`';
114};
115
116TestConnector.prototype.dbName = function(name) {
117 return name.toUpperCase();
118};
119
120TestConnector.prototype.getPlaceholderForValue = function(key) {
121 return '$' + key;
122};
123
124TestConnector.prototype.escapeValue = function(value) {
125 if (typeof value === 'number' || typeof value === 'boolean') {
126 return value;
127 }
128 if (typeof value === 'string') {
129 return "'" + value + "'";
130 }
131 if (value == null) {
132 return 'NULL';
133 }
134 if (typeof value === 'object') {
135 return String(value);
136 }
137 return value;
138};
139
140TestConnector.prototype.toColumnValue = function(prop, val, escaping) {
141 return escaping ? this.escapeValue(val) : val;
142};
143
144TestConnector.prototype._buildLimit = function(model, limit, offset) {
145 if (isNaN(limit)) {
146 limit = 0;
147 }
148 if (isNaN(offset)) {
149 offset = 0;
150 }
151 if (!limit && !offset) {
152 return '';
153 }
154 return 'LIMIT ' + (offset ? (offset + ',' + limit) : limit);
155};
156
157TestConnector.prototype.applyPagination =
158 function(model, stmt, filter) {
159 /* jshint unused:false */
160 const limitClause = this._buildLimit(model, filter.limit,
161 filter.offset || filter.skip);
162 return stmt.merge(limitClause);
163 };
164
165TestConnector.prototype.dropTable = function(model, cb) {
166 let err;
167 const exists = model in this._tables;
168 if (!exists) {
169 err = new Error('Model doesn\'t exist: ' + model);
170 } else {
171 delete this._tables[model];
172 }
173 process.nextTick(function() {
174 cb(err);
175 });
176};
177
178TestConnector.prototype.createTable = function(model, cb) {
179 let err;
180 const exists = model in this._tables;
181 if (exists) {
182 err = new Error('Model already exists: ' + model);
183 } else {
184 this._tables[model] = model;
185 }
186 process.nextTick(function() {
187 cb(err);
188 });
189};
190
191TestConnector.prototype.getInsertedId = function(model, info) {
192 return info;
193};
194
195TestConnector.prototype.fromColumnValue = function(propertyDef, value) {
196 return value;
197};
198
199TestConnector.prototype.beginTransaction = function(isolationLevel, cb) {
200 const name = 'tx_' + transactionId++;
201 cb(null, new MockTransaction(this, name));
202};
203
204TestConnector.prototype.commit = function(tx, cb) {
205 tx.commit(cb);
206};
207
208TestConnector.prototype.rollback = function(tx, cb) {
209 tx.rollback(cb);
210};
211
212TestConnector.prototype.executeSQL = function(sql, params, options, callback) {
213 const transaction = options.transaction;
214 const model = options.model;
215 const useTransaction = transaction && transaction.connector === this &&
216 transaction.connection;
217 const data = useTransaction ? transaction.connection.data : this.data;
218 const name = useTransaction ? transaction.connection.name : undefined;
219 if (sql.indexOf('INSERT') === 0) {
220 data[model] = data[model] || [];
221 data[model].push({sql: sql, params: params});
222 debug('INSERT', data, sql, name);
223 callback(null, 1);
224 } else {
225 debug('SELECT', data, sql, name);
226 const instances = data[model] || [];
227 const result = sql.indexOf('count(*) as "cnt"') !== -1 ?
228 [{cnt: instances.length}] : instances;
229 callback(null, result);
230 }
231};