@steedos/odata-v4-typeorm 1.20.0 → 2.2.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +125 -125
- package/config/default.json +6 -6
- package/{build/lib → lib}/createFilter.d.ts +13 -13
- package/{build/lib → lib}/createFilter.js +17 -15
- package/lib/createFilter.js.map +1 -0
- package/{build/lib → lib}/createQuery.d.ts +13 -13
- package/{build/lib → lib}/createQuery.js +14 -12
- package/lib/createQuery.js.map +1 -0
- package/{build/lib → lib}/executeQuery.d.ts +5 -5
- package/{build/lib → lib}/executeQuery.js +277 -268
- package/lib/executeQuery.js.map +1 -0
- package/{build/lib → lib}/index.d.ts +6 -6
- package/lib/index.js +14 -0
- package/lib/index.js.map +1 -0
- package/{build/lib → lib}/odataQueryMiddleware.d.ts +3 -3
- package/{build/lib → lib}/odataQueryMiddleware.js +29 -26
- package/lib/odataQueryMiddleware.js.map +1 -0
- package/{build/lib → lib}/sqlOptions.d.ts +7 -7
- package/lib/sqlOptions.js +3 -0
- package/{build/lib → lib}/sqlOptions.js.map +1 -1
- package/{build/lib → lib}/visitor.d.ts +20 -20
- package/{build/lib → lib}/visitor.js +308 -302
- package/lib/visitor.js.map +1 -0
- package/package.json +40 -52
- package/src/{lib/createFilter.ts → createFilter.ts} +26 -26
- package/src/{lib/createQuery.ts → createQuery.ts} +22 -22
- package/src/{lib/executeQuery.ts → executeQuery.ts} +291 -282
- package/src/{lib/index.ts → index.ts} +6 -6
- package/src/{lib/odataQueryMiddleware.ts → odataQueryMiddleware.ts} +17 -17
- package/src/{lib/sqlOptions.ts → sqlOptions.ts} +7 -7
- package/src/{lib/visitor.ts → visitor.ts} +301 -298
- package/tsconfig.json +11 -10
- package/build/example/sql.d.ts +0 -0
- package/build/example/sql.js +0 -131
- package/build/example/sql.js.map +0 -1
- package/build/lib/createFilter.js.map +0 -1
- package/build/lib/createQuery.js.map +0 -1
- package/build/lib/executeQuery.js.map +0 -1
- package/build/lib/index.js +0 -12
- package/build/lib/index.js.map +0 -1
- package/build/lib/odataQueryMiddleware.js.map +0 -1
- package/build/lib/sqlOptions.js +0 -2
- package/build/lib/visitor.js.map +0 -1
- package/src/example/sql.ts +0 -82
- package/src/example/world.sql +0 -5388
|
@@ -1,298 +1,301 @@
|
|
|
1
|
-
import {Token} from 'odata-v4-parser/lib/lexer';
|
|
2
|
-
import {Literal} from 'odata-v4-literal';
|
|
3
|
-
import {SQLLiteral, SQLLang, Visitor} from 'odata-v4-sql/lib/visitor';
|
|
4
|
-
import {SqlOptions} from './index';
|
|
5
|
-
|
|
6
|
-
export class TypeOrmVisitor extends Visitor {
|
|
7
|
-
//parameters:any[] = [];
|
|
8
|
-
includes: TypeOrmVisitor[] = [];
|
|
9
|
-
alias: string = ''// 'typeorm_query';
|
|
10
|
-
|
|
11
|
-
constructor(options) {
|
|
12
|
-
super(options);
|
|
13
|
-
if (!options.type) {
|
|
14
|
-
this.type = SQLLang.Oracle;
|
|
15
|
-
}
|
|
16
|
-
else{
|
|
17
|
-
this.type = options.type;
|
|
18
|
-
}
|
|
19
|
-
this.alias = options.alias || this.alias;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
from(table: string) {
|
|
23
|
-
let sql = `SELECT ${this.select} FROM [${table}] WHERE ${this.where} ORDER BY ${this.orderby}`;
|
|
24
|
-
switch (this.type) {
|
|
25
|
-
case SQLLang.Oracle:
|
|
26
|
-
if (typeof this.skip == "number") sql += ` OFFSET ${this.skip} ROWS`;
|
|
27
|
-
if (typeof this.limit == "number") {
|
|
28
|
-
if (typeof this.skip != "number") sql += " OFFSET 0 ROWS";
|
|
29
|
-
sql += ` FETCH NEXT ${this.limit} ROWS ONLY`;
|
|
30
|
-
}
|
|
31
|
-
case SQLLang.MsSql:
|
|
32
|
-
if (typeof this.orderby !== "string" || this.orderby === "1"){
|
|
33
|
-
this.orderby = "(select null) ASC";
|
|
34
|
-
}
|
|
35
|
-
let start = this.skip ? this.skip : 0;
|
|
36
|
-
let end = start + this.limit;
|
|
37
|
-
sql = `SELECT * from (SELECT ${this.select}, ROW_NUMBER() OVER(ORDER BY ${this.orderby}) AS RowId
|
|
38
|
-
FROM [${table}] WHERE ${this.where}) as a WHERE RowId BETWEEN ${start} + 1 and ${end}`;
|
|
39
|
-
break;
|
|
40
|
-
case SQLLang.MySql:
|
|
41
|
-
case SQLLang.PostgreSql:
|
|
42
|
-
default:
|
|
43
|
-
if (typeof this.limit == "number") sql += ` LIMIT ${this.limit}`;
|
|
44
|
-
if (typeof this.skip == "number") sql += ` OFFSET ${this.skip}`;
|
|
45
|
-
break;
|
|
46
|
-
}
|
|
47
|
-
// 给sql语句中字段名称增加中括号,防止字段名称使用了数据库的关键字
|
|
48
|
-
sql = sql.replace(/(\b\w+\b)\.(\b\w+\b)/g, '[$1].[$2]');
|
|
49
|
-
return sql;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
asMsSql() {
|
|
53
|
-
this.type = SQLLang.MsSql;
|
|
54
|
-
let rx = new RegExp("\\?", "g");
|
|
55
|
-
let keys = this.parameters.keys();
|
|
56
|
-
this.originalWhere = this.where;
|
|
57
|
-
this.where = this.where.replace(rx, () => `:${keys.next().value}`);
|
|
58
|
-
this.includes.forEach((item) => item.asMsSql());
|
|
59
|
-
return this;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
asPostgreSql() {
|
|
63
|
-
this.type = SQLLang.ANSI;
|
|
64
|
-
let rx = new RegExp("\\?", "g");
|
|
65
|
-
let keys = this.parameters.keys();
|
|
66
|
-
this.originalWhere = this.where;
|
|
67
|
-
this.where = this.where.replace(rx, () => `:${keys.next().value}`);
|
|
68
|
-
this.includes.forEach((item) => item.asPostgreSql());
|
|
69
|
-
return this;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
asType() {
|
|
73
|
-
switch (this.type) {
|
|
74
|
-
case SQLLang.MsSql: return this.asMsSql();
|
|
75
|
-
case SQLLang.ANSI:
|
|
76
|
-
case SQLLang.MySql:
|
|
77
|
-
case SQLLang.PostgreSql: return this.asPostgreSql();
|
|
78
|
-
case SQLLang.Oracle: return this.asOracleSql();
|
|
79
|
-
default: return this;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
protected VisitExpand(node: Token, context: any) {
|
|
84
|
-
node.value.items.forEach((item) => {
|
|
85
|
-
let expandPath = item.value.path.raw;
|
|
86
|
-
let visitor = this.includes.filter(v => v.navigationProperty == expandPath)[0];
|
|
87
|
-
if (!visitor) {
|
|
88
|
-
visitor = new TypeOrmVisitor(this.options);
|
|
89
|
-
visitor.parameterSeed = this.parameterSeed;
|
|
90
|
-
this.includes.push(visitor);
|
|
91
|
-
}
|
|
92
|
-
visitor.Visit(item);
|
|
93
|
-
this.parameterSeed = visitor.parameterSeed;
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
protected VisitSelectItem(node: Token, context: any) {
|
|
98
|
-
let item = node.raw.replace(/\//g, '.');
|
|
99
|
-
this.select += this.getIdentifier(item, context.identifier);//`${this.alias}.${item}`;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
protected VisitODataIdentifier(node: Token, context: any) {
|
|
103
|
-
if (context.identifier && context.identifier.endsWith('.')) {
|
|
104
|
-
this[context.target] += '.';
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
if (node.value.name === 'NULL') {
|
|
108
|
-
this[context.target] += node.value.name;
|
|
109
|
-
} else {
|
|
110
|
-
const ident = this.getIdentifier(node.value.name, context);//`${this.alias ? this.alias + '.' : ''}${node.value.name}`;
|
|
111
|
-
this[context.target] += ident
|
|
112
|
-
}
|
|
113
|
-
context.identifier = /*this.getIdentifier(node.value.name, context); //*/node.value.name;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
private getIdentifier(originalIdentifier: string, context: any) {
|
|
117
|
-
let alias = '';
|
|
118
|
-
if (!context || !context.identifier || !context.identifier.endsWith('.')) {
|
|
119
|
-
alias = this.alias + '.';
|
|
120
|
-
} else {
|
|
121
|
-
this[context.target] = this[context.target].replace(new RegExp(this.alias + '.' + context.identifier, 'g'), context.identifier)
|
|
122
|
-
}
|
|
123
|
-
return `${alias}${originalIdentifier}`;
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
protected VisitEqualsExpression(node: Token, context: any) {
|
|
127
|
-
this.Visit(node.value.left, context);
|
|
128
|
-
this.where += ' = ';
|
|
129
|
-
this.Visit(node.value.right, context);
|
|
130
|
-
if (this.options.useParameters && context.literal == null) {
|
|
131
|
-
this.where = this.where.replace(/= :p\d*$/, 'IS NULL')
|
|
132
|
-
.replace(new RegExp(`\\:p\\d* = ${context.identifier}$`),
|
|
133
|
-
`${context.identifier} IS NULL`);
|
|
134
|
-
} else if (context.literal == 'NULL') {
|
|
135
|
-
this.where = this.where.replace(/= NULL$/, 'IS NULL')
|
|
136
|
-
.replace(new RegExp(`NULL = ${context.identifier}$`), `${context.identifier} IS NULL`);
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
protected VisitNotEqualsExpression(node: Token, context: any) {
|
|
141
|
-
this.Visit(node.value.left, context);
|
|
142
|
-
this.where += ' <> ';
|
|
143
|
-
this.Visit(node.value.right, context);
|
|
144
|
-
if (this.options.useParameters && context.literal == null) {
|
|
145
|
-
this.where = this.where.replace(/<> :p\d*$/, 'IS NOT NULL')
|
|
146
|
-
.replace(new RegExp(`\\:p\\d* <> ${context.identifier}$`),
|
|
147
|
-
`${context.identifier} IS NOT NULL`);
|
|
148
|
-
} else if (context.literal == 'NULL') {
|
|
149
|
-
this.where = this.where.replace(/<> NULL$/, 'IS NOT NULL')
|
|
150
|
-
.replace(new RegExp(`NULL <> ${context.identifier}$`), `${context.identifier} IS NOT NULL`);
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
protected VisitLiteral(node: Token, context: any) {
|
|
155
|
-
if (this.options.useParameters) {
|
|
156
|
-
let name = `p${this.parameterSeed++}`;
|
|
157
|
-
let value = Literal.convert(node.value, node.raw);
|
|
158
|
-
context.literal = value;
|
|
159
|
-
if (context.literal != null) {
|
|
160
|
-
this.parameters.set(name, value);
|
|
161
|
-
}
|
|
162
|
-
this.where += `:${name}`;
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
this.
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
this.
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
this.
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
this.
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
this.
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
case SQLLang.
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
this.
|
|
253
|
-
this.
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
this.where += "
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
this.where += "
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
this.where += "
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
this.where += "
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
case "
|
|
279
|
-
case "
|
|
280
|
-
case "
|
|
281
|
-
case "
|
|
282
|
-
case "
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
this.where += "
|
|
289
|
-
break;
|
|
290
|
-
case "
|
|
291
|
-
this.where += "
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
}
|
|
1
|
+
import {Token} from 'odata-v4-parser/lib/lexer';
|
|
2
|
+
import {Literal} from 'odata-v4-literal';
|
|
3
|
+
import {SQLLiteral, SQLLang, Visitor} from 'odata-v4-sql/lib/visitor';
|
|
4
|
+
// import {SqlOptions} from './index';
|
|
5
|
+
|
|
6
|
+
export class TypeOrmVisitor extends Visitor {
|
|
7
|
+
//parameters:any[] = [];
|
|
8
|
+
includes: TypeOrmVisitor[] = [];
|
|
9
|
+
alias: string = ''// 'typeorm_query';
|
|
10
|
+
|
|
11
|
+
constructor(options) {
|
|
12
|
+
super(options);
|
|
13
|
+
if (!options.type) {
|
|
14
|
+
this.type = SQLLang.Oracle;
|
|
15
|
+
}
|
|
16
|
+
else{
|
|
17
|
+
this.type = options.type;
|
|
18
|
+
}
|
|
19
|
+
this.alias = options.alias || this.alias;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
from(table: string) {
|
|
23
|
+
let sql = `SELECT ${this.select} FROM [${table}] WHERE ${this.where} ORDER BY ${this.orderby}`;
|
|
24
|
+
switch (this.type) {
|
|
25
|
+
case SQLLang.Oracle:
|
|
26
|
+
if (typeof this.skip == "number") sql += ` OFFSET ${this.skip} ROWS`;
|
|
27
|
+
if (typeof this.limit == "number") {
|
|
28
|
+
if (typeof this.skip != "number") sql += " OFFSET 0 ROWS";
|
|
29
|
+
sql += ` FETCH NEXT ${this.limit} ROWS ONLY`;
|
|
30
|
+
}
|
|
31
|
+
case SQLLang.MsSql:
|
|
32
|
+
if (typeof this.orderby !== "string" || this.orderby === "1"){
|
|
33
|
+
this.orderby = "(select null) ASC";
|
|
34
|
+
}
|
|
35
|
+
let start = this.skip ? this.skip : 0;
|
|
36
|
+
let end = start + this.limit;
|
|
37
|
+
sql = `SELECT * from (SELECT ${this.select}, ROW_NUMBER() OVER(ORDER BY ${this.orderby}) AS RowId
|
|
38
|
+
FROM [${table}] WHERE ${this.where}) as a WHERE RowId BETWEEN ${start} + 1 and ${end}`;
|
|
39
|
+
break;
|
|
40
|
+
case SQLLang.MySql:
|
|
41
|
+
case SQLLang.PostgreSql:
|
|
42
|
+
default:
|
|
43
|
+
if (typeof this.limit == "number") sql += ` LIMIT ${this.limit}`;
|
|
44
|
+
if (typeof this.skip == "number") sql += ` OFFSET ${this.skip}`;
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
// 给sql语句中字段名称增加中括号,防止字段名称使用了数据库的关键字
|
|
48
|
+
sql = sql.replace(/(\b\w+\b)\.(\b\w+\b)/g, '[$1].[$2]');
|
|
49
|
+
return sql;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
asMsSql() {
|
|
53
|
+
this.type = SQLLang.MsSql;
|
|
54
|
+
let rx = new RegExp("\\?", "g");
|
|
55
|
+
let keys = this.parameters.keys();
|
|
56
|
+
this.originalWhere = this.where;
|
|
57
|
+
this.where = this.where.replace(rx, () => `:${keys.next().value}`);
|
|
58
|
+
this.includes.forEach((item) => item.asMsSql());
|
|
59
|
+
return this;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
asPostgreSql() {
|
|
63
|
+
this.type = SQLLang.ANSI;
|
|
64
|
+
let rx = new RegExp("\\?", "g");
|
|
65
|
+
let keys = this.parameters.keys();
|
|
66
|
+
this.originalWhere = this.where;
|
|
67
|
+
this.where = this.where.replace(rx, () => `:${keys.next().value}`);
|
|
68
|
+
this.includes.forEach((item) => item.asPostgreSql());
|
|
69
|
+
return this;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
asType() {
|
|
73
|
+
switch (this.type) {
|
|
74
|
+
case SQLLang.MsSql: return this.asMsSql();
|
|
75
|
+
case SQLLang.ANSI:
|
|
76
|
+
case SQLLang.MySql:
|
|
77
|
+
case SQLLang.PostgreSql: return this.asPostgreSql();
|
|
78
|
+
case SQLLang.Oracle: return this.asOracleSql();
|
|
79
|
+
default: return this;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
protected VisitExpand(node: Token, context: any) {
|
|
84
|
+
node.value.items.forEach((item) => {
|
|
85
|
+
let expandPath = item.value.path.raw;
|
|
86
|
+
let visitor = this.includes.filter(v => v.navigationProperty == expandPath)[0];
|
|
87
|
+
if (!visitor) {
|
|
88
|
+
visitor = new TypeOrmVisitor(this.options);
|
|
89
|
+
visitor.parameterSeed = this.parameterSeed;
|
|
90
|
+
this.includes.push(visitor);
|
|
91
|
+
}
|
|
92
|
+
visitor.Visit(item);
|
|
93
|
+
this.parameterSeed = visitor.parameterSeed;
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
protected VisitSelectItem(node: Token, context: any) {
|
|
98
|
+
let item = node.raw.replace(/\//g, '.');
|
|
99
|
+
this.select += this.getIdentifier(item, context.identifier);//`${this.alias}.${item}`;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
protected VisitODataIdentifier(node: Token, context: any) {
|
|
103
|
+
if (context.identifier && context.identifier.endsWith('.')) {
|
|
104
|
+
this[context.target] += '.';
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (node.value.name === 'NULL') {
|
|
108
|
+
this[context.target] += node.value.name;
|
|
109
|
+
} else {
|
|
110
|
+
const ident = this.getIdentifier(node.value.name, context);//`${this.alias ? this.alias + '.' : ''}${node.value.name}`;
|
|
111
|
+
this[context.target] += ident
|
|
112
|
+
}
|
|
113
|
+
context.identifier = /*this.getIdentifier(node.value.name, context); //*/node.value.name;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
private getIdentifier(originalIdentifier: string, context: any) {
|
|
117
|
+
let alias = '';
|
|
118
|
+
if (!context || !context.identifier || !context.identifier.endsWith('.')) {
|
|
119
|
+
alias = this.alias + '.';
|
|
120
|
+
} else {
|
|
121
|
+
this[context.target] = this[context.target].replace(new RegExp(this.alias + '.' + context.identifier, 'g'), context.identifier)
|
|
122
|
+
}
|
|
123
|
+
return `${alias}${originalIdentifier}`;
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
protected VisitEqualsExpression(node: Token, context: any) {
|
|
127
|
+
this.Visit(node.value.left, context);
|
|
128
|
+
this.where += ' = ';
|
|
129
|
+
this.Visit(node.value.right, context);
|
|
130
|
+
if (this.options.useParameters && context.literal == null) {
|
|
131
|
+
this.where = this.where.replace(/= :p\d*$/, 'IS NULL')
|
|
132
|
+
.replace(new RegExp(`\\:p\\d* = ${context.identifier}$`),
|
|
133
|
+
`${context.identifier} IS NULL`);
|
|
134
|
+
} else if (context.literal == 'NULL') {
|
|
135
|
+
this.where = this.where.replace(/= NULL$/, 'IS NULL')
|
|
136
|
+
.replace(new RegExp(`NULL = ${context.identifier}$`), `${context.identifier} IS NULL`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
protected VisitNotEqualsExpression(node: Token, context: any) {
|
|
141
|
+
this.Visit(node.value.left, context);
|
|
142
|
+
this.where += ' <> ';
|
|
143
|
+
this.Visit(node.value.right, context);
|
|
144
|
+
if (this.options.useParameters && context.literal == null) {
|
|
145
|
+
this.where = this.where.replace(/<> :p\d*$/, 'IS NOT NULL')
|
|
146
|
+
.replace(new RegExp(`\\:p\\d* <> ${context.identifier}$`),
|
|
147
|
+
`${context.identifier} IS NOT NULL`);
|
|
148
|
+
} else if (context.literal == 'NULL') {
|
|
149
|
+
this.where = this.where.replace(/<> NULL$/, 'IS NOT NULL')
|
|
150
|
+
.replace(new RegExp(`NULL <> ${context.identifier}$`), `${context.identifier} IS NOT NULL`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
protected VisitLiteral(node: Token, context: any) {
|
|
155
|
+
if (this.options.useParameters) {
|
|
156
|
+
let name = `p${this.parameterSeed++}`;
|
|
157
|
+
let value = Literal.convert(node.value, node.raw);
|
|
158
|
+
context.literal = value;
|
|
159
|
+
if (context.literal != null) {
|
|
160
|
+
this.parameters.set(name, value);
|
|
161
|
+
}
|
|
162
|
+
// this.where += `:${name}`;
|
|
163
|
+
// 因为useParameters为true,所以这里不可以把where追加为:p1这种格式,因为asOracleSql、asPostgreSql等用了正则替换?占位的方式重新设置:p{index}值
|
|
164
|
+
// 如果把where追加为:p1这种格式,已知的问题是VisitMethodCallExpression函数中的包括contains在内的所有method都只能写在过滤条件的最前面,而不可以写在后面的位置
|
|
165
|
+
this.where += `?`;
|
|
166
|
+
} else this.where += (context.literal = SQLLiteral.convert(node.value, node.raw));
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
protected VisitNotExpression(node: Token, context: any) {
|
|
170
|
+
if (node.value && node.value.type === "MethodCallExpression" && node.value.value.method) {
|
|
171
|
+
node.value.value.method = `not ${node.value.value.method}`;
|
|
172
|
+
this.VisitMethodCallExpression(node.value, context);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
protected VisitMethodCallExpression(node:Token, context:any){
|
|
177
|
+
var method = node.value.method;
|
|
178
|
+
var params = node.value.parameters || [];
|
|
179
|
+
switch (method){
|
|
180
|
+
case "contains":
|
|
181
|
+
this.Visit(params[0], context);
|
|
182
|
+
if (this.options.useParameters){
|
|
183
|
+
let name = `p${this.parameterSeed++}`;
|
|
184
|
+
let value = Literal.convert(params[1].value, params[1].raw);
|
|
185
|
+
this.parameters.set(name, `%${value}%`);
|
|
186
|
+
this.where += " like ?";
|
|
187
|
+
}else this.where += ` like '%${SQLLiteral.convert(params[1].value, params[1].raw).slice(1, -1)}%'`;
|
|
188
|
+
break;
|
|
189
|
+
case "not contains":
|
|
190
|
+
this.Visit(params[0], context);
|
|
191
|
+
if (this.options.useParameters) {
|
|
192
|
+
let name = `p${this.parameterSeed++}`;
|
|
193
|
+
let value = Literal.convert(params[1].value, params[1].raw);
|
|
194
|
+
this.parameters.set(name, `%${value}%`);
|
|
195
|
+
this.where += " not like ?";
|
|
196
|
+
} else this.where += ` not like '%${SQLLiteral.convert(params[1].value, params[1].raw).slice(1, -1)}%'`;
|
|
197
|
+
break;
|
|
198
|
+
case "endswith":
|
|
199
|
+
this.Visit(params[0], context);
|
|
200
|
+
if (this.options.useParameters){
|
|
201
|
+
let name = `p${this.parameterSeed++}`;
|
|
202
|
+
let value = Literal.convert(params[1].value, params[1].raw);
|
|
203
|
+
this.parameters.set(name, `%${value}`);
|
|
204
|
+
this.where += " like ?";
|
|
205
|
+
}else this.where += ` like '%${SQLLiteral.convert(params[1].value, params[1].raw).slice(1, -1)}'`;
|
|
206
|
+
break;
|
|
207
|
+
case "not endswith":
|
|
208
|
+
this.Visit(params[0], context);
|
|
209
|
+
if (this.options.useParameters) {
|
|
210
|
+
let name = `p${this.parameterSeed++}`;
|
|
211
|
+
let value = Literal.convert(params[1].value, params[1].raw);
|
|
212
|
+
this.parameters.set(name, `%${value}`);
|
|
213
|
+
this.where += " not like ?";
|
|
214
|
+
} else this.where += ` not like '%${SQLLiteral.convert(params[1].value, params[1].raw).slice(1, -1)}'`;
|
|
215
|
+
break;
|
|
216
|
+
case "startswith":
|
|
217
|
+
this.Visit(params[0], context);
|
|
218
|
+
if (this.options.useParameters){
|
|
219
|
+
let name = `p${this.parameterSeed++}`;
|
|
220
|
+
let value = Literal.convert(params[1].value, params[1].raw);
|
|
221
|
+
this.parameters.set(name, `${value}%`);
|
|
222
|
+
this.where += " like ?";
|
|
223
|
+
}else this.where += ` like '${SQLLiteral.convert(params[1].value, params[1].raw).slice(1, -1)}%'`;
|
|
224
|
+
break;
|
|
225
|
+
case "not startswith":
|
|
226
|
+
this.Visit(params[0], context);
|
|
227
|
+
if (this.options.useParameters) {
|
|
228
|
+
let name = `p${this.parameterSeed++}`;
|
|
229
|
+
let value = Literal.convert(params[1].value, params[1].raw);
|
|
230
|
+
this.parameters.set(name, `${value}%`);
|
|
231
|
+
this.where += " not like ?";
|
|
232
|
+
} else this.where += ` not like '${SQLLiteral.convert(params[1].value, params[1].raw).slice(1, -1)}%'`;
|
|
233
|
+
break;
|
|
234
|
+
case "indexof":
|
|
235
|
+
let fn = "";
|
|
236
|
+
switch (this.type) {
|
|
237
|
+
case SQLLang.MsSql:
|
|
238
|
+
fn = "CHARINDEX";
|
|
239
|
+
break;
|
|
240
|
+
case SQLLang.ANSI:
|
|
241
|
+
case SQLLang.MySql:
|
|
242
|
+
case SQLLang.PostgreSql:
|
|
243
|
+
default:
|
|
244
|
+
fn = "INSTR";
|
|
245
|
+
break;
|
|
246
|
+
}
|
|
247
|
+
if (fn === "CHARINDEX"){
|
|
248
|
+
const tmp = params[0];
|
|
249
|
+
params[0] = params[1];
|
|
250
|
+
params[1] = tmp;
|
|
251
|
+
}
|
|
252
|
+
this.where += `${fn}(`;
|
|
253
|
+
this.Visit(params[0], context);
|
|
254
|
+
this.where += ', ';
|
|
255
|
+
this.Visit(params[1], context);
|
|
256
|
+
this.where += ") - 1";
|
|
257
|
+
break;
|
|
258
|
+
case "round":
|
|
259
|
+
this.where += "ROUND(";
|
|
260
|
+
this.Visit(params[0], context);
|
|
261
|
+
this.where += ")";
|
|
262
|
+
break;
|
|
263
|
+
case "length":
|
|
264
|
+
this.where += "LEN(";
|
|
265
|
+
this.Visit(params[0], context);
|
|
266
|
+
this.where += ")";
|
|
267
|
+
break;
|
|
268
|
+
case "tolower":
|
|
269
|
+
this.where += "LOWER(";
|
|
270
|
+
this.Visit(params[0], context);
|
|
271
|
+
this.where += ")";
|
|
272
|
+
break;
|
|
273
|
+
case "toupper":
|
|
274
|
+
this.where += "UPPER(";
|
|
275
|
+
this.Visit(params[0], context);
|
|
276
|
+
this.where += ")";
|
|
277
|
+
break;
|
|
278
|
+
case "floor":
|
|
279
|
+
case "ceiling":
|
|
280
|
+
case "year":
|
|
281
|
+
case "month":
|
|
282
|
+
case "day":
|
|
283
|
+
case "hour":
|
|
284
|
+
case "minute":
|
|
285
|
+
case "second":
|
|
286
|
+
this.where += `${method.toUpperCase()}(`;
|
|
287
|
+
this.Visit(params[0], context);
|
|
288
|
+
this.where += ")";
|
|
289
|
+
break;
|
|
290
|
+
case "now":
|
|
291
|
+
this.where += "NOW()";
|
|
292
|
+
break;
|
|
293
|
+
case "trim":
|
|
294
|
+
this.where += "TRIM(' ' FROM ";
|
|
295
|
+
this.Visit(params[0], context);
|
|
296
|
+
this.where += ")";
|
|
297
|
+
break;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
}
|
package/tsconfig.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"sourceMap": true,
|
|
4
|
-
"target": "es6",
|
|
5
|
-
"module": "commonjs",
|
|
6
|
-
"declaration": true,
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
|
|
10
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"sourceMap": true,
|
|
4
|
+
"target": "es6",
|
|
5
|
+
"module": "commonjs",
|
|
6
|
+
"declaration": true,
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
"experimentalDecorators": true,
|
|
9
|
+
"outDir": "lib"
|
|
10
|
+
}
|
|
11
|
+
}
|
package/build/example/sql.d.ts
DELETED
|
File without changes
|