@opengis/fastify-table 1.2.67 → 1.2.69
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/README.md +86 -86
- package/package.json +1 -1
- package/server/migrations/cls.sql +39 -39
- package/server/plugins/cron/funcs/addCron.js +130 -130
- package/server/plugins/cron/index.js +6 -6
- package/server/plugins/crud/funcs/getOpt.js +13 -13
- package/server/plugins/crud/funcs/setOpt.js +21 -21
- package/server/plugins/crud/funcs/setToken.js +44 -44
- package/server/plugins/crud/funcs/utils/getFolder.js +11 -11
- package/server/plugins/crud/funcs/validateData.js +3 -3
- package/server/plugins/crud/index.js +23 -23
- package/server/plugins/hook/index.js +8 -8
- package/server/plugins/logger/errorStatus.js +19 -19
- package/server/plugins/logger/index.js +26 -26
- package/server/plugins/migration/index.js +7 -7
- package/server/plugins/pg/funcs/autoIndex.js +2 -2
- package/server/plugins/policy/sqlInjection.js +33 -33
- package/server/plugins/redis/client.js +8 -8
- package/server/plugins/redis/funcs/redisClients.js +3 -3
- package/server/plugins/redis/index.js +17 -17
- package/server/plugins/table/funcs/getData.js +3 -3
- package/server/plugins/table/funcs/getFilterSQL/index.js +68 -50
- package/server/plugins/table/funcs/getFilterSQL/util/formatValue.js +143 -119
- package/server/plugins/table/funcs/getFilterSQL/util/getCustomQuery.js +13 -13
- package/server/plugins/table/funcs/getFilterSQL/util/getFilterQuery.js +9 -6
- package/server/plugins/table/funcs/getFilterSQL/util/getOptimizedQuery.js +5 -11
- package/server/plugins/table/funcs/getFilterSQL/util/getTableSql.js +34 -34
- package/server/plugins/table/funcs/getTemplates.js +19 -19
- package/server/plugins/table/funcs/gisIRColumn.js +82 -82
- package/server/plugins/table/funcs/loadTemplate.js +1 -1
- package/server/plugins/table/funcs/loadTemplatePath.js +1 -1
- package/server/plugins/table/funcs/userTemplateDir.js +1 -1
- package/server/plugins/table/index.js +13 -13
- package/server/plugins/util/index.js +7 -7
- package/server/routes/cron/index.js +14 -14
- package/server/routes/crud/controllers/table.js +92 -88
- package/server/routes/logger/controllers/logger.file.js +92 -92
- package/server/routes/logger/controllers/utils/checkUserAccess.js +19 -19
- package/server/routes/logger/controllers/utils/getRootDir.js +26 -26
- package/server/routes/logger/index.js +17 -17
- package/server/routes/properties/controllers/properties.add.js +55 -55
- package/server/routes/properties/controllers/properties.get.js +17 -17
- package/server/routes/properties/index.js +16 -16
- package/server/routes/table/controllers/data.js +12 -7
- package/server/routes/table/controllers/filter.js +21 -4
- package/server/routes/table/controllers/form.js +42 -42
- package/server/routes/table/controllers/search.js +74 -74
- package/server/routes/table/controllers/suggest.js +2 -2
- package/server/routes/table/index.js +29 -29
- package/server/routes/table/schema.js +64 -64
- package/server/routes/util/controllers/status.monitor.js +8 -8
- package/server/routes/util/index.js +11 -11
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
const dateTypeList = ['date', 'timestamp', 'timestamp without time zone', 'timestamp with time zone'];
|
|
2
2
|
const numberTypeList = ['float8', 'int4', 'int8', 'numeric', 'double precision', 'integer'];
|
|
3
|
+
|
|
3
4
|
const isValidDate = (dateStr) => {
|
|
5
|
+
if (!dateStr) return false;
|
|
6
|
+
// iso date: 2024-01-01
|
|
7
|
+
if (dateStr?.indexOf('-') !== -1) {
|
|
8
|
+
const [yyyy, mm, dd] = dateStr.split('-');
|
|
9
|
+
return new Date(mm + '/' + dd + '/' + yyyy).toString() !== 'Invalid Date';
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// locale date: 01.01.2024
|
|
4
13
|
const [dd, mm, yyyy] = dateStr.split('.');
|
|
5
14
|
return new Date(mm + '/' + dd + '/' + yyyy).toString() !== 'Invalid Date';
|
|
6
15
|
};
|
|
@@ -8,6 +17,7 @@ const isValidDate = (dateStr) => {
|
|
|
8
17
|
function dt(y, m, d) {
|
|
9
18
|
return new Date(Date.UTC(y, m, d)).toISOString().slice(0, 10);
|
|
10
19
|
}
|
|
20
|
+
|
|
11
21
|
const dp = {
|
|
12
22
|
d: new Date().getDate(),
|
|
13
23
|
w: new Date().getDate() - (new Date().getDay() || 7) + 1,
|
|
@@ -22,96 +32,150 @@ function formatDateISOString(date) {
|
|
|
22
32
|
return `${year}-${month}-${day}`;
|
|
23
33
|
}
|
|
24
34
|
|
|
35
|
+
function getDates(value) {
|
|
36
|
+
// date range, specific options: current day, week, month, year etc.
|
|
37
|
+
if (value === 'cd') {
|
|
38
|
+
return [dt(dp.y, dp.m, dp.d)];
|
|
39
|
+
}
|
|
40
|
+
if (value === 'cw') {
|
|
41
|
+
return [dt(dp.y, dp.m, dp.w), dt(dp.y, dp.m, dp.w + 6)];
|
|
42
|
+
}
|
|
43
|
+
if (value === 'cm') {
|
|
44
|
+
return [dt(dp.y, dp.m, 1), dt(dp.y, dp.m + 1, 0)];
|
|
45
|
+
}
|
|
46
|
+
if (value === 'cq') {
|
|
47
|
+
return [dt(dp.y, dp.q, 1), dt(dp.y, dp.q + 3, 0)];
|
|
48
|
+
}
|
|
49
|
+
if (value === 'cy') {
|
|
50
|
+
return [dt(dp.y, 0, 1), dt(dp.y, 11, 31)];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// date range, example: 01.01.2024-31.12.2024
|
|
54
|
+
const [startDate, endDate] = value.split('-');
|
|
55
|
+
const min = formatDateISOString(startDate);
|
|
56
|
+
const max = formatDateISOString(endDate);
|
|
57
|
+
return [min, max];
|
|
58
|
+
}
|
|
59
|
+
|
|
25
60
|
function formatValue({
|
|
26
61
|
pg, table, filter = {}, name, value, operator = '=', dataTypeID, uid = 1, optimize,
|
|
27
62
|
}) {
|
|
28
|
-
const {
|
|
63
|
+
const { extra, sql, select } = filter;
|
|
29
64
|
const pk = pg?.pk && table ? pg.pk[table] : undefined;
|
|
30
65
|
|
|
31
66
|
if (!dataTypeID && !extra) return {};
|
|
32
|
-
|
|
33
|
-
const
|
|
67
|
+
|
|
68
|
+
const filterType = filter.type?.toLowerCase() || 'text';
|
|
69
|
+
const fieldType = pg.pgType?.[dataTypeID] || pg.pgType?.[{ date: 1114 }[filterType] || 25];
|
|
34
70
|
|
|
35
71
|
if (!name || !value || !fieldType) return {};
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const query = sql.replace(/\$1/g, `'${min}'::date`).replace(/\$2/g, `'${max}'::date`);
|
|
51
|
-
return { op: '=', query, extra, sql: true };
|
|
72
|
+
|
|
73
|
+
// Date filter
|
|
74
|
+
if (filterType === 'date' /* && dateTypeList.includes(fieldType) */) {
|
|
75
|
+
const [min, max] = getDates(value, name);
|
|
76
|
+
|
|
77
|
+
// check date is valid
|
|
78
|
+
if (!isValidDate(min) || (!isValidDate(max) && value !== 'cd')) {
|
|
79
|
+
return { op: 'between', query: 'false' };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// with sql subquery
|
|
83
|
+
if (sql) {
|
|
84
|
+
return { op: '=', query: sql.replace(/\$1/g, `'${min}'::date`).replace(/\$2/g, `'${max}'::date`) };
|
|
52
85
|
}
|
|
53
86
|
|
|
54
|
-
//
|
|
55
|
-
if (
|
|
56
|
-
|
|
57
|
-
const query = sql.replace(/\$1/g, min).replace(/\$2/g, max);
|
|
58
|
-
return { op: 'between', query, extra, sql: true };
|
|
87
|
+
// preset values
|
|
88
|
+
if (['cw', 'cm', 'cq', 'cy'].includes(value)) {
|
|
89
|
+
return { op: 'between', query: `${name}::date between '${min}'::date and '${max}'::date` };
|
|
59
90
|
}
|
|
60
91
|
|
|
92
|
+
// preset values: current day
|
|
93
|
+
if (value === 'cd') {
|
|
94
|
+
return { op: '=', query: `${name}::date = '${min}'::date` };
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// extra columns, example: crm.extra_data
|
|
98
|
+
if (extra?.table && pk) {
|
|
99
|
+
const query = extra?.table && pk
|
|
100
|
+
? `${pk} in (select object_id from ${extra.table} where property_key='${name}' and value_date::date between '${min}'::date and '${max}'::date)`
|
|
101
|
+
: `${pk} in (select ${pk} from ${extra.table} where ${name}::date between '${min}'::date and '${max}'::date)`;
|
|
102
|
+
return { op: 'between', query };
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// same date
|
|
106
|
+
if (max && min && min === max) {
|
|
107
|
+
return { op: 'strict', query: `${name}::date = '${min}'::date` };
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// default
|
|
111
|
+
return { op: 'between', query: `${name}::date between '${min}'::date and '${max}'::date` };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Range filter, example: 100-500
|
|
115
|
+
if (filterType === 'range' /* && numberTypeList.includes(fieldType) */) {
|
|
116
|
+
const [min, max] = value?.indexOf('_') !== -1 ? value.split('_') : value.split('-');
|
|
117
|
+
|
|
118
|
+
// with sql subquery
|
|
119
|
+
if (sql) {
|
|
120
|
+
return { op: '=', query: sql.replace(/\$1/g, min).replace(/\$2/g, max) };
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (min === 'min' && max === 'max') {
|
|
124
|
+
return { op: 'between', query: 'false' };
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// default
|
|
128
|
+
const query = (max === 'max' ? `${name} > ${min}` : null) || (min === 'min' ? `${name} < ${max}` : null) || `${name} between ${min} and ${max}`;
|
|
129
|
+
return { op: 'between', query };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Autocomplete, Check, Text filter with sql subquery
|
|
133
|
+
if (sql) {
|
|
61
134
|
// autocomplete, check
|
|
62
135
|
if (sql?.indexOf('any($1)') !== -1) {
|
|
63
136
|
const query = sql.replace(/= ?any\(\$1\)/g, `::text=any('{ ${value} }'::text[])`);
|
|
64
|
-
return { op: '=', query
|
|
137
|
+
return { op: '=', query };
|
|
65
138
|
}
|
|
66
139
|
|
|
67
|
-
//
|
|
140
|
+
// default
|
|
68
141
|
const query = sql.replace(/\$1/g, `'${value}'`);
|
|
69
|
-
return { op: '=', query
|
|
142
|
+
return { op: '=', query };
|
|
70
143
|
}
|
|
71
144
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
return { op: '=', query, extra };
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// date range
|
|
85
|
-
if (dateTypeList.includes(fieldType) && value?.includes('_')) {
|
|
86
|
-
const [min, max] = value.split('_');
|
|
87
|
-
const query = `${name} >= '${min}'::date and ${name} <= '${max}'::date`;
|
|
88
|
-
return { op: 'between', query, extra };
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// v3 filter date range, example - "01.01.2024-31.12.2024"
|
|
92
|
-
if (dateTypeList.includes(fieldType) && value?.includes('.') && value?.indexOf('-') === 10 && value?.length === 21) {
|
|
93
|
-
const [startDate, endDate] = value.split('-');
|
|
94
|
-
const min = formatDateISOString(startDate);
|
|
95
|
-
const max = formatDateISOString(endDate);
|
|
96
|
-
|
|
97
|
-
if (!isValidDate(startDate) || !isValidDate(endDate)) {
|
|
98
|
-
return { op: 'between', query: 'false', extra };
|
|
99
|
-
}
|
|
145
|
+
const matchNull = { null: 'is null', notnull: 'is not null' }[value];
|
|
146
|
+
const matchBoolean = fieldType === 'boolean' ? { true: 'is true', false: 'is false' }[value] : null;
|
|
147
|
+
const matchMulti = value?.indexOf(',') !== -1 ? `= any('{${value}}'::text[])` : null;
|
|
148
|
+
const match = matchNull || matchBoolean || matchMulti || (operator === '=' ? `='${value}'` : `ilike '%${value}%'`);
|
|
149
|
+
|
|
150
|
+
/* select query - from admin.cls / filter options */
|
|
151
|
+
if (['check', 'autocomplete', 'text', 'tags', 'avatar', 'radio'].includes(filterType)) {
|
|
152
|
+
|
|
153
|
+
// extra table, example: crm.extra_data
|
|
100
154
|
if (extra?.table && pk) {
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
155
|
+
const subquery = filterType === 'autocomplete' ? match : `in ( ( with q(id,name) as (${select}) select id from q where name::text ${match}))`;
|
|
156
|
+
const query = select
|
|
157
|
+
? `${pk} in (select object_id from ${extra.table} where property_key='${name}' and value_text ${subquery} )`
|
|
158
|
+
: `${pk} in (select object_id from ${extra.table} where property_key='${name}' and value_text ${match})`;
|
|
159
|
+
return { op: operator, query };
|
|
105
160
|
}
|
|
106
|
-
|
|
161
|
+
|
|
162
|
+
// default
|
|
163
|
+
const query = select && filterType === 'text'
|
|
164
|
+
? `${name}::text in ( ( with q(id,name) as (${select}) select id from q where name::text ${match}) )` // filter with cls
|
|
165
|
+
: `${name}::text ${match}`; // simple filter
|
|
166
|
+
return { op: operator, query };
|
|
107
167
|
}
|
|
108
168
|
|
|
109
169
|
// my rows
|
|
110
|
-
if (value === 'me' && uid
|
|
111
|
-
|
|
170
|
+
if (value === 'me' && uid) {
|
|
171
|
+
if (sql) {
|
|
172
|
+
return { op: '=', query: sql.replace(/\$1/g, `'${uid}'`) };
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const query = extra?.table && pk && fieldType === 'text'
|
|
112
176
|
? `${pk} in (select ${pk} from ${extra.table} where uid = '${uid}')`
|
|
113
177
|
: `${name}::text = '${uid}'`;
|
|
114
|
-
return { op: '=', query
|
|
178
|
+
return { op: '=', query };
|
|
115
179
|
}
|
|
116
180
|
|
|
117
181
|
const formatType = {
|
|
@@ -123,6 +187,7 @@ function formatValue({
|
|
|
123
187
|
geometry: 'geom',
|
|
124
188
|
}[fieldType] || 'text';
|
|
125
189
|
|
|
190
|
+
// sql column?
|
|
126
191
|
if (optimize && optimize.name !== optimize.pk) {
|
|
127
192
|
const val = filterType === 'text' ? `ilike '%${value}%'` : `= any('{${value}}')`;
|
|
128
193
|
return {
|
|
@@ -134,49 +199,33 @@ function formatValue({
|
|
|
134
199
|
};
|
|
135
200
|
}
|
|
136
201
|
|
|
202
|
+
// filter text array column
|
|
137
203
|
if (fieldType?.includes('[]')) {
|
|
138
|
-
return { op: 'in', query: `'{${value}}'::text[] && ${name}::text[]
|
|
204
|
+
return { op: 'in', query: `'{${value}}'::text[] && ${name}::text[]` };
|
|
139
205
|
}
|
|
140
206
|
|
|
141
|
-
// multiple
|
|
207
|
+
// filter multiple values, example: 1,2,3
|
|
142
208
|
if (value?.indexOf(',') !== -1) {
|
|
143
209
|
const values = value.split(',').filter((el) => el !== 'null');
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
: `${pk} in (select object_id from ${extra?.table} where property_key='${name}' and value_text in (${values?.map((el) => `'"${el}"'`).join(',')}) )`;
|
|
148
|
-
return { op: 'in', query, extra };
|
|
149
|
-
} else if (extra?.mode === 'property' && pk) {
|
|
210
|
+
|
|
211
|
+
// extra table, example: crm.extra_data
|
|
212
|
+
if (extra?.table && pk) {
|
|
150
213
|
const query = value?.indexOf('null') !== -1
|
|
151
|
-
? `${pk} in (select
|
|
152
|
-
: `${pk} in (select
|
|
153
|
-
return { op: 'in', query
|
|
214
|
+
? `${pk} in (select object_id from ${extra.table} where property_key='${name}' and ( value_text is null or value_text in (${values?.map((el) => `'"${el}"'`).join(',')}) ) )`
|
|
215
|
+
: `${pk} in (select object_id from ${extra.table} where property_key='${name}' and value_text in (${values?.map((el) => `'"${el}"'`).join(',')}) )`;
|
|
216
|
+
return { op: 'in', query };
|
|
154
217
|
}
|
|
155
218
|
|
|
219
|
+
// default
|
|
156
220
|
const query = value?.indexOf('null') !== -1
|
|
157
221
|
? `( ${name} is null or ${name}::text in (${values?.map((el) => `'${el}'`).join(',')}) )`
|
|
158
222
|
: `${name}::text in (${value.split(',')?.map((el) => `'${el}'`).join(',')})`;
|
|
159
|
-
return { op: 'in', query
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// v3 filter number range, example - "100_500"
|
|
163
|
-
if (numberTypeList.includes(fieldType) && value?.indexOf('_') !== -1) {
|
|
164
|
-
const [min, max] = value.split('_');
|
|
165
|
-
const query = (max === 'max' ? `${name} > ${min}` : null) || (min === 'min' ? `${name} <= ${max}` : null) || `${name} between ${min} and ${max}`;
|
|
166
|
-
return { op: 'between', query, extra };
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// number range
|
|
170
|
-
if (numberTypeList.includes(fieldType) && value?.indexOf('-') !== -1) {
|
|
171
|
-
const [min, max] = value.split('-');
|
|
172
|
-
if (min === 'min' && max === 'max') return {};
|
|
173
|
-
const query = (max === 'max' ? `${name} > ${min}` : null) || (min === 'min' ? `${name} < ${max}` : null) || `${name} between ${min} and ${max}`;
|
|
174
|
-
return { op: 'between', query, extra };
|
|
223
|
+
return { op: 'in', query };
|
|
175
224
|
}
|
|
176
225
|
|
|
177
226
|
if (['<', '>'].includes(operator)) {
|
|
178
227
|
const query = `${name} ${operator} '${value}'::${formatType}`;
|
|
179
|
-
return { op: operator, query
|
|
228
|
+
return { op: operator, query };
|
|
180
229
|
}
|
|
181
230
|
|
|
182
231
|
if (operator === '=' && filterType !== 'text' && !filter?.data) {
|
|
@@ -184,39 +233,14 @@ function formatValue({
|
|
|
184
233
|
null: `${name} is null`,
|
|
185
234
|
notnull: `${name} is not null`,
|
|
186
235
|
}[value] || `${name}::${formatType}='${value}'::${formatType}`;
|
|
187
|
-
return { op: '=', query
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
if (['~', '='].includes(operator)) {
|
|
191
|
-
const operator1 = (filterType === 'text' && (filter?.id || filter?.name) && operator === '=' ? '~' : operator);
|
|
192
|
-
const matchNull = { null: 'is null', notnull: 'is not null' }[value];
|
|
193
|
-
const matchBoolean = fieldType === 'boolean' ? { true: 'is true', false: 'is false' }[value] : null;
|
|
194
|
-
const match = matchNull || matchBoolean || ((operator1 === '=' || filterType === 'autocomplete') ? `='${value}'` : `ilike '%${value}%'`);
|
|
195
|
-
|
|
196
|
-
if (extra?.mode === 'property' && pk) {
|
|
197
|
-
const query = data && sql
|
|
198
|
-
? `${pk} in (select object_id from ${extra?.table} where property_key='${name}' and value_text in ( ( with q(id,name) as (${sql}) select id from q where ${filterType === 'autocomplete' ? 'id' : 'name'} ${match})))`
|
|
199
|
-
: `${pk} in (select object_id from ${extra?.table} where property_key='${name}' and value_text ${match})`;
|
|
200
|
-
return { op: 'ilike', query, extra };
|
|
201
|
-
} else if (extra?.mode === 'column') {
|
|
202
|
-
const query = data && sql
|
|
203
|
-
? `${pk} in (select ${pk} from ${extra?.table} where "${name}" in ( ( with q(id,name) as (${sql}) select id from q where ${filterType === 'autocomplete' ? 'id' : 'name'} ${match})))`
|
|
204
|
-
: `${pk} in (select ${pk} from ${extra?.table} where "${name}" ${match})`;
|
|
205
|
-
return { op: 'ilike', query, extra };
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
const query = data && sql && filterType == 'text'
|
|
209
|
-
? `${name || filter?.id} in ( ( with q(id,name) as (${sql}) select id from q where ${filterType === 'autocomplete' ? 'id' : 'name'}::text ${match}) )` // filter with cls
|
|
210
|
-
: `${name}::text ${match}`; // simple filter
|
|
211
|
-
// console.log(query);
|
|
212
|
-
return { op: 'ilike', query, extra };
|
|
236
|
+
return { op: '=', query };
|
|
213
237
|
}
|
|
214
238
|
|
|
215
239
|
// json
|
|
216
240
|
if (name.includes('.')) {
|
|
217
241
|
const [col, prop] = name.split('.');
|
|
218
242
|
const query = ` ${col}->>'${prop}' in ('${value.join("','")}')`;
|
|
219
|
-
return { op: 'in', query
|
|
243
|
+
return { op: 'in', query };
|
|
220
244
|
}
|
|
221
245
|
|
|
222
246
|
// geometry
|
|
@@ -225,7 +249,7 @@ function formatValue({
|
|
|
225
249
|
|
|
226
250
|
if (bbox?.length === 4) {
|
|
227
251
|
const query = ` ${name} && 'box(${bbox[0]} ${bbox[1]},${bbox[2]} ${bbox[3]})'::box2d `;
|
|
228
|
-
return { op: '&&', query
|
|
252
|
+
return { op: '&&', query };
|
|
229
253
|
}
|
|
230
254
|
}
|
|
231
255
|
return {};
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
async function getCustomQuery({
|
|
2
|
-
pg, table, customFilter,
|
|
3
|
-
}) {
|
|
4
|
-
if (!customFilter) return null;
|
|
5
|
-
const customFilterList = customFilter?.split(',')?.map((el) => el?.split('_').pop());
|
|
6
|
-
const { property_json: customFilterSQL } = await pg.one(`select json_agg(json_build_object('id',property_id,'name',property_key,'query',property_text)
|
|
7
|
-
) as property_json from admin.properties where property_key is not null and property_entity='customQuery' and object_id=$1`, [table]);
|
|
8
|
-
const data = customFilterSQL?.length ? customFilterSQL.filter((el) => customFilterList.includes(el.id)) || [] : [];
|
|
9
|
-
const customQuery = data?.map((el) => el.query).join(' and ');
|
|
10
|
-
return `${customQuery}`;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export default getCustomQuery;
|
|
1
|
+
async function getCustomQuery({
|
|
2
|
+
pg, table, customFilter,
|
|
3
|
+
}) {
|
|
4
|
+
if (!customFilter) return null;
|
|
5
|
+
const customFilterList = customFilter?.split(',')?.map((el) => el?.split('_').pop());
|
|
6
|
+
const { property_json: customFilterSQL } = await pg.one(`select json_agg(json_build_object('id',property_id,'name',property_key,'query',property_text)
|
|
7
|
+
) as property_json from admin.properties where property_key is not null and property_entity='customQuery' and object_id=$1`, [table]);
|
|
8
|
+
const data = customFilterSQL?.length ? customFilterSQL.filter((el) => customFilterList.includes(el.id)) || [] : [];
|
|
9
|
+
const customQuery = data?.map((el) => el.query).join(' and ');
|
|
10
|
+
return `${customQuery}`;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export default getCustomQuery;
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
import formatValue from './formatValue.js';
|
|
10
10
|
|
|
11
11
|
function getQuery({
|
|
12
|
-
pg, filter: filterStr, table, tableSQL, fields, filterList,
|
|
12
|
+
pg, filter: filterStr, table, tableSQL, fields, filterList, uid,
|
|
13
13
|
}) {
|
|
14
14
|
if (!filterStr) return null; // filter list API
|
|
15
15
|
|
|
@@ -21,8 +21,8 @@ function getQuery({
|
|
|
21
21
|
|
|
22
22
|
for (let i = 0; i < filterQueryArray.length; i += 1) {
|
|
23
23
|
const item = filterQueryArray[i];
|
|
24
|
-
const
|
|
25
|
-
const [name] = item.split(
|
|
24
|
+
const splitby = mainOperators?.find((el) => item.indexOf(el) !== -1) || '=';
|
|
25
|
+
const [name] = item.split(splitby);
|
|
26
26
|
|
|
27
27
|
// skip already added filter
|
|
28
28
|
if (resultList.find((el) => el.name === name)) {
|
|
@@ -30,10 +30,12 @@ function getQuery({
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
// filter
|
|
33
|
-
const filter = filterList?.find((el) =>
|
|
33
|
+
const filter = filterList?.find?.((el) => el.type && el.name === name) || { type: 'text' };
|
|
34
|
+
const { strict, extra } = filter;
|
|
35
|
+
const operator = filter.strict || ['check', 'autocomplete'].includes(filter.type.toLowerCase()) ? '=' : (splitby !== '=' ? splitby : '~');
|
|
34
36
|
|
|
35
37
|
// find all value
|
|
36
|
-
const value = filterQueryArray.filter((el) => el.
|
|
38
|
+
const value = filterQueryArray.filter((el) => el.split(splitby)?.[0] === name).map((el) => el.substring(name.length + 1)).join(',');
|
|
37
39
|
|
|
38
40
|
const optimize = fields?.find((el) => el.name === name) ? null : tableSQL.find((el) => el.name === name);
|
|
39
41
|
|
|
@@ -52,11 +54,12 @@ function getQuery({
|
|
|
52
54
|
value,
|
|
53
55
|
operator,
|
|
54
56
|
dataTypeID,
|
|
57
|
+
uid,
|
|
55
58
|
}) || {};
|
|
56
59
|
if (!query) continue;
|
|
57
60
|
|
|
58
61
|
resultList.push({
|
|
59
|
-
name, value, query, operator: op, filterType, type: fieldType,
|
|
62
|
+
name, value, query, operator: op, filterType, type: fieldType, strict, extra,
|
|
60
63
|
});
|
|
61
64
|
}
|
|
62
65
|
|
|
@@ -1,12 +1,6 @@
|
|
|
1
|
-
function getOptimizedQuery({
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const sqlList = body?.sql?.filter((el) => !el.disabled && el?.sql?.replace && (count ? el.count !== false : true))
|
|
7
|
-
.map((el) => ` left join lateral (${el.filter ? el.sql.replace(/limit 1/ig, '') : el.sql}) as ${el.name} on 1=1 `).join(' ');
|
|
8
|
-
|
|
9
|
-
return `(select * from ${tableName} t ${sqlList ? ` ${sqlList}` : ''} ${extraSqlList || ''} where 1=1 and ${q?.replace('q.', 't.') || '1=1'} ${order})q`;
|
|
1
|
+
export default function getOptimizedQuery({ table, orderby, sqlTable, sqlInline, extraSqlColumns, q }, count) {
|
|
2
|
+
if (sqlInline) {
|
|
3
|
+
return `(select * ${extraSqlColumns || ''} ${sqlInline ? sqlInline : ''} from ${table} t ${sqlTable && count ? ` ${sqlTable}` : ''})q where 1=1 and ${q ? q.replace('q.', 't.') : '1=1'} ${orderby ? `order by ${orderby}` : ''}`;
|
|
4
|
+
}
|
|
5
|
+
return `(select * ${extraSqlColumns || ''} ${sqlInline ? sqlInline : ''} from ${table} t ${sqlTable && count ? ` ${sqlTable}` : ''} where 1=1 and ${q ? q.replace('q.', 't.') : '1=1'} ${orderby ? `order by ${orderby}` : ''})q`;
|
|
10
6
|
}
|
|
11
|
-
|
|
12
|
-
export default getOptimizedQuery;
|
|
@@ -1,34 +1,34 @@
|
|
|
1
|
-
function getTable(table) {
|
|
2
|
-
const result = table?.toLowerCase()?.replace(/[\n\r]+/g, ' ')?.split(' from ')?.filter((el) => /^[a-z0-9_]+\.[a-z0-9_]+/.test(el))
|
|
3
|
-
?.map((el) => el.split(/[ )]/)[0]);
|
|
4
|
-
return result;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* @param {Number} opt.json - (1|0) 1 - Результат - Object, 0 - String
|
|
9
|
-
* @param {String} opt.query - запит до таблиці
|
|
10
|
-
* @param {String} opt.hash - інформація з хешу по запиту
|
|
11
|
-
*/
|
|
12
|
-
const tableSql = {};
|
|
13
|
-
async function getTableSql({
|
|
14
|
-
pg, body, table, fields,
|
|
15
|
-
}) {
|
|
16
|
-
if (tableSql[table]) return tableSql[table];
|
|
17
|
-
|
|
18
|
-
const fieldList = fields.map((el) => el.name);
|
|
19
|
-
|
|
20
|
-
const tableList = body?.sql?.map((el) => getTable(el.sql)).reduce((acc, el) => acc.concat(el), []).filter((el) => fieldList.includes(pg.pk[el]));
|
|
21
|
-
|
|
22
|
-
if (!tableList) { tableSql[table] = []; return []; }
|
|
23
|
-
|
|
24
|
-
const data = await Promise.all(tableList?.map(async (tableEl) => {
|
|
25
|
-
const { fields: fieldsEl } = await pg.query(`select * from ${tableEl} limit 0`);
|
|
26
|
-
return fieldsEl.map((el) => ({ name: el.name, table: tableEl, pk: pg.pk[tableEl] }));
|
|
27
|
-
}));
|
|
28
|
-
|
|
29
|
-
tableSql[table] = data.reduce((acc, el) => acc.concat(el), []);
|
|
30
|
-
|
|
31
|
-
return tableSql[table];
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export default getTableSql;
|
|
1
|
+
function getTable(table) {
|
|
2
|
+
const result = table?.toLowerCase()?.replace(/[\n\r]+/g, ' ')?.split(' from ')?.filter((el) => /^[a-z0-9_]+\.[a-z0-9_]+/.test(el))
|
|
3
|
+
?.map((el) => el.split(/[ )]/)[0]);
|
|
4
|
+
return result;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @param {Number} opt.json - (1|0) 1 - Результат - Object, 0 - String
|
|
9
|
+
* @param {String} opt.query - запит до таблиці
|
|
10
|
+
* @param {String} opt.hash - інформація з хешу по запиту
|
|
11
|
+
*/
|
|
12
|
+
const tableSql = {};
|
|
13
|
+
async function getTableSql({
|
|
14
|
+
pg, body, table, fields,
|
|
15
|
+
}) {
|
|
16
|
+
if (tableSql[table]) return tableSql[table];
|
|
17
|
+
|
|
18
|
+
const fieldList = fields.map((el) => el.name);
|
|
19
|
+
|
|
20
|
+
const tableList = body?.sql?.map((el) => getTable(el.sql)).reduce((acc, el) => acc.concat(el), []).filter((el) => fieldList.includes(pg.pk[el]));
|
|
21
|
+
|
|
22
|
+
if (!tableList) { tableSql[table] = []; return []; }
|
|
23
|
+
|
|
24
|
+
const data = await Promise.all(tableList?.map(async (tableEl) => {
|
|
25
|
+
const { fields: fieldsEl } = await pg.query(`select * from ${tableEl} limit 0`);
|
|
26
|
+
return fieldsEl.map((el) => ({ name: el.name, table: tableEl, pk: pg.pk[tableEl] }));
|
|
27
|
+
}));
|
|
28
|
+
|
|
29
|
+
tableSql[table] = data.reduce((acc, el) => acc.concat(el), []);
|
|
30
|
+
|
|
31
|
+
return tableSql[table];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export default getTableSql;
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
|
|
4
|
-
import config from '../../../../config.js';
|
|
5
|
-
|
|
6
|
-
const loadTemplate = {};
|
|
7
|
-
|
|
8
|
-
export default async function getTemplateDir(type) {
|
|
9
|
-
if (!type) return null;
|
|
10
|
-
|
|
11
|
-
const cwd = process.cwd();
|
|
12
|
-
const typeDir = path.join(cwd, (config.templateDir || 'server/templates'), type);
|
|
13
|
-
|
|
14
|
-
if (!loadTemplate[type]) {
|
|
15
|
-
const typeList = fs.existsSync(typeDir) ? fs.readdirSync(typeDir) : [];
|
|
16
|
-
loadTemplate[type] = typeList;
|
|
17
|
-
}
|
|
18
|
-
return loadTemplate[type];
|
|
19
|
-
}
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
|
|
4
|
+
import config from '../../../../config.js';
|
|
5
|
+
|
|
6
|
+
const loadTemplate = {};
|
|
7
|
+
|
|
8
|
+
export default async function getTemplateDir(type) {
|
|
9
|
+
if (!type) return null;
|
|
10
|
+
|
|
11
|
+
const cwd = process.cwd();
|
|
12
|
+
const typeDir = path.join(cwd, (config.templateDir || 'server/templates'), type);
|
|
13
|
+
|
|
14
|
+
if (!loadTemplate[type]) {
|
|
15
|
+
const typeList = fs.existsSync(typeDir) ? fs.readdirSync(typeDir) : [];
|
|
16
|
+
loadTemplate[type] = typeList;
|
|
17
|
+
}
|
|
18
|
+
return loadTemplate[type];
|
|
19
|
+
}
|