backend-plus 2.0.0-rc.1 → 2.0.0-rc.11
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 +6 -6
- package/for-client/my-menu.js +1 -1
- package/for-client/my-tables.js +10 -2
- package/install/get_app_user-fun.sql +6 -0
- package/lib/backend-plus.d.ts +10 -9
- package/lib/backend-plus.js +117 -50
- package/lib/procedures-table.js +7 -5
- package/package.json +18 -17
package/README.md
CHANGED
|
@@ -6,11 +6,11 @@ Backend for the anti Pareto rule.
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|

|
|
9
|
-
[](https://npmjs.org/package/backend-plus)
|
|
10
|
+
[](https://npmjs.org/package/backend-plus)
|
|
11
|
+
[](https://travis-ci.org/codenautas/backend-plus)
|
|
12
|
+
[](https://coveralls.io/r/codenautas/backend-plus)
|
|
13
|
+
[](https://david-dm.org/codenautas/backend-plus)
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
language: 
|
|
@@ -205,7 +205,7 @@ entry | usage
|
|
|
205
205
|
-----------------------------|---------------
|
|
206
206
|
server |
|
|
207
207
|
.port | port where is listening
|
|
208
|
-
.base-
|
|
208
|
+
.base-url | base url added to domain name
|
|
209
209
|
.module-store |
|
|
210
210
|
install | (see Spanish)
|
|
211
211
|
.dump | (see Spanish)
|
package/for-client/my-menu.js
CHANGED
|
@@ -152,7 +152,7 @@ myOwn.wScreens.procAux = {
|
|
|
152
152
|
button.disabled=false;
|
|
153
153
|
divProgressOutside.style.opacity=0.33;
|
|
154
154
|
toggleProgress.disabled=false;
|
|
155
|
-
labelProgress.textContent=resultOk?my.messages.completed:'error';
|
|
155
|
+
labelProgress.textContent=typeof resultOk == "string" ? resultOk : resultOk !== false ? my.messages.completed : 'error';
|
|
156
156
|
}).catch(function(err){
|
|
157
157
|
my.log(err);
|
|
158
158
|
divProgress.textContent=err.message;
|
package/for-client/my-tables.js
CHANGED
|
@@ -690,11 +690,18 @@ myOwn.tableGrid = function tableGrid(tableName, mainElement, opts){
|
|
|
690
690
|
if (myOwn.config.config['grid-row-retain-moved-or-deleted'] && !force) {
|
|
691
691
|
var depotsToRetain = grid.depots.filter(depot => depot.tick == tick);
|
|
692
692
|
for (depot of depotsToRetain) {
|
|
693
|
+
depot['$refreshed'] = false
|
|
693
694
|
if (depot.tr && depot.tr.getAttribute('not-here')) depot.tr.removeAttribute('not-here')
|
|
694
695
|
}
|
|
695
696
|
}
|
|
696
697
|
while (depot = depotsToDelete.pop()) {
|
|
697
698
|
depot.manager.displayAsDeleted(depot, force ? 'change-ff' : 'unknown');
|
|
699
|
+
if (myOwn.config.config['grid-row-retain-moved-or-deleted']) {
|
|
700
|
+
if(!depot['$refreshed']){
|
|
701
|
+
grid.retrieveRowAndRefresh(depot,{retrieveIgnoringWhere:true})
|
|
702
|
+
depot['$refreshed'] = true
|
|
703
|
+
}
|
|
704
|
+
}
|
|
698
705
|
}
|
|
699
706
|
}
|
|
700
707
|
})
|
|
@@ -1615,7 +1622,7 @@ myOwn.dialogDownload = function dialogDownload(grid){
|
|
|
1615
1622
|
}else{
|
|
1616
1623
|
separator='|';
|
|
1617
1624
|
var trans={
|
|
1618
|
-
'|':'
|
|
1625
|
+
'|':'\\x7C',
|
|
1619
1626
|
'\\':'\\\\',
|
|
1620
1627
|
'\r':'\\r',
|
|
1621
1628
|
'\n':'\\n',
|
|
@@ -2385,7 +2392,8 @@ myOwn.TableGrid.prototype.displayGrid = function displayGrid(){
|
|
|
2385
2392
|
fixedFields:grid.def.primaryKey.map(function(fieldName, i){
|
|
2386
2393
|
return {fieldName:fieldName, value:depot.primaryKeyValues[i]};
|
|
2387
2394
|
}),
|
|
2388
|
-
pick:grid.def.pick
|
|
2395
|
+
pick:grid.def.pick,
|
|
2396
|
+
retrieveIgnoringWhere: opts?opts.retrieveIgnoringWhere:false
|
|
2389
2397
|
}).then(function(result){
|
|
2390
2398
|
grid.depotRefresh(depot,{updatedRow:result[0], sendedForUpdate:{}}, opts);
|
|
2391
2399
|
})
|
package/lib/backend-plus.d.ts
CHANGED
|
@@ -35,7 +35,7 @@ export type UploadedFileInfo={
|
|
|
35
35
|
|
|
36
36
|
}
|
|
37
37
|
export type CoreFunction = ((context: ProcedureContext, parameters: CoreFunctionParameters) => Promise<any>)
|
|
38
|
-
|
|
38
|
+
| ((context: ProcedureContext, parameters: CoreFunctionParameters, files?:UploadedFileInfo[]) => Promise<any>);
|
|
39
39
|
|
|
40
40
|
export interface ProcedureDef {
|
|
41
41
|
action: string
|
|
@@ -252,6 +252,7 @@ export type Constraint = {constraintType:string, consName?:string} & (
|
|
|
252
252
|
{constraintType:'unique', fields:string[], where?:string} |
|
|
253
253
|
{constraintType:'check', expr?:string}
|
|
254
254
|
)
|
|
255
|
+
export type OtherTableDefs = Record<string,Partial<TableDefinition & {prefilledField:Record<string,any>}>>
|
|
255
256
|
export type TableDefinition = EditableDbDefinition & {
|
|
256
257
|
name:string
|
|
257
258
|
elementName?:string
|
|
@@ -285,15 +286,15 @@ export type TableDefinition = EditableDbDefinition & {
|
|
|
285
286
|
viewBody?:string
|
|
286
287
|
insertIfNotUpdate?:boolean
|
|
287
288
|
policies?:{
|
|
288
|
-
all ?:{using?:string, check?:string}
|
|
289
|
-
select?:{using?:string}
|
|
290
|
-
insert?:{
|
|
291
|
-
update?:{using?:string, check?:string}
|
|
292
|
-
delete?:{using?:string}
|
|
289
|
+
all ?:{name?:string, using?:string, check?:string}
|
|
290
|
+
select?:{name?:string, using?:string}
|
|
291
|
+
insert?:{name?:string, check?:string}
|
|
292
|
+
update?:{name?:string, using?:string, check?:string}
|
|
293
|
+
delete?:{name?:string, using?:string}
|
|
293
294
|
}
|
|
294
295
|
join?:string
|
|
295
296
|
constraintsDeferred?:boolean
|
|
296
|
-
otherTableDefs?:
|
|
297
|
+
otherTableDefs?:OtherTableDefs
|
|
297
298
|
}
|
|
298
299
|
foreignKeys?:ForeignKey[]
|
|
299
300
|
softForeignKeys?:ForeignKey[]
|
|
@@ -322,7 +323,6 @@ export type TableDefinition = EditableDbDefinition & {
|
|
|
322
323
|
filterColumns?:{column:string, operator:string, value:any}[],
|
|
323
324
|
gridAlias?:string /* front-end css my-table = gridAlias */
|
|
324
325
|
}
|
|
325
|
-
export type OtherTableDefs = TableDefinition['sql']['otherTableDefs']
|
|
326
326
|
export interface DetailTable { table?: string, fields: FieldsForConnectDetailTable, abr: string, label?: string, refreshParent?:boolean, refreshFromParent?:boolean, wScreen?:string, condition?:string }
|
|
327
327
|
export type TableDefinitionFunction = (context: ContextForDump, opts?:any) => TableDefinition;
|
|
328
328
|
export type TableItemDef=string|{name:string, path?:string, tableGenerator?:(context:TableContext)=>TableDefinition}
|
|
@@ -420,7 +420,8 @@ export class AppBackend{
|
|
|
420
420
|
i18n:{
|
|
421
421
|
messages:Record<LangId,Record<string, string>>
|
|
422
422
|
}
|
|
423
|
-
|
|
423
|
+
shutdownCallbackListAdd(param:{message:string, fun:()=>Promise<void>}):void
|
|
424
|
+
shutdownBackend():Promise<void>
|
|
424
425
|
setLog(opts:{until:string, results?:boolean}):void
|
|
425
426
|
getDataDumpTransformations(rawData:string):Promise<{rawData:string, prepareTransformationSql:string[], endTransformationSql:string[]}>
|
|
426
427
|
}
|
package/lib/backend-plus.js
CHANGED
|
@@ -54,6 +54,7 @@ var bestGlobals = require('best-globals');
|
|
|
54
54
|
var coalesce = bestGlobals.coalesce;
|
|
55
55
|
var changing = bestGlobals.changing;
|
|
56
56
|
var datetime = bestGlobals.datetime;
|
|
57
|
+
var splitRawRowIntoRow = bestGlobals.splitRawRowIntoRow;
|
|
57
58
|
const escapeRegExp = bestGlobals.escapeRegExp;
|
|
58
59
|
var isLowerIdent = bestGlobals.isLowerIdent;
|
|
59
60
|
|
|
@@ -96,7 +97,7 @@ class AppBackend{
|
|
|
96
97
|
/** @type {{path:string}[]} */
|
|
97
98
|
this.appStack=[];
|
|
98
99
|
/** @type {{message:string; fun:()=>void}[]} */
|
|
99
|
-
this.
|
|
100
|
+
this.shutdownCallbackList=[];
|
|
100
101
|
if(!this.rootPath){
|
|
101
102
|
console.log('ATENCIÓN hay que poner be.rootPath antes de llamar a super()');
|
|
102
103
|
this.rootPath=Path.resolve(__dirname,'..');
|
|
@@ -118,7 +119,7 @@ class AppBackend{
|
|
|
118
119
|
this.tableStructures = {};
|
|
119
120
|
this.configStaticConfig();
|
|
120
121
|
/** @type {null|()=>Promise<void>} */
|
|
121
|
-
this.
|
|
122
|
+
this.shutdownBackend = null;
|
|
122
123
|
/** @type {bp.Server} */
|
|
123
124
|
// @ts-ignore
|
|
124
125
|
this.server = null;
|
|
@@ -405,7 +406,7 @@ function MemoryPerodicallySaved(session){
|
|
|
405
406
|
console.log('dumping sessions every',dumpEverySeconds,'seconds');
|
|
406
407
|
var errorsToShow=4;
|
|
407
408
|
// TODO: hangs the server in devel mode
|
|
408
|
-
setInterval(function(){
|
|
409
|
+
var interval = setInterval(function(){
|
|
409
410
|
try{
|
|
410
411
|
fs.writeFile(fileName,json4all.stringify(store.store.dump()));
|
|
411
412
|
}catch(err){
|
|
@@ -416,6 +417,10 @@ function MemoryPerodicallySaved(session){
|
|
|
416
417
|
}
|
|
417
418
|
}
|
|
418
419
|
},dumpEverySeconds*1000);
|
|
420
|
+
be.shutdownCallbackListAdd({
|
|
421
|
+
message:'session saver',
|
|
422
|
+
fun:()=>clearInterval(interval)
|
|
423
|
+
})
|
|
419
424
|
});
|
|
420
425
|
}
|
|
421
426
|
}
|
|
@@ -456,7 +461,7 @@ AppBackend.prototype.setStaticConfig = function setStaticConfig(defConfigYamlStr
|
|
|
456
461
|
|
|
457
462
|
AppBackend.prototype.configList = function configList(){
|
|
458
463
|
var list=[this.staticConfig];
|
|
459
|
-
if(!this.staticConfig["client-setup"]
|
|
464
|
+
if(!this.staticConfig["client-setup"]?.title && fs.existsSync(this.rootPath+'/def-config.yaml')){
|
|
460
465
|
console.log('DEPRECATED!!!!!!')
|
|
461
466
|
console.error('ERROR el def-config hay que ponerlo dentro de staticConfig');
|
|
462
467
|
console.log('DEPRECATED!!!!!!')
|
|
@@ -466,7 +471,7 @@ AppBackend.prototype.configList = function configList(){
|
|
|
466
471
|
list.push(this.rootPath+'/def-config.yaml')
|
|
467
472
|
};
|
|
468
473
|
list.push(this.rootPath+'/local-config');
|
|
469
|
-
list.push(process.env.BACKEND_PLUS_LOCAL_CONFIG||{});
|
|
474
|
+
list.push(process.env.BACKEND_PLUS_LOCAL_CONFIG?.trim()||{});
|
|
470
475
|
return list;
|
|
471
476
|
};
|
|
472
477
|
|
|
@@ -625,32 +630,36 @@ AppBackend.prototype.start = function start(opts){
|
|
|
625
630
|
// @ts-ignore : only for testing */
|
|
626
631
|
this.getMainApp = function getMainApp(){ return mainApp; };
|
|
627
632
|
}
|
|
628
|
-
this.
|
|
633
|
+
this.shutdownCallbackListAdd = function(messageFun){
|
|
634
|
+
this.shutdownCallbackList.push(messageFun);
|
|
635
|
+
}
|
|
636
|
+
this.shutdownBackend = async function shutdownBackend(){
|
|
629
637
|
console.log('shooting down:');
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
638
|
+
var waitFor = [
|
|
639
|
+
new Promise(function(resolve,reject){
|
|
640
|
+
console.log('*','express server');
|
|
641
|
+
be.server.close(/** @param {Error} err */function(err){
|
|
642
|
+
if(err){
|
|
643
|
+
console.log('*', err)
|
|
644
|
+
reject(err);
|
|
645
|
+
}else{
|
|
646
|
+
console.log('*','express server done!')
|
|
647
|
+
resolve();
|
|
648
|
+
}
|
|
649
|
+
});
|
|
650
|
+
}),
|
|
651
|
+
...(be.shutdownCallbackList.map(x => (async function(){
|
|
652
|
+
console.log('shut:', x.message)
|
|
653
|
+
await x.fun()
|
|
654
|
+
console.log('done:', x.message)
|
|
655
|
+
})()))
|
|
656
|
+
];
|
|
657
|
+
console.log('*', 'waiting for all')
|
|
658
|
+
await Promise.all(waitFor);
|
|
659
|
+
console.log('*', 'all done')
|
|
660
|
+
mainApp = null;
|
|
661
|
+
console.log('* logWhy',logWhy)
|
|
662
|
+
logWhy && logWhy();
|
|
654
663
|
};
|
|
655
664
|
return Promise.resolve().then(function(){
|
|
656
665
|
var configList=be.configList();
|
|
@@ -704,7 +713,7 @@ AppBackend.prototype.start = function start(opts){
|
|
|
704
713
|
throw new Error("backend-plus: Motor not recongnized: "+be.config.db.motor);
|
|
705
714
|
}
|
|
706
715
|
be.db = pg;
|
|
707
|
-
be.dbUserNameExpr="
|
|
716
|
+
be.dbUserNameExpr="get_app_user()";
|
|
708
717
|
be.dbUserRolExpr=`(select ${be.db.quoteIdent(be.config.login.rolFieldName)}
|
|
709
718
|
from ${be.config.login.schema?be.db.quoteIdent(be.config.login.schema)+'.':''}${be.db.quoteIdent(be.config.login.table)}
|
|
710
719
|
where ${be.db.quoteIdent(be.config.login.userFieldName)} = ${be.dbUserNameExpr})`
|
|
@@ -760,6 +769,7 @@ AppBackend.prototype.start = function start(opts){
|
|
|
760
769
|
pg.log.inFileName = 'last-pg-error-local.sql'
|
|
761
770
|
pg.logLastError.inFileName = 'last-pg-error-local.sql'
|
|
762
771
|
}
|
|
772
|
+
be.config.db.search_path = be.config.db.search_path ?? [be.config.db.schema, 'public'];
|
|
763
773
|
be.getDbClient = function getDbClient(req){
|
|
764
774
|
var paramsDb = be.DoubleDragon?.dbParams?.[req?.user?.[be.config.login.userFieldName]] ?? be.config.db;
|
|
765
775
|
return pg.connect(paramsDb).then(function(client){
|
|
@@ -771,7 +781,7 @@ AppBackend.prototype.start = function start(opts){
|
|
|
771
781
|
return client.query(
|
|
772
782
|
"SET application_name = "+be.db.quoteLiteral(dbAppName)
|
|
773
783
|
).execute().then(function(){
|
|
774
|
-
var search_path = be.config.db.search_path
|
|
784
|
+
var search_path = be.config.db.search_path;
|
|
775
785
|
if(search_path.length>0){
|
|
776
786
|
return client.query("set SEARCH_PATH TO "+be.db.quoteIdentList(search_path)).execute().then(function(){
|
|
777
787
|
return client;
|
|
@@ -961,12 +971,18 @@ AppBackend.prototype.start = function start(opts){
|
|
|
961
971
|
loginPlusOpts.noLoggedUrlPath=be.config.login.unloggedLandPage;
|
|
962
972
|
}
|
|
963
973
|
mainApp.loginPlusManager.init(mainApp,changing(be.config.login.plus,loginPlusOpts));
|
|
964
|
-
be.
|
|
974
|
+
be.shutdownCallbackListAdd({
|
|
965
975
|
message:'login-plus manager',
|
|
966
976
|
fun:function(){
|
|
967
977
|
mainApp.loginPlusManager.closeManager();
|
|
968
978
|
}
|
|
969
979
|
});
|
|
980
|
+
be.shutdownCallbackListAdd({
|
|
981
|
+
message:'pg',
|
|
982
|
+
fun:function(){
|
|
983
|
+
pg.shutdown();
|
|
984
|
+
}
|
|
985
|
+
});
|
|
970
986
|
mainApp.loginPlusManager.setValidatorStrategy(
|
|
971
987
|
function(req, username, password, done) {
|
|
972
988
|
var client;
|
|
@@ -1130,7 +1146,7 @@ AppBackend.prototype.start = function start(opts){
|
|
|
1130
1146
|
}
|
|
1131
1147
|
return be.sendMail({
|
|
1132
1148
|
to: be.config.mailer?.supervise?.to,
|
|
1133
|
-
subject: `npm start ${be.config["client-setup"]
|
|
1149
|
+
subject: `npm start ${be.config["client-setup"]?.title || packagejson.name} ok ✔️`,
|
|
1134
1150
|
text:`Inicio del servicio: ${new Date().toJSON()}
|
|
1135
1151
|
|
|
1136
1152
|
Contexto: ${os.userInfo().username} ${process.cwd()}
|
|
@@ -1152,7 +1168,7 @@ AppBackend.prototype.start = function start(opts){
|
|
|
1152
1168
|
}
|
|
1153
1169
|
var mailDeAvisoDeFalla = be.sendMail({
|
|
1154
1170
|
to: be.config.mailer?.supervise?.to,
|
|
1155
|
-
subject: `npm start ${be.config["client-setup"]
|
|
1171
|
+
subject: `npm start ${be.config["client-setup"]?.title || packagejson.name} fallido 🛑`,
|
|
1156
1172
|
text:`Falla en el inicio del servicio: ${new Date().toJSON()}
|
|
1157
1173
|
|
|
1158
1174
|
Contexto: ${os.userInfo().username} ${process.cwd()}
|
|
@@ -1209,13 +1225,14 @@ AppBackend.prototype.checkDatabaseStructure = async function checkDatabaseStruct
|
|
|
1209
1225
|
}
|
|
1210
1226
|
if(be.config.login?.forget){
|
|
1211
1227
|
try{
|
|
1212
|
-
await client.query(`select tokentype, info, due from tokens limit 1`).fetchOneRowIfExists();
|
|
1228
|
+
await client.query(`select tokentype, info, due from his.tokens limit 1`).fetchOneRowIfExists();
|
|
1213
1229
|
}catch(err){
|
|
1214
1230
|
var mensaje = `
|
|
1215
1231
|
--------quizas falten los campos en la tabla tokens:
|
|
1216
1232
|
alter table tokens add column tokentype text;
|
|
1217
1233
|
alter table tokens add column info jsonb;
|
|
1218
1234
|
alter table tokens add column due timestamp;
|
|
1235
|
+
--------quizas falte moverla al esquema his.
|
|
1219
1236
|
`;
|
|
1220
1237
|
err.message += mensaje;
|
|
1221
1238
|
console.log(mensaje)
|
|
@@ -1253,6 +1270,21 @@ AppBackend.prototype.checkDatabaseStructure = async function checkDatabaseStruct
|
|
|
1253
1270
|
`;
|
|
1254
1271
|
throw new Error(message);
|
|
1255
1272
|
}
|
|
1273
|
+
var {rows: sql_routines} = await client.query(`SELECT routine_name, routine_schema, routine_definition
|
|
1274
|
+
FROM information_schema.routines
|
|
1275
|
+
WHERE routine_schema in (${be.config.db.search_path.map(path => be.db.quoteLiteral(path)).join(', ')})
|
|
1276
|
+
`).fetchAll();
|
|
1277
|
+
var sqlRoutines = likeAr.toPlainObject(sql_routines, 'routine_name');
|
|
1278
|
+
var message = ''
|
|
1279
|
+
likeAr(AppBackend.prototype.sql_routines).forEach((routine_name, def) => {
|
|
1280
|
+
if (sqlRoutines[routine_name] && def.dump.includes(sqlRoutines[routine_name].routine_definition)) {
|
|
1281
|
+
message += `
|
|
1282
|
+
----- hay que crear o actualizar la rutina ${routine_name}:
|
|
1283
|
+
${dump}
|
|
1284
|
+
`;
|
|
1285
|
+
}
|
|
1286
|
+
})
|
|
1287
|
+
if (message) throw new Error(message);
|
|
1256
1288
|
};
|
|
1257
1289
|
|
|
1258
1290
|
AppBackend.prototype.postConfig = function postConfig(){
|
|
@@ -2181,7 +2213,7 @@ AppBackend.prototype.mainPage = function mainPage(req, offlineMode, opts){
|
|
|
2181
2213
|
}
|
|
2182
2214
|
return html.html(attr,[
|
|
2183
2215
|
html.head([
|
|
2184
|
-
html.title(be.config["client-setup"]
|
|
2216
|
+
html.title(be.config["client-setup"]?.title),
|
|
2185
2217
|
html.meta({charset:"utf-8"}),
|
|
2186
2218
|
viewportAttrs?html.meta(viewportAttrs):null,
|
|
2187
2219
|
html.link({href: opts.icons.iconShortcut , rel: "shortcut icon", type: "image/png"}),
|
|
@@ -2804,10 +2836,11 @@ AppBackend.prototype.dumpDbSchemaPartial = async function dumpDbSchemaPartial(pa
|
|
|
2804
2836
|
lines.push('');
|
|
2805
2837
|
if(tableDef.sql.policies.enabled){
|
|
2806
2838
|
policyLines.push(`ALTER TABLE ${cualQuoteTableName} ENABLE ROW LEVEL SECURITY;`);
|
|
2807
|
-
['all', 'select', 'insert', 'update', 'delete'].forEach((command)=>{
|
|
2808
|
-
var polcom=tableDef.sql.policies[command];
|
|
2809
|
-
if(polcom
|
|
2810
|
-
policyLines.push(`CREATE POLICY
|
|
2839
|
+
[null, 'all', 'select', 'insert', 'update', 'delete'].forEach((command)=>{
|
|
2840
|
+
var polcom=tableDef.sql.policies[command] ?? {using: `true`, permissive:true};
|
|
2841
|
+
if(polcom?.using || polcom?.check){
|
|
2842
|
+
policyLines.push(`CREATE POLICY ${be.db.quoteIdent(polcom.name ?? `bp ${command ?? `base`}`)} ON ${cualQuoteTableName} `+
|
|
2843
|
+
`AS ${polcom.permissive ? `PERMISSIVE` : `RESTRICTIVE`} FOR ${command ?? `all`} TO ${be.config.db.user}`+
|
|
2811
2844
|
(polcom.using? ` USING ( ${polcom.using} )`:'')+
|
|
2812
2845
|
(polcom.check?` WITH CHECK ( ${polcom.check} )`:'')+';'
|
|
2813
2846
|
);
|
|
@@ -2847,6 +2880,7 @@ AppBackend.prototype.dumpDbSchemaPartial = async function dumpDbSchemaPartial(pa
|
|
|
2847
2880
|
allTableData = allTableContent.slice(startIndex, lastIndex);
|
|
2848
2881
|
} catch(err) {
|
|
2849
2882
|
if (err.code != 'ENOENT') throw err;
|
|
2883
|
+
//throw err;
|
|
2850
2884
|
}
|
|
2851
2885
|
}
|
|
2852
2886
|
if (allTableData) {
|
|
@@ -2919,7 +2953,7 @@ AppBackend.prototype.dumpDbSchemaPartial = async function dumpDbSchemaPartial(pa
|
|
|
2919
2953
|
}else{
|
|
2920
2954
|
var lines=content.split(/\r?\n/)
|
|
2921
2955
|
.filter(line => !(/^[-| ]*$/.test(line)) )
|
|
2922
|
-
.map(line => line
|
|
2956
|
+
.map(line => splitRawRowIntoRow(line))
|
|
2923
2957
|
.filter(line => line.length>1 || line.length==1 && line[0].trim() );
|
|
2924
2958
|
if(lines.length>1){
|
|
2925
2959
|
if(lines[0][0].startsWith('\ufeff')){
|
|
@@ -2964,26 +2998,57 @@ AppBackend.prototype.dumpDbSchemaPartial = async function dumpDbSchemaPartial(pa
|
|
|
2964
2998
|
console.log('silence "skipping content" messages in "local-config.yaml".install.dump.skip-content=true');
|
|
2965
2999
|
}
|
|
2966
3000
|
}
|
|
3001
|
+
let installFolders = be.config.install.dump.folders ?? ['install']
|
|
2967
3002
|
let texts = await Promise.all(
|
|
2968
3003
|
['prepare.sql','pre-adapt.sql','adapt.sql']
|
|
2969
3004
|
.concat(be.config.install.dump.scripts['prepare'])
|
|
2970
3005
|
.concat(be.config.install.dump.scripts['post-adapt'])
|
|
2971
|
-
.map(function(fileName){
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
3006
|
+
.map(async function(fileName){
|
|
3007
|
+
if (!fileName) return '';
|
|
3008
|
+
var i = 0;
|
|
3009
|
+
var content;
|
|
3010
|
+
do {
|
|
3011
|
+
var folder = installFolders[i];
|
|
3012
|
+
try{
|
|
3013
|
+
content = await fs.readFile(be.rootPath+'/'+folder+'/'+fileName, {encoding:'UTF8'});
|
|
3014
|
+
} catch (err) {
|
|
3015
|
+
if(err.code!='ENOENT') throw err;
|
|
2975
3016
|
}
|
|
2976
|
-
|
|
3017
|
+
i++;
|
|
3018
|
+
} while (i < installFolders.length && !content);
|
|
3019
|
+
if (!content) {
|
|
2977
3020
|
return '-- no '+fileName+'\n';
|
|
2978
|
-
}
|
|
2979
|
-
return '-- '+fileName+'\n'+content;
|
|
2980
|
-
}
|
|
3021
|
+
} else {
|
|
3022
|
+
return '-- '+folder+'/'+fileName+'\n'+content;
|
|
3023
|
+
};
|
|
2981
3024
|
})
|
|
2982
3025
|
);
|
|
3026
|
+
|
|
3027
|
+
var common = (await Promise.all(be.appStack.map(async function(stackNode){
|
|
3028
|
+
var common = [];
|
|
3029
|
+
for (var prefix of ['../', '../../']) {
|
|
3030
|
+
try {
|
|
3031
|
+
var dirName = Path.join(stackNode.path,prefix+'install').replace(regexpDistReplacer,'$1$2')
|
|
3032
|
+
var list = await fs.readdir(dirName);
|
|
3033
|
+
} catch (err) {
|
|
3034
|
+
if (err.code != 'ENOENT') throw err;
|
|
3035
|
+
var list = [];
|
|
3036
|
+
}
|
|
3037
|
+
for(var fileName of list){
|
|
3038
|
+
if (fileName.endsWith('-fun.sql')) {
|
|
3039
|
+
common.push(await fs.readFile(Path.join(dirName,fileName), 'utf-8'));
|
|
3040
|
+
}
|
|
3041
|
+
}
|
|
3042
|
+
}
|
|
3043
|
+
return common.join('\n');
|
|
3044
|
+
}))).join('\n');
|
|
3045
|
+
|
|
2983
3046
|
var prepareList=(be.config.install.dump.scripts['prepare']||[]);
|
|
2984
3047
|
var mainSql=(
|
|
2985
3048
|
(complete? linesCreate.join('\n'): '')+
|
|
2986
3049
|
(complete||opts.forDump? searchPathline.join('\n'): '')+
|
|
3050
|
+
'\n-- common'+
|
|
3051
|
+
common+'\n'+
|
|
2987
3052
|
(complete? '\n\n--prepare.sql\n'+ texts[0]+'\n\n' :'' )+
|
|
2988
3053
|
(complete? texts.slice(3,3+prepareList.length).join('\n\n')+'\n\n' : '' )+
|
|
2989
3054
|
'\n-- functions\n' + functionLines.join('\n')+
|
|
@@ -3116,6 +3181,8 @@ AppBackend.prototype.exportacionesGenerico = async function exportacionesGeneric
|
|
|
3116
3181
|
if (typeof result[0].title !== "string" || typeof result[0].rows !== "object" && !(result[0].rows instanceof Array) ) {
|
|
3117
3182
|
throw new Error ("exportacionesGenerico debe recibir {title:string, rows:Record<string, any>[]}")
|
|
3118
3183
|
}
|
|
3184
|
+
csvFileName = result[0].csvFileName ?? csvFileName;
|
|
3185
|
+
fileName = result[0].fileName ?? fileName;
|
|
3119
3186
|
await bestGlobals.sleep(100);
|
|
3120
3187
|
context.informProgress({message:`buscando archivos recién generados`})
|
|
3121
3188
|
/** @type {{url:string, label:string}[]} */
|
package/lib/procedures-table.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
"use strict";
|
|
3
3
|
|
|
4
|
-
var {datetime, changing, coalesce} = require('best-globals');
|
|
4
|
+
var {datetime, changing, coalesce, splitRawRowIntoRow} = require('best-globals');
|
|
5
5
|
var XLSX = require('xlsx');
|
|
6
6
|
var fs = require('fs/promises')
|
|
7
7
|
var fsSync = require('fs');
|
|
@@ -78,13 +78,14 @@ ProcedureTables = [
|
|
|
78
78
|
{name: 'table', encoding:'plain'},
|
|
79
79
|
{name: 'fixedFields', defaultValue:[]},
|
|
80
80
|
{name: 'paramfun', defaultValue:[]},
|
|
81
|
-
{name: 'pick', defaultValue:'', encoding:'plain'}
|
|
81
|
+
{name: 'pick', defaultValue:'', encoding:'plain'},
|
|
82
|
+
{name: 'retrieveIgnoringWhere', defaultValue:false}
|
|
82
83
|
],
|
|
83
84
|
coreFunction:
|
|
84
85
|
/**
|
|
85
86
|
*
|
|
86
87
|
* @param {*} context
|
|
87
|
-
* @param {{table:string, fixedFields:{fieldName:string, value:any, range:string}[], paramfun:string[], pick:string}} parameters
|
|
88
|
+
* @param {{table:string, fixedFields:{fieldName:string, value:any, range:string}[], paramfun:string[], pick:string, retrieveIgnoringWhere:boolean}} parameters * @param {{table:string, fixedFields:{fieldName:string, value:any, range:string}[], paramfun:string[], pick:string}} parameters
|
|
88
89
|
*/
|
|
89
90
|
async function tableDatum(context, parameters){
|
|
90
91
|
var be=context.be;
|
|
@@ -148,7 +149,7 @@ ProcedureTables = [
|
|
|
148
149
|
/** @type {string} */
|
|
149
150
|
var sql="SELECT "+[...defTable.sql.select].join(', ')+
|
|
150
151
|
"\n FROM "+defTable.sql.from+
|
|
151
|
-
"\n WHERE "+(defTable.sql.where||(defTable.allow.select && !defTable.forInsertOnlyMode?'true':'false'))+fixedClausule.join("")+
|
|
152
|
+
"\n WHERE "+((parameters.retrieveIgnoringWhere?'true':defTable.sql.where)||(defTable.allow.select && !defTable.forInsertOnlyMode?'true':'false'))+fixedClausule.join("")+
|
|
152
153
|
// " ORDER BY "+defTable.primaryKey.map(be.db.quoteIdent.bind(be.db)).join(',')
|
|
153
154
|
"\n ORDER BY "+(defTable.sql.orderBy||defTable.primaryKey).map(function(fieldName){ return be.db.quoteIdent(fieldName); }).join(',')
|
|
154
155
|
if(specialFixedClause.length){
|
|
@@ -804,7 +805,8 @@ ProcedureTables = [
|
|
|
804
805
|
var rowsForUpsert=lines.slice(1).map(function(line){
|
|
805
806
|
var othersArray = [];
|
|
806
807
|
if(separator=='|'){
|
|
807
|
-
var row = line
|
|
808
|
+
var row = splitRawRowIntoRow(line);
|
|
809
|
+
|
|
808
810
|
}else{
|
|
809
811
|
var row=line.split(separator);
|
|
810
812
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "backend-plus",
|
|
3
3
|
"description": "Backend for the anti Pareto rule",
|
|
4
|
-
"version": "2.0.0-rc.
|
|
4
|
+
"version": "2.0.0-rc.11",
|
|
5
5
|
"author": "Codenautas <codenautas@googlegroups.com>",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": "codenautas/backend-plus",
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
"lib",
|
|
12
12
|
"for-client",
|
|
13
13
|
"unlogged",
|
|
14
|
-
"src"
|
|
14
|
+
"src",
|
|
15
|
+
"install"
|
|
15
16
|
],
|
|
16
17
|
"contributors": [
|
|
17
18
|
{
|
|
@@ -31,32 +32,32 @@
|
|
|
31
32
|
"@upgraded/locate-path": "^6.0.0-alfa.1",
|
|
32
33
|
"ajax-best-promise": "^0.4.0",
|
|
33
34
|
"backend-skins": "^0.1.15",
|
|
34
|
-
"best-globals": "^1.1.
|
|
35
|
+
"best-globals": "^1.1.4",
|
|
35
36
|
"big.js": "^6.2.1",
|
|
36
37
|
"body-parser": "^1.20.2",
|
|
37
|
-
"cast-error": "^0.1.
|
|
38
|
+
"cast-error": "^0.1.1",
|
|
38
39
|
"castellano": "^0.1.3",
|
|
39
40
|
"connect-pg-simple": "^9.0.1",
|
|
40
41
|
"cookie-parser": "^1.4.6",
|
|
41
42
|
"dialog-promise": "^0.9.15",
|
|
42
43
|
"discrepances": "^0.2.8",
|
|
43
|
-
"express": "^4.
|
|
44
|
-
"express-session": "^1.
|
|
44
|
+
"express": "^4.19.2",
|
|
45
|
+
"express-session": "^1.18.0",
|
|
45
46
|
"express-useragent": "^1.0.15",
|
|
46
47
|
"fs-extra": "^11.2.0",
|
|
47
48
|
"js-to-html": "^1.3.2",
|
|
48
49
|
"js-yaml": "^4.1.0",
|
|
49
50
|
"json4all": "^1.3.0-beta.1",
|
|
50
51
|
"lazy-some": "^0.1.0",
|
|
51
|
-
"like-ar": "^0.
|
|
52
|
+
"like-ar": "^0.4.0",
|
|
52
53
|
"login-plus": "^1.7.1",
|
|
53
54
|
"memorystore": "^1.6.7",
|
|
54
55
|
"mini-tools": "^1.12.1",
|
|
55
56
|
"moment": "^2.30.1",
|
|
56
57
|
"multiparty": "^4.2.3",
|
|
57
|
-
"nodemailer": "^6.9.
|
|
58
|
+
"nodemailer": "^6.9.13",
|
|
58
59
|
"numeral": "^2.0.6",
|
|
59
|
-
"pg-promise-strict": "^1.
|
|
60
|
+
"pg-promise-strict": "^1.4.0",
|
|
60
61
|
"pikaday": "^1.8.2",
|
|
61
62
|
"pug": "^3.0.2",
|
|
62
63
|
"read-yaml-promise": "^1.0.2",
|
|
@@ -67,8 +68,8 @@
|
|
|
67
68
|
"session-file-store": "^1.5.0",
|
|
68
69
|
"sql-tools": "^0.1.2",
|
|
69
70
|
"stack-trace": "^0.0.10",
|
|
70
|
-
"stylus": "0.
|
|
71
|
-
"type-store": "^0.4.
|
|
71
|
+
"stylus": "0.63.0",
|
|
72
|
+
"type-store": "^0.4.1",
|
|
72
73
|
"typed-controls": "^0.12.0",
|
|
73
74
|
"xlsx": "https://cdn.sheetjs.com/xlsx-0.19.3/xlsx-0.19.3.tgz"
|
|
74
75
|
},
|
|
@@ -81,7 +82,7 @@
|
|
|
81
82
|
"@types/js-yaml": "^4.0.9",
|
|
82
83
|
"@types/mocha": "^10.0.6",
|
|
83
84
|
"@types/multiparty": "~0.0.36",
|
|
84
|
-
"@types/node": "^20.
|
|
85
|
+
"@types/node": "^20.12.2",
|
|
85
86
|
"@types/nodemailer": "^6.4.14",
|
|
86
87
|
"@types/numeral": "~2.0.5",
|
|
87
88
|
"@types/session-file-store": "^1.2.5",
|
|
@@ -89,20 +90,20 @@
|
|
|
89
90
|
"@types/websql": "~0.0.30",
|
|
90
91
|
"esprima": "^4.0.1",
|
|
91
92
|
"expect.js": "~0.3.1",
|
|
92
|
-
"karma": "6.4.
|
|
93
|
+
"karma": "6.4.3",
|
|
93
94
|
"karma-chrome-launcher": "^3.2.0",
|
|
94
95
|
"karma-expect": "^1.1.3",
|
|
95
|
-
"karma-firefox-launcher": "^2.1.
|
|
96
|
+
"karma-firefox-launcher": "^2.1.3",
|
|
96
97
|
"karma-ie-launcher": "^1.0.0",
|
|
97
98
|
"karma-mocha": "^2.0.1",
|
|
98
99
|
"kill-9": "~0.4.3",
|
|
99
|
-
"mocha": "^10.
|
|
100
|
+
"mocha": "^10.4.0",
|
|
100
101
|
"nyc": "^15.1.0",
|
|
101
|
-
"puppeteer": "^
|
|
102
|
+
"puppeteer": "^22.6.1",
|
|
102
103
|
"sinon": "^17.0.1",
|
|
103
104
|
"supertest": "^6.3.4",
|
|
104
105
|
"types.d.ts": "~0.6.21",
|
|
105
|
-
"typescript": "^5.
|
|
106
|
+
"typescript": "^5.4.3",
|
|
106
107
|
"why-is-node-running": "^2.2.2"
|
|
107
108
|
},
|
|
108
109
|
"engines": {
|