@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.
Files changed (52) hide show
  1. package/README.md +86 -86
  2. package/package.json +1 -1
  3. package/server/migrations/cls.sql +39 -39
  4. package/server/plugins/cron/funcs/addCron.js +130 -130
  5. package/server/plugins/cron/index.js +6 -6
  6. package/server/plugins/crud/funcs/getOpt.js +13 -13
  7. package/server/plugins/crud/funcs/setOpt.js +21 -21
  8. package/server/plugins/crud/funcs/setToken.js +44 -44
  9. package/server/plugins/crud/funcs/utils/getFolder.js +11 -11
  10. package/server/plugins/crud/funcs/validateData.js +3 -3
  11. package/server/plugins/crud/index.js +23 -23
  12. package/server/plugins/hook/index.js +8 -8
  13. package/server/plugins/logger/errorStatus.js +19 -19
  14. package/server/plugins/logger/index.js +26 -26
  15. package/server/plugins/migration/index.js +7 -7
  16. package/server/plugins/pg/funcs/autoIndex.js +2 -2
  17. package/server/plugins/policy/sqlInjection.js +33 -33
  18. package/server/plugins/redis/client.js +8 -8
  19. package/server/plugins/redis/funcs/redisClients.js +3 -3
  20. package/server/plugins/redis/index.js +17 -17
  21. package/server/plugins/table/funcs/getData.js +3 -3
  22. package/server/plugins/table/funcs/getFilterSQL/index.js +68 -50
  23. package/server/plugins/table/funcs/getFilterSQL/util/formatValue.js +143 -119
  24. package/server/plugins/table/funcs/getFilterSQL/util/getCustomQuery.js +13 -13
  25. package/server/plugins/table/funcs/getFilterSQL/util/getFilterQuery.js +9 -6
  26. package/server/plugins/table/funcs/getFilterSQL/util/getOptimizedQuery.js +5 -11
  27. package/server/plugins/table/funcs/getFilterSQL/util/getTableSql.js +34 -34
  28. package/server/plugins/table/funcs/getTemplates.js +19 -19
  29. package/server/plugins/table/funcs/gisIRColumn.js +82 -82
  30. package/server/plugins/table/funcs/loadTemplate.js +1 -1
  31. package/server/plugins/table/funcs/loadTemplatePath.js +1 -1
  32. package/server/plugins/table/funcs/userTemplateDir.js +1 -1
  33. package/server/plugins/table/index.js +13 -13
  34. package/server/plugins/util/index.js +7 -7
  35. package/server/routes/cron/index.js +14 -14
  36. package/server/routes/crud/controllers/table.js +92 -88
  37. package/server/routes/logger/controllers/logger.file.js +92 -92
  38. package/server/routes/logger/controllers/utils/checkUserAccess.js +19 -19
  39. package/server/routes/logger/controllers/utils/getRootDir.js +26 -26
  40. package/server/routes/logger/index.js +17 -17
  41. package/server/routes/properties/controllers/properties.add.js +55 -55
  42. package/server/routes/properties/controllers/properties.get.js +17 -17
  43. package/server/routes/properties/index.js +16 -16
  44. package/server/routes/table/controllers/data.js +12 -7
  45. package/server/routes/table/controllers/filter.js +21 -4
  46. package/server/routes/table/controllers/form.js +42 -42
  47. package/server/routes/table/controllers/search.js +74 -74
  48. package/server/routes/table/controllers/suggest.js +2 -2
  49. package/server/routes/table/index.js +29 -29
  50. package/server/routes/table/schema.js +64 -64
  51. package/server/routes/util/controllers/status.monitor.js +8 -8
  52. 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 { data, sql, extra, filtersql } = filter;
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
- // const fieldType = extra ? pg.pgType?.[{ Date: 1114 }[filter?.type] || 25] : pg.pgType?.[dataTypeID];
33
- const fieldType = pg.pgType?.[dataTypeID] || pg.pgType?.[{ Date: 1114 }[filter?.type || ''] || 25];
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
- const filterType = filter.type?.toLowerCase();
37
-
38
- // body.filterSql
39
- if (sql && filtersql) {
40
- // date range
41
- if (filterType === 'date') {
42
- const [startDate, endDate] = value.split('-');
43
- const min = formatDateISOString(startDate);
44
- const max = formatDateISOString(endDate);
45
-
46
- if (!isValidDate(startDate) || !isValidDate(endDate)) {
47
- return { op: 'between', query: 'false', extra, sql: true };
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
- // num range
55
- if (filterType === 'range') {
56
- const [min, max] = value?.indexOf('_') !== -1 ? value.split('_') : value.split('-');
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, extra, sql: true };
137
+ return { op: '=', query };
65
138
  }
66
139
 
67
- // text
140
+ // default
68
141
  const query = sql.replace(/\$1/g, `'${value}'`);
69
- return { op: '=', query, extra, sql: true };
142
+ return { op: '=', query };
70
143
  }
71
144
 
72
- // current day, week, month, year etc.
73
- if (dateTypeList.includes(fieldType) && !value?.includes('_') && ['cd', 'cw', 'cm', 'cq', 'cy'].includes(value)) {
74
- const query = {
75
- cd: `${name}::date = '${dt(dp.y, dp.m, dp.d)}'::date`,
76
- cw: `${name}::date >= '${dt(dp.y, dp.m, dp.w)}'::date and ${name} <= '${dt(dp.y, dp.m, dp.w + 6)}'::date`,
77
- cm: `${name}::date >= '${dt(dp.y, dp.m, 1)}'::date and ${name} <= '${dt(dp.y, dp.m + 1, 0)}'::date`,
78
- cq: `${name}::date >= '${dt(dp.y, dp.q, 1)}'::date and ${name} <= '${dt(dp.y, dp.q + 3, 0)}'::date`,
79
- cy: `${name}::date >= '${dt(dp.y, 0, 1)}'::date and ${name}::date <= '${dt(dp.y, 11, 31)}'::date`,
80
- }[value];
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 query = extra?.mode === 'property' && pk
102
- ? `${pk} in (select object_id from ${extra.table} where property_key='${name}' and value_date::date >= '${min}'::date and value_date::date <= '${max}'::date)`
103
- : `${pk} in (select ${pk} from ${extra.table} where ${name}::date >= '${min}'::date and ${name}::date <= '${max}'::date)`;
104
- return { op: 'between', query, extra };
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
- return { op: 'between', query: `${name}::date >= '${min}'::date and ${name}::date <= '${max}'::date`, extra };
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 && fieldType === 'text') {
111
- const query = extra?.table && pk
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, extra };
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[]`, extra };
204
+ return { op: 'in', query: `'{${value}}'::text[] && ${name}::text[]` };
139
205
  }
140
206
 
141
- // multiple items of 1 param
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
- if (extra?.mode === 'property' && pk) {
145
- const query = value?.indexOf('null') !== -1
146
- ? `${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(',')}) ) )`
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 ${pk} from ${extra?.table} where ( "${name}" is null or "${name}" in (${values?.map((el) => `'"${el}"'`).join(',')}) ) )`
152
- : `${pk} in (select ${pk} from ${extra?.table} where "${name}" in (${values?.map((el) => `'"${el}"'`).join(',')}) )`;
153
- return { op: 'in', query, extra };
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, extra };
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, extra };
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, extra };
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, extra };
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, extra };
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 operator = mainOperators?.find((el) => item.indexOf(el) !== -1) || '=';
25
- const [name] = item.split(operator);
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) => [el.id, el.name].includes(name)) || { type: 'text' };
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.startsWith(name)).map((el) => el.substring(name.length + 1)).join(',');
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({ body, extraSqlList, table, q }, count) {
2
- const order = body?.orderby || body?.order ? `order by ${body?.orderby || body?.order}` : '';
3
-
4
- const tableName = body?.table || body?.model || table;
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
+ }