-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
136 lines (120 loc) · 3.01 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
module.exports = where;
function where(query,options){
return new Where(options || {}).parse(query);
}
where.Where = Where;
function Where(options){
this.table = options.table || '';
this.values = [];
this.sql = '';
}
Where.prototype.parse = function(query){
this.sql = '';
if( !query ){
// ignore
} else if( Array.isArray(query) ){
this.sql += or(this,query);
} else if( typeof query == 'object' ){
this.sql += and(this,query);
}
return this;
}
Where.prototype.toString = function(){
var self = this;
return this.sql.replace(/\$(\d+)/g,function(r,i){
return esc(self.values[parseInt(i,10)-1]);
})
}
function and(where,obj){
return Object.keys(obj).map(value(where,obj)).join(' AND ');
}
function or(where,arr){
return arr.map(function(query,i){
if( Array.isArray(query) ){
return or(where,query);
} else if( typeof query == 'object' ){
return and(where,query);
} else {
throw new SyntaxError('OR values must be an object or an array')
}
}).join(' OR ');
}
function eq(where,k,v,negated){
if( Array.isArray(v) ){ // IN
if( !negated ){
return t(where,k) + ' IN ('+s(where,v)+')';
} else {
return t(where,k) + ' NOT IN ('+s(where,v)+')';
}
} else if( v === null ){ // IS NULL / NOT NULL
if( !negated ){
return t(where,k) + ' IS NULL';
} else {
return t(where,k) + ' IS NOT NULL';
}
} else if( !negated ){
return t(where,k) + ' = ' + s(where,v);
} else {
return t(where,k) + ' != ' + s(where,v);
}
}
function like(where,k,v){
return t(where,k) + ' LIKE ' + s(where,v);
}
function value(where,obj){
return function(k){
var v = obj[k];
if( Array.isArray(v) || simple(v) ){
return eq(where,k,v);
} else if( typeof v == 'object' ){
if( has(v,'not') ){
return eq(where,k,v.not,true);
} else if( has(v,'like') ){
if( simple(v.like) ){
return like(where,k,v.like);
} else {
throw new SyntaxError('"like" only supports strings');
}
} else {
throw new SyntaxError('nested objects require "like" or "not"');
}
} else {
throw new SyntaxError('only [], {} and simple values are accepted');
}
}
}
function s(where,v){
return '$'+where.values.push(v);
}
function t(where,k){
if( where.table ){
return '"'+where.table+'.'+k+'"';
} else {
return k;
}
}
function has(o,k){
return Object.prototype.hasOwnProperty.call(o,k);
}
function simple(v){
return typeof v == 'string' ||
typeof v == 'boolean' ||
typeof v == 'number' ||
typeof v == 'undefined' ||
v === null;
}
function esc(v){
if( typeof v == 'number' ){
return v.toString();
} else if( typeof v == 'string' ){
return '"'+v.replace(/"/g,function(){
return '""';
})+'"'
} else if( Array.isArray(v) ){
return v.map(esc).join(',');
} else if( v === null || typeof v == 'undefined' ){
return 'NULL';
} else {
throw new Error('not sure how to escape "'+v+'"');
}
}