1
- /**
2
- * Created by loi on 1/15/16.
3
- */
4
-
5
-
6
1
/*
7
2
* License information at https://github.com/Caltech-IPAC/firefly/blob/master/License.txt
8
3
*/
9
- const op_regex = new RegExp ( '(!=|>=|<=|<|>|=|like|in)' , 'i' ) ;
10
- const cond_regex = new RegExp ( '^' + op_regex . source + '\\s+(.+)' , 'i' ) ;
11
- const filter_regex = new RegExp ( '(\\S+)\\s+' + op_regex . source + '\\s+(.+)' , 'i' ) ;
4
+
5
+ import { getColumnIdx , getColumn } from './TableUtil.js' ;
6
+ const cond_regex = new RegExp ( '(!=|>=|<=|<|>|=|like|in)\\s*(.+)' ) ;
7
+ const cond_only_regex = new RegExp ( '^' + cond_regex . source , 'i' ) ;
8
+ const filter_regex = new RegExp ( '(\\S+)\\s*' + cond_regex . source , 'i' ) ;
12
9
13
10
export const FILTER_CONDITION_TTIPS =
14
11
`Valid values are one of (=, >, <, !=, >=, <=, LIKE) followed by a value separated by a space.
@@ -47,8 +44,8 @@ export class FilterInfo {
47
44
var filterInfo = new FilterInfo ( ) ;
48
45
if ( filterString ) {
49
46
filterString && filterString . split ( ';' ) . forEach ( ( v ) => {
50
- const parts = v . trim ( ) . match ( filter_regex ) ;
51
- if ( parts . length > 3 ) filterInfo . addFilter ( parts [ 1 ] , `${ parts [ 2 ] } ${ parts [ 3 ] } ` ) ;
47
+ const [ , cname , op , val ] = v . trim ( ) . match ( filter_regex ) || [ ] ;
48
+ if ( cname ) filterInfo . addFilter ( cname , `${ op } ${ val } ` ) ;
52
49
} ) ;
53
50
}
54
51
return filterInfo ;
@@ -63,8 +60,8 @@ export class FilterInfo {
63
60
static autoCorrect ( conditions ) {
64
61
if ( conditions ) {
65
62
const parts = conditions . split ( ';' ) . map ( ( v ) => {
66
- const opVal = v . replace ( / \( | \) | / g, '' ) . split ( op_regex ) ;
67
- var [ op , val ] = opVal . length > 1 ? [ opVal [ 1 ] , opVal [ 2 ] ] : [ 'like' , opVal [ 0 ] ] ; // defualt to 'like' if no operators found
63
+ var [ , op , val ] = v . trim ( ) . replace ( / [ ( ) ] / g, '' ) . match ( cond_only_regex ) || [ ] ;
64
+ [ op , val ] = op ? [ op , val ] : [ 'like' , v . trim ( ) ] ; // defualt to 'like' if no operators found
68
65
val = op . toLowerCase ( ) === 'in' ? `(${ val } )` : val ; // add parentheses when 'in' is used.
69
66
return `${ op } ${ val } ` ;
70
67
} ) ;
@@ -83,9 +80,9 @@ export class FilterInfo {
83
80
static autoCorrectFilter ( filterInfo ) {
84
81
if ( filterInfo ) {
85
82
const filters = filterInfo . split ( ';' ) . map ( ( v ) => {
86
- const parts = v . split ( op_regex ) . map ( ( s ) => s . trim ( ) ) ;
87
- if ( parts . length != 3 ) return v ;
88
- return `${ parts [ 0 ] } ${ FilterInfo . autoCorrect ( parts [ 1 ] + parts [ 2 ] ) } ` ;
83
+ const [ , cname , op , val ] = v . trim ( ) . match ( filter_regex ) || [ ] ;
84
+ if ( ! cname ) return v ;
85
+ return `${ cname } ${ FilterInfo . autoCorrect ( op + ' ' + val ) } ` ;
89
86
} ) ;
90
87
return filters . join ( ';' ) ;
91
88
} else {
@@ -100,7 +97,7 @@ export class FilterInfo {
100
97
*/
101
98
static isConditionValid ( conditions ) {
102
99
return ! conditions || conditions . split ( ';' ) . reduce ( ( rval , v ) => {
103
- return rval && cond_regex . test ( v . trim ( ) ) ;
100
+ return rval && cond_only_regex . test ( v . trim ( ) ) ;
104
101
} , true ) ;
105
102
}
106
103
@@ -117,19 +114,19 @@ export class FilterInfo {
117
114
118
115
/**
119
116
* validate the filterInfo string
120
- * @param conditions
121
- * @param columns array of column definitions
117
+ * @param { string } filterInfo
118
+ * @param { TableColumn[] } columns array of column definitions
122
119
* @returns {[boolean, string] } isValid plus an error message if isValid is false.
123
120
*/
124
121
static isValid ( filterInfo , columns = [ ] ) {
125
122
const rval = [ true , '' ] ;
126
123
const allowCols = columns . concat ( { name :'ROWID' } ) ;
127
124
if ( filterInfo && filterInfo . trim ( ) . length > 0 ) {
128
125
return filterInfo . split ( ';' ) . reduce ( ( [ isValid , msg ] , v ) => {
129
- const parts = v . split ( op_regex ) . map ( ( s ) => s . trim ( ) ) ;
130
- if ( parts . length !== 3 ) {
126
+ const [ , cname ] = v . trim ( ) . match ( filter_regex ) || [ ] ;
127
+ if ( ! cname ) {
131
128
msg += `\n"${ v } " is not a valid filter.` ;
132
- } else if ( ! allowCols . some ( ( col ) => col . name === parts [ 0 ] ) ) {
129
+ } else if ( ! allowCols . some ( ( c ) => c . name === cname ) ) {
133
130
msg += `\n"${ v } " column not found.\n` ;
134
131
}
135
132
return [ ! msg , msg ] ;
@@ -141,8 +138,8 @@ export class FilterInfo {
141
138
142
139
/**
143
140
* validator for free-form filters field
144
- * @param filterInfo string serialized filter list
145
- * @param columns array of column definitions
141
+ * @param { TableColumn[] } columns array of column definitions
142
+ * @param { string } filterInfo
146
143
* @returns {{valid: boolean, value: (string|*), message: string} }
147
144
*/
148
145
static validator ( columns , filterInfo ) {
@@ -151,6 +148,49 @@ export class FilterInfo {
151
148
return { valid, value : filterInfo , message} ;
152
149
}
153
150
151
+ /**
152
+ * returns a comparator function that takes a row(string[]) as parameter.
153
+ * This comparator will returns true if the given row passes the given filterStr.
154
+ * @param {string } filterStr
155
+ * @param {TableModel } tableModel
156
+ * @returns {function(): boolean }
157
+ */
158
+ static createComparator ( filterStr , tableModel ) {
159
+ var [ , cname , op , val ] = filterStr . match ( filter_regex ) || [ ] ;
160
+ if ( ! cname ) return ( ) => false ; // bad filter.. returns nothing.
161
+
162
+ op = op . toLowerCase ( ) ;
163
+ val = val . toLowerCase ( ) ;
164
+ const cidx = getColumnIdx ( tableModel , cname ) ;
165
+ const col = getColumn ( tableModel , cname ) ;
166
+ val = op === 'in' ? val . replace ( / [ ( ) ] / g, '' ) . split ( ',' ) . map ( ( s ) => s . trim ( ) ) : val ;
167
+ return ( row ) => {
168
+ var compareTo = row [ cidx ] . toLowerCase ( ) ;
169
+ if ( ! [ 'in' , 'like' ] . includes ( op ) && col . type . match ( / ^ [ d f i l ] / ) ) { // int, float, double, long .. or their short form.
170
+ val = Number ( val ) ;
171
+ compareTo = Number ( compareTo ) ;
172
+ }
173
+ switch ( op ) {
174
+ case '!=' :
175
+ return compareTo !== val ;
176
+ case '>=' :
177
+ return compareTo >= val ;
178
+ case '<=' :
179
+ return compareTo <= val ;
180
+ case '>' :
181
+ return compareTo > val ;
182
+ case '=' :
183
+ return compareTo === val ;
184
+ case 'like' :
185
+ return compareTo . includes ( val ) ;
186
+ case 'in' :
187
+ return val . includes ( compareTo ) ;
188
+ default :
189
+ return false ;
190
+ }
191
+ } ;
192
+ }
193
+
154
194
serialize ( ) {
155
195
return Object . keys ( this ) . reduce ( ( rval , key ) => {
156
196
this [ key ] . split ( ';' ) . forEach ( ( v ) => {
@@ -174,8 +214,8 @@ export class FilterInfo {
174
214
Reflect . deleteProperty ( this , colName ) ;
175
215
if ( conditions ) {
176
216
conditions . split ( ';' ) . forEach ( ( v ) => {
177
- const parts = v . trim ( ) . match ( cond_regex ) ;
178
- if ( parts . length > 2 ) this . addFilter ( colName , `${ parts [ 1 ] } ${ parts [ 2 ] } ` ) ;
217
+ const [ , op , val ] = v . trim ( ) . match ( cond_only_regex ) || [ ] ;
218
+ if ( op ) this . addFilter ( colName , `${ op } ${ val } ` ) ;
179
219
} ) ;
180
220
}
181
221
}
0 commit comments