1 | const assert = require('assert');
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 | function JoinClause(table, type, schema) {
|
9 | this.schema = schema;
|
10 | this.table = table;
|
11 | this.joinType = type;
|
12 | this.and = this;
|
13 | this.clauses = [];
|
14 | }
|
15 |
|
16 | function getClauseFromArguments(compilerType, bool, first, operator, second) {
|
17 | let data = null;
|
18 |
|
19 | if (typeof first === 'function') {
|
20 | data = {
|
21 | type: 'onWrapped',
|
22 | value: first,
|
23 | bool: bool,
|
24 | };
|
25 | } else {
|
26 | switch (arguments.length) {
|
27 | case 3: {
|
28 | data = { type: 'onRaw', value: first, bool };
|
29 | break;
|
30 | }
|
31 | case 4:
|
32 | data = {
|
33 | type: compilerType,
|
34 | column: first,
|
35 | operator: '=',
|
36 | value: operator,
|
37 | bool,
|
38 | };
|
39 | break;
|
40 | default:
|
41 | data = {
|
42 | type: compilerType,
|
43 | column: first,
|
44 | operator,
|
45 | value: second,
|
46 | bool,
|
47 | };
|
48 | }
|
49 | }
|
50 |
|
51 | return data;
|
52 | }
|
53 |
|
54 | Object.assign(JoinClause.prototype, {
|
55 | grouping: 'join',
|
56 |
|
57 |
|
58 | on(first) {
|
59 | if (typeof first === 'object' && typeof first.toSQL !== 'function') {
|
60 | const keys = Object.keys(first);
|
61 | let i = -1;
|
62 | const method = this._bool() === 'or' ? 'orOn' : 'on';
|
63 | while (++i < keys.length) {
|
64 | this[method](keys[i], first[keys[i]]);
|
65 | }
|
66 | return this;
|
67 | }
|
68 |
|
69 | const data = getClauseFromArguments('onBasic', this._bool(), ...arguments);
|
70 |
|
71 | if (data) {
|
72 | this.clauses.push(data);
|
73 | }
|
74 |
|
75 | return this;
|
76 | },
|
77 |
|
78 |
|
79 | using(column) {
|
80 | return this.clauses.push({ type: 'onUsing', column, bool: this._bool() });
|
81 | },
|
82 |
|
83 | |
84 |
|
85 |
|
86 |
|
87 |
|
88 |
|
89 | orOn(first, operator, second) {
|
90 | return this._bool('or').on.apply(this, arguments);
|
91 | },
|
92 |
|
93 | onVal(first) {
|
94 | if (typeof first === 'object' && typeof first.toSQL !== 'function') {
|
95 | const keys = Object.keys(first);
|
96 | let i = -1;
|
97 | const method = this._bool() === 'or' ? 'orOnVal' : 'onVal';
|
98 | while (++i < keys.length) {
|
99 | this[method](keys[i], first[keys[i]]);
|
100 | }
|
101 | return this;
|
102 | }
|
103 |
|
104 | const data = getClauseFromArguments('onVal', this._bool(), ...arguments);
|
105 |
|
106 | if (data) {
|
107 | this.clauses.push(data);
|
108 | }
|
109 |
|
110 | return this;
|
111 | },
|
112 |
|
113 | andOnVal() {
|
114 | return this.onVal(...arguments);
|
115 | },
|
116 |
|
117 | orOnVal() {
|
118 | return this._bool('or').onVal(...arguments);
|
119 | },
|
120 |
|
121 | onBetween(column, values) {
|
122 | assert(
|
123 | Array.isArray(values),
|
124 | 'The second argument to onBetween must be an array.'
|
125 | );
|
126 | assert(
|
127 | values.length === 2,
|
128 | 'You must specify 2 values for the onBetween clause'
|
129 | );
|
130 | this.clauses.push({
|
131 | type: 'onBetween',
|
132 | column,
|
133 | value: values,
|
134 | bool: this._bool(),
|
135 | not: this._not(),
|
136 | });
|
137 | return this;
|
138 | },
|
139 |
|
140 | onNotBetween(column, values) {
|
141 | return this._not(true).onBetween(column, values);
|
142 | },
|
143 |
|
144 | orOnBetween(column, values) {
|
145 | return this._bool('or').onBetween(column, values);
|
146 | },
|
147 |
|
148 | orOnNotBetween(column, values) {
|
149 | return this._bool('or')
|
150 | ._not(true)
|
151 | .onBetween(column, values);
|
152 | },
|
153 |
|
154 | onIn(column, values) {
|
155 | if (Array.isArray(values) && values.length === 0) return this.on(1, '=', 0);
|
156 | this.clauses.push({
|
157 | type: 'onIn',
|
158 | column,
|
159 | value: values,
|
160 | not: this._not(),
|
161 | bool: this._bool(),
|
162 | });
|
163 | return this;
|
164 | },
|
165 |
|
166 | onNotIn(column, values) {
|
167 | return this._not(true).onIn(column, values);
|
168 | },
|
169 |
|
170 | orOnIn(column, values) {
|
171 | return this._bool('or').onIn(column, values);
|
172 | },
|
173 |
|
174 | orOnNotIn(column, values) {
|
175 | return this._bool('or')
|
176 | ._not(true)
|
177 | .onIn(column, values);
|
178 | },
|
179 |
|
180 | onNull(column) {
|
181 | this.clauses.push({
|
182 | type: 'onNull',
|
183 | column,
|
184 | not: this._not(),
|
185 | bool: this._bool(),
|
186 | });
|
187 | return this;
|
188 | },
|
189 |
|
190 | orOnNull(callback) {
|
191 | return this._bool('or').onNull(callback);
|
192 | },
|
193 |
|
194 | onNotNull(callback) {
|
195 | return this._not(true).onNull(callback);
|
196 | },
|
197 |
|
198 | orOnNotNull(callback) {
|
199 | return this._not(true)
|
200 | ._bool('or')
|
201 | .onNull(callback);
|
202 | },
|
203 |
|
204 | onExists(callback) {
|
205 | this.clauses.push({
|
206 | type: 'onExists',
|
207 | value: callback,
|
208 | not: this._not(),
|
209 | bool: this._bool(),
|
210 | });
|
211 | return this;
|
212 | },
|
213 |
|
214 | orOnExists(callback) {
|
215 | return this._bool('or').onExists(callback);
|
216 | },
|
217 |
|
218 | onNotExists(callback) {
|
219 | return this._not(true).onExists(callback);
|
220 | },
|
221 |
|
222 | orOnNotExists(callback) {
|
223 | return this._not(true)
|
224 | ._bool('or')
|
225 | .onExists(callback);
|
226 | },
|
227 |
|
228 |
|
229 | type(type) {
|
230 | this.joinType = type;
|
231 | return this;
|
232 | },
|
233 |
|
234 | _bool(bool) {
|
235 | if (arguments.length === 1) {
|
236 | this._boolFlag = bool;
|
237 | return this;
|
238 | }
|
239 | const ret = this._boolFlag || 'and';
|
240 | this._boolFlag = 'and';
|
241 | return ret;
|
242 | },
|
243 |
|
244 | _not(val) {
|
245 | if (arguments.length === 1) {
|
246 | this._notFlag = val;
|
247 | return this;
|
248 | }
|
249 | const ret = this._notFlag;
|
250 | this._notFlag = false;
|
251 | return ret;
|
252 | },
|
253 | });
|
254 |
|
255 | Object.defineProperty(JoinClause.prototype, 'or', {
|
256 | get() {
|
257 | return this._bool('or');
|
258 | },
|
259 | });
|
260 |
|
261 | JoinClause.prototype.andOn = JoinClause.prototype.on;
|
262 | JoinClause.prototype.andOnIn = JoinClause.prototype.onIn;
|
263 | JoinClause.prototype.andOnNotIn = JoinClause.prototype.onNotIn;
|
264 | JoinClause.prototype.andOnNull = JoinClause.prototype.onNull;
|
265 | JoinClause.prototype.andOnNotNull = JoinClause.prototype.onNotNull;
|
266 | JoinClause.prototype.andOnExists = JoinClause.prototype.onExists;
|
267 | JoinClause.prototype.andOnNotExists = JoinClause.prototype.onNotExists;
|
268 | JoinClause.prototype.andOnBetween = JoinClause.prototype.onBetween;
|
269 | JoinClause.prototype.andOnNotBetween = JoinClause.prototype.onNotBetween;
|
270 |
|
271 | module.exports = JoinClause;
|