prostgles-server 3.0.87 → 3.0.89
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/.eslintignore +5 -0
- package/.eslintrc.json +30 -0
- package/dist/DBEventsManager.js +1 -1
- package/dist/DBEventsManager.js.map +1 -1
- package/dist/DBSchemaBuilder.d.ts.map +1 -1
- package/dist/DBSchemaBuilder.js +6 -6
- package/dist/DBSchemaBuilder.js.map +1 -1
- package/dist/DboBuilder/QueryBuilder/Functions.js +9 -9
- package/dist/DboBuilder/QueryBuilder/Functions.js.map +1 -1
- package/dist/DboBuilder/QueryBuilder/QueryBuilder.d.ts.map +1 -1
- package/dist/DboBuilder/QueryBuilder/QueryBuilder.js +8 -7
- package/dist/DboBuilder/QueryBuilder/QueryBuilder.js.map +1 -1
- package/dist/DboBuilder/QueryBuilder/makeSelectQuery.d.ts.map +1 -1
- package/dist/DboBuilder/QueryBuilder/makeSelectQuery.js +4 -4
- package/dist/DboBuilder/QueryBuilder/makeSelectQuery.js.map +1 -1
- package/dist/DboBuilder/TableHandler.d.ts.map +1 -1
- package/dist/DboBuilder/TableHandler.js +18 -20
- package/dist/DboBuilder/TableHandler.js.map +1 -1
- package/dist/DboBuilder/ViewHandler.d.ts +0 -10
- package/dist/DboBuilder/ViewHandler.d.ts.map +1 -1
- package/dist/DboBuilder/ViewHandler.js +50 -63
- package/dist/DboBuilder/ViewHandler.js.map +1 -1
- package/dist/DboBuilder/delete.js +0 -1
- package/dist/DboBuilder/delete.js.map +1 -1
- package/dist/DboBuilder/getColumns.js +5 -4
- package/dist/DboBuilder/getColumns.js.map +1 -1
- package/dist/DboBuilder/getCondition.d.ts.map +1 -1
- package/dist/DboBuilder/getCondition.js +6 -6
- package/dist/DboBuilder/getCondition.js.map +1 -1
- package/dist/DboBuilder/insert.js +15 -16
- package/dist/DboBuilder/insert.js.map +1 -1
- package/dist/DboBuilder/insertDataParse.d.ts.map +1 -1
- package/dist/DboBuilder/insertDataParse.js +9 -10
- package/dist/DboBuilder/insertDataParse.js.map +1 -1
- package/dist/DboBuilder/parseUpdateRules.js +2 -2
- package/dist/DboBuilder/parseUpdateRules.js.map +1 -1
- package/dist/DboBuilder/runSQL.d.ts.map +1 -1
- package/dist/DboBuilder/runSQL.js +5 -5
- package/dist/DboBuilder/runSQL.js.map +1 -1
- package/dist/DboBuilder/subscribe.js +3 -3
- package/dist/DboBuilder/subscribe.js.map +1 -1
- package/dist/DboBuilder/update.js +5 -6
- package/dist/DboBuilder/update.js.map +1 -1
- package/dist/DboBuilder/uploadFile.d.ts.map +1 -1
- package/dist/DboBuilder/uploadFile.js +1 -1
- package/dist/DboBuilder/uploadFile.js.map +1 -1
- package/dist/DboBuilder.d.ts.map +1 -1
- package/dist/DboBuilder.js +13 -14
- package/dist/DboBuilder.js.map +1 -1
- package/dist/FileManager.d.ts.map +1 -1
- package/dist/FileManager.js +3 -5
- package/dist/FileManager.js.map +1 -1
- package/dist/Filtering.js +7 -7
- package/dist/Filtering.js.map +1 -1
- package/dist/JSONBValidation/validate_jsonb_schema_sql.d.ts +3 -0
- package/dist/JSONBValidation/validate_jsonb_schema_sql.d.ts.map +1 -0
- package/dist/JSONBValidation/validate_jsonb_schema_sql.js +295 -0
- package/dist/JSONBValidation/validate_jsonb_schema_sql.js.map +1 -0
- package/dist/JSONBValidation/validation.d.ts +108 -0
- package/dist/JSONBValidation/validation.d.ts.map +1 -0
- package/dist/JSONBValidation/validation.js +222 -0
- package/dist/JSONBValidation/validation.js.map +1 -0
- package/dist/PostgresNotifListenManager.js +1 -1
- package/dist/PostgresNotifListenManager.js.map +1 -1
- package/dist/Prostgles.d.ts.map +1 -1
- package/dist/Prostgles.js +20 -20
- package/dist/Prostgles.js.map +1 -1
- package/dist/PubSubManager/initPubSubManager.d.ts.map +1 -1
- package/dist/PubSubManager/initPubSubManager.js +10 -7
- package/dist/PubSubManager/initPubSubManager.js.map +1 -1
- package/dist/PublishParser.d.ts.map +1 -1
- package/dist/PublishParser.js +122 -125
- package/dist/PublishParser.js.map +1 -1
- package/dist/SyncReplication.d.ts.map +1 -1
- package/dist/SyncReplication.js +19 -16
- package/dist/SyncReplication.js.map +1 -1
- package/dist/TableConfig.d.ts +9 -5
- package/dist/TableConfig.d.ts.map +1 -1
- package/dist/TableConfig.js +33 -12
- package/dist/TableConfig.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/shortestPath.js +11 -11
- package/dist/shortestPath.js.map +1 -1
- package/dist/validation.d.ts +50 -24
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +177 -53
- package/dist/validation.js.map +1 -1
- package/lib/AuthHandler.d.ts +11 -11
- package/lib/AuthHandler.d.ts.map +1 -1
- package/lib/DBEventsManager.js +1 -1
- package/lib/DBEventsManager.ts +1 -1
- package/lib/DBSchemaBuilder.d.ts +3 -3
- package/lib/DBSchemaBuilder.d.ts.map +1 -1
- package/lib/DBSchemaBuilder.js +6 -6
- package/lib/DBSchemaBuilder.ts +10 -12
- package/lib/DboBuilder/QueryBuilder/Functions.d.ts +3 -3
- package/lib/DboBuilder/QueryBuilder/Functions.d.ts.map +1 -1
- package/lib/DboBuilder/QueryBuilder/Functions.js +9 -9
- package/lib/DboBuilder/QueryBuilder/Functions.ts +13 -13
- package/lib/DboBuilder/QueryBuilder/QueryBuilder.d.ts +3 -3
- package/lib/DboBuilder/QueryBuilder/QueryBuilder.d.ts.map +1 -1
- package/lib/DboBuilder/QueryBuilder/QueryBuilder.js +8 -7
- package/lib/DboBuilder/QueryBuilder/QueryBuilder.ts +12 -12
- package/lib/DboBuilder/QueryBuilder/makeSelectQuery.d.ts.map +1 -1
- package/lib/DboBuilder/QueryBuilder/makeSelectQuery.js +4 -4
- package/lib/DboBuilder/QueryBuilder/makeSelectQuery.ts +5 -5
- package/lib/DboBuilder/TableHandler.d.ts +1 -1
- package/lib/DboBuilder/TableHandler.d.ts.map +1 -1
- package/lib/DboBuilder/TableHandler.js +18 -20
- package/lib/DboBuilder/TableHandler.ts +21 -20
- package/lib/DboBuilder/ViewHandler.d.ts +1 -11
- package/lib/DboBuilder/ViewHandler.d.ts.map +1 -1
- package/lib/DboBuilder/ViewHandler.js +50 -63
- package/lib/DboBuilder/ViewHandler.ts +68 -97
- package/lib/DboBuilder/delete.js +0 -1
- package/lib/DboBuilder/delete.ts +1 -1
- package/lib/DboBuilder/getColumns.js +5 -4
- package/lib/DboBuilder/getColumns.ts +5 -5
- package/lib/DboBuilder/getCondition.d.ts.map +1 -1
- package/lib/DboBuilder/getCondition.js +6 -6
- package/lib/DboBuilder/getCondition.ts +7 -7
- package/lib/DboBuilder/insert.js +15 -16
- package/lib/DboBuilder/insert.ts +18 -18
- package/lib/DboBuilder/insertDataParse.d.ts.map +1 -1
- package/lib/DboBuilder/insertDataParse.js +9 -10
- package/lib/DboBuilder/insertDataParse.ts +42 -43
- package/lib/DboBuilder/parseUpdateRules.js +2 -2
- package/lib/DboBuilder/parseUpdateRules.ts +2 -2
- package/lib/DboBuilder/runSQL.d.ts.map +1 -1
- package/lib/DboBuilder/runSQL.js +5 -5
- package/lib/DboBuilder/runSQL.ts +6 -6
- package/lib/DboBuilder/subscribe.d.ts +1 -1
- package/lib/DboBuilder/subscribe.d.ts.map +1 -1
- package/lib/DboBuilder/subscribe.js +3 -3
- package/lib/DboBuilder/subscribe.ts +3 -3
- package/lib/DboBuilder/update.js +5 -6
- package/lib/DboBuilder/update.ts +6 -6
- package/lib/DboBuilder/uploadFile.d.ts.map +1 -1
- package/lib/DboBuilder/uploadFile.js +1 -1
- package/lib/DboBuilder/uploadFile.ts +2 -2
- package/lib/DboBuilder.d.ts +22 -22
- package/lib/DboBuilder.d.ts.map +1 -1
- package/lib/DboBuilder.js +13 -14
- package/lib/DboBuilder.ts +19 -19
- package/lib/FileManager.d.ts +6 -6
- package/lib/FileManager.d.ts.map +1 -1
- package/lib/FileManager.js +3 -5
- package/lib/FileManager.ts +7 -6
- package/lib/Filtering.d.ts +1 -1
- package/lib/Filtering.d.ts.map +1 -1
- package/lib/Filtering.js +7 -7
- package/lib/Filtering.ts +7 -7
- package/lib/JSONBValidation/validate_jsonb_schema_sql.d.ts +3 -0
- package/lib/JSONBValidation/validate_jsonb_schema_sql.d.ts.map +1 -0
- package/lib/JSONBValidation/validate_jsonb_schema_sql.js +294 -0
- package/lib/JSONBValidation/validate_jsonb_schema_sql.ts +293 -0
- package/lib/JSONBValidation/validation.d.ts +108 -0
- package/lib/JSONBValidation/validation.d.ts.map +1 -0
- package/lib/JSONBValidation/validation.js +221 -0
- package/lib/JSONBValidation/validation.ts +332 -0
- package/lib/PostgresNotifListenManager.d.ts +1 -1
- package/lib/PostgresNotifListenManager.d.ts.map +1 -1
- package/lib/PostgresNotifListenManager.js +1 -1
- package/lib/PostgresNotifListenManager.ts +1 -1
- package/lib/Prostgles.d.ts +14 -14
- package/lib/Prostgles.d.ts.map +1 -1
- package/lib/Prostgles.js +20 -20
- package/lib/Prostgles.ts +22 -21
- package/lib/PubSubManager/PubSubManager.d.ts +7 -7
- package/lib/PubSubManager/PubSubManager.d.ts.map +1 -1
- package/lib/PubSubManager/initPubSubManager.d.ts.map +1 -1
- package/lib/PubSubManager/initPubSubManager.js +10 -7
- package/lib/PubSubManager/initPubSubManager.ts +12 -7
- package/lib/PublishParser.d.ts +32 -32
- package/lib/PublishParser.d.ts.map +1 -1
- package/lib/PublishParser.js +121 -124
- package/lib/PublishParser.ts +125 -127
- package/lib/SchemaWatch.d.ts +1 -1
- package/lib/SchemaWatch.d.ts.map +1 -1
- package/lib/SyncReplication.d.ts +5 -5
- package/lib/SyncReplication.d.ts.map +1 -1
- package/lib/SyncReplication.js +19 -16
- package/lib/SyncReplication.ts +470 -471
- package/lib/TableConfig.d.ts +28 -24
- package/lib/TableConfig.d.ts.map +1 -1
- package/lib/TableConfig.js +33 -12
- package/lib/TableConfig.ts +55 -21
- package/lib/index.js +1 -1
- package/lib/index.ts +1 -1
- package/lib/shortestPath.d.ts +1 -1
- package/lib/shortestPath.d.ts.map +1 -1
- package/lib/shortestPath.js +11 -11
- package/lib/shortestPath.ts +11 -11
- package/package.json +10 -6
- package/tests/client/PID.txt +1 -1
- package/tests/client/package-lock.json +53 -31
- package/tests/client/package.json +4 -1
- package/tests/isomorphic_queries.d.ts +4 -1
- package/tests/isomorphic_queries.d.ts.map +1 -1
- package/tests/isomorphic_queries.js +38 -30
- package/tests/isomorphic_queries.ts +40 -33
- package/tests/server/DBoGenerated.d.ts +1 -1
- package/tests/server/index.js +8 -7
- package/tests/server/index.ts +10 -8
- package/tests/server/package-lock.json +76 -58
- package/tests/server/package.json +2 -2
- package/tests/server/server.ts +2 -3
- package/lib/validation.d.ts +0 -100
- package/lib/validation.d.ts.map +0 -1
- package/lib/validation.js +0 -280
- package/lib/validation.ts +0 -360
package/lib/PublishParser.ts
CHANGED
|
@@ -406,7 +406,7 @@ export class PublishParser {
|
|
|
406
406
|
}
|
|
407
407
|
|
|
408
408
|
async getAllowedMethods(socket: any, userData?: AuthResult): Promise<{ [key: string]: Method; }> {
|
|
409
|
-
|
|
409
|
+
const methods: { [key: string]: Method; } = {};
|
|
410
410
|
|
|
411
411
|
const publishParams = await this.getPublishParams({ socket }, userData);
|
|
412
412
|
const _methods = await applyParamsIfFunc(this.publishMethods, publishParams);
|
|
@@ -433,10 +433,10 @@ export class PublishParser {
|
|
|
433
433
|
*/
|
|
434
434
|
async getPublish(localParams: LocalParams, clientInfo?: AuthResult): Promise<PublishObject> {
|
|
435
435
|
const publishParams = await this.getPublishParams(localParams, clientInfo)
|
|
436
|
-
|
|
436
|
+
const _publish = await applyParamsIfFunc(this.publish, publishParams);
|
|
437
437
|
|
|
438
438
|
if (_publish === "*") {
|
|
439
|
-
|
|
439
|
+
const publish = {} as any;
|
|
440
440
|
this.prostgles.dboBuilder.tablesOrViews?.map(tov => {
|
|
441
441
|
publish[tov.name] = "*";
|
|
442
442
|
});
|
|
@@ -455,7 +455,7 @@ export class PublishParser {
|
|
|
455
455
|
|
|
456
456
|
if (!command || !tableName) throw "command OR tableName are missing";
|
|
457
457
|
|
|
458
|
-
|
|
458
|
+
const rtm = RULE_TO_METHODS.find(rtms => (rtms.methods as any).includes(command));
|
|
459
459
|
if (!rtm) {
|
|
460
460
|
throw "Invalid command: " + command;
|
|
461
461
|
}
|
|
@@ -476,7 +476,7 @@ export class PublishParser {
|
|
|
476
476
|
|
|
477
477
|
if (schm && schm.err) throw schm.err;
|
|
478
478
|
|
|
479
|
-
|
|
479
|
+
const table_rule = await this.getTableRules({ tableName, localParams }, clientInfo);
|
|
480
480
|
if (!table_rule) throw { stack: ["getValidatedRequestRule()"], message: "Invalid or disallowed table: " + tableName };
|
|
481
481
|
|
|
482
482
|
|
|
@@ -493,174 +493,172 @@ export class PublishParser {
|
|
|
493
493
|
|
|
494
494
|
async getTableRules({ tableName, localParams }: DboTable, clientInfo?: AuthResult): Promise<ParsedPublishTable | undefined> {
|
|
495
495
|
|
|
496
|
-
|
|
497
|
-
if (!localParams || !tableName) throw { stack: ["getTableRules()"], message: "publish OR socket OR dbo OR tableName are missing" };
|
|
496
|
+
if (!localParams || !tableName) throw { stack: ["getTableRules()"], message: "publish OR socket OR dbo OR tableName are missing" };
|
|
498
497
|
|
|
499
|
-
|
|
498
|
+
const _publish = await this.getPublish(localParams, clientInfo);
|
|
500
499
|
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
500
|
+
const raw_table_rules = _publish[tableName];
|
|
501
|
+
if (!raw_table_rules || isObject(raw_table_rules) && Object.values(raw_table_rules).every(v => !v)) {
|
|
502
|
+
return undefined;
|
|
503
|
+
}
|
|
505
504
|
|
|
506
|
-
|
|
505
|
+
let parsed_table: ParsedPublishTable = {};
|
|
507
506
|
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
507
|
+
/* Get view or table specific rules */
|
|
508
|
+
const tHandler = (this.dbo[tableName] as TableHandler | ViewHandler);
|
|
509
|
+
const is_view = tHandler.is_view;
|
|
510
|
+
const canSubscribe = (!is_view || tHandler.columns.some(c => c.references));
|
|
511
|
+
if (!tHandler) {
|
|
512
|
+
throw { stack: ["getTableRules()"], message: `${tableName} could not be found in dbo` };
|
|
513
|
+
}
|
|
515
514
|
|
|
516
|
-
|
|
515
|
+
const MY_RULES = RULE_TO_METHODS.filter(r => {
|
|
517
516
|
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
517
|
+
/** Check PG User privileges */
|
|
518
|
+
const pgUserIsAllowedThis = tHandler.tableOrViewInfo.privileges[r.sqlRule];
|
|
519
|
+
let result = (!is_view || !r.table_only) && pgUserIsAllowedThis;
|
|
521
520
|
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
521
|
+
if (!pgUserIsAllowedThis && isPlainObject(raw_table_rules) && (raw_table_rules as PublishTableRule)[r.sqlRule]) {
|
|
522
|
+
throw `Your postgres user is not allowed ${r.sqlRule} on table ${tableName}`;
|
|
523
|
+
}
|
|
525
524
|
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
}
|
|
525
|
+
if ((r.rule === "subscribe" || r.rule === "sync") && !this.prostgles.isSuperUser) {
|
|
526
|
+
result = false;
|
|
527
|
+
if (isPlainObject(raw_table_rules) && (raw_table_rules as PublishTableRule)[r.rule]) {
|
|
528
|
+
throw `Cannot publish realtime rule ${tableName}.${r.rule}. Superuser is required for this`
|
|
531
529
|
}
|
|
530
|
+
}
|
|
532
531
|
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
532
|
+
if(r.rule === "subscribe" && !canSubscribe){
|
|
533
|
+
result = false;
|
|
534
|
+
}
|
|
536
535
|
|
|
537
|
-
|
|
538
|
-
|
|
536
|
+
return result;
|
|
537
|
+
});
|
|
539
538
|
|
|
540
539
|
|
|
541
540
|
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
541
|
+
/* All methods allowed. Add no limits for table rules */
|
|
542
|
+
if ([true, "*"].includes(raw_table_rules as any)) {
|
|
543
|
+
parsed_table = {};
|
|
544
|
+
MY_RULES.filter(r => r.no_limits).forEach(r => {
|
|
545
|
+
parsed_table[r.rule] = { ...r.no_limits as object } as any;
|
|
546
|
+
});
|
|
548
547
|
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
548
|
+
/** Specific rules allowed */
|
|
549
|
+
} else if (isPlainObject(raw_table_rules) && getKeys(raw_table_rules).length) {
|
|
550
|
+
const allRuleKeys: (keyof PublishViewRule | keyof PublishTableRule)[] = getKeys(raw_table_rules);
|
|
551
|
+
const dissallowedRuleKeys = allRuleKeys.filter(m => !(raw_table_rules as PublishTableRule)[m])
|
|
553
552
|
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
553
|
+
MY_RULES.map(r => {
|
|
554
|
+
/** Unless specifically disabled these are allowed */
|
|
555
|
+
if (["getInfo", "getColumns"].includes(r.rule) && !dissallowedRuleKeys.includes(r.rule as any)) {
|
|
556
|
+
parsed_table[r.rule] = r.no_limits as any;
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
560
559
|
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
560
|
+
/** Add no_limit values for implied/ fully allowed methods */
|
|
561
|
+
if ([true, "*"].includes((raw_table_rules as PublishTableRule)[r.rule] as any) && r.no_limits) {
|
|
562
|
+
parsed_table[r.rule] = Object.assign({}, r.no_limits) as any;
|
|
564
563
|
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
564
|
+
/** Carry over detailed config */
|
|
565
|
+
} else if (isPlainObject((raw_table_rules as any)[r.rule])) {
|
|
566
|
+
parsed_table[r.rule] = (raw_table_rules as any)[r.rule]
|
|
567
|
+
}
|
|
568
|
+
});
|
|
570
569
|
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
}
|
|
581
|
-
throw `Invalid rule in publish.${tableName} -> ${method} \n${extraInfo}Expecting any of: ${MY_RULES.flatMap(r => [r.rule, ...r.methods]).join(", ")}`;
|
|
570
|
+
allRuleKeys.filter(m => parsed_table[m])
|
|
571
|
+
.forEach((method) => {
|
|
572
|
+
const rule = parsed_table[method];
|
|
573
|
+
|
|
574
|
+
const rm = MY_RULES.find(r => r.rule === method || (r.methods as readonly string[]).includes(method));
|
|
575
|
+
if (!rm) {
|
|
576
|
+
let extraInfo = "";
|
|
577
|
+
if (is_view && RULE_TO_METHODS.find(r => !is_view && r.rule === method || (r.methods as any).includes(method))) {
|
|
578
|
+
extraInfo = "You've specified table rules to a view\n";
|
|
582
579
|
}
|
|
580
|
+
throw `Invalid rule in publish.${tableName} -> ${method} \n${extraInfo}Expecting any of: ${MY_RULES.flatMap(r => [r.rule, ...r.methods]).join(", ")}`;
|
|
581
|
+
}
|
|
583
582
|
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
}
|
|
583
|
+
/* Check RULES for invalid params */
|
|
584
|
+
/* Methods do not have params -> They use them from rules */
|
|
585
|
+
if (method === rm.rule && isObject(rule)) {
|
|
586
|
+
const method_params = getKeys(rule);
|
|
587
|
+
const iparam = method_params.find(p => !rm?.allowed_params.includes(<never>p));
|
|
588
|
+
if (iparam) {
|
|
589
|
+
throw `Invalid setting in publish.${tableName}.${method} -> ${iparam}. \n Expecting any of: ${rm.allowed_params.join(", ")}`;
|
|
592
590
|
}
|
|
591
|
+
}
|
|
593
592
|
|
|
594
|
-
|
|
595
|
-
|
|
593
|
+
/* Add default params (if missing) */
|
|
594
|
+
if (method === "sync") {
|
|
596
595
|
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
596
|
+
if ([true, "*"].includes(parsed_table[method] as any)) {
|
|
597
|
+
throw "Invalid sync rule. Expecting { id_fields: string[], synced_field: string } ";
|
|
598
|
+
}
|
|
600
599
|
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
}
|
|
604
|
-
if (typeof parsed_table[method]?.batch_size !== "number") {
|
|
605
|
-
parsed_table[method]!.batch_size = DEFAULT_SYNC_BATCH_SIZE;
|
|
606
|
-
}
|
|
600
|
+
if (typeof parsed_table[method]?.throttle !== "number") {
|
|
601
|
+
parsed_table[method]!.throttle = 100;
|
|
607
602
|
}
|
|
603
|
+
if (typeof parsed_table[method]?.batch_size !== "number") {
|
|
604
|
+
parsed_table[method]!.batch_size = DEFAULT_SYNC_BATCH_SIZE;
|
|
605
|
+
}
|
|
606
|
+
}
|
|
608
607
|
|
|
609
|
-
|
|
610
|
-
|
|
608
|
+
/* Enable subscribe if not explicitly disabled OR if VIEW with referenced tables */
|
|
609
|
+
const subKey = "subscribe" as const;
|
|
611
610
|
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
}
|
|
611
|
+
if (method === "select" && !dissallowedRuleKeys.includes(subKey)) {
|
|
612
|
+
const sr = MY_RULES.find(r => r.rule === subKey);
|
|
613
|
+
if (sr && canSubscribe) {
|
|
614
|
+
parsed_table[subKey] = { ...sr.no_limits as SubscribeRule };
|
|
615
|
+
parsed_table.subscribeOne = { ...sr.no_limits as SubscribeRule };
|
|
618
616
|
}
|
|
619
|
-
}
|
|
617
|
+
}
|
|
618
|
+
});
|
|
620
619
|
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
620
|
+
} else {
|
|
621
|
+
throw "Unexpected publish"
|
|
622
|
+
}
|
|
624
623
|
|
|
625
|
-
|
|
626
|
-
|
|
624
|
+
const getImpliedMethods = (tableRules: ParsedPublishTable): ParsedPublishTable => {
|
|
625
|
+
const res = { ...tableRules };
|
|
627
626
|
|
|
628
|
-
|
|
629
|
-
|
|
627
|
+
/* Add implied methods if not specifically dissallowed */
|
|
628
|
+
MY_RULES.map(r => {
|
|
630
629
|
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
630
|
+
/** THIS IS A MESS -> some methods cannot be dissallowed (unsync, unsubscribe...) */
|
|
631
|
+
r.methods.forEach(method => {
|
|
632
|
+
const isAllowed = tableRules[r.rule] && (tableRules as any)[method] === undefined;
|
|
633
|
+
if (isAllowed) {
|
|
635
634
|
|
|
636
|
-
|
|
635
|
+
if (method === "updateBatch" && !tableRules.update) {
|
|
636
|
+
// not allowed
|
|
637
637
|
|
|
638
|
-
|
|
638
|
+
} else if (method === "upsert" && (!tableRules.update || !tableRules.insert)) {
|
|
639
|
+
// not allowed
|
|
639
640
|
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
}
|
|
641
|
+
} else {
|
|
642
|
+
(res as any)[method] ??= true;
|
|
643
643
|
}
|
|
644
|
-
}
|
|
644
|
+
}
|
|
645
645
|
});
|
|
646
|
+
});
|
|
646
647
|
|
|
647
|
-
|
|
648
|
-
|
|
648
|
+
return res;
|
|
649
|
+
}
|
|
649
650
|
|
|
650
|
-
|
|
651
|
+
parsed_table = getImpliedMethods(parsed_table);
|
|
651
652
|
|
|
652
|
-
|
|
653
|
-
} catch (e) {
|
|
654
|
-
throw e;
|
|
655
|
-
}
|
|
653
|
+
return parsed_table;
|
|
656
654
|
}
|
|
657
655
|
|
|
658
656
|
|
|
659
657
|
|
|
660
658
|
/* Prepares schema for client. Only allowed views and commands will be present */
|
|
661
659
|
async getSchemaFromPublish(socket: any, userData?: AuthResult): Promise<{ schema: TableSchemaForClient; tables: DBSchemaTable[] }> {
|
|
662
|
-
|
|
663
|
-
|
|
660
|
+
const schema: TableSchemaForClient = {};
|
|
661
|
+
const tables: DBSchemaTable[] = []
|
|
664
662
|
|
|
665
663
|
try {
|
|
666
664
|
/* Publish tables and views based on socket */
|
|
@@ -730,7 +728,7 @@ export class PublishParser {
|
|
|
730
728
|
|
|
731
729
|
|
|
732
730
|
if (method === "getInfo" || method === "getColumns") {
|
|
733
|
-
|
|
731
|
+
const tableRules = await this.getValidatedRequestRule({ tableName, command: method, localParams: { socket } }, clientInfo);
|
|
734
732
|
const res = await (this.dbo[tableName] as any)[method](undefined, undefined, undefined, tableRules, { socket, isRemoteRequest: true });
|
|
735
733
|
if (method === "getInfo") {
|
|
736
734
|
tableInfo = res;
|
package/lib/SchemaWatch.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import { DboBuilder } from "./DboBuilder";
|
|
3
3
|
import { ProstglesInitOptions } from "./Prostgles";
|
|
4
|
-
export
|
|
4
|
+
export type VoidFunction = () => void;
|
|
5
5
|
export declare class SchemaWatch {
|
|
6
6
|
schema_checkIntervalMillis?: NodeJS.Timeout;
|
|
7
7
|
loaded: boolean;
|
package/lib/SchemaWatch.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SchemaWatch.d.ts","sourceRoot":"","sources":["SchemaWatch.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnD,
|
|
1
|
+
{"version":3,"file":"SchemaWatch.d.ts","sourceRoot":"","sources":["SchemaWatch.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnD,MAAM,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC;AAEtC,qBAAa,WAAW;IACtB,0BAA0B,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC;IAC5C,MAAM,UAAS;gBAEH,EAAE,WAAW,EAAE,eAAe,EAAE,mBAAmB,EAAE,YAAY,EAAE,eAAe,EAAE,EAAE,oBAAoB,GAAG;QAAE,YAAY,EAAE,UAAU,CAAC;QAAC,eAAe,EAAE,YAAY,CAAA;KAAE;CA8BrL"}
|
package/lib/SyncReplication.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { PubSubManager, SyncParams } from "./PubSubManager/PubSubManager";
|
|
2
2
|
import { AnyObject } from "prostgles-types";
|
|
3
|
-
export
|
|
3
|
+
export type ClientSyncInfo = Partial<{
|
|
4
4
|
c_fr: AnyObject;
|
|
5
5
|
c_lr: AnyObject;
|
|
6
6
|
/**
|
|
@@ -8,7 +8,7 @@ export declare type ClientSyncInfo = Partial<{
|
|
|
8
8
|
*/
|
|
9
9
|
c_count: number | string;
|
|
10
10
|
}>;
|
|
11
|
-
export
|
|
11
|
+
export type ServerSyncInfo = Partial<{
|
|
12
12
|
s_fr: AnyObject;
|
|
13
13
|
s_lr: AnyObject;
|
|
14
14
|
/**
|
|
@@ -16,17 +16,17 @@ export declare type ServerSyncInfo = Partial<{
|
|
|
16
16
|
*/
|
|
17
17
|
s_count: number | string;
|
|
18
18
|
}>;
|
|
19
|
-
export
|
|
19
|
+
export type SyncBatchInfo = Partial<{
|
|
20
20
|
from_synced: number | null;
|
|
21
21
|
to_synced: number | null;
|
|
22
22
|
end_offset: number | null;
|
|
23
23
|
}>;
|
|
24
|
-
export
|
|
24
|
+
export type onSyncRequestResponse = {
|
|
25
25
|
onSyncRequest?: ClientSyncInfo;
|
|
26
26
|
} | {
|
|
27
27
|
err: AnyObject | string;
|
|
28
28
|
};
|
|
29
|
-
export
|
|
29
|
+
export type ClientExpressData = ClientSyncInfo & {
|
|
30
30
|
data?: AnyObject[];
|
|
31
31
|
deleted?: AnyObject[];
|
|
32
32
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SyncReplication.d.ts","sourceRoot":"","sources":["SyncReplication.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,UAAU,EAA2B,MAAM,+BAA+B,CAAC;AACnG,OAAO,EAAgB,SAAS,EAAmB,MAAM,iBAAiB,CAAC;AAG3E,
|
|
1
|
+
{"version":3,"file":"SyncReplication.d.ts","sourceRoot":"","sources":["SyncReplication.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,UAAU,EAA2B,MAAM,+BAA+B,CAAC;AACnG,OAAO,EAAgB,SAAS,EAAmB,MAAM,iBAAiB,CAAC;AAG3E,MAAM,MAAM,cAAc,GAAG,OAAO,CAAC;IACnC,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE,SAAS,CAAC;IAChB;;OAEG;IACH,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;CAC1B,CAAC,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,OAAO,CAAC;IACnC,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE,SAAS,CAAC;IAChB;;OAEG;IACH,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;CAC1B,CAAC,CAAA;AAEF,MAAM,MAAM,aAAa,GAAG,OAAO,CAAC;IAClC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,CAAC,CAAC;AAEH,MAAM,MAAM,qBAAqB,GAAG;IAClC,aAAa,CAAC,EAAE,cAAc,CAAA;CAC/B,GAAG;IACF,GAAG,EAAE,SAAS,GAAG,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG,cAAc,GAAG;IAC/C,IAAI,CAAC,EAAE,SAAS,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,SAAS,EAAE,CAAC;CACvB,CAAA;AAMD,eAAO,MAAM,QAAQ,UAAiB,aAAa,QAAQ,UAAU,cAAc,iBAAiB,GAAG,SAAS,UAAU,SAAS,GAAG,QAAQ,kBA4d7I,CAAA"}
|
package/lib/SyncReplication.js
CHANGED
|
@@ -13,7 +13,8 @@ const syncData = async (_this, sync, clientData, source) => {
|
|
|
13
13
|
console.error("Orphaned socket", { sync, clientData });
|
|
14
14
|
return;
|
|
15
15
|
}
|
|
16
|
-
const sync_fields = [synced_field, ...id_fields.sort()], orderByAsc = sync_fields.reduce((a, v) => ({ ...a, [v]: true }), {}),
|
|
16
|
+
const sync_fields = [synced_field, ...id_fields.sort()], orderByAsc = sync_fields.reduce((a, v) => ({ ...a, [v]: true }), {}),
|
|
17
|
+
// orderByDesc = sync_fields.reduce((a, v) => ({ ...a, [v]: false }), {}),
|
|
17
18
|
// desc_params = { orderBy: [{ [synced_field]: false }].concat(id_fields.map(f => ({ [f]: false }) )) },
|
|
18
19
|
// asc_params = { orderBy: [synced_field].concat(id_fields) },
|
|
19
20
|
rowsIdsMatch = (a, b) => {
|
|
@@ -22,7 +23,7 @@ const syncData = async (_this, sync, clientData, source) => {
|
|
|
22
23
|
return rowsIdsMatch(a, b) && a?.[synced_field].toString() === b?.[synced_field].toString();
|
|
23
24
|
}, getServerRowInfo = async (args = {}) => {
|
|
24
25
|
const { from_synced = null, to_synced = null, offset = 0, limit } = args;
|
|
25
|
-
|
|
26
|
+
const _filter = { ...filter };
|
|
26
27
|
if (from_synced || to_synced) {
|
|
27
28
|
_filter[synced_field] = {
|
|
28
29
|
...(from_synced ? { $gte: from_synced } : {}),
|
|
@@ -39,11 +40,11 @@ const syncData = async (_this, sync, clientData, source) => {
|
|
|
39
40
|
return { s_fr: first_rows?.[0] || null, s_lr: last_rows?.[0] || null, s_count: count };
|
|
40
41
|
}, getClientRowInfo = (args = {}) => {
|
|
41
42
|
const { from_synced = null, to_synced = null, end_offset = null } = args;
|
|
42
|
-
|
|
43
|
-
|
|
43
|
+
const res = new Promise((resolve, reject) => {
|
|
44
|
+
const onSyncRequest = { from_synced, to_synced, end_offset }; //, forReal: true };
|
|
44
45
|
socket.emit(channel_name, { onSyncRequest }, (resp) => {
|
|
45
46
|
if (resp && "onSyncRequest" in resp && resp?.onSyncRequest) {
|
|
46
|
-
|
|
47
|
+
const c_fr = resp.onSyncRequest.c_fr, c_lr = resp.onSyncRequest.c_lr, c_count = resp.onSyncRequest.c_count;
|
|
47
48
|
// console.log(onSyncRequest, { c_fr, c_lr, c_count }, socket._user);
|
|
48
49
|
return resolve({ c_fr, c_lr, c_count });
|
|
49
50
|
}
|
|
@@ -73,14 +74,14 @@ const syncData = async (_this, sync, clientData, source) => {
|
|
|
73
74
|
});
|
|
74
75
|
}
|
|
75
76
|
}, getServerData = async (from_synced = 0, offset = 0) => {
|
|
76
|
-
|
|
77
|
+
const _filter = {
|
|
77
78
|
...filter,
|
|
78
79
|
[synced_field]: { $gte: from_synced || 0 }
|
|
79
80
|
};
|
|
80
81
|
if (!_this?.dbo?.[table_name]?.find)
|
|
81
82
|
throw "_this?.dbo?.[table_name]?.find is missing";
|
|
82
83
|
try {
|
|
83
|
-
|
|
84
|
+
const res = _this?.dbo?.[table_name]?.find?.(_filter, {
|
|
84
85
|
select: params.select,
|
|
85
86
|
orderBy: orderByAsc,
|
|
86
87
|
offset: offset || 0,
|
|
@@ -131,7 +132,7 @@ const syncData = async (_this, sync, clientData, source) => {
|
|
|
131
132
|
if (!table_rules)
|
|
132
133
|
throw "table_rules missing";
|
|
133
134
|
if (table_rules.update && updates.length) {
|
|
134
|
-
|
|
135
|
+
const updateData = [];
|
|
135
136
|
await Promise.all(updates.map(upd => {
|
|
136
137
|
const id_filter = (0, PubSubManager_1.pickKeys)(upd, id_fields);
|
|
137
138
|
const syncSafeFilter = { $and: [id_filter, { [synced_field]: { "<": upd[synced_field] } }] };
|
|
@@ -216,7 +217,7 @@ const syncData = async (_this, sync, clientData, source) => {
|
|
|
216
217
|
else {
|
|
217
218
|
result = Math.min(...getNumbers([c_fr[synced_field], s_fr?.[synced_field]]));
|
|
218
219
|
}
|
|
219
|
-
|
|
220
|
+
const min_count = Math.min(...getNumbers([c_count, s_count]));
|
|
220
221
|
let end_offset = 1; // Math.min(s_count, c_count) - 1;
|
|
221
222
|
let step = 0;
|
|
222
223
|
while (min_count > 5 && end_offset < min_count) {
|
|
@@ -224,7 +225,7 @@ const syncData = async (_this, sync, clientData, source) => {
|
|
|
224
225
|
// console.log("getLastSynced... end_offset > " + end_offset);
|
|
225
226
|
let server_row;
|
|
226
227
|
if (c_lr) {
|
|
227
|
-
|
|
228
|
+
const _filter = {};
|
|
228
229
|
sync_fields.map(key => {
|
|
229
230
|
_filter[key] = c_lr[key];
|
|
230
231
|
});
|
|
@@ -259,13 +260,14 @@ const syncData = async (_this, sync, clientData, source) => {
|
|
|
259
260
|
* Will push pull sync between client and server from a given from_synced value
|
|
260
261
|
*/
|
|
261
262
|
syncBatch = async (from_synced) => {
|
|
262
|
-
let offset = 0,
|
|
263
|
+
let offset = 0, canContinue = true;
|
|
264
|
+
const limit = batch_size, min_synced = from_synced || 0, max_synced = from_synced;
|
|
263
265
|
let inserted = 0, updated = 0, pushed = 0, deleted = 0, total = 0;
|
|
264
266
|
// console.log("syncBatch", from_synced)
|
|
265
267
|
while (canContinue) {
|
|
266
|
-
|
|
268
|
+
const cData = await getClientData(min_synced, offset);
|
|
267
269
|
if (cData.length) {
|
|
268
|
-
|
|
270
|
+
const res = await upsertData(cData);
|
|
269
271
|
inserted += res.inserted;
|
|
270
272
|
updated += res.updated;
|
|
271
273
|
}
|
|
@@ -289,12 +291,12 @@ const syncData = async (_this, sync, clientData, source) => {
|
|
|
289
291
|
}));
|
|
290
292
|
sData = await getServerData(min_synced, offset);
|
|
291
293
|
}
|
|
292
|
-
|
|
294
|
+
const forClient = sData.filter(s => {
|
|
293
295
|
return !cData.find(c => rowsIdsMatch(c, s) &&
|
|
294
296
|
+c[synced_field] >= +s[synced_field]);
|
|
295
297
|
});
|
|
296
298
|
if (forClient.length) {
|
|
297
|
-
|
|
299
|
+
const res = await pushData(forClient.filter(d => !sync.wal || !sync.wal.isInHistory(d)));
|
|
298
300
|
pushed += res.pushed;
|
|
299
301
|
}
|
|
300
302
|
if (sData.length) {
|
|
@@ -306,7 +308,7 @@ const syncData = async (_this, sync, clientData, source) => {
|
|
|
306
308
|
canContinue = sData.length >= limit;
|
|
307
309
|
// console.log(`sData ${sData.length} limit ${limit}`);
|
|
308
310
|
}
|
|
309
|
-
|
|
311
|
+
(0, PubSubManager_1.log)(`server.syncBatch ${table_name}: inserted( ${inserted} ) updated( ${updated} ) deleted( ${deleted} ) pushed to client( ${pushed} ) total( ${total} )`, socket._user);
|
|
310
312
|
return true;
|
|
311
313
|
};
|
|
312
314
|
if (!wal) {
|
|
@@ -377,6 +379,7 @@ const syncData = async (_this, sync, clientData, source) => {
|
|
|
377
379
|
}
|
|
378
380
|
}
|
|
379
381
|
else {
|
|
382
|
+
// do nothing
|
|
380
383
|
}
|
|
381
384
|
if (sync.wal.isSending())
|
|
382
385
|
return;
|