@opengis/fastify-table 1.0.51 → 1.0.53
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/Changelog.md +8 -0
- package/index.js +6 -0
- package/migration/exec.migrations.js +76 -0
- package/package.json +1 -1
- package/table/controllers/data.js +1 -13
- package/table/controllers/table.js +40 -0
- package/table/index.js +2 -0
package/Changelog.md
CHANGED
package/index.js
CHANGED
|
@@ -16,6 +16,8 @@ import policyPlugin from './policy/index.js';
|
|
|
16
16
|
|
|
17
17
|
import pgClients from './pg/pgClients.js';
|
|
18
18
|
|
|
19
|
+
import execMigrations from './migration/exec.migrations.js';
|
|
20
|
+
|
|
19
21
|
async function plugin(fastify, opt) {
|
|
20
22
|
// console.log(opt);
|
|
21
23
|
config.pg = opt.pg;
|
|
@@ -56,6 +58,10 @@ async function plugin(fastify, opt) {
|
|
|
56
58
|
await client.query(sql, [JSON.stringify(rows).replace(/'/g, "''")]);
|
|
57
59
|
}
|
|
58
60
|
}
|
|
61
|
+
// call from another repo / project
|
|
62
|
+
fastify.execMigrations = execMigrations;
|
|
63
|
+
// execute core migrations
|
|
64
|
+
await fastify.execMigrations();
|
|
59
65
|
});
|
|
60
66
|
if (!fastify.funcs) {
|
|
61
67
|
fastify.addHook('onRequest', async (req) => {
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
|
|
4
|
+
const time = Date.now();
|
|
5
|
+
|
|
6
|
+
import getPG from '../pg/funcs/getPG.js';
|
|
7
|
+
|
|
8
|
+
export default async function execMigrations(opt) {
|
|
9
|
+
try {
|
|
10
|
+
const pg = opt?.pg || getPG({ name: 'client' });
|
|
11
|
+
const rootDir = getCallerDir();
|
|
12
|
+
const dir = path.join(rootDir.replace(/\\/g, '/').replace(/^file:\/\/\//, ''), 'server/migrations');
|
|
13
|
+
|
|
14
|
+
console.log('migrations start', dir, Date.now() - time);
|
|
15
|
+
const exists = fs.existsSync(dir);
|
|
16
|
+
if (exists) {
|
|
17
|
+
// get directory sql file list
|
|
18
|
+
const content = fs.readdirSync(dir, { withFileTypes: true })
|
|
19
|
+
?.filter((el) => el.isFile() && path.extname(el.name) === '.sql')
|
|
20
|
+
?.map((el) => el.name) || [];
|
|
21
|
+
|
|
22
|
+
// execute sql files
|
|
23
|
+
if (content?.length) {
|
|
24
|
+
await sequence(content, { pg, dir }, execSql);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
console.log('migrations finish', dir, exists, Date.now() - time);
|
|
28
|
+
} catch(err) {
|
|
29
|
+
console.error('migrations error', err.toString(), Date.now() - time);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function getCallerDir() {
|
|
34
|
+
const originalFunc = Error.prepareStackTrace;
|
|
35
|
+
|
|
36
|
+
let callerfile;
|
|
37
|
+
try {
|
|
38
|
+
const err = new Error();
|
|
39
|
+
let currentfile;
|
|
40
|
+
|
|
41
|
+
Error.prepareStackTrace = function (err, stack) { return stack; };
|
|
42
|
+
|
|
43
|
+
currentfile = err.stack.shift().getFileName();
|
|
44
|
+
|
|
45
|
+
while (err.stack.length) {
|
|
46
|
+
callerfile = err.stack.shift().getFileName();
|
|
47
|
+
|
|
48
|
+
if(currentfile !== callerfile) break;
|
|
49
|
+
}
|
|
50
|
+
} catch (err) { }
|
|
51
|
+
|
|
52
|
+
Error.prepareStackTrace = originalFunc;
|
|
53
|
+
|
|
54
|
+
return path.dirname(callerfile);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function sequence(files, data, fn) {
|
|
58
|
+
return files.reduce((promise, filename) => promise.then(() => fn({
|
|
59
|
+
...data, filename,
|
|
60
|
+
})), Promise.resolve());
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async function execSql({
|
|
64
|
+
pg, dir, filename,
|
|
65
|
+
}) {
|
|
66
|
+
const start = Date.now();
|
|
67
|
+
const filepath = path.join(dir, filename);
|
|
68
|
+
const sql = fs.readFileSync(filepath, 'utf-8');
|
|
69
|
+
try {
|
|
70
|
+
console.log(filename, 'start', Date.now() - start);
|
|
71
|
+
await pg.query(sql);
|
|
72
|
+
console.log(filename, 'finish', Date.now() - start);
|
|
73
|
+
} catch (err) {
|
|
74
|
+
console.log(filepath, 'error', err.toString(), Date.now() - start);
|
|
75
|
+
}
|
|
76
|
+
}
|
package/package.json
CHANGED
|
@@ -24,7 +24,7 @@ export default async function data(req) {
|
|
|
24
24
|
const cols = columns.map((el) => el.name || el).join(',');
|
|
25
25
|
const columnList = dbColumns.map((el) => el.name || el).join(',');
|
|
26
26
|
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('') || '';
|
|
27
|
-
const cardSqlFiltered = params.id ? cardSql?.filter?.((el) => !el?.disabled && el?.name && el?.sql?.replace) : [];
|
|
27
|
+
const cardSqlFiltered = params.id ? (cardSql?.filter?.((el) => !el?.disabled && el?.name && el?.sql?.replace) || []) : [];
|
|
28
28
|
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('') || '' : '';
|
|
29
29
|
|
|
30
30
|
const fData = query.filter ? await getFilterSQL({
|
|
@@ -54,18 +54,6 @@ export default async function data(req) {
|
|
|
54
54
|
|
|
55
55
|
const { rows } = await pg.query(q, (params.id ? [params.id] : null) || (query.key && loadTable.key ? [query.key] : []));
|
|
56
56
|
|
|
57
|
-
const formData = form ? (await getTemplate('form', form) || {}) : {};
|
|
58
|
-
const extraKeys = Object.keys(formData)?.filter((key) => formData?.[key]?.type === 'DataTable' && formData?.[key]?.table && formData?.[key]?.parent_id && formData[key]?.colModel);
|
|
59
|
-
if (extraKeys?.length) {
|
|
60
|
-
await Promise.all(rows?.map(async (row) => {
|
|
61
|
-
await Promise.all(extraKeys?.map(async (key) => {
|
|
62
|
-
const { colModel, table: extraTable, parent_id: parentId } = formData[key];
|
|
63
|
-
const { rows: extraRows } = await pg.query(`select ${parentId} as parent, ${colModel.map((col) => col.name).join(',')} from ${extraTable} a where ${parentId}=$1`, [row.id]);
|
|
64
|
-
Object.assign(row, { [key]: extraRows });
|
|
65
|
-
}));
|
|
66
|
-
}));
|
|
67
|
-
}
|
|
68
|
-
|
|
69
57
|
const total = keyQuery || params.id ? rows.length : await pg.queryCache(`select count(*) from ${table} t where ${where.join(' and ') || 'true'}`).then((el) => el?.rows[0]?.count);
|
|
70
58
|
|
|
71
59
|
await metaFormat({ rows, table: params.table });
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import getTemplate from './utils/getTemplate.js';
|
|
2
|
+
import getMeta from '../../pg/funcs/getMeta.js';
|
|
3
|
+
|
|
4
|
+
export default async function table(req) {
|
|
5
|
+
const { pg, params = {}, query = {} } = req;
|
|
6
|
+
if (!params.id) return { message: 'not enough params', status: 400 };
|
|
7
|
+
|
|
8
|
+
const loadTable = await getTemplate('table', params.table);
|
|
9
|
+
if (!loadTable) { return { message: 'not found', status: 404 }; }
|
|
10
|
+
|
|
11
|
+
const { table, columns, form } = loadTable;
|
|
12
|
+
|
|
13
|
+
const { pk, columns: dbColumns = [] } = await getMeta(table);
|
|
14
|
+
if (!pk) return { message: `table not found: ${table}`, status: 404 };
|
|
15
|
+
|
|
16
|
+
const cols = columns.map((el) => el.name || el).join(',');
|
|
17
|
+
const columnList = dbColumns.map((el) => el.name || el).join(',');
|
|
18
|
+
|
|
19
|
+
const where = [`"${pk}" = $1`, loadTable.query].filter((el) => el);
|
|
20
|
+
const geom = columnList.includes('geom') ? `st_asgeojson(geom)::json as geom,` : '';
|
|
21
|
+
const q = `select "${pk}" as id, ${geom} ${cols || '*'} from ${table} t where ${where.join(' and ') || 'true'} limit 1`;
|
|
22
|
+
|
|
23
|
+
if (query.sql === '1') return q;
|
|
24
|
+
|
|
25
|
+
const { rows } = await pg.query(q, [params.id]);
|
|
26
|
+
|
|
27
|
+
const formData = form ? (await getTemplate('form', form) || {}) : {};
|
|
28
|
+
const extraKeys = Object.keys(formData)?.filter((key) => formData?.[key]?.type === 'DataTable' && formData?.[key]?.table && formData?.[key]?.parent_id && formData[key]?.colModel);
|
|
29
|
+
if (extraKeys?.length) {
|
|
30
|
+
await Promise.all(rows?.map(async (row) => {
|
|
31
|
+
await Promise.all(extraKeys?.map(async (key) => {
|
|
32
|
+
const { colModel, table: extraTable, parent_id: parentId } = formData[key];
|
|
33
|
+
const { rows: extraRows } = await pg.query(`select ${parentId} as parent, ${colModel.map((col) => col.name).join(',')} from ${extraTable} a where ${parentId}=$1`, [row.id]);
|
|
34
|
+
Object.assign(row, { [key]: extraRows });
|
|
35
|
+
}));
|
|
36
|
+
}));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return rows?.[0] || {};
|
|
40
|
+
}
|
package/table/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import suggest from './controllers/suggest.js';
|
|
2
2
|
import data from './controllers/data.js';
|
|
3
|
+
import table from './controllers/table.js';
|
|
3
4
|
import card from './controllers/card.js';
|
|
4
5
|
import search from './controllers/search.js';
|
|
5
6
|
import filter from './controllers/filter.js';
|
|
@@ -35,6 +36,7 @@ async function plugin(fastify, config = {}) {
|
|
|
35
36
|
|
|
36
37
|
fastify.get(`${prefix}/suggest/:data`, {}, suggest);
|
|
37
38
|
fastify.get(`${prefix}/data/:table/:id?`, { schema: tableSchema }, data); // vs.crm.data.api с node
|
|
39
|
+
fastify.get(`${prefix}/table/:table/:id`, { schema: tableSchema }, table);
|
|
38
40
|
fastify.get(`${prefix}/card/:table/:id`, { schema: tableSchema }, card);
|
|
39
41
|
fastify.get(`${prefix}/search`, { schema: searchTableSchema }, search);
|
|
40
42
|
fastify.get(`${prefix}/filter/:table`, {}, filter);
|