@opengis/fastify-table 1.0.97 → 1.1.1
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/.eslintrc.cjs +42 -42
- package/README.md +26 -26
- package/config.js +10 -10
- package/cron/controllers/cronApi.js +22 -22
- package/cron/controllers/utils/cronList.js +1 -1
- package/cron/funcs/addCron.js +131 -131
- package/cron/index.js +10 -10
- package/crud/controllers/utils/checkXSS.js +45 -45
- package/crud/controllers/utils/xssInjection.js +72 -72
- package/crud/funcs/dataUpdate.js +30 -30
- package/crud/funcs/getToken.js +27 -27
- package/crud/funcs/isFileExists.js +13 -13
- package/crud/funcs/setToken.js +53 -53
- package/crud/funcs/utils/logChanges.js +7 -4
- package/notification/controllers/testEmail.js +49 -49
- package/notification/funcs/utils/sendEmail.js +39 -39
- package/notification/index.js +38 -38
- package/package.json +1 -1
- package/pg/funcs/getPG.js +30 -30
- package/redis/funcs/getRedis.js +23 -23
- package/server/migrations/crm.sql +150 -150
- package/server/migrations/log.sql +80 -80
- package/server/templates/select/test.storage.data.json +3 -3
- package/server/templates/select/test.suggest.ato_new.json +2 -2
- package/server/templates/select/test.suggest.ato_new.sql +25 -25
- package/server/templates/select/test.suggest.data.json +4 -4
- package/server/templates/select/test.suggest.parent.sql +2 -2
- package/server.js +14 -14
- package/table/controllers/card.js +44 -44
- package/table/controllers/filter.js +37 -37
- package/table/controllers/form.js +28 -28
- package/table/controllers/search.js +80 -72
- package/table/controllers/utils/getSelect.js +20 -20
- package/table/controllers/utils/getTemplate.js +69 -28
- package/table/controllers/utils/getTemplatePath.js +40 -0
- package/table/controllers/utils/getTemplate_old.js +28 -0
- package/table/controllers/utils/getTemplates.js +18 -18
- package/table/controllers/utils/loadTemplate.js +1 -0
- package/table/controllers/utils/loadTemplatePath.js +1 -0
- package/table/index.js +84 -80
- package/test/api/crud.xss.test.js +72 -72
- package/test/api/notification.test.js +37 -37
- package/test/api/suggest.test.js +65 -65
- package/test/config.example +18 -18
- package/test/funcs/notification.test.js +31 -31
- package/test/funcs/pg.test.js +34 -34
- package/test/funcs/redis.test.js +19 -19
- package/test/templates/cls/test.json +9 -9
- package/test/templates/form/cp_building.form.json +32 -32
- package/test/templates/select/account_id.json +3 -3
- package/test/templates/select/storage.data.json +2 -2
- package/test/templates/table/gis.dataset.table.json +20 -20
- package/util/controllers/logger.file.js +90 -90
- package/util/controllers/next.id.js +4 -4
- package/util/controllers/properties.get.js +19 -19
- package/util/controllers/utils/checkUserAccess.js +19 -19
- package/util/controllers/utils/getRootDir.js +20 -20
- package/util/index.js +23 -23
- package/utils.js +8 -0
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
select
|
|
2
|
-
codifier,
|
|
3
|
-
case
|
|
4
|
-
when object_type = 'A' then name_ua
|
|
5
|
-
else case
|
|
6
|
-
when object_type in ('P', 'H', 'O', 'B') then name_ua || ' ' || prefix_ua
|
|
7
|
-
else prefix_ua || ' ' || name_ua
|
|
8
|
-
end
|
|
9
|
-
end as title
|
|
10
|
-
from
|
|
11
|
-
ato_new.ato_new_all
|
|
12
|
-
left join ato_new.ato_settings_city_and_terrytory on ato_type = object_type
|
|
13
|
-
where
|
|
14
|
-
codifier is not null
|
|
15
|
-
union
|
|
16
|
-
all
|
|
17
|
-
select
|
|
18
|
-
country_id,
|
|
19
|
-
name_ua as title
|
|
20
|
-
from
|
|
21
|
-
ato_new.country
|
|
22
|
-
where
|
|
23
|
-
country_id = '2845832997045798794'
|
|
24
|
-
union
|
|
25
|
-
all
|
|
1
|
+
select
|
|
2
|
+
codifier,
|
|
3
|
+
case
|
|
4
|
+
when object_type = 'A' then name_ua
|
|
5
|
+
else case
|
|
6
|
+
when object_type in ('P', 'H', 'O', 'B') then name_ua || ' ' || prefix_ua
|
|
7
|
+
else prefix_ua || ' ' || name_ua
|
|
8
|
+
end
|
|
9
|
+
end as title
|
|
10
|
+
from
|
|
11
|
+
ato_new.ato_new_all
|
|
12
|
+
left join ato_new.ato_settings_city_and_terrytory on ato_type = object_type
|
|
13
|
+
where
|
|
14
|
+
codifier is not null
|
|
15
|
+
union
|
|
16
|
+
all
|
|
17
|
+
select
|
|
18
|
+
country_id,
|
|
19
|
+
name_ua as title
|
|
20
|
+
from
|
|
21
|
+
ato_new.country
|
|
22
|
+
where
|
|
23
|
+
country_id = '2845832997045798794'
|
|
24
|
+
union
|
|
25
|
+
all
|
|
26
26
|
select 'UA00000000000000000', 'Україна'
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
{
|
|
2
|
-
"db": "mbk_poltava",
|
|
3
|
-
"key": "dataset_id",
|
|
4
|
-
"searchColumn": "table_name"
|
|
1
|
+
{
|
|
2
|
+
"db": "mbk_poltava",
|
|
3
|
+
"key": "dataset_id",
|
|
4
|
+
"searchColumn": "table_name"
|
|
5
5
|
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
select dataset_id, dataset_name, table_name from gis.dataset
|
|
2
|
-
where
|
|
1
|
+
select dataset_id, dataset_name, table_name from gis.dataset
|
|
2
|
+
where
|
|
3
3
|
dataset_id = '{{parent}}'
|
package/server.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
// This file contains code that we reuse
|
|
2
|
-
// between our tests.
|
|
3
|
-
import Fastify from 'fastify';
|
|
4
|
-
import config from './test/config.js';
|
|
5
|
-
import appService from './index.js';
|
|
6
|
-
|
|
7
|
-
const app = Fastify({ logger: false });
|
|
8
|
-
app.register(appService, config);
|
|
9
|
-
app.listen({ host: '0.0.0.0', port: process.env.PORT || 3000 }, (err) => {
|
|
10
|
-
if (err) {
|
|
11
|
-
app.log.error(err);
|
|
12
|
-
process.exit(1);
|
|
13
|
-
}
|
|
14
|
-
});
|
|
1
|
+
// This file contains code that we reuse
|
|
2
|
+
// between our tests.
|
|
3
|
+
import Fastify from 'fastify';
|
|
4
|
+
import config from './test/config.js';
|
|
5
|
+
import appService from './index.js';
|
|
6
|
+
|
|
7
|
+
const app = Fastify({ logger: false });
|
|
8
|
+
app.register(appService, config);
|
|
9
|
+
app.listen({ host: '0.0.0.0', port: process.env.PORT || 3000 }, (err) => {
|
|
10
|
+
if (err) {
|
|
11
|
+
app.log.error(err);
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
});
|
|
@@ -1,44 +1,44 @@
|
|
|
1
|
-
import getTemplate from './utils/getTemplate.js';
|
|
2
|
-
import getMeta from '../../pg/funcs/getMeta.js';
|
|
3
|
-
import metaFormat from '../funcs/metaFormat/index.js';
|
|
4
|
-
|
|
5
|
-
export default async function card(req) {
|
|
6
|
-
const time = Date.now();
|
|
7
|
-
const {
|
|
8
|
-
pg, params = {}, query = {}, opt = {},
|
|
9
|
-
} = req;
|
|
10
|
-
|
|
11
|
-
const loadTable = await getTemplate('table', params.table);
|
|
12
|
-
|
|
13
|
-
if (!loadTable) { return { message: 'template not found', status: 404 }; }
|
|
14
|
-
|
|
15
|
-
const {
|
|
16
|
-
table, columns, meta, sql, cardSql,
|
|
17
|
-
} = loadTable;
|
|
18
|
-
|
|
19
|
-
const { pk, columns: dbColumns = [] } = await getMeta(table);
|
|
20
|
-
|
|
21
|
-
if (!pk) return { message: `table not found: ${table}`, status: 404 };
|
|
22
|
-
|
|
23
|
-
const cols = columns.map((el) => el.name || el).join(',');
|
|
24
|
-
const columnList = dbColumns.map((el) => el.name || el).join(',');
|
|
25
|
-
const sqlTable = sql?.filter?.((el) => !el?.disabled && el?.sql?.replace).map((el, i) => ` left join lateral (${el.sql}) ${el.name || `t${i}`} on 1=1 `)?.join('') || '';
|
|
26
|
-
const cardSqlFiltered = opt.id || params.id ? cardSql?.filter?.((el) => !el?.disabled && el?.name && el?.sql?.replace) : [];
|
|
27
|
-
const cardSqlTable = cardSqlFiltered?.length ? cardSqlFiltered.map((el, i) => ` left join lateral (select json_agg(row_to_json(q)) as ${el.name} from (${el.sql})q) ct${i} on 1=1 `).join('') || '' : '';
|
|
28
|
-
|
|
29
|
-
const where = [`"${pk}" = $1`, loadTable.query].filter((el) => el);
|
|
30
|
-
const cardColumns = cardSqlFiltered?.length ? `,${cardSqlFiltered.map((el) => el.name)}` : '';
|
|
31
|
-
const q = `select ${pk ? `"${pk}" as id,` : ''} ${columnList.includes('geom') ? 'st_asgeojson(geom)::json as geom,' : ''} ${cols || '*'} ${cardColumns} from ${table} t ${sqlTable} ${cardSqlTable}
|
|
32
|
-
where ${where.join(' and ') || 'true'} limit 1`;
|
|
33
|
-
|
|
34
|
-
if (query.sql === '1') { return q; }
|
|
35
|
-
|
|
36
|
-
const { rows } = await pg.query(q, [opt.id || params.id]);
|
|
37
|
-
|
|
38
|
-
await metaFormat({ rows, table: params.table });
|
|
39
|
-
|
|
40
|
-
const data = meta.card?.length ? meta.card.reduce((acc, curr) => Object.assign(acc, { [columns.find((col) => col.name === curr)?.ua || '']: rows[0][curr] }), {}) : {};
|
|
41
|
-
return {
|
|
42
|
-
time: Date.now() - time, data,
|
|
43
|
-
};
|
|
44
|
-
}
|
|
1
|
+
import getTemplate from './utils/getTemplate.js';
|
|
2
|
+
import getMeta from '../../pg/funcs/getMeta.js';
|
|
3
|
+
import metaFormat from '../funcs/metaFormat/index.js';
|
|
4
|
+
|
|
5
|
+
export default async function card(req) {
|
|
6
|
+
const time = Date.now();
|
|
7
|
+
const {
|
|
8
|
+
pg, params = {}, query = {}, opt = {},
|
|
9
|
+
} = req;
|
|
10
|
+
|
|
11
|
+
const loadTable = await getTemplate('table', params.table);
|
|
12
|
+
|
|
13
|
+
if (!loadTable) { return { message: 'template not found', status: 404 }; }
|
|
14
|
+
|
|
15
|
+
const {
|
|
16
|
+
table, columns, meta, sql, cardSql,
|
|
17
|
+
} = loadTable;
|
|
18
|
+
|
|
19
|
+
const { pk, columns: dbColumns = [] } = await getMeta(table);
|
|
20
|
+
|
|
21
|
+
if (!pk) return { message: `table not found: ${table}`, status: 404 };
|
|
22
|
+
|
|
23
|
+
const cols = columns.map((el) => el.name || el).join(',');
|
|
24
|
+
const columnList = dbColumns.map((el) => el.name || el).join(',');
|
|
25
|
+
const sqlTable = sql?.filter?.((el) => !el?.disabled && el?.sql?.replace).map((el, i) => ` left join lateral (${el.sql}) ${el.name || `t${i}`} on 1=1 `)?.join('') || '';
|
|
26
|
+
const cardSqlFiltered = opt.id || params.id ? cardSql?.filter?.((el) => !el?.disabled && el?.name && el?.sql?.replace) : [];
|
|
27
|
+
const cardSqlTable = cardSqlFiltered?.length ? cardSqlFiltered.map((el, i) => ` left join lateral (select json_agg(row_to_json(q)) as ${el.name} from (${el.sql})q) ct${i} on 1=1 `).join('') || '' : '';
|
|
28
|
+
|
|
29
|
+
const where = [`"${pk}" = $1`, loadTable.query].filter((el) => el);
|
|
30
|
+
const cardColumns = cardSqlFiltered?.length ? `,${cardSqlFiltered.map((el) => el.name)}` : '';
|
|
31
|
+
const q = `select ${pk ? `"${pk}" as id,` : ''} ${columnList.includes('geom') ? 'st_asgeojson(geom)::json as geom,' : ''} ${cols || '*'} ${cardColumns} from ${table} t ${sqlTable} ${cardSqlTable}
|
|
32
|
+
where ${where.join(' and ') || 'true'} limit 1`;
|
|
33
|
+
|
|
34
|
+
if (query.sql === '1') { return q; }
|
|
35
|
+
|
|
36
|
+
const { rows } = await pg.query(q, [opt.id || params.id]);
|
|
37
|
+
|
|
38
|
+
await metaFormat({ rows, table: params.table });
|
|
39
|
+
|
|
40
|
+
const data = meta.card?.length ? meta.card.reduce((acc, curr) => Object.assign(acc, { [columns.find((col) => col.name === curr)?.ua || '']: rows[0][curr] }), {}) : {};
|
|
41
|
+
return {
|
|
42
|
+
time: Date.now() - time, data,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
@@ -1,37 +1,37 @@
|
|
|
1
|
-
import getTemplate from './utils/getTemplate.js';
|
|
2
|
-
import getSelect from './utils/getSelect.js';
|
|
3
|
-
import getMeta from '../../pg/funcs/getMeta.js';
|
|
4
|
-
|
|
5
|
-
export default async function filter(req) {
|
|
6
|
-
const time = Date.now();
|
|
7
|
-
|
|
8
|
-
const {
|
|
9
|
-
params,
|
|
10
|
-
} = req;
|
|
11
|
-
const loadTable = await getTemplate('table', params.table);
|
|
12
|
-
if (!loadTable) { return { status: 404, message: 'not found' }; }
|
|
13
|
-
const { columns } = await getMeta({ table: loadTable.table });
|
|
14
|
-
|
|
15
|
-
const filters = loadTable?.filters || loadTable?.filterList || [];
|
|
16
|
-
await Promise.all(filters.filter((el) => el.data).map(async (el) => {
|
|
17
|
-
const cls = await getSelect(el.data);
|
|
18
|
-
if (!cls?.arr || !loadTable.table) return;
|
|
19
|
-
const { dataTypeID } = columns.find((item) => item.name === el.id) || {};
|
|
20
|
-
const countArr = req.pg.pgType[dataTypeID]?.includes('[]')
|
|
21
|
-
? await req.pg.queryCache(`select unnest(${el.id})::text as id,count(*) from ${loadTable.table} group by unnest(${el.id})`)
|
|
22
|
-
: await req.pg.queryCache(`select ${el.id}::text as id,count(*) from ${loadTable.table} group by ${el.id}`);
|
|
23
|
-
|
|
24
|
-
const options = countArr.rows.map(cel => {
|
|
25
|
-
const data = cls?.arr.find(c => c.id === cel.id);
|
|
26
|
-
return { ...cel, ...data };
|
|
27
|
-
});
|
|
28
|
-
Object.assign(el, { options });
|
|
29
|
-
}));
|
|
30
|
-
return {
|
|
31
|
-
time: Date.now() - time,
|
|
32
|
-
list: filters,
|
|
33
|
-
custom: loadTable?.filterCustom?.map(el => ({ label: el.label })),
|
|
34
|
-
inline: loadTable?.filterInline,
|
|
35
|
-
state: loadTable?.filterState?.map(el => ({ label: el.label })),
|
|
36
|
-
};
|
|
37
|
-
}
|
|
1
|
+
import getTemplate from './utils/getTemplate.js';
|
|
2
|
+
import getSelect from './utils/getSelect.js';
|
|
3
|
+
import getMeta from '../../pg/funcs/getMeta.js';
|
|
4
|
+
|
|
5
|
+
export default async function filter(req) {
|
|
6
|
+
const time = Date.now();
|
|
7
|
+
|
|
8
|
+
const {
|
|
9
|
+
params,
|
|
10
|
+
} = req;
|
|
11
|
+
const loadTable = await getTemplate('table', params.table);
|
|
12
|
+
if (!loadTable) { return { status: 404, message: 'not found' }; }
|
|
13
|
+
const { columns } = await getMeta({ table: loadTable.table });
|
|
14
|
+
|
|
15
|
+
const filters = loadTable?.filters || loadTable?.filterList || [];
|
|
16
|
+
await Promise.all(filters.filter((el) => el.data).map(async (el) => {
|
|
17
|
+
const cls = await getSelect(el.data);
|
|
18
|
+
if (!cls?.arr || !loadTable.table) return;
|
|
19
|
+
const { dataTypeID } = columns.find((item) => item.name === el.id) || {};
|
|
20
|
+
const countArr = req.pg.pgType[dataTypeID]?.includes('[]')
|
|
21
|
+
? await req.pg.queryCache(`select unnest(${el.id})::text as id,count(*) from ${loadTable.table} group by unnest(${el.id})`)
|
|
22
|
+
: await req.pg.queryCache(`select ${el.id}::text as id,count(*) from ${loadTable.table} group by ${el.id}`);
|
|
23
|
+
|
|
24
|
+
const options = countArr.rows.map(cel => {
|
|
25
|
+
const data = cls?.arr.find(c => c.id === cel.id);
|
|
26
|
+
return { ...cel, ...data };
|
|
27
|
+
});
|
|
28
|
+
Object.assign(el, { options });
|
|
29
|
+
}));
|
|
30
|
+
return {
|
|
31
|
+
time: Date.now() - time,
|
|
32
|
+
list: filters,
|
|
33
|
+
custom: loadTable?.filterCustom?.map(el => ({ label: el.label })),
|
|
34
|
+
inline: loadTable?.filterInline,
|
|
35
|
+
state: loadTable?.filterState?.map(el => ({ label: el.label })),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
import getTemplate from './utils/getTemplate.js';
|
|
2
|
-
|
|
3
|
-
const sql = `select property_key as key, property_json as json, property_int as int,
|
|
4
|
-
property_text as text from admin.properties where 1=1`;
|
|
5
|
-
|
|
6
|
-
async function getSettings({ pg }) {
|
|
7
|
-
const { rows = [] } = await pg.query(sql);
|
|
8
|
-
const data = rows.reduce((acc, curr) => Object.assign(acc, { [curr.key]: curr.json || curr.int || curr.text }), {});
|
|
9
|
-
return data;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export default async function formFunction(req) {
|
|
13
|
-
const time = Date.now();
|
|
14
|
-
const { pg, params } = req;
|
|
15
|
-
const form = await getTemplate('form', params.form);
|
|
16
|
-
if (!form) { return { status: 404, message: 'not found' }; }
|
|
17
|
-
|
|
18
|
-
// replace settings
|
|
19
|
-
const arr = JSON.stringify(form).match(/{{settings.([^}]*)}}/g);
|
|
20
|
-
if (arr?.length) {
|
|
21
|
-
const string = JSON.stringify(form);
|
|
22
|
-
const settings = await getSettings({ pg });
|
|
23
|
-
const match = arr.reduce((acc, curr) => Object.assign(acc, { [curr]: settings[curr.replace(/^{{settings./g, '').replace(/}}$/, '')] }), {});
|
|
24
|
-
const res = Object.keys(match).reduce((s, m) => s.replace(m, match[m]), string);
|
|
25
|
-
return { time: Date.now() - time, form: JSON.parse(res) };
|
|
26
|
-
}
|
|
27
|
-
return { time: Date.now() - time, form };
|
|
28
|
-
}
|
|
1
|
+
import getTemplate from './utils/getTemplate.js';
|
|
2
|
+
|
|
3
|
+
const sql = `select property_key as key, property_json as json, property_int as int,
|
|
4
|
+
property_text as text from admin.properties where 1=1`;
|
|
5
|
+
|
|
6
|
+
async function getSettings({ pg }) {
|
|
7
|
+
const { rows = [] } = await pg.query(sql);
|
|
8
|
+
const data = rows.reduce((acc, curr) => Object.assign(acc, { [curr.key]: curr.json || curr.int || curr.text }), {});
|
|
9
|
+
return data;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export default async function formFunction(req) {
|
|
13
|
+
const time = Date.now();
|
|
14
|
+
const { pg, params } = req;
|
|
15
|
+
const form = await getTemplate('form', params.form);
|
|
16
|
+
if (!form) { return { status: 404, message: 'not found' }; }
|
|
17
|
+
|
|
18
|
+
// replace settings
|
|
19
|
+
const arr = JSON.stringify(form).match(/{{settings.([^}]*)}}/g);
|
|
20
|
+
if (arr?.length) {
|
|
21
|
+
const string = JSON.stringify(form);
|
|
22
|
+
const settings = await getSettings({ pg });
|
|
23
|
+
const match = arr.reduce((acc, curr) => Object.assign(acc, { [curr]: settings[curr.replace(/^{{settings./g, '').replace(/}}$/, '')] }), {});
|
|
24
|
+
const res = Object.keys(match).reduce((s, m) => s.replace(m, match[m]), string);
|
|
25
|
+
return { time: Date.now() - time, form: JSON.parse(res) };
|
|
26
|
+
}
|
|
27
|
+
return { time: Date.now() - time, form };
|
|
28
|
+
}
|
|
@@ -1,72 +1,80 @@
|
|
|
1
|
-
import getTemplate from './utils/getTemplate.js';
|
|
2
|
-
import getMeta from '../../pg/funcs/getMeta.js';
|
|
3
|
-
import metaFormat from '../funcs/metaFormat/index.js';
|
|
4
|
-
import getTemplates from './utils/getTemplates.js';
|
|
5
|
-
|
|
6
|
-
function sequence(tables, data, fn) {
|
|
7
|
-
return tables.reduce((promise, table) => promise.then(() => fn({
|
|
8
|
-
...data, tableName: table.replace('.json', ''),
|
|
9
|
-
})), Promise.resolve());
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
async function getData({
|
|
13
|
-
pg, funcs, tableName, query = {}, maxLimit, res,
|
|
14
|
-
}) {
|
|
15
|
-
const loadTable = await getTemplate('table', tableName);
|
|
16
|
-
|
|
17
|
-
if (!loadTable) { return { message: 'not found', status: 404 }; }
|
|
18
|
-
|
|
19
|
-
const {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
await
|
|
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
|
-
|
|
1
|
+
import getTemplate from './utils/getTemplate.js';
|
|
2
|
+
import getMeta from '../../pg/funcs/getMeta.js';
|
|
3
|
+
import metaFormat from '../funcs/metaFormat/index.js';
|
|
4
|
+
import getTemplates from './utils/getTemplates.js';
|
|
5
|
+
|
|
6
|
+
function sequence(tables, data, fn) {
|
|
7
|
+
return tables.reduce((promise, table) => promise.then(() => fn({
|
|
8
|
+
...data, tableName: table.replace('.json', ''),
|
|
9
|
+
})), Promise.resolve());
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async function getData({
|
|
13
|
+
pg, funcs, tableName, query = {}, maxLimit, res,
|
|
14
|
+
}) {
|
|
15
|
+
const loadTable = await getTemplate('table', tableName);
|
|
16
|
+
|
|
17
|
+
if (!loadTable) { return { message: 'not found', status: 404 }; }
|
|
18
|
+
|
|
19
|
+
const {
|
|
20
|
+
table, columns, meta,
|
|
21
|
+
} = loadTable;
|
|
22
|
+
|
|
23
|
+
const { pk } = await getMeta(table);
|
|
24
|
+
|
|
25
|
+
const cols = columns.map((el) => el.name || el).join(',');
|
|
26
|
+
const [orderColumn, orderDir] = (query.order || loadTable.order || '').split('-');
|
|
27
|
+
const order = cols.includes(orderColumn) && orderColumn?.length ? `order by ${orderColumn} ${query.desc || orderDir === 'desc' ? 'desc' : ''}` : '';
|
|
28
|
+
|
|
29
|
+
const limit = Math.max(maxLimit - res.rows.length, 0);
|
|
30
|
+
// Math.max(query.offset - res.rows.length,0)
|
|
31
|
+
const offset = query.page && query.page > 0 ? ` offset ${(query.page - 1) * limit}` : '';
|
|
32
|
+
|
|
33
|
+
const search1 = meta?.search && query.key ? `(${meta?.search.concat(meta?.title ? `,${meta?.title}` : '').split(',').map(el => `${el} ilike '%${query.key}%'`).join(' or ')})` : 'false';
|
|
34
|
+
|
|
35
|
+
const where = [!pk ? 'false' : 'true', loadTable.query, search1].filter((el) => el);
|
|
36
|
+
const q = `select ${[`"${pk}" as id`, meta?.title ? `${meta.title} as title` : ''].filter((el) => el).join(',')} from ${table} t where ${where.join(' and ') || 'true'} ${order} ${offset} limit ${limit}`;
|
|
37
|
+
if (query.sql) {
|
|
38
|
+
res.sql.push(q);
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const { rows } = await pg.query(q);
|
|
43
|
+
|
|
44
|
+
const total = await pg.queryCache(`select count(*) from ${table} t where ${where.join(' and ') || 'true'}`).then((el) => el?.rows[0]?.count) || 0;
|
|
45
|
+
|
|
46
|
+
await metaFormat({ rows, table: tableName });
|
|
47
|
+
res.total += +total;
|
|
48
|
+
rows.forEach((row) => {
|
|
49
|
+
const href = meta?.href ? funcs.handlebars.compile(meta.href)({ ...row, [pk]: row.id }) : undefined;
|
|
50
|
+
res.rows.push({
|
|
51
|
+
...row, register: tableName, register_title: loadTable.ua, href,
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export default async function search({
|
|
58
|
+
pg, funcs, query = {},
|
|
59
|
+
}) {
|
|
60
|
+
const time = Date.now();
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
const tables = query.table ? [query.table] : await getTemplates('table');
|
|
64
|
+
const res = { rows: [], sql: [], total: 0 };
|
|
65
|
+
|
|
66
|
+
const maxLimit = Math.min(100, query.limit || '16');
|
|
67
|
+
await sequence(tables, {
|
|
68
|
+
pg, funcs, query, maxLimit, res,
|
|
69
|
+
}, getData);
|
|
70
|
+
|
|
71
|
+
if (query.sql) return res.sql.join(';\n');
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
time: Date.now() - time, total: res.total, count: res.rows.length, rows: res.rows,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
catch (err) {
|
|
78
|
+
return { error: err.toString(), status: 500 };
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import getTemplate from './getTemplate.js';
|
|
2
|
-
|
|
3
|
-
const loadCls = {};
|
|
4
|
-
|
|
5
|
-
export default async function getSelect(name) {
|
|
6
|
-
if (loadCls[name]) return loadCls[name];
|
|
7
|
-
|
|
8
|
-
const clsData = await getTemplate('cls', name);
|
|
9
|
-
|
|
10
|
-
if (clsData) {
|
|
11
|
-
loadCls[name] = { arr: clsData };
|
|
12
|
-
return loadCls[name];
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const selectData = await getTemplate('select', name);
|
|
16
|
-
if (!selectData) { return null; }
|
|
17
|
-
|
|
18
|
-
loadCls[name] = selectData;
|
|
19
|
-
return loadCls[name];
|
|
20
|
-
}
|
|
1
|
+
import getTemplate from './getTemplate.js';
|
|
2
|
+
|
|
3
|
+
const loadCls = {};
|
|
4
|
+
|
|
5
|
+
export default async function getSelect(name) {
|
|
6
|
+
if (loadCls[name]) return loadCls[name];
|
|
7
|
+
|
|
8
|
+
const clsData = await getTemplate('cls', name);
|
|
9
|
+
console.log(clsData);
|
|
10
|
+
if (clsData) {
|
|
11
|
+
loadCls[name] = { arr: clsData };
|
|
12
|
+
return loadCls[name];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const selectData = await getTemplate('select', name);
|
|
16
|
+
if (!selectData) { return null; }
|
|
17
|
+
|
|
18
|
+
loadCls[name] = selectData;
|
|
19
|
+
return loadCls[name];
|
|
20
|
+
}
|
|
@@ -1,28 +1,69 @@
|
|
|
1
|
-
import { readFile } from 'fs/promises';
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
if (
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
1
|
+
import { readdir, readFile } from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import yaml from 'js-yaml';
|
|
4
|
+
|
|
5
|
+
import getTemplatePath from './getTemplatePath.js';
|
|
6
|
+
import loadTemplate from './loadTemplate.js';
|
|
7
|
+
|
|
8
|
+
async function readFileData(file) {
|
|
9
|
+
const data = await readFile(file, 'utf-8');
|
|
10
|
+
const ext = file.substring(file.lastIndexOf('.') + 1);
|
|
11
|
+
|
|
12
|
+
if (ext === 'yml') {
|
|
13
|
+
return yaml.load(data);
|
|
14
|
+
}
|
|
15
|
+
if (ext === 'json') {
|
|
16
|
+
return JSON.parse(data);
|
|
17
|
+
}
|
|
18
|
+
return data;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const isProduction = process.env.NODE_ENV === 'production';
|
|
22
|
+
|
|
23
|
+
async function getTemplateData(template) {
|
|
24
|
+
// dir template: dashboard, card
|
|
25
|
+
if (template[0][3]) {
|
|
26
|
+
const files = await readdir(template[0][1]);
|
|
27
|
+
const data = await Promise.all(files.map(async el => readFileData(path.join(template[0][1], el))));
|
|
28
|
+
return files.map((el, i) => [el, data[i]]);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// one file template: table, form
|
|
32
|
+
if (template.length === 1) {
|
|
33
|
+
const data = await readFileData(template[0][1]);
|
|
34
|
+
return data;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// multi file template: select, etc
|
|
38
|
+
if (template.length > 1) {
|
|
39
|
+
const data = await Promise.all(template.map(async el => readFileData(el[1])));
|
|
40
|
+
const result = {};
|
|
41
|
+
template.forEach((el, i) => {
|
|
42
|
+
Object.assign(result, typeof data[i] === 'object' ? data[i] : { [el[2]]: data[i] });
|
|
43
|
+
});
|
|
44
|
+
return result;
|
|
45
|
+
}
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
export default async function getTemplate(type, name) {
|
|
49
|
+
if (!type) return null;
|
|
50
|
+
if (!name) return null;
|
|
51
|
+
|
|
52
|
+
const key = `${type}:${name}`;
|
|
53
|
+
if (name === 'cache' && !isProduction) return loadTemplate; // all cache debug
|
|
54
|
+
if (loadTemplate[key] && isProduction) return loadTemplate[key]; // from cache
|
|
55
|
+
|
|
56
|
+
// type one or multi
|
|
57
|
+
const templateList = Array.isArray(type)
|
|
58
|
+
? type.map(el => getTemplatePath(el)).filter(list => list?.filter(el => el[0] === name).length)[0] || []
|
|
59
|
+
: getTemplatePath(type);
|
|
60
|
+
|
|
61
|
+
// find template
|
|
62
|
+
const template = templateList?.filter(el => el[0] === name);
|
|
63
|
+
if (name === 'list' && !isProduction) return templateList; // all template debug
|
|
64
|
+
|
|
65
|
+
if (!template.length) return null; // not found
|
|
66
|
+
|
|
67
|
+
loadTemplate[key] = await getTemplateData(template);
|
|
68
|
+
return loadTemplate[key];
|
|
69
|
+
}
|