New project structure
Beta of extract.js for extracting english locale
This commit is contained in:
parent
e18d2b2f84
commit
2edbd67205
247 changed files with 6405 additions and 4237 deletions
189
server/lib/dt-helpers.js
Normal file
189
server/lib/dt-helpers.js
Normal file
|
@ -0,0 +1,189 @@
|
|||
'use strict';
|
||||
|
||||
const knex = require('./knex');
|
||||
const entitySettings = require('./entity-settings');
|
||||
|
||||
async function ajaxListTx(tx, params, queryFun, columns, options) {
|
||||
options = options || {};
|
||||
|
||||
const columnsNames = [];
|
||||
const columnsSelect = [];
|
||||
|
||||
for (const col of columns) {
|
||||
if (typeof col === 'string') {
|
||||
columnsNames.push(col);
|
||||
columnsSelect.push(col);
|
||||
} else {
|
||||
columnsNames.push(col.name);
|
||||
|
||||
if (col.raw) {
|
||||
columnsSelect.push(tx.raw(col.raw));
|
||||
} else if (col.query) {
|
||||
columnsSelect.push(function () { return col.query(this); });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (params.operation === 'getBy') {
|
||||
const query = queryFun(tx);
|
||||
query.whereIn(columnsNames[parseInt(params.column)], params.values);
|
||||
query.select(columnsSelect);
|
||||
query.options({rowsAsArray:true});
|
||||
|
||||
const rows = await query;
|
||||
const rowsOfArray = rows.map(row => Object.keys(row).map(key => row[key]));
|
||||
return rowsOfArray;
|
||||
|
||||
} else {
|
||||
const whereFun = function() {
|
||||
let searchVal = '%' + params.search.value.replace(/\\/g, '\\\\').replace(/([%_])/g, '\\$1') + '%';
|
||||
for (let colIdx = 0; colIdx < params.columns.length; colIdx++) {
|
||||
const col = params.columns[colIdx];
|
||||
if (col.searchable) {
|
||||
this.orWhere(columnsNames[parseInt(col.data)], 'like', searchVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* There are a few SQL peculiarities that make this query a bit weird:
|
||||
- Group by (which is used in getting permissions) don't go well with count(*). Thus we run the actual query
|
||||
as a sub-query and then count the number of results.
|
||||
- SQL does not like if it have columns with the same name in the subquery. This happens multiple tables are joined.
|
||||
To circumvent this, we select only the first column (whatever it is). Since this is not "distinct", it is supposed
|
||||
to give us the right number of rows anyway.
|
||||
*/
|
||||
const recordsTotalQuery = tx.count('* as recordsTotal').from(function () { return queryFun(this).select(columnsSelect[0]).as('records'); }).first();
|
||||
const recordsTotal = (await recordsTotalQuery).recordsTotal;
|
||||
|
||||
const recordsFilteredQuery = tx.count('* as recordsFiltered').from(function () { return queryFun(this).select(columnsSelect[0]).where(whereFun).as('records'); }).first();
|
||||
const recordsFiltered = (await recordsFilteredQuery).recordsFiltered;
|
||||
|
||||
const query = queryFun(tx);
|
||||
query.where(whereFun);
|
||||
|
||||
query.offset(parseInt(params.start));
|
||||
|
||||
const limit = parseInt(params.length);
|
||||
if (limit >= 0) {
|
||||
query.limit(limit);
|
||||
}
|
||||
|
||||
query.select([...columnsSelect, ...options.extraColumns || [] ]);
|
||||
|
||||
for (const order of params.order) {
|
||||
if (options.orderByBuilder) {
|
||||
options.orderByBuilder(query, columnsNames[params.columns[order.column].data], order.dir);
|
||||
} else {
|
||||
query.orderBy(columnsNames[params.columns[order.column].data], order.dir);
|
||||
}
|
||||
}
|
||||
|
||||
query.options({rowsAsArray:true});
|
||||
|
||||
const rows = await query;
|
||||
const rowsOfArray = rows.map(row => {
|
||||
const arr = Object.keys(row).map(field => row[field]);
|
||||
|
||||
if (options.mapFun) {
|
||||
const result = options.mapFun(arr);
|
||||
return result || arr;
|
||||
} else {
|
||||
return arr;
|
||||
}
|
||||
});
|
||||
|
||||
const result = {
|
||||
draw: params.draw,
|
||||
recordsTotal,
|
||||
recordsFiltered,
|
||||
data: rowsOfArray
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
async function ajaxListWithPermissionsTx(tx, context, fetchSpecs, params, queryFun, columns, options) {
|
||||
// Note that this function is not intended to be used with the synthetic admin context obtained by contextHelpers.getAdminContext()
|
||||
options = options || {};
|
||||
|
||||
const permCols = [];
|
||||
for (const fetchSpec of fetchSpecs) {
|
||||
const entityType = entitySettings.getEntityType(fetchSpec.entityTypeId);
|
||||
const entityIdColumn = fetchSpec.column ? fetchSpec.column : entityType.entitiesTable + '.id';
|
||||
|
||||
permCols.push({
|
||||
name: `permissions_${fetchSpec.entityTypeId}`,
|
||||
query: builder => builder
|
||||
.from(entityType.permissionsTable)
|
||||
.select(knex.raw('GROUP_CONCAT(operation SEPARATOR \';\')'))
|
||||
.whereRaw(`${entityType.permissionsTable}.entity = ${entityIdColumn}`)
|
||||
.where(`${entityType.permissionsTable}.user`, context.user.id)
|
||||
.as(`permissions_${fetchSpec.entityTypeId}`)
|
||||
});
|
||||
}
|
||||
|
||||
return await ajaxListTx(
|
||||
tx,
|
||||
params,
|
||||
builder => {
|
||||
let query = queryFun(builder);
|
||||
|
||||
for (const fetchSpec of fetchSpecs) {
|
||||
const entityType = entitySettings.getEntityType(fetchSpec.entityTypeId);
|
||||
|
||||
if (fetchSpec.requiredOperations) {
|
||||
const entityIdColumn = fetchSpec.column ? fetchSpec.column : entityType.entitiesTable + '.id';
|
||||
|
||||
query = query.innerJoin(
|
||||
function () {
|
||||
return this.from(entityType.permissionsTable).distinct('entity').where('user', context.user.id).whereIn('operation', fetchSpec.requiredOperations).as(`permitted__${fetchSpec.entityTypeId}`);
|
||||
},
|
||||
`permitted__${fetchSpec.entityTypeId}.entity`, entityIdColumn)
|
||||
}
|
||||
}
|
||||
|
||||
return query;
|
||||
},
|
||||
[
|
||||
...columns,
|
||||
...permCols
|
||||
],
|
||||
{
|
||||
mapFun: data => {
|
||||
for (let idx = 0; idx < fetchSpecs.length; idx++) {
|
||||
data[columns.length + idx] = data[columns.length + idx].split(';');
|
||||
}
|
||||
|
||||
if (options.mapFun) {
|
||||
const result = options.mapFun(data);
|
||||
return result || data;
|
||||
} else {
|
||||
return data;
|
||||
}
|
||||
},
|
||||
|
||||
orderByBuilder: options.orderByBuilder,
|
||||
extraColumns: options.extraColumns
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
async function ajaxList(params, queryFun, columns, options) {
|
||||
return await knex.transaction(async tx => {
|
||||
return await ajaxListTx(tx, params, queryFun, columns, options)
|
||||
});
|
||||
}
|
||||
|
||||
async function ajaxListWithPermissions(context, fetchSpecs, params, queryFun, columns, options) {
|
||||
return await knex.transaction(async tx => {
|
||||
return await ajaxListWithPermissionsTx(tx, context, fetchSpecs, params, queryFun, columns, options)
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
ajaxListTx,
|
||||
ajaxList,
|
||||
ajaxListWithPermissionsTx,
|
||||
ajaxListWithPermissions
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue