@fto-consult/expo-ui 1.5.13 → 2.0.0
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fto-consult/expo-ui",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Bibliothèque de composants UI Expo,react-native",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -61,43 +61,46 @@
|
|
|
61
61
|
"@expo/html-elements": "^0.2.0",
|
|
62
62
|
"@expo/metro-config": "^0.4.0",
|
|
63
63
|
"@expo/webpack-config": "^0.17.2",
|
|
64
|
-
"@fto-consult/common": "^1.9.
|
|
64
|
+
"@fto-consult/common": "^1.9.8",
|
|
65
65
|
"@gorhom/portal": "^1.0.14",
|
|
66
66
|
"@react-native-async-storage/async-storage": "~1.17.3",
|
|
67
|
-
"@react-native-community/datetimepicker": "6.2
|
|
68
|
-
"@react-native-community/netinfo": "9.3.
|
|
67
|
+
"@react-native-community/datetimepicker": "6.5.2",
|
|
68
|
+
"@react-native-community/netinfo": "9.3.5",
|
|
69
69
|
"@react-navigation/native": "^6.0.13",
|
|
70
70
|
"@react-navigation/native-stack": "^6.9.1",
|
|
71
|
-
"@shopify/flash-list": "1.1
|
|
71
|
+
"@shopify/flash-list": "1.3.1",
|
|
72
72
|
"babel-plugin-inline-dotenv": "^1.7.0",
|
|
73
73
|
"babel-plugin-module-resolver": "^4.1.0",
|
|
74
74
|
"babel-plugin-transform-inline-environment-variables": "^0.4.4",
|
|
75
|
-
"expo": "^
|
|
76
|
-
"expo-camera": "~
|
|
77
|
-
"expo-clipboard": "~
|
|
78
|
-
"expo-image-picker": "~
|
|
79
|
-
"expo-linking": "~3.2.
|
|
80
|
-
"expo-sqlite": "~
|
|
81
|
-
"expo-status-bar": "~1.4.
|
|
82
|
-
"expo-system-ui": "~
|
|
83
|
-
"expo-web-browser": "~
|
|
75
|
+
"expo": "^47.0.0",
|
|
76
|
+
"expo-camera": "~13.0.0",
|
|
77
|
+
"expo-clipboard": "~4.0.1",
|
|
78
|
+
"expo-image-picker": "~14.0.1",
|
|
79
|
+
"expo-linking": "~3.2.3",
|
|
80
|
+
"expo-sqlite": "~11.0.0",
|
|
81
|
+
"expo-status-bar": "~1.4.2",
|
|
82
|
+
"expo-system-ui": "~2.0.1",
|
|
83
|
+
"expo-web-browser": "~12.0.0",
|
|
84
84
|
"google-libphonenumber": "^3.2.31",
|
|
85
85
|
"htmlparser2-without-node-native": "^3.9.2",
|
|
86
|
+
"mongo-parse": "^2.1.0",
|
|
86
87
|
"parent-package-json": "^2.0.1",
|
|
87
88
|
"prop-types": "^15.8.1",
|
|
88
89
|
"react-apexcharts": "^1.4.0",
|
|
89
90
|
"react-content-loader": "^6.2.0",
|
|
90
|
-
"react-dom": "18.
|
|
91
|
+
"react-dom": "18.1.0",
|
|
91
92
|
"react-native-big-list": "^1.5.5",
|
|
92
|
-
"react-native-gesture-handler": "~2.
|
|
93
|
+
"react-native-gesture-handler": "~2.8.0",
|
|
93
94
|
"react-native-paper": "^4.12.5",
|
|
94
95
|
"react-native-paper-dates": "^0.9.2",
|
|
95
|
-
"react-native-reanimated": "~2.
|
|
96
|
-
"react-native-safe-area-context": "4.
|
|
97
|
-
"react-native-svg": "
|
|
96
|
+
"react-native-reanimated": "~2.12.0",
|
|
97
|
+
"react-native-safe-area-context": "4.4.1",
|
|
98
|
+
"react-native-svg": "13.4.0",
|
|
98
99
|
"react-native-web": "~0.18.7",
|
|
99
|
-
"react-native-webview": "11.23.
|
|
100
|
+
"react-native-webview": "11.23.1",
|
|
100
101
|
"sharp-cli": "^2.1.0",
|
|
101
|
-
"tippy.js": "^6.3.7"
|
|
102
|
+
"tippy.js": "^6.3.7",
|
|
103
|
+
"react-native": "0.70.5",
|
|
104
|
+
"react": "18.1.0"
|
|
102
105
|
}
|
|
103
106
|
}
|
|
@@ -17,7 +17,7 @@ import {sortBy,isDecimal,extendObj,isObjOrArray,defaultNumber,defaultStr,isFunct
|
|
|
17
17
|
import {Datagrid as DatagridContentLoader} from "$ecomponents/ContentLoader";
|
|
18
18
|
import React from "$react";
|
|
19
19
|
import DateLib from "$lib/date";
|
|
20
|
-
import Filter,{canHandleFilter} from "$ecomponents/Filter";
|
|
20
|
+
import Filter,{canHandleFilter,prepareFilters} from "$ecomponents/Filter";
|
|
21
21
|
import {CHECKED_ICON_NAME} from "$ecomponents/Checkbox";
|
|
22
22
|
import { COLUMN_WIDTH,DATE_COLUMN_WIDTH } from "../utils";
|
|
23
23
|
import { StyleSheet,Dimensions,useWindowDimensions} from "react-native";
|
|
@@ -29,6 +29,7 @@ import i18n from "$i18n";
|
|
|
29
29
|
import { makePhoneCall,canMakePhoneCall as canMakeCall} from "$makePhoneCall";
|
|
30
30
|
import copyToClipboard from "$capp/clipboard";
|
|
31
31
|
import { Pressable } from "react-native";
|
|
32
|
+
import appConfig from "$capp/config";
|
|
32
33
|
|
|
33
34
|
export const arrayValueSeparator = ", ";
|
|
34
35
|
|
|
@@ -94,13 +95,13 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
94
95
|
value : uniqid(footerFieldName),override:false, writable: false
|
|
95
96
|
},
|
|
96
97
|
})
|
|
97
|
-
|
|
98
|
-
this.state.sort.column = "date";
|
|
99
|
-
}
|
|
98
|
+
|
|
100
99
|
this.state.sort.dir = defaultStr(this.state.sort.dir,this.state.sort.column == "date"?"desc":'asc')
|
|
101
100
|
this.hasColumnsHalreadyInitialized = false;
|
|
102
101
|
this.initColumns(props.columns);
|
|
103
|
-
|
|
102
|
+
if(!isNonNullString(this.state.sort.column) && "date" in this.state.columns){
|
|
103
|
+
this.state.sort.column = "date";
|
|
104
|
+
}
|
|
104
105
|
this.INITIAL_STATE = {
|
|
105
106
|
data,
|
|
106
107
|
sort : this.state.sort
|
|
@@ -1171,41 +1172,14 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
1171
1172
|
}
|
|
1172
1173
|
return this.doFilter(arg);
|
|
1173
1174
|
}
|
|
1175
|
+
///si les filtres devront être convertis au format SQL
|
|
1176
|
+
willConvertFiltersToSQL(){
|
|
1177
|
+
return !!defaultVal(this.props.convertFiltersToSQL,appConfig.get("convertDatagridFiltersToSQL"));;
|
|
1178
|
+
}
|
|
1174
1179
|
getFilters(){
|
|
1175
|
-
let filters = {}
|
|
1176
1180
|
this.filters = extendObj(true,{},this.filteredValues,this.filters)
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
if(!this.canHandleFilterVal(f)) {
|
|
1180
|
-
continue;
|
|
1181
|
-
}
|
|
1182
|
-
f.field = defaultStr(f.field,i);
|
|
1183
|
-
if(f.action =="$today"){
|
|
1184
|
-
f.operator = "$and";
|
|
1185
|
-
f.action = "$eq"
|
|
1186
|
-
}
|
|
1187
|
-
filters[f.operator] = defaultArray(filters[f.operator]);
|
|
1188
|
-
let ob = {};
|
|
1189
|
-
ob[f.field] = {}
|
|
1190
|
-
if(f.action == "$period"){
|
|
1191
|
-
let sp = defaultStr(f.value);
|
|
1192
|
-
if(sp){
|
|
1193
|
-
sp = sp.split("=>");
|
|
1194
|
-
if(DateLib.isValidSQLDate(sp[0]) && DateLib.isValidSQLDate(sp[1])){
|
|
1195
|
-
filters[f.operator].push({
|
|
1196
|
-
[f.field] : {$gte:sp[0]}
|
|
1197
|
-
})
|
|
1198
|
-
filters[f.operator].push({
|
|
1199
|
-
[f.field] : {$lte:sp[1]}
|
|
1200
|
-
})
|
|
1201
|
-
}
|
|
1202
|
-
}
|
|
1203
|
-
} else {
|
|
1204
|
-
ob[f.field][f.action] = f.value;
|
|
1205
|
-
filters[f.operator].push(ob)
|
|
1206
|
-
}
|
|
1207
|
-
}
|
|
1208
|
-
return filters;
|
|
1181
|
+
const preparedFilters = prepareFilters(this.filters,{filter:this.canHandleFilterVal.bind(this),convertToSQL:this.willConvertFiltersToSQL()});
|
|
1182
|
+
return preparedFilters;
|
|
1209
1183
|
}
|
|
1210
1184
|
fetchData(){}
|
|
1211
1185
|
/**** Filtre le tableau */
|
|
@@ -1665,6 +1639,8 @@ CommonDatagridComponent.propTypes = {
|
|
|
1665
1639
|
PropTypes.object,
|
|
1666
1640
|
PropTypes.func,
|
|
1667
1641
|
]),
|
|
1642
|
+
/*** si les filtres de données seront convertis au format SQL avant d'effectuer la requête distante */
|
|
1643
|
+
convertFiltersToSQL : PropTypes.bool,
|
|
1668
1644
|
isLoading : PropTypes.bool,///si les données sont en train d'être chargées
|
|
1669
1645
|
session : PropTypes.bool, /// si les données de sessions seront persistées
|
|
1670
1646
|
exportTableProps : PropTypes.oneOfType([
|
|
@@ -135,12 +135,13 @@ export default class CommonTableDatagrid extends CommonDatagrid{
|
|
|
135
135
|
return this.resolveFetchedDataPromise({cb,data:this.INITIAL_STATE.data}).then(resolve).catch(reject)
|
|
136
136
|
}
|
|
137
137
|
let fetchData = this.INITIAL_STATE.fetchData;
|
|
138
|
-
fetchOptions =
|
|
138
|
+
fetchOptions = isObj(fetchOptions)?Object.clone(fetchOptions):{};
|
|
139
139
|
fetchOptions.selector = defaultObj(fetchOptions.selector);
|
|
140
|
-
fetchOptions.selector.$and = defaultArray(fetchOptions.selector.$and);
|
|
141
140
|
fetchOptions.dataSources = this.currentDataSources;
|
|
142
|
-
|
|
141
|
+
const fetchFilters = this.getFilters();
|
|
142
|
+
fetchOptions = extendObj(true,true,{},fetchOptions,{selector : fetchFilters});
|
|
143
143
|
fetchOptions.dataSources = this.currentDataSources;
|
|
144
|
+
fetchOptions.sort = this.state.sort;
|
|
144
145
|
let limit = this.getQueryLimit();
|
|
145
146
|
if(limit > 0 && !this.isPivotDatagrid()){
|
|
146
147
|
fetchOptions.limit = limit;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
|
|
2
|
-
import {isNonNullString,defaultStr,isObjOrArray,isObj} from "$utils";
|
|
2
|
+
import {isNonNullString,defaultStr,defaultArray,isObjOrArray,isObj} from "$utils";
|
|
3
|
+
import DateLib from "$date";
|
|
4
|
+
import mangoParser from "mongo-parse";
|
|
3
5
|
|
|
4
6
|
export const filterTextTypes = ['text','number','email','search','tel','url','password',"id","idfield",'piecefield','piece'];
|
|
5
7
|
|
|
@@ -49,33 +51,97 @@ export const canHandleFilter = (f)=>{
|
|
|
49
51
|
|
|
50
52
|
}
|
|
51
53
|
|
|
54
|
+
export const regexExpressions = {
|
|
55
|
+
notcontains : {
|
|
56
|
+
left : "^((?!(",
|
|
57
|
+
right : ")).)*$",
|
|
58
|
+
/***@see : https://www.w3schools.com/sql/sql_like.asp */
|
|
59
|
+
sql : (string)=>{
|
|
60
|
+
return "%"+defaultStr(string).ltrim("%").rtrim("%")+"%";
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
notequals : {
|
|
64
|
+
left : "^(?!",
|
|
65
|
+
right : "$).*$",
|
|
66
|
+
},
|
|
67
|
+
equals : {
|
|
68
|
+
left : "/^",
|
|
69
|
+
right : '$/'
|
|
70
|
+
},
|
|
71
|
+
startswith : {
|
|
72
|
+
left : "/^",
|
|
73
|
+
right : '/',
|
|
74
|
+
sql : (string)=>{
|
|
75
|
+
return defaultStr(string).rtrim("%")+"%";
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
endswith : {
|
|
79
|
+
left : "",
|
|
80
|
+
right : '$/',
|
|
81
|
+
sql : (string)=>{
|
|
82
|
+
return "%"+defaultStr(string).ltrim("%");
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
contains : {
|
|
86
|
+
left : "/",
|
|
87
|
+
right : '/',
|
|
88
|
+
sql : (string)=>{
|
|
89
|
+
return "%"+defaultStr(string).ltrim("%").rtrim("%")+"%";
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
}
|
|
93
|
+
/**** prend en paramètre une chaine de caractère et un nom d'opérateur et génère
|
|
94
|
+
* la chaine de caracètre mango regex correspondant
|
|
95
|
+
*/
|
|
96
|
+
const toMangoRegex = (val,operator)=>{
|
|
97
|
+
if(!isNonNullString(val) || !isNonNullString(operator) || !regexExpressions[operator]) return "";
|
|
98
|
+
const rOp = regexExpressions[operator];
|
|
99
|
+
return rOp.left+escapeRegexChars(val)+rOp.right;
|
|
100
|
+
}
|
|
52
101
|
export const regexParser = {
|
|
53
102
|
equals : (val)=> {
|
|
54
|
-
|
|
55
|
-
return "/^"+escapeRegexChars(val)+'$/';
|
|
103
|
+
return toMangoRegex(val,"equals");
|
|
56
104
|
},
|
|
57
105
|
startswith : (val) => {
|
|
58
|
-
|
|
59
|
-
return "/^"+escapeRegexChars(val)+'/'
|
|
106
|
+
return toMangoRegex(val,"startswith");
|
|
60
107
|
},
|
|
61
108
|
endswith : (val) => {
|
|
62
|
-
|
|
63
|
-
return escapeRegexChars(val)+'$/'
|
|
109
|
+
return toMangoRegex(val,"endswith");
|
|
64
110
|
},
|
|
65
111
|
contains : (val) => {
|
|
66
|
-
|
|
67
|
-
return "/"+escapeRegexChars(val)+'/'
|
|
112
|
+
return toMangoRegex(val,"contains");
|
|
68
113
|
},
|
|
69
114
|
notequals : (val) => {
|
|
70
|
-
|
|
71
|
-
return "^(?!"+escapeRegexChars(val)+"$).*$"
|
|
115
|
+
return toMangoRegex(val,"notequals");
|
|
72
116
|
},
|
|
73
117
|
notcontains : (val) =>{
|
|
74
|
-
|
|
75
|
-
return "^((?!("+escapeRegexChars(val)+")).)*$"
|
|
118
|
+
return toMangoRegex(val,"notcontains");
|
|
76
119
|
}
|
|
77
|
-
|
|
78
|
-
|
|
120
|
+
}
|
|
121
|
+
/*** prend une expression regulière et le convertis en operateur, valeur
|
|
122
|
+
* @param {string} la valeur otenue au format regex
|
|
123
|
+
*/
|
|
124
|
+
export const regexDeparser = (regexValue)=>{
|
|
125
|
+
if(!regexValue) return null;
|
|
126
|
+
regexValue = regexValue.toString();
|
|
127
|
+
if(regexValue.endsWith("/i")){
|
|
128
|
+
regexValue = regexValue.rtrim("/i")+"/";
|
|
129
|
+
}
|
|
130
|
+
if(!isNonNullString(regexValue)) return null;
|
|
131
|
+
for(let i in regexExpressions){
|
|
132
|
+
const p = regexExpressions[i];
|
|
133
|
+
let rVal = regexValue.ltrim("/").rtrim("/");
|
|
134
|
+
const pLeft = p.left.ltrim("/"),pRight = p.right.rtrim("/");
|
|
135
|
+
if(rVal.startsWith(pLeft) && rVal.endsWith(pRight)){
|
|
136
|
+
return {
|
|
137
|
+
operator : i,
|
|
138
|
+
value : rVal.ltrim(pLeft).rtrim(pRight),
|
|
139
|
+
regexValue : rVal,
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
79
145
|
export const matchPouchDBOperator = (operator,value)=>{
|
|
80
146
|
if(!isNonNullString(operator)) return null;
|
|
81
147
|
if(!(value) && !isDecimal(value)) return null;
|
|
@@ -168,7 +234,7 @@ let Operators = {
|
|
|
168
234
|
regexpSupported: false
|
|
169
235
|
}
|
|
170
236
|
};
|
|
171
|
-
|
|
237
|
+
const utils = {
|
|
172
238
|
ALL: '#All#',
|
|
173
239
|
NONE: '#None#',
|
|
174
240
|
BLANK: '#Blank#"',
|
|
@@ -286,4 +352,140 @@ for(let i in utils.items){
|
|
|
286
352
|
utils.constants[i] = i;
|
|
287
353
|
}
|
|
288
354
|
|
|
289
|
-
|
|
355
|
+
/*** prend en paramètre un objet de filtres et les prépare pour la requête distante
|
|
356
|
+
* @param {object} filtersToPrepare les filtres à exploiter pour la requête distante
|
|
357
|
+
* le tableau des filtres
|
|
358
|
+
* @param {function|object} filter|options, la méthode utilisée pour effectuer un filtre sur les les élément à prendre en compte
|
|
359
|
+
*
|
|
360
|
+
*/
|
|
361
|
+
export const prepareFilters = (filtersToPrepare,opts)=>{
|
|
362
|
+
if(typeof opts =='function'){
|
|
363
|
+
opts = {filter:opts};
|
|
364
|
+
}
|
|
365
|
+
let {filter,convertToSQL:convToSQL} = opts;
|
|
366
|
+
const filters = {}
|
|
367
|
+
filter = typeof filter =='function'? filter : x=>true;
|
|
368
|
+
Object.map(filtersToPrepare,(f,i)=>{
|
|
369
|
+
if(!isObj(f) || !filter(f) || !isNonNullString(f.operator) || !isNonNullString(f.action)) {
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
f.field = defaultStr(f.field,i).trim();
|
|
373
|
+
f.action = defaultStr(f.action).toLowerCase().trim();
|
|
374
|
+
if(f.action =="$today"){
|
|
375
|
+
f.operator = "$and";
|
|
376
|
+
f.action = "$eq"
|
|
377
|
+
}
|
|
378
|
+
filters[f.operator] = defaultArray(filters[f.operator]);
|
|
379
|
+
const ob = {};
|
|
380
|
+
ob[f.field] = {}
|
|
381
|
+
if(f.action == "$period"){
|
|
382
|
+
let sp = defaultStr(f.value);
|
|
383
|
+
if(sp){
|
|
384
|
+
sp = sp.split("=>");
|
|
385
|
+
if(DateLib.isValidSQLDate(sp[0]) && DateLib.isValidSQLDate(sp[1])){
|
|
386
|
+
filters[f.operator].push({
|
|
387
|
+
[f.field] : {$gte:sp[0]}
|
|
388
|
+
})
|
|
389
|
+
filters[f.operator].push({
|
|
390
|
+
[f.field] : {$lte:sp[1]}
|
|
391
|
+
})
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
} else {
|
|
395
|
+
ob[f.field][f.action] = f.value;
|
|
396
|
+
filters[f.operator].push(ob)
|
|
397
|
+
}
|
|
398
|
+
});
|
|
399
|
+
return convToSQL ? convertToSQL(filters) : filters;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/*** la liste des actions supportés par les filtres
|
|
403
|
+
* @see : https://github.com/cloudant/mango from mango query mapping
|
|
404
|
+
*
|
|
405
|
+
*/
|
|
406
|
+
export const actions = ["$lt", "$gt", "$lte", "$gte", "$eq", "$exists", "$type", "$in", "$nin", "$all", "$size", "$or", "$nor", "$not", "$mod", "$regex", "$elemMatch"]
|
|
407
|
+
|
|
408
|
+
export default utils;
|
|
409
|
+
|
|
410
|
+
/*** convertis les filtres pris au format mangoesQuey, au format de sortie SQL
|
|
411
|
+
* @see : https://github.com/gordonBusyman/mongo-to-sql-converter
|
|
412
|
+
* @param {object} filters, les filtres au format mango query à convertir au format SQL
|
|
413
|
+
*/
|
|
414
|
+
export const convertToSQL = (filters)=>{
|
|
415
|
+
if(!isObjOrArray(filters)) return [];
|
|
416
|
+
const whereParsed = mangoParser.parse(filters)
|
|
417
|
+
return whereParsed.parts.reduce((prev, curr) => {
|
|
418
|
+
const c = whereClauseToSQL(curr);
|
|
419
|
+
return c ? [...prev,c] : prev;
|
|
420
|
+
}, []).map((filter)=>{
|
|
421
|
+
if(filter.field === MANGO_QUERY_OPERATOR){
|
|
422
|
+
delete filter.field;
|
|
423
|
+
}
|
|
424
|
+
return filter;
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
export const MANGO_QUERY_OPERATOR = "MANGO_QUERY_OPERATOR";
|
|
428
|
+
const whereClauseToSQL = (currentMongoParserElement) => {
|
|
429
|
+
let { field, operator, operand } = currentMongoParserElement;
|
|
430
|
+
if(!isNonNullString(operator) || !operatorsMap[operator]) return null;
|
|
431
|
+
operator = operatorsMap[operator]
|
|
432
|
+
if(operator == 'LIKE'){
|
|
433
|
+
const deparsed = regexDeparser(operand);
|
|
434
|
+
if(!isObj(deparsed)){
|
|
435
|
+
return null;
|
|
436
|
+
}
|
|
437
|
+
operand = deparsed.value;
|
|
438
|
+
const deparsedOp = deparsed.operator;
|
|
439
|
+
if(deparsedOp =='notcontains'){
|
|
440
|
+
operator = "NOT LIKE";
|
|
441
|
+
}
|
|
442
|
+
if(deparsedOp =='equals'){
|
|
443
|
+
operator = operatorsMap.$eq;
|
|
444
|
+
} else if(deparsedOp =='notequals'){
|
|
445
|
+
operator = operatorsMap.$ne;
|
|
446
|
+
} else{
|
|
447
|
+
const opMap = regexExpressions[deparsedOp];
|
|
448
|
+
if(!opMap || typeof opMap.sql !=='function') return null;
|
|
449
|
+
operand = opMap.sql(operand);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
// AND or OR operators with nested elements
|
|
453
|
+
if (typeof field === 'undefined') {
|
|
454
|
+
// parse nested elements
|
|
455
|
+
const nested = operand.reduce((prev, curr) => {
|
|
456
|
+
const parsed = mangoParser.parse(curr);
|
|
457
|
+
const prepared = whereClauseToSQL(parsed.parts[0]);
|
|
458
|
+
if(prepared){
|
|
459
|
+
return [...prev,prepared]
|
|
460
|
+
}
|
|
461
|
+
return prev;
|
|
462
|
+
}, [])
|
|
463
|
+
|
|
464
|
+
// nested WHERE element
|
|
465
|
+
return {
|
|
466
|
+
field: MANGO_QUERY_OPERATOR,
|
|
467
|
+
operator,
|
|
468
|
+
operand: nested
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
// simple WHERE element
|
|
472
|
+
return {
|
|
473
|
+
field,
|
|
474
|
+
operator,
|
|
475
|
+
operand
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// map mongoDB -> SQL operators
|
|
480
|
+
const operatorsMap = {
|
|
481
|
+
$or: 'OR',
|
|
482
|
+
$and: 'AND',
|
|
483
|
+
$lt: '<',
|
|
484
|
+
$lte: '<=',
|
|
485
|
+
$gt: '>',
|
|
486
|
+
$gte: '>=',
|
|
487
|
+
$ne: '!=',
|
|
488
|
+
$in: 'IN',
|
|
489
|
+
$eq: '=',
|
|
490
|
+
$regex : "LIKE"
|
|
491
|
+
}
|