UNPKG

3.39 kBJavaScriptView Raw
1var Query = module.exports = function Query(db, opts, cb) {
2
3 var self = this
4 if (!(self instanceof Query)) {
5 return new Query(db, opts, cb)
6 }
7
8 self.opts = opts
9 self.db = db
10
11 // list of host connection settings that are writable/readOnly
12 self.writable = []
13 self.readOnly = []
14
15 if (typeof cb !== 'function') cb = function() {}
16
17 self.detectTopology(cb)
18}
19
20
21Query.prototype.getConn = function(options) {
22 var self = this
23 if (options.write) {
24 return self.writable[randomInt(0, self.writable.length - 1)]
25 }
26 return self.readOnly[randomInt(0, self.readOnly.length - 1)]
27}
28
29
30Query.prototype.executeWrite = function(sql, values, options, cb) {
31 options = options || {}
32 options.write = true
33 return this.execute(sql, values, options, cb)
34}
35
36
37Query.prototype.execute = function(sql, values, options, cb) {
38 var self = this
39 var conn
40 var start
41
42 cb = cb || self.db._promiseResolver()
43
44 if (typeof options === 'function') {
45 cb = options
46 options = undefined
47 }
48
49 if (typeof sql !== 'string' && !isArray(sql)) {
50 return cb(new Error('sql must be string or array multiline string'))
51 }
52
53 if (typeof values === 'function') {
54 cb = values
55 values = undefined
56 }
57
58 if (isArray(sql)) {
59 sql = sql.join('\n')
60 }
61
62 if (values) {
63 sql = self.queryValues(sql, values)
64 }
65
66 options = options || {}
67 conn = self.getConn(options)
68 start = Date.now()
69
70 self.db._platform.getClient(conn, function(err, client, release) {
71 if (err) return cb(err)
72 self.db._platform.execute(client, sql, function(err, rows) {
73 if (err) {
74 if (!self.opts.silent) {
75 console.error(sql)
76 console.error('SQL ERROR:', err)
77 }
78 release()
79 return cb(err)
80 }
81
82 // release the client back to the pool
83 release()
84
85 if (self.opts.debug) {
86 self.opts.debug('\n' + sql + '\n' + (Date.now() - start) + 'ms')
87 }
88 cb(null, rows)
89 })
90 })
91 return cb.promise ? cb.promise : this
92}
93
94
95Query.prototype.detectTopology = function(cb) {
96 var self = this
97 self.db._platform.determineHosts(function(hosts) {
98 if (hosts.readOnly.length === 0 && hosts.writable.length === 0) {
99 return cb(new Error('Unable to connect to database.'))
100 }
101 if (hosts.readOnly.length === 0) {
102 hosts.readOnly = hosts.writable
103 }
104 self.readOnly = hosts.readOnly
105 self.writable = hosts.writable
106 cb(null)
107 })
108}
109
110
111// based on https://github.com/felixge/node-mysql#custom-format
112Query.prototype.queryValues = function(query, values) {
113 if (!values) return query;
114 return query.replace(/\:(\w+)/g, function (txt, key) {
115 if (values.hasOwnProperty(key)) {
116 if (isObject(values[key])) {
117 values[key] = JSON.stringify(values[key])
118 }
119 if (Array.isArray(values[key])) {
120 return values[key].map(function (v) {
121 return (typeof v === 'string') ? "'" + v + "'" : v
122 })
123 }
124 if (typeof values[key] !== 'string') {
125 return values[key]
126 }
127 return "'" + values[key].replace(/'/g, "''") + "'"
128 }
129 return txt
130 });
131};
132
133
134function isArray(value) {
135 return (Object.prototype.toString.call(value) === '[object Array]')
136}
137
138function isObject(value) {
139 return (Object.prototype.toString.call(value) === '[object Object]')
140}
141
142function randomInt(min, max) {
143 return Math.floor(Math.random()*(max-min+1)+min);
144}
145